• 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 #define HILOG_TAG "Runtime"
16 
17 #include "virtual_runtime.h"
18 
19 #include <cinttypes>
20 #include <iostream>
21 #include <sstream>
22 #include <unistd.h>
23 #if !is_mingw
24 #include <sys/mman.h>
25 #endif
26 
27 #include "dfx_maps.h"
28 #include "register.h"
29 #include "symbols_file.h"
30 #include "utilities.h"
31 
32 using namespace std::chrono;
33 namespace OHOS {
34 namespace Developtools {
35 namespace NativeDaemon {
36 namespace {
37 std::atomic<uint64_t> callStackErrCnt = 0;
38 constexpr uint32_t CALL_STACK_ERROR_TIMES = 10;
39 constexpr uint32_t SYMBOL_FILES_SIZE = 512;
40 constexpr uint32_t SECOND_INDEX = 2;
41 constexpr uint32_t THIRD_INDEX = 3;
42 constexpr uint32_t INFO_SIZE = 4;
43 }
44 // we unable to access 'swapper' from /proc/0/
ClearMaps()45 void VirtualRuntime::ClearMaps()
46 {
47     processMaps_.clear();
48 }
49 
VirtualRuntime(const NativeHookConfig & hookConfig)50 VirtualRuntime::VirtualRuntime(const NativeHookConfig& hookConfig): hookConfig_(hookConfig)
51 {
52     symbolsFiles_.reserve(SYMBOL_FILES_SIZE);
53     if (!hookConfig_.offline_symbolization()) {
54         userSymbolCache_.reserve(USER_SYMBOL_CACHE_LIMIT);
55     }
56 }
57 
~VirtualRuntime()58 VirtualRuntime::~VirtualRuntime()
59 {
60     PROFILER_LOG_INFO(LOG_CORE, "%s:%d UserSymbolCache size = %zu", __func__, __LINE__, userSymbolCache_.size());
61     PROFILER_LOG_INFO(LOG_CORE, "Total number of call stack errors: %" PRIu64 "", callStackErrCnt.load());
62     ClearMaps();
63 }
64 
ReadThreadName(pid_t tid)65 std::string VirtualRuntime::ReadThreadName(pid_t tid)
66 {
67     std::string comm = ReadFileToString(StringPrintf("/proc/%d/comm", tid)).c_str();
68     comm.erase(std::remove(comm.begin(), comm.end(), '\r'), comm.end());
69     comm.erase(std::remove(comm.begin(), comm.end(), '\n'), comm.end());
70     return comm;
71 }
72 
UpdateThread(pid_t pid,pid_t tid,const std::string name)73 VirtualThread &VirtualRuntime::UpdateThread(pid_t pid, pid_t tid, const std::string name)
74 {
75     pid_ = pid;
76 #ifdef HIPERF_DEBUG_TIME
77     const auto startTime = steady_clock::now();
78 #endif
79     VirtualThread &thread = GetThread(pid, tid);
80     if (!name.empty()) {
81         thread.name_ = name;
82     }
83 #ifdef HIPERF_DEBUG_TIME
84     updateThreadTimes_ += duration_cast<microseconds>(steady_clock::now() - startTime);
85 #endif
86     return thread;
87 }
88 
CreateThread(pid_t pid,pid_t tid)89 VirtualThread &VirtualRuntime::CreateThread(pid_t pid, pid_t tid)
90 {
91     // make a new one
92     userSpaceThreadMap_.emplace(std::piecewise_construct, std::forward_as_tuple(tid),
93                                 std::forward_as_tuple(pid, tid, symbolsFiles_, this));
94     VirtualThread& thr = userSpaceThreadMap_.at(tid);
95     return thr;
96 }
97 
GetThread(pid_t pid,pid_t tid)98 VirtualThread &VirtualRuntime::GetThread(pid_t pid, pid_t tid)
99 {
100     HLOGV("find thread %u:%u", pid, tid);
101     auto it = userSpaceThreadMap_.find(tid);
102     if (it == userSpaceThreadMap_.end()) {
103         // we also need thread
104         VirtualThread& thr = CreateThread(pid, tid);
105         return thr;
106     } else {
107         VirtualThread& thr = it->second;
108         return thr;
109     }
110 }
111 
MakeCallFrame(DfxSymbol & symbol,CallFrame & callFrame)112 void VirtualRuntime::MakeCallFrame(DfxSymbol &symbol, CallFrame &callFrame)
113 {
114     callFrame.vaddrInFile_ = symbol.funcVaddr_;
115     callFrame.symbolName_ = symbol.symbolName_;
116     callFrame.symbolIndex_ = symbol.index_;
117     callFrame.filePath_ = symbol.module_.empty() ? symbol.comm_ : symbol.module_;
118     callFrame.symbolOffset_ = symbol.offset_;
119     callFrame.callFrameId_ = symbol.symbolId_;
120     callFrame.symbolNameId_ = symbol.symbolNameId_;
121     callFrame.filePathId_ = symbol.filePathId_;
122     if (symbol.funcVaddr_ != 0) {
123         callFrame.offset_ = symbol.funcVaddr_;
124     } else {
125         callFrame.offset_ = callFrame.ip_;
126     }
127 }
128 
GetSymbolName(pid_t pid,pid_t tid,std::vector<CallFrame> & callFrames,int offset,bool first,bool onlyjs)129 bool VirtualRuntime::GetSymbolName(pid_t pid, pid_t tid, std::vector<CallFrame>& callFrames, int offset, bool first,
130                                    bool onlyjs)
131 {
132 #ifdef HIPERF_DEBUG_TIME
133     const auto startTime = steady_clock::now();
134 #endif
135     // Symbolic the Call Stack
136     HLOGV("total %zu frames", callFrames.size());
137 
138     perf_callchain_context perfCallchainContext = PERF_CONTEXT_MAX;
139     for (auto callFrameIt = callFrames.begin() + offset; callFrameIt != callFrames.end(); ++callFrameIt) {
140         auto &callFrame = callFrameIt.operator*();
141         if (onlyjs && !callFrame.isJsFrame_) {
142            // only symbolize arkts frame
143             continue;
144         }
145         if (callFrame.ip_ >= PERF_CONTEXT_MAX) {
146             // dont care, this is not issue.
147             HLOGV("%s", UpdatePerfContext(callFrame.ip_, perfCallchainContext).c_str());
148             continue;
149         }
150         auto symbol = GetSymbol(callFrame, pid, tid,
151             perfCallchainContext);
152         if (symbol.IsValid()) {
153             MakeCallFrame(symbol, callFrame);
154         } else {
155 #ifdef TRY_UNWIND_TWICE
156             if (first) {
157                 if (failedIPs_.find(callFrame.ip_) == failedIPs_.end()) {
158                     return false;
159                 } else {
160                     callFrames.erase(callFrameIt, callFrames.end());
161                     return true;
162                 }
163             } else {
164                 failedIPs_.insert(callFrame.ip_);
165                 callFrames.erase(callFrameIt, callFrames.end());
166                 return true;
167             }
168 #else
169             ++callStackErrCnt;
170             if (callStackErrCnt.load() % CALL_STACK_ERROR_TIMES == 0) {
171                 PROFILER_LOG_DEBUG(LOG_CORE, "number of call stack errors: %" PRIu64 "", callStackErrCnt.load());
172             }
173             if (callFrames.back().isJsFrame_) { //The fp mode js call stack is behind the native
174             //call stack, so it can't be deleted entirely
175                 callFrameIt = callFrames.erase(callFrameIt);
176                 --callFrameIt;
177                 continue;
178             }
179             callFrames.erase(callFrameIt, callFrames.end());
180             return true;
181 #endif
182         }
183         int index = callFrameIt - callFrames.begin();
184         HLOGV(" (%u)unwind symbol: %*s%s", index, index, "", callFrame.ToSymbolString().c_str());
185     }
186 #ifdef HIPERF_DEBUG_TIME
187     auto usedTime = duration_cast<microseconds>(steady_clock::now() - startTime);
188     if (usedTime.count() != 0) {
189         HLOGV("cost %0.3f ms to symbolic ", usedTime.count() / MS_DUARTION);
190     }
191     symbolicRecordTimes_ += usedTime;
192 #endif
193     return true;
194 }
195 
UpdateMaps(pid_t pid,pid_t tid)196 void VirtualRuntime::UpdateMaps(pid_t pid, pid_t tid)
197 {
198     auto &thread = UpdateThread(pid, tid);
199     if (thread.ParseMap(processMaps_, true)) {
200         PROFILER_LOG_DEBUG(LOG_CORE, "voluntarily update maps succeed");
201     } else {
202         PROFILER_LOG_DEBUG(LOG_CORE, "voluntarily update maps ignore");
203     }
204 }
205 
UnwindStack(std::vector<u64> & regs,const u8 * stack_addr,int stack_size,pid_t pid,pid_t tid,std::vector<CallFrame> & callFrames,size_t maxStackLevel)206 bool VirtualRuntime::UnwindStack(std::vector<u64>& regs,
207                                  const u8* stack_addr,
208                                  int stack_size,
209                                  pid_t pid,
210                                  pid_t tid,
211                                  std::vector<CallFrame>& callFrames,
212                                  size_t maxStackLevel)
213 {
214 #ifdef HIPERF_DEBUG_TIME
215     const auto startTime = steady_clock::now();
216 #endif
217     // if we have userstack ?
218     int offset = 0;
219     auto &thread = UpdateThread(pid, tid);
220     if (stack_size > 0) {
221         callstack_.UnwindCallStack(thread, &regs[0], regs.size(), stack_addr, stack_size, callFrames, maxStackLevel,
222             hookConfig_.js_stack_report() > 0 ? hookConfig_.max_js_stack_depth() : 0,
223             hookConfig_.js_stack_report() > 0);
224         if (callFrames.size() <= FILTER_STACK_DEPTH) {
225             callFrames.clear();
226             return false;
227         }
228         // Do not symbolize the first two frame, cause the two frame implement by tool itself
229         offset = FILTER_STACK_DEPTH;
230 #ifdef HIPERF_DEBUG_TIME
231         unwindCallStackTimes_ += duration_cast<microseconds>(steady_clock::now() - startTime);
232 #endif
233     }
234 #ifdef HIPERF_DEBUG_TIME
235     unwindFromRecordTimes_ += duration_cast<microseconds>(steady_clock::now() - startTime);
236 #endif
237     if (hookConfig_.offline_symbolization()) {
238         // only get js symbol if report js frame and offline symbolization for dwarf mode
239         if (hookConfig_.js_stack_report() > 0 && !hookConfig_.fp_unwind()) {
240             GetSymbolName(pid, tid, callFrames, offset, true, true);
241         }
242         return true;
243     }
244     if (!GetSymbolName(pid, tid, callFrames, offset, true)) {
245 #ifdef TRY_UNWIND_TWICE
246         HLOGD("clear and unwind one more time");
247         if (!thread.ParseMap(processMaps_, true)) {
248             GetSymbolName(pid, tid, callFrames, offset, false);
249             return false;
250         }
251         if (stack_size > 0) {
252             callFrames.clear();
253             callstack_.UnwindCallStack(thread, &regs[0], regs.size(), stack_addr,
254                 stack_size, callFrames, maxStackLevel, 0, hookConfig_.js_stack_report() > 0);
255         }
256         if (callFrames.size() <= FILTER_STACK_DEPTH) {
257             callFrames.clear();
258             return false;
259         }
260         if (!GetSymbolName(pid, tid, callFrames, offset, false)) {
261             return false;
262         }
263 #endif
264     }
265     return true;
266 }
267 
IsSymbolExist(const std::string & fileName)268 bool VirtualRuntime::IsSymbolExist(const std::string& fileName)
269 {
270     if (symbolsFiles_.find(fileName) != symbolsFiles_.end()) {
271         HLOGV("already have '%s'", fileName.c_str());
272         return true;
273     }
274     return false;
275 }
276 
DelSymbolFile(const std::string & fileName)277 void VirtualRuntime::DelSymbolFile(const std::string& fileName)
278 {
279     symbolsFiles_.erase(fileName);
280 }
281 
UpdateSymbols(std::string fileName,std::shared_ptr<DfxMap> map)282 void VirtualRuntime::UpdateSymbols(std::string fileName, std::shared_ptr<DfxMap> map)
283 {
284     HLOGD("try to find symbols for file: %s", fileName.c_str());
285 #ifdef HIPERF_DEBUG_TIME
286     const auto startTime = steady_clock::now();
287 #endif
288     if (symbolsFiles_.find(fileName) != symbolsFiles_.end()) {
289         HLOGV("already have '%s'", fileName.c_str());
290         return;
291     }
292 
293     // found it by name
294     auto symbolsFile = SymbolsFile::CreateSymbolsFile(fileName, pid_);
295     symbolsFile->SetMapsInfo(map);
296     // set sybol path If it exists
297     if (symbolsPaths_.size() > 0) {
298         symbolsFile->setSymbolsFilePath(symbolsPaths_); // also load from search path
299     }
300     if (loadSymboleWhenNeeded_) {
301         // load it when we need it
302         symbolsFiles_[symbolsFile->filePath_] = std::move(symbolsFile);
303     } else if (symbolsFile->LoadSymbols()) {
304         symbolsFiles_[symbolsFile->filePath_] = std::move(symbolsFile);
305     } else {
306         HLOGW("symbols file for '%s' not found.", fileName.c_str());
307     }
308 #ifdef HIPERF_DEBUG_TIME
309     auto usedTime = duration_cast<microseconds>(steady_clock::now() - startTime);
310     if (usedTime.count() != 0) {
311         HLOGV("cost %0.3f ms to load '%s'", usedTime.count() / MS_DUARTION, fileName.c_str());
312     }
313     updateSymbolsTimes_ += usedTime;
314 #endif
315 }
316 
UpdateHapSymbols(std::shared_ptr<DfxMap> map)317 bool VirtualRuntime::UpdateHapSymbols(std::shared_ptr<DfxMap> map)
318 {
319     auto symbolsFile = SymbolsFile::CreateSymbolsFile(map->name);
320     if (symbolsFile == nullptr) {
321         HLOGV("Failed to load CreateSymbolsFile for exec section in hap(%s)", map->name.c_str());
322         return false;
323     }
324     symbolsFile->SetMapsInfo(map);
325     // update maps name if load debuginfo successfully
326     if (!symbolsFile->LoadDebugInfo(map)) {
327         HLOGV("Failed to load debuginfo for exec section in hap(%s)", map->name.c_str());
328         return false;
329     }
330 
331     if (!loadSymboleWhenNeeded_) {
332         symbolsFile->LoadSymbols(map);
333     }
334     symbolsFiles_[symbolsFile->filePath_] = (std::move(symbolsFile));
335     return true;
336 }
337 
GetKernelSymbol(uint64_t ip,const std::vector<std::shared_ptr<DfxMap>> & maps,const VirtualThread & thread)338 const DfxSymbol VirtualRuntime::GetKernelSymbol(uint64_t ip, const std::vector<std::shared_ptr<DfxMap>> &maps,
339                                                 const VirtualThread &thread)
340 {
341     DfxSymbol vaddrSymbol(ip, thread.name_);
342     for (auto &map : maps) {
343         if (ip > map->begin && ip < map->end) {
344             HLOGM("found addr 0x%" PRIx64 " in kernel map 0x%" PRIx64 " - 0x%" PRIx64 " from %s",
345                   ip, map->begin, map->end, map->name.c_str());
346             vaddrSymbol.module_ = map->name;
347             // found symbols by file name
348             auto search = symbolsFiles_.find(map->name);
349             if (search != symbolsFiles_.end()) {
350                 auto& symbolsFile = search->second;
351                 vaddrSymbol.fileVaddr_ =
352                         symbolsFile->GetVaddrInSymbols(ip, map->begin, map->offset);
353                 HLOGV("found symbol vaddr 0x%" PRIx64 " for runtime vaddr 0x%" PRIx64
354                         " at '%s'",
355                         vaddrSymbol.fileVaddr_, ip, map->name.c_str());
356                 if (!symbolsFile->SymbolsLoaded()) {
357                     symbolsFile->LoadSymbols(map);
358                 }
359                 DfxSymbol foundSymbols = symbolsFile->GetSymbolWithVaddr(vaddrSymbol.fileVaddr_);
360                 foundSymbols.taskVaddr_ = ip;
361                 if (!foundSymbols.IsValid()) {
362                     HLOGW("addr 0x%" PRIx64 " vaddr  0x%" PRIx64 " NOT found in symbol file %s",
363                             ip, vaddrSymbol.fileVaddr_, map->name.c_str());
364                     return vaddrSymbol;
365                 } else {
366                     return foundSymbols;
367                 }
368             }
369             HLOGW("addr 0x%" PRIx64 " in map but NOT found the symbol file %s", ip,
370                   map->name.c_str());
371         } else {
372             HLOGM("addr 0x%" PRIx64 " not in map 0x%" PRIx64 " - 0x%" PRIx64 " from %s", ip,
373                   map->begin, map->end, map->name.c_str());
374         }
375     }
376     return vaddrSymbol;
377 }
378 
GetUserSymbol(uint64_t ip,const VirtualThread & thread)379 const DfxSymbol VirtualRuntime::GetUserSymbol(uint64_t ip, const VirtualThread &thread)
380 {
381     DfxSymbol vaddrSymbol(ip, thread.name_);
382     auto [curMaps, itemIndex] = FindMap(ip);
383     if (curMaps != nullptr) {
384         auto symbolsFilesIter = symbolsFiles_.find((curMaps->GetMaps())[itemIndex]->name);
385         if (symbolsFilesIter != symbolsFiles_.end()) {
386             auto symbolsFile = symbolsFilesIter->second.get();
387             symbolsFile->LoadDebugInfo((curMaps->GetMaps())[itemIndex]);
388             vaddrSymbol.fileVaddr_ =
389                 symbolsFile->GetVaddrInSymbols(ip, (curMaps->GetMaps())[itemIndex]->begin,
390                                                (curMaps->GetMaps())[itemIndex]->offset);
391             vaddrSymbol.module_ = (curMaps->GetMaps())[itemIndex]->name;
392             vaddrSymbol.symbolName_ = vaddrSymbol.GetName();
393             if (!symbolsFile->SymbolsLoaded()) {
394                 symbolsFile->LoadSymbols((curMaps->GetMaps())[itemIndex]);
395             }
396 
397             DfxSymbol foundSymbols;
398 
399             if (!symbolsFile->IsAbc()) {
400                 foundSymbols = symbolsFile->GetSymbolWithVaddr(vaddrSymbol.fileVaddr_);
401             } else {
402                 HLOGD("symbolsFile:%s is ABC :%d", symbolsFile->filePath_.c_str(), symbolsFile->IsAbc());
403                 foundSymbols = symbolsFile->GetSymbolWithPcAndMap(ip, curMaps->GetMaps()[itemIndex]);
404             }
405             foundSymbols.taskVaddr_ = ip;
406             foundSymbols.symbolName_ = foundSymbols.GetName();
407             if (!foundSymbols.IsValid()) {
408                 vaddrSymbol.filePathId_ = curMaps->filePathId_;
409                 return vaddrSymbol;
410             } else {
411                 foundSymbols.filePathId_ = curMaps->filePathId_;
412                 return foundSymbols;
413             }
414         } else {
415             HLOGW("addr 0x%" PRIx64 " in map but NOT found the symbol file %s", ip,
416                   curMaps->name_.c_str());
417         }
418     } else {
419         HLOGW("ReportVaddrMapMiss");
420 #ifdef HIPERF_DEBUG
421         thread.ReportVaddrMapMiss(ip);
422 #endif
423     }
424     return vaddrSymbol;
425 }
426 
GetSymbolCache(uint64_t ip,DfxSymbol & symbol,const VirtualThread & thread)427 bool VirtualRuntime::GetSymbolCache(uint64_t ip, DfxSymbol &symbol, const VirtualThread &thread)
428 {
429     auto [curMaps, itemIndex] = FindMap(ip);
430     if (curMaps != nullptr) {
431         auto foundSymbolIter = userSymbolCache_.find(std::pair(ip, curMaps->filePathId_));
432         if (foundSymbolIter != userSymbolCache_.end()) {
433             symbol = foundSymbolIter->second;
434             return true;
435         }
436     }
437     return false;
438 }
439 
UpdateSymbolCache(uint64_t ip,DfxSymbol & symbol,HashList<uint64_t,DfxSymbol> & cache)440 void VirtualRuntime::UpdateSymbolCache(uint64_t ip, DfxSymbol &symbol,
441     HashList<uint64_t, DfxSymbol> &cache)
442 {
443     // review change to LRU for memmory
444     HLOG_ASSERT_MESSAGE(cache.count(ip) == 0, "already have cached ip 0x%" PRIx64 "", ip);
445     cache[ip] = symbol;
446 }
447 
GetSymbol(CallFrame & callFrame,pid_t pid,pid_t tid,const perf_callchain_context & context)448 const DfxSymbol VirtualRuntime::GetSymbol(CallFrame& callFrame, pid_t pid, pid_t tid,
449                                           const perf_callchain_context &context)
450 {
451     HLOGM("try find tid %u ip 0x%" PRIx64 " in %zu symbolsFiles ", tid, callFrame.ip_, symbolsFiles_.size());
452     DfxSymbol symbol;
453     if (hookConfig_.fp_unwind() && callFrame.isJsFrame_) {
454         if (ArktsGetSymbolCache(callFrame, symbol)) {
455             return symbol;
456         } else {
457             symbol.filePathId_ = FillArkTsFilePath(callFrame.filePath_);
458             symbol.module_ = callFrame.filePath_;
459             symbol.symbolName_ = callFrame.symbolName_;
460             symbol.symbolId_ = userSymbolCache_.size() + 1;
461             if (hookConfig_.string_compressed()) {
462                 FillSymbolNameId(callFrame, symbol);
463                 FillFileSet(callFrame, symbol);
464             }
465             callFrame.needReport_ |= CALL_FRAME_REPORT;
466             userSymbolCache_[std::pair(callFrame.ip_, symbol.filePathId_)] = symbol;
467             return symbol;
468         }
469     } else if (GetSymbolCache(callFrame.ip_, symbol, GetThread(pid, tid))) {
470         return symbol;
471     }
472     if (context == PERF_CONTEXT_USER || (context == PERF_CONTEXT_MAX && !symbol.IsValid())) {
473         // check userspace memmap
474         symbol = GetUserSymbol(callFrame.ip_, GetThread(pid, tid));
475         if (symbol.IsValid()) {
476             HLOGM("GetUserSymbol valid tid = %d ip = 0x%" PRIx64 "", tid, callFrame.ip_);
477             symbol.symbolId_ = userSymbolCache_.size() + 1;
478             if (hookConfig_.string_compressed()) {
479                 FillSymbolNameId(callFrame, symbol);
480                 FillFileSet(callFrame, symbol);
481             }
482             callFrame.needReport_ |= CALL_FRAME_REPORT;
483             userSymbolCache_[std::pair(callFrame.ip_, symbol.filePathId_)] = symbol;
484         } else {
485             HLOGM("GetUserSymbol invalid!");
486         }
487     }
488 
489     return symbol;
490 }
491 
SetSymbolsPaths(const std::vector<std::string> & symbolsPaths)492 bool VirtualRuntime::SetSymbolsPaths(const std::vector<std::string> &symbolsPaths)
493 {
494     std::unique_ptr<SymbolsFile> symbolsFile = SymbolsFile::CreateSymbolsFile(SYMBOL_UNKNOW_FILE);
495     // we need check if the path is accessable
496     bool accessable = symbolsFile->setSymbolsFilePath(symbolsPaths);
497     if (accessable) {
498         symbolsPaths_ = symbolsPaths;
499     } else {
500         if (!symbolsPaths.empty()) {
501             printf("some symbols path unable access\n");
502         }
503     }
504     return accessable;
505 }
506 
FillMapsCache(std::string & currentFileName,std::shared_ptr<DfxMap> mapItem)507 void VirtualRuntime::FillMapsCache(std::string& currentFileName, std::shared_ptr<DfxMap> mapItem)
508 {
509     if (currentFileName.compare(mapItem->name) != 0) {
510         currentFileName = mapItem->name;
511         soBegin_ = mapItem->begin;
512         auto memMaps = std::make_shared<MemMaps>(++memMapFilePathId_);
513         memMaps->AddMap(mapItem, true);
514         mapsCache_[mapItem->begin] = memMaps;
515     } else {
516         if (auto curMapsIter = mapsCache_.find(soBegin_);
517                 curMapsIter != mapsCache_.end()) {
518             auto& curMaps = curMapsIter->second;
519             curMaps->soEnd_ = mapItem->end;
520             curMaps->AddMap(mapItem, false);
521             if (mapItem->prots & PROT_EXEC) {
522                 offlineMapAddr_.push_back(soBegin_);
523             }
524         }
525     }
526 }
527 
FillSymbolNameId(CallFrame & callFrame,DfxSymbol & symbol)528 void VirtualRuntime::FillSymbolNameId(CallFrame& callFrame, DfxSymbol& symbol)
529 {
530     auto itFuntion = functionMap_.find(std::string(symbol.symbolName_));
531     if (itFuntion != functionMap_.end()) {
532         symbol.symbolNameId_ = itFuntion->second;
533     } else {
534         symbol.symbolNameId_ = functionMap_.size() + 1;
535         functionMap_[std::string(symbol.symbolName_)] = symbol.symbolNameId_;
536         callFrame.needReport_ |= SYMBOL_NAME_ID_REPORT;
537     }
538 }
539 
FillFileSet(CallFrame & callFrame,const DfxSymbol & symbol)540 void VirtualRuntime::FillFileSet(CallFrame& callFrame, const DfxSymbol& symbol)
541 {
542     auto itFile = fileSet_.find(symbol.filePathId_);
543     if (itFile == fileSet_.end()) {
544         callFrame.needReport_ |= FILE_PATH_ID_REPORT;
545         fileSet_.insert(symbol.filePathId_);
546     }
547 }
548 
HandleMapInfo(std::vector<uint64_t> info,const std::string & filePath,pid_t pid,pid_t tid)549 void VirtualRuntime::HandleMapInfo(std::vector<uint64_t> info, const std::string& filePath, pid_t pid, pid_t tid)
550 {
551     if (info.size() != INFO_SIZE) {
552         return;
553     }
554     uint64_t begin = info[0];
555     uint64_t length = info[1];
556     uint64_t flags = info[SECOND_INDEX];
557     uint64_t offset = info[THIRD_INDEX];
558     if (!(flags & MAP_FIXED)) {
559         return;
560     }
561     if (offset == 0 && mapsCache_.find(begin) == mapsCache_.end()) {
562         soBegin_ = begin;
563         std::shared_ptr<DfxMap> mapItem = std::make_shared<DfxMap>(begin, begin + length, offset, flags, filePath);
564         auto memMaps = std::make_shared<MemMaps>(++memMapFilePathId_);
565         memMaps->AddMap(mapItem, true);
566         mapsCache_[begin] = memMaps;
567         UpdateSymbols(filePath, mapItem);
568         if (!hookConfig_.fp_unwind() && hookConfig_.startup_mode()) {
569             auto &thread = UpdateThread(pid, tid);
570             thread.ParseMap(processMaps_, false);
571         } else if (!hookConfig_.fp_unwind()) {
572             auto &thread = UpdateThread(pid, tid);
573             processMaps_.emplace_back(mapItem);
574             thread.SortMaps();
575         }
576     } else {
577         auto curMapsIter = mapsCache_.find(soBegin_);
578         if (curMapsIter != mapsCache_.end() && (curMapsIter->second->name_ == filePath)) {
579             auto& curMaps = curMapsIter->second;
580             curMaps->soEnd_ = begin + length;
581             std::shared_ptr<DfxMap> mapItem = std::make_shared<DfxMap>(begin, begin + length,
582                                                                        offset, flags, curMaps->name_);
583             if (mapItem->name.find(".hap") != std::string::npos && (mapItem->prots & PROT_EXEC)) {
584                 mapItem->prevMap = curMaps->GetMaps().back();
585                 HLOGD("update hap(%s) symbols", mapItem->name.c_str());
586                 UpdateHapSymbols(mapItem);
587             }
588             if (!hookConfig_.fp_unwind() && !hookConfig_.startup_mode()) {
589                 auto &thread = UpdateThread(pid, tid);
590                 processMaps_.emplace_back(mapItem);
591                 thread.SortMaps();
592             }
593             if (begin == curMaps->soBegin_) {
594                 if (!curMaps->ReplaceFront(mapItem)) {
595                     curMaps->AddMap(mapItem, false);
596                 }
597             } else {
598                 curMaps->AddMap(mapItem, false);
599             }
600         }
601     }
602     if (flags & PROT_EXEC) {
603         offlineMapAddr_.push_back(soBegin_);
604     }
605 }
606 
RemoveMaps(uint64_t addr)607 void VirtualRuntime::RemoveMaps(uint64_t addr)
608 {
609     mapsCache_.erase(addr);
610 }
611 
FindMap(uint64_t addr)612 std::pair<std::shared_ptr<MemMaps>, uint32_t> VirtualRuntime::FindMap(uint64_t addr)
613 {
614     auto iter = mapsCache_.upper_bound(addr);
615     if (iter == mapsCache_.begin()) {
616         // have map 2 3 4 5
617         // find 1 , will return 2 (index 0, begin elem)
618         // this same as not found any thins
619         return {nullptr, 0};
620     }
621 
622     std::shared_ptr<MemMaps> curMaps = (--iter)->second;
623     if (addr >= curMaps->soBegin_ && addr < curMaps->soEnd_) {
624         std::vector<std::shared_ptr<DfxMap>> mapVec = curMaps->GetMaps();
625         for (auto curMapItem = mapVec.begin();
626             curMapItem != mapVec.end(); ++curMapItem) {
627             if (addr >= (*curMapItem)->begin && addr < (*curMapItem)->end) {
628                 return {curMaps, curMapItem - mapVec.begin()};
629             }
630         }
631     }
632     return {nullptr, 0};
633 }
634 
ArktsGetSymbolCache(CallFrame & callFrame,DfxSymbol & symbol)635 bool VirtualRuntime::ArktsGetSymbolCache(CallFrame& callFrame, DfxSymbol &symbol)
636 {
637     uint32_t jsfilePathId = FindArkTsFilePath(callFrame.filePath_);
638     if (jsfilePathId != 0) {
639         auto foundSymbolIter = userSymbolCache_.find(std::pair(callFrame.ip_, jsfilePathId));
640         if (foundSymbolIter != userSymbolCache_.end()) {
641             symbol = foundSymbolIter->second;
642             return true;
643         }
644     }
645     return false;
646 }
647 
FindArkTsFilePath(std::string_view & jstr)648 uint32_t VirtualRuntime::FindArkTsFilePath(std::string_view& jstr)
649 {
650     auto iter = jsUrlMap_.find(jstr);
651     if (iter == jsUrlMap_.end()) {
652         return 0;
653     } else {
654         return iter->second;
655     }
656 }
657 
FillArkTsFilePath(std::string_view & jstr)658 uint32_t VirtualRuntime::FillArkTsFilePath(std::string_view& jstr)
659 {
660     auto iter = jsUrlMap_.find(jstr);
661     if (iter == jsUrlMap_.end()) {
662         jsUrlMap_[jstr] = ++memMapFilePathId_;
663     }
664     return jsUrlMap_[jstr];
665 }
666 
FillJsSymbolCache(CallFrame & callFrame,const DfxSymbol & symbol)667 void VirtualRuntime::FillJsSymbolCache(CallFrame& callFrame, const DfxSymbol& symbol)
668 {
669     userSymbolCache_[std::pair(callFrame.ip_, symbol.filePathId_)] = symbol;
670 }
671 
GetJsSymbolCacheSize()672 uint32_t VirtualRuntime::GetJsSymbolCacheSize()
673 {
674     return userSymbolCache_.size() + 1;
675 }
676 
677 } // namespace NativeDaemon
678 } // namespace Developtools
679 } // namespace OHOS
680