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 
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>>
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>
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 
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 
75 void DebugNamesDWARFIndex::Append(const DebugNames::Entry &entry,
76                                   DIEArray &offsets) {
77   if (DIERef ref = ToDIERef(entry))
78     offsets.push_back(ref);
79 }
80 
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 
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 
105 void DebugNamesDWARFIndex::GetGlobalVariables(const RegularExpression &regex,
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 
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 
149 void DebugNamesDWARFIndex::GetTypes(ConstString name, DIEArray &offsets) {
150   m_fallback.GetTypes(name, offsets);
151 
152   for (const DebugNames::Entry &entry :
153        m_debug_names_up->equal_range(name.GetStringRef())) {
154     if (isType(entry.tag()))
155       Append(entry, offsets);
156   }
157 }
158 
159 void DebugNamesDWARFIndex::GetTypes(const DWARFDeclContext &context,
160                                     DIEArray &offsets) {
161   m_fallback.GetTypes(context, offsets);
162 
163   for (const DebugNames::Entry &entry :
164        m_debug_names_up->equal_range(context[0].name)) {
165     if (entry.tag() == context[0].tag)
166       Append(entry, offsets);
167   }
168 }
169 
170 void DebugNamesDWARFIndex::GetNamespaces(ConstString name, DIEArray &offsets) {
171   m_fallback.GetNamespaces(name, offsets);
172 
173   for (const DebugNames::Entry &entry :
174        m_debug_names_up->equal_range(name.GetStringRef())) {
175     if (entry.tag() == DW_TAG_namespace)
176       Append(entry, offsets);
177   }
178 }
179 
180 void DebugNamesDWARFIndex::GetFunctions(
181     ConstString name, DWARFDebugInfo &info,
182     const CompilerDeclContext &parent_decl_ctx, uint32_t name_type_mask,
183     std::vector<DWARFDIE> &dies) {
184 
185   m_fallback.GetFunctions(name, info, parent_decl_ctx, name_type_mask, dies);
186 
187   for (const DebugNames::Entry &entry :
188        m_debug_names_up->equal_range(name.GetStringRef())) {
189     Tag tag = entry.tag();
190     if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine)
191       continue;
192 
193     if (DIERef ref = ToDIERef(entry))
194       ProcessFunctionDIE(name.GetStringRef(), ref, info, parent_decl_ctx,
195                          name_type_mask, dies);
196   }
197 }
198 
199 void DebugNamesDWARFIndex::GetFunctions(const RegularExpression &regex,
200                                         DIEArray &offsets) {
201   m_fallback.GetFunctions(regex, offsets);
202 
203   for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
204     for (DebugNames::NameTableEntry nte: ni) {
205       if (!regex.Execute(nte.getString()))
206         continue;
207 
208       uint32_t entry_offset = nte.getEntryOffset();
209       llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
210       for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
211         Tag tag = entry_or->tag();
212         if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine)
213           continue;
214 
215         Append(*entry_or, offsets);
216       }
217       MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
218     }
219   }
220 }
221 
222 void DebugNamesDWARFIndex::Dump(Stream &s) {
223   m_fallback.Dump(s);
224 
225   std::string data;
226   llvm::raw_string_ostream os(data);
227   m_debug_names_up->dump(os);
228   s.PutCString(os.str());
229 }
230