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

source code of lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h