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 void flush(); 108 109 // Evict entries from the binary cache until it is under the maximum size 110 // given in the options. Calling this invalidates references in the DI... 111 // objects returned by the methods above. 112 void pruneCache(); 113 114 static std::string 115 DemangleName(const std::string &Name, 116 const SymbolizableModule *DbiModuleDescriptor); 117 118 void setBuildIDFetcher(std::unique_ptr<BuildIDFetcher> Fetcher) { 119 BIDFetcher = std::move(Fetcher); 120 } 121 122 /// Returns a SymbolizableModule or an error if loading debug info failed. 123 /// Only one attempt is made to load a module, and errors during loading are 124 /// only reported once. Subsequent calls to get module info for a module that 125 /// failed to load will return nullptr. 126 Expected<SymbolizableModule *> 127 getOrCreateModuleInfo(const std::string &ModuleName); 128 129 private: 130 // Bundles together object file with code/data and object file with 131 // corresponding debug info. These objects can be the same. 132 using ObjectPair = std::pair<const ObjectFile *, const ObjectFile *>; 133 134 template <typename T> 135 Expected<DILineInfo> 136 symbolizeCodeCommon(const T &ModuleSpecifier, 137 object::SectionedAddress ModuleOffset); 138 template <typename T> 139 Expected<DIInliningInfo> 140 symbolizeInlinedCodeCommon(const T &ModuleSpecifier, 141 object::SectionedAddress ModuleOffset); 142 template <typename T> 143 Expected<DIGlobal> symbolizeDataCommon(const T &ModuleSpecifier, 144 object::SectionedAddress ModuleOffset); 145 template <typename T> 146 Expected<std::vector<DILocal>> 147 symbolizeFrameCommon(const T &ModuleSpecifier, 148 object::SectionedAddress ModuleOffset); 149 150 Expected<SymbolizableModule *> getOrCreateModuleInfo(const ObjectFile &Obj); 151 152 /// Returns a SymbolizableModule or an error if loading debug info failed. 153 /// Unlike the above, errors are reported each time, since they are more 154 /// likely to be transient. 155 Expected<SymbolizableModule *> 156 getOrCreateModuleInfo(ArrayRef<uint8_t> BuildID); 157 158 Expected<SymbolizableModule *> 159 createModuleInfo(const ObjectFile *Obj, std::unique_ptr<DIContext> Context, 160 StringRef ModuleName); 161 162 ObjectFile *lookUpDsymFile(const std::string &Path, 163 const MachOObjectFile *ExeObj, 164 const std::string &ArchName); 165 ObjectFile *lookUpDebuglinkObject(const std::string &Path, 166 const ObjectFile *Obj, 167 const std::string &ArchName); 168 ObjectFile *lookUpBuildIDObject(const std::string &Path, 169 const ELFObjectFileBase *Obj, 170 const std::string &ArchName); 171 172 bool findDebugBinary(const std::string &OrigPath, 173 const std::string &DebuglinkName, uint32_t CRCHash, 174 std::string &Result); 175 176 bool getOrFindDebugBinary(const ArrayRef<uint8_t> BuildID, 177 std::string &Result); 178 179 /// Returns pair of pointers to object and debug object. 180 Expected<ObjectPair> getOrCreateObjectPair(const std::string &Path, 181 const std::string &ArchName); 182 183 /// Return a pointer to object file at specified path, for a specified 184 /// architecture (e.g. if path refers to a Mach-O universal binary, only one 185 /// object file from it will be returned). 186 Expected<ObjectFile *> getOrCreateObject(const std::string &Path, 187 const std::string &ArchName); 188 189 /// Update the LRU cache order when a binary is accessed. 190 void recordAccess(CachedBinary &Bin); 191 192 std::map<std::string, std::unique_ptr<SymbolizableModule>, std::less<>> 193 Modules; 194 StringMap<std::string> BuildIDPaths; 195 196 /// Contains cached results of getOrCreateObjectPair(). 197 std::map<std::pair<std::string, std::string>, ObjectPair> 198 ObjectPairForPathArch; 199 200 /// Contains parsed binary for each path, or parsing error. 201 std::map<std::string, CachedBinary> BinaryForPath; 202 203 /// A list of cached binaries in LRU order. 204 simple_ilist<CachedBinary> LRUBinaries; 205 /// Sum of the sizes of the cached binaries. 206 size_t CacheSize = 0; 207 208 /// Parsed object file for path/architecture pair, where "path" refers 209 /// to Mach-O universal binary. 210 std::map<std::pair<std::string, std::string>, std::unique_ptr<ObjectFile>> 211 ObjectForUBPathAndArch; 212 213 Options Opts; 214 215 std::unique_ptr<BuildIDFetcher> BIDFetcher; 216 }; 217 218 // A binary intrusively linked into a LRU cache list. If the binary is empty, 219 // then the entry marks that an error occurred, and it is not part of the LRU 220 // list. 221 class CachedBinary : public ilist_node<CachedBinary> { 222 public: 223 CachedBinary() = default; 224 CachedBinary(OwningBinary<Binary> Bin) : Bin(std::move(Bin)) {} 225 226 OwningBinary<Binary> &operator*() { return Bin; } 227 OwningBinary<Binary> *operator->() { return &Bin; } 228 229 // Add an action to be performed when the binary is evicted, before all 230 // previously registered evictors. 231 void pushEvictor(std::function<void()> Evictor); 232 233 // Run all registered evictors in the reverse of the order in which they were 234 // added. 235 void evict() { 236 if (Evictor) 237 Evictor(); 238 } 239 240 size_t size() { return Bin.getBinary()->getData().size(); } 241 242 private: 243 OwningBinary<Binary> Bin; 244 std::function<void()> Evictor; 245 }; 246 247 } // end namespace symbolize 248 } // end namespace llvm 249 250 #endif // LLVM_DEBUGINFO_SYMBOLIZE_SYMBOLIZE_H 251