xref: /llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp (revision 7e00e3ae6dd4ba215dad27d1729df533cbb37795)
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(die.GetDIE()).second)
61           m_worklist.push_back(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(ElaboratingDIEIterator(die),
89                           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(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, form_value, 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(m_cu, /*check_hi_lo_pc=*/true)) {
181       bool addr_in_range =
182           llvm::any_of(*ranges, [&](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(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(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("NULL");
236     return;
237   }
238   const char *name = GetDIE()->GetAttributeValueAsString(GetCU(), DW_AT_name, nullptr, true);
239   if (!name)
240     return;
241   s.PutCString(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("NULL");
254     return;
255   }
256   if (const char *name = GetPubname()) {
257     s.PutCString(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("base ");
266     break;
267   case DW_TAG_class_type:
268     s.PutCString("class ");
269     break;
270   case DW_TAG_const_type:
271     s.PutCString("const ");
272     break;
273   case DW_TAG_enumeration_type:
274     s.PutCString("enum ");
275     break;
276   case DW_TAG_file_type:
277     s.PutCString("file ");
278     break;
279   case DW_TAG_interface_type:
280     s.PutCString("interface ");
281     break;
282   case DW_TAG_packed_type:
283     s.PutCString("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("restrict ");
293     break;
294   case DW_TAG_set_type:
295     s.PutCString("set ");
296     break;
297   case DW_TAG_shared_type:
298     s.PutCString("shared ");
299     break;
300   case DW_TAG_string_type:
301     s.PutCString("string ");
302     break;
303   case DW_TAG_structure_type:
304     s.PutCString("struct ");
305     break;
306   case DW_TAG_subrange_type:
307     s.PutCString("subrange ");
308     break;
309   case DW_TAG_subroutine_type:
310     s.PutCString("function ");
311     break;
312   case DW_TAG_thrown_type:
313     s.PutCString("thrown ");
314     break;
315   case DW_TAG_union_type:
316     s.PutCString("union ");
317     break;
318   case DW_TAG_unspecified_type:
319     s.PutCString("unspecified ");
320     break;
321   case DW_TAG_volatile_type:
322     s.PutCString("volatile ");
323     break;
324   case DW_TAG_LLVM_ptrauth_type: {
325     unsigned key = GetAttributeValueAsUnsigned(DW_AT_LLVM_ptrauth_key, 0);
326     bool isAddressDiscriminated = GetAttributeValueAsUnsigned(
327         DW_AT_LLVM_ptrauth_address_discriminated, 0);
328     unsigned extraDiscriminator =
329         GetAttributeValueAsUnsigned(DW_AT_LLVM_ptrauth_extra_discriminator, 0);
330     bool isaPointer =
331         GetAttributeValueAsUnsigned(DW_AT_LLVM_ptrauth_isa_pointer, 0);
332     bool authenticatesNullValues = GetAttributeValueAsUnsigned(
333         DW_AT_LLVM_ptrauth_authenticates_null_values, 0);
334     unsigned authenticationMode =
335         GetAttributeValueAsUnsigned(DW_AT_LLVM_ptrauth_authentication_mode, 3);
336 
337     s.Printf("__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(DW_AT_type))
348     next_die.AppendTypeName(s);
349 
350   switch (Tag()) {
351   case DW_TAG_array_type:
352     s.PutCString("[]");
353     break;
354   case DW_TAG_pointer_type:
355     s.PutChar('*');
356     break;
357   case DW_TAG_ptr_to_member_type:
358     s.PutChar('*');
359     break;
360   case DW_TAG_reference_type:
361     s.PutChar('&');
362     break;
363   default:
364     break;
365   }
366 }
367 
368 lldb_private::Type *DWARFDIE::ResolveType() const {
369   if (IsValid())
370     return GetDWARF()->ResolveType(*this, 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, 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('<'))
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         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(die.GetID()).second) {
428     // Handle outline member function DIEs by following the specification.
429     if (DWARFDIE spec = die.GetReferencedDIE(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(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(*this, derive_template_names, seen, context);
460   std::reverse(context.begin(), 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(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(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(*this, derive_template_names, seen, context);
507   std::reverse(context.begin(), 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, 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(*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(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(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(*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(*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         GetCU(), name, mangled, 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(child_iterator(*this), 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(m_cu, attr, form_value, nullptr, 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);
626 }
627 
628 DWARFDIE DWARFDIE::resolveReferencedType(DWARFFormValue v) const {
629   if (IsValid())
630     return v.Reference();
631   return {};
632 }
633 
634 DWARFDIE DWARFDIE::resolveTypeUnitReference() const {
635   if (DWARFDIE reference = GetReferencedDIE(DW_AT_signature))
636     return reference;
637   return *this;
638 }
639