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