1 //===- Symbolize.h ----------------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Header for LLVM symbolization library. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LLVM_DEBUGINFO_SYMBOLIZE_SYMBOLIZE_H 14 #define LLVM_DEBUGINFO_SYMBOLIZE_SYMBOLIZE_H 15 16 #include "llvm/ADT/StringMap.h" 17 #include "llvm/ADT/ilist_node.h" 18 #include "llvm/ADT/simple_ilist.h" 19 #include "llvm/DebugInfo/DIContext.h" 20 #include "llvm/Object/Binary.h" 21 #include "llvm/Object/BuildID.h" 22 #include "llvm/Support/Compiler.h" 23 #include "llvm/Support/Error.h" 24 #include <algorithm> 25 #include <cstdint> 26 #include <map> 27 #include <memory> 28 #include <string> 29 #include <utility> 30 #include <vector> 31 32 namespace llvm { 33 namespace object { 34 class ELFObjectFileBase; 35 class MachOObjectFile; 36 class ObjectFile; 37 struct SectionedAddress; 38 } // namespace object 39 40 namespace symbolize { 41 42 class SymbolizableModule; 43 44 using namespace object; 45 46 using FunctionNameKind = DILineInfoSpecifier::FunctionNameKind; 47 using FileLineInfoKind = DILineInfoSpecifier::FileLineInfoKind; 48 49 class CachedBinary; 50 51 class LLVMSymbolizer { 52 public: 53 struct Options { 54 FunctionNameKind PrintFunctions = FunctionNameKind::LinkageName; 55 FileLineInfoKind PathStyle = FileLineInfoKind::AbsoluteFilePath; 56 bool SkipLineZero = false; 57 bool UseSymbolTable = true; 58 bool Demangle = true; 59 bool RelativeAddresses = false; 60 bool UntagAddresses = false; 61 bool UseDIA = false; 62 bool DisableGsym = false; 63 std::string DefaultArch; 64 std::vector<std::string> DsymHints; 65 std::string FallbackDebugPath; 66 std::string DWPName; 67 std::vector<std::string> DebugFileDirectory; 68 std::vector<std::string> GsymFileDirectory; 69 size_t MaxCacheSize = 70 sizeof(size_t) == 4 71 ? 512 * 1024 * 1024 /* 512 MiB */ 72 : static_cast<size_t>(4ULL * 1024 * 1024 * 1024) /* 4 GiB */; 73 }; 74 75 LLVM_ABI LLVMSymbolizer(); 76 LLVM_ABI LLVMSymbolizer(const Options &Opts); 77 78 LLVM_ABI ~LLVMSymbolizer(); 79 80 // Overloads accepting ObjectFile does not support COFF currently 81 LLVM_ABI Expected<DILineInfo> 82 symbolizeCode(const ObjectFile &Obj, object::SectionedAddress ModuleOffset); 83 LLVM_ABI Expected<DILineInfo> 84 symbolizeCode(StringRef ModuleName, object::SectionedAddress ModuleOffset); 85 LLVM_ABI Expected<DILineInfo> 86 symbolizeCode(ArrayRef<uint8_t> BuildID, 87 object::SectionedAddress ModuleOffset); 88 LLVM_ABI Expected<DIInliningInfo> 89 symbolizeInlinedCode(const ObjectFile &Obj, 90 object::SectionedAddress ModuleOffset); 91 LLVM_ABI Expected<DIInliningInfo> 92 symbolizeInlinedCode(StringRef ModuleName, 93 object::SectionedAddress ModuleOffset); 94 LLVM_ABI Expected<DIInliningInfo> 95 symbolizeInlinedCode(ArrayRef<uint8_t> BuildID, 96 object::SectionedAddress ModuleOffset); 97 98 LLVM_ABI Expected<DIGlobal> 99 symbolizeData(const ObjectFile &Obj, object::SectionedAddress ModuleOffset); 100 LLVM_ABI Expected<DIGlobal> 101 symbolizeData(StringRef ModuleName, object::SectionedAddress ModuleOffset); 102 LLVM_ABI Expected<DIGlobal> 103 symbolizeData(ArrayRef<uint8_t> BuildID, 104 object::SectionedAddress ModuleOffset); 105 LLVM_ABI Expected<std::vector<DILocal>> 106 symbolizeFrame(const ObjectFile &Obj, object::SectionedAddress ModuleOffset); 107 LLVM_ABI Expected<std::vector<DILocal>> 108 symbolizeFrame(StringRef ModuleName, object::SectionedAddress ModuleOffset); 109 LLVM_ABI Expected<std::vector<DILocal>> 110 symbolizeFrame(ArrayRef<uint8_t> BuildID, 111 object::SectionedAddress ModuleOffset); 112 113 LLVM_ABI Expected<std::vector<DILineInfo>> 114 findSymbol(const ObjectFile &Obj, StringRef Symbol, uint64_t Offset); 115 LLVM_ABI Expected<std::vector<DILineInfo>> 116 findSymbol(StringRef ModuleName, StringRef Symbol, uint64_t Offset); 117 LLVM_ABI Expected<std::vector<DILineInfo>> 118 findSymbol(ArrayRef<uint8_t> BuildID, StringRef Symbol, uint64_t Offset); 119 120 LLVM_ABI void flush(); 121 122 // Evict entries from the binary cache until it is under the maximum size 123 // given in the options. Calling this invalidates references in the DI... 124 // objects returned by the methods above. 125 LLVM_ABI void pruneCache(); 126 127 LLVM_ABI static std::string 128 DemangleName(StringRef Name, const SymbolizableModule *DbiModuleDescriptor); 129 setBuildIDFetcher(std::unique_ptr<BuildIDFetcher> Fetcher)130 void setBuildIDFetcher(std::unique_ptr<BuildIDFetcher> Fetcher) { 131 BIDFetcher = std::move(Fetcher); 132 } 133 134 /// Returns a SymbolizableModule or an error if loading debug info failed. 135 /// Only one attempt is made to load a module, and errors during loading are 136 /// only reported once. Subsequent calls to get module info for a module that 137 /// failed to load will return nullptr. 138 LLVM_ABI Expected<SymbolizableModule *> 139 getOrCreateModuleInfo(StringRef ModuleName); 140 141 private: 142 // Bundles together object file with code/data and object file with 143 // corresponding debug info. These objects can be the same. 144 using ObjectPair = std::pair<const ObjectFile *, const ObjectFile *>; 145 146 template <typename T> 147 Expected<DILineInfo> 148 symbolizeCodeCommon(const T &ModuleSpecifier, 149 object::SectionedAddress ModuleOffset); 150 template <typename T> 151 Expected<DIInliningInfo> 152 symbolizeInlinedCodeCommon(const T &ModuleSpecifier, 153 object::SectionedAddress ModuleOffset); 154 template <typename T> 155 Expected<DIGlobal> symbolizeDataCommon(const T &ModuleSpecifier, 156 object::SectionedAddress ModuleOffset); 157 template <typename T> 158 Expected<std::vector<DILocal>> 159 symbolizeFrameCommon(const T &ModuleSpecifier, 160 object::SectionedAddress ModuleOffset); 161 template <typename T> 162 Expected<std::vector<DILineInfo>> 163 findSymbolCommon(const T &ModuleSpecifier, StringRef Symbol, uint64_t Offset); 164 165 Expected<SymbolizableModule *> getOrCreateModuleInfo(const ObjectFile &Obj); 166 167 /// Returns a SymbolizableModule or an error if loading debug info failed. 168 /// Unlike the above, errors are reported each time, since they are more 169 /// likely to be transient. 170 Expected<SymbolizableModule *> 171 getOrCreateModuleInfo(ArrayRef<uint8_t> BuildID); 172 173 Expected<SymbolizableModule *> 174 createModuleInfo(const ObjectFile *Obj, std::unique_ptr<DIContext> Context, 175 StringRef ModuleName); 176 177 ObjectFile *lookUpDsymFile(const std::string &Path, 178 const MachOObjectFile *ExeObj, 179 const std::string &ArchName); 180 ObjectFile *lookUpDebuglinkObject(const std::string &Path, 181 const ObjectFile *Obj, 182 const std::string &ArchName); 183 ObjectFile *lookUpBuildIDObject(const std::string &Path, 184 const ELFObjectFileBase *Obj, 185 const std::string &ArchName); 186 std::string lookUpGsymFile(const std::string &Path); 187 188 bool findDebugBinary(const std::string &OrigPath, 189 const std::string &DebuglinkName, uint32_t CRCHash, 190 std::string &Result); 191 192 bool getOrFindDebugBinary(const ArrayRef<uint8_t> BuildID, 193 std::string &Result); 194 195 /// Returns pair of pointers to object and debug object. 196 Expected<ObjectPair> getOrCreateObjectPair(const std::string &Path, 197 const std::string &ArchName); 198 199 /// Return a pointer to object file at specified path, for a specified 200 /// architecture (e.g. if path refers to a Mach-O universal binary, only one 201 /// object file from it will be returned). 202 Expected<ObjectFile *> getOrCreateObject(const std::string &Path, 203 const std::string &ArchName); 204 205 /// Update the LRU cache order when a binary is accessed. 206 void recordAccess(CachedBinary &Bin); 207 208 std::map<std::string, std::unique_ptr<SymbolizableModule>, std::less<>> 209 Modules; 210 StringMap<std::string> BuildIDPaths; 211 212 /// Contains cached results of getOrCreateObjectPair(). 213 std::map<std::pair<std::string, std::string>, ObjectPair> 214 ObjectPairForPathArch; 215 216 /// Contains parsed binary for each path, or parsing error. 217 std::map<std::string, CachedBinary, std::less<>> BinaryForPath; 218 219 /// A list of cached binaries in LRU order. 220 simple_ilist<CachedBinary> LRUBinaries; 221 /// Sum of the sizes of the cached binaries. 222 size_t CacheSize = 0; 223 224 /// Parsed object file for path/architecture pair, where "path" refers 225 /// to Mach-O universal binary. 226 std::map<std::pair<std::string, std::string>, std::unique_ptr<ObjectFile>> 227 ObjectForUBPathAndArch; 228 229 Options Opts; 230 231 std::unique_ptr<BuildIDFetcher> BIDFetcher; 232 }; 233 234 // A binary intrusively linked into a LRU cache list. If the binary is empty, 235 // then the entry marks that an error occurred, and it is not part of the LRU 236 // list. 237 class CachedBinary : public ilist_node<CachedBinary> { 238 public: 239 CachedBinary() = default; CachedBinary(OwningBinary<Binary> Bin)240 CachedBinary(OwningBinary<Binary> Bin) : Bin(std::move(Bin)) {} 241 242 OwningBinary<Binary> &operator*() { return Bin; } 243 OwningBinary<Binary> *operator->() { return &Bin; } 244 245 // Add an action to be performed when the binary is evicted, before all 246 // previously registered evictors. 247 LLVM_ABI void pushEvictor(std::function<void()> Evictor); 248 249 // Run all registered evictors in the reverse of the order in which they were 250 // added. evict()251 void evict() { 252 if (Evictor) 253 Evictor(); 254 } 255 size()256 size_t size() { return Bin.getBinary()->getData().size(); } 257 258 private: 259 OwningBinary<Binary> Bin; 260 std::function<void()> Evictor; 261 }; 262 263 } // end namespace symbolize 264 } // end namespace llvm 265 266 #endif // LLVM_DEBUGINFO_SYMBOLIZE_SYMBOLIZE_H 267