In order to recognize namespace aliases as a namespace, the DW_TAG_imported_declaration has to be taken into account. The name of these DIEs is already included in all accelerator tables as of D143397. Two of the three Index classes already handle this correctly: 1. ManualDWARFIndex (as of D143398) 2. AppleDWARFIndex works by default with D143397, since apple has a table dedicated to namespaces. This commit updates the third index class, DWARF 5's DebugNamesDWARFIndex. As a result, it fixes the following test with DWARF 5: commands/expression/namespace-alias/TestInlineNamespaceAlias.py Differential Revision: https://reviews.llvm.org/D154730
300 lines
9.8 KiB
C++
300 lines
9.8 KiB
C++
//===-- DebugNamesDWARFIndex.cpp ------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h"
|
|
#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"
|
|
#include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h"
|
|
#include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h"
|
|
#include "lldb/Core/Module.h"
|
|
#include "lldb/Utility/RegularExpression.h"
|
|
#include "lldb/Utility/Stream.h"
|
|
#include <optional>
|
|
|
|
using namespace lldb_private;
|
|
using namespace lldb;
|
|
using namespace lldb_private::dwarf;
|
|
|
|
llvm::Expected<std::unique_ptr<DebugNamesDWARFIndex>>
|
|
DebugNamesDWARFIndex::Create(Module &module, DWARFDataExtractor debug_names,
|
|
DWARFDataExtractor debug_str,
|
|
SymbolFileDWARF &dwarf) {
|
|
auto index_up = std::make_unique<DebugNames>(debug_names.GetAsLLVMDWARF(),
|
|
debug_str.GetAsLLVM());
|
|
if (llvm::Error E = index_up->extract())
|
|
return std::move(E);
|
|
|
|
return std::unique_ptr<DebugNamesDWARFIndex>(new DebugNamesDWARFIndex(
|
|
module, std::move(index_up), debug_names, debug_str, dwarf));
|
|
}
|
|
|
|
llvm::DenseSet<dw_offset_t>
|
|
DebugNamesDWARFIndex::GetUnits(const DebugNames &debug_names) {
|
|
llvm::DenseSet<dw_offset_t> result;
|
|
for (const DebugNames::NameIndex &ni : debug_names) {
|
|
for (uint32_t cu = 0; cu < ni.getCUCount(); ++cu)
|
|
result.insert(ni.getCUOffset(cu));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
std::optional<DIERef>
|
|
DebugNamesDWARFIndex::ToDIERef(const DebugNames::Entry &entry) {
|
|
std::optional<uint64_t> cu_offset = entry.getCUOffset();
|
|
if (!cu_offset)
|
|
return std::nullopt;
|
|
|
|
DWARFUnit *cu = m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *cu_offset);
|
|
if (!cu)
|
|
return std::nullopt;
|
|
|
|
cu = &cu->GetNonSkeletonUnit();
|
|
if (std::optional<uint64_t> die_offset = entry.getDIEUnitOffset())
|
|
return DIERef(cu->GetSymbolFileDWARF().GetFileIndex(),
|
|
DIERef::Section::DebugInfo, cu->GetOffset() + *die_offset);
|
|
|
|
return std::nullopt;
|
|
}
|
|
|
|
bool DebugNamesDWARFIndex::ProcessEntry(
|
|
const DebugNames::Entry &entry,
|
|
llvm::function_ref<bool(DWARFDIE die)> callback) {
|
|
std::optional<DIERef> ref = ToDIERef(entry);
|
|
if (!ref)
|
|
return true;
|
|
SymbolFileDWARF &dwarf = *llvm::cast<SymbolFileDWARF>(
|
|
m_module.GetSymbolFile()->GetBackingSymbolFile());
|
|
DWARFDIE die = dwarf.GetDIE(*ref);
|
|
if (!die)
|
|
return true;
|
|
return callback(die);
|
|
}
|
|
|
|
void DebugNamesDWARFIndex::MaybeLogLookupError(llvm::Error error,
|
|
const DebugNames::NameIndex &ni,
|
|
llvm::StringRef name) {
|
|
// Ignore SentinelErrors, log everything else.
|
|
LLDB_LOG_ERROR(
|
|
GetLog(DWARFLog::Lookups),
|
|
handleErrors(std::move(error), [](const DebugNames::SentinelError &) {}),
|
|
"Failed to parse index entries for index at {1:x}, name {2}: {0}",
|
|
ni.getUnitOffset(), name);
|
|
}
|
|
|
|
void DebugNamesDWARFIndex::GetGlobalVariables(
|
|
ConstString basename, llvm::function_ref<bool(DWARFDIE die)> callback) {
|
|
for (const DebugNames::Entry &entry :
|
|
m_debug_names_up->equal_range(basename.GetStringRef())) {
|
|
if (entry.tag() != DW_TAG_variable)
|
|
continue;
|
|
|
|
if (!ProcessEntry(entry, callback))
|
|
return;
|
|
}
|
|
|
|
m_fallback.GetGlobalVariables(basename, callback);
|
|
}
|
|
|
|
void DebugNamesDWARFIndex::GetGlobalVariables(
|
|
const RegularExpression ®ex,
|
|
llvm::function_ref<bool(DWARFDIE die)> callback) {
|
|
for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
|
|
for (DebugNames::NameTableEntry nte: ni) {
|
|
Mangled mangled_name(nte.getString());
|
|
if (!mangled_name.NameMatches(regex))
|
|
continue;
|
|
|
|
uint64_t entry_offset = nte.getEntryOffset();
|
|
llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
|
|
for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
|
|
if (entry_or->tag() != DW_TAG_variable)
|
|
continue;
|
|
|
|
if (!ProcessEntry(*entry_or, callback))
|
|
return;
|
|
}
|
|
MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
|
|
}
|
|
}
|
|
|
|
m_fallback.GetGlobalVariables(regex, callback);
|
|
}
|
|
|
|
void DebugNamesDWARFIndex::GetGlobalVariables(
|
|
DWARFUnit &cu, llvm::function_ref<bool(DWARFDIE die)> callback) {
|
|
uint64_t cu_offset = cu.GetOffset();
|
|
bool found_entry_for_cu = false;
|
|
for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
|
|
for (DebugNames::NameTableEntry nte: ni) {
|
|
uint64_t entry_offset = nte.getEntryOffset();
|
|
llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
|
|
for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
|
|
if (entry_or->tag() != DW_TAG_variable)
|
|
continue;
|
|
if (entry_or->getCUOffset() != cu_offset)
|
|
continue;
|
|
|
|
found_entry_for_cu = true;
|
|
if (!ProcessEntry(*entry_or, callback))
|
|
return;
|
|
}
|
|
MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
|
|
}
|
|
}
|
|
// If no name index for that particular CU was found, fallback to
|
|
// creating the manual index.
|
|
if (!found_entry_for_cu)
|
|
m_fallback.GetGlobalVariables(cu, callback);
|
|
}
|
|
|
|
void DebugNamesDWARFIndex::GetCompleteObjCClass(
|
|
ConstString class_name, bool must_be_implementation,
|
|
llvm::function_ref<bool(DWARFDIE die)> callback) {
|
|
// Keep a list of incomplete types as fallback for when we don't find the
|
|
// complete type.
|
|
DIEArray incomplete_types;
|
|
|
|
for (const DebugNames::Entry &entry :
|
|
m_debug_names_up->equal_range(class_name.GetStringRef())) {
|
|
if (entry.tag() != DW_TAG_structure_type &&
|
|
entry.tag() != DW_TAG_class_type)
|
|
continue;
|
|
|
|
std::optional<DIERef> ref = ToDIERef(entry);
|
|
if (!ref)
|
|
continue;
|
|
|
|
DWARFUnit *cu = m_debug_info.GetUnit(*ref);
|
|
if (!cu || !cu->Supports_DW_AT_APPLE_objc_complete_type()) {
|
|
incomplete_types.push_back(*ref);
|
|
continue;
|
|
}
|
|
|
|
DWARFDIE die = m_debug_info.GetDIE(*ref);
|
|
if (!die) {
|
|
ReportInvalidDIERef(*ref, class_name.GetStringRef());
|
|
continue;
|
|
}
|
|
|
|
if (die.GetAttributeValueAsUnsigned(DW_AT_APPLE_objc_complete_type, 0)) {
|
|
// If we find the complete version we're done.
|
|
callback(die);
|
|
return;
|
|
}
|
|
incomplete_types.push_back(*ref);
|
|
}
|
|
|
|
auto dierefcallback = DIERefCallback(callback, class_name.GetStringRef());
|
|
for (DIERef ref : incomplete_types)
|
|
if (!dierefcallback(ref))
|
|
return;
|
|
|
|
m_fallback.GetCompleteObjCClass(class_name, must_be_implementation, callback);
|
|
}
|
|
|
|
void DebugNamesDWARFIndex::GetTypes(
|
|
ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
|
|
for (const DebugNames::Entry &entry :
|
|
m_debug_names_up->equal_range(name.GetStringRef())) {
|
|
if (isType(entry.tag())) {
|
|
if (!ProcessEntry(entry, callback))
|
|
return;
|
|
}
|
|
}
|
|
|
|
m_fallback.GetTypes(name, callback);
|
|
}
|
|
|
|
void DebugNamesDWARFIndex::GetTypes(
|
|
const DWARFDeclContext &context,
|
|
llvm::function_ref<bool(DWARFDIE die)> callback) {
|
|
auto name = context[0].name;
|
|
for (const DebugNames::Entry &entry : m_debug_names_up->equal_range(name)) {
|
|
if (entry.tag() == context[0].tag) {
|
|
if (!ProcessEntry(entry, callback))
|
|
return;
|
|
}
|
|
}
|
|
|
|
m_fallback.GetTypes(context, callback);
|
|
}
|
|
|
|
void DebugNamesDWARFIndex::GetNamespaces(
|
|
ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
|
|
for (const DebugNames::Entry &entry :
|
|
m_debug_names_up->equal_range(name.GetStringRef())) {
|
|
dwarf::Tag entry_tag = entry.tag();
|
|
if (entry_tag == DW_TAG_namespace ||
|
|
entry_tag == DW_TAG_imported_declaration) {
|
|
if (!ProcessEntry(entry, callback))
|
|
return;
|
|
}
|
|
}
|
|
|
|
m_fallback.GetNamespaces(name, callback);
|
|
}
|
|
|
|
void DebugNamesDWARFIndex::GetFunctions(
|
|
const Module::LookupInfo &lookup_info, SymbolFileDWARF &dwarf,
|
|
const CompilerDeclContext &parent_decl_ctx,
|
|
llvm::function_ref<bool(DWARFDIE die)> callback) {
|
|
ConstString name = lookup_info.GetLookupName();
|
|
std::set<DWARFDebugInfoEntry *> seen;
|
|
for (const DebugNames::Entry &entry :
|
|
m_debug_names_up->equal_range(name.GetStringRef())) {
|
|
Tag tag = entry.tag();
|
|
if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine)
|
|
continue;
|
|
|
|
if (std::optional<DIERef> ref = ToDIERef(entry)) {
|
|
if (!ProcessFunctionDIE(lookup_info, *ref, dwarf, parent_decl_ctx,
|
|
[&](DWARFDIE die) {
|
|
if (!seen.insert(die.GetDIE()).second)
|
|
return true;
|
|
return callback(die);
|
|
}))
|
|
return;
|
|
}
|
|
}
|
|
|
|
m_fallback.GetFunctions(lookup_info, dwarf, parent_decl_ctx, callback);
|
|
}
|
|
|
|
void DebugNamesDWARFIndex::GetFunctions(
|
|
const RegularExpression ®ex,
|
|
llvm::function_ref<bool(DWARFDIE die)> callback) {
|
|
for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
|
|
for (DebugNames::NameTableEntry nte: ni) {
|
|
if (!regex.Execute(nte.getString()))
|
|
continue;
|
|
|
|
uint64_t entry_offset = nte.getEntryOffset();
|
|
llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
|
|
for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
|
|
Tag tag = entry_or->tag();
|
|
if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine)
|
|
continue;
|
|
|
|
if (!ProcessEntry(*entry_or, callback))
|
|
return;
|
|
}
|
|
MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
|
|
}
|
|
}
|
|
|
|
m_fallback.GetFunctions(regex, callback);
|
|
}
|
|
|
|
void DebugNamesDWARFIndex::Dump(Stream &s) {
|
|
m_fallback.Dump(s);
|
|
|
|
std::string data;
|
|
llvm::raw_string_ostream os(data);
|
|
m_debug_names_up->dump(os);
|
|
s.PutCString(os.str());
|
|
}
|