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 &regex,
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 &regex,
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