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