180814287SRaphael Isemann //===-- DebugNamesDWARFIndex.cpp ------------------------------------------===//
29337b41cSPavel Labath //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
69337b41cSPavel Labath //
79337b41cSPavel Labath //===----------------------------------------------------------------------===//
89337b41cSPavel Labath
99337b41cSPavel Labath #include "Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h"
10257ff339SPavel Labath #include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"
110e33a0cdSPavel Labath #include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h"
1208dae4bbSPavel Labath #include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h"
13d482fe2aSJan Kratochvil #include "lldb/Core/Module.h"
14e1d18758SPavel Labath #include "lldb/Utility/RegularExpression.h"
15e1d18758SPavel Labath #include "lldb/Utility/Stream.h"
169337b41cSPavel Labath
179337b41cSPavel Labath using namespace lldb_private;
189337b41cSPavel Labath using namespace lldb;
19ae869d44SShafik Yaghmour using namespace lldb_private::dwarf;
209337b41cSPavel Labath
219337b41cSPavel Labath llvm::Expected<std::unique_ptr<DebugNamesDWARFIndex>>
Create(Module & module,DWARFDataExtractor debug_names,DWARFDataExtractor debug_str,SymbolFileDWARF & dwarf)229337b41cSPavel Labath DebugNamesDWARFIndex::Create(Module &module, DWARFDataExtractor debug_names,
239337b41cSPavel Labath DWARFDataExtractor debug_str,
240f7cfb25SPavel Labath SymbolFileDWARF &dwarf) {
25a8f3ae7cSJonas Devlieghere auto index_up = std::make_unique<DebugNames>(debug_names.GetAsLLVM(),
26f4af9a9dSJonas Devlieghere debug_str.GetAsLLVM());
279337b41cSPavel Labath if (llvm::Error E = index_up->extract())
289337b41cSPavel Labath return std::move(E);
299337b41cSPavel Labath
309337b41cSPavel Labath return std::unique_ptr<DebugNamesDWARFIndex>(new DebugNamesDWARFIndex(
310f7cfb25SPavel Labath module, std::move(index_up), debug_names, debug_str, dwarf));
329337b41cSPavel Labath }
33e1d18758SPavel Labath
34452bd87cSPavel Labath llvm::DenseSet<dw_offset_t>
GetUnits(const DebugNames & debug_names)35452bd87cSPavel Labath DebugNamesDWARFIndex::GetUnits(const DebugNames &debug_names) {
36452bd87cSPavel Labath llvm::DenseSet<dw_offset_t> result;
37452bd87cSPavel Labath for (const DebugNames::NameIndex &ni : debug_names) {
38452bd87cSPavel Labath for (uint32_t cu = 0; cu < ni.getCUCount(); ++cu)
39452bd87cSPavel Labath result.insert(ni.getCUOffset(cu));
40452bd87cSPavel Labath }
41452bd87cSPavel Labath return result;
42452bd87cSPavel Labath }
43452bd87cSPavel Labath
4467b45aceSPavel Labath llvm::Optional<DIERef>
ToDIERef(const DebugNames::Entry & entry)4567b45aceSPavel Labath DebugNamesDWARFIndex::ToDIERef(const DebugNames::Entry &entry) {
46e1d18758SPavel Labath llvm::Optional<uint64_t> cu_offset = entry.getCUOffset();
4708dae4bbSPavel Labath if (!cu_offset)
4867b45aceSPavel Labath return llvm::None;
4908dae4bbSPavel Labath
50f4014e11SPavel Labath DWARFUnit *cu = m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *cu_offset);
5108dae4bbSPavel Labath if (!cu)
5267b45aceSPavel Labath return llvm::None;
5308dae4bbSPavel Labath
543b926988SPavel Labath cu = &cu->GetNonSkeletonUnit();
5508dae4bbSPavel Labath if (llvm::Optional<uint64_t> die_offset = entry.getDIEUnitOffset())
563b926988SPavel Labath return DIERef(cu->GetSymbolFileDWARF().GetDwoNum(),
573b926988SPavel Labath DIERef::Section::DebugInfo, cu->GetOffset() + *die_offset);
5808dae4bbSPavel Labath
5967b45aceSPavel Labath return llvm::None;
60257ff339SPavel Labath }
61257ff339SPavel Labath
ProcessEntry(const DebugNames::Entry & entry,llvm::function_ref<bool (DWARFDIE die)> callback,llvm::StringRef name)625e04b5f2SJan Kratochvil bool DebugNamesDWARFIndex::ProcessEntry(
635e04b5f2SJan Kratochvil const DebugNames::Entry &entry,
64d482fe2aSJan Kratochvil llvm::function_ref<bool(DWARFDIE die)> callback, llvm::StringRef name) {
65d482fe2aSJan Kratochvil llvm::Optional<DIERef> ref = ToDIERef(entry);
66d482fe2aSJan Kratochvil if (!ref)
675e04b5f2SJan Kratochvil return true;
68*7b81192dSJeffrey Tan SymbolFileDWARF &dwarf = *llvm::cast<SymbolFileDWARF>(
69*7b81192dSJeffrey Tan m_module.GetSymbolFile()->GetBackingSymbolFile());
70d482fe2aSJan Kratochvil DWARFDIE die = dwarf.GetDIE(*ref);
71d482fe2aSJan Kratochvil if (!die)
72d482fe2aSJan Kratochvil return true;
73d482fe2aSJan Kratochvil return callback(die);
74e1d18758SPavel Labath }
75e1d18758SPavel Labath
MaybeLogLookupError(llvm::Error error,const DebugNames::NameIndex & ni,llvm::StringRef name)76e1d18758SPavel Labath void DebugNamesDWARFIndex::MaybeLogLookupError(llvm::Error error,
77e1d18758SPavel Labath const DebugNames::NameIndex &ni,
78e1d18758SPavel Labath llvm::StringRef name) {
79e1d18758SPavel Labath // Ignore SentinelErrors, log everything else.
80e1d18758SPavel Labath LLDB_LOG_ERROR(
812d75f627SPavel Labath GetLog(DWARFLog::Lookups),
82e1d18758SPavel Labath handleErrors(std::move(error), [](const DebugNames::SentinelError &) {}),
83e1d18758SPavel Labath "Failed to parse index entries for index at {1:x}, name {2}: {0}",
84e1d18758SPavel Labath ni.getUnitOffset(), name);
85e1d18758SPavel Labath }
86e1d18758SPavel Labath
GetGlobalVariables(ConstString basename,llvm::function_ref<bool (DWARFDIE die)> callback)875e04b5f2SJan Kratochvil void DebugNamesDWARFIndex::GetGlobalVariables(
88d482fe2aSJan Kratochvil ConstString basename, llvm::function_ref<bool(DWARFDIE die)> callback) {
89e1d18758SPavel Labath for (const DebugNames::Entry &entry :
90e1d18758SPavel Labath m_debug_names_up->equal_range(basename.GetStringRef())) {
91e1d18758SPavel Labath if (entry.tag() != DW_TAG_variable)
92e1d18758SPavel Labath continue;
93e1d18758SPavel Labath
94d482fe2aSJan Kratochvil if (!ProcessEntry(entry, callback, basename.GetStringRef()))
955e04b5f2SJan Kratochvil return;
96e1d18758SPavel Labath }
97e1d18758SPavel Labath
985e04b5f2SJan Kratochvil m_fallback.GetGlobalVariables(basename, callback);
995e04b5f2SJan Kratochvil }
100452bd87cSPavel Labath
GetGlobalVariables(const RegularExpression & regex,llvm::function_ref<bool (DWARFDIE die)> callback)1015e04b5f2SJan Kratochvil void DebugNamesDWARFIndex::GetGlobalVariables(
1025e04b5f2SJan Kratochvil const RegularExpression ®ex,
103d482fe2aSJan Kratochvil llvm::function_ref<bool(DWARFDIE die)> callback) {
104e1d18758SPavel Labath for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
105e1d18758SPavel Labath for (DebugNames::NameTableEntry nte: ni) {
106e1d18758SPavel Labath if (!regex.Execute(nte.getString()))
107e1d18758SPavel Labath continue;
108e1d18758SPavel Labath
1090be73889SIgor Kudrin uint64_t entry_offset = nte.getEntryOffset();
110e1d18758SPavel Labath llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
111e1d18758SPavel Labath for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
112e1d18758SPavel Labath if (entry_or->tag() != DW_TAG_variable)
113e1d18758SPavel Labath continue;
114e1d18758SPavel Labath
115d482fe2aSJan Kratochvil if (!ProcessEntry(*entry_or, callback,
116d482fe2aSJan Kratochvil llvm::StringRef(nte.getString())))
1175e04b5f2SJan Kratochvil return;
118e1d18758SPavel Labath }
119e1d18758SPavel Labath MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
120e1d18758SPavel Labath }
121e1d18758SPavel Labath }
1225e04b5f2SJan Kratochvil
1235e04b5f2SJan Kratochvil m_fallback.GetGlobalVariables(regex, callback);
124e1d18758SPavel Labath }
125e1d18758SPavel Labath
GetGlobalVariables(DWARFUnit & cu,llvm::function_ref<bool (DWARFDIE die)> callback)1265e04b5f2SJan Kratochvil void DebugNamesDWARFIndex::GetGlobalVariables(
1270dda5425SKim-Anh Tran DWARFUnit &cu, llvm::function_ref<bool(DWARFDIE die)> callback) {
128f3932b9aSJan Kratochvil lldbassert(!cu.GetSymbolFileDWARF().GetDwoNum());
129dc4bd2e4SPavel Labath uint64_t cu_offset = cu.GetOffset();
1302e9853e0SKim-Anh Tran bool found_entry_for_cu = false;
131dc4bd2e4SPavel Labath for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
132dc4bd2e4SPavel Labath for (DebugNames::NameTableEntry nte: ni) {
1330be73889SIgor Kudrin uint64_t entry_offset = nte.getEntryOffset();
134dc4bd2e4SPavel Labath llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
135dc4bd2e4SPavel Labath for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
136dc4bd2e4SPavel Labath if (entry_or->tag() != DW_TAG_variable)
137dc4bd2e4SPavel Labath continue;
138dc4bd2e4SPavel Labath if (entry_or->getCUOffset() != cu_offset)
139dc4bd2e4SPavel Labath continue;
140dc4bd2e4SPavel Labath
1412e9853e0SKim-Anh Tran found_entry_for_cu = true;
142d482fe2aSJan Kratochvil if (!ProcessEntry(*entry_or, callback,
143d482fe2aSJan Kratochvil llvm::StringRef(nte.getString())))
1445e04b5f2SJan Kratochvil return;
145dc4bd2e4SPavel Labath }
146dc4bd2e4SPavel Labath MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
147dc4bd2e4SPavel Labath }
148dc4bd2e4SPavel Labath }
1492e9853e0SKim-Anh Tran // If no name index for that particular CU was found, fallback to
1502e9853e0SKim-Anh Tran // creating the manual index.
1512e9853e0SKim-Anh Tran if (!found_entry_for_cu)
1525e04b5f2SJan Kratochvil m_fallback.GetGlobalVariables(cu, callback);
153dc4bd2e4SPavel Labath }
154dc4bd2e4SPavel Labath
GetCompleteObjCClass(ConstString class_name,bool must_be_implementation,llvm::function_ref<bool (DWARFDIE die)> callback)1555e04b5f2SJan Kratochvil void DebugNamesDWARFIndex::GetCompleteObjCClass(
1565e04b5f2SJan Kratochvil ConstString class_name, bool must_be_implementation,
157d482fe2aSJan Kratochvil llvm::function_ref<bool(DWARFDIE die)> callback) {
1588e93917eSJonas Devlieghere // Keep a list of incomplete types as fallback for when we don't find the
1598e93917eSJonas Devlieghere // complete type.
1608e93917eSJonas Devlieghere DIEArray incomplete_types;
1618e93917eSJonas Devlieghere
1628e93917eSJonas Devlieghere for (const DebugNames::Entry &entry :
1638e93917eSJonas Devlieghere m_debug_names_up->equal_range(class_name.GetStringRef())) {
1648e93917eSJonas Devlieghere if (entry.tag() != DW_TAG_structure_type &&
1658e93917eSJonas Devlieghere entry.tag() != DW_TAG_class_type)
1668e93917eSJonas Devlieghere continue;
1678e93917eSJonas Devlieghere
16867b45aceSPavel Labath llvm::Optional<DIERef> ref = ToDIERef(entry);
1698e93917eSJonas Devlieghere if (!ref)
1708e93917eSJonas Devlieghere continue;
1718e93917eSJonas Devlieghere
1723b926988SPavel Labath DWARFUnit *cu = m_debug_info.GetUnit(*ref);
1738e93917eSJonas Devlieghere if (!cu || !cu->Supports_DW_AT_APPLE_objc_complete_type()) {
17467b45aceSPavel Labath incomplete_types.push_back(*ref);
1758e93917eSJonas Devlieghere continue;
1768e93917eSJonas Devlieghere }
1778e93917eSJonas Devlieghere
17867b45aceSPavel Labath DWARFDIE die = m_debug_info.GetDIE(*ref);
179d482fe2aSJan Kratochvil if (!die) {
180d482fe2aSJan Kratochvil ReportInvalidDIERef(*ref, class_name.GetStringRef());
1818e93917eSJonas Devlieghere continue;
182d482fe2aSJan Kratochvil }
1838e93917eSJonas Devlieghere
1848e93917eSJonas Devlieghere if (die.GetAttributeValueAsUnsigned(DW_AT_APPLE_objc_complete_type, 0)) {
1858e93917eSJonas Devlieghere // If we find the complete version we're done.
186d482fe2aSJan Kratochvil callback(die);
1878e93917eSJonas Devlieghere return;
1888e93917eSJonas Devlieghere }
18980237523SJan Kratochvil incomplete_types.push_back(*ref);
1908e93917eSJonas Devlieghere }
1918e93917eSJonas Devlieghere
192d482fe2aSJan Kratochvil auto dierefcallback = DIERefCallback(callback, class_name.GetStringRef());
1935e04b5f2SJan Kratochvil for (DIERef ref : incomplete_types)
194d482fe2aSJan Kratochvil if (!dierefcallback(ref))
1955e04b5f2SJan Kratochvil return;
1965e04b5f2SJan Kratochvil
1975e04b5f2SJan Kratochvil m_fallback.GetCompleteObjCClass(class_name, must_be_implementation, callback);
1988e93917eSJonas Devlieghere }
1998e93917eSJonas Devlieghere
GetTypes(ConstString name,llvm::function_ref<bool (DWARFDIE die)> callback)2005e04b5f2SJan Kratochvil void DebugNamesDWARFIndex::GetTypes(
201d482fe2aSJan Kratochvil ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
20269389692SPavel Labath for (const DebugNames::Entry &entry :
20369389692SPavel Labath m_debug_names_up->equal_range(name.GetStringRef())) {
2045e04b5f2SJan Kratochvil if (isType(entry.tag())) {
205d482fe2aSJan Kratochvil if (!ProcessEntry(entry, callback, name.GetStringRef()))
2065e04b5f2SJan Kratochvil return;
20769389692SPavel Labath }
20869389692SPavel Labath }
20969389692SPavel Labath
2105e04b5f2SJan Kratochvil m_fallback.GetTypes(name, callback);
2115e04b5f2SJan Kratochvil }
2120e33a0cdSPavel Labath
GetTypes(const DWARFDeclContext & context,llvm::function_ref<bool (DWARFDIE die)> callback)2135e04b5f2SJan Kratochvil void DebugNamesDWARFIndex::GetTypes(
2145e04b5f2SJan Kratochvil const DWARFDeclContext &context,
215d482fe2aSJan Kratochvil llvm::function_ref<bool(DWARFDIE die)> callback) {
216d482fe2aSJan Kratochvil auto name = context[0].name;
217d482fe2aSJan Kratochvil for (const DebugNames::Entry &entry : m_debug_names_up->equal_range(name)) {
2185e04b5f2SJan Kratochvil if (entry.tag() == context[0].tag) {
219d482fe2aSJan Kratochvil if (!ProcessEntry(entry, callback, name))
2205e04b5f2SJan Kratochvil return;
2210e33a0cdSPavel Labath }
2220e33a0cdSPavel Labath }
2230e33a0cdSPavel Labath
2245e04b5f2SJan Kratochvil m_fallback.GetTypes(context, callback);
2255e04b5f2SJan Kratochvil }
2266675e652SPavel Labath
GetNamespaces(ConstString name,llvm::function_ref<bool (DWARFDIE die)> callback)2275e04b5f2SJan Kratochvil void DebugNamesDWARFIndex::GetNamespaces(
228d482fe2aSJan Kratochvil ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
2296675e652SPavel Labath for (const DebugNames::Entry &entry :
2306675e652SPavel Labath m_debug_names_up->equal_range(name.GetStringRef())) {
2315e04b5f2SJan Kratochvil if (entry.tag() == DW_TAG_namespace) {
232d482fe2aSJan Kratochvil if (!ProcessEntry(entry, callback, name.GetStringRef()))
2335e04b5f2SJan Kratochvil return;
2346675e652SPavel Labath }
2356675e652SPavel Labath }
2366675e652SPavel Labath
2375e04b5f2SJan Kratochvil m_fallback.GetNamespaces(name, callback);
2385e04b5f2SJan Kratochvil }
2395e04b5f2SJan Kratochvil
GetFunctions(ConstString name,SymbolFileDWARF & dwarf,const CompilerDeclContext & parent_decl_ctx,uint32_t name_type_mask,llvm::function_ref<bool (DWARFDIE die)> callback)240257ff339SPavel Labath void DebugNamesDWARFIndex::GetFunctions(
2413b926988SPavel Labath ConstString name, SymbolFileDWARF &dwarf,
242257ff339SPavel Labath const CompilerDeclContext &parent_decl_ctx, uint32_t name_type_mask,
2435e04b5f2SJan Kratochvil llvm::function_ref<bool(DWARFDIE die)> callback) {
244257ff339SPavel Labath
2455e04b5f2SJan Kratochvil std::set<DWARFDebugInfoEntry *> seen;
246257ff339SPavel Labath for (const DebugNames::Entry &entry :
247257ff339SPavel Labath m_debug_names_up->equal_range(name.GetStringRef())) {
248257ff339SPavel Labath Tag tag = entry.tag();
249257ff339SPavel Labath if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine)
250257ff339SPavel Labath continue;
251257ff339SPavel Labath
2525e04b5f2SJan Kratochvil if (llvm::Optional<DIERef> ref = ToDIERef(entry)) {
2535e04b5f2SJan Kratochvil if (!ProcessFunctionDIE(name.GetStringRef(), *ref, dwarf, parent_decl_ctx,
2545e04b5f2SJan Kratochvil name_type_mask, [&](DWARFDIE die) {
2555e04b5f2SJan Kratochvil if (!seen.insert(die.GetDIE()).second)
2565e04b5f2SJan Kratochvil return true;
2575e04b5f2SJan Kratochvil return callback(die);
2585e04b5f2SJan Kratochvil }))
2595e04b5f2SJan Kratochvil return;
2605e04b5f2SJan Kratochvil }
261257ff339SPavel Labath }
262c6c7bfc4SGeorge Rimar
2635e04b5f2SJan Kratochvil m_fallback.GetFunctions(name, dwarf, parent_decl_ctx, name_type_mask,
2645e04b5f2SJan Kratochvil callback);
265257ff339SPavel Labath }
266257ff339SPavel Labath
GetFunctions(const RegularExpression & regex,llvm::function_ref<bool (DWARFDIE die)> callback)2675e04b5f2SJan Kratochvil void DebugNamesDWARFIndex::GetFunctions(
2685e04b5f2SJan Kratochvil const RegularExpression ®ex,
269d482fe2aSJan Kratochvil llvm::function_ref<bool(DWARFDIE die)> callback) {
270a3ee1e7fSPavel Labath for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
271a3ee1e7fSPavel Labath for (DebugNames::NameTableEntry nte: ni) {
272a3ee1e7fSPavel Labath if (!regex.Execute(nte.getString()))
273a3ee1e7fSPavel Labath continue;
274a3ee1e7fSPavel Labath
2750be73889SIgor Kudrin uint64_t entry_offset = nte.getEntryOffset();
276a3ee1e7fSPavel Labath llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
277a3ee1e7fSPavel Labath for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
278a3ee1e7fSPavel Labath Tag tag = entry_or->tag();
279a3ee1e7fSPavel Labath if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine)
280a3ee1e7fSPavel Labath continue;
281a3ee1e7fSPavel Labath
282d482fe2aSJan Kratochvil if (!ProcessEntry(*entry_or, callback,
283d482fe2aSJan Kratochvil llvm::StringRef(nte.getString())))
2845e04b5f2SJan Kratochvil return;
285a3ee1e7fSPavel Labath }
286a3ee1e7fSPavel Labath MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
287a3ee1e7fSPavel Labath }
288a3ee1e7fSPavel Labath }
2895e04b5f2SJan Kratochvil
2905e04b5f2SJan Kratochvil m_fallback.GetFunctions(regex, callback);
291a3ee1e7fSPavel Labath }
292a3ee1e7fSPavel Labath
Dump(Stream & s)293e1d18758SPavel Labath void DebugNamesDWARFIndex::Dump(Stream &s) {
294452bd87cSPavel Labath m_fallback.Dump(s);
295452bd87cSPavel Labath
296e1d18758SPavel Labath std::string data;
297e1d18758SPavel Labath llvm::raw_string_ostream os(data);
298e1d18758SPavel Labath m_debug_names_up->dump(os);
299e1d18758SPavel Labath s.PutCString(os.str());
300e1d18758SPavel Labath }
301