• 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,SymbolType type)129 bool VirtualRuntime::GetSymbolName(pid_t pid, pid_t tid, std::vector<CallFrame>& callFrames, int offset, bool first,
130                                    SymbolType type)
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 (type == SymbolType::JS_SYMBOL && !callFrame.isJsFrame_) {
142            // only symbolize arkts frame
143             continue;
144         }
145         if (type == SymbolType::NATIVE_SYMBOL && callFrame.isJsFrame_) {
146             continue;
147         }
148         if (callFrame.ip_ >= PERF_CONTEXT_MAX) {
149             // dont care, this is not issue.
150             HLOGV("%s", UpdatePerfContext(callFrame.ip_, perfCallchainContext).c_str());
151             continue;
152         }
153         auto symbol = GetSymbol(callFrame, pid, tid,
154             perfCallchainContext);
155         if (symbol.IsValid()) {
156             MakeCallFrame(symbol, callFrame);
157         } else {
158 #ifdef TRY_UNWIND_TWICE
159             if (first) {
160                 if (failedIPs_.find(callFrame.ip_) == failedIPs_.end()) {
161                     return false;
162                 } else {
163                     callFrames.erase(callFrameIt, callFrames.end());
164                     return true;
165                 }
166             } else {
167                 failedIPs_.insert(callFrame.ip_);
168                 callFrames.erase(callFrameIt, callFrames.end());
169                 return true;
170             }
171 #else
172             ++callStackErrCnt;
173             if (callStackErrCnt.load() % CALL_STACK_ERROR_TIMES == 0) {
174                 PROFILER_LOG_DEBUG(LOG_CORE, "number of call stack errors: %" PRIu64 "", callStackErrCnt.load());
175             }
176             if (callFrames.back().isJsFrame_) { //The fp mode js call stack is behind the native
177             //call stack, so it can't be deleted entirely
178                 callFrameIt = callFrames.erase(callFrameIt);
179                 --callFrameIt;
180                 continue;
181             }
182             callFrames.erase(callFrameIt, callFrames.end());
183             return true;
184 #endif
185         }
186         int index = callFrameIt - callFrames.begin();
187         HLOGV(" (%u)unwind symbol: %*s%s", index, index, "", callFrame.ToSymbolString().c_str());
188     }
189 #ifdef HIPERF_DEBUG_TIME
190     auto usedTime = duration_cast<microseconds>(steady_clock::now() - startTime);
191     if (usedTime.count() != 0) {
192         HLOGV("cost %0.3f ms to symbolic ", usedTime.count() / MS_DUARTION);
193     }
194     symbolicRecordTimes_ += usedTime;
195 #endif
196     return true;
197 }
198 
UpdateMaps(pid_t pid,pid_t tid)199 void VirtualRuntime::UpdateMaps(pid_t pid, pid_t tid)
200 {
201     auto &thread = UpdateThread(pid, tid);
202     if (thread.ParseMap(processMaps_, true)) {
203         PROFILER_LOG_DEBUG(LOG_CORE, "voluntarily update maps succeed");
204     } else {
205         PROFILER_LOG_DEBUG(LOG_CORE, "voluntarily update maps ignore");
206     }
207 }
208 
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)209 bool VirtualRuntime::UnwindStack(std::vector<u64>& regs,
210                                  const u8* stack_addr,
211                                  int stack_size,
212                                  pid_t pid,
213                                  pid_t tid,
214                                  std::vector<CallFrame>& callFrames,
215                                  size_t maxStackLevel)
216 {
217 #ifdef HIPERF_DEBUG_TIME
218     const auto startTime = steady_clock::now();
219 #endif
220     // if we have userstack ?
221     auto &thread = UpdateThread(pid, tid);
222     if (stack_size > 0) {
223         callstack_.UnwindCallStack(thread, &regs[0], regs.size(), stack_addr, stack_size, callFrames, maxStackLevel,
224             hookConfig_.js_stack_report() > 0 ? hookConfig_.max_js_stack_depth() : 0,
225             hookConfig_.js_stack_report() > 0);
226         if (callFrames.size() <= FILTER_STACK_DEPTH) {
227             callFrames.clear();
228             return false;
229         }
230         // Do not symbolize the first two frame, cause the two frame implement by tool itself
231 #ifdef HIPERF_DEBUG_TIME
232         unwindCallStackTimes_ += duration_cast<microseconds>(steady_clock::now() - startTime);
233 #endif
234     }
235 #ifdef HIPERF_DEBUG_TIME
236     unwindFromRecordTimes_ += duration_cast<microseconds>(steady_clock::now() - startTime);
237 #endif
238     return true;
239 }
240 
IsSymbolExist(const std::string & fileName)241 bool VirtualRuntime::IsSymbolExist(const std::string& fileName)
242 {
243     if (symbolsFiles_.find(fileName) != symbolsFiles_.end()) {
244         HLOGV("already have '%s'", fileName.c_str());
245         return true;
246     }
247     return false;
248 }
249 
DelSymbolFile(const std::string & fileName)250 void VirtualRuntime::DelSymbolFile(const std::string& fileName)
251 {
252     symbolsFiles_.erase(fileName);
253 }
254 
UpdateSymbols(std::string fileName,std::shared_ptr<DfxMap> map)255 void VirtualRuntime::UpdateSymbols(std::string fileName, std::shared_ptr<DfxMap> map)
256 {
257     HLOGD("try to find symbols for file: %s", fileName.c_str());
258 #ifdef HIPERF_DEBUG_TIME
259     const auto startTime = steady_clock::now();
260 #endif
261     if (symbolsFiles_.find(fileName) != symbolsFiles_.end()) {
262         HLOGV("already have '%s'", fileName.c_str());
263         return;
264     }
265 
266     // found it by name
267     auto symbolsFile = SymbolsFile::CreateSymbolsFile(fileName, pid_);
268     symbolsFile->SetMapsInfo(map);
269     // set sybol path If it exists
270     if (symbolsPaths_.size() > 0) {
271         symbolsFile->setSymbolsFilePath(symbolsPaths_); // also load from search path
272     }
273     if (loadSymboleWhenNeeded_) {
274         // load it when we need it
275         symbolsFiles_[symbolsFile->filePath_] = std::move(symbolsFile);
276     } else if (symbolsFile->LoadSymbols()) {
277         symbolsFiles_[symbolsFile->filePath_] = std::move(symbolsFile);
278     } else {
279         HLOGW("symbols file for '%s' not found.", fileName.c_str());
280     }
281 #ifdef HIPERF_DEBUG_TIME
282     auto usedTime = duration_cast<microseconds>(steady_clock::now() - startTime);
283     if (usedTime.count() != 0) {
284         HLOGV("cost %0.3f ms to load '%s'", usedTime.count() / MS_DUARTION, fileName.c_str());
285     }
286     updateSymbolsTimes_ += usedTime;
287 #endif
288 }
289 
UpdateHapSymbols(std::shared_ptr<DfxMap> map)290 bool VirtualRuntime::UpdateHapSymbols(std::shared_ptr<DfxMap> map)
291 {
292     auto symbolsFile = SymbolsFile::CreateSymbolsFile(map->name);
293     if (symbolsFile == nullptr) {
294         HLOGV("Failed to load CreateSymbolsFile for exec section in hap(%s)", map->name.c_str());
295         return false;
296     }
297     symbolsFile->SetMapsInfo(map);
298     // update maps name if load debuginfo successfully
299     if (!symbolsFile->LoadDebugInfo(map)) {
300         HLOGV("Failed to load debuginfo for exec section in hap(%s)", map->name.c_str());
301         return false;
302     }
303 
304     if (!loadSymboleWhenNeeded_) {
305         symbolsFile->LoadSymbols(map);
306     }
307     symbolsFiles_[symbolsFile->filePath_] = (std::move(symbolsFile));
308     return true;
309 }
310 
GetKernelSymbol(uint64_t ip,const std::vector<std::shared_ptr<DfxMap>> & maps,const VirtualThread & thread)311 const DfxSymbol VirtualRuntime::GetKernelSymbol(uint64_t ip, const std::vector<std::shared_ptr<DfxMap>> &maps,
312                                                 const VirtualThread &thread)
313 {
314     DfxSymbol vaddrSymbol(ip, thread.name_);
315     for (auto &map : maps) {
316         if (ip > map->begin && ip < map->end) {
317             HLOGM("found addr 0x%" PRIx64 " in kernel map 0x%" PRIx64 " - 0x%" PRIx64 " from %s",
318                   ip, map->begin, map->end, map->name.c_str());
319             vaddrSymbol.module_ = map->name;
320             // found symbols by file name
321             auto search = symbolsFiles_.find(map->name);
322             if (search != symbolsFiles_.end()) {
323                 auto& symbolsFile = search->second;
324                 vaddrSymbol.fileVaddr_ =
325                         symbolsFile->GetVaddrInSymbols(ip, map->begin, map->offset);
326                 HLOGV("found symbol vaddr 0x%" PRIx64 " for runtime vaddr 0x%" PRIx64
327                         " at '%s'",
328                         vaddrSymbol.fileVaddr_, ip, map->name.c_str());
329                 if (!symbolsFile->SymbolsLoaded()) {
330                     symbolsFile->LoadSymbols(map);
331                 }
332                 DfxSymbol foundSymbols = symbolsFile->GetSymbolWithVaddr(vaddrSymbol.fileVaddr_);
333                 foundSymbols.taskVaddr_ = ip;
334                 if (!foundSymbols.IsValid()) {
335                     HLOGW("addr 0x%" PRIx64 " vaddr  0x%" PRIx64 " NOT found in symbol file %s",
336                             ip, vaddrSymbol.fileVaddr_, map->name.c_str());
337                     return vaddrSymbol;
338                 } else {
339                     return foundSymbols;
340                 }
341             }
342             HLOGW("addr 0x%" PRIx64 " in map but NOT found the symbol file %s", ip,
343                   map->name.c_str());
344         } else {
345             HLOGM("addr 0x%" PRIx64 " not in map 0x%" PRIx64 " - 0x%" PRIx64 " from %s", ip,
346                   map->begin, map->end, map->name.c_str());
347         }
348     }
349     return vaddrSymbol;
350 }
351 
GetUserSymbol(uint64_t ip,const VirtualThread & thread)352 const DfxSymbol VirtualRuntime::GetUserSymbol(uint64_t ip, const VirtualThread &thread)
353 {
354     DfxSymbol vaddrSymbol(ip, thread.name_);
355     auto [curMaps, itemIndex] = FindMap(ip);
356     if (curMaps != nullptr) {
357         auto symbolsFilesIter = symbolsFiles_.find((curMaps->GetMaps())[itemIndex]->name);
358         if (symbolsFilesIter != symbolsFiles_.end()) {
359             auto symbolsFile = symbolsFilesIter->second.get();
360             symbolsFile->LoadDebugInfo((curMaps->GetMaps())[itemIndex]);
361             vaddrSymbol.fileVaddr_ =
362                 symbolsFile->GetVaddrInSymbols(ip, (curMaps->GetMaps())[itemIndex]->begin,
363                                                (curMaps->GetMaps())[itemIndex]->offset);
364             vaddrSymbol.module_ = (curMaps->GetMaps())[itemIndex]->name;
365             vaddrSymbol.symbolName_ = vaddrSymbol.GetName();
366             if (!symbolsFile->SymbolsLoaded()) {
367                 symbolsFile->LoadSymbols((curMaps->GetMaps())[itemIndex]);
368             }
369 
370             DfxSymbol foundSymbols;
371 
372             if (!symbolsFile->IsAbc()) {
373                 foundSymbols = symbolsFile->GetSymbolWithVaddr(vaddrSymbol.fileVaddr_);
374             } else {
375                 HLOGD("symbolsFile:%s is ABC :%d", symbolsFile->filePath_.c_str(), symbolsFile->IsAbc());
376                 foundSymbols = symbolsFile->GetSymbolWithPcAndMap(ip, curMaps->GetMaps()[itemIndex]);
377             }
378             foundSymbols.taskVaddr_ = ip;
379             foundSymbols.symbolName_ = foundSymbols.GetName();
380             if (!foundSymbols.IsValid()) {
381                 vaddrSymbol.filePathId_ = curMaps->filePathId_;
382                 return vaddrSymbol;
383             } else {
384                 foundSymbols.filePathId_ = curMaps->filePathId_;
385                 return foundSymbols;
386             }
387         } else {
388             HLOGW("addr 0x%" PRIx64 " in map but NOT found the symbol file %s", ip,
389                   curMaps->name_.c_str());
390         }
391     } else {
392         HLOGW("ReportVaddrMapMiss");
393 #ifdef HIPERF_DEBUG
394         thread.ReportVaddrMapMiss(ip);
395 #endif
396     }
397     return vaddrSymbol;
398 }
399 
GetSymbolCache(uint64_t ip,DfxSymbol & symbol,const VirtualThread & thread)400 bool VirtualRuntime::GetSymbolCache(uint64_t ip, DfxSymbol &symbol, const VirtualThread &thread)
401 {
402     auto [curMaps, itemIndex] = FindMap(ip);
403     if (curMaps != nullptr) {
404         auto foundSymbolIter = userSymbolCache_.find(std::pair(ip, curMaps->filePathId_));
405         if (foundSymbolIter != userSymbolCache_.end()) {
406             symbol = foundSymbolIter->second;
407             return true;
408         }
409     }
410     return false;
411 }
412 
UpdateSymbolCache(uint64_t ip,DfxSymbol & symbol,HashList<uint64_t,DfxSymbol> & cache)413 void VirtualRuntime::UpdateSymbolCache(uint64_t ip, DfxSymbol &symbol,
414     HashList<uint64_t, DfxSymbol> &cache)
415 {
416     // review change to LRU for memmory
417     HLOG_ASSERT_MESSAGE(cache.count(ip) == 0, "already have cached ip 0x%" PRIx64 "", ip);
418     cache[ip] = symbol;
419 }
420 
GetSymbol(CallFrame & callFrame,pid_t pid,pid_t tid,const perf_callchain_context & context)421 const DfxSymbol VirtualRuntime::GetSymbol(CallFrame& callFrame, pid_t pid, pid_t tid,
422                                           const perf_callchain_context &context)
423 {
424     HLOGM("try find tid %u ip 0x%" PRIx64 " in %zu symbolsFiles ", tid, callFrame.ip_, symbolsFiles_.size());
425     DfxSymbol symbol;
426     if (hookConfig_.fp_unwind() && callFrame.isJsFrame_) {
427         if (ArktsGetSymbolCache(callFrame, symbol)) {
428             return symbol;
429         } else {
430             symbol.filePathId_ = FillArkTsFilePath(callFrame.filePath_);
431             symbol.module_ = callFrame.filePath_;
432             symbol.symbolName_ = callFrame.symbolName_;
433             symbol.symbolId_ = userSymbolCache_.size() + 1;
434             if (hookConfig_.string_compressed()) {
435                 FillSymbolNameId(callFrame, symbol);
436                 FillFileSet(callFrame, symbol);
437             }
438             callFrame.needReport_ |= CALL_FRAME_REPORT;
439             userSymbolCache_[std::pair(callFrame.ip_, symbol.filePathId_)] = symbol;
440             return symbol;
441         }
442     } else if (GetSymbolCache(callFrame.ip_, symbol, GetThread(pid, tid))) {
443         return symbol;
444     }
445     if (context == PERF_CONTEXT_USER || (context == PERF_CONTEXT_MAX && !symbol.IsValid())) {
446         // check userspace memmap
447         symbol = GetUserSymbol(callFrame.ip_, GetThread(pid, tid));
448         if (symbol.IsValid()) {
449             HLOGM("GetUserSymbol valid tid = %d ip = 0x%" PRIx64 "", tid, callFrame.ip_);
450             symbol.symbolId_ = userSymbolCache_.size() + 1;
451             if (hookConfig_.string_compressed()) {
452                 FillSymbolNameId(callFrame, symbol);
453                 FillFileSet(callFrame, symbol);
454             }
455             callFrame.needReport_ |= CALL_FRAME_REPORT;
456             userSymbolCache_[std::pair(callFrame.ip_, symbol.filePathId_)] = symbol;
457         } else {
458             HLOGM("GetUserSymbol invalid!");
459         }
460     }
461 
462     return symbol;
463 }
464 
SetSymbolsPaths(const std::vector<std::string> & symbolsPaths)465 bool VirtualRuntime::SetSymbolsPaths(const std::vector<std::string> &symbolsPaths)
466 {
467     std::unique_ptr<SymbolsFile> symbolsFile = SymbolsFile::CreateSymbolsFile(SYMBOL_UNKNOW_FILE);
468     // we need check if the path is accessable
469     bool accessable = symbolsFile->setSymbolsFilePath(symbolsPaths);
470     if (accessable) {
471         symbolsPaths_ = symbolsPaths;
472     } else {
473         if (!symbolsPaths.empty()) {
474             printf("some symbols path unable access\n");
475         }
476     }
477     return accessable;
478 }
479 
FillMapsCache(std::string & currentFileName,std::shared_ptr<DfxMap> mapItem)480 void VirtualRuntime::FillMapsCache(std::string& currentFileName, std::shared_ptr<DfxMap> mapItem)
481 {
482     if (currentFileName.compare(mapItem->name) != 0) {
483         currentFileName = mapItem->name;
484         soBegin_ = mapItem->begin;
485         auto memMaps = std::make_shared<MemMaps>(++memMapFilePathId_);
486         memMaps->AddMap(mapItem, true);
487         mapsCache_[mapItem->begin] = memMaps;
488     } else {
489         if (auto curMapsIter = mapsCache_.find(soBegin_);
490                 curMapsIter != mapsCache_.end()) {
491             auto& curMaps = curMapsIter->second;
492             curMaps->soEnd_ = mapItem->end;
493             curMaps->AddMap(mapItem, false);
494             if (mapItem->prots & PROT_EXEC) {
495                 offlineMapAddr_.push_back(soBegin_);
496             }
497         }
498     }
499 }
500 
FillSymbolNameId(CallFrame & callFrame,DfxSymbol & symbol)501 void VirtualRuntime::FillSymbolNameId(CallFrame& callFrame, DfxSymbol& symbol)
502 {
503     auto itFuntion = functionMap_.find(std::string(symbol.symbolName_));
504     if (itFuntion != functionMap_.end()) {
505         symbol.symbolNameId_ = itFuntion->second;
506     } else {
507         symbol.symbolNameId_ = functionMap_.size() + 1;
508         functionMap_[std::string(symbol.symbolName_)] = symbol.symbolNameId_;
509         callFrame.needReport_ |= SYMBOL_NAME_ID_REPORT;
510     }
511 }
512 
FillFileSet(CallFrame & callFrame,const DfxSymbol & symbol)513 void VirtualRuntime::FillFileSet(CallFrame& callFrame, const DfxSymbol& symbol)
514 {
515     auto itFile = fileSet_.find(symbol.filePathId_);
516     if (itFile == fileSet_.end()) {
517         callFrame.needReport_ |= FILE_PATH_ID_REPORT;
518         fileSet_.insert(symbol.filePathId_);
519     }
520 }
521 
HandleMapInfo(std::vector<uint64_t> info,const std::string & filePath,pid_t pid,pid_t tid)522 void VirtualRuntime::HandleMapInfo(std::vector<uint64_t> info, const std::string& filePath, pid_t pid, pid_t tid)
523 {
524     if (info.size() != INFO_SIZE) {
525         return;
526     }
527     uint64_t begin = info[0];
528     uint64_t length = info[1];
529     uint64_t flags = info[SECOND_INDEX];
530     uint64_t offset = info[THIRD_INDEX];
531     if (!(flags & MAP_FIXED)) {
532         return;
533     }
534     if (offset == 0 && mapsCache_.find(begin) == mapsCache_.end()) {
535         soBegin_ = begin;
536         std::shared_ptr<DfxMap> mapItem = std::make_shared<DfxMap>(begin, begin + length, offset, flags, filePath);
537         auto memMaps = std::make_shared<MemMaps>(++memMapFilePathId_);
538         memMaps->AddMap(mapItem, true);
539         mapsCache_[begin] = memMaps;
540         UpdateSymbols(filePath, mapItem);
541         if (!hookConfig_.fp_unwind() && hookConfig_.startup_mode()) {
542             auto &thread = UpdateThread(pid, tid);
543             thread.ParseMap(processMaps_, false);
544         } else if (!hookConfig_.fp_unwind()) {
545             auto &thread = UpdateThread(pid, tid);
546             processMaps_.emplace_back(mapItem);
547             thread.SortMaps();
548         }
549     } else {
550         auto curMapsIter = mapsCache_.find(soBegin_);
551         if (curMapsIter != mapsCache_.end() && (curMapsIter->second->name_ == filePath)) {
552             auto& curMaps = curMapsIter->second;
553             curMaps->soEnd_ = begin + length;
554             std::shared_ptr<DfxMap> mapItem = std::make_shared<DfxMap>(begin, begin + length,
555                                                                        offset, flags, curMaps->name_);
556             if (mapItem->name.find(".hap") != std::string::npos && (mapItem->prots & PROT_EXEC)) {
557                 mapItem->prevMap = curMaps->GetMaps().back();
558                 HLOGD("update hap(%s) symbols", mapItem->name.c_str());
559                 UpdateHapSymbols(mapItem);
560             }
561             if (!hookConfig_.fp_unwind() && !hookConfig_.startup_mode()) {
562                 auto &thread = UpdateThread(pid, tid);
563                 processMaps_.emplace_back(mapItem);
564                 thread.SortMaps();
565             }
566             if (begin == curMaps->soBegin_) {
567                 if (!curMaps->ReplaceFront(mapItem)) {
568                     curMaps->AddMap(mapItem, false);
569                 }
570             } else {
571                 curMaps->AddMap(mapItem, false);
572             }
573         }
574     }
575     if (flags & PROT_EXEC) {
576         offlineMapAddr_.push_back(soBegin_);
577     }
578 }
579 
RemoveMaps(uint64_t addr)580 void VirtualRuntime::RemoveMaps(uint64_t addr)
581 {
582     mapsCache_.erase(addr);
583 }
584 
FindMap(uint64_t addr)585 std::pair<std::shared_ptr<MemMaps>, uint32_t> VirtualRuntime::FindMap(uint64_t addr)
586 {
587     auto iter = mapsCache_.upper_bound(addr);
588     if (iter == mapsCache_.begin()) {
589         // have map 2 3 4 5
590         // find 1 , will return 2 (index 0, begin elem)
591         // this same as not found any thins
592         return {nullptr, 0};
593     }
594 
595     std::shared_ptr<MemMaps> curMaps = (--iter)->second;
596     if (addr >= curMaps->soBegin_ && addr < curMaps->soEnd_) {
597         std::vector<std::shared_ptr<DfxMap>> mapVec = curMaps->GetMaps();
598         for (auto curMapItem = mapVec.begin();
599             curMapItem != mapVec.end(); ++curMapItem) {
600             if (addr >= (*curMapItem)->begin && addr < (*curMapItem)->end) {
601                 return {curMaps, curMapItem - mapVec.begin()};
602             }
603         }
604     }
605     return {nullptr, 0};
606 }
607 
ArktsGetSymbolCache(CallFrame & callFrame,DfxSymbol & symbol)608 bool VirtualRuntime::ArktsGetSymbolCache(CallFrame& callFrame, DfxSymbol &symbol)
609 {
610     uint32_t jsfilePathId = FindArkTsFilePath(callFrame.filePath_);
611     if (jsfilePathId != 0) {
612         auto foundSymbolIter = userSymbolCache_.find(std::pair(callFrame.ip_, jsfilePathId));
613         if (foundSymbolIter != userSymbolCache_.end()) {
614             symbol = foundSymbolIter->second;
615             return true;
616         }
617     }
618     return false;
619 }
620 
FindArkTsFilePath(std::string_view & jstr)621 uint32_t VirtualRuntime::FindArkTsFilePath(std::string_view& jstr)
622 {
623     auto iter = jsUrlMap_.find(jstr);
624     if (iter == jsUrlMap_.end()) {
625         return 0;
626     } else {
627         return iter->second;
628     }
629 }
630 
FillArkTsFilePath(std::string_view & jstr)631 uint32_t VirtualRuntime::FillArkTsFilePath(std::string_view& jstr)
632 {
633     auto iter = jsUrlMap_.find(jstr);
634     if (iter == jsUrlMap_.end()) {
635         jsUrlMap_[jstr] = ++memMapFilePathId_;
636     }
637     return jsUrlMap_[jstr];
638 }
639 
FillJsSymbolCache(CallFrame & callFrame,const DfxSymbol & symbol)640 void VirtualRuntime::FillJsSymbolCache(CallFrame& callFrame, const DfxSymbol& symbol)
641 {
642     userSymbolCache_[std::pair(callFrame.ip_, symbol.filePathId_)] = symbol;
643 }
644 
GetJsSymbolCacheSize()645 uint32_t VirtualRuntime::GetJsSymbolCacheSize()
646 {
647     return userSymbolCache_.size() + 1;
648 }
649 
650 } // namespace NativeDaemon
651 } // namespace Developtools
652 } // namespace OHOS
653