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