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