1dda28197Spatrick //===-- ManualDWARFIndex.cpp ----------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "Plugins/SymbolFile/DWARF/ManualDWARFIndex.h"
10061da546Spatrick #include "Plugins/Language/ObjC/ObjCLanguage.h"
11061da546Spatrick #include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"
12061da546Spatrick #include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h"
13061da546Spatrick #include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h"
14061da546Spatrick #include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h"
15*f6aab3d8Srobert #include "lldb/Core/DataFileCache.h"
16*f6aab3d8Srobert #include "lldb/Core/Debugger.h"
17061da546Spatrick #include "lldb/Core/Module.h"
18be691f3bSpatrick #include "lldb/Core/Progress.h"
19061da546Spatrick #include "lldb/Symbol/ObjectFile.h"
20*f6aab3d8Srobert #include "lldb/Utility/DataEncoder.h"
21*f6aab3d8Srobert #include "lldb/Utility/DataExtractor.h"
22061da546Spatrick #include "lldb/Utility/Stream.h"
23061da546Spatrick #include "lldb/Utility/Timer.h"
24be691f3bSpatrick #include "llvm/Support/FormatVariadic.h"
25dda28197Spatrick #include "llvm/Support/ThreadPool.h"
26*f6aab3d8Srobert #include <optional>
27061da546Spatrick
28061da546Spatrick using namespace lldb_private;
29061da546Spatrick using namespace lldb;
30*f6aab3d8Srobert using namespace lldb_private::dwarf;
31061da546Spatrick
Index()32061da546Spatrick void ManualDWARFIndex::Index() {
33*f6aab3d8Srobert if (m_indexed)
34061da546Spatrick return;
35*f6aab3d8Srobert m_indexed = true;
36061da546Spatrick
37*f6aab3d8Srobert ElapsedTime elapsed(m_index_time);
38*f6aab3d8Srobert LLDB_SCOPED_TIMERF("%p", static_cast<void *>(m_dwarf));
39*f6aab3d8Srobert if (LoadFromCache()) {
40*f6aab3d8Srobert m_dwarf->SetDebugInfoIndexWasLoadedFromCache();
41*f6aab3d8Srobert return;
42*f6aab3d8Srobert }
43061da546Spatrick
44*f6aab3d8Srobert DWARFDebugInfo &main_info = m_dwarf->DebugInfo();
45*f6aab3d8Srobert SymbolFileDWARFDwo *dwp_dwarf = m_dwarf->GetDwpSymbolFile().get();
46dda28197Spatrick DWARFDebugInfo *dwp_info = dwp_dwarf ? &dwp_dwarf->DebugInfo() : nullptr;
47061da546Spatrick
48061da546Spatrick std::vector<DWARFUnit *> units_to_index;
49dda28197Spatrick units_to_index.reserve(main_info.GetNumUnits() +
50dda28197Spatrick (dwp_info ? dwp_info->GetNumUnits() : 0));
51dda28197Spatrick
52dda28197Spatrick // Process all units in the main file, as well as any type units in the dwp
53dda28197Spatrick // file. Type units in dwo files are handled when we reach the dwo file in
54dda28197Spatrick // IndexUnit.
55dda28197Spatrick for (size_t U = 0; U < main_info.GetNumUnits(); ++U) {
56dda28197Spatrick DWARFUnit *unit = main_info.GetUnitAtIndex(U);
57061da546Spatrick if (unit && m_units_to_avoid.count(unit->GetOffset()) == 0)
58061da546Spatrick units_to_index.push_back(unit);
59061da546Spatrick }
60dda28197Spatrick if (dwp_info && dwp_info->ContainsTypeUnits()) {
61dda28197Spatrick for (size_t U = 0; U < dwp_info->GetNumUnits(); ++U) {
62dda28197Spatrick if (auto *tu = llvm::dyn_cast<DWARFTypeUnit>(dwp_info->GetUnitAtIndex(U)))
63dda28197Spatrick units_to_index.push_back(tu);
64dda28197Spatrick }
65dda28197Spatrick }
66dda28197Spatrick
67061da546Spatrick if (units_to_index.empty())
68061da546Spatrick return;
69061da546Spatrick
70be691f3bSpatrick StreamString module_desc;
71be691f3bSpatrick m_module.GetDescription(module_desc.AsRawOstream(),
72be691f3bSpatrick lldb::eDescriptionLevelBrief);
73be691f3bSpatrick
74be691f3bSpatrick // Include 2 passes per unit to index for extracting DIEs from the unit and
75be691f3bSpatrick // indexing the unit, and then 8 extra entries for finalizing each index set.
76be691f3bSpatrick const uint64_t total_progress = units_to_index.size() * 2 + 8;
77be691f3bSpatrick Progress progress(
78be691f3bSpatrick llvm::formatv("Manually indexing DWARF for {0}", module_desc.GetData()),
79be691f3bSpatrick total_progress);
80be691f3bSpatrick
81061da546Spatrick std::vector<IndexSet> sets(units_to_index.size());
82061da546Spatrick
83061da546Spatrick // Keep memory down by clearing DIEs for any units if indexing
84061da546Spatrick // caused us to load the unit's DIEs.
85*f6aab3d8Srobert std::vector<std::optional<DWARFUnit::ScopedExtractDIEs>> clear_cu_dies(
86061da546Spatrick units_to_index.size());
87061da546Spatrick auto parser_fn = [&](size_t cu_idx) {
88dda28197Spatrick IndexUnit(*units_to_index[cu_idx], dwp_dwarf, sets[cu_idx]);
89be691f3bSpatrick progress.Increment();
90061da546Spatrick };
91061da546Spatrick
92be691f3bSpatrick auto extract_fn = [&](size_t cu_idx) {
93061da546Spatrick clear_cu_dies[cu_idx] = units_to_index[cu_idx]->ExtractDIEsScoped();
94be691f3bSpatrick progress.Increment();
95061da546Spatrick };
96061da546Spatrick
97dda28197Spatrick // Share one thread pool across operations to avoid the overhead of
98dda28197Spatrick // recreating the threads.
99*f6aab3d8Srobert llvm::ThreadPoolTaskGroup task_group(Debugger::GetThreadPool());
100dda28197Spatrick
101061da546Spatrick // Create a task runner that extracts dies for each DWARF unit in a
102dda28197Spatrick // separate thread.
103061da546Spatrick // First figure out which units didn't have their DIEs already
104061da546Spatrick // parsed and remember this. If no DIEs were parsed prior to this index
105061da546Spatrick // function call, we are going to want to clear the CU dies after we are
106061da546Spatrick // done indexing to make sure we don't pull in all DWARF dies, but we need
107061da546Spatrick // to wait until all units have been indexed in case a DIE in one
108061da546Spatrick // unit refers to another and the indexes accesses those DIEs.
109dda28197Spatrick for (size_t i = 0; i < units_to_index.size(); ++i)
110*f6aab3d8Srobert task_group.async(extract_fn, i);
111*f6aab3d8Srobert task_group.wait();
112061da546Spatrick
113061da546Spatrick // Now create a task runner that can index each DWARF unit in a
114061da546Spatrick // separate thread so we can index quickly.
115dda28197Spatrick for (size_t i = 0; i < units_to_index.size(); ++i)
116*f6aab3d8Srobert task_group.async(parser_fn, i);
117*f6aab3d8Srobert task_group.wait();
118061da546Spatrick
119be691f3bSpatrick auto finalize_fn = [this, &sets, &progress](NameToDIE(IndexSet::*index)) {
120061da546Spatrick NameToDIE &result = m_set.*index;
121061da546Spatrick for (auto &set : sets)
122061da546Spatrick result.Append(set.*index);
123061da546Spatrick result.Finalize();
124be691f3bSpatrick progress.Increment();
125061da546Spatrick };
126061da546Spatrick
127*f6aab3d8Srobert task_group.async(finalize_fn, &IndexSet::function_basenames);
128*f6aab3d8Srobert task_group.async(finalize_fn, &IndexSet::function_fullnames);
129*f6aab3d8Srobert task_group.async(finalize_fn, &IndexSet::function_methods);
130*f6aab3d8Srobert task_group.async(finalize_fn, &IndexSet::function_selectors);
131*f6aab3d8Srobert task_group.async(finalize_fn, &IndexSet::objc_class_selectors);
132*f6aab3d8Srobert task_group.async(finalize_fn, &IndexSet::globals);
133*f6aab3d8Srobert task_group.async(finalize_fn, &IndexSet::types);
134*f6aab3d8Srobert task_group.async(finalize_fn, &IndexSet::namespaces);
135*f6aab3d8Srobert task_group.wait();
136*f6aab3d8Srobert
137*f6aab3d8Srobert SaveToCache();
138061da546Spatrick }
139061da546Spatrick
IndexUnit(DWARFUnit & unit,SymbolFileDWARFDwo * dwp,IndexSet & set)140dda28197Spatrick void ManualDWARFIndex::IndexUnit(DWARFUnit &unit, SymbolFileDWARFDwo *dwp,
141dda28197Spatrick IndexSet &set) {
142*f6aab3d8Srobert Log *log = GetLog(DWARFLog::Lookups);
143061da546Spatrick
144061da546Spatrick if (log) {
145061da546Spatrick m_module.LogMessage(
146*f6aab3d8Srobert log, "ManualDWARFIndex::IndexUnit for unit at .debug_info[{0:x16}]",
147061da546Spatrick unit.GetOffset());
148061da546Spatrick }
149061da546Spatrick
150dda28197Spatrick const LanguageType cu_language = SymbolFileDWARF::GetLanguage(unit);
151061da546Spatrick
152*f6aab3d8Srobert // First check if the unit has a DWO ID. If it does then we only want to index
153*f6aab3d8Srobert // the .dwo file or nothing at all. If we have a compile unit where we can't
154*f6aab3d8Srobert // locate the .dwo/.dwp file we don't want to index anything from the skeleton
155*f6aab3d8Srobert // compile unit because it is usally has no children unless
156*f6aab3d8Srobert // -fsplit-dwarf-inlining was used at compile time. This option will add a
157*f6aab3d8Srobert // copy of all DW_TAG_subprogram and any contained DW_TAG_inline_subroutine
158*f6aab3d8Srobert // DIEs so that symbolication will still work in the absence of the .dwo/.dwp
159*f6aab3d8Srobert // file, but the functions have no return types and all arguments and locals
160*f6aab3d8Srobert // have been removed. So we don't want to index any of these hacked up
161*f6aab3d8Srobert // function types. Types can still exist in the skeleton compile unit DWARF
162*f6aab3d8Srobert // though as some functions have template parameter types and other things
163*f6aab3d8Srobert // that cause extra copies of types to be included, but we should find these
164*f6aab3d8Srobert // types in the .dwo file only as methods could have return types removed and
165*f6aab3d8Srobert // we don't have to index incomplete types from the skeletone compile unit.
166*f6aab3d8Srobert if (unit.GetDWOId()) {
167061da546Spatrick if (SymbolFileDWARFDwo *dwo_symbol_file = unit.GetDwoSymbolFile()) {
168dda28197Spatrick // Type units in a dwp file are indexed separately, so we just need to
169dda28197Spatrick // process the split unit here. However, if the split unit is in a dwo file,
170dda28197Spatrick // then we need to process type units here.
171dda28197Spatrick if (dwo_symbol_file == dwp) {
172dda28197Spatrick IndexUnitImpl(unit.GetNonSkeletonUnit(), cu_language, set);
173dda28197Spatrick } else {
174dda28197Spatrick DWARFDebugInfo &dwo_info = dwo_symbol_file->DebugInfo();
175061da546Spatrick for (size_t i = 0; i < dwo_info.GetNumUnits(); ++i)
176061da546Spatrick IndexUnitImpl(*dwo_info.GetUnitAtIndex(i), cu_language, set);
177061da546Spatrick }
178061da546Spatrick }
179*f6aab3d8Srobert } else {
180*f6aab3d8Srobert // We either have a normal compile unit which we want to index.
181*f6aab3d8Srobert IndexUnitImpl(unit, cu_language, set);
182*f6aab3d8Srobert }
183dda28197Spatrick }
184061da546Spatrick
IndexUnitImpl(DWARFUnit & unit,const LanguageType cu_language,IndexSet & set)185061da546Spatrick void ManualDWARFIndex::IndexUnitImpl(DWARFUnit &unit,
186061da546Spatrick const LanguageType cu_language,
187061da546Spatrick IndexSet &set) {
188061da546Spatrick for (const DWARFDebugInfoEntry &die : unit.dies()) {
189061da546Spatrick const dw_tag_t tag = die.Tag();
190061da546Spatrick
191061da546Spatrick switch (tag) {
192061da546Spatrick case DW_TAG_array_type:
193061da546Spatrick case DW_TAG_base_type:
194061da546Spatrick case DW_TAG_class_type:
195061da546Spatrick case DW_TAG_constant:
196061da546Spatrick case DW_TAG_enumeration_type:
197061da546Spatrick case DW_TAG_inlined_subroutine:
198061da546Spatrick case DW_TAG_namespace:
199061da546Spatrick case DW_TAG_string_type:
200061da546Spatrick case DW_TAG_structure_type:
201061da546Spatrick case DW_TAG_subprogram:
202061da546Spatrick case DW_TAG_subroutine_type:
203061da546Spatrick case DW_TAG_typedef:
204061da546Spatrick case DW_TAG_union_type:
205061da546Spatrick case DW_TAG_unspecified_type:
206061da546Spatrick case DW_TAG_variable:
207061da546Spatrick break;
208061da546Spatrick
209061da546Spatrick default:
210061da546Spatrick continue;
211061da546Spatrick }
212061da546Spatrick
213061da546Spatrick DWARFAttributes attributes;
214061da546Spatrick const char *name = nullptr;
215061da546Spatrick const char *mangled_cstr = nullptr;
216061da546Spatrick bool is_declaration = false;
217061da546Spatrick // bool is_artificial = false;
218061da546Spatrick bool has_address = false;
219061da546Spatrick bool has_location_or_const_value = false;
220061da546Spatrick bool is_global_or_static_variable = false;
221061da546Spatrick
222061da546Spatrick DWARFFormValue specification_die_form;
223061da546Spatrick const size_t num_attributes = die.GetAttributes(&unit, attributes);
224061da546Spatrick if (num_attributes > 0) {
225061da546Spatrick for (uint32_t i = 0; i < num_attributes; ++i) {
226061da546Spatrick dw_attr_t attr = attributes.AttributeAtIndex(i);
227061da546Spatrick DWARFFormValue form_value;
228061da546Spatrick switch (attr) {
229061da546Spatrick case DW_AT_name:
230061da546Spatrick if (attributes.ExtractFormValueAtIndex(i, form_value))
231061da546Spatrick name = form_value.AsCString();
232061da546Spatrick break;
233061da546Spatrick
234061da546Spatrick case DW_AT_declaration:
235061da546Spatrick if (attributes.ExtractFormValueAtIndex(i, form_value))
236061da546Spatrick is_declaration = form_value.Unsigned() != 0;
237061da546Spatrick break;
238061da546Spatrick
239061da546Spatrick case DW_AT_MIPS_linkage_name:
240061da546Spatrick case DW_AT_linkage_name:
241061da546Spatrick if (attributes.ExtractFormValueAtIndex(i, form_value))
242061da546Spatrick mangled_cstr = form_value.AsCString();
243061da546Spatrick break;
244061da546Spatrick
245061da546Spatrick case DW_AT_low_pc:
246061da546Spatrick case DW_AT_high_pc:
247061da546Spatrick case DW_AT_ranges:
248061da546Spatrick has_address = true;
249061da546Spatrick break;
250061da546Spatrick
251061da546Spatrick case DW_AT_entry_pc:
252061da546Spatrick has_address = true;
253061da546Spatrick break;
254061da546Spatrick
255061da546Spatrick case DW_AT_location:
256061da546Spatrick case DW_AT_const_value:
257061da546Spatrick has_location_or_const_value = true;
258dda28197Spatrick is_global_or_static_variable = die.IsGlobalOrStaticScopeVariable();
259061da546Spatrick
260061da546Spatrick break;
261061da546Spatrick
262061da546Spatrick case DW_AT_specification:
263061da546Spatrick if (attributes.ExtractFormValueAtIndex(i, form_value))
264061da546Spatrick specification_die_form = form_value;
265061da546Spatrick break;
266061da546Spatrick }
267061da546Spatrick }
268061da546Spatrick }
269061da546Spatrick
270061da546Spatrick DIERef ref = *DWARFDIE(&unit, &die).GetDIERef();
271061da546Spatrick switch (tag) {
272061da546Spatrick case DW_TAG_inlined_subroutine:
273061da546Spatrick case DW_TAG_subprogram:
274061da546Spatrick if (has_address) {
275061da546Spatrick if (name) {
276061da546Spatrick bool is_objc_method = false;
277061da546Spatrick if (cu_language == eLanguageTypeObjC ||
278061da546Spatrick cu_language == eLanguageTypeObjC_plus_plus) {
279061da546Spatrick ObjCLanguage::MethodName objc_method(name, true);
280061da546Spatrick if (objc_method.IsValid(true)) {
281061da546Spatrick is_objc_method = true;
282061da546Spatrick ConstString class_name_with_category(
283061da546Spatrick objc_method.GetClassNameWithCategory());
284061da546Spatrick ConstString objc_selector_name(objc_method.GetSelector());
285061da546Spatrick ConstString objc_fullname_no_category_name(
286061da546Spatrick objc_method.GetFullNameWithoutCategory(true));
287061da546Spatrick ConstString class_name_no_category(objc_method.GetClassName());
288061da546Spatrick set.function_fullnames.Insert(ConstString(name), ref);
289061da546Spatrick if (class_name_with_category)
290061da546Spatrick set.objc_class_selectors.Insert(class_name_with_category, ref);
291061da546Spatrick if (class_name_no_category &&
292061da546Spatrick class_name_no_category != class_name_with_category)
293061da546Spatrick set.objc_class_selectors.Insert(class_name_no_category, ref);
294061da546Spatrick if (objc_selector_name)
295061da546Spatrick set.function_selectors.Insert(objc_selector_name, ref);
296061da546Spatrick if (objc_fullname_no_category_name)
297061da546Spatrick set.function_fullnames.Insert(objc_fullname_no_category_name,
298061da546Spatrick ref);
299061da546Spatrick }
300061da546Spatrick }
301061da546Spatrick // If we have a mangled name, then the DW_AT_name attribute is
302061da546Spatrick // usually the method name without the class or any parameters
303061da546Spatrick bool is_method = DWARFDIE(&unit, &die).IsMethod();
304061da546Spatrick
305061da546Spatrick if (is_method)
306061da546Spatrick set.function_methods.Insert(ConstString(name), ref);
307061da546Spatrick else
308061da546Spatrick set.function_basenames.Insert(ConstString(name), ref);
309061da546Spatrick
310061da546Spatrick if (!is_method && !mangled_cstr && !is_objc_method)
311061da546Spatrick set.function_fullnames.Insert(ConstString(name), ref);
312061da546Spatrick }
313061da546Spatrick if (mangled_cstr) {
314061da546Spatrick // Make sure our mangled name isn't the same string table entry as
315061da546Spatrick // our name. If it starts with '_', then it is ok, else compare the
316061da546Spatrick // string to make sure it isn't the same and we don't end up with
317061da546Spatrick // duplicate entries
318061da546Spatrick if (name && name != mangled_cstr &&
319061da546Spatrick ((mangled_cstr[0] == '_') ||
320061da546Spatrick (::strcmp(name, mangled_cstr) != 0))) {
321061da546Spatrick set.function_fullnames.Insert(ConstString(mangled_cstr), ref);
322061da546Spatrick }
323061da546Spatrick }
324061da546Spatrick }
325061da546Spatrick break;
326061da546Spatrick
327061da546Spatrick case DW_TAG_array_type:
328061da546Spatrick case DW_TAG_base_type:
329061da546Spatrick case DW_TAG_class_type:
330061da546Spatrick case DW_TAG_constant:
331061da546Spatrick case DW_TAG_enumeration_type:
332061da546Spatrick case DW_TAG_string_type:
333061da546Spatrick case DW_TAG_structure_type:
334061da546Spatrick case DW_TAG_subroutine_type:
335061da546Spatrick case DW_TAG_typedef:
336061da546Spatrick case DW_TAG_union_type:
337061da546Spatrick case DW_TAG_unspecified_type:
338061da546Spatrick if (name && !is_declaration)
339061da546Spatrick set.types.Insert(ConstString(name), ref);
340061da546Spatrick if (mangled_cstr && !is_declaration)
341061da546Spatrick set.types.Insert(ConstString(mangled_cstr), ref);
342061da546Spatrick break;
343061da546Spatrick
344061da546Spatrick case DW_TAG_namespace:
345061da546Spatrick if (name)
346061da546Spatrick set.namespaces.Insert(ConstString(name), ref);
347061da546Spatrick break;
348061da546Spatrick
349061da546Spatrick case DW_TAG_variable:
350061da546Spatrick if (name && has_location_or_const_value && is_global_or_static_variable) {
351061da546Spatrick set.globals.Insert(ConstString(name), ref);
352061da546Spatrick // Be sure to include variables by their mangled and demangled names if
353061da546Spatrick // they have any since a variable can have a basename "i", a mangled
354061da546Spatrick // named "_ZN12_GLOBAL__N_11iE" and a demangled mangled name
355061da546Spatrick // "(anonymous namespace)::i"...
356061da546Spatrick
357061da546Spatrick // Make sure our mangled name isn't the same string table entry as our
358061da546Spatrick // name. If it starts with '_', then it is ok, else compare the string
359061da546Spatrick // to make sure it isn't the same and we don't end up with duplicate
360061da546Spatrick // entries
361061da546Spatrick if (mangled_cstr && name != mangled_cstr &&
362061da546Spatrick ((mangled_cstr[0] == '_') || (::strcmp(name, mangled_cstr) != 0))) {
363061da546Spatrick set.globals.Insert(ConstString(mangled_cstr), ref);
364061da546Spatrick }
365061da546Spatrick }
366061da546Spatrick break;
367061da546Spatrick
368061da546Spatrick default:
369061da546Spatrick continue;
370061da546Spatrick }
371061da546Spatrick }
372061da546Spatrick }
373061da546Spatrick
GetGlobalVariables(ConstString basename,llvm::function_ref<bool (DWARFDIE die)> callback)374dda28197Spatrick void ManualDWARFIndex::GetGlobalVariables(
375dda28197Spatrick ConstString basename, llvm::function_ref<bool(DWARFDIE die)> callback) {
376061da546Spatrick Index();
377dda28197Spatrick m_set.globals.Find(basename,
378dda28197Spatrick DIERefCallback(callback, basename.GetStringRef()));
379061da546Spatrick }
380061da546Spatrick
GetGlobalVariables(const RegularExpression & regex,llvm::function_ref<bool (DWARFDIE die)> callback)381dda28197Spatrick void ManualDWARFIndex::GetGlobalVariables(
382dda28197Spatrick const RegularExpression ®ex,
383dda28197Spatrick llvm::function_ref<bool(DWARFDIE die)> callback) {
384061da546Spatrick Index();
385dda28197Spatrick m_set.globals.Find(regex, DIERefCallback(callback, regex.GetText()));
386061da546Spatrick }
387061da546Spatrick
GetGlobalVariables(DWARFUnit & unit,llvm::function_ref<bool (DWARFDIE die)> callback)388dda28197Spatrick void ManualDWARFIndex::GetGlobalVariables(
389*f6aab3d8Srobert DWARFUnit &unit, llvm::function_ref<bool(DWARFDIE die)> callback) {
390*f6aab3d8Srobert lldbassert(!unit.GetSymbolFileDWARF().GetDwoNum());
391061da546Spatrick Index();
392dda28197Spatrick m_set.globals.FindAllEntriesForUnit(unit, DIERefCallback(callback));
393061da546Spatrick }
394061da546Spatrick
GetObjCMethods(ConstString class_name,llvm::function_ref<bool (DWARFDIE die)> callback)395dda28197Spatrick void ManualDWARFIndex::GetObjCMethods(
396dda28197Spatrick ConstString class_name, llvm::function_ref<bool(DWARFDIE die)> callback) {
397061da546Spatrick Index();
398dda28197Spatrick m_set.objc_class_selectors.Find(
399dda28197Spatrick class_name, DIERefCallback(callback, class_name.GetStringRef()));
400061da546Spatrick }
401061da546Spatrick
GetCompleteObjCClass(ConstString class_name,bool must_be_implementation,llvm::function_ref<bool (DWARFDIE die)> callback)402dda28197Spatrick void ManualDWARFIndex::GetCompleteObjCClass(
403dda28197Spatrick ConstString class_name, bool must_be_implementation,
404dda28197Spatrick llvm::function_ref<bool(DWARFDIE die)> callback) {
405061da546Spatrick Index();
406dda28197Spatrick m_set.types.Find(class_name,
407dda28197Spatrick DIERefCallback(callback, class_name.GetStringRef()));
408061da546Spatrick }
409061da546Spatrick
GetTypes(ConstString name,llvm::function_ref<bool (DWARFDIE die)> callback)410dda28197Spatrick void ManualDWARFIndex::GetTypes(
411dda28197Spatrick ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
412061da546Spatrick Index();
413dda28197Spatrick m_set.types.Find(name, DIERefCallback(callback, name.GetStringRef()));
414061da546Spatrick }
415061da546Spatrick
GetTypes(const DWARFDeclContext & context,llvm::function_ref<bool (DWARFDIE die)> callback)416dda28197Spatrick void ManualDWARFIndex::GetTypes(
417dda28197Spatrick const DWARFDeclContext &context,
418dda28197Spatrick llvm::function_ref<bool(DWARFDIE die)> callback) {
419061da546Spatrick Index();
420dda28197Spatrick auto name = context[0].name;
421dda28197Spatrick m_set.types.Find(ConstString(name),
422dda28197Spatrick DIERefCallback(callback, llvm::StringRef(name)));
423061da546Spatrick }
424061da546Spatrick
GetNamespaces(ConstString name,llvm::function_ref<bool (DWARFDIE die)> callback)425dda28197Spatrick void ManualDWARFIndex::GetNamespaces(
426dda28197Spatrick ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
427061da546Spatrick Index();
428dda28197Spatrick m_set.namespaces.Find(name, DIERefCallback(callback, name.GetStringRef()));
429061da546Spatrick }
430061da546Spatrick
GetFunctions(const Module::LookupInfo & lookup_info,SymbolFileDWARF & dwarf,const CompilerDeclContext & parent_decl_ctx,llvm::function_ref<bool (DWARFDIE die)> callback)431dda28197Spatrick void ManualDWARFIndex::GetFunctions(
432*f6aab3d8Srobert const Module::LookupInfo &lookup_info, SymbolFileDWARF &dwarf,
433*f6aab3d8Srobert const CompilerDeclContext &parent_decl_ctx,
434dda28197Spatrick llvm::function_ref<bool(DWARFDIE die)> callback) {
435061da546Spatrick Index();
436*f6aab3d8Srobert ConstString name = lookup_info.GetLookupName();
437*f6aab3d8Srobert FunctionNameType name_type_mask = lookup_info.GetNameTypeMask();
438061da546Spatrick
439061da546Spatrick if (name_type_mask & eFunctionNameTypeFull) {
440dda28197Spatrick if (!m_set.function_fullnames.Find(
441dda28197Spatrick name, DIERefCallback(
442dda28197Spatrick [&](DWARFDIE die) {
443dda28197Spatrick if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx,
444dda28197Spatrick die))
445dda28197Spatrick return true;
446dda28197Spatrick return callback(die);
447dda28197Spatrick },
448dda28197Spatrick name.GetStringRef())))
449dda28197Spatrick return;
450061da546Spatrick }
451061da546Spatrick if (name_type_mask & eFunctionNameTypeBase) {
452dda28197Spatrick if (!m_set.function_basenames.Find(
453dda28197Spatrick name, DIERefCallback(
454dda28197Spatrick [&](DWARFDIE die) {
455dda28197Spatrick if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx,
456dda28197Spatrick die))
457dda28197Spatrick return true;
458dda28197Spatrick return callback(die);
459dda28197Spatrick },
460dda28197Spatrick name.GetStringRef())))
461dda28197Spatrick return;
462061da546Spatrick }
463061da546Spatrick
464061da546Spatrick if (name_type_mask & eFunctionNameTypeMethod && !parent_decl_ctx.IsValid()) {
465dda28197Spatrick if (!m_set.function_methods.Find(
466dda28197Spatrick name, DIERefCallback(callback, name.GetStringRef())))
467dda28197Spatrick return;
468061da546Spatrick }
469061da546Spatrick
470061da546Spatrick if (name_type_mask & eFunctionNameTypeSelector &&
471061da546Spatrick !parent_decl_ctx.IsValid()) {
472dda28197Spatrick if (!m_set.function_selectors.Find(
473dda28197Spatrick name, DIERefCallback(callback, name.GetStringRef())))
474dda28197Spatrick return;
475061da546Spatrick }
476061da546Spatrick }
477061da546Spatrick
GetFunctions(const RegularExpression & regex,llvm::function_ref<bool (DWARFDIE die)> callback)478dda28197Spatrick void ManualDWARFIndex::GetFunctions(
479dda28197Spatrick const RegularExpression ®ex,
480dda28197Spatrick llvm::function_ref<bool(DWARFDIE die)> callback) {
481061da546Spatrick Index();
482061da546Spatrick
483dda28197Spatrick if (!m_set.function_basenames.Find(regex,
484dda28197Spatrick DIERefCallback(callback, regex.GetText())))
485dda28197Spatrick return;
486dda28197Spatrick if (!m_set.function_fullnames.Find(regex,
487dda28197Spatrick DIERefCallback(callback, regex.GetText())))
488dda28197Spatrick return;
489061da546Spatrick }
490061da546Spatrick
Dump(Stream & s)491061da546Spatrick void ManualDWARFIndex::Dump(Stream &s) {
492061da546Spatrick s.Format("Manual DWARF index for ({0}) '{1:F}':",
493061da546Spatrick m_module.GetArchitecture().GetArchitectureName(),
494061da546Spatrick m_module.GetObjectFile()->GetFileSpec());
495061da546Spatrick s.Printf("\nFunction basenames:\n");
496061da546Spatrick m_set.function_basenames.Dump(&s);
497061da546Spatrick s.Printf("\nFunction fullnames:\n");
498061da546Spatrick m_set.function_fullnames.Dump(&s);
499061da546Spatrick s.Printf("\nFunction methods:\n");
500061da546Spatrick m_set.function_methods.Dump(&s);
501061da546Spatrick s.Printf("\nFunction selectors:\n");
502061da546Spatrick m_set.function_selectors.Dump(&s);
503061da546Spatrick s.Printf("\nObjective-C class selectors:\n");
504061da546Spatrick m_set.objc_class_selectors.Dump(&s);
505061da546Spatrick s.Printf("\nGlobals and statics:\n");
506061da546Spatrick m_set.globals.Dump(&s);
507061da546Spatrick s.Printf("\nTypes:\n");
508061da546Spatrick m_set.types.Dump(&s);
509061da546Spatrick s.Printf("\nNamespaces:\n");
510061da546Spatrick m_set.namespaces.Dump(&s);
511061da546Spatrick }
512*f6aab3d8Srobert
513*f6aab3d8Srobert constexpr llvm::StringLiteral kIdentifierManualDWARFIndex("DIDX");
514*f6aab3d8Srobert // Define IDs for the different tables when encoding and decoding the
515*f6aab3d8Srobert // ManualDWARFIndex NameToDIE objects so we can avoid saving any empty maps.
516*f6aab3d8Srobert enum DataID {
517*f6aab3d8Srobert kDataIDFunctionBasenames = 1u,
518*f6aab3d8Srobert kDataIDFunctionFullnames,
519*f6aab3d8Srobert kDataIDFunctionMethods,
520*f6aab3d8Srobert kDataIDFunctionSelectors,
521*f6aab3d8Srobert kDataIDFunctionObjcClassSelectors,
522*f6aab3d8Srobert kDataIDGlobals,
523*f6aab3d8Srobert kDataIDTypes,
524*f6aab3d8Srobert kDataIDNamespaces,
525*f6aab3d8Srobert kDataIDEnd = 255u,
526*f6aab3d8Srobert
527*f6aab3d8Srobert };
528*f6aab3d8Srobert constexpr uint32_t CURRENT_CACHE_VERSION = 1;
529*f6aab3d8Srobert
Decode(const DataExtractor & data,lldb::offset_t * offset_ptr)530*f6aab3d8Srobert bool ManualDWARFIndex::IndexSet::Decode(const DataExtractor &data,
531*f6aab3d8Srobert lldb::offset_t *offset_ptr) {
532*f6aab3d8Srobert StringTableReader strtab;
533*f6aab3d8Srobert // We now decode the string table for all strings in the data cache file.
534*f6aab3d8Srobert if (!strtab.Decode(data, offset_ptr))
535*f6aab3d8Srobert return false;
536*f6aab3d8Srobert
537*f6aab3d8Srobert llvm::StringRef identifier((const char *)data.GetData(offset_ptr, 4), 4);
538*f6aab3d8Srobert if (identifier != kIdentifierManualDWARFIndex)
539*f6aab3d8Srobert return false;
540*f6aab3d8Srobert const uint32_t version = data.GetU32(offset_ptr);
541*f6aab3d8Srobert if (version != CURRENT_CACHE_VERSION)
542*f6aab3d8Srobert return false;
543*f6aab3d8Srobert
544*f6aab3d8Srobert bool done = false;
545*f6aab3d8Srobert while (!done) {
546*f6aab3d8Srobert switch (data.GetU8(offset_ptr)) {
547*f6aab3d8Srobert default:
548*f6aab3d8Srobert // If we got here, this is not expected, we expect the data IDs to match
549*f6aab3d8Srobert // one of the values from the DataID enumeration.
550*f6aab3d8Srobert return false;
551*f6aab3d8Srobert case kDataIDFunctionBasenames:
552*f6aab3d8Srobert if (!function_basenames.Decode(data, offset_ptr, strtab))
553*f6aab3d8Srobert return false;
554*f6aab3d8Srobert break;
555*f6aab3d8Srobert case kDataIDFunctionFullnames:
556*f6aab3d8Srobert if (!function_fullnames.Decode(data, offset_ptr, strtab))
557*f6aab3d8Srobert return false;
558*f6aab3d8Srobert break;
559*f6aab3d8Srobert case kDataIDFunctionMethods:
560*f6aab3d8Srobert if (!function_methods.Decode(data, offset_ptr, strtab))
561*f6aab3d8Srobert return false;
562*f6aab3d8Srobert break;
563*f6aab3d8Srobert case kDataIDFunctionSelectors:
564*f6aab3d8Srobert if (!function_selectors.Decode(data, offset_ptr, strtab))
565*f6aab3d8Srobert return false;
566*f6aab3d8Srobert break;
567*f6aab3d8Srobert case kDataIDFunctionObjcClassSelectors:
568*f6aab3d8Srobert if (!objc_class_selectors.Decode(data, offset_ptr, strtab))
569*f6aab3d8Srobert return false;
570*f6aab3d8Srobert break;
571*f6aab3d8Srobert case kDataIDGlobals:
572*f6aab3d8Srobert if (!globals.Decode(data, offset_ptr, strtab))
573*f6aab3d8Srobert return false;
574*f6aab3d8Srobert break;
575*f6aab3d8Srobert case kDataIDTypes:
576*f6aab3d8Srobert if (!types.Decode(data, offset_ptr, strtab))
577*f6aab3d8Srobert return false;
578*f6aab3d8Srobert break;
579*f6aab3d8Srobert case kDataIDNamespaces:
580*f6aab3d8Srobert if (!namespaces.Decode(data, offset_ptr, strtab))
581*f6aab3d8Srobert return false;
582*f6aab3d8Srobert break;
583*f6aab3d8Srobert case kDataIDEnd:
584*f6aab3d8Srobert // We got to the end of our NameToDIE encodings.
585*f6aab3d8Srobert done = true;
586*f6aab3d8Srobert break;
587*f6aab3d8Srobert }
588*f6aab3d8Srobert }
589*f6aab3d8Srobert // Success!
590*f6aab3d8Srobert return true;
591*f6aab3d8Srobert }
592*f6aab3d8Srobert
Encode(DataEncoder & encoder) const593*f6aab3d8Srobert void ManualDWARFIndex::IndexSet::Encode(DataEncoder &encoder) const {
594*f6aab3d8Srobert ConstStringTable strtab;
595*f6aab3d8Srobert
596*f6aab3d8Srobert // Encoder the DWARF index into a separate encoder first. This allows us
597*f6aab3d8Srobert // gather all of the strings we willl need in "strtab" as we will need to
598*f6aab3d8Srobert // write the string table out before the symbol table.
599*f6aab3d8Srobert DataEncoder index_encoder(encoder.GetByteOrder(),
600*f6aab3d8Srobert encoder.GetAddressByteSize());
601*f6aab3d8Srobert
602*f6aab3d8Srobert index_encoder.AppendData(kIdentifierManualDWARFIndex);
603*f6aab3d8Srobert // Encode the data version.
604*f6aab3d8Srobert index_encoder.AppendU32(CURRENT_CACHE_VERSION);
605*f6aab3d8Srobert
606*f6aab3d8Srobert if (!function_basenames.IsEmpty()) {
607*f6aab3d8Srobert index_encoder.AppendU8(kDataIDFunctionBasenames);
608*f6aab3d8Srobert function_basenames.Encode(index_encoder, strtab);
609*f6aab3d8Srobert }
610*f6aab3d8Srobert if (!function_fullnames.IsEmpty()) {
611*f6aab3d8Srobert index_encoder.AppendU8(kDataIDFunctionFullnames);
612*f6aab3d8Srobert function_fullnames.Encode(index_encoder, strtab);
613*f6aab3d8Srobert }
614*f6aab3d8Srobert if (!function_methods.IsEmpty()) {
615*f6aab3d8Srobert index_encoder.AppendU8(kDataIDFunctionMethods);
616*f6aab3d8Srobert function_methods.Encode(index_encoder, strtab);
617*f6aab3d8Srobert }
618*f6aab3d8Srobert if (!function_selectors.IsEmpty()) {
619*f6aab3d8Srobert index_encoder.AppendU8(kDataIDFunctionSelectors);
620*f6aab3d8Srobert function_selectors.Encode(index_encoder, strtab);
621*f6aab3d8Srobert }
622*f6aab3d8Srobert if (!objc_class_selectors.IsEmpty()) {
623*f6aab3d8Srobert index_encoder.AppendU8(kDataIDFunctionObjcClassSelectors);
624*f6aab3d8Srobert objc_class_selectors.Encode(index_encoder, strtab);
625*f6aab3d8Srobert }
626*f6aab3d8Srobert if (!globals.IsEmpty()) {
627*f6aab3d8Srobert index_encoder.AppendU8(kDataIDGlobals);
628*f6aab3d8Srobert globals.Encode(index_encoder, strtab);
629*f6aab3d8Srobert }
630*f6aab3d8Srobert if (!types.IsEmpty()) {
631*f6aab3d8Srobert index_encoder.AppendU8(kDataIDTypes);
632*f6aab3d8Srobert types.Encode(index_encoder, strtab);
633*f6aab3d8Srobert }
634*f6aab3d8Srobert if (!namespaces.IsEmpty()) {
635*f6aab3d8Srobert index_encoder.AppendU8(kDataIDNamespaces);
636*f6aab3d8Srobert namespaces.Encode(index_encoder, strtab);
637*f6aab3d8Srobert }
638*f6aab3d8Srobert index_encoder.AppendU8(kDataIDEnd);
639*f6aab3d8Srobert
640*f6aab3d8Srobert // Now that all strings have been gathered, we will emit the string table.
641*f6aab3d8Srobert strtab.Encode(encoder);
642*f6aab3d8Srobert // Followed the the symbol table data.
643*f6aab3d8Srobert encoder.AppendData(index_encoder.GetData());
644*f6aab3d8Srobert }
645*f6aab3d8Srobert
Decode(const DataExtractor & data,lldb::offset_t * offset_ptr,bool & signature_mismatch)646*f6aab3d8Srobert bool ManualDWARFIndex::Decode(const DataExtractor &data,
647*f6aab3d8Srobert lldb::offset_t *offset_ptr,
648*f6aab3d8Srobert bool &signature_mismatch) {
649*f6aab3d8Srobert signature_mismatch = false;
650*f6aab3d8Srobert CacheSignature signature;
651*f6aab3d8Srobert if (!signature.Decode(data, offset_ptr))
652*f6aab3d8Srobert return false;
653*f6aab3d8Srobert if (CacheSignature(m_dwarf->GetObjectFile()) != signature) {
654*f6aab3d8Srobert signature_mismatch = true;
655*f6aab3d8Srobert return false;
656*f6aab3d8Srobert }
657*f6aab3d8Srobert IndexSet set;
658*f6aab3d8Srobert if (!set.Decode(data, offset_ptr))
659*f6aab3d8Srobert return false;
660*f6aab3d8Srobert m_set = std::move(set);
661*f6aab3d8Srobert return true;
662*f6aab3d8Srobert }
663*f6aab3d8Srobert
Encode(DataEncoder & encoder) const664*f6aab3d8Srobert bool ManualDWARFIndex::Encode(DataEncoder &encoder) const {
665*f6aab3d8Srobert CacheSignature signature(m_dwarf->GetObjectFile());
666*f6aab3d8Srobert if (!signature.Encode(encoder))
667*f6aab3d8Srobert return false;
668*f6aab3d8Srobert m_set.Encode(encoder);
669*f6aab3d8Srobert return true;
670*f6aab3d8Srobert }
671*f6aab3d8Srobert
GetCacheKey()672*f6aab3d8Srobert std::string ManualDWARFIndex::GetCacheKey() {
673*f6aab3d8Srobert std::string key;
674*f6aab3d8Srobert llvm::raw_string_ostream strm(key);
675*f6aab3d8Srobert // DWARF Index can come from different object files for the same module. A
676*f6aab3d8Srobert // module can have one object file as the main executable and might have
677*f6aab3d8Srobert // another object file in a separate symbol file, or we might have a .dwo file
678*f6aab3d8Srobert // that claims its module is the main executable.
679*f6aab3d8Srobert ObjectFile *objfile = m_dwarf->GetObjectFile();
680*f6aab3d8Srobert strm << objfile->GetModule()->GetCacheKey() << "-dwarf-index-"
681*f6aab3d8Srobert << llvm::format_hex(objfile->GetCacheHash(), 10);
682*f6aab3d8Srobert return strm.str();
683*f6aab3d8Srobert }
684*f6aab3d8Srobert
LoadFromCache()685*f6aab3d8Srobert bool ManualDWARFIndex::LoadFromCache() {
686*f6aab3d8Srobert DataFileCache *cache = Module::GetIndexCache();
687*f6aab3d8Srobert if (!cache)
688*f6aab3d8Srobert return false;
689*f6aab3d8Srobert ObjectFile *objfile = m_dwarf->GetObjectFile();
690*f6aab3d8Srobert if (!objfile)
691*f6aab3d8Srobert return false;
692*f6aab3d8Srobert std::unique_ptr<llvm::MemoryBuffer> mem_buffer_up =
693*f6aab3d8Srobert cache->GetCachedData(GetCacheKey());
694*f6aab3d8Srobert if (!mem_buffer_up)
695*f6aab3d8Srobert return false;
696*f6aab3d8Srobert DataExtractor data(mem_buffer_up->getBufferStart(),
697*f6aab3d8Srobert mem_buffer_up->getBufferSize(),
698*f6aab3d8Srobert endian::InlHostByteOrder(),
699*f6aab3d8Srobert objfile->GetAddressByteSize());
700*f6aab3d8Srobert bool signature_mismatch = false;
701*f6aab3d8Srobert lldb::offset_t offset = 0;
702*f6aab3d8Srobert const bool result = Decode(data, &offset, signature_mismatch);
703*f6aab3d8Srobert if (signature_mismatch)
704*f6aab3d8Srobert cache->RemoveCacheFile(GetCacheKey());
705*f6aab3d8Srobert return result;
706*f6aab3d8Srobert }
707*f6aab3d8Srobert
SaveToCache()708*f6aab3d8Srobert void ManualDWARFIndex::SaveToCache() {
709*f6aab3d8Srobert DataFileCache *cache = Module::GetIndexCache();
710*f6aab3d8Srobert if (!cache)
711*f6aab3d8Srobert return; // Caching is not enabled.
712*f6aab3d8Srobert ObjectFile *objfile = m_dwarf->GetObjectFile();
713*f6aab3d8Srobert if (!objfile)
714*f6aab3d8Srobert return;
715*f6aab3d8Srobert DataEncoder file(endian::InlHostByteOrder(), objfile->GetAddressByteSize());
716*f6aab3d8Srobert // Encode will return false if the object file doesn't have anything to make
717*f6aab3d8Srobert // a signature from.
718*f6aab3d8Srobert if (Encode(file)) {
719*f6aab3d8Srobert if (cache->SetCachedData(GetCacheKey(), file.GetData()))
720*f6aab3d8Srobert m_dwarf->SetDebugInfoIndexWasSavedToCache();
721*f6aab3d8Srobert }
722*f6aab3d8Srobert }
723