https://github.com/Michael137 updated 
https://github.com/llvm/llvm-project/pull/149827

>From fd6b6e8a3168fc233635e783773554ac980edb46 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Fri, 15 Nov 2024 01:59:36 +0000
Subject: [PATCH 1/5] [lldb][Expression] Encode Module and DIE UIDs into
 function AsmLabels

---
 lldb/include/lldb/Core/Module.h               |  4 +-
 lldb/include/lldb/Expression/Expression.h     | 25 ++++++
 lldb/include/lldb/Symbol/SymbolFile.h         | 14 ++++
 lldb/include/lldb/Symbol/TypeSystem.h         | 16 ++++
 lldb/source/Core/Module.cpp                   | 19 ++++-
 lldb/source/Expression/Expression.cpp         | 16 ++++
 lldb/source/Expression/IRExecutionUnit.cpp    | 74 +++++++++++++++++
 .../Clang/ClangExpressionDeclMap.cpp          |  2 +-
 .../SymbolFile/DWARF/DWARFASTParserClang.cpp  | 43 ++++++----
 .../SymbolFile/DWARF/SymbolFileDWARF.cpp      | 41 ++++++++++
 .../SymbolFile/DWARF/SymbolFileDWARF.h        |  3 +
 .../SymbolFile/NativePDB/PdbAstBuilder.cpp    |  6 +-
 .../NativePDB/UdtRecordCompleter.cpp          |  5 +-
 .../Plugins/SymbolFile/PDB/PDBASTParser.cpp   |  7 +-
 .../TypeSystem/Clang/TypeSystemClang.cpp      | 81 +++++++++++++++++--
 .../TypeSystem/Clang/TypeSystemClang.h        | 11 ++-
 lldb/unittests/Symbol/TestTypeSystemClang.cpp | 12 +--
 17 files changed, 335 insertions(+), 44 deletions(-)

diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h
index 8bb55c95773bc..3991a12997541 100644
--- a/lldb/include/lldb/Core/Module.h
+++ b/lldb/include/lldb/Core/Module.h
@@ -86,7 +86,8 @@ struct ModuleFunctionSearchOptions {
 ///
 /// The module will parse more detailed information as more queries are made.
 class Module : public std::enable_shared_from_this<Module>,
-               public SymbolContextScope {
+               public SymbolContextScope,
+               public UserID {
 public:
   class LookupInfo;
   // Static functions that can track the lifetime of module objects. This is
@@ -97,6 +98,7 @@ class Module : public std::enable_shared_from_this<Module>,
   // using the "--global" (-g for short).
   static size_t GetNumberAllocatedModules();
 
+  static Module *GetAllocatedModuleWithUID(lldb::user_id_t uid);
   static Module *GetAllocatedModuleAtIndex(size_t idx);
 
   static std::recursive_mutex &GetAllocationModuleCollectionMutex();
diff --git a/lldb/include/lldb/Expression/Expression.h 
b/lldb/include/lldb/Expression/Expression.h
index 8de9364436ccf..f32878c9bf876 100644
--- a/lldb/include/lldb/Expression/Expression.h
+++ b/lldb/include/lldb/Expression/Expression.h
@@ -96,6 +96,31 @@ class Expression {
                                  ///invalid.
 };
 
+/// Holds parsed information about a function call label that
+/// LLDB attaches as an AsmLabel to function AST nodes it parses
+/// from debug-info.
+///
+/// The format being:
+///
+///   <prefix>:<mangled name>:<module id>:<DIE id>
+///
+/// The label string needs to stay valid for the entire lifetime
+/// of this object.
+struct FunctionCallLabel {
+  llvm::StringRef m_lookup_name;
+  lldb::user_id_t m_module_id;
+
+  /// Mostly for debuggability.
+  lldb::user_id_t m_die_id;
+};
+
+/// LLDB attaches this prefix to mangled names of functions that it get called
+/// from JITted expressions.
+inline constexpr llvm::StringRef FunctionCallLabelPrefix = "$__lldb_func";
+
+bool consumeFunctionCallLabelPrefix(llvm::StringRef &name);
+bool hasFunctionCallLabelPrefix(llvm::StringRef name);
+
 } // namespace lldb_private
 
 #endif // LLDB_EXPRESSION_EXPRESSION_H
diff --git a/lldb/include/lldb/Symbol/SymbolFile.h 
b/lldb/include/lldb/Symbol/SymbolFile.h
index e95f95553c17c..6aca276fc85b6 100644
--- a/lldb/include/lldb/Symbol/SymbolFile.h
+++ b/lldb/include/lldb/Symbol/SymbolFile.h
@@ -18,6 +18,7 @@
 #include "lldb/Symbol/CompilerType.h"
 #include "lldb/Symbol/Function.h"
 #include "lldb/Symbol/SourceModule.h"
+#include "lldb/Symbol/SymbolContext.h"
 #include "lldb/Symbol/Type.h"
 #include "lldb/Symbol/TypeList.h"
 #include "lldb/Symbol/TypeSystem.h"
@@ -328,6 +329,19 @@ class SymbolFile : public PluginInterface {
   GetMangledNamesForFunction(const std::string &scope_qualified_name,
                              std::vector<ConstString> &mangled_names);
 
+  /// Resolves the function DIE identified by \c lookup_name within
+  /// this SymbolFile.
+  ///
+  /// \param[in,out] sc_list The resolved functions will be appended to this
+  /// list.
+  ///
+  /// \param[in] lookup_name The UID of the function DIE to resolve.
+  ///
+  virtual llvm::Error FindAndResolveFunction(SymbolContextList &sc_list,
+                                             llvm::StringRef lookup_name) {
+    return llvm::createStringError("Not implemented");
+  }
+
   virtual void GetTypes(lldb_private::SymbolContextScope *sc_scope,
                         lldb::TypeClass type_mask,
                         lldb_private::TypeList &type_list) = 0;
diff --git a/lldb/include/lldb/Symbol/TypeSystem.h 
b/lldb/include/lldb/Symbol/TypeSystem.h
index cb1f0130b548d..742c09251ea2f 100644
--- a/lldb/include/lldb/Symbol/TypeSystem.h
+++ b/lldb/include/lldb/Symbol/TypeSystem.h
@@ -548,6 +548,22 @@ class TypeSystem : public PluginInterface,
   bool GetHasForcefullyCompletedTypes() const {
     return m_has_forcefully_completed_types;
   }
+
+  /// Returns the components of the specified function call label.
+  ///
+  /// The format of \c label is described in \c FunctionCallLabel.
+  /// The label prefix is not one of the components.
+  virtual llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>>
+  splitFunctionCallLabel(llvm::StringRef label) const {
+    return llvm::createStringError("Not implemented.");
+  }
+
+  // Decodes the function label into a \c FunctionCallLabel.
+  virtual llvm::Expected<FunctionCallLabel>
+  makeFunctionCallLabel(llvm::StringRef label) const {
+    return llvm::createStringError("Not implemented.");
+  }
+
 protected:
   SymbolFile *m_sym_file = nullptr;
   /// Used for reporting statistics.
diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp
index 90997dada3666..edd79aff5d065 100644
--- a/lldb/source/Core/Module.cpp
+++ b/lldb/source/Core/Module.cpp
@@ -121,6 +121,15 @@ size_t Module::GetNumberAllocatedModules() {
   return GetModuleCollection().size();
 }
 
+Module *Module::GetAllocatedModuleWithUID(lldb::user_id_t uid) {
+  std::lock_guard<std::recursive_mutex> guard(
+      GetAllocationModuleCollectionMutex());
+  for (Module *mod : GetModuleCollection())
+    if (mod->GetID() == uid)
+      return mod;
+  return nullptr;
+}
+
 Module *Module::GetAllocatedModuleAtIndex(size_t idx) {
   std::lock_guard<std::recursive_mutex> guard(
       GetAllocationModuleCollectionMutex());
@@ -130,8 +139,11 @@ Module *Module::GetAllocatedModuleAtIndex(size_t idx) {
   return nullptr;
 }
 
+// TODO: needs a mutex
+static lldb::user_id_t g_unique_id = 1;
+
 Module::Module(const ModuleSpec &module_spec)
-    : m_unwind_table(*this), m_file_has_changed(false),
+    : UserID(g_unique_id++), m_unwind_table(*this), m_file_has_changed(false),
       m_first_file_changed_log(false) {
   // Scope for locker below...
   {
@@ -236,7 +248,8 @@ Module::Module(const ModuleSpec &module_spec)
 Module::Module(const FileSpec &file_spec, const ArchSpec &arch,
                ConstString object_name, lldb::offset_t object_offset,
                const llvm::sys::TimePoint<> &object_mod_time)
-    : m_mod_time(FileSystem::Instance().GetModificationTime(file_spec)),
+    : UserID(g_unique_id++),
+      m_mod_time(FileSystem::Instance().GetModificationTime(file_spec)),
       m_arch(arch), m_file(file_spec), m_object_name(object_name),
       m_object_offset(object_offset), m_object_mod_time(object_mod_time),
       m_unwind_table(*this), m_file_has_changed(false),
@@ -257,7 +270,7 @@ Module::Module(const FileSpec &file_spec, const ArchSpec 
&arch,
 }
 
 Module::Module()
-    : m_unwind_table(*this), m_file_has_changed(false),
+    : UserID(g_unique_id++), m_unwind_table(*this), m_file_has_changed(false),
       m_first_file_changed_log(false) {
   std::lock_guard<std::recursive_mutex> guard(
       GetAllocationModuleCollectionMutex());
diff --git a/lldb/source/Expression/Expression.cpp 
b/lldb/source/Expression/Expression.cpp
index 93f585edfce3d..e19c804caa3c6 100644
--- a/lldb/source/Expression/Expression.cpp
+++ b/lldb/source/Expression/Expression.cpp
@@ -10,6 +10,10 @@
 #include "lldb/Target/ExecutionContextScope.h"
 #include "lldb/Target/Target.h"
 
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+
 using namespace lldb_private;
 
 Expression::Expression(Target &target)
@@ -26,3 +30,15 @@ Expression::Expression(ExecutionContextScope &exe_scope)
       m_jit_end_addr(LLDB_INVALID_ADDRESS) {
   assert(m_target_wp.lock());
 }
+
+bool lldb_private::consumeFunctionCallLabelPrefix(llvm::StringRef &name) {
+  // On Darwin mangled names get a '_' prefix.
+  name.consume_front("_");
+  return name.consume_front(FunctionCallLabelPrefix);
+}
+
+bool lldb_private::hasFunctionCallLabelPrefix(llvm::StringRef name) {
+  // On Darwin mangled names get a '_' prefix.
+  name.consume_front("_");
+  return name.starts_with(FunctionCallLabelPrefix);
+}
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp 
b/lldb/source/Expression/IRExecutionUnit.cpp
index 6f812b91a8b1d..a9ea244889cce 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -13,6 +13,7 @@
 #include "llvm/IR/DiagnosticInfo.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Module.h"
+#include "llvm/Support/Error.h"
 #include "llvm/Support/SourceMgr.h"
 #include "llvm/Support/raw_ostream.h"
 
@@ -20,6 +21,7 @@
 #include "lldb/Core/Disassembler.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Core/Section.h"
+#include "lldb/Expression/Expression.h"
 #include "lldb/Expression/IRExecutionUnit.h"
 #include "lldb/Expression/ObjectFileJIT.h"
 #include "lldb/Host/HostInfo.h"
@@ -36,6 +38,7 @@
 #include "lldb/Utility/LLDBAssert.h"
 #include "lldb/Utility/LLDBLog.h"
 #include "lldb/Utility/Log.h"
+#include "lldb/lldb-defines.h"
 
 #include <optional>
 
@@ -771,6 +774,63 @@ class LoadAddressResolver {
   lldb::addr_t m_best_internal_load_address = LLDB_INVALID_ADDRESS;
 };
 
+/// Returns address of the function referred to by the special function call
+/// label \c label.
+///
+/// \param[in] label Function call label encoding the unique location of the
+/// function to look up.
+///                  Assumes that the \c FunctionCallLabelPrefix has been
+///                  stripped from the front of the label.
+static llvm::Expected<lldb::addr_t>
+ResolveFunctionCallLabel(llvm::StringRef name,
+                         const lldb_private::SymbolContext &sc,
+                         bool &symbol_was_missing_weak) {
+  symbol_was_missing_weak = false;
+
+  if (!sc.target_sp)
+    return llvm::createStringError("target not available.");
+
+  auto ts_or_err = sc.target_sp->GetScratchTypeSystemForLanguage(
+      lldb::eLanguageTypeC_plus_plus);
+  if (!ts_or_err || !*ts_or_err)
+    return llvm::joinErrors(
+        llvm::createStringError(
+            "failed to find scratch C++ TypeSystem for current target."),
+        ts_or_err.takeError());
+
+  auto ts_sp = *ts_or_err;
+
+  auto label_or_err = ts_sp->makeFunctionCallLabel(name);
+  if (!label_or_err)
+    return llvm::joinErrors(
+        llvm::createStringError("failed to create FunctionCallLabel from: %s",
+                                name.data()),
+        label_or_err.takeError());
+
+  const auto &label = *label_or_err;
+
+  Module *module = Module::GetAllocatedModuleWithUID(label.m_module_id);
+
+  if (!module)
+    return llvm::createStringError(
+        llvm::formatv("failed to find module by UID {0}", label.m_module_id));
+
+  auto *symbol_file = module->GetSymbolFile();
+  if (!symbol_file)
+    return llvm::createStringError(
+        llvm::formatv("no SymbolFile found on module {0:x}.", module));
+
+  SymbolContextList sc_list;
+  if (auto err =
+          symbol_file->FindAndResolveFunction(sc_list, label.m_lookup_name))
+    return llvm::joinErrors(
+        llvm::createStringError("failed to resolve function by UID"),
+        std::move(err));
+
+  LoadAddressResolver resolver(*sc.target_sp, symbol_was_missing_weak);
+  return resolver.Resolve(sc_list).value_or(LLDB_INVALID_ADDRESS);
+}
+
 lldb::addr_t
 IRExecutionUnit::FindInSymbols(const std::vector<ConstString> &names,
                                const lldb_private::SymbolContext &sc,
@@ -906,6 +966,20 @@ lldb::addr_t IRExecutionUnit::FindInUserDefinedSymbols(
 
 lldb::addr_t IRExecutionUnit::FindSymbol(lldb_private::ConstString name,
                                          bool &missing_weak) {
+  if (hasFunctionCallLabelPrefix(name.GetStringRef())) {
+    if (auto addr_or_err = ResolveFunctionCallLabel(name.GetStringRef(),
+                                                    m_sym_ctx, missing_weak)) {
+      return *addr_or_err;
+    } else {
+      LLDB_LOG_ERROR(GetLog(LLDBLog::Expressions), addr_or_err.takeError(),
+                     "Failed to resolve function call label {1}: {0}",
+                     name.GetStringRef());
+      return LLDB_INVALID_ADDRESS;
+    }
+  }
+
+  // TODO: do we still need the following lookups?
+
   std::vector<ConstString> candidate_C_names;
   std::vector<ConstString> candidate_CPlusPlus_names;
 
diff --git 
a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp 
b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
index 9f77fbc1d2434..a6c4334bf2e59 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
@@ -1991,7 +1991,7 @@ void 
ClangExpressionDeclMap::AddContextClassType(NameSearchContext &context,
     const bool is_artificial = false;
 
     CXXMethodDecl *method_decl = m_clang_ast_context->AddMethodToCXXRecordType(
-        copied_clang_type.GetOpaqueQualType(), "$__lldb_expr", nullptr,
+        copied_clang_type.GetOpaqueQualType(), "$__lldb_expr", std::nullopt,
         method_type, lldb::eAccessPublic, is_virtual, is_static, is_inline,
         is_explicit, is_attr_used, is_artificial);
 
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp 
b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index c76d67b47b336..6e9598c13ed5c 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -24,6 +24,7 @@
 #include "Plugins/Language/ObjC/ObjCLanguage.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Core/Value.h"
+#include "lldb/Expression/Expression.h"
 #include "lldb/Host/Host.h"
 #include "lldb/Symbol/CompileUnit.h"
 #include "lldb/Symbol/Function.h"
@@ -249,6 +250,28 @@ static unsigned GetCXXMethodCVQuals(const DWARFDIE 
&subprogram,
   return cv_quals;
 }
 
+static std::optional<std::string> MakeLLDBFuncAsmLabel(const DWARFDIE &die) {
+  char const *name = die.GetMangledName(/*substitute_name_allowed*/ false);
+  if (!name)
+    return std::nullopt;
+
+  auto module_sp = die.GetModule();
+  if (!module_sp)
+    return std::nullopt;
+
+  lldb::user_id_t module_id = module_sp->GetID();
+  if (module_id == LLDB_INVALID_UID)
+    return std::nullopt;
+
+  const auto die_id = die.GetID();
+  if (die_id == LLDB_INVALID_UID)
+    return std::nullopt;
+
+  return llvm::formatv("{0}:{1}:{2:x}:{3:x}", FunctionCallLabelPrefix, name,
+                       module_id, die_id)
+      .str();
+}
+
 TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc,
                                                      const DWARFDIE &die,
                                                      Log *log) {
@@ -1231,7 +1254,7 @@ std::pair<bool, TypeSP> 
DWARFASTParserClang::ParseCXXMethod(
 
   clang::CXXMethodDecl *cxx_method_decl = m_ast.AddMethodToCXXRecordType(
       class_opaque_type.GetOpaqueQualType(), attrs.name.GetCString(),
-      attrs.mangled_name, clang_type, accessibility, attrs.is_virtual,
+      MakeLLDBFuncAsmLabel(die), clang_type, accessibility, attrs.is_virtual,
       is_static, attrs.is_inline, attrs.is_explicit, is_attr_used,
       attrs.is_artificial);
 
@@ -1384,7 +1407,7 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
             ignore_containing_context ? m_ast.GetTranslationUnitDecl()
                                       : containing_decl_ctx,
             GetOwningClangModule(die), name, clang_type, attrs.storage,
-            attrs.is_inline);
+            attrs.is_inline, MakeLLDBFuncAsmLabel(die));
         std::free(name_buf);
 
         if (has_template_params) {
@@ -1394,7 +1417,7 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
               ignore_containing_context ? m_ast.GetTranslationUnitDecl()
                                         : containing_decl_ctx,
               GetOwningClangModule(die), attrs.name.GetStringRef(), clang_type,
-              attrs.storage, attrs.is_inline);
+              attrs.storage, attrs.is_inline, /*asm_label=*/std::nullopt);
           clang::FunctionTemplateDecl *func_template_decl =
               m_ast.CreateFunctionTemplateDecl(
                   containing_decl_ctx, GetOwningClangModule(die),
@@ -1406,20 +1429,6 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
         lldbassert(function_decl);
 
         if (function_decl) {
-          // Attach an asm(<mangled_name>) label to the FunctionDecl.
-          // This ensures that clang::CodeGen emits function calls
-          // using symbols that are mangled according to the 
DW_AT_linkage_name.
-          // If we didn't do this, the external symbols wouldn't exactly
-          // match the mangled name LLDB knows about and the IRExecutionUnit
-          // would have to fall back to searching object files for
-          // approximately matching function names. The motivating
-          // example is generating calls to ABI-tagged template functions.
-          // This is done separately for member functions in
-          // AddMethodToCXXRecordType.
-          if (attrs.mangled_name)
-            function_decl->addAttr(clang::AsmLabelAttr::CreateImplicit(
-                m_ast.getASTContext(), attrs.mangled_name, /*literal=*/false));
-
           LinkDeclContextToDIE(function_decl, die);
 
           const clang::FunctionProtoType *function_prototype(
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp 
b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 5b16ce5f75138..b6960bfe38fde 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -2471,6 +2471,47 @@ bool SymbolFileDWARF::ResolveFunction(const DWARFDIE 
&orig_die,
   return false;
 }
 
+llvm::Error
+SymbolFileDWARF::FindAndResolveFunction(SymbolContextList &sc_list,
+                                        llvm::StringRef lookup_name) {
+  std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+
+  DWARFDIE die;
+  Module::LookupInfo info(ConstString(lookup_name), 
lldb::eFunctionNameTypeFull,
+                          lldb::eLanguageTypeUnknown);
+
+  m_index->GetFunctions(info, *this, {}, [&](DWARFDIE entry) {
+    if (entry.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0))
+      return true;
+
+    // We don't check whether the specification DIE for this function
+    // corresponds to the declaration DIE because the declaration might be in
+    // a type-unit but the definition in the compile-unit (and it's
+    // specifcation would point to the declaration in the compile-unit). We
+    // rely on the mangled name within the module to be enough to find us the
+    // unique definition.
+    die = entry;
+    return false;
+  });
+
+  if (!die.IsValid())
+    return llvm::createStringError(
+        llvm::formatv("failed to find definition DIE for '{0}'", lookup_name));
+
+  if (!ResolveFunction(die, false, sc_list))
+    return llvm::createStringError("failed to resolve function DIE");
+
+  if (sc_list.IsEmpty())
+    return llvm::createStringError("no definition DIE found");
+
+  if (sc_list.GetSize() > 1)
+    return llvm::createStringError(
+        "found %d functions for %s but expected only 1", sc_list.GetSize(),
+        lookup_name.data());
+
+  return llvm::Error::success();
+}
+
 bool SymbolFileDWARF::DIEInDeclContext(const CompilerDeclContext &decl_ctx,
                                        const DWARFDIE &die,
                                        bool only_root_namespaces) {
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h 
b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index 2dc862cccca14..ee966366d3f2b 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -434,6 +434,9 @@ class SymbolFileDWARF : public SymbolFileCommon {
   DIEArray MergeBlockAbstractParameters(const DWARFDIE &block_die,
                                         DIEArray &&variable_dies);
 
+  llvm::Error FindAndResolveFunction(SymbolContextList &sc_list,
+                                     llvm::StringRef lookup_name) override;
+
   // Given a die_offset, figure out the symbol context representing that die.
   bool ResolveFunction(const DWARFDIE &die, bool include_inlines,
                        SymbolContextList &sc_list);
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp 
b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
index 702ec5e5c9ea9..bce721c149fee 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
@@ -88,7 +88,7 @@ struct CreateMethodDecl : public TypeVisitorCallbacks {
                          MethodOptions::CompilerGenerated;
     function_decl = m_clang.AddMethodToCXXRecordType(
         parent_ty, proc_name,
-        /*mangled_name=*/nullptr, func_ct, /*access=*/access_type,
+        /*mangled_name=*/std::nullopt, func_ct, /*access=*/access_type,
         /*is_virtual=*/is_virtual, /*is_static=*/is_static,
         /*is_inline=*/false, /*is_explicit=*/false,
         /*is_attr_used=*/false, /*is_artificial=*/is_artificial);
@@ -903,7 +903,7 @@ PdbAstBuilder::CreateFunctionDecl(PdbCompilandSymId func_id,
     if (!function_decl) {
       function_decl = m_clang.AddMethodToCXXRecordType(
           parent_opaque_ty, func_name,
-          /*mangled_name=*/nullptr, func_ct,
+          /*mangled_name=*/std::nullopt, func_ct,
           /*access=*/lldb::AccessType::eAccessPublic,
           /*is_virtual=*/false, /*is_static=*/false,
           /*is_inline=*/false, /*is_explicit=*/false,
@@ -913,7 +913,7 @@ PdbAstBuilder::CreateFunctionDecl(PdbCompilandSymId func_id,
   } else {
     function_decl = m_clang.CreateFunctionDeclaration(
         parent, OptionalClangModuleID(), func_name, func_ct, func_storage,
-        is_inline);
+        is_inline, /*asm_label=*/std::nullopt);
     CreateFunctionParameters(func_id, *function_decl, param_count);
   }
   return function_decl;
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp 
b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
index 807ee5b30779c..5e77ea7f85603 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
@@ -111,9 +111,8 @@ void UdtRecordCompleter::AddMethod(llvm::StringRef name, 
TypeIndex type_idx,
   bool is_artificial = (options & MethodOptions::CompilerGenerated) ==
                        MethodOptions::CompilerGenerated;
   m_ast_builder.clang().AddMethodToCXXRecordType(
-      derived_opaque_ty, name.data(), nullptr, method_ct,
-      access_type, attrs.isVirtual(), attrs.isStatic(), false, false, false,
-      is_artificial);
+      derived_opaque_ty, name.data(), std::nullopt, method_ct, access_type,
+      attrs.isVirtual(), attrs.isStatic(), false, false, false, is_artificial);
 
   m_cxx_record_map[derived_opaque_ty].insert({name, method_ct});
 }
diff --git a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp 
b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
index 0090d8ff03ab6..548a3ed25111f 100644
--- a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
+++ b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
@@ -954,7 +954,8 @@ PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol 
&symbol) {
 
     auto decl = m_ast.CreateFunctionDeclaration(
         decl_context, OptionalClangModuleID(), name,
-        type->GetForwardCompilerType(), storage, func->hasInlineAttribute());
+        type->GetForwardCompilerType(), storage, func->hasInlineAttribute(),
+        /*asm_label=*/std::nullopt);
 
     std::vector<clang::ParmVarDecl *> params;
     if (std::unique_ptr<PDBSymbolTypeFunctionSig> sig = func->getSignature()) {
@@ -1446,8 +1447,8 @@ PDBASTParser::AddRecordMethod(lldb_private::SymbolFile 
&symbol_file,
   // TODO: get mangled name for the method.
   return m_ast.AddMethodToCXXRecordType(
       record_type.GetOpaqueQualType(), name.c_str(),
-      /*mangled_name*/ nullptr, method_comp_type, access, method.isVirtual(),
-      method.isStatic(), method.hasInlineAttribute(),
+      /*mangled_name*/ std::nullopt, method_comp_type, access,
+      method.isVirtual(), method.isStatic(), method.hasInlineAttribute(),
       /*is_explicit*/ false, // FIXME: Need this field in CodeView.
       /*is_attr_used*/ false,
       /*is_artificial*/ method.isCompilerGenerated());
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp 
b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index e847ede1a4ba6..03bdc555c0613 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -60,6 +60,7 @@
 #include "lldb/Core/Module.h"
 #include "lldb/Core/PluginManager.h"
 #include "lldb/Core/UniqueCStringMap.h"
+#include "lldb/Expression/Expression.h"
 #include "lldb/Host/StreamFile.h"
 #include "lldb/Symbol/ObjectFile.h"
 #include "lldb/Symbol/SymbolFile.h"
@@ -2137,7 +2138,8 @@ std::string TypeSystemClang::GetTypeNameForDecl(const 
NamedDecl *named_decl,
 FunctionDecl *TypeSystemClang::CreateFunctionDeclaration(
     clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module,
     llvm::StringRef name, const CompilerType &function_clang_type,
-    clang::StorageClass storage, bool is_inline) {
+    clang::StorageClass storage, bool is_inline,
+    std::optional<std::string> asm_label) {
   FunctionDecl *func_decl = nullptr;
   ASTContext &ast = getASTContext();
   if (!decl_ctx)
@@ -2158,6 +2160,21 @@ FunctionDecl *TypeSystemClang::CreateFunctionDeclaration(
   func_decl->setConstexprKind(isConstexprSpecified
                                   ? ConstexprSpecKind::Constexpr
                                   : ConstexprSpecKind::Unspecified);
+
+  // Attach an asm(<mangled_name>) label to the FunctionDecl.
+  // This ensures that clang::CodeGen emits function calls
+  // using symbols that are mangled according to the DW_AT_linkage_name.
+  // If we didn't do this, the external symbols wouldn't exactly
+  // match the mangled name LLDB knows about and the IRExecutionUnit
+  // would have to fall back to searching object files for
+  // approximately matching function names. The motivating
+  // example is generating calls to ABI-tagged template functions.
+  // This is done separately for member functions in
+  // AddMethodToCXXRecordType.
+  if (asm_label)
+    func_decl->addAttr(clang::AsmLabelAttr::CreateImplicit(ast, *asm_label,
+                                                           /*literal=*/false));
+
   SetOwningModule(func_decl, owning_module);
   decl_ctx->addDecl(func_decl);
 
@@ -7647,7 +7664,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 +7797,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.
@@ -9037,6 +9053,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)) {
@@ -9759,3 +9782,51 @@ void TypeSystemClang::LogCreation() const {
     LLDB_LOG(log, "Created new TypeSystem for (ASTContext*){0:x} '{1}'",
              &getASTContext(), getDisplayName());
 }
+
+// Expected format is:
+// $__lldb_func:<mangled name>:<module id>:<definition/declaration DIE id>
+llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>>
+TypeSystemClang::splitFunctionCallLabel(llvm::StringRef label) const {
+  if (!consumeFunctionCallLabelPrefix(label))
+    return llvm::createStringError(
+        "expected function call label prefix not found in %s", label.data());
+  if (!label.consume_front(":"))
+    return llvm::createStringError(
+        "incorrect format: expected ':' as the first character.");
+
+  llvm::SmallVector<llvm::StringRef, 3> components;
+  label.split(components, ":");
+
+  if (components.size() != 3)
+    return llvm::createStringError(
+        "incorrect format: too many label subcomponents.");
+
+  return components;
+}
+
+llvm::Expected<FunctionCallLabel>
+TypeSystemClang::makeFunctionCallLabel(llvm::StringRef label) const {
+  auto components_or_err = splitFunctionCallLabel(label);
+  if (!components_or_err)
+    return llvm::joinErrors(
+        llvm::createStringError("Failed to decode function call label"),
+        components_or_err.takeError());
+
+  const auto &components = *components_or_err;
+
+  llvm::StringRef module_label = components[1];
+  llvm::StringRef die_label = components[2];
+
+  lldb::user_id_t module_id = 0;
+  if (module_label.consumeInteger(0, module_id))
+    return llvm::createStringError(
+        llvm::formatv("failed to parse module ID from '{0}'.", components[1]));
+
+  lldb::user_id_t die_id;
+  if (die_label.consumeInteger(/*Radix=*/0, die_id))
+    return llvm::createStringError(
+        llvm::formatv("failed to parse DIE ID from '{0}'.", components[2]));
+
+  return FunctionCallLabel{/*.m_lookup_name =*/components[0],
+                           /*.m_module_id =*/module_id, /*.m_die_id =*/die_id};
+}
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h 
b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index 63dee9dceded3..726a0eea9382a 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -477,7 +477,8 @@ class TypeSystemClang : public TypeSystem {
   clang::FunctionDecl *CreateFunctionDeclaration(
       clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module,
       llvm::StringRef name, const CompilerType &function_Type,
-      clang::StorageClass storage, bool is_inline);
+      clang::StorageClass storage, bool is_inline,
+      std::optional<std::string> asm_label);
 
   CompilerType
   CreateFunctionType(const CompilerType &result_type,
@@ -1001,7 +1002,7 @@ class TypeSystemClang : public TypeSystem {
 
   clang::CXXMethodDecl *AddMethodToCXXRecordType(
       lldb::opaque_compiler_type_t type, llvm::StringRef name,
-      const char *mangled_name, const CompilerType &method_type,
+      std::optional<std::string> mangled_name, const CompilerType &method_type,
       lldb::AccessType access, bool is_virtual, bool is_static, bool is_inline,
       bool is_explicit, bool is_attr_used, bool is_artificial);
 
@@ -1098,6 +1099,12 @@ class TypeSystemClang : public TypeSystem {
       lldb::opaque_compiler_type_t type, Stream &s,
       lldb::DescriptionLevel level = lldb::eDescriptionLevelFull) override;
 
+  llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>>
+  splitFunctionCallLabel(llvm::StringRef label) const override;
+
+  llvm::Expected<FunctionCallLabel>
+  makeFunctionCallLabel(llvm::StringRef label) const override;
+
   static void DumpTypeName(const CompilerType &type);
 
   static clang::EnumDecl *GetAsEnumDecl(const CompilerType &type);
diff --git a/lldb/unittests/Symbol/TestTypeSystemClang.cpp 
b/lldb/unittests/Symbol/TestTypeSystemClang.cpp
index 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);
 

>From 326d7865190eb132aed85615766b9ebcc2a1c81c Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Mon, 21 Jul 2025 12:15:24 +0100
Subject: [PATCH 2/5] 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 4e242f81ad8a93406f71d1aada29c9d253bc8806 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Mon, 21 Jul 2025 10:02:50 +0100
Subject: [PATCH 3/5] Structors init

---
 clang/lib/AST/Mangle.cpp                      | 12 +++
 libcxxabi/src/demangle/ItaniumDemangle.h      |  2 +
 lldb/include/lldb/Expression/Expression.h     |  5 +
 lldb/include/lldb/Symbol/SymbolFile.h         |  6 +-
 lldb/include/lldb/Symbol/TypeSystem.h         |  2 +-
 lldb/source/Expression/IRExecutionUnit.cpp    |  9 +-
 .../SymbolFile/DWARF/DWARFASTParserClang.cpp  | 32 ++++++-
 .../SymbolFile/DWARF/SymbolFileDWARF.cpp      | 58 +++++++++---
 .../SymbolFile/DWARF/SymbolFileDWARF.h        |  6 +-
 .../TypeSystem/Clang/TypeSystemClang.cpp      | 92 +++++++++++++++++--
 .../TypeSystem/Clang/TypeSystemClang.h        | 12 ++-
 llvm/include/llvm/Demangle/Demangle.h         |  3 +
 llvm/include/llvm/Demangle/ItaniumDemangle.h  |  2 +
 llvm/lib/Demangle/ItaniumDemangle.cpp         | 10 +-
 14 files changed, 217 insertions(+), 34 deletions(-)

diff --git a/clang/lib/AST/Mangle.cpp b/clang/lib/AST/Mangle.cpp
index 9652fdbc4e125..d0b9f1435e732 100644
--- a/clang/lib/AST/Mangle.cpp
+++ b/clang/lib/AST/Mangle.cpp
@@ -152,6 +152,13 @@ bool MangleContext::shouldMangleDeclName(const NamedDecl 
*D) {
   return shouldMangleCXXName(D);
 }
 
+static void tryEmitDebugStructorVariant(GlobalDecl GD, raw_ostream &Out) {
+  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());
@@ -165,6 +172,11 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream 
&Out) {
     // do not add a "\01" prefix.
     if (!ALA->getIsLiteralLabel() || ALA->getLabel().starts_with("llvm.")) {
       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 b306b2013445c..aae56fe5f1df2 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 f32878c9bf876..fe7a6fa0dc527 100644
--- a/lldb/include/lldb/Expression/Expression.h
+++ b/lldb/include/lldb/Expression/Expression.h
@@ -112,6 +112,11 @@ struct FunctionCallLabel {
 
   /// Mostly for debuggability.
   lldb::user_id_t m_die_id;
+
+  virtual ~FunctionCallLabel() = default;
+  virtual std::optional<uint8_t> getItaniumStructorVariant() const {
+    return std::nullopt;
+  }
 };
 
 /// LLDB attaches this prefix to mangled names of functions that it get called
diff --git a/lldb/include/lldb/Symbol/SymbolFile.h 
b/lldb/include/lldb/Symbol/SymbolFile.h
index 6aca276fc85b6..8fd1d5490b147 100644
--- a/lldb/include/lldb/Symbol/SymbolFile.h
+++ b/lldb/include/lldb/Symbol/SymbolFile.h
@@ -337,8 +337,10 @@ class SymbolFile : public PluginInterface {
   ///
   /// \param[in] lookup_name The UID of the function DIE to resolve.
   ///
-  virtual llvm::Error FindAndResolveFunction(SymbolContextList &sc_list,
-                                             llvm::StringRef lookup_name) {
+  virtual llvm::Error
+  FindAndResolveFunction(SymbolContextList &sc_list,
+                         llvm::StringRef lookup_name, lldb::user_id_t spec,
+                         std::optional<uint8_t> structor_variant) {
     return llvm::createStringError("Not implemented");
   }
 
diff --git a/lldb/include/lldb/Symbol/TypeSystem.h 
b/lldb/include/lldb/Symbol/TypeSystem.h
index 742c09251ea2f..cd887cd003579 100644
--- a/lldb/include/lldb/Symbol/TypeSystem.h
+++ b/lldb/include/lldb/Symbol/TypeSystem.h
@@ -559,7 +559,7 @@ class TypeSystem : public PluginInterface,
   }
 
   // Decodes the function label into a \c FunctionCallLabel.
-  virtual llvm::Expected<FunctionCallLabel>
+  virtual llvm::Expected<std::unique_ptr<FunctionCallLabel>>
   makeFunctionCallLabel(llvm::StringRef label) const {
     return llvm::createStringError("Not implemented.");
   }
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp 
b/lldb/source/Expression/IRExecutionUnit.cpp
index 40635d0829168..7ae6962c78819 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -801,13 +801,13 @@ ResolveFunctionCallLabel(llvm::StringRef name,
   auto ts_sp = *ts_or_err;
 
   auto label_or_err = ts_sp->makeFunctionCallLabel(name);
-  if (!label_or_err)
+  if (!label_or_err || !*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;
+  const auto &label = **label_or_err;
 
   Module *module = Module::GetAllocatedModuleWithUID(label.m_module_id);
 
@@ -821,8 +821,9 @@ ResolveFunctionCallLabel(llvm::StringRef name,
         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))
+  if (auto err = symbol_file->FindAndResolveFunction(
+          sc_list, label.m_lookup_name, label.m_die_id,
+          label.getItaniumStructorVariant()))
     return llvm::joinErrors(
         llvm::createStringError("failed to resolve function by UID"),
         std::move(err));
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp 
b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 6e9598c13ed5c..f031fcad8a786 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::optional<std::string> MakeLLDBFuncAsmLabel(const DWARFDIE &die) {
-  char const *name = die.GetMangledName(/*substitute_name_allowed*/ false);
+  const char *name = GetMangledOrStructorName(die);
   if (!name)
     return std::nullopt;
 
@@ -267,7 +295,7 @@ 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,
+  return llvm::formatv("{0}:{1}:{2:x}:{3:x}:", FunctionCallLabelPrefix, name,
                        module_id, die_id)
       .str();
 }
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp 
b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index b6960bfe38fde..91c32d2bc3170 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -76,6 +76,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"
 
@@ -2471,32 +2472,63 @@ bool SymbolFileDWARF::ResolveFunction(const DWARFDIE 
&orig_die,
   return false;
 }
 
-llvm::Error
-SymbolFileDWARF::FindAndResolveFunction(SymbolContextList &sc_list,
-                                        llvm::StringRef lookup_name) {
+llvm::Error SymbolFileDWARF::FindAndResolveFunction(
+    SymbolContextList &sc_list, llvm::StringRef lookup_name,
+    lldb::user_id_t die_id, std::optional<uint8_t> structor_variant) {
   std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
-
-  DWARFDIE die;
-  Module::LookupInfo info(ConstString(lookup_name), 
lldb::eFunctionNameTypeFull,
+  DWARFDIE die = GetDIE(die_id);
+  if (!die.IsValid())
+    return llvm::createStringError("invalid DIE for UID: %" PRIu64, die_id);
+
+  // eFunctionNameTypeFull for mangled name lookup.
+  // eFunctionNameTypeMethod is required for structor lookups (since we look
+  // those up by DW_AT_name).
+  Module::LookupInfo info(ConstString(lookup_name),
+                          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 (!structor_variant) {
+      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;
+
+    if (D.getCtorOrDtorVariant() != structor_variant)
+      return true;
+
     die = entry;
+
     return false;
   });
 
   if (!die.IsValid())
     return llvm::createStringError(
-        llvm::formatv("failed to find definition DIE for '{0}'", lookup_name));
+        llvm::formatv("failed to find definition DIE for [lookup_name={0}] "
+                      "[DIE ID={1:x}] [structor={2}]",
+                      lookup_name, die_id, structor_variant.value_or(-1)));
 
   if (!ResolveFunction(die, false, sc_list))
     return llvm::createStringError("failed to resolve function DIE");
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h 
b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index ee966366d3f2b..4473630f8ce1a 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -434,8 +434,10 @@ 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
+  FindAndResolveFunction(SymbolContextList &sc_list,
+                         llvm::StringRef lookup_name, lldb::user_id_t spec,
+                         std::optional<uint8_t> structor_variant) 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/TypeSystem/Clang/TypeSystemClang.cpp 
b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 03bdc555c0613..85ad7b3c40f8b 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"
@@ -9783,8 +9784,40 @@ void TypeSystemClang::LogCreation() const {
              &getASTContext(), getDisplayName());
 }
 
+static llvm::Expected<
+    std::variant<std::monostate, clang::CXXCtorType, clang::CXXDtorType>>
+ParseStructorType(llvm::StringRef label) {
+  if (label.empty())
+    return std::monostate{};
+
+  bool is_ctor = label.consume_front("C");
+  if (!is_ctor && label.starts_with("D"))
+    return llvm::createStringError("invalid structor type prefix in %s",
+                                   label.data());
+
+  uint8_t type;
+  if (label.consumeInteger(0, type))
+    return llvm::createStringError("failed to parse structor type value %s",
+                                   label.data());
+
+  if (is_ctor) {
+    if (type > clang::CXXCtorType::Ctor_DefaultClosure)
+      return llvm::createStringError("C++ constructor type %d out of range",
+                                     type);
+
+    return static_cast<CXXCtorType>(type);
+  }
+
+  if (type > clang::CXXDtorType::Dtor_Deleting)
+    return llvm::createStringError("C++ destructor type %d out of range", 
type);
+
+  return static_cast<CXXDtorType>(type);
+}
+
+// clang-format off
 // Expected format is:
-// $__lldb_func:<mangled name>:<module id>:<definition/declaration DIE id>
+// $__lldb_func:<mangled name>:<module id>:<definition/declaration DIE 
id>:[<structor variant>]
+// clang-format on
 llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>>
 TypeSystemClang::splitFunctionCallLabel(llvm::StringRef label) const {
   if (!consumeFunctionCallLabelPrefix(label))
@@ -9794,17 +9827,17 @@ TypeSystemClang::splitFunctionCallLabel(llvm::StringRef 
label) const {
     return llvm::createStringError(
         "incorrect format: expected ':' as the first character.");
 
-  llvm::SmallVector<llvm::StringRef, 3> components;
+  llvm::SmallVector<llvm::StringRef, 4> components;
   label.split(components, ":");
 
-  if (components.size() != 3)
+  if (components.size() != 4)
     return llvm::createStringError(
         "incorrect format: too many label subcomponents.");
 
   return components;
 }
 
-llvm::Expected<FunctionCallLabel>
+llvm::Expected<std::unique_ptr<FunctionCallLabel>>
 TypeSystemClang::makeFunctionCallLabel(llvm::StringRef label) const {
   auto components_or_err = splitFunctionCallLabel(label);
   if (!components_or_err)
@@ -9816,6 +9849,7 @@ TypeSystemClang::makeFunctionCallLabel(llvm::StringRef 
label) const {
 
   llvm::StringRef module_label = components[1];
   llvm::StringRef die_label = components[2];
+  llvm::StringRef structor_variant = components[3];
 
   lldb::user_id_t module_id = 0;
   if (module_label.consumeInteger(0, module_id))
@@ -9827,6 +9861,52 @@ 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};
+  auto structor_type_or_err = ParseStructorType(structor_variant);
+  if (!structor_type_or_err)
+    return llvm::joinErrors(
+        llvm::createStringError(llvm::formatv(
+            "failed to parse structor kind from '{0}'.", components[2])),
+        structor_type_or_err.takeError());
+
+  auto ret = std::make_unique<ClangFunctionCallLabel>();
+  ret->m_lookup_name = components[0];
+  ret->m_module_id = module_id;
+  ret->m_die_id = die_id;
+  ret->m_structor_type = std::move(*structor_type_or_err);
+
+  return ret;
+}
+
+std::optional<uint8_t>
+TypeSystemClang::ClangFunctionCallLabel::getItaniumStructorVariant() const {
+  if (m_structor_type.index() == 0)
+    return std::nullopt;
+
+  if (auto *ctor = std::get_if<clang::CXXCtorType>(&m_structor_type)) {
+    switch (*ctor) {
+    case clang::CXXCtorType::Ctor_Complete:
+      return 1;
+    case clang::CXXCtorType::Ctor_Base:
+      return 2;
+    case clang::CXXCtorType::Ctor_Comdat:
+    case clang::CXXCtorType::Ctor_CopyingClosure:
+    case clang::CXXCtorType::Ctor_DefaultClosure:
+      // No Itanium equivalent
+      return std::nullopt;
+    }
+  } else if (auto *dtor = std::get_if<clang::CXXDtorType>(&m_structor_type)) {
+    switch (*dtor) {
+    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:
+      // No Itanium equivalent
+      return std::nullopt;
+    }
+  }
+
+  return std::nullopt;
 }
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h 
b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index 726a0eea9382a..6ba17e4bb1cda 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"
@@ -1102,7 +1104,15 @@ class TypeSystemClang : public TypeSystem {
   llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>>
   splitFunctionCallLabel(llvm::StringRef label) const override;
 
-  llvm::Expected<FunctionCallLabel>
+  struct ClangFunctionCallLabel : public FunctionCallLabel {
+    /// Structor kind according to the Itanium ABI.
+    std::variant<std::monostate, clang::CXXCtorType, clang::CXXDtorType>
+        m_structor_type;
+
+    std::optional<uint8_t> getItaniumStructorVariant() const override;
+  };
+
+  llvm::Expected<std::unique_ptr<FunctionCallLabel>>
   makeFunctionCallLabel(llvm::StringRef label) const override;
 
   static void DumpTypeName(const CompilerType &type);
diff --git a/llvm/include/llvm/Demangle/Demangle.h 
b/llvm/include/llvm/Demangle/Demangle.h
index 21e7457b6336f..568d57e37823e 100644
--- a/llvm/include/llvm/Demangle/Demangle.h
+++ b/llvm/include/llvm/Demangle/Demangle.h
@@ -122,6 +122,9 @@ struct ItaniumPartialDemangler {
   /// If this symbol describes a constructor or destructor.
   bool isCtorOrDtor() const;
 
+  /// If this symbol describes a constructor or destructor.
+  std::optional<int> getCtorOrDtorVariant() const;
+
   /// If this symbol describes a function.
   bool isFunction() const;
 
diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h 
b/llvm/include/llvm/Demangle/ItaniumDemangle.h
index 5533652736dc8..ec1a527ca7e7c 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 {

>From b716bcb505d11d862dda09d02ae15bd1078314f0 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Mon, 21 Jul 2025 16:29:08 +0100
Subject: [PATCH 4/5] fixup! fix constructor aliasing

---
 .../SymbolFile/DWARF/SymbolFileDWARF.cpp      | 23 ++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp 
b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 91c32d2bc3170..51f0c94320766 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -2488,6 +2488,7 @@ llvm::Error SymbolFileDWARF::FindAndResolveFunction(
                               lldb::eFunctionNameTypeMethod,
                           lldb::eLanguageTypeUnknown);
 
+  llvm::DenseMap<uint8_t, DWARFDIE> variant_to_die;
   m_index->GetFunctions(info, *this, {}, [&](DWARFDIE entry) {
     if (entry.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0))
       return true;
@@ -2516,14 +2517,30 @@ llvm::Error SymbolFileDWARF::FindAndResolveFunction(
     if (D.partialDemangle(mangled))
       return true;
 
-    if (D.getCtorOrDtorVariant() != structor_variant)
+    auto maybe_variant = D.getCtorOrDtorVariant();
+    if (!maybe_variant)
       return true;
 
-    die = entry;
+    assert(!variant_to_die.contains(*maybe_variant));
 
-    return false;
+    variant_to_die[*maybe_variant] = entry;
+
+    return true;
   });
 
+  if (structor_variant) {
+    if (auto it = variant_to_die.find(*structor_variant);
+        it != variant_to_die.end()) {
+      die = it->getSecond();
+    }
+    // TODO: only do this for constructors.
+    else if (structor_variant == 1)
+      // On Linux the C1 constructor variant is often an alias
+      // to C2 (and C1 is never actually emitted into the object file).
+      if (auto it = variant_to_die.find(2); it != variant_to_die.end())
+        die = it->getSecond();
+  }
+
   if (!die.IsValid())
     return llvm::createStringError(
         llvm::formatv("failed to find definition DIE for [lookup_name={0}] "

>From 03fb460d124f4d60349fbc08bc77dc7a6150853c Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Mon, 21 Jul 2025 16:41:23 +0100
Subject: [PATCH 5/5] fixup! fix custom linkage name test

---
 .../Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp     | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp 
b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 51f0c94320766..62330be36aeeb 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -2483,10 +2483,14 @@ llvm::Error SymbolFileDWARF::FindAndResolveFunction(
   // eFunctionNameTypeFull for mangled name lookup.
   // eFunctionNameTypeMethod is required for structor lookups (since we look
   // those up by DW_AT_name).
-  Module::LookupInfo info(ConstString(lookup_name),
-                          lldb::eFunctionNameTypeFull |
-                              lldb::eFunctionNameTypeMethod,
+  Module::LookupInfo info(ConstString(lookup_name), {},
                           lldb::eLanguageTypeUnknown);
+  // FIXME: Set this separately because for TestExprsBug35310 
Module::LookupInfo
+  // constructor would unset the eFunctionNameTypeFull! Because of
+  // GetFunctionNameInfo (which for custom linkage names doesn't return
+  // eFunctionNameTypeFull)
+  info.SetNameTypeMask(lldb::eFunctionNameTypeFull |
+                       lldb::eFunctionNameTypeMethod);
 
   llvm::DenseMap<uint8_t, DWARFDIE> variant_to_die;
   m_index->GetFunctions(info, *this, {}, [&](DWARFDIE entry) {
@@ -2541,7 +2545,7 @@ llvm::Error SymbolFileDWARF::FindAndResolveFunction(
         die = it->getSecond();
   }
 
-  if (!die.IsValid())
+  if (!die.IsValid() || die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0))
     return llvm::createStringError(
         llvm::formatv("failed to find definition DIE for [lookup_name={0}] "
                       "[DIE ID={1:x}] [structor={2}]",

_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to