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