1 /* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 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 #include "call_stack.h" 23 #include "perf_event_record.h" 24 #include "symbols_file.h" 25 #include "virtual_thread.h" 26 27 namespace OHOS { 28 namespace Developtools { 29 namespace NativeDaemon { 30 /* 31 This Class contains userspace thread objects. and kernel space objects 32 It represents a virtual operating environment, mainly referring to the relationship between pid, 33 mmaps, and symbols. 34 35 It mainly receives data is ip pointer (virtual address), pid 36 According to these data, it will find the corresponding mmap and its corresponding elf (also called 37 DSO) 38 39 Then find the corresponding symbol in the corresponding elf symbol file according to the offset 40 recorded in the corresponding mmap. 41 */ 42 43 class VirtualRuntime { 44 public: 45 VirtualRuntime(bool onDevice = true); 46 virtual ~VirtualRuntime(); 47 // thread need hook the record 48 // from the record , it will call back to write some Simulated Record 49 // case 1. some mmap will be create when it read mmaps for each new process (from record sample) 50 51 // set symbols path , it will send to every symobile file for search 52 bool SetSymbolsPaths(const std::vector<std::string> &symbolsPaths); 53 54 // any mode 55 static_assert(sizeof(pid_t) == sizeof(int)); 56 GetSymbolsFiles()57 const std::set<std::unique_ptr<SymbolsFile>, CCompareSymbolsFile> &GetSymbolsFiles() const 58 { 59 return symbolsFiles_; 60 } 61 62 const Symbol GetSymbol(uint64_t ip, pid_t pid, pid_t tid, 63 const perf_callchain_context &context = PERF_CONTEXT_MAX); 64 65 VirtualThread &GetThread(pid_t pid, pid_t tid); GetThreads()66 const std::map<pid_t, VirtualThread> &GetThreads() const 67 { 68 return userSpaceThreadMap_; 69 } 70 71 bool UnwindStack(std::vector<u64> regs, 72 const u8* stack_addr, 73 int stack_size, 74 pid_t pid, 75 pid_t tid, 76 std::vector<CallFrame>& callsFrames, 77 size_t maxStackLevel); 78 bool GetSymbolName(pid_t pid, pid_t tid, std::vector<CallFrame>& callsFrames, int offset, bool first); 79 void ClearMaps(); 80 // debug time 81 #ifdef HIPERF_DEBUG_TIME 82 std::chrono::microseconds updateSymbolsTimes_ = std::chrono::microseconds::zero(); 83 std::chrono::microseconds unwindFromRecordTimes_ = std::chrono::microseconds::zero(); 84 std::chrono::microseconds unwindCallStackTimes_ = std::chrono::microseconds::zero(); 85 std::chrono::microseconds symbolicRecordTimes_ = std::chrono::microseconds::zero(); 86 std::chrono::microseconds updateThreadTimes_ = std::chrono::microseconds::zero(); 87 #endif 88 const bool loadSymboleWhenNeeded_ = true; // thie is a feature config 89 void UpdateSymbols(std::string filename); 90 bool IsSymbolExist(std::string fileName); 91 void UpdateMaps(pid_t pid, pid_t tid); 92 private: 93 CallStack callstack_; 94 // pid map with user space thread 95 pthread_mutex_t threadMapsLock_; 96 std::map<pid_t, VirtualThread> userSpaceThreadMap_; 97 // not pid , just memmap 98 std::vector<MemMapItem> kernelSpaceMemMaps_; 99 pthread_mutex_t processSymbolsFileLock_; 100 std::set<std::unique_ptr<SymbolsFile>, CCompareSymbolsFile> symbolsFiles_; 101 enum SymbolCacheLimit : std::size_t { 102 KERNEL_SYMBOL_CACHE_LIMIT = 4000, 103 THREAD_SYMBOL_CACHE_LIMIT = 2000, 104 }; 105 std::unordered_map<pid_t, HashList<uint64_t, Symbol>> threadSymbolCache_; 106 HashList<uint64_t, Symbol> kernelSymbolCache_ {KERNEL_SYMBOL_CACHE_LIMIT}; 107 bool GetSymbolCache(uint64_t ip, pid_t pid, pid_t tid, Symbol &symbol, 108 const perf_callchain_context &context); 109 void UpdateSymbolCache(uint64_t ip, Symbol &symbol, HashList<uint64_t, Symbol> &cache); 110 111 // find synbols function name 112 void MakeCallFrame(Symbol &symbol, CallFrame &callFrame); 113 114 // threads 115 VirtualThread &UpdateThread(pid_t pid, pid_t tid, const std::string name = ""); 116 std::string ReadThreadName(pid_t tid); 117 VirtualThread &CreateThread(pid_t pid, pid_t tid); 118 119 const Symbol GetKernelSymbol(uint64_t ip, const std::vector<MemMapItem> &memMaps, 120 const VirtualThread &thread); 121 const Symbol GetUserSymbol(uint64_t ip, const VirtualThread &thread); 122 123 std::vector<std::string> symbolsPaths_; 124 125 friend class VirtualRuntimeTest; 126 friend class VirtualThread; 127 pthread_mutex_t threadMemMapsLock_; 128 std::vector<MemMapItem> processMemMaps_; 129 std::unordered_set<uint64_t> failedIPs_; 130 }; 131 } // namespace NativeDaemon 132 } // namespace Developtools 133 } // namespace OHOS 134 #endif