1292932Sdim//===-- DWARFDIE.cpp --------------------------------------------*- C++ -*-===//
2292932Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6292932Sdim//
7292932Sdim//===----------------------------------------------------------------------===//
8292932Sdim
9292932Sdim#include "DWARFDIE.h"
10292932Sdim
11309124Sdim#include "DWARFASTParser.h"
12292932Sdim#include "DWARFDebugInfo.h"
13292932Sdim#include "DWARFDebugInfoEntry.h"
14292932Sdim#include "DWARFDeclContext.h"
15341825Sdim#include "DWARFUnit.h"
16292932Sdim
17292932Sdimusing namespace lldb_private;
18292932Sdim
19353358Sdimnamespace {
20292932Sdim
21353358Sdim/// Iterate through all DIEs elaborating (i.e. reachable by a chain of
22353358Sdim/// DW_AT_specification and DW_AT_abstract_origin attributes) a given DIE. For
23353358Sdim/// convenience, the starting die is included in the sequence as the first
24353358Sdim/// item.
25353358Sdimclass ElaboratingDIEIterator
26353358Sdim    : public std::iterator<std::input_iterator_tag, DWARFDIE> {
27292932Sdim
28353358Sdim  // The operating invariant is: top of m_worklist contains the "current" item
29353358Sdim  // and the rest of the list are items yet to be visited. An empty worklist
30353358Sdim  // means we've reached the end.
31353358Sdim  // Infinite recursion is prevented by maintaining a list of seen DIEs.
32353358Sdim  // Container sizes are optimized for the case of following DW_AT_specification
33353358Sdim  // and DW_AT_abstract_origin just once.
34353358Sdim  llvm::SmallVector<DWARFDIE, 2> m_worklist;
35353358Sdim  llvm::SmallSet<lldb::user_id_t, 3> m_seen;
36353358Sdim
37353358Sdim  void Next() {
38353358Sdim    assert(!m_worklist.empty() && "Incrementing end iterator?");
39353358Sdim
40353358Sdim    // Pop the current item from the list.
41353358Sdim    DWARFDIE die = m_worklist.back();
42353358Sdim    m_worklist.pop_back();
43353358Sdim
44353358Sdim    // And add back any items that elaborate it.
45353358Sdim    for (dw_attr_t attr : {DW_AT_specification, DW_AT_abstract_origin}) {
46353358Sdim      if (DWARFDIE d = die.GetReferencedDIE(attr))
47353358Sdim        if (m_seen.insert(die.GetID()).second)
48353358Sdim          m_worklist.push_back(d);
49353358Sdim    }
50341825Sdim  }
51353358Sdim
52353358Sdimpublic:
53353358Sdim  /// An iterator starting at die d.
54353358Sdim  explicit ElaboratingDIEIterator(DWARFDIE d) : m_worklist(1, d) {}
55353358Sdim
56353358Sdim  /// End marker
57353358Sdim  ElaboratingDIEIterator() {}
58353358Sdim
59353358Sdim  const DWARFDIE &operator*() const { return m_worklist.back(); }
60353358Sdim  ElaboratingDIEIterator &operator++() {
61353358Sdim    Next();
62353358Sdim    return *this;
63353358Sdim  }
64353358Sdim  ElaboratingDIEIterator operator++(int) {
65353358Sdim    ElaboratingDIEIterator I = *this;
66353358Sdim    Next();
67353358Sdim    return I;
68353358Sdim  }
69353358Sdim
70353358Sdim  friend bool operator==(const ElaboratingDIEIterator &a,
71353358Sdim                         const ElaboratingDIEIterator &b) {
72353358Sdim    if (a.m_worklist.empty() || b.m_worklist.empty())
73353358Sdim      return a.m_worklist.empty() == b.m_worklist.empty();
74353358Sdim    return a.m_worklist.back() == b.m_worklist.back();
75353358Sdim  }
76353358Sdim  friend bool operator!=(const ElaboratingDIEIterator &a,
77353358Sdim                         const ElaboratingDIEIterator &b) {
78353358Sdim    return !(a == b);
79353358Sdim  }
80353358Sdim};
81353358Sdim
82353358Sdimllvm::iterator_range<ElaboratingDIEIterator>
83353358Sdimelaborating_dies(const DWARFDIE &die) {
84353358Sdim  return llvm::make_range(ElaboratingDIEIterator(die),
85353358Sdim                          ElaboratingDIEIterator());
86292932Sdim}
87353358Sdim} // namespace
88292932Sdim
89292932SdimDWARFDIE
90314564SdimDWARFDIE::GetParent() const {
91314564Sdim  if (IsValid())
92314564Sdim    return DWARFDIE(m_cu, m_die->GetParent());
93314564Sdim  else
94314564Sdim    return DWARFDIE();
95292932Sdim}
96292932Sdim
97292932SdimDWARFDIE
98314564SdimDWARFDIE::GetFirstChild() const {
99314564Sdim  if (IsValid())
100314564Sdim    return DWARFDIE(m_cu, m_die->GetFirstChild());
101314564Sdim  else
102314564Sdim    return DWARFDIE();
103292932Sdim}
104292932Sdim
105292932SdimDWARFDIE
106314564SdimDWARFDIE::GetSibling() const {
107314564Sdim  if (IsValid())
108314564Sdim    return DWARFDIE(m_cu, m_die->GetSibling());
109314564Sdim  else
110314564Sdim    return DWARFDIE();
111292932Sdim}
112292932Sdim
113292932SdimDWARFDIE
114314564SdimDWARFDIE::GetReferencedDIE(const dw_attr_t attr) const {
115353358Sdim  if (IsValid())
116353358Sdim    return m_die->GetAttributeValueAsReference(GetCU(), attr);
117314564Sdim  else
118353358Sdim    return {};
119292932Sdim}
120292932Sdim
121292932SdimDWARFDIE
122314564SdimDWARFDIE::GetDIE(dw_offset_t die_offset) const {
123314564Sdim  if (IsValid())
124314564Sdim    return m_cu->GetDIE(die_offset);
125314564Sdim  else
126314564Sdim    return DWARFDIE();
127292932Sdim}
128292932Sdim
129309124SdimDWARFDIE
130314564SdimDWARFDIE::GetAttributeValueAsReferenceDIE(const dw_attr_t attr) const {
131314564Sdim  if (IsValid()) {
132341825Sdim    DWARFUnit *cu = GetCU();
133314564Sdim    const bool check_specification_or_abstract_origin = true;
134314564Sdim    DWARFFormValue form_value;
135353358Sdim    if (m_die->GetAttributeValue(cu, attr, form_value, nullptr,
136314564Sdim                                 check_specification_or_abstract_origin))
137353358Sdim      return form_value.Reference();
138314564Sdim  }
139314564Sdim  return DWARFDIE();
140309124Sdim}
141309124Sdim
142292932SdimDWARFDIE
143314564SdimDWARFDIE::LookupDeepestBlock(lldb::addr_t file_addr) const {
144314564Sdim  if (IsValid()) {
145314564Sdim    SymbolFileDWARF *dwarf = GetDWARF();
146341825Sdim    DWARFUnit *cu = GetCU();
147314564Sdim    DWARFDebugInfoEntry *function_die = nullptr;
148314564Sdim    DWARFDebugInfoEntry *block_die = nullptr;
149353358Sdim    if (m_die->LookupAddress(file_addr, cu, &function_die, &block_die)) {
150314564Sdim      if (block_die && block_die != function_die) {
151314564Sdim        if (cu->ContainsDIEOffset(block_die->GetOffset()))
152314564Sdim          return DWARFDIE(cu, block_die);
153314564Sdim        else
154353358Sdim          return DWARFDIE(dwarf->DebugInfo()->GetUnit(DIERef(
155353358Sdim                              cu->GetSymbolFileDWARF().GetDwoNum(),
156353358Sdim                              cu->GetDebugSection(), block_die->GetOffset())),
157314564Sdim                          block_die);
158314564Sdim      }
159292932Sdim    }
160314564Sdim  }
161314564Sdim  return DWARFDIE();
162292932Sdim}
163292932Sdim
164314564Sdimconst char *DWARFDIE::GetMangledName() const {
165314564Sdim  if (IsValid())
166353358Sdim    return m_die->GetMangledName(m_cu);
167314564Sdim  else
168314564Sdim    return nullptr;
169292932Sdim}
170292932Sdim
171314564Sdimconst char *DWARFDIE::GetPubname() const {
172314564Sdim  if (IsValid())
173353358Sdim    return m_die->GetPubname(m_cu);
174314564Sdim  else
175314564Sdim    return nullptr;
176292932Sdim}
177292932Sdim
178314564Sdimconst char *DWARFDIE::GetQualifiedName(std::string &storage) const {
179314564Sdim  if (IsValid())
180353358Sdim    return m_die->GetQualifiedName(m_cu, storage);
181314564Sdim  else
182314564Sdim    return nullptr;
183292932Sdim}
184292932Sdim
185353358Sdim// GetName
186353358Sdim//
187353358Sdim// Get value of the DW_AT_name attribute and place that value into the supplied
188353358Sdim// stream object. If the DIE is a NULL object "NULL" is placed into the stream,
189353358Sdim// and if no DW_AT_name attribute exists for the DIE then nothing is printed.
190353358Sdimvoid DWARFDIE::GetName(Stream &s) const {
191353358Sdim  if (!IsValid())
192353358Sdim    return;
193353358Sdim  if (GetDIE()->IsNULL()) {
194353358Sdim    s.PutCString("NULL");
195353358Sdim    return;
196353358Sdim  }
197353358Sdim  const char *name = GetDIE()->GetAttributeValueAsString(GetCU(), DW_AT_name, nullptr, true);
198353358Sdim  if (!name)
199353358Sdim    return;
200353358Sdim  s.PutCString(name);
201353358Sdim}
202353358Sdim
203353358Sdim// AppendTypeName
204353358Sdim//
205353358Sdim// Follows the type name definition down through all needed tags to end up with
206353358Sdim// a fully qualified type name and dump the results to the supplied stream.
207353358Sdim// This is used to show the name of types given a type identifier.
208353358Sdimvoid DWARFDIE::AppendTypeName(Stream &s) const {
209353358Sdim  if (!IsValid())
210353358Sdim    return;
211353358Sdim  if (GetDIE()->IsNULL()) {
212353358Sdim    s.PutCString("NULL");
213353358Sdim    return;
214353358Sdim  }
215353358Sdim  if (const char *name = GetPubname()) {
216353358Sdim    s.PutCString(name);
217353358Sdim    return;
218353358Sdim  }
219353358Sdim  switch (Tag()) {
220353358Sdim  case DW_TAG_array_type:
221353358Sdim    break; // print out a "[]" after printing the full type of the element
222353358Sdim           // below
223353358Sdim  case DW_TAG_base_type:
224353358Sdim    s.PutCString("base ");
225353358Sdim    break;
226353358Sdim  case DW_TAG_class_type:
227353358Sdim    s.PutCString("class ");
228353358Sdim    break;
229353358Sdim  case DW_TAG_const_type:
230353358Sdim    s.PutCString("const ");
231353358Sdim    break;
232353358Sdim  case DW_TAG_enumeration_type:
233353358Sdim    s.PutCString("enum ");
234353358Sdim    break;
235353358Sdim  case DW_TAG_file_type:
236353358Sdim    s.PutCString("file ");
237353358Sdim    break;
238353358Sdim  case DW_TAG_interface_type:
239353358Sdim    s.PutCString("interface ");
240353358Sdim    break;
241353358Sdim  case DW_TAG_packed_type:
242353358Sdim    s.PutCString("packed ");
243353358Sdim    break;
244353358Sdim  case DW_TAG_pointer_type:
245353358Sdim    break; // print out a '*' after printing the full type below
246353358Sdim  case DW_TAG_ptr_to_member_type:
247353358Sdim    break; // print out a '*' after printing the full type below
248353358Sdim  case DW_TAG_reference_type:
249353358Sdim    break; // print out a '&' after printing the full type below
250353358Sdim  case DW_TAG_restrict_type:
251353358Sdim    s.PutCString("restrict ");
252353358Sdim    break;
253353358Sdim  case DW_TAG_set_type:
254353358Sdim    s.PutCString("set ");
255353358Sdim    break;
256353358Sdim  case DW_TAG_shared_type:
257353358Sdim    s.PutCString("shared ");
258353358Sdim    break;
259353358Sdim  case DW_TAG_string_type:
260353358Sdim    s.PutCString("string ");
261353358Sdim    break;
262353358Sdim  case DW_TAG_structure_type:
263353358Sdim    s.PutCString("struct ");
264353358Sdim    break;
265353358Sdim  case DW_TAG_subrange_type:
266353358Sdim    s.PutCString("subrange ");
267353358Sdim    break;
268353358Sdim  case DW_TAG_subroutine_type:
269353358Sdim    s.PutCString("function ");
270353358Sdim    break;
271353358Sdim  case DW_TAG_thrown_type:
272353358Sdim    s.PutCString("thrown ");
273353358Sdim    break;
274353358Sdim  case DW_TAG_union_type:
275353358Sdim    s.PutCString("union ");
276353358Sdim    break;
277353358Sdim  case DW_TAG_unspecified_type:
278353358Sdim    s.PutCString("unspecified ");
279353358Sdim    break;
280353358Sdim  case DW_TAG_volatile_type:
281353358Sdim    s.PutCString("volatile ");
282353358Sdim    break;
283353358Sdim  default:
284353358Sdim    return;
285353358Sdim  }
286353358Sdim
287353358Sdim  // Follow the DW_AT_type if possible
288353358Sdim  if (DWARFDIE next_die = GetAttributeValueAsReferenceDIE(DW_AT_type))
289353358Sdim    next_die.AppendTypeName(s);
290353358Sdim
291353358Sdim  switch (Tag()) {
292353358Sdim  case DW_TAG_array_type:
293353358Sdim    s.PutCString("[]");
294353358Sdim    break;
295353358Sdim  case DW_TAG_pointer_type:
296353358Sdim    s.PutChar('*');
297353358Sdim    break;
298353358Sdim  case DW_TAG_ptr_to_member_type:
299353358Sdim    s.PutChar('*');
300353358Sdim    break;
301353358Sdim  case DW_TAG_reference_type:
302353358Sdim    s.PutChar('&');
303353358Sdim    break;
304353358Sdim  default:
305353358Sdim    break;
306353358Sdim  }
307353358Sdim}
308353358Sdim
309314564Sdimlldb_private::Type *DWARFDIE::ResolveType() const {
310314564Sdim  if (IsValid())
311314564Sdim    return GetDWARF()->ResolveType(*this, true);
312314564Sdim  else
313314564Sdim    return nullptr;
314292932Sdim}
315292932Sdim
316353358Sdimlldb_private::Type *DWARFDIE::ResolveTypeUID(const DWARFDIE &die) const {
317353358Sdim  if (SymbolFileDWARF *dwarf = GetDWARF())
318353358Sdim    return dwarf->ResolveTypeUID(die, true);
319353358Sdim  return nullptr;
320292932Sdim}
321292932Sdim
322353358Sdimstd::vector<DWARFDIE> DWARFDIE::GetDeclContextDIEs() const {
323353358Sdim  if (!IsValid())
324353358Sdim    return {};
325353358Sdim
326353358Sdim  std::vector<DWARFDIE> result;
327353358Sdim  DWARFDIE parent = GetParentDeclContextDIE();
328353358Sdim  while (parent.IsValid() && parent.GetDIE() != GetDIE()) {
329353358Sdim    result.push_back(std::move(parent));
330353358Sdim    parent = parent.GetParentDeclContextDIE();
331314564Sdim  }
332353358Sdim
333353358Sdim  return result;
334292932Sdim}
335292932Sdim
336314564Sdimvoid DWARFDIE::GetDWARFDeclContext(DWARFDeclContext &dwarf_decl_ctx) const {
337314564Sdim  if (IsValid()) {
338314564Sdim    dwarf_decl_ctx.SetLanguage(GetLanguage());
339353358Sdim    m_die->GetDWARFDeclContext(GetCU(), dwarf_decl_ctx);
340314564Sdim  } else {
341314564Sdim    dwarf_decl_ctx.Clear();
342314564Sdim  }
343292932Sdim}
344292932Sdim
345360784Sdimvoid DWARFDIE::GetDeclContext(
346360784Sdim    llvm::SmallVectorImpl<lldb_private::CompilerContext> &context) const {
347314564Sdim  const dw_tag_t tag = Tag();
348341825Sdim  if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit)
349314564Sdim    return;
350314564Sdim  DWARFDIE parent = GetParent();
351314564Sdim  if (parent)
352344779Sdim    parent.GetDeclContext(context);
353314564Sdim  switch (tag) {
354314564Sdim  case DW_TAG_module:
355360784Sdim    context.push_back({CompilerContextKind::Module, ConstString(GetName())});
356314564Sdim    break;
357314564Sdim  case DW_TAG_namespace:
358360784Sdim    context.push_back({CompilerContextKind::Namespace, ConstString(GetName())});
359314564Sdim    break;
360314564Sdim  case DW_TAG_structure_type:
361360784Sdim    context.push_back({CompilerContextKind::Struct, ConstString(GetName())});
362314564Sdim    break;
363314564Sdim  case DW_TAG_union_type:
364360784Sdim    context.push_back({CompilerContextKind::Union, ConstString(GetName())});
365314564Sdim    break;
366314564Sdim  case DW_TAG_class_type:
367360784Sdim    context.push_back({CompilerContextKind::Class, ConstString(GetName())});
368314564Sdim    break;
369314564Sdim  case DW_TAG_enumeration_type:
370360784Sdim    context.push_back({CompilerContextKind::Enum, ConstString(GetName())});
371314564Sdim    break;
372314564Sdim  case DW_TAG_subprogram:
373360784Sdim    context.push_back(
374360784Sdim        {CompilerContextKind::Function, ConstString(GetPubname())});
375314564Sdim    break;
376314564Sdim  case DW_TAG_variable:
377360784Sdim    context.push_back(
378360784Sdim        {CompilerContextKind::Variable, ConstString(GetPubname())});
379314564Sdim    break;
380314564Sdim  case DW_TAG_typedef:
381360784Sdim    context.push_back({CompilerContextKind::Typedef, ConstString(GetName())});
382314564Sdim    break;
383314564Sdim  default:
384314564Sdim    break;
385314564Sdim  }
386292932Sdim}
387292932Sdim
388292932SdimDWARFDIE
389314564SdimDWARFDIE::GetParentDeclContextDIE() const {
390314564Sdim  if (IsValid())
391353358Sdim    return m_die->GetParentDeclContextDIE(m_cu);
392314564Sdim  else
393314564Sdim    return DWARFDIE();
394292932Sdim}
395292932Sdim
396341825Sdimbool DWARFDIE::IsStructUnionOrClass() const {
397341825Sdim  const dw_tag_t tag = Tag();
398341825Sdim  return tag == DW_TAG_class_type || tag == DW_TAG_structure_type ||
399341825Sdim         tag == DW_TAG_union_type;
400292932Sdim}
401292932Sdim
402341825Sdimbool DWARFDIE::IsMethod() const {
403353358Sdim  for (DWARFDIE d : elaborating_dies(*this))
404341825Sdim    if (d.GetParent().IsStructUnionOrClass())
405341825Sdim      return true;
406341825Sdim  return false;
407292932Sdim}
408292932Sdim
409314564Sdimbool DWARFDIE::GetDIENamesAndRanges(
410314564Sdim    const char *&name, const char *&mangled, DWARFRangeList &ranges,
411314564Sdim    int &decl_file, int &decl_line, int &decl_column, int &call_file,
412314564Sdim    int &call_line, int &call_column,
413314564Sdim    lldb_private::DWARFExpression *frame_base) const {
414314564Sdim  if (IsValid()) {
415314564Sdim    return m_die->GetDIENamesAndRanges(
416353358Sdim        GetCU(), name, mangled, ranges, decl_file, decl_line, decl_column,
417353358Sdim        call_file, call_line, call_column, frame_base);
418314564Sdim  } else
419314564Sdim    return false;
420292932Sdim}
421292932Sdim
422314564SdimCompilerDecl DWARFDIE::GetDecl() const {
423314564Sdim  DWARFASTParser *dwarf_ast = GetDWARFParser();
424314564Sdim  if (dwarf_ast)
425314564Sdim    return dwarf_ast->GetDeclForUIDFromDWARF(*this);
426314564Sdim  else
427314564Sdim    return CompilerDecl();
428309124Sdim}
429309124Sdim
430314564SdimCompilerDeclContext DWARFDIE::GetDeclContext() const {
431314564Sdim  DWARFASTParser *dwarf_ast = GetDWARFParser();
432314564Sdim  if (dwarf_ast)
433314564Sdim    return dwarf_ast->GetDeclContextForUIDFromDWARF(*this);
434314564Sdim  else
435314564Sdim    return CompilerDeclContext();
436309124Sdim}
437309124Sdim
438314564SdimCompilerDeclContext DWARFDIE::GetContainingDeclContext() const {
439314564Sdim  DWARFASTParser *dwarf_ast = GetDWARFParser();
440314564Sdim  if (dwarf_ast)
441314564Sdim    return dwarf_ast->GetDeclContextContainingUIDFromDWARF(*this);
442314564Sdim  else
443314564Sdim    return CompilerDeclContext();
444309124Sdim}
445