1 //===-- LLVMSymbolize.cpp -------------------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // Implementation for LLVM symbolization library. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/DebugInfo/Symbolize/Symbolize.h" 15 16 #include "llvm/ADT/STLExtras.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/Object/ELFObjectFile.h" 22 #include "llvm/Object/MachO.h" 23 #include "llvm/Object/SymbolSize.h" 24 #include "llvm/Support/COFF.h" 25 #include "llvm/Support/Casting.h" 26 #include "llvm/Support/Compression.h" 27 #include "llvm/Support/DataExtractor.h" 28 #include "llvm/Support/Errc.h" 29 #include "llvm/Support/FileSystem.h" 30 #include "llvm/Support/MemoryBuffer.h" 31 #include "llvm/Support/Path.h" 32 #include <sstream> 33 #include <stdlib.h> 34 35 #if defined(_MSC_VER) 36 #include <Windows.h> 37 #include <DbgHelp.h> 38 #pragma comment(lib, "dbghelp.lib") 39 40 // Windows.h conflicts with our COFF header definitions. 41 #ifdef IMAGE_FILE_MACHINE_I386 42 #undef IMAGE_FILE_MACHINE_I386 43 #endif 44 #endif 45 46 namespace llvm { 47 namespace symbolize { 48 49 // FIXME: Move this to llvm-symbolizer tool. 50 static bool error(std::error_code ec) { 51 if (!ec) 52 return false; 53 errs() << "LLVMSymbolizer: error reading file: " << ec.message() << ".\n"; 54 return true; 55 } 56 57 static DILineInfoSpecifier 58 getDILineInfoSpecifier(FunctionNameKind FNKind) { 59 return DILineInfoSpecifier( 60 DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FNKind); 61 } 62 63 ModuleInfo::ModuleInfo(ObjectFile *Obj, std::unique_ptr<DIContext> DICtx) 64 : Module(Obj), DebugInfoContext(std::move(DICtx)) { 65 std::unique_ptr<DataExtractor> OpdExtractor; 66 uint64_t OpdAddress = 0; 67 // Find the .opd (function descriptor) section if any, for big-endian 68 // PowerPC64 ELF. 69 if (Module->getArch() == Triple::ppc64) { 70 for (section_iterator Section : Module->sections()) { 71 StringRef Name; 72 if (!error(Section->getName(Name)) && Name == ".opd") { 73 StringRef Data; 74 if (!error(Section->getContents(Data))) { 75 OpdExtractor.reset(new DataExtractor(Data, Module->isLittleEndian(), 76 Module->getBytesInAddress())); 77 OpdAddress = Section->getAddress(); 78 } 79 break; 80 } 81 } 82 } 83 std::vector<std::pair<SymbolRef, uint64_t>> Symbols = 84 computeSymbolSizes(*Module); 85 for (auto &P : Symbols) 86 addSymbol(P.first, P.second, OpdExtractor.get(), OpdAddress); 87 88 // If this is a COFF object and we didn't find any symbols, try the export 89 // table. 90 if (Symbols.empty()) { 91 if (auto *CoffObj = dyn_cast<COFFObjectFile>(Obj)) 92 addCoffExportSymbols(CoffObj); 93 } 94 } 95 96 namespace { 97 struct OffsetNamePair { 98 uint32_t Offset; 99 StringRef Name; 100 bool operator<(const OffsetNamePair &R) const { 101 return Offset < R.Offset; 102 } 103 }; 104 } 105 106 void ModuleInfo::addCoffExportSymbols(const COFFObjectFile *CoffObj) { 107 // Get all export names and offsets. 108 std::vector<OffsetNamePair> ExportSyms; 109 for (const ExportDirectoryEntryRef &Ref : CoffObj->export_directories()) { 110 StringRef Name; 111 uint32_t Offset; 112 if (error(Ref.getSymbolName(Name)) || error(Ref.getExportRVA(Offset))) 113 return; 114 ExportSyms.push_back(OffsetNamePair{Offset, Name}); 115 } 116 if (ExportSyms.empty()) 117 return; 118 119 // Sort by ascending offset. 120 array_pod_sort(ExportSyms.begin(), ExportSyms.end()); 121 122 // Approximate the symbol sizes by assuming they run to the next symbol. 123 // FIXME: This assumes all exports are functions. 124 uint64_t ImageBase = CoffObj->getImageBase(); 125 for (auto I = ExportSyms.begin(), E = ExportSyms.end(); I != E; ++I) { 126 OffsetNamePair &Export = *I; 127 // FIXME: The last export has a one byte size now. 128 uint32_t NextOffset = I != E ? I->Offset : Export.Offset + 1; 129 uint64_t SymbolStart = ImageBase + Export.Offset; 130 uint64_t SymbolSize = NextOffset - Export.Offset; 131 SymbolDesc SD = {SymbolStart, SymbolSize}; 132 Functions.insert(std::make_pair(SD, Export.Name)); 133 } 134 } 135 136 void ModuleInfo::addSymbol(const SymbolRef &Symbol, uint64_t SymbolSize, 137 DataExtractor *OpdExtractor, uint64_t OpdAddress) { 138 SymbolRef::Type SymbolType = Symbol.getType(); 139 if (SymbolType != SymbolRef::ST_Function && SymbolType != SymbolRef::ST_Data) 140 return; 141 ErrorOr<uint64_t> SymbolAddressOrErr = Symbol.getAddress(); 142 if (error(SymbolAddressOrErr.getError())) 143 return; 144 uint64_t SymbolAddress = *SymbolAddressOrErr; 145 if (OpdExtractor) { 146 // For big-endian PowerPC64 ELF, symbols in the .opd section refer to 147 // function descriptors. The first word of the descriptor is a pointer to 148 // the function's code. 149 // For the purposes of symbolization, pretend the symbol's address is that 150 // of the function's code, not the descriptor. 151 uint64_t OpdOffset = SymbolAddress - OpdAddress; 152 uint32_t OpdOffset32 = OpdOffset; 153 if (OpdOffset == OpdOffset32 && 154 OpdExtractor->isValidOffsetForAddress(OpdOffset32)) 155 SymbolAddress = OpdExtractor->getAddress(&OpdOffset32); 156 } 157 ErrorOr<StringRef> SymbolNameOrErr = Symbol.getName(); 158 if (error(SymbolNameOrErr.getError())) 159 return; 160 StringRef SymbolName = *SymbolNameOrErr; 161 // Mach-O symbol table names have leading underscore, skip it. 162 if (Module->isMachO() && SymbolName.size() > 0 && SymbolName[0] == '_') 163 SymbolName = SymbolName.drop_front(); 164 // FIXME: If a function has alias, there are two entries in symbol table 165 // with same address size. Make sure we choose the correct one. 166 auto &M = SymbolType == SymbolRef::ST_Function ? Functions : Objects; 167 SymbolDesc SD = { SymbolAddress, SymbolSize }; 168 M.insert(std::make_pair(SD, SymbolName)); 169 } 170 171 // Return true if this is a 32-bit x86 PE COFF module. 172 bool ModuleInfo::isWin32Module() const { 173 auto *CoffObject = dyn_cast<COFFObjectFile>(Module); 174 return CoffObject && CoffObject->getMachine() == COFF::IMAGE_FILE_MACHINE_I386; 175 } 176 177 uint64_t ModuleInfo::getModulePreferredBase() const { 178 if (auto *CoffObject = dyn_cast<COFFObjectFile>(Module)) 179 return CoffObject->getImageBase(); 180 return 0; 181 } 182 183 bool ModuleInfo::getNameFromSymbolTable(SymbolRef::Type Type, uint64_t Address, 184 std::string &Name, uint64_t &Addr, 185 uint64_t &Size) const { 186 const auto &SymbolMap = Type == SymbolRef::ST_Function ? Functions : Objects; 187 if (SymbolMap.empty()) 188 return false; 189 SymbolDesc SD = { Address, Address }; 190 auto SymbolIterator = SymbolMap.upper_bound(SD); 191 if (SymbolIterator == SymbolMap.begin()) 192 return false; 193 --SymbolIterator; 194 if (SymbolIterator->first.Size != 0 && 195 SymbolIterator->first.Addr + SymbolIterator->first.Size <= Address) 196 return false; 197 Name = SymbolIterator->second.str(); 198 Addr = SymbolIterator->first.Addr; 199 Size = SymbolIterator->first.Size; 200 return true; 201 } 202 203 DILineInfo ModuleInfo::symbolizeCode(uint64_t ModuleOffset, 204 FunctionNameKind FNKind, 205 bool UseSymbolTable) const { 206 DILineInfo LineInfo; 207 if (DebugInfoContext) { 208 LineInfo = DebugInfoContext->getLineInfoForAddress( 209 ModuleOffset, getDILineInfoSpecifier(FNKind)); 210 } 211 // Override function name from symbol table if necessary. 212 if (FNKind == FunctionNameKind::LinkageName && UseSymbolTable) { 213 std::string FunctionName; 214 uint64_t Start, Size; 215 if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset, 216 FunctionName, Start, Size)) { 217 LineInfo.FunctionName = FunctionName; 218 } 219 } 220 return LineInfo; 221 } 222 223 DIInliningInfo ModuleInfo::symbolizeInlinedCode(uint64_t ModuleOffset, 224 FunctionNameKind FNKind, 225 bool UseSymbolTable) const { 226 DIInliningInfo InlinedContext; 227 228 if (DebugInfoContext) { 229 InlinedContext = DebugInfoContext->getInliningInfoForAddress( 230 ModuleOffset, getDILineInfoSpecifier(FNKind)); 231 } 232 // Make sure there is at least one frame in context. 233 if (InlinedContext.getNumberOfFrames() == 0) { 234 InlinedContext.addFrame(DILineInfo()); 235 } 236 // Override the function name in lower frame with name from symbol table. 237 if (FNKind == FunctionNameKind::LinkageName && UseSymbolTable) { 238 DIInliningInfo PatchedInlinedContext; 239 for (uint32_t i = 0, n = InlinedContext.getNumberOfFrames(); i < n; i++) { 240 DILineInfo LineInfo = InlinedContext.getFrame(i); 241 if (i == n - 1) { 242 std::string FunctionName; 243 uint64_t Start, Size; 244 if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset, 245 FunctionName, Start, Size)) { 246 LineInfo.FunctionName = FunctionName; 247 } 248 } 249 PatchedInlinedContext.addFrame(LineInfo); 250 } 251 InlinedContext = PatchedInlinedContext; 252 } 253 return InlinedContext; 254 } 255 256 bool ModuleInfo::symbolizeData(uint64_t ModuleOffset, std::string &Name, 257 uint64_t &Start, uint64_t &Size) const { 258 return getNameFromSymbolTable(SymbolRef::ST_Data, ModuleOffset, Name, Start, 259 Size); 260 } 261 262 const char LLVMSymbolizer::kBadString[] = "??"; 263 264 std::string LLVMSymbolizer::symbolizeCode(const std::string &ModuleName, 265 uint64_t ModuleOffset) { 266 ModuleInfo *Info = getOrCreateModuleInfo(ModuleName); 267 if (!Info) 268 return printDILineInfo(DILineInfo(), Info); 269 270 // If the user is giving us relative addresses, add the preferred base of the 271 // object to the offset before we do the query. It's what DIContext expects. 272 if (Opts.RelativeAddresses) 273 ModuleOffset += Info->getModulePreferredBase(); 274 275 if (Opts.PrintInlining) { 276 DIInliningInfo InlinedContext = Info->symbolizeInlinedCode( 277 ModuleOffset, Opts.PrintFunctions, Opts.UseSymbolTable); 278 uint32_t FramesNum = InlinedContext.getNumberOfFrames(); 279 assert(FramesNum > 0); 280 std::string Result; 281 for (uint32_t i = 0; i < FramesNum; i++) { 282 DILineInfo LineInfo = InlinedContext.getFrame(i); 283 Result += printDILineInfo(LineInfo, Info); 284 } 285 return Result; 286 } 287 DILineInfo LineInfo = Info->symbolizeCode(ModuleOffset, Opts.PrintFunctions, 288 Opts.UseSymbolTable); 289 return printDILineInfo(LineInfo, Info); 290 } 291 292 std::string LLVMSymbolizer::symbolizeData(const std::string &ModuleName, 293 uint64_t ModuleOffset) { 294 std::string Name = kBadString; 295 uint64_t Start = 0; 296 uint64_t Size = 0; 297 if (Opts.UseSymbolTable) { 298 if (ModuleInfo *Info = getOrCreateModuleInfo(ModuleName)) { 299 // If the user is giving us relative addresses, add the preferred base of the 300 // object to the offset before we do the query. It's what DIContext expects. 301 if (Opts.RelativeAddresses) 302 ModuleOffset += Info->getModulePreferredBase(); 303 if (Info->symbolizeData(ModuleOffset, Name, Start, Size) && Opts.Demangle) 304 Name = DemangleName(Name, Info); 305 } 306 } 307 std::stringstream ss; 308 ss << Name << "\n" << Start << " " << Size << "\n"; 309 return ss.str(); 310 } 311 312 void LLVMSymbolizer::flush() { 313 Modules.clear(); 314 ObjectPairForPathArch.clear(); 315 ObjectFileForArch.clear(); 316 } 317 318 // For Path="/path/to/foo" and Basename="foo" assume that debug info is in 319 // /path/to/foo.dSYM/Contents/Resources/DWARF/foo. 320 // For Path="/path/to/bar.dSYM" and Basename="foo" assume that debug info is in 321 // /path/to/bar.dSYM/Contents/Resources/DWARF/foo. 322 static 323 std::string getDarwinDWARFResourceForPath( 324 const std::string &Path, const std::string &Basename) { 325 SmallString<16> ResourceName = StringRef(Path); 326 if (sys::path::extension(Path) != ".dSYM") { 327 ResourceName += ".dSYM"; 328 } 329 sys::path::append(ResourceName, "Contents", "Resources", "DWARF"); 330 sys::path::append(ResourceName, Basename); 331 return ResourceName.str(); 332 } 333 334 static bool checkFileCRC(StringRef Path, uint32_t CRCHash) { 335 ErrorOr<std::unique_ptr<MemoryBuffer>> MB = 336 MemoryBuffer::getFileOrSTDIN(Path); 337 if (!MB) 338 return false; 339 return !zlib::isAvailable() || CRCHash == zlib::crc32(MB.get()->getBuffer()); 340 } 341 342 static bool findDebugBinary(const std::string &OrigPath, 343 const std::string &DebuglinkName, uint32_t CRCHash, 344 std::string &Result) { 345 std::string OrigRealPath = OrigPath; 346 #if defined(HAVE_REALPATH) 347 if (char *RP = realpath(OrigPath.c_str(), nullptr)) { 348 OrigRealPath = RP; 349 free(RP); 350 } 351 #endif 352 SmallString<16> OrigDir(OrigRealPath); 353 llvm::sys::path::remove_filename(OrigDir); 354 SmallString<16> DebugPath = OrigDir; 355 // Try /path/to/original_binary/debuglink_name 356 llvm::sys::path::append(DebugPath, DebuglinkName); 357 if (checkFileCRC(DebugPath, CRCHash)) { 358 Result = DebugPath.str(); 359 return true; 360 } 361 // Try /path/to/original_binary/.debug/debuglink_name 362 DebugPath = OrigRealPath; 363 llvm::sys::path::append(DebugPath, ".debug", DebuglinkName); 364 if (checkFileCRC(DebugPath, CRCHash)) { 365 Result = DebugPath.str(); 366 return true; 367 } 368 // Try /usr/lib/debug/path/to/original_binary/debuglink_name 369 DebugPath = "/usr/lib/debug"; 370 llvm::sys::path::append(DebugPath, llvm::sys::path::relative_path(OrigDir), 371 DebuglinkName); 372 if (checkFileCRC(DebugPath, CRCHash)) { 373 Result = DebugPath.str(); 374 return true; 375 } 376 return false; 377 } 378 379 static bool getGNUDebuglinkContents(const ObjectFile *Obj, std::string &DebugName, 380 uint32_t &CRCHash) { 381 if (!Obj) 382 return false; 383 for (const SectionRef &Section : Obj->sections()) { 384 StringRef Name; 385 Section.getName(Name); 386 Name = Name.substr(Name.find_first_not_of("._")); 387 if (Name == "gnu_debuglink") { 388 StringRef Data; 389 Section.getContents(Data); 390 DataExtractor DE(Data, Obj->isLittleEndian(), 0); 391 uint32_t Offset = 0; 392 if (const char *DebugNameStr = DE.getCStr(&Offset)) { 393 // 4-byte align the offset. 394 Offset = (Offset + 3) & ~0x3; 395 if (DE.isValidOffsetForDataOfSize(Offset, 4)) { 396 DebugName = DebugNameStr; 397 CRCHash = DE.getU32(&Offset); 398 return true; 399 } 400 } 401 break; 402 } 403 } 404 return false; 405 } 406 407 static 408 bool darwinDsymMatchesBinary(const MachOObjectFile *DbgObj, 409 const MachOObjectFile *Obj) { 410 ArrayRef<uint8_t> dbg_uuid = DbgObj->getUuid(); 411 ArrayRef<uint8_t> bin_uuid = Obj->getUuid(); 412 if (dbg_uuid.empty() || bin_uuid.empty()) 413 return false; 414 return !memcmp(dbg_uuid.data(), bin_uuid.data(), dbg_uuid.size()); 415 } 416 417 ObjectFile *LLVMSymbolizer::lookUpDsymFile(const std::string &ExePath, 418 const MachOObjectFile *MachExeObj, const std::string &ArchName) { 419 // On Darwin we may find DWARF in separate object file in 420 // resource directory. 421 std::vector<std::string> DsymPaths; 422 StringRef Filename = sys::path::filename(ExePath); 423 DsymPaths.push_back(getDarwinDWARFResourceForPath(ExePath, Filename)); 424 for (const auto &Path : Opts.DsymHints) { 425 DsymPaths.push_back(getDarwinDWARFResourceForPath(Path, Filename)); 426 } 427 for (const auto &path : DsymPaths) { 428 ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(path); 429 std::error_code EC = BinaryOrErr.getError(); 430 if (EC != errc::no_such_file_or_directory && !error(EC)) { 431 OwningBinary<Binary> B = std::move(BinaryOrErr.get()); 432 ObjectFile *DbgObj = 433 getObjectFileFromBinary(B.getBinary(), ArchName); 434 const MachOObjectFile *MachDbgObj = 435 dyn_cast<const MachOObjectFile>(DbgObj); 436 if (!MachDbgObj) continue; 437 if (darwinDsymMatchesBinary(MachDbgObj, MachExeObj)) { 438 addOwningBinary(std::move(B)); 439 return DbgObj; 440 } 441 } 442 } 443 return nullptr; 444 } 445 446 LLVMSymbolizer::ObjectPair 447 LLVMSymbolizer::getOrCreateObjects(const std::string &Path, 448 const std::string &ArchName) { 449 const auto &I = ObjectPairForPathArch.find(std::make_pair(Path, ArchName)); 450 if (I != ObjectPairForPathArch.end()) 451 return I->second; 452 ObjectFile *Obj = nullptr; 453 ObjectFile *DbgObj = nullptr; 454 ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(Path); 455 if (!error(BinaryOrErr.getError())) { 456 OwningBinary<Binary> &B = BinaryOrErr.get(); 457 Obj = getObjectFileFromBinary(B.getBinary(), ArchName); 458 if (!Obj) { 459 ObjectPair Res = std::make_pair(nullptr, nullptr); 460 ObjectPairForPathArch[std::make_pair(Path, ArchName)] = Res; 461 return Res; 462 } 463 addOwningBinary(std::move(B)); 464 if (auto MachObj = dyn_cast<const MachOObjectFile>(Obj)) 465 DbgObj = lookUpDsymFile(Path, MachObj, ArchName); 466 // Try to locate the debug binary using .gnu_debuglink section. 467 if (!DbgObj) { 468 std::string DebuglinkName; 469 uint32_t CRCHash; 470 std::string DebugBinaryPath; 471 if (getGNUDebuglinkContents(Obj, DebuglinkName, CRCHash) && 472 findDebugBinary(Path, DebuglinkName, CRCHash, DebugBinaryPath)) { 473 BinaryOrErr = createBinary(DebugBinaryPath); 474 if (!error(BinaryOrErr.getError())) { 475 OwningBinary<Binary> B = std::move(BinaryOrErr.get()); 476 DbgObj = getObjectFileFromBinary(B.getBinary(), ArchName); 477 addOwningBinary(std::move(B)); 478 } 479 } 480 } 481 } 482 if (!DbgObj) 483 DbgObj = Obj; 484 ObjectPair Res = std::make_pair(Obj, DbgObj); 485 ObjectPairForPathArch[std::make_pair(Path, ArchName)] = Res; 486 return Res; 487 } 488 489 ObjectFile * 490 LLVMSymbolizer::getObjectFileFromBinary(Binary *Bin, 491 const std::string &ArchName) { 492 if (!Bin) 493 return nullptr; 494 ObjectFile *Res = nullptr; 495 if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(Bin)) { 496 const auto &I = ObjectFileForArch.find( 497 std::make_pair(UB, ArchName)); 498 if (I != ObjectFileForArch.end()) 499 return I->second; 500 ErrorOr<std::unique_ptr<ObjectFile>> ParsedObj = 501 UB->getObjectForArch(ArchName); 502 if (ParsedObj) { 503 Res = ParsedObj.get().get(); 504 ParsedBinariesAndObjects.push_back(std::move(ParsedObj.get())); 505 } 506 ObjectFileForArch[std::make_pair(UB, ArchName)] = Res; 507 } else if (Bin->isObject()) { 508 Res = cast<ObjectFile>(Bin); 509 } 510 return Res; 511 } 512 513 ModuleInfo * 514 LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) { 515 const auto &I = Modules.find(ModuleName); 516 if (I != Modules.end()) 517 return I->second.get(); 518 std::string BinaryName = ModuleName; 519 std::string ArchName = Opts.DefaultArch; 520 size_t ColonPos = ModuleName.find_last_of(':'); 521 // Verify that substring after colon form a valid arch name. 522 if (ColonPos != std::string::npos) { 523 std::string ArchStr = ModuleName.substr(ColonPos + 1); 524 if (Triple(ArchStr).getArch() != Triple::UnknownArch) { 525 BinaryName = ModuleName.substr(0, ColonPos); 526 ArchName = ArchStr; 527 } 528 } 529 ObjectPair Objects = getOrCreateObjects(BinaryName, ArchName); 530 531 if (!Objects.first) { 532 // Failed to find valid object file. 533 Modules.insert( 534 std::make_pair(ModuleName, std::unique_ptr<ModuleInfo>(nullptr))); 535 return nullptr; 536 } 537 std::unique_ptr<DIContext> Context; 538 if (auto CoffObject = dyn_cast<COFFObjectFile>(Objects.first)) { 539 // If this is a COFF object, assume it contains PDB debug information. If 540 // we don't find any we will fall back to the DWARF case. 541 std::unique_ptr<IPDBSession> Session; 542 PDB_ErrorCode Error = loadDataForEXE(PDB_ReaderType::DIA, 543 Objects.first->getFileName(), Session); 544 if (Error == PDB_ErrorCode::Success) { 545 Context.reset(new PDBContext(*CoffObject, std::move(Session))); 546 } 547 } 548 if (!Context) 549 Context.reset(new DWARFContextInMemory(*Objects.second)); 550 assert(Context); 551 auto Info = llvm::make_unique<ModuleInfo>(Objects.first, std::move(Context)); 552 ModuleInfo *Res = Info.get(); 553 Modules.insert(std::make_pair(ModuleName, std::move(Info))); 554 return Res; 555 } 556 557 std::string LLVMSymbolizer::printDILineInfo(DILineInfo LineInfo, 558 ModuleInfo *ModInfo) const { 559 // By default, DILineInfo contains "<invalid>" for function/filename it 560 // cannot fetch. We replace it to "??" to make our output closer to addr2line. 561 static const std::string kDILineInfoBadString = "<invalid>"; 562 std::stringstream Result; 563 if (Opts.PrintFunctions != FunctionNameKind::None) { 564 std::string FunctionName = LineInfo.FunctionName; 565 if (FunctionName == kDILineInfoBadString) 566 FunctionName = kBadString; 567 else if (Opts.Demangle) 568 FunctionName = DemangleName(FunctionName, ModInfo); 569 Result << FunctionName << "\n"; 570 } 571 std::string Filename = LineInfo.FileName; 572 if (Filename == kDILineInfoBadString) 573 Filename = kBadString; 574 Result << Filename << ":" << LineInfo.Line << ":" << LineInfo.Column << "\n"; 575 return Result.str(); 576 } 577 578 // Undo these various manglings for Win32 extern "C" functions: 579 // cdecl - _foo 580 // stdcall - _foo@12 581 // fastcall - @foo@12 582 // vectorcall - foo@@12 583 // These are all different linkage names for 'foo'. 584 static StringRef demanglePE32ExternCFunc(StringRef SymbolName) { 585 // Remove any '_' or '@' prefix. 586 char Front = SymbolName.empty() ? '\0' : SymbolName[0]; 587 if (Front == '_' || Front == '@') 588 SymbolName = SymbolName.drop_front(); 589 590 // Remove any '@[0-9]+' suffix. 591 if (Front != '?') { 592 size_t AtPos = SymbolName.rfind('@'); 593 if (AtPos != StringRef::npos && 594 std::all_of(SymbolName.begin() + AtPos + 1, SymbolName.end(), 595 [](char C) { return C >= '0' && C <= '9'; })) { 596 SymbolName = SymbolName.substr(0, AtPos); 597 } 598 } 599 600 // Remove any ending '@' for vectorcall. 601 if (SymbolName.endswith("@")) 602 SymbolName = SymbolName.drop_back(); 603 604 return SymbolName; 605 } 606 607 #if !defined(_MSC_VER) 608 // Assume that __cxa_demangle is provided by libcxxabi (except for Windows). 609 extern "C" char *__cxa_demangle(const char *mangled_name, char *output_buffer, 610 size_t *length, int *status); 611 #endif 612 613 std::string LLVMSymbolizer::DemangleName(const std::string &Name, 614 ModuleInfo *ModInfo) { 615 #if !defined(_MSC_VER) 616 // We can spoil names of symbols with C linkage, so use an heuristic 617 // approach to check if the name should be demangled. 618 if (Name.substr(0, 2) == "_Z") { 619 int status = 0; 620 char *DemangledName = __cxa_demangle(Name.c_str(), nullptr, nullptr, &status); 621 if (status != 0) 622 return Name; 623 std::string Result = DemangledName; 624 free(DemangledName); 625 return Result; 626 } 627 #else 628 if (!Name.empty() && Name.front() == '?') { 629 // Only do MSVC C++ demangling on symbols starting with '?'. 630 char DemangledName[1024] = {0}; 631 DWORD result = ::UnDecorateSymbolName( 632 Name.c_str(), DemangledName, 1023, 633 UNDNAME_NO_ACCESS_SPECIFIERS | // Strip public, private, protected 634 UNDNAME_NO_ALLOCATION_LANGUAGE | // Strip __thiscall, __stdcall, etc 635 UNDNAME_NO_THROW_SIGNATURES | // Strip throw() specifications 636 UNDNAME_NO_MEMBER_TYPE | // Strip virtual, static, etc specifiers 637 UNDNAME_NO_MS_KEYWORDS | // Strip all MS extension keywords 638 UNDNAME_NO_FUNCTION_RETURNS); // Strip function return types 639 return (result == 0) ? Name : std::string(DemangledName); 640 } 641 #endif 642 if (ModInfo->isWin32Module()) 643 return std::string(demanglePE32ExternCFunc(Name)); 644 return Name; 645 } 646 647 } // namespace symbolize 648 } // namespace llvm 649