1 //===-- DebugNamesDWARFIndex.cpp -------------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h"
10 #include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"
11 #include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h"
12 #include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h"
13 #include "lldb/Utility/RegularExpression.h"
14 #include "lldb/Utility/Stream.h"
16 using namespace lldb_private;
19 llvm::Expected<std::unique_ptr<DebugNamesDWARFIndex>>
20 DebugNamesDWARFIndex::Create(Module &module, DWARFDataExtractor debug_names,
21 DWARFDataExtractor debug_str,
22 DWARFDebugInfo *debug_info) {
24 return llvm::make_error<llvm::StringError>("debug info null",
25 llvm::inconvertibleErrorCode());
27 auto index_up = llvm::make_unique<DebugNames>(debug_names.GetAsLLVM(),
28 debug_str.GetAsLLVM());
29 if (llvm::Error E = index_up->extract())
32 return std::unique_ptr<DebugNamesDWARFIndex>(new DebugNamesDWARFIndex(
33 module, std::move(index_up), debug_names, debug_str, *debug_info));
36 llvm::DenseSet<dw_offset_t>
37 DebugNamesDWARFIndex::GetUnits(const DebugNames &debug_names) {
38 llvm::DenseSet<dw_offset_t> result;
39 for (const DebugNames::NameIndex &ni : debug_names) {
40 for (uint32_t cu = 0; cu < ni.getCUCount(); ++cu)
41 result.insert(ni.getCUOffset(cu));
46 llvm::Optional<DIERef>
47 DebugNamesDWARFIndex::ToDIERef(const DebugNames::Entry &entry) {
48 llvm::Optional<uint64_t> cu_offset = entry.getCUOffset();
52 DWARFUnit *cu = m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *cu_offset);
56 // This initializes the DWO symbol file. It's not possible for
57 // GetDwoSymbolFile to call this automatically because of mutual recursion
58 // between this and DWARFDebugInfoEntry::GetAttributeValue.
59 cu->ExtractUnitDIEIfNeeded();
60 cu = &cu->GetNonSkeletonUnit();
62 if (llvm::Optional<uint64_t> die_offset = entry.getDIEUnitOffset())
63 return DIERef(cu->GetSymbolFileDWARF().GetDwoNum(),
64 DIERef::Section::DebugInfo, cu->GetOffset() + *die_offset);
69 void DebugNamesDWARFIndex::Append(const DebugNames::Entry &entry,
71 if (llvm::Optional<DIERef> ref = ToDIERef(entry))
72 offsets.push_back(*ref);
75 void DebugNamesDWARFIndex::MaybeLogLookupError(llvm::Error error,
76 const DebugNames::NameIndex &ni,
77 llvm::StringRef name) {
78 // Ignore SentinelErrors, log everything else.
80 LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS),
81 handleErrors(std::move(error), [](const DebugNames::SentinelError &) {}),
82 "Failed to parse index entries for index at {1:x}, name {2}: {0}",
83 ni.getUnitOffset(), name);
86 void DebugNamesDWARFIndex::GetGlobalVariables(ConstString basename,
88 m_fallback.GetGlobalVariables(basename, offsets);
90 for (const DebugNames::Entry &entry :
91 m_debug_names_up->equal_range(basename.GetStringRef())) {
92 if (entry.tag() != DW_TAG_variable)
95 Append(entry, offsets);
99 void DebugNamesDWARFIndex::GetGlobalVariables(const RegularExpression ®ex,
101 m_fallback.GetGlobalVariables(regex, offsets);
103 for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
104 for (DebugNames::NameTableEntry nte: ni) {
105 if (!regex.Execute(nte.getString()))
108 uint32_t entry_offset = nte.getEntryOffset();
109 llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
110 for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
111 if (entry_or->tag() != DW_TAG_variable)
114 Append(*entry_or, offsets);
116 MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
121 void DebugNamesDWARFIndex::GetGlobalVariables(const DWARFUnit &cu,
123 m_fallback.GetGlobalVariables(cu, offsets);
125 uint64_t cu_offset = cu.GetOffset();
126 for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
127 for (DebugNames::NameTableEntry nte: ni) {
128 uint32_t entry_offset = nte.getEntryOffset();
129 llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
130 for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
131 if (entry_or->tag() != DW_TAG_variable)
133 if (entry_or->getCUOffset() != cu_offset)
136 Append(*entry_or, offsets);
138 MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
143 void DebugNamesDWARFIndex::GetCompleteObjCClass(ConstString class_name,
144 bool must_be_implementation,
146 m_fallback.GetCompleteObjCClass(class_name, must_be_implementation, offsets);
148 // Keep a list of incomplete types as fallback for when we don't find the
150 DIEArray incomplete_types;
152 for (const DebugNames::Entry &entry :
153 m_debug_names_up->equal_range(class_name.GetStringRef())) {
154 if (entry.tag() != DW_TAG_structure_type &&
155 entry.tag() != DW_TAG_class_type)
158 llvm::Optional<DIERef> ref = ToDIERef(entry);
162 DWARFUnit *cu = m_debug_info.GetUnit(*ref);
163 if (!cu || !cu->Supports_DW_AT_APPLE_objc_complete_type()) {
164 incomplete_types.push_back(*ref);
168 // FIXME: We should return DWARFDIEs so we don't have to resolve it twice.
169 DWARFDIE die = m_debug_info.GetDIE(*ref);
173 if (die.GetAttributeValueAsUnsigned(DW_AT_APPLE_objc_complete_type, 0)) {
174 // If we find the complete version we're done.
175 offsets.push_back(*ref);
178 incomplete_types.push_back(*ref);
182 offsets.insert(offsets.end(), incomplete_types.begin(),
183 incomplete_types.end());
186 void DebugNamesDWARFIndex::GetTypes(ConstString name, DIEArray &offsets) {
187 m_fallback.GetTypes(name, offsets);
189 for (const DebugNames::Entry &entry :
190 m_debug_names_up->equal_range(name.GetStringRef())) {
191 if (isType(entry.tag()))
192 Append(entry, offsets);
196 void DebugNamesDWARFIndex::GetTypes(const DWARFDeclContext &context,
198 m_fallback.GetTypes(context, offsets);
200 for (const DebugNames::Entry &entry :
201 m_debug_names_up->equal_range(context[0].name)) {
202 if (entry.tag() == context[0].tag)
203 Append(entry, offsets);
207 void DebugNamesDWARFIndex::GetNamespaces(ConstString name, DIEArray &offsets) {
208 m_fallback.GetNamespaces(name, offsets);
210 for (const DebugNames::Entry &entry :
211 m_debug_names_up->equal_range(name.GetStringRef())) {
212 if (entry.tag() == DW_TAG_namespace)
213 Append(entry, offsets);
217 void DebugNamesDWARFIndex::GetFunctions(
218 ConstString name, SymbolFileDWARF &dwarf,
219 const CompilerDeclContext &parent_decl_ctx, uint32_t name_type_mask,
220 std::vector<DWARFDIE> &dies) {
222 std::vector<DWARFDIE> v;
223 m_fallback.GetFunctions(name, dwarf, parent_decl_ctx, name_type_mask, v);
225 for (const DebugNames::Entry &entry :
226 m_debug_names_up->equal_range(name.GetStringRef())) {
227 Tag tag = entry.tag();
228 if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine)
231 if (llvm::Optional<DIERef> ref = ToDIERef(entry))
232 ProcessFunctionDIE(name.GetStringRef(), *ref, dwarf, parent_decl_ctx,
236 std::set<DWARFDebugInfoEntry *> seen;
237 for (DWARFDIE die : v)
238 if (seen.insert(die.GetDIE()).second)
242 void DebugNamesDWARFIndex::GetFunctions(const RegularExpression ®ex,
244 m_fallback.GetFunctions(regex, offsets);
246 for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
247 for (DebugNames::NameTableEntry nte: ni) {
248 if (!regex.Execute(nte.getString()))
251 uint32_t entry_offset = nte.getEntryOffset();
252 llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
253 for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
254 Tag tag = entry_or->tag();
255 if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine)
258 Append(*entry_or, offsets);
260 MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
265 void DebugNamesDWARFIndex::Dump(Stream &s) {
269 llvm::raw_string_ostream os(data);
270 m_debug_names_up->dump(os);
271 s.PutCString(os.str());