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