[Lldb-commits] [lldb] [DRAFT] [lldb][Expression] Encode Module and DIE UIDs into function AsmLabels (PR #148877)
Michael Buch via lldb-commits
lldb-commits at lists.llvm.org
Fri Jul 18 03:23:10 PDT 2025
https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/148877
>From 386c354b54f619bdad4d3b3f965771282a4647b8 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] [lldb][Expression] Encode Module and DIE UIDs into function
AsmLabels
---
lldb/include/lldb/Core/Module.h | 4 +-
lldb/include/lldb/Expression/Expression.h | 6 ++
lldb/include/lldb/Symbol/SymbolFile.h | 14 +++
lldb/source/Core/Module.cpp | 19 +++-
lldb/source/Expression/Expression.cpp | 5 +
lldb/source/Expression/IRExecutionUnit.cpp | 101 ++++++++++++++++--
.../Clang/ClangExpressionDeclMap.cpp | 2 +-
.../SymbolFile/DWARF/DWARFASTParserClang.cpp | 44 +++++---
.../SymbolFile/DWARF/SymbolFileDWARF.cpp | 45 ++++++++
.../SymbolFile/DWARF/SymbolFileDWARF.h | 3 +
.../SymbolFile/NativePDB/PdbAstBuilder.cpp | 6 +-
.../Plugins/SymbolFile/PDB/PDBASTParser.cpp | 7 +-
.../TypeSystem/Clang/TypeSystemClang.cpp | 50 ++++++++-
.../TypeSystem/Clang/TypeSystemClang.h | 5 +-
lldb/unittests/Symbol/TestTypeSystemClang.cpp | 12 +--
15 files changed, 274 insertions(+), 49 deletions(-)
diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h
index 8bb55c95773bc..3991a12997541 100644
--- a/lldb/include/lldb/Core/Module.h
+++ b/lldb/include/lldb/Core/Module.h
@@ -86,7 +86,8 @@ struct ModuleFunctionSearchOptions {
///
/// The module will parse more detailed information as more queries are made.
class Module : public std::enable_shared_from_this<Module>,
- public SymbolContextScope {
+ public SymbolContextScope,
+ public UserID {
public:
class LookupInfo;
// Static functions that can track the lifetime of module objects. This is
@@ -97,6 +98,7 @@ class Module : public std::enable_shared_from_this<Module>,
// using the "--global" (-g for short).
static size_t GetNumberAllocatedModules();
+ static Module *GetAllocatedModuleWithUID(lldb::user_id_t uid);
static Module *GetAllocatedModuleAtIndex(size_t idx);
static std::recursive_mutex &GetAllocationModuleCollectionMutex();
diff --git a/lldb/include/lldb/Expression/Expression.h b/lldb/include/lldb/Expression/Expression.h
index 8de9364436ccf..8e629a0d96661 100644
--- a/lldb/include/lldb/Expression/Expression.h
+++ b/lldb/include/lldb/Expression/Expression.h
@@ -96,6 +96,12 @@ class Expression {
///invalid.
};
+/// LLDB attaches this prefix to mangled names of functions that it get called
+/// from JITted expressions.
+inline constexpr llvm::StringRef FunctionCallLabelPrefix = "$__lldb_func";
+
+bool consumeFunctionCallLabelPrefix(llvm::StringRef &name);
+
} // namespace lldb_private
#endif // LLDB_EXPRESSION_EXPRESSION_H
diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h
index e95f95553c17c..70dc20664df20 100644
--- a/lldb/include/lldb/Symbol/SymbolFile.h
+++ b/lldb/include/lldb/Symbol/SymbolFile.h
@@ -18,6 +18,7 @@
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/SourceModule.h"
+#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Symbol/TypeList.h"
#include "lldb/Symbol/TypeSystem.h"
@@ -328,6 +329,19 @@ class SymbolFile : public PluginInterface {
GetMangledNamesForFunction(const std::string &scope_qualified_name,
std::vector<ConstString> &mangled_names);
+ /// Resolves the function DIE uniquely identified by \c uid within
+ /// this SymbolFile.
+ ///
+ /// \param[in,out] sc_list The resolved functions will be appended to this
+ /// list.
+ ///
+ /// \param[in] uid The UID of the function DIE to resolve.
+ ///
+ virtual llvm::Error ResolveFunctionUID(SymbolContextList &sc_list,
+ lldb::user_id_t uid) {
+ return llvm::createStringError("Not implemented");
+ }
+
virtual void GetTypes(lldb_private::SymbolContextScope *sc_scope,
lldb::TypeClass type_mask,
lldb_private::TypeList &type_list) = 0;
diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp
index 90997dada3666..edd79aff5d065 100644
--- a/lldb/source/Core/Module.cpp
+++ b/lldb/source/Core/Module.cpp
@@ -121,6 +121,15 @@ size_t Module::GetNumberAllocatedModules() {
return GetModuleCollection().size();
}
+Module *Module::GetAllocatedModuleWithUID(lldb::user_id_t uid) {
+ std::lock_guard<std::recursive_mutex> guard(
+ GetAllocationModuleCollectionMutex());
+ for (Module *mod : GetModuleCollection())
+ if (mod->GetID() == uid)
+ return mod;
+ return nullptr;
+}
+
Module *Module::GetAllocatedModuleAtIndex(size_t idx) {
std::lock_guard<std::recursive_mutex> guard(
GetAllocationModuleCollectionMutex());
@@ -130,8 +139,11 @@ Module *Module::GetAllocatedModuleAtIndex(size_t idx) {
return nullptr;
}
+// TODO: needs a mutex
+static lldb::user_id_t g_unique_id = 1;
+
Module::Module(const ModuleSpec &module_spec)
- : m_unwind_table(*this), m_file_has_changed(false),
+ : UserID(g_unique_id++), m_unwind_table(*this), m_file_has_changed(false),
m_first_file_changed_log(false) {
// Scope for locker below...
{
@@ -236,7 +248,8 @@ Module::Module(const ModuleSpec &module_spec)
Module::Module(const FileSpec &file_spec, const ArchSpec &arch,
ConstString object_name, lldb::offset_t object_offset,
const llvm::sys::TimePoint<> &object_mod_time)
- : m_mod_time(FileSystem::Instance().GetModificationTime(file_spec)),
+ : UserID(g_unique_id++),
+ m_mod_time(FileSystem::Instance().GetModificationTime(file_spec)),
m_arch(arch), m_file(file_spec), m_object_name(object_name),
m_object_offset(object_offset), m_object_mod_time(object_mod_time),
m_unwind_table(*this), m_file_has_changed(false),
@@ -257,7 +270,7 @@ Module::Module(const FileSpec &file_spec, const ArchSpec &arch,
}
Module::Module()
- : m_unwind_table(*this), m_file_has_changed(false),
+ : UserID(g_unique_id++), m_unwind_table(*this), m_file_has_changed(false),
m_first_file_changed_log(false) {
std::lock_guard<std::recursive_mutex> guard(
GetAllocationModuleCollectionMutex());
diff --git a/lldb/source/Expression/Expression.cpp b/lldb/source/Expression/Expression.cpp
index 93f585edfce3d..d60d84b7ca409 100644
--- a/lldb/source/Expression/Expression.cpp
+++ b/lldb/source/Expression/Expression.cpp
@@ -26,3 +26,8 @@ Expression::Expression(ExecutionContextScope &exe_scope)
m_jit_end_addr(LLDB_INVALID_ADDRESS) {
assert(m_target_wp.lock());
}
+
+bool lldb_private::consumeFunctionCallLabelPrefix(llvm::StringRef &name) {
+ name.consume_front("_");
+ return name.consume_front(FunctionCallLabelPrefix);
+}
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp
index e445fa8833022..7bbb09b36cd20 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -13,6 +13,7 @@
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/raw_ostream.h"
@@ -20,6 +21,7 @@
#include "lldb/Core/Disassembler.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Section.h"
+#include "lldb/Expression/Expression.h"
#include "lldb/Expression/IRExecutionUnit.h"
#include "lldb/Expression/ObjectFileJIT.h"
#include "lldb/Host/HostInfo.h"
@@ -36,6 +38,7 @@
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
+#include "lldb/lldb-defines.h"
#include <optional>
@@ -700,7 +703,7 @@ void IRExecutionUnit::CollectCandidateCPlusPlusNames(
class LoadAddressResolver {
public:
- LoadAddressResolver(Target *target, bool &symbol_was_missing_weak)
+ LoadAddressResolver(Target &target, bool &symbol_was_missing_weak)
: m_target(target), m_symbol_was_missing_weak(symbol_was_missing_weak) {}
std::optional<lldb::addr_t> Resolve(SymbolContextList &sc_list) {
@@ -722,11 +725,11 @@ class LoadAddressResolver {
// First try the symbol.
if (candidate_sc.symbol) {
- load_address = candidate_sc.symbol->ResolveCallableAddress(*m_target);
+ load_address = candidate_sc.symbol->ResolveCallableAddress(m_target);
if (load_address == LLDB_INVALID_ADDRESS) {
Address addr = candidate_sc.symbol->GetAddress();
- load_address = m_target->GetProcessSP()
- ? addr.GetLoadAddress(m_target)
+ load_address = m_target.GetProcessSP()
+ ? addr.GetLoadAddress(&m_target)
: addr.GetFileAddress();
}
}
@@ -734,8 +737,8 @@ class LoadAddressResolver {
// If that didn't work, try the function.
if (load_address == LLDB_INVALID_ADDRESS && candidate_sc.function) {
Address addr = candidate_sc.function->GetAddress();
- load_address = m_target->GetProcessSP() ? addr.GetLoadAddress(m_target)
- : addr.GetFileAddress();
+ load_address = m_target.GetProcessSP() ? addr.GetLoadAddress(&m_target)
+ : addr.GetFileAddress();
}
// We found a load address.
@@ -766,11 +769,78 @@ class LoadAddressResolver {
}
private:
- Target *m_target;
+ Target &m_target;
bool &m_symbol_was_missing_weak;
lldb::addr_t m_best_internal_load_address = LLDB_INVALID_ADDRESS;
};
+/// Returns address of the function referred to by the special function call
+/// label \c label.
+///
+/// \param[in] label Function call label encoding the unique location of the
+/// function to look up.
+/// Assumes that the \c FunctionCallLabelPrefix has been
+/// stripped from the front of the label.
+static llvm::Expected<lldb::addr_t>
+ResolveFunctionCallLabel(llvm::StringRef label,
+ const lldb_private::SymbolContext &sc,
+ bool &symbol_was_missing_weak) {
+ symbol_was_missing_weak = false;
+
+ // Expected format at this point is:
+ // :<mangled name>:<module id>:<definition/declaration DIE id>
+
+ if (!label.consume_front(":"))
+ return llvm::createStringError(
+ "incorrect format: expected ':' as the first character.");
+
+ // TODO: can we make use of the mangled name for sanity checking?
+ llvm::SmallVector<llvm::StringRef, 3> components;
+ label.split(components, ":");
+
+ if (components.size() != 3)
+ return llvm::createStringError(
+ "incorrect format: too many label subcomponents.");
+
+ llvm::StringRef module_label = components[1];
+ llvm::StringRef die = components[2];
+
+ lldb::user_id_t module_id = 0;
+ if (module_label.consumeInteger(0, module_id))
+ return llvm::createStringError(
+ llvm::formatv("failed to parse module ID from '{0}'.", components[1]));
+
+ Module *module = Module::GetAllocatedModuleWithUID(module_id);
+
+ if (!module)
+ return llvm::createStringError(
+ llvm::formatv("failed to find module by UID {0}", module_id));
+
+ lldb::user_id_t die_id;
+ if (die.consumeInteger(/*Radix=*/0, die_id)) {
+ LLDB_LOG(GetLog(LLDBLog::Expressions), "failed to parse DIE ID from '{0}'.",
+ components[2]);
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ auto *symbol_file = module->GetSymbolFile();
+ if (!symbol_file)
+ return llvm::createStringError(
+ llvm::formatv("no SymbolFile found on module {0:x}.", module));
+
+ SymbolContextList sc_list;
+ if (auto err = symbol_file->ResolveFunctionUID(sc_list, die_id))
+ return llvm::joinErrors(
+ llvm::createStringError("failed to resolve function by UID"),
+ std::move(err));
+
+ if (!sc.target_sp)
+ return llvm::createStringError("target not available.");
+
+ LoadAddressResolver resolver(*sc.target_sp, symbol_was_missing_weak);
+ return resolver.Resolve(sc_list).value_or(LLDB_INVALID_ADDRESS);
+}
+
lldb::addr_t
IRExecutionUnit::FindInSymbols(const std::vector<ConstString> &names,
const lldb_private::SymbolContext &sc,
@@ -790,7 +860,7 @@ IRExecutionUnit::FindInSymbols(const std::vector<ConstString> &names,
for (size_t i = 0; i < m_preferred_modules.GetSize(); ++i)
non_local_images.Remove(m_preferred_modules.GetModuleAtIndex(i));
- LoadAddressResolver resolver(target, symbol_was_missing_weak);
+ LoadAddressResolver resolver(*target, symbol_was_missing_weak);
ModuleFunctionSearchOptions function_options;
function_options.include_symbols = true;
@@ -906,6 +976,21 @@ lldb::addr_t IRExecutionUnit::FindInUserDefinedSymbols(
lldb::addr_t IRExecutionUnit::FindSymbol(lldb_private::ConstString name,
bool &missing_weak) {
+ auto name_ref = name.GetStringRef();
+ if (consumeFunctionCallLabelPrefix(name_ref)) {
+ if (auto addr_or_err =
+ ResolveFunctionCallLabel(name_ref, m_sym_ctx, missing_weak)) {
+ return *addr_or_err;
+ } else {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Expressions), addr_or_err.takeError(),
+ "Failed to resolve function call label {1}: {0}",
+ name.GetStringRef());
+ return LLDB_INVALID_ADDRESS;
+ }
+ }
+
+ // TODO: do we still need the following lookups?
+
std::vector<ConstString> candidate_C_names;
std::vector<ConstString> candidate_CPlusPlus_names;
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
index 9f77fbc1d2434..a6c4334bf2e59 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
@@ -1991,7 +1991,7 @@ void ClangExpressionDeclMap::AddContextClassType(NameSearchContext &context,
const bool is_artificial = false;
CXXMethodDecl *method_decl = m_clang_ast_context->AddMethodToCXXRecordType(
- copied_clang_type.GetOpaqueQualType(), "$__lldb_expr", nullptr,
+ copied_clang_type.GetOpaqueQualType(), "$__lldb_expr", std::nullopt,
method_type, lldb::eAccessPublic, is_virtual, is_static, is_inline,
is_explicit, is_attr_used, is_artificial);
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index c76d67b47b336..9b9c34cb114ac 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -24,6 +24,7 @@
#include "Plugins/Language/ObjC/ObjCLanguage.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Value.h"
+#include "lldb/Expression/Expression.h"
#include "lldb/Host/Host.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/Function.h"
@@ -249,6 +250,29 @@ static unsigned GetCXXMethodCVQuals(const DWARFDIE &subprogram,
return cv_quals;
}
+static std::optional<std::string> MakeLLDBFuncAsmLabel(const DWARFDIE &die) {
+ std::optional<std::string> label;
+ char const *mangled = die.GetMangledName(/*substitute_name_allowed=*/false);
+ if (mangled)
+ label.emplace(mangled);
+
+ auto module_sp = die.GetModule();
+ if (!module_sp)
+ return std::nullopt;
+
+ lldb::user_id_t module_id = module_sp->GetID();
+ if (module_id == LLDB_INVALID_UID)
+ return std::nullopt;
+
+ const auto die_id = die.GetID();
+ if (die_id == LLDB_INVALID_UID)
+ return std::nullopt;
+
+ return llvm::formatv("{0}:{1}:{2:x}:{3:x}", FunctionCallLabelPrefix,
+ mangled ? mangled : "", module_id, die_id)
+ .str();
+}
+
TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc,
const DWARFDIE &die,
Log *log) {
@@ -1231,7 +1255,7 @@ std::pair<bool, TypeSP> DWARFASTParserClang::ParseCXXMethod(
clang::CXXMethodDecl *cxx_method_decl = m_ast.AddMethodToCXXRecordType(
class_opaque_type.GetOpaqueQualType(), attrs.name.GetCString(),
- attrs.mangled_name, clang_type, accessibility, attrs.is_virtual,
+ MakeLLDBFuncAsmLabel(die), clang_type, accessibility, attrs.is_virtual,
is_static, attrs.is_inline, attrs.is_explicit, is_attr_used,
attrs.is_artificial);
@@ -1384,7 +1408,7 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
ignore_containing_context ? m_ast.GetTranslationUnitDecl()
: containing_decl_ctx,
GetOwningClangModule(die), name, clang_type, attrs.storage,
- attrs.is_inline);
+ attrs.is_inline, MakeLLDBFuncAsmLabel(die));
std::free(name_buf);
if (has_template_params) {
@@ -1394,7 +1418,7 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
ignore_containing_context ? m_ast.GetTranslationUnitDecl()
: containing_decl_ctx,
GetOwningClangModule(die), attrs.name.GetStringRef(), clang_type,
- attrs.storage, attrs.is_inline);
+ attrs.storage, attrs.is_inline, /*asm_label=*/std::nullopt);
clang::FunctionTemplateDecl *func_template_decl =
m_ast.CreateFunctionTemplateDecl(
containing_decl_ctx, GetOwningClangModule(die),
@@ -1406,20 +1430,6 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
lldbassert(function_decl);
if (function_decl) {
- // Attach an asm(<mangled_name>) label to the FunctionDecl.
- // This ensures that clang::CodeGen emits function calls
- // using symbols that are mangled according to the DW_AT_linkage_name.
- // If we didn't do this, the external symbols wouldn't exactly
- // match the mangled name LLDB knows about and the IRExecutionUnit
- // would have to fall back to searching object files for
- // approximately matching function names. The motivating
- // example is generating calls to ABI-tagged template functions.
- // This is done separately for member functions in
- // AddMethodToCXXRecordType.
- if (attrs.mangled_name)
- function_decl->addAttr(clang::AsmLabelAttr::CreateImplicit(
- m_ast.getASTContext(), attrs.mangled_name, /*literal=*/false));
-
LinkDeclContextToDIE(function_decl, die);
const clang::FunctionProtoType *function_prototype(
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 5b16ce5f75138..b781cff767e4f 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -2471,6 +2471,51 @@ bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die,
return false;
}
+llvm::Error SymbolFileDWARF::ResolveFunctionUID(SymbolContextList &sc_list,
+ lldb::user_id_t uid) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ auto die = GetDIE(uid);
+
+ if (!die.IsValid())
+ return llvm::createStringError("invalid input DIE");
+
+ // Look up by DW_AT_linkage_name if we can. Otherwise we can use the
+ // DW_AT_name.
+ char const *name = die.GetPubname();
+ if (!name)
+ return llvm::createStringError("input DIE has no name");
+
+ // If we're trying to resolve a function declaration DIE, find the definition.
+ if (die.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0)) {
+ Module::LookupInfo info(ConstString(name), lldb::eFunctionNameTypeMethod,
+ lldb::eLanguageTypeUnknown);
+
+ m_index->GetFunctions(info, *this, {}, [&](DWARFDIE entry) {
+ if (entry.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0))
+ return true;
+
+ if (auto spec = entry.GetAttributeValueAsReferenceDIE(
+ llvm::dwarf::DW_AT_specification);
+ spec == die) {
+ die = entry;
+ return false;
+ }
+
+ return true;
+ });
+ }
+
+ if (!ResolveFunction(die, false, sc_list))
+ return llvm::createStringError("failed to resolve function DIE");
+
+ if (sc_list.IsEmpty())
+ return llvm::createStringError("no definition DIE found");
+
+ assert(sc_list.GetSize() == 1);
+
+ return llvm::Error::success();
+}
+
bool SymbolFileDWARF::DIEInDeclContext(const CompilerDeclContext &decl_ctx,
const DWARFDIE &die,
bool only_root_namespaces) {
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index 2dc862cccca14..377d412825a6a 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -154,6 +154,9 @@ class SymbolFileDWARF : public SymbolFileCommon {
std::vector<CompilerContext>
GetCompilerContextForUID(lldb::user_id_t uid) override;
+ llvm::Error ResolveFunctionUID(SymbolContextList &sc_list,
+ lldb::user_id_t uid) override;
+
void ParseDeclsForContext(CompilerDeclContext decl_ctx) override;
uint32_t ResolveSymbolContext(const Address &so_addr,
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
index 702ec5e5c9ea9..bce721c149fee 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
@@ -88,7 +88,7 @@ struct CreateMethodDecl : public TypeVisitorCallbacks {
MethodOptions::CompilerGenerated;
function_decl = m_clang.AddMethodToCXXRecordType(
parent_ty, proc_name,
- /*mangled_name=*/nullptr, func_ct, /*access=*/access_type,
+ /*mangled_name=*/std::nullopt, func_ct, /*access=*/access_type,
/*is_virtual=*/is_virtual, /*is_static=*/is_static,
/*is_inline=*/false, /*is_explicit=*/false,
/*is_attr_used=*/false, /*is_artificial=*/is_artificial);
@@ -903,7 +903,7 @@ PdbAstBuilder::CreateFunctionDecl(PdbCompilandSymId func_id,
if (!function_decl) {
function_decl = m_clang.AddMethodToCXXRecordType(
parent_opaque_ty, func_name,
- /*mangled_name=*/nullptr, func_ct,
+ /*mangled_name=*/std::nullopt, func_ct,
/*access=*/lldb::AccessType::eAccessPublic,
/*is_virtual=*/false, /*is_static=*/false,
/*is_inline=*/false, /*is_explicit=*/false,
@@ -913,7 +913,7 @@ PdbAstBuilder::CreateFunctionDecl(PdbCompilandSymId func_id,
} else {
function_decl = m_clang.CreateFunctionDeclaration(
parent, OptionalClangModuleID(), func_name, func_ct, func_storage,
- is_inline);
+ is_inline, /*asm_label=*/std::nullopt);
CreateFunctionParameters(func_id, *function_decl, param_count);
}
return function_decl;
diff --git a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
index 0090d8ff03ab6..548a3ed25111f 100644
--- a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
+++ b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
@@ -954,7 +954,8 @@ PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol) {
auto decl = m_ast.CreateFunctionDeclaration(
decl_context, OptionalClangModuleID(), name,
- type->GetForwardCompilerType(), storage, func->hasInlineAttribute());
+ type->GetForwardCompilerType(), storage, func->hasInlineAttribute(),
+ /*asm_label=*/std::nullopt);
std::vector<clang::ParmVarDecl *> params;
if (std::unique_ptr<PDBSymbolTypeFunctionSig> sig = func->getSignature()) {
@@ -1446,8 +1447,8 @@ PDBASTParser::AddRecordMethod(lldb_private::SymbolFile &symbol_file,
// TODO: get mangled name for the method.
return m_ast.AddMethodToCXXRecordType(
record_type.GetOpaqueQualType(), name.c_str(),
- /*mangled_name*/ nullptr, method_comp_type, access, method.isVirtual(),
- method.isStatic(), method.hasInlineAttribute(),
+ /*mangled_name*/ std::nullopt, method_comp_type, access,
+ method.isVirtual(), method.isStatic(), method.hasInlineAttribute(),
/*is_explicit*/ false, // FIXME: Need this field in CodeView.
/*is_attr_used*/ false,
/*is_artificial*/ method.isCompilerGenerated());
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index e847ede1a4ba6..79b22257fff47 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -2137,7 +2137,8 @@ std::string TypeSystemClang::GetTypeNameForDecl(const NamedDecl *named_decl,
FunctionDecl *TypeSystemClang::CreateFunctionDeclaration(
clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module,
llvm::StringRef name, const CompilerType &function_clang_type,
- clang::StorageClass storage, bool is_inline) {
+ clang::StorageClass storage, bool is_inline,
+ std::optional<std::string> asm_label) {
FunctionDecl *func_decl = nullptr;
ASTContext &ast = getASTContext();
if (!decl_ctx)
@@ -2158,6 +2159,21 @@ FunctionDecl *TypeSystemClang::CreateFunctionDeclaration(
func_decl->setConstexprKind(isConstexprSpecified
? ConstexprSpecKind::Constexpr
: ConstexprSpecKind::Unspecified);
+
+ // Attach an asm(<mangled_name>) label to the FunctionDecl.
+ // This ensures that clang::CodeGen emits function calls
+ // using symbols that are mangled according to the DW_AT_linkage_name.
+ // If we didn't do this, the external symbols wouldn't exactly
+ // match the mangled name LLDB knows about and the IRExecutionUnit
+ // would have to fall back to searching object files for
+ // approximately matching function names. The motivating
+ // example is generating calls to ABI-tagged template functions.
+ // This is done separately for member functions in
+ // AddMethodToCXXRecordType.
+ if (asm_label)
+ func_decl->addAttr(clang::AsmLabelAttr::CreateImplicit(ast, *asm_label,
+ /*literal=*/false));
+
SetOwningModule(func_decl, owning_module);
decl_ctx->addDecl(func_decl);
@@ -7647,7 +7663,7 @@ TypeSystemClang::CreateParameterDeclarations(
clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType(
lldb::opaque_compiler_type_t type, llvm::StringRef name,
- const char *mangled_name, const CompilerType &method_clang_type,
+ std::optional<std::string> asm_label, const CompilerType &method_clang_type,
lldb::AccessType access, bool is_virtual, bool is_static, bool is_inline,
bool is_explicit, bool is_attr_used, bool is_artificial) {
if (!type || !method_clang_type.IsValid() || name.empty())
@@ -7780,10 +7796,9 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType(
if (is_attr_used)
cxx_method_decl->addAttr(clang::UsedAttr::CreateImplicit(getASTContext()));
- if (mangled_name != nullptr) {
+ if (asm_label)
cxx_method_decl->addAttr(clang::AsmLabelAttr::CreateImplicit(
- getASTContext(), mangled_name, /*literal=*/false));
- }
+ getASTContext(), *asm_label, /*literal=*/false));
// Parameters on member function declarations in DWARF generally don't
// have names, so we omit them when creating the ParmVarDecls.
@@ -9016,6 +9031,27 @@ bool TypeSystemClang::LayoutRecordType(
// CompilerDecl override functions
+// TODO: remove duplication with the ResolveFunctionCallLabel in
+// IRExecutionUnit.cpp
+static std::optional<llvm::StringRef>
+GetMangledNameFromLLDBFuncLabel(llvm::StringRef label) {
+ if (!consumeFunctionCallLabelPrefix(label))
+ return {};
+
+ if (!label.consume_front(":"))
+ return {};
+
+ // Expected format at this point is: <mangled name>:<module
+ // id>:<definition/declaration DIE id>
+ llvm::SmallVector<llvm::StringRef, 3> components;
+ label.split(components, ":");
+
+ if (components.size() != 3)
+ return {};
+
+ return components[0];
+}
+
ConstString TypeSystemClang::DeclGetName(void *opaque_decl) {
if (opaque_decl) {
clang::NamedDecl *nd =
@@ -9037,6 +9073,10 @@ ConstString TypeSystemClang::DeclGetMangledName(void *opaque_decl) {
if (!mc || !mc->shouldMangleCXXName(nd))
return {};
+ if (const auto *label = nd->getAttr<AsmLabelAttr>())
+ if (auto name = GetMangledNameFromLLDBFuncLabel(label->getLabel()))
+ return ConstString(*name);
+
llvm::SmallVector<char, 1024> buf;
llvm::raw_svector_ostream llvm_ostrm(buf);
if (llvm::isa<clang::CXXConstructorDecl>(nd)) {
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index 63dee9dceded3..dcf77f9ec1cb8 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -477,7 +477,8 @@ class TypeSystemClang : public TypeSystem {
clang::FunctionDecl *CreateFunctionDeclaration(
clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module,
llvm::StringRef name, const CompilerType &function_Type,
- clang::StorageClass storage, bool is_inline);
+ clang::StorageClass storage, bool is_inline,
+ std::optional<std::string> asm_label);
CompilerType
CreateFunctionType(const CompilerType &result_type,
@@ -1001,7 +1002,7 @@ class TypeSystemClang : public TypeSystem {
clang::CXXMethodDecl *AddMethodToCXXRecordType(
lldb::opaque_compiler_type_t type, llvm::StringRef name,
- const char *mangled_name, const CompilerType &method_type,
+ std::optional<std::string> mangled_name, const CompilerType &method_type,
lldb::AccessType access, bool is_virtual, bool is_static, bool is_inline,
bool is_explicit, bool is_attr_used, bool is_artificial);
diff --git a/lldb/unittests/Symbol/TestTypeSystemClang.cpp b/lldb/unittests/Symbol/TestTypeSystemClang.cpp
index d555d27bef958..c0428a62f7b3d 100644
--- a/lldb/unittests/Symbol/TestTypeSystemClang.cpp
+++ b/lldb/unittests/Symbol/TestTypeSystemClang.cpp
@@ -869,7 +869,7 @@ TEST_F(TestTypeSystemClang, TestFunctionTemplateConstruction) {
CompilerType clang_type = m_ast->CreateFunctionType(int_type, {}, false, 0U);
FunctionDecl *func = m_ast->CreateFunctionDeclaration(
TU, OptionalClangModuleID(), "foo", clang_type, StorageClass::SC_None,
- false);
+ false, std::nullopt);
TypeSystemClang::TemplateParameterInfos empty_params;
// Create the actual function template.
@@ -900,7 +900,7 @@ TEST_F(TestTypeSystemClang, TestFunctionTemplateInRecordConstruction) {
// 2. It is mirroring the behavior of DWARFASTParserClang::ParseSubroutine.
FunctionDecl *func = m_ast->CreateFunctionDeclaration(
TU, OptionalClangModuleID(), "foo", clang_type, StorageClass::SC_None,
- false);
+ false, std::nullopt);
TypeSystemClang::TemplateParameterInfos empty_params;
// Create the actual function template.
@@ -938,7 +938,7 @@ TEST_F(TestTypeSystemClang, TestDeletingImplicitCopyCstrDueToMoveCStr) {
bool is_attr_used = false;
bool is_artificial = false;
m_ast->AddMethodToCXXRecordType(
- t.GetOpaqueQualType(), class_name, nullptr, function_type,
+ t.GetOpaqueQualType(), class_name, std::nullopt, function_type,
lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline,
is_explicit, is_attr_used, is_artificial);
@@ -975,7 +975,7 @@ TEST_F(TestTypeSystemClang, TestNotDeletingUserCopyCstrDueToMoveCStr) {
CompilerType function_type = m_ast->CreateFunctionType(
return_type, args, /*variadic=*/false, /*quals*/ 0U);
m_ast->AddMethodToCXXRecordType(
- t.GetOpaqueQualType(), class_name, nullptr, function_type,
+ t.GetOpaqueQualType(), class_name, std::nullopt, function_type,
lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline,
is_explicit, is_attr_used, is_artificial);
}
@@ -987,7 +987,7 @@ TEST_F(TestTypeSystemClang, TestNotDeletingUserCopyCstrDueToMoveCStr) {
m_ast->CreateFunctionType(return_type, args,
/*variadic=*/false, /*quals*/ 0U);
m_ast->AddMethodToCXXRecordType(
- t.GetOpaqueQualType(), class_name, nullptr, function_type,
+ t.GetOpaqueQualType(), class_name, std::nullopt, function_type,
lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline,
is_explicit, is_attr_used, is_artificial);
}
@@ -1098,7 +1098,7 @@ TEST_F(TestTypeSystemClang, AddMethodToCXXRecordType_ParmVarDecls) {
m_ast->CreateFunctionType(return_type, param_types,
/*variadic=*/false, /*quals*/ 0U);
m_ast->AddMethodToCXXRecordType(
- t.GetOpaqueQualType(), "myFunc", nullptr, function_type,
+ t.GetOpaqueQualType(), "myFunc", std::nullopt, function_type,
lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline,
is_explicit, is_attr_used, is_artificial);
More information about the lldb-commits
mailing list