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