1/* 2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 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 16#define HILOG_TAG "Symbols" 17 18#include "symbols_file.h" 19 20#include <algorithm> 21#include <chrono> 22#include <cxxabi.h> 23#include <cstdlib> 24#include <fcntl.h> 25#include <fstream> 26#include <string_view> 27#include <type_traits> 28 29#if defined(is_mingw) && is_mingw 30#include <memoryapi.h> 31#else 32#include <sys/mman.h> 33#include <sys/stat.h> 34#endif 35#include <unistd.h> 36 37#include "dfx_ark.h" 38#include "dfx_extractor_utils.h" 39#include "dfx_symbols.h" 40#include "dwarf_encoding.h" 41#include "hiperf_hilog.h" 42#include "unwinder_config.h" 43#include "utilities.h" 44 45using namespace OHOS::HiviewDFX; 46using namespace std::chrono; 47 48namespace OHOS { 49namespace Developtools { 50namespace HiPerf { 51bool SymbolsFile::onRecording_ = true; 52bool SymbolsFile::needParseJsFunc_ = false; 53 54const std::string SymbolsFile::GetBuildId() const 55{ 56 return buildId_; 57} 58 59bool SymbolsFile::UpdateBuildIdIfMatch(std::string buildId) 60{ 61 /* 62 here we have two case 63 1 buildId_ is empty 64 a) always return match 65 2 buildId_ is not empty 66 a) really check if the same one 67 */ 68 69 if (buildId_.empty()) { 70 // we have new empty build 71 if (buildId.empty()) { 72 // both empty , no build id provided 73 HLOGD("build id is empty."); 74 return true; 75 } else { 76 buildId_ = buildId; 77 HLOGD("new buildId %s", buildId_.c_str()); 78 return true; 79 } 80 } else { 81 // we already have a build id 82 // so this is not the first time load symbol 83 // we need check if it match 84 HLOGV("expected buildid: %s vs %s", buildId_.c_str(), buildId.c_str()); 85 86 if (buildId_ != buildId) { 87 HLOGW("id not match"); 88 return false; 89 } else { 90 HLOGD("id match"); 91 return true; 92 } 93 } 94} 95 96std::string SymbolsFile::SearchReadableFile(const std::vector<std::string> &searchPaths, 97 const std::string &filePath) const 98{ 99 if (filePath.empty()) { 100 HLOGW("nothing to found"); 101 return filePath; 102 } 103 for (auto searchPath : searchPaths) { 104 if (searchPath.back() != PATH_SEPARATOR) { 105 searchPath += PATH_SEPARATOR; 106 } 107 std::string PossibleFilePath = searchPath + filePath; 108 if (CheckPathReadable(PossibleFilePath)) { 109 return PossibleFilePath; 110 } 111 HLOGW("have not found '%s' in search paths %s", filePath.c_str(), searchPath.c_str()); 112 } 113 return EMPTY_STRING; 114} 115 116const std::string SymbolsFile::FindSymbolFile( 117 const std::vector<std::string> &symbolsFileSearchPaths, std::string symboleFilePath) const 118{ 119 /* 120 this function do 2 things: 121 find by name: 122 1 find dso path 123 2 find search path 124 a) search path + dso path 125 b) search path + dso name 126 127 show we should return filePath_ as default ? 128 */ 129 if (symboleFilePath.empty()) { 130 symboleFilePath = filePath_; 131 HLOGD("use default filename: %s ", symboleFilePath.c_str()); 132 } 133 symboleFilePath = PlatformPathConvert(symboleFilePath); 134 std::string foundPath; 135 // search first if we have path 136 if (symbolsFileSearchPaths.size() != 0) { 137 foundPath = SearchReadableFile(symbolsFileSearchPaths, symboleFilePath); 138 if (foundPath.empty()) { 139 HLOGV("try base name for: %s split with %s", symboleFilePath.c_str(), 140 PATH_SEPARATOR_STR.c_str()); 141 auto pathSplit = StringSplit(symboleFilePath, PATH_SEPARATOR_STR); 142 if (pathSplit.size() > 1) { 143 HLOGV("base name is: %s ", pathSplit.back().c_str()); 144 // found it again with base name , split it and get last name 145 foundPath = SearchReadableFile(symbolsFileSearchPaths, pathSplit.back()); 146 } 147 } 148 } 149 150 // only access the patch in onRecording_ 151 // in report mode we don't load any thing in runtime path 152 if (foundPath.empty() and onRecording_) { 153 // try access direct at last 154 if (CheckPathReadable(symboleFilePath)) { 155 // found direct folder 156 HLOGD("find %s in current work dir", symboleFilePath.c_str()); 157 return symboleFilePath; 158 } 159 } 160 return foundPath; 161} 162 163class ElfFileSymbols : public SymbolsFile { 164public: 165 explicit ElfFileSymbols(const std::string &symbolFilePath, 166 const SymbolsFileType symbolsFileType = SYMBOL_ELF_FILE) 167 : SymbolsFile(symbolsFileType, symbolFilePath) 168 { 169 } 170 171 virtual ~ElfFileSymbols() 172 { 173 } 174 175 DfxSymbol GetSymbolWithPcAndMap(uint64_t pc, std::shared_ptr<DfxMap> map) override 176 { 177 const DfxSymbol symbol; 178 return symbol; 179 } 180 181 bool LoadSymbols(std::shared_ptr<DfxMap> map, const std::string &symbolFilePath) override 182 { 183 symbolsLoaded_ = true; 184 std::string findPath = FindSymbolFile(symbolsFileSearchPaths_, symbolFilePath); 185 if (findPath.empty() && elfFile_ == nullptr) { // elf not compressed in hap has been initialized before 186 HLOGW("elf found failed (belong to %s)", filePath_.c_str()); 187 return false; 188 } 189 if (LoadElfSymbols(map, findPath)) { 190 return true; 191 } else { 192 HLOGW("elf open failed with '%s'", findPath.c_str()); 193 return false; 194 } 195 return false; 196 } 197 198 void EnableMiniDebugInfo() override 199 { 200 UnwinderConfig::SetEnableMiniDebugInfo(true); 201 } 202 203 std::shared_ptr<DfxElf> GetElfFile() override 204 { 205 return elfFile_; 206 } 207 208 const std::unordered_map<uint64_t, ElfLoadInfo> GetPtLoads() override 209 { 210 CHECK_TRUE(elfFile_ == nullptr, info_, 0, ""); 211 return elfFile_->GetPtLoads(); 212 } 213 214protected: 215 bool LoadDebugInfo(std::shared_ptr<DfxMap> map, const std::string &symbolFilePath) override 216 { 217 std::lock_guard<std::mutex> lock(mutex_); 218 if (debugInfoLoadResult_) { 219 return true; // it must have been loaded 220 } else if (debugInfoLoaded_) { 221 return debugInfoLoadResult_; // return the result of loaded 222 } else { 223 debugInfoLoaded_ = true; 224 } 225 std::string elfPath = FindSymbolFile(symbolsFileSearchPaths_, symbolFilePath); 226 if (elfPath.empty()) { 227 HLOGW("elf found failed (belong to %s)", filePath_.c_str()); 228 return false; 229 } 230 231 if (elfFile_ == nullptr) { 232 if (StringEndsWith(elfPath, ".hap")) { 233 CHECK_TRUE(map == nullptr, false, 1, "map should not be nullptr."); 234 elfFile_ = DfxElf::CreateFromHap(elfPath, map->prevMap, map->offset); 235 HLOGD("try create elf from hap"); 236 } else { 237 elfFile_ = std::make_shared<DfxElf>(elfPath); 238 } 239 } 240 241 CHECK_TRUE(elfFile_ == nullptr, false, 1, "Failed to create elf file for %s.", elfPath.c_str()); 242 243 CHECK_TRUE(!elfFile_->IsValid(), false, 1, "parser elf file failed."); 244 245 HLOGD("loaded elf %s", elfPath.c_str()); 246 // update path for so in hap 247 if (StringEndsWith(elfPath, ".hap")) { 248 filePath_ = elfPath + "!" + elfFile_->GetElfName(); 249 HLOGD("update path for so in hap %s.", filePath_.c_str()); 250 if (map == nullptr) { 251 HLOGW("map should not be nullptr."); 252 return false; 253 } 254 map->name = filePath_; 255 map->elf = elfFile_; 256 map->prevMap->name = filePath_; 257 map->prevMap->elf = elfFile_; 258 } 259 260 textExecVaddr_ = elfFile_->GetStartVaddr(); 261 textExecVaddrFileOffset_ = elfFile_->GetStartOffset(); 262 263 HLOGD("textExecVaddr_ 0x%016" PRIx64 " file offset 0x%016" PRIx64 "", textExecVaddr_, 264 textExecVaddrFileOffset_); 265 266#ifndef __arm__ 267 ShdrInfo shinfo; 268 if (elfFile_->GetSectionInfo(shinfo, ".eh_frame_hdr")) { 269 auto mmapPtr = elfFile_->GetMmapPtr(); 270 CHECK_TRUE(mmapPtr == nullptr, false, 1, "mmapPtr should not be nullptr."); 271 LoadEhFrameHDR(mmapPtr + shinfo.offset, shinfo.size, shinfo.offset); 272 } 273#endif 274 275 HLOGD("LoadDebugInfo success!"); 276 debugInfoLoadResult_ = true; 277 return true; 278 } 279 280private: 281 bool EhFrameHDRValid_ {false}; 282 uint64_t ehFrameHDRElfOffset_ {0}; 283 uint64_t ehFrameHDRFdeCount_ {0}; 284 uint64_t ehFrameHDRFdeTableItemSize_ {0}; 285 uint64_t ehFrameHDRFdeTableElfOffset_ {0}; 286 std::shared_ptr<DfxElf> elfFile_; 287 std::unordered_map<uint64_t, ElfLoadInfo> info_; 288 289 bool GetSectionInfo(const std::string &name, uint64_t §ionVaddr, uint64_t §ionSize, 290 uint64_t §ionFileOffset) const override 291 { 292 struct ShdrInfo shdrInfo; 293 if (elfFile_->GetSectionInfo(shdrInfo, name)) { 294 sectionVaddr = shdrInfo.addr; 295 sectionSize = shdrInfo.size; 296 sectionFileOffset = shdrInfo.offset; 297 HLOGM("Get Section '%s' %" PRIx64 " - %" PRIx64 "", name.c_str(), sectionVaddr, sectionSize); 298 return true; 299 } else { 300 HLOGW("Section '%s' not found", name.c_str()); 301 return false; 302 } 303 } 304 305#ifndef __arm__ 306 bool GetHDRSectionInfo(uint64_t &ehFrameHdrElfOffset, uint64_t &fdeTableElfOffset, 307 uint64_t &fdeTableSize) override 308 { 309 CHECK_TRUE(elfFile_ == nullptr, false, 0, ""); 310 ShdrInfo shinfo; 311 if (!elfFile_->GetSectionInfo(shinfo, ".eh_frame_hdr")) { 312 return false; 313 } 314 315 ehFrameHDRElfOffset_ = shinfo.offset; 316 if (EhFrameHDRValid_) { 317 ehFrameHdrElfOffset = ehFrameHDRElfOffset_; 318 fdeTableElfOffset = ehFrameHDRFdeTableElfOffset_; 319 fdeTableSize = ehFrameHDRFdeCount_; 320 return true; 321 } 322 auto mmapPtr = elfFile_->GetMmapPtr(); 323 if (mmapPtr == nullptr) { 324 HLOGE("mmapPtr should not be nullptr."); 325 return false; 326 } 327 if (!LoadEhFrameHDR(mmapPtr + shinfo.offset, elfFile_->GetMmapSize(), shinfo.offset)) { 328 HLOGW("Failed to load eh_frame_hdr"); 329 return false; 330 } 331 332 ehFrameHdrElfOffset = ehFrameHDRElfOffset_; 333 fdeTableElfOffset = ehFrameHDRFdeTableElfOffset_; 334 fdeTableSize = ehFrameHDRFdeCount_; 335 return true; 336 } 337#endif 338 339 void DumpEhFrameHDR() 340 { 341 HLOGD(" ehFrameHDRElfOffset_: 0x%" PRIx64 "", ehFrameHDRElfOffset_); 342 HLOGD(" ehFrameHDRFdeCount_: 0x%" PRIx64 "", ehFrameHDRFdeCount_); 343 HLOGD(" ehFrameHDRFdeTableElfOffset_: 0x%" PRIx64 "", ehFrameHDRFdeTableElfOffset_); 344 HLOGD(" ehFrameHDRFdeTableItemSize_: 0x%" PRIx64 "", ehFrameHDRFdeTableItemSize_); 345 } 346 347 bool LoadEhFrameHDR(const unsigned char *buffer, size_t bufferSize, uint64_t shdrOffset) 348 { 349 const eh_frame_hdr *ehFrameHdr = reinterpret_cast<const eh_frame_hdr *>(buffer); 350 CHECK_TRUE(ehFrameHdr == nullptr, false, 0, ""); 351 const uint8_t *dataPtr = ehFrameHdr->encode_data; 352 DwarfEncoding dwEhFramePtr(ehFrameHdr->eh_frame_ptr_enc, dataPtr); 353 DwarfEncoding dwFdeCount(ehFrameHdr->fde_count_enc, dataPtr); 354 DwarfEncoding dwTable(ehFrameHdr->table_enc, dataPtr); 355 DwarfEncoding dwTableValue(ehFrameHdr->table_enc, dataPtr); 356 357 HLOGD("eh_frame_hdr:"); 358 HexDump(ehFrameHdr, BITS_OF_FOUR_BYTE, bufferSize); 359 unsigned char version = ehFrameHdr->version; 360 HLOGD(" version: %02x:%s", version, (version == 1) ? "valid" : "invalid"); 361 HLOGD(" eh_frame_ptr_enc: %s", dwEhFramePtr.ToString().c_str()); 362 HLOGD(" fde_count_enc: %s", dwFdeCount.ToString().c_str()); 363 HLOGD(" table_enc: %s", dwTable.ToString().c_str()); 364 HLOGD(" table_value_enc: %s", dwTableValue.ToString().c_str()); 365 HLOGD(" table_item_size: %zd", dwTable.GetSize() + dwTableValue.GetSize()); 366 HLOGD(" table_offset_in_hdr: %zu", dwTable.GetData() - buffer); 367 368 CHECK_TRUE(version != 1, false, 1, "eh_frame_hdr version is invalid"); 369 EhFrameHDRValid_ = true; 370 ehFrameHDRElfOffset_ = shdrOffset; 371 ehFrameHDRFdeCount_ = dwFdeCount.GetAppliedValue(); 372 ehFrameHDRFdeTableElfOffset_ = dwTable.GetData() - buffer + shdrOffset; 373 ehFrameHDRFdeTableItemSize_ = dwTable.GetSize() + dwTableValue.GetSize(); 374 DumpEhFrameHDR(); 375 376 if (!dwFdeCount.IsOmit() && dwFdeCount.GetValue() > 0) { 377 return true; 378 } else { 379 HLOGW("fde table not found.\n"); 380 } 381 return false; 382 } 383 384 void UpdateSymbols(std::vector<DfxSymbol> &symbolsTable, const std::string &elfPath) 385 { 386 symbols_.clear(); 387 HLOGD("%zu symbols loadded from symbolsTable.", symbolsTable.size()); 388 389 symbols_.swap(symbolsTable); 390 391 AdjustSymbols(); 392 HLOGD("%zu symbols loadded from elf '%s'.", symbols_.size(), elfPath.c_str()); 393 for (auto& symbol: symbols_) { 394 HLOGD("symbol %s", symbol.ToDebugString().c_str()); 395 } 396 if (buildId_.empty()) { 397 HLOGD("buildId not found from elf '%s'.", elfPath.c_str()); 398 // don't failed. some time the lib have not got the build id 399 // buildId not found from elf '/system/bin/ld-musl-arm.so.1'. 400 } 401 } 402 403 void AddSymbols(std::vector<DfxSymbol>& symbolsTable, std::shared_ptr<DfxElf> elf, const std::string& filePath) 404 { 405 // use elfFile_ to get symbolsTable 406 DfxSymbols::ParseSymbols(symbolsTable, elf, filePath); 407 DfxSymbols::AddSymbolsByPlt(symbolsTable, elf, filePath); 408 } 409 410 bool LoadElfSymbols(std::shared_ptr<DfxMap> map, std::string elfPath) 411 { 412#ifdef HIPERF_DEBUG_TIME 413 const auto startTime = steady_clock::now(); 414#endif 415 if (elfFile_ == nullptr) { 416 if (StringEndsWith(elfPath, ".hap") && map != nullptr) { 417 elfFile_ = DfxElf::CreateFromHap(elfPath, map->prevMap, map->offset); 418 map->elf = elfFile_; 419 } else { 420 elfFile_ = std::make_shared<DfxElf>(elfPath); 421 } 422 } 423 CHECK_TRUE(elfFile_ == nullptr, false, 1, "Failed to create elf file for %s.", elfPath.c_str()); 424 HLOGD("loaded elf %s", elfPath.c_str()); 425 if (!elfFile_->IsValid()) { 426 HLOGD("parser elf file failed."); 427 return false; 428 } 429 430 textExecVaddr_ = elfFile_->GetStartVaddr(); 431 textExecVaddrFileOffset_ = elfFile_->GetStartOffset(); 432 HLOGD("textExecVaddr_ 0x%016" PRIx64 " file offset 0x%016" PRIx64 "", textExecVaddr_, 433 textExecVaddrFileOffset_); 434 435 // we prepare two table here 436 // only one we will push in to symbols_ 437 // or both drop if build id is not same 438 std::string buildIdFound = elfFile_->GetBuildId(); 439 std::vector<DfxSymbol> symbolsTable; 440 AddSymbols(symbolsTable, elfFile_, filePath_); 441 if (UpdateBuildIdIfMatch(buildIdFound)) { 442 UpdateSymbols(symbolsTable, elfPath); 443 } else { 444 HLOGW("symbols will not update for '%s' because buildId is not match.", 445 elfPath.c_str()); 446 // this mean failed . we don't goon for this. 447 return false; 448 } 449 450#ifdef HIPERF_DEBUG_TIME 451 auto usedTime = duration_cast<microseconds>(steady_clock::now() - startTime); 452 if (usedTime.count() != 0) { 453 HLOGV("cost %0.3f ms to load symbols '%s'", 454 usedTime.count() / static_cast<double>(milliseconds::duration::period::den), 455 elfPath.c_str()); 456 } 457#endif 458 return true; 459 } 460 461 uint64_t GetVaddrInSymbols(uint64_t ip, uint64_t mapStart, 462 uint64_t mapPageOffset) const override 463 { 464 /* 465 00200000-002c5000 r--p 00000000 08:02 46400311 466 002c5000-00490000 r-xp 000c5000 08:02 4640031 467 468 [14] .text PROGBITS 00000000002c5000 000c5000 469 470 if ip is 0x46e6ab 471 1. find the map range is 002c5000-00490000 472 2. ip - map start(002c5000) = map section offset 473 3. map section offset + map page offset(000c5000) = elf file offset 474 4. elf file offset - exec file offset(000c5000) 475 = ip offset (ip always in exec file offset) 476 5. ip offset + exec begin vaddr(2c5000) = virtual ip in elf 477 */ 478 uint64_t vaddr = ip - mapStart + mapPageOffset - textExecVaddrFileOffset_ + textExecVaddr_; 479 HLOGM(" ip :0x%016" PRIx64 " -> elf offset :0x%016" PRIx64 " -> vaddr :0x%016" PRIx64 " ", 480 ip, ip - mapStart + mapPageOffset, vaddr); 481 HLOGM("(minExecAddrFileOffset_ is 0x%" PRIx64 " textExecVaddr_ is 0x%" PRIx64 ")", 482 textExecVaddrFileOffset_, textExecVaddr_); 483 return vaddr; 484 } 485}; 486 487class KernelSymbols : public ElfFileSymbols { 488public: 489 explicit KernelSymbols(const std::string &symbolFilePath) 490 : ElfFileSymbols(symbolFilePath, SYMBOL_KERNEL_FILE) 491 { 492 } 493 494 KernelSymbols(const std::string &symbolFilePath, 495 const SymbolsFileType symbolsFileType) 496 : ElfFileSymbols(symbolFilePath, symbolsFileType) 497 { 498 } 499 500 static constexpr const int KSYM_MIN_TOKENS = 3; 501 static constexpr const int KSYM_DEFAULT_LINE = 35000; 502 static constexpr const int KSYM_DEFAULT_SIZE = 1024 * 1024 * 1; // 1MB 503 504 bool ParseKallsymsLine(const std::string &kallsymsPath) 505 { 506#ifdef HIPERF_DEBUG_SYMBOLS_TIME 507 const auto startTime = steady_clock::now(); 508 std::chrono::microseconds parseLineTime = std::chrono::microseconds::zero(); 509 std::chrono::microseconds sscanfTime = std::chrono::microseconds::zero(); 510 std::chrono::microseconds newTime = std::chrono::microseconds::zero(); 511 std::chrono::microseconds readFileTime = std::chrono::microseconds::zero(); 512#endif 513 size_t lines = 0; 514#ifdef HIPERF_DEBUG_SYMBOLS_TIME 515 const auto eachFileStartTime = steady_clock::now(); 516#endif 517 std::string kallsym; 518 CHECK_TRUE(!ReadFileToString(kallsymsPath, kallsym, KSYM_DEFAULT_SIZE) || kallsym.empty(), false, 1, 519 "%s load failed.", kallsymsPath.c_str()); 520#ifdef HIPERF_DEBUG_SYMBOLS_TIME 521 // any way we finish the line scan 522 readFileTime += duration_cast<milliseconds>(steady_clock::now() - eachFileStartTime); 523#endif 524 // reduce the mem alloc 525 symbols_.reserve(KSYM_DEFAULT_LINE); 526 527 char *lineBegin = kallsym.data(); 528 char *dataEnd = lineBegin + kallsym.size(); 529 while (lineBegin < dataEnd) { 530 char *lineEnd = strchr(lineBegin, '\n'); 531 if (lineEnd != nullptr) { 532 *lineEnd = '\0'; 533 } else { 534 lineEnd = dataEnd; 535 } 536 size_t lineSize = (lineEnd != nullptr) ? (lineEnd - lineBegin) : (dataEnd - lineBegin); 537 538#ifdef HIPERF_DEBUG_SYMBOLS_TIME 539 const auto eachLineStartTime = steady_clock::now(); 540#endif 541 lines++; 542 uint64_t addr = 0; 543 char type = '\0'; 544 545 char nameRaw[lineSize]; 546 char moduleRaw[lineSize]; 547 int ret = sscanf_s(lineBegin, "%" PRIx64 " %c %s%s", &addr, &type, sizeof(type), 548 nameRaw, sizeof(nameRaw), moduleRaw, sizeof(moduleRaw)); 549 550#ifdef HIPERF_DEBUG_SYMBOLS_TIME 551 // any way we finish the line scan 552 sscanfTime += duration_cast<milliseconds>(steady_clock::now() - eachLineStartTime); 553#endif 554 if (ret >= KSYM_MIN_TOKENS) { 555 if (ret == KSYM_MIN_TOKENS) { 556 moduleRaw[0] = '\0'; 557 } 558 HLOGM(" 0x%016" PRIx64 " %c '%s' '%s'", addr, type, nameRaw, moduleRaw); 559 } else { 560 HLOGW("unknown line %d: '%s'", ret, lineBegin); 561 lineBegin = lineEnd + 1; 562 continue; 563 } 564 lineBegin = lineEnd + 1; 565 std::string name = nameRaw; 566 std::string module = moduleRaw; 567 568 /* 569 T 570 The symbol is in the text (code) section. 571 572 W 573 The symbol is a weak symbol that has not been specifically 574 tagged as a weak object symbol. When a weak defined symbol is 575 linked with a normal defined symbol, the normal defined symbol 576 is used with no error. When a weak undefined symbol is linked 577 and the symbol is not defined, the value of the weak symbol 578 becomes zero with no error. 579 */ 580 if (addr != 0 && strchr("TtWw", type)) { 581#ifdef HIPERF_DEBUG_SYMBOLS_TIME 582 const auto eachNewSymbolTime = steady_clock::now(); 583#endif 584 // we only need text symbols 585 symbols_.emplace_back(addr, name, module.empty() ? filePath_ : module); 586#ifdef HIPERF_DEBUG_SYMBOLS_TIME 587 newTime += duration_cast<milliseconds>(steady_clock::now() - eachNewSymbolTime); 588#endif 589 } 590#ifdef HIPERF_DEBUG_SYMBOLS_TIME 591 parseLineTime += duration_cast<milliseconds>(steady_clock::now() - eachLineStartTime); 592#endif 593 } 594#ifdef HIPERF_DEBUG_SYMBOLS_TIME 595 std::chrono::microseconds usedTime = 596 duration_cast<milliseconds>(steady_clock::now() - startTime); 597 printf("parse kernel symbols use : %0.3f ms\n", usedTime.count() / MS_DURATION); 598 printf("parse line use : %0.3f ms\n", parseLineTime.count() / MS_DURATION); 599 printf("sscanf line use : %0.3f ms\n", sscanfTime.count() / MS_DURATION); 600 printf("new symbols use : %0.3f ms\n", newTime.count() / MS_DURATION); 601 printf("read file use : %0.3f ms\n", readFileTime.count() / MS_DURATION); 602#endif 603 HLOGD("load %s: %zu line processed(%zu symbols)", kallsymsPath.c_str(), lines, symbols_.size()); 604 return true; 605 } 606 607 const std::string KPTR_RESTRICT = "/proc/sys/kernel/kptr_restrict"; 608 609 bool LoadKernelSyms() 610 { 611 if (!IsRoot()) { 612 return false; 613 } 614 HLOGD("try read /proc/kallsyms"); 615 if (access("/proc/kallsyms", R_OK) != 0) { 616 printf("No vmlinux path is given, and kallsyms cannot be opened\n"); 617 return false; 618 } 619 bool hasChangeKptr = false; 620 std::string oldKptrRestrict = ReadFileToString(KPTR_RESTRICT); 621 if (oldKptrRestrict.front() != '0') { 622 printf("/proc/sys/kernel/kptr_restrict is NOT 0, will try set it to 0.\n"); 623 hasChangeKptr = WriteStringToFile(KPTR_RESTRICT, "0"); 624 if (!hasChangeKptr) { 625 printf("/proc/sys/kernel/kptr_restrict write failed and we can't not change it.\n"); 626 } 627 } 628 629 // getline end 630 CHECK_TRUE(!ParseKallsymsLine("/proc/kallsyms"), false, 0, ""); 631 632 if (hasChangeKptr) { 633 if (!WriteStringToFile(KPTR_RESTRICT, oldKptrRestrict)) { 634 printf("recover /proc/sys/kernel/kptr_restrict fail.\n"); 635 } 636 } 637 638 if (symbols_.empty()) { 639 printf("The symbol table addresses in /proc/kallsyms are all 0.\n" 640 "Please check the value of /proc/sys/kernel/kptr_restrict, it " 641 "should be 0.\n" 642 "Or provide a separate vmlinux path.\n"); 643 644 if (buildId_.size() != 0) { 645 // but we got the buildid , so we make a dummpy symbols 646 HLOGD("kallsyms not found. but we have the buildid"); 647 return true; 648 } else { 649 // we got nothing 650 return false; 651 } 652 } else { 653 AdjustSymbols(); 654 HLOGV("%zu symbols_ loadded from kallsyms.\n", symbols_.size()); 655 return true; 656 } 657 } 658 bool LoadSymbols(std::shared_ptr<DfxMap> map, const std::string &symbolFilePath) override 659 { 660 symbolsLoaded_ = true; 661 HLOGV("KernelSymbols try read '%s' search paths size %zu, inDeviceRecord %d", 662 symbolFilePath.c_str(), symbolsFileSearchPaths_.size(), onRecording_); 663 664 if (onRecording_) { 665 const auto startTime = std::chrono::steady_clock::now(); 666 if (!LoadKernelSyms()) { 667 if (IsRoot()) { 668 printf("parse kalsyms failed.\n"); 669 } 670 return false; 671 } else { 672 const auto thisTime = std::chrono::steady_clock::now(); 673 const auto usedTimeMsTick = 674 std::chrono::duration_cast<std::chrono::milliseconds>(thisTime - startTime); 675 HLOGV("Load kernel symbols (total %" PRId64 " ms)\n", (int64_t)usedTimeMsTick.count()); 676 // load complete 677 return true; 678 } 679 680 // try read 681 HLOGD("try read /sys/kernel/notes"); 682 std::string notes = ReadFileToString("/sys/kernel/notes"); 683 if (notes.empty()) { 684 printf("notes cannot be opened, unable get buildid\n"); 685 return false; 686 } else { 687 HLOGD("kernel notes size: %zu", notes.size()); 688 buildId_ = DfxElf::GetBuildId((uint64_t)notes.data(), (uint64_t)notes.size()); 689 } 690 } // no search path 691 692 // try vmlinux 693 return ElfFileSymbols::LoadSymbols(nullptr, KERNEL_ELF_NAME); 694 } 695 uint64_t GetVaddrInSymbols(uint64_t ip, uint64_t mapStart, uint64_t) const override 696 { 697 // ip is vaddr in /proc/kallsyms 698 return ip; 699 } 700 ~KernelSymbols() override {} 701}; 702 703class KernelThreadSymbols : public KernelSymbols { 704public: 705 explicit KernelThreadSymbols(const std::string &symbolFilePath) 706 : KernelSymbols(symbolFilePath, SYMBOL_KERNEL_THREAD_FILE) 707 { 708 } 709 710 bool LoadKernelSyms() 711 { 712 if (!IsRoot()) { 713 return false; 714 } 715 // find real proc path by filePath_ 716 std::string procPath; 717 if (filePath_ == SYSMGR_FILE_NAME) { 718 procPath = StringPrintf("/proc/%u/uallsyms", SYSMGR_PID); 719 } else if (filePath_ == DEVHOST_FILE_NAME) { 720 procPath = "/proc/devhost/root/kallsyms"; 721 } 722 HLOGD("try read kernel thread symbol file %s in %s", filePath_.c_str(), procPath.c_str()); 723 CHECK_TRUE(access(procPath.c_str(), R_OK) != 0, false, LOG_TYPE_PRINTF, 724 "kernel thread symbol file %s cannot be opened\n", filePath_.c_str()); 725 bool hasChangeKptr = false; 726 std::string oldKptrRestrict = ReadFileToString(KPTR_RESTRICT); 727 if (oldKptrRestrict.front() != '0') { 728 printf("/proc/sys/kernel/kptr_restrict is NOT 0, will try set it to 0.\n"); 729 hasChangeKptr = WriteStringToFile(KPTR_RESTRICT, "0"); 730 if (!hasChangeKptr) { 731 printf("/proc/sys/kernel/kptr_restrict write failed and we can't not change it.\n"); 732 } 733 } 734 735 // getline end 736 CHECK_TRUE(!ParseKallsymsLine(procPath), false, 0, ""); 737 738 if (hasChangeKptr) { 739 if (!WriteStringToFile(KPTR_RESTRICT, oldKptrRestrict)) { 740 printf("recover /proc/sys/kernel/kptr_restrict fail.\n"); 741 } 742 } 743 744 if (symbols_.empty()) { 745 printf("The symbol table addresses in %s are all 0.\n" 746 "Please check the value of /proc/sys/kernel/kptr_restrict, it " 747 "should be 0.\n", filePath_.c_str()); 748 return false; 749 } else { 750 AdjustSymbols(); 751 HLOGV("%zu symbols_ loadded from %s.\n", symbols_.size(), procPath.c_str()); 752 return true; 753 } 754 } 755 756 bool LoadSymbols(std::shared_ptr<DfxMap> map, const std::string &symbolFilePath) override 757 { 758 symbolsLoaded_ = true; 759 HLOGV("KernelThreadSymbols try read '%s', inDeviceRecord %d", 760 filePath_.c_str(), onRecording_); 761 762 if (onRecording_) { 763 const auto startTime = std::chrono::steady_clock::now(); 764 if (!LoadKernelSyms()) { 765 if (IsRoot()) { 766 printf("parse %s failed.\n", filePath_.c_str()); 767 } 768 } else { 769 const auto thisTime = std::chrono::steady_clock::now(); 770 const auto usedTimeMsTick = 771 std::chrono::duration_cast<std::chrono::milliseconds>(thisTime - startTime); 772 HLOGV("Load kernel thread symbols (total %" PRId64 " ms)\n", (int64_t)usedTimeMsTick.count()); 773 // load complete 774 return true; 775 } 776 } // no search path 777 778 // try elf 779 return ElfFileSymbols::LoadSymbols(nullptr, filePath_); 780 } 781 ~KernelThreadSymbols() override {} 782}; 783 784class KernelModuleSymbols : public ElfFileSymbols { 785public: 786 explicit KernelModuleSymbols(const std::string &symbolFilePath) : ElfFileSymbols(symbolFilePath) 787 { 788 HLOGV("create %s", symbolFilePath.c_str()); 789 symbolFileType_ = SYMBOL_KERNEL_MODULE_FILE; 790 module_ = symbolFilePath; 791 } 792 ~KernelModuleSymbols() override {}; 793 794 bool LoadSymbols(std::shared_ptr<DfxMap> map, const std::string &symbolFilePath) override 795 { 796 symbolsLoaded_ = true; 797 if (module_ == filePath_ and onRecording_) { 798 // file name still not convert to ko file path 799 // this is in record mode 800 HLOGV("find ko name %s", module_.c_str()); 801 for (const std::string &path : kernelModulePaths) { 802 if (access(path.c_str(), R_OK) == 0) { 803 std::string koPath = path + module_ + KERNEL_MODULES_EXT_NAME; 804 HLOGV("found ko in %s", koPath.c_str()); 805 if (access(koPath.c_str(), R_OK) == 0) { 806 // create symbol 807 filePath_ = koPath; 808 break; // find next ko 809 } 810 } 811 } 812 LoadBuildId(); 813 } else { 814 HLOGV("we have file path, load with %s", filePath_.c_str()); 815 return ElfFileSymbols::LoadSymbols(nullptr, filePath_); 816 } 817 return false; 818 } 819 uint64_t GetVaddrInSymbols(uint64_t ip, uint64_t mapStart, uint64_t) const override 820 { 821 return ip - mapStart; 822 } 823 824private: 825 bool LoadBuildId() 826 { 827 std::string sysFile = "/sys/module/" + module_ + "/notes/.note.gnu.build-id"; 828 std::string buildIdRaw = ReadFileToString(sysFile); 829 if (!buildIdRaw.empty()) { 830 buildId_ = DfxElf::GetBuildId((uint64_t)buildIdRaw.data(), (uint64_t)buildIdRaw.size()); 831 HLOGD("kerne module %s(%s) build id %s", module_.c_str(), filePath_.c_str(), 832 buildId_.c_str()); 833 return buildId_.empty() ? false : true; 834 } 835 return false; 836 } 837 838 const std::vector<std::string> kernelModulePaths = {"/vendor/modules/"}; 839 std::string module_ = ""; 840}; 841 842class JavaFileSymbols : public ElfFileSymbols { 843public: 844 explicit JavaFileSymbols(const std::string &symbolFilePath) : ElfFileSymbols(symbolFilePath) 845 { 846 symbolFileType_ = SYMBOL_KERNEL_FILE; 847 } 848 bool LoadSymbols(std::shared_ptr<DfxMap> map, const std::string &symbolFilePath) override 849 { 850 symbolsLoaded_ = true; 851 return false; 852 } 853 ~JavaFileSymbols() override {} 854 855 uint64_t GetVaddrInSymbols(uint64_t ip, uint64_t mapStart, 856 uint64_t mapPageOffset) const override 857 { 858 // this is different with elf 859 // elf use ip - mapStart + mapPageOffset - minExecAddrFileOffset_ + textExecVaddr_ 860 return ip - mapStart + mapPageOffset; 861 } 862}; 863 864class JSFileSymbols : public ElfFileSymbols { 865public: 866 explicit JSFileSymbols(const std::string &symbolFilePath) : ElfFileSymbols(symbolFilePath) 867 { 868 symbolFileType_ = SYMBOL_KERNEL_FILE; 869 } 870 bool LoadSymbols(std::shared_ptr<DfxMap> map, const std::string &symbolFilePath) override 871 { 872 symbolsLoaded_ = true; 873 return false; 874 } 875 ~JSFileSymbols() override {} 876}; 877 878class HapFileSymbols : public ElfFileSymbols { 879private: 880#if defined(is_ohos) && is_ohos 881 std::unique_ptr<DfxExtractor> dfxExtractor_; 882 bool hapExtracted_ = false; 883#endif 884 std::unique_ptr<uint8_t[]> abcDataPtr_ = nullptr; 885 [[maybe_unused]] uintptr_t loadOffSet_ = 0; 886 [[maybe_unused]] size_t abcDataSize_ = 0; 887 [[maybe_unused]] uintptr_t arkExtractorptr_ = 0; 888 bool isHapAbc_ = false; 889 pid_t pid_ = 0; 890public: 891 explicit HapFileSymbols(const std::string &symbolFilePath, pid_t pid) 892 : ElfFileSymbols(symbolFilePath, SYMBOL_HAP_FILE) 893 { 894 pid_ = pid; 895 } 896 897 bool IsHapAbc() 898 { 899#if defined(is_ohos) && is_ohos 900 if (hapExtracted_) { 901 return isHapAbc_; 902 } 903 hapExtracted_ = true; 904 HLOGD("the symbol file is %s, pid is %d.", filePath_.c_str(), pid_); 905 if (IsRoot()) { 906 if (IsApplicationEncryped(pid_)) { 907 HLOGD("no need to parse js symbols"); 908 return false; 909 } 910 } 911 912 CHECK_TRUE(StringEndsWith(filePath_, ".hap") && map_->IsMapExec(), false, 1, 913 "map is exec not abc file , the symbol file is:%s", map_->name.c_str()); 914 915 if (StringEndsWith(filePath_, ".hap") || StringEndsWith(filePath_, ".hsp") || 916 StringEndsWith(filePath_, ".hqf")) { 917 dfxExtractor_ = std::make_unique<DfxExtractor>(filePath_); 918 CHECK_TRUE(!dfxExtractor_->GetHapAbcInfo(loadOffSet_, abcDataPtr_, abcDataSize_), false, 1, 919 "failed to call GetHapAbcInfo, the symbol file is:%s", filePath_.c_str()); 920 HLOGD("loadOffSet %u", (uint32_t)loadOffSet_); 921 if (abcDataPtr_ != nullptr) { 922 isHapAbc_ = true; 923 HLOGD("symbol file : %s, isAbc: %d", filePath_.c_str(), isHapAbc_); 924 } 925 } else { 926 loadOffSet_ = map_->offset; 927 abcDataSize_ = map_->end - map_->begin; 928 abcDataPtr_ = std::make_unique<uint8_t[]>(abcDataSize_); 929 auto size = DfxMemory::ReadProcMemByPid(pid_, map_->begin, abcDataPtr_.get(), map_->end - map_->begin); 930 if (size != abcDataSize_) { 931 HLOGD("return size is small abcDataPtr : %s, isAbc: %d", abcDataPtr_.get(), isHapAbc_); 932 return false; 933 } 934 isHapAbc_ = true; 935 HLOGD("symbol file name %s loadOffSet %u abcDataSize_ %u", 936 filePath_.c_str(), (uint32_t)loadOffSet_, (uint32_t)abcDataSize_); 937 } 938 auto ret = DfxArk::ArkCreateJsSymbolExtractor(&arkExtractorptr_); 939 if (ret < 0) { 940 arkExtractorptr_ = 0; 941 HLOGE("failed to call ArkCreateJsSymbolExtractor, the symbol file is:%s", filePath_.c_str()); 942 } 943#endif 944 return isHapAbc_; 945 } 946 947 bool IsAbc() override 948 { 949 return isHapAbc_ == true; 950 } 951 952 void SetBoolValue(bool value) override 953 { 954 isHapAbc_ = value; 955 } 956 957 bool LoadDebugInfo(std::shared_ptr<DfxMap> map, const std::string &symbolFilePath) override 958 { 959 HLOGD("map ptr:%p, map name:%s", map.get(), map->name.c_str()); 960 if (debugInfoLoaded_) { 961 return true; 962 } 963 CHECK_TRUE(!onRecording_, true, 0, ""); 964 965 if (!IsHapAbc()) { 966 ElfFileSymbols::LoadDebugInfo(map, ""); 967 } 968 debugInfoLoaded_ = true; 969 debugInfoLoadResult_ = true; 970 return true; 971 } 972 973 bool LoadSymbols(std::shared_ptr<DfxMap> map, const std::string &symbolFilePath) override 974 { 975 HLOGD("map ptr:%p, map name:%s", map.get(), map->name.c_str()); 976 CHECK_TRUE(symbolsLoaded_ || !onRecording_, true, 0, ""); 977 symbolsLoaded_ = true; 978 if (!IsHapAbc()) { 979 ElfFileSymbols::LoadSymbols(map, ""); 980 } 981 return true; 982 } 983 984 DfxSymbol GetSymbolWithPcAndMap(uint64_t ip, std::shared_ptr<DfxMap> map) override 985 { 986 // get cache 987 auto iter = symbolsMap_.find(ip); 988 if (iter != symbolsMap_.end()) { 989 return iter->second; 990 } 991 if (map == nullptr) { 992 return DfxSymbol(ip, ""); 993 } 994 HLOGD("map ptr:%p, map name:%s", map.get(), map->name.c_str()); 995 996#if defined(is_ohos) && is_ohos 997 if (IsAbc() && needParseJsFunc_) { 998 JsFunction jsFunc; 999 std::string module = map->name; 1000 HLOGD("map->name module:%s", module.c_str()); 1001 auto ret = DfxArk::ParseArkFrameInfo(static_cast<uintptr_t>(ip), static_cast<uintptr_t>(map->begin), 1002 loadOffSet_, abcDataPtr_.get(), abcDataSize_, 1003 arkExtractorptr_, &jsFunc); 1004 if (ret == -1) { 1005 HLOGD("failed to call ParseArkFrameInfo, the symbol file is : %s", map->name.c_str()); 1006 return DfxSymbol(ip, ""); 1007 } 1008 this->symbolsMap_.insert(std::make_pair(ip, 1009 DfxSymbol(ip, 1010 jsFunc.codeBegin, 1011 jsFunc.functionName, 1012 jsFunc.ToString(), 1013 map->name))); 1014 1015 DfxSymbol &foundSymbol = symbolsMap_[ip]; 1016 if (!foundSymbol.matched_) { 1017 foundSymbol.matched_ = true; 1018 foundSymbol.symbolFileIndex_ = id_; 1019 matchedSymbols_.push_back(&(symbolsMap_[ip])); 1020 } 1021 1022 HLOGD("ip : 0x%" PRIx64 " the symbol file is : %s, function is %s demangle_ : %s", ip, 1023 symbolsMap_[ip].module_.data(), jsFunc.functionName, matchedSymbols_.back()->demangle_.data()); 1024 return symbolsMap_[ip]; 1025 } 1026#endif 1027 DfxSymbol symbol(ip, ""); 1028 return symbol; 1029 } 1030}; 1031 1032class UnknowFileSymbols : public SymbolsFile { 1033public: 1034 explicit UnknowFileSymbols(const std::string &symbolFilePath) 1035 : SymbolsFile(SYMBOL_UNKNOW_FILE, symbolFilePath) 1036 { 1037 } 1038 bool LoadSymbols(std::shared_ptr<DfxMap> map, const std::string &symbolFilePath) override 1039 { 1040 symbolsLoaded_ = true; 1041 return false; 1042 } 1043 ~UnknowFileSymbols() override {} 1044}; 1045 1046SymbolsFile::~SymbolsFile() {} 1047 1048std::unique_ptr<SymbolsFile> SymbolsFile::CreateSymbolsFile(SymbolsFileType symbolType, 1049 const std::string symbolFilePath, pid_t pid) 1050{ 1051 switch (symbolType) { 1052 case SYMBOL_KERNEL_FILE: 1053 return std::make_unique<KernelSymbols>(symbolFilePath.empty() ? KERNEL_MMAP_NAME 1054 : symbolFilePath); 1055 case SYMBOL_KERNEL_MODULE_FILE: 1056 return std::make_unique<KernelModuleSymbols>(symbolFilePath); 1057 case SYMBOL_KERNEL_THREAD_FILE: 1058 return std::make_unique<KernelThreadSymbols>(symbolFilePath); 1059 case SYMBOL_ELF_FILE: 1060 return std::make_unique<ElfFileSymbols>(symbolFilePath); 1061 case SYMBOL_JAVA_FILE: 1062 return std::make_unique<JavaFileSymbols>(symbolFilePath); 1063 case SYMBOL_JS_FILE: 1064 return std::make_unique<JSFileSymbols>(symbolFilePath); 1065 case SYMBOL_HAP_FILE: 1066 return std::make_unique<HapFileSymbols>(symbolFilePath, pid); 1067 default: 1068 return std::make_unique<SymbolsFile>(SYMBOL_UNKNOW_FILE, symbolFilePath); 1069 } 1070} 1071 1072std::unique_ptr<SymbolsFile> SymbolsFile::CreateSymbolsFile(const std::string &symbolFilePath, pid_t pid) 1073{ 1074 // we need check file name here 1075 if (symbolFilePath == KERNEL_MMAP_NAME) { 1076 return SymbolsFile::CreateSymbolsFile(SYMBOL_KERNEL_FILE, symbolFilePath); 1077 } else if (symbolFilePath == SYSMGR_FILE_NAME || 1078 symbolFilePath == DEVHOST_LINUX_FILE_NAME || 1079 StringStartsWith(symbolFilePath, DEVHOST_LINUX_PREFIX)) { 1080 return SymbolsFile::CreateSymbolsFile(SYMBOL_KERNEL_THREAD_FILE, symbolFilePath); 1081 } else if (StringEndsWith(symbolFilePath, KERNEL_MODULES_EXT_NAME)) { 1082 return SymbolsFile::CreateSymbolsFile(SYMBOL_KERNEL_MODULE_FILE, symbolFilePath); 1083 } else if (IsArkJsFile(symbolFilePath)) { 1084 return SymbolsFile::CreateSymbolsFile(SYMBOL_HAP_FILE, symbolFilePath, pid); 1085 } else { 1086 // default is elf, this may be problematic in the future. 1087 return SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE, symbolFilePath); 1088 } 1089} 1090 1091void SymbolsFile::AdjustSymbols() 1092{ 1093 if (symbols_.size() <= 0) { 1094 return; 1095 } 1096 1097 // order 1098 sort(symbols_.begin(), symbols_.end(), [](const DfxSymbol& a, const DfxSymbol& b) { 1099 return a.funcVaddr_ < b.funcVaddr_; 1100 }); 1101 HLOGV("sort completed"); 1102 1103 size_t fullSize = symbols_.size(); 1104 size_t erased = 0; 1105 1106 // Check for duplicate vaddr 1107 auto last = std::unique(symbols_.begin(), symbols_.end(), [](const DfxSymbol &a, const DfxSymbol &b) { 1108 return (a.funcVaddr_ == b.funcVaddr_); 1109 }); 1110 symbols_.erase(last, symbols_.end()); 1111 erased = fullSize - symbols_.size(); 1112 HLOGV("uniqued completed"); 1113 auto it = symbols_.begin(); 1114 while (it != symbols_.end()) { 1115 it->index_ = it - symbols_.begin(); 1116 it++; 1117 } 1118 HLOGV("indexed completed"); 1119 1120 HLOG_ASSERT(symbols_.size() != 0); 1121 1122 if (textExecVaddrRange_ == maxVaddr) { 1123 textExecVaddrRange_ = symbols_.back().funcVaddr_ - symbols_.front().funcVaddr_; 1124 } 1125 1126 HLOGDDD("%zu symbols after adjust (%zu erased) 0x%016" PRIx64 " - 0x%016" PRIx64 1127 " @0x%016" PRIx64 " ", 1128 symbols_.size(), erased, symbols_.front().funcVaddr_, symbols_.back().funcVaddr_, 1129 textExecVaddrFileOffset_); 1130} 1131 1132void SymbolsFile::SortMatchedSymbols() 1133{ 1134 if (matchedSymbols_.size() <= 1u) { 1135 return; 1136 } 1137 sort(matchedSymbols_.begin(), matchedSymbols_.end(), [](const DfxSymbol* a, const DfxSymbol* b) { 1138 if (a == nullptr || b == nullptr) { 1139 return true; 1140 } 1141 return a->funcVaddr_ < b->funcVaddr_; 1142 }); 1143} 1144 1145const std::vector<DfxSymbol> &SymbolsFile::GetSymbols() 1146{ 1147 return symbols_; 1148} 1149 1150const std::vector<DfxSymbol *> &SymbolsFile::GetMatchedSymbols() 1151{ 1152 return matchedSymbols_; 1153} 1154 1155const DfxSymbol SymbolsFile::GetSymbolWithVaddr(uint64_t vaddrInFile) 1156{ 1157#ifdef HIPERF_DEBUG_TIME 1158 const auto startTime = steady_clock::now(); 1159#endif 1160 DfxSymbol symbol; 1161 // it should be already order from small to large 1162 auto found = 1163 std::upper_bound(symbols_.begin(), symbols_.end(), vaddrInFile, DfxSymbol::ValueLessThen); 1164 /* 1165 if data is { 1, 2, 4, 5, 5, 6 }; 1166 upper_bound for each val : 1167 0 < 1 at index 0 1168 1 < 2 at index 1 1169 2 < 4 at index 2 1170 3 < 4 at index 2 1171 4 < 5 at index 3 1172 5 < 6 at index 5 1173 6 < not found 1174 if key symbol vaddr is { 1, 2, 4, 5, 5, 6 }; 1175 check ip vaddr for each val : 1176 ip sym 1177 0 not found 1178 1 1 1179 1 1 1180 2 2 1181 3 3 1182 4 4 1183 5 5 1184 6 6 1185 7 7 1186 */ 1187 if (found != symbols_.begin()) { 1188 found = std::prev(found); 1189 if (found != symbols_.end()) { 1190 if (found->Contain(vaddrInFile)) { 1191 found->offsetToVaddr_ = vaddrInFile - found->funcVaddr_; 1192 if (!found->matched_) { 1193 found->matched_ = true; 1194 matchedSymbols_.push_back(&(*found)); 1195 } 1196 symbol = *found; // copy 1197 HLOGV("found '%s' for vaddr 0x%016" PRIx64 "", symbol.ToString().c_str(), vaddrInFile); 1198 } 1199 } 1200 } 1201 1202 if (!symbol.IsValid()) { 1203 HLOGV("NOT found vaddr 0x%" PRIx64 " in symbole file %s(%zu)", vaddrInFile, 1204 filePath_.c_str(), symbols_.size()); 1205 } 1206 symbol.fileVaddr_ = vaddrInFile; 1207 symbol.symbolFileIndex_ = id_; 1208 1209#ifdef HIPERF_DEBUG_TIME 1210 auto usedTime = duration_cast<milliseconds>(steady_clock::now() - startTime); 1211 if (usedTime > 1ms) { 1212 HLOGW("cost %" PRId64 "ms to search ", usedTime.count()); 1213 } 1214#endif 1215 return symbol; 1216} 1217 1218bool SymbolsFile::CheckPathReadable(const std::string &path) const 1219{ 1220 if (access(path.c_str(), R_OK) == 0) { 1221 return true; 1222 } else { 1223 HLOGM("'%s' is unable read", path.c_str()); 1224 return false; 1225 } 1226} 1227 1228bool SymbolsFile::setSymbolsFilePath(const std::vector<std::string> &symbolsSearchPaths) 1229{ 1230 symbolsFileSearchPaths_.clear(); 1231 for (auto &symbolsSearchPath : symbolsSearchPaths) { 1232 if (CheckPathReadable(symbolsSearchPath)) { 1233 symbolsFileSearchPaths_.emplace_back(symbolsSearchPath); 1234 HLOGV("'%s' is add to symbolsSearchPath", symbolsSearchPath.c_str()); 1235 } 1236 } 1237 return (symbolsFileSearchPaths_.size() > 0); 1238} 1239 1240std::unique_ptr<SymbolsFile> SymbolsFile::LoadSymbolsFromSaved( 1241 const SymbolFileStruct &symbolFileStruct) 1242{ 1243 bool isHapSymbolFile = static_cast<SymbolsFileType>(symbolFileStruct.symbolType_) == SYMBOL_HAP_FILE; 1244 HLOGD("isHapSymbolFile : %d", isHapSymbolFile); 1245 auto symbolsFile = CreateSymbolsFile(symbolFileStruct.filePath_); 1246 1247 // default create elf file. but hap file need special operation. 1248 symbolsFile->filePath_ = symbolFileStruct.filePath_; 1249 symbolsFile->symbolFileType_ = static_cast<SymbolsFileType>(symbolFileStruct.symbolType_); 1250 symbolsFile->textExecVaddr_ = symbolFileStruct.textExecVaddr_; 1251 symbolsFile->textExecVaddrFileOffset_ = symbolFileStruct.textExecVaddrFileOffset_; 1252 symbolsFile->buildId_ = symbolFileStruct.buildId_; 1253 for (auto &symbolStruct : symbolFileStruct.symbolStructs_) { 1254 symbolsFile->symbols_.emplace_back(symbolStruct.vaddr_, symbolStruct.len_, 1255 symbolStruct.symbolName_, symbolFileStruct.filePath_); 1256 } 1257 symbolsFile->AdjustSymbols(); // reorder 1258 if (isHapSymbolFile) { 1259 for (const auto& symbol : symbolsFile->symbols_) { 1260 symbolsFile->symbolsMap_.emplace(symbol.funcVaddr_, symbol); 1261 } 1262 symbolsFile->SetBoolValue(true); 1263 } 1264 symbolsFile->debugInfoLoadResult_ = true; 1265 symbolsFile->symbolsLoaded_ = true; // all ready LoadFrom perf.data 1266 HLOGV("load %zu symbol from SymbolFileStruct for file '%s'", symbolsFile->symbols_.size(), 1267 symbolsFile->filePath_.c_str()); 1268 return symbolsFile; 1269} 1270 1271void SymbolsFile::SetBoolValue(bool value) 1272{ 1273} 1274 1275void SymbolsFile::ExportSymbolToFileFormat(SymbolFileStruct &symbolFileStruct) 1276{ 1277 symbolFileStruct.filePath_ = filePath_; 1278 symbolFileStruct.symbolType_ = symbolFileType_; 1279 symbolFileStruct.textExecVaddr_ = textExecVaddr_; 1280 symbolFileStruct.textExecVaddrFileOffset_ = textExecVaddrFileOffset_; 1281 symbolFileStruct.buildId_ = buildId_; 1282 1283 SortMatchedSymbols(); 1284 auto symbols = GetMatchedSymbols(); 1285 symbolFileStruct.symbolStructs_.reserve(symbols.size()); 1286 for (const auto symbol : symbols) { 1287 auto &symbolStruct = symbolFileStruct.symbolStructs_.emplace_back(); 1288 symbolStruct.vaddr_ = symbol->funcVaddr_; 1289 symbolStruct.len_ = symbol->size_; 1290 symbolStruct.symbolName_ = symbol->GetName(); 1291 } 1292 1293 HLOGV("export %zu symbol to SymbolFileStruct from %s", symbolFileStruct.symbolStructs_.size(), 1294 filePath_.c_str()); 1295} 1296 1297uint64_t SymbolsFile::GetVaddrInSymbols(uint64_t ip, uint64_t mapStart, uint64_t mapOffset) const 1298{ 1299 // no convert 1300 return ip; 1301} 1302 1303void SymbolsFile::AddSymbol(DfxSymbol symbol) 1304{ 1305 symbolsLoaded_ = true; 1306 symbols_.emplace_back(symbol); 1307} 1308} // namespace HiPerf 1309} // namespace Developtools 1310} // namespace OHOS 1311