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