brintos

brintos / llvm-project-archived public Read only

0
0
Text · 39.9 KiB · b78e6ce Raw
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