https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/148877
>From 0cc8acace55c0f0638643bfd2922a289a373ec38 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Fri, 15 Nov 2024 01:59:36 +0000 Subject: [PATCH 1/5] [lldb][Expression] Encode Module and DIE UIDs into function AsmLabels --- lldb/include/lldb/Expression/Expression.h | 6 + lldb/include/lldb/Symbol/SymbolFile.h | 6 + lldb/source/Expression/Expression.cpp | 5 + lldb/source/Expression/IRExecutionUnit.cpp | 119 ++++++++++++++++++ .../Clang/ClangExpressionDeclMap.cpp | 2 +- .../Language/CPlusPlus/CPlusPlusLanguage.cpp | 5 + .../SymbolFile/DWARF/DWARFASTParserClang.cpp | 59 ++++++--- .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 52 ++++++++ .../SymbolFile/DWARF/SymbolFileDWARF.h | 5 + .../SymbolFile/NativePDB/PdbAstBuilder.cpp | 6 +- .../Plugins/SymbolFile/PDB/PDBASTParser.cpp | 7 +- .../TypeSystem/Clang/TypeSystemClang.cpp | 50 +++++++- .../TypeSystem/Clang/TypeSystemClang.h | 5 +- lldb/unittests/Symbol/TestTypeSystemClang.cpp | 12 +- 14 files changed, 302 insertions(+), 37 deletions(-) diff --git a/lldb/include/lldb/Expression/Expression.h b/lldb/include/lldb/Expression/Expression.h index 8de9364436ccf..8e629a0d96661 100644 --- a/lldb/include/lldb/Expression/Expression.h +++ b/lldb/include/lldb/Expression/Expression.h @@ -96,6 +96,12 @@ class Expression { ///invalid. }; +/// LLDB attaches this prefix to mangled names of functions that it get called +/// from JITted expressions. +inline constexpr llvm::StringRef FunctionCallLabelPrefix = "$__lldb_func"; + +bool consumeFunctionCallLabelPrefix(llvm::StringRef &name); + } // namespace lldb_private #endif // LLDB_EXPRESSION_EXPRESSION_H diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h index e95f95553c17c..c52da2d54b1e2 100644 --- a/lldb/include/lldb/Symbol/SymbolFile.h +++ b/lldb/include/lldb/Symbol/SymbolFile.h @@ -18,6 +18,7 @@ #include "lldb/Symbol/CompilerType.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/SourceModule.h" +#include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/Type.h" #include "lldb/Symbol/TypeList.h" #include "lldb/Symbol/TypeSystem.h" @@ -328,6 +329,11 @@ class SymbolFile : public PluginInterface { GetMangledNamesForFunction(const std::string &scope_qualified_name, std::vector<ConstString> &mangled_names); + virtual llvm::Error ResolveFunctionUID(SymbolContextList &sc_list, + lldb::user_id_t uid) { + return llvm::createStringError("Not implemented"); + } + virtual void GetTypes(lldb_private::SymbolContextScope *sc_scope, lldb::TypeClass type_mask, lldb_private::TypeList &type_list) = 0; diff --git a/lldb/source/Expression/Expression.cpp b/lldb/source/Expression/Expression.cpp index 93f585edfce3d..d60d84b7ca409 100644 --- a/lldb/source/Expression/Expression.cpp +++ b/lldb/source/Expression/Expression.cpp @@ -26,3 +26,8 @@ Expression::Expression(ExecutionContextScope &exe_scope) m_jit_end_addr(LLDB_INVALID_ADDRESS) { assert(m_target_wp.lock()); } + +bool lldb_private::consumeFunctionCallLabelPrefix(llvm::StringRef &name) { + name.consume_front("_"); + return name.consume_front(FunctionCallLabelPrefix); +} diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp index e445fa8833022..01052b56d1f6f 100644 --- a/lldb/source/Expression/IRExecutionUnit.cpp +++ b/lldb/source/Expression/IRExecutionUnit.cpp @@ -20,6 +20,7 @@ #include "lldb/Core/Disassembler.h" #include "lldb/Core/Module.h" #include "lldb/Core/Section.h" +#include "lldb/Expression/Expression.h" #include "lldb/Expression/IRExecutionUnit.h" #include "lldb/Expression/ObjectFileJIT.h" #include "lldb/Host/HostInfo.h" @@ -771,6 +772,120 @@ class LoadAddressResolver { lldb::addr_t m_best_internal_load_address = LLDB_INVALID_ADDRESS; }; +/// Returns the \c lldb_private::Module referred to by \c module. +/// +/// \param[in] module Module UUID or integer uniquely identifying the module. +/// \param[in] target Target that the module referred to by \c module lives in. +static llvm::Expected<Module *> GetModulePtr(llvm::StringRef module, + Target &target) { + // TODO: instead of using a pointer use a freshly assigned UID that LLDB + // assigns to a module. + uintptr_t module_ptr = 0; + if (module.starts_with("0x") && !module.consumeInteger(0, module_ptr) && + module_ptr != 0) + return reinterpret_cast<Module *>(module_ptr); + + UUID module_uuid; + if (!module_uuid.SetFromStringRef(module) || !module_uuid.IsValid()) + return llvm::createStringError("failed to create Module UUID from '%s'", + module.data()); + + Module *found_module = target.GetImages().FindModule(module_uuid).get(); + if (!found_module) + return llvm::createStringError("failed to find module with UUID '{0}'", + module.data()); + + return found_module; +} + +/// Returns address of the function referred to by the special function call +/// label \c label. +/// +/// \param[in] label Function call label encoding the unique location of the +/// function to look up. +/// Assumes that the \c FunctionCallLabelPrefix has been +/// stripped from the front of the label. +static lldb::addr_t +ResolveFunctionCallLabel(llvm::StringRef label, + const lldb_private::SymbolContext &sc, + bool &symbol_was_missing_weak) { + symbol_was_missing_weak = false; + + Target *target = sc.target_sp.get(); + if (!target) { + LLDB_LOG(GetLog(LLDBLog::Expressions), + "Failed to resolve function label '{0}': target not available.", + label); + return LLDB_INVALID_ADDRESS; + } + + // Expected format at this point is: + // :<mangled name>:<module id>:<definition/declaration DIE id> + + if (!label.consume_front(":")) { + LLDB_LOG(GetLog(LLDBLog::Expressions), + "Failed to resolve function label '{0}': incorrect format: " + "expected ':' as the first character.", + label); + return LLDB_INVALID_ADDRESS; + } + + // TODO: can we make use of the mangled name for sanity checking? + llvm::SmallVector<llvm::StringRef, 3> components; + label.split(components, ":"); + + if (components.size() != 3) { + LLDB_LOG(GetLog(LLDBLog::Expressions), + "Failed to resolve function label '{0}': incorrect format: too " + "many label subcomponents.", + label); + return LLDB_INVALID_ADDRESS; + } + + const llvm::StringRef module_label = components[1]; + llvm::StringRef die = components[2]; + + auto found_module_or_err = GetModulePtr(module_label, *target); + if (!found_module_or_err) { + LLDB_LOG_ERROR(GetLog(LLDBLog::Expressions), + found_module_or_err.takeError(), + "Failed to resolve function label {1}: {0}", label); + return LLDB_INVALID_ADDRESS; + } + + Module *found_module = *found_module_or_err; + + lldb::user_id_t die_id; + if (die.consumeInteger(/*Radix=*/0, die_id)) { + LLDB_LOG(GetLog(LLDBLog::Expressions), + "Failed to resolve function label '{0}': failed to parse DIE ID " + "for '{1}'.", + label, components[2]); + return LLDB_INVALID_ADDRESS; + } + + auto *symbol_file = found_module->GetSymbolFile(); + if (!symbol_file) { + LLDB_LOG(GetLog(LLDBLog::Expressions), + "Failed to resolve function label '{0}': no SymbolFile found on " + "module.", + label); + return LLDB_INVALID_ADDRESS; + } + + // TODO: API should return SC list item and we should push it back to sc_list + // here. In that case we wouldn't need the sc_list size checks below... + SymbolContextList sc_list; + if (auto err = symbol_file->ResolveFunctionUID(sc_list, die_id)) { + LLDB_LOG_ERROR(GetLog(LLDBLog::Expressions), std::move(err), + "Failed to resolve function by UID: {0}"); + return LLDB_INVALID_ADDRESS; + } + + LoadAddressResolver resolver(target, symbol_was_missing_weak); + return resolver.Resolve(sc_list).value_or(LLDB_INVALID_ADDRESS); +} + lldb::addr_t IRExecutionUnit::FindInSymbols(const std::vector<ConstString> &names, const lldb_private::SymbolContext &sc, @@ -906,6 +1021,10 @@ lldb::addr_t IRExecutionUnit::FindInUserDefinedSymbols( lldb::addr_t IRExecutionUnit::FindSymbol(lldb_private::ConstString name, bool &missing_weak) { + auto name_ref = name.GetStringRef(); + if (consumeFunctionCallLabelPrefix(name_ref)) + return ResolveFunctionCallLabel(name_ref, m_sym_ctx, missing_weak); + std::vector<ConstString> candidate_C_names; std::vector<ConstString> candidate_CPlusPlus_names; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp index 9f77fbc1d2434..a6c4334bf2e59 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -1991,7 +1991,7 @@ void ClangExpressionDeclMap::AddContextClassType(NameSearchContext &context, const bool is_artificial = false; CXXMethodDecl *method_decl = m_clang_ast_context->AddMethodToCXXRecordType( - copied_clang_type.GetOpaqueQualType(), "$__lldb_expr", nullptr, + copied_clang_type.GetOpaqueQualType(), "$__lldb_expr", std::nullopt, method_type, lldb::eAccessPublic, is_virtual, is_static, is_inline, is_explicit, is_attr_used, is_artificial); diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index a8ebde0b55815..cfa2f63cc41de 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -400,6 +400,11 @@ bool CPlusPlusLanguage::CxxMethodName::TrySimplifiedParse() { // A::B::C::fun(std::vector<T> &) const size_t arg_start, arg_end; llvm::StringRef full(m_full.GetCString()); + + // TODO: check for "operator" in IsTrivialBasename + // if (full.starts_with("operator()")) + // return false; + llvm::StringRef parens("()", 2); if (ReverseFindMatchingChars(full, parens, arg_start, arg_end)) { m_arguments = full.substr(arg_start, arg_end - arg_start + 1); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index c76d67b47b336..a7cbc794c744d 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -24,6 +24,7 @@ #include "Plugins/Language/ObjC/ObjCLanguage.h" #include "lldb/Core/Module.h" #include "lldb/Core/Value.h" +#include "lldb/Expression/Expression.h" #include "lldb/Host/Host.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" @@ -249,6 +250,44 @@ static unsigned GetCXXMethodCVQuals(const DWARFDIE &subprogram, return cv_quals; } +// TODO: +// 0. Adjust FindInSymbols +// 1. log failure paths +// 2. What happens for functions without a linkage name? Previously we didn't +// attach a label for those but now we would +// 3. Unit-test +// 4. API test (whilch checks expr and AST dump) +static std::optional<std::string> MakeLLDBFuncAsmLabel(const DWARFDIE &die) { + std::optional<std::string> label; + char const *mangled = die.GetMangledName(/*substitute_name_allowed=*/false); + if (mangled) + label.emplace(mangled); + + auto module_sp = die.GetModule(); + if (!module_sp) + return label; + + // Module UID is only a Darwin concept (?) + // If UUID is not available encode as pointer. + // Maybe add character to signal whether this is a pointer + // or UUID. Or maybe if it's not hex that implies a UUID? + auto module_id = module_sp->GetUUID(); + Module *module_ptr = nullptr; + if (!module_id.IsValid()) + module_ptr = module_sp.get(); + + const auto die_id = die.GetID(); + if (die_id == LLDB_INVALID_UID) + return label; + + return llvm::formatv("{0}:{1}:{2}:{3:x}", FunctionCallLabelPrefix, + mangled ? mangled : "", + module_ptr ? llvm::formatv("{0:x}", module_ptr).str() + : module_id.GetAsString(), + die_id) + .str(); +} + TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc, const DWARFDIE &die, Log *log) { @@ -1231,7 +1270,7 @@ std::pair<bool, TypeSP> DWARFASTParserClang::ParseCXXMethod( clang::CXXMethodDecl *cxx_method_decl = m_ast.AddMethodToCXXRecordType( class_opaque_type.GetOpaqueQualType(), attrs.name.GetCString(), - attrs.mangled_name, clang_type, accessibility, attrs.is_virtual, + MakeLLDBFuncAsmLabel(die), clang_type, accessibility, attrs.is_virtual, is_static, attrs.is_inline, attrs.is_explicit, is_attr_used, attrs.is_artificial); @@ -1384,7 +1423,7 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, ignore_containing_context ? m_ast.GetTranslationUnitDecl() : containing_decl_ctx, GetOwningClangModule(die), name, clang_type, attrs.storage, - attrs.is_inline); + attrs.is_inline, MakeLLDBFuncAsmLabel(die)); std::free(name_buf); if (has_template_params) { @@ -1394,7 +1433,7 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, ignore_containing_context ? m_ast.GetTranslationUnitDecl() : containing_decl_ctx, GetOwningClangModule(die), attrs.name.GetStringRef(), clang_type, - attrs.storage, attrs.is_inline); + attrs.storage, attrs.is_inline, /*asm_label=*/std::nullopt); clang::FunctionTemplateDecl *func_template_decl = m_ast.CreateFunctionTemplateDecl( containing_decl_ctx, GetOwningClangModule(die), @@ -1406,20 +1445,6 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, lldbassert(function_decl); if (function_decl) { - // Attach an asm(<mangled_name>) label to the FunctionDecl. - // This ensures that clang::CodeGen emits function calls - // using symbols that are mangled according to the DW_AT_linkage_name. - // If we didn't do this, the external symbols wouldn't exactly - // match the mangled name LLDB knows about and the IRExecutionUnit - // would have to fall back to searching object files for - // approximately matching function names. The motivating - // example is generating calls to ABI-tagged template functions. - // This is done separately for member functions in - // AddMethodToCXXRecordType. - if (attrs.mangled_name) - function_decl->addAttr(clang::AsmLabelAttr::CreateImplicit( - m_ast.getASTContext(), attrs.mangled_name, /*literal=*/false)); - LinkDeclContextToDIE(function_decl, die); const clang::FunctionProtoType *function_prototype( diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 5b16ce5f75138..dea0ec7ad509a 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -11,6 +11,7 @@ #include "llvm/DebugInfo/DWARF/DWARFAddressRange.h" #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/Error.h" #include "llvm/Support/FileUtilities.h" #include "llvm/Support/FormatAdapters.h" #include "llvm/Support/Threading.h" @@ -22,6 +23,7 @@ #include "lldb/Core/Progress.h" #include "lldb/Core/Section.h" #include "lldb/Core/Value.h" +#include "lldb/Symbol/SymbolContext.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/RegularExpression.h" @@ -73,6 +75,7 @@ #include "ManualDWARFIndex.h" #include "SymbolFileDWARFDebugMap.h" #include "SymbolFileDWARFDwo.h" +#include "lldb/lldb-enumerations.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" @@ -2471,6 +2474,51 @@ bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die, return false; } +llvm::Error SymbolFileDWARF::ResolveFunctionUID(SymbolContextList &sc_list, + lldb::user_id_t uid) { + std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); + auto die = GetDIE(uid); + + if (!die.IsValid()) + return llvm::createStringError( + llvm::formatv("{0}: invalid input DIE", __func__)); + + // TODO: clang indexes by mangled name too...so could technically look up + // by mangled name....but GCC doesn't do that + char const *name = die.GetMangledName(/*substitute_name_allowed=*/true); + if (!name) + return llvm::createStringError( + llvm::formatv("{0}: input DIE has no name", __func__)); + + Module::LookupInfo info(ConstString(name), lldb::eFunctionNameTypeMethod, + lldb::eLanguageTypeUnknown); + m_index->GetFunctions(info, *this, {}, [&](DWARFDIE entry) { + if (entry.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0)) + return true; + + if (auto spec = entry.GetAttributeValueAsReferenceDIE( + llvm::dwarf::DW_AT_specification); + spec == die) { + die = entry; + return false; + } + + return true; + }); + + if (!ResolveFunction(die, false, sc_list)) + return llvm::createStringError( + llvm::formatv("{0}: failed to resolve function DIE", __func__)); + + if (sc_list.IsEmpty()) + return llvm::createStringError( + llvm::formatv("{0}: no definition DIE found", __func__)); + + assert(sc_list.GetSize() == 1); + + return llvm::Error::success(); +} + bool SymbolFileDWARF::DIEInDeclContext(const CompilerDeclContext &decl_ctx, const DWARFDIE &die, bool only_root_namespaces) { @@ -2958,6 +3006,10 @@ TypeSP SymbolFileDWARF::FindCompleteObjCDefinitionTypeForDIE( return type_sp; } +// llvm::Expected<DWARFDIE> +// SymbolFileDWARF::FindFunctionDefinitionDIE(const DWARFDIE &die) { +// } + DWARFDIE SymbolFileDWARF::FindDefinitionDIE(const DWARFDIE &die) { const char *name = die.GetName(); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index 2dc862cccca14..f3f6d565f3d4a 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -374,6 +374,8 @@ class SymbolFileDWARF : public SymbolFileCommon { SymbolFileDWARF(const SymbolFileDWARF &) = delete; const SymbolFileDWARF &operator=(const SymbolFileDWARF &) = delete; + // llvm::Expected<DWARFDIE> FindFunctionDefinitionDIE(const DWARFDIE &die); + virtual void LoadSectionData(lldb::SectionType sect_type, DWARFDataExtractor &data); @@ -438,6 +440,9 @@ class SymbolFileDWARF : public SymbolFileCommon { bool ResolveFunction(const DWARFDIE &die, bool include_inlines, SymbolContextList &sc_list); + llvm::Error ResolveFunctionUID(SymbolContextList &sc_list, + lldb::user_id_t uid) override; + /// Resolve functions and (possibly) blocks for the given file address and a /// compile unit. The compile unit comes from the sc argument and it must be /// set. The results of the lookup (if any) are written back to the symbol diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp index 702ec5e5c9ea9..bce721c149fee 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp @@ -88,7 +88,7 @@ struct CreateMethodDecl : public TypeVisitorCallbacks { MethodOptions::CompilerGenerated; function_decl = m_clang.AddMethodToCXXRecordType( parent_ty, proc_name, - /*mangled_name=*/nullptr, func_ct, /*access=*/access_type, + /*mangled_name=*/std::nullopt, func_ct, /*access=*/access_type, /*is_virtual=*/is_virtual, /*is_static=*/is_static, /*is_inline=*/false, /*is_explicit=*/false, /*is_attr_used=*/false, /*is_artificial=*/is_artificial); @@ -903,7 +903,7 @@ PdbAstBuilder::CreateFunctionDecl(PdbCompilandSymId func_id, if (!function_decl) { function_decl = m_clang.AddMethodToCXXRecordType( parent_opaque_ty, func_name, - /*mangled_name=*/nullptr, func_ct, + /*mangled_name=*/std::nullopt, func_ct, /*access=*/lldb::AccessType::eAccessPublic, /*is_virtual=*/false, /*is_static=*/false, /*is_inline=*/false, /*is_explicit=*/false, @@ -913,7 +913,7 @@ PdbAstBuilder::CreateFunctionDecl(PdbCompilandSymId func_id, } else { function_decl = m_clang.CreateFunctionDeclaration( parent, OptionalClangModuleID(), func_name, func_ct, func_storage, - is_inline); + is_inline, /*asm_label=*/std::nullopt); CreateFunctionParameters(func_id, *function_decl, param_count); } return function_decl; diff --git a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp index 0090d8ff03ab6..548a3ed25111f 100644 --- a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp +++ b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp @@ -954,7 +954,8 @@ PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol) { auto decl = m_ast.CreateFunctionDeclaration( decl_context, OptionalClangModuleID(), name, - type->GetForwardCompilerType(), storage, func->hasInlineAttribute()); + type->GetForwardCompilerType(), storage, func->hasInlineAttribute(), + /*asm_label=*/std::nullopt); std::vector<clang::ParmVarDecl *> params; if (std::unique_ptr<PDBSymbolTypeFunctionSig> sig = func->getSignature()) { @@ -1446,8 +1447,8 @@ PDBASTParser::AddRecordMethod(lldb_private::SymbolFile &symbol_file, // TODO: get mangled name for the method. return m_ast.AddMethodToCXXRecordType( record_type.GetOpaqueQualType(), name.c_str(), - /*mangled_name*/ nullptr, method_comp_type, access, method.isVirtual(), - method.isStatic(), method.hasInlineAttribute(), + /*mangled_name*/ std::nullopt, method_comp_type, access, + method.isVirtual(), method.isStatic(), method.hasInlineAttribute(), /*is_explicit*/ false, // FIXME: Need this field in CodeView. /*is_attr_used*/ false, /*is_artificial*/ method.isCompilerGenerated()); diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index e847ede1a4ba6..79b22257fff47 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -2137,7 +2137,8 @@ std::string TypeSystemClang::GetTypeNameForDecl(const NamedDecl *named_decl, FunctionDecl *TypeSystemClang::CreateFunctionDeclaration( clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, llvm::StringRef name, const CompilerType &function_clang_type, - clang::StorageClass storage, bool is_inline) { + clang::StorageClass storage, bool is_inline, + std::optional<std::string> asm_label) { FunctionDecl *func_decl = nullptr; ASTContext &ast = getASTContext(); if (!decl_ctx) @@ -2158,6 +2159,21 @@ FunctionDecl *TypeSystemClang::CreateFunctionDeclaration( func_decl->setConstexprKind(isConstexprSpecified ? ConstexprSpecKind::Constexpr : ConstexprSpecKind::Unspecified); + + // Attach an asm(<mangled_name>) label to the FunctionDecl. + // This ensures that clang::CodeGen emits function calls + // using symbols that are mangled according to the DW_AT_linkage_name. + // If we didn't do this, the external symbols wouldn't exactly + // match the mangled name LLDB knows about and the IRExecutionUnit + // would have to fall back to searching object files for + // approximately matching function names. The motivating + // example is generating calls to ABI-tagged template functions. + // This is done separately for member functions in + // AddMethodToCXXRecordType. + if (asm_label) + func_decl->addAttr(clang::AsmLabelAttr::CreateImplicit(ast, *asm_label, + /*literal=*/false)); + SetOwningModule(func_decl, owning_module); decl_ctx->addDecl(func_decl); @@ -7647,7 +7663,7 @@ TypeSystemClang::CreateParameterDeclarations( clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( lldb::opaque_compiler_type_t type, llvm::StringRef name, - const char *mangled_name, const CompilerType &method_clang_type, + std::optional<std::string> asm_label, const CompilerType &method_clang_type, lldb::AccessType access, bool is_virtual, bool is_static, bool is_inline, bool is_explicit, bool is_attr_used, bool is_artificial) { if (!type || !method_clang_type.IsValid() || name.empty()) @@ -7780,10 +7796,9 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( if (is_attr_used) cxx_method_decl->addAttr(clang::UsedAttr::CreateImplicit(getASTContext())); - if (mangled_name != nullptr) { + if (asm_label) cxx_method_decl->addAttr(clang::AsmLabelAttr::CreateImplicit( - getASTContext(), mangled_name, /*literal=*/false)); - } + getASTContext(), *asm_label, /*literal=*/false)); // Parameters on member function declarations in DWARF generally don't // have names, so we omit them when creating the ParmVarDecls. @@ -9016,6 +9031,27 @@ bool TypeSystemClang::LayoutRecordType( // CompilerDecl override functions +// TODO: remove duplication with the ResolveFunctionCallLabel in +// IRExecutionUnit.cpp +static std::optional<llvm::StringRef> +GetMangledNameFromLLDBFuncLabel(llvm::StringRef label) { + if (!consumeFunctionCallLabelPrefix(label)) + return {}; + + if (!label.consume_front(":")) + return {}; + + // Expected format at this point is: <mangled name>:<module + // id>:<definition/declaration DIE id> + llvm::SmallVector<llvm::StringRef, 3> components; + label.split(components, ":"); + + if (components.size() != 3) + return {}; + + return components[0]; +} + ConstString TypeSystemClang::DeclGetName(void *opaque_decl) { if (opaque_decl) { clang::NamedDecl *nd = @@ -9037,6 +9073,10 @@ ConstString TypeSystemClang::DeclGetMangledName(void *opaque_decl) { if (!mc || !mc->shouldMangleCXXName(nd)) return {}; + if (const auto *label = nd->getAttr<AsmLabelAttr>()) + if (auto name = GetMangledNameFromLLDBFuncLabel(label->getLabel())) + return ConstString(*name); + llvm::SmallVector<char, 1024> buf; llvm::raw_svector_ostream llvm_ostrm(buf); if (llvm::isa<clang::CXXConstructorDecl>(nd)) { diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index 63dee9dceded3..dcf77f9ec1cb8 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -477,7 +477,8 @@ class TypeSystemClang : public TypeSystem { clang::FunctionDecl *CreateFunctionDeclaration( clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, llvm::StringRef name, const CompilerType &function_Type, - clang::StorageClass storage, bool is_inline); + clang::StorageClass storage, bool is_inline, + std::optional<std::string> asm_label); CompilerType CreateFunctionType(const CompilerType &result_type, @@ -1001,7 +1002,7 @@ class TypeSystemClang : public TypeSystem { clang::CXXMethodDecl *AddMethodToCXXRecordType( lldb::opaque_compiler_type_t type, llvm::StringRef name, - const char *mangled_name, const CompilerType &method_type, + std::optional<std::string> mangled_name, const CompilerType &method_type, lldb::AccessType access, bool is_virtual, bool is_static, bool is_inline, bool is_explicit, bool is_attr_used, bool is_artificial); diff --git a/lldb/unittests/Symbol/TestTypeSystemClang.cpp b/lldb/unittests/Symbol/TestTypeSystemClang.cpp index d555d27bef958..c0428a62f7b3d 100644 --- a/lldb/unittests/Symbol/TestTypeSystemClang.cpp +++ b/lldb/unittests/Symbol/TestTypeSystemClang.cpp @@ -869,7 +869,7 @@ TEST_F(TestTypeSystemClang, TestFunctionTemplateConstruction) { CompilerType clang_type = m_ast->CreateFunctionType(int_type, {}, false, 0U); FunctionDecl *func = m_ast->CreateFunctionDeclaration( TU, OptionalClangModuleID(), "foo", clang_type, StorageClass::SC_None, - false); + false, std::nullopt); TypeSystemClang::TemplateParameterInfos empty_params; // Create the actual function template. @@ -900,7 +900,7 @@ TEST_F(TestTypeSystemClang, TestFunctionTemplateInRecordConstruction) { // 2. It is mirroring the behavior of DWARFASTParserClang::ParseSubroutine. FunctionDecl *func = m_ast->CreateFunctionDeclaration( TU, OptionalClangModuleID(), "foo", clang_type, StorageClass::SC_None, - false); + false, std::nullopt); TypeSystemClang::TemplateParameterInfos empty_params; // Create the actual function template. @@ -938,7 +938,7 @@ TEST_F(TestTypeSystemClang, TestDeletingImplicitCopyCstrDueToMoveCStr) { bool is_attr_used = false; bool is_artificial = false; m_ast->AddMethodToCXXRecordType( - t.GetOpaqueQualType(), class_name, nullptr, function_type, + t.GetOpaqueQualType(), class_name, std::nullopt, function_type, lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline, is_explicit, is_attr_used, is_artificial); @@ -975,7 +975,7 @@ TEST_F(TestTypeSystemClang, TestNotDeletingUserCopyCstrDueToMoveCStr) { CompilerType function_type = m_ast->CreateFunctionType( return_type, args, /*variadic=*/false, /*quals*/ 0U); m_ast->AddMethodToCXXRecordType( - t.GetOpaqueQualType(), class_name, nullptr, function_type, + t.GetOpaqueQualType(), class_name, std::nullopt, function_type, lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline, is_explicit, is_attr_used, is_artificial); } @@ -987,7 +987,7 @@ TEST_F(TestTypeSystemClang, TestNotDeletingUserCopyCstrDueToMoveCStr) { m_ast->CreateFunctionType(return_type, args, /*variadic=*/false, /*quals*/ 0U); m_ast->AddMethodToCXXRecordType( - t.GetOpaqueQualType(), class_name, nullptr, function_type, + t.GetOpaqueQualType(), class_name, std::nullopt, function_type, lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline, is_explicit, is_attr_used, is_artificial); } @@ -1098,7 +1098,7 @@ TEST_F(TestTypeSystemClang, AddMethodToCXXRecordType_ParmVarDecls) { m_ast->CreateFunctionType(return_type, param_types, /*variadic=*/false, /*quals*/ 0U); m_ast->AddMethodToCXXRecordType( - t.GetOpaqueQualType(), "myFunc", nullptr, function_type, + t.GetOpaqueQualType(), "myFunc", std::nullopt, function_type, lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline, is_explicit, is_attr_used, is_artificial); >From 5640b00922a98085f7ae31749f9063d531c6eec4 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Thu, 17 Jul 2025 20:35:50 +0100 Subject: [PATCH 2/5] fixup! module id --- lldb/include/lldb/Core/Module.h | 3 +- lldb/include/lldb/Core/ModuleList.h | 1 + lldb/source/Core/Module.cpp | 8 +-- lldb/source/Core/ModuleList.cpp | 16 ++++++ lldb/source/Expression/IRExecutionUnit.cpp | 53 ++++++------------- .../Language/CPlusPlus/CPlusPlusLanguage.cpp | 5 -- .../SymbolFile/DWARF/DWARFASTParserClang.cpp | 27 +++------- .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 42 +++++++-------- .../SymbolFile/DWARF/SymbolFileDWARF.h | 2 - 9 files changed, 67 insertions(+), 90 deletions(-) diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h index 8bb55c95773bc..8513e147ee523 100644 --- a/lldb/include/lldb/Core/Module.h +++ b/lldb/include/lldb/Core/Module.h @@ -86,7 +86,8 @@ struct ModuleFunctionSearchOptions { /// /// The module will parse more detailed information as more queries are made. class Module : public std::enable_shared_from_this<Module>, - public SymbolContextScope { + public SymbolContextScope, + public UserID { public: class LookupInfo; // Static functions that can track the lifetime of module objects. This is diff --git a/lldb/include/lldb/Core/ModuleList.h b/lldb/include/lldb/Core/ModuleList.h index 909ee08f9ba62..56b26a29c0c66 100644 --- a/lldb/include/lldb/Core/ModuleList.h +++ b/lldb/include/lldb/Core/ModuleList.h @@ -350,6 +350,7 @@ class ModuleList { // MD5 checksum, or a smarter object file equivalent, so finding modules by // UUID values is very efficient and accurate. lldb::ModuleSP FindModule(const UUID &uuid) const; + lldb::ModuleSP FindModule(lldb::user_id_t uuid) const; /// Finds the first module whose file specification matches \a module_spec. lldb::ModuleSP FindFirstModule(const ModuleSpec &module_spec) const; diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index 90997dada3666..fa4c95d93acea 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -130,8 +130,10 @@ Module *Module::GetAllocatedModuleAtIndex(size_t idx) { return nullptr; } +static lldb::user_id_t g_unique_id = 1; + Module::Module(const ModuleSpec &module_spec) - : m_unwind_table(*this), m_file_has_changed(false), + : UserID(g_unique_id++), m_unwind_table(*this), m_file_has_changed(false), m_first_file_changed_log(false) { // Scope for locker below... { @@ -236,7 +238,7 @@ Module::Module(const ModuleSpec &module_spec) Module::Module(const FileSpec &file_spec, const ArchSpec &arch, ConstString object_name, lldb::offset_t object_offset, const llvm::sys::TimePoint<> &object_mod_time) - : m_mod_time(FileSystem::Instance().GetModificationTime(file_spec)), + : UserID(g_unique_id++), m_mod_time(FileSystem::Instance().GetModificationTime(file_spec)), m_arch(arch), m_file(file_spec), m_object_name(object_name), m_object_offset(object_offset), m_object_mod_time(object_mod_time), m_unwind_table(*this), m_file_has_changed(false), @@ -257,7 +259,7 @@ Module::Module(const FileSpec &file_spec, const ArchSpec &arch, } Module::Module() - : m_unwind_table(*this), m_file_has_changed(false), + : UserID(g_unique_id++), m_unwind_table(*this), m_file_has_changed(false), m_first_file_changed_log(false) { std::lock_guard<std::recursive_mutex> guard( GetAllocationModuleCollectionMutex()); diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp index d5ddf6e846112..06fa41b097dc3 100644 --- a/lldb/source/Core/ModuleList.cpp +++ b/lldb/source/Core/ModuleList.cpp @@ -567,6 +567,22 @@ ModuleSP ModuleList::FindModule(const Module *module_ptr) const { return module_sp; } +ModuleSP ModuleList::FindModule(lldb::user_id_t uid) const { + ModuleSP module_sp; + + std::lock_guard<std::recursive_mutex> guard(m_modules_mutex); + collection::const_iterator pos, end = m_modules.end(); + + for (pos = m_modules.begin(); pos != end; ++pos) { + if ((*pos)->GetID() == uid) { + module_sp = (*pos); + break; + } + } + + return module_sp; +} + ModuleSP ModuleList::FindModule(const UUID &uuid) const { ModuleSP module_sp; diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp index 01052b56d1f6f..5cc7b24c3f577 100644 --- a/lldb/source/Expression/IRExecutionUnit.cpp +++ b/lldb/source/Expression/IRExecutionUnit.cpp @@ -772,32 +772,6 @@ class LoadAddressResolver { lldb::addr_t m_best_internal_load_address = LLDB_INVALID_ADDRESS; }; -/// Returns the \c lldb_private::Module referred to by \c module. -/// -/// \param[in] module Module UUID or integer uniquely identifying the module. -/// \param[in] target Target that the module referred to by \c module lives in. -static llvm::Expected<Module *> GetModulePtr(llvm::StringRef module, - Target &target) { - // TODO: instead of using a pointer use a freshly assigned UID that LLDB - // assigns to a module. - uintptr_t module_ptr = 0; - if (module.starts_with("0x") && !module.consumeInteger(0, module_ptr) && - module_ptr != 0) - return reinterpret_cast<Module *>(module_ptr); - - UUID module_uuid; - if (!module_uuid.SetFromStringRef(module) || !module_uuid.IsValid()) - return llvm::createStringError("failed to create Module UUID from '%s'", - module.data()); - - Module *found_module = target.GetImages().FindModule(module_uuid).get(); - if (!found_module) - return llvm::createStringError("failed to find module with UUID '{0}'", - module.data()); - - return found_module; -} - /// Returns address of the function referred to by the special function call /// label \c label. /// @@ -842,18 +816,25 @@ ResolveFunctionCallLabel(llvm::StringRef label, return LLDB_INVALID_ADDRESS; } - const llvm::StringRef module_label = components[1]; + llvm::StringRef module_label = components[1]; llvm::StringRef die = components[2]; - auto found_module_or_err = GetModulePtr(module_label, *target); - if (!found_module_or_err) { - LLDB_LOG_ERROR(GetLog(LLDBLog::Expressions), - found_module_or_err.takeError(), - "Failed to resolve function label {1}: {0}", label); + lldb::user_id_t module_id = 0; + if (module_label.consumeInteger(0, module_id)) { + LLDB_LOG(GetLog(LLDBLog::Expressions), + "Failed to resolve function label '{0}': failed to parse module ID " + "for '{1}'.", + label, components[1]); return LLDB_INVALID_ADDRESS; } - Module *found_module = *found_module_or_err; + auto module_sp = target->GetImages().FindModule(module_id); + + if (!module_sp) { + LLDB_LOG(GetLog(LLDBLog::Expressions), + "Failed to resolve function label {0}: failed to find module by UID {1}", label, module_id); + return LLDB_INVALID_ADDRESS; + } lldb::user_id_t die_id; if (die.consumeInteger(/*Radix=*/0, die_id)) { @@ -864,7 +845,7 @@ ResolveFunctionCallLabel(llvm::StringRef label, return LLDB_INVALID_ADDRESS; } - auto *symbol_file = found_module->GetSymbolFile(); + auto *symbol_file = module_sp->GetSymbolFile(); if (!symbol_file) { LLDB_LOG(GetLog(LLDBLog::Expressions), "Failed to resolve function label '{0}': no SymbolFile found on " @@ -873,8 +854,6 @@ ResolveFunctionCallLabel(llvm::StringRef label, return LLDB_INVALID_ADDRESS; } - // TODO: API should return SC list item and we should push it back to sc_list - // here. In that case we wouldn't need the sc_list size checks below... SymbolContextList sc_list; if (auto err = symbol_file->ResolveFunctionUID(sc_list, die_id)) { LLDB_LOG_ERROR(GetLog(LLDBLog::Expressions), std::move(err), @@ -1025,6 +1004,8 @@ lldb::addr_t IRExecutionUnit::FindSymbol(lldb_private::ConstString name, if (consumeFunctionCallLabelPrefix(name_ref)) return ResolveFunctionCallLabel(name_ref, m_sym_ctx, missing_weak); + // TODO: do we still need the following lookups? + std::vector<ConstString> candidate_C_names; std::vector<ConstString> candidate_CPlusPlus_names; diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index cfa2f63cc41de..a8ebde0b55815 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -400,11 +400,6 @@ bool CPlusPlusLanguage::CxxMethodName::TrySimplifiedParse() { // A::B::C::fun(std::vector<T> &) const size_t arg_start, arg_end; llvm::StringRef full(m_full.GetCString()); - - // TODO: check for "operator" in IsTrivialBasename - // if (full.starts_with("operator()")) - // return false; - llvm::StringRef parens("()", 2); if (ReverseFindMatchingChars(full, parens, arg_start, arg_end)) { m_arguments = full.substr(arg_start, arg_end - arg_start + 1); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index a7cbc794c744d..217d4292fb0d5 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -250,13 +250,6 @@ static unsigned GetCXXMethodCVQuals(const DWARFDIE &subprogram, return cv_quals; } -// TODO: -// 0. Adjust FindInSymbols -// 1. log failure paths -// 2. What happens for functions without a linkage name? Previously we didn't -// attach a label for those but now we would -// 3. Unit-test -// 4. API test (whilch checks expr and AST dump) static std::optional<std::string> MakeLLDBFuncAsmLabel(const DWARFDIE &die) { std::optional<std::string> label; char const *mangled = die.GetMangledName(/*substitute_name_allowed=*/false); @@ -265,25 +258,19 @@ static std::optional<std::string> MakeLLDBFuncAsmLabel(const DWARFDIE &die) { auto module_sp = die.GetModule(); if (!module_sp) - return label; + return std::nullopt; - // Module UID is only a Darwin concept (?) - // If UUID is not available encode as pointer. - // Maybe add character to signal whether this is a pointer - // or UUID. Or maybe if it's not hex that implies a UUID? - auto module_id = module_sp->GetUUID(); - Module *module_ptr = nullptr; - if (!module_id.IsValid()) - module_ptr = module_sp.get(); + lldb::user_id_t module_id = module_sp->GetID(); + if (module_id == LLDB_INVALID_UID) + return std::nullopt; const auto die_id = die.GetID(); if (die_id == LLDB_INVALID_UID) - return label; + return std::nullopt; - return llvm::formatv("{0}:{1}:{2}:{3:x}", FunctionCallLabelPrefix, + return llvm::formatv("{0}:{1}:{2:x}:{3:x}", FunctionCallLabelPrefix, mangled ? mangled : "", - module_ptr ? llvm::formatv("{0:x}", module_ptr).str() - : module_id.GetAsString(), + module_id, die_id) .str(); } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index dea0ec7ad509a..ed0cbfe28afb2 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -11,7 +11,6 @@ #include "llvm/DebugInfo/DWARF/DWARFAddressRange.h" #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h" #include "llvm/Support/Casting.h" -#include "llvm/Support/Error.h" #include "llvm/Support/FileUtilities.h" #include "llvm/Support/FormatAdapters.h" #include "llvm/Support/Threading.h" @@ -23,7 +22,6 @@ #include "lldb/Core/Progress.h" #include "lldb/Core/Section.h" #include "lldb/Core/Value.h" -#include "lldb/Symbol/SymbolContext.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/RegularExpression.h" @@ -75,7 +73,6 @@ #include "ManualDWARFIndex.h" #include "SymbolFileDWARFDebugMap.h" #include "SymbolFileDWARFDwo.h" -#include "lldb/lldb-enumerations.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" @@ -2483,28 +2480,31 @@ llvm::Error SymbolFileDWARF::ResolveFunctionUID(SymbolContextList &sc_list, return llvm::createStringError( llvm::formatv("{0}: invalid input DIE", __func__)); - // TODO: clang indexes by mangled name too...so could technically look up - // by mangled name....but GCC doesn't do that - char const *name = die.GetMangledName(/*substitute_name_allowed=*/true); + // Look up by DW_AT_linkage_name if we can. Otherwise we can use the DW_AT_name. + char const *name = die.GetPubname(); if (!name) return llvm::createStringError( llvm::formatv("{0}: input DIE has no name", __func__)); - Module::LookupInfo info(ConstString(name), lldb::eFunctionNameTypeMethod, - lldb::eLanguageTypeUnknown); - m_index->GetFunctions(info, *this, {}, [&](DWARFDIE entry) { - if (entry.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0)) - return true; + // If we're trying to resolve a function declaration DIE, find the definition. + if (die.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0)) { + Module::LookupInfo info(ConstString(name), lldb::eFunctionNameTypeMethod, + lldb::eLanguageTypeUnknown); - if (auto spec = entry.GetAttributeValueAsReferenceDIE( - llvm::dwarf::DW_AT_specification); - spec == die) { - die = entry; - return false; - } + m_index->GetFunctions(info, *this, {}, [&](DWARFDIE entry) { + if (entry.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0)) + return true; - return true; - }); + if (auto spec = entry.GetAttributeValueAsReferenceDIE( + llvm::dwarf::DW_AT_specification); + spec == die) { + die = entry; + return false; + } + + return true; + }); + } if (!ResolveFunction(die, false, sc_list)) return llvm::createStringError( @@ -3006,10 +3006,6 @@ TypeSP SymbolFileDWARF::FindCompleteObjCDefinitionTypeForDIE( return type_sp; } -// llvm::Expected<DWARFDIE> -// SymbolFileDWARF::FindFunctionDefinitionDIE(const DWARFDIE &die) { -// } - DWARFDIE SymbolFileDWARF::FindDefinitionDIE(const DWARFDIE &die) { const char *name = die.GetName(); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index f3f6d565f3d4a..f20a4b03fbdc0 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -374,8 +374,6 @@ class SymbolFileDWARF : public SymbolFileCommon { SymbolFileDWARF(const SymbolFileDWARF &) = delete; const SymbolFileDWARF &operator=(const SymbolFileDWARF &) = delete; - // llvm::Expected<DWARFDIE> FindFunctionDefinitionDIE(const DWARFDIE &die); - virtual void LoadSectionData(lldb::SectionType sect_type, DWARFDataExtractor &data); >From 08dae775610025864e13fe2eb735bcffe811c4c9 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Fri, 18 Jul 2025 09:41:37 +0100 Subject: [PATCH 3/5] fixup! module id --- lldb/include/lldb/Core/Module.h | 1 + lldb/source/Core/Module.cpp | 10 ++++++++++ lldb/source/Expression/IRExecutionUnit.cpp | 19 ++++++++++--------- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h index 8513e147ee523..3991a12997541 100644 --- a/lldb/include/lldb/Core/Module.h +++ b/lldb/include/lldb/Core/Module.h @@ -98,6 +98,7 @@ class Module : public std::enable_shared_from_this<Module>, // using the "--global" (-g for short). static size_t GetNumberAllocatedModules(); + static Module *GetAllocatedModuleWithUID(lldb::user_id_t uid); static Module *GetAllocatedModuleAtIndex(size_t idx); static std::recursive_mutex &GetAllocationModuleCollectionMutex(); diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index fa4c95d93acea..b89d72a399a42 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -121,6 +121,15 @@ size_t Module::GetNumberAllocatedModules() { return GetModuleCollection().size(); } +Module *Module::GetAllocatedModuleWithUID(lldb::user_id_t uid) { + std::lock_guard<std::recursive_mutex> guard( + GetAllocationModuleCollectionMutex()); + for (Module *mod: GetModuleCollection()) + if (mod->GetID() == uid) + return mod; + return nullptr; +} + Module *Module::GetAllocatedModuleAtIndex(size_t idx) { std::lock_guard<std::recursive_mutex> guard( GetAllocationModuleCollectionMutex()); @@ -130,6 +139,7 @@ Module *Module::GetAllocatedModuleAtIndex(size_t idx) { return nullptr; } +// TODO: needs a mutex static lldb::user_id_t g_unique_id = 1; Module::Module(const ModuleSpec &module_spec) diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp index 5cc7b24c3f577..205dd966e6f0a 100644 --- a/lldb/source/Expression/IRExecutionUnit.cpp +++ b/lldb/source/Expression/IRExecutionUnit.cpp @@ -785,14 +785,6 @@ ResolveFunctionCallLabel(llvm::StringRef label, bool &symbol_was_missing_weak) { symbol_was_missing_weak = false; - Target *target = sc.target_sp.get(); - if (!target) { - LLDB_LOG(GetLog(LLDBLog::Expressions), - "Failed to resolve function label '{0}': target not available.", - label); - return LLDB_INVALID_ADDRESS; - } - // Expected format at this point is: // :<mangled name>:<module id>:<definition/declaration DIE id> @@ -828,7 +820,8 @@ ResolveFunctionCallLabel(llvm::StringRef label, return LLDB_INVALID_ADDRESS; } - auto module_sp = target->GetImages().FindModule(module_id); + //auto module_sp = target->GetImages().FindModule(module_id); + Module *module_sp = Module::GetAllocatedModuleWithUID(module_id); if (!module_sp) { LLDB_LOG(GetLog(LLDBLog::Expressions), @@ -861,6 +854,14 @@ ResolveFunctionCallLabel(llvm::StringRef label, return LLDB_INVALID_ADDRESS; } + Target *target = sc.target_sp.get(); + if (!target) { + LLDB_LOG(GetLog(LLDBLog::Expressions), + "Failed to resolve function label '{0}': target not available.", + label); + return LLDB_INVALID_ADDRESS; + } + LoadAddressResolver resolver(target, symbol_was_missing_weak); return resolver.Resolve(sc_list).value_or(LLDB_INVALID_ADDRESS); } >From 82adcf98f2fdf943293ee56a7cb7781c59c1f974 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Fri, 18 Jul 2025 10:29:19 +0100 Subject: [PATCH 4/5] fixup! clean up logging --- lldb/include/lldb/Symbol/SymbolFile.h | 7 ++ lldb/source/Expression/IRExecutionUnit.cpp | 81 +++++++------------ .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 12 +-- .../SymbolFile/DWARF/SymbolFileDWARF.h | 6 +- 4 files changed, 43 insertions(+), 63 deletions(-) diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h index c52da2d54b1e2..8c658f44d6bf3 100644 --- a/lldb/include/lldb/Symbol/SymbolFile.h +++ b/lldb/include/lldb/Symbol/SymbolFile.h @@ -329,6 +329,13 @@ class SymbolFile : public PluginInterface { GetMangledNamesForFunction(const std::string &scope_qualified_name, std::vector<ConstString> &mangled_names); + /// Resolves the function DIE uniquely identified by \c uid within + /// this SymbolFile. + /// + /// \param[in,out] sc_list The resolved functions will be appended to this list. + /// + /// \param[in] uid The UID of the function DIE to resolve. + /// virtual llvm::Error ResolveFunctionUID(SymbolContextList &sc_list, lldb::user_id_t uid) { return llvm::createStringError("Not implemented"); diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp index 205dd966e6f0a..1c32b7ed228f1 100644 --- a/lldb/source/Expression/IRExecutionUnit.cpp +++ b/lldb/source/Expression/IRExecutionUnit.cpp @@ -13,6 +13,7 @@ #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include "llvm/Support/Error.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" @@ -37,6 +38,7 @@ #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" +#include "lldb/lldb-defines.h" #include <optional> @@ -779,7 +781,7 @@ class LoadAddressResolver { /// function to look up. /// Assumes that the \c FunctionCallLabelPrefix has been /// stripped from the front of the label. -static lldb::addr_t +static llvm::Expected<lldb::addr_t> ResolveFunctionCallLabel(llvm::StringRef label, const lldb_private::SymbolContext &sc, bool &symbol_was_missing_weak) { @@ -788,79 +790,47 @@ ResolveFunctionCallLabel(llvm::StringRef label, // Expected format at this point is: // :<mangled name>:<module id>:<definition/declaration DIE id> - if (!label.consume_front(":")) { - LLDB_LOG(GetLog(LLDBLog::Expressions), - "Failed to resolve function label '{0}': incorrect format: " - "expected ':' as the first character.", - label); - return LLDB_INVALID_ADDRESS; - } + if (!label.consume_front(":")) + return llvm::createStringError("incorrect format: expected ':' as the first character."); // TODO: can we make use of the mangled name for sanity checking? llvm::SmallVector<llvm::StringRef, 3> components; label.split(components, ":"); - if (components.size() != 3) { - LLDB_LOG(GetLog(LLDBLog::Expressions), - "Failed to resolve function label '{0}': incorrect format: too " - "many label subcomponents.", - label); - return LLDB_INVALID_ADDRESS; - } + if (components.size() != 3) + return llvm::createStringError("incorrect format: too many label subcomponents."); llvm::StringRef module_label = components[1]; llvm::StringRef die = components[2]; lldb::user_id_t module_id = 0; - if (module_label.consumeInteger(0, module_id)) { - LLDB_LOG(GetLog(LLDBLog::Expressions), - "Failed to resolve function label '{0}': failed to parse module ID " - "for '{1}'.", - label, components[1]); - return LLDB_INVALID_ADDRESS; - } + if (module_label.consumeInteger(0, module_id)) + return llvm::createStringError(llvm::formatv("failed to parse module ID from '{0}'.", components[1])); //auto module_sp = target->GetImages().FindModule(module_id); - Module *module_sp = Module::GetAllocatedModuleWithUID(module_id); + Module *module = Module::GetAllocatedModuleWithUID(module_id); - if (!module_sp) { - LLDB_LOG(GetLog(LLDBLog::Expressions), - "Failed to resolve function label {0}: failed to find module by UID {1}", label, module_id); - return LLDB_INVALID_ADDRESS; - } + if (!module) + return llvm::createStringError(llvm::formatv("failed to find module by UID {0}", module_id)); lldb::user_id_t die_id; if (die.consumeInteger(/*Radix=*/0, die_id)) { LLDB_LOG(GetLog(LLDBLog::Expressions), - "Failed to resolve function label '{0}': failed to parse DIE ID " - "for '{1}'.", - label, components[2]); + "failed to parse DIE ID from '{0}'.", components[2]); return LLDB_INVALID_ADDRESS; } - auto *symbol_file = module_sp->GetSymbolFile(); - if (!symbol_file) { - LLDB_LOG(GetLog(LLDBLog::Expressions), - "Failed to resolve function label '{0}': no SymbolFile found on " - "module.", - label); - return LLDB_INVALID_ADDRESS; - } + auto *symbol_file = module->GetSymbolFile(); + if (!symbol_file) + return llvm::createStringError(llvm::formatv("no SymbolFile found on module {0:x}.", module)); SymbolContextList sc_list; - if (auto err = symbol_file->ResolveFunctionUID(sc_list, die_id)) { - LLDB_LOG_ERROR(GetLog(LLDBLog::Expressions), std::move(err), - "Failed to resolve function by UID: {0}"); - return LLDB_INVALID_ADDRESS; - } + if (auto err = symbol_file->ResolveFunctionUID(sc_list, die_id)) + return llvm::joinErrors(llvm::createStringError("failed to resolve function by UID"), std::move(err)); Target *target = sc.target_sp.get(); - if (!target) { - LLDB_LOG(GetLog(LLDBLog::Expressions), - "Failed to resolve function label '{0}': target not available.", - label); - return LLDB_INVALID_ADDRESS; - } + if (!target) + return llvm::createStringError( "target not available."); LoadAddressResolver resolver(target, symbol_was_missing_weak); return resolver.Resolve(sc_list).value_or(LLDB_INVALID_ADDRESS); @@ -1002,8 +972,15 @@ lldb::addr_t IRExecutionUnit::FindInUserDefinedSymbols( lldb::addr_t IRExecutionUnit::FindSymbol(lldb_private::ConstString name, bool &missing_weak) { auto name_ref = name.GetStringRef(); - if (consumeFunctionCallLabelPrefix(name_ref)) - return ResolveFunctionCallLabel(name_ref, m_sym_ctx, missing_weak); + if (consumeFunctionCallLabelPrefix(name_ref)) { + if (auto addr_or_err = ResolveFunctionCallLabel(name_ref, m_sym_ctx, missing_weak)) { + return *addr_or_err; + } else { + LLDB_LOG_ERROR(GetLog(LLDBLog::Expressions), addr_or_err.takeError(), + "Failed to resolve function call label {1}: {0}", name.GetStringRef()); + return LLDB_INVALID_ADDRESS; + } + } // TODO: do we still need the following lookups? diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index ed0cbfe28afb2..b5240f220fe4f 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -2477,14 +2477,12 @@ llvm::Error SymbolFileDWARF::ResolveFunctionUID(SymbolContextList &sc_list, auto die = GetDIE(uid); if (!die.IsValid()) - return llvm::createStringError( - llvm::formatv("{0}: invalid input DIE", __func__)); + return llvm::createStringError("invalid input DIE"); // Look up by DW_AT_linkage_name if we can. Otherwise we can use the DW_AT_name. char const *name = die.GetPubname(); if (!name) - return llvm::createStringError( - llvm::formatv("{0}: input DIE has no name", __func__)); + return llvm::createStringError("input DIE has no name"); // If we're trying to resolve a function declaration DIE, find the definition. if (die.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0)) { @@ -2507,12 +2505,10 @@ llvm::Error SymbolFileDWARF::ResolveFunctionUID(SymbolContextList &sc_list, } if (!ResolveFunction(die, false, sc_list)) - return llvm::createStringError( - llvm::formatv("{0}: failed to resolve function DIE", __func__)); + return llvm::createStringError("failed to resolve function DIE"); if (sc_list.IsEmpty()) - return llvm::createStringError( - llvm::formatv("{0}: no definition DIE found", __func__)); + return llvm::createStringError("no definition DIE found"); assert(sc_list.GetSize() == 1); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index f20a4b03fbdc0..377d412825a6a 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -154,6 +154,9 @@ class SymbolFileDWARF : public SymbolFileCommon { std::vector<CompilerContext> GetCompilerContextForUID(lldb::user_id_t uid) override; + llvm::Error ResolveFunctionUID(SymbolContextList &sc_list, + lldb::user_id_t uid) override; + void ParseDeclsForContext(CompilerDeclContext decl_ctx) override; uint32_t ResolveSymbolContext(const Address &so_addr, @@ -438,9 +441,6 @@ class SymbolFileDWARF : public SymbolFileCommon { bool ResolveFunction(const DWARFDIE &die, bool include_inlines, SymbolContextList &sc_list); - llvm::Error ResolveFunctionUID(SymbolContextList &sc_list, - lldb::user_id_t uid) override; - /// Resolve functions and (possibly) blocks for the given file address and a /// compile unit. The compile unit comes from the sc argument and it must be /// set. The results of the lookup (if any) are written back to the symbol >From fa7f1ab129a3496a7f8ee6d6ddbcdaec185a759a Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Fri, 18 Jul 2025 10:30:07 +0100 Subject: [PATCH 5/5] fixup! remove redundant FindModule API --- lldb/include/lldb/Core/ModuleList.h | 1 - lldb/source/Core/ModuleList.cpp | 17 ----------------- lldb/source/Expression/IRExecutionUnit.cpp | 1 - 3 files changed, 19 deletions(-) diff --git a/lldb/include/lldb/Core/ModuleList.h b/lldb/include/lldb/Core/ModuleList.h index 56b26a29c0c66..909ee08f9ba62 100644 --- a/lldb/include/lldb/Core/ModuleList.h +++ b/lldb/include/lldb/Core/ModuleList.h @@ -350,7 +350,6 @@ class ModuleList { // MD5 checksum, or a smarter object file equivalent, so finding modules by // UUID values is very efficient and accurate. lldb::ModuleSP FindModule(const UUID &uuid) const; - lldb::ModuleSP FindModule(lldb::user_id_t uuid) const; /// Finds the first module whose file specification matches \a module_spec. lldb::ModuleSP FindFirstModule(const ModuleSpec &module_spec) const; diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp index 06fa41b097dc3..afd992b636e77 100644 --- a/lldb/source/Core/ModuleList.cpp +++ b/lldb/source/Core/ModuleList.cpp @@ -583,23 +583,6 @@ ModuleSP ModuleList::FindModule(lldb::user_id_t uid) const { return module_sp; } -ModuleSP ModuleList::FindModule(const UUID &uuid) const { - ModuleSP module_sp; - - if (uuid.IsValid()) { - std::lock_guard<std::recursive_mutex> guard(m_modules_mutex); - collection::const_iterator pos, end = m_modules.end(); - - for (pos = m_modules.begin(); pos != end; ++pos) { - if ((*pos)->GetUUID() == uuid) { - module_sp = (*pos); - break; - } - } - } - return module_sp; -} - void ModuleList::FindTypes(Module *search_first, const TypeQuery &query, TypeResults &results) const { std::lock_guard<std::recursive_mutex> guard(m_modules_mutex); diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp index 1c32b7ed228f1..ded862ce5926c 100644 --- a/lldb/source/Expression/IRExecutionUnit.cpp +++ b/lldb/source/Expression/IRExecutionUnit.cpp @@ -807,7 +807,6 @@ ResolveFunctionCallLabel(llvm::StringRef label, if (module_label.consumeInteger(0, module_id)) return llvm::createStringError(llvm::formatv("failed to parse module ID from '{0}'.", components[1])); - //auto module_sp = target->GetImages().FindModule(module_id); Module *module = Module::GetAllocatedModuleWithUID(module_id); if (!module) _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits