157f8837aSAlexey Samsonov //===-- LLVMSymbolize.cpp -------------------------------------------------===//
257f8837aSAlexey Samsonov //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
657f8837aSAlexey Samsonov //
757f8837aSAlexey Samsonov //===----------------------------------------------------------------------===//
857f8837aSAlexey Samsonov //
957f8837aSAlexey Samsonov // Implementation for LLVM symbolization library.
1057f8837aSAlexey Samsonov //
1157f8837aSAlexey Samsonov //===----------------------------------------------------------------------===//
1257f8837aSAlexey Samsonov
1357f8837aSAlexey Samsonov #include "llvm/DebugInfo/Symbolize/Symbolize.h"
1457f8837aSAlexey Samsonov
1557f8837aSAlexey Samsonov #include "llvm/ADT/STLExtras.h"
1657f8837aSAlexey Samsonov #include "llvm/DebugInfo/DWARF/DWARFContext.h"
1757f8837aSAlexey Samsonov #include "llvm/DebugInfo/PDB/PDB.h"
1857f8837aSAlexey Samsonov #include "llvm/DebugInfo/PDB/PDBContext.h"
194a6553f4SDaniel Thornburgh #include "llvm/DebugInfo/Symbolize/DIFetcher.h"
203c34ef40SSnehasish Kumar #include "llvm/DebugInfo/Symbolize/SymbolizableObjectFile.h"
21cd72cbc6SEugene Zemtsov #include "llvm/Demangle/Demangle.h"
22dafc5d75SReid Kleckner #include "llvm/Object/COFF.h"
23db29f437Sserge-sans-paille #include "llvm/Object/ELFObjectFile.h"
2457f8837aSAlexey Samsonov #include "llvm/Object/MachO.h"
251eaae4c3SAlexey Samsonov #include "llvm/Object/MachOUniversal.h"
2618873b22SEugene Leviant #include "llvm/Support/CRC.h"
2757f8837aSAlexey Samsonov #include "llvm/Support/Casting.h"
2857f8837aSAlexey Samsonov #include "llvm/Support/DataExtractor.h"
2957f8837aSAlexey Samsonov #include "llvm/Support/Errc.h"
3057f8837aSAlexey Samsonov #include "llvm/Support/FileSystem.h"
3157f8837aSAlexey Samsonov #include "llvm/Support/MemoryBuffer.h"
3257f8837aSAlexey Samsonov #include "llvm/Support/Path.h"
3335623fb7SEugene Zelenko #include <algorithm>
3435623fb7SEugene Zelenko #include <cassert>
3535623fb7SEugene Zelenko #include <cstring>
3657f8837aSAlexey Samsonov
3757f8837aSAlexey Samsonov namespace llvm {
38ed98c1b3Sserge-sans-paille namespace codeview {
39ed98c1b3Sserge-sans-paille union DebugInfo;
40ed98c1b3Sserge-sans-paille }
41ed98c1b3Sserge-sans-paille namespace object {
42ed98c1b3Sserge-sans-paille template <class ELFT> class ELFFile;
43ed98c1b3Sserge-sans-paille }
4457f8837aSAlexey Samsonov namespace symbolize {
4557f8837aSAlexey Samsonov
4663bf2284SReid Kleckner LLVMSymbolizer::LLVMSymbolizer() = default;
4763bf2284SReid Kleckner
LLVMSymbolizer(const Options & Opts)481e396affSBenjamin Kramer LLVMSymbolizer::LLVMSymbolizer(const Options &Opts) : Opts(Opts) {}
491e396affSBenjamin Kramer
501e396affSBenjamin Kramer LLVMSymbolizer::~LLVMSymbolizer() = default;
511e396affSBenjamin Kramer
5212999d74SScott Linder template <typename T>
53e5adb68eSDavid Blaikie Expected<DILineInfo>
symbolizeCodeCommon(const T & ModuleSpecifier,object::SectionedAddress ModuleOffset)5412999d74SScott Linder LLVMSymbolizer::symbolizeCodeCommon(const T &ModuleSpecifier,
55e5bdedacSPeter Collingbourne object::SectionedAddress ModuleOffset) {
5612999d74SScott Linder
5712999d74SScott Linder auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
5812999d74SScott Linder if (!InfoOrErr)
5912999d74SScott Linder return InfoOrErr.takeError();
6012999d74SScott Linder
6112999d74SScott Linder SymbolizableModule *Info = *InfoOrErr;
6212999d74SScott Linder
63f27f3f84SReid Kleckner // A null module means an error has already been reported. Return an empty
64f27f3f84SReid Kleckner // result.
65f27f3f84SReid Kleckner if (!Info)
66f27f3f84SReid Kleckner return DILineInfo();
6757f8837aSAlexey Samsonov
6857f8837aSAlexey Samsonov // If the user is giving us relative addresses, add the preferred base of the
6957f8837aSAlexey Samsonov // object to the offset before we do the query. It's what DIContext expects.
7057f8837aSAlexey Samsonov if (Opts.RelativeAddresses)
7177fc1f60SAlexey Lapshin ModuleOffset.Address += Info->getModulePreferredBase();
7257f8837aSAlexey Samsonov
735de4ba17SSterling Augustine DILineInfo LineInfo = Info->symbolizeCode(
745de4ba17SSterling Augustine ModuleOffset, DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions),
750fb6451aSAlexey Samsonov Opts.UseSymbolTable);
7668812498SAlexey Samsonov if (Opts.Demangle)
7768812498SAlexey Samsonov LineInfo.FunctionName = DemangleName(LineInfo.FunctionName, Info);
78d6aa8202SAlexey Samsonov return LineInfo;
7957f8837aSAlexey Samsonov }
8057f8837aSAlexey Samsonov
815de4692cSYuanfang Chen Expected<DILineInfo>
symbolizeCode(const ObjectFile & Obj,object::SectionedAddress ModuleOffset)825de4692cSYuanfang Chen LLVMSymbolizer::symbolizeCode(const ObjectFile &Obj,
835de4692cSYuanfang Chen object::SectionedAddress ModuleOffset) {
8412999d74SScott Linder return symbolizeCodeCommon(Obj, ModuleOffset);
855de4692cSYuanfang Chen }
865de4692cSYuanfang Chen
875de4692cSYuanfang Chen Expected<DILineInfo>
symbolizeCode(const std::string & ModuleName,object::SectionedAddress ModuleOffset)885de4692cSYuanfang Chen LLVMSymbolizer::symbolizeCode(const std::string &ModuleName,
895de4692cSYuanfang Chen object::SectionedAddress ModuleOffset) {
9012999d74SScott Linder return symbolizeCodeCommon(ModuleName, ModuleOffset);
915de4692cSYuanfang Chen }
925de4692cSYuanfang Chen
93dcd4950dSDaniel Thornburgh Expected<DILineInfo>
symbolizeCode(ArrayRef<uint8_t> BuildID,object::SectionedAddress ModuleOffset)94dcd4950dSDaniel Thornburgh LLVMSymbolizer::symbolizeCode(ArrayRef<uint8_t> BuildID,
95dcd4950dSDaniel Thornburgh object::SectionedAddress ModuleOffset) {
96dcd4950dSDaniel Thornburgh return symbolizeCodeCommon(BuildID, ModuleOffset);
97dcd4950dSDaniel Thornburgh }
98dcd4950dSDaniel Thornburgh
9912999d74SScott Linder template <typename T>
symbolizeInlinedCodeCommon(const T & ModuleSpecifier,object::SectionedAddress ModuleOffset)10012999d74SScott Linder Expected<DIInliningInfo> LLVMSymbolizer::symbolizeInlinedCodeCommon(
10112999d74SScott Linder const T &ModuleSpecifier, object::SectionedAddress ModuleOffset) {
10212999d74SScott Linder auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
10312999d74SScott Linder if (!InfoOrErr)
104f27f3f84SReid Kleckner return InfoOrErr.takeError();
105f27f3f84SReid Kleckner
10612999d74SScott Linder SymbolizableModule *Info = *InfoOrErr;
10712999d74SScott Linder
108f27f3f84SReid Kleckner // A null module means an error has already been reported. Return an empty
109f27f3f84SReid Kleckner // result.
110f27f3f84SReid Kleckner if (!Info)
111f27f3f84SReid Kleckner return DIInliningInfo();
11246c1ce6fSAlexey Samsonov
11346c1ce6fSAlexey Samsonov // If the user is giving us relative addresses, add the preferred base of the
11446c1ce6fSAlexey Samsonov // object to the offset before we do the query. It's what DIContext expects.
11546c1ce6fSAlexey Samsonov if (Opts.RelativeAddresses)
11677fc1f60SAlexey Lapshin ModuleOffset.Address += Info->getModulePreferredBase();
11746c1ce6fSAlexey Samsonov
11846c1ce6fSAlexey Samsonov DIInliningInfo InlinedContext = Info->symbolizeInlinedCode(
1195de4ba17SSterling Augustine ModuleOffset, DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions),
1205de4ba17SSterling Augustine Opts.UseSymbolTable);
12168812498SAlexey Samsonov if (Opts.Demangle) {
12268812498SAlexey Samsonov for (int i = 0, n = InlinedContext.getNumberOfFrames(); i < n; i++) {
12368812498SAlexey Samsonov auto *Frame = InlinedContext.getMutableFrame(i);
12468812498SAlexey Samsonov Frame->FunctionName = DemangleName(Frame->FunctionName, Info);
12568812498SAlexey Samsonov }
12668812498SAlexey Samsonov }
127d6aa8202SAlexey Samsonov return InlinedContext;
12846c1ce6fSAlexey Samsonov }
12946c1ce6fSAlexey Samsonov
13012999d74SScott Linder Expected<DIInliningInfo>
symbolizeInlinedCode(const ObjectFile & Obj,object::SectionedAddress ModuleOffset)13112999d74SScott Linder LLVMSymbolizer::symbolizeInlinedCode(const ObjectFile &Obj,
13277fc1f60SAlexey Lapshin object::SectionedAddress ModuleOffset) {
13312999d74SScott Linder return symbolizeInlinedCodeCommon(Obj, ModuleOffset);
13412999d74SScott Linder }
13512999d74SScott Linder
13612999d74SScott Linder Expected<DIInliningInfo>
symbolizeInlinedCode(const std::string & ModuleName,object::SectionedAddress ModuleOffset)13712999d74SScott Linder LLVMSymbolizer::symbolizeInlinedCode(const std::string &ModuleName,
13812999d74SScott Linder object::SectionedAddress ModuleOffset) {
13912999d74SScott Linder return symbolizeInlinedCodeCommon(ModuleName, ModuleOffset);
14012999d74SScott Linder }
14112999d74SScott Linder
142dcd4950dSDaniel Thornburgh Expected<DIInliningInfo>
symbolizeInlinedCode(ArrayRef<uint8_t> BuildID,object::SectionedAddress ModuleOffset)143dcd4950dSDaniel Thornburgh LLVMSymbolizer::symbolizeInlinedCode(ArrayRef<uint8_t> BuildID,
144dcd4950dSDaniel Thornburgh object::SectionedAddress ModuleOffset) {
145dcd4950dSDaniel Thornburgh return symbolizeInlinedCodeCommon(BuildID, ModuleOffset);
146dcd4950dSDaniel Thornburgh }
147dcd4950dSDaniel Thornburgh
14812999d74SScott Linder template <typename T>
14912999d74SScott Linder Expected<DIGlobal>
symbolizeDataCommon(const T & ModuleSpecifier,object::SectionedAddress ModuleOffset)15012999d74SScott Linder LLVMSymbolizer::symbolizeDataCommon(const T &ModuleSpecifier,
15112999d74SScott Linder object::SectionedAddress ModuleOffset) {
15212999d74SScott Linder
15312999d74SScott Linder auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
15412999d74SScott Linder if (!InfoOrErr)
155f27f3f84SReid Kleckner return InfoOrErr.takeError();
156f27f3f84SReid Kleckner
15712999d74SScott Linder SymbolizableModule *Info = *InfoOrErr;
158f27f3f84SReid Kleckner // A null module means an error has already been reported. Return an empty
159f27f3f84SReid Kleckner // result.
160f27f3f84SReid Kleckner if (!Info)
161f27f3f84SReid Kleckner return DIGlobal();
16268812498SAlexey Samsonov
1638df3a07aSAlexey Samsonov // If the user is giving us relative addresses, add the preferred base of
1648df3a07aSAlexey Samsonov // the object to the offset before we do the query. It's what DIContext
1658df3a07aSAlexey Samsonov // expects.
16657f8837aSAlexey Samsonov if (Opts.RelativeAddresses)
16777fc1f60SAlexey Lapshin ModuleOffset.Address += Info->getModulePreferredBase();
16868812498SAlexey Samsonov
16976f7ecb8SAlexey Samsonov DIGlobal Global = Info->symbolizeData(ModuleOffset);
17068812498SAlexey Samsonov if (Opts.Demangle)
17168812498SAlexey Samsonov Global.Name = DemangleName(Global.Name, Info);
172d6aa8202SAlexey Samsonov return Global;
17357f8837aSAlexey Samsonov }
17457f8837aSAlexey Samsonov
17512999d74SScott Linder Expected<DIGlobal>
symbolizeData(const ObjectFile & Obj,object::SectionedAddress ModuleOffset)17612999d74SScott Linder LLVMSymbolizer::symbolizeData(const ObjectFile &Obj,
1779c8282a9SPeter Collingbourne object::SectionedAddress ModuleOffset) {
17812999d74SScott Linder return symbolizeDataCommon(Obj, ModuleOffset);
17912999d74SScott Linder }
18012999d74SScott Linder
18112999d74SScott Linder Expected<DIGlobal>
symbolizeData(const std::string & ModuleName,object::SectionedAddress ModuleOffset)18212999d74SScott Linder LLVMSymbolizer::symbolizeData(const std::string &ModuleName,
18312999d74SScott Linder object::SectionedAddress ModuleOffset) {
18412999d74SScott Linder return symbolizeDataCommon(ModuleName, ModuleOffset);
18512999d74SScott Linder }
18612999d74SScott Linder
187dcd4950dSDaniel Thornburgh Expected<DIGlobal>
symbolizeData(ArrayRef<uint8_t> BuildID,object::SectionedAddress ModuleOffset)188dcd4950dSDaniel Thornburgh LLVMSymbolizer::symbolizeData(ArrayRef<uint8_t> BuildID,
189dcd4950dSDaniel Thornburgh object::SectionedAddress ModuleOffset) {
190dcd4950dSDaniel Thornburgh return symbolizeDataCommon(BuildID, ModuleOffset);
191dcd4950dSDaniel Thornburgh }
192dcd4950dSDaniel Thornburgh
19312999d74SScott Linder template <typename T>
19412999d74SScott Linder Expected<std::vector<DILocal>>
symbolizeFrameCommon(const T & ModuleSpecifier,object::SectionedAddress ModuleOffset)19512999d74SScott Linder LLVMSymbolizer::symbolizeFrameCommon(const T &ModuleSpecifier,
19612999d74SScott Linder object::SectionedAddress ModuleOffset) {
19712999d74SScott Linder auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
19812999d74SScott Linder if (!InfoOrErr)
1999c8282a9SPeter Collingbourne return InfoOrErr.takeError();
2009c8282a9SPeter Collingbourne
20112999d74SScott Linder SymbolizableModule *Info = *InfoOrErr;
2029c8282a9SPeter Collingbourne // A null module means an error has already been reported. Return an empty
2039c8282a9SPeter Collingbourne // result.
2049c8282a9SPeter Collingbourne if (!Info)
2059c8282a9SPeter Collingbourne return std::vector<DILocal>();
2069c8282a9SPeter Collingbourne
2079c8282a9SPeter Collingbourne // If the user is giving us relative addresses, add the preferred base of
2089c8282a9SPeter Collingbourne // the object to the offset before we do the query. It's what DIContext
2099c8282a9SPeter Collingbourne // expects.
2109c8282a9SPeter Collingbourne if (Opts.RelativeAddresses)
2119c8282a9SPeter Collingbourne ModuleOffset.Address += Info->getModulePreferredBase();
2129c8282a9SPeter Collingbourne
2139c8282a9SPeter Collingbourne return Info->symbolizeFrame(ModuleOffset);
2149c8282a9SPeter Collingbourne }
2159c8282a9SPeter Collingbourne
21612999d74SScott Linder Expected<std::vector<DILocal>>
symbolizeFrame(const ObjectFile & Obj,object::SectionedAddress ModuleOffset)21712999d74SScott Linder LLVMSymbolizer::symbolizeFrame(const ObjectFile &Obj,
21812999d74SScott Linder object::SectionedAddress ModuleOffset) {
21912999d74SScott Linder return symbolizeFrameCommon(Obj, ModuleOffset);
22012999d74SScott Linder }
22112999d74SScott Linder
22212999d74SScott Linder Expected<std::vector<DILocal>>
symbolizeFrame(const std::string & ModuleName,object::SectionedAddress ModuleOffset)22312999d74SScott Linder LLVMSymbolizer::symbolizeFrame(const std::string &ModuleName,
22412999d74SScott Linder object::SectionedAddress ModuleOffset) {
22512999d74SScott Linder return symbolizeFrameCommon(ModuleName, ModuleOffset);
22612999d74SScott Linder }
22712999d74SScott Linder
228dcd4950dSDaniel Thornburgh Expected<std::vector<DILocal>>
symbolizeFrame(ArrayRef<uint8_t> BuildID,object::SectionedAddress ModuleOffset)229dcd4950dSDaniel Thornburgh LLVMSymbolizer::symbolizeFrame(ArrayRef<uint8_t> BuildID,
230dcd4950dSDaniel Thornburgh object::SectionedAddress ModuleOffset) {
231dcd4950dSDaniel Thornburgh return symbolizeFrameCommon(BuildID, ModuleOffset);
232dcd4950dSDaniel Thornburgh }
233dcd4950dSDaniel Thornburgh
flush()23457f8837aSAlexey Samsonov void LLVMSymbolizer::flush() {
2351eaae4c3SAlexey Samsonov ObjectForUBPathAndArch.clear();
23602106ec1SDaniel Thornburgh LRUBinaries.clear();
23702106ec1SDaniel Thornburgh CacheSize = 0;
2381eaae4c3SAlexey Samsonov BinaryForPath.clear();
23957f8837aSAlexey Samsonov ObjectPairForPathArch.clear();
2401eaae4c3SAlexey Samsonov Modules.clear();
241dcd4950dSDaniel Thornburgh BuildIDPaths.clear();
24257f8837aSAlexey Samsonov }
24357f8837aSAlexey Samsonov
24435623fb7SEugene Zelenko namespace {
24535623fb7SEugene Zelenko
24657f8837aSAlexey Samsonov // For Path="/path/to/foo" and Basename="foo" assume that debug info is in
24757f8837aSAlexey Samsonov // /path/to/foo.dSYM/Contents/Resources/DWARF/foo.
24857f8837aSAlexey Samsonov // For Path="/path/to/bar.dSYM" and Basename="foo" assume that debug info is in
24957f8837aSAlexey Samsonov // /path/to/bar.dSYM/Contents/Resources/DWARF/foo.
getDarwinDWARFResourceForPath(const std::string & Path,const std::string & Basename)250a12000e4SSimon Giesecke std::string getDarwinDWARFResourceForPath(const std::string &Path,
251a12000e4SSimon Giesecke const std::string &Basename) {
25257f8837aSAlexey Samsonov SmallString<16> ResourceName = StringRef(Path);
25357f8837aSAlexey Samsonov if (sys::path::extension(Path) != ".dSYM") {
25457f8837aSAlexey Samsonov ResourceName += ".dSYM";
25557f8837aSAlexey Samsonov }
25657f8837aSAlexey Samsonov sys::path::append(ResourceName, "Contents", "Resources", "DWARF");
25757f8837aSAlexey Samsonov sys::path::append(ResourceName, Basename);
258adcd0268SBenjamin Kramer return std::string(ResourceName.str());
25957f8837aSAlexey Samsonov }
26057f8837aSAlexey Samsonov
checkFileCRC(StringRef Path,uint32_t CRCHash)26135623fb7SEugene Zelenko bool checkFileCRC(StringRef Path, uint32_t CRCHash) {
26257f8837aSAlexey Samsonov ErrorOr<std::unique_ptr<MemoryBuffer>> MB =
26357f8837aSAlexey Samsonov MemoryBuffer::getFileOrSTDIN(Path);
26457f8837aSAlexey Samsonov if (!MB)
26557f8837aSAlexey Samsonov return false;
2661e1e3ba2SHans Wennborg return CRCHash == llvm::crc32(arrayRefFromStringRef(MB.get()->getBuffer()));
26757f8837aSAlexey Samsonov }
26857f8837aSAlexey Samsonov
getGNUDebuglinkContents(const ObjectFile * Obj,std::string & DebugName,uint32_t & CRCHash)26935623fb7SEugene Zelenko bool getGNUDebuglinkContents(const ObjectFile *Obj, std::string &DebugName,
27057f8837aSAlexey Samsonov uint32_t &CRCHash) {
27157f8837aSAlexey Samsonov if (!Obj)
27257f8837aSAlexey Samsonov return false;
27357f8837aSAlexey Samsonov for (const SectionRef &Section : Obj->sections()) {
27457f8837aSAlexey Samsonov StringRef Name;
2752410fb46SDuncan P. N. Exon Smith consumeError(Section.getName().moveInto(Name));
276bcc00e1aSGeorge Rimar
27757f8837aSAlexey Samsonov Name = Name.substr(Name.find_first_not_of("._"));
27857f8837aSAlexey Samsonov if (Name == "gnu_debuglink") {
279e183340cSFangrui Song Expected<StringRef> ContentsOrErr = Section.getContents();
280e183340cSFangrui Song if (!ContentsOrErr) {
281e183340cSFangrui Song consumeError(ContentsOrErr.takeError());
282e183340cSFangrui Song return false;
283e183340cSFangrui Song }
284e183340cSFangrui Song DataExtractor DE(*ContentsOrErr, Obj->isLittleEndian(), 0);
285f26a70a5SIgor Kudrin uint64_t Offset = 0;
28657f8837aSAlexey Samsonov if (const char *DebugNameStr = DE.getCStr(&Offset)) {
28757f8837aSAlexey Samsonov // 4-byte align the offset.
28857f8837aSAlexey Samsonov Offset = (Offset + 3) & ~0x3;
28957f8837aSAlexey Samsonov if (DE.isValidOffsetForDataOfSize(Offset, 4)) {
29057f8837aSAlexey Samsonov DebugName = DebugNameStr;
29157f8837aSAlexey Samsonov CRCHash = DE.getU32(&Offset);
29257f8837aSAlexey Samsonov return true;
29357f8837aSAlexey Samsonov }
29457f8837aSAlexey Samsonov }
29557f8837aSAlexey Samsonov break;
29657f8837aSAlexey Samsonov }
29757f8837aSAlexey Samsonov }
29857f8837aSAlexey Samsonov return false;
29957f8837aSAlexey Samsonov }
30057f8837aSAlexey Samsonov
darwinDsymMatchesBinary(const MachOObjectFile * DbgObj,const MachOObjectFile * Obj)30157f8837aSAlexey Samsonov bool darwinDsymMatchesBinary(const MachOObjectFile *DbgObj,
30257f8837aSAlexey Samsonov const MachOObjectFile *Obj) {
30357f8837aSAlexey Samsonov ArrayRef<uint8_t> dbg_uuid = DbgObj->getUuid();
30457f8837aSAlexey Samsonov ArrayRef<uint8_t> bin_uuid = Obj->getUuid();
30557f8837aSAlexey Samsonov if (dbg_uuid.empty() || bin_uuid.empty())
30657f8837aSAlexey Samsonov return false;
30757f8837aSAlexey Samsonov return !memcmp(dbg_uuid.data(), bin_uuid.data(), dbg_uuid.size());
30857f8837aSAlexey Samsonov }
30957f8837aSAlexey Samsonov
31000e436f1SPetr Hosek template <typename ELFT>
getBuildID(const ELFFile<ELFT> & Obj)311ffbce65fSGeorgii Rymar Optional<ArrayRef<uint8_t>> getBuildID(const ELFFile<ELFT> &Obj) {
312ffbce65fSGeorgii Rymar auto PhdrsOrErr = Obj.program_headers();
31300e436f1SPetr Hosek if (!PhdrsOrErr) {
31400e436f1SPetr Hosek consumeError(PhdrsOrErr.takeError());
31500e436f1SPetr Hosek return {};
31600e436f1SPetr Hosek }
31700e436f1SPetr Hosek for (const auto &P : *PhdrsOrErr) {
31800e436f1SPetr Hosek if (P.p_type != ELF::PT_NOTE)
31900e436f1SPetr Hosek continue;
32000e436f1SPetr Hosek Error Err = Error::success();
321ffbce65fSGeorgii Rymar for (auto N : Obj.notes(P, Err))
322a12000e4SSimon Giesecke if (N.getType() == ELF::NT_GNU_BUILD_ID &&
323a12000e4SSimon Giesecke N.getName() == ELF::ELF_NOTE_GNU)
32400e436f1SPetr Hosek return N.getDesc();
325369ea47bSPetr Hosek consumeError(std::move(Err));
32600e436f1SPetr Hosek }
32700e436f1SPetr Hosek return {};
32800e436f1SPetr Hosek }
32900e436f1SPetr Hosek
330*babef908SNoah Shutty } // end anonymous namespace
331*babef908SNoah Shutty
getBuildID(const ELFObjectFileBase * Obj)33200e436f1SPetr Hosek Optional<ArrayRef<uint8_t>> getBuildID(const ELFObjectFileBase *Obj) {
33300e436f1SPetr Hosek Optional<ArrayRef<uint8_t>> BuildID;
33400e436f1SPetr Hosek if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Obj))
33500e436f1SPetr Hosek BuildID = getBuildID(O->getELFFile());
33600e436f1SPetr Hosek else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(Obj))
33700e436f1SPetr Hosek BuildID = getBuildID(O->getELFFile());
33800e436f1SPetr Hosek else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(Obj))
33900e436f1SPetr Hosek BuildID = getBuildID(O->getELFFile());
34000e436f1SPetr Hosek else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(Obj))
34100e436f1SPetr Hosek BuildID = getBuildID(O->getELFFile());
34200e436f1SPetr Hosek else
34300e436f1SPetr Hosek llvm_unreachable("unsupported file format");
34400e436f1SPetr Hosek return BuildID;
34500e436f1SPetr Hosek }
34600e436f1SPetr Hosek
lookUpDsymFile(const std::string & ExePath,const MachOObjectFile * MachExeObj,const std::string & ArchName)34757f8837aSAlexey Samsonov ObjectFile *LLVMSymbolizer::lookUpDsymFile(const std::string &ExePath,
348a12000e4SSimon Giesecke const MachOObjectFile *MachExeObj,
349a12000e4SSimon Giesecke const std::string &ArchName) {
35057f8837aSAlexey Samsonov // On Darwin we may find DWARF in separate object file in
35157f8837aSAlexey Samsonov // resource directory.
35257f8837aSAlexey Samsonov std::vector<std::string> DsymPaths;
35357f8837aSAlexey Samsonov StringRef Filename = sys::path::filename(ExePath);
354adcd0268SBenjamin Kramer DsymPaths.push_back(
355adcd0268SBenjamin Kramer getDarwinDWARFResourceForPath(ExePath, std::string(Filename)));
35657f8837aSAlexey Samsonov for (const auto &Path : Opts.DsymHints) {
357adcd0268SBenjamin Kramer DsymPaths.push_back(
358adcd0268SBenjamin Kramer getDarwinDWARFResourceForPath(Path, std::string(Filename)));
35957f8837aSAlexey Samsonov }
3601eaae4c3SAlexey Samsonov for (const auto &Path : DsymPaths) {
3611eaae4c3SAlexey Samsonov auto DbgObjOrErr = getOrCreateObject(Path, ArchName);
362f27f3f84SReid Kleckner if (!DbgObjOrErr) {
363f27f3f84SReid Kleckner // Ignore errors, the file might not exist.
364f27f3f84SReid Kleckner consumeError(DbgObjOrErr.takeError());
365884adda0SAlexey Samsonov continue;
366f27f3f84SReid Kleckner }
367884adda0SAlexey Samsonov ObjectFile *DbgObj = DbgObjOrErr.get();
368f27f3f84SReid Kleckner if (!DbgObj)
369f27f3f84SReid Kleckner continue;
3701eaae4c3SAlexey Samsonov const MachOObjectFile *MachDbgObj = dyn_cast<const MachOObjectFile>(DbgObj);
371884adda0SAlexey Samsonov if (!MachDbgObj)
372884adda0SAlexey Samsonov continue;
3731eaae4c3SAlexey Samsonov if (darwinDsymMatchesBinary(MachDbgObj, MachExeObj))
37457f8837aSAlexey Samsonov return DbgObj;
37557f8837aSAlexey Samsonov }
37657f8837aSAlexey Samsonov return nullptr;
37757f8837aSAlexey Samsonov }
37857f8837aSAlexey Samsonov
lookUpDebuglinkObject(const std::string & Path,const ObjectFile * Obj,const std::string & ArchName)3795365a01dSAlexey Samsonov ObjectFile *LLVMSymbolizer::lookUpDebuglinkObject(const std::string &Path,
3805365a01dSAlexey Samsonov const ObjectFile *Obj,
3815365a01dSAlexey Samsonov const std::string &ArchName) {
3825365a01dSAlexey Samsonov std::string DebuglinkName;
3835365a01dSAlexey Samsonov uint32_t CRCHash;
3845365a01dSAlexey Samsonov std::string DebugBinaryPath;
3855365a01dSAlexey Samsonov if (!getGNUDebuglinkContents(Obj, DebuglinkName, CRCHash))
3865365a01dSAlexey Samsonov return nullptr;
3874a6553f4SDaniel Thornburgh if (!findDebugBinary(Path, DebuglinkName, CRCHash, DebugBinaryPath))
3885365a01dSAlexey Samsonov return nullptr;
3891eaae4c3SAlexey Samsonov auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName);
390f27f3f84SReid Kleckner if (!DbgObjOrErr) {
391f27f3f84SReid Kleckner // Ignore errors, the file might not exist.
392f27f3f84SReid Kleckner consumeError(DbgObjOrErr.takeError());
3935365a01dSAlexey Samsonov return nullptr;
394f27f3f84SReid Kleckner }
3955365a01dSAlexey Samsonov return DbgObjOrErr.get();
3965365a01dSAlexey Samsonov }
3975365a01dSAlexey Samsonov
lookUpBuildIDObject(const std::string & Path,const ELFObjectFileBase * Obj,const std::string & ArchName)39800e436f1SPetr Hosek ObjectFile *LLVMSymbolizer::lookUpBuildIDObject(const std::string &Path,
39900e436f1SPetr Hosek const ELFObjectFileBase *Obj,
40000e436f1SPetr Hosek const std::string &ArchName) {
40100e436f1SPetr Hosek auto BuildID = getBuildID(Obj);
40200e436f1SPetr Hosek if (!BuildID)
40300e436f1SPetr Hosek return nullptr;
40400e436f1SPetr Hosek if (BuildID->size() < 2)
40500e436f1SPetr Hosek return nullptr;
40600e436f1SPetr Hosek std::string DebugBinaryPath;
407dcd4950dSDaniel Thornburgh if (!getOrFindDebugBinary(*BuildID, DebugBinaryPath))
40800e436f1SPetr Hosek return nullptr;
40900e436f1SPetr Hosek auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName);
41000e436f1SPetr Hosek if (!DbgObjOrErr) {
41100e436f1SPetr Hosek consumeError(DbgObjOrErr.takeError());
41200e436f1SPetr Hosek return nullptr;
41300e436f1SPetr Hosek }
41400e436f1SPetr Hosek return DbgObjOrErr.get();
41500e436f1SPetr Hosek }
41600e436f1SPetr Hosek
findDebugBinary(const std::string & OrigPath,const std::string & DebuglinkName,uint32_t CRCHash,std::string & Result)4174a6553f4SDaniel Thornburgh bool LLVMSymbolizer::findDebugBinary(const std::string &OrigPath,
4184a6553f4SDaniel Thornburgh const std::string &DebuglinkName,
4194a6553f4SDaniel Thornburgh uint32_t CRCHash, std::string &Result) {
4204a6553f4SDaniel Thornburgh SmallString<16> OrigDir(OrigPath);
4214a6553f4SDaniel Thornburgh llvm::sys::path::remove_filename(OrigDir);
4224a6553f4SDaniel Thornburgh SmallString<16> DebugPath = OrigDir;
4234a6553f4SDaniel Thornburgh // Try relative/path/to/original_binary/debuglink_name
4244a6553f4SDaniel Thornburgh llvm::sys::path::append(DebugPath, DebuglinkName);
4254a6553f4SDaniel Thornburgh if (checkFileCRC(DebugPath, CRCHash)) {
4264a6553f4SDaniel Thornburgh Result = std::string(DebugPath.str());
4274a6553f4SDaniel Thornburgh return true;
4284a6553f4SDaniel Thornburgh }
4294a6553f4SDaniel Thornburgh // Try relative/path/to/original_binary/.debug/debuglink_name
4304a6553f4SDaniel Thornburgh DebugPath = OrigDir;
4314a6553f4SDaniel Thornburgh llvm::sys::path::append(DebugPath, ".debug", DebuglinkName);
4324a6553f4SDaniel Thornburgh if (checkFileCRC(DebugPath, CRCHash)) {
4334a6553f4SDaniel Thornburgh Result = std::string(DebugPath.str());
4344a6553f4SDaniel Thornburgh return true;
4354a6553f4SDaniel Thornburgh }
4364a6553f4SDaniel Thornburgh // Make the path absolute so that lookups will go to
4374a6553f4SDaniel Thornburgh // "/usr/lib/debug/full/path/to/debug", not
4384a6553f4SDaniel Thornburgh // "/usr/lib/debug/to/debug"
4394a6553f4SDaniel Thornburgh llvm::sys::fs::make_absolute(OrigDir);
4404a6553f4SDaniel Thornburgh if (!Opts.FallbackDebugPath.empty()) {
4414a6553f4SDaniel Thornburgh // Try <FallbackDebugPath>/absolute/path/to/original_binary/debuglink_name
4424a6553f4SDaniel Thornburgh DebugPath = Opts.FallbackDebugPath;
4434a6553f4SDaniel Thornburgh } else {
4444a6553f4SDaniel Thornburgh #if defined(__NetBSD__)
4454a6553f4SDaniel Thornburgh // Try /usr/libdata/debug/absolute/path/to/original_binary/debuglink_name
4464a6553f4SDaniel Thornburgh DebugPath = "/usr/libdata/debug";
4474a6553f4SDaniel Thornburgh #else
4484a6553f4SDaniel Thornburgh // Try /usr/lib/debug/absolute/path/to/original_binary/debuglink_name
4494a6553f4SDaniel Thornburgh DebugPath = "/usr/lib/debug";
4504a6553f4SDaniel Thornburgh #endif
4514a6553f4SDaniel Thornburgh }
4524a6553f4SDaniel Thornburgh llvm::sys::path::append(DebugPath, llvm::sys::path::relative_path(OrigDir),
4534a6553f4SDaniel Thornburgh DebuglinkName);
4544a6553f4SDaniel Thornburgh if (checkFileCRC(DebugPath, CRCHash)) {
4554a6553f4SDaniel Thornburgh Result = std::string(DebugPath.str());
4564a6553f4SDaniel Thornburgh return true;
4574a6553f4SDaniel Thornburgh }
4584a6553f4SDaniel Thornburgh return false;
4594a6553f4SDaniel Thornburgh }
4604a6553f4SDaniel Thornburgh
getBuildIDStr(ArrayRef<uint8_t> BuildID)461dcd4950dSDaniel Thornburgh static StringRef getBuildIDStr(ArrayRef<uint8_t> BuildID) {
462dcd4950dSDaniel Thornburgh return StringRef(reinterpret_cast<const char *>(BuildID.data()),
463dcd4950dSDaniel Thornburgh BuildID.size());
464dcd4950dSDaniel Thornburgh }
465dcd4950dSDaniel Thornburgh
getOrFindDebugBinary(const ArrayRef<uint8_t> BuildID,std::string & Result)466dcd4950dSDaniel Thornburgh bool LLVMSymbolizer::getOrFindDebugBinary(const ArrayRef<uint8_t> BuildID,
4674a6553f4SDaniel Thornburgh std::string &Result) {
468dcd4950dSDaniel Thornburgh StringRef BuildIDStr = getBuildIDStr(BuildID);
469dcd4950dSDaniel Thornburgh auto I = BuildIDPaths.find(BuildIDStr);
470dcd4950dSDaniel Thornburgh if (I != BuildIDPaths.end()) {
471dcd4950dSDaniel Thornburgh Result = I->second;
472dcd4950dSDaniel Thornburgh return true;
473dcd4950dSDaniel Thornburgh }
474dcd4950dSDaniel Thornburgh auto recordPath = [&](StringRef Path) {
475dcd4950dSDaniel Thornburgh Result = Path.str();
476dcd4950dSDaniel Thornburgh auto InsertResult = BuildIDPaths.insert({BuildIDStr, Result});
477dcd4950dSDaniel Thornburgh assert(InsertResult.second);
478f8701a30SFangrui Song (void)InsertResult;
479dcd4950dSDaniel Thornburgh };
480dcd4950dSDaniel Thornburgh
4814a6553f4SDaniel Thornburgh Optional<std::string> Path;
4824a6553f4SDaniel Thornburgh Path = LocalDIFetcher(Opts.DebugFileDirectory).fetchBuildID(BuildID);
4834a6553f4SDaniel Thornburgh if (Path) {
484dcd4950dSDaniel Thornburgh recordPath(*Path);
4854a6553f4SDaniel Thornburgh return true;
4864a6553f4SDaniel Thornburgh }
4874a6553f4SDaniel Thornburgh
4884a6553f4SDaniel Thornburgh // Try caller-provided debug info fetchers.
4894a6553f4SDaniel Thornburgh for (const std::unique_ptr<DIFetcher> &Fetcher : DIFetchers) {
4904a6553f4SDaniel Thornburgh Path = Fetcher->fetchBuildID(BuildID);
4914a6553f4SDaniel Thornburgh if (Path) {
492dcd4950dSDaniel Thornburgh recordPath(*Path);
4934a6553f4SDaniel Thornburgh return true;
4944a6553f4SDaniel Thornburgh }
4954a6553f4SDaniel Thornburgh }
4964a6553f4SDaniel Thornburgh
4974a6553f4SDaniel Thornburgh return false;
4984a6553f4SDaniel Thornburgh }
4994a6553f4SDaniel Thornburgh
500f27f3f84SReid Kleckner Expected<LLVMSymbolizer::ObjectPair>
getOrCreateObjectPair(const std::string & Path,const std::string & ArchName)5011eaae4c3SAlexey Samsonov LLVMSymbolizer::getOrCreateObjectPair(const std::string &Path,
50257f8837aSAlexey Samsonov const std::string &ArchName) {
50322e478f0SFangrui Song auto I = ObjectPairForPathArch.find(std::make_pair(Path, ArchName));
50402106ec1SDaniel Thornburgh if (I != ObjectPairForPathArch.end()) {
50502106ec1SDaniel Thornburgh recordAccess(BinaryForPath.find(Path)->second);
50657f8837aSAlexey Samsonov return I->second;
50702106ec1SDaniel Thornburgh }
508884adda0SAlexey Samsonov
5091eaae4c3SAlexey Samsonov auto ObjOrErr = getOrCreateObject(Path, ArchName);
510f27f3f84SReid Kleckner if (!ObjOrErr) {
51122e478f0SFangrui Song ObjectPairForPathArch.emplace(std::make_pair(Path, ArchName),
51222e478f0SFangrui Song ObjectPair(nullptr, nullptr));
513f27f3f84SReid Kleckner return ObjOrErr.takeError();
51457f8837aSAlexey Samsonov }
515884adda0SAlexey Samsonov
516884adda0SAlexey Samsonov ObjectFile *Obj = ObjOrErr.get();
517884adda0SAlexey Samsonov assert(Obj != nullptr);
518884adda0SAlexey Samsonov ObjectFile *DbgObj = nullptr;
519884adda0SAlexey Samsonov
52057f8837aSAlexey Samsonov if (auto MachObj = dyn_cast<const MachOObjectFile>(Obj))
52157f8837aSAlexey Samsonov DbgObj = lookUpDsymFile(Path, MachObj, ArchName);
52200e436f1SPetr Hosek else if (auto ELFObj = dyn_cast<const ELFObjectFileBase>(Obj))
52300e436f1SPetr Hosek DbgObj = lookUpBuildIDObject(Path, ELFObj, ArchName);
5245365a01dSAlexey Samsonov if (!DbgObj)
5255365a01dSAlexey Samsonov DbgObj = lookUpDebuglinkObject(Path, Obj, ArchName);
52657f8837aSAlexey Samsonov if (!DbgObj)
52757f8837aSAlexey Samsonov DbgObj = Obj;
52857f8837aSAlexey Samsonov ObjectPair Res = std::make_pair(Obj, DbgObj);
52902106ec1SDaniel Thornburgh std::string DbgObjPath = DbgObj->getFileName().str();
53002106ec1SDaniel Thornburgh auto Pair =
53122e478f0SFangrui Song ObjectPairForPathArch.emplace(std::make_pair(Path, ArchName), Res);
53202106ec1SDaniel Thornburgh BinaryForPath.find(DbgObjPath)->second.pushEvictor([this, I = Pair.first]() {
53302106ec1SDaniel Thornburgh ObjectPairForPathArch.erase(I);
53402106ec1SDaniel Thornburgh });
53557f8837aSAlexey Samsonov return Res;
53657f8837aSAlexey Samsonov }
53757f8837aSAlexey Samsonov
538f27f3f84SReid Kleckner Expected<ObjectFile *>
getOrCreateObject(const std::string & Path,const std::string & ArchName)5391eaae4c3SAlexey Samsonov LLVMSymbolizer::getOrCreateObject(const std::string &Path,
54057f8837aSAlexey Samsonov const std::string &ArchName) {
54122e478f0SFangrui Song Binary *Bin;
54222e478f0SFangrui Song auto Pair = BinaryForPath.emplace(Path, OwningBinary<Binary>());
54322e478f0SFangrui Song if (!Pair.second) {
54402106ec1SDaniel Thornburgh Bin = Pair.first->second->getBinary();
54502106ec1SDaniel Thornburgh recordAccess(Pair.first->second);
5461eaae4c3SAlexey Samsonov } else {
54722e478f0SFangrui Song Expected<OwningBinary<Binary>> BinOrErr = createBinary(Path);
54822e478f0SFangrui Song if (!BinOrErr)
54922e478f0SFangrui Song return BinOrErr.takeError();
55002106ec1SDaniel Thornburgh
55102106ec1SDaniel Thornburgh CachedBinary &CachedBin = Pair.first->second;
55202106ec1SDaniel Thornburgh CachedBin = std::move(BinOrErr.get());
55302106ec1SDaniel Thornburgh CachedBin.pushEvictor([this, I = Pair.first]() { BinaryForPath.erase(I); });
55402106ec1SDaniel Thornburgh LRUBinaries.push_back(CachedBin);
55502106ec1SDaniel Thornburgh CacheSize += CachedBin.size();
55602106ec1SDaniel Thornburgh Bin = CachedBin->getBinary();
5571eaae4c3SAlexey Samsonov }
5581eaae4c3SAlexey Samsonov
559f27f3f84SReid Kleckner if (!Bin)
560f27f3f84SReid Kleckner return static_cast<ObjectFile *>(nullptr);
5611eaae4c3SAlexey Samsonov
562f27f3f84SReid Kleckner if (MachOUniversalBinary *UB = dyn_cast_or_null<MachOUniversalBinary>(Bin)) {
56322e478f0SFangrui Song auto I = ObjectForUBPathAndArch.find(std::make_pair(Path, ArchName));
56422e478f0SFangrui Song if (I != ObjectForUBPathAndArch.end())
565f27f3f84SReid Kleckner return I->second.get();
56622e478f0SFangrui Song
5679acb1099SKevin Enderby Expected<std::unique_ptr<ObjectFile>> ObjOrErr =
5684fd11c1eSAlexander Shaposhnikov UB->getMachOObjectForArch(ArchName);
5699acb1099SKevin Enderby if (!ObjOrErr) {
57022e478f0SFangrui Song ObjectForUBPathAndArch.emplace(std::make_pair(Path, ArchName),
57122e478f0SFangrui Song std::unique_ptr<ObjectFile>());
572f27f3f84SReid Kleckner return ObjOrErr.takeError();
5731eaae4c3SAlexey Samsonov }
5741eaae4c3SAlexey Samsonov ObjectFile *Res = ObjOrErr->get();
57502106ec1SDaniel Thornburgh auto Pair = ObjectForUBPathAndArch.emplace(std::make_pair(Path, ArchName),
57622e478f0SFangrui Song std::move(ObjOrErr.get()));
57702106ec1SDaniel Thornburgh BinaryForPath.find(Path)->second.pushEvictor(
57802106ec1SDaniel Thornburgh [this, Iter = Pair.first]() { ObjectForUBPathAndArch.erase(Iter); });
57957f8837aSAlexey Samsonov return Res;
58057f8837aSAlexey Samsonov }
581884adda0SAlexey Samsonov if (Bin->isObject()) {
582884adda0SAlexey Samsonov return cast<ObjectFile>(Bin);
583884adda0SAlexey Samsonov }
584f27f3f84SReid Kleckner return errorCodeToError(object_error::arch_not_found);
585884adda0SAlexey Samsonov }
58657f8837aSAlexey Samsonov
587f27f3f84SReid Kleckner Expected<SymbolizableModule *>
createModuleInfo(const ObjectFile * Obj,std::unique_ptr<DIContext> Context,StringRef ModuleName)5885de4692cSYuanfang Chen LLVMSymbolizer::createModuleInfo(const ObjectFile *Obj,
5895de4692cSYuanfang Chen std::unique_ptr<DIContext> Context,
5905de4692cSYuanfang Chen StringRef ModuleName) {
591a56d81f4SPeter Collingbourne auto InfoOrErr = SymbolizableObjectFile::create(Obj, std::move(Context),
592a56d81f4SPeter Collingbourne Opts.UntagAddresses);
5935de4692cSYuanfang Chen std::unique_ptr<SymbolizableModule> SymMod;
5945de4692cSYuanfang Chen if (InfoOrErr)
5955de4692cSYuanfang Chen SymMod = std::move(*InfoOrErr);
596ddf77f10SBenjamin Kramer auto InsertResult = Modules.insert(
597ddf77f10SBenjamin Kramer std::make_pair(std::string(ModuleName), std::move(SymMod)));
5985de4692cSYuanfang Chen assert(InsertResult.second);
5991c03389cSReid Kleckner if (!InfoOrErr)
6001c03389cSReid Kleckner return InfoOrErr.takeError();
6015de4692cSYuanfang Chen return InsertResult.first->second.get();
6025de4692cSYuanfang Chen }
6035de4692cSYuanfang Chen
6045de4692cSYuanfang Chen Expected<SymbolizableModule *>
getOrCreateModuleInfo(const std::string & ModuleName)605e5bdedacSPeter Collingbourne LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
60657f8837aSAlexey Samsonov std::string BinaryName = ModuleName;
60757f8837aSAlexey Samsonov std::string ArchName = Opts.DefaultArch;
60857f8837aSAlexey Samsonov size_t ColonPos = ModuleName.find_last_of(':');
60957f8837aSAlexey Samsonov // Verify that substring after colon form a valid arch name.
61057f8837aSAlexey Samsonov if (ColonPos != std::string::npos) {
61157f8837aSAlexey Samsonov std::string ArchStr = ModuleName.substr(ColonPos + 1);
61257f8837aSAlexey Samsonov if (Triple(ArchStr).getArch() != Triple::UnknownArch) {
61357f8837aSAlexey Samsonov BinaryName = ModuleName.substr(0, ColonPos);
61457f8837aSAlexey Samsonov ArchName = ArchStr;
61557f8837aSAlexey Samsonov }
61657f8837aSAlexey Samsonov }
61702106ec1SDaniel Thornburgh
61802106ec1SDaniel Thornburgh auto I = Modules.find(ModuleName);
61902106ec1SDaniel Thornburgh if (I != Modules.end()) {
62002106ec1SDaniel Thornburgh recordAccess(BinaryForPath.find(BinaryName)->second);
62102106ec1SDaniel Thornburgh return I->second.get();
62202106ec1SDaniel Thornburgh }
62302106ec1SDaniel Thornburgh
6241eaae4c3SAlexey Samsonov auto ObjectsOrErr = getOrCreateObjectPair(BinaryName, ArchName);
625f27f3f84SReid Kleckner if (!ObjectsOrErr) {
62657f8837aSAlexey Samsonov // Failed to find valid object file.
62722e478f0SFangrui Song Modules.emplace(ModuleName, std::unique_ptr<SymbolizableModule>());
628f27f3f84SReid Kleckner return ObjectsOrErr.takeError();
62957f8837aSAlexey Samsonov }
630884adda0SAlexey Samsonov ObjectPair Objects = ObjectsOrErr.get();
631884adda0SAlexey Samsonov
6327a952e53SAlexey Samsonov std::unique_ptr<DIContext> Context;
633f27f3f84SReid Kleckner // If this is a COFF object containing PDB info, use a PDBContext to
634f27f3f84SReid Kleckner // symbolize. Otherwise, use DWARF.
63557f8837aSAlexey Samsonov if (auto CoffObject = dyn_cast<COFFObjectFile>(Objects.first)) {
63601528021SSaleem Abdulrasool const codeview::DebugInfo *DebugInfo;
637f27f3f84SReid Kleckner StringRef PDBFileName;
63801528021SSaleem Abdulrasool auto EC = CoffObject->getDebugPDBInfo(DebugInfo, PDBFileName);
639d1882f21SReid Kleckner if (!EC && DebugInfo != nullptr && !PDBFileName.empty()) {
640ec28fc34SZachary Turner using namespace pdb;
64157f8837aSAlexey Samsonov std::unique_ptr<IPDBSession> Session;
642724bf4eeSAmy Huang
643efd1ec0dSAmy Huang PDB_ReaderType ReaderType =
644efd1ec0dSAmy Huang Opts.UseDIA ? PDB_ReaderType::DIA : PDB_ReaderType::Native;
645641ae73fSAmy Huang if (auto Err = loadDataForEXE(ReaderType, Objects.first->getFileName(),
646641ae73fSAmy Huang Session)) {
64722e478f0SFangrui Song Modules.emplace(ModuleName, std::unique_ptr<SymbolizableModule>());
6486a7efef4SAlexandre Ganea // Return along the PDB filename to provide more context
6496a7efef4SAlexandre Ganea return createFileError(PDBFileName, std::move(Err));
650f27f3f84SReid Kleckner }
6517a952e53SAlexey Samsonov Context.reset(new PDBContext(*CoffObject, std::move(Session)));
65257f8837aSAlexey Samsonov }
65357f8837aSAlexey Samsonov }
65457f8837aSAlexey Samsonov if (!Context)
6555a865b0bSAlexander Yermolovich Context = DWARFContext::create(
6565a865b0bSAlexander Yermolovich *Objects.second, DWARFContext::ProcessDebugRelocations::Process,
6575a865b0bSAlexander Yermolovich nullptr, Opts.DWPName);
65802106ec1SDaniel Thornburgh auto ModuleOrErr =
65902106ec1SDaniel Thornburgh createModuleInfo(Objects.first, std::move(Context), ModuleName);
66002106ec1SDaniel Thornburgh if (ModuleOrErr) {
66102106ec1SDaniel Thornburgh auto I = Modules.find(ModuleName);
66202106ec1SDaniel Thornburgh BinaryForPath.find(BinaryName)->second.pushEvictor([this, I]() {
66302106ec1SDaniel Thornburgh Modules.erase(I);
66402106ec1SDaniel Thornburgh });
66502106ec1SDaniel Thornburgh }
66602106ec1SDaniel Thornburgh return ModuleOrErr;
66757f8837aSAlexey Samsonov }
66857f8837aSAlexey Samsonov
66912999d74SScott Linder Expected<SymbolizableModule *>
getOrCreateModuleInfo(const ObjectFile & Obj)67012999d74SScott Linder LLVMSymbolizer::getOrCreateModuleInfo(const ObjectFile &Obj) {
67112999d74SScott Linder StringRef ObjName = Obj.getFileName();
67212999d74SScott Linder auto I = Modules.find(ObjName);
67312999d74SScott Linder if (I != Modules.end())
67412999d74SScott Linder return I->second.get();
67512999d74SScott Linder
67612999d74SScott Linder std::unique_ptr<DIContext> Context = DWARFContext::create(Obj);
67712999d74SScott Linder // FIXME: handle COFF object with PDB info to use PDBContext
67812999d74SScott Linder return createModuleInfo(&Obj, std::move(Context), ObjName);
67912999d74SScott Linder }
68012999d74SScott Linder
681dcd4950dSDaniel Thornburgh Expected<SymbolizableModule *>
getOrCreateModuleInfo(ArrayRef<uint8_t> BuildID)682dcd4950dSDaniel Thornburgh LLVMSymbolizer::getOrCreateModuleInfo(ArrayRef<uint8_t> BuildID) {
683dcd4950dSDaniel Thornburgh std::string Path;
684dcd4950dSDaniel Thornburgh if (!getOrFindDebugBinary(BuildID, Path)) {
685dcd4950dSDaniel Thornburgh return createStringError(errc::no_such_file_or_directory,
686dcd4950dSDaniel Thornburgh Twine("could not find build ID '") +
687dcd4950dSDaniel Thornburgh toHex(BuildID) + "'");
688dcd4950dSDaniel Thornburgh }
689dcd4950dSDaniel Thornburgh return getOrCreateModuleInfo(Path);
690dcd4950dSDaniel Thornburgh }
691dcd4950dSDaniel Thornburgh
69235623fb7SEugene Zelenko namespace {
69335623fb7SEugene Zelenko
69457f8837aSAlexey Samsonov // Undo these various manglings for Win32 extern "C" functions:
69557f8837aSAlexey Samsonov // cdecl - _foo
69657f8837aSAlexey Samsonov // stdcall - _foo@12
69757f8837aSAlexey Samsonov // fastcall - @foo@12
69857f8837aSAlexey Samsonov // vectorcall - foo@@12
69957f8837aSAlexey Samsonov // These are all different linkage names for 'foo'.
demanglePE32ExternCFunc(StringRef SymbolName)70035623fb7SEugene Zelenko StringRef demanglePE32ExternCFunc(StringRef SymbolName) {
70157f8837aSAlexey Samsonov // Remove any '_' or '@' prefix.
70257f8837aSAlexey Samsonov char Front = SymbolName.empty() ? '\0' : SymbolName[0];
70357f8837aSAlexey Samsonov if (Front == '_' || Front == '@')
70457f8837aSAlexey Samsonov SymbolName = SymbolName.drop_front();
70557f8837aSAlexey Samsonov
70657f8837aSAlexey Samsonov // Remove any '@[0-9]+' suffix.
70757f8837aSAlexey Samsonov if (Front != '?') {
70857f8837aSAlexey Samsonov size_t AtPos = SymbolName.rfind('@');
70957f8837aSAlexey Samsonov if (AtPos != StringRef::npos &&
710551aaa24SKazu Hirata all_of(drop_begin(SymbolName, AtPos + 1), isDigit))
71157f8837aSAlexey Samsonov SymbolName = SymbolName.substr(0, AtPos);
71257f8837aSAlexey Samsonov }
71357f8837aSAlexey Samsonov
71457f8837aSAlexey Samsonov // Remove any ending '@' for vectorcall.
71557f8837aSAlexey Samsonov if (SymbolName.endswith("@"))
71657f8837aSAlexey Samsonov SymbolName = SymbolName.drop_back();
71757f8837aSAlexey Samsonov
71857f8837aSAlexey Samsonov return SymbolName;
71957f8837aSAlexey Samsonov }
72057f8837aSAlexey Samsonov
72135623fb7SEugene Zelenko } // end anonymous namespace
72235623fb7SEugene Zelenko
72367c56014SZachary Turner std::string
DemangleName(const std::string & Name,const SymbolizableModule * DbiModuleDescriptor)72467c56014SZachary Turner LLVMSymbolizer::DemangleName(const std::string &Name,
72567c56014SZachary Turner const SymbolizableModule *DbiModuleDescriptor) {
72648ce523aSTomasz Miąsko std::string Result;
72748ce523aSTomasz Miąsko if (nonMicrosoftDemangle(Name.c_str(), Result))
728b8f79023SMartin Storsjo return Result;
729cd72cbc6SEugene Zemtsov
730b8f79023SMartin Storsjo if (!Name.empty() && Name.front() == '?') {
731b8f79023SMartin Storsjo // Only do MSVC C++ demangling on symbols starting with '?'.
732a4f6b598SMartin Storsjo int status = 0;
733a4f6b598SMartin Storsjo char *DemangledName = microsoftDemangle(
734bc1c3655SNico Weber Name.c_str(), nullptr, nullptr, nullptr, &status,
735a4f6b598SMartin Storsjo MSDemangleFlags(MSDF_NoAccessSpecifier | MSDF_NoCallingConvention |
736a4f6b598SMartin Storsjo MSDF_NoMemberType | MSDF_NoReturnType));
737a4f6b598SMartin Storsjo if (status != 0)
738a4f6b598SMartin Storsjo return Name;
73948ce523aSTomasz Miąsko Result = DemangledName;
740a4f6b598SMartin Storsjo free(DemangledName);
741a4f6b598SMartin Storsjo return Result;
742b8f79023SMartin Storsjo }
743a4f6b598SMartin Storsjo
74467c56014SZachary Turner if (DbiModuleDescriptor && DbiModuleDescriptor->isWin32Module())
74557f8837aSAlexey Samsonov return std::string(demanglePE32ExternCFunc(Name));
74657f8837aSAlexey Samsonov return Name;
74757f8837aSAlexey Samsonov }
74857f8837aSAlexey Samsonov
recordAccess(CachedBinary & Bin)74902106ec1SDaniel Thornburgh void LLVMSymbolizer::recordAccess(CachedBinary &Bin) {
75002106ec1SDaniel Thornburgh if (Bin->getBinary())
75102106ec1SDaniel Thornburgh LRUBinaries.splice(LRUBinaries.end(), LRUBinaries, Bin.getIterator());
75202106ec1SDaniel Thornburgh }
75302106ec1SDaniel Thornburgh
pruneCache()75402106ec1SDaniel Thornburgh void LLVMSymbolizer::pruneCache() {
75502106ec1SDaniel Thornburgh // Evict the LRU binary until the max cache size is reached or there's <= 1
75602106ec1SDaniel Thornburgh // item in the cache. The MRU binary is always kept to avoid thrashing if it's
75702106ec1SDaniel Thornburgh // larger than the cache size.
75802106ec1SDaniel Thornburgh while (CacheSize > Opts.MaxCacheSize && !LRUBinaries.empty() &&
75902106ec1SDaniel Thornburgh std::next(LRUBinaries.begin()) != LRUBinaries.end()) {
76002106ec1SDaniel Thornburgh CachedBinary &Bin = LRUBinaries.front();
76102106ec1SDaniel Thornburgh CacheSize -= Bin.size();
76202106ec1SDaniel Thornburgh LRUBinaries.pop_front();
76302106ec1SDaniel Thornburgh Bin.evict();
76402106ec1SDaniel Thornburgh }
76502106ec1SDaniel Thornburgh }
76602106ec1SDaniel Thornburgh
pushEvictor(std::function<void ()> NewEvictor)76702106ec1SDaniel Thornburgh void CachedBinary::pushEvictor(std::function<void()> NewEvictor) {
76802106ec1SDaniel Thornburgh if (Evictor) {
76902106ec1SDaniel Thornburgh this->Evictor = [OldEvictor = std::move(this->Evictor),
77002106ec1SDaniel Thornburgh NewEvictor = std::move(NewEvictor)]() {
77102106ec1SDaniel Thornburgh NewEvictor();
77202106ec1SDaniel Thornburgh OldEvictor();
77302106ec1SDaniel Thornburgh };
77402106ec1SDaniel Thornburgh } else {
77502106ec1SDaniel Thornburgh this->Evictor = std::move(NewEvictor);
77602106ec1SDaniel Thornburgh }
77702106ec1SDaniel Thornburgh }
77802106ec1SDaniel Thornburgh
77957f8837aSAlexey Samsonov } // namespace symbolize
78057f8837aSAlexey Samsonov } // namespace llvm
781