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/BTF/BTFContext.h" 17 #include "llvm/DebugInfo/DWARF/DWARFContext.h" 18 #include "llvm/DebugInfo/PDB/PDB.h" 19 #include "llvm/DebugInfo/PDB/PDBContext.h" 20 #include "llvm/DebugInfo/Symbolize/SymbolizableObjectFile.h" 21 #include "llvm/Demangle/Demangle.h" 22 #include "llvm/Object/BuildID.h" 23 #include "llvm/Object/COFF.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/DataExtractor.h" 30 #include "llvm/Support/Errc.h" 31 #include "llvm/Support/FileSystem.h" 32 #include "llvm/Support/MemoryBuffer.h" 33 #include "llvm/Support/Path.h" 34 #include <algorithm> 35 #include <cassert> 36 #include <cstring> 37 38 namespace llvm { 39 namespace codeview { 40 union DebugInfo; 41 } 42 namespace symbolize { 43 44 LLVMSymbolizer::LLVMSymbolizer() = default; 45 46 LLVMSymbolizer::LLVMSymbolizer(const Options &Opts) 47 : Opts(Opts), 48 BIDFetcher(std::make_unique<BuildIDFetcher>(Opts.DebugFileDirectory)) {} 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 } // end anonymous namespace 311 312 ObjectFile *LLVMSymbolizer::lookUpDsymFile(const std::string &ExePath, 313 const MachOObjectFile *MachExeObj, 314 const std::string &ArchName) { 315 // On Darwin we may find DWARF in separate object file in 316 // resource directory. 317 std::vector<std::string> DsymPaths; 318 StringRef Filename = sys::path::filename(ExePath); 319 DsymPaths.push_back( 320 getDarwinDWARFResourceForPath(ExePath, std::string(Filename))); 321 for (const auto &Path : Opts.DsymHints) { 322 DsymPaths.push_back( 323 getDarwinDWARFResourceForPath(Path, std::string(Filename))); 324 } 325 for (const auto &Path : DsymPaths) { 326 auto DbgObjOrErr = getOrCreateObject(Path, ArchName); 327 if (!DbgObjOrErr) { 328 // Ignore errors, the file might not exist. 329 consumeError(DbgObjOrErr.takeError()); 330 continue; 331 } 332 ObjectFile *DbgObj = DbgObjOrErr.get(); 333 if (!DbgObj) 334 continue; 335 const MachOObjectFile *MachDbgObj = dyn_cast<const MachOObjectFile>(DbgObj); 336 if (!MachDbgObj) 337 continue; 338 if (darwinDsymMatchesBinary(MachDbgObj, MachExeObj)) 339 return DbgObj; 340 } 341 return nullptr; 342 } 343 344 ObjectFile *LLVMSymbolizer::lookUpDebuglinkObject(const std::string &Path, 345 const ObjectFile *Obj, 346 const std::string &ArchName) { 347 std::string DebuglinkName; 348 uint32_t CRCHash; 349 std::string DebugBinaryPath; 350 if (!getGNUDebuglinkContents(Obj, DebuglinkName, CRCHash)) 351 return nullptr; 352 if (!findDebugBinary(Path, DebuglinkName, CRCHash, DebugBinaryPath)) 353 return nullptr; 354 auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName); 355 if (!DbgObjOrErr) { 356 // Ignore errors, the file might not exist. 357 consumeError(DbgObjOrErr.takeError()); 358 return nullptr; 359 } 360 return DbgObjOrErr.get(); 361 } 362 363 ObjectFile *LLVMSymbolizer::lookUpBuildIDObject(const std::string &Path, 364 const ELFObjectFileBase *Obj, 365 const std::string &ArchName) { 366 auto BuildID = getBuildID(Obj); 367 if (BuildID.size() < 2) 368 return nullptr; 369 std::string DebugBinaryPath; 370 if (!getOrFindDebugBinary(BuildID, DebugBinaryPath)) 371 return nullptr; 372 auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName); 373 if (!DbgObjOrErr) { 374 consumeError(DbgObjOrErr.takeError()); 375 return nullptr; 376 } 377 return DbgObjOrErr.get(); 378 } 379 380 bool LLVMSymbolizer::findDebugBinary(const std::string &OrigPath, 381 const std::string &DebuglinkName, 382 uint32_t CRCHash, std::string &Result) { 383 SmallString<16> OrigDir(OrigPath); 384 llvm::sys::path::remove_filename(OrigDir); 385 SmallString<16> DebugPath = OrigDir; 386 // Try relative/path/to/original_binary/debuglink_name 387 llvm::sys::path::append(DebugPath, DebuglinkName); 388 if (checkFileCRC(DebugPath, CRCHash)) { 389 Result = std::string(DebugPath.str()); 390 return true; 391 } 392 // Try relative/path/to/original_binary/.debug/debuglink_name 393 DebugPath = OrigDir; 394 llvm::sys::path::append(DebugPath, ".debug", DebuglinkName); 395 if (checkFileCRC(DebugPath, CRCHash)) { 396 Result = std::string(DebugPath.str()); 397 return true; 398 } 399 // Make the path absolute so that lookups will go to 400 // "/usr/lib/debug/full/path/to/debug", not 401 // "/usr/lib/debug/to/debug" 402 llvm::sys::fs::make_absolute(OrigDir); 403 if (!Opts.FallbackDebugPath.empty()) { 404 // Try <FallbackDebugPath>/absolute/path/to/original_binary/debuglink_name 405 DebugPath = Opts.FallbackDebugPath; 406 } else { 407 #if defined(__NetBSD__) 408 // Try /usr/libdata/debug/absolute/path/to/original_binary/debuglink_name 409 DebugPath = "/usr/libdata/debug"; 410 #else 411 // Try /usr/lib/debug/absolute/path/to/original_binary/debuglink_name 412 DebugPath = "/usr/lib/debug"; 413 #endif 414 } 415 llvm::sys::path::append(DebugPath, llvm::sys::path::relative_path(OrigDir), 416 DebuglinkName); 417 if (checkFileCRC(DebugPath, CRCHash)) { 418 Result = std::string(DebugPath.str()); 419 return true; 420 } 421 return false; 422 } 423 424 static StringRef getBuildIDStr(ArrayRef<uint8_t> BuildID) { 425 return StringRef(reinterpret_cast<const char *>(BuildID.data()), 426 BuildID.size()); 427 } 428 429 bool LLVMSymbolizer::getOrFindDebugBinary(const ArrayRef<uint8_t> BuildID, 430 std::string &Result) { 431 StringRef BuildIDStr = getBuildIDStr(BuildID); 432 auto I = BuildIDPaths.find(BuildIDStr); 433 if (I != BuildIDPaths.end()) { 434 Result = I->second; 435 return true; 436 } 437 if (!BIDFetcher) 438 return false; 439 if (std::optional<std::string> Path = BIDFetcher->fetch(BuildID)) { 440 Result = *Path; 441 auto InsertResult = BuildIDPaths.insert({BuildIDStr, Result}); 442 assert(InsertResult.second); 443 (void)InsertResult; 444 return true; 445 } 446 447 return false; 448 } 449 450 Expected<LLVMSymbolizer::ObjectPair> 451 LLVMSymbolizer::getOrCreateObjectPair(const std::string &Path, 452 const std::string &ArchName) { 453 auto I = ObjectPairForPathArch.find(std::make_pair(Path, ArchName)); 454 if (I != ObjectPairForPathArch.end()) { 455 recordAccess(BinaryForPath.find(Path)->second); 456 return I->second; 457 } 458 459 auto ObjOrErr = getOrCreateObject(Path, ArchName); 460 if (!ObjOrErr) { 461 ObjectPairForPathArch.emplace(std::make_pair(Path, ArchName), 462 ObjectPair(nullptr, nullptr)); 463 return ObjOrErr.takeError(); 464 } 465 466 ObjectFile *Obj = ObjOrErr.get(); 467 assert(Obj != nullptr); 468 ObjectFile *DbgObj = nullptr; 469 470 if (auto MachObj = dyn_cast<const MachOObjectFile>(Obj)) 471 DbgObj = lookUpDsymFile(Path, MachObj, ArchName); 472 else if (auto ELFObj = dyn_cast<const ELFObjectFileBase>(Obj)) 473 DbgObj = lookUpBuildIDObject(Path, ELFObj, ArchName); 474 if (!DbgObj) 475 DbgObj = lookUpDebuglinkObject(Path, Obj, ArchName); 476 if (!DbgObj) 477 DbgObj = Obj; 478 ObjectPair Res = std::make_pair(Obj, DbgObj); 479 std::string DbgObjPath = DbgObj->getFileName().str(); 480 auto Pair = 481 ObjectPairForPathArch.emplace(std::make_pair(Path, ArchName), Res); 482 BinaryForPath.find(DbgObjPath)->second.pushEvictor([this, I = Pair.first]() { 483 ObjectPairForPathArch.erase(I); 484 }); 485 return Res; 486 } 487 488 Expected<ObjectFile *> 489 LLVMSymbolizer::getOrCreateObject(const std::string &Path, 490 const std::string &ArchName) { 491 Binary *Bin; 492 auto Pair = BinaryForPath.emplace(Path, OwningBinary<Binary>()); 493 if (!Pair.second) { 494 Bin = Pair.first->second->getBinary(); 495 recordAccess(Pair.first->second); 496 } else { 497 Expected<OwningBinary<Binary>> BinOrErr = createBinary(Path); 498 if (!BinOrErr) 499 return BinOrErr.takeError(); 500 501 CachedBinary &CachedBin = Pair.first->second; 502 CachedBin = std::move(BinOrErr.get()); 503 CachedBin.pushEvictor([this, I = Pair.first]() { BinaryForPath.erase(I); }); 504 LRUBinaries.push_back(CachedBin); 505 CacheSize += CachedBin.size(); 506 Bin = CachedBin->getBinary(); 507 } 508 509 if (!Bin) 510 return static_cast<ObjectFile *>(nullptr); 511 512 if (MachOUniversalBinary *UB = dyn_cast_or_null<MachOUniversalBinary>(Bin)) { 513 auto I = ObjectForUBPathAndArch.find(std::make_pair(Path, ArchName)); 514 if (I != ObjectForUBPathAndArch.end()) 515 return I->second.get(); 516 517 Expected<std::unique_ptr<ObjectFile>> ObjOrErr = 518 UB->getMachOObjectForArch(ArchName); 519 if (!ObjOrErr) { 520 ObjectForUBPathAndArch.emplace(std::make_pair(Path, ArchName), 521 std::unique_ptr<ObjectFile>()); 522 return ObjOrErr.takeError(); 523 } 524 ObjectFile *Res = ObjOrErr->get(); 525 auto Pair = ObjectForUBPathAndArch.emplace(std::make_pair(Path, ArchName), 526 std::move(ObjOrErr.get())); 527 BinaryForPath.find(Path)->second.pushEvictor( 528 [this, Iter = Pair.first]() { ObjectForUBPathAndArch.erase(Iter); }); 529 return Res; 530 } 531 if (Bin->isObject()) { 532 return cast<ObjectFile>(Bin); 533 } 534 return errorCodeToError(object_error::arch_not_found); 535 } 536 537 Expected<SymbolizableModule *> 538 LLVMSymbolizer::createModuleInfo(const ObjectFile *Obj, 539 std::unique_ptr<DIContext> Context, 540 StringRef ModuleName) { 541 auto InfoOrErr = SymbolizableObjectFile::create(Obj, std::move(Context), 542 Opts.UntagAddresses); 543 std::unique_ptr<SymbolizableModule> SymMod; 544 if (InfoOrErr) 545 SymMod = std::move(*InfoOrErr); 546 auto InsertResult = Modules.insert( 547 std::make_pair(std::string(ModuleName), std::move(SymMod))); 548 assert(InsertResult.second); 549 if (!InfoOrErr) 550 return InfoOrErr.takeError(); 551 return InsertResult.first->second.get(); 552 } 553 554 Expected<SymbolizableModule *> 555 LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) { 556 std::string BinaryName = ModuleName; 557 std::string ArchName = Opts.DefaultArch; 558 size_t ColonPos = ModuleName.find_last_of(':'); 559 // Verify that substring after colon form a valid arch name. 560 if (ColonPos != std::string::npos) { 561 std::string ArchStr = ModuleName.substr(ColonPos + 1); 562 if (Triple(ArchStr).getArch() != Triple::UnknownArch) { 563 BinaryName = ModuleName.substr(0, ColonPos); 564 ArchName = ArchStr; 565 } 566 } 567 568 auto I = Modules.find(ModuleName); 569 if (I != Modules.end()) { 570 recordAccess(BinaryForPath.find(BinaryName)->second); 571 return I->second.get(); 572 } 573 574 auto ObjectsOrErr = getOrCreateObjectPair(BinaryName, ArchName); 575 if (!ObjectsOrErr) { 576 // Failed to find valid object file. 577 Modules.emplace(ModuleName, std::unique_ptr<SymbolizableModule>()); 578 return ObjectsOrErr.takeError(); 579 } 580 ObjectPair Objects = ObjectsOrErr.get(); 581 582 std::unique_ptr<DIContext> Context; 583 // If this is a COFF object containing PDB info, use a PDBContext to 584 // symbolize. Otherwise, use DWARF. 585 if (auto CoffObject = dyn_cast<COFFObjectFile>(Objects.first)) { 586 const codeview::DebugInfo *DebugInfo; 587 StringRef PDBFileName; 588 auto EC = CoffObject->getDebugPDBInfo(DebugInfo, PDBFileName); 589 if (!EC && DebugInfo != nullptr && !PDBFileName.empty()) { 590 #if 0 591 using namespace pdb; 592 std::unique_ptr<IPDBSession> Session; 593 594 PDB_ReaderType ReaderType = 595 Opts.UseDIA ? PDB_ReaderType::DIA : PDB_ReaderType::Native; 596 if (auto Err = loadDataForEXE(ReaderType, Objects.first->getFileName(), 597 Session)) { 598 Modules.emplace(ModuleName, std::unique_ptr<SymbolizableModule>()); 599 // Return along the PDB filename to provide more context 600 return createFileError(PDBFileName, std::move(Err)); 601 } 602 Context.reset(new PDBContext(*CoffObject, std::move(Session))); 603 #else 604 return make_error<StringError>( 605 "PDB support not compiled in", 606 std::make_error_code(std::errc::not_supported)); 607 #endif 608 } 609 } 610 if (!Context) 611 Context = DWARFContext::create( 612 *Objects.second, DWARFContext::ProcessDebugRelocations::Process, 613 nullptr, Opts.DWPName); 614 auto ModuleOrErr = 615 createModuleInfo(Objects.first, std::move(Context), ModuleName); 616 if (ModuleOrErr) { 617 auto I = Modules.find(ModuleName); 618 BinaryForPath.find(BinaryName)->second.pushEvictor([this, I]() { 619 Modules.erase(I); 620 }); 621 } 622 return ModuleOrErr; 623 } 624 625 // For BPF programs .BTF.ext section contains line numbers information, 626 // use it if regular DWARF is not available (e.g. for stripped binary). 627 static bool useBTFContext(const ObjectFile &Obj) { 628 return Obj.makeTriple().isBPF() && !Obj.hasDebugInfo() && 629 BTFParser::hasBTFSections(Obj); 630 } 631 632 Expected<SymbolizableModule *> 633 LLVMSymbolizer::getOrCreateModuleInfo(const ObjectFile &Obj) { 634 StringRef ObjName = Obj.getFileName(); 635 auto I = Modules.find(ObjName); 636 if (I != Modules.end()) 637 return I->second.get(); 638 639 std::unique_ptr<DIContext> Context; 640 if (useBTFContext(Obj)) 641 Context = BTFContext::create(Obj); 642 else 643 Context = DWARFContext::create(Obj); 644 // FIXME: handle COFF object with PDB info to use PDBContext 645 return createModuleInfo(&Obj, std::move(Context), ObjName); 646 } 647 648 Expected<SymbolizableModule *> 649 LLVMSymbolizer::getOrCreateModuleInfo(ArrayRef<uint8_t> BuildID) { 650 std::string Path; 651 if (!getOrFindDebugBinary(BuildID, Path)) { 652 return createStringError(errc::no_such_file_or_directory, 653 "could not find build ID"); 654 } 655 return getOrCreateModuleInfo(Path); 656 } 657 658 namespace { 659 660 // Undo these various manglings for Win32 extern "C" functions: 661 // cdecl - _foo 662 // stdcall - _foo@12 663 // fastcall - @foo@12 664 // vectorcall - foo@@12 665 // These are all different linkage names for 'foo'. 666 StringRef demanglePE32ExternCFunc(StringRef SymbolName) { 667 char Front = SymbolName.empty() ? '\0' : SymbolName[0]; 668 669 // Remove any '@[0-9]+' suffix. 670 bool HasAtNumSuffix = false; 671 if (Front != '?') { 672 size_t AtPos = SymbolName.rfind('@'); 673 if (AtPos != StringRef::npos && 674 all_of(drop_begin(SymbolName, AtPos + 1), isDigit)) { 675 SymbolName = SymbolName.substr(0, AtPos); 676 HasAtNumSuffix = true; 677 } 678 } 679 680 // Remove any ending '@' for vectorcall. 681 bool IsVectorCall = false; 682 if (HasAtNumSuffix && SymbolName.endswith("@")) { 683 SymbolName = SymbolName.drop_back(); 684 IsVectorCall = true; 685 } 686 687 // If not vectorcall, remove any '_' or '@' prefix. 688 if (!IsVectorCall && (Front == '_' || Front == '@')) 689 SymbolName = SymbolName.drop_front(); 690 691 return SymbolName; 692 } 693 694 } // end anonymous namespace 695 696 std::string 697 LLVMSymbolizer::DemangleName(const std::string &Name, 698 const SymbolizableModule *DbiModuleDescriptor) { 699 std::string Result; 700 if (nonMicrosoftDemangle(Name, Result)) 701 return Result; 702 703 if (!Name.empty() && Name.front() == '?') { 704 // Only do MSVC C++ demangling on symbols starting with '?'. 705 int status = 0; 706 char *DemangledName = microsoftDemangle( 707 Name, nullptr, &status, 708 MSDemangleFlags(MSDF_NoAccessSpecifier | MSDF_NoCallingConvention | 709 MSDF_NoMemberType | MSDF_NoReturnType)); 710 if (status != 0) 711 return Name; 712 Result = DemangledName; 713 free(DemangledName); 714 return Result; 715 } 716 717 if (DbiModuleDescriptor && DbiModuleDescriptor->isWin32Module()) { 718 std::string DemangledCName(demanglePE32ExternCFunc(Name)); 719 // On i386 Windows, the C name mangling for different calling conventions 720 // may also be applied on top of the Itanium or Rust name mangling. 721 if (nonMicrosoftDemangle(DemangledCName, Result)) 722 return Result; 723 return DemangledCName; 724 } 725 return Name; 726 } 727 728 void LLVMSymbolizer::recordAccess(CachedBinary &Bin) { 729 if (Bin->getBinary()) 730 LRUBinaries.splice(LRUBinaries.end(), LRUBinaries, Bin.getIterator()); 731 } 732 733 void LLVMSymbolizer::pruneCache() { 734 // Evict the LRU binary until the max cache size is reached or there's <= 1 735 // item in the cache. The MRU binary is always kept to avoid thrashing if it's 736 // larger than the cache size. 737 while (CacheSize > Opts.MaxCacheSize && !LRUBinaries.empty() && 738 std::next(LRUBinaries.begin()) != LRUBinaries.end()) { 739 CachedBinary &Bin = LRUBinaries.front(); 740 CacheSize -= Bin.size(); 741 LRUBinaries.pop_front(); 742 Bin.evict(); 743 } 744 } 745 746 void CachedBinary::pushEvictor(std::function<void()> NewEvictor) { 747 if (Evictor) { 748 this->Evictor = [OldEvictor = std::move(this->Evictor), 749 NewEvictor = std::move(NewEvictor)]() { 750 NewEvictor(); 751 OldEvictor(); 752 }; 753 } else { 754 this->Evictor = std::move(NewEvictor); 755 } 756 } 757 758 } // namespace symbolize 759 } // namespace llvm 760