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: 63 dw_offset_t GetOffset() const { return m_offset; } 64 uint16_t GetVersion() const { return m_version; } 65 uint16_t GetAddressByteSize() const { return m_addr_size; } 66 dw_offset_t GetLength() const { return m_length; } 67 dw_offset_t GetAbbrOffset() const { return m_abbr_offset; } 68 uint8_t GetUnitType() const { return m_unit_type; } 69 const llvm::DWARFUnitIndex::Entry *GetIndexEntry() const { 70 return m_index_entry; 71 } 72 uint64_t GetTypeHash() const { return m_type_hash; } 73 dw_offset_t GetTypeOffset() const { return m_type_offset; } 74 std::optional<uint64_t> GetDWOId() const { return m_dwo_id; } 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 } 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 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. 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 147 size_t GetLengthByteSize() const { return 4; } 148 149 bool ContainsDIEOffset(dw_offset_t die_offset) const { 150 return die_offset >= GetFirstDIEOffset() && 151 die_offset < GetNextUnitOffset(); 152 } 153 dw_offset_t GetFirstDIEOffset() const { 154 return GetOffset() + GetHeaderByteSize(); 155 } 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. 160 dw_offset_t GetLength() const { return m_header.GetLength(); } 161 uint16_t GetVersion() const { return m_header.GetVersion(); } 162 const llvm::DWARFAbbreviationDeclarationSet *GetAbbreviations() const; 163 dw_offset_t GetAbbrevOffset() const; 164 uint8_t GetAddressByteSize() const { return m_header.GetAddressByteSize(); } 165 dw_addr_t GetAddrBase() const { return m_addr_base.value_or(0); } 166 dw_addr_t GetBaseAddress() const { return m_base_addr; } 167 dw_offset_t GetLineTableOffset(); 168 dw_addr_t GetRangesBase() const { return m_ranges_base; } 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 184 DWARFBaseDIE GetUnitDIEOnly() { return {this, GetUnitDIEPtrOnly()}; } 185 186 DWARFDIE DIE() { return DWARFDIE(this, DIEPtr()); } 187 188 DWARFDIE GetDIE(dw_offset_t die_offset); 189 190 DWARFUnit &GetNonSkeletonUnit(); 191 192 static uint8_t GetAddressByteSize(const DWARFUnit *cu); 193 194 static uint8_t GetDefaultAddressSize(); 195 196 void *GetUserData() const; 197 198 void SetUserData(void *d); 199 200 bool Supports_DW_AT_APPLE_objc_complete_type(); 201 202 bool DW_AT_decl_file_attributes_are_invalid(); 203 204 bool Supports_unnamed_objc_bitfields(); 205 206 SymbolFileDWARF &GetSymbolFileDWARF() const { return m_dwarf; } 207 208 DWARFProducer GetProducer(); 209 210 llvm::VersionTuple GetProducerVersion(); 211 212 uint64_t GetDWARFLanguageType(); 213 214 bool GetIsOptimized(); 215 216 const FileSpec &GetCompilationDirectory(); 217 const FileSpec &GetAbsolutePath(); 218 FileSpec GetFile(size_t file_idx); 219 FileSpec::Style GetPathStyle(); 220 221 SymbolFileDWARFDwo *GetDwoSymbolFile(); 222 223 die_iterator_range dies() { 224 ExtractDIEsIfNeeded(); 225 return die_iterator_range(m_die_array.begin(), m_die_array.end()); 226 } 227 228 DIERef::Section GetDebugSection() const { return m_section; } 229 230 uint8_t GetUnitType() const { return m_header.GetUnitType(); } 231 bool IsTypeUnit() const { return m_header.IsTypeUnit(); } 232 /// Note that this check only works for DWARF5+. 233 bool IsSkeletonUnit() const { 234 return GetUnitType() == llvm::dwarf::DW_UT_skeleton; 235 } 236 237 std::optional<uint64_t> GetStringOffsetSectionItem(uint32_t index) const; 238 239 /// Return a list of address ranges resulting from a (possibly encoded) 240 /// range list starting at a given offset in the appropriate ranges section. 241 llvm::Expected<DWARFRangeList> FindRnglistFromOffset(dw_offset_t offset); 242 243 /// Return a list of address ranges retrieved from an encoded range 244 /// list whose offset is found via a table lookup given an index (DWARF v5 245 /// and later). 246 llvm::Expected<DWARFRangeList> FindRnglistFromIndex(uint32_t index); 247 248 /// Return a rangelist's offset based on an index. The index designates 249 /// an entry in the rangelist table's offset array and is supplied by 250 /// DW_FORM_rnglistx. 251 llvm::Expected<uint64_t> GetRnglistOffset(uint32_t Index); 252 253 std::optional<uint64_t> GetLoclistOffset(uint32_t Index) { 254 if (!m_loclist_table_header) 255 return std::nullopt; 256 257 std::optional<uint64_t> Offset = m_loclist_table_header->getOffsetEntry( 258 m_dwarf.GetDWARFContext().getOrLoadLocListsData().GetAsLLVM(), Index); 259 if (!Offset) 260 return std::nullopt; 261 return *Offset + m_loclists_base; 262 } 263 264 /// Return the location table for parsing the given location list data. The 265 /// format is chosen according to the unit type. Never returns null. 266 std::unique_ptr<llvm::DWARFLocationTable> 267 GetLocationTable(const DataExtractor &data) const; 268 269 DWARFDataExtractor GetLocationData() const; 270 271 /// Returns true if any DIEs in the unit match any DW_TAG values in \a tags. 272 /// 273 /// \param[in] tags 274 /// An array of dw_tag_t values to check all abbrevitions for. 275 /// 276 /// \returns 277 /// True if any DIEs match any tag in \a tags, false otherwise. 278 bool HasAny(llvm::ArrayRef<dw_tag_t> tags); 279 280 /// Get the fission .dwo file specific error for this compile unit. 281 /// 282 /// The skeleton compile unit only can have a DWO error. Any other type 283 /// of DWARFUnit will not have a valid DWO error. 284 /// 285 /// \returns 286 /// A valid DWO error if there is a problem with anything in the 287 /// locating or parsing inforamtion in the .dwo file 288 const Status &GetDwoError() const { return m_dwo_error; } 289 290 /// Set the fission .dwo file specific error for this compile unit. 291 /// 292 /// This helps tracks issues that arise when trying to locate or parse a 293 /// .dwo file. Things like a missing .dwo file, DWO ID mismatch, and other 294 /// .dwo errors can be stored in each compile unit so the issues can be 295 /// communicated to the user. 296 void SetDwoError(const Status &error) { m_dwo_error = error; } 297 298 protected: 299 DWARFUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid, 300 const DWARFUnitHeader &header, 301 const llvm::DWARFAbbreviationDeclarationSet &abbrevs, 302 DIERef::Section section, bool is_dwo); 303 304 llvm::Error ExtractHeader(SymbolFileDWARF &dwarf, 305 const DWARFDataExtractor &data, 306 lldb::offset_t *offset_ptr); 307 308 // Get the DWARF unit DWARF debug information entry. Parse the single DIE 309 // if needed. 310 const DWARFDebugInfoEntry *GetUnitDIEPtrOnly() { 311 ExtractUnitDIENoDwoIfNeeded(); 312 // m_first_die_mutex is not required as m_first_die is never cleared. 313 if (!m_first_die) 314 return nullptr; 315 return &m_first_die; 316 } 317 318 // Get all DWARF debug informration entries. Parse all DIEs if needed. 319 const DWARFDebugInfoEntry *DIEPtr() { 320 ExtractDIEsIfNeeded(); 321 if (m_die_array.empty()) 322 return nullptr; 323 return &m_die_array[0]; 324 } 325 326 const std::optional<llvm::DWARFDebugRnglistTable> &GetRnglistTable(); 327 328 DWARFDataExtractor GetRnglistData() const; 329 330 SymbolFileDWARF &m_dwarf; 331 std::shared_ptr<DWARFUnit> m_dwo; 332 DWARFUnitHeader m_header; 333 const llvm::DWARFAbbreviationDeclarationSet *m_abbrevs = nullptr; 334 void *m_user_data = nullptr; 335 // The compile unit debug information entry item 336 DWARFDebugInfoEntry::collection m_die_array; 337 mutable llvm::sys::RWMutex m_die_array_mutex; 338 // It is used for tracking of ScopedExtractDIEs instances. 339 mutable llvm::sys::RWMutex m_die_array_scoped_mutex; 340 // ScopedExtractDIEs instances should not call ClearDIEsRWLocked() 341 // as someone called ExtractDIEsIfNeeded(). 342 std::atomic<bool> m_cancel_scopes; 343 // GetUnitDIEPtrOnly() needs to return pointer to the first DIE. 344 // But the first element of m_die_array after ExtractUnitDIEIfNeeded() 345 // would possibly move in memory after later ExtractDIEsIfNeeded(). 346 DWARFDebugInfoEntry m_first_die; 347 llvm::sys::RWMutex m_first_die_mutex; 348 // A table similar to the .debug_aranges table, but this one points to the 349 // exact DW_TAG_subprogram DIEs 350 std::unique_ptr<DWARFDebugAranges> m_func_aranges_up; 351 dw_addr_t m_base_addr = 0; 352 DWARFProducer m_producer = eProducerInvalid; 353 llvm::VersionTuple m_producer_version; 354 std::optional<uint64_t> m_language_type; 355 LazyBool m_is_optimized = eLazyBoolCalculate; 356 std::optional<FileSpec> m_comp_dir; 357 std::optional<FileSpec> m_file_spec; 358 std::optional<dw_addr_t> m_addr_base; ///< Value of DW_AT_addr_base. 359 dw_addr_t m_loclists_base = 0; ///< Value of DW_AT_loclists_base. 360 dw_addr_t m_ranges_base = 0; ///< Value of DW_AT_rnglists_base. 361 std::optional<uint64_t> m_gnu_addr_base; 362 std::optional<uint64_t> m_gnu_ranges_base; 363 364 /// Value of DW_AT_stmt_list. 365 dw_offset_t m_line_table_offset = DW_INVALID_OFFSET; 366 367 dw_offset_t m_str_offsets_base = 0; // Value of DW_AT_str_offsets_base. 368 369 std::optional<llvm::DWARFDebugRnglistTable> m_rnglist_table; 370 bool m_rnglist_table_done = false; 371 std::optional<llvm::DWARFListTableHeader> m_loclist_table_header; 372 373 const DIERef::Section m_section; 374 bool m_is_dwo; 375 bool m_has_parsed_non_skeleton_unit; 376 /// Value of DW_AT_GNU_dwo_id (v4) or dwo_id from CU header (v5). 377 std::optional<uint64_t> m_dwo_id; 378 /// If we get an error when trying to load a .dwo file, save that error here. 379 /// Errors include .dwo/.dwp file not found, or the .dwp/.dwp file was found 380 /// but DWO ID doesn't match, etc. 381 Status m_dwo_error; 382 383 private: 384 void ParseProducerInfo(); 385 void ExtractDIEsRWLocked(); 386 void ClearDIEsRWLocked(); 387 388 void AddUnitDIE(const DWARFDebugInfoEntry &cu_die); 389 void SetDwoStrOffsetsBase(); 390 391 void ComputeCompDirAndGuessPathStyle(); 392 void ComputeAbsolutePath(); 393 394 DWARFUnit(const DWARFUnit &) = delete; 395 const DWARFUnit &operator=(const DWARFUnit &) = delete; 396 }; 397 } // namespace dwarf 398 } // namespace lldb_private::plugin 399 400 #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFUNIT_H 401