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, ®s[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