Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
14 | pmbaty | 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 | 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; |
||
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 | } // end namespace symbolize |
||
247 | } // end namespace llvm |
||
248 | |||
249 | #endif // LLVM_DEBUGINFO_SYMBOLIZE_SYMBOLIZE_H |