Augusto Noronha d7fb086668
[lldb] Refactor LookupInfo object to be per-language (#168797)
Some months ago, the LookupInfo constructor logic was refactored to not
depend on language specific logic, and use languages plugins instead. In
this refactor, when the language type is unknown, a single LookupInfo
object will handle multiple languages. This doesn't work well, as
multiple languages might want to configure the LookupInfo object in
different ways. For example, different languages might want to set the
m_lookup_name differently from each other, but the previous
implementation would pick the first name a language provided, and
effectively ignored every other language. Other fields of the LookupInfo
object are also configured in incompatible ways.

This approach doesn't seem to be a problem upstream, since only the
C++/Objective-C language plugins are available, but it broke downstream
on the Swift fork, as adding Swift to the list of default languages when
the language type is unknown breaks C++ tests.

This patch makes it so instead of building a single LookupInfo object
for multiple languages, one LookupInfo object is built per language
instead.

rdar://159531216
2025-12-03 16:15:36 -08:00

191 lines
7.1 KiB
C++

//===-- DWARFIndex.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/DWARFIndex.h"
#include "DWARFDebugInfoEntry.h"
#include "DWARFDeclContext.h"
#include "Plugins/Language/ObjC/ObjCLanguage.h"
#include "Plugins/SymbolFile/DWARF/DWARFDIE.h"
#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
#include "lldb/Core/Mangled.h"
#include "lldb/Core/Module.h"
#include "lldb/Target/Language.h"
#include "lldb/lldb-private-enumerations.h"
using namespace lldb_private;
using namespace lldb;
using namespace lldb_private::plugin::dwarf;
DWARFIndex::~DWARFIndex() = default;
IterationAction DWARFIndex::ProcessFunctionDIE(
const Module::LookupInfo &lookup_info, DWARFDIE die,
const CompilerDeclContext &parent_decl_ctx,
llvm::function_ref<IterationAction(DWARFDIE die)> callback) {
llvm::StringRef name = lookup_info.GetLookupName().GetStringRef();
FunctionNameType name_type_mask = lookup_info.GetNameTypeMask();
if (!(name_type_mask & eFunctionNameTypeFull)) {
ConstString name_to_match_against;
if (const char *mangled_die_name = die.GetMangledName()) {
name_to_match_against = ConstString(mangled_die_name);
} else {
SymbolFileDWARF *symbols = die.GetDWARF();
if (ConstString demangled_die_name =
symbols->ConstructFunctionDemangledName(die))
name_to_match_against = demangled_die_name;
}
if (!lookup_info.NameMatchesLookupInfo(name_to_match_against,
lookup_info.GetLanguageType()))
return IterationAction::Continue;
}
// Exit early if we're searching exclusively for methods or selectors and
// we have a context specified (no methods in namespaces).
uint32_t looking_for_nonmethods =
name_type_mask & ~(eFunctionNameTypeMethod | eFunctionNameTypeSelector);
if (!looking_for_nonmethods && parent_decl_ctx.IsValid())
return IterationAction::Continue;
// Otherwise, we need to also check that the context matches. If it does not
// match, we do nothing.
if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx, die))
return IterationAction::Continue;
// In case of a full match, we just insert everything we find.
if (name_type_mask & eFunctionNameTypeFull && die.GetMangledName() == name)
return callback(die);
// If looking for ObjC selectors, we need to also check if the name is a
// possible selector.
if (name_type_mask & eFunctionNameTypeSelector &&
ObjCLanguage::IsPossibleObjCMethodName(die.GetName()))
return callback(die);
bool looking_for_methods = name_type_mask & lldb::eFunctionNameTypeMethod;
bool looking_for_functions = name_type_mask & lldb::eFunctionNameTypeBase;
if (looking_for_methods || looking_for_functions) {
// If we're looking for either methods or functions, we definitely want this
// die. Otherwise, only keep it if the die type matches what we are
// searching for.
if ((looking_for_methods && looking_for_functions) ||
looking_for_methods == die.IsMethod())
return callback(die);
}
return IterationAction::Continue;
}
DWARFIndex::DIERefCallbackImpl::DIERefCallbackImpl(
const DWARFIndex &index,
llvm::function_ref<IterationAction(DWARFDIE die)> callback,
llvm::StringRef name)
: m_index(index),
m_dwarf(*llvm::cast<SymbolFileDWARF>(
index.m_module.GetSymbolFile()->GetBackingSymbolFile())),
m_callback(callback), m_name(name) {}
IterationAction DWARFIndex::DIERefCallbackImpl::operator()(DIERef ref) const {
if (DWARFDIE die = m_dwarf.GetDIE(ref))
return m_callback(die);
m_index.ReportInvalidDIERef(ref, m_name);
return IterationAction::Continue;
}
IterationAction DWARFIndex::DIERefCallbackImpl::operator()(
const llvm::AppleAcceleratorTable::Entry &entry) const {
return this->operator()(DIERef(std::nullopt, DIERef::Section::DebugInfo,
*entry.getDIESectionOffset()));
}
void DWARFIndex::ReportInvalidDIERef(DIERef ref, llvm::StringRef name) const {
m_module.ReportErrorIfModifyDetected(
"the DWARF debug information has been modified (accelerator table had "
"bad die {0:x16} for '{1}')\n",
ref.die_offset(), name.str().c_str());
}
void DWARFIndex::GetFullyQualifiedType(
const DWARFDeclContext &context,
llvm::function_ref<IterationAction(DWARFDIE die)> callback) {
GetTypes(context, [&](DWARFDIE die) {
return GetFullyQualifiedTypeImpl(context, die, callback);
});
}
IterationAction DWARFIndex::GetFullyQualifiedTypeImpl(
const DWARFDeclContext &context, DWARFDIE die,
llvm::function_ref<IterationAction(DWARFDIE die)> callback) {
DWARFDeclContext dwarf_decl_ctx = die.GetDWARFDeclContext();
if (dwarf_decl_ctx == context)
return callback(die);
return IterationAction::Continue;
}
void DWARFIndex::GetTypesWithQuery(
TypeQuery &query,
llvm::function_ref<IterationAction(DWARFDIE die)> callback) {
GetTypes(query.GetTypeBasename(), [&](DWARFDIE die) {
return ProcessTypeDIEMatchQuery(query, die, callback);
});
}
IterationAction DWARFIndex::ProcessTypeDIEMatchQuery(
TypeQuery &query, DWARFDIE die,
llvm::function_ref<IterationAction(DWARFDIE die)> callback) {
// Check the language, but only if we have a language filter.
if (query.HasLanguage() &&
!query.LanguageMatches(SymbolFileDWARF::GetLanguageFamily(*die.GetCU())))
return IterationAction::Continue;
// Since mangled names are unique, we only need to check if the names are
// the same.
if (query.GetSearchByMangledName()) {
if (die.GetMangledName(/*substitute_name_allowed=*/false) !=
query.GetTypeBasename().GetStringRef())
return IterationAction::Continue;
return callback(die);
}
std::vector<lldb_private::CompilerContext> die_context;
if (query.GetModuleSearch())
die_context = die.GetDeclContext();
else
die_context = die.GetTypeLookupContext();
if (!query.ContextMatches(die_context))
return IterationAction::Continue;
return callback(die);
}
void DWARFIndex::GetNamespacesWithParents(
ConstString name, const CompilerDeclContext &parent_decl_ctx,
llvm::function_ref<IterationAction(DWARFDIE die)> callback) {
GetNamespaces(name, [&](DWARFDIE die) {
return ProcessNamespaceDieMatchParents(parent_decl_ctx, die, callback);
});
}
void DWARFIndex::GetFunctions(
const std::vector<Module::LookupInfo> &lookup_infos, SymbolFileDWARF &dwarf,
const CompilerDeclContext &parent_decl_ctx,
llvm::function_ref<IterationAction(DWARFDIE die)> callback) {
for (auto &lookup_info : lookup_infos)
GetFunctions(lookup_info, dwarf, parent_decl_ctx, callback);
}
IterationAction DWARFIndex::ProcessNamespaceDieMatchParents(
const CompilerDeclContext &parent_decl_ctx, DWARFDIE die,
llvm::function_ref<IterationAction(DWARFDIE die)> callback) {
if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx, die))
return IterationAction::Continue;
return callback(die);
}