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