Skip to content

Commit 1237095

Browse files
committed
[DWARF] Extract indexing code into a separate class hierarchy
Summary: This places the `if(m_using_apple_tables)` branches inside the SymbolFileDWARF class behind an abstract DWARFIndex class. The class currently has two implementations: - AppleIndex, which searches using .apple_names and friends - ManualIndex, which searches using a manually built index Most of the methods of the class are very simple, and simply extract the list of DIEs for the given name from the appropriate sub-table. The main exception are the two GetFunctions overloads, which take a couple of extra paramenters, including some callbacks. It was not possible to split these up the same way as other methods, as here we were doing a lot of post-processing on the results. The post-processing is similar for the two cases, but not identical. I hope to factor these further in separate patches. Other interesting methods are: - Preload(): do any preprocessing to make lookups faster (noop for AppleIndex, forces a build of the lookup tables for ManualIndex). - ReportInvalidDIEOffset(): Used to notify the users of an invalid index (prints a message for AppleIndex, noop for ManualIndex). - Dump(): dumps the index state (noop for AppleIndex, prints the lookup tables for ManualIndex). Reviewers: clayborg, JDevlieghere Subscribers: mgorny, aprantl, lldb-commits Differential Revision: https://reviews.llvm.org/D46889 llvm-svn: 332719
1 parent c4b8d36 commit 1237095

12 files changed

+911
-702
lines changed
Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,306 @@
1+
//===-- AppleDWARFIndex.cpp ------------------------------------*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include "Plugins/SymbolFile/DWARF/AppleDWARFIndex.h"
11+
#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"
12+
#include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h"
13+
#include "Plugins/SymbolFile/DWARF/DWARFUnit.h"
14+
#include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h"
15+
16+
#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
17+
#include "Plugins/Language/ObjC/ObjCLanguage.h"
18+
#include "lldb/Core/Module.h"
19+
#include "lldb/Symbol/Function.h"
20+
21+
using namespace lldb_private;
22+
using namespace lldb;
23+
24+
std::unique_ptr<AppleDWARFIndex> AppleDWARFIndex::Create(
25+
Module &module, DWARFDataExtractor apple_names,
26+
DWARFDataExtractor apple_namespaces, DWARFDataExtractor apple_types,
27+
DWARFDataExtractor apple_objc, DWARFDataExtractor debug_str) {
28+
auto apple_names_table_up = llvm::make_unique<DWARFMappedHash::MemoryTable>(
29+
apple_names, debug_str, ".apple_names");
30+
if (!apple_names_table_up->IsValid())
31+
apple_names_table_up.reset();
32+
33+
auto apple_namespaces_table_up =
34+
llvm::make_unique<DWARFMappedHash::MemoryTable>(
35+
apple_namespaces, debug_str, ".apple_namespaces");
36+
if (!apple_namespaces_table_up->IsValid())
37+
apple_namespaces_table_up.reset();
38+
39+
auto apple_types_table_up = llvm::make_unique<DWARFMappedHash::MemoryTable>(
40+
apple_types, debug_str, ".apple_types");
41+
if (!apple_types_table_up->IsValid())
42+
apple_types_table_up.reset();
43+
44+
auto apple_objc_table_up = llvm::make_unique<DWARFMappedHash::MemoryTable>(
45+
apple_objc, debug_str, ".apple_objc");
46+
if (!apple_objc_table_up->IsValid())
47+
apple_objc_table_up.reset();
48+
49+
if (apple_names_table_up || apple_names_table_up || apple_types_table_up ||
50+
apple_objc_table_up)
51+
return llvm::make_unique<AppleDWARFIndex>(
52+
module, std::move(apple_names_table_up),
53+
std::move(apple_namespaces_table_up), std::move(apple_types_table_up),
54+
std::move(apple_objc_table_up));
55+
56+
return nullptr;
57+
}
58+
59+
void AppleDWARFIndex::GetGlobalVariables(ConstString name, DIEArray &offsets) {
60+
if (!m_apple_names_up)
61+
return;
62+
63+
const char *name_cstr = name.GetCString();
64+
llvm::StringRef basename;
65+
llvm::StringRef context;
66+
67+
if (!CPlusPlusLanguage::ExtractContextAndIdentifier(name_cstr, context,
68+
basename))
69+
basename = name_cstr;
70+
71+
m_apple_names_up->FindByName(basename, offsets);
72+
}
73+
74+
void AppleDWARFIndex::GetGlobalVariables(const RegularExpression &regex,
75+
DIEArray &offsets) {
76+
if (!m_apple_names_up)
77+
return;
78+
79+
DWARFMappedHash::DIEInfoArray hash_data;
80+
if (m_apple_names_up->AppendAllDIEsThatMatchingRegex(regex, hash_data))
81+
DWARFMappedHash::ExtractDIEArray(hash_data, offsets);
82+
}
83+
84+
void AppleDWARFIndex::GetGlobalVariables(const DWARFUnit &cu,
85+
DIEArray &offsets) {
86+
if (!m_apple_names_up)
87+
return;
88+
89+
DWARFMappedHash::DIEInfoArray hash_data;
90+
if (m_apple_names_up->AppendAllDIEsInRange(
91+
cu.GetOffset(), cu.GetNextCompileUnitOffset(), hash_data))
92+
DWARFMappedHash::ExtractDIEArray(hash_data, offsets);
93+
}
94+
95+
void AppleDWARFIndex::GetObjCMethods(ConstString class_name,
96+
DIEArray &offsets) {
97+
if (m_apple_objc_up)
98+
m_apple_objc_up->FindByName(class_name.GetStringRef(), offsets);
99+
}
100+
101+
void AppleDWARFIndex::GetCompleteObjCClass(ConstString class_name,
102+
bool must_be_implementation,
103+
DIEArray &offsets) {
104+
if (m_apple_types_up) {
105+
m_apple_types_up->FindCompleteObjCClassByName(
106+
class_name.GetStringRef(), offsets, must_be_implementation);
107+
}
108+
}
109+
110+
void AppleDWARFIndex::GetTypes(ConstString name, DIEArray &offsets) {
111+
if (m_apple_types_up)
112+
m_apple_types_up->FindByName(name.GetStringRef(), offsets);
113+
}
114+
115+
void AppleDWARFIndex::GetTypes(const DWARFDeclContext &context,
116+
DIEArray &offsets) {
117+
if (!m_apple_types_up)
118+
return;
119+
120+
Log *log = LogChannelDWARF::GetLogIfAny(DWARF_LOG_TYPE_COMPLETION |
121+
DWARF_LOG_LOOKUPS);
122+
const bool has_tag = m_apple_types_up->GetHeader().header_data.ContainsAtom(
123+
DWARFMappedHash::eAtomTypeTag);
124+
const bool has_qualified_name_hash =
125+
m_apple_types_up->GetHeader().header_data.ContainsAtom(
126+
DWARFMappedHash::eAtomTypeQualNameHash);
127+
const ConstString type_name(context[0].name);
128+
const dw_tag_t tag = context[0].tag;
129+
if (has_tag && has_qualified_name_hash) {
130+
const char *qualified_name = context.GetQualifiedName();
131+
const uint32_t qualified_name_hash = llvm::djbHash(qualified_name);
132+
if (log)
133+
m_module.LogMessage(log, "FindByNameAndTagAndQualifiedNameHash()");
134+
m_apple_types_up->FindByNameAndTagAndQualifiedNameHash(
135+
type_name.GetStringRef(), tag, qualified_name_hash, offsets);
136+
} else if (has_tag) {
137+
if (log)
138+
m_module.LogMessage(log, "FindByNameAndTag()");
139+
m_apple_types_up->FindByNameAndTag(type_name.GetStringRef(), tag, offsets);
140+
} else
141+
m_apple_types_up->FindByName(type_name.GetStringRef(), offsets);
142+
}
143+
144+
void AppleDWARFIndex::GetNamespaces(ConstString name, DIEArray &offsets) {
145+
if (m_apple_namespaces_up)
146+
m_apple_namespaces_up->FindByName(name.GetStringRef(), offsets);
147+
}
148+
149+
void AppleDWARFIndex::GetFunctions(
150+
ConstString name, DWARFDebugInfo &info,
151+
llvm::function_ref<bool(const DWARFDIE &die, bool include_inlines,
152+
lldb_private::SymbolContextList &sc_list)>
153+
resolve_function,
154+
llvm::function_ref<CompilerDeclContext(lldb::user_id_t type_uid)>
155+
get_decl_context_containing_uid,
156+
const CompilerDeclContext *parent_decl_ctx, uint32_t name_type_mask,
157+
bool include_inlines, SymbolContextList &sc_list) {
158+
if (!m_apple_names_up)
159+
return;
160+
161+
std::set<const DWARFDebugInfoEntry *> resolved_dies;
162+
DIEArray offsets;
163+
164+
uint32_t num_matches = 0;
165+
166+
if (name_type_mask & eFunctionNameTypeFull) {
167+
// If they asked for the full name, match what they typed. At some
168+
// point we may want to canonicalize this (strip double spaces, etc.
169+
// For now, we just add all the dies that we find by exact match.
170+
num_matches = m_apple_names_up->FindByName(name.GetStringRef(), offsets);
171+
for (uint32_t i = 0; i < num_matches; i++) {
172+
const DIERef &die_ref = offsets[i];
173+
DWARFDIE die = info.GetDIE(die_ref);
174+
if (die) {
175+
if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx, die))
176+
continue; // The containing decl contexts don't match
177+
178+
if (resolved_dies.find(die.GetDIE()) == resolved_dies.end()) {
179+
if (resolve_function(die, include_inlines, sc_list))
180+
resolved_dies.insert(die.GetDIE());
181+
}
182+
} else
183+
ReportInvalidDIEOffset(die_ref.die_offset, name.GetStringRef());
184+
}
185+
}
186+
187+
if (name_type_mask & eFunctionNameTypeSelector) {
188+
if (parent_decl_ctx && parent_decl_ctx->IsValid())
189+
return; // no selectors in namespaces
190+
191+
num_matches = m_apple_names_up->FindByName(name.GetStringRef(), offsets);
192+
// Now make sure these are actually ObjC methods. In this case we can
193+
// simply look up the name, and if it is an ObjC method name, we're
194+
// good.
195+
196+
for (uint32_t i = 0; i < num_matches; i++) {
197+
const DIERef &die_ref = offsets[i];
198+
DWARFDIE die = info.GetDIE(die_ref);
199+
if (die) {
200+
const char *die_name = die.GetName();
201+
if (ObjCLanguage::IsPossibleObjCMethodName(die_name)) {
202+
if (resolved_dies.find(die.GetDIE()) == resolved_dies.end()) {
203+
if (resolve_function(die, include_inlines, sc_list))
204+
resolved_dies.insert(die.GetDIE());
205+
}
206+
}
207+
} else
208+
ReportInvalidDIEOffset(die_ref.die_offset, name.GetStringRef());
209+
}
210+
offsets.clear();
211+
}
212+
213+
if (((name_type_mask & eFunctionNameTypeMethod) && !parent_decl_ctx) ||
214+
name_type_mask & eFunctionNameTypeBase) {
215+
// The apple_names table stores just the "base name" of C++ methods in
216+
// the table. So we have to extract the base name, look that up, and
217+
// if there is any other information in the name we were passed in we
218+
// have to post-filter based on that.
219+
220+
// FIXME: Arrange the logic above so that we don't calculate the base
221+
// name twice:
222+
num_matches = m_apple_names_up->FindByName(name.GetStringRef(), offsets);
223+
224+
for (uint32_t i = 0; i < num_matches; i++) {
225+
const DIERef &die_ref = offsets[i];
226+
DWARFDIE die = info.GetDIE(die_ref);
227+
if (die) {
228+
if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx, die))
229+
continue; // The containing decl contexts don't match
230+
231+
// If we get to here, the die is good, and we should add it:
232+
if (resolved_dies.find(die.GetDIE()) == resolved_dies.end() &&
233+
resolve_function(die, include_inlines, sc_list)) {
234+
bool keep_die = true;
235+
if ((name_type_mask &
236+
(eFunctionNameTypeBase | eFunctionNameTypeMethod)) !=
237+
(eFunctionNameTypeBase | eFunctionNameTypeMethod)) {
238+
// We are looking for either basenames or methods, so we need
239+
// to trim out the ones we won't want by looking at the type
240+
SymbolContext sc;
241+
if (sc_list.GetLastContext(sc)) {
242+
if (sc.block) {
243+
// We have an inlined function
244+
} else if (sc.function) {
245+
Type *type = sc.function->GetType();
246+
247+
if (type) {
248+
CompilerDeclContext decl_ctx =
249+
get_decl_context_containing_uid(type->GetID());
250+
if (decl_ctx.IsStructUnionOrClass()) {
251+
if (name_type_mask & eFunctionNameTypeBase) {
252+
sc_list.RemoveContextAtIndex(sc_list.GetSize() - 1);
253+
keep_die = false;
254+
}
255+
} else {
256+
if (name_type_mask & eFunctionNameTypeMethod) {
257+
sc_list.RemoveContextAtIndex(sc_list.GetSize() - 1);
258+
keep_die = false;
259+
}
260+
}
261+
} else {
262+
m_module.ReportWarning(
263+
"function at die offset 0x%8.8x had no function type",
264+
die_ref.die_offset);
265+
}
266+
}
267+
}
268+
}
269+
if (keep_die)
270+
resolved_dies.insert(die.GetDIE());
271+
}
272+
} else
273+
ReportInvalidDIEOffset(die_ref.die_offset, name.GetStringRef());
274+
}
275+
offsets.clear();
276+
}
277+
}
278+
279+
void AppleDWARFIndex::GetFunctions(
280+
const RegularExpression &regex, DWARFDebugInfo &info,
281+
llvm::function_ref<bool(const DWARFDIE &die, bool include_inlines,
282+
lldb_private::SymbolContextList &sc_list)>
283+
resolve_function,
284+
bool include_inlines, SymbolContextList &sc_list) {
285+
if (!m_apple_names_up)
286+
return;
287+
288+
DIEArray offsets;
289+
DWARFMappedHash::DIEInfoArray hash_data;
290+
if (m_apple_names_up->AppendAllDIEsThatMatchingRegex(regex, hash_data)) {
291+
DWARFMappedHash::ExtractDIEArray(hash_data, offsets);
292+
ParseFunctions(offsets, info, resolve_function, include_inlines, sc_list);
293+
}
294+
}
295+
296+
void AppleDWARFIndex::ReportInvalidDIEOffset(dw_offset_t offset,
297+
llvm::StringRef name) {
298+
m_module.ReportErrorIfModifyDetected(
299+
"the DWARF debug information has been modified (accelerator table had "
300+
"bad die 0x%8.8x for '%s')\n",
301+
offset, name.str().c_str());
302+
}
303+
304+
void AppleDWARFIndex::Dump(Stream &s) {
305+
// TODO: Implement dumping.
306+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
//===-- AppleDWARFIndex.h --------------------------------------*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef LLDB_APPLEDWARFINDEX_H
11+
#define LLDB_APPLEDWARFINDEX_H
12+
13+
#include "Plugins/SymbolFile/DWARF/DWARFIndex.h"
14+
#include "Plugins/SymbolFile/DWARF/HashedNameToDIE.h"
15+
16+
namespace lldb_private {
17+
class AppleDWARFIndex : public DWARFIndex {
18+
public:
19+
static std::unique_ptr<AppleDWARFIndex>
20+
Create(Module &module, DWARFDataExtractor apple_names,
21+
DWARFDataExtractor apple_namespaces, DWARFDataExtractor apple_types,
22+
DWARFDataExtractor apple_objc, DWARFDataExtractor debug_str);
23+
24+
AppleDWARFIndex(
25+
Module &module, std::unique_ptr<DWARFMappedHash::MemoryTable> apple_names,
26+
std::unique_ptr<DWARFMappedHash::MemoryTable> apple_namespaces,
27+
std::unique_ptr<DWARFMappedHash::MemoryTable> apple_types,
28+
std::unique_ptr<DWARFMappedHash::MemoryTable> apple_objc)
29+
: DWARFIndex(module), m_apple_names_up(std::move(apple_names)),
30+
m_apple_namespaces_up(std::move(apple_namespaces)),
31+
m_apple_types_up(std::move(apple_types)),
32+
m_apple_objc_up(std::move(apple_objc)) {}
33+
34+
void Preload() override {}
35+
36+
void GetGlobalVariables(ConstString name, DIEArray &offsets) override;
37+
void GetGlobalVariables(const RegularExpression &regex,
38+
DIEArray &offsets) override;
39+
void GetGlobalVariables(const DWARFUnit &cu, DIEArray &offsets) override;
40+
void GetObjCMethods(ConstString class_name, DIEArray &offsets) override;
41+
void GetCompleteObjCClass(ConstString class_name, bool must_be_implementation,
42+
DIEArray &offsets) override;
43+
void GetTypes(ConstString name, DIEArray &offsets) override;
44+
void GetTypes(const DWARFDeclContext &context, DIEArray &offsets) override;
45+
void GetNamespaces(ConstString name, DIEArray &offsets) override;
46+
void GetFunctions(
47+
ConstString name, DWARFDebugInfo &info,
48+
llvm::function_ref<bool(const DWARFDIE &die, bool include_inlines,
49+
lldb_private::SymbolContextList &sc_list)>
50+
resolve_function,
51+
llvm::function_ref<CompilerDeclContext(lldb::user_id_t type_uid)>
52+
get_decl_context_containing_uid,
53+
const CompilerDeclContext *parent_decl_ctx, uint32_t name_type_mask,
54+
bool include_inlines, SymbolContextList &sc_list) override;
55+
void GetFunctions(
56+
const RegularExpression &regex, DWARFDebugInfo &info,
57+
llvm::function_ref<bool(const DWARFDIE &die, bool include_inlines,
58+
lldb_private::SymbolContextList &sc_list)>
59+
resolve_function,
60+
bool include_inlines, SymbolContextList &sc_list) override;
61+
62+
void ReportInvalidDIEOffset(dw_offset_t offset,
63+
llvm::StringRef name) override;
64+
void Dump(Stream &s) override;
65+
66+
private:
67+
std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_names_up;
68+
std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_namespaces_up;
69+
std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_types_up;
70+
std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_objc_up;
71+
};
72+
} // namespace lldb_private
73+
74+
#endif // LLDB_APPLEDWARFINDEX_H

lldb/source/Plugins/SymbolFile/DWARF/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
add_lldb_library(lldbPluginSymbolFileDWARF PLUGIN
2+
AppleDWARFIndex.cpp
23
DIERef.cpp
34
DWARFAbbreviationDeclaration.cpp
45
DWARFASTParserClang.cpp
@@ -23,9 +24,11 @@ add_lldb_library(lldbPluginSymbolFileDWARF PLUGIN
2324
DWARFDIE.cpp
2425
DWARFDIECollection.cpp
2526
DWARFFormValue.cpp
27+
DWARFIndex.cpp
2628
DWARFUnit.cpp
2729
HashedNameToDIE.cpp
2830
LogChannelDWARF.cpp
31+
ManualDWARFIndex.cpp
2932
NameToDIE.cpp
3033
SymbolFileDWARF.cpp
3134
SymbolFileDWARFDwo.cpp

0 commit comments

Comments
 (0)