1 | //===-- DWARFDebugInfoEntry.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 "DWARFDebugInfoEntry.h" |
10 | |
11 | #include <cassert> |
12 | |
13 | #include <algorithm> |
14 | #include <optional> |
15 | |
16 | #include "llvm/Support/LEB128.h" |
17 | |
18 | #include "lldb/Core/Module.h" |
19 | #include "lldb/Expression/DWARFExpression.h" |
20 | #include "lldb/Symbol/ObjectFile.h" |
21 | #include "lldb/Utility/Stream.h" |
22 | #include "lldb/Utility/StreamString.h" |
23 | |
24 | #include "DWARFCompileUnit.h" |
25 | #include "DWARFDebugAranges.h" |
26 | #include "DWARFDebugInfo.h" |
27 | #include "DWARFDebugRanges.h" |
28 | #include "DWARFDeclContext.h" |
29 | #include "DWARFFormValue.h" |
30 | #include "DWARFUnit.h" |
31 | #include "SymbolFileDWARF.h" |
32 | #include "SymbolFileDWARFDwo.h" |
33 | |
34 | #include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" |
35 | |
36 | using namespace lldb_private; |
37 | using namespace lldb_private::dwarf; |
38 | using namespace lldb_private::plugin::dwarf; |
39 | extern int g_verbose; |
40 | |
41 | // Extract a debug info entry for a given DWARFUnit from the data |
42 | // starting at the offset in offset_ptr |
43 | bool DWARFDebugInfoEntry::(const DWARFDataExtractor &data, |
44 | const DWARFUnit *cu, |
45 | lldb::offset_t *offset_ptr) { |
46 | m_offset = *offset_ptr; |
47 | m_parent_idx = 0; |
48 | m_sibling_idx = 0; |
49 | const uint64_t abbr_idx = data.GetULEB128(offset_ptr); |
50 | lldbassert(abbr_idx <= UINT16_MAX); |
51 | m_abbr_idx = abbr_idx; |
52 | |
53 | if (m_abbr_idx == 0) { |
54 | m_tag = llvm::dwarf::DW_TAG_null; |
55 | m_has_children = false; |
56 | return true; // NULL debug tag entry |
57 | } |
58 | |
59 | const auto *abbrevDecl = GetAbbreviationDeclarationPtr(cu); |
60 | if (abbrevDecl == nullptr) { |
61 | cu->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( |
62 | format: "[{0:x16}]: invalid abbreviation code {1}, " |
63 | "please file a bug and " |
64 | "attach the file at the start of this error message" , |
65 | args: (uint64_t)m_offset, args: (unsigned)abbr_idx); |
66 | // WE can't parse anymore if the DWARF is borked... |
67 | *offset_ptr = UINT32_MAX; |
68 | return false; |
69 | } |
70 | m_tag = abbrevDecl->getTag(); |
71 | m_has_children = abbrevDecl->hasChildren(); |
72 | // Skip all data in the .debug_info or .debug_types for the attributes |
73 | for (const auto &attribute : abbrevDecl->attributes()) { |
74 | if (DWARFFormValue::SkipValue(form: attribute.Form, debug_info_data: data, offset_ptr, unit: cu)) |
75 | continue; |
76 | |
77 | cu->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( |
78 | format: "[{0:x16}]: Unsupported DW_FORM_{1:x}, please file a bug " |
79 | "and " |
80 | "attach the file at the start of this error message" , |
81 | args: (uint64_t)m_offset, args: (unsigned)attribute.Form); |
82 | *offset_ptr = m_offset; |
83 | return false; |
84 | } |
85 | return true; |
86 | } |
87 | |
88 | static DWARFRangeList GetRangesOrReportError(DWARFUnit &unit, |
89 | const DWARFDebugInfoEntry &die, |
90 | const DWARFFormValue &value) { |
91 | llvm::Expected<DWARFRangeList> expected_ranges = |
92 | (value.Form() == DW_FORM_rnglistx) |
93 | ? unit.FindRnglistFromIndex(index: value.Unsigned()) |
94 | : unit.FindRnglistFromOffset(offset: value.Unsigned()); |
95 | if (expected_ranges) |
96 | return std::move(*expected_ranges); |
97 | |
98 | unit.GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( |
99 | format: "[{0:x16}]: DIE has DW_AT_ranges({1} {2:x16}) attribute, but " |
100 | "range extraction failed ({3}), please file a bug " |
101 | "and attach the file at the start of this error message" , |
102 | args: die.GetOffset(), |
103 | args: llvm::dwarf::FormEncodingString(Encoding: value.Form()).str().c_str(), |
104 | args: value.Unsigned(), args: toString(E: expected_ranges.takeError()).c_str()); |
105 | return DWARFRangeList(); |
106 | } |
107 | |
108 | static void ExtractAttrAndFormValue( |
109 | const llvm::DWARFAbbreviationDeclaration::AttributeSpec &attr_spec, |
110 | dw_attr_t &attr, DWARFFormValue &form_value) { |
111 | attr = attr_spec.Attr; |
112 | form_value.FormRef() = attr_spec.Form; |
113 | if (attr_spec.isImplicitConst()) |
114 | form_value.SetSigned(attr_spec.getImplicitConstValue()); |
115 | } |
116 | |
117 | // GetDIENamesAndRanges |
118 | // |
119 | // Gets the valid address ranges for a given DIE by looking for a |
120 | // DW_AT_low_pc/DW_AT_high_pc pair, DW_AT_entry_pc, or DW_AT_ranges attributes. |
121 | bool DWARFDebugInfoEntry::GetDIENamesAndRanges( |
122 | DWARFUnit *cu, const char *&name, const char *&mangled, |
123 | DWARFRangeList &ranges, std::optional<int> &decl_file, |
124 | std::optional<int> &decl_line, std::optional<int> &decl_column, |
125 | std::optional<int> &call_file, std::optional<int> &call_line, |
126 | std::optional<int> &call_column, DWARFExpressionList *frame_base) const { |
127 | dw_addr_t lo_pc = LLDB_INVALID_ADDRESS; |
128 | dw_addr_t hi_pc = LLDB_INVALID_ADDRESS; |
129 | std::vector<DWARFDIE> dies; |
130 | bool set_frame_base_loclist_addr = false; |
131 | |
132 | SymbolFileDWARF &dwarf = cu->GetSymbolFileDWARF(); |
133 | lldb::ModuleSP module = dwarf.GetObjectFile()->GetModule(); |
134 | |
135 | if (const auto *abbrevDecl = GetAbbreviationDeclarationPtr(cu)) { |
136 | const DWARFDataExtractor &data = cu->GetData(); |
137 | lldb::offset_t offset = GetFirstAttributeOffset(); |
138 | |
139 | if (!data.ValidOffset(offset)) |
140 | return false; |
141 | |
142 | bool do_offset = false; |
143 | |
144 | for (const auto &attribute : abbrevDecl->attributes()) { |
145 | DWARFFormValue form_value(cu); |
146 | dw_attr_t attr; |
147 | ExtractAttrAndFormValue(attr_spec: attribute, attr, form_value); |
148 | |
149 | if (form_value.ExtractValue(data, offset_ptr: &offset)) { |
150 | switch (attr) { |
151 | case DW_AT_low_pc: |
152 | lo_pc = form_value.Address(); |
153 | |
154 | if (do_offset) |
155 | hi_pc += lo_pc; |
156 | do_offset = false; |
157 | break; |
158 | |
159 | case DW_AT_entry_pc: |
160 | lo_pc = form_value.Address(); |
161 | break; |
162 | |
163 | case DW_AT_high_pc: |
164 | if (form_value.Form() == DW_FORM_addr || |
165 | form_value.Form() == DW_FORM_addrx || |
166 | form_value.Form() == DW_FORM_GNU_addr_index) { |
167 | hi_pc = form_value.Address(); |
168 | } else { |
169 | hi_pc = form_value.Unsigned(); |
170 | if (lo_pc == LLDB_INVALID_ADDRESS) |
171 | do_offset = hi_pc != LLDB_INVALID_ADDRESS; |
172 | else |
173 | hi_pc += lo_pc; // DWARF 4 introduces <offset-from-lo-pc> to save |
174 | // on relocations |
175 | } |
176 | break; |
177 | |
178 | case DW_AT_ranges: |
179 | ranges = GetRangesOrReportError(unit&: *cu, die: *this, value: form_value); |
180 | break; |
181 | |
182 | case DW_AT_name: |
183 | if (name == nullptr) |
184 | name = form_value.AsCString(); |
185 | break; |
186 | |
187 | case DW_AT_MIPS_linkage_name: |
188 | case DW_AT_linkage_name: |
189 | if (mangled == nullptr) |
190 | mangled = form_value.AsCString(); |
191 | break; |
192 | |
193 | case DW_AT_abstract_origin: |
194 | dies.push_back(x: form_value.Reference()); |
195 | break; |
196 | |
197 | case DW_AT_specification: |
198 | dies.push_back(x: form_value.Reference()); |
199 | break; |
200 | |
201 | case DW_AT_decl_file: |
202 | if (!decl_file) |
203 | decl_file = form_value.Unsigned(); |
204 | break; |
205 | |
206 | case DW_AT_decl_line: |
207 | if (!decl_line) |
208 | decl_line = form_value.Unsigned(); |
209 | break; |
210 | |
211 | case DW_AT_decl_column: |
212 | if (!decl_column) |
213 | decl_column = form_value.Unsigned(); |
214 | break; |
215 | |
216 | case DW_AT_call_file: |
217 | if (!call_file) |
218 | call_file = form_value.Unsigned(); |
219 | break; |
220 | |
221 | case DW_AT_call_line: |
222 | if (!call_line) |
223 | call_line = form_value.Unsigned(); |
224 | break; |
225 | |
226 | case DW_AT_call_column: |
227 | if (!call_column) |
228 | call_column = form_value.Unsigned(); |
229 | break; |
230 | |
231 | case DW_AT_frame_base: |
232 | if (frame_base) { |
233 | if (form_value.BlockData()) { |
234 | uint32_t block_offset = |
235 | form_value.BlockData() - data.GetDataStart(); |
236 | uint32_t block_length = form_value.Unsigned(); |
237 | *frame_base = |
238 | DWARFExpressionList(module, |
239 | DWARFExpression(DataExtractor( |
240 | data, block_offset, block_length)), |
241 | cu); |
242 | } else { |
243 | DataExtractor data = cu->GetLocationData(); |
244 | const dw_offset_t offset = form_value.Unsigned(); |
245 | if (data.ValidOffset(offset)) { |
246 | data = DataExtractor(data, offset, data.GetByteSize() - offset); |
247 | if (lo_pc != LLDB_INVALID_ADDRESS) { |
248 | assert(lo_pc >= cu->GetBaseAddress()); |
249 | DWARFExpression::ParseDWARFLocationList(dwarf_cu: cu, data, loc_list: frame_base); |
250 | frame_base->SetFuncFileAddress(lo_pc); |
251 | } else |
252 | set_frame_base_loclist_addr = true; |
253 | } |
254 | } |
255 | } |
256 | break; |
257 | |
258 | default: |
259 | break; |
260 | } |
261 | } |
262 | } |
263 | } |
264 | |
265 | if (ranges.IsEmpty()) { |
266 | if (lo_pc != LLDB_INVALID_ADDRESS) { |
267 | if (hi_pc != LLDB_INVALID_ADDRESS && hi_pc > lo_pc) |
268 | ranges.Append(entry: DWARFRangeList::Entry(lo_pc, hi_pc - lo_pc)); |
269 | else |
270 | ranges.Append(entry: DWARFRangeList::Entry(lo_pc, 0)); |
271 | } |
272 | } |
273 | |
274 | if (set_frame_base_loclist_addr) { |
275 | dw_addr_t lowest_range_pc = ranges.GetMinRangeBase(fail_value: 0); |
276 | assert(lowest_range_pc >= cu->GetBaseAddress()); |
277 | frame_base->SetFuncFileAddress(lowest_range_pc); |
278 | } |
279 | |
280 | if (ranges.IsEmpty() || name == nullptr || mangled == nullptr) { |
281 | for (const DWARFDIE &die : dies) { |
282 | if (die) { |
283 | die.GetDIE()->GetDIENamesAndRanges(cu: die.GetCU(), name, mangled, ranges, |
284 | decl_file, decl_line, decl_column, |
285 | call_file, call_line, call_column); |
286 | } |
287 | } |
288 | } |
289 | return !ranges.IsEmpty(); |
290 | } |
291 | |
292 | // Get all attribute values for a given DIE, including following any |
293 | // specification or abstract origin attributes and including those in the |
294 | // results. Any duplicate attributes will have the first instance take |
295 | // precedence (this can happen for declaration attributes). |
296 | void DWARFDebugInfoEntry::GetAttributes(DWARFUnit *cu, |
297 | DWARFAttributes &attributes, |
298 | Recurse recurse, |
299 | uint32_t curr_depth) const { |
300 | const auto *abbrevDecl = GetAbbreviationDeclarationPtr(cu); |
301 | if (!abbrevDecl) { |
302 | attributes.Clear(); |
303 | return; |
304 | } |
305 | |
306 | const DWARFDataExtractor &data = cu->GetData(); |
307 | lldb::offset_t offset = GetFirstAttributeOffset(); |
308 | |
309 | for (const auto &attribute : abbrevDecl->attributes()) { |
310 | DWARFFormValue form_value(cu); |
311 | dw_attr_t attr; |
312 | ExtractAttrAndFormValue(attr_spec: attribute, attr, form_value); |
313 | |
314 | // If we are tracking down DW_AT_specification or DW_AT_abstract_origin |
315 | // attributes, the depth will be non-zero. We need to omit certain |
316 | // attributes that don't make sense. |
317 | switch (attr) { |
318 | case DW_AT_sibling: |
319 | case DW_AT_declaration: |
320 | if (curr_depth > 0) { |
321 | // This attribute doesn't make sense when combined with the DIE that |
322 | // references this DIE. We know a DIE is referencing this DIE because |
323 | // curr_depth is not zero |
324 | break; |
325 | } |
326 | [[fallthrough]]; |
327 | default: |
328 | attributes.Append(form_value, attr_die_offset: offset, attr); |
329 | break; |
330 | } |
331 | |
332 | if (recurse == Recurse::yes && |
333 | ((attr == DW_AT_specification) || (attr == DW_AT_abstract_origin))) { |
334 | if (form_value.ExtractValue(data, offset_ptr: &offset)) { |
335 | DWARFDIE spec_die = form_value.Reference(); |
336 | if (spec_die) |
337 | spec_die.GetDIE()->GetAttributes(cu: spec_die.GetCU(), attributes, |
338 | recurse, curr_depth: curr_depth + 1); |
339 | } |
340 | } else { |
341 | const dw_form_t form = form_value.Form(); |
342 | std::optional<uint8_t> fixed_skip_size = |
343 | DWARFFormValue::GetFixedSize(form, u: cu); |
344 | if (fixed_skip_size) |
345 | offset += *fixed_skip_size; |
346 | else |
347 | DWARFFormValue::SkipValue(form, debug_info_data: data, offset_ptr: &offset, unit: cu); |
348 | } |
349 | } |
350 | } |
351 | |
352 | // GetAttributeValue |
353 | // |
354 | // Get the value of an attribute and return the .debug_info or .debug_types |
355 | // offset of the attribute if it was properly extracted into form_value, |
356 | // or zero if we fail since an offset of zero is invalid for an attribute (it |
357 | // would be a compile unit header). |
358 | dw_offset_t DWARFDebugInfoEntry::GetAttributeValue( |
359 | const DWARFUnit *cu, const dw_attr_t attr, DWARFFormValue &form_value, |
360 | dw_offset_t *end_attr_offset_ptr, |
361 | bool check_specification_or_abstract_origin) const { |
362 | if (const auto *abbrevDecl = GetAbbreviationDeclarationPtr(cu)) { |
363 | std::optional<uint32_t> attr_idx = abbrevDecl->findAttributeIndex(attr); |
364 | |
365 | if (attr_idx) { |
366 | const DWARFDataExtractor &data = cu->GetData(); |
367 | lldb::offset_t offset = GetFirstAttributeOffset(); |
368 | |
369 | uint32_t idx = 0; |
370 | while (idx < *attr_idx) |
371 | DWARFFormValue::SkipValue(form: abbrevDecl->getFormByIndex(idx: idx++), debug_info_data: data, |
372 | offset_ptr: &offset, unit: cu); |
373 | |
374 | const dw_offset_t attr_offset = offset; |
375 | form_value.SetUnit(cu); |
376 | form_value.SetForm(abbrevDecl->getFormByIndex(idx)); |
377 | if (form_value.ExtractValue(data, offset_ptr: &offset)) { |
378 | if (end_attr_offset_ptr) |
379 | *end_attr_offset_ptr = offset; |
380 | return attr_offset; |
381 | } |
382 | } |
383 | } |
384 | |
385 | if (check_specification_or_abstract_origin) { |
386 | if (GetAttributeValue(cu, attr: DW_AT_specification, form_value)) { |
387 | DWARFDIE die = form_value.Reference(); |
388 | if (die) { |
389 | dw_offset_t die_offset = die.GetDIE()->GetAttributeValue( |
390 | cu: die.GetCU(), attr, form_value, end_attr_offset_ptr, check_specification_or_abstract_origin: false); |
391 | if (die_offset) |
392 | return die_offset; |
393 | } |
394 | } |
395 | |
396 | if (GetAttributeValue(cu, attr: DW_AT_abstract_origin, form_value)) { |
397 | DWARFDIE die = form_value.Reference(); |
398 | if (die) { |
399 | dw_offset_t die_offset = die.GetDIE()->GetAttributeValue( |
400 | cu: die.GetCU(), attr, form_value, end_attr_offset_ptr, check_specification_or_abstract_origin: false); |
401 | if (die_offset) |
402 | return die_offset; |
403 | } |
404 | } |
405 | } |
406 | return 0; |
407 | } |
408 | |
409 | // GetAttributeValueAsString |
410 | // |
411 | // Get the value of an attribute as a string return it. The resulting pointer |
412 | // to the string data exists within the supplied SymbolFileDWARF and will only |
413 | // be available as long as the SymbolFileDWARF is still around and it's content |
414 | // doesn't change. |
415 | const char *DWARFDebugInfoEntry::GetAttributeValueAsString( |
416 | const DWARFUnit *cu, const dw_attr_t attr, const char *fail_value, |
417 | bool check_specification_or_abstract_origin) const { |
418 | DWARFFormValue form_value; |
419 | if (GetAttributeValue(cu, attr, form_value, end_attr_offset_ptr: nullptr, |
420 | check_specification_or_abstract_origin)) |
421 | return form_value.AsCString(); |
422 | return fail_value; |
423 | } |
424 | |
425 | // GetAttributeValueAsUnsigned |
426 | // |
427 | // Get the value of an attribute as unsigned and return it. |
428 | uint64_t DWARFDebugInfoEntry::GetAttributeValueAsUnsigned( |
429 | const DWARFUnit *cu, const dw_attr_t attr, uint64_t fail_value, |
430 | bool check_specification_or_abstract_origin) const { |
431 | DWARFFormValue form_value; |
432 | if (GetAttributeValue(cu, attr, form_value, end_attr_offset_ptr: nullptr, |
433 | check_specification_or_abstract_origin)) |
434 | return form_value.Unsigned(); |
435 | return fail_value; |
436 | } |
437 | |
438 | std::optional<uint64_t> |
439 | DWARFDebugInfoEntry::GetAttributeValueAsOptionalUnsigned( |
440 | const DWARFUnit *cu, const dw_attr_t attr, |
441 | bool check_specification_or_abstract_origin) const { |
442 | DWARFFormValue form_value; |
443 | if (GetAttributeValue(cu, attr, form_value, end_attr_offset_ptr: nullptr, |
444 | check_specification_or_abstract_origin)) |
445 | return form_value.Unsigned(); |
446 | return std::nullopt; |
447 | } |
448 | |
449 | // GetAttributeValueAsReference |
450 | // |
451 | // Get the value of an attribute as reference and fix up and compile unit |
452 | // relative offsets as needed. |
453 | DWARFDIE DWARFDebugInfoEntry::GetAttributeValueAsReference( |
454 | const DWARFUnit *cu, const dw_attr_t attr, |
455 | bool check_specification_or_abstract_origin) const { |
456 | DWARFFormValue form_value; |
457 | if (GetAttributeValue(cu, attr, form_value, end_attr_offset_ptr: nullptr, |
458 | check_specification_or_abstract_origin)) |
459 | return form_value.Reference(); |
460 | return {}; |
461 | } |
462 | |
463 | uint64_t DWARFDebugInfoEntry::GetAttributeValueAsAddress( |
464 | const DWARFUnit *cu, const dw_attr_t attr, uint64_t fail_value, |
465 | bool check_specification_or_abstract_origin) const { |
466 | DWARFFormValue form_value; |
467 | if (GetAttributeValue(cu, attr, form_value, end_attr_offset_ptr: nullptr, |
468 | check_specification_or_abstract_origin)) |
469 | return form_value.Address(); |
470 | return fail_value; |
471 | } |
472 | |
473 | // GetAttributeHighPC |
474 | // |
475 | // Get the hi_pc, adding hi_pc to lo_pc when specified as an <offset-from-low- |
476 | // pc>. |
477 | // |
478 | // Returns the hi_pc or fail_value. |
479 | dw_addr_t DWARFDebugInfoEntry::GetAttributeHighPC( |
480 | const DWARFUnit *cu, dw_addr_t lo_pc, uint64_t fail_value, |
481 | bool check_specification_or_abstract_origin) const { |
482 | DWARFFormValue form_value; |
483 | if (GetAttributeValue(cu, attr: DW_AT_high_pc, form_value, end_attr_offset_ptr: nullptr, |
484 | check_specification_or_abstract_origin)) { |
485 | dw_form_t form = form_value.Form(); |
486 | if (form == DW_FORM_addr || form == DW_FORM_addrx || |
487 | form == DW_FORM_GNU_addr_index) |
488 | return form_value.Address(); |
489 | |
490 | // DWARF4 can specify the hi_pc as an <offset-from-lowpc> |
491 | return lo_pc + form_value.Unsigned(); |
492 | } |
493 | return fail_value; |
494 | } |
495 | |
496 | // GetAttributeAddressRange |
497 | // |
498 | // Get the lo_pc and hi_pc, adding hi_pc to lo_pc when specified as an <offset- |
499 | // from-low-pc>. |
500 | // |
501 | // Returns true or sets lo_pc and hi_pc to fail_value. |
502 | bool DWARFDebugInfoEntry::GetAttributeAddressRange( |
503 | const DWARFUnit *cu, dw_addr_t &lo_pc, dw_addr_t &hi_pc, |
504 | uint64_t fail_value, bool check_specification_or_abstract_origin) const { |
505 | lo_pc = GetAttributeValueAsAddress(cu, attr: DW_AT_low_pc, fail_value, |
506 | check_specification_or_abstract_origin); |
507 | if (lo_pc != fail_value) { |
508 | hi_pc = GetAttributeHighPC(cu, lo_pc, fail_value, |
509 | check_specification_or_abstract_origin); |
510 | if (hi_pc != fail_value) |
511 | return true; |
512 | } |
513 | lo_pc = fail_value; |
514 | hi_pc = fail_value; |
515 | return false; |
516 | } |
517 | |
518 | DWARFRangeList DWARFDebugInfoEntry::GetAttributeAddressRanges( |
519 | DWARFUnit *cu, bool check_hi_lo_pc, |
520 | bool check_specification_or_abstract_origin) const { |
521 | |
522 | DWARFFormValue form_value; |
523 | if (GetAttributeValue(cu, attr: DW_AT_ranges, form_value)) |
524 | return GetRangesOrReportError(unit&: *cu, die: *this, value: form_value); |
525 | |
526 | DWARFRangeList ranges; |
527 | if (check_hi_lo_pc) { |
528 | dw_addr_t lo_pc = LLDB_INVALID_ADDRESS; |
529 | dw_addr_t hi_pc = LLDB_INVALID_ADDRESS; |
530 | if (GetAttributeAddressRange(cu, lo_pc, hi_pc, LLDB_INVALID_ADDRESS, |
531 | check_specification_or_abstract_origin)) { |
532 | if (lo_pc < hi_pc) |
533 | ranges.Append(entry: DWARFRangeList::Entry(lo_pc, hi_pc - lo_pc)); |
534 | } |
535 | } |
536 | return ranges; |
537 | } |
538 | |
539 | // GetName |
540 | // |
541 | // Get value of the DW_AT_name attribute and return it if one exists, else |
542 | // return NULL. |
543 | const char *DWARFDebugInfoEntry::GetName(const DWARFUnit *cu) const { |
544 | return GetAttributeValueAsString(cu, attr: DW_AT_name, fail_value: nullptr, check_specification_or_abstract_origin: true); |
545 | } |
546 | |
547 | // GetMangledName |
548 | // |
549 | // Get value of the DW_AT_MIPS_linkage_name attribute and return it if one |
550 | // exists, else return the value of the DW_AT_name attribute |
551 | const char * |
552 | DWARFDebugInfoEntry::GetMangledName(const DWARFUnit *cu, |
553 | bool substitute_name_allowed) const { |
554 | const char *name = nullptr; |
555 | |
556 | name = GetAttributeValueAsString(cu, attr: DW_AT_MIPS_linkage_name, fail_value: nullptr, check_specification_or_abstract_origin: true); |
557 | if (name) |
558 | return name; |
559 | |
560 | name = GetAttributeValueAsString(cu, attr: DW_AT_linkage_name, fail_value: nullptr, check_specification_or_abstract_origin: true); |
561 | if (name) |
562 | return name; |
563 | |
564 | if (!substitute_name_allowed) |
565 | return nullptr; |
566 | |
567 | name = GetAttributeValueAsString(cu, attr: DW_AT_name, fail_value: nullptr, check_specification_or_abstract_origin: true); |
568 | return name; |
569 | } |
570 | |
571 | // GetPubname |
572 | // |
573 | // Get value the name for a DIE as it should appear for a .debug_pubnames or |
574 | // .debug_pubtypes section. |
575 | const char *DWARFDebugInfoEntry::GetPubname(const DWARFUnit *cu) const { |
576 | const char *name = nullptr; |
577 | if (!cu) |
578 | return name; |
579 | |
580 | name = GetAttributeValueAsString(cu, attr: DW_AT_MIPS_linkage_name, fail_value: nullptr, check_specification_or_abstract_origin: true); |
581 | if (name) |
582 | return name; |
583 | |
584 | name = GetAttributeValueAsString(cu, attr: DW_AT_linkage_name, fail_value: nullptr, check_specification_or_abstract_origin: true); |
585 | if (name) |
586 | return name; |
587 | |
588 | name = GetAttributeValueAsString(cu, attr: DW_AT_name, fail_value: nullptr, check_specification_or_abstract_origin: true); |
589 | return name; |
590 | } |
591 | |
592 | /// This function is builds a table very similar to the standard .debug_aranges |
593 | /// table, except that the actual DIE offset for the function is placed in the |
594 | /// table instead of the compile unit offset. |
595 | void DWARFDebugInfoEntry::BuildFunctionAddressRangeTable( |
596 | DWARFUnit *cu, DWARFDebugAranges *debug_aranges) const { |
597 | if (m_tag) { |
598 | if (m_tag == DW_TAG_subprogram) { |
599 | DWARFRangeList ranges = |
600 | GetAttributeAddressRanges(cu, /*check_hi_lo_pc=*/true); |
601 | for (const auto &r : ranges) { |
602 | debug_aranges->AppendRange(cu_offset: GetOffset(), low_pc: r.GetRangeBase(), |
603 | high_pc: r.GetRangeEnd()); |
604 | } |
605 | } |
606 | |
607 | const DWARFDebugInfoEntry *child = GetFirstChild(); |
608 | while (child) { |
609 | child->BuildFunctionAddressRangeTable(cu, debug_aranges); |
610 | child = child->GetSibling(); |
611 | } |
612 | } |
613 | } |
614 | |
615 | DWARFDeclContext |
616 | DWARFDebugInfoEntry::GetDWARFDeclContextStatic(const DWARFDebugInfoEntry *die, |
617 | DWARFUnit *cu) { |
618 | DWARFDeclContext dwarf_decl_ctx; |
619 | for (;;) { |
620 | const dw_tag_t tag = die->Tag(); |
621 | if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit) |
622 | return dwarf_decl_ctx; |
623 | dwarf_decl_ctx.AppendDeclContext(tag, name: die->GetName(cu)); |
624 | DWARFDIE parent_decl_ctx_die = die->GetParentDeclContextDIE(cu); |
625 | if (!parent_decl_ctx_die || parent_decl_ctx_die.GetDIE() == die) |
626 | return dwarf_decl_ctx; |
627 | if (parent_decl_ctx_die.Tag() == DW_TAG_compile_unit || |
628 | parent_decl_ctx_die.Tag() == DW_TAG_partial_unit) |
629 | return dwarf_decl_ctx; |
630 | die = parent_decl_ctx_die.GetDIE(); |
631 | cu = parent_decl_ctx_die.GetCU(); |
632 | } |
633 | } |
634 | |
635 | DWARFDeclContext DWARFDebugInfoEntry::GetDWARFDeclContext(DWARFUnit *cu) const { |
636 | return GetDWARFDeclContextStatic(die: this, cu); |
637 | } |
638 | |
639 | DWARFDIE |
640 | DWARFDebugInfoEntry::GetParentDeclContextDIE(DWARFUnit *cu) const { |
641 | DWARFAttributes attributes = GetAttributes(cu, recurse: Recurse::yes); |
642 | return GetParentDeclContextDIE(cu, attributes); |
643 | } |
644 | |
645 | DWARFDIE |
646 | DWARFDebugInfoEntry::GetParentDeclContextDIE( |
647 | DWARFUnit *cu, const DWARFAttributes &attributes) const { |
648 | DWARFDIE die(cu, const_cast<DWARFDebugInfoEntry *>(this)); |
649 | |
650 | while (die) { |
651 | // If this is the original DIE that we are searching for a declaration for, |
652 | // then don't look in the cache as we don't want our own decl context to be |
653 | // our decl context... |
654 | if (die.GetDIE() != this) { |
655 | switch (die.Tag()) { |
656 | case DW_TAG_compile_unit: |
657 | case DW_TAG_partial_unit: |
658 | case DW_TAG_namespace: |
659 | case DW_TAG_structure_type: |
660 | case DW_TAG_union_type: |
661 | case DW_TAG_class_type: |
662 | return die; |
663 | |
664 | default: |
665 | break; |
666 | } |
667 | } |
668 | |
669 | DWARFDIE spec_die = attributes.FormValueAsReference(attr: DW_AT_specification); |
670 | if (spec_die) { |
671 | DWARFDIE decl_ctx_die = spec_die.GetParentDeclContextDIE(); |
672 | if (decl_ctx_die) |
673 | return decl_ctx_die; |
674 | } |
675 | |
676 | DWARFDIE abs_die = attributes.FormValueAsReference(attr: DW_AT_abstract_origin); |
677 | if (abs_die) { |
678 | DWARFDIE decl_ctx_die = abs_die.GetParentDeclContextDIE(); |
679 | if (decl_ctx_die) |
680 | return decl_ctx_die; |
681 | } |
682 | |
683 | die = die.GetParent(); |
684 | } |
685 | return DWARFDIE(); |
686 | } |
687 | |
688 | lldb::offset_t DWARFDebugInfoEntry::GetFirstAttributeOffset() const { |
689 | return GetOffset() + llvm::getULEB128Size(Value: m_abbr_idx); |
690 | } |
691 | |
692 | const llvm::DWARFAbbreviationDeclaration * |
693 | DWARFDebugInfoEntry::GetAbbreviationDeclarationPtr(const DWARFUnit *cu) const { |
694 | if (!cu) |
695 | return nullptr; |
696 | |
697 | const llvm::DWARFAbbreviationDeclarationSet *abbrev_set = |
698 | cu->GetAbbreviations(); |
699 | if (!abbrev_set) |
700 | return nullptr; |
701 | |
702 | return abbrev_set->getAbbreviationDeclaration(AbbrCode: m_abbr_idx); |
703 | } |
704 | |
705 | bool DWARFDebugInfoEntry::IsGlobalOrStaticScopeVariable() const { |
706 | if (Tag() != DW_TAG_variable) |
707 | return false; |
708 | const DWARFDebugInfoEntry *parent_die = GetParent(); |
709 | while (parent_die != nullptr) { |
710 | switch (parent_die->Tag()) { |
711 | case DW_TAG_subprogram: |
712 | case DW_TAG_lexical_block: |
713 | case DW_TAG_inlined_subroutine: |
714 | return false; |
715 | |
716 | case DW_TAG_compile_unit: |
717 | case DW_TAG_partial_unit: |
718 | return true; |
719 | |
720 | default: |
721 | break; |
722 | } |
723 | parent_die = parent_die->GetParent(); |
724 | } |
725 | return false; |
726 | } |
727 | |
728 | bool DWARFDebugInfoEntry::operator==(const DWARFDebugInfoEntry &rhs) const { |
729 | return m_offset == rhs.m_offset && m_parent_idx == rhs.m_parent_idx && |
730 | m_sibling_idx == rhs.m_sibling_idx && |
731 | m_abbr_idx == rhs.m_abbr_idx && m_has_children == rhs.m_has_children && |
732 | m_tag == rhs.m_tag; |
733 | } |
734 | |
735 | bool DWARFDebugInfoEntry::operator!=(const DWARFDebugInfoEntry &rhs) const { |
736 | return !(*this == rhs); |
737 | } |
738 | |