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 HIPERF_VIRTUAL_RUNTIME_H 16 #define HIPERF_VIRTUAL_RUNTIME_H 17 #include <unistd.h> 18 #include <sys/types.h> 19 #include <pthread.h> 20 #include <functional> 21 #include <map> 22 #if defined(is_ohos) && is_ohos 23 #include "call_stack.h" 24 #endif 25 #include "hashlistpp.h" 26 #include "perf_event_record.h" 27 #include "symbols_file.h" 28 #include "virtual_thread.h" 29 #include "native_hook_config.pb.h" 30 31 namespace OHOS { 32 namespace Developtools { 33 namespace NativeDaemon { 34 /* 35 This Class contains userspace thread objects. and kernel space objects 36 It represents a virtual operating environment, mainly referring to the relationship between pid, 37 mmaps, and symbols. 38 39 It mainly receives data is ip pointer (virtual address), pid 40 According to these data, it will find the corresponding mmap and its corresponding elf (also called 41 DSO) 42 43 Then find the corresponding symbol in the corresponding elf symbol file according to the offset 44 recorded in the corresponding mmap. 45 */ 46 47 class VirtualRuntime { 48 public: 49 VirtualRuntime() = default; 50 VirtualRuntime(const NativeHookConfig& hookConfig); 51 virtual ~VirtualRuntime(); 52 // thread need hook the record 53 // from the record , it will call back to write some Simulated Record 54 // case 1. some mmap will be create when it read mmaps for each new process (from record sample) 55 56 // set symbols path , it will send to every symobile file for search 57 bool SetSymbolsPaths(const std::vector<std::string> &symbolsPaths); 58 59 // any mode 60 static_assert(sizeof(pid_t) == sizeof(int)); 61 GetSymbolsFiles() const62 const std::unordered_map<std::string, std::unique_ptr<SymbolsFile>> &GetSymbolsFiles() const 63 { 64 return symbolsFiles_; 65 } 66 67 const DfxSymbol GetSymbol(CallFrame& callFrame, pid_t pid, pid_t tid, 68 const perf_callchain_context &context = PERF_CONTEXT_MAX); 69 70 VirtualThread &GetThread(pid_t pid, pid_t tid); GetThreads() const71 const std::map<pid_t, VirtualThread> &GetThreads() const 72 { 73 return userSpaceThreadMap_; 74 } 75 76 bool UnwindStack(std::vector<u64>& regs, 77 const u8* stack_addr, 78 int stack_size, 79 pid_t pid, 80 pid_t tid, 81 std::vector<CallFrame>& callFrames, 82 size_t maxStackLevel); 83 bool GetSymbolName(pid_t pid, pid_t tid, std::vector<CallFrame>& callFrames, int offset, bool first, 84 bool onlyjs = false); 85 void ClearMaps(); 86 void FillMapsCache(std::string& currentFileName, std::shared_ptr<DfxMap> mapItem); 87 void HandleMapInfo(std::vector<uint64_t> info, const std::string& filePath, pid_t pid, pid_t tid); 88 void RemoveMaps(uint64_t addr); 89 // threads 90 VirtualThread &UpdateThread(pid_t pid, pid_t tid, const std::string name = ""); 91 void FillSymbolNameId(CallFrame& callFrame, DfxSymbol& symbol); 92 void FillFileSet(CallFrame& callFrame, const DfxSymbol& symbol); 93 uint32_t FillArkTsFilePath(std::string_view& jstr); 94 uint32_t FindArkTsFilePath(std::string_view& jstr); 95 bool ArktsGetSymbolCache(CallFrame& callFrame, DfxSymbol &symbol); 96 uint32_t GetJsSymbolCacheSize(); 97 void FillJsSymbolCache(CallFrame& callFrame, const DfxSymbol& symbol); GetOfflineMaps()98 std::vector<uint64_t>& GetOfflineMaps() 99 { 100 return offlineMapAddr_; 101 } 102 ClearOfflineMaps()103 void ClearOfflineMaps() 104 { 105 offlineMapAddr_.clear(); 106 } 107 GetMapsCache()108 std::map<uint64_t, std::shared_ptr<MemMaps>>& GetMapsCache() 109 { 110 return mapsCache_; 111 } 112 113 std::pair<std::shared_ptr<MemMaps>, uint32_t> FindMap(uint64_t addr); 114 uint64_t soBegin_ {0}; 115 // debug time 116 #ifdef HIPERF_DEBUG_TIME 117 std::chrono::microseconds updateSymbolsTimes_ = std::chrono::microseconds::zero(); 118 std::chrono::microseconds unwindFromRecordTimes_ = std::chrono::microseconds::zero(); 119 std::chrono::microseconds unwindCallStackTimes_ = std::chrono::microseconds::zero(); 120 std::chrono::microseconds symbolicRecordTimes_ = std::chrono::microseconds::zero(); 121 std::chrono::microseconds updateThreadTimes_ = std::chrono::microseconds::zero(); 122 #endif 123 const bool loadSymboleWhenNeeded_ = true; // thie is a feature config 124 void UpdateSymbols(std::string filename, std::shared_ptr<DfxMap> map); 125 // we don't know whether hap vma mapping is stand for a so 126 // thus we need try to parse it first 127 bool UpdateHapSymbols(std::shared_ptr<DfxMap> map); 128 bool IsSymbolExist(const std::string& fileName); 129 void DelSymbolFile(const std::string& fileName); 130 void UpdateMaps(pid_t pid, pid_t tid); GetProcessMaps()131 std::vector<std::shared_ptr<DfxMap>>& GetProcessMaps() 132 { 133 return processMaps_; 134 } 135 136 public: 137 enum SymbolCacheLimit : std::size_t { 138 USER_SYMBOL_CACHE_LIMIT = 10000, 139 }; 140 141 private: 142 struct SymbolCacheKey : public std::pair<uint64_t, uint32_t> { 143 uint64_t& ip = first; 144 uint32_t& filePathId = second; 145 explicit SymbolCacheKey() = default; 146 virtual ~SymbolCacheKey() = default; 147 SymbolCacheKey(const SymbolCacheKey &) = default; operator =OHOS::Developtools::NativeDaemon::VirtualRuntime::SymbolCacheKey148 SymbolCacheKey& operator=(const SymbolCacheKey& sym) 149 { 150 ip = sym.ip; 151 filePathId = sym.filePathId; 152 return *this; 153 } SymbolCacheKeyOHOS::Developtools::NativeDaemon::VirtualRuntime::SymbolCacheKey154 SymbolCacheKey(const std::pair<uint64_t, uint32_t>& arg) : pair(arg), ip(first), filePathId(second) {} SymbolCacheKeyOHOS::Developtools::NativeDaemon::VirtualRuntime::SymbolCacheKey155 SymbolCacheKey(uint64_t ip, uint32_t filePathId) : pair(ip, filePathId), ip(first), filePathId(second) {} 156 }; 157 158 // boost library recommendation algorithm to reduce hash collisions. 159 struct HashPair { operator ()OHOS::Developtools::NativeDaemon::VirtualRuntime::HashPair160 size_t operator() (const SymbolCacheKey& key) const 161 { 162 std::hash<uint64_t> hasher; 163 size_t seed = 0; 164 // 6 and 2 is the number of displacements 165 seed ^= hasher(key.ip) + 0x9e3779b9 + (seed << 6) + (seed >> 2); 166 seed ^= hasher(key.filePathId) + 0x9e3779b9 + (seed << 6) + (seed >> 2); 167 return seed; 168 } 169 }; 170 #if defined(is_ohos) && is_ohos 171 CallStack callstack_; 172 #endif 173 // pid map with user space thread 174 pid_t pid_ = 0; 175 pthread_mutex_t threadMapsLock_; 176 std::map<pid_t, VirtualThread> userSpaceThreadMap_; 177 // not pid , just map 178 std::vector<DfxMap> kernelSpaceMaps_; 179 pthread_mutex_t processSymbolsFileLock_; 180 std::unordered_set<uint32_t> fileSet_; // for mapItem filePathId_ 181 std::unordered_map<std::string, uint32_t> functionMap_; 182 std::unordered_map<std::string, std::unique_ptr<SymbolsFile>> symbolsFiles_; 183 std::unordered_map<SymbolCacheKey, DfxSymbol, HashPair> userSymbolCache_; 184 bool GetSymbolCache(uint64_t ip, DfxSymbol &symbol, const VirtualThread &thread); 185 void UpdateSymbolCache(uint64_t ip, DfxSymbol &symbol, HashList<uint64_t, DfxSymbol> &cache); 186 187 // find synbols function name 188 void MakeCallFrame(DfxSymbol &symbol, CallFrame &callFrame); 189 190 std::string ReadThreadName(pid_t tid); 191 VirtualThread &CreateThread(pid_t pid, pid_t tid); 192 193 const DfxSymbol GetKernelSymbol(uint64_t ip, const std::vector<std::shared_ptr<DfxMap>> &maps, 194 const VirtualThread &thread); 195 const DfxSymbol GetUserSymbol(uint64_t ip, const VirtualThread &thread); 196 197 std::vector<std::string> symbolsPaths_; 198 199 friend class VirtualRuntimeTest; 200 friend class VirtualThread; 201 std::vector<std::shared_ptr<DfxMap>> processMaps_; 202 std::unordered_set<uint64_t> failedIPs_; 203 const NativeHookConfig hookConfig_; 204 uint32_t memMapFilePathId_ = 0; 205 std::map<uint64_t, std::shared_ptr<MemMaps>> mapsCache_; // key is memMap soBegin, value is MemMaps 206 std::vector<uint64_t> offlineMapAddr_; // element is memMap soBegin 207 std::unordered_map<std::string_view, uint32_t> jsUrlMap_; // Key is js url , value is filePathId 208 }; 209 } // namespace NativeDaemon 210 } // namespace Developtools 211 } // namespace OHOS 212 #endif