1 //===-- DWARFUnit.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 LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFUNIT_H
10 #define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFUNIT_H
11 
12 #include "DWARFDIE.h"
13 #include "DWARFDebugInfoEntry.h"
14 #include "lldb/Utility/XcodeSDK.h"
15 #include "lldb/lldb-enumerations.h"
16 #include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
17 #include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h"
18 #include "llvm/Support/RWMutex.h"
19 #include <atomic>
20 #include <optional>
21 
22 namespace lldb_private::plugin {
23 namespace dwarf {
24 class DWARFUnit;
25 class DWARFCompileUnit;
26 class NameToDIE;
27 class SymbolFileDWARF;
28 class SymbolFileDWARFDwo;
29 
30 typedef std::shared_ptr<DWARFUnit> DWARFUnitSP;
31 
32 enum DWARFProducer {
33   eProducerInvalid = 0,
34   eProducerClang,
35   eProducerGCC,
36   eProducerLLVMGCC,
37   eProducerSwift,
38   eProducerOther
39 };
40 
41 /// Base class describing the header of any kind of "unit."  Some information
42 /// is specific to certain unit types.  We separate this class out so we can
43 /// parse the header before deciding what specific kind of unit to construct.
44 class DWARFUnitHeader {
45   dw_offset_t m_offset = 0;
46   dw_offset_t m_length = 0;
47   uint16_t m_version = 0;
48   dw_offset_t m_abbr_offset = 0;
49 
50   const llvm::DWARFUnitIndex::Entry *m_index_entry = nullptr;
51 
52   uint8_t m_unit_type = 0;
53   uint8_t m_addr_size = 0;
54 
55   uint64_t m_type_hash = 0;
56   uint32_t m_type_offset = 0;
57 
58   std::optional<uint64_t> m_dwo_id;
59 
60   DWARFUnitHeader() = default;
61 
62 public:
GetOffset()63   dw_offset_t GetOffset() const { return m_offset; }
GetVersion()64   uint16_t GetVersion() const { return m_version; }
GetAddressByteSize()65   uint16_t GetAddressByteSize() const { return m_addr_size; }
GetLength()66   dw_offset_t GetLength() const { return m_length; }
GetAbbrOffset()67   dw_offset_t GetAbbrOffset() const { return m_abbr_offset; }
GetUnitType()68   uint8_t GetUnitType() const { return m_unit_type; }
GetIndexEntry()69   const llvm::DWARFUnitIndex::Entry *GetIndexEntry() const {
70     return m_index_entry;
71   }
GetTypeHash()72   uint64_t GetTypeHash() const { return m_type_hash; }
GetTypeOffset()73   dw_offset_t GetTypeOffset() const { return m_type_offset; }
GetDWOId()74   std::optional<uint64_t> GetDWOId() const { return m_dwo_id; }
IsTypeUnit()75   bool IsTypeUnit() const {
76     return m_unit_type == llvm::dwarf::DW_UT_type ||
77            m_unit_type == llvm::dwarf::DW_UT_split_type;
78   }
GetNextUnitOffset()79   dw_offset_t GetNextUnitOffset() const { return m_offset + m_length + 4; }
80 
81   llvm::Error ApplyIndexEntry(const llvm::DWARFUnitIndex::Entry *index_entry);
82 
83   static llvm::Expected<DWARFUnitHeader> extract(const DWARFDataExtractor &data,
84                                                  DIERef::Section section,
85                                                  DWARFContext &dwarf_context,
86                                                  lldb::offset_t *offset_ptr);
87 };
88 
89 class DWARFUnit : public UserID {
90   using die_iterator_range =
91       llvm::iterator_range<DWARFDebugInfoEntry::collection::iterator>;
92 
93 public:
94   static llvm::Expected<DWARFUnitSP>
95   extract(SymbolFileDWARF &dwarf2Data, lldb::user_id_t uid,
96           const DWARFDataExtractor &debug_info, DIERef::Section section,
97           lldb::offset_t *offset_ptr);
98   virtual ~DWARFUnit();
99 
IsDWOUnit()100   bool IsDWOUnit() { return m_is_dwo; }
101   std::optional<uint64_t> GetDWOId();
102 
103   void ExtractUnitDIEIfNeeded();
104   void ExtractUnitDIENoDwoIfNeeded();
105   void ExtractDIEsIfNeeded();
106 
107   class ScopedExtractDIEs {
108     DWARFUnit *m_cu;
109 
110   public:
111     bool m_clear_dies = false;
112     ScopedExtractDIEs(DWARFUnit &cu);
113     ~ScopedExtractDIEs();
114     ScopedExtractDIEs(const ScopedExtractDIEs &) = delete;
115     const ScopedExtractDIEs &operator=(const ScopedExtractDIEs &) = delete;
116     ScopedExtractDIEs(ScopedExtractDIEs &&rhs);
117     ScopedExtractDIEs &operator=(ScopedExtractDIEs &&rhs);
118   };
119   ScopedExtractDIEs ExtractDIEsScoped();
120 
121   bool Verify(Stream *s) const;
122   virtual void Dump(Stream *s) const = 0;
123   /// Get the data that contains the DIE information for this unit.
124   ///
125   /// This will return the correct bytes that contain the data for
126   /// this DWARFUnit. It could be .debug_info or .debug_types
127   /// depending on where the data for this unit originates.
128   ///
129   /// \return
130   ///   The correct data for the DIE information in this unit.
131   const DWARFDataExtractor &GetData() const;
132 
133   /// Get the size in bytes of the unit header.
134   ///
135   /// \return
136   ///     Byte size of the unit header
137   uint32_t GetHeaderByteSize() const;
138 
139   // Offset of the initial length field.
GetOffset()140   dw_offset_t GetOffset() const { return m_header.GetOffset(); }
141   /// Get the size in bytes of the length field in the header.
142   ///
143   /// In DWARF32 this is just 4 bytes
144   ///
145   /// \return
146   ///     Byte size of the compile unit header length field
GetLengthByteSize()147   size_t GetLengthByteSize() const { return 4; }
148 
ContainsDIEOffset(dw_offset_t die_offset)149   bool ContainsDIEOffset(dw_offset_t die_offset) const {
150     return die_offset >= GetFirstDIEOffset() &&
151            die_offset < GetNextUnitOffset();
152   }
GetFirstDIEOffset()153   dw_offset_t GetFirstDIEOffset() const {
154     return GetOffset() + GetHeaderByteSize();
155   }
GetNextUnitOffset()156   dw_offset_t GetNextUnitOffset() const { return m_header.GetNextUnitOffset(); }
157   // Size of the CU data (without initial length and without header).
158   size_t GetDebugInfoSize() const;
159   // Size of the CU data incl. header but without initial length.
GetLength()160   dw_offset_t GetLength() const { return m_header.GetLength(); }
GetVersion()161   uint16_t GetVersion() const { return m_header.GetVersion(); }
162   const llvm::DWARFAbbreviationDeclarationSet *GetAbbreviations() const;
163   dw_offset_t GetAbbrevOffset() const;
GetAddressByteSize()164   uint8_t GetAddressByteSize() const { return m_header.GetAddressByteSize(); }
GetAddrBase()165   dw_addr_t GetAddrBase() const { return m_addr_base.value_or(0); }
GetBaseAddress()166   dw_addr_t GetBaseAddress() const { return m_base_addr; }
167   dw_offset_t GetLineTableOffset();
GetRangesBase()168   dw_addr_t GetRangesBase() const { return m_ranges_base; }
GetStrOffsetsBase()169   dw_addr_t GetStrOffsetsBase() const { return m_str_offsets_base; }
170   void SetAddrBase(dw_addr_t addr_base);
171   void SetLoclistsBase(dw_addr_t loclists_base);
172   void SetRangesBase(dw_addr_t ranges_base);
173   void SetStrOffsetsBase(dw_offset_t str_offsets_base);
174   virtual void BuildAddressRangeTable(DWARFDebugAranges *debug_aranges) = 0;
175 
176   dw_addr_t ReadAddressFromDebugAddrSection(uint32_t index) const;
177 
178   lldb::ByteOrder GetByteOrder() const;
179 
180   const DWARFDebugAranges &GetFunctionAranges();
181 
182   void SetBaseAddress(dw_addr_t base_addr);
183 
GetUnitDIEOnly()184   DWARFBaseDIE GetUnitDIEOnly() { return {this, GetUnitDIEPtrOnly()}; }
185 
DIE()186   DWARFDIE DIE() { return DWARFDIE(this, DIEPtr()); }
187 
188   DWARFDIE GetDIE(dw_offset_t die_offset);
189 
190   /// Returns the AT_Name of the DIE at `die_offset`, if it exists, without
191   /// parsing the entire compile unit. An empty is string is returned upon
192   /// error or if the attribute is not present.
193   llvm::StringRef PeekDIEName(dw_offset_t die_offset);
194 
195   DWARFUnit &GetNonSkeletonUnit();
196 
197   static uint8_t GetAddressByteSize(const DWARFUnit *cu);
198 
199   static uint8_t GetDefaultAddressSize();
200 
201   void *GetUserData() const;
202 
203   void SetUserData(void *d);
204 
205   bool Supports_DW_AT_APPLE_objc_complete_type();
206 
207   bool DW_AT_decl_file_attributes_are_invalid();
208 
209   bool Supports_unnamed_objc_bitfields();
210 
GetSymbolFileDWARF()211   SymbolFileDWARF &GetSymbolFileDWARF() const { return m_dwarf; }
212 
213   DWARFProducer GetProducer();
214 
215   llvm::VersionTuple GetProducerVersion();
216 
217   uint64_t GetDWARFLanguageType();
218 
219   bool GetIsOptimized();
220 
221   const FileSpec &GetCompilationDirectory();
222   const FileSpec &GetAbsolutePath();
223   FileSpec GetFile(size_t file_idx);
224   FileSpec::Style GetPathStyle();
225 
226   SymbolFileDWARFDwo *GetDwoSymbolFile();
227 
dies()228   die_iterator_range dies() {
229     ExtractDIEsIfNeeded();
230     return die_iterator_range(m_die_array.begin(), m_die_array.end());
231   }
232 
GetDebugSection()233   DIERef::Section GetDebugSection() const { return m_section; }
234 
GetUnitType()235   uint8_t GetUnitType() const { return m_header.GetUnitType(); }
IsTypeUnit()236   bool IsTypeUnit() const { return m_header.IsTypeUnit(); }
237   /// Note that this check only works for DWARF5+.
IsSkeletonUnit()238   bool IsSkeletonUnit() const {
239     return GetUnitType() == llvm::dwarf::DW_UT_skeleton;
240   }
241 
242   std::optional<uint64_t> GetStringOffsetSectionItem(uint32_t index) const;
243 
244   /// Return a list of address ranges resulting from a (possibly encoded)
245   /// range list starting at a given offset in the appropriate ranges section.
246   llvm::Expected<DWARFRangeList> FindRnglistFromOffset(dw_offset_t offset);
247 
248   /// Return a list of address ranges retrieved from an encoded range
249   /// list whose offset is found via a table lookup given an index (DWARF v5
250   /// and later).
251   llvm::Expected<DWARFRangeList> FindRnglistFromIndex(uint32_t index);
252 
253   /// Return a rangelist's offset based on an index. The index designates
254   /// an entry in the rangelist table's offset array and is supplied by
255   /// DW_FORM_rnglistx.
256   llvm::Expected<uint64_t> GetRnglistOffset(uint32_t Index);
257 
GetLoclistOffset(uint32_t Index)258   std::optional<uint64_t> GetLoclistOffset(uint32_t Index) {
259     if (!m_loclist_table_header)
260       return std::nullopt;
261 
262     std::optional<uint64_t> Offset = m_loclist_table_header->getOffsetEntry(
263         m_dwarf.GetDWARFContext().getOrLoadLocListsData().GetAsLLVM(), Index);
264     if (!Offset)
265       return std::nullopt;
266     return *Offset + m_loclists_base;
267   }
268 
269   /// Return the location table for parsing the given location list data. The
270   /// format is chosen according to the unit type. Never returns null.
271   std::unique_ptr<llvm::DWARFLocationTable>
272   GetLocationTable(const DataExtractor &data) const;
273 
274   DWARFDataExtractor GetLocationData() const;
275 
276   /// Returns true if any DIEs in the unit match any DW_TAG values in \a tags.
277   ///
278   /// \param[in] tags
279   ///   An array of dw_tag_t values to check all abbrevitions for.
280   ///
281   /// \returns
282   ///   True if any DIEs match any tag in \a tags, false otherwise.
283   bool HasAny(llvm::ArrayRef<dw_tag_t> tags);
284 
285   /// Get the fission .dwo file specific error for this compile unit.
286   ///
287   /// The skeleton compile unit only can have a DWO error. Any other type
288   /// of DWARFUnit will not have a valid DWO error.
289   ///
290   /// \returns
291   ///   A valid DWO error if there is a problem with anything in the
292   ///   locating or parsing inforamtion in the .dwo file
GetDwoError()293   const Status &GetDwoError() const { return m_dwo_error; }
294 
295   /// Set the fission .dwo file specific error for this compile unit.
296   ///
297   /// This helps tracks issues that arise when trying to locate or parse a
298   /// .dwo file. Things like a missing .dwo file, DWO ID mismatch, and other
299   /// .dwo errors can be stored in each compile unit so the issues can be
300   /// communicated to the user.
SetDwoError(const Status & error)301   void SetDwoError(const Status &error) { m_dwo_error = error; }
302 
303 protected:
304   DWARFUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid,
305             const DWARFUnitHeader &header,
306             const llvm::DWARFAbbreviationDeclarationSet &abbrevs,
307             DIERef::Section section, bool is_dwo);
308 
309   llvm::Error ExtractHeader(SymbolFileDWARF &dwarf,
310                             const DWARFDataExtractor &data,
311                             lldb::offset_t *offset_ptr);
312 
313   // Get the DWARF unit DWARF debug information entry. Parse the single DIE
314   // if needed.
GetUnitDIEPtrOnly()315   const DWARFDebugInfoEntry *GetUnitDIEPtrOnly() {
316     ExtractUnitDIENoDwoIfNeeded();
317     // m_first_die_mutex is not required as m_first_die is never cleared.
318     if (!m_first_die)
319       return nullptr;
320     return &m_first_die;
321   }
322 
323   // Get all DWARF debug informration entries. Parse all DIEs if needed.
DIEPtr()324   const DWARFDebugInfoEntry *DIEPtr() {
325     ExtractDIEsIfNeeded();
326     if (m_die_array.empty())
327       return nullptr;
328     return &m_die_array[0];
329   }
330 
331   const std::optional<llvm::DWARFDebugRnglistTable> &GetRnglistTable();
332 
333   DWARFDataExtractor GetRnglistData() const;
334 
335   SymbolFileDWARF &m_dwarf;
336   std::shared_ptr<DWARFUnit> m_dwo;
337   DWARFUnitHeader m_header;
338   const llvm::DWARFAbbreviationDeclarationSet *m_abbrevs = nullptr;
339   void *m_user_data = nullptr;
340   // The compile unit debug information entry item
341   DWARFDebugInfoEntry::collection m_die_array;
342   mutable llvm::sys::RWMutex m_die_array_mutex;
343   // It is used for tracking of ScopedExtractDIEs instances.
344   mutable llvm::sys::RWMutex m_die_array_scoped_mutex;
345   // ScopedExtractDIEs instances should not call ClearDIEsRWLocked()
346   // as someone called ExtractDIEsIfNeeded().
347   std::atomic<bool> m_cancel_scopes;
348   // GetUnitDIEPtrOnly() needs to return pointer to the first DIE.
349   // But the first element of m_die_array after ExtractUnitDIEIfNeeded()
350   // would possibly move in memory after later ExtractDIEsIfNeeded().
351   DWARFDebugInfoEntry m_first_die;
352   llvm::sys::RWMutex m_first_die_mutex;
353   // A table similar to the .debug_aranges table, but this one points to the
354   // exact DW_TAG_subprogram DIEs
355   std::unique_ptr<DWARFDebugAranges> m_func_aranges_up;
356   dw_addr_t m_base_addr = 0;
357   DWARFProducer m_producer = eProducerInvalid;
358   llvm::VersionTuple m_producer_version;
359   std::optional<uint64_t> m_language_type;
360   LazyBool m_is_optimized = eLazyBoolCalculate;
361   std::optional<FileSpec> m_comp_dir;
362   std::optional<FileSpec> m_file_spec;
363   std::optional<dw_addr_t> m_addr_base; ///< Value of DW_AT_addr_base.
364   dw_addr_t m_loclists_base = 0;        ///< Value of DW_AT_loclists_base.
365   dw_addr_t m_ranges_base = 0;          ///< Value of DW_AT_rnglists_base.
366   std::optional<uint64_t> m_gnu_addr_base;
367   std::optional<uint64_t> m_gnu_ranges_base;
368 
369   /// Value of DW_AT_stmt_list.
370   dw_offset_t m_line_table_offset = DW_INVALID_OFFSET;
371 
372   dw_offset_t m_str_offsets_base = 0; // Value of DW_AT_str_offsets_base.
373 
374   std::optional<llvm::DWARFDebugRnglistTable> m_rnglist_table;
375   bool m_rnglist_table_done = false;
376   std::optional<llvm::DWARFListTableHeader> m_loclist_table_header;
377 
378   const DIERef::Section m_section;
379   bool m_is_dwo;
380   bool m_has_parsed_non_skeleton_unit;
381   /// Value of DW_AT_GNU_dwo_id (v4) or dwo_id from CU header (v5).
382   std::optional<uint64_t> m_dwo_id;
383   /// If we get an error when trying to load a .dwo file, save that error here.
384   /// Errors include .dwo/.dwp file not found, or the .dwp/.dwp file was found
385   /// but DWO ID doesn't match, etc.
386   Status m_dwo_error;
387 
388 private:
389   void ParseProducerInfo();
390   void ExtractDIEsRWLocked();
391   void ClearDIEsRWLocked();
392 
393   void AddUnitDIE(const DWARFDebugInfoEntry &cu_die);
394   void SetDwoStrOffsetsBase();
395 
396   void ComputeCompDirAndGuessPathStyle();
397   void ComputeAbsolutePath();
398 
399   DWARFUnit(const DWARFUnit &) = delete;
400   const DWARFUnit &operator=(const DWARFUnit &) = delete;
401 };
402 } // namespace dwarf
403 } // namespace lldb_private::plugin
404 
405 #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFUNIT_H
406