1/* 2 * Copyright (c) 2021-2024 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#include "dfx_elf.h" 17 18#include <algorithm> 19#include <cstdlib> 20#include <fcntl.h> 21#include <securec.h> 22#include <string> 23#if is_mingw 24#include "dfx_nonlinux_define.h" 25#else 26#include <elf.h> 27#include <sys/mman.h> 28#endif 29#include <sys/stat.h> 30#include <sys/types.h> 31#include <unistd.h> 32#include <utility> 33 34#include "dfx_define.h" 35#include "dfx_log.h" 36#include "dfx_instr_statistic.h" 37#include "dfx_util.h" 38#include "dfx_maps.h" 39#include "dfx_trace_dlsym.h" 40#include "dwarf_define.h" 41#if defined(ENABLE_MINIDEBUGINFO) 42#include "dfx_xz_utils.h" 43#endif 44#include "string_util.h" 45#include "unwinder_config.h" 46 47namespace OHOS { 48namespace HiviewDFX { 49namespace { 50#undef LOG_DOMAIN 51#undef LOG_TAG 52#define LOG_DOMAIN 0xD002D11 53#define LOG_TAG "DfxElf" 54} 55 56std::shared_ptr<DfxElf> DfxElf::Create(const std::string& path) 57{ 58 auto elf = std::make_shared<DfxElf>(path); 59 if (elf->IsValid()) { 60 return elf; 61 } 62 return nullptr; 63} 64 65std::shared_ptr<DfxElf> DfxElf::CreateFromHap(const std::string& file, std::shared_ptr<DfxMap> prevMap, 66 uint64_t& offset) 67{ 68 // elf header is in the first mmap area 69 // c3840000-c38a6000 r--p 00174000 /data/storage/el1/bundle/entry.hap <- program header 70 // c38a6000-c3945000 r-xp 001d9000 /data/storage/el1/bundle/entry.hap <- pc is in this region 71 // c3945000-c394b000 r--p 00277000 /data/storage/el1/bundle/entry.hap 72 // c394b000-c394c000 rw-p 0027c000 /data/storage/el1/bundle/entry.hap 73 if (prevMap == nullptr) { 74 DFXLOGE("current hap mapitem has no prev mapitem, maybe pc is wrong?"); 75 return nullptr; 76 } 77 if (!StartsWith(file, "/proc") || !EndsWith(file, ".hap")) { 78 DFXLOGD("Illegal file path, please check file: %{public}s", file.c_str()); 79 return nullptr; 80 } 81 int fd = OHOS_TEMP_FAILURE_RETRY(open(file.c_str(), O_RDONLY)); 82 if (fd < 0) { 83 DFXLOGE("Failed to open hap file, errno(%{public}d)", errno); 84 return nullptr; 85 } 86 auto fileSize = GetFileSize(fd); 87 size_t elfSize = 0; 88 size_t size = prevMap->end - prevMap->begin; 89 do { 90 auto mmap = std::make_shared<DfxMmap>(); 91 if (!mmap->Init(fd, size, (off_t)prevMap->offset)) { 92 DFXLOGE("Failed to mmap program header in hap."); 93 break; 94 } 95 96 elfSize = GetElfSize(mmap->Get()); 97 if (elfSize <= 0 || elfSize + prevMap->offset > static_cast<uint64_t>(fileSize)) { 98 DFXLOGE("Invalid elf size? elf size: %{public}d, hap size: %{public}d", (int)elfSize, (int)fileSize); 99 elfSize = 0; 100 break; 101 } 102 103 offset -= prevMap->offset; 104 } while (false); 105 106 if (elfSize != 0) { 107 DFXLOGU("elfSize: %{public}zu", elfSize); 108 auto elf = std::make_shared<DfxElf>(fd, elfSize, prevMap->offset); 109 if (elf->IsValid()) { 110 close(fd); 111 elf->SetBaseOffset(prevMap->offset); 112 return elf; 113 } 114 } 115 close(fd); 116 return nullptr; 117} 118 119DfxElf::DfxElf(const std::string& file) 120{ 121 if (mmap_ == nullptr && (!file.empty())) { 122 DFXLOGU("file: %{public}s", file.c_str()); 123#if defined(is_ohos) && is_ohos 124 if (!DfxMaps::IsLegalMapItem(file)) { 125 DFXLOGD("Illegal map file, please check file: %{public}s", file.c_str()); 126 return; 127 } 128#endif 129 std::string realPath = file; 130 if (!StartsWith(file, "/proc/")) { // sandbox file should not be check by realpath function 131 if (!RealPath(file, realPath)) { 132 DFXLOGW("Failed to realpath %{public}s, errno(%{public}d)", file.c_str(), errno); 133 return; 134 } 135 } 136#if defined(is_mingw) && is_mingw 137 int fd = OHOS_TEMP_FAILURE_RETRY(open(realPath.c_str(), O_RDONLY | O_BINARY)); 138#else 139 int fd = OHOS_TEMP_FAILURE_RETRY(open(realPath.c_str(), O_RDONLY)); 140#endif 141 if (fd > 0) { 142 auto size = static_cast<size_t>(GetFileSize(fd)); 143 mmap_ = std::make_shared<DfxMmap>(); 144 if (!mmap_->Init(fd, size, 0)) { 145 DFXLOGE("Failed to mmap init."); 146 } 147 close(fd); 148 } else { 149 DFXLOGE("Failed to open file: %{public}s", file.c_str()); 150 } 151 } 152 Init(); 153} 154 155DfxElf::DfxElf(const int fd, const size_t elfSz, const off_t offset) 156{ 157 if (mmap_ == nullptr) { 158 mmap_ = std::make_shared<DfxMmap>(); 159 if (!mmap_->Init(fd, elfSz, offset)) { 160 DFXLOGE("Failed to mmap init elf in hap."); 161 } 162 } 163 Init(); 164} 165 166DfxElf::DfxElf(uint8_t *decompressedData, size_t size) 167{ 168 if (mmap_ == nullptr) { 169 mmap_ = std::make_shared<DfxMmap>(); 170 // this mean the embedded elf initialization. 171 mmap_->Init(decompressedData, size); 172 mmap_->SetNeedUnmap(false); 173 } 174 Init(); 175} 176 177void DfxElf::Init() 178{ 179 uti_.namePtr = 0; 180 uti_.format = -1; 181 hasTableInfo_ = false; 182} 183 184void DfxElf::Clear() 185{ 186 if (elfParse_ != nullptr) { 187 elfParse_.reset(); 188 elfParse_ = nullptr; 189 } 190 191 if (mmap_ != nullptr) { 192 mmap_->Clear(); 193 mmap_.reset(); 194 mmap_ = nullptr; 195 } 196} 197 198bool DfxElf::IsEmbeddedElfValid() 199{ 200#if defined(ENABLE_MINIDEBUGINFO) 201 if (embeddedElf_ == nullptr) { 202 return InitEmbeddedElf(); 203 } 204 return embeddedElf_ != nullptr && embeddedElf_->IsValid(); 205#endif 206 return false; 207} 208 209std::shared_ptr<DfxElf> DfxElf::GetEmbeddedElf() 210{ 211 return embeddedElf_; 212} 213 214std::shared_ptr<MiniDebugInfo> DfxElf::GetMiniDebugInfo() 215{ 216 return miniDebugInfo_; 217} 218 219bool DfxElf::InitEmbeddedElf() 220{ 221#if defined(ENABLE_MINIDEBUGINFO) 222 DFX_TRACE_SCOPED_DLSYM("InitEmbeddedElf"); 223 if (!UnwinderConfig::GetEnableMiniDebugInfo() || miniDebugInfo_ == nullptr || GetMmapPtr() == nullptr) { 224 return false; 225 } 226 uint8_t *addr = miniDebugInfo_->offset + const_cast<uint8_t*>(GetMmapPtr()); 227 embeddedElfData_ = std::make_shared<std::vector<uint8_t>>(); 228 if (embeddedElfData_ == nullptr) { 229 DFXLOGE("Create embeddedElfData failed."); 230 return false; 231 } 232 if (XzDecompress(addr, miniDebugInfo_->size, embeddedElfData_)) { 233 // embeddedElfData_ store the decompressed bytes. 234 // use these bytes to construct an elf. 235 embeddedElf_ = std::make_shared<DfxElf>(embeddedElfData_->data(), embeddedElfData_->size()); 236 if (embeddedElf_ != nullptr && embeddedElf_->IsValid()) { 237 return true; 238 } else { 239 DFXLOGE("Failed to parse Embedded Elf."); 240 } 241 } else { 242 DFXLOGE("Failed to decompressed .gnu_debugdata seciton."); 243 } 244#endif 245 return false; 246} 247 248bool DfxElf::InitHeaders() 249{ 250 if (mmap_ == nullptr) { 251 return false; 252 } 253 254 if (elfParse_ != nullptr) { 255 return true; 256 } 257 258 uint8_t ident[SELFMAG + 1]; 259 if (!Read(0, ident, SELFMAG) || !IsValidElf(ident, SELFMAG)) { 260 return false; 261 } 262 263 if (!Read(EI_CLASS, &classType_, sizeof(uint8_t))) { 264 return false; 265 } 266 267 if (classType_ == ELFCLASS32) { 268 elfParse_ = std::unique_ptr<ElfParser>(new ElfParser32(mmap_)); 269 } else if (classType_ == ELFCLASS64) { 270 elfParse_ = std::unique_ptr<ElfParser>(new ElfParser64(mmap_)); 271 } else { 272 DFXLOGW("InitHeaders failed, classType: %{public}d", classType_); 273 return false; 274 } 275 if (elfParse_ != nullptr) { 276 valid_ = true; 277 elfParse_->InitHeaders(); 278#if defined(ENABLE_MINIDEBUGINFO) 279 miniDebugInfo_ = elfParse_->GetMiniDebugInfo(); 280#endif 281 } 282 return valid_; 283} 284 285bool DfxElf::IsValid() 286{ 287 if (valid_ == false) { 288 InitHeaders(); 289 } 290 return valid_; 291} 292 293uint8_t DfxElf::GetClassType() 294{ 295 if (IsValid()) { 296 return classType_; 297 } 298 return ELFCLASSNONE; 299} 300 301ArchType DfxElf::GetArchType() 302{ 303 if (IsValid()) { 304 elfParse_->GetArchType(); 305 } 306 return ARCH_UNKNOWN; 307} 308 309int64_t DfxElf::GetLoadBias() 310{ 311 if (loadBias_ == 0) { 312 if (IsValid()) { 313 loadBias_ = elfParse_->GetLoadBias(); 314 DFXLOGU("Elf loadBias: %{public}" PRIx64 "", (uint64_t)loadBias_); 315 } 316 } 317 return loadBias_; 318} 319 320uint64_t DfxElf::GetLoadBase(uint64_t mapStart, uint64_t mapOffset) 321{ 322 if (loadBase_ == static_cast<uint64_t>(-1)) { 323 if (IsValid()) { 324 DFXLOGU("mapStart: %{public}" PRIx64 ", mapOffset: %{public}" PRIx64 "", 325 (uint64_t)mapStart, (uint64_t)mapOffset); 326 loadBase_ = mapStart - mapOffset - static_cast<uint64_t>(GetLoadBias()); 327 DFXLOGU("Elf loadBase: %{public}" PRIx64 "", (uint64_t)loadBase_); 328 } 329 } 330 return loadBase_; 331} 332 333void DfxElf::SetLoadBase(uint64_t base) 334{ 335 loadBase_ = base; 336} 337 338void DfxElf::SetBaseOffset(uint64_t offset) 339{ 340 baseOffset_ = offset; 341} 342 343uint64_t DfxElf::GetBaseOffset() 344{ 345 return baseOffset_; 346} 347 348uint64_t DfxElf::GetStartPc() 349{ 350 if (startPc_ == static_cast<uint64_t>(-1)) { 351 if (IsValid()) { 352 auto startVaddr = elfParse_->GetStartVaddr(); 353 if (loadBase_ != static_cast<uint64_t>(-1) && startVaddr != static_cast<uint64_t>(-1)) { 354 startPc_ = startVaddr + loadBase_; 355 DFXLOGU("Elf startPc: %{public}" PRIx64 "", (uint64_t)startPc_); 356 } 357 } 358 } 359 return startPc_; 360} 361 362uint64_t DfxElf::GetStartVaddr() 363{ 364 if (IsValid()) { 365 return elfParse_->GetStartVaddr(); 366 } 367 return 0; 368} 369 370uint64_t DfxElf::GetEndPc() 371{ 372 if (endPc_ == 0) { 373 if (IsValid()) { 374 auto endVaddr = elfParse_->GetEndVaddr(); 375 if (loadBase_ != static_cast<uint64_t>(-1) && endVaddr != 0) { 376 endPc_ = endVaddr + loadBase_; 377 DFXLOGU("Elf endPc: %{public}" PRIx64 "", (uint64_t)endPc_); 378 } 379 } 380 } 381 return endPc_; 382} 383 384uint64_t DfxElf::GetEndVaddr() 385{ 386 if (IsValid()) { 387 return elfParse_->GetEndVaddr(); 388 } 389 return 0; 390} 391 392uint64_t DfxElf::GetStartOffset() 393{ 394 if (IsValid()) { 395 return elfParse_->GetStartOffset(); 396 } 397 return 0; 398} 399 400uint64_t DfxElf::GetRelPc(uint64_t pc, uint64_t mapStart, uint64_t mapOffset) 401{ 402 return (pc - GetLoadBase(mapStart, mapOffset)); 403} 404 405uint64_t DfxElf::GetElfSize() 406{ 407 if (!IsValid()) { 408 return 0; 409 } 410 return elfParse_->GetElfSize(); 411} 412 413std::string DfxElf::GetElfName() 414{ 415 if (!IsValid()) { 416 return ""; 417 } 418 return elfParse_->GetElfName(); 419} 420 421void DfxElf::SetBuildId(const std::string& buildId) 422{ 423 buildId_ = buildId; 424} 425 426std::string DfxElf::GetBuildId() 427{ 428 if (buildId_.empty()) { 429 if (!IsValid()) { 430 return ""; 431 } 432 ShdrInfo shdr; 433 if ((GetSectionInfo(shdr, NOTE_GNU_BUILD_ID) || GetSectionInfo(shdr, NOTES)) && GetMmapPtr() != nullptr) { 434 std::string buildIdHex = GetBuildId((uint64_t)((char*)GetMmapPtr() + shdr.offset), shdr.size); 435 if (!buildIdHex.empty()) { 436 buildId_ = ToReadableBuildId(buildIdHex); 437 DFXLOGU("Elf buildId: %{public}s", buildId_.c_str()); 438 } 439 } 440 } 441 return buildId_; 442} 443 444std::string DfxElf::GetBuildId(uint64_t noteAddr, uint64_t noteSize) 445{ 446 uint64_t tmp; 447 if (__builtin_add_overflow(noteAddr, noteSize, &tmp)) { 448 DFXLOGE("noteAddr overflow"); 449 return ""; 450 } 451 uint64_t offset = 0; 452 uint64_t ptr = noteAddr; 453 while (offset < noteSize) { 454 ElfW(Nhdr) nhdr; 455 if (noteSize - offset < sizeof(nhdr)) { 456 return ""; 457 } 458 ptr = noteAddr + offset; 459 if (memcpy_s(&nhdr, sizeof(nhdr), reinterpret_cast<void*>(ptr), sizeof(nhdr)) != 0) { 460 DFXLOGE("memcpy_s nhdr failed"); 461 return ""; 462 } 463 offset += sizeof(nhdr); 464 if (noteSize - offset < nhdr.n_namesz) { 465 return ""; 466 } 467 if (nhdr.n_namesz > 0) { 468 std::string name(nhdr.n_namesz, '\0'); 469 ptr = noteAddr + offset; 470 if (memcpy_s(&(name[0]), nhdr.n_namesz, reinterpret_cast<void*>(ptr), nhdr.n_namesz) != 0) { 471 DFXLOGE("memcpy_s note name failed"); 472 return ""; 473 } 474 // Trim trailing \0 as GNU is stored as a C string in the ELF file. 475 if (name.size() != 0 && name.back() == '\0') { 476 name.resize(name.size() - 1); 477 } 478 // Align nhdr.n_namesz to next power multiple of 4. See man 5 elf. 479 offset += (nhdr.n_namesz + 3) & ~3; // 3 : Align the offset to a 4-byte boundary 480 if (name != "GNU" || nhdr.n_type != NT_GNU_BUILD_ID) { 481 offset += (nhdr.n_descsz + 3) & ~3; // 3 : Align the offset to a 4-byte boundary 482 continue; 483 } 484 if (noteSize - offset < nhdr.n_descsz || nhdr.n_descsz == 0) { 485 return ""; 486 } 487 std::string buildIdRaw(nhdr.n_descsz, '\0'); 488 ptr = noteAddr + offset; 489 if (memcpy_s(&buildIdRaw[0], nhdr.n_descsz, reinterpret_cast<void*>(ptr), nhdr.n_descsz) != 0) { 490 return ""; 491 } 492 return buildIdRaw; 493 } 494 // Align hdr.n_descsz to next power multiple of 4. See man 5 elf. 495 offset += (nhdr.n_descsz + 3) & ~3; // 3 : Align the offset to a 4-byte boundary 496 } 497 return ""; 498} 499 500uintptr_t DfxElf::GetGlobalPointer() 501{ 502 if (!IsValid()) { 503 return 0; 504 } 505 return elfParse_->GetGlobalPointer(); 506} 507 508std::string DfxElf::ToReadableBuildId(const std::string& buildIdHex) 509{ 510 if (buildIdHex.empty()) { 511 return ""; 512 } 513 static const char HEXTABLE[] = "0123456789abcdef"; 514 static const int HEXLENGTH = 16; 515 static const int HEX_EXPAND_PARAM = 2; 516 const size_t len = buildIdHex.length(); 517 std::string buildId(len * HEX_EXPAND_PARAM, '\0'); 518 519 for (size_t i = 0; i < len; i++) { 520 unsigned int n = buildIdHex[i]; 521 buildId[i * HEX_EXPAND_PARAM] = HEXTABLE[(n >> 4) % HEXLENGTH]; // 4 : higher 4 bit of uint8 522 buildId[i * HEX_EXPAND_PARAM + 1] = HEXTABLE[n % HEXLENGTH]; 523 } 524 return buildId; 525} 526 527bool DfxElf::GetSectionInfo(ShdrInfo& shdr, const std::string secName) 528{ 529 if (!IsValid()) { 530 return false; 531 } 532 return elfParse_->GetSectionInfo(shdr, secName); 533} 534 535bool DfxElf::GetSectionData(unsigned char *buf, uint64_t size, std::string secName) 536{ 537 if (!IsValid()) { 538 return false; 539 } 540 return elfParse_->GetSectionData(buf, size, secName); 541} 542 543const std::vector<ElfSymbol>& DfxElf::GetElfSymbols() 544{ 545 if (!elfSymbols_.empty()) { 546 return elfSymbols_; 547 } 548 elfSymbols_ = elfParse_->GetElfSymbols(false); 549#if defined(ENABLE_MINIDEBUGINFO) 550 if (IsEmbeddedElfValid()) { 551 auto symbols = embeddedElf_->elfParse_->GetElfSymbols(false); 552 DFXLOGU("Get EmbeddedElf ElfSymbols, size: %{public}zu", symbols.size()); 553 elfSymbols_.insert(elfSymbols_.end(), symbols.begin(), symbols.end()); 554 } 555#endif 556 std::sort(elfSymbols_.begin(), elfSymbols_.end(), [](const ElfSymbol& sym1, const ElfSymbol& sym2) { 557 return sym1.value < sym2.value; 558 }); 559 auto pred = [](ElfSymbol a, ElfSymbol b) { return a.value == b.value; }; 560 elfSymbols_.erase(std::unique(elfSymbols_.begin(), elfSymbols_.end(), pred), elfSymbols_.end()); 561 elfSymbols_.shrink_to_fit(); 562 DFXLOGU("GetElfSymbols, size: %{public}zu", elfSymbols_.size()); 563 return elfSymbols_; 564} 565 566const std::vector<ElfSymbol>& DfxElf::GetFuncSymbols() 567{ 568 if (!funcSymbols_.empty()) { 569 return funcSymbols_; 570 } 571 funcSymbols_ = elfParse_->GetElfSymbols(true); 572#if defined(ENABLE_MINIDEBUGINFO) 573 if (IsEmbeddedElfValid()) { 574 auto symbols = embeddedElf_->elfParse_->GetElfSymbols(true); 575 DFXLOGU("Get EmbeddedElf FuncSymbols, size: %{public}zu", symbols.size()); 576 funcSymbols_.insert(funcSymbols_.end(), symbols.begin(), symbols.end()); 577 } 578#endif 579 std::sort(funcSymbols_.begin(), funcSymbols_.end(), [](const ElfSymbol& sym1, const ElfSymbol& sym2) { 580 return sym1.value < sym2.value; 581 }); 582 auto pred = [](ElfSymbol a, ElfSymbol b) { return a.value == b.value; }; 583 funcSymbols_.erase(std::unique(funcSymbols_.begin(), funcSymbols_.end(), pred), funcSymbols_.end()); 584 funcSymbols_.shrink_to_fit(); 585 DFXLOGU("GetFuncSymbols, size: %{public}zu", funcSymbols_.size()); 586 return funcSymbols_; 587} 588 589bool DfxElf::GetFuncInfoLazily(uint64_t addr, ElfSymbol& elfSymbol) 590{ 591 DFX_TRACE_SCOPED_DLSYM("GetFuncInfoLazily"); 592 if (FindFuncSymbol(addr, funcSymbols_, elfSymbol)) { 593 return true; 594 } 595 bool findSymbol = false; 596#if defined(ENABLE_MINIDEBUGINFO) 597 if (IsEmbeddedElfValid() && 598 embeddedElf_->elfParse_->GetElfSymbolByAddr(addr, elfSymbol)) { 599 funcSymbols_.emplace_back(elfSymbol); 600 findSymbol = true; 601 } 602#endif 603 604 if (!findSymbol && elfParse_->GetElfSymbolByAddr(addr, elfSymbol)) { 605 funcSymbols_.emplace_back(elfSymbol); 606 findSymbol = true; 607 } 608 609 if (findSymbol) { 610 std::sort(funcSymbols_.begin(), funcSymbols_.end(), [](const ElfSymbol& sym1, const ElfSymbol& sym2) { 611 return sym1.value < sym2.value; 612 }); 613 auto pred = [](ElfSymbol a, ElfSymbol b) { return a.value == b.value; }; 614 funcSymbols_.erase(std::unique(funcSymbols_.begin(), funcSymbols_.end(), pred), funcSymbols_.end()); 615 funcSymbols_.shrink_to_fit(); 616 DFXLOGU("GetFuncInfoLazily, size: %{public}zu", funcSymbols_.size()); 617 return true; 618 } 619 return false; 620} 621 622bool DfxElf::GetFuncInfo(uint64_t addr, ElfSymbol& elfSymbol) 623{ 624 if (UnwinderConfig::GetEnableLoadSymbolLazily()) { 625 return GetFuncInfoLazily(addr, elfSymbol); 626 } 627 628 auto symbols = GetFuncSymbols(); 629 return FindFuncSymbol(addr, symbols, elfSymbol); 630} 631 632bool DfxElf::FindFuncSymbol(uint64_t addr, const std::vector<ElfSymbol>& symbols, ElfSymbol& elfSymbol) 633{ 634 DFX_TRACE_SCOPED_DLSYM("FindFuncSymbol"); 635 if (symbols.empty()) { 636 return false; 637 } 638 size_t begin = 0; 639 size_t end = symbols.size(); 640 while (begin < end) { 641 size_t mid = begin + (end - begin) / 2; 642 const auto& symbol = symbols[mid]; 643 if (addr < symbol.value) { 644 end = mid; 645 } else if (addr < (symbol.value + symbol.size)) { 646 elfSymbol = symbol; 647 return true; 648 } else { 649 begin = mid + 1; 650 } 651 } 652 return false; 653} 654 655const std::unordered_map<uint64_t, ElfLoadInfo>& DfxElf::GetPtLoads() 656{ 657 return elfParse_->GetPtLoads(); 658} 659 660bool DfxElf::FillUnwindTableByExidx(ShdrInfo shdr, uintptr_t loadBase, struct UnwindTableInfo* uti) 661{ 662 if (uti == nullptr) { 663 return false; 664 } 665 uti->gp = 0; 666 uti->tableData = loadBase + shdr.addr; 667 uti->tableLen = shdr.size; 668 INSTR_STATISTIC(InstructionEntriesArmExidx, shdr.size, 0); 669 uti->format = UNW_INFO_FORMAT_ARM_EXIDX; 670 DFXLOGU("[%{public}d]: tableData: %{public}" PRIx64 ", tableLen: %{public}d", __LINE__, 671 (uint64_t)uti->tableData, (int)uti->tableLen); 672 return true; 673} 674 675#if is_ohos && !is_mingw 676bool DfxElf::FillUnwindTableByEhhdrLocal(struct DwarfEhFrameHdr* hdr, struct UnwindTableInfo* uti) 677{ 678 if (hdr == nullptr) { 679 return false; 680 } 681 if (hdr->version != DW_EH_VERSION) { 682 DFXLOGE("[%{public}d]: version(%{public}d) error", __LINE__, hdr->version); 683 return false; 684 } 685 686 uintptr_t ptr = (uintptr_t)(&(hdr->ehFrame)); 687 DFXLOGU("[%{public}d]: hdr: %{public}" PRIx64 ", ehFrame: %{public}" PRIx64 "", __LINE__, 688 (uint64_t)hdr, (uint64_t)ptr); 689 690 auto acc = std::make_shared<DfxAccessorsLocal>(); 691 auto memory = std::make_shared<DfxMemory>(acc); 692 DFXLOGU("[%{public}d]: gp: %{public}" PRIx64 ", ehFramePtrEnc: %{public}x, fdeCountEnc: %{public}x", __LINE__, 693 (uint64_t)uti->gp, hdr->ehFramePtrEnc, hdr->fdeCountEnc); 694 memory->SetDataOffset(uti->gp); 695 MAYBE_UNUSED uintptr_t ehFrameStart = memory->ReadEncodedValue(ptr, hdr->ehFramePtrEnc); 696 uintptr_t fdeCount = memory->ReadEncodedValue(ptr, hdr->fdeCountEnc); 697 DFXLOGU("[%{public}d]: ehFrameStart: %{public}" PRIx64 ", fdeCount: %{public}d", __LINE__, 698 (uint64_t)ehFrameStart, (int)fdeCount); 699 700 if (hdr->tableEnc != (DW_EH_PE_datarel | DW_EH_PE_sdata4)) { 701 DFXLOGU("[%{public}d]: tableEnc: %{public}x", __LINE__, hdr->tableEnc); 702 if (hdr->fdeCountEnc == DW_EH_PE_omit) { 703 fdeCount = ~0UL; 704 } 705 if (hdr->ehFramePtrEnc == DW_EH_PE_omit) { 706 DFXLOGE("[%{public}d]: ehFramePtrEnc(%{public}x) error", __LINE__, hdr->ehFramePtrEnc); 707 return false; 708 } 709 uti->isLinear = true; 710 uti->tableLen = fdeCount; 711 uti->tableData = ehFrameStart; 712 } else { 713 uti->isLinear = false; 714 uti->tableLen = (fdeCount * sizeof(DwarfTableEntry)) / sizeof(uintptr_t); 715 uti->tableData = ptr; 716 uti->segbase = (uintptr_t)hdr; 717 } 718 uti->format = UNW_INFO_FORMAT_REMOTE_TABLE; 719 DFXLOGU("[%{public}d]: tableData: %{public}" PRIx64 ", tableLen: %{public}d", __LINE__, 720 (uint64_t)uti->tableData, (int)uti->tableLen); 721 return true; 722} 723#endif 724 725bool DfxElf::FillUnwindTableByEhhdr(struct DwarfEhFrameHdr* hdr, uintptr_t shdrBase, struct UnwindTableInfo* uti) 726{ 727 if ((hdr == nullptr) || (uti == nullptr)) { 728 return false; 729 } 730 if (hdr->version != DW_EH_VERSION) { 731 DFXLOGE("[%{public}d]: version(%{public}d) error", __LINE__, hdr->version); 732 return false; 733 } 734 uintptr_t ptr = (uintptr_t)(&(hdr->ehFrame)); 735 DFXLOGU("[%{public}d]: hdr: %{public}" PRIx64 ", ehFrame: %{public}" PRIx64 "", __LINE__, 736 (uint64_t)hdr, (uint64_t)ptr); 737 738 uti->gp = GetGlobalPointer(); 739 DFXLOGU("[%{public}d]: gp: %{public}" PRIx64 ", ehFramePtrEnc: %{public}x, fdeCountEnc: %{public}x", __LINE__, 740 (uint64_t)uti->gp, hdr->ehFramePtrEnc, hdr->fdeCountEnc); 741 mmap_->SetDataOffset(uti->gp); 742 auto ptrOffset = ptr - reinterpret_cast<uintptr_t>(GetMmapPtr()); 743 MAYBE_UNUSED uintptr_t ehFrameStart = mmap_->ReadEncodedValue(ptrOffset, hdr->ehFramePtrEnc); 744 uintptr_t fdeCount = mmap_->ReadEncodedValue(ptrOffset, hdr->fdeCountEnc); 745 DFXLOGU("[%{public}d]: ehFrameStart: %{public}" PRIx64 ", fdeCount: %{public}d", __LINE__, 746 (uint64_t)ehFrameStart, (int)fdeCount); 747 ptr = reinterpret_cast<uintptr_t>(GetMmapPtr()) + ptrOffset; 748 749 if (hdr->tableEnc != (DW_EH_PE_datarel | DW_EH_PE_sdata4)) { 750 DFXLOGU("[%{public}d]: tableEnc: %{public}x", __LINE__, hdr->tableEnc); 751 if (hdr->fdeCountEnc == DW_EH_PE_omit) { 752 fdeCount = ~0UL; 753 } 754 if (hdr->ehFramePtrEnc == DW_EH_PE_omit) { 755 DFXLOGE("[%{public}d]: ehFramePtrEnc(%{public}x) error", __LINE__, hdr->ehFramePtrEnc); 756 return false; 757 } 758 uti->isLinear = true; 759 uti->tableLen = fdeCount; 760 uti->tableData = shdrBase + ehFrameStart; 761 uti->segbase = shdrBase; 762 } else { 763 uti->isLinear = false; 764 uti->tableLen = (fdeCount * sizeof(DwarfTableEntry)) / sizeof(uintptr_t); 765 uti->tableData = shdrBase + ptr - (uintptr_t)hdr; 766 uti->segbase = shdrBase; 767 } 768 uti->format = UNW_INFO_FORMAT_REMOTE_TABLE; 769 DFXLOGU("[%{public}d]: tableData: %{public}" PRIx64 ", tableLen: %{public}d", __LINE__, 770 (uint64_t)uti->tableData, (int)uti->tableLen); 771 return true; 772} 773 774int DfxElf::FindUnwindTableInfo(uintptr_t pc, std::shared_ptr<DfxMap> map, struct UnwindTableInfo& uti) 775{ 776 if (hasTableInfo_ && pc >= uti_.startPc && pc < uti_.endPc) { 777 uti = uti_; 778 DFXLOGU("FindUnwindTableInfo had found"); 779 return UNW_ERROR_NONE; 780 } 781 if (map == nullptr) { 782 return UNW_ERROR_INVALID_MAP; 783 } 784 uintptr_t loadBase = GetLoadBase(map->begin, map->offset); 785 uti.startPc = GetStartPc(); 786 uti.endPc = GetEndPc(); 787 if (pc < uti.startPc || pc >= uti.endPc) { 788 DFXLOGU("Elf startPc: %{public}" PRIx64 ", endPc: %{public}" PRIx64 "", 789 (uint64_t)uti.startPc, (uint64_t)uti.endPc); 790 return UNW_ERROR_PC_NOT_IN_UNWIND_INFO; 791 } 792 793 ShdrInfo shdr; 794#if defined(__arm__) 795 if (GetSectionInfo(shdr, ARM_EXIDX)) { 796 hasTableInfo_ = FillUnwindTableByExidx(shdr, loadBase, &uti); 797 } 798#endif 799 800 if (!hasTableInfo_) { 801 struct DwarfEhFrameHdr* hdr = nullptr; 802 struct DwarfEhFrameHdr synthHdr; 803 if (GetSectionInfo(shdr, EH_FRAME_HDR) && GetMmapPtr() != nullptr) { 804 INSTR_STATISTIC(InstructionEntriesEhFrame, shdr.size, 0); 805 hdr = (struct DwarfEhFrameHdr *) (shdr.offset + (char *)GetMmapPtr()); 806 } else if (GetSectionInfo(shdr, EH_FRAME) && GetMmapPtr() != nullptr) { 807 DFXLOGW("[%{public}d]: Elf(%{public}s) no found .eh_frame_hdr section, " \ 808 "using synthetic .eh_frame section", __LINE__, map->name.c_str()); 809 INSTR_STATISTIC(InstructionEntriesEhFrame, shdr.size, 0); 810 synthHdr.version = DW_EH_VERSION; 811 synthHdr.ehFramePtrEnc = DW_EH_PE_absptr | 812 ((sizeof(ElfW(Addr)) == 4) ? DW_EH_PE_udata4 : DW_EH_PE_udata8); // 4 : four bytes 813 synthHdr.fdeCountEnc = DW_EH_PE_omit; 814 synthHdr.tableEnc = DW_EH_PE_omit; 815 synthHdr.ehFrame = (ElfW(Addr))(shdr.offset + (char*)GetMmapPtr()); 816 hdr = &synthHdr; 817 } 818 uintptr_t shdrBase = static_cast<uintptr_t>(loadBase + shdr.addr); 819 hasTableInfo_ = FillUnwindTableByEhhdr(hdr, shdrBase, &uti); 820 } 821 822 if (hasTableInfo_) { 823 uti_ = uti; 824 return UNW_ERROR_NONE; 825 } 826 return UNW_ERROR_NO_UNWIND_INFO; 827} 828 829int DfxElf::FindUnwindTableLocal(uintptr_t pc, struct UnwindTableInfo& uti) 830{ 831#if is_ohos && !is_mingw 832 DlCbData cbData; 833 (void)memset_s(&cbData, sizeof(cbData), 0, sizeof(cbData)); 834 cbData.pc = pc; 835 cbData.uti.format = -1; 836 int ret = dl_iterate_phdr(DlPhdrCb, &cbData); 837 if (ret > 0) { 838 if (cbData.uti.format != -1) { 839 uti = cbData.uti; 840 return UNW_ERROR_NONE; 841 } 842 } 843 return UNW_ERROR_NO_UNWIND_INFO; 844#else 845 return UNW_ERROR_UNSUPPORTED_VERSION; 846#endif 847} 848 849#if is_ohos && !is_mingw 850bool DfxElf::FindSection(struct dl_phdr_info *info, const std::string secName, ShdrInfo& shdr) 851{ 852 if (info == nullptr) { 853 return false; 854 } 855 const char *file = info->dlpi_name; 856 if (strlen(file) == 0) { 857 file = PROC_SELF_EXE_PATH; 858 } 859 860 auto elf = Create(file); 861 if (elf == nullptr) { 862 return false; 863 } 864 865 return elf->GetSectionInfo(shdr, secName); 866} 867 868int DfxElf::DlPhdrCb(struct dl_phdr_info *info, size_t size, void *data) 869{ 870 struct DlCbData *cbData = (struct DlCbData *)data; 871 if ((info == nullptr) || (cbData == nullptr)) { 872 return -1; 873 } 874 UnwindTableInfo* uti = &cbData->uti; 875 uintptr_t pc = cbData->pc; 876 const ElfW(Phdr) *pText = nullptr; 877 const ElfW(Phdr) *pDynamic = nullptr; 878#if defined(__arm__) 879 const ElfW(Phdr) *pArmExidx = nullptr; 880#endif 881 const ElfW(Phdr) *pEhHdr = nullptr; 882 883 const ElfW(Phdr) *phdr = info->dlpi_phdr; 884 ElfW(Addr) loadBase = info->dlpi_addr; 885 for (size_t i = 0; i < info->dlpi_phnum && phdr != nullptr; i++, phdr++) { 886 switch (phdr->p_type) { 887 case PT_LOAD: { 888 ElfW(Addr) vaddr = phdr->p_vaddr + loadBase; 889 if (pc >= vaddr && pc < vaddr + phdr->p_memsz) { 890 pText = phdr; 891 } 892 break; 893 } 894#if defined(__arm__) 895 case PT_ARM_EXIDX: { 896 pArmExidx = phdr; 897 break; 898 } 899#endif 900 case PT_GNU_EH_FRAME: { 901 pEhHdr = phdr; 902 break; 903 } 904 case PT_DYNAMIC: { 905 pDynamic = phdr; 906 break; 907 } 908 default: 909 break; 910 } 911 } 912 if (pText == nullptr) { 913 return 0; 914 } 915 uti->startPc = pText->p_vaddr + loadBase; 916 uti->endPc = uti->startPc + pText->p_memsz; 917 DFXLOGU("Elf name: %{public}s", info->dlpi_name); 918 uti->namePtr = (uintptr_t) info->dlpi_name; 919 920#if defined(__arm__) 921 if (pArmExidx) { 922 ShdrInfo shdr; 923 shdr.addr = pArmExidx->p_vaddr; 924 shdr.size = pArmExidx->p_memsz; 925 return FillUnwindTableByExidx(shdr, loadBase, uti); 926 } 927#endif 928 929 if (pDynamic) { 930 ElfW(Dyn) *dyn = (ElfW(Dyn) *)(pDynamic->p_vaddr + loadBase); 931 if (dyn == nullptr) { 932 return 0; 933 } 934 for (; dyn->d_tag != DT_NULL; ++dyn) { 935 if (dyn->d_tag == DT_PLTGOT) { 936 uti->gp = dyn->d_un.d_ptr; 937 break; 938 } 939 } 940 } else { 941 uti->gp = 0; 942 } 943 944 struct DwarfEhFrameHdr *hdr = nullptr; 945 struct DwarfEhFrameHdr synthHdr; 946 if (pEhHdr) { 947 INSTR_STATISTIC(InstructionEntriesEhFrame, pEhHdr->p_memsz, 0); 948 hdr = (struct DwarfEhFrameHdr *) (pEhHdr->p_vaddr + loadBase); 949 } else { 950 ShdrInfo shdr; 951 if (FindSection(info, EH_FRAME, shdr)) { 952 DFXLOGW("[%{public}d]: Elf(%{public}s) no found .eh_frame_hdr section, " \ 953 "using synthetic .eh_frame section", __LINE__, info->dlpi_name); 954 INSTR_STATISTIC(InstructionEntriesEhFrame, shdr.size, 0); 955 synthHdr.version = DW_EH_VERSION; 956 synthHdr.ehFramePtrEnc = DW_EH_PE_absptr | 957 ((sizeof(ElfW(Addr)) == 4) ? DW_EH_PE_udata4 : DW_EH_PE_udata8); // 4 : four bytes 958 synthHdr.fdeCountEnc = DW_EH_PE_omit; 959 synthHdr.tableEnc = DW_EH_PE_omit; 960 synthHdr.ehFrame = (ElfW(Addr))(shdr.addr + info->dlpi_addr); 961 hdr = &synthHdr; 962 } 963 } 964 return FillUnwindTableByEhhdrLocal(hdr, uti); 965} 966#endif 967 968bool DfxElf::Read(uintptr_t pos, void *buf, size_t size) 969{ 970 if ((mmap_ != nullptr) && (mmap_->Read(pos, buf, size) == size)) { 971 return true; 972 } 973 return false; 974} 975 976const uint8_t* DfxElf::GetMmapPtr() 977{ 978 if (mmap_ == nullptr) { 979 return nullptr; 980 } 981 return static_cast<uint8_t *>(mmap_->Get()); 982} 983 984size_t DfxElf::GetMmapSize() 985{ 986 if (mmap_ == nullptr) { 987 return 0; 988 } 989 return mmap_->Size(); 990} 991 992bool DfxElf::IsValidElf(const void* ptr, size_t size) 993{ 994 if (ptr == nullptr) { 995 return false; 996 } 997 998 if (memcmp(ptr, ELFMAG, size) != 0) { 999 DFXLOGD("Invalid elf hdr?"); 1000 return false; 1001 } 1002 return true; 1003} 1004 1005size_t DfxElf::GetElfSize(const void* ptr) 1006{ 1007 if (!IsValidElf(ptr, SELFMAG)) { 1008 return 0; 1009 } 1010 1011 const uint8_t* data = static_cast<const uint8_t*>(ptr); 1012 uint8_t classType = data[EI_CLASS]; 1013 if (classType == ELFCLASS32) { 1014 Elf32_Ehdr *ehdr = (Elf32_Ehdr *)data; 1015 return static_cast<size_t>(ehdr->e_shoff + (ehdr->e_shentsize * ehdr->e_shnum)); 1016 } else if (classType == ELFCLASS64) { 1017 Elf64_Ehdr *ehdr = (Elf64_Ehdr *)data; 1018 return static_cast<size_t>(ehdr->e_shoff + (ehdr->e_shentsize * ehdr->e_shnum)); 1019 } 1020 DFXLOGW("classType(%{public}d) error", classType); 1021 return 0; 1022} 1023} // namespace HiviewDFX 1024} // namespace OHOS 1025