1 //===-- LLVMSymbolize.cpp -------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // Implementation for LLVM symbolization library.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/DebugInfo/Symbolize/Symbolize.h"
15 #include "SymbolizableObjectFile.h"
17 #include "llvm/ADT/STLExtras.h"
18 #include "llvm/BinaryFormat/COFF.h"
19 #include "llvm/Config/config.h"
20 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
21 #include "llvm/DebugInfo/PDB/PDB.h"
22 #include "llvm/DebugInfo/PDB/PDBContext.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"
44 LLVMSymbolizer::symbolizeCodeCommon(const T
&ModuleSpecifier
,
45 object::SectionedAddress ModuleOffset
) {
47 auto InfoOrErr
= getOrCreateModuleInfo(ModuleSpecifier
);
49 return InfoOrErr
.takeError();
51 SymbolizableModule
*Info
= *InfoOrErr
;
53 // A null module means an error has already been reported. Return an empty
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();
63 DILineInfo LineInfo
= Info
->symbolizeCode(
64 ModuleOffset
, DILineInfoSpecifier(Opts
.PathStyle
, Opts
.PrintFunctions
),
67 LineInfo
.FunctionName
= DemangleName(LineInfo
.FunctionName
, Info
);
72 LLVMSymbolizer::symbolizeCode(const ObjectFile
&Obj
,
73 object::SectionedAddress ModuleOffset
) {
74 return symbolizeCodeCommon(Obj
, ModuleOffset
);
78 LLVMSymbolizer::symbolizeCode(const std::string
&ModuleName
,
79 object::SectionedAddress ModuleOffset
) {
80 return symbolizeCodeCommon(ModuleName
, ModuleOffset
);
84 Expected
<DIInliningInfo
> LLVMSymbolizer::symbolizeInlinedCodeCommon(
85 const T
&ModuleSpecifier
, object::SectionedAddress ModuleOffset
) {
86 auto InfoOrErr
= getOrCreateModuleInfo(ModuleSpecifier
);
88 return InfoOrErr
.takeError();
90 SymbolizableModule
*Info
= *InfoOrErr
;
92 // A null module means an error has already been reported. Return an empty
95 return DIInliningInfo();
97 // If the user is giving us relative addresses, add the preferred base of the
98 // object to the offset before we do the query. It's what DIContext expects.
99 if (Opts
.RelativeAddresses
)
100 ModuleOffset
.Address
+= Info
->getModulePreferredBase();
102 DIInliningInfo InlinedContext
= Info
->symbolizeInlinedCode(
103 ModuleOffset
, DILineInfoSpecifier(Opts
.PathStyle
, Opts
.PrintFunctions
),
104 Opts
.UseSymbolTable
);
106 for (int i
= 0, n
= InlinedContext
.getNumberOfFrames(); i
< n
; i
++) {
107 auto *Frame
= InlinedContext
.getMutableFrame(i
);
108 Frame
->FunctionName
= DemangleName(Frame
->FunctionName
, Info
);
111 return InlinedContext
;
114 Expected
<DIInliningInfo
>
115 LLVMSymbolizer::symbolizeInlinedCode(const ObjectFile
&Obj
,
116 object::SectionedAddress ModuleOffset
) {
117 return symbolizeInlinedCodeCommon(Obj
, ModuleOffset
);
120 Expected
<DIInliningInfo
>
121 LLVMSymbolizer::symbolizeInlinedCode(const std::string
&ModuleName
,
122 object::SectionedAddress ModuleOffset
) {
123 return symbolizeInlinedCodeCommon(ModuleName
, ModuleOffset
);
126 template <typename T
>
128 LLVMSymbolizer::symbolizeDataCommon(const T
&ModuleSpecifier
,
129 object::SectionedAddress ModuleOffset
) {
131 auto InfoOrErr
= getOrCreateModuleInfo(ModuleSpecifier
);
133 return InfoOrErr
.takeError();
135 SymbolizableModule
*Info
= *InfoOrErr
;
136 // A null module means an error has already been reported. Return an empty
141 // If the user is giving us relative addresses, add the preferred base of
142 // the object to the offset before we do the query. It's what DIContext
144 if (Opts
.RelativeAddresses
)
145 ModuleOffset
.Address
+= Info
->getModulePreferredBase();
147 DIGlobal Global
= Info
->symbolizeData(ModuleOffset
);
149 Global
.Name
= DemangleName(Global
.Name
, Info
);
154 LLVMSymbolizer::symbolizeData(const ObjectFile
&Obj
,
155 object::SectionedAddress ModuleOffset
) {
156 return symbolizeDataCommon(Obj
, ModuleOffset
);
160 LLVMSymbolizer::symbolizeData(const std::string
&ModuleName
,
161 object::SectionedAddress ModuleOffset
) {
162 return symbolizeDataCommon(ModuleName
, ModuleOffset
);
165 template <typename T
>
166 Expected
<std::vector
<DILocal
>>
167 LLVMSymbolizer::symbolizeFrameCommon(const T
&ModuleSpecifier
,
168 object::SectionedAddress ModuleOffset
) {
169 auto InfoOrErr
= getOrCreateModuleInfo(ModuleSpecifier
);
171 return InfoOrErr
.takeError();
173 SymbolizableModule
*Info
= *InfoOrErr
;
174 // A null module means an error has already been reported. Return an empty
177 return std::vector
<DILocal
>();
179 // If the user is giving us relative addresses, add the preferred base of
180 // the object to the offset before we do the query. It's what DIContext
182 if (Opts
.RelativeAddresses
)
183 ModuleOffset
.Address
+= Info
->getModulePreferredBase();
185 return Info
->symbolizeFrame(ModuleOffset
);
188 Expected
<std::vector
<DILocal
>>
189 LLVMSymbolizer::symbolizeFrame(const ObjectFile
&Obj
,
190 object::SectionedAddress ModuleOffset
) {
191 return symbolizeFrameCommon(Obj
, ModuleOffset
);
194 Expected
<std::vector
<DILocal
>>
195 LLVMSymbolizer::symbolizeFrame(const std::string
&ModuleName
,
196 object::SectionedAddress ModuleOffset
) {
197 return symbolizeFrameCommon(ModuleName
, ModuleOffset
);
200 void LLVMSymbolizer::flush() {
201 ObjectForUBPathAndArch
.clear();
202 BinaryForPath
.clear();
203 ObjectPairForPathArch
.clear();
209 // For Path="/path/to/foo" and Basename="foo" assume that debug info is in
210 // /path/to/foo.dSYM/Contents/Resources/DWARF/foo.
211 // For Path="/path/to/bar.dSYM" and Basename="foo" assume that debug info is in
212 // /path/to/bar.dSYM/Contents/Resources/DWARF/foo.
213 std::string
getDarwinDWARFResourceForPath(const std::string
&Path
,
214 const std::string
&Basename
) {
215 SmallString
<16> ResourceName
= StringRef(Path
);
216 if (sys::path::extension(Path
) != ".dSYM") {
217 ResourceName
+= ".dSYM";
219 sys::path::append(ResourceName
, "Contents", "Resources", "DWARF");
220 sys::path::append(ResourceName
, Basename
);
221 return std::string(ResourceName
.str());
224 bool checkFileCRC(StringRef Path
, uint32_t CRCHash
) {
225 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> MB
=
226 MemoryBuffer::getFileOrSTDIN(Path
);
229 return CRCHash
== llvm::crc32(arrayRefFromStringRef(MB
.get()->getBuffer()));
232 bool findDebugBinary(const std::string
&OrigPath
,
233 const std::string
&DebuglinkName
, uint32_t CRCHash
,
234 const std::string
&FallbackDebugPath
,
235 std::string
&Result
) {
236 SmallString
<16> OrigDir(OrigPath
);
237 llvm::sys::path::remove_filename(OrigDir
);
238 SmallString
<16> DebugPath
= OrigDir
;
239 // Try relative/path/to/original_binary/debuglink_name
240 llvm::sys::path::append(DebugPath
, DebuglinkName
);
241 if (checkFileCRC(DebugPath
, CRCHash
)) {
242 Result
= std::string(DebugPath
.str());
245 // Try relative/path/to/original_binary/.debug/debuglink_name
247 llvm::sys::path::append(DebugPath
, ".debug", DebuglinkName
);
248 if (checkFileCRC(DebugPath
, CRCHash
)) {
249 Result
= std::string(DebugPath
.str());
252 // Make the path absolute so that lookups will go to
253 // "/usr/lib/debug/full/path/to/debug", not
254 // "/usr/lib/debug/to/debug"
255 llvm::sys::fs::make_absolute(OrigDir
);
256 if (!FallbackDebugPath
.empty()) {
257 // Try <FallbackDebugPath>/absolute/path/to/original_binary/debuglink_name
258 DebugPath
= FallbackDebugPath
;
260 #if defined(__NetBSD__)
261 // Try /usr/libdata/debug/absolute/path/to/original_binary/debuglink_name
262 DebugPath
= "/usr/libdata/debug";
264 // Try /usr/lib/debug/absolute/path/to/original_binary/debuglink_name
265 DebugPath
= "/usr/lib/debug";
268 llvm::sys::path::append(DebugPath
, llvm::sys::path::relative_path(OrigDir
),
270 if (checkFileCRC(DebugPath
, CRCHash
)) {
271 Result
= std::string(DebugPath
.str());
277 bool getGNUDebuglinkContents(const ObjectFile
*Obj
, std::string
&DebugName
,
281 for (const SectionRef
&Section
: Obj
->sections()) {
283 if (Expected
<StringRef
> NameOrErr
= Section
.getName())
286 consumeError(NameOrErr
.takeError());
288 Name
= Name
.substr(Name
.find_first_not_of("._"));
289 if (Name
== "gnu_debuglink") {
290 Expected
<StringRef
> ContentsOrErr
= Section
.getContents();
291 if (!ContentsOrErr
) {
292 consumeError(ContentsOrErr
.takeError());
295 DataExtractor
DE(*ContentsOrErr
, Obj
->isLittleEndian(), 0);
297 if (const char *DebugNameStr
= DE
.getCStr(&Offset
)) {
298 // 4-byte align the offset.
299 Offset
= (Offset
+ 3) & ~0x3;
300 if (DE
.isValidOffsetForDataOfSize(Offset
, 4)) {
301 DebugName
= DebugNameStr
;
302 CRCHash
= DE
.getU32(&Offset
);
312 bool darwinDsymMatchesBinary(const MachOObjectFile
*DbgObj
,
313 const MachOObjectFile
*Obj
) {
314 ArrayRef
<uint8_t> dbg_uuid
= DbgObj
->getUuid();
315 ArrayRef
<uint8_t> bin_uuid
= Obj
->getUuid();
316 if (dbg_uuid
.empty() || bin_uuid
.empty())
318 return !memcmp(dbg_uuid
.data(), bin_uuid
.data(), dbg_uuid
.size());
321 template <typename ELFT
>
322 Optional
<ArrayRef
<uint8_t>> getBuildID(const ELFFile
<ELFT
> &Obj
) {
323 auto PhdrsOrErr
= Obj
.program_headers();
325 consumeError(PhdrsOrErr
.takeError());
328 for (const auto &P
: *PhdrsOrErr
) {
329 if (P
.p_type
!= ELF::PT_NOTE
)
331 Error Err
= Error::success();
332 for (auto N
: Obj
.notes(P
, Err
))
333 if (N
.getType() == ELF::NT_GNU_BUILD_ID
&&
334 N
.getName() == ELF::ELF_NOTE_GNU
)
336 consumeError(std::move(Err
));
341 Optional
<ArrayRef
<uint8_t>> getBuildID(const ELFObjectFileBase
*Obj
) {
342 Optional
<ArrayRef
<uint8_t>> BuildID
;
343 if (auto *O
= dyn_cast
<ELFObjectFile
<ELF32LE
>>(Obj
))
344 BuildID
= getBuildID(O
->getELFFile());
345 else if (auto *O
= dyn_cast
<ELFObjectFile
<ELF32BE
>>(Obj
))
346 BuildID
= getBuildID(O
->getELFFile());
347 else if (auto *O
= dyn_cast
<ELFObjectFile
<ELF64LE
>>(Obj
))
348 BuildID
= getBuildID(O
->getELFFile());
349 else if (auto *O
= dyn_cast
<ELFObjectFile
<ELF64BE
>>(Obj
))
350 BuildID
= getBuildID(O
->getELFFile());
352 llvm_unreachable("unsupported file format");
356 bool findDebugBinary(const std::vector
<std::string
> &DebugFileDirectory
,
357 const ArrayRef
<uint8_t> BuildID
, std::string
&Result
) {
358 auto getDebugPath
= [&](StringRef Directory
) {
359 SmallString
<128> Path
{Directory
};
360 sys::path::append(Path
, ".build-id",
361 llvm::toHex(BuildID
[0], /*LowerCase=*/true),
362 llvm::toHex(BuildID
.slice(1), /*LowerCase=*/true));
366 if (DebugFileDirectory
.empty()) {
367 SmallString
<128> Path
= getDebugPath(
368 #if defined(__NetBSD__)
369 // Try /usr/libdata/debug/.build-id/../...
372 // Try /usr/lib/debug/.build-id/../...
376 if (llvm::sys::fs::exists(Path
)) {
377 Result
= std::string(Path
.str());
381 for (const auto &Directory
: DebugFileDirectory
) {
382 // Try <debug-file-directory>/.build-id/../...
383 SmallString
<128> Path
= getDebugPath(Directory
);
384 if (llvm::sys::fs::exists(Path
)) {
385 Result
= std::string(Path
.str());
393 } // end anonymous namespace
395 ObjectFile
*LLVMSymbolizer::lookUpDsymFile(const std::string
&ExePath
,
396 const MachOObjectFile
*MachExeObj
,
397 const std::string
&ArchName
) {
398 // On Darwin we may find DWARF in separate object file in
399 // resource directory.
400 std::vector
<std::string
> DsymPaths
;
401 StringRef Filename
= sys::path::filename(ExePath
);
403 getDarwinDWARFResourceForPath(ExePath
, std::string(Filename
)));
404 for (const auto &Path
: Opts
.DsymHints
) {
406 getDarwinDWARFResourceForPath(Path
, std::string(Filename
)));
408 for (const auto &Path
: DsymPaths
) {
409 auto DbgObjOrErr
= getOrCreateObject(Path
, ArchName
);
411 // Ignore errors, the file might not exist.
412 consumeError(DbgObjOrErr
.takeError());
415 ObjectFile
*DbgObj
= DbgObjOrErr
.get();
418 const MachOObjectFile
*MachDbgObj
= dyn_cast
<const MachOObjectFile
>(DbgObj
);
421 if (darwinDsymMatchesBinary(MachDbgObj
, MachExeObj
))
427 ObjectFile
*LLVMSymbolizer::lookUpDebuglinkObject(const std::string
&Path
,
428 const ObjectFile
*Obj
,
429 const std::string
&ArchName
) {
430 std::string DebuglinkName
;
432 std::string DebugBinaryPath
;
433 if (!getGNUDebuglinkContents(Obj
, DebuglinkName
, CRCHash
))
435 if (!findDebugBinary(Path
, DebuglinkName
, CRCHash
, Opts
.FallbackDebugPath
,
438 auto DbgObjOrErr
= getOrCreateObject(DebugBinaryPath
, ArchName
);
440 // Ignore errors, the file might not exist.
441 consumeError(DbgObjOrErr
.takeError());
444 return DbgObjOrErr
.get();
447 ObjectFile
*LLVMSymbolizer::lookUpBuildIDObject(const std::string
&Path
,
448 const ELFObjectFileBase
*Obj
,
449 const std::string
&ArchName
) {
450 auto BuildID
= getBuildID(Obj
);
453 if (BuildID
->size() < 2)
455 std::string DebugBinaryPath
;
456 if (!findDebugBinary(Opts
.DebugFileDirectory
, *BuildID
, DebugBinaryPath
))
458 auto DbgObjOrErr
= getOrCreateObject(DebugBinaryPath
, ArchName
);
460 consumeError(DbgObjOrErr
.takeError());
463 return DbgObjOrErr
.get();
466 Expected
<LLVMSymbolizer::ObjectPair
>
467 LLVMSymbolizer::getOrCreateObjectPair(const std::string
&Path
,
468 const std::string
&ArchName
) {
469 auto I
= ObjectPairForPathArch
.find(std::make_pair(Path
, ArchName
));
470 if (I
!= ObjectPairForPathArch
.end())
473 auto ObjOrErr
= getOrCreateObject(Path
, ArchName
);
475 ObjectPairForPathArch
.emplace(std::make_pair(Path
, ArchName
),
476 ObjectPair(nullptr, nullptr));
477 return ObjOrErr
.takeError();
480 ObjectFile
*Obj
= ObjOrErr
.get();
481 assert(Obj
!= nullptr);
482 ObjectFile
*DbgObj
= nullptr;
484 if (auto MachObj
= dyn_cast
<const MachOObjectFile
>(Obj
))
485 DbgObj
= lookUpDsymFile(Path
, MachObj
, ArchName
);
486 else if (auto ELFObj
= dyn_cast
<const ELFObjectFileBase
>(Obj
))
487 DbgObj
= lookUpBuildIDObject(Path
, ELFObj
, ArchName
);
489 DbgObj
= lookUpDebuglinkObject(Path
, Obj
, ArchName
);
492 ObjectPair Res
= std::make_pair(Obj
, DbgObj
);
493 ObjectPairForPathArch
.emplace(std::make_pair(Path
, ArchName
), Res
);
497 Expected
<ObjectFile
*>
498 LLVMSymbolizer::getOrCreateObject(const std::string
&Path
,
499 const std::string
&ArchName
) {
501 auto Pair
= BinaryForPath
.emplace(Path
, OwningBinary
<Binary
>());
503 Bin
= Pair
.first
->second
.getBinary();
505 Expected
<OwningBinary
<Binary
>> BinOrErr
= createBinary(Path
);
507 return BinOrErr
.takeError();
508 Pair
.first
->second
= std::move(BinOrErr
.get());
509 Bin
= Pair
.first
->second
.getBinary();
513 return static_cast<ObjectFile
*>(nullptr);
515 if (MachOUniversalBinary
*UB
= dyn_cast_or_null
<MachOUniversalBinary
>(Bin
)) {
516 auto I
= ObjectForUBPathAndArch
.find(std::make_pair(Path
, ArchName
));
517 if (I
!= ObjectForUBPathAndArch
.end())
518 return I
->second
.get();
520 Expected
<std::unique_ptr
<ObjectFile
>> ObjOrErr
=
521 UB
->getMachOObjectForArch(ArchName
);
523 ObjectForUBPathAndArch
.emplace(std::make_pair(Path
, ArchName
),
524 std::unique_ptr
<ObjectFile
>());
525 return ObjOrErr
.takeError();
527 ObjectFile
*Res
= ObjOrErr
->get();
528 ObjectForUBPathAndArch
.emplace(std::make_pair(Path
, ArchName
),
529 std::move(ObjOrErr
.get()));
532 if (Bin
->isObject()) {
533 return cast
<ObjectFile
>(Bin
);
535 return errorCodeToError(object_error::arch_not_found
);
538 Expected
<SymbolizableModule
*>
539 LLVMSymbolizer::createModuleInfo(const ObjectFile
*Obj
,
540 std::unique_ptr
<DIContext
> Context
,
541 StringRef ModuleName
) {
542 auto InfoOrErr
= SymbolizableObjectFile::create(Obj
, std::move(Context
),
543 Opts
.UntagAddresses
);
544 std::unique_ptr
<SymbolizableModule
> SymMod
;
546 SymMod
= std::move(*InfoOrErr
);
547 auto InsertResult
= Modules
.insert(
548 std::make_pair(std::string(ModuleName
), std::move(SymMod
)));
549 assert(InsertResult
.second
);
551 return InfoOrErr
.takeError();
552 return InsertResult
.first
->second
.get();
555 Expected
<SymbolizableModule
*>
556 LLVMSymbolizer::getOrCreateModuleInfo(const std::string
&ModuleName
) {
557 auto I
= Modules
.find(ModuleName
);
558 if (I
!= Modules
.end())
559 return I
->second
.get();
561 std::string BinaryName
= ModuleName
;
562 std::string ArchName
= Opts
.DefaultArch
;
563 size_t ColonPos
= ModuleName
.find_last_of(':');
564 // Verify that substring after colon form a valid arch name.
565 if (ColonPos
!= std::string::npos
) {
566 std::string ArchStr
= ModuleName
.substr(ColonPos
+ 1);
567 if (Triple(ArchStr
).getArch() != Triple::UnknownArch
) {
568 BinaryName
= ModuleName
.substr(0, ColonPos
);
572 auto ObjectsOrErr
= getOrCreateObjectPair(BinaryName
, ArchName
);
574 // Failed to find valid object file.
575 Modules
.emplace(ModuleName
, std::unique_ptr
<SymbolizableModule
>());
576 return ObjectsOrErr
.takeError();
578 ObjectPair Objects
= ObjectsOrErr
.get();
580 std::unique_ptr
<DIContext
> Context
;
581 // If this is a COFF object containing PDB info, use a PDBContext to
582 // symbolize. Otherwise, use DWARF.
583 if (auto CoffObject
= dyn_cast
<COFFObjectFile
>(Objects
.first
)) {
584 const codeview::DebugInfo
*DebugInfo
;
585 StringRef PDBFileName
;
586 auto EC
= CoffObject
->getDebugPDBInfo(DebugInfo
, PDBFileName
);
587 if (!EC
&& DebugInfo
!= nullptr && !PDBFileName
.empty()) {
589 std::unique_ptr
<IPDBSession
> Session
;
591 PDB_ReaderType ReaderType
=
592 Opts
.UseDIA
? PDB_ReaderType::DIA
: PDB_ReaderType::Native
;
593 if (auto Err
= loadDataForEXE(ReaderType
, Objects
.first
->getFileName(),
595 Modules
.emplace(ModuleName
, std::unique_ptr
<SymbolizableModule
>());
596 // Return along the PDB filename to provide more context
597 return createFileError(PDBFileName
, std::move(Err
));
599 Context
.reset(new PDBContext(*CoffObject
, std::move(Session
)));
603 Context
= DWARFContext::create(
604 *Objects
.second
, DWARFContext::ProcessDebugRelocations::Process
,
605 nullptr, Opts
.DWPName
);
606 return createModuleInfo(Objects
.first
, std::move(Context
), ModuleName
);
609 Expected
<SymbolizableModule
*>
610 LLVMSymbolizer::getOrCreateModuleInfo(const ObjectFile
&Obj
) {
611 StringRef ObjName
= Obj
.getFileName();
612 auto I
= Modules
.find(ObjName
);
613 if (I
!= Modules
.end())
614 return I
->second
.get();
616 std::unique_ptr
<DIContext
> Context
= DWARFContext::create(Obj
);
617 // FIXME: handle COFF object with PDB info to use PDBContext
618 return createModuleInfo(&Obj
, std::move(Context
), ObjName
);
623 // Undo these various manglings for Win32 extern "C" functions:
626 // fastcall - @foo@12
627 // vectorcall - foo@@12
628 // These are all different linkage names for 'foo'.
629 StringRef
demanglePE32ExternCFunc(StringRef SymbolName
) {
630 // Remove any '_' or '@' prefix.
631 char Front
= SymbolName
.empty() ? '\0' : SymbolName
[0];
632 if (Front
== '_' || Front
== '@')
633 SymbolName
= SymbolName
.drop_front();
635 // Remove any '@[0-9]+' suffix.
637 size_t AtPos
= SymbolName
.rfind('@');
638 if (AtPos
!= StringRef::npos
&&
639 all_of(drop_begin(SymbolName
, AtPos
+ 1), isDigit
))
640 SymbolName
= SymbolName
.substr(0, AtPos
);
643 // Remove any ending '@' for vectorcall.
644 if (SymbolName
.endswith("@"))
645 SymbolName
= SymbolName
.drop_back();
650 } // end anonymous namespace
653 LLVMSymbolizer::DemangleName(const std::string
&Name
,
654 const SymbolizableModule
*DbiModuleDescriptor
) {
655 // We can spoil names of symbols with C linkage, so use an heuristic
656 // approach to check if the name should be demangled.
657 if (Name
.substr(0, 2) == "_Z") {
659 char *DemangledName
=
660 itaniumDemangle(Name
.c_str(), nullptr, nullptr, &status
);
663 std::string Result
= DemangledName
;
668 if (!Name
.empty() && Name
.front() == '?') {
669 // Only do MSVC C++ demangling on symbols starting with '?'.
671 char *DemangledName
= microsoftDemangle(
672 Name
.c_str(), nullptr, nullptr, nullptr, &status
,
673 MSDemangleFlags(MSDF_NoAccessSpecifier
| MSDF_NoCallingConvention
|
674 MSDF_NoMemberType
| MSDF_NoReturnType
));
677 std::string Result
= DemangledName
;
682 if (DbiModuleDescriptor
&& DbiModuleDescriptor
->isWin32Module())
683 return std::string(demanglePE32ExternCFunc(Name
));
687 } // namespace symbolize