1 | //===- DWARFContext.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 | #ifndef LLVM_DEBUGINFO_DWARF_DWARFCONTEXT_H |
10 | #define LLVM_DEBUGINFO_DWARF_DWARFCONTEXT_H |
11 | |
12 | #include "llvm/ADT/SmallVector.h" |
13 | #include "llvm/ADT/StringExtras.h" |
14 | #include "llvm/ADT/StringMap.h" |
15 | #include "llvm/ADT/StringRef.h" |
16 | #include "llvm/DebugInfo/DIContext.h" |
17 | #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" |
18 | #include "llvm/DebugInfo/DWARF/DWARFDie.h" |
19 | #include "llvm/DebugInfo/DWARF/DWARFObject.h" |
20 | #include "llvm/DebugInfo/DWARF/DWARFUnit.h" |
21 | #include "llvm/Object/Binary.h" |
22 | #include "llvm/Object/ObjectFile.h" |
23 | #include "llvm/Support/DataExtractor.h" |
24 | #include "llvm/Support/Error.h" |
25 | #include "llvm/TargetParser/Host.h" |
26 | #include <cstdint> |
27 | #include <memory> |
28 | #include <mutex> |
29 | |
30 | namespace llvm { |
31 | |
32 | class MemoryBuffer; |
33 | class AppleAcceleratorTable; |
34 | class DWARFCompileUnit; |
35 | class DWARFDebugAbbrev; |
36 | class DWARFDebugAranges; |
37 | class DWARFDebugFrame; |
38 | class DWARFDebugLoc; |
39 | class DWARFDebugMacro; |
40 | class DWARFDebugNames; |
41 | class DWARFGdbIndex; |
42 | class DWARFTypeUnit; |
43 | class DWARFUnitIndex; |
44 | |
45 | /// DWARFContext |
46 | /// This data structure is the top level entity that deals with dwarf debug |
47 | /// information parsing. The actual data is supplied through DWARFObj. |
48 | class DWARFContext : public DIContext { |
49 | public: |
50 | /// DWARFContextState |
51 | /// This structure contains all member variables for DWARFContext that need |
52 | /// to be protected in multi-threaded environments. Threading support can be |
53 | /// enabled by setting the ThreadSafe to true when constructing a |
54 | /// DWARFContext to allow DWARRContext to be able to be used in a |
55 | /// multi-threaded environment, or not enabled to allow for maximum |
56 | /// performance in single threaded environments. |
57 | class DWARFContextState { |
58 | protected: |
59 | /// Helper enum to distinguish between macro[.dwo] and macinfo[.dwo] |
60 | /// section. |
61 | enum MacroSecType { |
62 | MacinfoSection, |
63 | MacinfoDwoSection, |
64 | MacroSection, |
65 | MacroDwoSection |
66 | }; |
67 | |
68 | DWARFContext &D; |
69 | public: |
70 | DWARFContextState(DWARFContext &DC) : D(DC) {} |
71 | virtual ~DWARFContextState() = default; |
72 | virtual DWARFUnitVector &getNormalUnits() = 0; |
73 | virtual DWARFUnitVector &getDWOUnits(bool Lazy = false) = 0; |
74 | virtual const DWARFDebugAbbrev *getDebugAbbrevDWO() = 0; |
75 | virtual const DWARFUnitIndex &getCUIndex() = 0; |
76 | virtual const DWARFUnitIndex &getTUIndex() = 0; |
77 | virtual DWARFGdbIndex &getGdbIndex() = 0; |
78 | virtual const DWARFDebugAbbrev *getDebugAbbrev() = 0; |
79 | virtual const DWARFDebugLoc *getDebugLoc() = 0; |
80 | virtual const DWARFDebugAranges *getDebugAranges() = 0; |
81 | virtual Expected<const DWARFDebugLine::LineTable *> |
82 | getLineTableForUnit(DWARFUnit *U, |
83 | function_ref<void(Error)> RecoverableErrHandler) = 0; |
84 | virtual void clearLineTableForUnit(DWARFUnit *U) = 0; |
85 | virtual Expected<const DWARFDebugFrame *> getDebugFrame() = 0; |
86 | virtual Expected<const DWARFDebugFrame *> getEHFrame() = 0; |
87 | virtual const DWARFDebugMacro *getDebugMacinfo() = 0; |
88 | virtual const DWARFDebugMacro *getDebugMacinfoDWO() = 0; |
89 | virtual const DWARFDebugMacro *getDebugMacro() = 0; |
90 | virtual const DWARFDebugMacro *getDebugMacroDWO() = 0; |
91 | virtual const DWARFDebugNames &getDebugNames() = 0; |
92 | virtual const AppleAcceleratorTable &getAppleNames() = 0; |
93 | virtual const AppleAcceleratorTable &getAppleTypes() = 0; |
94 | virtual const AppleAcceleratorTable &getAppleNamespaces() = 0; |
95 | virtual const AppleAcceleratorTable &getAppleObjC() = 0; |
96 | virtual std::shared_ptr<DWARFContext> |
97 | getDWOContext(StringRef AbsolutePath) = 0; |
98 | virtual const DenseMap<uint64_t, DWARFTypeUnit *> & |
99 | getTypeUnitMap(bool IsDWO) = 0; |
100 | virtual bool isThreadSafe() const = 0; |
101 | |
102 | /// Parse a macro[.dwo] or macinfo[.dwo] section. |
103 | std::unique_ptr<DWARFDebugMacro> |
104 | parseMacroOrMacinfo(MacroSecType SectionType); |
105 | |
106 | }; |
107 | friend class DWARFContextState; |
108 | |
109 | private: |
110 | /// All important state for a DWARFContext that needs to be threadsafe needs |
111 | /// to go into DWARFContextState. |
112 | std::unique_ptr<DWARFContextState> State; |
113 | |
114 | /// The maximum DWARF version of all units. |
115 | unsigned MaxVersion = 0; |
116 | |
117 | std::function<void(Error)> RecoverableErrorHandler = |
118 | WithColor::defaultErrorHandler; |
119 | std::function<void(Error)> WarningHandler = WithColor::defaultWarningHandler; |
120 | |
121 | /// Read compile units from the debug_info.dwo section (if necessary) |
122 | /// and type units from the debug_types.dwo section (if necessary) |
123 | /// and store them in DWOUnits. |
124 | /// If \p Lazy is true, set up to parse but don't actually parse them. |
125 | enum { EagerParse = false, LazyParse = true }; |
126 | DWARFUnitVector &getDWOUnits(bool Lazy = false); |
127 | |
128 | std::unique_ptr<const DWARFObject> DObj; |
129 | |
130 | // When set parses debug_info.dwo/debug_abbrev.dwo manually and populates CU |
131 | // Index, and TU Index for DWARF5. |
132 | bool ParseCUTUIndexManually = false; |
133 | |
134 | public: |
135 | DWARFContext(std::unique_ptr<const DWARFObject> DObj, |
136 | std::string DWPName = "" , |
137 | std::function<void(Error)> RecoverableErrorHandler = |
138 | WithColor::defaultErrorHandler, |
139 | std::function<void(Error)> WarningHandler = |
140 | WithColor::defaultWarningHandler, |
141 | bool ThreadSafe = false); |
142 | ~DWARFContext() override; |
143 | |
144 | DWARFContext(DWARFContext &) = delete; |
145 | DWARFContext &operator=(DWARFContext &) = delete; |
146 | |
147 | const DWARFObject &getDWARFObj() const { return *DObj; } |
148 | |
149 | static bool classof(const DIContext *DICtx) { |
150 | return DICtx->getKind() == CK_DWARF; |
151 | } |
152 | |
153 | /// Dump a textual representation to \p OS. If any \p DumpOffsets are present, |
154 | /// dump only the record at the specified offset. |
155 | void dump(raw_ostream &OS, DIDumpOptions DumpOpts, |
156 | std::array<std::optional<uint64_t>, DIDT_ID_Count> DumpOffsets); |
157 | |
158 | void dump(raw_ostream &OS, DIDumpOptions DumpOpts) override { |
159 | std::array<std::optional<uint64_t>, DIDT_ID_Count> DumpOffsets; |
160 | dump(OS, DumpOpts, DumpOffsets); |
161 | } |
162 | |
163 | bool verify(raw_ostream &OS, DIDumpOptions DumpOpts = {}) override; |
164 | |
165 | using unit_iterator_range = DWARFUnitVector::iterator_range; |
166 | using compile_unit_range = DWARFUnitVector::compile_unit_range; |
167 | |
168 | /// Get units from .debug_info in this context. |
169 | unit_iterator_range info_section_units() { |
170 | DWARFUnitVector &NormalUnits = State->getNormalUnits(); |
171 | return unit_iterator_range(NormalUnits.begin(), |
172 | NormalUnits.begin() + |
173 | NormalUnits.getNumInfoUnits()); |
174 | } |
175 | |
176 | const DWARFUnitVector &getNormalUnitsVector() { |
177 | return State->getNormalUnits(); |
178 | } |
179 | |
180 | /// Get units from .debug_types in this context. |
181 | unit_iterator_range types_section_units() { |
182 | DWARFUnitVector &NormalUnits = State->getNormalUnits(); |
183 | return unit_iterator_range( |
184 | NormalUnits.begin() + NormalUnits.getNumInfoUnits(), NormalUnits.end()); |
185 | } |
186 | |
187 | /// Get compile units in this context. |
188 | compile_unit_range compile_units() { |
189 | return make_filter_range(Range: info_section_units(), Pred: isCompileUnit); |
190 | } |
191 | |
192 | // If you want type_units(), it'll need to be a concat iterator of a filter of |
193 | // TUs in info_section + all the (all type) units in types_section |
194 | |
195 | /// Get all normal compile/type units in this context. |
196 | unit_iterator_range normal_units() { |
197 | DWARFUnitVector &NormalUnits = State->getNormalUnits(); |
198 | return unit_iterator_range(NormalUnits.begin(), NormalUnits.end()); |
199 | } |
200 | |
201 | /// Get units from .debug_info..dwo in the DWO context. |
202 | unit_iterator_range dwo_info_section_units() { |
203 | DWARFUnitVector &DWOUnits = State->getDWOUnits(); |
204 | return unit_iterator_range(DWOUnits.begin(), |
205 | DWOUnits.begin() + DWOUnits.getNumInfoUnits()); |
206 | } |
207 | |
208 | const DWARFUnitVector &getDWOUnitsVector() { |
209 | return State->getDWOUnits(); |
210 | } |
211 | |
212 | /// Get units from .debug_types.dwo in the DWO context. |
213 | unit_iterator_range dwo_types_section_units() { |
214 | DWARFUnitVector &DWOUnits = State->getDWOUnits(); |
215 | return unit_iterator_range(DWOUnits.begin() + DWOUnits.getNumInfoUnits(), |
216 | DWOUnits.end()); |
217 | } |
218 | |
219 | /// Get compile units in the DWO context. |
220 | compile_unit_range dwo_compile_units() { |
221 | return make_filter_range(Range: dwo_info_section_units(), Pred: isCompileUnit); |
222 | } |
223 | |
224 | // If you want dwo_type_units(), it'll need to be a concat iterator of a |
225 | // filter of TUs in dwo_info_section + all the (all type) units in |
226 | // dwo_types_section. |
227 | |
228 | /// Get all units in the DWO context. |
229 | unit_iterator_range dwo_units() { |
230 | DWARFUnitVector &DWOUnits = State->getDWOUnits(); |
231 | return unit_iterator_range(DWOUnits.begin(), DWOUnits.end()); |
232 | } |
233 | |
234 | /// Get the number of compile units in this context. |
235 | unsigned getNumCompileUnits() { |
236 | return State->getNormalUnits().getNumInfoUnits(); |
237 | } |
238 | |
239 | /// Get the number of type units in this context. |
240 | unsigned getNumTypeUnits() { |
241 | return State->getNormalUnits().getNumTypesUnits(); |
242 | } |
243 | |
244 | /// Get the number of compile units in the DWO context. |
245 | unsigned getNumDWOCompileUnits() { |
246 | return State->getDWOUnits().getNumInfoUnits(); |
247 | } |
248 | |
249 | /// Get the number of type units in the DWO context. |
250 | unsigned getNumDWOTypeUnits() { |
251 | return State->getDWOUnits().getNumTypesUnits(); |
252 | } |
253 | |
254 | /// Get the unit at the specified index. |
255 | DWARFUnit *getUnitAtIndex(unsigned index) { |
256 | return State->getNormalUnits()[index].get(); |
257 | } |
258 | |
259 | /// Get the unit at the specified index for the DWO units. |
260 | DWARFUnit *getDWOUnitAtIndex(unsigned index) { |
261 | return State->getDWOUnits()[index].get(); |
262 | } |
263 | |
264 | DWARFCompileUnit *getDWOCompileUnitForHash(uint64_t Hash); |
265 | DWARFTypeUnit *getTypeUnitForHash(uint16_t Version, uint64_t Hash, bool IsDWO); |
266 | |
267 | /// Return the compile unit that includes an offset (relative to .debug_info). |
268 | DWARFCompileUnit *getCompileUnitForOffset(uint64_t Offset); |
269 | |
270 | /// Get a DIE given an exact offset. |
271 | DWARFDie getDIEForOffset(uint64_t Offset); |
272 | |
273 | unsigned getMaxVersion() { |
274 | // Ensure info units have been parsed to discover MaxVersion |
275 | info_section_units(); |
276 | return MaxVersion; |
277 | } |
278 | |
279 | unsigned getMaxDWOVersion() { |
280 | // Ensure DWO info units have been parsed to discover MaxVersion |
281 | dwo_info_section_units(); |
282 | return MaxVersion; |
283 | } |
284 | |
285 | void setMaxVersionIfGreater(unsigned Version) { |
286 | if (Version > MaxVersion) |
287 | MaxVersion = Version; |
288 | } |
289 | |
290 | const DWARFUnitIndex &getCUIndex(); |
291 | DWARFGdbIndex &getGdbIndex(); |
292 | const DWARFUnitIndex &getTUIndex(); |
293 | |
294 | /// Get a pointer to the parsed DebugAbbrev object. |
295 | const DWARFDebugAbbrev *getDebugAbbrev(); |
296 | |
297 | /// Get a pointer to the parsed DebugLoc object. |
298 | const DWARFDebugLoc *getDebugLoc(); |
299 | |
300 | /// Get a pointer to the parsed dwo abbreviations object. |
301 | const DWARFDebugAbbrev *getDebugAbbrevDWO(); |
302 | |
303 | /// Get a pointer to the parsed DebugAranges object. |
304 | const DWARFDebugAranges *getDebugAranges(); |
305 | |
306 | /// Get a pointer to the parsed frame information object. |
307 | Expected<const DWARFDebugFrame *> getDebugFrame(); |
308 | |
309 | /// Get a pointer to the parsed eh frame information object. |
310 | Expected<const DWARFDebugFrame *> getEHFrame(); |
311 | |
312 | /// Get a pointer to the parsed DebugMacinfo information object. |
313 | const DWARFDebugMacro *getDebugMacinfo(); |
314 | |
315 | /// Get a pointer to the parsed DebugMacinfoDWO information object. |
316 | const DWARFDebugMacro *getDebugMacinfoDWO(); |
317 | |
318 | /// Get a pointer to the parsed DebugMacro information object. |
319 | const DWARFDebugMacro *getDebugMacro(); |
320 | |
321 | /// Get a pointer to the parsed DebugMacroDWO information object. |
322 | const DWARFDebugMacro *getDebugMacroDWO(); |
323 | |
324 | /// Get a reference to the parsed accelerator table object. |
325 | const DWARFDebugNames &getDebugNames(); |
326 | |
327 | /// Get a reference to the parsed accelerator table object. |
328 | const AppleAcceleratorTable &getAppleNames(); |
329 | |
330 | /// Get a reference to the parsed accelerator table object. |
331 | const AppleAcceleratorTable &getAppleTypes(); |
332 | |
333 | /// Get a reference to the parsed accelerator table object. |
334 | const AppleAcceleratorTable &getAppleNamespaces(); |
335 | |
336 | /// Get a reference to the parsed accelerator table object. |
337 | const AppleAcceleratorTable &getAppleObjC(); |
338 | |
339 | /// Get a pointer to a parsed line table corresponding to a compile unit. |
340 | /// Report any parsing issues as warnings on stderr. |
341 | const DWARFDebugLine::LineTable *getLineTableForUnit(DWARFUnit *U); |
342 | |
343 | /// Get a pointer to a parsed line table corresponding to a compile unit. |
344 | /// Report any recoverable parsing problems using the handler. |
345 | Expected<const DWARFDebugLine::LineTable *> |
346 | getLineTableForUnit(DWARFUnit *U, |
347 | function_ref<void(Error)> RecoverableErrorHandler); |
348 | |
349 | // Clear the line table object corresponding to a compile unit for memory |
350 | // management purpose. When it's referred to again, it'll be re-populated. |
351 | void clearLineTableForUnit(DWARFUnit *U); |
352 | |
353 | DataExtractor () const { |
354 | return DataExtractor(DObj->getStrSection(), false, 0); |
355 | } |
356 | DataExtractor () const { |
357 | return DataExtractor(DObj->getStrDWOSection(), false, 0); |
358 | } |
359 | DataExtractor () const { |
360 | return DataExtractor(DObj->getLineStrSection(), false, 0); |
361 | } |
362 | |
363 | /// Wraps the returned DIEs for a given address. |
364 | struct DIEsForAddress { |
365 | DWARFCompileUnit *CompileUnit = nullptr; |
366 | DWARFDie FunctionDIE; |
367 | DWARFDie BlockDIE; |
368 | explicit operator bool() const { return CompileUnit != nullptr; } |
369 | }; |
370 | |
371 | /// Get the compilation unit, the function DIE and lexical block DIE for the |
372 | /// given address where applicable. |
373 | /// TODO: change input parameter from "uint64_t Address" |
374 | /// into "SectionedAddress Address" |
375 | /// \param[in] CheckDWO If this is false then only search for address matches |
376 | /// in the current context's DIEs. If this is true, then each |
377 | /// DWARFUnit that has a DWO file will have the debug info in the |
378 | /// DWO file searched as well. This allows for lookups to succeed |
379 | /// by searching the split DWARF debug info when using the main |
380 | /// executable's debug info. |
381 | DIEsForAddress getDIEsForAddress(uint64_t Address, bool CheckDWO = false); |
382 | |
383 | DILineInfo getLineInfoForAddress( |
384 | object::SectionedAddress Address, |
385 | DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; |
386 | DILineInfo |
387 | getLineInfoForDataAddress(object::SectionedAddress Address) override; |
388 | DILineInfoTable getLineInfoForAddressRange( |
389 | object::SectionedAddress Address, uint64_t Size, |
390 | DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; |
391 | DIInliningInfo getInliningInfoForAddress( |
392 | object::SectionedAddress Address, |
393 | DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; |
394 | |
395 | std::vector<DILocal> |
396 | getLocalsForAddress(object::SectionedAddress Address) override; |
397 | |
398 | bool isLittleEndian() const { return DObj->isLittleEndian(); } |
399 | static unsigned getMaxSupportedVersion() { return 5; } |
400 | static bool isSupportedVersion(unsigned version) { |
401 | return version >= 2 && version <= getMaxSupportedVersion(); |
402 | } |
403 | |
404 | static SmallVector<uint8_t, 3> getSupportedAddressSizes() { |
405 | return {2, 4, 8}; |
406 | } |
407 | static bool isAddressSizeSupported(unsigned AddressSize) { |
408 | return llvm::is_contained(Range: getSupportedAddressSizes(), Element: AddressSize); |
409 | } |
410 | template <typename... Ts> |
411 | static Error checkAddressSizeSupported(unsigned AddressSize, |
412 | std::error_code EC, char const *Fmt, |
413 | const Ts &...Vals) { |
414 | if (isAddressSizeSupported(AddressSize)) |
415 | return Error::success(); |
416 | std::string Buffer; |
417 | raw_string_ostream Stream(Buffer); |
418 | Stream << format(Fmt, Vals...) |
419 | << " has unsupported address size: " << AddressSize |
420 | << " (supported are " ; |
421 | ListSeparator LS; |
422 | for (unsigned Size : DWARFContext::getSupportedAddressSizes()) |
423 | Stream << LS << Size; |
424 | Stream << ')'; |
425 | return make_error<StringError>(Args&: Buffer, Args&: EC); |
426 | } |
427 | |
428 | std::shared_ptr<DWARFContext> getDWOContext(StringRef AbsolutePath); |
429 | |
430 | function_ref<void(Error)> getRecoverableErrorHandler() { |
431 | return RecoverableErrorHandler; |
432 | } |
433 | |
434 | function_ref<void(Error)> getWarningHandler() { return WarningHandler; } |
435 | |
436 | enum class ProcessDebugRelocations { Process, Ignore }; |
437 | |
438 | static std::unique_ptr<DWARFContext> |
439 | create(const object::ObjectFile &Obj, |
440 | ProcessDebugRelocations RelocAction = ProcessDebugRelocations::Process, |
441 | const LoadedObjectInfo *L = nullptr, std::string DWPName = "" , |
442 | std::function<void(Error)> RecoverableErrorHandler = |
443 | WithColor::defaultErrorHandler, |
444 | std::function<void(Error)> WarningHandler = |
445 | WithColor::defaultWarningHandler, |
446 | bool ThreadSafe = false); |
447 | |
448 | static std::unique_ptr<DWARFContext> |
449 | create(const StringMap<std::unique_ptr<MemoryBuffer>> &Sections, |
450 | uint8_t AddrSize, bool isLittleEndian = sys::IsLittleEndianHost, |
451 | std::function<void(Error)> RecoverableErrorHandler = |
452 | WithColor::defaultErrorHandler, |
453 | std::function<void(Error)> WarningHandler = |
454 | WithColor::defaultWarningHandler, |
455 | bool ThreadSafe = false); |
456 | |
457 | /// Get address size from CUs. |
458 | /// TODO: refactor compile_units() to make this const. |
459 | uint8_t getCUAddrSize(); |
460 | |
461 | Triple::ArchType getArch() const { |
462 | return getDWARFObj().getFile()->getArch(); |
463 | } |
464 | |
465 | /// Return the compile unit which contains instruction with provided |
466 | /// address. |
467 | /// TODO: change input parameter from "uint64_t Address" |
468 | /// into "SectionedAddress Address" |
469 | DWARFCompileUnit *getCompileUnitForCodeAddress(uint64_t Address); |
470 | |
471 | /// Return the compile unit which contains data with the provided address. |
472 | /// Note: This is more expensive than `getCompileUnitForAddress`, as if |
473 | /// `Address` isn't found in the CU ranges (which is cheap), then it falls |
474 | /// back to an expensive O(n) walk of all CU's looking for data that spans the |
475 | /// address. |
476 | /// TODO: change input parameter from "uint64_t Address" into |
477 | /// "SectionedAddress Address" |
478 | DWARFCompileUnit *getCompileUnitForDataAddress(uint64_t Address); |
479 | |
480 | /// Returns whether CU/TU should be populated manually. TU Index populated |
481 | /// manually only for DWARF5. |
482 | bool getParseCUTUIndexManually() const { return ParseCUTUIndexManually; } |
483 | |
484 | /// Sets whether CU/TU should be populated manually. TU Index populated |
485 | /// manually only for DWARF5. |
486 | void setParseCUTUIndexManually(bool PCUTU) { ParseCUTUIndexManually = PCUTU; } |
487 | |
488 | private: |
489 | void addLocalsForDie(DWARFCompileUnit *CU, DWARFDie Subprogram, DWARFDie Die, |
490 | std::vector<DILocal> &Result); |
491 | }; |
492 | |
493 | } // end namespace llvm |
494 | |
495 | #endif // LLVM_DEBUGINFO_DWARF_DWARFCONTEXT_H |
496 | |