https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/148877
>From 727ab0818b609f3f946af78b8679d3a80c25e175 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/2] [lldb][Expression] Encode Module and DIE UIDs into function AsmLabels --- lldb/include/lldb/Core/Module.h | 4 +- lldb/include/lldb/Expression/Expression.h | 6 ++ lldb/include/lldb/Symbol/SymbolFile.h | 14 +++ lldb/source/Core/Module.cpp | 19 ++++- lldb/source/Expression/Expression.cpp | 5 ++ lldb/source/Expression/IRExecutionUnit.cpp | 85 +++++++++++++++++++ .../Clang/ClangExpressionDeclMap.cpp | 2 +- .../SymbolFile/DWARF/DWARFASTParserClang.cpp | 44 ++++++---- .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 45 ++++++++++ .../SymbolFile/DWARF/SymbolFileDWARF.h | 3 + .../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 +-- 15 files changed, 266 insertions(+), 41 deletions(-) diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h index 8bb55c95773bc..3991a12997541 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 @@ -97,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/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..70dc20664df20 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,19 @@ 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"); + } + virtual void GetTypes(lldb_private::SymbolContextScope *sc_scope, lldb::TypeClass type_mask, lldb_private::TypeList &type_list) = 0; diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index 90997dada3666..edd79aff5d065 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,8 +139,11 @@ 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) - : 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 +248,8 @@ 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 +270,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/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 6f812b91a8b1d..7bbb09b36cd20 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" @@ -20,6 +21,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" @@ -36,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> @@ -771,6 +774,73 @@ class LoadAddressResolver { lldb::addr_t m_best_internal_load_address = LLDB_INVALID_ADDRESS; }; +/// 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 llvm::Expected<lldb::addr_t> +ResolveFunctionCallLabel(llvm::StringRef label, + const lldb_private::SymbolContext &sc, + bool &symbol_was_missing_weak) { + symbol_was_missing_weak = false; + + // Expected format at this point is: + // :<mangled name>:<module id>:<definition/declaration DIE id> + + 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) + 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)) + return llvm::createStringError( + llvm::formatv("failed to parse module ID from '{0}'.", components[1])); + + Module *module = Module::GetAllocatedModuleWithUID(module_id); + + 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 parse DIE ID from '{0}'.", + components[2]); + 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)) + return llvm::joinErrors( + llvm::createStringError("failed to resolve function by UID"), + std::move(err)); + + if (!sc.target_sp) + return llvm::createStringError("target not available."); + + LoadAddressResolver resolver(*sc.target_sp, 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 +976,21 @@ 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)) { + 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? + 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/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index c76d67b47b336..9b9c34cb114ac 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,29 @@ static unsigned GetCXXMethodCVQuals(const DWARFDIE &subprogram, return cv_quals; } +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 std::nullopt; + + 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 std::nullopt; + + return llvm::formatv("{0}:{1}:{2:x}:{3:x}", FunctionCallLabelPrefix, + mangled ? mangled : "", module_id, die_id) + .str(); +} + TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc, const DWARFDIE &die, Log *log) { @@ -1231,7 +1255,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 +1408,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 +1418,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 +1430,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..b781cff767e4f 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -2471,6 +2471,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("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("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)) { + 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("failed to resolve function DIE"); + + if (sc_list.IsEmpty()) + return llvm::createStringError("no definition DIE found"); + + assert(sc_list.GetSize() == 1); + + return llvm::Error::success(); +} + bool SymbolFileDWARF::DIEInDeclContext(const CompilerDeclContext &decl_ctx, const DWARFDIE &die, bool only_root_namespaces) { diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index 2dc862cccca14..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, 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 189826a80ce742c047c8c06c91fb19e92c23899d Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Fri, 18 Jul 2025 15:23:47 +0100 Subject: [PATCH 2/2] fixup! refactoring --- lldb/include/lldb/Expression/Expression.h | 10 ++++ lldb/source/Expression/Expression.cpp | 58 +++++++++++++++++++ lldb/source/Expression/IRExecutionUnit.cpp | 50 +++++----------- .../TypeSystem/Clang/TypeSystemClang.cpp | 31 +++------- 4 files changed, 89 insertions(+), 60 deletions(-) diff --git a/lldb/include/lldb/Expression/Expression.h b/lldb/include/lldb/Expression/Expression.h index 8e629a0d96661..10051f017224d 100644 --- a/lldb/include/lldb/Expression/Expression.h +++ b/lldb/include/lldb/Expression/Expression.h @@ -96,11 +96,21 @@ class Expression { ///invalid. }; +struct FunctionCallLabel { + llvm::StringRef m_mangled_name; + lldb::user_id_t m_die_id; + lldb::user_id_t m_module_id; +}; + /// 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); +bool hasFunctionCallLabelPrefix(llvm::StringRef name); +llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>> +splitFunctionCallLabel(llvm::StringRef label); +llvm::Expected<FunctionCallLabel> makeFunctionCallLabel(llvm::StringRef label); } // namespace lldb_private diff --git a/lldb/source/Expression/Expression.cpp b/lldb/source/Expression/Expression.cpp index d60d84b7ca409..a2fd4a15679ab 100644 --- a/lldb/source/Expression/Expression.cpp +++ b/lldb/source/Expression/Expression.cpp @@ -10,6 +10,10 @@ #include "lldb/Target/ExecutionContextScope.h" #include "lldb/Target/Target.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" + using namespace lldb_private; Expression::Expression(Target &target) @@ -31,3 +35,57 @@ bool lldb_private::consumeFunctionCallLabelPrefix(llvm::StringRef &name) { name.consume_front("_"); return name.consume_front(FunctionCallLabelPrefix); } + +bool lldb_private::hasFunctionCallLabelPrefix(llvm::StringRef name) { + return name.starts_with(FunctionCallLabelPrefix); +} + +// Expected format is: +// $__lldb_func:<mangled name>:<module id>:<definition/declaration DIE id> +llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>> +lldb_private::splitFunctionCallLabel(llvm::StringRef label) { + if (!consumeFunctionCallLabelPrefix(label)) + return llvm::createStringError( + "expected function call label prefix not found in %s", label.data()); + + if (!label.consume_front(":")) + return llvm::createStringError( + "incorrect format: expected ':' as the first character."); + + llvm::SmallVector<llvm::StringRef, 3> components; + label.split(components, ":"); + + if (components.size() != 3) + return llvm::createStringError( + "incorrect format: too many label subcomponents."); + + return components; +} + +llvm::Expected<FunctionCallLabel> +lldb_private::makeFunctionCallLabel(llvm::StringRef label) { + auto components_or_err = splitFunctionCallLabel(label); + if (!components_or_err) + return llvm::joinErrors( + llvm::createStringError("Failed to decode function call label"), + components_or_err.takeError()); + + const auto &components = *components_or_err; + + llvm::StringRef module_label = components[1]; + llvm::StringRef die_label = components[2]; + + lldb::user_id_t module_id = 0; + if (module_label.consumeInteger(0, module_id)) + return llvm::createStringError(llvm::formatv( + "failed to parse module ID from '%s'.", components[1].data())); + + lldb::user_id_t die_id; + if (die_label.consumeInteger(/*Radix=*/0, die_id)) + return llvm::createStringError("failed to parse DIE ID from '%s'.", + components[2].data()); + + return FunctionCallLabel{.m_mangled_name = components[0], + .m_module_id = module_id, + .m_die_id = die_id}; +} diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp index 7bbb09b36cd20..b79edc5dfadc1 100644 --- a/lldb/source/Expression/IRExecutionUnit.cpp +++ b/lldb/source/Expression/IRExecutionUnit.cpp @@ -782,46 +782,25 @@ class LoadAddressResolver { /// Assumes that the \c FunctionCallLabelPrefix has been /// stripped from the front of the label. static llvm::Expected<lldb::addr_t> -ResolveFunctionCallLabel(llvm::StringRef label, +ResolveFunctionCallLabel(llvm::StringRef name, const lldb_private::SymbolContext &sc, bool &symbol_was_missing_weak) { symbol_was_missing_weak = false; - // Expected format at this point is: - // :<mangled name>:<module id>:<definition/declaration DIE id> - - 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) - return llvm::createStringError( - "incorrect format: too many label subcomponents."); - - llvm::StringRef module_label = components[1]; - llvm::StringRef die = components[2]; + auto label_or_err = makeFunctionCallLabel(name); + if (!label_or_err) + return llvm::joinErrors( + llvm::createStringError("failed to create FunctionCallLabel from: %s", + name.data()), + label_or_err.takeError()); - lldb::user_id_t module_id = 0; - if (module_label.consumeInteger(0, module_id)) - return llvm::createStringError( - llvm::formatv("failed to parse module ID from '{0}'.", components[1])); + const auto &label = *label_or_err; - Module *module = Module::GetAllocatedModuleWithUID(module_id); + Module *module = Module::GetAllocatedModuleWithUID(label.m_module_id); 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 parse DIE ID from '{0}'.", - components[2]); - return LLDB_INVALID_ADDRESS; - } + llvm::formatv("failed to find module by UID {0}", label.m_module_id)); auto *symbol_file = module->GetSymbolFile(); if (!symbol_file) @@ -829,7 +808,7 @@ ResolveFunctionCallLabel(llvm::StringRef label, llvm::formatv("no SymbolFile found on module {0:x}.", module)); SymbolContextList sc_list; - if (auto err = symbol_file->ResolveFunctionUID(sc_list, die_id)) + if (auto err = symbol_file->ResolveFunctionUID(sc_list, label.m_die_id)) return llvm::joinErrors( llvm::createStringError("failed to resolve function by UID"), std::move(err)); @@ -976,10 +955,9 @@ 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)) { - if (auto addr_or_err = - ResolveFunctionCallLabel(name_ref, m_sym_ctx, missing_weak)) { + if (hasFunctionCallLabelPrefix(name.GetStringRef())) { + if (auto addr_or_err = ResolveFunctionCallLabel(name.GetStringRef(), + m_sym_ctx, missing_weak)) { return *addr_or_err; } else { LLDB_LOG_ERROR(GetLog(LLDBLog::Expressions), addr_or_err.takeError(), diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 79b22257fff47..448a64c4c4306 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -60,6 +60,7 @@ #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/UniqueCStringMap.h" +#include "lldb/Expression/Expression.h" #include "lldb/Host/StreamFile.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolFile.h" @@ -9031,27 +9032,6 @@ 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 = @@ -9073,9 +9053,12 @@ 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); + if (const auto *label = nd->getAttr<AsmLabelAttr>()) { + if (auto components_or_err = splitFunctionCallLabel(label->getLabel())) + return ConstString((*components_or_err)[0]); + else + llvm::consumeError(components_or_err.takeError()); + } llvm::SmallVector<char, 1024> buf; llvm::raw_svector_ostream llvm_ostrm(buf); _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits