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