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