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