Path: blob/main/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
39644 views
//===-- DWARFUnit.cpp -----------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "DWARFUnit.h"910#include "lldb/Core/Module.h"11#include "lldb/Symbol/ObjectFile.h"12#include "lldb/Utility/LLDBAssert.h"13#include "lldb/Utility/StreamString.h"14#include "lldb/Utility/Timer.h"15#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"16#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"17#include "llvm/Object/Error.h"1819#include "DWARFCompileUnit.h"20#include "DWARFDebugAranges.h"21#include "DWARFDebugInfo.h"22#include "DWARFTypeUnit.h"23#include "LogChannelDWARF.h"24#include "SymbolFileDWARFDwo.h"25#include <optional>2627using namespace lldb;28using namespace lldb_private;29using namespace lldb_private::dwarf;30using namespace lldb_private::plugin::dwarf;3132extern int g_verbose;3334DWARFUnit::DWARFUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid,35const llvm::DWARFUnitHeader &header,36const llvm::DWARFAbbreviationDeclarationSet &abbrevs,37DIERef::Section section, bool is_dwo)38: UserID(uid), m_dwarf(dwarf), m_header(header), m_abbrevs(&abbrevs),39m_cancel_scopes(false), m_section(section), m_is_dwo(is_dwo),40m_has_parsed_non_skeleton_unit(false), m_dwo_id(header.getDWOId()) {}4142DWARFUnit::~DWARFUnit() = default;4344// Parses first DIE of a compile unit, excluding DWO.45void DWARFUnit::ExtractUnitDIENoDwoIfNeeded() {46{47llvm::sys::ScopedReader lock(m_first_die_mutex);48if (m_first_die)49return; // Already parsed50}51llvm::sys::ScopedWriter lock(m_first_die_mutex);52if (m_first_die)53return; // Already parsed5455ElapsedTime elapsed(m_dwarf.GetDebugInfoParseTimeRef());5657// Set the offset to that of the first DIE and calculate the start of the58// next compilation unit header.59lldb::offset_t offset = GetFirstDIEOffset();6061// We are in our compile unit, parse starting at the offset we were told to62// parse63const DWARFDataExtractor &data = GetData();64if (offset < GetNextUnitOffset() &&65m_first_die.Extract(data, *this, &offset)) {66AddUnitDIE(m_first_die);67return;68}69}7071// Parses first DIE of a compile unit including DWO.72void DWARFUnit::ExtractUnitDIEIfNeeded() {73ExtractUnitDIENoDwoIfNeeded();7475if (m_has_parsed_non_skeleton_unit)76return;7778m_has_parsed_non_skeleton_unit = true;79m_dwo_error.Clear();8081if (!m_dwo_id)82return; // No DWO file.8384std::shared_ptr<SymbolFileDWARFDwo> dwo_symbol_file =85m_dwarf.GetDwoSymbolFileForCompileUnit(*this, m_first_die);86if (!dwo_symbol_file)87return;8889DWARFUnit *dwo_cu = dwo_symbol_file->GetDWOCompileUnitForHash(*m_dwo_id);9091if (!dwo_cu) {92SetDwoError(Status::createWithFormat(93"unable to load .dwo file from \"{0}\" due to ID ({1:x16}) mismatch "94"for skeleton DIE at {2:x8}",95dwo_symbol_file->GetObjectFile()->GetFileSpec().GetPath().c_str(),96*m_dwo_id, m_first_die.GetOffset()));97return; // Can't fetch the compile unit from the dwo file.98}99// If the skeleton compile unit gets its unit DIE parsed first, then this100// will fill in the DWO file's back pointer to this skeleton compile unit.101// If the DWO files get parsed on their own first the skeleton back link102// can be done manually in DWARFUnit::GetSkeletonCompileUnit() which will103// do a reverse lookup and cache the result.104dwo_cu->SetSkeletonUnit(this);105106DWARFBaseDIE dwo_cu_die = dwo_cu->GetUnitDIEOnly();107if (!dwo_cu_die.IsValid()) {108// Can't fetch the compile unit DIE from the dwo file.109SetDwoError(Status::createWithFormat(110"unable to extract compile unit DIE from .dwo file for skeleton "111"DIE at {0:x16}",112m_first_die.GetOffset()));113return;114}115116// Here for DWO CU we want to use the address base set in the skeleton unit117// (DW_AT_addr_base) if it is available and use the DW_AT_GNU_addr_base118// otherwise. We do that because pre-DWARF v5 could use the DW_AT_GNU_*119// attributes which were applicable to the DWO units. The corresponding120// DW_AT_* attributes standardized in DWARF v5 are also applicable to the121// main unit in contrast.122if (m_addr_base)123dwo_cu->SetAddrBase(*m_addr_base);124else if (m_gnu_addr_base)125dwo_cu->SetAddrBase(*m_gnu_addr_base);126127if (GetVersion() <= 4 && m_gnu_ranges_base)128dwo_cu->SetRangesBase(*m_gnu_ranges_base);129else if (dwo_symbol_file->GetDWARFContext()130.getOrLoadRngListsData()131.GetByteSize() > 0)132dwo_cu->SetRangesBase(llvm::DWARFListTableHeader::getHeaderSize(DWARF32));133134if (GetVersion() >= 5 &&135dwo_symbol_file->GetDWARFContext().getOrLoadLocListsData().GetByteSize() >1360)137dwo_cu->SetLoclistsBase(llvm::DWARFListTableHeader::getHeaderSize(DWARF32));138139dwo_cu->SetBaseAddress(GetBaseAddress());140141m_dwo = std::shared_ptr<DWARFUnit>(std::move(dwo_symbol_file), dwo_cu);142}143144// Parses a compile unit and indexes its DIEs if it hasn't already been done.145// It will leave this compile unit extracted forever.146void DWARFUnit::ExtractDIEsIfNeeded() {147m_cancel_scopes = true;148149{150llvm::sys::ScopedReader lock(m_die_array_mutex);151if (!m_die_array.empty())152return; // Already parsed153}154llvm::sys::ScopedWriter lock(m_die_array_mutex);155if (!m_die_array.empty())156return; // Already parsed157158ExtractDIEsRWLocked();159}160161// Parses a compile unit and indexes its DIEs if it hasn't already been done.162// It will clear this compile unit after returned instance gets out of scope,163// no other ScopedExtractDIEs instance is running for this compile unit164// and no ExtractDIEsIfNeeded() has been executed during this ScopedExtractDIEs165// lifetime.166DWARFUnit::ScopedExtractDIEs DWARFUnit::ExtractDIEsScoped() {167ScopedExtractDIEs scoped(*this);168169{170llvm::sys::ScopedReader lock(m_die_array_mutex);171if (!m_die_array.empty())172return scoped; // Already parsed173}174llvm::sys::ScopedWriter lock(m_die_array_mutex);175if (!m_die_array.empty())176return scoped; // Already parsed177178// Otherwise m_die_array would be already populated.179lldbassert(!m_cancel_scopes);180181ExtractDIEsRWLocked();182scoped.m_clear_dies = true;183return scoped;184}185186DWARFUnit::ScopedExtractDIEs::ScopedExtractDIEs(DWARFUnit &cu) : m_cu(&cu) {187m_cu->m_die_array_scoped_mutex.lock_shared();188}189190DWARFUnit::ScopedExtractDIEs::~ScopedExtractDIEs() {191if (!m_cu)192return;193m_cu->m_die_array_scoped_mutex.unlock_shared();194if (!m_clear_dies || m_cu->m_cancel_scopes)195return;196// Be sure no other ScopedExtractDIEs is running anymore.197llvm::sys::ScopedWriter lock_scoped(m_cu->m_die_array_scoped_mutex);198llvm::sys::ScopedWriter lock(m_cu->m_die_array_mutex);199if (m_cu->m_cancel_scopes)200return;201m_cu->ClearDIEsRWLocked();202}203204DWARFUnit::ScopedExtractDIEs::ScopedExtractDIEs(ScopedExtractDIEs &&rhs)205: m_cu(rhs.m_cu), m_clear_dies(rhs.m_clear_dies) {206rhs.m_cu = nullptr;207}208209DWARFUnit::ScopedExtractDIEs &210DWARFUnit::ScopedExtractDIEs::operator=(DWARFUnit::ScopedExtractDIEs &&rhs) {211m_cu = rhs.m_cu;212rhs.m_cu = nullptr;213m_clear_dies = rhs.m_clear_dies;214return *this;215}216217// Parses a compile unit and indexes its DIEs, m_die_array_mutex must be218// held R/W and m_die_array must be empty.219void DWARFUnit::ExtractDIEsRWLocked() {220llvm::sys::ScopedWriter first_die_lock(m_first_die_mutex);221222ElapsedTime elapsed(m_dwarf.GetDebugInfoParseTimeRef());223LLDB_SCOPED_TIMERF(224"%s",225llvm::formatv("{0:x16}: DWARFUnit::ExtractDIEsIfNeeded()", GetOffset())226.str()227.c_str());228229// Set the offset to that of the first DIE and calculate the start of the230// next compilation unit header.231lldb::offset_t offset = GetFirstDIEOffset();232lldb::offset_t next_cu_offset = GetNextUnitOffset();233234DWARFDebugInfoEntry die;235236uint32_t depth = 0;237// We are in our compile unit, parse starting at the offset we were told to238// parse239const DWARFDataExtractor &data = GetData();240std::vector<uint32_t> die_index_stack;241die_index_stack.reserve(32);242die_index_stack.push_back(0);243bool prev_die_had_children = false;244while (offset < next_cu_offset && die.Extract(data, *this, &offset)) {245const bool null_die = die.IsNULL();246if (depth == 0) {247assert(m_die_array.empty() && "Compile unit DIE already added");248249// The average bytes per DIE entry has been seen to be around 14-20 so250// lets pre-reserve half of that since we are now stripping the NULL251// tags.252253// Only reserve the memory if we are adding children of the main254// compile unit DIE. The compile unit DIE is always the first entry, so255// if our size is 1, then we are adding the first compile unit child256// DIE and should reserve the memory.257m_die_array.reserve(GetDebugInfoSize() / 24);258m_die_array.push_back(die);259260if (!m_first_die)261AddUnitDIE(m_die_array.front());262263// With -fsplit-dwarf-inlining, clang will emit non-empty skeleton compile264// units. We are not able to access these DIE *and* the dwo file265// simultaneously. We also don't need to do that as the dwo file will266// contain a superset of information. So, we don't even attempt to parse267// any remaining DIEs.268if (m_dwo) {269m_die_array.front().SetHasChildren(false);270break;271}272273} else {274if (null_die) {275if (prev_die_had_children) {276// This will only happen if a DIE says is has children but all it277// contains is a NULL tag. Since we are removing the NULL DIEs from278// the list (saves up to 25% in C++ code), we need a way to let the279// DIE know that it actually doesn't have children.280if (!m_die_array.empty())281m_die_array.back().SetHasChildren(false);282}283} else {284die.SetParentIndex(m_die_array.size() - die_index_stack[depth - 1]);285286if (die_index_stack.back())287m_die_array[die_index_stack.back()].SetSiblingIndex(288m_die_array.size() - die_index_stack.back());289290// Only push the DIE if it isn't a NULL DIE291m_die_array.push_back(die);292}293}294295if (null_die) {296// NULL DIE.297if (!die_index_stack.empty())298die_index_stack.pop_back();299300if (depth > 0)301--depth;302prev_die_had_children = false;303} else {304die_index_stack.back() = m_die_array.size() - 1;305// Normal DIE306const bool die_has_children = die.HasChildren();307if (die_has_children) {308die_index_stack.push_back(0);309++depth;310}311prev_die_had_children = die_has_children;312}313314if (depth == 0)315break; // We are done with this compile unit!316}317318if (!m_die_array.empty()) {319// The last die cannot have children (if it did, it wouldn't be the last320// one). This only makes a difference for malformed dwarf that does not have321// a terminating null die.322m_die_array.back().SetHasChildren(false);323324if (m_first_die) {325// Only needed for the assertion.326m_first_die.SetHasChildren(m_die_array.front().HasChildren());327lldbassert(m_first_die == m_die_array.front());328}329m_first_die = m_die_array.front();330}331332m_die_array.shrink_to_fit();333334if (m_dwo)335m_dwo->ExtractDIEsIfNeeded();336}337338// This is used when a split dwarf is enabled.339// A skeleton compilation unit may contain the DW_AT_str_offsets_base attribute340// that points to the first string offset of the CU contribution to the341// .debug_str_offsets. At the same time, the corresponding split debug unit also342// may use DW_FORM_strx* forms pointing to its own .debug_str_offsets.dwo and343// for that case, we should find the offset (skip the section header).344void DWARFUnit::SetDwoStrOffsetsBase() {345lldb::offset_t baseOffset = 0;346347if (const llvm::DWARFUnitIndex::Entry *entry = m_header.getIndexEntry()) {348if (const auto *contribution =349entry->getContribution(llvm::DW_SECT_STR_OFFSETS))350baseOffset = contribution->getOffset();351else352return;353}354355if (GetVersion() >= 5) {356const DWARFDataExtractor &strOffsets =357GetSymbolFileDWARF().GetDWARFContext().getOrLoadStrOffsetsData();358uint64_t length = strOffsets.GetU32(&baseOffset);359if (length == 0xffffffff)360length = strOffsets.GetU64(&baseOffset);361362// Check version.363if (strOffsets.GetU16(&baseOffset) < 5)364return;365366// Skip padding.367baseOffset += 2;368}369370SetStrOffsetsBase(baseOffset);371}372373std::optional<uint64_t> DWARFUnit::GetDWOId() {374ExtractUnitDIENoDwoIfNeeded();375return m_dwo_id;376}377378// m_die_array_mutex must be already held as read/write.379void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) {380DWARFAttributes attributes = cu_die.GetAttributes(this);381382// Extract DW_AT_addr_base first, as other attributes may need it.383for (size_t i = 0; i < attributes.Size(); ++i) {384if (attributes.AttributeAtIndex(i) != DW_AT_addr_base)385continue;386DWARFFormValue form_value;387if (attributes.ExtractFormValueAtIndex(i, form_value)) {388SetAddrBase(form_value.Unsigned());389break;390}391}392393for (size_t i = 0; i < attributes.Size(); ++i) {394dw_attr_t attr = attributes.AttributeAtIndex(i);395DWARFFormValue form_value;396if (!attributes.ExtractFormValueAtIndex(i, form_value))397continue;398switch (attr) {399default:400break;401case DW_AT_loclists_base:402SetLoclistsBase(form_value.Unsigned());403break;404case DW_AT_rnglists_base:405SetRangesBase(form_value.Unsigned());406break;407case DW_AT_str_offsets_base:408SetStrOffsetsBase(form_value.Unsigned());409break;410case DW_AT_low_pc:411SetBaseAddress(form_value.Address());412break;413case DW_AT_entry_pc:414// If the value was already set by DW_AT_low_pc, don't update it.415if (m_base_addr == LLDB_INVALID_ADDRESS)416SetBaseAddress(form_value.Address());417break;418case DW_AT_stmt_list:419m_line_table_offset = form_value.Unsigned();420break;421case DW_AT_GNU_addr_base:422m_gnu_addr_base = form_value.Unsigned();423break;424case DW_AT_GNU_ranges_base:425m_gnu_ranges_base = form_value.Unsigned();426break;427case DW_AT_GNU_dwo_id:428m_dwo_id = form_value.Unsigned();429break;430}431}432433if (m_is_dwo) {434m_has_parsed_non_skeleton_unit = true;435SetDwoStrOffsetsBase();436return;437}438}439440size_t DWARFUnit::GetDebugInfoSize() const {441return GetLengthByteSize() + GetLength() - GetHeaderByteSize();442}443444const llvm::DWARFAbbreviationDeclarationSet *445DWARFUnit::GetAbbreviations() const {446return m_abbrevs;447}448449dw_offset_t DWARFUnit::GetAbbrevOffset() const {450return m_abbrevs ? m_abbrevs->getOffset() : DW_INVALID_OFFSET;451}452453dw_offset_t DWARFUnit::GetLineTableOffset() {454ExtractUnitDIENoDwoIfNeeded();455return m_line_table_offset;456}457458void DWARFUnit::SetAddrBase(dw_addr_t addr_base) { m_addr_base = addr_base; }459460// Parse the rangelist table header, including the optional array of offsets461// following it (DWARF v5 and later).462template <typename ListTableType>463static llvm::Expected<ListTableType>464ParseListTableHeader(const llvm::DWARFDataExtractor &data, uint64_t offset,465DwarfFormat format) {466// We are expected to be called with Offset 0 or pointing just past the table467// header. Correct Offset in the latter case so that it points to the start468// of the header.469if (offset == 0) {470// This means DW_AT_rnglists_base is missing and therefore DW_FORM_rnglistx471// cannot be handled. Returning a default-constructed ListTableType allows472// DW_FORM_sec_offset to be supported.473return ListTableType();474}475476uint64_t HeaderSize = llvm::DWARFListTableHeader::getHeaderSize(format);477if (offset < HeaderSize)478return llvm::createStringError(std::errc::invalid_argument,479"did not detect a valid"480" list table with base = 0x%" PRIx64 "\n",481offset);482offset -= HeaderSize;483ListTableType Table;484if (llvm::Error E = Table.extractHeaderAndOffsets(data, &offset))485return std::move(E);486return Table;487}488489void DWARFUnit::SetLoclistsBase(dw_addr_t loclists_base) {490uint64_t offset = 0;491if (const llvm::DWARFUnitIndex::Entry *entry = m_header.getIndexEntry()) {492const auto *contribution = entry->getContribution(llvm::DW_SECT_LOCLISTS);493if (!contribution) {494GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(495"Failed to find location list contribution for CU with DWO Id "496"{0:x16}",497*GetDWOId());498return;499}500offset += contribution->getOffset();501}502m_loclists_base = loclists_base;503504uint64_t header_size = llvm::DWARFListTableHeader::getHeaderSize(DWARF32);505if (loclists_base < header_size)506return;507508m_loclist_table_header.emplace(".debug_loclists", "locations");509offset += loclists_base - header_size;510if (llvm::Error E = m_loclist_table_header->extract(511m_dwarf.GetDWARFContext().getOrLoadLocListsData().GetAsLLVMDWARF(),512&offset)) {513GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(514"Failed to extract location list table at offset {0:x16} (location "515"list base: {1:x16}): {2}",516offset, loclists_base, toString(std::move(E)).c_str());517}518}519520std::unique_ptr<llvm::DWARFLocationTable>521DWARFUnit::GetLocationTable(const DataExtractor &data) const {522llvm::DWARFDataExtractor llvm_data(523data.GetData(), data.GetByteOrder() == lldb::eByteOrderLittle,524data.GetAddressByteSize());525526if (m_is_dwo || GetVersion() >= 5)527return std::make_unique<llvm::DWARFDebugLoclists>(llvm_data, GetVersion());528return std::make_unique<llvm::DWARFDebugLoc>(llvm_data);529}530531DWARFDataExtractor DWARFUnit::GetLocationData() const {532DWARFContext &Ctx = GetSymbolFileDWARF().GetDWARFContext();533const DWARFDataExtractor &data =534GetVersion() >= 5 ? Ctx.getOrLoadLocListsData() : Ctx.getOrLoadLocData();535if (const llvm::DWARFUnitIndex::Entry *entry = m_header.getIndexEntry()) {536if (const auto *contribution = entry->getContribution(537GetVersion() >= 5 ? llvm::DW_SECT_LOCLISTS : llvm::DW_SECT_EXT_LOC))538return DWARFDataExtractor(data, contribution->getOffset(),539contribution->getLength32());540return DWARFDataExtractor();541}542return data;543}544545DWARFDataExtractor DWARFUnit::GetRnglistData() const {546DWARFContext &Ctx = GetSymbolFileDWARF().GetDWARFContext();547const DWARFDataExtractor &data = Ctx.getOrLoadRngListsData();548if (const llvm::DWARFUnitIndex::Entry *entry = m_header.getIndexEntry()) {549if (const auto *contribution =550entry->getContribution(llvm::DW_SECT_RNGLISTS))551return DWARFDataExtractor(data, contribution->getOffset(),552contribution->getLength32());553GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(554"Failed to find range list contribution for CU with signature {0:x16}",555entry->getSignature());556557return DWARFDataExtractor();558}559return data;560}561562void DWARFUnit::SetRangesBase(dw_addr_t ranges_base) {563lldbassert(!m_rnglist_table_done);564565m_ranges_base = ranges_base;566}567568const std::optional<llvm::DWARFDebugRnglistTable> &569DWARFUnit::GetRnglistTable() {570if (GetVersion() >= 5 && !m_rnglist_table_done) {571m_rnglist_table_done = true;572if (auto table_or_error =573ParseListTableHeader<llvm::DWARFDebugRnglistTable>(574GetRnglistData().GetAsLLVMDWARF(), m_ranges_base, DWARF32))575m_rnglist_table = std::move(table_or_error.get());576else577GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(578"Failed to extract range list table at offset {0:x16}: {1}",579m_ranges_base, toString(table_or_error.takeError()).c_str());580}581return m_rnglist_table;582}583584// This function is called only for DW_FORM_rnglistx.585llvm::Expected<uint64_t> DWARFUnit::GetRnglistOffset(uint32_t Index) {586if (!GetRnglistTable())587return llvm::createStringError(std::errc::invalid_argument,588"missing or invalid range list table");589if (!m_ranges_base)590return llvm::createStringError(591std::errc::invalid_argument,592llvm::formatv("DW_FORM_rnglistx cannot be used without "593"DW_AT_rnglists_base for CU at {0:x16}",594GetOffset())595.str()596.c_str());597if (std::optional<uint64_t> off = GetRnglistTable()->getOffsetEntry(598GetRnglistData().GetAsLLVM(), Index))599return *off + m_ranges_base;600return llvm::createStringError(601std::errc::invalid_argument,602"invalid range list table index %u; OffsetEntryCount is %u, "603"DW_AT_rnglists_base is %" PRIu64,604Index, GetRnglistTable()->getOffsetEntryCount(), m_ranges_base);605}606607void DWARFUnit::SetStrOffsetsBase(dw_offset_t str_offsets_base) {608m_str_offsets_base = str_offsets_base;609}610611dw_addr_t DWARFUnit::ReadAddressFromDebugAddrSection(uint32_t index) const {612uint32_t index_size = GetAddressByteSize();613dw_offset_t addr_base = GetAddrBase();614dw_addr_t offset = addr_base + static_cast<dw_addr_t>(index) * index_size;615const DWARFDataExtractor &data =616m_dwarf.GetDWARFContext().getOrLoadAddrData();617if (data.ValidOffsetForDataOfSize(offset, index_size))618return data.GetMaxU64_unchecked(&offset, index_size);619return LLDB_INVALID_ADDRESS;620}621622// It may be called only with m_die_array_mutex held R/W.623void DWARFUnit::ClearDIEsRWLocked() {624m_die_array.clear();625m_die_array.shrink_to_fit();626627if (m_dwo && !m_dwo->m_cancel_scopes)628m_dwo->ClearDIEsRWLocked();629}630631lldb::ByteOrder DWARFUnit::GetByteOrder() const {632return m_dwarf.GetObjectFile()->GetByteOrder();633}634635void DWARFUnit::SetBaseAddress(dw_addr_t base_addr) { m_base_addr = base_addr; }636637// Compare function DWARFDebugAranges::Range structures638static bool CompareDIEOffset(const DWARFDebugInfoEntry &die,639const dw_offset_t die_offset) {640return die.GetOffset() < die_offset;641}642643// GetDIE()644//645// Get the DIE (Debug Information Entry) with the specified offset by first646// checking if the DIE is contained within this compile unit and grabbing the647// DIE from this compile unit. Otherwise we grab the DIE from the DWARF file.648DWARFDIE649DWARFUnit::GetDIE(dw_offset_t die_offset) {650if (die_offset == DW_INVALID_OFFSET)651return DWARFDIE(); // Not found652653if (!ContainsDIEOffset(die_offset)) {654GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(655"GetDIE for DIE {0:x16} is outside of its CU {0:x16}", die_offset,656GetOffset());657return DWARFDIE(); // Not found658}659660ExtractDIEsIfNeeded();661DWARFDebugInfoEntry::const_iterator end = m_die_array.cend();662DWARFDebugInfoEntry::const_iterator pos =663lower_bound(m_die_array.cbegin(), end, die_offset, CompareDIEOffset);664665if (pos != end && die_offset == (*pos).GetOffset())666return DWARFDIE(this, &(*pos));667return DWARFDIE(); // Not found668}669670llvm::StringRef DWARFUnit::PeekDIEName(dw_offset_t die_offset) {671DWARFDebugInfoEntry die;672if (!die.Extract(GetData(), *this, &die_offset))673return llvm::StringRef();674675// Does die contain a DW_AT_Name?676if (const char *name =677die.GetAttributeValueAsString(this, DW_AT_name, nullptr))678return name;679680// Does its DW_AT_specification or DW_AT_abstract_origin contain an AT_Name?681for (auto attr : {DW_AT_specification, DW_AT_abstract_origin}) {682DWARFFormValue form_value;683if (!die.GetAttributeValue(this, attr, form_value))684continue;685auto [unit, offset] = form_value.ReferencedUnitAndOffset();686if (unit)687if (auto name = unit->PeekDIEName(offset); !name.empty())688return name;689}690691return llvm::StringRef();692}693694DWARFUnit &DWARFUnit::GetNonSkeletonUnit() {695ExtractUnitDIEIfNeeded();696if (m_dwo)697return *m_dwo;698return *this;699}700701uint8_t DWARFUnit::GetAddressByteSize(const DWARFUnit *cu) {702if (cu)703return cu->GetAddressByteSize();704return DWARFUnit::GetDefaultAddressSize();705}706707uint8_t DWARFUnit::GetDefaultAddressSize() { return 4; }708709DWARFCompileUnit *DWARFUnit::GetSkeletonUnit() {710if (m_skeleton_unit == nullptr && IsDWOUnit()) {711SymbolFileDWARFDwo *dwo =712llvm::dyn_cast_or_null<SymbolFileDWARFDwo>(&GetSymbolFileDWARF());713// Do a reverse lookup if the skeleton compile unit wasn't set.714if (dwo)715m_skeleton_unit = dwo->GetBaseSymbolFile().GetSkeletonUnit(this);716}717return llvm::dyn_cast_or_null<DWARFCompileUnit>(m_skeleton_unit);718}719720void DWARFUnit::SetSkeletonUnit(DWARFUnit *skeleton_unit) {721// If someone is re-setting the skeleton compile unit backlink, make sure722// it is setting it to a valid value when it wasn't valid, or if the723// value in m_skeleton_unit was valid, it should be the same value.724assert(skeleton_unit);725assert(m_skeleton_unit == nullptr || m_skeleton_unit == skeleton_unit);726m_skeleton_unit = skeleton_unit;727}728729bool DWARFUnit::Supports_DW_AT_APPLE_objc_complete_type() {730return GetProducer() != eProducerLLVMGCC;731}732733bool DWARFUnit::DW_AT_decl_file_attributes_are_invalid() {734// llvm-gcc makes completely invalid decl file attributes and won't ever be735// fixed, so we need to know to ignore these.736return GetProducer() == eProducerLLVMGCC;737}738739bool DWARFUnit::Supports_unnamed_objc_bitfields() {740if (GetProducer() == eProducerClang)741return GetProducerVersion() >= llvm::VersionTuple(425, 0, 13);742// Assume all other compilers didn't have incorrect ObjC bitfield info.743return true;744}745746void DWARFUnit::ParseProducerInfo() {747m_producer = eProducerOther;748const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly();749if (!die)750return;751752llvm::StringRef producer(753die->GetAttributeValueAsString(this, DW_AT_producer, nullptr));754if (producer.empty())755return;756757static const RegularExpression g_swiftlang_version_regex(758llvm::StringRef(R"(swiftlang-([0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?))"));759static const RegularExpression g_clang_version_regex(760llvm::StringRef(R"(clang-([0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?))"));761static const RegularExpression g_llvm_gcc_regex(762llvm::StringRef(R"(4\.[012]\.[01] )"763R"(\(Based on Apple Inc\. build [0-9]+\) )"764R"(\(LLVM build [\.0-9]+\)$)"));765766llvm::SmallVector<llvm::StringRef, 3> matches;767if (g_swiftlang_version_regex.Execute(producer, &matches)) {768m_producer_version.tryParse(matches[1]);769m_producer = eProducerSwift;770} else if (producer.contains("clang")) {771if (g_clang_version_regex.Execute(producer, &matches))772m_producer_version.tryParse(matches[1]);773m_producer = eProducerClang;774} else if (producer.contains("GNU")) {775m_producer = eProducerGCC;776} else if (g_llvm_gcc_regex.Execute(producer)) {777m_producer = eProducerLLVMGCC;778}779}780781DWARFProducer DWARFUnit::GetProducer() {782if (m_producer == eProducerInvalid)783ParseProducerInfo();784return m_producer;785}786787llvm::VersionTuple DWARFUnit::GetProducerVersion() {788if (m_producer_version.empty())789ParseProducerInfo();790return m_producer_version;791}792793uint64_t DWARFUnit::GetDWARFLanguageType() {794if (m_language_type)795return *m_language_type;796797const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly();798if (!die)799m_language_type = 0;800else801m_language_type = die->GetAttributeValueAsUnsigned(this, DW_AT_language, 0);802return *m_language_type;803}804805bool DWARFUnit::GetIsOptimized() {806if (m_is_optimized == eLazyBoolCalculate) {807const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly();808if (die) {809m_is_optimized = eLazyBoolNo;810if (die->GetAttributeValueAsUnsigned(this, DW_AT_APPLE_optimized, 0) ==8111) {812m_is_optimized = eLazyBoolYes;813}814}815}816return m_is_optimized == eLazyBoolYes;817}818819FileSpec::Style DWARFUnit::GetPathStyle() {820if (!m_comp_dir)821ComputeCompDirAndGuessPathStyle();822return m_comp_dir->GetPathStyle();823}824825const FileSpec &DWARFUnit::GetCompilationDirectory() {826if (!m_comp_dir)827ComputeCompDirAndGuessPathStyle();828return *m_comp_dir;829}830831const FileSpec &DWARFUnit::GetAbsolutePath() {832if (!m_file_spec)833ComputeAbsolutePath();834return *m_file_spec;835}836837FileSpec DWARFUnit::GetFile(size_t file_idx) {838return m_dwarf.GetFile(*this, file_idx);839}840841// DWARF2/3 suggests the form hostname:pathname for compilation directory.842// Remove the host part if present.843static llvm::StringRef844removeHostnameFromPathname(llvm::StringRef path_from_dwarf) {845if (!path_from_dwarf.contains(':'))846return path_from_dwarf;847llvm::StringRef host, path;848std::tie(host, path) = path_from_dwarf.split(':');849850if (host.contains('/'))851return path_from_dwarf;852853// check whether we have a windows path, and so the first character is a854// drive-letter not a hostname.855if (host.size() == 1 && llvm::isAlpha(host[0]) &&856(path.starts_with("\\") || path.starts_with("/")))857return path_from_dwarf;858859return path;860}861862void DWARFUnit::ComputeCompDirAndGuessPathStyle() {863m_comp_dir = FileSpec();864const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly();865if (!die)866return;867868llvm::StringRef comp_dir = removeHostnameFromPathname(869die->GetAttributeValueAsString(this, DW_AT_comp_dir, nullptr));870if (!comp_dir.empty()) {871FileSpec::Style comp_dir_style =872FileSpec::GuessPathStyle(comp_dir).value_or(FileSpec::Style::native);873m_comp_dir = FileSpec(comp_dir, comp_dir_style);874} else {875// Try to detect the style based on the DW_AT_name attribute, but just store876// the detected style in the m_comp_dir field.877const char *name =878die->GetAttributeValueAsString(this, DW_AT_name, nullptr);879m_comp_dir = FileSpec(880"", FileSpec::GuessPathStyle(name).value_or(FileSpec::Style::native));881}882}883884void DWARFUnit::ComputeAbsolutePath() {885m_file_spec = FileSpec();886const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly();887if (!die)888return;889890m_file_spec =891FileSpec(die->GetAttributeValueAsString(this, DW_AT_name, nullptr),892GetPathStyle());893894if (m_file_spec->IsRelative())895m_file_spec->MakeAbsolute(GetCompilationDirectory());896}897898SymbolFileDWARFDwo *DWARFUnit::GetDwoSymbolFile(bool load_all_debug_info) {899if (load_all_debug_info)900ExtractUnitDIEIfNeeded();901if (m_dwo)902return &llvm::cast<SymbolFileDWARFDwo>(m_dwo->GetSymbolFileDWARF());903return nullptr;904}905906const DWARFDebugAranges &DWARFUnit::GetFunctionAranges() {907if (m_func_aranges_up == nullptr) {908m_func_aranges_up = std::make_unique<DWARFDebugAranges>();909const DWARFDebugInfoEntry *die = DIEPtr();910if (die)911die->BuildFunctionAddressRangeTable(this, m_func_aranges_up.get());912913if (m_dwo) {914const DWARFDebugInfoEntry *dwo_die = m_dwo->DIEPtr();915if (dwo_die)916dwo_die->BuildFunctionAddressRangeTable(m_dwo.get(),917m_func_aranges_up.get());918}919920const bool minimize = false;921m_func_aranges_up->Sort(minimize);922}923return *m_func_aranges_up;924}925926llvm::Expected<DWARFUnitSP>927DWARFUnit::extract(SymbolFileDWARF &dwarf, user_id_t uid,928const DWARFDataExtractor &debug_info,929DIERef::Section section, lldb::offset_t *offset_ptr) {930assert(debug_info.ValidOffset(*offset_ptr));931932DWARFContext &context = dwarf.GetDWARFContext();933934// FIXME: Either properly map between DIERef::Section and935// llvm::DWARFSectionKind or switch to llvm's definition entirely.936llvm::DWARFSectionKind section_kind_llvm =937section == DIERef::Section::DebugInfo938? llvm::DWARFSectionKind::DW_SECT_INFO939: llvm::DWARFSectionKind::DW_SECT_EXT_TYPES;940941llvm::DWARFDataExtractor debug_info_llvm = debug_info.GetAsLLVMDWARF();942llvm::DWARFUnitHeader header;943if (llvm::Error extract_err = header.extract(944context.GetAsLLVM(), debug_info_llvm, offset_ptr, section_kind_llvm))945return std::move(extract_err);946947if (context.isDwo()) {948const llvm::DWARFUnitIndex::Entry *entry = nullptr;949const llvm::DWARFUnitIndex &index = header.isTypeUnit()950? context.GetAsLLVM().getTUIndex()951: context.GetAsLLVM().getCUIndex();952if (index) {953if (header.isTypeUnit())954entry = index.getFromHash(header.getTypeHash());955else if (auto dwo_id = header.getDWOId())956entry = index.getFromHash(*dwo_id);957}958if (!entry)959entry = index.getFromOffset(header.getOffset());960if (entry)961if (llvm::Error err = header.applyIndexEntry(entry))962return std::move(err);963}964965const llvm::DWARFDebugAbbrev *abbr = dwarf.DebugAbbrev();966if (!abbr)967return llvm::make_error<llvm::object::GenericBinaryError>(968"No debug_abbrev data");969970bool abbr_offset_OK =971dwarf.GetDWARFContext().getOrLoadAbbrevData().ValidOffset(972header.getAbbrOffset());973if (!abbr_offset_OK)974return llvm::make_error<llvm::object::GenericBinaryError>(975"Abbreviation offset for unit is not valid");976977llvm::Expected<const llvm::DWARFAbbreviationDeclarationSet *> abbrevs_or_err =978abbr->getAbbreviationDeclarationSet(header.getAbbrOffset());979if (!abbrevs_or_err)980return abbrevs_or_err.takeError();981982const llvm::DWARFAbbreviationDeclarationSet *abbrevs = *abbrevs_or_err;983if (!abbrevs)984return llvm::make_error<llvm::object::GenericBinaryError>(985"No abbrev exists at the specified offset.");986987bool is_dwo = dwarf.GetDWARFContext().isDwo();988if (header.isTypeUnit())989return DWARFUnitSP(990new DWARFTypeUnit(dwarf, uid, header, *abbrevs, section, is_dwo));991return DWARFUnitSP(992new DWARFCompileUnit(dwarf, uid, header, *abbrevs, section, is_dwo));993}994995const lldb_private::DWARFDataExtractor &DWARFUnit::GetData() const {996return m_section == DIERef::Section::DebugTypes997? m_dwarf.GetDWARFContext().getOrLoadDebugTypesData()998: m_dwarf.GetDWARFContext().getOrLoadDebugInfoData();999}10001001uint32_t DWARFUnit::GetHeaderByteSize() const {1002switch (m_header.getUnitType()) {1003case llvm::dwarf::DW_UT_compile:1004case llvm::dwarf::DW_UT_partial:1005return GetVersion() < 5 ? 11 : 12;1006case llvm::dwarf::DW_UT_skeleton:1007case llvm::dwarf::DW_UT_split_compile:1008return 20;1009case llvm::dwarf::DW_UT_type:1010case llvm::dwarf::DW_UT_split_type:1011return GetVersion() < 5 ? 23 : 24;1012}1013llvm_unreachable("invalid UnitType.");1014}10151016std::optional<uint64_t>1017DWARFUnit::GetStringOffsetSectionItem(uint32_t index) const {1018offset_t offset = GetStrOffsetsBase() + index * 4;1019return m_dwarf.GetDWARFContext().getOrLoadStrOffsetsData().GetU32(&offset);1020}10211022llvm::Expected<DWARFRangeList>1023DWARFUnit::FindRnglistFromOffset(dw_offset_t offset) {1024if (GetVersion() <= 4) {1025const DWARFDebugRanges *debug_ranges = m_dwarf.GetDebugRanges();1026if (!debug_ranges)1027return llvm::make_error<llvm::object::GenericBinaryError>(1028"No debug_ranges section");1029return debug_ranges->FindRanges(this, offset);1030}10311032if (!GetRnglistTable())1033return llvm::createStringError(std::errc::invalid_argument,1034"missing or invalid range list table");10351036llvm::DWARFDataExtractor data = GetRnglistData().GetAsLLVMDWARF();10371038// As DW_AT_rnglists_base may be missing we need to call setAddressSize.1039data.setAddressSize(m_header.getAddressByteSize());1040auto range_list_or_error = GetRnglistTable()->findList(data, offset);1041if (!range_list_or_error)1042return range_list_or_error.takeError();10431044llvm::Expected<llvm::DWARFAddressRangesVector> llvm_ranges =1045range_list_or_error->getAbsoluteRanges(1046llvm::object::SectionedAddress{GetBaseAddress()},1047GetAddressByteSize(), [&](uint32_t index) {1048uint32_t index_size = GetAddressByteSize();1049dw_offset_t addr_base = GetAddrBase();1050lldb::offset_t offset =1051addr_base + static_cast<lldb::offset_t>(index) * index_size;1052return llvm::object::SectionedAddress{1053m_dwarf.GetDWARFContext().getOrLoadAddrData().GetMaxU64(1054&offset, index_size)};1055});1056if (!llvm_ranges)1057return llvm_ranges.takeError();10581059DWARFRangeList ranges;1060for (const llvm::DWARFAddressRange &llvm_range : *llvm_ranges) {1061ranges.Append(DWARFRangeList::Entry(llvm_range.LowPC,1062llvm_range.HighPC - llvm_range.LowPC));1063}1064ranges.Sort();1065return ranges;1066}10671068llvm::Expected<DWARFRangeList> DWARFUnit::FindRnglistFromIndex(uint32_t index) {1069llvm::Expected<uint64_t> maybe_offset = GetRnglistOffset(index);1070if (!maybe_offset)1071return maybe_offset.takeError();1072return FindRnglistFromOffset(*maybe_offset);1073}10741075bool DWARFUnit::HasAny(llvm::ArrayRef<dw_tag_t> tags) {1076ExtractUnitDIEIfNeeded();1077if (m_dwo)1078return m_dwo->HasAny(tags);10791080for (const auto &die : m_die_array) {1081for (const auto tag : tags) {1082if (tag == die.Tag())1083return true;1084}1085}1086return false;1087}108810891090