1 | //===-- DWARFDIE.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 "DWARFDIE.h" |
10 | |
11 | #include "DWARFASTParser.h" |
12 | #include "DWARFDebugInfo.h" |
13 | #include "DWARFDebugInfoEntry.h" |
14 | #include "DWARFDeclContext.h" |
15 | #include "DWARFUnit.h" |
16 | #include "LogChannelDWARF.h" |
17 | #include "lldb/Symbol/Type.h" |
18 | |
19 | #include "llvm/ADT/iterator.h" |
20 | #include "llvm/BinaryFormat/Dwarf.h" |
21 | #include "llvm/DebugInfo/DWARF/DWARFAddressRange.h" |
22 | #include "llvm/DebugInfo/DWARF/DWARFTypePrinter.h" |
23 | #include "llvm/Support/raw_ostream.h" |
24 | |
25 | using namespace lldb_private; |
26 | using namespace lldb_private::dwarf; |
27 | using namespace lldb_private::plugin::dwarf; |
28 | |
29 | namespace { |
30 | |
31 | /// Iterate through all DIEs elaborating (i.e. reachable by a chain of |
32 | /// DW_AT_specification, DW_AT_abstract_origin and/or DW_AT_signature |
33 | /// attributes) a given DIE. For convenience, the starting die is included in |
34 | /// the sequence as the first item. |
35 | class ElaboratingDIEIterator |
36 | : public llvm::iterator_facade_base< |
37 | ElaboratingDIEIterator, std::input_iterator_tag, DWARFDIE, |
38 | std::ptrdiff_t, DWARFDIE *, DWARFDIE *> { |
39 | |
40 | // The operating invariant is: top of m_worklist contains the "current" item |
41 | // and the rest of the list are items yet to be visited. An empty worklist |
42 | // means we've reached the end. |
43 | // Infinite recursion is prevented by maintaining a list of seen DIEs. |
44 | // Container sizes are optimized for the case of following DW_AT_specification |
45 | // and DW_AT_abstract_origin just once. |
46 | llvm::SmallVector<DWARFDIE, 2> m_worklist; |
47 | llvm::SmallSet<DWARFDebugInfoEntry *, 3> m_seen; |
48 | |
49 | void Next() { |
50 | assert(!m_worklist.empty() && "Incrementing end iterator?" ); |
51 | |
52 | // Pop the current item from the list. |
53 | DWARFDIE die = m_worklist.back(); |
54 | m_worklist.pop_back(); |
55 | |
56 | // And add back any items that elaborate it. |
57 | for (dw_attr_t attr : |
58 | {DW_AT_specification, DW_AT_abstract_origin, DW_AT_signature}) { |
59 | if (DWARFDIE d = die.GetReferencedDIE(attr)) |
60 | if (m_seen.insert(Ptr: die.GetDIE()).second) |
61 | m_worklist.push_back(Elt: d); |
62 | } |
63 | } |
64 | |
65 | public: |
66 | /// An iterator starting at die d. |
67 | explicit ElaboratingDIEIterator(DWARFDIE d) : m_worklist(1, d) {} |
68 | |
69 | /// End marker |
70 | ElaboratingDIEIterator() = default; |
71 | |
72 | const DWARFDIE &operator*() const { return m_worklist.back(); } |
73 | ElaboratingDIEIterator &operator++() { |
74 | Next(); |
75 | return *this; |
76 | } |
77 | |
78 | friend bool operator==(const ElaboratingDIEIterator &a, |
79 | const ElaboratingDIEIterator &b) { |
80 | if (a.m_worklist.empty() || b.m_worklist.empty()) |
81 | return a.m_worklist.empty() == b.m_worklist.empty(); |
82 | return a.m_worklist.back() == b.m_worklist.back(); |
83 | } |
84 | }; |
85 | |
86 | llvm::iterator_range<ElaboratingDIEIterator> |
87 | elaborating_dies(const DWARFDIE &die) { |
88 | return llvm::make_range(x: ElaboratingDIEIterator(die), |
89 | y: ElaboratingDIEIterator()); |
90 | } |
91 | } // namespace |
92 | |
93 | DWARFDIE |
94 | DWARFDIE::GetParent() const { |
95 | if (IsValid()) |
96 | return DWARFDIE(m_cu, m_die->GetParent()); |
97 | else |
98 | return DWARFDIE(); |
99 | } |
100 | |
101 | DWARFDIE |
102 | DWARFDIE::GetFirstChild() const { |
103 | if (IsValid()) |
104 | return DWARFDIE(m_cu, m_die->GetFirstChild()); |
105 | else |
106 | return DWARFDIE(); |
107 | } |
108 | |
109 | DWARFDIE |
110 | DWARFDIE::GetSibling() const { |
111 | if (IsValid()) |
112 | return DWARFDIE(m_cu, m_die->GetSibling()); |
113 | else |
114 | return DWARFDIE(); |
115 | } |
116 | |
117 | DWARFDIE |
118 | DWARFDIE::GetReferencedDIE(const dw_attr_t attr) const { |
119 | if (IsValid()) |
120 | return m_die->GetAttributeValueAsReference(cu: GetCU(), attr); |
121 | else |
122 | return {}; |
123 | } |
124 | |
125 | DWARFDIE |
126 | DWARFDIE::GetDIE(dw_offset_t die_offset) const { |
127 | if (IsValid()) |
128 | return m_cu->GetDIE(die_offset); |
129 | else |
130 | return DWARFDIE(); |
131 | } |
132 | |
133 | DWARFDIE |
134 | DWARFDIE::GetAttributeValueAsReferenceDIE(const dw_attr_t attr) const { |
135 | if (IsValid()) { |
136 | DWARFUnit *cu = GetCU(); |
137 | const bool check_elaborating_dies = true; |
138 | DWARFFormValue form_value; |
139 | if (m_die->GetAttributeValue(cu, attr, formValue&: form_value, end_attr_offset_ptr: nullptr, |
140 | check_elaborating_dies)) |
141 | return form_value.Reference(); |
142 | } |
143 | return DWARFDIE(); |
144 | } |
145 | |
146 | DWARFDIE |
147 | DWARFDIE::LookupDeepestBlock(lldb::addr_t address) const { |
148 | if (!IsValid()) |
149 | return DWARFDIE(); |
150 | |
151 | DWARFDIE result; |
152 | bool check_children = false; |
153 | bool match_addr_range = false; |
154 | switch (Tag()) { |
155 | case DW_TAG_class_type: |
156 | case DW_TAG_namespace: |
157 | case DW_TAG_structure_type: |
158 | case DW_TAG_common_block: |
159 | check_children = true; |
160 | break; |
161 | case DW_TAG_compile_unit: |
162 | case DW_TAG_module: |
163 | case DW_TAG_catch_block: |
164 | case DW_TAG_subprogram: |
165 | case DW_TAG_try_block: |
166 | case DW_TAG_partial_unit: |
167 | match_addr_range = true; |
168 | break; |
169 | case DW_TAG_lexical_block: |
170 | case DW_TAG_inlined_subroutine: |
171 | check_children = true; |
172 | match_addr_range = true; |
173 | break; |
174 | default: |
175 | break; |
176 | } |
177 | |
178 | if (match_addr_range) { |
179 | if (llvm::Expected<llvm::DWARFAddressRangesVector> ranges = |
180 | m_die->GetAttributeAddressRanges(cu: m_cu, /*check_hi_lo_pc=*/true)) { |
181 | bool addr_in_range = |
182 | llvm::any_of(Range&: *ranges, P: [&](const llvm::DWARFAddressRange &r) { |
183 | return r.LowPC <= address && address < r.HighPC; |
184 | }); |
185 | if (addr_in_range) { |
186 | switch (Tag()) { |
187 | default: |
188 | break; |
189 | |
190 | case DW_TAG_inlined_subroutine: // Inlined Function |
191 | case DW_TAG_lexical_block: // Block { } in code |
192 | result = *this; |
193 | break; |
194 | } |
195 | } |
196 | check_children = addr_in_range; |
197 | } else { |
198 | LLDB_LOG_ERROR(GetLog(DWARFLog::DebugInfo), ranges.takeError(), |
199 | "DIE({1:x}): {0}" , GetID()); |
200 | } |
201 | } |
202 | |
203 | if (check_children) { |
204 | for (DWARFDIE child : children()) { |
205 | if (DWARFDIE child_result = child.LookupDeepestBlock(address)) |
206 | return child_result; |
207 | } |
208 | } |
209 | return result; |
210 | } |
211 | |
212 | const char *DWARFDIE::GetMangledName(bool substitute_name_allowed) const { |
213 | if (IsValid()) |
214 | return m_die->GetMangledName(cu: m_cu, substitute_name_allowed); |
215 | else |
216 | return nullptr; |
217 | } |
218 | |
219 | const char *DWARFDIE::GetPubname() const { |
220 | if (IsValid()) |
221 | return m_die->GetPubname(cu: m_cu); |
222 | else |
223 | return nullptr; |
224 | } |
225 | |
226 | // GetName |
227 | // |
228 | // Get value of the DW_AT_name attribute and place that value into the supplied |
229 | // stream object. If the DIE is a NULL object "NULL" is placed into the stream, |
230 | // and if no DW_AT_name attribute exists for the DIE then nothing is printed. |
231 | void DWARFDIE::GetName(Stream &s) const { |
232 | if (!IsValid()) |
233 | return; |
234 | if (GetDIE()->IsNULL()) { |
235 | s.PutCString(cstr: "NULL" ); |
236 | return; |
237 | } |
238 | const char *name = GetDIE()->GetAttributeValueAsString(cu: GetCU(), attr: DW_AT_name, fail_value: nullptr, check_elaborating_dies: true); |
239 | if (!name) |
240 | return; |
241 | s.PutCString(cstr: name); |
242 | } |
243 | |
244 | // AppendTypeName |
245 | // |
246 | // Follows the type name definition down through all needed tags to end up with |
247 | // a fully qualified type name and dump the results to the supplied stream. |
248 | // This is used to show the name of types given a type identifier. |
249 | void DWARFDIE::AppendTypeName(Stream &s) const { |
250 | if (!IsValid()) |
251 | return; |
252 | if (GetDIE()->IsNULL()) { |
253 | s.PutCString(cstr: "NULL" ); |
254 | return; |
255 | } |
256 | if (const char *name = GetPubname()) { |
257 | s.PutCString(cstr: name); |
258 | return; |
259 | } |
260 | switch (Tag()) { |
261 | case DW_TAG_array_type: |
262 | break; // print out a "[]" after printing the full type of the element |
263 | // below |
264 | case DW_TAG_base_type: |
265 | s.PutCString(cstr: "base " ); |
266 | break; |
267 | case DW_TAG_class_type: |
268 | s.PutCString(cstr: "class " ); |
269 | break; |
270 | case DW_TAG_const_type: |
271 | s.PutCString(cstr: "const " ); |
272 | break; |
273 | case DW_TAG_enumeration_type: |
274 | s.PutCString(cstr: "enum " ); |
275 | break; |
276 | case DW_TAG_file_type: |
277 | s.PutCString(cstr: "file " ); |
278 | break; |
279 | case DW_TAG_interface_type: |
280 | s.PutCString(cstr: "interface " ); |
281 | break; |
282 | case DW_TAG_packed_type: |
283 | s.PutCString(cstr: "packed " ); |
284 | break; |
285 | case DW_TAG_pointer_type: |
286 | break; // print out a '*' after printing the full type below |
287 | case DW_TAG_ptr_to_member_type: |
288 | break; // print out a '*' after printing the full type below |
289 | case DW_TAG_reference_type: |
290 | break; // print out a '&' after printing the full type below |
291 | case DW_TAG_restrict_type: |
292 | s.PutCString(cstr: "restrict " ); |
293 | break; |
294 | case DW_TAG_set_type: |
295 | s.PutCString(cstr: "set " ); |
296 | break; |
297 | case DW_TAG_shared_type: |
298 | s.PutCString(cstr: "shared " ); |
299 | break; |
300 | case DW_TAG_string_type: |
301 | s.PutCString(cstr: "string " ); |
302 | break; |
303 | case DW_TAG_structure_type: |
304 | s.PutCString(cstr: "struct " ); |
305 | break; |
306 | case DW_TAG_subrange_type: |
307 | s.PutCString(cstr: "subrange " ); |
308 | break; |
309 | case DW_TAG_subroutine_type: |
310 | s.PutCString(cstr: "function " ); |
311 | break; |
312 | case DW_TAG_thrown_type: |
313 | s.PutCString(cstr: "thrown " ); |
314 | break; |
315 | case DW_TAG_union_type: |
316 | s.PutCString(cstr: "union " ); |
317 | break; |
318 | case DW_TAG_unspecified_type: |
319 | s.PutCString(cstr: "unspecified " ); |
320 | break; |
321 | case DW_TAG_volatile_type: |
322 | s.PutCString(cstr: "volatile " ); |
323 | break; |
324 | case DW_TAG_LLVM_ptrauth_type: { |
325 | unsigned key = GetAttributeValueAsUnsigned(attr: DW_AT_LLVM_ptrauth_key, fail_value: 0); |
326 | bool isAddressDiscriminated = GetAttributeValueAsUnsigned( |
327 | attr: DW_AT_LLVM_ptrauth_address_discriminated, fail_value: 0); |
328 | unsigned = |
329 | GetAttributeValueAsUnsigned(attr: DW_AT_LLVM_ptrauth_extra_discriminator, fail_value: 0); |
330 | bool isaPointer = |
331 | GetAttributeValueAsUnsigned(attr: DW_AT_LLVM_ptrauth_isa_pointer, fail_value: 0); |
332 | bool authenticatesNullValues = GetAttributeValueAsUnsigned( |
333 | attr: DW_AT_LLVM_ptrauth_authenticates_null_values, fail_value: 0); |
334 | unsigned authenticationMode = |
335 | GetAttributeValueAsUnsigned(attr: DW_AT_LLVM_ptrauth_authentication_mode, fail_value: 3); |
336 | |
337 | s.Printf(format: "__ptrauth(%d, %d, 0x0%x, %d, %d, %d)" , key, |
338 | isAddressDiscriminated, extraDiscriminator, isaPointer, |
339 | authenticatesNullValues, authenticationMode); |
340 | break; |
341 | } |
342 | default: |
343 | return; |
344 | } |
345 | |
346 | // Follow the DW_AT_type if possible |
347 | if (DWARFDIE next_die = GetAttributeValueAsReferenceDIE(attr: DW_AT_type)) |
348 | next_die.AppendTypeName(s); |
349 | |
350 | switch (Tag()) { |
351 | case DW_TAG_array_type: |
352 | s.PutCString(cstr: "[]" ); |
353 | break; |
354 | case DW_TAG_pointer_type: |
355 | s.PutChar(ch: '*'); |
356 | break; |
357 | case DW_TAG_ptr_to_member_type: |
358 | s.PutChar(ch: '*'); |
359 | break; |
360 | case DW_TAG_reference_type: |
361 | s.PutChar(ch: '&'); |
362 | break; |
363 | default: |
364 | break; |
365 | } |
366 | } |
367 | |
368 | lldb_private::Type *DWARFDIE::ResolveType() const { |
369 | if (IsValid()) |
370 | return GetDWARF()->ResolveType(die: *this, assert_not_being_parsed: true); |
371 | else |
372 | return nullptr; |
373 | } |
374 | |
375 | lldb_private::Type *DWARFDIE::ResolveTypeUID(const DWARFDIE &die) const { |
376 | if (SymbolFileDWARF *dwarf = GetDWARF()) |
377 | return dwarf->ResolveTypeUID(die, assert_not_being_parsed: true); |
378 | return nullptr; |
379 | } |
380 | |
381 | static CompilerContext GetContextEntry(DWARFDIE die, |
382 | bool derive_template_names) { |
383 | auto ctx = [die](CompilerContextKind kind) { |
384 | return CompilerContext(kind, ConstString(die.GetName())); |
385 | }; |
386 | |
387 | switch (die.Tag()) { |
388 | case DW_TAG_module: |
389 | return ctx(CompilerContextKind::Module); |
390 | case DW_TAG_namespace: |
391 | return ctx(CompilerContextKind::Namespace); |
392 | case DW_TAG_enumeration_type: |
393 | return ctx(CompilerContextKind::Enum); |
394 | case DW_TAG_subprogram: |
395 | return ctx(CompilerContextKind::Function); |
396 | case DW_TAG_variable: |
397 | return ctx(CompilerContextKind::Variable); |
398 | case DW_TAG_typedef: |
399 | return ctx(CompilerContextKind::Typedef); |
400 | case DW_TAG_base_type: |
401 | return ctx(CompilerContextKind::Builtin); |
402 | case DW_TAG_class_type: |
403 | case DW_TAG_structure_type: |
404 | case DW_TAG_union_type: { |
405 | CompilerContextKind kind = die.Tag() == DW_TAG_union_type |
406 | ? CompilerContextKind::Union |
407 | : CompilerContextKind::ClassOrStruct; |
408 | llvm::StringRef name = die.GetName(); |
409 | if (!derive_template_names || name.contains(C: '<')) |
410 | return CompilerContext(kind, ConstString(name)); |
411 | |
412 | std::string name_storage = name.str(); |
413 | llvm::raw_string_ostream os(name_storage); |
414 | llvm::DWARFTypePrinter<DWARFDIE>(os).appendAndTerminateTemplateParameters( |
415 | D: die); |
416 | return CompilerContext(kind, ConstString(os.str())); |
417 | } |
418 | default: |
419 | llvm_unreachable("Check tag type in the caller!" ); |
420 | } |
421 | } |
422 | |
423 | static void GetDeclContextImpl(DWARFDIE die, bool derive_template_names, |
424 | llvm::SmallSet<lldb::user_id_t, 4> &seen, |
425 | std::vector<CompilerContext> &context) { |
426 | // Stop if we hit a cycle. |
427 | while (die && seen.insert(V: die.GetID()).second) { |
428 | // Handle outline member function DIEs by following the specification. |
429 | if (DWARFDIE spec = die.GetReferencedDIE(attr: DW_AT_specification)) { |
430 | die = spec; |
431 | continue; |
432 | } |
433 | |
434 | // Add this DIE's contribution at the end of the chain. |
435 | switch (die.Tag()) { |
436 | case DW_TAG_module: |
437 | case DW_TAG_namespace: |
438 | case DW_TAG_class_type: |
439 | case DW_TAG_structure_type: |
440 | case DW_TAG_union_type: |
441 | case DW_TAG_enumeration_type: |
442 | case DW_TAG_subprogram: |
443 | case DW_TAG_variable: |
444 | case DW_TAG_typedef: |
445 | context.push_back(x: GetContextEntry(die, derive_template_names)); |
446 | break; |
447 | default: |
448 | break; |
449 | } |
450 | // Now process the parent. |
451 | die = die.GetParent(); |
452 | } |
453 | } |
454 | |
455 | std::vector<CompilerContext> |
456 | DWARFDIE::GetDeclContext(bool derive_template_names) const { |
457 | llvm::SmallSet<lldb::user_id_t, 4> seen; |
458 | std::vector<CompilerContext> context; |
459 | GetDeclContextImpl(die: *this, derive_template_names, seen, context); |
460 | std::reverse(first: context.begin(), last: context.end()); |
461 | return context; |
462 | } |
463 | |
464 | static void GetTypeLookupContextImpl(DWARFDIE die, bool derive_template_names, |
465 | llvm::SmallSet<lldb::user_id_t, 4> &seen, |
466 | std::vector<CompilerContext> &context) { |
467 | // Stop if we hit a cycle. |
468 | while (die && seen.insert(V: die.GetID()).second) { |
469 | // Add this DIE's contribution at the end of the chain. |
470 | switch (die.Tag()) { |
471 | case DW_TAG_namespace: |
472 | case DW_TAG_class_type: |
473 | case DW_TAG_structure_type: |
474 | case DW_TAG_union_type: |
475 | case DW_TAG_enumeration_type: |
476 | case DW_TAG_variable: |
477 | case DW_TAG_typedef: |
478 | case DW_TAG_base_type: |
479 | context.push_back(x: GetContextEntry(die, derive_template_names)); |
480 | break; |
481 | |
482 | // If any of the tags below appear in the parent chain, stop the decl |
483 | // context and return. Prior to these being in here, if a type existed in a |
484 | // namespace "a" like "a::my_struct", but we also have a function in that |
485 | // same namespace "a" which contained a type named "my_struct", both would |
486 | // return "a::my_struct" as the declaration context since the |
487 | // DW_TAG_subprogram would be skipped and its parent would be found. |
488 | case DW_TAG_compile_unit: |
489 | case DW_TAG_type_unit: |
490 | case DW_TAG_subprogram: |
491 | case DW_TAG_lexical_block: |
492 | case DW_TAG_inlined_subroutine: |
493 | return; |
494 | default: |
495 | break; |
496 | } |
497 | // Now process the parent. |
498 | die = die.GetParent(); |
499 | } |
500 | } |
501 | |
502 | std::vector<CompilerContext> |
503 | DWARFDIE::GetTypeLookupContext(bool derive_template_names) const { |
504 | llvm::SmallSet<lldb::user_id_t, 4> seen; |
505 | std::vector<CompilerContext> context; |
506 | GetTypeLookupContextImpl(die: *this, derive_template_names, seen, context); |
507 | std::reverse(first: context.begin(), last: context.end()); |
508 | return context; |
509 | } |
510 | |
511 | static DWARFDeclContext GetDWARFDeclContextImpl(DWARFDIE die) { |
512 | DWARFDeclContext dwarf_decl_ctx; |
513 | while (die) { |
514 | const dw_tag_t tag = die.Tag(); |
515 | if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit) |
516 | break; |
517 | dwarf_decl_ctx.AppendDeclContext(tag, name: die.GetName()); |
518 | DWARFDIE parent_decl_ctx_die = die.GetParentDeclContextDIE(); |
519 | if (parent_decl_ctx_die == die) |
520 | break; |
521 | die = parent_decl_ctx_die; |
522 | } |
523 | return dwarf_decl_ctx; |
524 | } |
525 | |
526 | DWARFDeclContext DWARFDIE::GetDWARFDeclContext() const { |
527 | return GetDWARFDeclContextImpl(die: *this); |
528 | } |
529 | |
530 | static DWARFDIE GetParentDeclContextDIEImpl(DWARFDIE die) { |
531 | DWARFDIE orig_die = die; |
532 | while (die) { |
533 | // If this is the original DIE that we are searching for a declaration for, |
534 | // then don't look in the cache as we don't want our own decl context to be |
535 | // our decl context... |
536 | if (die != orig_die) { |
537 | switch (die.Tag()) { |
538 | case DW_TAG_compile_unit: |
539 | case DW_TAG_partial_unit: |
540 | case DW_TAG_namespace: |
541 | case DW_TAG_structure_type: |
542 | case DW_TAG_union_type: |
543 | case DW_TAG_class_type: |
544 | return die; |
545 | |
546 | default: |
547 | break; |
548 | } |
549 | } |
550 | |
551 | if (DWARFDIE spec_die = die.GetReferencedDIE(attr: DW_AT_specification)) { |
552 | if (DWARFDIE decl_ctx_die = spec_die.GetParentDeclContextDIE()) |
553 | return decl_ctx_die; |
554 | } |
555 | |
556 | if (DWARFDIE abs_die = die.GetReferencedDIE(attr: DW_AT_abstract_origin)) { |
557 | if (DWARFDIE decl_ctx_die = abs_die.GetParentDeclContextDIE()) |
558 | return decl_ctx_die; |
559 | } |
560 | |
561 | die = die.GetParent(); |
562 | } |
563 | return DWARFDIE(); |
564 | } |
565 | |
566 | DWARFDIE |
567 | DWARFDIE::GetParentDeclContextDIE() const { |
568 | return GetParentDeclContextDIEImpl(die: *this); |
569 | } |
570 | |
571 | bool DWARFDIE::IsStructUnionOrClass() const { |
572 | const dw_tag_t tag = Tag(); |
573 | return tag == DW_TAG_class_type || tag == DW_TAG_structure_type || |
574 | tag == DW_TAG_union_type; |
575 | } |
576 | |
577 | bool DWARFDIE::IsMethod() const { |
578 | for (DWARFDIE d : elaborating_dies(die: *this)) |
579 | if (d.GetParent().IsStructUnionOrClass()) |
580 | return true; |
581 | return false; |
582 | } |
583 | |
584 | bool DWARFDIE::GetDIENamesAndRanges( |
585 | const char *&name, const char *&mangled, |
586 | llvm::DWARFAddressRangesVector &ranges, std::optional<int> &decl_file, |
587 | std::optional<int> &decl_line, std::optional<int> &decl_column, |
588 | std::optional<int> &call_file, std::optional<int> &call_line, |
589 | std::optional<int> &call_column, |
590 | lldb_private::DWARFExpressionList *frame_base) const { |
591 | if (IsValid()) { |
592 | return m_die->GetDIENamesAndRanges( |
593 | cu: GetCU(), name, mangled, rangeList&: ranges, decl_file, decl_line, decl_column, |
594 | call_file, call_line, call_column, frame_base); |
595 | } else |
596 | return false; |
597 | } |
598 | |
599 | // The following methods use LLVM naming convension in order to be are used by |
600 | // LLVM libraries. |
601 | llvm::iterator_range<DWARFDIE::child_iterator> DWARFDIE::children() const { |
602 | return llvm::make_range(x: child_iterator(*this), y: child_iterator()); |
603 | } |
604 | |
605 | DWARFDIE::child_iterator DWARFDIE::begin() const { |
606 | return child_iterator(*this); |
607 | } |
608 | |
609 | DWARFDIE::child_iterator DWARFDIE::end() const { return child_iterator(); } |
610 | |
611 | std::optional<DWARFFormValue> DWARFDIE::find(const dw_attr_t attr) const { |
612 | DWARFFormValue form_value; |
613 | if (m_die->GetAttributeValue(cu: m_cu, attr, formValue&: form_value, end_attr_offset_ptr: nullptr, check_elaborating_dies: false)) |
614 | return form_value; |
615 | return std::nullopt; |
616 | } |
617 | |
618 | std::optional<uint64_t> DWARFDIE::getLanguage() const { |
619 | if (IsValid()) |
620 | return m_cu->GetDWARFLanguageType(); |
621 | return std::nullopt; |
622 | } |
623 | |
624 | DWARFDIE DWARFDIE::resolveReferencedType(dw_attr_t attr) const { |
625 | return GetReferencedDIE(attr).resolveTypeUnitReference(); |
626 | } |
627 | |
628 | DWARFDIE DWARFDIE::resolveReferencedType(DWARFFormValue v) const { |
629 | if (IsValid()) |
630 | return v.Reference().resolveTypeUnitReference(); |
631 | return {}; |
632 | } |
633 | |
634 | DWARFDIE DWARFDIE::resolveTypeUnitReference() const { |
635 | if (DWARFDIE reference = GetReferencedDIE(attr: DW_AT_signature)) |
636 | return reference; |
637 | return *this; |
638 | } |
639 | |