xref: /openbsd-src/gnu/llvm/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp (revision d415bd752c734aee168c4ee86ff32e8cc249eb16)
109467b48Spatrick //===-- LLVMSymbolize.cpp -------------------------------------------------===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick //
909467b48Spatrick // Implementation for LLVM symbolization library.
1009467b48Spatrick //
1109467b48Spatrick //===----------------------------------------------------------------------===//
1209467b48Spatrick 
1309467b48Spatrick #include "llvm/DebugInfo/Symbolize/Symbolize.h"
1409467b48Spatrick 
1509467b48Spatrick #include "llvm/ADT/STLExtras.h"
1609467b48Spatrick #include "llvm/DebugInfo/DWARF/DWARFContext.h"
1709467b48Spatrick #include "llvm/DebugInfo/PDB/PDB.h"
1809467b48Spatrick #include "llvm/DebugInfo/PDB/PDBContext.h"
19*d415bd75Srobert #include "llvm/DebugInfo/Symbolize/SymbolizableObjectFile.h"
2009467b48Spatrick #include "llvm/Demangle/Demangle.h"
21*d415bd75Srobert #include "llvm/Object/BuildID.h"
2209467b48Spatrick #include "llvm/Object/COFF.h"
23*d415bd75Srobert #include "llvm/Object/ELFObjectFile.h"
2409467b48Spatrick #include "llvm/Object/MachO.h"
2509467b48Spatrick #include "llvm/Object/MachOUniversal.h"
2609467b48Spatrick #include "llvm/Support/CRC.h"
2709467b48Spatrick #include "llvm/Support/Casting.h"
2809467b48Spatrick #include "llvm/Support/DataExtractor.h"
2909467b48Spatrick #include "llvm/Support/Errc.h"
3009467b48Spatrick #include "llvm/Support/FileSystem.h"
3109467b48Spatrick #include "llvm/Support/MemoryBuffer.h"
3209467b48Spatrick #include "llvm/Support/Path.h"
3309467b48Spatrick #include <algorithm>
3409467b48Spatrick #include <cassert>
3509467b48Spatrick #include <cstring>
3609467b48Spatrick 
3709467b48Spatrick namespace llvm {
38*d415bd75Srobert namespace codeview {
39*d415bd75Srobert union DebugInfo;
40*d415bd75Srobert }
4109467b48Spatrick namespace symbolize {
4209467b48Spatrick 
43*d415bd75Srobert LLVMSymbolizer::LLVMSymbolizer() = default;
44*d415bd75Srobert 
LLVMSymbolizer(const Options & Opts)45*d415bd75Srobert LLVMSymbolizer::LLVMSymbolizer(const Options &Opts)
46*d415bd75Srobert     : Opts(Opts),
47*d415bd75Srobert       BIDFetcher(std::make_unique<BuildIDFetcher>(Opts.DebugFileDirectory)) {}
48*d415bd75Srobert 
49*d415bd75Srobert LLVMSymbolizer::~LLVMSymbolizer() = default;
50*d415bd75Srobert 
5173471bf0Spatrick template <typename T>
5209467b48Spatrick Expected<DILineInfo>
symbolizeCodeCommon(const T & ModuleSpecifier,object::SectionedAddress ModuleOffset)5373471bf0Spatrick LLVMSymbolizer::symbolizeCodeCommon(const T &ModuleSpecifier,
5409467b48Spatrick                                     object::SectionedAddress ModuleOffset) {
5573471bf0Spatrick 
5673471bf0Spatrick   auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
5773471bf0Spatrick   if (!InfoOrErr)
5873471bf0Spatrick     return InfoOrErr.takeError();
5973471bf0Spatrick 
6073471bf0Spatrick   SymbolizableModule *Info = *InfoOrErr;
6173471bf0Spatrick 
6209467b48Spatrick   // A null module means an error has already been reported. Return an empty
6309467b48Spatrick   // result.
6409467b48Spatrick   if (!Info)
6509467b48Spatrick     return DILineInfo();
6609467b48Spatrick 
6709467b48Spatrick   // If the user is giving us relative addresses, add the preferred base of the
6809467b48Spatrick   // object to the offset before we do the query. It's what DIContext expects.
6909467b48Spatrick   if (Opts.RelativeAddresses)
7009467b48Spatrick     ModuleOffset.Address += Info->getModulePreferredBase();
7109467b48Spatrick 
72097a140dSpatrick   DILineInfo LineInfo = Info->symbolizeCode(
73097a140dSpatrick       ModuleOffset, DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions),
7409467b48Spatrick       Opts.UseSymbolTable);
7509467b48Spatrick   if (Opts.Demangle)
7609467b48Spatrick     LineInfo.FunctionName = DemangleName(LineInfo.FunctionName, Info);
7709467b48Spatrick   return LineInfo;
7809467b48Spatrick }
7909467b48Spatrick 
8009467b48Spatrick Expected<DILineInfo>
symbolizeCode(const ObjectFile & Obj,object::SectionedAddress ModuleOffset)8109467b48Spatrick LLVMSymbolizer::symbolizeCode(const ObjectFile &Obj,
8209467b48Spatrick                               object::SectionedAddress ModuleOffset) {
8373471bf0Spatrick   return symbolizeCodeCommon(Obj, ModuleOffset);
8409467b48Spatrick }
8509467b48Spatrick 
8609467b48Spatrick Expected<DILineInfo>
symbolizeCode(const std::string & ModuleName,object::SectionedAddress ModuleOffset)8709467b48Spatrick LLVMSymbolizer::symbolizeCode(const std::string &ModuleName,
8809467b48Spatrick                               object::SectionedAddress ModuleOffset) {
8973471bf0Spatrick   return symbolizeCodeCommon(ModuleName, ModuleOffset);
9009467b48Spatrick }
9109467b48Spatrick 
92*d415bd75Srobert Expected<DILineInfo>
symbolizeCode(ArrayRef<uint8_t> BuildID,object::SectionedAddress ModuleOffset)93*d415bd75Srobert LLVMSymbolizer::symbolizeCode(ArrayRef<uint8_t> BuildID,
94*d415bd75Srobert                               object::SectionedAddress ModuleOffset) {
95*d415bd75Srobert   return symbolizeCodeCommon(BuildID, ModuleOffset);
96*d415bd75Srobert }
97*d415bd75Srobert 
9873471bf0Spatrick template <typename T>
symbolizeInlinedCodeCommon(const T & ModuleSpecifier,object::SectionedAddress ModuleOffset)9973471bf0Spatrick Expected<DIInliningInfo> LLVMSymbolizer::symbolizeInlinedCodeCommon(
10073471bf0Spatrick     const T &ModuleSpecifier, object::SectionedAddress ModuleOffset) {
10173471bf0Spatrick   auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
10273471bf0Spatrick   if (!InfoOrErr)
10309467b48Spatrick     return InfoOrErr.takeError();
10409467b48Spatrick 
10573471bf0Spatrick   SymbolizableModule *Info = *InfoOrErr;
10673471bf0Spatrick 
10709467b48Spatrick   // A null module means an error has already been reported. Return an empty
10809467b48Spatrick   // result.
10909467b48Spatrick   if (!Info)
11009467b48Spatrick     return DIInliningInfo();
11109467b48Spatrick 
11209467b48Spatrick   // If the user is giving us relative addresses, add the preferred base of the
11309467b48Spatrick   // object to the offset before we do the query. It's what DIContext expects.
11409467b48Spatrick   if (Opts.RelativeAddresses)
11509467b48Spatrick     ModuleOffset.Address += Info->getModulePreferredBase();
11609467b48Spatrick 
11709467b48Spatrick   DIInliningInfo InlinedContext = Info->symbolizeInlinedCode(
118097a140dSpatrick       ModuleOffset, DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions),
119097a140dSpatrick       Opts.UseSymbolTable);
12009467b48Spatrick   if (Opts.Demangle) {
12109467b48Spatrick     for (int i = 0, n = InlinedContext.getNumberOfFrames(); i < n; i++) {
12209467b48Spatrick       auto *Frame = InlinedContext.getMutableFrame(i);
12309467b48Spatrick       Frame->FunctionName = DemangleName(Frame->FunctionName, Info);
12409467b48Spatrick     }
12509467b48Spatrick   }
12609467b48Spatrick   return InlinedContext;
12709467b48Spatrick }
12809467b48Spatrick 
12973471bf0Spatrick Expected<DIInliningInfo>
symbolizeInlinedCode(const ObjectFile & Obj,object::SectionedAddress ModuleOffset)13073471bf0Spatrick LLVMSymbolizer::symbolizeInlinedCode(const ObjectFile &Obj,
13109467b48Spatrick                                      object::SectionedAddress ModuleOffset) {
13273471bf0Spatrick   return symbolizeInlinedCodeCommon(Obj, ModuleOffset);
13373471bf0Spatrick }
13473471bf0Spatrick 
13573471bf0Spatrick Expected<DIInliningInfo>
symbolizeInlinedCode(const std::string & ModuleName,object::SectionedAddress ModuleOffset)13673471bf0Spatrick LLVMSymbolizer::symbolizeInlinedCode(const std::string &ModuleName,
13773471bf0Spatrick                                      object::SectionedAddress ModuleOffset) {
13873471bf0Spatrick   return symbolizeInlinedCodeCommon(ModuleName, ModuleOffset);
13973471bf0Spatrick }
14073471bf0Spatrick 
141*d415bd75Srobert Expected<DIInliningInfo>
symbolizeInlinedCode(ArrayRef<uint8_t> BuildID,object::SectionedAddress ModuleOffset)142*d415bd75Srobert LLVMSymbolizer::symbolizeInlinedCode(ArrayRef<uint8_t> BuildID,
143*d415bd75Srobert                                      object::SectionedAddress ModuleOffset) {
144*d415bd75Srobert   return symbolizeInlinedCodeCommon(BuildID, ModuleOffset);
145*d415bd75Srobert }
146*d415bd75Srobert 
14773471bf0Spatrick template <typename T>
14873471bf0Spatrick Expected<DIGlobal>
symbolizeDataCommon(const T & ModuleSpecifier,object::SectionedAddress ModuleOffset)14973471bf0Spatrick LLVMSymbolizer::symbolizeDataCommon(const T &ModuleSpecifier,
15073471bf0Spatrick                                     object::SectionedAddress ModuleOffset) {
15173471bf0Spatrick 
15273471bf0Spatrick   auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
15373471bf0Spatrick   if (!InfoOrErr)
15409467b48Spatrick     return InfoOrErr.takeError();
15509467b48Spatrick 
15673471bf0Spatrick   SymbolizableModule *Info = *InfoOrErr;
15709467b48Spatrick   // A null module means an error has already been reported. Return an empty
15809467b48Spatrick   // result.
15909467b48Spatrick   if (!Info)
16009467b48Spatrick     return DIGlobal();
16109467b48Spatrick 
16209467b48Spatrick   // If the user is giving us relative addresses, add the preferred base of
16309467b48Spatrick   // the object to the offset before we do the query. It's what DIContext
16409467b48Spatrick   // expects.
16509467b48Spatrick   if (Opts.RelativeAddresses)
16609467b48Spatrick     ModuleOffset.Address += Info->getModulePreferredBase();
16709467b48Spatrick 
16809467b48Spatrick   DIGlobal Global = Info->symbolizeData(ModuleOffset);
16909467b48Spatrick   if (Opts.Demangle)
17009467b48Spatrick     Global.Name = DemangleName(Global.Name, Info);
17109467b48Spatrick   return Global;
17209467b48Spatrick }
17309467b48Spatrick 
17473471bf0Spatrick Expected<DIGlobal>
symbolizeData(const ObjectFile & Obj,object::SectionedAddress ModuleOffset)17573471bf0Spatrick LLVMSymbolizer::symbolizeData(const ObjectFile &Obj,
17609467b48Spatrick                               object::SectionedAddress ModuleOffset) {
17773471bf0Spatrick   return symbolizeDataCommon(Obj, ModuleOffset);
17873471bf0Spatrick }
17973471bf0Spatrick 
18073471bf0Spatrick Expected<DIGlobal>
symbolizeData(const std::string & ModuleName,object::SectionedAddress ModuleOffset)18173471bf0Spatrick LLVMSymbolizer::symbolizeData(const std::string &ModuleName,
18273471bf0Spatrick                               object::SectionedAddress ModuleOffset) {
18373471bf0Spatrick   return symbolizeDataCommon(ModuleName, ModuleOffset);
18473471bf0Spatrick }
18573471bf0Spatrick 
186*d415bd75Srobert Expected<DIGlobal>
symbolizeData(ArrayRef<uint8_t> BuildID,object::SectionedAddress ModuleOffset)187*d415bd75Srobert LLVMSymbolizer::symbolizeData(ArrayRef<uint8_t> BuildID,
188*d415bd75Srobert                               object::SectionedAddress ModuleOffset) {
189*d415bd75Srobert   return symbolizeDataCommon(BuildID, ModuleOffset);
190*d415bd75Srobert }
191*d415bd75Srobert 
19273471bf0Spatrick template <typename T>
19373471bf0Spatrick Expected<std::vector<DILocal>>
symbolizeFrameCommon(const T & ModuleSpecifier,object::SectionedAddress ModuleOffset)19473471bf0Spatrick LLVMSymbolizer::symbolizeFrameCommon(const T &ModuleSpecifier,
19573471bf0Spatrick                                      object::SectionedAddress ModuleOffset) {
19673471bf0Spatrick   auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
19773471bf0Spatrick   if (!InfoOrErr)
19809467b48Spatrick     return InfoOrErr.takeError();
19909467b48Spatrick 
20073471bf0Spatrick   SymbolizableModule *Info = *InfoOrErr;
20109467b48Spatrick   // A null module means an error has already been reported. Return an empty
20209467b48Spatrick   // result.
20309467b48Spatrick   if (!Info)
20409467b48Spatrick     return std::vector<DILocal>();
20509467b48Spatrick 
20609467b48Spatrick   // If the user is giving us relative addresses, add the preferred base of
20709467b48Spatrick   // the object to the offset before we do the query. It's what DIContext
20809467b48Spatrick   // expects.
20909467b48Spatrick   if (Opts.RelativeAddresses)
21009467b48Spatrick     ModuleOffset.Address += Info->getModulePreferredBase();
21109467b48Spatrick 
21209467b48Spatrick   return Info->symbolizeFrame(ModuleOffset);
21309467b48Spatrick }
21409467b48Spatrick 
21573471bf0Spatrick Expected<std::vector<DILocal>>
symbolizeFrame(const ObjectFile & Obj,object::SectionedAddress ModuleOffset)21673471bf0Spatrick LLVMSymbolizer::symbolizeFrame(const ObjectFile &Obj,
21773471bf0Spatrick                                object::SectionedAddress ModuleOffset) {
21873471bf0Spatrick   return symbolizeFrameCommon(Obj, ModuleOffset);
21973471bf0Spatrick }
22073471bf0Spatrick 
22173471bf0Spatrick Expected<std::vector<DILocal>>
symbolizeFrame(const std::string & ModuleName,object::SectionedAddress ModuleOffset)22273471bf0Spatrick LLVMSymbolizer::symbolizeFrame(const std::string &ModuleName,
22373471bf0Spatrick                                object::SectionedAddress ModuleOffset) {
22473471bf0Spatrick   return symbolizeFrameCommon(ModuleName, ModuleOffset);
22573471bf0Spatrick }
22673471bf0Spatrick 
227*d415bd75Srobert Expected<std::vector<DILocal>>
symbolizeFrame(ArrayRef<uint8_t> BuildID,object::SectionedAddress ModuleOffset)228*d415bd75Srobert LLVMSymbolizer::symbolizeFrame(ArrayRef<uint8_t> BuildID,
229*d415bd75Srobert                                object::SectionedAddress ModuleOffset) {
230*d415bd75Srobert   return symbolizeFrameCommon(BuildID, ModuleOffset);
231*d415bd75Srobert }
232*d415bd75Srobert 
flush()23309467b48Spatrick void LLVMSymbolizer::flush() {
23409467b48Spatrick   ObjectForUBPathAndArch.clear();
235*d415bd75Srobert   LRUBinaries.clear();
236*d415bd75Srobert   CacheSize = 0;
23709467b48Spatrick   BinaryForPath.clear();
23809467b48Spatrick   ObjectPairForPathArch.clear();
23909467b48Spatrick   Modules.clear();
240*d415bd75Srobert   BuildIDPaths.clear();
24109467b48Spatrick }
24209467b48Spatrick 
24309467b48Spatrick namespace {
24409467b48Spatrick 
24509467b48Spatrick // For Path="/path/to/foo" and Basename="foo" assume that debug info is in
24609467b48Spatrick // /path/to/foo.dSYM/Contents/Resources/DWARF/foo.
24709467b48Spatrick // For Path="/path/to/bar.dSYM" and Basename="foo" assume that debug info is in
24809467b48Spatrick // /path/to/bar.dSYM/Contents/Resources/DWARF/foo.
getDarwinDWARFResourceForPath(const std::string & Path,const std::string & Basename)24973471bf0Spatrick std::string getDarwinDWARFResourceForPath(const std::string &Path,
25073471bf0Spatrick                                           const std::string &Basename) {
25109467b48Spatrick   SmallString<16> ResourceName = StringRef(Path);
25209467b48Spatrick   if (sys::path::extension(Path) != ".dSYM") {
25309467b48Spatrick     ResourceName += ".dSYM";
25409467b48Spatrick   }
25509467b48Spatrick   sys::path::append(ResourceName, "Contents", "Resources", "DWARF");
25609467b48Spatrick   sys::path::append(ResourceName, Basename);
257097a140dSpatrick   return std::string(ResourceName.str());
25809467b48Spatrick }
25909467b48Spatrick 
checkFileCRC(StringRef Path,uint32_t CRCHash)26009467b48Spatrick bool checkFileCRC(StringRef Path, uint32_t CRCHash) {
26109467b48Spatrick   ErrorOr<std::unique_ptr<MemoryBuffer>> MB =
26209467b48Spatrick       MemoryBuffer::getFileOrSTDIN(Path);
26309467b48Spatrick   if (!MB)
26409467b48Spatrick     return false;
26509467b48Spatrick   return CRCHash == llvm::crc32(arrayRefFromStringRef(MB.get()->getBuffer()));
26609467b48Spatrick }
26709467b48Spatrick 
getGNUDebuglinkContents(const ObjectFile * Obj,std::string & DebugName,uint32_t & CRCHash)26809467b48Spatrick bool getGNUDebuglinkContents(const ObjectFile *Obj, std::string &DebugName,
26909467b48Spatrick                              uint32_t &CRCHash) {
27009467b48Spatrick   if (!Obj)
27109467b48Spatrick     return false;
27209467b48Spatrick   for (const SectionRef &Section : Obj->sections()) {
27309467b48Spatrick     StringRef Name;
274*d415bd75Srobert     consumeError(Section.getName().moveInto(Name));
27509467b48Spatrick 
27609467b48Spatrick     Name = Name.substr(Name.find_first_not_of("._"));
27709467b48Spatrick     if (Name == "gnu_debuglink") {
27809467b48Spatrick       Expected<StringRef> ContentsOrErr = Section.getContents();
27909467b48Spatrick       if (!ContentsOrErr) {
28009467b48Spatrick         consumeError(ContentsOrErr.takeError());
28109467b48Spatrick         return false;
28209467b48Spatrick       }
28309467b48Spatrick       DataExtractor DE(*ContentsOrErr, Obj->isLittleEndian(), 0);
28409467b48Spatrick       uint64_t Offset = 0;
28509467b48Spatrick       if (const char *DebugNameStr = DE.getCStr(&Offset)) {
28609467b48Spatrick         // 4-byte align the offset.
28709467b48Spatrick         Offset = (Offset + 3) & ~0x3;
28809467b48Spatrick         if (DE.isValidOffsetForDataOfSize(Offset, 4)) {
28909467b48Spatrick           DebugName = DebugNameStr;
29009467b48Spatrick           CRCHash = DE.getU32(&Offset);
29109467b48Spatrick           return true;
29209467b48Spatrick         }
29309467b48Spatrick       }
29409467b48Spatrick       break;
29509467b48Spatrick     }
29609467b48Spatrick   }
29709467b48Spatrick   return false;
29809467b48Spatrick }
29909467b48Spatrick 
darwinDsymMatchesBinary(const MachOObjectFile * DbgObj,const MachOObjectFile * Obj)30009467b48Spatrick bool darwinDsymMatchesBinary(const MachOObjectFile *DbgObj,
30109467b48Spatrick                              const MachOObjectFile *Obj) {
30209467b48Spatrick   ArrayRef<uint8_t> dbg_uuid = DbgObj->getUuid();
30309467b48Spatrick   ArrayRef<uint8_t> bin_uuid = Obj->getUuid();
30409467b48Spatrick   if (dbg_uuid.empty() || bin_uuid.empty())
30509467b48Spatrick     return false;
30609467b48Spatrick   return !memcmp(dbg_uuid.data(), bin_uuid.data(), dbg_uuid.size());
30709467b48Spatrick }
30809467b48Spatrick 
30909467b48Spatrick } // end anonymous namespace
31009467b48Spatrick 
lookUpDsymFile(const std::string & ExePath,const MachOObjectFile * MachExeObj,const std::string & ArchName)31109467b48Spatrick ObjectFile *LLVMSymbolizer::lookUpDsymFile(const std::string &ExePath,
31273471bf0Spatrick                                            const MachOObjectFile *MachExeObj,
31373471bf0Spatrick                                            const std::string &ArchName) {
31409467b48Spatrick   // On Darwin we may find DWARF in separate object file in
31509467b48Spatrick   // resource directory.
31609467b48Spatrick   std::vector<std::string> DsymPaths;
31709467b48Spatrick   StringRef Filename = sys::path::filename(ExePath);
318097a140dSpatrick   DsymPaths.push_back(
319097a140dSpatrick       getDarwinDWARFResourceForPath(ExePath, std::string(Filename)));
32009467b48Spatrick   for (const auto &Path : Opts.DsymHints) {
321097a140dSpatrick     DsymPaths.push_back(
322097a140dSpatrick         getDarwinDWARFResourceForPath(Path, std::string(Filename)));
32309467b48Spatrick   }
32409467b48Spatrick   for (const auto &Path : DsymPaths) {
32509467b48Spatrick     auto DbgObjOrErr = getOrCreateObject(Path, ArchName);
32609467b48Spatrick     if (!DbgObjOrErr) {
32709467b48Spatrick       // Ignore errors, the file might not exist.
32809467b48Spatrick       consumeError(DbgObjOrErr.takeError());
32909467b48Spatrick       continue;
33009467b48Spatrick     }
33109467b48Spatrick     ObjectFile *DbgObj = DbgObjOrErr.get();
33209467b48Spatrick     if (!DbgObj)
33309467b48Spatrick       continue;
33409467b48Spatrick     const MachOObjectFile *MachDbgObj = dyn_cast<const MachOObjectFile>(DbgObj);
33509467b48Spatrick     if (!MachDbgObj)
33609467b48Spatrick       continue;
33709467b48Spatrick     if (darwinDsymMatchesBinary(MachDbgObj, MachExeObj))
33809467b48Spatrick       return DbgObj;
33909467b48Spatrick   }
34009467b48Spatrick   return nullptr;
34109467b48Spatrick }
34209467b48Spatrick 
lookUpDebuglinkObject(const std::string & Path,const ObjectFile * Obj,const std::string & ArchName)34309467b48Spatrick ObjectFile *LLVMSymbolizer::lookUpDebuglinkObject(const std::string &Path,
34409467b48Spatrick                                                   const ObjectFile *Obj,
34509467b48Spatrick                                                   const std::string &ArchName) {
34609467b48Spatrick   std::string DebuglinkName;
34709467b48Spatrick   uint32_t CRCHash;
34809467b48Spatrick   std::string DebugBinaryPath;
34909467b48Spatrick   if (!getGNUDebuglinkContents(Obj, DebuglinkName, CRCHash))
35009467b48Spatrick     return nullptr;
351*d415bd75Srobert   if (!findDebugBinary(Path, DebuglinkName, CRCHash, DebugBinaryPath))
35209467b48Spatrick     return nullptr;
35309467b48Spatrick   auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName);
35409467b48Spatrick   if (!DbgObjOrErr) {
35509467b48Spatrick     // Ignore errors, the file might not exist.
35609467b48Spatrick     consumeError(DbgObjOrErr.takeError());
35709467b48Spatrick     return nullptr;
35809467b48Spatrick   }
35909467b48Spatrick   return DbgObjOrErr.get();
36009467b48Spatrick }
36109467b48Spatrick 
lookUpBuildIDObject(const std::string & Path,const ELFObjectFileBase * Obj,const std::string & ArchName)36209467b48Spatrick ObjectFile *LLVMSymbolizer::lookUpBuildIDObject(const std::string &Path,
36309467b48Spatrick                                                 const ELFObjectFileBase *Obj,
36409467b48Spatrick                                                 const std::string &ArchName) {
36509467b48Spatrick   auto BuildID = getBuildID(Obj);
36609467b48Spatrick   if (!BuildID)
36709467b48Spatrick     return nullptr;
36809467b48Spatrick   if (BuildID->size() < 2)
36909467b48Spatrick     return nullptr;
37009467b48Spatrick   std::string DebugBinaryPath;
371*d415bd75Srobert   if (!getOrFindDebugBinary(*BuildID, DebugBinaryPath))
37209467b48Spatrick     return nullptr;
37309467b48Spatrick   auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName);
37409467b48Spatrick   if (!DbgObjOrErr) {
37509467b48Spatrick     consumeError(DbgObjOrErr.takeError());
37609467b48Spatrick     return nullptr;
37709467b48Spatrick   }
37809467b48Spatrick   return DbgObjOrErr.get();
37909467b48Spatrick }
38009467b48Spatrick 
findDebugBinary(const std::string & OrigPath,const std::string & DebuglinkName,uint32_t CRCHash,std::string & Result)381*d415bd75Srobert bool LLVMSymbolizer::findDebugBinary(const std::string &OrigPath,
382*d415bd75Srobert                                      const std::string &DebuglinkName,
383*d415bd75Srobert                                      uint32_t CRCHash, std::string &Result) {
384*d415bd75Srobert   SmallString<16> OrigDir(OrigPath);
385*d415bd75Srobert   llvm::sys::path::remove_filename(OrigDir);
386*d415bd75Srobert   SmallString<16> DebugPath = OrigDir;
387*d415bd75Srobert   // Try relative/path/to/original_binary/debuglink_name
388*d415bd75Srobert   llvm::sys::path::append(DebugPath, DebuglinkName);
389*d415bd75Srobert   if (checkFileCRC(DebugPath, CRCHash)) {
390*d415bd75Srobert     Result = std::string(DebugPath.str());
391*d415bd75Srobert     return true;
392*d415bd75Srobert   }
393*d415bd75Srobert   // Try relative/path/to/original_binary/.debug/debuglink_name
394*d415bd75Srobert   DebugPath = OrigDir;
395*d415bd75Srobert   llvm::sys::path::append(DebugPath, ".debug", DebuglinkName);
396*d415bd75Srobert   if (checkFileCRC(DebugPath, CRCHash)) {
397*d415bd75Srobert     Result = std::string(DebugPath.str());
398*d415bd75Srobert     return true;
399*d415bd75Srobert   }
400*d415bd75Srobert   // Make the path absolute so that lookups will go to
401*d415bd75Srobert   // "/usr/lib/debug/full/path/to/debug", not
402*d415bd75Srobert   // "/usr/lib/debug/to/debug"
403*d415bd75Srobert   llvm::sys::fs::make_absolute(OrigDir);
404*d415bd75Srobert   if (!Opts.FallbackDebugPath.empty()) {
405*d415bd75Srobert     // Try <FallbackDebugPath>/absolute/path/to/original_binary/debuglink_name
406*d415bd75Srobert     DebugPath = Opts.FallbackDebugPath;
407*d415bd75Srobert   } else {
408*d415bd75Srobert #if defined(__NetBSD__)
409*d415bd75Srobert     // Try /usr/libdata/debug/absolute/path/to/original_binary/debuglink_name
410*d415bd75Srobert     DebugPath = "/usr/libdata/debug";
411*d415bd75Srobert #else
412*d415bd75Srobert     // Try /usr/lib/debug/absolute/path/to/original_binary/debuglink_name
413*d415bd75Srobert     DebugPath = "/usr/lib/debug";
414*d415bd75Srobert #endif
415*d415bd75Srobert   }
416*d415bd75Srobert   llvm::sys::path::append(DebugPath, llvm::sys::path::relative_path(OrigDir),
417*d415bd75Srobert                           DebuglinkName);
418*d415bd75Srobert   if (checkFileCRC(DebugPath, CRCHash)) {
419*d415bd75Srobert     Result = std::string(DebugPath.str());
420*d415bd75Srobert     return true;
421*d415bd75Srobert   }
422*d415bd75Srobert   return false;
423*d415bd75Srobert }
424*d415bd75Srobert 
getBuildIDStr(ArrayRef<uint8_t> BuildID)425*d415bd75Srobert static StringRef getBuildIDStr(ArrayRef<uint8_t> BuildID) {
426*d415bd75Srobert   return StringRef(reinterpret_cast<const char *>(BuildID.data()),
427*d415bd75Srobert                    BuildID.size());
428*d415bd75Srobert }
429*d415bd75Srobert 
getOrFindDebugBinary(const ArrayRef<uint8_t> BuildID,std::string & Result)430*d415bd75Srobert bool LLVMSymbolizer::getOrFindDebugBinary(const ArrayRef<uint8_t> BuildID,
431*d415bd75Srobert                                           std::string &Result) {
432*d415bd75Srobert   StringRef BuildIDStr = getBuildIDStr(BuildID);
433*d415bd75Srobert   auto I = BuildIDPaths.find(BuildIDStr);
434*d415bd75Srobert   if (I != BuildIDPaths.end()) {
435*d415bd75Srobert     Result = I->second;
436*d415bd75Srobert     return true;
437*d415bd75Srobert   }
438*d415bd75Srobert   if (!BIDFetcher)
439*d415bd75Srobert     return false;
440*d415bd75Srobert   if (std::optional<std::string> Path = BIDFetcher->fetch(BuildID)) {
441*d415bd75Srobert     Result = *Path;
442*d415bd75Srobert     auto InsertResult = BuildIDPaths.insert({BuildIDStr, Result});
443*d415bd75Srobert     assert(InsertResult.second);
444*d415bd75Srobert     (void)InsertResult;
445*d415bd75Srobert     return true;
446*d415bd75Srobert   }
447*d415bd75Srobert 
448*d415bd75Srobert   return false;
449*d415bd75Srobert }
450*d415bd75Srobert 
45109467b48Spatrick Expected<LLVMSymbolizer::ObjectPair>
getOrCreateObjectPair(const std::string & Path,const std::string & ArchName)45209467b48Spatrick LLVMSymbolizer::getOrCreateObjectPair(const std::string &Path,
45309467b48Spatrick                                       const std::string &ArchName) {
45409467b48Spatrick   auto I = ObjectPairForPathArch.find(std::make_pair(Path, ArchName));
455*d415bd75Srobert   if (I != ObjectPairForPathArch.end()) {
456*d415bd75Srobert     recordAccess(BinaryForPath.find(Path)->second);
45709467b48Spatrick     return I->second;
458*d415bd75Srobert   }
45909467b48Spatrick 
46009467b48Spatrick   auto ObjOrErr = getOrCreateObject(Path, ArchName);
46109467b48Spatrick   if (!ObjOrErr) {
46209467b48Spatrick     ObjectPairForPathArch.emplace(std::make_pair(Path, ArchName),
46309467b48Spatrick                                   ObjectPair(nullptr, nullptr));
46409467b48Spatrick     return ObjOrErr.takeError();
46509467b48Spatrick   }
46609467b48Spatrick 
46709467b48Spatrick   ObjectFile *Obj = ObjOrErr.get();
46809467b48Spatrick   assert(Obj != nullptr);
46909467b48Spatrick   ObjectFile *DbgObj = nullptr;
47009467b48Spatrick 
47109467b48Spatrick   if (auto MachObj = dyn_cast<const MachOObjectFile>(Obj))
47209467b48Spatrick     DbgObj = lookUpDsymFile(Path, MachObj, ArchName);
47309467b48Spatrick   else if (auto ELFObj = dyn_cast<const ELFObjectFileBase>(Obj))
47409467b48Spatrick     DbgObj = lookUpBuildIDObject(Path, ELFObj, ArchName);
47509467b48Spatrick   if (!DbgObj)
47609467b48Spatrick     DbgObj = lookUpDebuglinkObject(Path, Obj, ArchName);
47709467b48Spatrick   if (!DbgObj)
47809467b48Spatrick     DbgObj = Obj;
47909467b48Spatrick   ObjectPair Res = std::make_pair(Obj, DbgObj);
480*d415bd75Srobert   std::string DbgObjPath = DbgObj->getFileName().str();
481*d415bd75Srobert   auto Pair =
48209467b48Spatrick       ObjectPairForPathArch.emplace(std::make_pair(Path, ArchName), Res);
483*d415bd75Srobert   BinaryForPath.find(DbgObjPath)->second.pushEvictor([this, I = Pair.first]() {
484*d415bd75Srobert     ObjectPairForPathArch.erase(I);
485*d415bd75Srobert   });
48609467b48Spatrick   return Res;
48709467b48Spatrick }
48809467b48Spatrick 
48909467b48Spatrick Expected<ObjectFile *>
getOrCreateObject(const std::string & Path,const std::string & ArchName)49009467b48Spatrick LLVMSymbolizer::getOrCreateObject(const std::string &Path,
49109467b48Spatrick                                   const std::string &ArchName) {
49209467b48Spatrick   Binary *Bin;
49309467b48Spatrick   auto Pair = BinaryForPath.emplace(Path, OwningBinary<Binary>());
49409467b48Spatrick   if (!Pair.second) {
495*d415bd75Srobert     Bin = Pair.first->second->getBinary();
496*d415bd75Srobert     recordAccess(Pair.first->second);
49709467b48Spatrick   } else {
49809467b48Spatrick     Expected<OwningBinary<Binary>> BinOrErr = createBinary(Path);
49909467b48Spatrick     if (!BinOrErr)
50009467b48Spatrick       return BinOrErr.takeError();
501*d415bd75Srobert 
502*d415bd75Srobert     CachedBinary &CachedBin = Pair.first->second;
503*d415bd75Srobert     CachedBin = std::move(BinOrErr.get());
504*d415bd75Srobert     CachedBin.pushEvictor([this, I = Pair.first]() { BinaryForPath.erase(I); });
505*d415bd75Srobert     LRUBinaries.push_back(CachedBin);
506*d415bd75Srobert     CacheSize += CachedBin.size();
507*d415bd75Srobert     Bin = CachedBin->getBinary();
50809467b48Spatrick   }
50909467b48Spatrick 
51009467b48Spatrick   if (!Bin)
51109467b48Spatrick     return static_cast<ObjectFile *>(nullptr);
51209467b48Spatrick 
51309467b48Spatrick   if (MachOUniversalBinary *UB = dyn_cast_or_null<MachOUniversalBinary>(Bin)) {
51409467b48Spatrick     auto I = ObjectForUBPathAndArch.find(std::make_pair(Path, ArchName));
51509467b48Spatrick     if (I != ObjectForUBPathAndArch.end())
51609467b48Spatrick       return I->second.get();
51709467b48Spatrick 
51809467b48Spatrick     Expected<std::unique_ptr<ObjectFile>> ObjOrErr =
51909467b48Spatrick         UB->getMachOObjectForArch(ArchName);
52009467b48Spatrick     if (!ObjOrErr) {
52109467b48Spatrick       ObjectForUBPathAndArch.emplace(std::make_pair(Path, ArchName),
52209467b48Spatrick                                      std::unique_ptr<ObjectFile>());
52309467b48Spatrick       return ObjOrErr.takeError();
52409467b48Spatrick     }
52509467b48Spatrick     ObjectFile *Res = ObjOrErr->get();
526*d415bd75Srobert     auto Pair = ObjectForUBPathAndArch.emplace(std::make_pair(Path, ArchName),
52709467b48Spatrick                                                std::move(ObjOrErr.get()));
528*d415bd75Srobert     BinaryForPath.find(Path)->second.pushEvictor(
529*d415bd75Srobert         [this, Iter = Pair.first]() { ObjectForUBPathAndArch.erase(Iter); });
53009467b48Spatrick     return Res;
53109467b48Spatrick   }
53209467b48Spatrick   if (Bin->isObject()) {
53309467b48Spatrick     return cast<ObjectFile>(Bin);
53409467b48Spatrick   }
53509467b48Spatrick   return errorCodeToError(object_error::arch_not_found);
53609467b48Spatrick }
53709467b48Spatrick 
53809467b48Spatrick Expected<SymbolizableModule *>
createModuleInfo(const ObjectFile * Obj,std::unique_ptr<DIContext> Context,StringRef ModuleName)53909467b48Spatrick LLVMSymbolizer::createModuleInfo(const ObjectFile *Obj,
54009467b48Spatrick                                  std::unique_ptr<DIContext> Context,
54109467b48Spatrick                                  StringRef ModuleName) {
54209467b48Spatrick   auto InfoOrErr = SymbolizableObjectFile::create(Obj, std::move(Context),
54309467b48Spatrick                                                   Opts.UntagAddresses);
54409467b48Spatrick   std::unique_ptr<SymbolizableModule> SymMod;
54509467b48Spatrick   if (InfoOrErr)
54609467b48Spatrick     SymMod = std::move(*InfoOrErr);
547097a140dSpatrick   auto InsertResult = Modules.insert(
548097a140dSpatrick       std::make_pair(std::string(ModuleName), std::move(SymMod)));
54909467b48Spatrick   assert(InsertResult.second);
550097a140dSpatrick   if (!InfoOrErr)
551097a140dSpatrick     return InfoOrErr.takeError();
55209467b48Spatrick   return InsertResult.first->second.get();
55309467b48Spatrick }
55409467b48Spatrick 
55509467b48Spatrick Expected<SymbolizableModule *>
getOrCreateModuleInfo(const std::string & ModuleName)55609467b48Spatrick LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
55709467b48Spatrick   std::string BinaryName = ModuleName;
55809467b48Spatrick   std::string ArchName = Opts.DefaultArch;
55909467b48Spatrick   size_t ColonPos = ModuleName.find_last_of(':');
56009467b48Spatrick   // Verify that substring after colon form a valid arch name.
56109467b48Spatrick   if (ColonPos != std::string::npos) {
56209467b48Spatrick     std::string ArchStr = ModuleName.substr(ColonPos + 1);
56309467b48Spatrick     if (Triple(ArchStr).getArch() != Triple::UnknownArch) {
56409467b48Spatrick       BinaryName = ModuleName.substr(0, ColonPos);
56509467b48Spatrick       ArchName = ArchStr;
56609467b48Spatrick     }
56709467b48Spatrick   }
568*d415bd75Srobert 
569*d415bd75Srobert   auto I = Modules.find(ModuleName);
570*d415bd75Srobert   if (I != Modules.end()) {
571*d415bd75Srobert     recordAccess(BinaryForPath.find(BinaryName)->second);
572*d415bd75Srobert     return I->second.get();
573*d415bd75Srobert   }
574*d415bd75Srobert 
57509467b48Spatrick   auto ObjectsOrErr = getOrCreateObjectPair(BinaryName, ArchName);
57609467b48Spatrick   if (!ObjectsOrErr) {
57709467b48Spatrick     // Failed to find valid object file.
57809467b48Spatrick     Modules.emplace(ModuleName, std::unique_ptr<SymbolizableModule>());
57909467b48Spatrick     return ObjectsOrErr.takeError();
58009467b48Spatrick   }
58109467b48Spatrick   ObjectPair Objects = ObjectsOrErr.get();
58209467b48Spatrick 
58309467b48Spatrick   std::unique_ptr<DIContext> Context;
58409467b48Spatrick   // If this is a COFF object containing PDB info, use a PDBContext to
58509467b48Spatrick   // symbolize. Otherwise, use DWARF.
58609467b48Spatrick   if (auto CoffObject = dyn_cast<COFFObjectFile>(Objects.first)) {
58709467b48Spatrick     const codeview::DebugInfo *DebugInfo;
58809467b48Spatrick     StringRef PDBFileName;
58909467b48Spatrick     auto EC = CoffObject->getDebugPDBInfo(DebugInfo, PDBFileName);
59009467b48Spatrick     if (!EC && DebugInfo != nullptr && !PDBFileName.empty()) {
59109467b48Spatrick       using namespace pdb;
59209467b48Spatrick       std::unique_ptr<IPDBSession> Session;
59373471bf0Spatrick 
59473471bf0Spatrick       PDB_ReaderType ReaderType =
59573471bf0Spatrick           Opts.UseDIA ? PDB_ReaderType::DIA : PDB_ReaderType::Native;
596097a140dSpatrick       if (auto Err = loadDataForEXE(ReaderType, Objects.first->getFileName(),
597097a140dSpatrick                                     Session)) {
59809467b48Spatrick         Modules.emplace(ModuleName, std::unique_ptr<SymbolizableModule>());
59909467b48Spatrick         // Return along the PDB filename to provide more context
60009467b48Spatrick         return createFileError(PDBFileName, std::move(Err));
60109467b48Spatrick       }
60209467b48Spatrick       Context.reset(new PDBContext(*CoffObject, std::move(Session)));
60309467b48Spatrick     }
60409467b48Spatrick   }
60509467b48Spatrick   if (!Context)
606*d415bd75Srobert     Context = DWARFContext::create(
607*d415bd75Srobert         *Objects.second, DWARFContext::ProcessDebugRelocations::Process,
608*d415bd75Srobert         nullptr, Opts.DWPName);
609*d415bd75Srobert   auto ModuleOrErr =
610*d415bd75Srobert       createModuleInfo(Objects.first, std::move(Context), ModuleName);
611*d415bd75Srobert   if (ModuleOrErr) {
612*d415bd75Srobert     auto I = Modules.find(ModuleName);
613*d415bd75Srobert     BinaryForPath.find(BinaryName)->second.pushEvictor([this, I]() {
614*d415bd75Srobert       Modules.erase(I);
615*d415bd75Srobert     });
616*d415bd75Srobert   }
617*d415bd75Srobert   return ModuleOrErr;
61809467b48Spatrick }
61909467b48Spatrick 
62073471bf0Spatrick Expected<SymbolizableModule *>
getOrCreateModuleInfo(const ObjectFile & Obj)62173471bf0Spatrick LLVMSymbolizer::getOrCreateModuleInfo(const ObjectFile &Obj) {
62273471bf0Spatrick   StringRef ObjName = Obj.getFileName();
62373471bf0Spatrick   auto I = Modules.find(ObjName);
62473471bf0Spatrick   if (I != Modules.end())
62573471bf0Spatrick     return I->second.get();
62673471bf0Spatrick 
62773471bf0Spatrick   std::unique_ptr<DIContext> Context = DWARFContext::create(Obj);
62873471bf0Spatrick   // FIXME: handle COFF object with PDB info to use PDBContext
62973471bf0Spatrick   return createModuleInfo(&Obj, std::move(Context), ObjName);
63073471bf0Spatrick }
63173471bf0Spatrick 
632*d415bd75Srobert Expected<SymbolizableModule *>
getOrCreateModuleInfo(ArrayRef<uint8_t> BuildID)633*d415bd75Srobert LLVMSymbolizer::getOrCreateModuleInfo(ArrayRef<uint8_t> BuildID) {
634*d415bd75Srobert   std::string Path;
635*d415bd75Srobert   if (!getOrFindDebugBinary(BuildID, Path)) {
636*d415bd75Srobert     return createStringError(errc::no_such_file_or_directory,
637*d415bd75Srobert                              Twine("could not find build ID '") +
638*d415bd75Srobert                                  toHex(BuildID) + "'");
639*d415bd75Srobert   }
640*d415bd75Srobert   return getOrCreateModuleInfo(Path);
641*d415bd75Srobert }
642*d415bd75Srobert 
64309467b48Spatrick namespace {
64409467b48Spatrick 
64509467b48Spatrick // Undo these various manglings for Win32 extern "C" functions:
64609467b48Spatrick // cdecl       - _foo
64709467b48Spatrick // stdcall     - _foo@12
64809467b48Spatrick // fastcall    - @foo@12
64909467b48Spatrick // vectorcall  - foo@@12
65009467b48Spatrick // These are all different linkage names for 'foo'.
demanglePE32ExternCFunc(StringRef SymbolName)65109467b48Spatrick StringRef demanglePE32ExternCFunc(StringRef SymbolName) {
65209467b48Spatrick   char Front = SymbolName.empty() ? '\0' : SymbolName[0];
65309467b48Spatrick 
65409467b48Spatrick   // Remove any '@[0-9]+' suffix.
655*d415bd75Srobert   bool HasAtNumSuffix = false;
65609467b48Spatrick   if (Front != '?') {
65709467b48Spatrick     size_t AtPos = SymbolName.rfind('@');
65809467b48Spatrick     if (AtPos != StringRef::npos &&
659*d415bd75Srobert         all_of(drop_begin(SymbolName, AtPos + 1), isDigit)) {
66009467b48Spatrick       SymbolName = SymbolName.substr(0, AtPos);
661*d415bd75Srobert       HasAtNumSuffix = true;
662*d415bd75Srobert     }
66309467b48Spatrick   }
66409467b48Spatrick 
66509467b48Spatrick   // Remove any ending '@' for vectorcall.
666*d415bd75Srobert   bool IsVectorCall = false;
667*d415bd75Srobert   if (HasAtNumSuffix && SymbolName.endswith("@")) {
66809467b48Spatrick     SymbolName = SymbolName.drop_back();
669*d415bd75Srobert     IsVectorCall = true;
670*d415bd75Srobert   }
671*d415bd75Srobert 
672*d415bd75Srobert   // If not vectorcall, remove any '_' or '@' prefix.
673*d415bd75Srobert   if (!IsVectorCall && (Front == '_' || Front == '@'))
674*d415bd75Srobert     SymbolName = SymbolName.drop_front();
67509467b48Spatrick 
67609467b48Spatrick   return SymbolName;
67709467b48Spatrick }
67809467b48Spatrick 
67909467b48Spatrick } // end anonymous namespace
68009467b48Spatrick 
68109467b48Spatrick std::string
DemangleName(const std::string & Name,const SymbolizableModule * DbiModuleDescriptor)68209467b48Spatrick LLVMSymbolizer::DemangleName(const std::string &Name,
68309467b48Spatrick                              const SymbolizableModule *DbiModuleDescriptor) {
684*d415bd75Srobert   std::string Result;
685*d415bd75Srobert   if (nonMicrosoftDemangle(Name.c_str(), Result))
68609467b48Spatrick     return Result;
68709467b48Spatrick 
68809467b48Spatrick   if (!Name.empty() && Name.front() == '?') {
68909467b48Spatrick     // Only do MSVC C++ demangling on symbols starting with '?'.
69009467b48Spatrick     int status = 0;
69109467b48Spatrick     char *DemangledName = microsoftDemangle(
692097a140dSpatrick         Name.c_str(), nullptr, nullptr, nullptr, &status,
69309467b48Spatrick         MSDemangleFlags(MSDF_NoAccessSpecifier | MSDF_NoCallingConvention |
69409467b48Spatrick                         MSDF_NoMemberType | MSDF_NoReturnType));
69509467b48Spatrick     if (status != 0)
69609467b48Spatrick       return Name;
697*d415bd75Srobert     Result = DemangledName;
69809467b48Spatrick     free(DemangledName);
69909467b48Spatrick     return Result;
70009467b48Spatrick   }
70109467b48Spatrick 
702*d415bd75Srobert   if (DbiModuleDescriptor && DbiModuleDescriptor->isWin32Module()) {
703*d415bd75Srobert     std::string DemangledCName(demanglePE32ExternCFunc(Name));
704*d415bd75Srobert     // On i386 Windows, the C name mangling for different calling conventions
705*d415bd75Srobert     // may also be applied on top of the Itanium or Rust name mangling.
706*d415bd75Srobert     if (nonMicrosoftDemangle(DemangledCName.c_str(), Result))
707*d415bd75Srobert       return Result;
708*d415bd75Srobert     return DemangledCName;
709*d415bd75Srobert   }
71009467b48Spatrick   return Name;
71109467b48Spatrick }
71209467b48Spatrick 
recordAccess(CachedBinary & Bin)713*d415bd75Srobert void LLVMSymbolizer::recordAccess(CachedBinary &Bin) {
714*d415bd75Srobert   if (Bin->getBinary())
715*d415bd75Srobert     LRUBinaries.splice(LRUBinaries.end(), LRUBinaries, Bin.getIterator());
716*d415bd75Srobert }
717*d415bd75Srobert 
pruneCache()718*d415bd75Srobert void LLVMSymbolizer::pruneCache() {
719*d415bd75Srobert   // Evict the LRU binary until the max cache size is reached or there's <= 1
720*d415bd75Srobert   // item in the cache. The MRU binary is always kept to avoid thrashing if it's
721*d415bd75Srobert   // larger than the cache size.
722*d415bd75Srobert   while (CacheSize > Opts.MaxCacheSize && !LRUBinaries.empty() &&
723*d415bd75Srobert          std::next(LRUBinaries.begin()) != LRUBinaries.end()) {
724*d415bd75Srobert     CachedBinary &Bin = LRUBinaries.front();
725*d415bd75Srobert     CacheSize -= Bin.size();
726*d415bd75Srobert     LRUBinaries.pop_front();
727*d415bd75Srobert     Bin.evict();
728*d415bd75Srobert   }
729*d415bd75Srobert }
730*d415bd75Srobert 
pushEvictor(std::function<void ()> NewEvictor)731*d415bd75Srobert void CachedBinary::pushEvictor(std::function<void()> NewEvictor) {
732*d415bd75Srobert   if (Evictor) {
733*d415bd75Srobert     this->Evictor = [OldEvictor = std::move(this->Evictor),
734*d415bd75Srobert                      NewEvictor = std::move(NewEvictor)]() {
735*d415bd75Srobert       NewEvictor();
736*d415bd75Srobert       OldEvictor();
737*d415bd75Srobert     };
738*d415bd75Srobert   } else {
739*d415bd75Srobert     this->Evictor = std::move(NewEvictor);
740*d415bd75Srobert   }
741*d415bd75Srobert }
742*d415bd75Srobert 
74309467b48Spatrick } // namespace symbolize
74409467b48Spatrick } // namespace llvm
745