https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/148877
>From 382395408c4b9a38206e984328ab472c25e7c55f Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Fri, 15 Nov 2024 01:59:36 +0000 Subject: [PATCH 01/12] [lldb][Expression] Encode Module and DIE UIDs into function AsmLabels --- lldb/include/lldb/Core/Module.h | 4 +- lldb/include/lldb/Expression/Expression.h | 25 ++++++ lldb/include/lldb/Symbol/SymbolFile.h | 14 ++++ lldb/include/lldb/Symbol/TypeSystem.h | 16 ++++ lldb/source/Core/Module.cpp | 19 ++++- lldb/source/Expression/Expression.cpp | 16 ++++ lldb/source/Expression/IRExecutionUnit.cpp | 74 +++++++++++++++++ .../Clang/ClangExpressionDeclMap.cpp | 2 +- .../SymbolFile/DWARF/DWARFASTParserClang.cpp | 43 ++++++---- .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 41 ++++++++++ .../SymbolFile/DWARF/SymbolFileDWARF.h | 3 + .../SymbolFile/NativePDB/PdbAstBuilder.cpp | 6 +- .../NativePDB/UdtRecordCompleter.cpp | 5 +- .../Plugins/SymbolFile/PDB/PDBASTParser.cpp | 7 +- .../TypeSystem/Clang/TypeSystemClang.cpp | 81 +++++++++++++++++-- .../TypeSystem/Clang/TypeSystemClang.h | 11 ++- lldb/unittests/Symbol/TestTypeSystemClang.cpp | 12 +-- 17 files changed, 335 insertions(+), 44 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..f32878c9bf876 100644 --- a/lldb/include/lldb/Expression/Expression.h +++ b/lldb/include/lldb/Expression/Expression.h @@ -96,6 +96,31 @@ class Expression { ///invalid. }; +/// Holds parsed information about a function call label that +/// LLDB attaches as an AsmLabel to function AST nodes it parses +/// from debug-info. +/// +/// The format being: +/// +/// <prefix>:<mangled name>:<module id>:<DIE id> +/// +/// The label string needs to stay valid for the entire lifetime +/// of this object. +struct FunctionCallLabel { + llvm::StringRef m_lookup_name; + lldb::user_id_t m_module_id; + + /// Mostly for debuggability. + lldb::user_id_t m_die_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); + } // 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..6aca276fc85b6 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 identified by \c lookup_name within + /// this SymbolFile. + /// + /// \param[in,out] sc_list The resolved functions will be appended to this + /// list. + /// + /// \param[in] lookup_name The UID of the function DIE to resolve. + /// + virtual llvm::Error FindAndResolveFunction(SymbolContextList &sc_list, + llvm::StringRef lookup_name) { + 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/include/lldb/Symbol/TypeSystem.h b/lldb/include/lldb/Symbol/TypeSystem.h index cb1f0130b548d..742c09251ea2f 100644 --- a/lldb/include/lldb/Symbol/TypeSystem.h +++ b/lldb/include/lldb/Symbol/TypeSystem.h @@ -548,6 +548,22 @@ class TypeSystem : public PluginInterface, bool GetHasForcefullyCompletedTypes() const { return m_has_forcefully_completed_types; } + + /// Returns the components of the specified function call label. + /// + /// The format of \c label is described in \c FunctionCallLabel. + /// The label prefix is not one of the components. + virtual llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>> + splitFunctionCallLabel(llvm::StringRef label) const { + return llvm::createStringError("Not implemented."); + } + + // Decodes the function label into a \c FunctionCallLabel. + virtual llvm::Expected<FunctionCallLabel> + makeFunctionCallLabel(llvm::StringRef label) const { + return llvm::createStringError("Not implemented."); + } + protected: SymbolFile *m_sym_file = nullptr; /// Used for reporting statistics. 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..e19c804caa3c6 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) @@ -26,3 +30,15 @@ Expression::Expression(ExecutionContextScope &exe_scope) m_jit_end_addr(LLDB_INVALID_ADDRESS) { assert(m_target_wp.lock()); } + +bool lldb_private::consumeFunctionCallLabelPrefix(llvm::StringRef &name) { + // On Darwin mangled names get a '_' prefix. + name.consume_front("_"); + return name.consume_front(FunctionCallLabelPrefix); +} + +bool lldb_private::hasFunctionCallLabelPrefix(llvm::StringRef name) { + // On Darwin mangled names get a '_' prefix. + name.consume_front("_"); + return name.starts_with(FunctionCallLabelPrefix); +} diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp index 6f812b91a8b1d..a9ea244889cce 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,63 @@ 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 name, + const lldb_private::SymbolContext &sc, + bool &symbol_was_missing_weak) { + symbol_was_missing_weak = false; + + if (!sc.target_sp) + return llvm::createStringError("target not available."); + + auto ts_or_err = sc.target_sp->GetScratchTypeSystemForLanguage( + lldb::eLanguageTypeC_plus_plus); + if (!ts_or_err || !*ts_or_err) + return llvm::joinErrors( + llvm::createStringError( + "failed to find scratch C++ TypeSystem for current target."), + ts_or_err.takeError()); + + auto ts_sp = *ts_or_err; + + auto label_or_err = ts_sp->makeFunctionCallLabel(name); + if (!label_or_err) + return llvm::joinErrors( + llvm::createStringError("failed to create FunctionCallLabel from: %s", + name.data()), + label_or_err.takeError()); + + const auto &label = *label_or_err; + + Module *module = Module::GetAllocatedModuleWithUID(label.m_module_id); + + if (!module) + return llvm::createStringError( + llvm::formatv("failed to find module by UID {0}", label.m_module_id)); + + 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->FindAndResolveFunction(sc_list, label.m_lookup_name)) + return llvm::joinErrors( + llvm::createStringError("failed to resolve function by UID"), + std::move(err)); + + 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 +966,20 @@ lldb::addr_t IRExecutionUnit::FindInUserDefinedSymbols( lldb::addr_t IRExecutionUnit::FindSymbol(lldb_private::ConstString name, bool &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(), + "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 ba65f50a44d10..8af3ed06aa3f0 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,28 @@ static unsigned GetCXXMethodCVQuals(const DWARFDIE &subprogram, return cv_quals; } +static std::optional<std::string> MakeLLDBFuncAsmLabel(const DWARFDIE &die) { + char const *name = die.GetMangledName(/*substitute_name_allowed*/ false); + if (!name) + return std::nullopt; + + 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, name, + module_id, die_id) + .str(); +} + TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc, const DWARFDIE &die, Log *log) { @@ -1231,7 +1254,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 +1407,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 +1417,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 +1429,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 4b4a58297ded4..a1164646cbb29 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -2471,6 +2471,47 @@ bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die, return false; } +llvm::Error +SymbolFileDWARF::FindAndResolveFunction(SymbolContextList &sc_list, + llvm::StringRef lookup_name) { + std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); + + DWARFDIE die; + Module::LookupInfo info(ConstString(lookup_name), lldb::eFunctionNameTypeFull, + lldb::eLanguageTypeUnknown); + + m_index->GetFunctions(info, *this, {}, [&](DWARFDIE entry) { + if (entry.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0)) + return true; + + // We don't check whether the specification DIE for this function + // corresponds to the declaration DIE because the declaration might be in + // a type-unit but the definition in the compile-unit (and it's + // specifcation would point to the declaration in the compile-unit). We + // rely on the mangled name within the module to be enough to find us the + // unique definition. + die = entry; + return false; + }); + + if (!die.IsValid()) + return llvm::createStringError( + llvm::formatv("failed to find definition DIE for '{0}'", lookup_name)); + + 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"); + + if (sc_list.GetSize() > 1) + return llvm::createStringError( + "found %d functions for %s but expected only 1", sc_list.GetSize(), + lookup_name.data()); + + 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..ee966366d3f2b 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -434,6 +434,9 @@ class SymbolFileDWARF : public SymbolFileCommon { DIEArray MergeBlockAbstractParameters(const DWARFDIE &block_die, DIEArray &&variable_dies); + llvm::Error FindAndResolveFunction(SymbolContextList &sc_list, + llvm::StringRef lookup_name) override; + // Given a die_offset, figure out the symbol context representing that die. bool ResolveFunction(const DWARFDIE &die, bool include_inlines, SymbolContextList &sc_list); 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/NativePDB/UdtRecordCompleter.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp index 807ee5b30779c..5e77ea7f85603 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp @@ -111,9 +111,8 @@ void UdtRecordCompleter::AddMethod(llvm::StringRef name, TypeIndex type_idx, bool is_artificial = (options & MethodOptions::CompilerGenerated) == MethodOptions::CompilerGenerated; m_ast_builder.clang().AddMethodToCXXRecordType( - derived_opaque_ty, name.data(), nullptr, method_ct, - access_type, attrs.isVirtual(), attrs.isStatic(), false, false, false, - is_artificial); + derived_opaque_ty, name.data(), std::nullopt, method_ct, access_type, + attrs.isVirtual(), attrs.isStatic(), false, false, false, is_artificial); m_cxx_record_map[derived_opaque_ty].insert({name, method_ct}); } 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 256952dcf9085..0c476e5b9d01b 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" @@ -2137,7 +2138,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 +2160,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); @@ -7651,7 +7668,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()) @@ -7784,10 +7801,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. @@ -9041,6 +9057,13 @@ ConstString TypeSystemClang::DeclGetMangledName(void *opaque_decl) { if (!mc || !mc->shouldMangleCXXName(nd)) return {}; + 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); if (llvm::isa<clang::CXXConstructorDecl>(nd)) { @@ -9763,3 +9786,51 @@ void TypeSystemClang::LogCreation() const { LLDB_LOG(log, "Created new TypeSystem for (ASTContext*){0:x} '{1}'", &getASTContext(), getDisplayName()); } + +// Expected format is: +// $__lldb_func:<mangled name>:<module id>:<definition/declaration DIE id> +llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>> +TypeSystemClang::splitFunctionCallLabel(llvm::StringRef label) const { + 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> +TypeSystemClang::makeFunctionCallLabel(llvm::StringRef label) const { + 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 '{0}'.", components[1])); + + lldb::user_id_t die_id; + if (die_label.consumeInteger(/*Radix=*/0, die_id)) + return llvm::createStringError( + llvm::formatv("failed to parse DIE ID from '{0}'.", components[2])); + + return FunctionCallLabel{/*.m_lookup_name =*/components[0], + /*.m_module_id =*/module_id, /*.m_die_id =*/die_id}; +} diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index 63dee9dceded3..726a0eea9382a 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); @@ -1098,6 +1099,12 @@ class TypeSystemClang : public TypeSystem { lldb::opaque_compiler_type_t type, Stream &s, lldb::DescriptionLevel level = lldb::eDescriptionLevelFull) override; + llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>> + splitFunctionCallLabel(llvm::StringRef label) const override; + + llvm::Expected<FunctionCallLabel> + makeFunctionCallLabel(llvm::StringRef label) const override; + static void DumpTypeName(const CompilerType &type); static clang::EnumDecl *GetAsEnumDecl(const CompilerType &type); diff --git a/lldb/unittests/Symbol/TestTypeSystemClang.cpp b/lldb/unittests/Symbol/TestTypeSystemClang.cpp index 71930ab54f409..588361e65c7a1 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 f15648061c93d37619b894cffc95009d823a13d7 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Mon, 21 Jul 2025 12:15:24 +0100 Subject: [PATCH 02/12] fixup! add quotes --- lldb/source/Expression/IRExecutionUnit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp index a9ea244889cce..40635d0829168 100644 --- a/lldb/source/Expression/IRExecutionUnit.cpp +++ b/lldb/source/Expression/IRExecutionUnit.cpp @@ -972,7 +972,7 @@ lldb::addr_t IRExecutionUnit::FindSymbol(lldb_private::ConstString name, return *addr_or_err; } else { LLDB_LOG_ERROR(GetLog(LLDBLog::Expressions), addr_or_err.takeError(), - "Failed to resolve function call label {1}: {0}", + "Failed to resolve function call label '{1}': {0}", name.GetStringRef()); return LLDB_INVALID_ADDRESS; } >From 6dddabcbd21cbaf65bd6244fd2d3d17dd42ffcee Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Mon, 28 Jul 2025 11:43:17 +0100 Subject: [PATCH 03/12] fixup! create literal AsmLabels --- lldb/include/lldb/Expression/Expression.h | 3 --- lldb/source/Expression/Expression.cpp | 12 ------------ lldb/source/Expression/IRExecutionUnit.cpp | 2 +- .../Plugins/TypeSystem/Clang/TypeSystemClang.cpp | 6 +++--- 4 files changed, 4 insertions(+), 19 deletions(-) diff --git a/lldb/include/lldb/Expression/Expression.h b/lldb/include/lldb/Expression/Expression.h index f32878c9bf876..9044d26cf6670 100644 --- a/lldb/include/lldb/Expression/Expression.h +++ b/lldb/include/lldb/Expression/Expression.h @@ -118,9 +118,6 @@ struct FunctionCallLabel { /// from JITted expressions. inline constexpr llvm::StringRef FunctionCallLabelPrefix = "$__lldb_func"; -bool consumeFunctionCallLabelPrefix(llvm::StringRef &name); -bool hasFunctionCallLabelPrefix(llvm::StringRef name); - } // namespace lldb_private #endif // LLDB_EXPRESSION_EXPRESSION_H diff --git a/lldb/source/Expression/Expression.cpp b/lldb/source/Expression/Expression.cpp index e19c804caa3c6..f85a3284d7eda 100644 --- a/lldb/source/Expression/Expression.cpp +++ b/lldb/source/Expression/Expression.cpp @@ -30,15 +30,3 @@ Expression::Expression(ExecutionContextScope &exe_scope) m_jit_end_addr(LLDB_INVALID_ADDRESS) { assert(m_target_wp.lock()); } - -bool lldb_private::consumeFunctionCallLabelPrefix(llvm::StringRef &name) { - // On Darwin mangled names get a '_' prefix. - name.consume_front("_"); - return name.consume_front(FunctionCallLabelPrefix); -} - -bool lldb_private::hasFunctionCallLabelPrefix(llvm::StringRef name) { - // On Darwin mangled names get a '_' prefix. - name.consume_front("_"); - return name.starts_with(FunctionCallLabelPrefix); -} diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp index 40635d0829168..9a545c40eacd0 100644 --- a/lldb/source/Expression/IRExecutionUnit.cpp +++ b/lldb/source/Expression/IRExecutionUnit.cpp @@ -966,7 +966,7 @@ lldb::addr_t IRExecutionUnit::FindInUserDefinedSymbols( lldb::addr_t IRExecutionUnit::FindSymbol(lldb_private::ConstString name, bool &missing_weak) { - if (hasFunctionCallLabelPrefix(name.GetStringRef())) { + if (name.GetStringRef().starts_with(FunctionCallLabelPrefix)) { if (auto addr_or_err = ResolveFunctionCallLabel(name.GetStringRef(), m_sym_ctx, missing_weak)) { return *addr_or_err; diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 0c476e5b9d01b..fadd1e3266040 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -2173,7 +2173,7 @@ FunctionDecl *TypeSystemClang::CreateFunctionDeclaration( // AddMethodToCXXRecordType. if (asm_label) func_decl->addAttr(clang::AsmLabelAttr::CreateImplicit(ast, *asm_label, - /*literal=*/false)); + /*literal=*/true)); SetOwningModule(func_decl, owning_module); decl_ctx->addDecl(func_decl); @@ -7803,7 +7803,7 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( if (asm_label) cxx_method_decl->addAttr(clang::AsmLabelAttr::CreateImplicit( - getASTContext(), *asm_label, /*literal=*/false)); + getASTContext(), *asm_label, /*literal=*/true)); // Parameters on member function declarations in DWARF generally don't // have names, so we omit them when creating the ParmVarDecls. @@ -9791,7 +9791,7 @@ void TypeSystemClang::LogCreation() const { // $__lldb_func:<mangled name>:<module id>:<definition/declaration DIE id> llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>> TypeSystemClang::splitFunctionCallLabel(llvm::StringRef label) const { - if (!consumeFunctionCallLabelPrefix(label)) + if (!label.consume_front(FunctionCallLabelPrefix)) return llvm::createStringError( "expected function call label prefix not found in %s", label.data()); if (!label.consume_front(":")) >From 52662a7d0f09fb1dc104a1242c574dc864b40d88 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Mon, 28 Jul 2025 12:02:49 +0100 Subject: [PATCH 04/12] fixup! move to new FindModule API; make module UID atomic --- lldb/include/lldb/Core/Module.h | 1 - lldb/include/lldb/Core/ModuleList.h | 8 ++++++++ lldb/source/Core/Module.cpp | 12 +----------- lldb/source/Core/ModuleList.cpp | 14 ++++++++++++++ lldb/source/Expression/IRExecutionUnit.cpp | 8 ++++---- 5 files changed, 27 insertions(+), 16 deletions(-) diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h index 3991a12997541..8513e147ee523 100644 --- a/lldb/include/lldb/Core/Module.h +++ b/lldb/include/lldb/Core/Module.h @@ -98,7 +98,6 @@ 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/Core/ModuleList.h b/lldb/include/lldb/Core/ModuleList.h index d5e291f3380a8..6ecdcf10fa85f 100644 --- a/lldb/include/lldb/Core/ModuleList.h +++ b/lldb/include/lldb/Core/ModuleList.h @@ -352,6 +352,14 @@ class ModuleList { // UUID values is very efficient and accurate. lldb::ModuleSP FindModule(const UUID &uuid) const; + /// Find a module by LLDB-specific unique identifier. + /// + /// \param[in] uid The UID of the module assigned to it on construction. + /// + /// \returns ModuleSP of module with \c uid. Returns nullptr if no such + /// module could be found. + lldb::ModuleSP FindModule(lldb::user_id_t uid) 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 edd79aff5d065..f27a95de484df 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -121,15 +121,6 @@ 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()); @@ -139,8 +130,7 @@ Module *Module::GetAllocatedModuleAtIndex(size_t idx) { return nullptr; } -// TODO: needs a mutex -static lldb::user_id_t g_unique_id = 1; +static std::atomic<lldb::user_id_t> g_unique_id = 1; Module::Module(const ModuleSpec &module_spec) : UserID(g_unique_id++), m_unwind_table(*this), m_file_has_changed(false), diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp index d2e5be8c79b17..e3dfa799ebb65 100644 --- a/lldb/source/Core/ModuleList.cpp +++ b/lldb/source/Core/ModuleList.cpp @@ -584,6 +584,20 @@ ModuleSP ModuleList::FindModule(const UUID &uuid) const { return module_sp; } +ModuleSP ModuleList::FindModule(lldb::user_id_t uid) const { + ModuleSP module_sp; + ForEach([&](const ModuleSP &m) { + if (m->GetID() == uid) { + module_sp = m; + return true; + } + + return false; + }); + + 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 9a545c40eacd0..e7387dc2b3bf9 100644 --- a/lldb/source/Expression/IRExecutionUnit.cpp +++ b/lldb/source/Expression/IRExecutionUnit.cpp @@ -809,16 +809,16 @@ ResolveFunctionCallLabel(llvm::StringRef name, const auto &label = *label_or_err; - Module *module = Module::GetAllocatedModuleWithUID(label.m_module_id); + auto module_sp = sc.target_sp->GetImages().FindModule(label.m_module_id); - if (!module) + if (!module_sp) return llvm::createStringError( llvm::formatv("failed to find module by UID {0}", label.m_module_id)); - auto *symbol_file = module->GetSymbolFile(); + auto *symbol_file = module_sp->GetSymbolFile(); if (!symbol_file) return llvm::createStringError( - llvm::formatv("no SymbolFile found on module {0:x}.", module)); + llvm::formatv("no SymbolFile found on module {0:x}.", module_sp.get())); SymbolContextList sc_list; if (auto err = >From 527bdb0ffc9b11c090446257d4bb97ed7c81e646 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Mon, 28 Jul 2025 12:16:22 +0100 Subject: [PATCH 05/12] fixup! rename FunctionCallLabel members --- lldb/include/lldb/Expression/Expression.h | 21 +++++++++++++------ lldb/source/Expression/IRExecutionUnit.cpp | 6 +++--- .../TypeSystem/Clang/TypeSystemClang.cpp | 6 ++---- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/lldb/include/lldb/Expression/Expression.h b/lldb/include/lldb/Expression/Expression.h index 9044d26cf6670..0f2281790a055 100644 --- a/lldb/include/lldb/Expression/Expression.h +++ b/lldb/include/lldb/Expression/Expression.h @@ -102,16 +102,25 @@ class Expression { /// /// The format being: /// -/// <prefix>:<mangled name>:<module id>:<DIE id> +/// <prefix>:<mangled name>:<module uid>:<symbol uid> /// /// The label string needs to stay valid for the entire lifetime /// of this object. struct FunctionCallLabel { - llvm::StringRef m_lookup_name; - lldb::user_id_t m_module_id; - - /// Mostly for debuggability. - lldb::user_id_t m_die_id; + /// Name to use when searching for the function symbol in + /// \c module_id. For most function calls this will be a + /// mangled name. In cases where a mangled name can't be used, + /// this will be the function name. + llvm::StringRef lookup_name; + + /// Unique identifier of the lldb_private::Module + /// which contains the symbol identified by \c symbol_id. + lldb::user_id_t module_id; + + /// Unique identifier of the function symbol on which to + /// perform the function call. For example, for DWARF this would + /// be the DIE UID. + lldb::user_id_t symbol_id; }; /// LLDB attaches this prefix to mangled names of functions that it get called diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp index e7387dc2b3bf9..33f34831126ac 100644 --- a/lldb/source/Expression/IRExecutionUnit.cpp +++ b/lldb/source/Expression/IRExecutionUnit.cpp @@ -809,11 +809,11 @@ ResolveFunctionCallLabel(llvm::StringRef name, const auto &label = *label_or_err; - auto module_sp = sc.target_sp->GetImages().FindModule(label.m_module_id); + auto module_sp = sc.target_sp->GetImages().FindModule(label.module_id); if (!module_sp) return llvm::createStringError( - llvm::formatv("failed to find module by UID {0}", label.m_module_id)); + llvm::formatv("failed to find module by UID {0}", label.module_id)); auto *symbol_file = module_sp->GetSymbolFile(); if (!symbol_file) @@ -822,7 +822,7 @@ ResolveFunctionCallLabel(llvm::StringRef name, SymbolContextList sc_list; if (auto err = - symbol_file->FindAndResolveFunction(sc_list, label.m_lookup_name)) + symbol_file->FindAndResolveFunction(sc_list, label.lookup_name)) return llvm::joinErrors( llvm::createStringError("failed to resolve function by UID"), std::move(err)); diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index fadd1e3266040..7a73abc9a3ef4 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -9787,8 +9787,6 @@ void TypeSystemClang::LogCreation() const { &getASTContext(), getDisplayName()); } -// Expected format is: -// $__lldb_func:<mangled name>:<module id>:<definition/declaration DIE id> llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>> TypeSystemClang::splitFunctionCallLabel(llvm::StringRef label) const { if (!label.consume_front(FunctionCallLabelPrefix)) @@ -9831,6 +9829,6 @@ TypeSystemClang::makeFunctionCallLabel(llvm::StringRef label) const { return llvm::createStringError( llvm::formatv("failed to parse DIE ID from '{0}'.", components[2])); - return FunctionCallLabel{/*.m_lookup_name =*/components[0], - /*.m_module_id =*/module_id, /*.m_die_id =*/die_id}; + return FunctionCallLabel{/*.lookup_name=*/components[0], + /*.module_id=*/module_id, /*.symbol_id=*/die_id}; } >From c337ab584c9990b84ca9e78613821f914552f10c Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Mon, 28 Jul 2025 12:29:44 +0100 Subject: [PATCH 06/12] fixup! remove unused headers --- lldb/source/Expression/Expression.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lldb/source/Expression/Expression.cpp b/lldb/source/Expression/Expression.cpp index f85a3284d7eda..93f585edfce3d 100644 --- a/lldb/source/Expression/Expression.cpp +++ b/lldb/source/Expression/Expression.cpp @@ -10,10 +10,6 @@ #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) >From 13a0eaff6033a1cc439d3e5400827d9a428f5473 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Mon, 28 Jul 2025 12:41:58 +0100 Subject: [PATCH 07/12] fixup! move FunctionCallLabel APIs into Expression component --- lldb/include/lldb/Expression/Expression.h | 11 ++++ lldb/include/lldb/Symbol/TypeSystem.h | 15 ------ lldb/source/Expression/Expression.cpp | 50 +++++++++++++++++++ lldb/source/Expression/IRExecutionUnit.cpp | 12 +---- .../TypeSystem/Clang/TypeSystemClang.cpp | 48 +----------------- .../TypeSystem/Clang/TypeSystemClang.h | 6 --- 6 files changed, 64 insertions(+), 78 deletions(-) diff --git a/lldb/include/lldb/Expression/Expression.h b/lldb/include/lldb/Expression/Expression.h index 0f2281790a055..35d7d71f6b253 100644 --- a/lldb/include/lldb/Expression/Expression.h +++ b/lldb/include/lldb/Expression/Expression.h @@ -127,6 +127,17 @@ struct FunctionCallLabel { /// from JITted expressions. inline constexpr llvm::StringRef FunctionCallLabelPrefix = "$__lldb_func"; +/// Returns the components of the specified function call label. +/// +/// The format of \c label is described in \c FunctionCallLabel. +/// The label prefix is not one of the components. +llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>> +splitFunctionCallLabel(llvm::StringRef label); + +// Decodes the function label into a \c FunctionCallLabel. +llvm::Expected<FunctionCallLabel> +makeFunctionCallLabel(llvm::StringRef label); + } // namespace lldb_private #endif // LLDB_EXPRESSION_EXPRESSION_H diff --git a/lldb/include/lldb/Symbol/TypeSystem.h b/lldb/include/lldb/Symbol/TypeSystem.h index 742c09251ea2f..40bd59056a5df 100644 --- a/lldb/include/lldb/Symbol/TypeSystem.h +++ b/lldb/include/lldb/Symbol/TypeSystem.h @@ -549,21 +549,6 @@ class TypeSystem : public PluginInterface, return m_has_forcefully_completed_types; } - /// Returns the components of the specified function call label. - /// - /// The format of \c label is described in \c FunctionCallLabel. - /// The label prefix is not one of the components. - virtual llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>> - splitFunctionCallLabel(llvm::StringRef label) const { - return llvm::createStringError("Not implemented."); - } - - // Decodes the function label into a \c FunctionCallLabel. - virtual llvm::Expected<FunctionCallLabel> - makeFunctionCallLabel(llvm::StringRef label) const { - return llvm::createStringError("Not implemented."); - } - protected: SymbolFile *m_sym_file = nullptr; /// Used for reporting statistics. diff --git a/lldb/source/Expression/Expression.cpp b/lldb/source/Expression/Expression.cpp index 93f585edfce3d..f55e8b1f8e485 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/StringRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Error.h" + using namespace lldb_private; Expression::Expression(Target &target) @@ -26,3 +30,49 @@ Expression::Expression(ExecutionContextScope &exe_scope) m_jit_end_addr(LLDB_INVALID_ADDRESS) { assert(m_target_wp.lock()); } + +llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>> +lldb_private::splitFunctionCallLabel(llvm::StringRef label) { + if (!label.consume_front(FunctionCallLabelPrefix)) + 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 '{0}'.", components[1])); + + lldb::user_id_t die_id; + if (die_label.consumeInteger(/*Radix=*/0, die_id)) + return llvm::createStringError( + llvm::formatv("failed to parse DIE ID from '{0}'.", components[2])); + + return FunctionCallLabel{/*.lookup_name=*/components[0], + /*.module_id=*/module_id, /*.symbol_id=*/die_id}; +} diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp index 33f34831126ac..56a01d7003c50 100644 --- a/lldb/source/Expression/IRExecutionUnit.cpp +++ b/lldb/source/Expression/IRExecutionUnit.cpp @@ -790,17 +790,7 @@ ResolveFunctionCallLabel(llvm::StringRef name, if (!sc.target_sp) return llvm::createStringError("target not available."); - auto ts_or_err = sc.target_sp->GetScratchTypeSystemForLanguage( - lldb::eLanguageTypeC_plus_plus); - if (!ts_or_err || !*ts_or_err) - return llvm::joinErrors( - llvm::createStringError( - "failed to find scratch C++ TypeSystem for current target."), - ts_or_err.takeError()); - - auto ts_sp = *ts_or_err; - - auto label_or_err = ts_sp->makeFunctionCallLabel(name); + auto label_or_err = makeFunctionCallLabel(name); if (!label_or_err) return llvm::joinErrors( llvm::createStringError("failed to create FunctionCallLabel from: %s", diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 7a73abc9a3ef4..797da3be74c64 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -9057,6 +9057,8 @@ ConstString TypeSystemClang::DeclGetMangledName(void *opaque_decl) { if (!mc || !mc->shouldMangleCXXName(nd)) return {}; + // We have a LLDB FunctionCallLabel instead of an ordinary mangled name. + // Extract the mangled name out of this label. if (const auto *label = nd->getAttr<AsmLabelAttr>()) { if (auto components_or_err = splitFunctionCallLabel(label->getLabel())) return ConstString((*components_or_err)[0]); @@ -9786,49 +9788,3 @@ void TypeSystemClang::LogCreation() const { LLDB_LOG(log, "Created new TypeSystem for (ASTContext*){0:x} '{1}'", &getASTContext(), getDisplayName()); } - -llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>> -TypeSystemClang::splitFunctionCallLabel(llvm::StringRef label) const { - if (!label.consume_front(FunctionCallLabelPrefix)) - 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> -TypeSystemClang::makeFunctionCallLabel(llvm::StringRef label) const { - 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 '{0}'.", components[1])); - - lldb::user_id_t die_id; - if (die_label.consumeInteger(/*Radix=*/0, die_id)) - return llvm::createStringError( - llvm::formatv("failed to parse DIE ID from '{0}'.", components[2])); - - return FunctionCallLabel{/*.lookup_name=*/components[0], - /*.module_id=*/module_id, /*.symbol_id=*/die_id}; -} diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index 726a0eea9382a..dcf77f9ec1cb8 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -1099,12 +1099,6 @@ class TypeSystemClang : public TypeSystem { lldb::opaque_compiler_type_t type, Stream &s, lldb::DescriptionLevel level = lldb::eDescriptionLevelFull) override; - llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>> - splitFunctionCallLabel(llvm::StringRef label) const override; - - llvm::Expected<FunctionCallLabel> - makeFunctionCallLabel(llvm::StringRef label) const override; - static void DumpTypeName(const CompilerType &type); static clang::EnumDecl *GetAsEnumDecl(const CompilerType &type); >From b3f075d729c1b819b1dae195c1f45c84a45370b5 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Mon, 28 Jul 2025 12:54:20 +0100 Subject: [PATCH 08/12] fixup! adjust TypeSystemClang::DeclGetMangledName --- .../TypeSystem/Clang/TypeSystemClang.cpp | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 797da3be74c64..2e9311bdd930c 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -9046,6 +9046,21 @@ ConstString TypeSystemClang::DeclGetName(void *opaque_decl) { return ConstString(); } +static ConstString +ExtractMangledNameFromFunctionCallLabel(llvm::StringRef label) { + auto components_or_err = splitFunctionCallLabel(label); + if (!components_or_err) { + llvm::consumeError(components_or_err.takeError()); + return {}; + } + + llvm::StringRef mangled = (*components_or_err)[0]; + if (Mangled::IsMangledName(mangled)) + return ConstString(mangled); + + return {}; +} + ConstString TypeSystemClang::DeclGetMangledName(void *opaque_decl) { clang::NamedDecl *nd = llvm::dyn_cast_or_null<clang::NamedDecl>( static_cast<clang::Decl *>(opaque_decl)); @@ -9057,14 +9072,12 @@ ConstString TypeSystemClang::DeclGetMangledName(void *opaque_decl) { if (!mc || !mc->shouldMangleCXXName(nd)) return {}; - // We have a LLDB FunctionCallLabel instead of an ordinary mangled name. + // We have an LLDB FunctionCallLabel instead of an ordinary mangled name. // Extract the mangled name out of this label. - 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()); - } + if (const auto *label = nd->getAttr<AsmLabelAttr>()) + if (ConstString mangled = + ExtractMangledNameFromFunctionCallLabel(label->getLabel())) + return mangled; llvm::SmallVector<char, 1024> buf; llvm::raw_svector_ostream llvm_ostrm(buf); >From d3c63096fd260b527c8200046c56c7f4d7d04a83 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Mon, 28 Jul 2025 15:08:30 +0100 Subject: [PATCH 09/12] fixup! move label encoding/decoding into FunctionCallLabel structure --- lldb/include/lldb/Expression/Expression.h | 19 +++++++++++++++---- lldb/source/Expression/Expression.cpp | 8 +++++++- lldb/source/Expression/IRExecutionUnit.cpp | 2 +- .../SymbolFile/DWARF/DWARFASTParserClang.cpp | 7 ++++--- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/lldb/include/lldb/Expression/Expression.h b/lldb/include/lldb/Expression/Expression.h index 35d7d71f6b253..83d3dc75620ba 100644 --- a/lldb/include/lldb/Expression/Expression.h +++ b/lldb/include/lldb/Expression/Expression.h @@ -121,6 +121,21 @@ struct FunctionCallLabel { /// perform the function call. For example, for DWARF this would /// be the DIE UID. lldb::user_id_t symbol_id; + + /// Decodes the specified function \c label into a \c FunctionCallLabel. + static llvm::Expected<FunctionCallLabel> fromString(llvm::StringRef label); + + /// Encode this FunctionCallLabel into it's string representation. + /// + /// The representation roundtrips through \c fromString: + /// \code{.cpp} + /// llvm::StringRef encoded = "$__lldb_func:_Z3foov:0x0:0x0"; + /// FunctionCallLabel label = *fromString(label); + /// + /// assert (label.toString() == encoded); + /// assert (*fromString(label.toString()) == label); + /// \endcode + std::string toString() const; }; /// LLDB attaches this prefix to mangled names of functions that it get called @@ -134,10 +149,6 @@ inline constexpr llvm::StringRef FunctionCallLabelPrefix = "$__lldb_func"; llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>> splitFunctionCallLabel(llvm::StringRef label); -// Decodes the function label into a \c FunctionCallLabel. -llvm::Expected<FunctionCallLabel> -makeFunctionCallLabel(llvm::StringRef label); - } // namespace lldb_private #endif // LLDB_EXPRESSION_EXPRESSION_H diff --git a/lldb/source/Expression/Expression.cpp b/lldb/source/Expression/Expression.cpp index f55e8b1f8e485..1ea18dce772ba 100644 --- a/lldb/source/Expression/Expression.cpp +++ b/lldb/source/Expression/Expression.cpp @@ -51,7 +51,7 @@ lldb_private::splitFunctionCallLabel(llvm::StringRef label) { } llvm::Expected<FunctionCallLabel> -lldb_private::makeFunctionCallLabel(llvm::StringRef label) { +lldb_private::FunctionCallLabel::fromString(llvm::StringRef label) { auto components_or_err = splitFunctionCallLabel(label); if (!components_or_err) return llvm::joinErrors( @@ -76,3 +76,9 @@ lldb_private::makeFunctionCallLabel(llvm::StringRef label) { return FunctionCallLabel{/*.lookup_name=*/components[0], /*.module_id=*/module_id, /*.symbol_id=*/die_id}; } + +std::string lldb_private::FunctionCallLabel::toString() const { + return llvm::formatv("{0}:{1}:{2:x}:{3:x}", FunctionCallLabelPrefix, + lookup_name, module_id, symbol_id) + .str(); +} diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp index 56a01d7003c50..a1d8f30f373eb 100644 --- a/lldb/source/Expression/IRExecutionUnit.cpp +++ b/lldb/source/Expression/IRExecutionUnit.cpp @@ -790,7 +790,7 @@ ResolveFunctionCallLabel(llvm::StringRef name, if (!sc.target_sp) return llvm::createStringError("target not available."); - auto label_or_err = makeFunctionCallLabel(name); + auto label_or_err = FunctionCallLabel::fromString(name); if (!label_or_err) return llvm::joinErrors( llvm::createStringError("failed to create FunctionCallLabel from: %s", diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index 8af3ed06aa3f0..5cacc97039726 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -267,9 +267,10 @@ static std::optional<std::string> MakeLLDBFuncAsmLabel(const DWARFDIE &die) { if (die_id == LLDB_INVALID_UID) return std::nullopt; - return llvm::formatv("{0}:{1}:{2:x}:{3:x}", FunctionCallLabelPrefix, name, - module_id, die_id) - .str(); + return FunctionCallLabel{/*.lookup_name=*/name, + /*module_id=*/module_id, + /*symbol_id=*/die_id} + .toString(); } TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc, >From 1b8d66b66ebcfe057157e82569e1fc3c20599885 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Mon, 28 Jul 2025 15:25:16 +0100 Subject: [PATCH 10/12] fixup! make mangled name last component in label; remove need for splitting helper --- lldb/include/lldb/Expression/Expression.h | 26 ++++++++----------- lldb/source/Expression/Expression.cpp | 25 +++++++++++------- .../SymbolFile/DWARF/DWARFASTParserClang.cpp | 8 +++--- .../TypeSystem/Clang/TypeSystemClang.cpp | 8 +++--- 4 files changed, 35 insertions(+), 32 deletions(-) diff --git a/lldb/include/lldb/Expression/Expression.h b/lldb/include/lldb/Expression/Expression.h index 83d3dc75620ba..7dce9aa21e5d2 100644 --- a/lldb/include/lldb/Expression/Expression.h +++ b/lldb/include/lldb/Expression/Expression.h @@ -102,17 +102,11 @@ class Expression { /// /// The format being: /// -/// <prefix>:<mangled name>:<module uid>:<symbol uid> +/// <prefix>:<module uid>:<symbol uid>:<mangled name> /// /// The label string needs to stay valid for the entire lifetime /// of this object. struct FunctionCallLabel { - /// Name to use when searching for the function symbol in - /// \c module_id. For most function calls this will be a - /// mangled name. In cases where a mangled name can't be used, - /// this will be the function name. - llvm::StringRef lookup_name; - /// Unique identifier of the lldb_private::Module /// which contains the symbol identified by \c symbol_id. lldb::user_id_t module_id; @@ -122,6 +116,15 @@ struct FunctionCallLabel { /// be the DIE UID. lldb::user_id_t symbol_id; + /// Name to use when searching for the function symbol in + /// \c module_id. For most function calls this will be a + /// mangled name. In cases where a mangled name can't be used, + /// this will be the function name. + /// + /// NOTE: kept as last element so we don't have to worry about + /// ':' in the mangled name when parsing the label. + llvm::StringRef lookup_name; + /// Decodes the specified function \c label into a \c FunctionCallLabel. static llvm::Expected<FunctionCallLabel> fromString(llvm::StringRef label); @@ -129,7 +132,7 @@ struct FunctionCallLabel { /// /// The representation roundtrips through \c fromString: /// \code{.cpp} - /// llvm::StringRef encoded = "$__lldb_func:_Z3foov:0x0:0x0"; + /// llvm::StringRef encoded = "$__lldb_func:0x0:0x0:_Z3foov"; /// FunctionCallLabel label = *fromString(label); /// /// assert (label.toString() == encoded); @@ -142,13 +145,6 @@ struct FunctionCallLabel { /// from JITted expressions. inline constexpr llvm::StringRef FunctionCallLabelPrefix = "$__lldb_func"; -/// Returns the components of the specified function call label. -/// -/// The format of \c label is described in \c FunctionCallLabel. -/// The label prefix is not one of the components. -llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>> -splitFunctionCallLabel(llvm::StringRef label); - } // namespace lldb_private #endif // LLDB_EXPRESSION_EXPRESSION_H diff --git a/lldb/source/Expression/Expression.cpp b/lldb/source/Expression/Expression.cpp index 1ea18dce772ba..dc2d6bf520f05 100644 --- a/lldb/source/Expression/Expression.cpp +++ b/lldb/source/Expression/Expression.cpp @@ -31,8 +31,12 @@ Expression::Expression(ExecutionContextScope &exe_scope) assert(m_target_wp.lock()); } -llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>> -lldb_private::splitFunctionCallLabel(llvm::StringRef label) { +/// Returns the components of the specified function call label. +/// +/// The format of \c label is described in \c FunctionCallLabel. +/// The label prefix is not one of the components. +static llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>> +splitFunctionCallLabel(llvm::StringRef label) { if (!label.consume_front(FunctionCallLabelPrefix)) return llvm::createStringError( "expected function call label prefix not found in %s", label.data()); @@ -60,25 +64,26 @@ lldb_private::FunctionCallLabel::fromString(llvm::StringRef label) { const auto &components = *components_or_err; - llvm::StringRef module_label = components[1]; - llvm::StringRef die_label = components[2]; + llvm::StringRef module_label = components[0]; + llvm::StringRef die_label = components[1]; 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])); + llvm::formatv("failed to parse module ID from '{0}'.", components[0])); lldb::user_id_t die_id; if (die_label.consumeInteger(/*Radix=*/0, die_id)) return llvm::createStringError( - llvm::formatv("failed to parse DIE ID from '{0}'.", components[2])); + llvm::formatv("failed to parse DIE ID from '{0}'.", components[1])); - return FunctionCallLabel{/*.lookup_name=*/components[0], - /*.module_id=*/module_id, /*.symbol_id=*/die_id}; + return FunctionCallLabel{/*.module_id=*/module_id, + /*.symbol_id=*/die_id, + /*.lookup_name=*/components[2]}; } std::string lldb_private::FunctionCallLabel::toString() const { - return llvm::formatv("{0}:{1}:{2:x}:{3:x}", FunctionCallLabelPrefix, - lookup_name, module_id, symbol_id) + return llvm::formatv("{0}:{1:x}:{2:x}:{3}", FunctionCallLabelPrefix, + module_id, symbol_id, lookup_name) .str(); } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index 5cacc97039726..98c07f4a2b94f 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -267,9 +267,11 @@ static std::optional<std::string> MakeLLDBFuncAsmLabel(const DWARFDIE &die) { if (die_id == LLDB_INVALID_UID) return std::nullopt; - return FunctionCallLabel{/*.lookup_name=*/name, - /*module_id=*/module_id, - /*symbol_id=*/die_id} + return FunctionCallLabel{ + /*module_id=*/module_id, + /*symbol_id=*/die_id, + /*.lookup_name=*/name + } .toString(); } diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 2e9311bdd930c..84e3320ab70ba 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -9048,13 +9048,13 @@ ConstString TypeSystemClang::DeclGetName(void *opaque_decl) { static ConstString ExtractMangledNameFromFunctionCallLabel(llvm::StringRef label) { - auto components_or_err = splitFunctionCallLabel(label); - if (!components_or_err) { - llvm::consumeError(components_or_err.takeError()); + auto label_or_err = FunctionCallLabel::fromString(label); + if (!label_or_err) { + llvm::consumeError(label_or_err.takeError()); return {}; } - llvm::StringRef mangled = (*components_or_err)[0]; + llvm::StringRef mangled = label_or_err->lookup_name; if (Mangled::IsMangledName(mangled)) return ConstString(mangled); >From 1becf7dd7bdacb2d8a20ade83993c04a13d93e6d Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Mon, 28 Jul 2025 15:44:13 +0100 Subject: [PATCH 11/12] fixup! rebase on latest ModuleList changes --- lldb/source/Core/ModuleList.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp index e3dfa799ebb65..01f46b62b57bd 100644 --- a/lldb/source/Core/ModuleList.cpp +++ b/lldb/source/Core/ModuleList.cpp @@ -589,10 +589,10 @@ ModuleSP ModuleList::FindModule(lldb::user_id_t uid) const { ForEach([&](const ModuleSP &m) { if (m->GetID() == uid) { module_sp = m; - return true; + return IterationAction::Stop; } - return false; + return IterationAction::Continue; }); return module_sp; >From 9aec4ecbf291460d97270f18c6d8b79e11b91f7c Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Mon, 28 Jul 2025 15:44:54 +0100 Subject: [PATCH 12/12] fixup! remove mention of mangled name from FunctionCallLabel doc --- lldb/include/lldb/Expression/Expression.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/include/lldb/Expression/Expression.h b/lldb/include/lldb/Expression/Expression.h index 7dce9aa21e5d2..4dc74b13fa8f9 100644 --- a/lldb/include/lldb/Expression/Expression.h +++ b/lldb/include/lldb/Expression/Expression.h @@ -102,7 +102,7 @@ class Expression { /// /// The format being: /// -/// <prefix>:<module uid>:<symbol uid>:<mangled name> +/// <prefix>:<module uid>:<symbol uid>:<name> /// /// The label string needs to stay valid for the entire lifetime /// of this object. _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits