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