xref: /freebsd/contrib/llvm-project/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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:
DWARFContextState(DWARFContext & DC)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 
getDWARFObj()147   const DWARFObject &getDWARFObj() const { return *DObj; }
148 
classof(const DIContext * DICtx)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 
dump(raw_ostream & OS,DIDumpOptions DumpOpts)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.
info_section_units()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 
getNormalUnitsVector()176   const DWARFUnitVector &getNormalUnitsVector() {
177     return State->getNormalUnits();
178   }
179 
180   /// Get units from .debug_types in this context.
types_section_units()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.
compile_units()188   compile_unit_range compile_units() {
189     return make_filter_range(info_section_units(), 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.
normal_units()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.
dwo_info_section_units()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 
getDWOUnitsVector()208   const DWARFUnitVector &getDWOUnitsVector() {
209     return State->getDWOUnits();
210   }
211 
212   /// Get units from .debug_types.dwo in the DWO context.
dwo_types_section_units()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.
dwo_compile_units()220   compile_unit_range dwo_compile_units() {
221     return make_filter_range(dwo_info_section_units(), 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.
dwo_units()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.
getNumCompileUnits()235   unsigned getNumCompileUnits() {
236     return State->getNormalUnits().getNumInfoUnits();
237   }
238 
239   /// Get the number of type units in this context.
getNumTypeUnits()240   unsigned getNumTypeUnits() {
241     return State->getNormalUnits().getNumTypesUnits();
242   }
243 
244   /// Get the number of compile units in the DWO context.
getNumDWOCompileUnits()245   unsigned getNumDWOCompileUnits() {
246     return State->getDWOUnits().getNumInfoUnits();
247   }
248 
249   /// Get the number of type units in the DWO context.
getNumDWOTypeUnits()250   unsigned getNumDWOTypeUnits() {
251     return State->getDWOUnits().getNumTypesUnits();
252   }
253 
254   /// Get the unit at the specified index.
getUnitAtIndex(unsigned 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.
getDWOUnitAtIndex(unsigned index)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 
getMaxVersion()273   unsigned getMaxVersion() {
274     // Ensure info units have been parsed to discover MaxVersion
275     info_section_units();
276     return MaxVersion;
277   }
278 
getMaxDWOVersion()279   unsigned getMaxDWOVersion() {
280     // Ensure DWO info units have been parsed to discover MaxVersion
281     dwo_info_section_units();
282     return MaxVersion;
283   }
284 
setMaxVersionIfGreater(unsigned Version)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 
getStringExtractor()353   DataExtractor getStringExtractor() const {
354     return DataExtractor(DObj->getStrSection(), false, 0);
355   }
getStringDWOExtractor()356   DataExtractor getStringDWOExtractor() const {
357     return DataExtractor(DObj->getStrDWOSection(), false, 0);
358   }
getLineStringExtractor()359   DataExtractor getLineStringExtractor() 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 
isLittleEndian()398   bool isLittleEndian() const { return DObj->isLittleEndian(); }
getMaxSupportedVersion()399   static unsigned getMaxSupportedVersion() { return 5; }
isSupportedVersion(unsigned version)400   static bool isSupportedVersion(unsigned version) {
401     return version >= 2 && version <= getMaxSupportedVersion();
402   }
403 
getSupportedAddressSizes()404   static SmallVector<uint8_t, 3> getSupportedAddressSizes() {
405     return {2, 4, 8};
406   }
isAddressSizeSupported(unsigned AddressSize)407   static bool isAddressSizeSupported(unsigned AddressSize) {
408     return llvm::is_contained(getSupportedAddressSizes(), AddressSize);
409   }
410   template <typename... Ts>
checkAddressSizeSupported(unsigned AddressSize,std::error_code EC,char const * Fmt,const Ts &...Vals)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>(Buffer, EC);
426   }
427 
428   std::shared_ptr<DWARFContext> getDWOContext(StringRef AbsolutePath);
429 
getRecoverableErrorHandler()430   function_ref<void(Error)> getRecoverableErrorHandler() {
431     return RecoverableErrorHandler;
432   }
433 
getWarningHandler()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 
getArch()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.
getParseCUTUIndexManually()482   bool getParseCUTUIndexManually() const { return ParseCUTUIndexManually; }
483 
484   /// Sets whether CU/TU should be populated manually. TU Index populated
485   /// manually only for DWARF5.
setParseCUTUIndexManually(bool PCUTU)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