| 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/LogChannelDWARF.h" |
| 13 | #include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h" |
| 14 | #include "lldb/Core/Module.h" |
| 15 | #include "lldb/Utility/RegularExpression.h" |
| 16 | #include "lldb/Utility/Stream.h" |
| 17 | #include "llvm/ADT/Sequence.h" |
| 18 | #include <optional> |
| 19 | |
| 20 | using namespace lldb_private; |
| 21 | using namespace lldb; |
| 22 | using namespace lldb_private::dwarf; |
| 23 | using namespace lldb_private::plugin::dwarf; |
| 24 | |
| 25 | llvm::Expected<std::unique_ptr<DebugNamesDWARFIndex>> |
| 26 | DebugNamesDWARFIndex::(Module &module, DWARFDataExtractor debug_names, |
| 27 | DWARFDataExtractor debug_str, |
| 28 | SymbolFileDWARF &dwarf) { |
| 29 | auto index_up = std::make_unique<DebugNames>(args: debug_names.GetAsLLVMDWARF(), |
| 30 | args: debug_str.GetAsLLVM()); |
| 31 | if (llvm::Error E = index_up->extract()) |
| 32 | return std::move(E); |
| 33 | |
| 34 | return std::unique_ptr<DebugNamesDWARFIndex>(new DebugNamesDWARFIndex( |
| 35 | module, std::move(index_up), debug_names, debug_str, dwarf)); |
| 36 | } |
| 37 | |
| 38 | llvm::DenseSet<uint64_t> |
| 39 | DebugNamesDWARFIndex::GetTypeUnitSignatures(const DebugNames &debug_names) { |
| 40 | llvm::DenseSet<uint64_t> result; |
| 41 | for (const DebugNames::NameIndex &ni : debug_names) { |
| 42 | const uint32_t num_tus = ni.getForeignTUCount(); |
| 43 | for (uint32_t tu = 0; tu < num_tus; ++tu) |
| 44 | result.insert(V: ni.getForeignTUSignature(TU: tu)); |
| 45 | } |
| 46 | return result; |
| 47 | } |
| 48 | |
| 49 | llvm::DenseSet<dw_offset_t> |
| 50 | DebugNamesDWARFIndex::GetUnits(const DebugNames &debug_names) { |
| 51 | llvm::DenseSet<dw_offset_t> result; |
| 52 | for (const DebugNames::NameIndex &ni : debug_names) { |
| 53 | const uint32_t num_cus = ni.getCUCount(); |
| 54 | for (uint32_t cu = 0; cu < num_cus; ++cu) |
| 55 | result.insert(V: ni.getCUOffset(CU: cu)); |
| 56 | const uint32_t num_tus = ni.getLocalTUCount(); |
| 57 | for (uint32_t tu = 0; tu < num_tus; ++tu) |
| 58 | result.insert(V: ni.getLocalTUOffset(TU: tu)); |
| 59 | } |
| 60 | return result; |
| 61 | } |
| 62 | |
| 63 | std::optional<DWARFTypeUnit *> |
| 64 | DebugNamesDWARFIndex::GetForeignTypeUnit(const DebugNames::Entry &entry) const { |
| 65 | std::optional<uint64_t> type_sig = entry.getForeignTUTypeSignature(); |
| 66 | if (!type_sig.has_value()) |
| 67 | return std::nullopt; |
| 68 | |
| 69 | // Ask the entry for the skeleton compile unit offset and fetch the .dwo |
| 70 | // file from it and get the type unit by signature from there. If we find |
| 71 | // the type unit in the .dwo file, we don't need to check that the |
| 72 | // DW_AT_dwo_name matches because each .dwo file can have its own type unit. |
| 73 | std::optional<uint64_t> cu_offset = entry.getRelatedCUOffset(); |
| 74 | if (!cu_offset) |
| 75 | return nullptr; // Return NULL, this is a type unit, but couldn't find it. |
| 76 | |
| 77 | DWARFUnit *cu = |
| 78 | m_debug_info.GetUnitAtOffset(section: DIERef::Section::DebugInfo, cu_offset: *cu_offset); |
| 79 | if (!cu) |
| 80 | return nullptr; // Return NULL, this is a type unit, but couldn't find it. |
| 81 | |
| 82 | auto dwp_sp = m_debug_info.GetDwpSymbolFile(); |
| 83 | if (!dwp_sp) { |
| 84 | // No .dwp file, we need to load the .dwo file. |
| 85 | DWARFUnit &dwo_cu = cu->GetNonSkeletonUnit(); |
| 86 | // We don't need the check if the type unit matches the .dwo file if we have |
| 87 | // a .dwo file (not a .dwp), so we can just return the value here. |
| 88 | if (!dwo_cu.IsDWOUnit()) |
| 89 | return nullptr; // We weren't able to load the .dwo file. |
| 90 | return dwo_cu.GetSymbolFileDWARF().DebugInfo().GetTypeUnitForHash( |
| 91 | hash: *type_sig); |
| 92 | } |
| 93 | // We have a .dwp file, just get the type unit from there. We need to verify |
| 94 | // that the type unit that ended up in the final .dwp file is the right type |
| 95 | // unit. Type units have signatures which are the same across multiple .dwo |
| 96 | // files, but only one of those type units will end up in the .dwp file. The |
| 97 | // contents of type units for the same type can be different in different .dwo |
| 98 | // files, which means the DIE offsets might not be the same between two |
| 99 | // different type units. So we need to determine if this accelerator table |
| 100 | // matches the type unit that ended up in the .dwp file. If it doesn't match, |
| 101 | // then we need to ignore this accelerator table entry as the type unit that |
| 102 | // is in the .dwp file will have its own index. In order to determine if the |
| 103 | // type unit that ended up in a .dwp file matches this DebugNames::Entry, we |
| 104 | // need to find the skeleton compile unit for this entry. |
| 105 | DWARFTypeUnit *foreign_tu = dwp_sp->DebugInfo().GetTypeUnitForHash(hash: *type_sig); |
| 106 | if (!foreign_tu) |
| 107 | return nullptr; // Return NULL, this is a type unit, but couldn't find it. |
| 108 | |
| 109 | DWARFBaseDIE cu_die = cu->GetUnitDIEOnly(); |
| 110 | DWARFBaseDIE tu_die = foreign_tu->GetUnitDIEOnly(); |
| 111 | llvm::StringRef cu_dwo_name = |
| 112 | cu_die.GetAttributeValueAsString(attr: DW_AT_dwo_name, fail_value: nullptr); |
| 113 | llvm::StringRef tu_dwo_name = |
| 114 | tu_die.GetAttributeValueAsString(attr: DW_AT_dwo_name, fail_value: nullptr); |
| 115 | if (cu_dwo_name == tu_dwo_name) |
| 116 | return foreign_tu; // We found a match! |
| 117 | return nullptr; // Return NULL, this is a type unit, but couldn't find it. |
| 118 | } |
| 119 | |
| 120 | DWARFUnit * |
| 121 | DebugNamesDWARFIndex::GetNonSkeletonUnit(const DebugNames::Entry &entry) const { |
| 122 | |
| 123 | if (std::optional<DWARFTypeUnit *> foreign_tu = GetForeignTypeUnit(entry)) |
| 124 | return foreign_tu.value(); |
| 125 | |
| 126 | // Look for a DWARF unit offset (CU offset or local TU offset) as they are |
| 127 | // both offsets into the .debug_info section. |
| 128 | std::optional<uint64_t> unit_offset = entry.getCUOffset(); |
| 129 | if (!unit_offset) |
| 130 | unit_offset = entry.getLocalTUOffset(); |
| 131 | if (unit_offset) { |
| 132 | if (DWARFUnit *cu = m_debug_info.GetUnitAtOffset(section: DIERef::Section::DebugInfo, |
| 133 | cu_offset: *unit_offset)) |
| 134 | return &cu->GetNonSkeletonUnit(); |
| 135 | } |
| 136 | return nullptr; |
| 137 | } |
| 138 | |
| 139 | DWARFDIE DebugNamesDWARFIndex::GetDIE(const DebugNames::Entry &entry) const { |
| 140 | DWARFUnit *unit = GetNonSkeletonUnit(entry); |
| 141 | std::optional<uint64_t> die_offset = entry.getDIEUnitOffset(); |
| 142 | if (!unit || !die_offset) |
| 143 | return DWARFDIE(); |
| 144 | if (DWARFDIE die = unit->GetDIE(die_offset: unit->GetOffset() + *die_offset)) |
| 145 | return die; |
| 146 | |
| 147 | m_module.ReportErrorIfModifyDetected( |
| 148 | format: "the DWARF debug information has been modified (bad offset {0:x} in " |
| 149 | "debug_names section)\n" , |
| 150 | args&: *die_offset); |
| 151 | return DWARFDIE(); |
| 152 | } |
| 153 | |
| 154 | bool DebugNamesDWARFIndex::ProcessEntry( |
| 155 | const DebugNames::Entry &entry, |
| 156 | llvm::function_ref<bool(DWARFDIE die)> callback) { |
| 157 | DWARFDIE die = GetDIE(entry); |
| 158 | if (!die) |
| 159 | return true; |
| 160 | // Clang used to erroneously emit index entries for declaration DIEs in case |
| 161 | // when the definition is in a type unit (llvm.org/pr77696). |
| 162 | if (die.IsStructUnionOrClass() && |
| 163 | die.GetAttributeValueAsUnsigned(attr: DW_AT_declaration, fail_value: 0)) |
| 164 | return true; |
| 165 | return callback(die); |
| 166 | } |
| 167 | |
| 168 | void DebugNamesDWARFIndex::MaybeLogLookupError(llvm::Error error, |
| 169 | const DebugNames::NameIndex &ni, |
| 170 | llvm::StringRef name) { |
| 171 | // Ignore SentinelErrors, log everything else. |
| 172 | LLDB_LOG_ERROR( |
| 173 | GetLog(DWARFLog::Lookups), |
| 174 | handleErrors(std::move(error), [](const DebugNames::SentinelError &) {}), |
| 175 | "Failed to parse index entries for index at {1:x}, name {2}: {0}" , |
| 176 | ni.getUnitOffset(), name); |
| 177 | } |
| 178 | |
| 179 | void DebugNamesDWARFIndex::GetGlobalVariables( |
| 180 | ConstString basename, llvm::function_ref<bool(DWARFDIE die)> callback) { |
| 181 | for (const DebugNames::Entry &entry : |
| 182 | m_debug_names_up->equal_range(Key: basename.GetStringRef())) { |
| 183 | if (entry.tag() != DW_TAG_variable) |
| 184 | continue; |
| 185 | |
| 186 | if (!ProcessEntry(entry, callback)) |
| 187 | return; |
| 188 | } |
| 189 | |
| 190 | m_fallback.GetGlobalVariables(basename, callback); |
| 191 | } |
| 192 | |
| 193 | void DebugNamesDWARFIndex::GetGlobalVariables( |
| 194 | const RegularExpression ®ex, |
| 195 | llvm::function_ref<bool(DWARFDIE die)> callback) { |
| 196 | for (const DebugNames::NameIndex &ni: *m_debug_names_up) { |
| 197 | for (DebugNames::NameTableEntry nte: ni) { |
| 198 | Mangled mangled_name(nte.getString()); |
| 199 | if (!mangled_name.NameMatches(regex)) |
| 200 | continue; |
| 201 | |
| 202 | uint64_t entry_offset = nte.getEntryOffset(); |
| 203 | llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(Offset: &entry_offset); |
| 204 | for (; entry_or; entry_or = ni.getEntry(Offset: &entry_offset)) { |
| 205 | if (entry_or->tag() != DW_TAG_variable) |
| 206 | continue; |
| 207 | |
| 208 | if (!ProcessEntry(entry: *entry_or, callback)) |
| 209 | return; |
| 210 | } |
| 211 | MaybeLogLookupError(error: entry_or.takeError(), ni, name: nte.getString()); |
| 212 | } |
| 213 | } |
| 214 | |
| 215 | m_fallback.GetGlobalVariables(regex, callback); |
| 216 | } |
| 217 | |
| 218 | void DebugNamesDWARFIndex::GetGlobalVariables( |
| 219 | DWARFUnit &cu, llvm::function_ref<bool(DWARFDIE die)> callback) { |
| 220 | uint64_t cu_offset = cu.GetOffset(); |
| 221 | bool found_entry_for_cu = false; |
| 222 | for (const DebugNames::NameIndex &ni : *m_debug_names_up) { |
| 223 | // Check if this name index contains an entry for the given CU. |
| 224 | bool cu_matches = false; |
| 225 | for (uint32_t i = 0; i < ni.getCUCount(); ++i) { |
| 226 | if (ni.getCUOffset(CU: i) == cu_offset) { |
| 227 | cu_matches = true; |
| 228 | break; |
| 229 | } |
| 230 | } |
| 231 | if (!cu_matches) |
| 232 | continue; |
| 233 | |
| 234 | for (DebugNames::NameTableEntry nte : ni) { |
| 235 | uint64_t entry_offset = nte.getEntryOffset(); |
| 236 | llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(Offset: &entry_offset); |
| 237 | for (; entry_or; entry_or = ni.getEntry(Offset: &entry_offset)) { |
| 238 | if (entry_or->tag() != DW_TAG_variable) |
| 239 | continue; |
| 240 | if (entry_or->getCUOffset() != cu_offset) |
| 241 | continue; |
| 242 | |
| 243 | found_entry_for_cu = true; |
| 244 | if (!ProcessEntry(entry: *entry_or, callback)) |
| 245 | return; |
| 246 | } |
| 247 | MaybeLogLookupError(error: entry_or.takeError(), ni, name: nte.getString()); |
| 248 | } |
| 249 | } |
| 250 | // If no name index for that particular CU was found, fallback to |
| 251 | // creating the manual index. |
| 252 | if (!found_entry_for_cu) |
| 253 | m_fallback.GetGlobalVariables(unit&: cu, callback); |
| 254 | } |
| 255 | |
| 256 | void DebugNamesDWARFIndex::GetCompleteObjCClass( |
| 257 | ConstString class_name, bool must_be_implementation, |
| 258 | llvm::function_ref<bool(DWARFDIE die)> callback) { |
| 259 | // Keep a list of incomplete types as fallback for when we don't find the |
| 260 | // complete type. |
| 261 | std::vector<DWARFDIE> incomplete_types; |
| 262 | |
| 263 | for (const DebugNames::Entry &entry : |
| 264 | m_debug_names_up->equal_range(Key: class_name.GetStringRef())) { |
| 265 | if (entry.tag() != DW_TAG_structure_type && |
| 266 | entry.tag() != DW_TAG_class_type) |
| 267 | continue; |
| 268 | |
| 269 | DWARFDIE die = GetDIE(entry); |
| 270 | if (!die) { |
| 271 | // Report invalid |
| 272 | continue; |
| 273 | } |
| 274 | |
| 275 | if (die.GetAttributeValueAsUnsigned(attr: DW_AT_APPLE_objc_complete_type, fail_value: 0)) { |
| 276 | // If we find the complete version we're done. |
| 277 | callback(die); |
| 278 | return; |
| 279 | } |
| 280 | incomplete_types.push_back(x: die); |
| 281 | } |
| 282 | |
| 283 | for (DWARFDIE die : incomplete_types) |
| 284 | if (!callback(die)) |
| 285 | return; |
| 286 | |
| 287 | m_fallback.GetCompleteObjCClass(class_name, must_be_implementation, callback); |
| 288 | } |
| 289 | |
| 290 | namespace { |
| 291 | using Entry = llvm::DWARFDebugNames::Entry; |
| 292 | |
| 293 | /// If `entry` and all of its parents have an `IDX_parent`, use that information |
| 294 | /// to build and return a list of at most `max_parents` parent Entries. |
| 295 | /// `entry` itself is not included in the list. |
| 296 | /// If any parent does not have an `IDX_parent`, or the Entry data is corrupted, |
| 297 | /// nullopt is returned. |
| 298 | std::optional<llvm::SmallVector<Entry, 4>> |
| 299 | getParentChain(Entry entry, |
| 300 | uint32_t max_parents = std::numeric_limits<uint32_t>::max()) { |
| 301 | llvm::SmallVector<Entry, 4> parent_entries; |
| 302 | |
| 303 | do { |
| 304 | if (!entry.hasParentInformation()) |
| 305 | return std::nullopt; |
| 306 | |
| 307 | llvm::Expected<std::optional<Entry>> parent = entry.getParentDIEEntry(); |
| 308 | if (!parent) { |
| 309 | // Bad data. |
| 310 | LLDB_LOG_ERROR( |
| 311 | GetLog(DWARFLog::Lookups), parent.takeError(), |
| 312 | "Failed to extract parent entry from a non-empty IDX_parent" ); |
| 313 | return std::nullopt; |
| 314 | } |
| 315 | |
| 316 | // Last parent in the chain. |
| 317 | if (!parent->has_value()) |
| 318 | break; |
| 319 | |
| 320 | parent_entries.push_back(Elt: **parent); |
| 321 | entry = **parent; |
| 322 | } while (parent_entries.size() < max_parents); |
| 323 | |
| 324 | return parent_entries; |
| 325 | } |
| 326 | } // namespace |
| 327 | |
| 328 | void DebugNamesDWARFIndex::GetFullyQualifiedType( |
| 329 | const DWARFDeclContext &context, |
| 330 | llvm::function_ref<bool(DWARFDIE die)> callback) { |
| 331 | if (context.GetSize() == 0) |
| 332 | return; |
| 333 | |
| 334 | llvm::StringRef leaf_name = context[0].name; |
| 335 | llvm::SmallVector<llvm::StringRef> parent_names; |
| 336 | for (auto idx : llvm::seq<int>(Begin: 1, End: context.GetSize())) |
| 337 | parent_names.emplace_back(Args: context[idx].name); |
| 338 | |
| 339 | // For each entry, grab its parent chain and check if we have a match. |
| 340 | for (const DebugNames::Entry &entry : |
| 341 | m_debug_names_up->equal_range(Key: leaf_name)) { |
| 342 | if (!isType(T: entry.tag())) |
| 343 | continue; |
| 344 | |
| 345 | // If we get a NULL foreign_tu back, the entry doesn't match the type unit |
| 346 | // in the .dwp file, or we were not able to load the .dwo file or the DWO ID |
| 347 | // didn't match. |
| 348 | std::optional<DWARFTypeUnit *> foreign_tu = GetForeignTypeUnit(entry); |
| 349 | if (foreign_tu && foreign_tu.value() == nullptr) |
| 350 | continue; |
| 351 | |
| 352 | // Grab at most one extra parent, subsequent parents are not necessary to |
| 353 | // test equality. |
| 354 | std::optional<llvm::SmallVector<Entry, 4>> parent_chain = |
| 355 | getParentChain(entry, max_parents: parent_names.size() + 1); |
| 356 | |
| 357 | if (!parent_chain) { |
| 358 | // Fallback: use the base class implementation. |
| 359 | if (!ProcessEntry(entry, callback: [&](DWARFDIE die) { |
| 360 | return GetFullyQualifiedTypeImpl(context, die, callback); |
| 361 | })) |
| 362 | return; |
| 363 | continue; |
| 364 | } |
| 365 | |
| 366 | if (SameParentChain(parent_names, parent_entries: *parent_chain)) { |
| 367 | if (!ProcessEntry(entry, callback)) |
| 368 | return; |
| 369 | } |
| 370 | } |
| 371 | m_fallback.GetFullyQualifiedType(context, callback); |
| 372 | } |
| 373 | |
| 374 | bool DebugNamesDWARFIndex::SameAsEntryContext( |
| 375 | const CompilerContext &query_context, |
| 376 | const DebugNames::Entry &entry) const { |
| 377 | // TODO: check dwarf tag matches. |
| 378 | // Peek at the AT_name of `entry` and test equality to `name`. |
| 379 | auto maybe_dieoffset = entry.getDIEUnitOffset(); |
| 380 | if (!maybe_dieoffset) |
| 381 | return false; |
| 382 | DWARFUnit *unit = GetNonSkeletonUnit(entry); |
| 383 | if (!unit) |
| 384 | return false; |
| 385 | return query_context.name == |
| 386 | unit->PeekDIEName(die_offset: unit->GetOffset() + *maybe_dieoffset); |
| 387 | } |
| 388 | |
| 389 | bool DebugNamesDWARFIndex::SameParentChain( |
| 390 | llvm::ArrayRef<llvm::StringRef> parent_names, |
| 391 | llvm::ArrayRef<DebugNames::Entry> parent_entries) const { |
| 392 | |
| 393 | if (parent_entries.size() != parent_names.size()) |
| 394 | return false; |
| 395 | |
| 396 | auto SameAsEntryATName = [this](llvm::StringRef name, |
| 397 | const DebugNames::Entry &entry) { |
| 398 | // Peek at the AT_name of `entry` and test equality to `name`. |
| 399 | auto maybe_dieoffset = entry.getDIEUnitOffset(); |
| 400 | if (!maybe_dieoffset) |
| 401 | return false; |
| 402 | DWARFUnit *unit = GetNonSkeletonUnit(entry); |
| 403 | if (!unit) |
| 404 | return false; |
| 405 | return name == unit->PeekDIEName(die_offset: unit->GetOffset() + *maybe_dieoffset); |
| 406 | }; |
| 407 | |
| 408 | // If the AT_name of any parent fails to match the expected name, we don't |
| 409 | // have a match. |
| 410 | for (auto [parent_name, parent_entry] : |
| 411 | llvm::zip_equal(t&: parent_names, u&: parent_entries)) |
| 412 | if (!SameAsEntryATName(parent_name, parent_entry)) |
| 413 | return false; |
| 414 | return true; |
| 415 | } |
| 416 | |
| 417 | bool DebugNamesDWARFIndex::SameParentChain( |
| 418 | llvm::ArrayRef<CompilerContext> parent_contexts, |
| 419 | llvm::ArrayRef<DebugNames::Entry> parent_entries) const { |
| 420 | if (parent_entries.size() != parent_contexts.size()) |
| 421 | return false; |
| 422 | |
| 423 | // If the AT_name of any parent fails to match the expected name, we don't |
| 424 | // have a match. |
| 425 | for (auto [parent_context, parent_entry] : |
| 426 | llvm::zip_equal(t&: parent_contexts, u&: parent_entries)) |
| 427 | if (!SameAsEntryContext(query_context: parent_context, entry: parent_entry)) |
| 428 | return false; |
| 429 | return true; |
| 430 | } |
| 431 | |
| 432 | bool DebugNamesDWARFIndex::WithinParentChain( |
| 433 | llvm::ArrayRef<CompilerContext> query_contexts, |
| 434 | llvm::ArrayRef<DebugNames::Entry> parent_chain) const { |
| 435 | if (query_contexts.size() == parent_chain.size()) |
| 436 | return SameParentChain(parent_contexts: query_contexts, parent_entries: parent_chain); |
| 437 | |
| 438 | // If parent chain does not have enough entries, we can't possibly have a |
| 439 | // match. |
| 440 | while (!query_contexts.empty() && |
| 441 | query_contexts.size() <= parent_chain.size()) { |
| 442 | if (SameAsEntryContext(query_context: query_contexts.front(), entry: parent_chain.front())) { |
| 443 | query_contexts = query_contexts.drop_front(); |
| 444 | parent_chain = parent_chain.drop_front(); |
| 445 | } else { |
| 446 | // Name does not match, try next parent_chain entry if the current entry |
| 447 | // is namespace because the current one can be an inline namespace. |
| 448 | if (parent_chain.front().tag() != DW_TAG_namespace) |
| 449 | return false; |
| 450 | parent_chain = parent_chain.drop_front(); |
| 451 | } |
| 452 | } |
| 453 | return query_contexts.empty(); |
| 454 | } |
| 455 | |
| 456 | void DebugNamesDWARFIndex::GetTypes( |
| 457 | ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) { |
| 458 | for (const DebugNames::Entry &entry : |
| 459 | m_debug_names_up->equal_range(Key: name.GetStringRef())) { |
| 460 | if (isType(T: entry.tag())) { |
| 461 | if (!ProcessEntry(entry, callback)) |
| 462 | return; |
| 463 | } |
| 464 | } |
| 465 | |
| 466 | m_fallback.GetTypes(name, callback); |
| 467 | } |
| 468 | |
| 469 | void DebugNamesDWARFIndex::GetTypes( |
| 470 | const DWARFDeclContext &context, |
| 471 | llvm::function_ref<bool(DWARFDIE die)> callback) { |
| 472 | auto name = context[0].name; |
| 473 | for (const DebugNames::Entry &entry : m_debug_names_up->equal_range(Key: name)) { |
| 474 | if (entry.tag() == context[0].tag) { |
| 475 | if (!ProcessEntry(entry, callback)) |
| 476 | return; |
| 477 | } |
| 478 | } |
| 479 | |
| 480 | m_fallback.GetTypes(context, callback); |
| 481 | } |
| 482 | |
| 483 | void DebugNamesDWARFIndex::GetNamespaces( |
| 484 | ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) { |
| 485 | for (const DebugNames::Entry &entry : |
| 486 | m_debug_names_up->equal_range(Key: name.GetStringRef())) { |
| 487 | lldb_private::dwarf::Tag entry_tag = entry.tag(); |
| 488 | if (entry_tag == DW_TAG_namespace || |
| 489 | entry_tag == DW_TAG_imported_declaration) { |
| 490 | if (!ProcessEntry(entry, callback)) |
| 491 | return; |
| 492 | } |
| 493 | } |
| 494 | |
| 495 | m_fallback.GetNamespaces(name, callback); |
| 496 | } |
| 497 | |
| 498 | llvm::SmallVector<CompilerContext> |
| 499 | DebugNamesDWARFIndex::GetTypeQueryParentContexts(TypeQuery &query) { |
| 500 | std::vector<lldb_private::CompilerContext> &query_decl_context = |
| 501 | query.GetContextRef(); |
| 502 | llvm::SmallVector<CompilerContext> parent_contexts; |
| 503 | if (!query_decl_context.empty()) { |
| 504 | // Skip the last entry as it's the type we're matching parents for. |
| 505 | // Reverse the query decl context to match parent chain order. |
| 506 | llvm::ArrayRef<CompilerContext> parent_contexts_ref( |
| 507 | query_decl_context.data(), query_decl_context.size() - 1); |
| 508 | for (const CompilerContext &ctx : llvm::reverse(C&: parent_contexts_ref)) { |
| 509 | // Skip any context without name because .debug_names might not encode |
| 510 | // them. (e.g. annonymous namespace) |
| 511 | if ((ctx.kind & CompilerContextKind::AnyType) != |
| 512 | CompilerContextKind::Invalid && |
| 513 | !ctx.name.IsEmpty()) |
| 514 | parent_contexts.push_back(Elt: ctx); |
| 515 | } |
| 516 | } |
| 517 | return parent_contexts; |
| 518 | } |
| 519 | |
| 520 | void DebugNamesDWARFIndex::GetTypesWithQuery( |
| 521 | TypeQuery &query, llvm::function_ref<bool(DWARFDIE die)> callback) { |
| 522 | ConstString name = query.GetTypeBasename(); |
| 523 | std::vector<lldb_private::CompilerContext> query_context = |
| 524 | query.GetContextRef(); |
| 525 | if (query_context.size() <= 1 && !query.GetExactMatch()) |
| 526 | return GetTypes(name, callback); |
| 527 | |
| 528 | llvm::SmallVector<CompilerContext> parent_contexts = |
| 529 | GetTypeQueryParentContexts(query); |
| 530 | // For each entry, grab its parent chain and check if we have a match. |
| 531 | for (const DebugNames::Entry &entry : m_debug_names_up->equal_range(Key: name)) { |
| 532 | if (!isType(T: entry.tag())) |
| 533 | continue; |
| 534 | |
| 535 | // If we get a NULL foreign_tu back, the entry doesn't match the type unit |
| 536 | // in the .dwp file, or we were not able to load the .dwo file or the DWO ID |
| 537 | // didn't match. |
| 538 | std::optional<DWARFTypeUnit *> foreign_tu = GetForeignTypeUnit(entry); |
| 539 | if (foreign_tu && foreign_tu.value() == nullptr) |
| 540 | continue; |
| 541 | |
| 542 | std::optional<llvm::SmallVector<Entry, 4>> parent_chain = |
| 543 | getParentChain(entry); |
| 544 | if (!parent_chain) { |
| 545 | // Fallback: use the base class implementation. |
| 546 | if (!ProcessEntry(entry, callback: [&](DWARFDIE die) { |
| 547 | return ProcessTypeDIEMatchQuery(query, die, callback); |
| 548 | })) |
| 549 | return; |
| 550 | continue; |
| 551 | } |
| 552 | |
| 553 | if (WithinParentChain(query_contexts: parent_contexts, parent_chain: *parent_chain)) { |
| 554 | if (!ProcessEntry(entry, callback: [&](DWARFDIE die) { |
| 555 | // After .debug_names filtering still sending to base class for |
| 556 | // further filtering before calling the callback. |
| 557 | return ProcessTypeDIEMatchQuery(query, die, callback); |
| 558 | })) |
| 559 | // If the callback returns false, we're done. |
| 560 | return; |
| 561 | } |
| 562 | } |
| 563 | m_fallback.GetTypesWithQuery(query, callback); |
| 564 | } |
| 565 | |
| 566 | void DebugNamesDWARFIndex::GetNamespacesWithParents( |
| 567 | ConstString name, const CompilerDeclContext &parent_decl_ctx, |
| 568 | llvm::function_ref<bool(DWARFDIE die)> callback) { |
| 569 | std::vector<lldb_private::CompilerContext> parent_contexts = |
| 570 | parent_decl_ctx.GetCompilerContext(); |
| 571 | llvm::SmallVector<CompilerContext> parent_named_contexts; |
| 572 | std::copy_if(first: parent_contexts.rbegin(), last: parent_contexts.rend(), |
| 573 | result: std::back_inserter(x&: parent_named_contexts), |
| 574 | pred: [](const CompilerContext &ctx) { return !ctx.name.IsEmpty(); }); |
| 575 | for (const DebugNames::Entry &entry : |
| 576 | m_debug_names_up->equal_range(Key: name.GetStringRef())) { |
| 577 | lldb_private::dwarf::Tag entry_tag = entry.tag(); |
| 578 | if (entry_tag == DW_TAG_namespace || |
| 579 | entry_tag == DW_TAG_imported_declaration) { |
| 580 | std::optional<llvm::SmallVector<Entry, 4>> parent_chain = |
| 581 | getParentChain(entry); |
| 582 | if (!parent_chain) { |
| 583 | // Fallback: use the base class implementation. |
| 584 | if (!ProcessEntry(entry, callback: [&](DWARFDIE die) { |
| 585 | return ProcessNamespaceDieMatchParents(parent_decl_ctx, die, |
| 586 | callback); |
| 587 | })) |
| 588 | return; |
| 589 | continue; |
| 590 | } |
| 591 | |
| 592 | if (WithinParentChain(query_contexts: parent_named_contexts, parent_chain: *parent_chain)) { |
| 593 | if (!ProcessEntry(entry, callback: [&](DWARFDIE die) { |
| 594 | // After .debug_names filtering still sending to base class for |
| 595 | // further filtering before calling the callback. |
| 596 | return ProcessNamespaceDieMatchParents(parent_decl_ctx, die, |
| 597 | callback); |
| 598 | })) |
| 599 | // If the callback returns false, we're done. |
| 600 | return; |
| 601 | } |
| 602 | } |
| 603 | } |
| 604 | m_fallback.GetNamespacesWithParents(name, parent_decl_ctx, callback); |
| 605 | } |
| 606 | |
| 607 | void DebugNamesDWARFIndex::GetFunctions( |
| 608 | const Module::LookupInfo &lookup_info, SymbolFileDWARF &dwarf, |
| 609 | const CompilerDeclContext &parent_decl_ctx, |
| 610 | llvm::function_ref<bool(DWARFDIE die)> callback) { |
| 611 | ConstString name = lookup_info.GetLookupName(); |
| 612 | std::set<DWARFDebugInfoEntry *> seen; |
| 613 | for (const DebugNames::Entry &entry : |
| 614 | m_debug_names_up->equal_range(Key: name.GetStringRef())) { |
| 615 | Tag tag = entry.tag(); |
| 616 | if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine) |
| 617 | continue; |
| 618 | |
| 619 | if (DWARFDIE die = GetDIE(entry)) { |
| 620 | if (!ProcessFunctionDIE(lookup_info, die, parent_decl_ctx, |
| 621 | callback: [&](DWARFDIE die) { |
| 622 | if (!seen.insert(x: die.GetDIE()).second) |
| 623 | return true; |
| 624 | return callback(die); |
| 625 | })) |
| 626 | return; |
| 627 | } |
| 628 | } |
| 629 | |
| 630 | m_fallback.GetFunctions(lookup_info, dwarf, parent_decl_ctx, callback); |
| 631 | } |
| 632 | |
| 633 | void DebugNamesDWARFIndex::GetFunctions( |
| 634 | const RegularExpression ®ex, |
| 635 | llvm::function_ref<bool(DWARFDIE die)> callback) { |
| 636 | for (const DebugNames::NameIndex &ni: *m_debug_names_up) { |
| 637 | for (DebugNames::NameTableEntry nte: ni) { |
| 638 | if (!regex.Execute(string: nte.getString())) |
| 639 | continue; |
| 640 | |
| 641 | uint64_t entry_offset = nte.getEntryOffset(); |
| 642 | llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(Offset: &entry_offset); |
| 643 | for (; entry_or; entry_or = ni.getEntry(Offset: &entry_offset)) { |
| 644 | Tag tag = entry_or->tag(); |
| 645 | if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine) |
| 646 | continue; |
| 647 | |
| 648 | if (!ProcessEntry(entry: *entry_or, callback)) |
| 649 | return; |
| 650 | } |
| 651 | MaybeLogLookupError(error: entry_or.takeError(), ni, name: nte.getString()); |
| 652 | } |
| 653 | } |
| 654 | |
| 655 | m_fallback.GetFunctions(regex, callback); |
| 656 | } |
| 657 | |
| 658 | void DebugNamesDWARFIndex::Dump(Stream &s) { |
| 659 | m_fallback.Dump(s); |
| 660 | |
| 661 | std::string data; |
| 662 | llvm::raw_string_ostream os(data); |
| 663 | m_debug_names_up->dump(OS&: os); |
| 664 | s.PutCString(cstr: data); |
| 665 | } |
| 666 | |