• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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()62     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()71     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     void ClearMaps();
85     void FillMapsCache(std::string& currentFileName, std::shared_ptr<DfxMap> mapItem);
86     void HandleMapInfo(uint64_t begin, uint64_t length, uint32_t flags, uint64_t offset, const std::string& filePath);
87     void RemoveMaps(uint64_t addr);
88       // threads
89     VirtualThread &UpdateThread(pid_t pid, pid_t tid, const std::string name = "");
GetOfflineMaps()90     std::vector<uint64_t>& GetOfflineMaps()
91     {
92         return offlineMapAddr_;
93     }
94 
ClearOfflineMaps()95     void ClearOfflineMaps()
96     {
97         offlineMapAddr_.clear();
98     }
99 
GetMapsCache()100     std::map<uint64_t, std::shared_ptr<MemMaps>>& GetMapsCache()
101     {
102         return mapsCache_;
103     }
104 
105     std::pair<std::shared_ptr<MemMaps>, uint32_t> FindMap(uint64_t addr);
106     uint64_t soBegin_ {0};
107     // debug time
108 #ifdef HIPERF_DEBUG_TIME
109     std::chrono::microseconds updateSymbolsTimes_ = std::chrono::microseconds::zero();
110     std::chrono::microseconds unwindFromRecordTimes_ = std::chrono::microseconds::zero();
111     std::chrono::microseconds unwindCallStackTimes_ = std::chrono::microseconds::zero();
112     std::chrono::microseconds symbolicRecordTimes_ = std::chrono::microseconds::zero();
113     std::chrono::microseconds updateThreadTimes_ = std::chrono::microseconds::zero();
114 #endif
115     const bool loadSymboleWhenNeeded_ = true; // thie is a feature config
116     void UpdateSymbols(std::string filename);
117     // we don't know whether hap vma mapping is stand for a so
118     // thus we need try to parse it first
119     bool UpdateHapSymbols(std::shared_ptr<DfxMap> map);
120     bool IsSymbolExist(const std::string& fileName);
121     void DelSymbolFile(const std::string& fileName);
122     void UpdateMaps(pid_t pid, pid_t tid);
GetProcessMaps()123     std::vector<std::shared_ptr<DfxMap>>& GetProcessMaps()
124     {
125         return processMaps_;
126     }
127 
128 public:
129     enum SymbolCacheLimit : std::size_t {
130         USER_SYMBOL_CACHE_LIMIT = 10000,
131     };
132 
133 private:
134     struct SymbolCacheKey : public std::pair<uint64_t, uint32_t> {
135         uint64_t& ip = first;
136         uint32_t& filePathId = second;
137         explicit SymbolCacheKey() = default;
138         virtual ~SymbolCacheKey() = default;
139         SymbolCacheKey(const SymbolCacheKey &) = default;
140         SymbolCacheKey& operator=(const SymbolCacheKey& sym)
141         {
142             ip = sym.ip;
143             filePathId = sym.filePathId;
144             return *this;
145         }
SymbolCacheKeySymbolCacheKey146         SymbolCacheKey(const std::pair<uint64_t, uint32_t>& arg) : pair(arg), ip(first), filePathId(second) {}
SymbolCacheKeySymbolCacheKey147         SymbolCacheKey(uint64_t ip, uint32_t filePathId) : pair(ip, filePathId), ip(first), filePathId(second) {}
148     };
149 
150     // boost library recommendation algorithm to reduce hash collisions.
151     struct HashPair {
operatorHashPair152         size_t operator() (const SymbolCacheKey& key) const
153         {
154             std::hash<uint64_t> hasher;
155             size_t seed = 0;
156             // 6 and 2 is the number of displacements
157             seed ^= hasher(key.ip) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
158             seed ^= hasher(key.filePathId) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
159             return seed;
160         }
161     };
162 #if defined(is_ohos) && is_ohos
163     CallStack callstack_;
164 #endif
165     // pid map with user space thread
166     pthread_mutex_t threadMapsLock_;
167     std::map<pid_t, VirtualThread> userSpaceThreadMap_;
168     // not pid , just map
169     std::vector<DfxMap> kernelSpaceMaps_;
170     pthread_mutex_t processSymbolsFileLock_;
171     std::unordered_set<uint32_t> fileSet_; // for mapItem filePathId_
172     std::unordered_map<std::string, uint32_t> functionMap_;
173     std::unordered_map<std::string, std::unique_ptr<SymbolsFile>> symbolsFiles_;
174     std::unordered_map<SymbolCacheKey, DfxSymbol, HashPair> userSymbolCache_;
175     bool GetSymbolCache(uint64_t ip, DfxSymbol &symbol, const VirtualThread &thread);
176     void UpdateSymbolCache(uint64_t ip, DfxSymbol &symbol, HashList<uint64_t, DfxSymbol> &cache);
177 
178     // find synbols function name
179     void MakeCallFrame(DfxSymbol &symbol, CallFrame &callFrame);
180 
181     std::string ReadThreadName(pid_t tid);
182     VirtualThread &CreateThread(pid_t pid, pid_t tid);
183 
184     const DfxSymbol GetKernelSymbol(uint64_t ip, const std::vector<std::shared_ptr<DfxMap>> &maps,
185                                  const VirtualThread &thread);
186     const DfxSymbol GetUserSymbol(uint64_t ip, const VirtualThread &thread);
187     void FillSymbolNameId(CallFrame& callFrame, DfxSymbol& symbol);
188     void FillFileSet(CallFrame& callFrame, const DfxSymbol& symbol);
189 
190     std::vector<std::string> symbolsPaths_;
191 
192     friend class VirtualRuntimeTest;
193     friend class VirtualThread;
194     std::vector<std::shared_ptr<DfxMap>> processMaps_;
195     std::unordered_set<uint64_t> failedIPs_;
196     const NativeHookConfig hookConfig_;
197     uint32_t memMapFilePathId_ = 0;
198     std::map<uint64_t, std::shared_ptr<MemMaps>> mapsCache_; // key is memMap soBegin, value is MemMaps
199     std::vector<uint64_t> offlineMapAddr_; // element is memMap soBegin
200 };
201 } // namespace NativeDaemon
202 } // namespace Developtools
203 } // namespace OHOS
204 #endif