1 /* 2 * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 #ifndef STACK_PREPROCESS_H 16 #define STACK_PREPROCESS_H 17 18 #include <chrono> 19 #include <thread> 20 #include <unordered_map> 21 #include <list> 22 #include <algorithm> 23 #include <mutex> 24 #include <variant> 25 26 #include "logging.h" 27 #include "nocopyable.h" 28 #include "stack_data_repeater.h" 29 #include "buffer_writer.h" 30 #include "virtual_runtime.h" 31 #include "hook_common.h" 32 #include "native_hook_config.pb.h" 33 #include "native_hook_result.pb.h" 34 #include "native_hook_result.pbencoder.h" 35 #include "safe_map.h" 36 #include "schedule_task_manager.h" 37 38 using WriterStructPtr = std::unique_ptr<WriterStruct>::pointer; 39 class StackPreprocess : public std::enable_shared_from_this<StackPreprocess> { 40 public: 41 struct RecordStatistic { 42 uint32_t pid {0}; 43 uint32_t callstackId {0}; 44 uint32_t tagId {0}; 45 RecordStatisticsEvent::MemoryType type {RecordStatisticsEvent::MALLOC}; 46 uint64_t applyCount {0}; 47 uint64_t releaseCount {0}; 48 uint64_t applySize {0}; 49 uint64_t releaseSize {0}; 50 }; 51 52 explicit StackPreprocess(const StackDataRepeaterPtr& dataRepeater, const NativeHookConfig& hookConfig, 53 clockid_t pluginDataClockId, FILE* fpHookData = nullptr, bool isHookStandalone = false, 54 bool isSaService = false, bool isProtobufSerialize = true); 55 ~StackPreprocess(); 56 void SetWriter(const std::shared_ptr<Writer>& writer); 57 void SetWriter(const WriterStructPtr& writer); 58 bool StartTakeResults(); 59 bool StopTakeResults(); 60 void FinishTraceFile(); 61 bool FlushRecordStatistics(); 62 void FlushRecordApplyAndReleaseMatchData(); 63 void ForceStop(); SetPid(int32_t pid)64 inline void SetPid(int32_t pid) 65 { 66 pid_ = pid; 67 } InitStatisticsTime()68 inline void InitStatisticsTime() 69 { 70 lastStatisticsTime_ = std::chrono::steady_clock::now(); 71 } 72 void SaveMemTag(uint32_t tagId, const std::string& tagName); 73 bool GetMemTag(uint32_t tagId, std::string& tagName); 74 void SaveJsRawStack(uint64_t jsChainId, const char* jsRawStack); 75 const char* GetJsRawStack(uint64_t jsChainId); 76 void ReportBasicData(); 77 void WriteHookConfig(); 78 void TakeResultsFromShmem(const std::shared_ptr<EventNotifier>&, const std::shared_ptr<ShareMemoryBlock>&); SetNmdFd(uint32_t fd)79 void SetNmdFd(uint32_t fd) 80 { 81 nmdFd_ = fd; 82 } SetFlushSize(uint64_t size)83 void SetFlushSize(uint64_t size) 84 { 85 double tenth = static_cast<double>(size) / 10.0; 86 flushSize_ = static_cast<uint64_t>(std::ceil(tenth)); 87 PROFILER_LOG_INFO(LOG_CORE, "SetFlushSize size: %" PRIu64 ", flushSize_: %" PRIu64 "", size, flushSize_); 88 if (isProtobufSerialize_) { 89 bufferSize_ = flushSize_ << 1; 90 buffer_ = std::make_unique<uint8_t[]>(bufferSize_); 91 } 92 } 93 94 private: 95 using CallFrame = OHOS::Developtools::NativeDaemon::CallFrame; 96 struct ElfSymbolTable { 97 uint64_t textVaddr; 98 uint32_t textOffset; 99 uint32_t symEntSize; 100 std::vector<uint8_t> strTable; 101 std::vector<uint8_t> symTable; 102 }; 103 104 enum RecordStatisticsLimit : std::size_t { 105 STATISTICS_MAP_SZIE = 100000, 106 STATISTICS_PERIOD_DATA_SIZE = 100000, 107 ALLOC_ADDRMAMP_SIZE = 100000, 108 MATCH_ADDRMAMP_SIZE = 100000, 109 }; 110 111 struct ScopedLockFile { ScopedLockFileStackPreprocess::ScopedLockFile112 ScopedLockFile(FILE* fpHook): fpHookData(fpHook) 113 { 114 flockfile(fpHookData); 115 } ~ScopedLockFileStackPreprocess::ScopedLockFile116 ~ScopedLockFile() 117 { 118 funlockfile(fpHookData); 119 } 120 FILE* fpHookData {nullptr}; 121 }; 122 123 private: 124 void TakeResults(); 125 template <typename T> 126 void SetHookData(RawStackPtr rawStack, T& stackData); 127 template <typename T> 128 void SetHookData(RawStackPtr rawStack, std::vector<CallFrame>& callFrames, T& stackData); 129 void WriteFrames(RawStackPtr RawStack, const std::vector<CallFrame>& callFrames); 130 template <typename T> 131 void SetFrameInfo(T& frame, CallFrame& callFrame); 132 template <typename T> 133 void ReportSymbolNameMap(CallFrame& callFrame, T& stackData); 134 template <typename T> 135 void ReportFilePathMap(CallFrame& callFrame, T& stackData); 136 template <typename T> 137 void ReportFrameMap(CallFrame& callFrame, T& stackData); 138 void ReportThreadNameMap(uint32_t tid, const std::string& tname); 139 void SetMapsInfo(); 140 template <typename T> 141 void SetSymbolInfo(uint32_t filePathId, ElfSymbolTable& symbolInfo, T& batchNativeHookData); 142 template <typename T> 143 void FlushCheck(T& stackData); 144 void FlushData(BatchNativeHookData& stackData); 145 void FlushData(OHOS::Developtools::Profiler::ProtoEncoder::BatchNativeHookData& stackData); 146 void Flush(const uint8_t* src, size_t size); 147 void GetSymbols(const std::string& filePath, ElfSymbolTable& symbols); 148 template <typename T> 149 void FillOfflineCallStack(std::vector<CallFrame>& callFrames, size_t idx, T& stackData); 150 template <typename T> 151 void FillCallStack(std::vector<CallFrame>& callFrames, size_t idx, T& stackData); 152 template <typename T> 153 uint32_t SetCallStackMap(T& stackData); 154 template <typename T> 155 uint32_t GetCallStackId(const RawStackPtr& rawStack, std::vector<CallFrame>& callFrames, T& stackData); 156 uint32_t FindCallStackId(std::vector<uint64_t>& callStack); 157 template <typename T> 158 void SetEventFrame(const RawStackPtr& rawStack, std::vector<CallFrame>& callFrames, 159 T* event, uint32_t stackId, const std::string& type = ""); 160 template <typename T> 161 void SetEventFrame(const ReportEventBaseData& rawStack, T* event, uint32_t stackMapId, 162 const std::string& type = ""); 163 template <typename T> 164 void SetAllocStatisticsFrame(const RawStackPtr& rawStack, std::vector<CallFrame>& callFrames, T& stackData); 165 template <typename T> 166 void SetAllocStatisticsFrame(const RawStackPtr& rawStack, T& stackData); 167 template <typename T> 168 void SetApplyAndReleaseMatchFrame(RawStackPtr rawStack, std::vector<CallFrame>& callFrames, T& stackData); 169 void IntervalFlushRecordStatistics(); 170 void IntervalFlushApplyAndReleaseMatchData(); 171 bool HandleNoStackEvent(RawStackPtr& rawStack); 172 bool SetFreeStatisticsData(uint64_t addr); 173 void SetAllocStatisticsData(const RawStackPtr& rawStack, size_t stackId, bool isExists = false); 174 unsigned LgFloor(unsigned long x); 175 uint64_t PowCeil(uint64_t x); 176 size_t ComputeAlign(size_t size); 177 void ReportOfflineSymbolizationData(); 178 179 RandomWriteCtx* StartReport(); 180 void FinishReport(); 181 void FillFpNativeIp(RawStackPtr& rawData); 182 void FillFpJsData(RawStackPtr& rawData); 183 void FillDwarfErrorStack(); 184 void FillNapiStack(std::string& tagName, std::vector<CallFrame>& callFrames, uint64_t napiIndex); 185 private: 186 std::chrono::steady_clock::time_point lastStatisticsTime_ = std::chrono::steady_clock::now(); 187 std::shared_ptr<Writer> writer_ = nullptr; 188 StackDataRepeaterPtr dataRepeater_ = nullptr; 189 std::thread thread_ {}; 190 std::unique_ptr<uint8_t[]> buffer_; 191 std::atomic_bool isStopTakeData_ = false; 192 std::shared_ptr<OHOS::Developtools::NativeDaemon::VirtualRuntime> runtime_instance; 193 DISALLOW_COPY_AND_MOVE(StackPreprocess); 194 OHOS::SafeMap<uint32_t, std::string> memTagMap_ = {}; 195 std::unordered_map<uint32_t, std::string> threadNameMap_ = {}; 196 NativeHookConfig hookConfig_; 197 uint32_t ignoreCnts_ = 0; 198 uint32_t eventCnts_ = 0; 199 bool flushBasicData_ {true}; 200 std::vector<u64> u64regs_; 201 std::vector<CallFrame> callFrames_; 202 std::vector<uint64_t> callStack_; 203 // Key is callStack_, value is call stack id 204 std::map<std::vector<uint64_t>, uint32_t> callStackMap_; 205 // Key is ip , response_library_mode used 206 std::unordered_map<uint64_t, uint32_t> responseLibraryMap_; 207 std::chrono::seconds statisticsInterval_ {0}; 208 // Key is call stack id, value is recordstatistic data 209 std::unordered_map<uint32_t, RecordStatistic> recordStatisticsMap_; 210 // Key is call stack id, value is recordstatistic data pointer 211 std::unordered_map<uint32_t, RecordStatistic*> statisticsPeriodData_; 212 // Key is alloc or mmap address, value first is mallocsize, second is recordstatistic data pointer 213 std::unordered_map<uint64_t, std::pair<uint64_t, RecordStatistic*>> allocAddrMap_; 214 // Key is alloc or mmap address, value is ReportEventBaseData list iterator 215 std::unordered_map<uint64_t, std::list<ReportEventBaseData>::iterator> applyAndReleaseMatchIntervallMap_; 216 std::list<ReportEventBaseData> applyAndReleaseMatchPeriodListData_; 217 std::chrono::seconds applyAndReleaseMatchInterval_{0}; 218 // used for plugin data 219 clockid_t pluginDataClockId_ = CLOCK_REALTIME; 220 // used for clac wait time in StackDataRepeater::TakeRawData() or statistics HookData 221 clockid_t hookDataClockId_ = CLOCK_REALTIME; 222 FILE* fpHookData_ {nullptr}; 223 bool isHookStandaloneSerialize_ {false}; 224 int32_t pid_ {-1}; 225 std::mutex mtx_; 226 bool isSaService_{false}; 227 std::mutex allocAddrMapMtx_; 228 bool isProtobufSerialize_{true}; 229 WriterStructPtr resultWriter_{nullptr}; 230 std::variant<BatchNativeHookData, OHOS::Developtools::Profiler::ProtoEncoder::BatchNativeHookData> stackData_; 231 uint64_t flushSize_{0}; 232 uint64_t bufferSize_{0}; 233 bool statisticsModelFlushCallstack_{false}; 234 OHOS::Developtools::Profiler::ProtoEncoder::ProfilerPluginData profilerPluginData_; 235 // Key is js stack id , value is js raw stack pointer 236 std::map<uint64_t, const char*> jsStackMap_ = {}; 237 std::set<std::string> jsStackSet_ = {}; 238 bool unwindFailReport_ = true; 239 std::vector<std::string> prctlPeriodTags_; // applyAndReleaseMatchInterval mode used 240 std::vector<std::string> fpJsCallStacks_; 241 std::atomic<uint64_t> napiIndex_{1}; 242 ScheduleTaskManager scheduleTaskManager_; 243 uint32_t nmdFd_ = 0; 244 }; 245 246 #endif // STACK_PREPROCESS_H