1 //===-- LLVMSymbolize.cpp -------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Implementation for LLVM symbolization library. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "llvm/DebugInfo/Symbolize/Symbolize.h" 14 15 #include "llvm/ADT/STLExtras.h" 16 #include "llvm/DebugInfo/DWARF/DWARFContext.h" 17 #include "llvm/DebugInfo/PDB/PDB.h" 18 #include "llvm/DebugInfo/PDB/PDBContext.h" 19 #include "llvm/DebugInfo/Symbolize/DIFetcher.h" 20 #include "llvm/DebugInfo/Symbolize/SymbolizableObjectFile.h" 21 #include "llvm/Demangle/Demangle.h" 22 #include "llvm/Object/COFF.h" 23 #include "llvm/Object/ELF.h" 24 #include "llvm/Object/ELFObjectFile.h" 25 #include "llvm/Object/MachO.h" 26 #include "llvm/Object/MachOUniversal.h" 27 #include "llvm/Support/CRC.h" 28 #include "llvm/Support/Casting.h" 29 #include "llvm/Support/Compression.h" 30 #include "llvm/Support/DataExtractor.h" 31 #include "llvm/Support/Errc.h" 32 #include "llvm/Support/FileSystem.h" 33 #include "llvm/Support/MemoryBuffer.h" 34 #include "llvm/Support/Path.h" 35 #include <algorithm> 36 #include <cassert> 37 #include <cstring> 38 39 namespace llvm { 40 namespace symbolize { 41 42 LLVMSymbolizer::LLVMSymbolizer() = default; 43 44 LLVMSymbolizer::LLVMSymbolizer(const Options &Opts) : Opts(Opts) {} 45 46 LLVMSymbolizer::~LLVMSymbolizer() = default; 47 48 template <typename T> 49 Expected<DILineInfo> 50 LLVMSymbolizer::symbolizeCodeCommon(const T &ModuleSpecifier, 51 object::SectionedAddress ModuleOffset) { 52 53 auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier); 54 if (!InfoOrErr) 55 return InfoOrErr.takeError(); 56 57 SymbolizableModule *Info = *InfoOrErr; 58 59 // A null module means an error has already been reported. Return an empty 60 // result. 61 if (!Info) 62 return DILineInfo(); 63 64 // If the user is giving us relative addresses, add the preferred base of the 65 // object to the offset before we do the query. It's what DIContext expects. 66 if (Opts.RelativeAddresses) 67 ModuleOffset.Address += Info->getModulePreferredBase(); 68 69 DILineInfo LineInfo = Info->symbolizeCode( 70 ModuleOffset, DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions), 71 Opts.UseSymbolTable); 72 if (Opts.Demangle) 73 LineInfo.FunctionName = DemangleName(LineInfo.FunctionName, Info); 74 return LineInfo; 75 } 76 77 Expected<DILineInfo> 78 LLVMSymbolizer::symbolizeCode(const ObjectFile &Obj, 79 object::SectionedAddress ModuleOffset) { 80 return symbolizeCodeCommon(Obj, ModuleOffset); 81 } 82 83 Expected<DILineInfo> 84 LLVMSymbolizer::symbolizeCode(const std::string &ModuleName, 85 object::SectionedAddress ModuleOffset) { 86 return symbolizeCodeCommon(ModuleName, ModuleOffset); 87 } 88 89 Expected<DILineInfo> 90 LLVMSymbolizer::symbolizeCode(ArrayRef<uint8_t> BuildID, 91 object::SectionedAddress ModuleOffset) { 92 return symbolizeCodeCommon(BuildID, ModuleOffset); 93 } 94 95 template <typename T> 96 Expected<DIInliningInfo> LLVMSymbolizer::symbolizeInlinedCodeCommon( 97 const T &ModuleSpecifier, object::SectionedAddress ModuleOffset) { 98 auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier); 99 if (!InfoOrErr) 100 return InfoOrErr.takeError(); 101 102 SymbolizableModule *Info = *InfoOrErr; 103 104 // A null module means an error has already been reported. Return an empty 105 // result. 106 if (!Info) 107 return DIInliningInfo(); 108 109 // If the user is giving us relative addresses, add the preferred base of the 110 // object to the offset before we do the query. It's what DIContext expects. 111 if (Opts.RelativeAddresses) 112 ModuleOffset.Address += Info->getModulePreferredBase(); 113 114 DIInliningInfo InlinedContext = Info->symbolizeInlinedCode( 115 ModuleOffset, DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions), 116 Opts.UseSymbolTable); 117 if (Opts.Demangle) { 118 for (int i = 0, n = InlinedContext.getNumberOfFrames(); i < n; i++) { 119 auto *Frame = InlinedContext.getMutableFrame(i); 120 Frame->FunctionName = DemangleName(Frame->FunctionName, Info); 121 } 122 } 123 return InlinedContext; 124 } 125 126 Expected<DIInliningInfo> 127 LLVMSymbolizer::symbolizeInlinedCode(const ObjectFile &Obj, 128 object::SectionedAddress ModuleOffset) { 129 return symbolizeInlinedCodeCommon(Obj, ModuleOffset); 130 } 131 132 Expected<DIInliningInfo> 133 LLVMSymbolizer::symbolizeInlinedCode(const std::string &ModuleName, 134 object::SectionedAddress ModuleOffset) { 135 return symbolizeInlinedCodeCommon(ModuleName, ModuleOffset); 136 } 137 138 Expected<DIInliningInfo> 139 LLVMSymbolizer::symbolizeInlinedCode(ArrayRef<uint8_t> BuildID, 140 object::SectionedAddress ModuleOffset) { 141 return symbolizeInlinedCodeCommon(BuildID, ModuleOffset); 142 } 143 144 template <typename T> 145 Expected<DIGlobal> 146 LLVMSymbolizer::symbolizeDataCommon(const T &ModuleSpecifier, 147 object::SectionedAddress ModuleOffset) { 148 149 auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier); 150 if (!InfoOrErr) 151 return InfoOrErr.takeError(); 152 153 SymbolizableModule *Info = *InfoOrErr; 154 // A null module means an error has already been reported. Return an empty 155 // result. 156 if (!Info) 157 return DIGlobal(); 158 159 // If the user is giving us relative addresses, add the preferred base of 160 // the object to the offset before we do the query. It's what DIContext 161 // expects. 162 if (Opts.RelativeAddresses) 163 ModuleOffset.Address += Info->getModulePreferredBase(); 164 165 DIGlobal Global = Info->symbolizeData(ModuleOffset); 166 if (Opts.Demangle) 167 Global.Name = DemangleName(Global.Name, Info); 168 return Global; 169 } 170 171 Expected<DIGlobal> 172 LLVMSymbolizer::symbolizeData(const ObjectFile &Obj, 173 object::SectionedAddress ModuleOffset) { 174 return symbolizeDataCommon(Obj, ModuleOffset); 175 } 176 177 Expected<DIGlobal> 178 LLVMSymbolizer::symbolizeData(const std::string &ModuleName, 179 object::SectionedAddress ModuleOffset) { 180 return symbolizeDataCommon(ModuleName, ModuleOffset); 181 } 182 183 Expected<DIGlobal> 184 LLVMSymbolizer::symbolizeData(ArrayRef<uint8_t> BuildID, 185 object::SectionedAddress ModuleOffset) { 186 return symbolizeDataCommon(BuildID, ModuleOffset); 187 } 188 189 template <typename T> 190 Expected<std::vector<DILocal>> 191 LLVMSymbolizer::symbolizeFrameCommon(const T &ModuleSpecifier, 192 object::SectionedAddress ModuleOffset) { 193 auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier); 194 if (!InfoOrErr) 195 return InfoOrErr.takeError(); 196 197 SymbolizableModule *Info = *InfoOrErr; 198 // A null module means an error has already been reported. Return an empty 199 // result. 200 if (!Info) 201 return std::vector<DILocal>(); 202 203 // If the user is giving us relative addresses, add the preferred base of 204 // the object to the offset before we do the query. It's what DIContext 205 // expects. 206 if (Opts.RelativeAddresses) 207 ModuleOffset.Address += Info->getModulePreferredBase(); 208 209 return Info->symbolizeFrame(ModuleOffset); 210 } 211 212 Expected<std::vector<DILocal>> 213 LLVMSymbolizer::symbolizeFrame(const ObjectFile &Obj, 214 object::SectionedAddress ModuleOffset) { 215 return symbolizeFrameCommon(Obj, ModuleOffset); 216 } 217 218 Expected<std::vector<DILocal>> 219 LLVMSymbolizer::symbolizeFrame(const std::string &ModuleName, 220 object::SectionedAddress ModuleOffset) { 221 return symbolizeFrameCommon(ModuleName, ModuleOffset); 222 } 223 224 Expected<std::vector<DILocal>> 225 LLVMSymbolizer::symbolizeFrame(ArrayRef<uint8_t> BuildID, 226 object::SectionedAddress ModuleOffset) { 227 return symbolizeFrameCommon(BuildID, ModuleOffset); 228 } 229 230 void LLVMSymbolizer::flush() { 231 ObjectForUBPathAndArch.clear(); 232 LRUBinaries.clear(); 233 CacheSize = 0; 234 BinaryForPath.clear(); 235 ObjectPairForPathArch.clear(); 236 Modules.clear(); 237 BuildIDPaths.clear(); 238 } 239 240 namespace { 241 242 // For Path="/path/to/foo" and Basename="foo" assume that debug info is in 243 // /path/to/foo.dSYM/Contents/Resources/DWARF/foo. 244 // For Path="/path/to/bar.dSYM" and Basename="foo" assume that debug info is in 245 // /path/to/bar.dSYM/Contents/Resources/DWARF/foo. 246 std::string getDarwinDWARFResourceForPath(const std::string &Path, 247 const std::string &Basename) { 248 SmallString<16> ResourceName = StringRef(Path); 249 if (sys::path::extension(Path) != ".dSYM") { 250 ResourceName += ".dSYM"; 251 } 252 sys::path::append(ResourceName, "Contents", "Resources", "DWARF"); 253 sys::path::append(ResourceName, Basename); 254 return std::string(ResourceName.str()); 255 } 256 257 bool checkFileCRC(StringRef Path, uint32_t CRCHash) { 258 ErrorOr<std::unique_ptr<MemoryBuffer>> MB = 259 MemoryBuffer::getFileOrSTDIN(Path); 260 if (!MB) 261 return false; 262 return CRCHash == llvm::crc32(arrayRefFromStringRef(MB.get()->getBuffer())); 263 } 264 265 bool getGNUDebuglinkContents(const ObjectFile *Obj, std::string &DebugName, 266 uint32_t &CRCHash) { 267 if (!Obj) 268 return false; 269 for (const SectionRef &Section : Obj->sections()) { 270 StringRef Name; 271 consumeError(Section.getName().moveInto(Name)); 272 273 Name = Name.substr(Name.find_first_not_of("._")); 274 if (Name == "gnu_debuglink") { 275 Expected<StringRef> ContentsOrErr = Section.getContents(); 276 if (!ContentsOrErr) { 277 consumeError(ContentsOrErr.takeError()); 278 return false; 279 } 280 DataExtractor DE(*ContentsOrErr, Obj->isLittleEndian(), 0); 281 uint64_t Offset = 0; 282 if (const char *DebugNameStr = DE.getCStr(&Offset)) { 283 // 4-byte align the offset. 284 Offset = (Offset + 3) & ~0x3; 285 if (DE.isValidOffsetForDataOfSize(Offset, 4)) { 286 DebugName = DebugNameStr; 287 CRCHash = DE.getU32(&Offset); 288 return true; 289 } 290 } 291 break; 292 } 293 } 294 return false; 295 } 296 297 bool darwinDsymMatchesBinary(const MachOObjectFile *DbgObj, 298 const MachOObjectFile *Obj) { 299 ArrayRef<uint8_t> dbg_uuid = DbgObj->getUuid(); 300 ArrayRef<uint8_t> bin_uuid = Obj->getUuid(); 301 if (dbg_uuid.empty() || bin_uuid.empty()) 302 return false; 303 return !memcmp(dbg_uuid.data(), bin_uuid.data(), dbg_uuid.size()); 304 } 305 306 template <typename ELFT> 307 Optional<ArrayRef<uint8_t>> getBuildID(const ELFFile<ELFT> &Obj) { 308 auto PhdrsOrErr = Obj.program_headers(); 309 if (!PhdrsOrErr) { 310 consumeError(PhdrsOrErr.takeError()); 311 return {}; 312 } 313 for (const auto &P : *PhdrsOrErr) { 314 if (P.p_type != ELF::PT_NOTE) 315 continue; 316 Error Err = Error::success(); 317 for (auto N : Obj.notes(P, Err)) 318 if (N.getType() == ELF::NT_GNU_BUILD_ID && 319 N.getName() == ELF::ELF_NOTE_GNU) 320 return N.getDesc(); 321 consumeError(std::move(Err)); 322 } 323 return {}; 324 } 325 326 Optional<ArrayRef<uint8_t>> getBuildID(const ELFObjectFileBase *Obj) { 327 Optional<ArrayRef<uint8_t>> BuildID; 328 if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Obj)) 329 BuildID = getBuildID(O->getELFFile()); 330 else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(Obj)) 331 BuildID = getBuildID(O->getELFFile()); 332 else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(Obj)) 333 BuildID = getBuildID(O->getELFFile()); 334 else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(Obj)) 335 BuildID = getBuildID(O->getELFFile()); 336 else 337 llvm_unreachable("unsupported file format"); 338 return BuildID; 339 } 340 341 } // end anonymous namespace 342 343 ObjectFile *LLVMSymbolizer::lookUpDsymFile(const std::string &ExePath, 344 const MachOObjectFile *MachExeObj, 345 const std::string &ArchName) { 346 // On Darwin we may find DWARF in separate object file in 347 // resource directory. 348 std::vector<std::string> DsymPaths; 349 StringRef Filename = sys::path::filename(ExePath); 350 DsymPaths.push_back( 351 getDarwinDWARFResourceForPath(ExePath, std::string(Filename))); 352 for (const auto &Path : Opts.DsymHints) { 353 DsymPaths.push_back( 354 getDarwinDWARFResourceForPath(Path, std::string(Filename))); 355 } 356 for (const auto &Path : DsymPaths) { 357 auto DbgObjOrErr = getOrCreateObject(Path, ArchName); 358 if (!DbgObjOrErr) { 359 // Ignore errors, the file might not exist. 360 consumeError(DbgObjOrErr.takeError()); 361 continue; 362 } 363 ObjectFile *DbgObj = DbgObjOrErr.get(); 364 if (!DbgObj) 365 continue; 366 const MachOObjectFile *MachDbgObj = dyn_cast<const MachOObjectFile>(DbgObj); 367 if (!MachDbgObj) 368 continue; 369 if (darwinDsymMatchesBinary(MachDbgObj, MachExeObj)) 370 return DbgObj; 371 } 372 return nullptr; 373 } 374 375 ObjectFile *LLVMSymbolizer::lookUpDebuglinkObject(const std::string &Path, 376 const ObjectFile *Obj, 377 const std::string &ArchName) { 378 std::string DebuglinkName; 379 uint32_t CRCHash; 380 std::string DebugBinaryPath; 381 if (!getGNUDebuglinkContents(Obj, DebuglinkName, CRCHash)) 382 return nullptr; 383 if (!findDebugBinary(Path, DebuglinkName, CRCHash, DebugBinaryPath)) 384 return nullptr; 385 auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName); 386 if (!DbgObjOrErr) { 387 // Ignore errors, the file might not exist. 388 consumeError(DbgObjOrErr.takeError()); 389 return nullptr; 390 } 391 return DbgObjOrErr.get(); 392 } 393 394 ObjectFile *LLVMSymbolizer::lookUpBuildIDObject(const std::string &Path, 395 const ELFObjectFileBase *Obj, 396 const std::string &ArchName) { 397 auto BuildID = getBuildID(Obj); 398 if (!BuildID) 399 return nullptr; 400 if (BuildID->size() < 2) 401 return nullptr; 402 std::string DebugBinaryPath; 403 if (!getOrFindDebugBinary(*BuildID, DebugBinaryPath)) 404 return nullptr; 405 auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName); 406 if (!DbgObjOrErr) { 407 consumeError(DbgObjOrErr.takeError()); 408 return nullptr; 409 } 410 return DbgObjOrErr.get(); 411 } 412 413 bool LLVMSymbolizer::findDebugBinary(const std::string &OrigPath, 414 const std::string &DebuglinkName, 415 uint32_t CRCHash, std::string &Result) { 416 SmallString<16> OrigDir(OrigPath); 417 llvm::sys::path::remove_filename(OrigDir); 418 SmallString<16> DebugPath = OrigDir; 419 // Try relative/path/to/original_binary/debuglink_name 420 llvm::sys::path::append(DebugPath, DebuglinkName); 421 if (checkFileCRC(DebugPath, CRCHash)) { 422 Result = std::string(DebugPath.str()); 423 return true; 424 } 425 // Try relative/path/to/original_binary/.debug/debuglink_name 426 DebugPath = OrigDir; 427 llvm::sys::path::append(DebugPath, ".debug", DebuglinkName); 428 if (checkFileCRC(DebugPath, CRCHash)) { 429 Result = std::string(DebugPath.str()); 430 return true; 431 } 432 // Make the path absolute so that lookups will go to 433 // "/usr/lib/debug/full/path/to/debug", not 434 // "/usr/lib/debug/to/debug" 435 llvm::sys::fs::make_absolute(OrigDir); 436 if (!Opts.FallbackDebugPath.empty()) { 437 // Try <FallbackDebugPath>/absolute/path/to/original_binary/debuglink_name 438 DebugPath = Opts.FallbackDebugPath; 439 } else { 440 #if defined(__NetBSD__) 441 // Try /usr/libdata/debug/absolute/path/to/original_binary/debuglink_name 442 DebugPath = "/usr/libdata/debug"; 443 #else 444 // Try /usr/lib/debug/absolute/path/to/original_binary/debuglink_name 445 DebugPath = "/usr/lib/debug"; 446 #endif 447 } 448 llvm::sys::path::append(DebugPath, llvm::sys::path::relative_path(OrigDir), 449 DebuglinkName); 450 if (checkFileCRC(DebugPath, CRCHash)) { 451 Result = std::string(DebugPath.str()); 452 return true; 453 } 454 return false; 455 } 456 457 static StringRef getBuildIDStr(ArrayRef<uint8_t> BuildID) { 458 return StringRef(reinterpret_cast<const char *>(BuildID.data()), 459 BuildID.size()); 460 } 461 462 bool LLVMSymbolizer::getOrFindDebugBinary(const ArrayRef<uint8_t> BuildID, 463 std::string &Result) { 464 StringRef BuildIDStr = getBuildIDStr(BuildID); 465 auto I = BuildIDPaths.find(BuildIDStr); 466 if (I != BuildIDPaths.end()) { 467 Result = I->second; 468 return true; 469 } 470 auto recordPath = [&](StringRef Path) { 471 Result = Path.str(); 472 auto InsertResult = BuildIDPaths.insert({BuildIDStr, Result}); 473 assert(InsertResult.second); 474 (void)InsertResult; 475 }; 476 477 Optional<std::string> Path; 478 Path = LocalDIFetcher(Opts.DebugFileDirectory).fetchBuildID(BuildID); 479 if (Path) { 480 recordPath(*Path); 481 return true; 482 } 483 484 // Try caller-provided debug info fetchers. 485 for (const std::unique_ptr<DIFetcher> &Fetcher : DIFetchers) { 486 Path = Fetcher->fetchBuildID(BuildID); 487 if (Path) { 488 recordPath(*Path); 489 return true; 490 } 491 } 492 493 return false; 494 } 495 496 Expected<LLVMSymbolizer::ObjectPair> 497 LLVMSymbolizer::getOrCreateObjectPair(const std::string &Path, 498 const std::string &ArchName) { 499 auto I = ObjectPairForPathArch.find(std::make_pair(Path, ArchName)); 500 if (I != ObjectPairForPathArch.end()) { 501 recordAccess(BinaryForPath.find(Path)->second); 502 return I->second; 503 } 504 505 auto ObjOrErr = getOrCreateObject(Path, ArchName); 506 if (!ObjOrErr) { 507 ObjectPairForPathArch.emplace(std::make_pair(Path, ArchName), 508 ObjectPair(nullptr, nullptr)); 509 return ObjOrErr.takeError(); 510 } 511 512 ObjectFile *Obj = ObjOrErr.get(); 513 assert(Obj != nullptr); 514 ObjectFile *DbgObj = nullptr; 515 516 if (auto MachObj = dyn_cast<const MachOObjectFile>(Obj)) 517 DbgObj = lookUpDsymFile(Path, MachObj, ArchName); 518 else if (auto ELFObj = dyn_cast<const ELFObjectFileBase>(Obj)) 519 DbgObj = lookUpBuildIDObject(Path, ELFObj, ArchName); 520 if (!DbgObj) 521 DbgObj = lookUpDebuglinkObject(Path, Obj, ArchName); 522 if (!DbgObj) 523 DbgObj = Obj; 524 ObjectPair Res = std::make_pair(Obj, DbgObj); 525 std::string DbgObjPath = DbgObj->getFileName().str(); 526 auto Pair = 527 ObjectPairForPathArch.emplace(std::make_pair(Path, ArchName), Res); 528 BinaryForPath.find(DbgObjPath)->second.pushEvictor([this, I = Pair.first]() { 529 ObjectPairForPathArch.erase(I); 530 }); 531 return Res; 532 } 533 534 Expected<ObjectFile *> 535 LLVMSymbolizer::getOrCreateObject(const std::string &Path, 536 const std::string &ArchName) { 537 Binary *Bin; 538 auto Pair = BinaryForPath.emplace(Path, OwningBinary<Binary>()); 539 if (!Pair.second) { 540 Bin = Pair.first->second->getBinary(); 541 recordAccess(Pair.first->second); 542 } else { 543 Expected<OwningBinary<Binary>> BinOrErr = createBinary(Path); 544 if (!BinOrErr) 545 return BinOrErr.takeError(); 546 547 CachedBinary &CachedBin = Pair.first->second; 548 CachedBin = std::move(BinOrErr.get()); 549 CachedBin.pushEvictor([this, I = Pair.first]() { BinaryForPath.erase(I); }); 550 LRUBinaries.push_back(CachedBin); 551 CacheSize += CachedBin.size(); 552 Bin = CachedBin->getBinary(); 553 } 554 555 if (!Bin) 556 return static_cast<ObjectFile *>(nullptr); 557 558 if (MachOUniversalBinary *UB = dyn_cast_or_null<MachOUniversalBinary>(Bin)) { 559 auto I = ObjectForUBPathAndArch.find(std::make_pair(Path, ArchName)); 560 if (I != ObjectForUBPathAndArch.end()) 561 return I->second.get(); 562 563 Expected<std::unique_ptr<ObjectFile>> ObjOrErr = 564 UB->getMachOObjectForArch(ArchName); 565 if (!ObjOrErr) { 566 ObjectForUBPathAndArch.emplace(std::make_pair(Path, ArchName), 567 std::unique_ptr<ObjectFile>()); 568 return ObjOrErr.takeError(); 569 } 570 ObjectFile *Res = ObjOrErr->get(); 571 auto Pair = ObjectForUBPathAndArch.emplace(std::make_pair(Path, ArchName), 572 std::move(ObjOrErr.get())); 573 BinaryForPath.find(Path)->second.pushEvictor( 574 [this, Iter = Pair.first]() { ObjectForUBPathAndArch.erase(Iter); }); 575 return Res; 576 } 577 if (Bin->isObject()) { 578 return cast<ObjectFile>(Bin); 579 } 580 return errorCodeToError(object_error::arch_not_found); 581 } 582 583 Expected<SymbolizableModule *> 584 LLVMSymbolizer::createModuleInfo(const ObjectFile *Obj, 585 std::unique_ptr<DIContext> Context, 586 StringRef ModuleName) { 587 auto InfoOrErr = SymbolizableObjectFile::create(Obj, std::move(Context), 588 Opts.UntagAddresses); 589 std::unique_ptr<SymbolizableModule> SymMod; 590 if (InfoOrErr) 591 SymMod = std::move(*InfoOrErr); 592 auto InsertResult = Modules.insert( 593 std::make_pair(std::string(ModuleName), std::move(SymMod))); 594 assert(InsertResult.second); 595 if (!InfoOrErr) 596 return InfoOrErr.takeError(); 597 return InsertResult.first->second.get(); 598 } 599 600 Expected<SymbolizableModule *> 601 LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) { 602 std::string BinaryName = ModuleName; 603 std::string ArchName = Opts.DefaultArch; 604 size_t ColonPos = ModuleName.find_last_of(':'); 605 // Verify that substring after colon form a valid arch name. 606 if (ColonPos != std::string::npos) { 607 std::string ArchStr = ModuleName.substr(ColonPos + 1); 608 if (Triple(ArchStr).getArch() != Triple::UnknownArch) { 609 BinaryName = ModuleName.substr(0, ColonPos); 610 ArchName = ArchStr; 611 } 612 } 613 614 auto I = Modules.find(ModuleName); 615 if (I != Modules.end()) { 616 recordAccess(BinaryForPath.find(BinaryName)->second); 617 return I->second.get(); 618 } 619 620 auto ObjectsOrErr = getOrCreateObjectPair(BinaryName, ArchName); 621 if (!ObjectsOrErr) { 622 // Failed to find valid object file. 623 Modules.emplace(ModuleName, std::unique_ptr<SymbolizableModule>()); 624 return ObjectsOrErr.takeError(); 625 } 626 ObjectPair Objects = ObjectsOrErr.get(); 627 628 std::unique_ptr<DIContext> Context; 629 // If this is a COFF object containing PDB info, use a PDBContext to 630 // symbolize. Otherwise, use DWARF. 631 if (auto CoffObject = dyn_cast<COFFObjectFile>(Objects.first)) { 632 const codeview::DebugInfo *DebugInfo; 633 StringRef PDBFileName; 634 auto EC = CoffObject->getDebugPDBInfo(DebugInfo, PDBFileName); 635 if (!EC && DebugInfo != nullptr && !PDBFileName.empty()) { 636 using namespace pdb; 637 std::unique_ptr<IPDBSession> Session; 638 639 PDB_ReaderType ReaderType = 640 Opts.UseDIA ? PDB_ReaderType::DIA : PDB_ReaderType::Native; 641 if (auto Err = loadDataForEXE(ReaderType, Objects.first->getFileName(), 642 Session)) { 643 Modules.emplace(ModuleName, std::unique_ptr<SymbolizableModule>()); 644 // Return along the PDB filename to provide more context 645 return createFileError(PDBFileName, std::move(Err)); 646 } 647 Context.reset(new PDBContext(*CoffObject, std::move(Session))); 648 } 649 } 650 if (!Context) 651 Context = DWARFContext::create( 652 *Objects.second, DWARFContext::ProcessDebugRelocations::Process, 653 nullptr, Opts.DWPName); 654 auto ModuleOrErr = 655 createModuleInfo(Objects.first, std::move(Context), ModuleName); 656 if (ModuleOrErr) { 657 auto I = Modules.find(ModuleName); 658 BinaryForPath.find(BinaryName)->second.pushEvictor([this, I]() { 659 Modules.erase(I); 660 }); 661 } 662 return ModuleOrErr; 663 } 664 665 Expected<SymbolizableModule *> 666 LLVMSymbolizer::getOrCreateModuleInfo(const ObjectFile &Obj) { 667 StringRef ObjName = Obj.getFileName(); 668 auto I = Modules.find(ObjName); 669 if (I != Modules.end()) 670 return I->second.get(); 671 672 std::unique_ptr<DIContext> Context = DWARFContext::create(Obj); 673 // FIXME: handle COFF object with PDB info to use PDBContext 674 return createModuleInfo(&Obj, std::move(Context), ObjName); 675 } 676 677 Expected<SymbolizableModule *> 678 LLVMSymbolizer::getOrCreateModuleInfo(ArrayRef<uint8_t> BuildID) { 679 std::string Path; 680 if (!getOrFindDebugBinary(BuildID, Path)) { 681 return createStringError(errc::no_such_file_or_directory, 682 Twine("could not find build ID '") + 683 toHex(BuildID) + "'"); 684 } 685 return getOrCreateModuleInfo(Path); 686 } 687 688 namespace { 689 690 // Undo these various manglings for Win32 extern "C" functions: 691 // cdecl - _foo 692 // stdcall - _foo@12 693 // fastcall - @foo@12 694 // vectorcall - foo@@12 695 // These are all different linkage names for 'foo'. 696 StringRef demanglePE32ExternCFunc(StringRef SymbolName) { 697 // Remove any '_' or '@' prefix. 698 char Front = SymbolName.empty() ? '\0' : SymbolName[0]; 699 if (Front == '_' || Front == '@') 700 SymbolName = SymbolName.drop_front(); 701 702 // Remove any '@[0-9]+' suffix. 703 if (Front != '?') { 704 size_t AtPos = SymbolName.rfind('@'); 705 if (AtPos != StringRef::npos && 706 all_of(drop_begin(SymbolName, AtPos + 1), isDigit)) 707 SymbolName = SymbolName.substr(0, AtPos); 708 } 709 710 // Remove any ending '@' for vectorcall. 711 if (SymbolName.endswith("@")) 712 SymbolName = SymbolName.drop_back(); 713 714 return SymbolName; 715 } 716 717 } // end anonymous namespace 718 719 std::string 720 LLVMSymbolizer::DemangleName(const std::string &Name, 721 const SymbolizableModule *DbiModuleDescriptor) { 722 std::string Result; 723 if (nonMicrosoftDemangle(Name.c_str(), Result)) 724 return Result; 725 726 if (!Name.empty() && Name.front() == '?') { 727 // Only do MSVC C++ demangling on symbols starting with '?'. 728 int status = 0; 729 char *DemangledName = microsoftDemangle( 730 Name.c_str(), nullptr, nullptr, nullptr, &status, 731 MSDemangleFlags(MSDF_NoAccessSpecifier | MSDF_NoCallingConvention | 732 MSDF_NoMemberType | MSDF_NoReturnType)); 733 if (status != 0) 734 return Name; 735 Result = DemangledName; 736 free(DemangledName); 737 return Result; 738 } 739 740 if (DbiModuleDescriptor && DbiModuleDescriptor->isWin32Module()) 741 return std::string(demanglePE32ExternCFunc(Name)); 742 return Name; 743 } 744 745 void LLVMSymbolizer::recordAccess(CachedBinary &Bin) { 746 if (Bin->getBinary()) 747 LRUBinaries.splice(LRUBinaries.end(), LRUBinaries, Bin.getIterator()); 748 } 749 750 void LLVMSymbolizer::pruneCache() { 751 // Evict the LRU binary until the max cache size is reached or there's <= 1 752 // item in the cache. The MRU binary is always kept to avoid thrashing if it's 753 // larger than the cache size. 754 while (CacheSize > Opts.MaxCacheSize && !LRUBinaries.empty() && 755 std::next(LRUBinaries.begin()) != LRUBinaries.end()) { 756 CachedBinary &Bin = LRUBinaries.front(); 757 CacheSize -= Bin.size(); 758 LRUBinaries.pop_front(); 759 Bin.evict(); 760 } 761 } 762 763 void CachedBinary::pushEvictor(std::function<void()> NewEvictor) { 764 if (Evictor) { 765 this->Evictor = [OldEvictor = std::move(this->Evictor), 766 NewEvictor = std::move(NewEvictor)]() { 767 NewEvictor(); 768 OldEvictor(); 769 }; 770 } else { 771 this->Evictor = std::move(NewEvictor); 772 } 773 } 774 775 } // namespace symbolize 776 } // namespace llvm 777