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