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