1 //===-- DWARFDebugInfo.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-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 
28 using namespace lldb;
29 using namespace lldb_private;
30 
31 // Constructor
32 DWARFDebugInfo::DWARFDebugInfo(SymbolFileDWARF &dwarf,
33                                lldb_private::DWARFContext &context)
34     : m_dwarf(dwarf), m_context(context), m_units(), m_cu_aranges_up() {}
35 
36 const DWARFDebugAranges &DWARFDebugInfo::GetCompileUnitAranges() {
37   if (m_cu_aranges_up)
38     return *m_cu_aranges_up;
39 
40   m_cu_aranges_up = std::make_unique<DWARFDebugAranges>();
41   const DWARFDataExtractor &debug_aranges_data =
42       m_context.getOrLoadArangesData();
43 
44   // Extract what we can from the .debug_aranges first.
45   m_cu_aranges_up->extract(debug_aranges_data);
46 
47   // Make a list of all CUs represented by the .debug_aranges data.
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 .debug_aranges.
56   const size_t num_units = GetNumUnits();
57   for (size_t idx = 0; idx < num_units; ++idx) {
58     DWARFUnit *cu = GetUnitAtIndex(idx);
59 
60     dw_offset_t offset = cu->GetOffset();
61     if (cus_with_data.find(offset) == cus_with_data.end())
62       cu->BuildAddressRangeTable(m_cu_aranges_up.get());
63   }
64 
65   const bool minimize = true;
66   m_cu_aranges_up->Sort(minimize);
67   return *m_cu_aranges_up;
68 }
69 
70 void DWARFDebugInfo::ParseUnitsFor(DIERef::Section section) {
71   DWARFDataExtractor data = section == DIERef::Section::DebugTypes
72                                 ? m_context.getOrLoadDebugTypesData()
73                                 : m_context.getOrLoadDebugInfoData();
74   lldb::offset_t offset = 0;
75   while (data.ValidOffset(offset)) {
76     llvm::Expected<DWARFUnitSP> unit_sp = DWARFUnit::extract(
77         m_dwarf, m_units.size(), data, section, &offset);
78 
79     if (!unit_sp) {
80       // FIXME: Propagate this error up.
81       llvm::consumeError(unit_sp.takeError());
82       return;
83     }
84 
85     // If it didn't return an error, then it should be returning a valid Unit.
86     assert(*unit_sp);
87     m_units.push_back(*unit_sp);
88     offset = (*unit_sp)->GetNextUnitOffset();
89 
90     if (auto *type_unit = llvm::dyn_cast<DWARFTypeUnit>(unit_sp->get())) {
91       m_type_hash_to_unit_index.emplace_back(type_unit->GetTypeHash(),
92                                              unit_sp.get()->GetID());
93     }
94   }
95 }
96 
97 void DWARFDebugInfo::ParseUnitHeadersIfNeeded() {
98   llvm::call_once(m_units_once_flag, [&] {
99     ParseUnitsFor(DIERef::Section::DebugInfo);
100     ParseUnitsFor(DIERef::Section::DebugTypes);
101     llvm::sort(m_type_hash_to_unit_index, llvm::less_first());
102   });
103 }
104 
105 size_t DWARFDebugInfo::GetNumUnits() {
106   ParseUnitHeadersIfNeeded();
107   return m_units.size();
108 }
109 
110 DWARFUnit *DWARFDebugInfo::GetUnitAtIndex(size_t idx) {
111   DWARFUnit *cu = nullptr;
112   if (idx < GetNumUnits())
113     cu = m_units[idx].get();
114   return cu;
115 }
116 
117 uint32_t DWARFDebugInfo::FindUnitIndex(DIERef::Section section,
118                                        dw_offset_t offset) {
119   ParseUnitHeadersIfNeeded();
120 
121   // llvm::lower_bound is not used as for DIE offsets it would still return
122   // index +1 and GetOffset() returning index itself would be a special case.
123   auto pos = llvm::upper_bound(
124       m_units, std::make_pair(section, offset),
125       [](const std::pair<DIERef::Section, dw_offset_t> &lhs,
126          const DWARFUnitSP &rhs) {
127         return lhs < std::make_pair(rhs->GetDebugSection(), rhs->GetOffset());
128       });
129   uint32_t idx = std::distance(m_units.begin(), pos);
130   if (idx == 0)
131     return DW_INVALID_OFFSET;
132   return idx - 1;
133 }
134 
135 DWARFUnit *DWARFDebugInfo::GetUnitAtOffset(DIERef::Section section,
136                                            dw_offset_t cu_offset,
137                                            uint32_t *idx_ptr) {
138   uint32_t idx = FindUnitIndex(section, cu_offset);
139   DWARFUnit *result = GetUnitAtIndex(idx);
140   if (result && result->GetOffset() != cu_offset) {
141     result = nullptr;
142     idx = DW_INVALID_INDEX;
143   }
144   if (idx_ptr)
145     *idx_ptr = idx;
146   return result;
147 }
148 
149 DWARFUnit *DWARFDebugInfo::GetUnit(const DIERef &die_ref) {
150   return GetUnitContainingDIEOffset(die_ref.section(), die_ref.die_offset());
151 }
152 
153 DWARFUnit *
154 DWARFDebugInfo::GetUnitContainingDIEOffset(DIERef::Section section,
155                                            dw_offset_t die_offset) {
156   uint32_t idx = FindUnitIndex(section, die_offset);
157   DWARFUnit *result = GetUnitAtIndex(idx);
158   if (result && !result->ContainsDIEOffset(die_offset))
159     return nullptr;
160   return result;
161 }
162 
163 DWARFTypeUnit *DWARFDebugInfo::GetTypeUnitForHash(uint64_t hash) {
164   auto pos = llvm::lower_bound(m_type_hash_to_unit_index,
165                                std::make_pair(hash, 0u), llvm::less_first());
166   if (pos == m_type_hash_to_unit_index.end() || pos->first != hash)
167     return nullptr;
168   return llvm::cast<DWARFTypeUnit>(GetUnitAtIndex(pos->second));
169 }
170 
171 bool DWARFDebugInfo::ContainsTypeUnits() {
172   ParseUnitHeadersIfNeeded();
173   return !m_type_hash_to_unit_index.empty();
174 }
175 
176 // GetDIE()
177 //
178 // Get the DIE (Debug Information Entry) with the specified offset.
179 DWARFDIE
180 DWARFDebugInfo::GetDIE(const DIERef &die_ref) {
181   DWARFUnit *cu = GetUnit(die_ref);
182   if (cu)
183     return cu->GetNonSkeletonUnit().GetDIE(die_ref.die_offset());
184   return DWARFDIE(); // Not found
185 }
186