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