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/DebugInfo/Symbolize/DIFetcher.h"
21 #include "llvm/Object/Binary.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 addDIFetcher(std::unique_ptr<DIFetcher> Fetcher) {
119     DIFetchers.push_back(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   SmallVector<std::unique_ptr<DIFetcher>> DIFetchers;
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;
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.
234   void evict() {
235     if (Evictor)
236       Evictor();
237   }
238 
239   size_t size() { return Bin.getBinary()->getData().size(); }
240 
241 private:
242   OwningBinary<Binary> Bin;
243   std::function<void()> Evictor;
244 };
245 
246 Optional<ArrayRef<uint8_t>> getBuildID(const ELFObjectFileBase *Obj);
247 
248 } // end namespace symbolize
249 } // end namespace llvm
250 
251 #endif // LLVM_DEBUGINFO_SYMBOLIZE_SYMBOLIZE_H
252