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 | #include "LogChannelDWARF.h" |
28 | |
29 | using namespace lldb; |
30 | using namespace lldb_private; |
31 | using namespace lldb_private::plugin::dwarf; |
32 | |
33 | // Constructor |
34 | DWARFDebugInfo::DWARFDebugInfo(SymbolFileDWARF &dwarf, DWARFContext &context) |
35 | : m_dwarf(dwarf), m_context(context), m_units(), m_cu_aranges_up() {} |
36 | |
37 | const 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 | |
45 | // Extract what we can from the .debug_aranges first. |
46 | m_cu_aranges_up->extract(debug_aranges_data); |
47 | |
48 | // Make a list of all CUs represented by the .debug_aranges data. |
49 | std::set<dw_offset_t> cus_with_data; |
50 | for (size_t n = 0; n < m_cu_aranges_up->GetNumRanges(); n++) { |
51 | dw_offset_t offset = m_cu_aranges_up->OffsetAtIndex(idx: n); |
52 | if (offset != DW_INVALID_OFFSET) |
53 | cus_with_data.insert(x: offset); |
54 | } |
55 | |
56 | // Manually build arange data for everything that wasn't in .debug_aranges. |
57 | // The .debug_aranges accelerator is not guaranteed to be complete. |
58 | // Tools such as dsymutil can provide stronger guarantees than required by the |
59 | // standard. Without that guarantee, we have to iterate over every CU in the |
60 | // .debug_info and make sure there's a corresponding entry in the table and if |
61 | // not, add one for every subprogram. |
62 | ObjectFile *OF = m_dwarf.GetObjectFile(); |
63 | if (!OF || !OF->CanTrustAddressRanges()) { |
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(x: offset) == cus_with_data.end()) |
70 | cu->BuildAddressRangeTable(debug_aranges: m_cu_aranges_up.get()); |
71 | } |
72 | } |
73 | |
74 | const bool minimize = true; |
75 | m_cu_aranges_up->Sort(minimize); |
76 | return *m_cu_aranges_up; |
77 | } |
78 | |
79 | void DWARFDebugInfo::ParseUnitsFor(DIERef::Section section) { |
80 | DWARFDataExtractor data = section == DIERef::Section::DebugTypes |
81 | ? m_context.getOrLoadDebugTypesData() |
82 | : m_context.getOrLoadDebugInfoData(); |
83 | lldb::offset_t offset = 0; |
84 | while (data.ValidOffset(offset)) { |
85 | const lldb::offset_t = offset; |
86 | llvm::Expected<DWARFUnitSP> expected_unit_sp = |
87 | DWARFUnit::extract(dwarf2Data&: m_dwarf, uid: m_units.size(), debug_info: data, section, offset_ptr: &offset); |
88 | |
89 | if (!expected_unit_sp) { |
90 | Log *log = GetLog(mask: DWARFLog::DebugInfo); |
91 | if (log) |
92 | LLDB_LOG(log, "Unable to extract DWARFUnitHeader at {0:x}: {1}" , |
93 | unit_header_offset, |
94 | llvm::toString(expected_unit_sp.takeError())); |
95 | else |
96 | llvm::consumeError(Err: expected_unit_sp.takeError()); |
97 | return; |
98 | } |
99 | |
100 | DWARFUnitSP unit_sp = *expected_unit_sp; |
101 | |
102 | // If it didn't return an error, then it should be returning a valid Unit. |
103 | assert((bool)unit_sp); |
104 | |
105 | // Keep a map of DWO ID back to the skeleton units. Sometimes accelerator |
106 | // table lookups can cause the DWO files to be accessed before the skeleton |
107 | // compile unit is parsed, so we keep a map to allow us to match up the DWO |
108 | // file to the back to the skeleton compile units. |
109 | if (unit_sp->GetUnitType() == lldb_private::dwarf::DW_UT_skeleton) { |
110 | if (std::optional<uint64_t> unit_dwo_id = unit_sp->GetHeaderDWOId()) |
111 | m_dwarf5_dwo_id_to_skeleton_unit[*unit_dwo_id] = unit_sp.get(); |
112 | } |
113 | |
114 | m_units.push_back(x: unit_sp); |
115 | offset = unit_sp->GetNextUnitOffset(); |
116 | |
117 | if (auto *type_unit = llvm::dyn_cast<DWARFTypeUnit>(Val: unit_sp.get())) { |
118 | m_type_hash_to_unit_index.emplace_back(args: type_unit->GetTypeHash(), |
119 | args: unit_sp->GetID()); |
120 | } |
121 | } |
122 | } |
123 | |
124 | DWARFUnit *DWARFDebugInfo::GetSkeletonUnit(DWARFUnit *dwo_unit) { |
125 | // If this isn't a DWO unit, don't try and find the skeleton unit. |
126 | if (!dwo_unit->IsDWOUnit()) |
127 | return nullptr; |
128 | |
129 | auto dwo_id = dwo_unit->GetDWOId(); |
130 | if (!dwo_id.has_value()) |
131 | return nullptr; |
132 | |
133 | // Parse the unit headers so that m_dwarf5_dwo_id_to_skeleton_unit is filled |
134 | // in with all of the DWARF5 skeleton compile units DWO IDs since it is easy |
135 | // to access the DWO IDs in the DWARFUnitHeader for each DWARFUnit. |
136 | ParseUnitHeadersIfNeeded(); |
137 | |
138 | // Find the value in our cache and return it we we find it. This cache may |
139 | // only contain DWARF5 units. |
140 | auto iter = m_dwarf5_dwo_id_to_skeleton_unit.find(Val: *dwo_id); |
141 | if (iter != m_dwarf5_dwo_id_to_skeleton_unit.end()) |
142 | return iter->second; |
143 | |
144 | // DWARF5 unit headers have the DWO ID and should have already been in the map |
145 | // so if it wasn't found in the above find() call, then we didn't find it and |
146 | // don't need to do the more expensive DWARF4 search. |
147 | if (dwo_unit->GetVersion() >= 5) |
148 | return nullptr; |
149 | |
150 | // Parse all DWO IDs from all DWARF4 and earlier compile units that have DWO |
151 | // IDs. It is more expensive to get the DWO IDs from DWARF4 compile units as |
152 | // we need to parse the unit DIE and extract the DW_AT_dwo_id or |
153 | // DW_AT_GNU_dwo_id attribute values, so do this only if we didn't find our |
154 | // match above search and only for DWARF4 and earlier compile units. |
155 | llvm::call_once(flag&: m_dwarf4_dwo_id_to_skeleton_unit_once_flag, F: [this]() { |
156 | for (uint32_t i = 0, num = GetNumUnits(); i < num; ++i) { |
157 | if (DWARFUnit *unit = GetUnitAtIndex(idx: i)) { |
158 | if (unit->GetVersion() < 5) { |
159 | if (std::optional<uint64_t> unit_dwo_id = unit->GetDWOId()) |
160 | m_dwarf4_dwo_id_to_skeleton_unit[*unit_dwo_id] = unit; |
161 | } |
162 | } |
163 | } |
164 | }); |
165 | |
166 | // Search the DWARF4 DWO results that we parsed lazily. |
167 | iter = m_dwarf4_dwo_id_to_skeleton_unit.find(Val: *dwo_id); |
168 | if (iter != m_dwarf4_dwo_id_to_skeleton_unit.end()) |
169 | return iter->second; |
170 | return nullptr; |
171 | } |
172 | |
173 | void DWARFDebugInfo::() { |
174 | llvm::call_once(flag&: m_units_once_flag, F: [&] { |
175 | ParseUnitsFor(section: DIERef::Section::DebugInfo); |
176 | ParseUnitsFor(section: DIERef::Section::DebugTypes); |
177 | llvm::sort(C&: m_type_hash_to_unit_index, Comp: llvm::less_first()); |
178 | }); |
179 | } |
180 | |
181 | size_t DWARFDebugInfo::GetNumUnits() { |
182 | ParseUnitHeadersIfNeeded(); |
183 | return m_units.size(); |
184 | } |
185 | |
186 | DWARFUnit *DWARFDebugInfo::GetUnitAtIndex(size_t idx) { |
187 | DWARFUnit *cu = nullptr; |
188 | if (idx < GetNumUnits()) |
189 | cu = m_units[idx].get(); |
190 | return cu; |
191 | } |
192 | |
193 | uint32_t DWARFDebugInfo::FindUnitIndex(DIERef::Section section, |
194 | dw_offset_t offset) { |
195 | ParseUnitHeadersIfNeeded(); |
196 | |
197 | // llvm::lower_bound is not used as for DIE offsets it would still return |
198 | // index +1 and GetOffset() returning index itself would be a special case. |
199 | auto pos = llvm::upper_bound( |
200 | Range&: m_units, Value: std::make_pair(x&: section, y&: offset), |
201 | C: [](const std::pair<DIERef::Section, dw_offset_t> &lhs, |
202 | const DWARFUnitSP &rhs) { |
203 | return lhs < std::make_pair(x: rhs->GetDebugSection(), y: rhs->GetOffset()); |
204 | }); |
205 | uint32_t idx = std::distance(first: m_units.begin(), last: pos); |
206 | if (idx == 0) |
207 | return DW_INVALID_INDEX; |
208 | return idx - 1; |
209 | } |
210 | |
211 | DWARFUnit *DWARFDebugInfo::GetUnitAtOffset(DIERef::Section section, |
212 | dw_offset_t cu_offset, |
213 | uint32_t *idx_ptr) { |
214 | uint32_t idx = FindUnitIndex(section, offset: cu_offset); |
215 | DWARFUnit *result = GetUnitAtIndex(idx); |
216 | if (result && result->GetOffset() != cu_offset) { |
217 | result = nullptr; |
218 | idx = DW_INVALID_INDEX; |
219 | } |
220 | if (idx_ptr) |
221 | *idx_ptr = idx; |
222 | return result; |
223 | } |
224 | |
225 | DWARFUnit *DWARFDebugInfo::GetUnit(const DIERef &die_ref) { |
226 | return GetUnitContainingDIEOffset(section: die_ref.section(), die_offset: die_ref.die_offset()); |
227 | } |
228 | |
229 | DWARFUnit * |
230 | DWARFDebugInfo::GetUnitContainingDIEOffset(DIERef::Section section, |
231 | dw_offset_t die_offset) { |
232 | uint32_t idx = FindUnitIndex(section, offset: die_offset); |
233 | DWARFUnit *result = GetUnitAtIndex(idx); |
234 | if (result && !result->ContainsDIEOffset(die_offset)) |
235 | return nullptr; |
236 | return result; |
237 | } |
238 | |
239 | DWARFTypeUnit *DWARFDebugInfo::GetTypeUnitForHash(uint64_t hash) { |
240 | auto pos = llvm::lower_bound(Range&: m_type_hash_to_unit_index, |
241 | Value: std::make_pair(x&: hash, y: 0u), C: llvm::less_first()); |
242 | if (pos == m_type_hash_to_unit_index.end() || pos->first != hash) |
243 | return nullptr; |
244 | return llvm::cast<DWARFTypeUnit>(Val: GetUnitAtIndex(idx: pos->second)); |
245 | } |
246 | |
247 | bool DWARFDebugInfo::ContainsTypeUnits() { |
248 | ParseUnitHeadersIfNeeded(); |
249 | return !m_type_hash_to_unit_index.empty(); |
250 | } |
251 | |
252 | // GetDIE() |
253 | // |
254 | // Get the DIE (Debug Information Entry) with the specified offset. |
255 | DWARFDIE |
256 | DWARFDebugInfo::GetDIE(const DIERef &die_ref) { |
257 | DWARFUnit *cu = GetUnit(die_ref); |
258 | if (cu) |
259 | return cu->GetNonSkeletonUnit().GetDIE(die_offset: die_ref.die_offset()); |
260 | return DWARFDIE(); // Not found |
261 | } |
262 | |
263 | llvm::StringRef DWARFDebugInfo::PeekDIEName(const DIERef &die_ref) { |
264 | if (DWARFUnit *cu = GetUnit(die_ref)) |
265 | return cu->GetNonSkeletonUnit().PeekDIEName(die_offset: die_ref.die_offset()); |
266 | return llvm::StringRef(); |
267 | } |
268 | |