[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
Thu Jul 17 06:15:35 PDT 2025
https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/148877
>From 31d9f127ede936a525e8a1630a0d910a2eef0369 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/Expression/Expression.h | 6 +
lldb/include/lldb/Symbol/SymbolFile.h | 6 +
lldb/source/Expression/Expression.cpp | 5 +
lldb/source/Expression/IRExecutionUnit.cpp | 119 ++++++++++++++++++
.../Clang/ClangExpressionDeclMap.cpp | 2 +-
.../Language/CPlusPlus/CPlusPlusLanguage.cpp | 5 +
.../SymbolFile/DWARF/DWARFASTParserClang.cpp | 59 ++++++---
.../SymbolFile/DWARF/SymbolFileDWARF.cpp | 52 ++++++++
.../SymbolFile/DWARF/SymbolFileDWARF.h | 5 +
.../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 +-
14 files changed, 302 insertions(+), 37 deletions(-)
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..c52da2d54b1e2 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,11 @@ class SymbolFile : public PluginInterface {
GetMangledNamesForFunction(const std::string &scope_qualified_name,
std::vector<ConstString> &mangled_names);
+ 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/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..01052b56d1f6f 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -20,6 +20,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"
@@ -771,6 +772,120 @@ class LoadAddressResolver {
lldb::addr_t m_best_internal_load_address = LLDB_INVALID_ADDRESS;
};
+/// Returns the \c lldb_private::Module referred to by \c module.
+///
+/// \param[in] module Module UUID or integer uniquely identifying the module.
+/// \param[in] target Target that the module referred to by \c module lives in.
+static llvm::Expected<Module *> GetModulePtr(llvm::StringRef module,
+ Target &target) {
+ // TODO: instead of using a pointer use a freshly assigned UID that LLDB
+ // assigns to a module.
+ uintptr_t module_ptr = 0;
+ if (module.starts_with("0x") && !module.consumeInteger(0, module_ptr) &&
+ module_ptr != 0)
+ return reinterpret_cast<Module *>(module_ptr);
+
+ UUID module_uuid;
+ if (!module_uuid.SetFromStringRef(module) || !module_uuid.IsValid())
+ return llvm::createStringError("failed to create Module UUID from '%s'",
+ module.data());
+
+ Module *found_module = target.GetImages().FindModule(module_uuid).get();
+ if (!found_module)
+ return llvm::createStringError("failed to find module with UUID '{0}'",
+ module.data());
+
+ return found_module;
+}
+
+/// 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 lldb::addr_t
+ResolveFunctionCallLabel(llvm::StringRef label,
+ const lldb_private::SymbolContext &sc,
+ bool &symbol_was_missing_weak) {
+ symbol_was_missing_weak = false;
+
+ Target *target = sc.target_sp.get();
+ if (!target) {
+ LLDB_LOG(GetLog(LLDBLog::Expressions),
+ "Failed to resolve function label '{0}': target not available.",
+ label);
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ // Expected format at this point is:
+ // :<mangled name>:<module id>:<definition/declaration DIE id>
+
+ if (!label.consume_front(":")) {
+ LLDB_LOG(GetLog(LLDBLog::Expressions),
+ "Failed to resolve function label '{0}': incorrect format: "
+ "expected ':' as the first character.",
+ label);
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ // 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) {
+ LLDB_LOG(GetLog(LLDBLog::Expressions),
+ "Failed to resolve function label '{0}': incorrect format: too "
+ "many label subcomponents.",
+ label);
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ const llvm::StringRef module_label = components[1];
+ llvm::StringRef die = components[2];
+
+ auto found_module_or_err = GetModulePtr(module_label, *target);
+ if (!found_module_or_err) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Expressions),
+ found_module_or_err.takeError(),
+ "Failed to resolve function label {1}: {0}", label);
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ Module *found_module = *found_module_or_err;
+
+ lldb::user_id_t die_id;
+ if (die.consumeInteger(/*Radix=*/0, die_id)) {
+ LLDB_LOG(GetLog(LLDBLog::Expressions),
+ "Failed to resolve function label '{0}': failed to parse DIE ID "
+ "for '{1}'.",
+ label, components[2]);
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ auto *symbol_file = found_module->GetSymbolFile();
+ if (!symbol_file) {
+ LLDB_LOG(GetLog(LLDBLog::Expressions),
+ "Failed to resolve function label '{0}': no SymbolFile found on "
+ "module.",
+ label);
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ // TODO: API should return SC list item and we should push it back to sc_list
+ // here. In that case we wouldn't need the sc_list size checks below...
+ SymbolContextList sc_list;
+ if (auto err = symbol_file->ResolveFunctionUID(sc_list, die_id)) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Expressions), std::move(err),
+ "Failed to resolve function by UID: {0}");
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ LoadAddressResolver resolver(target, 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 +1021,10 @@ 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))
+ return ResolveFunctionCallLabel(name_ref, m_sym_ctx, missing_weak);
+
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/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index a8ebde0b55815..cfa2f63cc41de 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -400,6 +400,11 @@ bool CPlusPlusLanguage::CxxMethodName::TrySimplifiedParse() {
// A::B::C::fun(std::vector<T> &) const
size_t arg_start, arg_end;
llvm::StringRef full(m_full.GetCString());
+
+ // TODO: check for "operator" in IsTrivialBasename
+ // if (full.starts_with("operator()"))
+ // return false;
+
llvm::StringRef parens("()", 2);
if (ReverseFindMatchingChars(full, parens, arg_start, arg_end)) {
m_arguments = full.substr(arg_start, arg_end - arg_start + 1);
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index c76d67b47b336..a7cbc794c744d 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,44 @@ static unsigned GetCXXMethodCVQuals(const DWARFDIE &subprogram,
return cv_quals;
}
+// TODO:
+// 0. Adjust FindInSymbols
+// 1. log failure paths
+// 2. What happens for functions without a linkage name? Previously we didn't
+// attach a label for those but now we would
+// 3. Unit-test
+// 4. API test (whilch checks expr and AST dump)
+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 label;
+
+ // Module UID is only a Darwin concept (?)
+ // If UUID is not available encode as pointer.
+ // Maybe add character to signal whether this is a pointer
+ // or UUID. Or maybe if it's not hex that implies a UUID?
+ auto module_id = module_sp->GetUUID();
+ Module *module_ptr = nullptr;
+ if (!module_id.IsValid())
+ module_ptr = module_sp.get();
+
+ const auto die_id = die.GetID();
+ if (die_id == LLDB_INVALID_UID)
+ return label;
+
+ return llvm::formatv("{0}:{1}:{2}:{3:x}", FunctionCallLabelPrefix,
+ mangled ? mangled : "",
+ module_ptr ? llvm::formatv("{0:x}", module_ptr).str()
+ : module_id.GetAsString(),
+ die_id)
+ .str();
+}
+
TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc,
const DWARFDIE &die,
Log *log) {
@@ -1231,7 +1270,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 +1423,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 +1433,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 +1445,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..dea0ec7ad509a 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -11,6 +11,7 @@
#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
#include "llvm/Support/Casting.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/FormatAdapters.h"
#include "llvm/Support/Threading.h"
@@ -22,6 +23,7 @@
#include "lldb/Core/Progress.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/Value.h"
+#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/RegularExpression.h"
@@ -73,6 +75,7 @@
#include "ManualDWARFIndex.h"
#include "SymbolFileDWARFDebugMap.h"
#include "SymbolFileDWARFDwo.h"
+#include "lldb/lldb-enumerations.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
@@ -2471,6 +2474,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(
+ llvm::formatv("{0}: invalid input DIE", __func__));
+
+ // TODO: clang indexes by mangled name too...so could technically look up
+ // by mangled name....but GCC doesn't do that
+ char const *name = die.GetMangledName(/*substitute_name_allowed=*/true);
+ if (!name)
+ return llvm::createStringError(
+ llvm::formatv("{0}: input DIE has no name", __func__));
+
+ 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(
+ llvm::formatv("{0}: failed to resolve function DIE", __func__));
+
+ if (sc_list.IsEmpty())
+ return llvm::createStringError(
+ llvm::formatv("{0}: no definition DIE found", __func__));
+
+ assert(sc_list.GetSize() == 1);
+
+ return llvm::Error::success();
+}
+
bool SymbolFileDWARF::DIEInDeclContext(const CompilerDeclContext &decl_ctx,
const DWARFDIE &die,
bool only_root_namespaces) {
@@ -2958,6 +3006,10 @@ TypeSP SymbolFileDWARF::FindCompleteObjCDefinitionTypeForDIE(
return type_sp;
}
+// llvm::Expected<DWARFDIE>
+// SymbolFileDWARF::FindFunctionDefinitionDIE(const DWARFDIE &die) {
+// }
+
DWARFDIE
SymbolFileDWARF::FindDefinitionDIE(const DWARFDIE &die) {
const char *name = die.GetName();
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index 2dc862cccca14..f3f6d565f3d4a 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -374,6 +374,8 @@ class SymbolFileDWARF : public SymbolFileCommon {
SymbolFileDWARF(const SymbolFileDWARF &) = delete;
const SymbolFileDWARF &operator=(const SymbolFileDWARF &) = delete;
+ // llvm::Expected<DWARFDIE> FindFunctionDefinitionDIE(const DWARFDIE &die);
+
virtual void LoadSectionData(lldb::SectionType sect_type,
DWARFDataExtractor &data);
@@ -438,6 +440,9 @@ class SymbolFileDWARF : public SymbolFileCommon {
bool ResolveFunction(const DWARFDIE &die, bool include_inlines,
SymbolContextList &sc_list);
+ llvm::Error ResolveFunctionUID(SymbolContextList &sc_list,
+ lldb::user_id_t uid) override;
+
/// Resolve functions and (possibly) blocks for the given file address and a
/// compile unit. The compile unit comes from the sc argument and it must be
/// set. The results of the lookup (if any) are written back to the symbol
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