xref: /freebsd-src/contrib/llvm-project/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===-- LLVMSymbolize.cpp -------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // Implementation for LLVM symbolization library.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "llvm/DebugInfo/Symbolize/Symbolize.h"
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
1606c3fb27SDimitry Andric #include "llvm/DebugInfo/BTF/BTFContext.h"
170b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFContext.h"
180b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/PDB.h"
190b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/PDBContext.h"
2081ad6265SDimitry Andric #include "llvm/DebugInfo/Symbolize/SymbolizableObjectFile.h"
210b57cec5SDimitry Andric #include "llvm/Demangle/Demangle.h"
22bdd1243dSDimitry Andric #include "llvm/Object/BuildID.h"
230b57cec5SDimitry Andric #include "llvm/Object/COFF.h"
2481ad6265SDimitry Andric #include "llvm/Object/ELFObjectFile.h"
250b57cec5SDimitry Andric #include "llvm/Object/MachO.h"
260b57cec5SDimitry Andric #include "llvm/Object/MachOUniversal.h"
270b57cec5SDimitry Andric #include "llvm/Support/CRC.h"
280b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
290b57cec5SDimitry Andric #include "llvm/Support/DataExtractor.h"
300b57cec5SDimitry Andric #include "llvm/Support/Errc.h"
310b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
320b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
330b57cec5SDimitry Andric #include "llvm/Support/Path.h"
340b57cec5SDimitry Andric #include <algorithm>
350b57cec5SDimitry Andric #include <cassert>
360b57cec5SDimitry Andric #include <cstring>
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric namespace llvm {
3981ad6265SDimitry Andric namespace codeview {
4081ad6265SDimitry Andric union DebugInfo;
4181ad6265SDimitry Andric }
420b57cec5SDimitry Andric namespace symbolize {
430b57cec5SDimitry Andric 
4481ad6265SDimitry Andric LLVMSymbolizer::LLVMSymbolizer() = default;
4581ad6265SDimitry Andric 
46bdd1243dSDimitry Andric LLVMSymbolizer::LLVMSymbolizer(const Options &Opts)
47bdd1243dSDimitry Andric     : Opts(Opts),
48bdd1243dSDimitry Andric       BIDFetcher(std::make_unique<BuildIDFetcher>(Opts.DebugFileDirectory)) {}
4981ad6265SDimitry Andric 
5081ad6265SDimitry Andric LLVMSymbolizer::~LLVMSymbolizer() = default;
5181ad6265SDimitry Andric 
52fe6060f1SDimitry Andric template <typename T>
530b57cec5SDimitry Andric Expected<DILineInfo>
54fe6060f1SDimitry Andric LLVMSymbolizer::symbolizeCodeCommon(const T &ModuleSpecifier,
550b57cec5SDimitry Andric                                     object::SectionedAddress ModuleOffset) {
56fe6060f1SDimitry Andric 
57fe6060f1SDimitry Andric   auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
58fe6060f1SDimitry Andric   if (!InfoOrErr)
59fe6060f1SDimitry Andric     return InfoOrErr.takeError();
60fe6060f1SDimitry Andric 
61fe6060f1SDimitry Andric   SymbolizableModule *Info = *InfoOrErr;
62fe6060f1SDimitry Andric 
630b57cec5SDimitry Andric   // A null module means an error has already been reported. Return an empty
640b57cec5SDimitry Andric   // result.
650b57cec5SDimitry Andric   if (!Info)
660b57cec5SDimitry Andric     return DILineInfo();
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric   // If the user is giving us relative addresses, add the preferred base of the
690b57cec5SDimitry Andric   // object to the offset before we do the query. It's what DIContext expects.
700b57cec5SDimitry Andric   if (Opts.RelativeAddresses)
710b57cec5SDimitry Andric     ModuleOffset.Address += Info->getModulePreferredBase();
720b57cec5SDimitry Andric 
735ffd83dbSDimitry Andric   DILineInfo LineInfo = Info->symbolizeCode(
745ffd83dbSDimitry Andric       ModuleOffset, DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions),
750b57cec5SDimitry Andric       Opts.UseSymbolTable);
760b57cec5SDimitry Andric   if (Opts.Demangle)
770b57cec5SDimitry Andric     LineInfo.FunctionName = DemangleName(LineInfo.FunctionName, Info);
780b57cec5SDimitry Andric   return LineInfo;
790b57cec5SDimitry Andric }
800b57cec5SDimitry Andric 
810b57cec5SDimitry Andric Expected<DILineInfo>
820b57cec5SDimitry Andric LLVMSymbolizer::symbolizeCode(const ObjectFile &Obj,
830b57cec5SDimitry Andric                               object::SectionedAddress ModuleOffset) {
84fe6060f1SDimitry Andric   return symbolizeCodeCommon(Obj, ModuleOffset);
850b57cec5SDimitry Andric }
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric Expected<DILineInfo>
880b57cec5SDimitry Andric LLVMSymbolizer::symbolizeCode(const std::string &ModuleName,
890b57cec5SDimitry Andric                               object::SectionedAddress ModuleOffset) {
90fe6060f1SDimitry Andric   return symbolizeCodeCommon(ModuleName, ModuleOffset);
910b57cec5SDimitry Andric }
920b57cec5SDimitry Andric 
9381ad6265SDimitry Andric Expected<DILineInfo>
9481ad6265SDimitry Andric LLVMSymbolizer::symbolizeCode(ArrayRef<uint8_t> BuildID,
9581ad6265SDimitry Andric                               object::SectionedAddress ModuleOffset) {
9681ad6265SDimitry Andric   return symbolizeCodeCommon(BuildID, ModuleOffset);
9781ad6265SDimitry Andric }
9881ad6265SDimitry Andric 
99fe6060f1SDimitry Andric template <typename T>
100fe6060f1SDimitry Andric Expected<DIInliningInfo> LLVMSymbolizer::symbolizeInlinedCodeCommon(
101fe6060f1SDimitry Andric     const T &ModuleSpecifier, object::SectionedAddress ModuleOffset) {
102fe6060f1SDimitry Andric   auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
103fe6060f1SDimitry Andric   if (!InfoOrErr)
1040b57cec5SDimitry Andric     return InfoOrErr.takeError();
1050b57cec5SDimitry Andric 
106fe6060f1SDimitry Andric   SymbolizableModule *Info = *InfoOrErr;
107fe6060f1SDimitry Andric 
1080b57cec5SDimitry Andric   // A null module means an error has already been reported. Return an empty
1090b57cec5SDimitry Andric   // result.
1100b57cec5SDimitry Andric   if (!Info)
1110b57cec5SDimitry Andric     return DIInliningInfo();
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric   // If the user is giving us relative addresses, add the preferred base of the
1140b57cec5SDimitry Andric   // object to the offset before we do the query. It's what DIContext expects.
1150b57cec5SDimitry Andric   if (Opts.RelativeAddresses)
1160b57cec5SDimitry Andric     ModuleOffset.Address += Info->getModulePreferredBase();
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric   DIInliningInfo InlinedContext = Info->symbolizeInlinedCode(
1195ffd83dbSDimitry Andric       ModuleOffset, DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions),
1205ffd83dbSDimitry Andric       Opts.UseSymbolTable);
1210b57cec5SDimitry Andric   if (Opts.Demangle) {
1220b57cec5SDimitry Andric     for (int i = 0, n = InlinedContext.getNumberOfFrames(); i < n; i++) {
1230b57cec5SDimitry Andric       auto *Frame = InlinedContext.getMutableFrame(i);
1240b57cec5SDimitry Andric       Frame->FunctionName = DemangleName(Frame->FunctionName, Info);
1250b57cec5SDimitry Andric     }
1260b57cec5SDimitry Andric   }
1270b57cec5SDimitry Andric   return InlinedContext;
1280b57cec5SDimitry Andric }
1290b57cec5SDimitry Andric 
130fe6060f1SDimitry Andric Expected<DIInliningInfo>
131fe6060f1SDimitry Andric LLVMSymbolizer::symbolizeInlinedCode(const ObjectFile &Obj,
1320b57cec5SDimitry Andric                                      object::SectionedAddress ModuleOffset) {
133fe6060f1SDimitry Andric   return symbolizeInlinedCodeCommon(Obj, ModuleOffset);
134fe6060f1SDimitry Andric }
135fe6060f1SDimitry Andric 
136fe6060f1SDimitry Andric Expected<DIInliningInfo>
137fe6060f1SDimitry Andric LLVMSymbolizer::symbolizeInlinedCode(const std::string &ModuleName,
138fe6060f1SDimitry Andric                                      object::SectionedAddress ModuleOffset) {
139fe6060f1SDimitry Andric   return symbolizeInlinedCodeCommon(ModuleName, ModuleOffset);
140fe6060f1SDimitry Andric }
141fe6060f1SDimitry Andric 
14281ad6265SDimitry Andric Expected<DIInliningInfo>
14381ad6265SDimitry Andric LLVMSymbolizer::symbolizeInlinedCode(ArrayRef<uint8_t> BuildID,
14481ad6265SDimitry Andric                                      object::SectionedAddress ModuleOffset) {
14581ad6265SDimitry Andric   return symbolizeInlinedCodeCommon(BuildID, ModuleOffset);
14681ad6265SDimitry Andric }
14781ad6265SDimitry Andric 
148fe6060f1SDimitry Andric template <typename T>
149fe6060f1SDimitry Andric Expected<DIGlobal>
150fe6060f1SDimitry Andric LLVMSymbolizer::symbolizeDataCommon(const T &ModuleSpecifier,
151fe6060f1SDimitry Andric                                     object::SectionedAddress ModuleOffset) {
152fe6060f1SDimitry Andric 
153fe6060f1SDimitry Andric   auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
154fe6060f1SDimitry Andric   if (!InfoOrErr)
1550b57cec5SDimitry Andric     return InfoOrErr.takeError();
1560b57cec5SDimitry Andric 
157fe6060f1SDimitry Andric   SymbolizableModule *Info = *InfoOrErr;
1580b57cec5SDimitry Andric   // A null module means an error has already been reported. Return an empty
1590b57cec5SDimitry Andric   // result.
1600b57cec5SDimitry Andric   if (!Info)
1610b57cec5SDimitry Andric     return DIGlobal();
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric   // If the user is giving us relative addresses, add the preferred base of
1640b57cec5SDimitry Andric   // the object to the offset before we do the query. It's what DIContext
1650b57cec5SDimitry Andric   // expects.
1660b57cec5SDimitry Andric   if (Opts.RelativeAddresses)
1670b57cec5SDimitry Andric     ModuleOffset.Address += Info->getModulePreferredBase();
1680b57cec5SDimitry Andric 
1690b57cec5SDimitry Andric   DIGlobal Global = Info->symbolizeData(ModuleOffset);
1700b57cec5SDimitry Andric   if (Opts.Demangle)
1710b57cec5SDimitry Andric     Global.Name = DemangleName(Global.Name, Info);
1720b57cec5SDimitry Andric   return Global;
1730b57cec5SDimitry Andric }
1740b57cec5SDimitry Andric 
175fe6060f1SDimitry Andric Expected<DIGlobal>
176fe6060f1SDimitry Andric LLVMSymbolizer::symbolizeData(const ObjectFile &Obj,
1770b57cec5SDimitry Andric                               object::SectionedAddress ModuleOffset) {
178fe6060f1SDimitry Andric   return symbolizeDataCommon(Obj, ModuleOffset);
179fe6060f1SDimitry Andric }
180fe6060f1SDimitry Andric 
181fe6060f1SDimitry Andric Expected<DIGlobal>
182fe6060f1SDimitry Andric LLVMSymbolizer::symbolizeData(const std::string &ModuleName,
183fe6060f1SDimitry Andric                               object::SectionedAddress ModuleOffset) {
184fe6060f1SDimitry Andric   return symbolizeDataCommon(ModuleName, ModuleOffset);
185fe6060f1SDimitry Andric }
186fe6060f1SDimitry Andric 
18781ad6265SDimitry Andric Expected<DIGlobal>
18881ad6265SDimitry Andric LLVMSymbolizer::symbolizeData(ArrayRef<uint8_t> BuildID,
18981ad6265SDimitry Andric                               object::SectionedAddress ModuleOffset) {
19081ad6265SDimitry Andric   return symbolizeDataCommon(BuildID, ModuleOffset);
19181ad6265SDimitry Andric }
19281ad6265SDimitry Andric 
193fe6060f1SDimitry Andric template <typename T>
194fe6060f1SDimitry Andric Expected<std::vector<DILocal>>
195fe6060f1SDimitry Andric LLVMSymbolizer::symbolizeFrameCommon(const T &ModuleSpecifier,
196fe6060f1SDimitry Andric                                      object::SectionedAddress ModuleOffset) {
197fe6060f1SDimitry Andric   auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
198fe6060f1SDimitry Andric   if (!InfoOrErr)
1990b57cec5SDimitry Andric     return InfoOrErr.takeError();
2000b57cec5SDimitry Andric 
201fe6060f1SDimitry Andric   SymbolizableModule *Info = *InfoOrErr;
2020b57cec5SDimitry Andric   // A null module means an error has already been reported. Return an empty
2030b57cec5SDimitry Andric   // result.
2040b57cec5SDimitry Andric   if (!Info)
2050b57cec5SDimitry Andric     return std::vector<DILocal>();
2060b57cec5SDimitry Andric 
2070b57cec5SDimitry Andric   // If the user is giving us relative addresses, add the preferred base of
2080b57cec5SDimitry Andric   // the object to the offset before we do the query. It's what DIContext
2090b57cec5SDimitry Andric   // expects.
2100b57cec5SDimitry Andric   if (Opts.RelativeAddresses)
2110b57cec5SDimitry Andric     ModuleOffset.Address += Info->getModulePreferredBase();
2120b57cec5SDimitry Andric 
2130b57cec5SDimitry Andric   return Info->symbolizeFrame(ModuleOffset);
2140b57cec5SDimitry Andric }
2150b57cec5SDimitry Andric 
216fe6060f1SDimitry Andric Expected<std::vector<DILocal>>
217fe6060f1SDimitry Andric LLVMSymbolizer::symbolizeFrame(const ObjectFile &Obj,
218fe6060f1SDimitry Andric                                object::SectionedAddress ModuleOffset) {
219fe6060f1SDimitry Andric   return symbolizeFrameCommon(Obj, ModuleOffset);
220fe6060f1SDimitry Andric }
221fe6060f1SDimitry Andric 
222fe6060f1SDimitry Andric Expected<std::vector<DILocal>>
223fe6060f1SDimitry Andric LLVMSymbolizer::symbolizeFrame(const std::string &ModuleName,
224fe6060f1SDimitry Andric                                object::SectionedAddress ModuleOffset) {
225fe6060f1SDimitry Andric   return symbolizeFrameCommon(ModuleName, ModuleOffset);
226fe6060f1SDimitry Andric }
227fe6060f1SDimitry Andric 
22881ad6265SDimitry Andric Expected<std::vector<DILocal>>
22981ad6265SDimitry Andric LLVMSymbolizer::symbolizeFrame(ArrayRef<uint8_t> BuildID,
23081ad6265SDimitry Andric                                object::SectionedAddress ModuleOffset) {
23181ad6265SDimitry Andric   return symbolizeFrameCommon(BuildID, ModuleOffset);
23281ad6265SDimitry Andric }
23381ad6265SDimitry Andric 
2345f757f3fSDimitry Andric template <typename T>
2355f757f3fSDimitry Andric Expected<std::vector<DILineInfo>>
2365f757f3fSDimitry Andric LLVMSymbolizer::findSymbolCommon(const T &ModuleSpecifier, StringRef Symbol,
2375f757f3fSDimitry Andric                                  uint64_t Offset) {
2385f757f3fSDimitry Andric   auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
2395f757f3fSDimitry Andric   if (!InfoOrErr)
2405f757f3fSDimitry Andric     return InfoOrErr.takeError();
2415f757f3fSDimitry Andric 
2425f757f3fSDimitry Andric   SymbolizableModule *Info = *InfoOrErr;
2435f757f3fSDimitry Andric   std::vector<DILineInfo> Result;
2445f757f3fSDimitry Andric 
2455f757f3fSDimitry Andric   // A null module means an error has already been reported. Return an empty
2465f757f3fSDimitry Andric   // result.
2475f757f3fSDimitry Andric   if (!Info)
2485f757f3fSDimitry Andric     return Result;
2495f757f3fSDimitry Andric 
2505f757f3fSDimitry Andric   for (object::SectionedAddress A : Info->findSymbol(Symbol, Offset)) {
2515f757f3fSDimitry Andric     DILineInfo LineInfo = Info->symbolizeCode(
2525f757f3fSDimitry Andric         A, DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions),
2535f757f3fSDimitry Andric         Opts.UseSymbolTable);
2545f757f3fSDimitry Andric     if (LineInfo.FileName != DILineInfo::BadString) {
2555f757f3fSDimitry Andric       if (Opts.Demangle)
2565f757f3fSDimitry Andric         LineInfo.FunctionName = DemangleName(LineInfo.FunctionName, Info);
2575f757f3fSDimitry Andric       Result.push_back(LineInfo);
2585f757f3fSDimitry Andric     }
2595f757f3fSDimitry Andric   }
2605f757f3fSDimitry Andric 
2615f757f3fSDimitry Andric   return Result;
2625f757f3fSDimitry Andric }
2635f757f3fSDimitry Andric 
2645f757f3fSDimitry Andric Expected<std::vector<DILineInfo>>
2655f757f3fSDimitry Andric LLVMSymbolizer::findSymbol(const ObjectFile &Obj, StringRef Symbol,
2665f757f3fSDimitry Andric                            uint64_t Offset) {
2675f757f3fSDimitry Andric   return findSymbolCommon(Obj, Symbol, Offset);
2685f757f3fSDimitry Andric }
2695f757f3fSDimitry Andric 
2705f757f3fSDimitry Andric Expected<std::vector<DILineInfo>>
2715f757f3fSDimitry Andric LLVMSymbolizer::findSymbol(const std::string &ModuleName, StringRef Symbol,
2725f757f3fSDimitry Andric                            uint64_t Offset) {
2735f757f3fSDimitry Andric   return findSymbolCommon(ModuleName, Symbol, Offset);
2745f757f3fSDimitry Andric }
2755f757f3fSDimitry Andric 
2765f757f3fSDimitry Andric Expected<std::vector<DILineInfo>>
2775f757f3fSDimitry Andric LLVMSymbolizer::findSymbol(ArrayRef<uint8_t> BuildID, StringRef Symbol,
2785f757f3fSDimitry Andric                            uint64_t Offset) {
2795f757f3fSDimitry Andric   return findSymbolCommon(BuildID, Symbol, Offset);
2805f757f3fSDimitry Andric }
2815f757f3fSDimitry Andric 
2820b57cec5SDimitry Andric void LLVMSymbolizer::flush() {
2830b57cec5SDimitry Andric   ObjectForUBPathAndArch.clear();
28481ad6265SDimitry Andric   LRUBinaries.clear();
28581ad6265SDimitry Andric   CacheSize = 0;
2860b57cec5SDimitry Andric   BinaryForPath.clear();
2870b57cec5SDimitry Andric   ObjectPairForPathArch.clear();
2880b57cec5SDimitry Andric   Modules.clear();
28981ad6265SDimitry Andric   BuildIDPaths.clear();
2900b57cec5SDimitry Andric }
2910b57cec5SDimitry Andric 
2920b57cec5SDimitry Andric namespace {
2930b57cec5SDimitry Andric 
2940b57cec5SDimitry Andric // For Path="/path/to/foo" and Basename="foo" assume that debug info is in
2950b57cec5SDimitry Andric // /path/to/foo.dSYM/Contents/Resources/DWARF/foo.
2960b57cec5SDimitry Andric // For Path="/path/to/bar.dSYM" and Basename="foo" assume that debug info is in
2970b57cec5SDimitry Andric // /path/to/bar.dSYM/Contents/Resources/DWARF/foo.
298fe6060f1SDimitry Andric std::string getDarwinDWARFResourceForPath(const std::string &Path,
299fe6060f1SDimitry Andric                                           const std::string &Basename) {
3000b57cec5SDimitry Andric   SmallString<16> ResourceName = StringRef(Path);
3010b57cec5SDimitry Andric   if (sys::path::extension(Path) != ".dSYM") {
3020b57cec5SDimitry Andric     ResourceName += ".dSYM";
3030b57cec5SDimitry Andric   }
3040b57cec5SDimitry Andric   sys::path::append(ResourceName, "Contents", "Resources", "DWARF");
3050b57cec5SDimitry Andric   sys::path::append(ResourceName, Basename);
3067a6dacacSDimitry Andric   return std::string(ResourceName);
3070b57cec5SDimitry Andric }
3080b57cec5SDimitry Andric 
3090b57cec5SDimitry Andric bool checkFileCRC(StringRef Path, uint32_t CRCHash) {
3100b57cec5SDimitry Andric   ErrorOr<std::unique_ptr<MemoryBuffer>> MB =
3110b57cec5SDimitry Andric       MemoryBuffer::getFileOrSTDIN(Path);
3120b57cec5SDimitry Andric   if (!MB)
3130b57cec5SDimitry Andric     return false;
3148bcb0991SDimitry Andric   return CRCHash == llvm::crc32(arrayRefFromStringRef(MB.get()->getBuffer()));
3150b57cec5SDimitry Andric }
3160b57cec5SDimitry Andric 
3170b57cec5SDimitry Andric bool getGNUDebuglinkContents(const ObjectFile *Obj, std::string &DebugName,
3180b57cec5SDimitry Andric                              uint32_t &CRCHash) {
3190b57cec5SDimitry Andric   if (!Obj)
3200b57cec5SDimitry Andric     return false;
3210b57cec5SDimitry Andric   for (const SectionRef &Section : Obj->sections()) {
3220b57cec5SDimitry Andric     StringRef Name;
323349cc55cSDimitry Andric     consumeError(Section.getName().moveInto(Name));
3248bcb0991SDimitry Andric 
3250b57cec5SDimitry Andric     Name = Name.substr(Name.find_first_not_of("._"));
3260b57cec5SDimitry Andric     if (Name == "gnu_debuglink") {
3270b57cec5SDimitry Andric       Expected<StringRef> ContentsOrErr = Section.getContents();
3280b57cec5SDimitry Andric       if (!ContentsOrErr) {
3290b57cec5SDimitry Andric         consumeError(ContentsOrErr.takeError());
3300b57cec5SDimitry Andric         return false;
3310b57cec5SDimitry Andric       }
3320b57cec5SDimitry Andric       DataExtractor DE(*ContentsOrErr, Obj->isLittleEndian(), 0);
3338bcb0991SDimitry Andric       uint64_t Offset = 0;
3340b57cec5SDimitry Andric       if (const char *DebugNameStr = DE.getCStr(&Offset)) {
3350b57cec5SDimitry Andric         // 4-byte align the offset.
3360b57cec5SDimitry Andric         Offset = (Offset + 3) & ~0x3;
3370b57cec5SDimitry Andric         if (DE.isValidOffsetForDataOfSize(Offset, 4)) {
3380b57cec5SDimitry Andric           DebugName = DebugNameStr;
3390b57cec5SDimitry Andric           CRCHash = DE.getU32(&Offset);
3400b57cec5SDimitry Andric           return true;
3410b57cec5SDimitry Andric         }
3420b57cec5SDimitry Andric       }
3430b57cec5SDimitry Andric       break;
3440b57cec5SDimitry Andric     }
3450b57cec5SDimitry Andric   }
3460b57cec5SDimitry Andric   return false;
3470b57cec5SDimitry Andric }
3480b57cec5SDimitry Andric 
3490b57cec5SDimitry Andric bool darwinDsymMatchesBinary(const MachOObjectFile *DbgObj,
3500b57cec5SDimitry Andric                              const MachOObjectFile *Obj) {
3510b57cec5SDimitry Andric   ArrayRef<uint8_t> dbg_uuid = DbgObj->getUuid();
3520b57cec5SDimitry Andric   ArrayRef<uint8_t> bin_uuid = Obj->getUuid();
3530b57cec5SDimitry Andric   if (dbg_uuid.empty() || bin_uuid.empty())
3540b57cec5SDimitry Andric     return false;
3550b57cec5SDimitry Andric   return !memcmp(dbg_uuid.data(), bin_uuid.data(), dbg_uuid.size());
3560b57cec5SDimitry Andric }
3570b57cec5SDimitry Andric 
358753f127fSDimitry Andric } // end anonymous namespace
359753f127fSDimitry Andric 
3600b57cec5SDimitry Andric ObjectFile *LLVMSymbolizer::lookUpDsymFile(const std::string &ExePath,
361fe6060f1SDimitry Andric                                            const MachOObjectFile *MachExeObj,
362fe6060f1SDimitry Andric                                            const std::string &ArchName) {
3630b57cec5SDimitry Andric   // On Darwin we may find DWARF in separate object file in
3640b57cec5SDimitry Andric   // resource directory.
3650b57cec5SDimitry Andric   std::vector<std::string> DsymPaths;
3660b57cec5SDimitry Andric   StringRef Filename = sys::path::filename(ExePath);
3675ffd83dbSDimitry Andric   DsymPaths.push_back(
3685ffd83dbSDimitry Andric       getDarwinDWARFResourceForPath(ExePath, std::string(Filename)));
3690b57cec5SDimitry Andric   for (const auto &Path : Opts.DsymHints) {
3705ffd83dbSDimitry Andric     DsymPaths.push_back(
3715ffd83dbSDimitry Andric         getDarwinDWARFResourceForPath(Path, std::string(Filename)));
3720b57cec5SDimitry Andric   }
3730b57cec5SDimitry Andric   for (const auto &Path : DsymPaths) {
3740b57cec5SDimitry Andric     auto DbgObjOrErr = getOrCreateObject(Path, ArchName);
3750b57cec5SDimitry Andric     if (!DbgObjOrErr) {
3760b57cec5SDimitry Andric       // Ignore errors, the file might not exist.
3770b57cec5SDimitry Andric       consumeError(DbgObjOrErr.takeError());
3780b57cec5SDimitry Andric       continue;
3790b57cec5SDimitry Andric     }
3800b57cec5SDimitry Andric     ObjectFile *DbgObj = DbgObjOrErr.get();
3810b57cec5SDimitry Andric     if (!DbgObj)
3820b57cec5SDimitry Andric       continue;
3830b57cec5SDimitry Andric     const MachOObjectFile *MachDbgObj = dyn_cast<const MachOObjectFile>(DbgObj);
3840b57cec5SDimitry Andric     if (!MachDbgObj)
3850b57cec5SDimitry Andric       continue;
3860b57cec5SDimitry Andric     if (darwinDsymMatchesBinary(MachDbgObj, MachExeObj))
3870b57cec5SDimitry Andric       return DbgObj;
3880b57cec5SDimitry Andric   }
3890b57cec5SDimitry Andric   return nullptr;
3900b57cec5SDimitry Andric }
3910b57cec5SDimitry Andric 
3920b57cec5SDimitry Andric ObjectFile *LLVMSymbolizer::lookUpDebuglinkObject(const std::string &Path,
3930b57cec5SDimitry Andric                                                   const ObjectFile *Obj,
3940b57cec5SDimitry Andric                                                   const std::string &ArchName) {
3950b57cec5SDimitry Andric   std::string DebuglinkName;
3960b57cec5SDimitry Andric   uint32_t CRCHash;
3970b57cec5SDimitry Andric   std::string DebugBinaryPath;
3980b57cec5SDimitry Andric   if (!getGNUDebuglinkContents(Obj, DebuglinkName, CRCHash))
3990b57cec5SDimitry Andric     return nullptr;
400d56accc7SDimitry Andric   if (!findDebugBinary(Path, DebuglinkName, CRCHash, DebugBinaryPath))
4010b57cec5SDimitry Andric     return nullptr;
4020b57cec5SDimitry Andric   auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName);
4030b57cec5SDimitry Andric   if (!DbgObjOrErr) {
4040b57cec5SDimitry Andric     // Ignore errors, the file might not exist.
4050b57cec5SDimitry Andric     consumeError(DbgObjOrErr.takeError());
4060b57cec5SDimitry Andric     return nullptr;
4070b57cec5SDimitry Andric   }
4080b57cec5SDimitry Andric   return DbgObjOrErr.get();
4090b57cec5SDimitry Andric }
4100b57cec5SDimitry Andric 
411480093f4SDimitry Andric ObjectFile *LLVMSymbolizer::lookUpBuildIDObject(const std::string &Path,
412480093f4SDimitry Andric                                                 const ELFObjectFileBase *Obj,
413480093f4SDimitry Andric                                                 const std::string &ArchName) {
414480093f4SDimitry Andric   auto BuildID = getBuildID(Obj);
41506c3fb27SDimitry Andric   if (BuildID.size() < 2)
416480093f4SDimitry Andric     return nullptr;
417480093f4SDimitry Andric   std::string DebugBinaryPath;
41806c3fb27SDimitry Andric   if (!getOrFindDebugBinary(BuildID, DebugBinaryPath))
419480093f4SDimitry Andric     return nullptr;
420480093f4SDimitry Andric   auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName);
421480093f4SDimitry Andric   if (!DbgObjOrErr) {
422480093f4SDimitry Andric     consumeError(DbgObjOrErr.takeError());
423480093f4SDimitry Andric     return nullptr;
424480093f4SDimitry Andric   }
425480093f4SDimitry Andric   return DbgObjOrErr.get();
426480093f4SDimitry Andric }
427480093f4SDimitry Andric 
428d56accc7SDimitry Andric bool LLVMSymbolizer::findDebugBinary(const std::string &OrigPath,
429d56accc7SDimitry Andric                                      const std::string &DebuglinkName,
430d56accc7SDimitry Andric                                      uint32_t CRCHash, std::string &Result) {
431d56accc7SDimitry Andric   SmallString<16> OrigDir(OrigPath);
432d56accc7SDimitry Andric   llvm::sys::path::remove_filename(OrigDir);
433d56accc7SDimitry Andric   SmallString<16> DebugPath = OrigDir;
434d56accc7SDimitry Andric   // Try relative/path/to/original_binary/debuglink_name
435d56accc7SDimitry Andric   llvm::sys::path::append(DebugPath, DebuglinkName);
436d56accc7SDimitry Andric   if (checkFileCRC(DebugPath, CRCHash)) {
4377a6dacacSDimitry Andric     Result = std::string(DebugPath);
438d56accc7SDimitry Andric     return true;
439d56accc7SDimitry Andric   }
440d56accc7SDimitry Andric   // Try relative/path/to/original_binary/.debug/debuglink_name
441d56accc7SDimitry Andric   DebugPath = OrigDir;
442d56accc7SDimitry Andric   llvm::sys::path::append(DebugPath, ".debug", DebuglinkName);
443d56accc7SDimitry Andric   if (checkFileCRC(DebugPath, CRCHash)) {
4447a6dacacSDimitry Andric     Result = std::string(DebugPath);
445d56accc7SDimitry Andric     return true;
446d56accc7SDimitry Andric   }
447d56accc7SDimitry Andric   // Make the path absolute so that lookups will go to
448d56accc7SDimitry Andric   // "/usr/lib/debug/full/path/to/debug", not
449d56accc7SDimitry Andric   // "/usr/lib/debug/to/debug"
450d56accc7SDimitry Andric   llvm::sys::fs::make_absolute(OrigDir);
451d56accc7SDimitry Andric   if (!Opts.FallbackDebugPath.empty()) {
452d56accc7SDimitry Andric     // Try <FallbackDebugPath>/absolute/path/to/original_binary/debuglink_name
453d56accc7SDimitry Andric     DebugPath = Opts.FallbackDebugPath;
454d56accc7SDimitry Andric   } else {
455d56accc7SDimitry Andric #if defined(__NetBSD__)
456d56accc7SDimitry Andric     // Try /usr/libdata/debug/absolute/path/to/original_binary/debuglink_name
457d56accc7SDimitry Andric     DebugPath = "/usr/libdata/debug";
458d56accc7SDimitry Andric #else
459d56accc7SDimitry Andric     // Try /usr/lib/debug/absolute/path/to/original_binary/debuglink_name
460d56accc7SDimitry Andric     DebugPath = "/usr/lib/debug";
461d56accc7SDimitry Andric #endif
462d56accc7SDimitry Andric   }
463d56accc7SDimitry Andric   llvm::sys::path::append(DebugPath, llvm::sys::path::relative_path(OrigDir),
464d56accc7SDimitry Andric                           DebuglinkName);
465d56accc7SDimitry Andric   if (checkFileCRC(DebugPath, CRCHash)) {
4667a6dacacSDimitry Andric     Result = std::string(DebugPath);
467d56accc7SDimitry Andric     return true;
468d56accc7SDimitry Andric   }
469d56accc7SDimitry Andric   return false;
470d56accc7SDimitry Andric }
471d56accc7SDimitry Andric 
47281ad6265SDimitry Andric static StringRef getBuildIDStr(ArrayRef<uint8_t> BuildID) {
47381ad6265SDimitry Andric   return StringRef(reinterpret_cast<const char *>(BuildID.data()),
47481ad6265SDimitry Andric                    BuildID.size());
47581ad6265SDimitry Andric }
47681ad6265SDimitry Andric 
47781ad6265SDimitry Andric bool LLVMSymbolizer::getOrFindDebugBinary(const ArrayRef<uint8_t> BuildID,
478d56accc7SDimitry Andric                                           std::string &Result) {
47981ad6265SDimitry Andric   StringRef BuildIDStr = getBuildIDStr(BuildID);
48081ad6265SDimitry Andric   auto I = BuildIDPaths.find(BuildIDStr);
48181ad6265SDimitry Andric   if (I != BuildIDPaths.end()) {
48281ad6265SDimitry Andric     Result = I->second;
48381ad6265SDimitry Andric     return true;
48481ad6265SDimitry Andric   }
485bdd1243dSDimitry Andric   if (!BIDFetcher)
486bdd1243dSDimitry Andric     return false;
487bdd1243dSDimitry Andric   if (std::optional<std::string> Path = BIDFetcher->fetch(BuildID)) {
488bdd1243dSDimitry Andric     Result = *Path;
48981ad6265SDimitry Andric     auto InsertResult = BuildIDPaths.insert({BuildIDStr, Result});
49081ad6265SDimitry Andric     assert(InsertResult.second);
49181ad6265SDimitry Andric     (void)InsertResult;
492d56accc7SDimitry Andric     return true;
493d56accc7SDimitry Andric   }
494d56accc7SDimitry Andric 
495d56accc7SDimitry Andric   return false;
496d56accc7SDimitry Andric }
497d56accc7SDimitry Andric 
4980b57cec5SDimitry Andric Expected<LLVMSymbolizer::ObjectPair>
4990b57cec5SDimitry Andric LLVMSymbolizer::getOrCreateObjectPair(const std::string &Path,
5000b57cec5SDimitry Andric                                       const std::string &ArchName) {
5010b57cec5SDimitry Andric   auto I = ObjectPairForPathArch.find(std::make_pair(Path, ArchName));
50281ad6265SDimitry Andric   if (I != ObjectPairForPathArch.end()) {
50381ad6265SDimitry Andric     recordAccess(BinaryForPath.find(Path)->second);
5040b57cec5SDimitry Andric     return I->second;
50581ad6265SDimitry Andric   }
5060b57cec5SDimitry Andric 
5070b57cec5SDimitry Andric   auto ObjOrErr = getOrCreateObject(Path, ArchName);
5080b57cec5SDimitry Andric   if (!ObjOrErr) {
5090b57cec5SDimitry Andric     ObjectPairForPathArch.emplace(std::make_pair(Path, ArchName),
5100b57cec5SDimitry Andric                                   ObjectPair(nullptr, nullptr));
5110b57cec5SDimitry Andric     return ObjOrErr.takeError();
5120b57cec5SDimitry Andric   }
5130b57cec5SDimitry Andric 
5140b57cec5SDimitry Andric   ObjectFile *Obj = ObjOrErr.get();
5150b57cec5SDimitry Andric   assert(Obj != nullptr);
5160b57cec5SDimitry Andric   ObjectFile *DbgObj = nullptr;
5170b57cec5SDimitry Andric 
5180b57cec5SDimitry Andric   if (auto MachObj = dyn_cast<const MachOObjectFile>(Obj))
5190b57cec5SDimitry Andric     DbgObj = lookUpDsymFile(Path, MachObj, ArchName);
520480093f4SDimitry Andric   else if (auto ELFObj = dyn_cast<const ELFObjectFileBase>(Obj))
521480093f4SDimitry Andric     DbgObj = lookUpBuildIDObject(Path, ELFObj, ArchName);
5220b57cec5SDimitry Andric   if (!DbgObj)
5230b57cec5SDimitry Andric     DbgObj = lookUpDebuglinkObject(Path, Obj, ArchName);
5240b57cec5SDimitry Andric   if (!DbgObj)
5250b57cec5SDimitry Andric     DbgObj = Obj;
5260b57cec5SDimitry Andric   ObjectPair Res = std::make_pair(Obj, DbgObj);
52781ad6265SDimitry Andric   std::string DbgObjPath = DbgObj->getFileName().str();
52881ad6265SDimitry Andric   auto Pair =
5290b57cec5SDimitry Andric       ObjectPairForPathArch.emplace(std::make_pair(Path, ArchName), Res);
53081ad6265SDimitry Andric   BinaryForPath.find(DbgObjPath)->second.pushEvictor([this, I = Pair.first]() {
53181ad6265SDimitry Andric     ObjectPairForPathArch.erase(I);
53281ad6265SDimitry Andric   });
5330b57cec5SDimitry Andric   return Res;
5340b57cec5SDimitry Andric }
5350b57cec5SDimitry Andric 
5360b57cec5SDimitry Andric Expected<ObjectFile *>
5370b57cec5SDimitry Andric LLVMSymbolizer::getOrCreateObject(const std::string &Path,
5380b57cec5SDimitry Andric                                   const std::string &ArchName) {
5390b57cec5SDimitry Andric   Binary *Bin;
5400b57cec5SDimitry Andric   auto Pair = BinaryForPath.emplace(Path, OwningBinary<Binary>());
5410b57cec5SDimitry Andric   if (!Pair.second) {
54281ad6265SDimitry Andric     Bin = Pair.first->second->getBinary();
54381ad6265SDimitry Andric     recordAccess(Pair.first->second);
5440b57cec5SDimitry Andric   } else {
5450b57cec5SDimitry Andric     Expected<OwningBinary<Binary>> BinOrErr = createBinary(Path);
5460b57cec5SDimitry Andric     if (!BinOrErr)
5470b57cec5SDimitry Andric       return BinOrErr.takeError();
54881ad6265SDimitry Andric 
54981ad6265SDimitry Andric     CachedBinary &CachedBin = Pair.first->second;
55081ad6265SDimitry Andric     CachedBin = std::move(BinOrErr.get());
55181ad6265SDimitry Andric     CachedBin.pushEvictor([this, I = Pair.first]() { BinaryForPath.erase(I); });
55281ad6265SDimitry Andric     LRUBinaries.push_back(CachedBin);
55381ad6265SDimitry Andric     CacheSize += CachedBin.size();
55481ad6265SDimitry Andric     Bin = CachedBin->getBinary();
5550b57cec5SDimitry Andric   }
5560b57cec5SDimitry Andric 
5570b57cec5SDimitry Andric   if (!Bin)
5580b57cec5SDimitry Andric     return static_cast<ObjectFile *>(nullptr);
5590b57cec5SDimitry Andric 
5600b57cec5SDimitry Andric   if (MachOUniversalBinary *UB = dyn_cast_or_null<MachOUniversalBinary>(Bin)) {
5610b57cec5SDimitry Andric     auto I = ObjectForUBPathAndArch.find(std::make_pair(Path, ArchName));
5620b57cec5SDimitry Andric     if (I != ObjectForUBPathAndArch.end())
5630b57cec5SDimitry Andric       return I->second.get();
5640b57cec5SDimitry Andric 
5650b57cec5SDimitry Andric     Expected<std::unique_ptr<ObjectFile>> ObjOrErr =
5668bcb0991SDimitry Andric         UB->getMachOObjectForArch(ArchName);
5670b57cec5SDimitry Andric     if (!ObjOrErr) {
5680b57cec5SDimitry Andric       ObjectForUBPathAndArch.emplace(std::make_pair(Path, ArchName),
5690b57cec5SDimitry Andric                                      std::unique_ptr<ObjectFile>());
5700b57cec5SDimitry Andric       return ObjOrErr.takeError();
5710b57cec5SDimitry Andric     }
5720b57cec5SDimitry Andric     ObjectFile *Res = ObjOrErr->get();
57381ad6265SDimitry Andric     auto Pair = ObjectForUBPathAndArch.emplace(std::make_pair(Path, ArchName),
5740b57cec5SDimitry Andric                                                std::move(ObjOrErr.get()));
57581ad6265SDimitry Andric     BinaryForPath.find(Path)->second.pushEvictor(
57681ad6265SDimitry Andric         [this, Iter = Pair.first]() { ObjectForUBPathAndArch.erase(Iter); });
5770b57cec5SDimitry Andric     return Res;
5780b57cec5SDimitry Andric   }
5790b57cec5SDimitry Andric   if (Bin->isObject()) {
5800b57cec5SDimitry Andric     return cast<ObjectFile>(Bin);
5810b57cec5SDimitry Andric   }
5820b57cec5SDimitry Andric   return errorCodeToError(object_error::arch_not_found);
5830b57cec5SDimitry Andric }
5840b57cec5SDimitry Andric 
5850b57cec5SDimitry Andric Expected<SymbolizableModule *>
5860b57cec5SDimitry Andric LLVMSymbolizer::createModuleInfo(const ObjectFile *Obj,
5870b57cec5SDimitry Andric                                  std::unique_ptr<DIContext> Context,
5880b57cec5SDimitry Andric                                  StringRef ModuleName) {
5898bcb0991SDimitry Andric   auto InfoOrErr = SymbolizableObjectFile::create(Obj, std::move(Context),
5908bcb0991SDimitry Andric                                                   Opts.UntagAddresses);
5910b57cec5SDimitry Andric   std::unique_ptr<SymbolizableModule> SymMod;
5920b57cec5SDimitry Andric   if (InfoOrErr)
5930b57cec5SDimitry Andric     SymMod = std::move(*InfoOrErr);
5945ffd83dbSDimitry Andric   auto InsertResult = Modules.insert(
5955ffd83dbSDimitry Andric       std::make_pair(std::string(ModuleName), std::move(SymMod)));
5960b57cec5SDimitry Andric   assert(InsertResult.second);
5975ffd83dbSDimitry Andric   if (!InfoOrErr)
5985ffd83dbSDimitry Andric     return InfoOrErr.takeError();
5990b57cec5SDimitry Andric   return InsertResult.first->second.get();
6000b57cec5SDimitry Andric }
6010b57cec5SDimitry Andric 
6020b57cec5SDimitry Andric Expected<SymbolizableModule *>
6030b57cec5SDimitry Andric LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
6040b57cec5SDimitry Andric   std::string BinaryName = ModuleName;
6050b57cec5SDimitry Andric   std::string ArchName = Opts.DefaultArch;
6060b57cec5SDimitry Andric   size_t ColonPos = ModuleName.find_last_of(':');
6070b57cec5SDimitry Andric   // Verify that substring after colon form a valid arch name.
6080b57cec5SDimitry Andric   if (ColonPos != std::string::npos) {
6090b57cec5SDimitry Andric     std::string ArchStr = ModuleName.substr(ColonPos + 1);
6100b57cec5SDimitry Andric     if (Triple(ArchStr).getArch() != Triple::UnknownArch) {
6110b57cec5SDimitry Andric       BinaryName = ModuleName.substr(0, ColonPos);
6120b57cec5SDimitry Andric       ArchName = ArchStr;
6130b57cec5SDimitry Andric     }
6140b57cec5SDimitry Andric   }
61581ad6265SDimitry Andric 
61681ad6265SDimitry Andric   auto I = Modules.find(ModuleName);
61781ad6265SDimitry Andric   if (I != Modules.end()) {
61881ad6265SDimitry Andric     recordAccess(BinaryForPath.find(BinaryName)->second);
61981ad6265SDimitry Andric     return I->second.get();
62081ad6265SDimitry Andric   }
62181ad6265SDimitry Andric 
6220b57cec5SDimitry Andric   auto ObjectsOrErr = getOrCreateObjectPair(BinaryName, ArchName);
6230b57cec5SDimitry Andric   if (!ObjectsOrErr) {
6240b57cec5SDimitry Andric     // Failed to find valid object file.
6250b57cec5SDimitry Andric     Modules.emplace(ModuleName, std::unique_ptr<SymbolizableModule>());
6260b57cec5SDimitry Andric     return ObjectsOrErr.takeError();
6270b57cec5SDimitry Andric   }
6280b57cec5SDimitry Andric   ObjectPair Objects = ObjectsOrErr.get();
6290b57cec5SDimitry Andric 
6300b57cec5SDimitry Andric   std::unique_ptr<DIContext> Context;
631*0fca6ea1SDimitry Andric   // If this is a COFF object containing PDB info and not containing DWARF
632*0fca6ea1SDimitry Andric   // section, use a PDBContext to symbolize. Otherwise, use DWARF.
6330b57cec5SDimitry Andric   if (auto CoffObject = dyn_cast<COFFObjectFile>(Objects.first)) {
6340b57cec5SDimitry Andric     const codeview::DebugInfo *DebugInfo;
6350b57cec5SDimitry Andric     StringRef PDBFileName;
6360b57cec5SDimitry Andric     auto EC = CoffObject->getDebugPDBInfo(DebugInfo, PDBFileName);
637*0fca6ea1SDimitry Andric     // Use DWARF if there're DWARF sections.
638*0fca6ea1SDimitry Andric     bool HasDwarf =
639*0fca6ea1SDimitry Andric         llvm::any_of(Objects.first->sections(), [](SectionRef Section) -> bool {
640*0fca6ea1SDimitry Andric           if (Expected<StringRef> SectionName = Section.getName())
641*0fca6ea1SDimitry Andric             return SectionName.get() == ".debug_info";
642*0fca6ea1SDimitry Andric           return false;
643*0fca6ea1SDimitry Andric         });
644*0fca6ea1SDimitry Andric     if (!EC && !HasDwarf && DebugInfo != nullptr && !PDBFileName.empty()) {
645cfe333b8SDimitry Andric #if 0
6460b57cec5SDimitry Andric       using namespace pdb;
6470b57cec5SDimitry Andric       std::unique_ptr<IPDBSession> Session;
648e8d8bef9SDimitry Andric 
649e8d8bef9SDimitry Andric       PDB_ReaderType ReaderType =
650e8d8bef9SDimitry Andric           Opts.UseDIA ? PDB_ReaderType::DIA : PDB_ReaderType::Native;
6515ffd83dbSDimitry Andric       if (auto Err = loadDataForEXE(ReaderType, Objects.first->getFileName(),
6525ffd83dbSDimitry Andric                                     Session)) {
6530b57cec5SDimitry Andric         Modules.emplace(ModuleName, std::unique_ptr<SymbolizableModule>());
6540b57cec5SDimitry Andric         // Return along the PDB filename to provide more context
6550b57cec5SDimitry Andric         return createFileError(PDBFileName, std::move(Err));
6560b57cec5SDimitry Andric       }
6570b57cec5SDimitry Andric       Context.reset(new PDBContext(*CoffObject, std::move(Session)));
658cfe333b8SDimitry Andric #else
659cfe333b8SDimitry Andric       return make_error<StringError>(
660cfe333b8SDimitry Andric         "PDB support not compiled in",
661cfe333b8SDimitry Andric         std::make_error_code(std::errc::not_supported));
662cfe333b8SDimitry Andric #endif
6630b57cec5SDimitry Andric     }
6640b57cec5SDimitry Andric   }
6650b57cec5SDimitry Andric   if (!Context)
666349cc55cSDimitry Andric     Context = DWARFContext::create(
667349cc55cSDimitry Andric         *Objects.second, DWARFContext::ProcessDebugRelocations::Process,
668349cc55cSDimitry Andric         nullptr, Opts.DWPName);
66981ad6265SDimitry Andric   auto ModuleOrErr =
67081ad6265SDimitry Andric       createModuleInfo(Objects.first, std::move(Context), ModuleName);
67181ad6265SDimitry Andric   if (ModuleOrErr) {
67281ad6265SDimitry Andric     auto I = Modules.find(ModuleName);
67381ad6265SDimitry Andric     BinaryForPath.find(BinaryName)->second.pushEvictor([this, I]() {
67481ad6265SDimitry Andric       Modules.erase(I);
67581ad6265SDimitry Andric     });
67681ad6265SDimitry Andric   }
67781ad6265SDimitry Andric   return ModuleOrErr;
6780b57cec5SDimitry Andric }
6790b57cec5SDimitry Andric 
68006c3fb27SDimitry Andric // For BPF programs .BTF.ext section contains line numbers information,
68106c3fb27SDimitry Andric // use it if regular DWARF is not available (e.g. for stripped binary).
68206c3fb27SDimitry Andric static bool useBTFContext(const ObjectFile &Obj) {
68306c3fb27SDimitry Andric   return Obj.makeTriple().isBPF() && !Obj.hasDebugInfo() &&
68406c3fb27SDimitry Andric          BTFParser::hasBTFSections(Obj);
68506c3fb27SDimitry Andric }
68606c3fb27SDimitry Andric 
687fe6060f1SDimitry Andric Expected<SymbolizableModule *>
688fe6060f1SDimitry Andric LLVMSymbolizer::getOrCreateModuleInfo(const ObjectFile &Obj) {
689fe6060f1SDimitry Andric   StringRef ObjName = Obj.getFileName();
690fe6060f1SDimitry Andric   auto I = Modules.find(ObjName);
691fe6060f1SDimitry Andric   if (I != Modules.end())
692fe6060f1SDimitry Andric     return I->second.get();
693fe6060f1SDimitry Andric 
69406c3fb27SDimitry Andric   std::unique_ptr<DIContext> Context;
69506c3fb27SDimitry Andric   if (useBTFContext(Obj))
69606c3fb27SDimitry Andric     Context = BTFContext::create(Obj);
69706c3fb27SDimitry Andric   else
69806c3fb27SDimitry Andric     Context = DWARFContext::create(Obj);
699fe6060f1SDimitry Andric   // FIXME: handle COFF object with PDB info to use PDBContext
700fe6060f1SDimitry Andric   return createModuleInfo(&Obj, std::move(Context), ObjName);
701fe6060f1SDimitry Andric }
702fe6060f1SDimitry Andric 
70381ad6265SDimitry Andric Expected<SymbolizableModule *>
70481ad6265SDimitry Andric LLVMSymbolizer::getOrCreateModuleInfo(ArrayRef<uint8_t> BuildID) {
70581ad6265SDimitry Andric   std::string Path;
70681ad6265SDimitry Andric   if (!getOrFindDebugBinary(BuildID, Path)) {
70781ad6265SDimitry Andric     return createStringError(errc::no_such_file_or_directory,
70806c3fb27SDimitry Andric                              "could not find build ID");
70981ad6265SDimitry Andric   }
71081ad6265SDimitry Andric   return getOrCreateModuleInfo(Path);
71181ad6265SDimitry Andric }
71281ad6265SDimitry Andric 
7130b57cec5SDimitry Andric namespace {
7140b57cec5SDimitry Andric 
7150b57cec5SDimitry Andric // Undo these various manglings for Win32 extern "C" functions:
7160b57cec5SDimitry Andric // cdecl       - _foo
7170b57cec5SDimitry Andric // stdcall     - _foo@12
7180b57cec5SDimitry Andric // fastcall    - @foo@12
7190b57cec5SDimitry Andric // vectorcall  - foo@@12
7200b57cec5SDimitry Andric // These are all different linkage names for 'foo'.
7210b57cec5SDimitry Andric StringRef demanglePE32ExternCFunc(StringRef SymbolName) {
7220b57cec5SDimitry Andric   char Front = SymbolName.empty() ? '\0' : SymbolName[0];
7230b57cec5SDimitry Andric 
7240b57cec5SDimitry Andric   // Remove any '@[0-9]+' suffix.
7251ac55f4cSDimitry Andric   bool HasAtNumSuffix = false;
7260b57cec5SDimitry Andric   if (Front != '?') {
7270b57cec5SDimitry Andric     size_t AtPos = SymbolName.rfind('@');
7280b57cec5SDimitry Andric     if (AtPos != StringRef::npos &&
7291ac55f4cSDimitry Andric         all_of(drop_begin(SymbolName, AtPos + 1), isDigit)) {
7300b57cec5SDimitry Andric       SymbolName = SymbolName.substr(0, AtPos);
7311ac55f4cSDimitry Andric       HasAtNumSuffix = true;
7321ac55f4cSDimitry Andric     }
7330b57cec5SDimitry Andric   }
7340b57cec5SDimitry Andric 
7350b57cec5SDimitry Andric   // Remove any ending '@' for vectorcall.
7361ac55f4cSDimitry Andric   bool IsVectorCall = false;
7375f757f3fSDimitry Andric   if (HasAtNumSuffix && SymbolName.ends_with("@")) {
7380b57cec5SDimitry Andric     SymbolName = SymbolName.drop_back();
7391ac55f4cSDimitry Andric     IsVectorCall = true;
7401ac55f4cSDimitry Andric   }
7411ac55f4cSDimitry Andric 
7421ac55f4cSDimitry Andric   // If not vectorcall, remove any '_' or '@' prefix.
7431ac55f4cSDimitry Andric   if (!IsVectorCall && (Front == '_' || Front == '@'))
7441ac55f4cSDimitry Andric     SymbolName = SymbolName.drop_front();
7450b57cec5SDimitry Andric 
7460b57cec5SDimitry Andric   return SymbolName;
7470b57cec5SDimitry Andric }
7480b57cec5SDimitry Andric 
7490b57cec5SDimitry Andric } // end anonymous namespace
7500b57cec5SDimitry Andric 
7510b57cec5SDimitry Andric std::string
7520b57cec5SDimitry Andric LLVMSymbolizer::DemangleName(const std::string &Name,
7530b57cec5SDimitry Andric                              const SymbolizableModule *DbiModuleDescriptor) {
754349cc55cSDimitry Andric   std::string Result;
75506c3fb27SDimitry Andric   if (nonMicrosoftDemangle(Name, Result))
7560b57cec5SDimitry Andric     return Result;
7570b57cec5SDimitry Andric 
7580b57cec5SDimitry Andric   if (!Name.empty() && Name.front() == '?') {
7590b57cec5SDimitry Andric     // Only do MSVC C++ demangling on symbols starting with '?'.
7608bcb0991SDimitry Andric     int status = 0;
7618bcb0991SDimitry Andric     char *DemangledName = microsoftDemangle(
76206c3fb27SDimitry Andric         Name, nullptr, &status,
7638bcb0991SDimitry Andric         MSDemangleFlags(MSDF_NoAccessSpecifier | MSDF_NoCallingConvention |
7648bcb0991SDimitry Andric                         MSDF_NoMemberType | MSDF_NoReturnType));
7658bcb0991SDimitry Andric     if (status != 0)
7668bcb0991SDimitry Andric       return Name;
767349cc55cSDimitry Andric     Result = DemangledName;
7688bcb0991SDimitry Andric     free(DemangledName);
7698bcb0991SDimitry Andric     return Result;
7700b57cec5SDimitry Andric   }
7718bcb0991SDimitry Andric 
7721ac55f4cSDimitry Andric   if (DbiModuleDescriptor && DbiModuleDescriptor->isWin32Module()) {
7731ac55f4cSDimitry Andric     std::string DemangledCName(demanglePE32ExternCFunc(Name));
7741ac55f4cSDimitry Andric     // On i386 Windows, the C name mangling for different calling conventions
7751ac55f4cSDimitry Andric     // may also be applied on top of the Itanium or Rust name mangling.
77606c3fb27SDimitry Andric     if (nonMicrosoftDemangle(DemangledCName, Result))
7771ac55f4cSDimitry Andric       return Result;
7781ac55f4cSDimitry Andric     return DemangledCName;
7791ac55f4cSDimitry Andric   }
7800b57cec5SDimitry Andric   return Name;
7810b57cec5SDimitry Andric }
7820b57cec5SDimitry Andric 
78381ad6265SDimitry Andric void LLVMSymbolizer::recordAccess(CachedBinary &Bin) {
78481ad6265SDimitry Andric   if (Bin->getBinary())
78581ad6265SDimitry Andric     LRUBinaries.splice(LRUBinaries.end(), LRUBinaries, Bin.getIterator());
78681ad6265SDimitry Andric }
78781ad6265SDimitry Andric 
78881ad6265SDimitry Andric void LLVMSymbolizer::pruneCache() {
78981ad6265SDimitry Andric   // Evict the LRU binary until the max cache size is reached or there's <= 1
79081ad6265SDimitry Andric   // item in the cache. The MRU binary is always kept to avoid thrashing if it's
79181ad6265SDimitry Andric   // larger than the cache size.
79281ad6265SDimitry Andric   while (CacheSize > Opts.MaxCacheSize && !LRUBinaries.empty() &&
79381ad6265SDimitry Andric          std::next(LRUBinaries.begin()) != LRUBinaries.end()) {
79481ad6265SDimitry Andric     CachedBinary &Bin = LRUBinaries.front();
79581ad6265SDimitry Andric     CacheSize -= Bin.size();
79681ad6265SDimitry Andric     LRUBinaries.pop_front();
79781ad6265SDimitry Andric     Bin.evict();
79881ad6265SDimitry Andric   }
79981ad6265SDimitry Andric }
80081ad6265SDimitry Andric 
80181ad6265SDimitry Andric void CachedBinary::pushEvictor(std::function<void()> NewEvictor) {
80281ad6265SDimitry Andric   if (Evictor) {
80381ad6265SDimitry Andric     this->Evictor = [OldEvictor = std::move(this->Evictor),
80481ad6265SDimitry Andric                      NewEvictor = std::move(NewEvictor)]() {
80581ad6265SDimitry Andric       NewEvictor();
80681ad6265SDimitry Andric       OldEvictor();
80781ad6265SDimitry Andric     };
80881ad6265SDimitry Andric   } else {
80981ad6265SDimitry Andric     this->Evictor = std::move(NewEvictor);
81081ad6265SDimitry Andric   }
81181ad6265SDimitry Andric }
81281ad6265SDimitry Andric 
8130b57cec5SDimitry Andric } // namespace symbolize
8140b57cec5SDimitry Andric } // namespace llvm
815