1//===-- AppleDWARFIndex.cpp ------------------------------------*- C++ -*-===//
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 "Plugins/SymbolFile/DWARF/AppleDWARFIndex.h"
10#include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h"
11#include "Plugins/SymbolFile/DWARF/DWARFUnit.h"
12#include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h"
13
14#include "lldb/Core/Module.h"
15#include "lldb/Symbol/Function.h"
16
17using namespace lldb_private;
18using namespace lldb;
19
20std::unique_ptr<AppleDWARFIndex> AppleDWARFIndex::Create(
21    Module &module, DWARFDataExtractor apple_names,
22    DWARFDataExtractor apple_namespaces, DWARFDataExtractor apple_types,
23    DWARFDataExtractor apple_objc, DWARFDataExtractor debug_str) {
24  auto apple_names_table_up = std::make_unique<DWARFMappedHash::MemoryTable>(
25      apple_names, debug_str, ".apple_names");
26  if (!apple_names_table_up->IsValid())
27    apple_names_table_up.reset();
28
29  auto apple_namespaces_table_up =
30      std::make_unique<DWARFMappedHash::MemoryTable>(
31          apple_namespaces, debug_str, ".apple_namespaces");
32  if (!apple_namespaces_table_up->IsValid())
33    apple_namespaces_table_up.reset();
34
35  auto apple_types_table_up = std::make_unique<DWARFMappedHash::MemoryTable>(
36      apple_types, debug_str, ".apple_types");
37  if (!apple_types_table_up->IsValid())
38    apple_types_table_up.reset();
39
40  auto apple_objc_table_up = std::make_unique<DWARFMappedHash::MemoryTable>(
41      apple_objc, debug_str, ".apple_objc");
42  if (!apple_objc_table_up->IsValid())
43    apple_objc_table_up.reset();
44
45  if (apple_names_table_up || apple_names_table_up || apple_types_table_up ||
46      apple_objc_table_up)
47    return std::make_unique<AppleDWARFIndex>(
48        module, std::move(apple_names_table_up),
49        std::move(apple_namespaces_table_up), std::move(apple_types_table_up),
50        std::move(apple_objc_table_up));
51
52  return nullptr;
53}
54
55void AppleDWARFIndex::GetGlobalVariables(ConstString basename, DIEArray &offsets) {
56  if (m_apple_names_up)
57    m_apple_names_up->FindByName(basename.GetStringRef(), offsets);
58}
59
60void AppleDWARFIndex::GetGlobalVariables(const RegularExpression &regex,
61                                         DIEArray &offsets) {
62  if (!m_apple_names_up)
63    return;
64
65  DWARFMappedHash::DIEInfoArray hash_data;
66  if (m_apple_names_up->AppendAllDIEsThatMatchingRegex(regex, hash_data))
67    DWARFMappedHash::ExtractDIEArray(hash_data, offsets);
68}
69
70void AppleDWARFIndex::GetGlobalVariables(const DWARFUnit &cu,
71                                         DIEArray &offsets) {
72  if (!m_apple_names_up)
73    return;
74
75  DWARFMappedHash::DIEInfoArray hash_data;
76  if (m_apple_names_up->AppendAllDIEsInRange(cu.GetOffset(),
77                                             cu.GetNextUnitOffset(), hash_data))
78    DWARFMappedHash::ExtractDIEArray(hash_data, offsets);
79}
80
81void AppleDWARFIndex::GetObjCMethods(ConstString class_name,
82                                     DIEArray &offsets) {
83  if (m_apple_objc_up)
84    m_apple_objc_up->FindByName(class_name.GetStringRef(), offsets);
85}
86
87void AppleDWARFIndex::GetCompleteObjCClass(ConstString class_name,
88                                           bool must_be_implementation,
89                                           DIEArray &offsets) {
90  if (m_apple_types_up) {
91    m_apple_types_up->FindCompleteObjCClassByName(
92        class_name.GetStringRef(), offsets, must_be_implementation);
93  }
94}
95
96void AppleDWARFIndex::GetTypes(ConstString name, DIEArray &offsets) {
97  if (m_apple_types_up)
98    m_apple_types_up->FindByName(name.GetStringRef(), offsets);
99}
100
101void AppleDWARFIndex::GetTypes(const DWARFDeclContext &context,
102                               DIEArray &offsets) {
103  if (!m_apple_types_up)
104    return;
105
106  Log *log = LogChannelDWARF::GetLogIfAny(DWARF_LOG_TYPE_COMPLETION |
107                                          DWARF_LOG_LOOKUPS);
108  const bool has_tag = m_apple_types_up->GetHeader().header_data.ContainsAtom(
109      DWARFMappedHash::eAtomTypeTag);
110  const bool has_qualified_name_hash =
111      m_apple_types_up->GetHeader().header_data.ContainsAtom(
112          DWARFMappedHash::eAtomTypeQualNameHash);
113
114  const ConstString type_name(context[0].name);
115  const dw_tag_t tag = context[0].tag;
116  if (has_tag && has_qualified_name_hash) {
117    const char *qualified_name = context.GetQualifiedName();
118    const uint32_t qualified_name_hash = llvm::djbHash(qualified_name);
119    if (log)
120      m_module.LogMessage(log, "FindByNameAndTagAndQualifiedNameHash()");
121    m_apple_types_up->FindByNameAndTagAndQualifiedNameHash(
122        type_name.GetStringRef(), tag, qualified_name_hash, offsets);
123    return;
124  }
125
126  if (has_tag) {
127    // When searching for a scoped type (for example,
128    // "std::vector<int>::const_iterator") searching for the innermost
129    // name alone ("const_iterator") could yield many false
130    // positives. By searching for the parent type ("vector<int>")
131    // first we can avoid extracting type DIEs from object files that
132    // would fail the filter anyway.
133    if (!has_qualified_name_hash && (context.GetSize() > 1) &&
134        (context[1].tag == DW_TAG_class_type ||
135         context[1].tag == DW_TAG_structure_type)) {
136      DIEArray class_matches;
137      m_apple_types_up->FindByName(context[1].name, class_matches);
138      if (class_matches.empty())
139        return;
140    }
141
142    if (log)
143      m_module.LogMessage(log, "FindByNameAndTag()");
144    m_apple_types_up->FindByNameAndTag(type_name.GetStringRef(), tag, offsets);
145    return;
146  }
147
148  m_apple_types_up->FindByName(type_name.GetStringRef(), offsets);
149}
150
151void AppleDWARFIndex::GetNamespaces(ConstString name, DIEArray &offsets) {
152  if (m_apple_namespaces_up)
153    m_apple_namespaces_up->FindByName(name.GetStringRef(), offsets);
154}
155
156void AppleDWARFIndex::GetFunctions(ConstString name, SymbolFileDWARF &dwarf,
157                                   const CompilerDeclContext &parent_decl_ctx,
158                                   uint32_t name_type_mask,
159                                   std::vector<DWARFDIE> &dies) {
160  DIEArray offsets;
161  m_apple_names_up->FindByName(name.GetStringRef(), offsets);
162  for (const DIERef &die_ref : offsets) {
163    ProcessFunctionDIE(name.GetStringRef(), die_ref, dwarf, parent_decl_ctx,
164                       name_type_mask, dies);
165  }
166}
167
168void AppleDWARFIndex::GetFunctions(const RegularExpression &regex,
169                                   DIEArray &offsets) {
170  if (!m_apple_names_up)
171    return;
172
173  DWARFMappedHash::DIEInfoArray hash_data;
174  if (m_apple_names_up->AppendAllDIEsThatMatchingRegex(regex, hash_data))
175    DWARFMappedHash::ExtractDIEArray(hash_data, offsets);
176}
177
178void AppleDWARFIndex::ReportInvalidDIERef(const DIERef &ref,
179                                          llvm::StringRef name) {
180  m_module.ReportErrorIfModifyDetected(
181      "the DWARF debug information has been modified (accelerator table had "
182      "bad die 0x%8.8x for '%s')\n",
183      ref.die_offset(), name.str().c_str());
184}
185
186void AppleDWARFIndex::Dump(Stream &s) {
187  if (m_apple_names_up)
188    s.PutCString(".apple_names index present\n");
189  if (m_apple_namespaces_up)
190    s.PutCString(".apple_namespaces index present\n");
191  if (m_apple_types_up)
192    s.PutCString(".apple_types index present\n");
193  if (m_apple_objc_up)
194    s.PutCString(".apple_objc index present\n");
195  // TODO: Dump index contents
196}
197