1//===-- DWARFDebugInfo.cpp --------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "SymbolFileDWARF.h"
10
11#include <algorithm>
12#include <set>
13
14#include "lldb/Host/PosixApi.h"
15#include "lldb/Symbol/ObjectFile.h"
16#include "lldb/Utility/RegularExpression.h"
17#include "lldb/Utility/Stream.h"
18#include "llvm/Support/Casting.h"
19
20#include "DWARFCompileUnit.h"
21#include "DWARFContext.h"
22#include "DWARFDebugAranges.h"
23#include "DWARFDebugInfo.h"
24#include "DWARFDebugInfoEntry.h"
25#include "DWARFFormValue.h"
26#include "DWARFTypeUnit.h"
27
28using namespace lldb;
29using namespace lldb_private;
30using namespace std;
31
32// Constructor
33DWARFDebugInfo::DWARFDebugInfo(SymbolFileDWARF &dwarf,
34                               lldb_private::DWARFContext &context)
35    : m_dwarf(dwarf), m_context(context), m_units(), m_cu_aranges_up() {}
36
37llvm::Expected<DWARFDebugAranges &> DWARFDebugInfo::GetCompileUnitAranges() {
38  if (m_cu_aranges_up)
39    return *m_cu_aranges_up;
40
41  m_cu_aranges_up = std::make_unique<DWARFDebugAranges>();
42  const DWARFDataExtractor &debug_aranges_data =
43      m_context.getOrLoadArangesData();
44  if (llvm::Error error = m_cu_aranges_up->extract(debug_aranges_data))
45    return std::move(error);
46
47  // Make a list of all CUs represented by the arange data in the file.
48  std::set<dw_offset_t> cus_with_data;
49  for (size_t n = 0; n < m_cu_aranges_up->GetNumRanges(); n++) {
50    dw_offset_t offset = m_cu_aranges_up->OffsetAtIndex(n);
51    if (offset != DW_INVALID_OFFSET)
52      cus_with_data.insert(offset);
53  }
54
55  // Manually build arange data for everything that wasn't in the
56  // .debug_aranges table.
57  const size_t num_units = GetNumUnits();
58  for (size_t idx = 0; idx < num_units; ++idx) {
59    DWARFUnit *cu = GetUnitAtIndex(idx);
60
61    dw_offset_t offset = cu->GetOffset();
62    if (cus_with_data.find(offset) == cus_with_data.end())
63      cu->BuildAddressRangeTable(m_cu_aranges_up.get());
64  }
65
66  const bool minimize = true;
67  m_cu_aranges_up->Sort(minimize);
68  return *m_cu_aranges_up;
69}
70
71void DWARFDebugInfo::ParseUnitsFor(DIERef::Section section) {
72  DWARFDataExtractor data = section == DIERef::Section::DebugTypes
73                                ? m_context.getOrLoadDebugTypesData()
74                                : m_context.getOrLoadDebugInfoData();
75  lldb::offset_t offset = 0;
76  while (data.ValidOffset(offset)) {
77    llvm::Expected<DWARFUnitSP> unit_sp =
78        DWARFUnit::extract(m_dwarf, m_units.size(), data, section, &offset);
79
80    if (!unit_sp) {
81      // FIXME: Propagate this error up.
82      llvm::consumeError(unit_sp.takeError());
83      return;
84    }
85
86    // If it didn't return an error, then it should be returning a valid Unit.
87    assert(*unit_sp);
88    m_units.push_back(*unit_sp);
89    offset = (*unit_sp)->GetNextUnitOffset();
90
91    if (auto *type_unit = llvm::dyn_cast<DWARFTypeUnit>(unit_sp->get())) {
92      m_type_hash_to_unit_index.emplace_back(type_unit->GetTypeHash(),
93                                             unit_sp.get()->GetID());
94    }
95  }
96}
97
98void DWARFDebugInfo::ParseUnitHeadersIfNeeded() {
99  if (!m_units.empty())
100    return;
101
102  ParseUnitsFor(DIERef::Section::DebugInfo);
103  ParseUnitsFor(DIERef::Section::DebugTypes);
104  llvm::sort(m_type_hash_to_unit_index, llvm::less_first());
105}
106
107size_t DWARFDebugInfo::GetNumUnits() {
108  ParseUnitHeadersIfNeeded();
109  return m_units.size();
110}
111
112DWARFUnit *DWARFDebugInfo::GetUnitAtIndex(user_id_t idx) {
113  DWARFUnit *cu = nullptr;
114  if (idx < GetNumUnits())
115    cu = m_units[idx].get();
116  return cu;
117}
118
119uint32_t DWARFDebugInfo::FindUnitIndex(DIERef::Section section,
120                                       dw_offset_t offset) {
121  ParseUnitHeadersIfNeeded();
122
123  // llvm::lower_bound is not used as for DIE offsets it would still return
124  // index +1 and GetOffset() returning index itself would be a special case.
125  auto pos = llvm::upper_bound(
126      m_units, std::make_pair(section, offset),
127      [](const std::pair<DIERef::Section, dw_offset_t> &lhs,
128         const DWARFUnitSP &rhs) {
129        return lhs < std::make_pair(rhs->GetDebugSection(), rhs->GetOffset());
130      });
131  uint32_t idx = std::distance(m_units.begin(), pos);
132  if (idx == 0)
133    return DW_INVALID_OFFSET;
134  return idx - 1;
135}
136
137DWARFUnit *DWARFDebugInfo::GetUnitAtOffset(DIERef::Section section,
138                                           dw_offset_t cu_offset,
139                                           uint32_t *idx_ptr) {
140  uint32_t idx = FindUnitIndex(section, cu_offset);
141  DWARFUnit *result = GetUnitAtIndex(idx);
142  if (result && result->GetOffset() != cu_offset) {
143    result = nullptr;
144    idx = DW_INVALID_INDEX;
145  }
146  if (idx_ptr)
147    *idx_ptr = idx;
148  return result;
149}
150
151DWARFUnit *DWARFDebugInfo::GetUnit(const DIERef &die_ref) {
152  return GetUnitContainingDIEOffset(die_ref.section(), die_ref.die_offset());
153}
154
155DWARFUnit *
156DWARFDebugInfo::GetUnitContainingDIEOffset(DIERef::Section section,
157                                           dw_offset_t die_offset) {
158  uint32_t idx = FindUnitIndex(section, die_offset);
159  DWARFUnit *result = GetUnitAtIndex(idx);
160  if (result && !result->ContainsDIEOffset(die_offset))
161    return nullptr;
162  return result;
163}
164
165DWARFTypeUnit *DWARFDebugInfo::GetTypeUnitForHash(uint64_t hash) {
166  auto pos = llvm::lower_bound(m_type_hash_to_unit_index,
167                               std::make_pair(hash, 0u), llvm::less_first());
168  if (pos == m_type_hash_to_unit_index.end() || pos->first != hash)
169    return nullptr;
170  return llvm::cast<DWARFTypeUnit>(GetUnitAtIndex(pos->second));
171}
172
173bool DWARFDebugInfo::ContainsTypeUnits() {
174  ParseUnitHeadersIfNeeded();
175  return !m_type_hash_to_unit_index.empty();
176}
177
178DWARFDIE
179DWARFDebugInfo::GetDIEForDIEOffset(DIERef::Section section,
180                                   dw_offset_t die_offset) {
181  DWARFUnit *cu = GetUnitContainingDIEOffset(section, die_offset);
182  if (cu)
183    return cu->GetDIE(die_offset);
184  return DWARFDIE();
185}
186
187// GetDIE()
188//
189// Get the DIE (Debug Information Entry) with the specified offset.
190DWARFDIE
191DWARFDebugInfo::GetDIE(const DIERef &die_ref) {
192  DWARFUnit *cu = GetUnit(die_ref);
193  if (cu)
194    return cu->GetDIE(die_ref.die_offset());
195  return DWARFDIE(); // Not found
196}
197
198