• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "native_hook_config.pb.h"
27 
28 namespace OHOS {
29 namespace Developtools {
30 namespace NativeDaemon {
31 /*
32 This Class contains userspace thread objects. and kernel space objects
33 It represents a virtual operating environment, mainly referring to the relationship between pid,
34 mmaps, and symbols.
35 
36 It mainly receives data is ip pointer (virtual address), pid
37 According to these data, it will find the corresponding mmap and its corresponding elf (also called
38 DSO)
39 
40 Then find the corresponding symbol in the corresponding elf symbol file according to the offset
41 recorded in the corresponding mmap.
42 */
43 
44 class VirtualRuntime {
45 public:
46     VirtualRuntime() = default;
47     VirtualRuntime(const NativeHookConfig& hookConfig);
48     virtual ~VirtualRuntime();
49     // thread need hook the record
50     // from the record , it will call back to write some Simulated Record
51     // case 1. some mmap will be create when it read mmaps for each new process (from record sample)
52 
53     // set symbols path , it will send to every symobile file for search
54     bool SetSymbolsPaths(const std::vector<std::string> &symbolsPaths);
55 
56     // any mode
57     static_assert(sizeof(pid_t) == sizeof(int));
58 
GetSymbolsFiles()59     const std::unordered_map<std::string, std::unique_ptr<SymbolsFile>> &GetSymbolsFiles() const
60     {
61         return symbolsFiles_;
62     }
63 
64     const Symbol GetSymbol(CallFrame& callFrame, pid_t pid, pid_t tid,
65                            const perf_callchain_context &context = PERF_CONTEXT_MAX);
66 
67     VirtualThread &GetThread(pid_t pid, pid_t tid);
GetThreads()68     const std::map<pid_t, VirtualThread> &GetThreads() const
69     {
70         return userSpaceThreadMap_;
71     }
72 
73     bool UnwindStack(std::vector<u64>& regs,
74                      const u8* stack_addr,
75                      int stack_size,
76                      pid_t pid,
77                      pid_t tid,
78                      std::vector<CallFrame>& callFrames,
79                      size_t maxStackLevel);
80     bool GetSymbolName(pid_t pid, pid_t tid, std::vector<CallFrame>& callFrames, int offset, bool first);
81     void ClearMaps();
82     void FillMapsCache(std::string& currentFileName, MemMapItem& memMapItem);
83     void HandleMapInfo(uint64_t begin, uint64_t length, uint32_t flags, uint64_t offset, const std::string& filePath);
84     void RemoveMaps(uint64_t addr);
GetOfflineMaps()85     std::vector<uint64_t>& GetOfflineMaps()
86     {
87         return offlineMapAddr_;
88     }
89 
ClearOfflineMaps()90     void ClearOfflineMaps()
91     {
92         offlineMapAddr_.clear();
93     }
94 
GetMapsCache()95     std::map<uint64_t, MemMaps>& GetMapsCache()
96     {
97         return mapsCache_;
98     }
99 
100     std::pair<MemMaps*, uint32_t> FindMap(uint64_t addr);
101     uint64_t soBegin_ {0};
102     // debug time
103 #ifdef HIPERF_DEBUG_TIME
104     std::chrono::microseconds updateSymbolsTimes_ = std::chrono::microseconds::zero();
105     std::chrono::microseconds unwindFromRecordTimes_ = std::chrono::microseconds::zero();
106     std::chrono::microseconds unwindCallStackTimes_ = std::chrono::microseconds::zero();
107     std::chrono::microseconds symbolicRecordTimes_ = std::chrono::microseconds::zero();
108     std::chrono::microseconds updateThreadTimes_ = std::chrono::microseconds::zero();
109 #endif
110     const bool loadSymboleWhenNeeded_ = true; // thie is a feature config
111     void UpdateSymbols(std::string filename);
112     bool IsSymbolExist(const std::string& fileName);
113     void DelSymbolFile(const std::string& fileName);
114     void UpdateMaps(pid_t pid, pid_t tid);
GetProcessMaps()115     std::vector<MemMapItem>& GetProcessMaps()
116     {
117         return processMemMaps_;
118     }
119 
120 public:
121     enum SymbolCacheLimit : std::size_t {
122         USER_SYMBOL_CACHE_LIMIT = 10000,
123     };
124 
125 private:
126     struct SymbolCacheKey : public std::pair<uint64_t, uint32_t> {
127         uint64_t& ip = first;
128         uint32_t& filePathId = second;
129         explicit SymbolCacheKey() = default;
130         virtual ~SymbolCacheKey() = default;
131         SymbolCacheKey(const SymbolCacheKey &) = default;
132         SymbolCacheKey& operator=(const SymbolCacheKey& sym)
133         {
134             ip = sym.ip;
135             filePathId = sym.filePathId;
136             return *this;
137         }
SymbolCacheKeySymbolCacheKey138         SymbolCacheKey(const std::pair<uint64_t, uint32_t>& arg) : pair(arg), ip(first), filePathId(second) {}
SymbolCacheKeySymbolCacheKey139         SymbolCacheKey(uint64_t ip, uint32_t filePathId) : pair(ip, filePathId), ip(first), filePathId(second) {}
140     };
141 
142     // boost library recommendation algorithm to reduce hash collisions.
143     struct HashPair {
operatorHashPair144         size_t operator() (const SymbolCacheKey& key) const
145         {
146             std::hash<uint64_t> hasher;
147             size_t seed = 0;
148             // 6 and 2 is the number of displacements
149             seed ^= hasher(key.ip) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
150             seed ^= hasher(key.filePathId) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
151             return seed;
152         }
153     };
154     CallStack callstack_;
155     // pid map with user space thread
156     pthread_mutex_t threadMapsLock_;
157     std::map<pid_t, VirtualThread> userSpaceThreadMap_;
158     // not pid , just memmap
159     std::vector<MemMapItem> kernelSpaceMemMaps_;
160     pthread_mutex_t processSymbolsFileLock_;
161     std::unordered_set<uint32_t> fileSet_; // for memMpaItem filePathId_
162     std::unordered_map<std::string, uint32_t> functionMap_;
163     std::unordered_map<std::string, std::unique_ptr<SymbolsFile>> symbolsFiles_;
164     std::unordered_map<SymbolCacheKey, Symbol, HashPair> userSymbolCache_;
165     bool GetSymbolCache(uint64_t ip, Symbol &symbol, const VirtualThread &thread);
166     void UpdateSymbolCache(uint64_t ip, Symbol &symbol, HashList<uint64_t, Symbol> &cache);
167 
168     // find synbols function name
169     void MakeCallFrame(Symbol &symbol, CallFrame &callFrame);
170 
171     // threads
172     VirtualThread &UpdateThread(pid_t pid, pid_t tid, const std::string name = "");
173     std::string ReadThreadName(pid_t tid);
174     VirtualThread &CreateThread(pid_t pid, pid_t tid);
175 
176     const Symbol GetKernelSymbol(uint64_t ip, const std::vector<MemMapItem> &memMaps,
177                                  const VirtualThread &thread);
178     const Symbol GetUserSymbol(uint64_t ip, const VirtualThread &thread);
179     void FillSymbolNameId(CallFrame& callFrame, Symbol& symbol);
180     void FillFileSet(CallFrame& callFrame, const Symbol& symbol);
181 
182     std::vector<std::string> symbolsPaths_;
183 
184     friend class VirtualRuntimeTest;
185     friend class VirtualThread;
186     std::vector<MemMapItem> processMemMaps_;
187     std::unordered_set<uint64_t> failedIPs_;
188     const NativeHookConfig hookConfig_;
189     uint32_t memMapFilePathId_ = 0;
190     std::map<uint64_t, MemMaps> mapsCache_; // key is memMap soBegin, value is MemMaps
191     std::vector<uint64_t> offlineMapAddr_; // element is memMap soBegin
192 };
193 } // namespace NativeDaemon
194 } // namespace Developtools
195 } // namespace OHOS
196 #endif