[Lldb-commits] [lldb] [lldb][Expression] Encode Module and DIE UIDs into function AsmLabels (PR #148877)
Michael Buch via lldb-commits
lldb-commits at lists.llvm.org
Wed Jul 30 04:54:43 PDT 2025
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 <michaelbuch12 at gmail.com>
Date: Fri, 15 Nov 2024 01:59:36 +0000
Subject: [PATCH 01/24] [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 <michaelbuch12 at gmail.com>
Date: Mon, 21 Jul 2025 12:15:24 +0100
Subject: [PATCH 02/24] 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 <michaelbuch12 at gmail.com>
Date: Mon, 28 Jul 2025 11:43:17 +0100
Subject: [PATCH 03/24] 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 <michaelbuch12 at gmail.com>
Date: Mon, 28 Jul 2025 12:02:49 +0100
Subject: [PATCH 04/24] 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 <michaelbuch12 at gmail.com>
Date: Mon, 28 Jul 2025 12:16:22 +0100
Subject: [PATCH 05/24] 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 <michaelbuch12 at gmail.com>
Date: Mon, 28 Jul 2025 12:29:44 +0100
Subject: [PATCH 06/24] 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 <michaelbuch12 at gmail.com>
Date: Mon, 28 Jul 2025 12:41:58 +0100
Subject: [PATCH 07/24] 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 <michaelbuch12 at gmail.com>
Date: Mon, 28 Jul 2025 12:54:20 +0100
Subject: [PATCH 08/24] 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 <michaelbuch12 at gmail.com>
Date: Mon, 28 Jul 2025 15:08:30 +0100
Subject: [PATCH 09/24] 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 <michaelbuch12 at gmail.com>
Date: Mon, 28 Jul 2025 15:25:16 +0100
Subject: [PATCH 10/24] 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 <michaelbuch12 at gmail.com>
Date: Mon, 28 Jul 2025 15:44:13 +0100
Subject: [PATCH 11/24] 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 <michaelbuch12 at gmail.com>
Date: Mon, 28 Jul 2025 15:44:54 +0100
Subject: [PATCH 12/24] 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.
>From d5bda43899a36441f135d25d657e807ab28158bb Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Mon, 28 Jul 2025 16:35:47 +0100
Subject: [PATCH 13/24] fixup! add format_provider for FunctionCallLabel
---
lldb/include/lldb/Expression/Expression.h | 8 ++++++++
lldb/source/Expression/Expression.cpp | 9 ++++++++-
2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/lldb/include/lldb/Expression/Expression.h b/lldb/include/lldb/Expression/Expression.h
index 4dc74b13fa8f9..a6c49bcc10ad0 100644
--- a/lldb/include/lldb/Expression/Expression.h
+++ b/lldb/include/lldb/Expression/Expression.h
@@ -13,6 +13,7 @@
#include <string>
#include <vector>
+#include "llvm/Support/FormatProviders.h"
#include "lldb/Expression/ExpressionTypeSystemHelper.h"
#include "lldb/lldb-forward.h"
@@ -147,4 +148,11 @@ inline constexpr llvm::StringRef FunctionCallLabelPrefix = "$__lldb_func";
} // namespace lldb_private
+namespace llvm {
+template <> struct format_provider<lldb_private::FunctionCallLabel> {
+ static void format(const lldb_private::FunctionCallLabel &label,
+ raw_ostream &OS, StringRef Style);
+};
+} // namespace llvm
+
#endif // LLDB_EXPRESSION_EXPRESSION_H
diff --git a/lldb/source/Expression/Expression.cpp b/lldb/source/Expression/Expression.cpp
index dc2d6bf520f05..251904fbc7dcb 100644
--- a/lldb/source/Expression/Expression.cpp
+++ b/lldb/source/Expression/Expression.cpp
@@ -10,8 +10,8 @@
#include "lldb/Target/ExecutionContextScope.h"
#include "lldb/Target/Target.h"
-#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
using namespace lldb_private;
@@ -87,3 +87,10 @@ std::string lldb_private::FunctionCallLabel::toString() const {
module_id, symbol_id, lookup_name)
.str();
}
+
+void llvm::format_provider<FunctionCallLabel>::format(
+ const FunctionCallLabel &label, raw_ostream &OS, StringRef Style) {
+ OS << llvm::formatv("FunctionCallLabel{ module_id: {0:x}, symbol_id: {1:x}, "
+ "lookup_name: {2} }",
+ label.module_id, label.symbol_id, label.lookup_name);
+}
>From 785e96a4ac2e2f08bf37a57f60fb43661d877490 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Mon, 28 Jul 2025 16:36:12 +0100
Subject: [PATCH 14/24] fixup! only do name lookup for declaration DIE cases
---
lldb/include/lldb/Symbol/SymbolFile.h | 12 ++--
lldb/source/Expression/IRExecutionUnit.cpp | 3 +-
.../SymbolFile/DWARF/SymbolFileDWARF.cpp | 61 +++++++++++--------
.../SymbolFile/DWARF/SymbolFileDWARF.h | 4 +-
4 files changed, 46 insertions(+), 34 deletions(-)
diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h
index 6aca276fc85b6..45798f667cb22 100644
--- a/lldb/include/lldb/Symbol/SymbolFile.h
+++ b/lldb/include/lldb/Symbol/SymbolFile.h
@@ -329,16 +329,18 @@ 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.
+ /// Resolves the function corresponding to the specified LLDB function
+ /// call \c label.
///
/// \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.
+ /// \param[in] label The FunctionCallLabel to be resolved.
///
- virtual llvm::Error FindAndResolveFunction(SymbolContextList &sc_list,
- llvm::StringRef lookup_name) {
+ /// \returns An llvm::Error if the specified \c label couldn't be resolved.
+ /// Returns \c llvm::ErrorSuccess otherwise.
+ virtual llvm::Error ResolveFunctionCallLabel(SymbolContextList &sc_list,
+ const FunctionCallLabel &label) {
return llvm::createStringError("Not implemented");
}
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp
index a1d8f30f373eb..ef119f6875870 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -811,8 +811,7 @@ ResolveFunctionCallLabel(llvm::StringRef name,
llvm::formatv("no SymbolFile found on module {0:x}.", module_sp.get()));
SymbolContextList sc_list;
- if (auto err =
- symbol_file->FindAndResolveFunction(sc_list, label.lookup_name))
+ if (auto err = symbol_file->ResolveFunctionCallLabel(sc_list, label))
return llvm::joinErrors(
llvm::createStringError("failed to resolve function by UID"),
std::move(err));
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index a1164646cbb29..a87126acfcc6a 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -2472,42 +2472,53 @@ bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die,
}
llvm::Error
-SymbolFileDWARF::FindAndResolveFunction(SymbolContextList &sc_list,
- llvm::StringRef lookup_name) {
+SymbolFileDWARF::ResolveFunctionCallLabel(SymbolContextList &sc_list,
+ const FunctionCallLabel &label) {
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
- DWARFDIE die;
- Module::LookupInfo info(ConstString(lookup_name), lldb::eFunctionNameTypeFull,
- lldb::eLanguageTypeUnknown);
+ DWARFDIE die = GetDIE(label.symbol_id);
+ if (!die.IsValid())
+ return llvm::createStringError(
+ llvm::formatv("invalid DIE ID in {0}", label));
- m_index->GetFunctions(info, *this, {}, [&](DWARFDIE entry) {
- if (entry.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0))
- return true;
+ // Label was created using a declaration DIE. Need to fetch the definition
+ // to resolve the function call.
+ if (die.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0)) {
+ Module::LookupInfo info(ConstString(label.lookup_name),
+ lldb::eFunctionNameTypeFull,
+ lldb::eLanguageTypeUnknown);
- // 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;
- });
+ m_index->GetFunctions(info, *this, {}, [&](DWARFDIE entry) {
+ if (entry.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0))
+ return true;
- if (!die.IsValid())
- return llvm::createStringError(
- llvm::formatv("failed to find definition DIE for '{0}'", lookup_name));
+ // 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 (!ResolveFunction(die, false, sc_list))
- return llvm::createStringError("failed to resolve function DIE");
+ if (die.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0))
+ return llvm::createStringError(
+ llvm::formatv("failed to find definition DIE for {0}", label));
+ }
+
+ if (!ResolveFunction(die, /*include_inlines=*/false, sc_list))
+ return llvm::createStringError(
+ llvm::formatv("failed to resolve function for {0}", label));
if (sc_list.IsEmpty())
- return llvm::createStringError("no definition DIE found");
+ return llvm::createStringError(
+ llvm::formatv("failed to find function for {0}", label));
if (sc_list.GetSize() > 1)
return llvm::createStringError(
- "found %d functions for %s but expected only 1", sc_list.GetSize(),
- lookup_name.data());
+ llvm::formatv("found {0} functions for {1} but expected only 1",
+ sc_list.GetSize(), label));
return llvm::Error::success();
}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index ee966366d3f2b..bf83eb332a8c3 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -434,8 +434,8 @@ class SymbolFileDWARF : public SymbolFileCommon {
DIEArray MergeBlockAbstractParameters(const DWARFDIE &block_die,
DIEArray &&variable_dies);
- llvm::Error FindAndResolveFunction(SymbolContextList &sc_list,
- llvm::StringRef lookup_name) override;
+ llvm::Error ResolveFunctionCallLabel(SymbolContextList &sc_list,
+ const FunctionCallLabel &label) override;
// Given a die_offset, figure out the symbol context representing that die.
bool ResolveFunction(const DWARFDIE &die, bool include_inlines,
>From 609af2af3ff28db879ea5024c8d4168a07e28cdc Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Tue, 29 Jul 2025 12:08:45 +0100
Subject: [PATCH 15/24] fixup! add tests; account for ':' in mangled name;
adjust error messages
---
lldb/source/Expression/Expression.cpp | 25 ++--
.../SymbolFile/DWARF/DWARFASTParserClang.cpp | 10 +-
lldb/unittests/Expression/CMakeLists.txt | 1 +
lldb/unittests/Expression/ExpressionTest.cpp | 109 ++++++++++++++++++
4 files changed, 135 insertions(+), 10 deletions(-)
create mode 100644 lldb/unittests/Expression/ExpressionTest.cpp
diff --git a/lldb/source/Expression/Expression.cpp b/lldb/source/Expression/Expression.cpp
index 251904fbc7dcb..a57bcbe97e117 100644
--- a/lldb/source/Expression/Expression.cpp
+++ b/lldb/source/Expression/Expression.cpp
@@ -39,17 +39,23 @@ 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());
+ "expected function call label prefix not found.");
if (!label.consume_front(":"))
return llvm::createStringError(
- "incorrect format: expected ':' as the first character.");
+ "expected ':' as the first character after prefix.");
- llvm::SmallVector<llvm::StringRef, 3> components;
- label.split(components, ":");
+ auto sep1 = label.find_first_of(":");
+ if (sep1 == llvm::StringRef::npos)
+ return llvm::createStringError("no ':' separator found.");
- if (components.size() != 3)
- return llvm::createStringError(
- "incorrect format: too many label subcomponents.");
+ auto sep2 = label.find_first_of(":", sep1 + 1);
+ if (sep2 == llvm::StringRef::npos)
+ return llvm::createStringError("only single ':' separator found.");
+
+ llvm::SmallVector<llvm::StringRef, 3> components;
+ components.push_back(label.slice(0, sep1));
+ components.push_back(label.slice(sep1 + 1, sep2));
+ components.push_back(label.slice(sep2 + 1, llvm::StringRef::npos));
return components;
}
@@ -59,7 +65,8 @@ lldb_private::FunctionCallLabel::fromString(llvm::StringRef label) {
auto components_or_err = splitFunctionCallLabel(label);
if (!components_or_err)
return llvm::joinErrors(
- llvm::createStringError("Failed to decode function call label"),
+ llvm::createStringError("failed to split function call label '%s'",
+ label.data()),
components_or_err.takeError());
const auto &components = *components_or_err;
@@ -75,7 +82,7 @@ lldb_private::FunctionCallLabel::fromString(llvm::StringRef label) {
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[1]));
+ llvm::formatv("failed to parse symbol ID from '{0}'.", components[1]));
return FunctionCallLabel{/*.module_id=*/module_id,
/*.symbol_id=*/die_id,
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 98c07f4a2b94f..c92d95e2b18da 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -255,7 +255,15 @@ static std::optional<std::string> MakeLLDBFuncAsmLabel(const DWARFDIE &die) {
if (!name)
return std::nullopt;
- auto module_sp = die.GetModule();
+ SymbolFileDWARF *dwarf = die.GetDWARF();
+ if (!dwarf)
+ return std::nullopt;
+
+ ObjectFile *main_obj = dwarf->GetMainObjectFile();
+ if (!main_obj)
+ return std::nullopt;
+
+ auto module_sp = main_obj->GetModule();
if (!module_sp)
return std::nullopt;
diff --git a/lldb/unittests/Expression/CMakeLists.txt b/lldb/unittests/Expression/CMakeLists.txt
index 185b19f84cae7..3970f5ab7e5d9 100644
--- a/lldb/unittests/Expression/CMakeLists.txt
+++ b/lldb/unittests/Expression/CMakeLists.txt
@@ -4,6 +4,7 @@ add_lldb_unittest(ExpressionTests
DiagnosticManagerTest.cpp
DWARFExpressionTest.cpp
CppModuleConfigurationTest.cpp
+ ExpressionTest.cpp
LINK_LIBS
lldbCore
diff --git a/lldb/unittests/Expression/ExpressionTest.cpp b/lldb/unittests/Expression/ExpressionTest.cpp
new file mode 100644
index 0000000000000..542ce5005d7d9
--- /dev/null
+++ b/lldb/unittests/Expression/ExpressionTest.cpp
@@ -0,0 +1,109 @@
+//===-- ExpressionTest.cpp ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include "TestingSupport/TestUtilities.h"
+#include "lldb/Expression/Expression.h"
+#include "llvm/Testing/Support/Error.h"
+
+using namespace lldb_private;
+
+struct LabelTestCase {
+ llvm::StringRef encoded;
+ FunctionCallLabel label;
+ llvm::SmallVector<llvm::StringRef> error_pattern;
+};
+
+static LabelTestCase g_label_test_cases[] = {
+ // Failure modes
+ {"0x0:0x0:_Z3foov",
+ {},
+ {"failed to split function call label '0x0:0x0:_Z3foov'",
+ "expected function call label prefix not found."}},
+ {"$__lldb_func0x0:0x0:_Z3foov",
+ {},
+ {"failed to split function call label '$__lldb_func0x0:0x0:_Z3foov'",
+ "expected ':' as the first character after prefix."}},
+ {"$__lldb_func:",
+ {},
+ {"failed to split function call label '$__lldb_func:'",
+ "no ':' separator found."}},
+ {"$__lldb_func:0x0:0x0",
+ {},
+ {"failed to split function call label '$__lldb_func:0x0:0x0'",
+ "only single ':' separator found."}},
+ {"$__lldb_func:abc:0x0:_Z3foov",
+ {},
+ {"failed to parse module ID from 'abc'."}},
+ {"$__lldb_func:-1:0x0:_Z3foov",
+ {},
+ {"failed to parse module ID from '-1'."}},
+ {"$__lldb_func:0x0:abc:_Z3foov",
+ {},
+ {"failed to parse symbol ID from 'abc'."}},
+ {"$__lldb_func:0x5:-1:_Z3foov",
+ {},
+ {"failed to parse symbol ID from '-1'."}},
+ {"$__lldb_func:0x0:0x0:_Z3foov",
+ {
+ /*.module_id=*/0x0,
+ /*.symbol_id=*/0x0,
+ /*.lookup_name=*/"_Z3foov",
+ },
+ {}},
+ {"$__lldb_func:0x0:0x0:abc:def:::a",
+ {
+ /*.module_id=*/0x0,
+ /*.symbol_id=*/0x0,
+ /*.lookup_name=*/"abc:def:::a",
+ },
+ {}},
+ {"$__lldb_func:0xd2:0xf0:$__lldb_func",
+ {
+ /*.module_id=*/0xd2,
+ /*.symbol_id=*/0xf0,
+ /*.lookup_name=*/"$__lldb_func",
+ },
+ {}},
+};
+
+struct ExpressionTestFixture : public testing::TestWithParam<LabelTestCase> {};
+
+TEST_P(ExpressionTestFixture, FunctionCallLabel) {
+ const auto &[encoded, label, errors] = GetParam();
+
+ auto decoded_or_err = FunctionCallLabel::fromString(encoded);
+ if (!errors.empty()) {
+ EXPECT_THAT_EXPECTED(
+ decoded_or_err,
+ llvm::FailedWithMessageArray(testing::ElementsAreArray(errors)));
+ return;
+ }
+
+ EXPECT_THAT_EXPECTED(decoded_or_err, llvm::Succeeded());
+
+ auto label_str = label.toString();
+ EXPECT_EQ(decoded_or_err->toString(), encoded);
+ EXPECT_EQ(label_str, encoded);
+
+ EXPECT_EQ(decoded_or_err->module_id, label.module_id);
+ EXPECT_EQ(decoded_or_err->symbol_id, label.symbol_id);
+ EXPECT_EQ(decoded_or_err->lookup_name, label.lookup_name);
+
+ auto roundtrip_or_err = FunctionCallLabel::fromString(label_str);
+ EXPECT_THAT_EXPECTED(roundtrip_or_err, llvm::Succeeded());
+
+ EXPECT_EQ(roundtrip_or_err->module_id, label.module_id);
+ EXPECT_EQ(roundtrip_or_err->symbol_id, label.symbol_id);
+ EXPECT_EQ(roundtrip_or_err->lookup_name, label.lookup_name);
+}
+
+INSTANTIATE_TEST_SUITE_P(FunctionCallLabelTest, ExpressionTestFixture,
+ testing::ValuesIn(g_label_test_cases));
>From fc60861e1b020cf91ff8a37e0a2cdc3658e2299c Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 10:11:05 +0100
Subject: [PATCH 16/24] fixup! drop \01 mangling prefix when searching using IR
function name
---
lldb/source/Expression/IRInterpreter.cpp | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/lldb/source/Expression/IRInterpreter.cpp b/lldb/source/Expression/IRInterpreter.cpp
index fa74e8828a574..91404831aeb9b 100644
--- a/lldb/source/Expression/IRInterpreter.cpp
+++ b/lldb/source/Expression/IRInterpreter.cpp
@@ -259,7 +259,9 @@ class InterpreterStackFrame {
break;
case Value::FunctionVal:
if (const Function *constant_func = dyn_cast<Function>(constant)) {
- lldb_private::ConstString name(constant_func->getName());
+ lldb_private::ConstString name(
+ llvm::GlobalValue::dropLLVMManglingEscape(
+ constant_func->getName()));
bool missing_weak = false;
lldb::addr_t addr = m_execution_unit.FindSymbol(name, missing_weak);
if (addr == LLDB_INVALID_ADDRESS)
>From dd9a69cdf324b8470aa8a3470655924084e05e0e Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 10:13:44 +0100
Subject: [PATCH 17/24] fixup! search .o files when searching for module by UID
---
lldb/include/lldb/Core/ModuleList.h | 8 ------
lldb/source/Core/ModuleList.cpp | 14 ---------
lldb/source/Expression/IRExecutionUnit.cpp | 33 ++++++++++++++++++++--
3 files changed, 31 insertions(+), 24 deletions(-)
diff --git a/lldb/include/lldb/Core/ModuleList.h b/lldb/include/lldb/Core/ModuleList.h
index 6ecdcf10fa85f..d5e291f3380a8 100644
--- a/lldb/include/lldb/Core/ModuleList.h
+++ b/lldb/include/lldb/Core/ModuleList.h
@@ -352,14 +352,6 @@ 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/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp
index 01f46b62b57bd..d2e5be8c79b17 100644
--- a/lldb/source/Core/ModuleList.cpp
+++ b/lldb/source/Core/ModuleList.cpp
@@ -584,20 +584,6 @@ 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 IterationAction::Stop;
- }
-
- return IterationAction::Continue;
- });
-
- 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 ef119f6875870..128e1beb76991 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -774,6 +774,36 @@ class LoadAddressResolver {
lldb::addr_t m_best_internal_load_address = LLDB_INVALID_ADDRESS;
};
+/// 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.
+static lldb::ModuleSP FindDebugModule(lldb::user_id_t uid,
+ const ModuleList &modules) {
+ lldb::ModuleSP module_sp;
+ modules.ForEach([&](const lldb::ModuleSP &m) {
+ if (m->GetID() == uid) {
+ module_sp = m;
+ return IterationAction::Stop;
+ }
+
+ auto *sym = m->GetSymbolFile();
+ if (!sym)
+ return IterationAction::Continue;
+
+ auto debug_modules = sym->GetDebugInfoModules();
+ module_sp = FindDebugModule(uid, debug_modules);
+ if (module_sp)
+ return IterationAction::Stop;
+
+ return IterationAction::Continue;
+ });
+
+ return module_sp;
+}
+
/// Returns address of the function referred to by the special function call
/// label \c label.
///
@@ -799,8 +829,7 @@ ResolveFunctionCallLabel(llvm::StringRef name,
const auto &label = *label_or_err;
- auto module_sp = sc.target_sp->GetImages().FindModule(label.module_id);
-
+ auto module_sp = FindDebugModule(label.module_id, sc.target_sp->GetImages());
if (!module_sp)
return llvm::createStringError(
llvm::formatv("failed to find module by UID {0}", label.module_id));
>From 3256170dab1eabc9871020af81220458e417706a Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 10:15:14 +0100
Subject: [PATCH 18/24] fixup! revert whitespace change
---
lldb/include/lldb/Symbol/TypeSystem.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/lldb/include/lldb/Symbol/TypeSystem.h b/lldb/include/lldb/Symbol/TypeSystem.h
index 40bd59056a5df..cb1f0130b548d 100644
--- a/lldb/include/lldb/Symbol/TypeSystem.h
+++ b/lldb/include/lldb/Symbol/TypeSystem.h
@@ -548,7 +548,6 @@ class TypeSystem : public PluginInterface,
bool GetHasForcefullyCompletedTypes() const {
return m_has_forcefully_completed_types;
}
-
protected:
SymbolFile *m_sym_file = nullptr;
/// Used for reporting statistics.
>From 632508f708da918a673bfba6868cf969ed029390 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 10:26:42 +0100
Subject: [PATCH 19/24] fixup! remove stale comment
---
lldb/source/Expression/IRExecutionUnit.cpp | 2 --
1 file changed, 2 deletions(-)
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp
index 128e1beb76991..448a3cb649c0d 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -809,8 +809,6 @@ static lldb::ModuleSP FindDebugModule(lldb::user_id_t uid,
///
/// \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,
>From 0721cf8de7ee2363d9e070b052980315ba3f5a82 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 11:50:23 +0100
Subject: [PATCH 20/24] fixup! implement
SymbolFileDWARFDebugMap::ResolveFunctionCallLabel
---
lldb/include/lldb/Core/ModuleList.h | 8 +++++++
lldb/source/Core/ModuleList.cpp | 14 +++++++++++
lldb/source/Expression/IRExecutionUnit.cpp | 2 +-
.../SymbolFile/DWARF/DWARFASTParserClang.cpp | 24 +++++++++++++------
.../DWARF/SymbolFileDWARFDebugMap.cpp | 11 +++++++++
.../DWARF/SymbolFileDWARFDebugMap.h | 3 +++
6 files changed, 54 insertions(+), 8 deletions(-)
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/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp
index d2e5be8c79b17..01f46b62b57bd 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 IterationAction::Stop;
+ }
+
+ return IterationAction::Continue;
+ });
+
+ 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 448a3cb649c0d..90d087553b35b 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -827,7 +827,7 @@ ResolveFunctionCallLabel(llvm::StringRef name,
const auto &label = *label_or_err;
- auto module_sp = FindDebugModule(label.module_id, sc.target_sp->GetImages());
+ 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.module_id));
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index c92d95e2b18da..3e48c41cb934e 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -259,15 +259,25 @@ static std::optional<std::string> MakeLLDBFuncAsmLabel(const DWARFDIE &die) {
if (!dwarf)
return std::nullopt;
- ObjectFile *main_obj = dwarf->GetMainObjectFile();
- if (!main_obj)
- return std::nullopt;
+ auto get_module_id = [&](SymbolFile *sym) {
+ if (!sym)
+ return LLDB_INVALID_UID;
- auto module_sp = main_obj->GetModule();
- if (!module_sp)
- return std::nullopt;
+ auto *obj = sym->GetMainObjectFile();
+ if (!obj)
+ return LLDB_INVALID_UID;
+
+ auto module_sp = obj->GetModule();
+ if (!module_sp)
+ return LLDB_INVALID_UID;
+
+ return module_sp->GetID();
+ };
+
+ lldb::user_id_t module_id = get_module_id(dwarf->GetDebugMapSymfile());
+ if (module_id == LLDB_INVALID_UID)
+ module_id = get_module_id(dwarf);
- lldb::user_id_t module_id = module_sp->GetID();
if (module_id == LLDB_INVALID_UID)
return std::nullopt;
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
index dd94f0b36f2b2..b532e4d8c83e1 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
@@ -1602,3 +1602,14 @@ void SymbolFileDWARFDebugMap::GetCompileOptions(
return IterationAction::Continue;
});
}
+
+llvm::Error SymbolFileDWARFDebugMap::ResolveFunctionCallLabel(
+ SymbolContextList &sc_list, const FunctionCallLabel &label) {
+ const uint64_t oso_idx = GetOSOIndexFromUserID(label.symbol_id);
+ SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex(oso_idx);
+ if (!oso_dwarf)
+ return llvm::createStringError(llvm::formatv(
+ "couldn't find symbol file for {0} in debug-map.", label));
+
+ return oso_dwarf->ResolveFunctionCallLabel(sc_list, label);
+}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
index f074b17082e62..31a2889cf3ff6 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
@@ -144,6 +144,9 @@ class SymbolFileDWARFDebugMap : public SymbolFileCommon {
void
GetCompileOptions(std::unordered_map<lldb::CompUnitSP, Args> &args) override;
+ llvm::Error ResolveFunctionCallLabel(SymbolContextList &sc_list,
+ const FunctionCallLabel &label) override;
+
protected:
enum { kHaveInitializedOSOs = (1 << 0), kNumFlags };
>From a9cae489b7cb6d006335f011d249f95593f9479e Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 12:38:48 +0100
Subject: [PATCH 21/24] fixup! add test for when definition is in different
Module than declaration
---
.../cpp/expr-definition-in-dylib/Makefile | 6 ++++++
.../TestExprDefinitionInDylib.py | 19 +++++++++++++++++++
.../lang/cpp/expr-definition-in-dylib/lib.cpp | 5 +++++
.../lang/cpp/expr-definition-in-dylib/lib.h | 8 ++++++++
.../cpp/expr-definition-in-dylib/main.cpp | 6 ++++++
5 files changed, 44 insertions(+)
create mode 100644 lldb/test/API/lang/cpp/expr-definition-in-dylib/Makefile
create mode 100644 lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py
create mode 100644 lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.cpp
create mode 100644 lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.h
create mode 100644 lldb/test/API/lang/cpp/expr-definition-in-dylib/main.cpp
diff --git a/lldb/test/API/lang/cpp/expr-definition-in-dylib/Makefile b/lldb/test/API/lang/cpp/expr-definition-in-dylib/Makefile
new file mode 100644
index 0000000000000..82daeb1dd3f90
--- /dev/null
+++ b/lldb/test/API/lang/cpp/expr-definition-in-dylib/Makefile
@@ -0,0 +1,6 @@
+CXX_SOURCES := main.cpp
+
+DYLIB_CXX_SOURCES := lib.cpp
+DYLIB_NAME := lib
+
+include Makefile.rules
diff --git a/lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py b/lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py
new file mode 100644
index 0000000000000..3a89eb01b3932
--- /dev/null
+++ b/lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py
@@ -0,0 +1,19 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class ExprDefinitionInDylibTestCase(TestBase):
+ def test(self):
+ """
+ Tests that we can call functions whose definition
+ is in a different LLDB module than it's declaration.
+ """
+ self.build()
+
+ lldbutil.run_to_source_breakpoint(
+ self, "return", lldb.SBFileSpec("main.cpp")
+ )
+
+ self.expect_expr("f.method()", result_value="-72", result_type="int")
diff --git a/lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.cpp b/lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.cpp
new file mode 100644
index 0000000000000..c4336d7b69be4
--- /dev/null
+++ b/lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.cpp
@@ -0,0 +1,5 @@
+#include "lib.h"
+
+int Foo::method() {
+ return -72;
+}
diff --git a/lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.h b/lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.h
new file mode 100644
index 0000000000000..9568db2166ec4
--- /dev/null
+++ b/lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.h
@@ -0,0 +1,8 @@
+#ifndef LIB_H_IN
+#define LIB_H_IN
+
+struct Foo {
+ int method();
+};
+
+#endif // LIB_H_IN
diff --git a/lldb/test/API/lang/cpp/expr-definition-in-dylib/main.cpp b/lldb/test/API/lang/cpp/expr-definition-in-dylib/main.cpp
new file mode 100644
index 0000000000000..2fddb2b7b3e74
--- /dev/null
+++ b/lldb/test/API/lang/cpp/expr-definition-in-dylib/main.cpp
@@ -0,0 +1,6 @@
+#include "lib.h"
+
+int main() {
+ Foo f;
+ return f.method();
+}
>From e614a8ed06c5153dad737962b677853c37870609 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 12:39:07 +0100
Subject: [PATCH 22/24] fixup! clang-format
---
lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.cpp | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.cpp b/lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.cpp
index c4336d7b69be4..ad148cebb00d1 100644
--- a/lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.cpp
+++ b/lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.cpp
@@ -1,5 +1,3 @@
#include "lib.h"
-int Foo::method() {
- return -72;
-}
+int Foo::method() { return -72; }
>From 124c342484d16956a31d87612e82a04750523743 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 12:51:45 +0100
Subject: [PATCH 23/24] fixup! python format
---
.../cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py b/lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py
index 3a89eb01b3932..13480001dd82f 100644
--- a/lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py
+++ b/lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py
@@ -12,8 +12,6 @@ def test(self):
"""
self.build()
- lldbutil.run_to_source_breakpoint(
- self, "return", lldb.SBFileSpec("main.cpp")
- )
+ lldbutil.run_to_source_breakpoint(self, "return", lldb.SBFileSpec("main.cpp"))
self.expect_expr("f.method()", result_value="-72", result_type="int")
>From b1af3dd06c0bc47916c1a46caee7bec46f07ad9f Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 12:54:00 +0100
Subject: [PATCH 24/24] fixup! clang-format
---
.../Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 3e48c41cb934e..897bd2276bc8f 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -285,11 +285,9 @@ static std::optional<std::string> MakeLLDBFuncAsmLabel(const DWARFDIE &die) {
if (die_id == LLDB_INVALID_UID)
return std::nullopt;
- return FunctionCallLabel{
- /*module_id=*/module_id,
- /*symbol_id=*/die_id,
- /*.lookup_name=*/name
- }
+ return FunctionCallLabel{/*module_id=*/module_id,
+ /*symbol_id=*/die_id,
+ /*.lookup_name=*/name}
.toString();
}
More information about the lldb-commits
mailing list