1 //===-- DebugNamesDWARFIndex.cpp ------------------------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
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"
15 
16 using namespace lldb_private;
17 using namespace lldb;
18 
19 llvm::Expected<std::unique_ptr<DebugNamesDWARFIndex>>
20 DebugNamesDWARFIndex::Create(Module &module, DWARFDataExtractor debug_names,
21                              DWARFDataExtractor debug_str,
22                              DWARFDebugInfo *debug_info) {
23   if (!debug_info) {
24     return llvm::make_error<llvm::StringError>("debug info null",
25                                                llvm::inconvertibleErrorCode());
26   }
27   auto index_up = std::make_unique<DebugNames>(debug_names.GetAsLLVM(),
28                                                 debug_str.GetAsLLVM());
29   if (llvm::Error E = index_up->extract())
30     return std::move(E);
31 
32   return std::unique_ptr<DebugNamesDWARFIndex>(new DebugNamesDWARFIndex(
33       module, std::move(index_up), debug_names, debug_str, *debug_info));
34 }
35 
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));
42   }
43   return result;
44 }
45 
46 llvm::Optional<DIERef>
47 DebugNamesDWARFIndex::ToDIERef(const DebugNames::Entry &entry) {
48   llvm::Optional<uint64_t> cu_offset = entry.getCUOffset();
49   if (!cu_offset)
50     return llvm::None;
51 
52   DWARFUnit *cu = m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *cu_offset);
53   if (!cu)
54     return llvm::None;
55 
56   cu = &cu->GetNonSkeletonUnit();
57   if (llvm::Optional<uint64_t> die_offset = entry.getDIEUnitOffset())
58     return DIERef(cu->GetSymbolFileDWARF().GetDwoNum(),
59                   DIERef::Section::DebugInfo, cu->GetOffset() + *die_offset);
60 
61   return llvm::None;
62 }
63 
64 void DebugNamesDWARFIndex::Append(const DebugNames::Entry &entry,
65                                   DIEArray &offsets) {
66   if (llvm::Optional<DIERef> ref = ToDIERef(entry))
67     offsets.push_back(*ref);
68 }
69 
70 void DebugNamesDWARFIndex::MaybeLogLookupError(llvm::Error error,
71                                                const DebugNames::NameIndex &ni,
72                                                llvm::StringRef name) {
73   // Ignore SentinelErrors, log everything else.
74   LLDB_LOG_ERROR(
75       LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS),
76       handleErrors(std::move(error), [](const DebugNames::SentinelError &) {}),
77       "Failed to parse index entries for index at {1:x}, name {2}: {0}",
78       ni.getUnitOffset(), name);
79 }
80 
81 void DebugNamesDWARFIndex::GetGlobalVariables(ConstString basename,
82                                               DIEArray &offsets) {
83   m_fallback.GetGlobalVariables(basename, offsets);
84 
85   for (const DebugNames::Entry &entry :
86        m_debug_names_up->equal_range(basename.GetStringRef())) {
87     if (entry.tag() != DW_TAG_variable)
88       continue;
89 
90     Append(entry, offsets);
91   }
92 }
93 
94 void DebugNamesDWARFIndex::GetGlobalVariables(const RegularExpression &regex,
95                                               DIEArray &offsets) {
96   m_fallback.GetGlobalVariables(regex, offsets);
97 
98   for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
99     for (DebugNames::NameTableEntry nte: ni) {
100       if (!regex.Execute(nte.getString()))
101         continue;
102 
103       uint64_t entry_offset = nte.getEntryOffset();
104       llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
105       for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
106         if (entry_or->tag() != DW_TAG_variable)
107           continue;
108 
109         Append(*entry_or, offsets);
110       }
111       MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
112     }
113   }
114 }
115 
116 void DebugNamesDWARFIndex::GetGlobalVariables(const DWARFUnit &cu,
117                                               DIEArray &offsets) {
118   m_fallback.GetGlobalVariables(cu, offsets);
119 
120   uint64_t cu_offset = cu.GetOffset();
121   for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
122     for (DebugNames::NameTableEntry nte: ni) {
123       uint64_t entry_offset = nte.getEntryOffset();
124       llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
125       for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
126         if (entry_or->tag() != DW_TAG_variable)
127           continue;
128         if (entry_or->getCUOffset() != cu_offset)
129           continue;
130 
131         Append(*entry_or, offsets);
132       }
133       MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
134     }
135   }
136 }
137 
138 void DebugNamesDWARFIndex::GetCompleteObjCClass(ConstString class_name,
139                                                 bool must_be_implementation,
140                                                 DIEArray &offsets) {
141   m_fallback.GetCompleteObjCClass(class_name, must_be_implementation, offsets);
142 
143   // Keep a list of incomplete types as fallback for when we don't find the
144   // complete type.
145   DIEArray incomplete_types;
146 
147   for (const DebugNames::Entry &entry :
148        m_debug_names_up->equal_range(class_name.GetStringRef())) {
149     if (entry.tag() != DW_TAG_structure_type &&
150         entry.tag() != DW_TAG_class_type)
151       continue;
152 
153     llvm::Optional<DIERef> ref = ToDIERef(entry);
154     if (!ref)
155       continue;
156 
157     DWARFUnit *cu = m_debug_info.GetUnit(*ref);
158     if (!cu || !cu->Supports_DW_AT_APPLE_objc_complete_type()) {
159       incomplete_types.push_back(*ref);
160       continue;
161     }
162 
163     // FIXME: We should return DWARFDIEs so we don't have to resolve it twice.
164     DWARFDIE die = m_debug_info.GetDIE(*ref);
165     if (!die)
166       continue;
167 
168     if (die.GetAttributeValueAsUnsigned(DW_AT_APPLE_objc_complete_type, 0)) {
169       // If we find the complete version we're done.
170       offsets.push_back(*ref);
171       return;
172     } else {
173       incomplete_types.push_back(*ref);
174     }
175   }
176 
177   offsets.insert(offsets.end(), incomplete_types.begin(),
178                  incomplete_types.end());
179 }
180 
181 void DebugNamesDWARFIndex::GetTypes(ConstString name, DIEArray &offsets) {
182   m_fallback.GetTypes(name, offsets);
183 
184   for (const DebugNames::Entry &entry :
185        m_debug_names_up->equal_range(name.GetStringRef())) {
186     if (isType(entry.tag()))
187       Append(entry, offsets);
188   }
189 }
190 
191 void DebugNamesDWARFIndex::GetTypes(const DWARFDeclContext &context,
192                                     DIEArray &offsets) {
193   m_fallback.GetTypes(context, offsets);
194 
195   for (const DebugNames::Entry &entry :
196        m_debug_names_up->equal_range(context[0].name)) {
197     if (entry.tag() == context[0].tag)
198       Append(entry, offsets);
199   }
200 }
201 
202 void DebugNamesDWARFIndex::GetNamespaces(ConstString name, DIEArray &offsets) {
203   m_fallback.GetNamespaces(name, offsets);
204 
205   for (const DebugNames::Entry &entry :
206        m_debug_names_up->equal_range(name.GetStringRef())) {
207     if (entry.tag() == DW_TAG_namespace)
208       Append(entry, offsets);
209   }
210 }
211 
212 void DebugNamesDWARFIndex::GetFunctions(
213     ConstString name, SymbolFileDWARF &dwarf,
214     const CompilerDeclContext &parent_decl_ctx, uint32_t name_type_mask,
215     std::vector<DWARFDIE> &dies) {
216 
217   std::vector<DWARFDIE> v;
218   m_fallback.GetFunctions(name, dwarf, parent_decl_ctx, name_type_mask, v);
219 
220   for (const DebugNames::Entry &entry :
221        m_debug_names_up->equal_range(name.GetStringRef())) {
222     Tag tag = entry.tag();
223     if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine)
224       continue;
225 
226     if (llvm::Optional<DIERef> ref = ToDIERef(entry))
227       ProcessFunctionDIE(name.GetStringRef(), *ref, dwarf, parent_decl_ctx,
228                          name_type_mask, v);
229   }
230 
231   std::set<DWARFDebugInfoEntry *> seen;
232   for (DWARFDIE die : v)
233     if (seen.insert(die.GetDIE()).second)
234       dies.push_back(die);
235 }
236 
237 void DebugNamesDWARFIndex::GetFunctions(const RegularExpression &regex,
238                                         DIEArray &offsets) {
239   m_fallback.GetFunctions(regex, offsets);
240 
241   for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
242     for (DebugNames::NameTableEntry nte: ni) {
243       if (!regex.Execute(nte.getString()))
244         continue;
245 
246       uint64_t entry_offset = nte.getEntryOffset();
247       llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
248       for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
249         Tag tag = entry_or->tag();
250         if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine)
251           continue;
252 
253         Append(*entry_or, offsets);
254       }
255       MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
256     }
257   }
258 }
259 
260 void DebugNamesDWARFIndex::Dump(Stream &s) {
261   m_fallback.Dump(s);
262 
263   std::string data;
264   llvm::raw_string_ostream os(data);
265   m_debug_names_up->dump(os);
266   s.PutCString(os.str());
267 }
268