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