[clang] [libcxxabi] [lldb] [llvm] [DRAFT] [lldb][Expression] Add structor variant to LLDB's function call labels (PR #149827)
Michael Buch via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 31 06:20:21 PDT 2025
https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/149827
>From 87a26cef46aace78ac5901861478a3b7ca19a384 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/36] [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 +++++++++++++++++++
.../SymbolFile/DWARF/DWARFASTParserClang.cpp | 21 +++++-
.../SymbolFile/DWARF/SymbolFileDWARF.cpp | 41 ++++++++++
.../SymbolFile/DWARF/SymbolFileDWARF.h | 3 +
.../TypeSystem/Clang/TypeSystemClang.cpp | 56 ++++++++++++++
.../TypeSystem/Clang/TypeSystemClang.h | 6 ++
lldb/unittests/Symbol/TestTypeSystemClang.cpp | 24 ++++++
13 files changed, 312 insertions(+), 7 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/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index e58e28a260ab0..6bf3b91c900c9 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,12 +250,26 @@ static unsigned GetCXXMethodCVQuals(const DWARFDIE &subprogram,
return cv_quals;
}
-static std::string MakeLLDBFuncAsmLabel(const DWARFDIE &die) {
+static std::optional<std::string> MakeLLDBFuncAsmLabel(const DWARFDIE &die) {
char const *name = die.GetMangledName(/*substitute_name_allowed*/ false);
if (!name)
- return {};
+ return std::nullopt;
- return name;
+ 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,
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 41ab8d1b75b34..552a675c833c7 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -2475,6 +2475,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 56d8ccbd97e46..94463fa2dc2e3 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -436,6 +436,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/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 836f9feebb27a..3d33c9728b8af 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"
@@ -9055,6 +9056,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)) {
@@ -9777,3 +9785,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 de66bb68c6a4c..4e92a452af815 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -1098,6 +1098,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 57857676c7df9..228ee2ed9b6ea 100644
--- a/lldb/unittests/Symbol/TestTypeSystemClang.cpp
+++ b/lldb/unittests/Symbol/TestTypeSystemClang.cpp
@@ -869,7 +869,11 @@ 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,
+<<<<<<< HEAD
false, /*asm_label=*/{});
+=======
+ false, std::nullopt);
+>>>>>>> 382395408c4b ([lldb][Expression] Encode Module and DIE UIDs into function AsmLabels)
TypeSystemClang::TemplateParameterInfos empty_params;
// Create the actual function template.
@@ -900,7 +904,11 @@ 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,
+<<<<<<< HEAD
false, /*asm_label=*/{});
+=======
+ false, std::nullopt);
+>>>>>>> 382395408c4b ([lldb][Expression] Encode Module and DIE UIDs into function AsmLabels)
TypeSystemClang::TemplateParameterInfos empty_params;
// Create the actual function template.
@@ -938,7 +946,11 @@ TEST_F(TestTypeSystemClang, TestDeletingImplicitCopyCstrDueToMoveCStr) {
bool is_attr_used = false;
bool is_artificial = false;
m_ast->AddMethodToCXXRecordType(
+<<<<<<< HEAD
t.GetOpaqueQualType(), class_name, /*asm_label=*/{}, function_type,
+=======
+ t.GetOpaqueQualType(), class_name, std::nullopt, function_type,
+>>>>>>> 382395408c4b ([lldb][Expression] Encode Module and DIE UIDs into function AsmLabels)
lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline,
is_explicit, is_attr_used, is_artificial);
@@ -975,7 +987,11 @@ TEST_F(TestTypeSystemClang, TestNotDeletingUserCopyCstrDueToMoveCStr) {
CompilerType function_type = m_ast->CreateFunctionType(
return_type, args, /*variadic=*/false, /*quals*/ 0U);
m_ast->AddMethodToCXXRecordType(
+<<<<<<< HEAD
t.GetOpaqueQualType(), class_name, /*asm_label=*/{}, function_type,
+=======
+ t.GetOpaqueQualType(), class_name, std::nullopt, function_type,
+>>>>>>> 382395408c4b ([lldb][Expression] Encode Module and DIE UIDs into function AsmLabels)
lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline,
is_explicit, is_attr_used, is_artificial);
}
@@ -987,7 +1003,11 @@ TEST_F(TestTypeSystemClang, TestNotDeletingUserCopyCstrDueToMoveCStr) {
m_ast->CreateFunctionType(return_type, args,
/*variadic=*/false, /*quals*/ 0U);
m_ast->AddMethodToCXXRecordType(
+<<<<<<< HEAD
t.GetOpaqueQualType(), class_name, /*asm_label=*/{}, function_type,
+=======
+ t.GetOpaqueQualType(), class_name, std::nullopt, function_type,
+>>>>>>> 382395408c4b ([lldb][Expression] Encode Module and DIE UIDs into function AsmLabels)
lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline,
is_explicit, is_attr_used, is_artificial);
}
@@ -1098,7 +1118,11 @@ TEST_F(TestTypeSystemClang, AddMethodToCXXRecordType_ParmVarDecls) {
m_ast->CreateFunctionType(return_type, param_types,
/*variadic=*/false, /*quals*/ 0U);
m_ast->AddMethodToCXXRecordType(
+<<<<<<< HEAD
t.GetOpaqueQualType(), "myFunc", /*asm_label=*/{}, function_type,
+=======
+ t.GetOpaqueQualType(), "myFunc", std::nullopt, function_type,
+>>>>>>> 382395408c4b ([lldb][Expression] Encode Module and DIE UIDs into function AsmLabels)
lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline,
is_explicit, is_attr_used, is_artificial);
>From 818cf2287f8f7ef79af92de8d955ed1397e7ca74 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/36] 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 53a43aaf5b83b9416af2f2a6bb5960e2e499b4f9 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/36] 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 | 2 +-
4 files changed, 2 insertions(+), 17 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 3d33c9728b8af..94beb4af97335 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -9790,7 +9790,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 5078c8523e1a20189e53b9ed1dbc6d7b08032c0d 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/36] 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 6741c7b4d27ce82f589b828916e033943515093f 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/36] 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 94beb4af97335..cf6cc2053f8ed 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -9786,8 +9786,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))
@@ -9830,6 +9828,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 96cbb48bfe43b22e0002d99243666fb77b265750 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/36] 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 65f8706b5a9d68f1f33508340c4204c86bd45391 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/36] 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 cf6cc2053f8ed..c81a8b8651c41 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -9056,6 +9056,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]);
@@ -9785,49 +9787,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 4e92a452af815..de66bb68c6a4c 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -1098,12 +1098,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 3e27e98e94abeaa3bab948a899f688f15efbee27 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/36] 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 c81a8b8651c41..ad26e0f5d2cbf 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -9045,6 +9045,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));
@@ -9056,14 +9071,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 76ae694c1eeaceb956c3919efebc86cef524fc38 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/36] 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 6bf3b91c900c9..999632edbbbe8 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 1e6e9c012b7bd895c858ec71f029cece8755aae0 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/36] 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 999632edbbbe8..938d52f7d6b0b 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 ad26e0f5d2cbf..ab5f4138187ed 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -9047,13 +9047,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 73768e663f0cc09a08199f2ded1fcf4a79dc5209 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/36] 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 6eb12d95bf7b381078b713c24110d5fc5a1e39d1 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/36] 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 de9c994a8fbbcebfd9517007dcfa8b20b1273534 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/36] 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 308d33d4aacec2f5a5462b7c9fbfbd18e63504fd 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/36] 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 552a675c833c7..c0a74c871c68f 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -2476,42 +2476,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 94463fa2dc2e3..93b5b58ac0929 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -436,8 +436,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 7408359c4f7d22e23e03533177b147c5259deb8d 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/36] 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 938d52f7d6b0b..e76b599fd5f9c 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 533cdc673e6d1..4c58b3c5e3922 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 75c5cd01cfddac4a412391f9dcf1901a573fdd11 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/36] 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 cc7d462b4ab9c21918c09a3f95377bef4de91f68 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/36] 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 0ce95bd4c1c59b48fe11d3b3b62d71e9f6809897 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/36] 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 5789808305dd377a807fef5496d241059f8a2a3e 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/36] 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 6973ac27c406070a516b7788b8b59ac7465e6490 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/36] 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 e76b599fd5f9c..f1a8433842bab 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 e43310a51b8ac37cf0cb2bd8c92c25ae16a8a305 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/36] 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 e8146d7457ddd599f1326cafe33883a2c3bbc37b 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/36] 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 e4129ce205d6d397e461ee2c400c3649dbaaa6b7 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/36] 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 36b39a4483eb279367d50598547b1060472d0be4 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/36] 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 f1a8433842bab..4b386ac2093a7 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();
}
>From e882765006208691a0c8f233718ab5d1ae71b73e Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 13:09:41 +0100
Subject: [PATCH 25/36] fixup! mark test NO_DEBUG_INFO_TESTCASE
---
.../cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py | 2 ++
1 file changed, 2 insertions(+)
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 13480001dd82f..84559155f3c4b 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
@@ -5,6 +5,8 @@
class ExprDefinitionInDylibTestCase(TestBase):
+ NO_DEBUG_INFO_TESTCASE = True
+
def test(self):
"""
Tests that we can call functions whose definition
>From a8a98902ded0dbf0632855f0bf24d2ff70fb4fda Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 13:10:11 +0100
Subject: [PATCH 26/36] fixup! fallback to name lookup if definition is in
separate module from declaration
---
lldb/source/Expression/IRExecutionUnit.cpp | 35 +++++++++++-----------
1 file changed, 17 insertions(+), 18 deletions(-)
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp
index 90d087553b35b..cea5ca90d7315 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -806,11 +806,8 @@ static lldb::ModuleSP FindDebugModule(lldb::user_id_t uid,
/// 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.
static llvm::Expected<lldb::addr_t>
-ResolveFunctionCallLabel(llvm::StringRef name,
+ResolveFunctionCallLabel(const FunctionCallLabel &label,
const lldb_private::SymbolContext &sc,
bool &symbol_was_missing_weak) {
symbol_was_missing_weak = false;
@@ -818,15 +815,6 @@ ResolveFunctionCallLabel(llvm::StringRef name,
if (!sc.target_sp)
return llvm::createStringError("target not available.");
- auto label_or_err = FunctionCallLabel::fromString(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;
-
auto module_sp = sc.target_sp->GetImages().FindModule(label.module_id);
if (!module_sp)
return llvm::createStringError(
@@ -983,19 +971,30 @@ lldb::addr_t IRExecutionUnit::FindInUserDefinedSymbols(
lldb::addr_t IRExecutionUnit::FindSymbol(lldb_private::ConstString name,
bool &missing_weak) {
if (name.GetStringRef().starts_with(FunctionCallLabelPrefix)) {
- if (auto addr_or_err = ResolveFunctionCallLabel(name.GetStringRef(),
- m_sym_ctx, missing_weak)) {
+ auto label_or_err = FunctionCallLabel::fromString(name);
+ if (!label_or_err) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Expressions), label_or_err.takeError(),
+ "failed to create FunctionCallLabel from '{0}': {1}",
+ name.GetStringRef());
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ if (auto addr_or_err =
+ ResolveFunctionCallLabel(*label_or_err, 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;
+
+ // Fall back to lookup by name despite error in resolving the label.
+ // May happen in practice if the definition of a function lives in
+ // a different lldb_private::Module than it's declaration. Meaning
+ // we couldn't pin-point it using the information encoded in the label.
+ name.SetString(label_or_err->lookup_name);
}
}
- // TODO: do we still need the following lookups?
-
std::vector<ConstString> candidate_C_names;
std::vector<ConstString> candidate_CPlusPlus_names;
>From a5b2e26ba6d1af1d6a8c5787d3d05c093ac3cbf3 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 16:17:28 +0100
Subject: [PATCH 27/36] fixup! register dylib in test
Otherwise executable fails to launch on linux
---
.../TestExprDefinitionInDylib.py | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
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 84559155f3c4b..1eddd265eab93 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
@@ -14,6 +14,19 @@ def test(self):
"""
self.build()
- lldbutil.run_to_source_breakpoint(self, "return", lldb.SBFileSpec("main.cpp"))
+ target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
+ self.assertTrue(target, VALID_TARGET)
+
+ env = self.registerSharedLibrariesWithTarget(target, ["lib"])
+
+ breakpoint = lldbutil.run_break_set_by_file_and_line(
+ self, "main.cpp", line_number("main.cpp", "return")
+ )
+
+ process = target.LaunchSimple(None, env, self.get_process_working_directory())
+
+ self.assertIsNotNone(
+ lldbutil.get_one_thread_stopped_at_breakpoint_id(self.process(), breakpoint)
+ )
self.expect_expr("f.method()", result_value="-72", result_type="int")
>From 5aa13329d31fa5e1d16376b588578db188928099 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 15:34:01 +0100
Subject: [PATCH 28/36] fixup! fix typo
---
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 a6c49bcc10ad0..086aa1406a1c6 100644
--- a/lldb/include/lldb/Expression/Expression.h
+++ b/lldb/include/lldb/Expression/Expression.h
@@ -129,7 +129,7 @@ struct FunctionCallLabel {
/// 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.
+ /// Encode this FunctionCallLabel into its string representation.
///
/// The representation roundtrips through \c fromString:
/// \code{.cpp}
>From 98d2c4bd96cb181680ac7be6ff37adc030d45767 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 15:42:03 +0100
Subject: [PATCH 29/36] fixup! SymbolContextList -> SymbolContext
---
lldb/include/lldb/Symbol/SymbolFile.h | 9 +++------
lldb/source/Expression/IRExecutionUnit.cpp | 9 ++++++---
.../Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp | 13 +++++--------
.../Plugins/SymbolFile/DWARF/SymbolFileDWARF.h | 4 ++--
.../SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp | 6 +++---
.../SymbolFile/DWARF/SymbolFileDWARFDebugMap.h | 4 ++--
6 files changed, 21 insertions(+), 24 deletions(-)
diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h
index 45798f667cb22..bbc615d9fdc38 100644
--- a/lldb/include/lldb/Symbol/SymbolFile.h
+++ b/lldb/include/lldb/Symbol/SymbolFile.h
@@ -332,15 +332,12 @@ class SymbolFile : public PluginInterface {
/// 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] label The FunctionCallLabel to be resolved.
///
/// \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) {
+ /// Returns the resolved function (as a SymbolContext) otherwise.
+ virtual llvm::Expected<SymbolContext>
+ ResolveFunctionCallLabel(const FunctionCallLabel &label) {
return llvm::createStringError("Not implemented");
}
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp
index cea5ca90d7315..870b71eee3c7c 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -825,11 +825,14 @@ ResolveFunctionCallLabel(const FunctionCallLabel &label,
return llvm::createStringError(
llvm::formatv("no SymbolFile found on module {0:x}.", module_sp.get()));
- SymbolContextList sc_list;
- if (auto err = symbol_file->ResolveFunctionCallLabel(sc_list, label))
+ auto sc_or_err = symbol_file->ResolveFunctionCallLabel(label);
+ if (!sc_or_err)
return llvm::joinErrors(
llvm::createStringError("failed to resolve function by UID"),
- std::move(err));
+ sc_or_err.takeError());
+
+ SymbolContextList sc_list;
+ sc_list.Append(*sc_or_err);
LoadAddressResolver resolver(*sc.target_sp, symbol_was_missing_weak);
return resolver.Resolve(sc_list).value_or(LLDB_INVALID_ADDRESS);
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index c0a74c871c68f..874fbf7c160b8 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -2475,9 +2475,8 @@ bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die,
return false;
}
-llvm::Error
-SymbolFileDWARF::ResolveFunctionCallLabel(SymbolContextList &sc_list,
- const FunctionCallLabel &label) {
+llvm::Expected<SymbolContext>
+SymbolFileDWARF::ResolveFunctionCallLabel(const FunctionCallLabel &label) {
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
DWARFDIE die = GetDIE(label.symbol_id);
@@ -2511,6 +2510,7 @@ SymbolFileDWARF::ResolveFunctionCallLabel(SymbolContextList &sc_list,
llvm::formatv("failed to find definition DIE for {0}", label));
}
+ SymbolContextList sc_list;
if (!ResolveFunction(die, /*include_inlines=*/false, sc_list))
return llvm::createStringError(
llvm::formatv("failed to resolve function for {0}", label));
@@ -2519,12 +2519,9 @@ SymbolFileDWARF::ResolveFunctionCallLabel(SymbolContextList &sc_list,
return llvm::createStringError(
llvm::formatv("failed to find function for {0}", label));
- if (sc_list.GetSize() > 1)
- return llvm::createStringError(
- llvm::formatv("found {0} functions for {1} but expected only 1",
- sc_list.GetSize(), label));
+ assert(sc_list.GetSize() == 1);
- return llvm::Error::success();
+ return sc_list[0];
}
bool SymbolFileDWARF::DIEInDeclContext(const CompilerDeclContext &decl_ctx,
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index 93b5b58ac0929..3ec538da8cf77 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -436,8 +436,8 @@ class SymbolFileDWARF : public SymbolFileCommon {
DIEArray MergeBlockAbstractParameters(const DWARFDIE &block_die,
DIEArray &&variable_dies);
- llvm::Error ResolveFunctionCallLabel(SymbolContextList &sc_list,
- const FunctionCallLabel &label) override;
+ llvm::Expected<SymbolContext>
+ ResolveFunctionCallLabel(const FunctionCallLabel &label) override;
// Given a die_offset, figure out the symbol context representing that die.
bool ResolveFunction(const DWARFDIE &die, bool include_inlines,
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
index b532e4d8c83e1..9d7452a1988fa 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
@@ -1603,13 +1603,13 @@ void SymbolFileDWARFDebugMap::GetCompileOptions(
});
}
-llvm::Error SymbolFileDWARFDebugMap::ResolveFunctionCallLabel(
- SymbolContextList &sc_list, const FunctionCallLabel &label) {
+llvm::Expected<SymbolContext> SymbolFileDWARFDebugMap::ResolveFunctionCallLabel(
+ 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);
+ return oso_dwarf->ResolveFunctionCallLabel(label);
}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
index 31a2889cf3ff6..e1f1df23951c6 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
@@ -144,8 +144,8 @@ class SymbolFileDWARFDebugMap : public SymbolFileCommon {
void
GetCompileOptions(std::unordered_map<lldb::CompUnitSP, Args> &args) override;
- llvm::Error ResolveFunctionCallLabel(SymbolContextList &sc_list,
- const FunctionCallLabel &label) override;
+ llvm::Expected<SymbolContext>
+ ResolveFunctionCallLabel(const FunctionCallLabel &label) override;
protected:
enum { kHaveInitializedOSOs = (1 << 0), kNumFlags };
>From 2a0b79940994fd0ec85e352625b944b6bc611736 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 16:16:33 +0100
Subject: [PATCH 30/36] fixup! simplify label parsing
---
lldb/source/Expression/Expression.cpp | 60 ++++++--------------
lldb/unittests/Expression/ExpressionTest.cpp | 39 ++++++++-----
2 files changed, 43 insertions(+), 56 deletions(-)
diff --git a/lldb/source/Expression/Expression.cpp b/lldb/source/Expression/Expression.cpp
index a57bcbe97e117..796851ff15ca3 100644
--- a/lldb/source/Expression/Expression.cpp
+++ b/lldb/source/Expression/Expression.cpp
@@ -11,6 +11,7 @@
#include "lldb/Target/Target.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
@@ -31,62 +32,35 @@ Expression::Expression(ExecutionContextScope &exe_scope)
assert(m_target_wp.lock());
}
-/// 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.");
- if (!label.consume_front(":"))
- return llvm::createStringError(
- "expected ':' as the first character after prefix.");
-
- auto sep1 = label.find_first_of(":");
- if (sep1 == llvm::StringRef::npos)
- return llvm::createStringError("no ':' separator found.");
-
- 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;
-}
-
llvm::Expected<FunctionCallLabel>
lldb_private::FunctionCallLabel::fromString(llvm::StringRef label) {
- auto components_or_err = splitFunctionCallLabel(label);
- if (!components_or_err)
- return llvm::joinErrors(
- llvm::createStringError("failed to split function call label '%s'",
- label.data()),
- components_or_err.takeError());
+ llvm::SmallVector<llvm::StringRef, 4> components;
+ label.split(components, ":", /*MaxSplit=*/3);
+
+ if (components.size() != 4)
+ return llvm::createStringError("malformed function call label.");
- const auto &components = *components_or_err;
+ if (components[0] != FunctionCallLabelPrefix)
+ return llvm::createStringError(llvm::formatv(
+ "expected function call label prefix '{0}' but found '{1}' instead.",
+ FunctionCallLabelPrefix, components[0]));
- llvm::StringRef module_label = components[0];
- llvm::StringRef die_label = components[1];
+ 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))
+ if (!llvm::to_integer(module_label, module_id))
return llvm::createStringError(
- llvm::formatv("failed to parse module ID from '{0}'.", components[0]));
+ llvm::formatv("failed to parse module ID from '{0}'.", module_label));
lldb::user_id_t die_id;
- if (die_label.consumeInteger(/*Radix=*/0, die_id))
+ if (!llvm::to_integer(die_label, die_id))
return llvm::createStringError(
- llvm::formatv("failed to parse symbol ID from '{0}'.", components[1]));
+ llvm::formatv("failed to parse symbol ID from '{0}'.", die_label));
return FunctionCallLabel{/*.module_id=*/module_id,
/*.symbol_id=*/die_id,
- /*.lookup_name=*/components[2]};
+ /*.lookup_name=*/components[3]};
}
std::string lldb_private::FunctionCallLabel::toString() const {
diff --git a/lldb/unittests/Expression/ExpressionTest.cpp b/lldb/unittests/Expression/ExpressionTest.cpp
index 542ce5005d7d9..12f6dd515fd11 100644
--- a/lldb/unittests/Expression/ExpressionTest.cpp
+++ b/lldb/unittests/Expression/ExpressionTest.cpp
@@ -23,34 +23,47 @@ struct LabelTestCase {
static LabelTestCase g_label_test_cases[] = {
// Failure modes
- {"0x0:0x0:_Z3foov",
+ {"bar:0x0:0x0:_Z3foov",
{},
- {"failed to split function call label '0x0:0x0:_Z3foov'",
- "expected function call label prefix not found."}},
- {"$__lldb_func0x0:0x0:_Z3foov",
+ {"expected function call label prefix '$__lldb_func' but found 'bar' "
+ "instead."}},
+ {"$__lldb_func :0x0:0x0:_Z3foov",
{},
- {"failed to split function call label '$__lldb_func0x0:0x0:_Z3foov'",
- "expected ':' as the first character after prefix."}},
- {"$__lldb_func:",
+ {"expected function call label prefix '$__lldb_func' but found "
+ "'$__lldb_func ' instead."}},
+ {"$__lldb_funcc:0x0:0x0:_Z3foov",
{},
- {"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."}},
+ {"expected function call label prefix '$__lldb_func' but found "
+ "'$__lldb_funcc' instead."}},
+ {"", {}, {"malformed function call label."}},
+ {"foo", {}, {"malformed function call label."}},
+ {"$__lldb_func", {}, {"malformed function call label."}},
+ {"$__lldb_func:", {}, {"malformed function call label."}},
+ {"$__lldb_func:0x0:0x0", {}, {"malformed function call label."}},
{"$__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:0x0invalid:0x0:_Z3foov",
+ {},
+ {"failed to parse module ID from '0x0invalid'."}},
+ {"$__lldb_func:0x0 :0x0:_Z3foov",
+ {},
+ {"failed to parse module ID from '0x0 '."}},
{"$__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:0x5:0x0invalid:_Z3foov",
+ {},
+ {"failed to parse symbol ID from '0x0invalid'."}},
+ {"$__lldb_func:0x5:0x0 :_Z3foov",
+ {},
+ {"failed to parse symbol ID from '0x0 '."}},
{"$__lldb_func:0x0:0x0:_Z3foov",
{
/*.module_id=*/0x0,
>From e080b6d5461e5eae9341c7458a92416c33346ae8 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 16:45:37 +0100
Subject: [PATCH 31/36] fixup! remove unused function
---
lldb/source/Expression/IRExecutionUnit.cpp | 30 ----------------------
1 file changed, 30 deletions(-)
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp
index 870b71eee3c7c..b50f5dcc0c61e 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -774,36 +774,6 @@ 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.
static llvm::Expected<lldb::addr_t>
>From 24fbf6c4666eb22dba61d4d5a88ec95726df10b4 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 16:46:29 +0100
Subject: [PATCH 32/36] fixup! add TODO
---
lldb/source/Expression/IRExecutionUnit.cpp | 3 +++
1 file changed, 3 insertions(+)
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp
index b50f5dcc0c61e..6f16196373dbc 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -968,6 +968,9 @@ lldb::addr_t IRExecutionUnit::FindSymbol(lldb_private::ConstString name,
}
}
+ // TODO: now with function call labels, do we still need to
+ // generate alternate manglings?
+
std::vector<ConstString> candidate_C_names;
std::vector<ConstString> candidate_CPlusPlus_names;
>From fa0b004bac72ef50d0ccfdeb0835d6a4e3763413 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 17:39:16 +0100
Subject: [PATCH 33/36] fixup! fix docs
---
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 086aa1406a1c6..20067f469895b 100644
--- a/lldb/include/lldb/Expression/Expression.h
+++ b/lldb/include/lldb/Expression/Expression.h
@@ -142,7 +142,7 @@ struct FunctionCallLabel {
std::string toString() const;
};
-/// LLDB attaches this prefix to mangled names of functions that it get called
+/// LLDB attaches this prefix to mangled names of functions that get called
/// from JITted expressions.
inline constexpr llvm::StringRef FunctionCallLabelPrefix = "$__lldb_func";
>From edd781de6f718814e6fe32d41fe294b0b88c3c54 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 23:09:57 +0100
Subject: [PATCH 34/36] fixup! no need for std::optional
(cherry picked from commit 7aeed0f42b364ac4272f3cb7b526fcb6dbc38d33)
---
.../SymbolFile/DWARF/DWARFASTParserClang.cpp | 10 ++++----
lldb/unittests/Symbol/TestTypeSystemClang.cpp | 24 -------------------
2 files changed, 5 insertions(+), 29 deletions(-)
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 4b386ac2093a7..781c1c6c5745d 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -250,14 +250,14 @@ static unsigned GetCXXMethodCVQuals(const DWARFDIE &subprogram,
return cv_quals;
}
-static std::optional<std::string> MakeLLDBFuncAsmLabel(const DWARFDIE &die) {
+static std::string MakeLLDBFuncAsmLabel(const DWARFDIE &die) {
char const *name = die.GetMangledName(/*substitute_name_allowed*/ false);
if (!name)
- return std::nullopt;
+ return {};
SymbolFileDWARF *dwarf = die.GetDWARF();
if (!dwarf)
- return std::nullopt;
+ return {};
auto get_module_id = [&](SymbolFile *sym) {
if (!sym)
@@ -279,11 +279,11 @@ static std::optional<std::string> MakeLLDBFuncAsmLabel(const DWARFDIE &die) {
module_id = get_module_id(dwarf);
if (module_id == LLDB_INVALID_UID)
- return std::nullopt;
+ return {};
const auto die_id = die.GetID();
if (die_id == LLDB_INVALID_UID)
- return std::nullopt;
+ return {};
return FunctionCallLabel{/*module_id=*/module_id,
/*symbol_id=*/die_id,
diff --git a/lldb/unittests/Symbol/TestTypeSystemClang.cpp b/lldb/unittests/Symbol/TestTypeSystemClang.cpp
index 228ee2ed9b6ea..57857676c7df9 100644
--- a/lldb/unittests/Symbol/TestTypeSystemClang.cpp
+++ b/lldb/unittests/Symbol/TestTypeSystemClang.cpp
@@ -869,11 +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,
-<<<<<<< HEAD
false, /*asm_label=*/{});
-=======
- false, std::nullopt);
->>>>>>> 382395408c4b ([lldb][Expression] Encode Module and DIE UIDs into function AsmLabels)
TypeSystemClang::TemplateParameterInfos empty_params;
// Create the actual function template.
@@ -904,11 +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,
-<<<<<<< HEAD
false, /*asm_label=*/{});
-=======
- false, std::nullopt);
->>>>>>> 382395408c4b ([lldb][Expression] Encode Module and DIE UIDs into function AsmLabels)
TypeSystemClang::TemplateParameterInfos empty_params;
// Create the actual function template.
@@ -946,11 +938,7 @@ TEST_F(TestTypeSystemClang, TestDeletingImplicitCopyCstrDueToMoveCStr) {
bool is_attr_used = false;
bool is_artificial = false;
m_ast->AddMethodToCXXRecordType(
-<<<<<<< HEAD
t.GetOpaqueQualType(), class_name, /*asm_label=*/{}, function_type,
-=======
- t.GetOpaqueQualType(), class_name, std::nullopt, function_type,
->>>>>>> 382395408c4b ([lldb][Expression] Encode Module and DIE UIDs into function AsmLabels)
lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline,
is_explicit, is_attr_used, is_artificial);
@@ -987,11 +975,7 @@ TEST_F(TestTypeSystemClang, TestNotDeletingUserCopyCstrDueToMoveCStr) {
CompilerType function_type = m_ast->CreateFunctionType(
return_type, args, /*variadic=*/false, /*quals*/ 0U);
m_ast->AddMethodToCXXRecordType(
-<<<<<<< HEAD
t.GetOpaqueQualType(), class_name, /*asm_label=*/{}, function_type,
-=======
- t.GetOpaqueQualType(), class_name, std::nullopt, function_type,
->>>>>>> 382395408c4b ([lldb][Expression] Encode Module and DIE UIDs into function AsmLabels)
lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline,
is_explicit, is_attr_used, is_artificial);
}
@@ -1003,11 +987,7 @@ TEST_F(TestTypeSystemClang, TestNotDeletingUserCopyCstrDueToMoveCStr) {
m_ast->CreateFunctionType(return_type, args,
/*variadic=*/false, /*quals*/ 0U);
m_ast->AddMethodToCXXRecordType(
-<<<<<<< HEAD
t.GetOpaqueQualType(), class_name, /*asm_label=*/{}, function_type,
-=======
- t.GetOpaqueQualType(), class_name, std::nullopt, function_type,
->>>>>>> 382395408c4b ([lldb][Expression] Encode Module and DIE UIDs into function AsmLabels)
lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline,
is_explicit, is_attr_used, is_artificial);
}
@@ -1118,11 +1098,7 @@ TEST_F(TestTypeSystemClang, AddMethodToCXXRecordType_ParmVarDecls) {
m_ast->CreateFunctionType(return_type, param_types,
/*variadic=*/false, /*quals*/ 0U);
m_ast->AddMethodToCXXRecordType(
-<<<<<<< HEAD
t.GetOpaqueQualType(), "myFunc", /*asm_label=*/{}, function_type,
-=======
- t.GetOpaqueQualType(), "myFunc", std::nullopt, function_type,
->>>>>>> 382395408c4b ([lldb][Expression] Encode Module and DIE UIDs into function AsmLabels)
lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline,
is_explicit, is_attr_used, is_artificial);
>From f1e3ce118911757ecb0f379fa1c43c574f4462e4 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Thu, 31 Jul 2025 08:33:17 +0100
Subject: [PATCH 35/36] fixup! add tests for
TypeSystemClang::DeclGetMangledName
---
lldb/unittests/Symbol/TestTypeSystemClang.cpp | 116 ++++++++++++++++++
1 file changed, 116 insertions(+)
diff --git a/lldb/unittests/Symbol/TestTypeSystemClang.cpp b/lldb/unittests/Symbol/TestTypeSystemClang.cpp
index 57857676c7df9..eb0780d068d36 100644
--- a/lldb/unittests/Symbol/TestTypeSystemClang.cpp
+++ b/lldb/unittests/Symbol/TestTypeSystemClang.cpp
@@ -17,6 +17,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprCXX.h"
+#include "llvm/IR/GlobalValue.h"
#include "gtest/gtest.h"
using namespace clang;
@@ -1116,3 +1117,118 @@ TEST_F(TestTypeSystemClang, AddMethodToCXXRecordType_ParmVarDecls) {
EXPECT_EQ(method_it->getParamDecl(0)->getDeclContext(), *method_it);
EXPECT_EQ(method_it->getParamDecl(1)->getDeclContext(), *method_it);
}
+
+TEST_F(TestTypeSystemClang, AsmLabel_CtorDtor) {
+ // Tests TypeSystemClang::DeclGetMangledName for constructors/destructors
+ // with and without AsmLabels.
+
+ llvm::StringRef class_name = "S";
+ CompilerType t = clang_utils::createRecord(*m_ast, class_name);
+ m_ast->StartTagDeclarationDefinition(t);
+
+ CompilerType return_type = m_ast->GetBasicType(lldb::eBasicTypeVoid);
+ const bool is_virtual = false;
+ const bool is_static = false;
+ const bool is_inline = false;
+ const bool is_explicit = true;
+ const bool is_attr_used = false;
+ const bool is_artificial = false;
+
+ CompilerType function_type =
+ m_ast->CreateFunctionType(return_type, {},
+ /*variadic=*/false, /*quals*/ 0U);
+ auto *ctor_nolabel = m_ast->AddMethodToCXXRecordType(
+ t.GetOpaqueQualType(), "S", /*asm_label=*/{}, function_type,
+ lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline,
+ is_explicit, is_attr_used, is_artificial);
+
+ auto *dtor_nolabel = m_ast->AddMethodToCXXRecordType(
+ t.GetOpaqueQualType(), "~S", /*asm_label=*/{}, function_type,
+ lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline,
+ is_explicit, is_attr_used, is_artificial);
+
+ auto *ctor = m_ast->AddMethodToCXXRecordType(
+ t.GetOpaqueQualType(), "S", /*asm_label=*/"$__lldb_func:0x0:0x0:S",
+ function_type, lldb::AccessType::eAccessPublic, is_virtual, is_static,
+ is_inline, is_explicit, is_attr_used, is_artificial);
+
+ auto *dtor = m_ast->AddMethodToCXXRecordType(
+ t.GetOpaqueQualType(), "~S", /*asm_label=*/"$__lldb_func:0x0:0x0:~S",
+ function_type, lldb::AccessType::eAccessPublic, is_virtual, is_static,
+ is_inline, is_explicit, is_attr_used, is_artificial);
+
+ m_ast->CompleteTagDeclarationDefinition(t);
+
+ ASSERT_TRUE(ctor_nolabel);
+ ASSERT_TRUE(dtor_nolabel);
+ ASSERT_TRUE(ctor);
+ ASSERT_TRUE(dtor);
+
+ ASSERT_STREQ(m_ast->DeclGetMangledName(ctor_nolabel).GetCString(),
+ "_ZN1SC1Ev");
+ ASSERT_STREQ(m_ast->DeclGetMangledName(dtor_nolabel).GetCString(),
+ "_ZN1SD1Ev");
+ ASSERT_STREQ(m_ast->DeclGetMangledName(ctor).GetCString(),
+ "\01$__lldb_func:0x0:0x0:S");
+ ASSERT_STREQ(m_ast->DeclGetMangledName(dtor).GetCString(),
+ "\01$__lldb_func:0x0:0x0:~S");
+}
+
+struct AsmLabelTestCase {
+ llvm::StringRef mangled;
+ llvm::StringRef expected;
+};
+
+class TestTypeSystemClangAsmLabel
+ : public testing::TestWithParam<AsmLabelTestCase> {
+public:
+ SubsystemRAII<FileSystem, HostInfo> subsystems;
+
+ void SetUp() override {
+ m_holder =
+ std::make_unique<clang_utils::TypeSystemClangHolder>("test ASTContext");
+ m_ast = m_holder->GetAST();
+ }
+
+ void TearDown() override {
+ m_ast = nullptr;
+ m_holder.reset();
+ }
+
+protected:
+ TypeSystemClang *m_ast = nullptr;
+ std::unique_ptr<clang_utils::TypeSystemClangHolder> m_holder;
+};
+
+static AsmLabelTestCase g_asm_label_test_cases[] = {
+ {/*mangled=*/"$__lldb_func:0x0:0x0:_Z3foov",
+ /*expected=*/"_Z3foov"},
+ {/*mangled=*/"$__lldb_func:0x0:0x0:foo",
+ /*expected=*/"$__lldb_func:0x0:0x0:foo"},
+ {/*mangled=*/"foo",
+ /*expected=*/"foo"},
+ {/*mangled=*/"_Z3foov",
+ /*expected=*/"_Z3foov"},
+ {/*mangled=*/"$__lldb_func:",
+ /*expected=*/"$__lldb_func:"},
+};
+
+TEST_P(TestTypeSystemClangAsmLabel, DeclGetMangledName) {
+ const auto &[mangled, expected] = GetParam();
+
+ CompilerType int_type = m_ast->GetBasicType(lldb::eBasicTypeInt);
+ clang::TranslationUnitDecl *TU = m_ast->GetTranslationUnitDecl();
+
+ // Prepare the declarations/types we need for the template.
+ CompilerType clang_type = m_ast->CreateFunctionType(int_type, {}, false, 0U);
+ FunctionDecl *func = m_ast->CreateFunctionDeclaration(
+ TU, OptionalClangModuleID(), "foo", clang_type, StorageClass::SC_None,
+ false, /*asm_label=*/mangled);
+
+ ASSERT_EQ(llvm::GlobalValue::dropLLVMManglingEscape(
+ m_ast->DeclGetMangledName(func).GetStringRef()),
+ expected);
+}
+
+INSTANTIATE_TEST_SUITE_P(AsmLabelTests, TestTypeSystemClangAsmLabel,
+ testing::ValuesIn(g_asm_label_test_cases));
>From 44410a459303cab42a8d05bb6da3ebf1b64c7046 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Thu, 31 Jul 2025 09:52:44 +0100
Subject: [PATCH 36/36] Structors Init
---
clang/lib/AST/Mangle.cpp | 15 +++
libcxxabi/src/demangle/ItaniumDemangle.h | 2 +
lldb/include/lldb/Expression/Expression.h | 6 +-
lldb/source/Expression/Expression.cpp | 22 +++--
lldb/source/Expression/IRExecutionUnit.cpp | 2 +-
.../SymbolFile/DWARF/DWARFASTParserClang.cpp | 34 ++++++-
.../SymbolFile/DWARF/SymbolFileDWARF.cpp | 95 +++++++++++++++++--
.../TypeSystem/Clang/TypeSystemClang.cpp | 1 +
.../TypeSystem/Clang/TypeSystemClang.h | 2 +
llvm/include/llvm/Demangle/Demangle.h | 3 +
llvm/include/llvm/Demangle/ItaniumDemangle.h | 2 +
llvm/lib/Demangle/ItaniumDemangle.cpp | 10 +-
12 files changed, 171 insertions(+), 23 deletions(-)
diff --git a/clang/lib/AST/Mangle.cpp b/clang/lib/AST/Mangle.cpp
index 9652fdbc4e125..eebf82aed3ec5 100644
--- a/clang/lib/AST/Mangle.cpp
+++ b/clang/lib/AST/Mangle.cpp
@@ -152,6 +152,14 @@ bool MangleContext::shouldMangleDeclName(const NamedDecl *D) {
return shouldMangleCXXName(D);
}
+static void tryEmitDebugStructorVariant(GlobalDecl GD, raw_ostream &Out) {
+ // TODO: shouldn't append but instead slice
+ if (llvm::isa<clang::CXXConstructorDecl>(GD.getDecl()))
+ Out << "C" << GD.getCtorType();
+ else if (llvm::isa<clang::CXXDestructorDecl>(GD.getDecl()))
+ Out << "D" << GD.getDtorType();
+}
+
void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
const ASTContext &ASTContext = getASTContext();
const NamedDecl *D = cast<NamedDecl>(GD.getDecl());
@@ -161,10 +169,12 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) {
// If we have an asm name, then we use it as the mangling.
+ // TODO: remove this getIsLiteralLabel branch
// If the label isn't literal, or if this is an alias for an LLVM intrinsic,
// do not add a "\01" prefix.
if (!ALA->getIsLiteralLabel() || ALA->getLabel().starts_with("llvm.")) {
Out << ALA->getLabel();
+
return;
}
@@ -186,6 +196,11 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
Out << '\01'; // LLVM IR Marker for __asm("foo")
Out << ALA->getLabel();
+
+ // TODO: ideally should have separate attribute for this?
+ if (ASTContext.getLangOpts().DebuggerSupport)
+ tryEmitDebugStructorVariant(GD, Out);
+
return;
}
diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h b/libcxxabi/src/demangle/ItaniumDemangle.h
index 6f27da7b9cadf..7b3983bc89367 100644
--- a/libcxxabi/src/demangle/ItaniumDemangle.h
+++ b/libcxxabi/src/demangle/ItaniumDemangle.h
@@ -1766,6 +1766,8 @@ class CtorDtorName final : public Node {
template<typename Fn> void match(Fn F) const { F(Basename, IsDtor, Variant); }
+ int getVariant() const { return Variant; }
+
void printLeft(OutputBuffer &OB) const override {
if (IsDtor)
OB += "~";
diff --git a/lldb/include/lldb/Expression/Expression.h b/lldb/include/lldb/Expression/Expression.h
index 20067f469895b..c2702bd9dca96 100644
--- a/lldb/include/lldb/Expression/Expression.h
+++ b/lldb/include/lldb/Expression/Expression.h
@@ -103,7 +103,7 @@ class Expression {
///
/// The format being:
///
-/// <prefix>:<module uid>:<symbol uid>:<name>
+/// <prefix>:<module uid>:<symbol uid>:<discriminator>:<name>
///
/// The label string needs to stay valid for the entire lifetime
/// of this object.
@@ -126,6 +126,8 @@ struct FunctionCallLabel {
/// ':' in the mangled name when parsing the label.
llvm::StringRef lookup_name;
+ llvm::StringRef discriminator;
+
/// Decodes the specified function \c label into a \c FunctionCallLabel.
static llvm::Expected<FunctionCallLabel> fromString(llvm::StringRef label);
@@ -133,7 +135,7 @@ struct FunctionCallLabel {
///
/// The representation roundtrips through \c fromString:
/// \code{.cpp}
- /// llvm::StringRef encoded = "$__lldb_func:0x0:0x0:_Z3foov";
+ /// llvm::StringRef encoded = "$__lldb_func:0x0:0x0:_Z3foov:";
/// FunctionCallLabel label = *fromString(label);
///
/// assert (label.toString() == encoded);
diff --git a/lldb/source/Expression/Expression.cpp b/lldb/source/Expression/Expression.cpp
index 796851ff15ca3..c9baa228fe888 100644
--- a/lldb/source/Expression/Expression.cpp
+++ b/lldb/source/Expression/Expression.cpp
@@ -34,10 +34,10 @@ Expression::Expression(ExecutionContextScope &exe_scope)
llvm::Expected<FunctionCallLabel>
lldb_private::FunctionCallLabel::fromString(llvm::StringRef label) {
- llvm::SmallVector<llvm::StringRef, 4> components;
- label.split(components, ":", /*MaxSplit=*/3);
+ llvm::SmallVector<llvm::StringRef, 5> components;
+ label.split(components, ":", /*MaxSplit=*/4);
- if (components.size() != 4)
+ if (components.size() != 5)
return llvm::createStringError("malformed function call label.");
if (components[0] != FunctionCallLabelPrefix)
@@ -47,6 +47,10 @@ lldb_private::FunctionCallLabel::fromString(llvm::StringRef label) {
llvm::StringRef module_label = components[1];
llvm::StringRef die_label = components[2];
+ llvm::StringRef lookup_name =
+ components[3]; // TODO: mangled name should come last...clang should
+ // splice it into the label?
+ llvm::StringRef discriminator = components[4];
lldb::user_id_t module_id = 0;
if (!llvm::to_integer(module_label, module_id))
@@ -60,18 +64,20 @@ lldb_private::FunctionCallLabel::fromString(llvm::StringRef label) {
return FunctionCallLabel{/*.module_id=*/module_id,
/*.symbol_id=*/die_id,
- /*.lookup_name=*/components[3]};
+ /*.lookup_name=*/lookup_name,
+ /*.discriminator=*/discriminator};
}
std::string lldb_private::FunctionCallLabel::toString() const {
- return llvm::formatv("{0}:{1:x}:{2:x}:{3}", FunctionCallLabelPrefix,
- module_id, symbol_id, lookup_name)
+ return llvm::formatv("{0}:{1:x}:{2:x}:{3}:{4}", FunctionCallLabelPrefix,
+ module_id, symbol_id, lookup_name, discriminator)
.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);
+ "lookup_name: {2}, discriminator: {3} }",
+ label.module_id, label.symbol_id, label.lookup_name,
+ label.discriminator);
}
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp
index 6f16196373dbc..5e40df282e7b0 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -947,7 +947,7 @@ lldb::addr_t IRExecutionUnit::FindSymbol(lldb_private::ConstString name,
auto label_or_err = FunctionCallLabel::fromString(name);
if (!label_or_err) {
LLDB_LOG_ERROR(GetLog(LLDBLog::Expressions), label_or_err.takeError(),
- "failed to create FunctionCallLabel from '{0}': {1}",
+ "failed to create FunctionCallLabel from '{1}': {0}",
name.GetStringRef());
return LLDB_INVALID_ADDRESS;
}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 781c1c6c5745d..3a7c34f545a2e 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -250,8 +250,36 @@ static unsigned GetCXXMethodCVQuals(const DWARFDIE &subprogram,
return cv_quals;
}
+static const char *GetMangledOrStructorName(const DWARFDIE &die) {
+ const char *name = die.GetMangledName(/*substitute_name_allowed*/ false);
+ if (name)
+ return name;
+
+ name = die.GetName();
+ if (!name)
+ return nullptr;
+
+ DWARFDIE parent = die.GetParent();
+ if (!parent.IsStructUnionOrClass())
+ return nullptr;
+
+ const char *parent_name = parent.GetName();
+ if (!parent_name)
+ return nullptr;
+
+ // Constructor.
+ if (::strcmp(parent_name, name) == 0)
+ return name;
+
+ // Destructor.
+ if (name[0] == '~' && ::strcmp(parent_name, name + 1))
+ return name;
+
+ return nullptr;
+}
+
static std::string MakeLLDBFuncAsmLabel(const DWARFDIE &die) {
- char const *name = die.GetMangledName(/*substitute_name_allowed*/ false);
+ char const *name = GetMangledOrStructorName(die);
if (!name)
return {};
@@ -285,9 +313,11 @@ static std::string MakeLLDBFuncAsmLabel(const DWARFDIE &die) {
if (die_id == LLDB_INVALID_UID)
return {};
+ // Note, discriminator is added by Clang during mangling.
return FunctionCallLabel{/*module_id=*/module_id,
/*symbol_id=*/die_id,
- /*.lookup_name=*/name}
+ /*.lookup_name=*/name,
+ /*discriminator=*/{}}
.toString();
}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 874fbf7c160b8..f189547585011 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -7,7 +7,9 @@
//===----------------------------------------------------------------------===//
#include "SymbolFileDWARF.h"
+#include "clang/Basic/ABI.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
#include "llvm/Support/Casting.h"
@@ -77,6 +79,7 @@
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
+#include "llvm/Demangle/Demangle.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FormatVariadic.h"
@@ -2475,6 +2478,56 @@ bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die,
return false;
}
+static uint8_t ClangToItaniumCtorKind(clang::CXXCtorType kind) {
+ switch (kind) {
+ case clang::CXXCtorType::Ctor_Complete:
+ return 1;
+ case clang::CXXCtorType::Ctor_Base:
+ return 2;
+ case clang::CXXCtorType::Ctor_CopyingClosure:
+ case clang::CXXCtorType::Ctor_DefaultClosure:
+ case clang::CXXCtorType::Ctor_Comdat:
+ llvm_unreachable("Unexpected constructor kind.");
+ }
+}
+
+static uint8_t ClangToItaniumDtorKind(clang::CXXDtorType kind) {
+ switch (kind) {
+ case clang::CXXDtorType::Dtor_Deleting:
+ return 0;
+ case clang::CXXDtorType::Dtor_Complete:
+ return 1;
+ case clang::CXXDtorType::Dtor_Base:
+ return 2;
+ case clang::CXXDtorType::Dtor_Comdat:
+ llvm_unreachable("Unexpected destructor kind.");
+ }
+}
+
+static std::optional<uint8_t>
+GetItaniumCtorDtorVariant(llvm::StringRef discriminator) {
+ const bool is_ctor = discriminator.consume_front("C");
+ if (!is_ctor && !discriminator.consume_front("D"))
+ return std::nullopt;
+
+ uint64_t structor_kind;
+ if (!llvm::to_integer(discriminator, structor_kind))
+ return std::nullopt;
+
+ if (is_ctor) {
+ if (structor_kind > clang::CXXCtorType::Ctor_DefaultClosure)
+ return std::nullopt;
+
+ return ClangToItaniumCtorKind(
+ static_cast<clang::CXXCtorType>(structor_kind));
+ }
+
+ if (structor_kind > clang::CXXDtorType::Dtor_Deleting)
+ return std::nullopt;
+
+ return ClangToItaniumDtorKind(static_cast<clang::CXXDtorType>(structor_kind));
+}
+
llvm::Expected<SymbolContext>
SymbolFileDWARF::ResolveFunctionCallLabel(const FunctionCallLabel &label) {
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
@@ -2487,21 +2540,49 @@ SymbolFileDWARF::ResolveFunctionCallLabel(const FunctionCallLabel &label) {
// 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)) {
+ // eFunctionNameTypeFull for mangled name lookup.
+ // eFunctionNameTypeMethod is required for structor lookups (since we look
+ // those up by DW_AT_name).
Module::LookupInfo info(ConstString(label.lookup_name),
- lldb::eFunctionNameTypeFull,
+ lldb::eFunctionNameTypeFull |
+ lldb::eFunctionNameTypeMethod,
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.
+ // TODO: this specification check doesn't work if declaration DIE was in a
+ // type-unit (we should only encode DIEs from .debug_info).
+ auto spec = entry.GetAttributeValueAsReferenceDIE(DW_AT_specification);
+ if (!spec)
+ return true;
+
+ if (spec != die)
+ return true;
+
+ // We're not picking a specific structor variant DIE, so we're done here.
+ if (label.discriminator.empty()) {
+ die = entry;
+ return false;
+ }
+
+ const char *mangled =
+ entry.GetMangledName(/*substitute_name_allowed=*/false);
+ if (!mangled)
+ return true;
+
+ llvm::ItaniumPartialDemangler D;
+ if (D.partialDemangle(mangled))
+ return true;
+
+ // TODO: account for constructor alias (only an issue on Linux)
+ if (D.getCtorOrDtorVariant() !=
+ GetItaniumCtorDtorVariant(label.discriminator).value_or(-1))
+ return true;
+
die = entry;
+
return false;
});
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index ab5f4138187ed..fdc50375c03ec 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -10,6 +10,7 @@
#include "clang/AST/DeclBase.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/Basic/ABI.h"
#include "clang/Frontend/ASTConsumers.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/FormatAdapters.h"
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index de66bb68c6a4c..ab979129f21cc 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -18,6 +18,7 @@
#include <set>
#include <string>
#include <utility>
+#include <variant>
#include <vector>
#include "clang/AST/ASTContext.h"
@@ -26,6 +27,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/Type.h"
+#include "clang/Basic/ABI.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/SmallVector.h"
diff --git a/llvm/include/llvm/Demangle/Demangle.h b/llvm/include/llvm/Demangle/Demangle.h
index d9b08b2d856dc..6af8fad9ceb86 100644
--- a/llvm/include/llvm/Demangle/Demangle.h
+++ b/llvm/include/llvm/Demangle/Demangle.h
@@ -127,6 +127,9 @@ struct ItaniumPartialDemangler {
/// If this symbol describes a constructor or destructor.
DEMANGLE_ABI bool isCtorOrDtor() const;
+ /// If this symbol describes a constructor or destructor.
+ std::optional<int> getCtorOrDtorVariant() const;
+
/// If this symbol describes a function.
DEMANGLE_ABI bool isFunction() const;
diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h b/llvm/include/llvm/Demangle/ItaniumDemangle.h
index 62d427c3966bb..c0db02f8e7fef 100644
--- a/llvm/include/llvm/Demangle/ItaniumDemangle.h
+++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h
@@ -1766,6 +1766,8 @@ class CtorDtorName final : public Node {
template<typename Fn> void match(Fn F) const { F(Basename, IsDtor, Variant); }
+ int getVariant() const { return Variant; }
+
void printLeft(OutputBuffer &OB) const override {
if (IsDtor)
OB += "~";
diff --git a/llvm/lib/Demangle/ItaniumDemangle.cpp b/llvm/lib/Demangle/ItaniumDemangle.cpp
index 1009cc91ca12a..a5d7a5576fccf 100644
--- a/llvm/lib/Demangle/ItaniumDemangle.cpp
+++ b/llvm/lib/Demangle/ItaniumDemangle.cpp
@@ -560,13 +560,17 @@ bool ItaniumPartialDemangler::hasFunctionQualifiers() const {
}
bool ItaniumPartialDemangler::isCtorOrDtor() const {
+ return getCtorOrDtorVariant().has_value();
+}
+
+std::optional<int> ItaniumPartialDemangler::getCtorOrDtorVariant() const {
const Node *N = static_cast<const Node *>(RootNode);
while (N) {
switch (N->getKind()) {
default:
- return false;
+ return std::nullopt;
case Node::KCtorDtorName:
- return true;
+ return static_cast<const CtorDtorName *>(N)->getVariant();
case Node::KAbiTagAttr:
N = static_cast<const AbiTagAttr *>(N)->Base;
@@ -588,7 +592,7 @@ bool ItaniumPartialDemangler::isCtorOrDtor() const {
break;
}
}
- return false;
+ return std::nullopt;
}
bool ItaniumPartialDemangler::isFunction() const {
More information about the llvm-commits
mailing list