1164 lines · cpp
1//===-- DWARFUnit.cpp -----------------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "DWARFUnit.h"10 11#include "lldb/Core/Module.h"12#include "lldb/Symbol/ObjectFile.h"13#include "lldb/Utility/LLDBAssert.h"14#include "lldb/Utility/StreamString.h"15#include "lldb/Utility/Timer.h"16#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h"17#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"18#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"19#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"20#include "llvm/Object/Error.h"21 22#include "DWARFCompileUnit.h"23#include "DWARFDebugAranges.h"24#include "DWARFDebugInfo.h"25#include "DWARFTypeUnit.h"26#include "LogChannelDWARF.h"27#include "SymbolFileDWARFDwo.h"28#include <optional>29 30using namespace lldb;31using namespace lldb_private;32using namespace lldb_private::plugin::dwarf;33using namespace llvm::dwarf;34 35extern int g_verbose;36 37DWARFUnit::DWARFUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid,38 const llvm::DWARFUnitHeader &header,39 const llvm::DWARFAbbreviationDeclarationSet &abbrevs,40 DIERef::Section section, bool is_dwo)41 : UserID(uid), m_dwarf(dwarf), m_header(header), m_abbrevs(&abbrevs),42 m_cancel_scopes(false), m_section(section), m_is_dwo(is_dwo),43 m_has_parsed_non_skeleton_unit(false), m_dwo_id(header.getDWOId()) {}44 45DWARFUnit::~DWARFUnit() = default;46 47// Parses first DIE of a compile unit, excluding DWO.48void DWARFUnit::ExtractUnitDIENoDwoIfNeeded() {49 {50 llvm::sys::ScopedReader lock(m_first_die_mutex);51 if (m_first_die)52 return; // Already parsed53 }54 llvm::sys::ScopedWriter lock(m_first_die_mutex);55 if (m_first_die)56 return; // Already parsed57 58 ElapsedTime elapsed(m_dwarf.GetDebugInfoParseTimeRef());59 60 // Set the offset to that of the first DIE and calculate the start of the61 // next compilation unit header.62 lldb::offset_t offset = GetFirstDIEOffset();63 64 // We are in our compile unit, parse starting at the offset we were told to65 // parse66 const DWARFDataExtractor &data = GetData();67 if (offset < GetNextUnitOffset() &&68 m_first_die.Extract(data, *this, &offset)) {69 AddUnitDIE(m_first_die);70 return;71 }72}73 74// Parses first DIE of a compile unit including DWO.75void DWARFUnit::ExtractUnitDIEIfNeeded() {76 ExtractUnitDIENoDwoIfNeeded();77 78 if (m_has_parsed_non_skeleton_unit)79 return;80 81 m_has_parsed_non_skeleton_unit = true;82 m_dwo_error.Clear();83 84 if (!m_dwo_id)85 return; // No DWO file.86 87 std::shared_ptr<SymbolFileDWARFDwo> dwo_symbol_file =88 m_dwarf.GetDwoSymbolFileForCompileUnit(*this, m_first_die);89 if (!dwo_symbol_file)90 return;91 92 DWARFUnit *dwo_cu = dwo_symbol_file->GetDWOCompileUnitForHash(*m_dwo_id);93 94 if (!dwo_cu) {95 SetDwoError(Status::FromErrorStringWithFormatv(96 "unable to load .dwo file from \"{0}\" due to ID ({1:x16}) mismatch "97 "for skeleton DIE at {2:x8}",98 dwo_symbol_file->GetObjectFile()->GetFileSpec().GetPath(), *m_dwo_id,99 m_first_die.GetOffset()));100 return; // Can't fetch the compile unit from the dwo file.101 }102 103 // Link the DWO unit to this object, if it hasn't been linked already (this104 // can happen when we have an index, and the DWO unit is parsed first).105 if (!dwo_cu->LinkToSkeletonUnit(*this)) {106 SetDwoError(Status::FromErrorStringWithFormatv(107 "multiple compile units with Dwo ID {0:x16}", *m_dwo_id));108 return;109 }110 111 DWARFBaseDIE dwo_cu_die = dwo_cu->GetUnitDIEOnly();112 if (!dwo_cu_die.IsValid()) {113 // Can't fetch the compile unit DIE from the dwo file.114 SetDwoError(Status::FromErrorStringWithFormatv(115 "unable to extract compile unit DIE from .dwo file for skeleton "116 "DIE at {0:x16}",117 m_first_die.GetOffset()));118 return;119 }120 121 // Here for DWO CU we want to use the address base set in the skeleton unit122 // (DW_AT_addr_base) if it is available and use the DW_AT_GNU_addr_base123 // otherwise. We do that because pre-DWARF v5 could use the DW_AT_GNU_*124 // attributes which were applicable to the DWO units. The corresponding125 // DW_AT_* attributes standardized in DWARF v5 are also applicable to the126 // main unit in contrast.127 if (m_addr_base)128 dwo_cu->SetAddrBase(*m_addr_base);129 else if (m_gnu_addr_base)130 dwo_cu->SetAddrBase(*m_gnu_addr_base);131 132 if (GetVersion() <= 4 && m_gnu_ranges_base)133 dwo_cu->SetRangesBase(*m_gnu_ranges_base);134 else if (dwo_symbol_file->GetDWARFContext()135 .getOrLoadRngListsData()136 .GetByteSize() > 0)137 dwo_cu->SetRangesBase(llvm::DWARFListTableHeader::getHeaderSize(DWARF32));138 139 if (GetVersion() >= 5 &&140 dwo_symbol_file->GetDWARFContext().getOrLoadLocListsData().GetByteSize() >141 0)142 dwo_cu->SetLoclistsBase(llvm::DWARFListTableHeader::getHeaderSize(DWARF32));143 144 dwo_cu->SetBaseAddress(GetBaseAddress());145 146 m_dwo = std::shared_ptr<DWARFUnit>(std::move(dwo_symbol_file), dwo_cu);147}148 149// Parses a compile unit and indexes its DIEs if it hasn't already been done.150// It will leave this compile unit extracted forever.151void DWARFUnit::ExtractDIEsIfNeeded() {152 m_cancel_scopes = true;153 154 {155 llvm::sys::ScopedReader lock(m_die_array_mutex);156 if (!m_die_array.empty())157 return; // Already parsed158 }159 llvm::sys::ScopedWriter lock(m_die_array_mutex);160 if (!m_die_array.empty())161 return; // Already parsed162 163 ExtractDIEsRWLocked();164}165 166// Parses a compile unit and indexes its DIEs if it hasn't already been done.167// It will clear this compile unit after returned instance gets out of scope,168// no other ScopedExtractDIEs instance is running for this compile unit169// and no ExtractDIEsIfNeeded() has been executed during this ScopedExtractDIEs170// lifetime.171DWARFUnit::ScopedExtractDIEs DWARFUnit::ExtractDIEsScoped() {172 ScopedExtractDIEs scoped(*this);173 174 {175 llvm::sys::ScopedReader lock(m_die_array_mutex);176 if (!m_die_array.empty())177 return scoped; // Already parsed178 }179 llvm::sys::ScopedWriter lock(m_die_array_mutex);180 if (!m_die_array.empty())181 return scoped; // Already parsed182 183 // Otherwise m_die_array would be already populated.184 lldbassert(!m_cancel_scopes);185 186 ExtractDIEsRWLocked();187 scoped.m_clear_dies = true;188 return scoped;189}190 191DWARFUnit::ScopedExtractDIEs::ScopedExtractDIEs(DWARFUnit &cu) : m_cu(&cu) {192 llvm::sys::ScopedLock lock(m_cu->m_die_array_scoped_mutex);193 ++m_cu->m_die_array_scoped_count;194}195 196DWARFUnit::ScopedExtractDIEs::~ScopedExtractDIEs() {197 if (!m_cu)198 return;199 llvm::sys::ScopedLock lock(m_cu->m_die_array_scoped_mutex);200 --m_cu->m_die_array_scoped_count;201 if (m_cu->m_die_array_scoped_count == 0 && m_clear_dies &&202 !m_cu->m_cancel_scopes) {203 llvm::sys::ScopedWriter lock(m_cu->m_die_array_mutex);204 m_cu->ClearDIEsRWLocked();205 }206}207 208DWARFUnit::ScopedExtractDIEs::ScopedExtractDIEs(ScopedExtractDIEs &&rhs)209 : m_cu(rhs.m_cu), m_clear_dies(rhs.m_clear_dies) {210 rhs.m_cu = nullptr;211}212 213DWARFUnit::ScopedExtractDIEs &214DWARFUnit::ScopedExtractDIEs::operator=(DWARFUnit::ScopedExtractDIEs &&rhs) {215 m_cu = rhs.m_cu;216 rhs.m_cu = nullptr;217 m_clear_dies = rhs.m_clear_dies;218 return *this;219}220 221// Parses a compile unit and indexes its DIEs, m_die_array_mutex must be222// held R/W and m_die_array must be empty.223void DWARFUnit::ExtractDIEsRWLocked() {224 llvm::sys::ScopedWriter first_die_lock(m_first_die_mutex);225 226 ElapsedTime elapsed(m_dwarf.GetDebugInfoParseTimeRef());227 LLDB_SCOPED_TIMERF(228 "%s",229 llvm::formatv("{0:x16}: DWARFUnit::ExtractDIEsIfNeeded()", GetOffset())230 .str()231 .c_str());232 233 // Set the offset to that of the first DIE and calculate the start of the234 // next compilation unit header.235 lldb::offset_t offset = GetFirstDIEOffset();236 lldb::offset_t next_cu_offset = GetNextUnitOffset();237 238 DWARFDebugInfoEntry die;239 240 uint32_t depth = 0;241 // We are in our compile unit, parse starting at the offset we were told to242 // parse243 const DWARFDataExtractor &data = GetData();244 std::vector<uint32_t> die_index_stack;245 die_index_stack.reserve(32);246 die_index_stack.push_back(0);247 bool prev_die_had_children = false;248 while (offset < next_cu_offset && die.Extract(data, *this, &offset)) {249 const bool null_die = die.IsNULL();250 if (depth == 0) {251 assert(m_die_array.empty() && "Compile unit DIE already added");252 253 // The average bytes per DIE entry has been seen to be around 14-20 so254 // lets pre-reserve half of that since we are now stripping the NULL255 // tags.256 257 // Only reserve the memory if we are adding children of the main258 // compile unit DIE. The compile unit DIE is always the first entry, so259 // if our size is 1, then we are adding the first compile unit child260 // DIE and should reserve the memory.261 m_die_array.reserve(GetDebugInfoSize() / 24);262 m_die_array.push_back(die);263 264 if (!m_first_die)265 AddUnitDIE(m_die_array.front());266 267 // With -fsplit-dwarf-inlining, clang will emit non-empty skeleton compile268 // units. We are not able to access these DIE *and* the dwo file269 // simultaneously. We also don't need to do that as the dwo file will270 // contain a superset of information. So, we don't even attempt to parse271 // any remaining DIEs.272 if (m_dwo) {273 m_die_array.front().SetHasChildren(false);274 break;275 }276 277 } else {278 if (null_die) {279 if (prev_die_had_children) {280 // This will only happen if a DIE says is has children but all it281 // contains is a NULL tag. Since we are removing the NULL DIEs from282 // the list (saves up to 25% in C++ code), we need a way to let the283 // DIE know that it actually doesn't have children.284 if (!m_die_array.empty())285 m_die_array.back().SetHasChildren(false);286 }287 } else {288 die.SetParentIndex(m_die_array.size() - die_index_stack[depth - 1]);289 290 if (die_index_stack.back())291 m_die_array[die_index_stack.back()].SetSiblingIndex(292 m_die_array.size() - die_index_stack.back());293 294 // Only push the DIE if it isn't a NULL DIE295 m_die_array.push_back(die);296 }297 }298 299 if (null_die) {300 // NULL DIE.301 if (!die_index_stack.empty())302 die_index_stack.pop_back();303 304 if (depth > 0)305 --depth;306 prev_die_had_children = false;307 } else {308 die_index_stack.back() = m_die_array.size() - 1;309 // Normal DIE310 const bool die_has_children = die.HasChildren();311 if (die_has_children) {312 die_index_stack.push_back(0);313 ++depth;314 }315 prev_die_had_children = die_has_children;316 }317 318 if (depth == 0)319 break; // We are done with this compile unit!320 }321 322 if (!m_die_array.empty()) {323 // The last die cannot have children (if it did, it wouldn't be the last324 // one). This only makes a difference for malformed dwarf that does not have325 // a terminating null die.326 m_die_array.back().SetHasChildren(false);327 328 if (m_first_die) {329 // Only needed for the assertion.330 m_first_die.SetHasChildren(m_die_array.front().HasChildren());331 lldbassert(m_first_die == m_die_array.front());332 }333 m_first_die = m_die_array.front();334 }335 336 m_die_array.shrink_to_fit();337 338 if (m_dwo)339 m_dwo->ExtractDIEsIfNeeded();340}341 342// This is used when a split dwarf is enabled.343// A skeleton compilation unit may contain the DW_AT_str_offsets_base attribute344// that points to the first string offset of the CU contribution to the345// .debug_str_offsets. At the same time, the corresponding split debug unit also346// may use DW_FORM_strx* forms pointing to its own .debug_str_offsets.dwo and347// for that case, we should find the offset (skip the section header).348void DWARFUnit::SetDwoStrOffsetsBase() {349 lldb::offset_t baseOffset = 0;350 351 // Size of offset for .debug_str_offsets is same as DWARF offset byte size352 // of the DWARFUnit as a default. We might override this if below if needed.353 m_str_offset_size = m_header.getDwarfOffsetByteSize();354 355 if (const llvm::DWARFUnitIndex::Entry *entry = m_header.getIndexEntry()) {356 if (const auto *contribution =357 entry->getContribution(llvm::DW_SECT_STR_OFFSETS))358 baseOffset = contribution->getOffset();359 else360 return;361 }362 363 if (GetVersion() >= 5) {364 const llvm::DWARFDataExtractor &strOffsets = GetSymbolFileDWARF()365 .GetDWARFContext()366 .getOrLoadStrOffsetsData()367 .GetAsLLVMDWARF();368 369 uint64_t length;370 llvm::dwarf::DwarfFormat format;371 std::tie(length, format) = strOffsets.getInitialLength(&baseOffset);372 m_str_offset_size = format == llvm::dwarf::DwarfFormat::DWARF64 ? 8 : 4;373 // Check version.374 if (strOffsets.getU16(&baseOffset) < 5)375 return;376 377 // Skip padding.378 baseOffset += 2;379 }380 381 SetStrOffsetsBase(baseOffset);382}383 384std::optional<uint64_t> DWARFUnit::GetDWOId() {385 ExtractUnitDIENoDwoIfNeeded();386 return m_dwo_id;387}388 389// m_die_array_mutex must be already held as read/write.390void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) {391 DWARFAttributes attributes = cu_die.GetAttributes(this);392 393 // Extract DW_AT_addr_base first, as other attributes may need it.394 for (size_t i = 0; i < attributes.Size(); ++i) {395 if (attributes.AttributeAtIndex(i) != DW_AT_addr_base)396 continue;397 DWARFFormValue form_value;398 if (attributes.ExtractFormValueAtIndex(i, form_value)) {399 SetAddrBase(form_value.Unsigned());400 break;401 }402 }403 404 for (size_t i = 0; i < attributes.Size(); ++i) {405 dw_attr_t attr = attributes.AttributeAtIndex(i);406 DWARFFormValue form_value;407 if (!attributes.ExtractFormValueAtIndex(i, form_value))408 continue;409 switch (attr) {410 default:411 break;412 case DW_AT_loclists_base:413 SetLoclistsBase(form_value.Unsigned());414 break;415 case DW_AT_rnglists_base:416 SetRangesBase(form_value.Unsigned());417 break;418 case DW_AT_str_offsets_base:419 // When we have a DW_AT_str_offsets_base attribute, it points us to the420 // first string offset for this DWARFUnit which is after the string421 // offsets table header. In this case we use the DWARF32/DWARF64 of the422 // DWARFUnit to determine the string offset byte size. DWO files do not423 // use this attribute and they point to the start of the string offsets424 // table header which can be used to determine the DWARF32/DWARF64 status425 // of the string table. See SetDwoStrOffsetsBase() for now it figures out426 // the m_str_offset_size value that should be used.427 SetStrOffsetsBase(form_value.Unsigned());428 m_str_offset_size = m_header.getDwarfOffsetByteSize();429 break;430 case DW_AT_low_pc:431 SetBaseAddress(form_value.Address());432 break;433 case DW_AT_entry_pc:434 // If the value was already set by DW_AT_low_pc, don't update it.435 if (m_base_addr == LLDB_INVALID_ADDRESS)436 SetBaseAddress(form_value.Address());437 break;438 case DW_AT_stmt_list:439 m_line_table_offset = form_value.Unsigned();440 break;441 case DW_AT_GNU_addr_base:442 m_gnu_addr_base = form_value.Unsigned();443 break;444 case DW_AT_GNU_ranges_base:445 m_gnu_ranges_base = form_value.Unsigned();446 break;447 case DW_AT_GNU_dwo_id:448 m_dwo_id = form_value.Unsigned();449 break;450 }451 }452 453 if (m_is_dwo) {454 m_has_parsed_non_skeleton_unit = true;455 SetDwoStrOffsetsBase();456 return;457 }458}459 460size_t DWARFUnit::GetDebugInfoSize() const {461 return GetLengthByteSize() + GetLength() - GetHeaderByteSize();462}463 464const llvm::DWARFAbbreviationDeclarationSet *465DWARFUnit::GetAbbreviations() const {466 return m_abbrevs;467}468 469dw_offset_t DWARFUnit::GetAbbrevOffset() const {470 return m_abbrevs ? m_abbrevs->getOffset() : DW_INVALID_OFFSET;471}472 473dw_offset_t DWARFUnit::GetLineTableOffset() {474 ExtractUnitDIENoDwoIfNeeded();475 return m_line_table_offset;476}477 478void DWARFUnit::SetAddrBase(dw_addr_t addr_base) { m_addr_base = addr_base; }479 480// Parse the rangelist table header, including the optional array of offsets481// following it (DWARF v5 and later).482template <typename ListTableType>483static llvm::Expected<ListTableType>484ParseListTableHeader(const llvm::DWARFDataExtractor &data, uint64_t offset,485 DwarfFormat format) {486 // We are expected to be called with Offset 0 or pointing just past the table487 // header. Correct Offset in the latter case so that it points to the start488 // of the header.489 if (offset == 0) {490 // This means DW_AT_rnglists_base is missing and therefore DW_FORM_rnglistx491 // cannot be handled. Returning a default-constructed ListTableType allows492 // DW_FORM_sec_offset to be supported.493 return ListTableType();494 }495 496 uint64_t HeaderSize = llvm::DWARFListTableHeader::getHeaderSize(format);497 if (offset < HeaderSize)498 return llvm::createStringError(std::errc::invalid_argument,499 "did not detect a valid"500 " list table with base = 0x%" PRIx64 "\n",501 offset);502 offset -= HeaderSize;503 ListTableType Table;504 if (llvm::Error E = Table.extractHeaderAndOffsets(data, &offset))505 return std::move(E);506 return Table;507}508 509void DWARFUnit::SetLoclistsBase(dw_addr_t loclists_base) {510 uint64_t offset = 0;511 if (const llvm::DWARFUnitIndex::Entry *entry = m_header.getIndexEntry()) {512 const auto *contribution = entry->getContribution(llvm::DW_SECT_LOCLISTS);513 if (!contribution) {514 GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(515 "Failed to find location list contribution for CU with DWO Id "516 "{0:x16}",517 *GetDWOId());518 return;519 }520 offset += contribution->getOffset();521 }522 m_loclists_base = loclists_base;523 524 uint64_t header_size = llvm::DWARFListTableHeader::getHeaderSize(DWARF32);525 if (loclists_base < header_size)526 return;527 528 m_loclist_table_header.emplace(".debug_loclists", "locations");529 offset += loclists_base - header_size;530 if (llvm::Error E = m_loclist_table_header->extract(531 m_dwarf.GetDWARFContext().getOrLoadLocListsData().GetAsLLVMDWARF(),532 &offset)) {533 GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(534 "Failed to extract location list table at offset {0:x16} (location "535 "list base: {1:x16}): {2}",536 offset, loclists_base, toString(std::move(E)).c_str());537 }538}539 540std::unique_ptr<llvm::DWARFLocationTable>541DWARFUnit::GetLocationTable(const DataExtractor &data) const {542 llvm::DWARFDataExtractor llvm_data(543 data.GetData(), data.GetByteOrder() == lldb::eByteOrderLittle,544 data.GetAddressByteSize());545 546 if (m_is_dwo || GetVersion() >= 5)547 return std::make_unique<llvm::DWARFDebugLoclists>(llvm_data, GetVersion());548 return std::make_unique<llvm::DWARFDebugLoc>(llvm_data);549}550 551DWARFDataExtractor DWARFUnit::GetLocationData() const {552 DWARFContext &Ctx = GetSymbolFileDWARF().GetDWARFContext();553 const DWARFDataExtractor &data =554 GetVersion() >= 5 ? Ctx.getOrLoadLocListsData() : Ctx.getOrLoadLocData();555 if (const llvm::DWARFUnitIndex::Entry *entry = m_header.getIndexEntry()) {556 if (const auto *contribution = entry->getContribution(557 GetVersion() >= 5 ? llvm::DW_SECT_LOCLISTS : llvm::DW_SECT_EXT_LOC))558 return DWARFDataExtractor(data, contribution->getOffset(),559 contribution->getLength32());560 return DWARFDataExtractor();561 }562 return data;563}564 565DWARFDataExtractor DWARFUnit::GetRnglistData() const {566 DWARFContext &Ctx = GetSymbolFileDWARF().GetDWARFContext();567 const DWARFDataExtractor &data = Ctx.getOrLoadRngListsData();568 if (const llvm::DWARFUnitIndex::Entry *entry = m_header.getIndexEntry()) {569 if (const auto *contribution =570 entry->getContribution(llvm::DW_SECT_RNGLISTS))571 return DWARFDataExtractor(data, contribution->getOffset(),572 contribution->getLength32());573 GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(574 "Failed to find range list contribution for CU with signature {0:x16}",575 entry->getSignature());576 577 return DWARFDataExtractor();578 }579 return data;580}581 582void DWARFUnit::SetRangesBase(dw_addr_t ranges_base) {583 lldbassert(!m_rnglist_table_done);584 585 m_ranges_base = ranges_base;586}587 588const std::optional<llvm::DWARFDebugRnglistTable> &589DWARFUnit::GetRnglistTable() {590 if (GetVersion() >= 5 && !m_rnglist_table_done) {591 m_rnglist_table_done = true;592 if (auto table_or_error =593 ParseListTableHeader<llvm::DWARFDebugRnglistTable>(594 GetRnglistData().GetAsLLVMDWARF(), m_ranges_base, DWARF32))595 m_rnglist_table = std::move(table_or_error.get());596 else597 GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(598 "Failed to extract range list table at offset {0:x16}: {1}",599 m_ranges_base, toString(table_or_error.takeError()).c_str());600 }601 return m_rnglist_table;602}603 604// This function is called only for DW_FORM_rnglistx.605llvm::Expected<uint64_t> DWARFUnit::GetRnglistOffset(uint32_t Index) {606 if (!GetRnglistTable())607 return llvm::createStringError(std::errc::invalid_argument,608 "missing or invalid range list table");609 if (!m_ranges_base)610 return llvm::createStringError(611 std::errc::invalid_argument,612 llvm::formatv("DW_FORM_rnglistx cannot be used without "613 "DW_AT_rnglists_base for CU at {0:x16}",614 GetOffset())615 .str()616 .c_str());617 if (std::optional<uint64_t> off = GetRnglistTable()->getOffsetEntry(618 GetRnglistData().GetAsLLVM(), Index))619 return *off + m_ranges_base;620 return llvm::createStringError(621 std::errc::invalid_argument,622 "invalid range list table index %u; OffsetEntryCount is %u, "623 "DW_AT_rnglists_base is %" PRIu64,624 Index, GetRnglistTable()->getOffsetEntryCount(), m_ranges_base);625}626 627void DWARFUnit::SetStrOffsetsBase(dw_offset_t str_offsets_base) {628 m_str_offsets_base = str_offsets_base;629}630 631dw_addr_t DWARFUnit::ReadAddressFromDebugAddrSection(uint32_t index) const {632 uint32_t index_size = GetAddressByteSize();633 dw_offset_t addr_base = GetAddrBase();634 dw_addr_t offset = addr_base + static_cast<dw_addr_t>(index) * index_size;635 const DWARFDataExtractor &data =636 m_dwarf.GetDWARFContext().getOrLoadAddrData();637 if (data.ValidOffsetForDataOfSize(offset, index_size))638 return data.GetMaxU64_unchecked(&offset, index_size);639 return LLDB_INVALID_ADDRESS;640}641 642// It may be called only with m_die_array_mutex held R/W.643void DWARFUnit::ClearDIEsRWLocked() {644 m_die_array.clear();645 m_die_array.shrink_to_fit();646 647 if (m_dwo && !m_dwo->m_cancel_scopes)648 m_dwo->ClearDIEsRWLocked();649}650 651lldb::ByteOrder DWARFUnit::GetByteOrder() const {652 return m_dwarf.GetObjectFile()->GetByteOrder();653}654 655void DWARFUnit::SetBaseAddress(dw_addr_t base_addr) { m_base_addr = base_addr; }656 657// Compare function DWARFDebugAranges::Range structures658static bool CompareDIEOffset(const DWARFDebugInfoEntry &die,659 const dw_offset_t die_offset) {660 return die.GetOffset() < die_offset;661}662 663// GetDIE()664//665// Get the DIE (Debug Information Entry) with the specified offset by first666// checking if the DIE is contained within this compile unit and grabbing the667// DIE from this compile unit. Otherwise we grab the DIE from the DWARF file.668DWARFDIE669DWARFUnit::GetDIE(dw_offset_t die_offset) {670 if (die_offset == DW_INVALID_OFFSET)671 return DWARFDIE(); // Not found672 673 if (!ContainsDIEOffset(die_offset)) {674 GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(675 "GetDIE for DIE {0:x16} is outside of its CU {1:x16}", die_offset,676 GetOffset());677 return DWARFDIE(); // Not found678 }679 680 ExtractDIEsIfNeeded();681 DWARFDebugInfoEntry::const_iterator end = m_die_array.cend();682 DWARFDebugInfoEntry::const_iterator pos =683 lower_bound(m_die_array.cbegin(), end, die_offset, CompareDIEOffset);684 685 if (pos != end && die_offset == (*pos).GetOffset())686 return DWARFDIE(this, &(*pos));687 return DWARFDIE(); // Not found688}689 690llvm::StringRef DWARFUnit::PeekDIEName(dw_offset_t die_offset) {691 DWARFDebugInfoEntry die;692 if (!die.Extract(GetData(), *this, &die_offset))693 return llvm::StringRef();694 695 // Does die contain a DW_AT_Name?696 if (const char *name =697 die.GetAttributeValueAsString(this, DW_AT_name, nullptr))698 return name;699 700 // Does its DW_AT_specification or DW_AT_abstract_origin contain an AT_Name?701 for (auto attr : {DW_AT_specification, DW_AT_abstract_origin}) {702 DWARFFormValue form_value;703 if (!die.GetAttributeValue(this, attr, form_value))704 continue;705 auto [unit, offset] = form_value.ReferencedUnitAndOffset();706 if (unit)707 if (auto name = unit->PeekDIEName(offset); !name.empty())708 return name;709 }710 711 return llvm::StringRef();712}713 714llvm::Expected<std::pair<uint64_t, bool>>715DWARFUnit::GetDIEBitSizeAndSign(uint64_t relative_die_offset) const {716 // Retrieve the type DIE that the value is being converted to. This717 // offset is compile unit relative so we need to fix it up.718 const uint64_t abs_die_offset = relative_die_offset + GetOffset();719 // FIXME: the constness has annoying ripple effects.720 DWARFDIE die = const_cast<DWARFUnit *>(this)->GetDIE(abs_die_offset);721 if (!die)722 return llvm::createStringError("cannot resolve DW_OP_convert type DIE");723 uint64_t encoding =724 die.GetAttributeValueAsUnsigned(DW_AT_encoding, DW_ATE_hi_user);725 uint64_t bit_size = die.GetAttributeValueAsUnsigned(DW_AT_byte_size, 0) * 8;726 if (!bit_size)727 bit_size = die.GetAttributeValueAsUnsigned(DW_AT_bit_size, 0);728 if (!bit_size)729 return llvm::createStringError("unsupported type size");730 bool sign;731 switch (encoding) {732 case DW_ATE_signed:733 case DW_ATE_signed_char:734 sign = true;735 break;736 case DW_ATE_unsigned:737 case DW_ATE_unsigned_char:738 sign = false;739 break;740 default:741 return llvm::createStringError("unsupported encoding");742 }743 return std::pair{bit_size, sign};744}745 746lldb::offset_t747DWARFUnit::GetVendorDWARFOpcodeSize(const DataExtractor &data,748 const lldb::offset_t data_offset,749 const uint8_t op) const {750 return GetSymbolFileDWARF().GetVendorDWARFOpcodeSize(data, data_offset, op);751}752 753bool DWARFUnit::ParseVendorDWARFOpcode(uint8_t op, const DataExtractor &opcodes,754 lldb::offset_t &offset,755 RegisterContext *reg_ctx,756 lldb::RegisterKind reg_kind,757 std::vector<Value> &stack) const {758 return GetSymbolFileDWARF().ParseVendorDWARFOpcode(op, opcodes, offset,759 reg_ctx, reg_kind, stack);760}761 762bool DWARFUnit::ParseDWARFLocationList(763 const DataExtractor &data, DWARFExpressionList &location_list) const {764 location_list.Clear();765 std::unique_ptr<llvm::DWARFLocationTable> loctable_up =766 GetLocationTable(data);767 Log *log = GetLog(DWARFLog::DebugInfo);768 auto lookup_addr =769 [&](uint32_t index) -> std::optional<llvm::object::SectionedAddress> {770 addr_t address = ReadAddressFromDebugAddrSection(index);771 if (address == LLDB_INVALID_ADDRESS)772 return std::nullopt;773 return llvm::object::SectionedAddress{address};774 };775 auto process_list = [&](llvm::Expected<llvm::DWARFLocationExpression> loc) {776 if (!loc) {777 LLDB_LOG_ERROR(log, loc.takeError(), "{0}");778 return true;779 }780 auto buffer_sp =781 std::make_shared<DataBufferHeap>(loc->Expr.data(), loc->Expr.size());782 DWARFExpression expr = DWARFExpression(DataExtractor(783 buffer_sp, data.GetByteOrder(), data.GetAddressByteSize()));784 location_list.AddExpression(loc->Range->LowPC, loc->Range->HighPC, expr);785 return true;786 };787 llvm::Error error = loctable_up->visitAbsoluteLocationList(788 0, llvm::object::SectionedAddress{GetBaseAddress()}, lookup_addr,789 process_list);790 location_list.Sort();791 if (error) {792 LLDB_LOG_ERROR(log, std::move(error), "{0}");793 return false;794 }795 return true;796}797 798DWARFUnit &DWARFUnit::GetNonSkeletonUnit() {799 ExtractUnitDIEIfNeeded();800 if (m_dwo)801 return *m_dwo;802 return *this;803}804 805uint8_t DWARFUnit::GetAddressByteSize(const DWARFUnit *cu) {806 if (cu)807 return cu->GetAddressByteSize();808 return DWARFUnit::GetDefaultAddressSize();809}810 811uint8_t DWARFUnit::GetDefaultAddressSize() { return 4; }812 813DWARFCompileUnit *DWARFUnit::GetSkeletonUnit() {814 if (m_skeleton_unit.load() == nullptr && IsDWOUnit()) {815 SymbolFileDWARFDwo *dwo =816 llvm::dyn_cast_or_null<SymbolFileDWARFDwo>(&GetSymbolFileDWARF());817 // Do a reverse lookup if the skeleton compile unit wasn't set.818 DWARFUnit *candidate_skeleton_unit =819 dwo ? dwo->GetBaseSymbolFile().GetSkeletonUnit(this) : nullptr;820 if (candidate_skeleton_unit)821 (void)LinkToSkeletonUnit(*candidate_skeleton_unit);822 // Linking may fail due to a race, so be sure to return the actual value.823 }824 return llvm::dyn_cast_or_null<DWARFCompileUnit>(m_skeleton_unit.load());825}826 827bool DWARFUnit::LinkToSkeletonUnit(DWARFUnit &skeleton_unit) {828 DWARFUnit *expected_unit = nullptr;829 if (m_skeleton_unit.compare_exchange_strong(expected_unit, &skeleton_unit))830 return true;831 if (expected_unit == &skeleton_unit) {832 // Exchange failed because it already contained the right value.833 return true;834 }835 return false; // Already linked to a different unit.836}837 838bool DWARFUnit::Supports_unnamed_objc_bitfields() {839 if (GetProducer() == eProducerClang)840 return GetProducerVersion() >= llvm::VersionTuple(425, 0, 13);841 // Assume all other compilers didn't have incorrect ObjC bitfield info.842 return true;843}844 845void DWARFUnit::ParseProducerInfo() {846 m_producer = eProducerOther;847 const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly();848 if (!die)849 return;850 851 llvm::StringRef producer(852 die->GetAttributeValueAsString(this, DW_AT_producer, nullptr));853 if (producer.empty())854 return;855 856 static const RegularExpression g_swiftlang_version_regex(857 llvm::StringRef(R"(swiftlang-([0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?))"));858 static const RegularExpression g_clang_version_regex(859 llvm::StringRef(R"(clang-([0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?))"));860 861 llvm::SmallVector<llvm::StringRef, 3> matches;862 if (g_swiftlang_version_regex.Execute(producer, &matches)) {863 m_producer_version.tryParse(matches[1]);864 m_producer = eProducerSwift;865 } else if (producer.contains("clang")) {866 if (g_clang_version_regex.Execute(producer, &matches))867 m_producer_version.tryParse(matches[1]);868 m_producer = eProducerClang;869 } else if (producer.contains("GNU")) {870 m_producer = eProducerGCC;871 }872}873 874DWARFProducer DWARFUnit::GetProducer() {875 if (m_producer == eProducerInvalid)876 ParseProducerInfo();877 return m_producer;878}879 880llvm::VersionTuple DWARFUnit::GetProducerVersion() {881 if (m_producer_version.empty())882 ParseProducerInfo();883 return m_producer_version;884}885 886uint64_t DWARFUnit::GetDWARFLanguageType() {887 if (m_language_type)888 return *m_language_type;889 890 const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly();891 if (!die)892 m_language_type = 0;893 else894 m_language_type = die->GetAttributeValueAsUnsigned(this, DW_AT_language, 0);895 return *m_language_type;896}897 898bool DWARFUnit::GetIsOptimized() {899 if (m_is_optimized == eLazyBoolCalculate) {900 const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly();901 if (die) {902 m_is_optimized = eLazyBoolNo;903 if (die->GetAttributeValueAsUnsigned(this, DW_AT_APPLE_optimized, 0) ==904 1) {905 m_is_optimized = eLazyBoolYes;906 }907 }908 }909 return m_is_optimized == eLazyBoolYes;910}911 912FileSpec::Style DWARFUnit::GetPathStyle() {913 if (!m_comp_dir)914 ComputeCompDirAndGuessPathStyle();915 return m_comp_dir->GetPathStyle();916}917 918const FileSpec &DWARFUnit::GetCompilationDirectory() {919 if (!m_comp_dir)920 ComputeCompDirAndGuessPathStyle();921 return *m_comp_dir;922}923 924const FileSpec &DWARFUnit::GetAbsolutePath() {925 if (!m_file_spec)926 ComputeAbsolutePath();927 return *m_file_spec;928}929 930FileSpec DWARFUnit::GetFile(size_t file_idx) {931 return m_dwarf.GetFile(*this, file_idx);932}933 934// DWARF2/3 suggests the form hostname:pathname for compilation directory.935// Remove the host part if present.936static llvm::StringRef937removeHostnameFromPathname(llvm::StringRef path_from_dwarf) {938 if (!path_from_dwarf.contains(':'))939 return path_from_dwarf;940 llvm::StringRef host, path;941 std::tie(host, path) = path_from_dwarf.split(':');942 943 if (host.contains('/'))944 return path_from_dwarf;945 946 // check whether we have a windows path, and so the first character is a947 // drive-letter not a hostname.948 if (host.size() == 1 && llvm::isAlpha(host[0]) &&949 (path.starts_with("\\") || path.starts_with("/")))950 return path_from_dwarf;951 952 return path;953}954 955void DWARFUnit::ComputeCompDirAndGuessPathStyle() {956 m_comp_dir = FileSpec();957 const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly();958 if (!die)959 return;960 961 llvm::StringRef comp_dir = removeHostnameFromPathname(962 die->GetAttributeValueAsString(this, DW_AT_comp_dir, nullptr));963 if (!comp_dir.empty()) {964 FileSpec::Style comp_dir_style =965 FileSpec::GuessPathStyle(comp_dir).value_or(FileSpec::Style::native);966 m_comp_dir = FileSpec(comp_dir, comp_dir_style);967 } else {968 // Try to detect the style based on the DW_AT_name attribute, but just store969 // the detected style in the m_comp_dir field.970 const char *name =971 die->GetAttributeValueAsString(this, DW_AT_name, nullptr);972 m_comp_dir = FileSpec(973 "", FileSpec::GuessPathStyle(name).value_or(FileSpec::Style::native));974 }975}976 977void DWARFUnit::ComputeAbsolutePath() {978 m_file_spec = FileSpec();979 const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly();980 if (!die)981 return;982 983 m_file_spec =984 FileSpec(die->GetAttributeValueAsString(this, DW_AT_name, nullptr),985 GetPathStyle());986 987 if (m_file_spec->IsRelative())988 m_file_spec->MakeAbsolute(GetCompilationDirectory());989}990 991SymbolFileDWARFDwo *DWARFUnit::GetDwoSymbolFile(bool load_all_debug_info) {992 if (load_all_debug_info)993 ExtractUnitDIEIfNeeded();994 if (m_dwo)995 return &llvm::cast<SymbolFileDWARFDwo>(m_dwo->GetSymbolFileDWARF());996 return nullptr;997}998 999const DWARFDebugAranges &DWARFUnit::GetFunctionAranges() {1000 if (m_func_aranges_up == nullptr) {1001 m_func_aranges_up = std::make_unique<DWARFDebugAranges>();1002 const DWARFDebugInfoEntry *die = DIEPtr();1003 if (die)1004 die->BuildFunctionAddressRangeTable(this, m_func_aranges_up.get());1005 1006 if (m_dwo) {1007 const DWARFDebugInfoEntry *dwo_die = m_dwo->DIEPtr();1008 if (dwo_die)1009 dwo_die->BuildFunctionAddressRangeTable(m_dwo.get(),1010 m_func_aranges_up.get());1011 }1012 1013 const bool minimize = false;1014 m_func_aranges_up->Sort(minimize);1015 }1016 return *m_func_aranges_up;1017}1018 1019llvm::Expected<DWARFUnitSP>1020DWARFUnit::extract(SymbolFileDWARF &dwarf, user_id_t uid,1021 const DWARFDataExtractor &debug_info,1022 DIERef::Section section, lldb::offset_t *offset_ptr) {1023 assert(debug_info.ValidOffset(*offset_ptr));1024 1025 DWARFContext &context = dwarf.GetDWARFContext();1026 1027 // FIXME: Either properly map between DIERef::Section and1028 // llvm::DWARFSectionKind or switch to llvm's definition entirely.1029 llvm::DWARFSectionKind section_kind_llvm =1030 section == DIERef::Section::DebugInfo1031 ? llvm::DWARFSectionKind::DW_SECT_INFO1032 : llvm::DWARFSectionKind::DW_SECT_EXT_TYPES;1033 1034 llvm::DWARFDataExtractor debug_info_llvm = debug_info.GetAsLLVMDWARF();1035 llvm::DWARFUnitHeader header;1036 if (llvm::Error extract_err = header.extract(1037 context.GetAsLLVM(), debug_info_llvm, offset_ptr, section_kind_llvm))1038 return std::move(extract_err);1039 1040 if (context.isDwo()) {1041 const llvm::DWARFUnitIndex::Entry *entry = nullptr;1042 const llvm::DWARFUnitIndex &index = header.isTypeUnit()1043 ? context.GetAsLLVM().getTUIndex()1044 : context.GetAsLLVM().getCUIndex();1045 if (index) {1046 if (header.isTypeUnit())1047 entry = index.getFromHash(header.getTypeHash());1048 else if (auto dwo_id = header.getDWOId())1049 entry = index.getFromHash(*dwo_id);1050 }1051 if (!entry)1052 entry = index.getFromOffset(header.getOffset());1053 if (entry)1054 if (llvm::Error err = header.applyIndexEntry(entry))1055 return std::move(err);1056 }1057 1058 const llvm::DWARFDebugAbbrev *abbr = dwarf.DebugAbbrev();1059 if (!abbr)1060 return llvm::make_error<llvm::object::GenericBinaryError>(1061 "No debug_abbrev data");1062 1063 bool abbr_offset_OK =1064 dwarf.GetDWARFContext().getOrLoadAbbrevData().ValidOffset(1065 header.getAbbrOffset());1066 if (!abbr_offset_OK)1067 return llvm::make_error<llvm::object::GenericBinaryError>(1068 "Abbreviation offset for unit is not valid");1069 1070 llvm::Expected<const llvm::DWARFAbbreviationDeclarationSet *> abbrevs_or_err =1071 abbr->getAbbreviationDeclarationSet(header.getAbbrOffset());1072 if (!abbrevs_or_err)1073 return abbrevs_or_err.takeError();1074 1075 const llvm::DWARFAbbreviationDeclarationSet *abbrevs = *abbrevs_or_err;1076 if (!abbrevs)1077 return llvm::make_error<llvm::object::GenericBinaryError>(1078 "No abbrev exists at the specified offset.");1079 1080 bool is_dwo = dwarf.GetDWARFContext().isDwo();1081 if (header.isTypeUnit())1082 return DWARFUnitSP(1083 new DWARFTypeUnit(dwarf, uid, header, *abbrevs, section, is_dwo));1084 return DWARFUnitSP(1085 new DWARFCompileUnit(dwarf, uid, header, *abbrevs, section, is_dwo));1086}1087 1088const lldb_private::DWARFDataExtractor &DWARFUnit::GetData() const {1089 return m_section == DIERef::Section::DebugTypes1090 ? m_dwarf.GetDWARFContext().getOrLoadDebugTypesData()1091 : m_dwarf.GetDWARFContext().getOrLoadDebugInfoData();1092}1093 1094uint32_t DWARFUnit::GetHeaderByteSize() const { return m_header.getSize(); }1095 1096std::optional<uint64_t>1097DWARFUnit::GetStringOffsetSectionItem(uint32_t index) const {1098 lldb::offset_t offset = GetStrOffsetsBase() + index * m_str_offset_size;1099 return m_dwarf.GetDWARFContext().getOrLoadStrOffsetsData().GetMaxU64(1100 &offset, m_str_offset_size);1101}1102 1103llvm::Expected<llvm::DWARFAddressRangesVector>1104DWARFUnit::FindRnglistFromOffset(dw_offset_t offset) {1105 if (GetVersion() <= 4) {1106 llvm::DWARFDataExtractor data =1107 m_dwarf.GetDWARFContext().getOrLoadRangesData().GetAsLLVMDWARF();1108 data.setAddressSize(m_header.getAddressByteSize());1109 1110 llvm::DWARFDebugRangeList list;1111 if (llvm::Error e = list.extract(data, &offset))1112 return e;1113 return list.getAbsoluteRanges(1114 llvm::object::SectionedAddress{GetBaseAddress()});1115 }1116 1117 // DWARF >= v51118 if (!GetRnglistTable())1119 return llvm::createStringError(std::errc::invalid_argument,1120 "missing or invalid range list table");1121 1122 llvm::DWARFDataExtractor data = GetRnglistData().GetAsLLVMDWARF();1123 1124 // As DW_AT_rnglists_base may be missing we need to call setAddressSize.1125 data.setAddressSize(m_header.getAddressByteSize());1126 auto range_list_or_error = GetRnglistTable()->findList(data, offset);1127 if (!range_list_or_error)1128 return range_list_or_error.takeError();1129 1130 return range_list_or_error->getAbsoluteRanges(1131 llvm::object::SectionedAddress{GetBaseAddress()}, GetAddressByteSize(),1132 [&](uint32_t index) {1133 uint32_t index_size = GetAddressByteSize();1134 dw_offset_t addr_base = GetAddrBase();1135 lldb::offset_t offset =1136 addr_base + static_cast<lldb::offset_t>(index) * index_size;1137 return llvm::object::SectionedAddress{1138 m_dwarf.GetDWARFContext().getOrLoadAddrData().GetMaxU64(1139 &offset, index_size)};1140 });1141}1142 1143llvm::Expected<llvm::DWARFAddressRangesVector>1144DWARFUnit::FindRnglistFromIndex(uint32_t index) {1145 llvm::Expected<uint64_t> maybe_offset = GetRnglistOffset(index);1146 if (!maybe_offset)1147 return maybe_offset.takeError();1148 return FindRnglistFromOffset(*maybe_offset);1149}1150 1151bool DWARFUnit::HasAny(llvm::ArrayRef<dw_tag_t> tags) {1152 ExtractUnitDIEIfNeeded();1153 if (m_dwo)1154 return m_dwo->HasAny(tags);1155 1156 for (const auto &die : m_die_array) {1157 for (const auto tag : tags) {1158 if (tag == die.Tag())1159 return true;1160 }1161 }1162 return false;1163}1164