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

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

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

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

>From f15648061c93d37619b894cffc95009d823a13d7 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Mon, 21 Jul 2025 12:15:24 +0100
Subject: [PATCH 02/19] fixup! add quotes

---
 lldb/source/Expression/IRExecutionUnit.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lldb/source/Expression/IRExecutionUnit.cpp 
b/lldb/source/Expression/IRExecutionUnit.cpp
index a9ea244889cce..40635d0829168 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -972,7 +972,7 @@ lldb::addr_t 
IRExecutionUnit::FindSymbol(lldb_private::ConstString name,
       return *addr_or_err;
     } else {
       LLDB_LOG_ERROR(GetLog(LLDBLog::Expressions), addr_or_err.takeError(),
-                     "Failed to resolve function call label {1}: {0}",
+                     "Failed to resolve function call label '{1}': {0}",
                      name.GetStringRef());
       return LLDB_INVALID_ADDRESS;
     }

>From 6dddabcbd21cbaf65bd6244fd2d3d17dd42ffcee Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Mon, 28 Jul 2025 11:43:17 +0100
Subject: [PATCH 03/19] fixup! create literal AsmLabels

---
 lldb/include/lldb/Expression/Expression.h            |  3 ---
 lldb/source/Expression/Expression.cpp                | 12 ------------
 lldb/source/Expression/IRExecutionUnit.cpp           |  2 +-
 .../Plugins/TypeSystem/Clang/TypeSystemClang.cpp     |  6 +++---
 4 files changed, 4 insertions(+), 19 deletions(-)

diff --git a/lldb/include/lldb/Expression/Expression.h 
b/lldb/include/lldb/Expression/Expression.h
index f32878c9bf876..9044d26cf6670 100644
--- a/lldb/include/lldb/Expression/Expression.h
+++ b/lldb/include/lldb/Expression/Expression.h
@@ -118,9 +118,6 @@ struct FunctionCallLabel {
 /// from JITted expressions.
 inline constexpr llvm::StringRef FunctionCallLabelPrefix = "$__lldb_func";
 
-bool consumeFunctionCallLabelPrefix(llvm::StringRef &name);
-bool hasFunctionCallLabelPrefix(llvm::StringRef name);
-
 } // namespace lldb_private
 
 #endif // LLDB_EXPRESSION_EXPRESSION_H
diff --git a/lldb/source/Expression/Expression.cpp 
b/lldb/source/Expression/Expression.cpp
index e19c804caa3c6..f85a3284d7eda 100644
--- a/lldb/source/Expression/Expression.cpp
+++ b/lldb/source/Expression/Expression.cpp
@@ -30,15 +30,3 @@ Expression::Expression(ExecutionContextScope &exe_scope)
       m_jit_end_addr(LLDB_INVALID_ADDRESS) {
   assert(m_target_wp.lock());
 }
-
-bool lldb_private::consumeFunctionCallLabelPrefix(llvm::StringRef &name) {
-  // On Darwin mangled names get a '_' prefix.
-  name.consume_front("_");
-  return name.consume_front(FunctionCallLabelPrefix);
-}
-
-bool lldb_private::hasFunctionCallLabelPrefix(llvm::StringRef name) {
-  // On Darwin mangled names get a '_' prefix.
-  name.consume_front("_");
-  return name.starts_with(FunctionCallLabelPrefix);
-}
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp 
b/lldb/source/Expression/IRExecutionUnit.cpp
index 40635d0829168..9a545c40eacd0 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -966,7 +966,7 @@ lldb::addr_t IRExecutionUnit::FindInUserDefinedSymbols(
 
 lldb::addr_t IRExecutionUnit::FindSymbol(lldb_private::ConstString name,
                                          bool &missing_weak) {
-  if (hasFunctionCallLabelPrefix(name.GetStringRef())) {
+  if (name.GetStringRef().starts_with(FunctionCallLabelPrefix)) {
     if (auto addr_or_err = ResolveFunctionCallLabel(name.GetStringRef(),
                                                     m_sym_ctx, missing_weak)) {
       return *addr_or_err;
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp 
b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 0c476e5b9d01b..fadd1e3266040 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -2173,7 +2173,7 @@ FunctionDecl *TypeSystemClang::CreateFunctionDeclaration(
   // AddMethodToCXXRecordType.
   if (asm_label)
     func_decl->addAttr(clang::AsmLabelAttr::CreateImplicit(ast, *asm_label,
-                                                           /*literal=*/false));
+                                                           /*literal=*/true));
 
   SetOwningModule(func_decl, owning_module);
   decl_ctx->addDecl(func_decl);
@@ -7803,7 +7803,7 @@ clang::CXXMethodDecl 
*TypeSystemClang::AddMethodToCXXRecordType(
 
   if (asm_label)
     cxx_method_decl->addAttr(clang::AsmLabelAttr::CreateImplicit(
-        getASTContext(), *asm_label, /*literal=*/false));
+        getASTContext(), *asm_label, /*literal=*/true));
 
   // Parameters on member function declarations in DWARF generally don't
   // have names, so we omit them when creating the ParmVarDecls.
@@ -9791,7 +9791,7 @@ void TypeSystemClang::LogCreation() const {
 // $__lldb_func:<mangled name>:<module id>:<definition/declaration DIE id>
 llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>>
 TypeSystemClang::splitFunctionCallLabel(llvm::StringRef label) const {
-  if (!consumeFunctionCallLabelPrefix(label))
+  if (!label.consume_front(FunctionCallLabelPrefix))
     return llvm::createStringError(
         "expected function call label prefix not found in %s", label.data());
   if (!label.consume_front(":"))

>From 52662a7d0f09fb1dc104a1242c574dc864b40d88 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Mon, 28 Jul 2025 12:02:49 +0100
Subject: [PATCH 04/19] fixup! move to new FindModule API; make module UID
 atomic

---
 lldb/include/lldb/Core/Module.h            |  1 -
 lldb/include/lldb/Core/ModuleList.h        |  8 ++++++++
 lldb/source/Core/Module.cpp                | 12 +-----------
 lldb/source/Core/ModuleList.cpp            | 14 ++++++++++++++
 lldb/source/Expression/IRExecutionUnit.cpp |  8 ++++----
 5 files changed, 27 insertions(+), 16 deletions(-)

diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h
index 3991a12997541..8513e147ee523 100644
--- a/lldb/include/lldb/Core/Module.h
+++ b/lldb/include/lldb/Core/Module.h
@@ -98,7 +98,6 @@ class Module : public std::enable_shared_from_this<Module>,
   // using the "--global" (-g for short).
   static size_t GetNumberAllocatedModules();
 
-  static Module *GetAllocatedModuleWithUID(lldb::user_id_t uid);
   static Module *GetAllocatedModuleAtIndex(size_t idx);
 
   static std::recursive_mutex &GetAllocationModuleCollectionMutex();
diff --git a/lldb/include/lldb/Core/ModuleList.h 
b/lldb/include/lldb/Core/ModuleList.h
index d5e291f3380a8..6ecdcf10fa85f 100644
--- a/lldb/include/lldb/Core/ModuleList.h
+++ b/lldb/include/lldb/Core/ModuleList.h
@@ -352,6 +352,14 @@ class ModuleList {
   // UUID values is very efficient and accurate.
   lldb::ModuleSP FindModule(const UUID &uuid) const;
 
+  /// Find a module by LLDB-specific unique identifier.
+  ///
+  /// \param[in] uid The UID of the module assigned to it on construction.
+  ///
+  /// \returns ModuleSP of module with \c uid. Returns nullptr if no such
+  /// module could be found.
+  lldb::ModuleSP FindModule(lldb::user_id_t uid) const;
+
   /// Finds the first module whose file specification matches \a module_spec.
   lldb::ModuleSP FindFirstModule(const ModuleSpec &module_spec) const;
 
diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp
index edd79aff5d065..f27a95de484df 100644
--- a/lldb/source/Core/Module.cpp
+++ b/lldb/source/Core/Module.cpp
@@ -121,15 +121,6 @@ size_t Module::GetNumberAllocatedModules() {
   return GetModuleCollection().size();
 }
 
-Module *Module::GetAllocatedModuleWithUID(lldb::user_id_t uid) {
-  std::lock_guard<std::recursive_mutex> guard(
-      GetAllocationModuleCollectionMutex());
-  for (Module *mod : GetModuleCollection())
-    if (mod->GetID() == uid)
-      return mod;
-  return nullptr;
-}
-
 Module *Module::GetAllocatedModuleAtIndex(size_t idx) {
   std::lock_guard<std::recursive_mutex> guard(
       GetAllocationModuleCollectionMutex());
@@ -139,8 +130,7 @@ Module *Module::GetAllocatedModuleAtIndex(size_t idx) {
   return nullptr;
 }
 
-// TODO: needs a mutex
-static lldb::user_id_t g_unique_id = 1;
+static std::atomic<lldb::user_id_t> g_unique_id = 1;
 
 Module::Module(const ModuleSpec &module_spec)
     : UserID(g_unique_id++), m_unwind_table(*this), m_file_has_changed(false),
diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp
index d2e5be8c79b17..e3dfa799ebb65 100644
--- a/lldb/source/Core/ModuleList.cpp
+++ b/lldb/source/Core/ModuleList.cpp
@@ -584,6 +584,20 @@ ModuleSP ModuleList::FindModule(const UUID &uuid) const {
   return module_sp;
 }
 
+ModuleSP ModuleList::FindModule(lldb::user_id_t uid) const {
+  ModuleSP module_sp;
+  ForEach([&](const ModuleSP &m) {
+    if (m->GetID() == uid) {
+      module_sp = m;
+      return true;
+    }
+
+    return false;
+  });
+
+  return module_sp;
+}
+
 void ModuleList::FindTypes(Module *search_first, const TypeQuery &query,
                            TypeResults &results) const {
   std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp 
b/lldb/source/Expression/IRExecutionUnit.cpp
index 9a545c40eacd0..e7387dc2b3bf9 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -809,16 +809,16 @@ ResolveFunctionCallLabel(llvm::StringRef name,
 
   const auto &label = *label_or_err;
 
-  Module *module = Module::GetAllocatedModuleWithUID(label.m_module_id);
+  auto module_sp = sc.target_sp->GetImages().FindModule(label.m_module_id);
 
-  if (!module)
+  if (!module_sp)
     return llvm::createStringError(
         llvm::formatv("failed to find module by UID {0}", label.m_module_id));
 
-  auto *symbol_file = module->GetSymbolFile();
+  auto *symbol_file = module_sp->GetSymbolFile();
   if (!symbol_file)
     return llvm::createStringError(
-        llvm::formatv("no SymbolFile found on module {0:x}.", module));
+        llvm::formatv("no SymbolFile found on module {0:x}.", 
module_sp.get()));
 
   SymbolContextList sc_list;
   if (auto err =

>From 527bdb0ffc9b11c090446257d4bb97ed7c81e646 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Mon, 28 Jul 2025 12:16:22 +0100
Subject: [PATCH 05/19] fixup! rename FunctionCallLabel members

---
 lldb/include/lldb/Expression/Expression.h     | 21 +++++++++++++------
 lldb/source/Expression/IRExecutionUnit.cpp    |  6 +++---
 .../TypeSystem/Clang/TypeSystemClang.cpp      |  6 ++----
 3 files changed, 20 insertions(+), 13 deletions(-)

diff --git a/lldb/include/lldb/Expression/Expression.h 
b/lldb/include/lldb/Expression/Expression.h
index 9044d26cf6670..0f2281790a055 100644
--- a/lldb/include/lldb/Expression/Expression.h
+++ b/lldb/include/lldb/Expression/Expression.h
@@ -102,16 +102,25 @@ class Expression {
 ///
 /// The format being:
 ///
-///   <prefix>:<mangled name>:<module id>:<DIE id>
+///   <prefix>:<mangled name>:<module uid>:<symbol uid>
 ///
 /// The label string needs to stay valid for the entire lifetime
 /// of this object.
 struct FunctionCallLabel {
-  llvm::StringRef m_lookup_name;
-  lldb::user_id_t m_module_id;
-
-  /// Mostly for debuggability.
-  lldb::user_id_t m_die_id;
+  /// Name to use when searching for the function symbol in
+  /// \c module_id. For most function calls this will be a
+  /// mangled name. In cases where a mangled name can't be used,
+  /// this will be the function name.
+  llvm::StringRef lookup_name;
+
+  /// Unique identifier of the lldb_private::Module
+  /// which contains the symbol identified by \c symbol_id.
+  lldb::user_id_t module_id;
+
+  /// Unique identifier of the function symbol on which to
+  /// perform the function call. For example, for DWARF this would
+  /// be the DIE UID.
+  lldb::user_id_t symbol_id;
 };
 
 /// LLDB attaches this prefix to mangled names of functions that it get called
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp 
b/lldb/source/Expression/IRExecutionUnit.cpp
index e7387dc2b3bf9..33f34831126ac 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -809,11 +809,11 @@ ResolveFunctionCallLabel(llvm::StringRef name,
 
   const auto &label = *label_or_err;
 
-  auto module_sp = sc.target_sp->GetImages().FindModule(label.m_module_id);
+  auto module_sp = sc.target_sp->GetImages().FindModule(label.module_id);
 
   if (!module_sp)
     return llvm::createStringError(
-        llvm::formatv("failed to find module by UID {0}", label.m_module_id));
+        llvm::formatv("failed to find module by UID {0}", label.module_id));
 
   auto *symbol_file = module_sp->GetSymbolFile();
   if (!symbol_file)
@@ -822,7 +822,7 @@ ResolveFunctionCallLabel(llvm::StringRef name,
 
   SymbolContextList sc_list;
   if (auto err =
-          symbol_file->FindAndResolveFunction(sc_list, label.m_lookup_name))
+          symbol_file->FindAndResolveFunction(sc_list, label.lookup_name))
     return llvm::joinErrors(
         llvm::createStringError("failed to resolve function by UID"),
         std::move(err));
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp 
b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index fadd1e3266040..7a73abc9a3ef4 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -9787,8 +9787,6 @@ void TypeSystemClang::LogCreation() const {
              &getASTContext(), getDisplayName());
 }
 
-// Expected format is:
-// $__lldb_func:<mangled name>:<module id>:<definition/declaration DIE id>
 llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>>
 TypeSystemClang::splitFunctionCallLabel(llvm::StringRef label) const {
   if (!label.consume_front(FunctionCallLabelPrefix))
@@ -9831,6 +9829,6 @@ TypeSystemClang::makeFunctionCallLabel(llvm::StringRef 
label) const {
     return llvm::createStringError(
         llvm::formatv("failed to parse DIE ID from '{0}'.", components[2]));
 
-  return FunctionCallLabel{/*.m_lookup_name =*/components[0],
-                           /*.m_module_id =*/module_id, /*.m_die_id =*/die_id};
+  return FunctionCallLabel{/*.lookup_name=*/components[0],
+                           /*.module_id=*/module_id, /*.symbol_id=*/die_id};
 }

>From c337ab584c9990b84ca9e78613821f914552f10c Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Mon, 28 Jul 2025 12:29:44 +0100
Subject: [PATCH 06/19] fixup! remove unused headers

---
 lldb/source/Expression/Expression.cpp | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/lldb/source/Expression/Expression.cpp 
b/lldb/source/Expression/Expression.cpp
index f85a3284d7eda..93f585edfce3d 100644
--- a/lldb/source/Expression/Expression.cpp
+++ b/lldb/source/Expression/Expression.cpp
@@ -10,10 +10,6 @@
 #include "lldb/Target/ExecutionContextScope.h"
 #include "lldb/Target/Target.h"
 
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/Error.h"
-
 using namespace lldb_private;
 
 Expression::Expression(Target &target)

>From 13a0eaff6033a1cc439d3e5400827d9a428f5473 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Mon, 28 Jul 2025 12:41:58 +0100
Subject: [PATCH 07/19] fixup! move FunctionCallLabel APIs into Expression
 component

---
 lldb/include/lldb/Expression/Expression.h     | 11 ++++
 lldb/include/lldb/Symbol/TypeSystem.h         | 15 ------
 lldb/source/Expression/Expression.cpp         | 50 +++++++++++++++++++
 lldb/source/Expression/IRExecutionUnit.cpp    | 12 +----
 .../TypeSystem/Clang/TypeSystemClang.cpp      | 48 +-----------------
 .../TypeSystem/Clang/TypeSystemClang.h        |  6 ---
 6 files changed, 64 insertions(+), 78 deletions(-)

diff --git a/lldb/include/lldb/Expression/Expression.h 
b/lldb/include/lldb/Expression/Expression.h
index 0f2281790a055..35d7d71f6b253 100644
--- a/lldb/include/lldb/Expression/Expression.h
+++ b/lldb/include/lldb/Expression/Expression.h
@@ -127,6 +127,17 @@ struct FunctionCallLabel {
 /// from JITted expressions.
 inline constexpr llvm::StringRef FunctionCallLabelPrefix = "$__lldb_func";
 
+/// Returns the components of the specified function call label.
+///
+/// The format of \c label is described in \c FunctionCallLabel.
+/// The label prefix is not one of the components.
+llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>>
+splitFunctionCallLabel(llvm::StringRef label);
+
+// Decodes the function label into a \c FunctionCallLabel.
+llvm::Expected<FunctionCallLabel>
+makeFunctionCallLabel(llvm::StringRef label);
+
 } // namespace lldb_private
 
 #endif // LLDB_EXPRESSION_EXPRESSION_H
diff --git a/lldb/include/lldb/Symbol/TypeSystem.h 
b/lldb/include/lldb/Symbol/TypeSystem.h
index 742c09251ea2f..40bd59056a5df 100644
--- a/lldb/include/lldb/Symbol/TypeSystem.h
+++ b/lldb/include/lldb/Symbol/TypeSystem.h
@@ -549,21 +549,6 @@ class TypeSystem : public PluginInterface,
     return m_has_forcefully_completed_types;
   }
 
-  /// Returns the components of the specified function call label.
-  ///
-  /// The format of \c label is described in \c FunctionCallLabel.
-  /// The label prefix is not one of the components.
-  virtual llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>>
-  splitFunctionCallLabel(llvm::StringRef label) const {
-    return llvm::createStringError("Not implemented.");
-  }
-
-  // Decodes the function label into a \c FunctionCallLabel.
-  virtual llvm::Expected<FunctionCallLabel>
-  makeFunctionCallLabel(llvm::StringRef label) const {
-    return llvm::createStringError("Not implemented.");
-  }
-
 protected:
   SymbolFile *m_sym_file = nullptr;
   /// Used for reporting statistics.
diff --git a/lldb/source/Expression/Expression.cpp 
b/lldb/source/Expression/Expression.cpp
index 93f585edfce3d..f55e8b1f8e485 100644
--- a/lldb/source/Expression/Expression.cpp
+++ b/lldb/source/Expression/Expression.cpp
@@ -10,6 +10,10 @@
 #include "lldb/Target/ExecutionContextScope.h"
 #include "lldb/Target/Target.h"
 
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Error.h"
+
 using namespace lldb_private;
 
 Expression::Expression(Target &target)
@@ -26,3 +30,49 @@ Expression::Expression(ExecutionContextScope &exe_scope)
       m_jit_end_addr(LLDB_INVALID_ADDRESS) {
   assert(m_target_wp.lock());
 }
+
+llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>>
+lldb_private::splitFunctionCallLabel(llvm::StringRef label) {
+  if (!label.consume_front(FunctionCallLabelPrefix))
+    return llvm::createStringError(
+        "expected function call label prefix not found in %s", label.data());
+  if (!label.consume_front(":"))
+    return llvm::createStringError(
+        "incorrect format: expected ':' as the first character.");
+
+  llvm::SmallVector<llvm::StringRef, 3> components;
+  label.split(components, ":");
+
+  if (components.size() != 3)
+    return llvm::createStringError(
+        "incorrect format: too many label subcomponents.");
+
+  return components;
+}
+
+llvm::Expected<FunctionCallLabel>
+lldb_private::makeFunctionCallLabel(llvm::StringRef label) {
+  auto components_or_err = splitFunctionCallLabel(label);
+  if (!components_or_err)
+    return llvm::joinErrors(
+        llvm::createStringError("Failed to decode function call label"),
+        components_or_err.takeError());
+
+  const auto &components = *components_or_err;
+
+  llvm::StringRef module_label = components[1];
+  llvm::StringRef die_label = components[2];
+
+  lldb::user_id_t module_id = 0;
+  if (module_label.consumeInteger(0, module_id))
+    return llvm::createStringError(
+        llvm::formatv("failed to parse module ID from '{0}'.", components[1]));
+
+  lldb::user_id_t die_id;
+  if (die_label.consumeInteger(/*Radix=*/0, die_id))
+    return llvm::createStringError(
+        llvm::formatv("failed to parse DIE ID from '{0}'.", components[2]));
+
+  return FunctionCallLabel{/*.lookup_name=*/components[0],
+                           /*.module_id=*/module_id, /*.symbol_id=*/die_id};
+}
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp 
b/lldb/source/Expression/IRExecutionUnit.cpp
index 33f34831126ac..56a01d7003c50 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -790,17 +790,7 @@ ResolveFunctionCallLabel(llvm::StringRef name,
   if (!sc.target_sp)
     return llvm::createStringError("target not available.");
 
-  auto ts_or_err = sc.target_sp->GetScratchTypeSystemForLanguage(
-      lldb::eLanguageTypeC_plus_plus);
-  if (!ts_or_err || !*ts_or_err)
-    return llvm::joinErrors(
-        llvm::createStringError(
-            "failed to find scratch C++ TypeSystem for current target."),
-        ts_or_err.takeError());
-
-  auto ts_sp = *ts_or_err;
-
-  auto label_or_err = ts_sp->makeFunctionCallLabel(name);
+  auto label_or_err = makeFunctionCallLabel(name);
   if (!label_or_err)
     return llvm::joinErrors(
         llvm::createStringError("failed to create FunctionCallLabel from: %s",
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp 
b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 7a73abc9a3ef4..797da3be74c64 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -9057,6 +9057,8 @@ ConstString TypeSystemClang::DeclGetMangledName(void 
*opaque_decl) {
   if (!mc || !mc->shouldMangleCXXName(nd))
     return {};
 
+  // We have a LLDB FunctionCallLabel instead of an ordinary mangled name.
+  // Extract the mangled name out of this label.
   if (const auto *label = nd->getAttr<AsmLabelAttr>()) {
     if (auto components_or_err = splitFunctionCallLabel(label->getLabel()))
       return ConstString((*components_or_err)[0]);
@@ -9786,49 +9788,3 @@ void TypeSystemClang::LogCreation() const {
     LLDB_LOG(log, "Created new TypeSystem for (ASTContext*){0:x} '{1}'",
              &getASTContext(), getDisplayName());
 }
-
-llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>>
-TypeSystemClang::splitFunctionCallLabel(llvm::StringRef label) const {
-  if (!label.consume_front(FunctionCallLabelPrefix))
-    return llvm::createStringError(
-        "expected function call label prefix not found in %s", label.data());
-  if (!label.consume_front(":"))
-    return llvm::createStringError(
-        "incorrect format: expected ':' as the first character.");
-
-  llvm::SmallVector<llvm::StringRef, 3> components;
-  label.split(components, ":");
-
-  if (components.size() != 3)
-    return llvm::createStringError(
-        "incorrect format: too many label subcomponents.");
-
-  return components;
-}
-
-llvm::Expected<FunctionCallLabel>
-TypeSystemClang::makeFunctionCallLabel(llvm::StringRef label) const {
-  auto components_or_err = splitFunctionCallLabel(label);
-  if (!components_or_err)
-    return llvm::joinErrors(
-        llvm::createStringError("Failed to decode function call label"),
-        components_or_err.takeError());
-
-  const auto &components = *components_or_err;
-
-  llvm::StringRef module_label = components[1];
-  llvm::StringRef die_label = components[2];
-
-  lldb::user_id_t module_id = 0;
-  if (module_label.consumeInteger(0, module_id))
-    return llvm::createStringError(
-        llvm::formatv("failed to parse module ID from '{0}'.", components[1]));
-
-  lldb::user_id_t die_id;
-  if (die_label.consumeInteger(/*Radix=*/0, die_id))
-    return llvm::createStringError(
-        llvm::formatv("failed to parse DIE ID from '{0}'.", components[2]));
-
-  return FunctionCallLabel{/*.lookup_name=*/components[0],
-                           /*.module_id=*/module_id, /*.symbol_id=*/die_id};
-}
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h 
b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index 726a0eea9382a..dcf77f9ec1cb8 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -1099,12 +1099,6 @@ class TypeSystemClang : public TypeSystem {
       lldb::opaque_compiler_type_t type, Stream &s,
       lldb::DescriptionLevel level = lldb::eDescriptionLevelFull) override;
 
-  llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>>
-  splitFunctionCallLabel(llvm::StringRef label) const override;
-
-  llvm::Expected<FunctionCallLabel>
-  makeFunctionCallLabel(llvm::StringRef label) const override;
-
   static void DumpTypeName(const CompilerType &type);
 
   static clang::EnumDecl *GetAsEnumDecl(const CompilerType &type);

>From b3f075d729c1b819b1dae195c1f45c84a45370b5 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Mon, 28 Jul 2025 12:54:20 +0100
Subject: [PATCH 08/19] fixup! adjust TypeSystemClang::DeclGetMangledName

---
 .../TypeSystem/Clang/TypeSystemClang.cpp      | 27 ++++++++++++++-----
 1 file changed, 20 insertions(+), 7 deletions(-)

diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp 
b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 797da3be74c64..2e9311bdd930c 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -9046,6 +9046,21 @@ ConstString TypeSystemClang::DeclGetName(void 
*opaque_decl) {
   return ConstString();
 }
 
+static ConstString
+ExtractMangledNameFromFunctionCallLabel(llvm::StringRef label) {
+  auto components_or_err = splitFunctionCallLabel(label);
+  if (!components_or_err) {
+    llvm::consumeError(components_or_err.takeError());
+    return {};
+  }
+
+  llvm::StringRef mangled = (*components_or_err)[0];
+  if (Mangled::IsMangledName(mangled))
+    return ConstString(mangled);
+
+  return {};
+}
+
 ConstString TypeSystemClang::DeclGetMangledName(void *opaque_decl) {
   clang::NamedDecl *nd = llvm::dyn_cast_or_null<clang::NamedDecl>(
       static_cast<clang::Decl *>(opaque_decl));
@@ -9057,14 +9072,12 @@ ConstString TypeSystemClang::DeclGetMangledName(void 
*opaque_decl) {
   if (!mc || !mc->shouldMangleCXXName(nd))
     return {};
 
-  // We have a LLDB FunctionCallLabel instead of an ordinary mangled name.
+  // We have an LLDB FunctionCallLabel instead of an ordinary mangled name.
   // Extract the mangled name out of this label.
-  if (const auto *label = nd->getAttr<AsmLabelAttr>()) {
-    if (auto components_or_err = splitFunctionCallLabel(label->getLabel()))
-      return ConstString((*components_or_err)[0]);
-    else
-      llvm::consumeError(components_or_err.takeError());
-  }
+  if (const auto *label = nd->getAttr<AsmLabelAttr>())
+    if (ConstString mangled =
+            ExtractMangledNameFromFunctionCallLabel(label->getLabel()))
+      return mangled;
 
   llvm::SmallVector<char, 1024> buf;
   llvm::raw_svector_ostream llvm_ostrm(buf);

>From d3c63096fd260b527c8200046c56c7f4d7d04a83 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Mon, 28 Jul 2025 15:08:30 +0100
Subject: [PATCH 09/19] fixup! move label encoding/decoding into
 FunctionCallLabel structure

---
 lldb/include/lldb/Expression/Expression.h     | 19 +++++++++++++++----
 lldb/source/Expression/Expression.cpp         |  8 +++++++-
 lldb/source/Expression/IRExecutionUnit.cpp    |  2 +-
 .../SymbolFile/DWARF/DWARFASTParserClang.cpp  |  7 ++++---
 4 files changed, 27 insertions(+), 9 deletions(-)

diff --git a/lldb/include/lldb/Expression/Expression.h 
b/lldb/include/lldb/Expression/Expression.h
index 35d7d71f6b253..83d3dc75620ba 100644
--- a/lldb/include/lldb/Expression/Expression.h
+++ b/lldb/include/lldb/Expression/Expression.h
@@ -121,6 +121,21 @@ struct FunctionCallLabel {
   /// perform the function call. For example, for DWARF this would
   /// be the DIE UID.
   lldb::user_id_t symbol_id;
+
+  /// Decodes the specified function \c label into a \c FunctionCallLabel.
+  static llvm::Expected<FunctionCallLabel> fromString(llvm::StringRef label);
+
+  /// Encode this FunctionCallLabel into it's string representation.
+  ///
+  /// The representation roundtrips through \c fromString:
+  /// \code{.cpp}
+  /// llvm::StringRef encoded = "$__lldb_func:_Z3foov:0x0:0x0";
+  /// FunctionCallLabel label = *fromString(label);
+  ///
+  /// assert (label.toString() == encoded);
+  /// assert (*fromString(label.toString()) == label);
+  /// \endcode
+  std::string toString() const;
 };
 
 /// LLDB attaches this prefix to mangled names of functions that it get called
@@ -134,10 +149,6 @@ inline constexpr llvm::StringRef FunctionCallLabelPrefix = 
"$__lldb_func";
 llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>>
 splitFunctionCallLabel(llvm::StringRef label);
 
-// Decodes the function label into a \c FunctionCallLabel.
-llvm::Expected<FunctionCallLabel>
-makeFunctionCallLabel(llvm::StringRef label);
-
 } // namespace lldb_private
 
 #endif // LLDB_EXPRESSION_EXPRESSION_H
diff --git a/lldb/source/Expression/Expression.cpp 
b/lldb/source/Expression/Expression.cpp
index f55e8b1f8e485..1ea18dce772ba 100644
--- a/lldb/source/Expression/Expression.cpp
+++ b/lldb/source/Expression/Expression.cpp
@@ -51,7 +51,7 @@ lldb_private::splitFunctionCallLabel(llvm::StringRef label) {
 }
 
 llvm::Expected<FunctionCallLabel>
-lldb_private::makeFunctionCallLabel(llvm::StringRef label) {
+lldb_private::FunctionCallLabel::fromString(llvm::StringRef label) {
   auto components_or_err = splitFunctionCallLabel(label);
   if (!components_or_err)
     return llvm::joinErrors(
@@ -76,3 +76,9 @@ lldb_private::makeFunctionCallLabel(llvm::StringRef label) {
   return FunctionCallLabel{/*.lookup_name=*/components[0],
                            /*.module_id=*/module_id, /*.symbol_id=*/die_id};
 }
+
+std::string lldb_private::FunctionCallLabel::toString() const {
+  return llvm::formatv("{0}:{1}:{2:x}:{3:x}", FunctionCallLabelPrefix,
+                       lookup_name, module_id, symbol_id)
+      .str();
+}
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp 
b/lldb/source/Expression/IRExecutionUnit.cpp
index 56a01d7003c50..a1d8f30f373eb 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -790,7 +790,7 @@ ResolveFunctionCallLabel(llvm::StringRef name,
   if (!sc.target_sp)
     return llvm::createStringError("target not available.");
 
-  auto label_or_err = makeFunctionCallLabel(name);
+  auto label_or_err = FunctionCallLabel::fromString(name);
   if (!label_or_err)
     return llvm::joinErrors(
         llvm::createStringError("failed to create FunctionCallLabel from: %s",
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp 
b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 8af3ed06aa3f0..5cacc97039726 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -267,9 +267,10 @@ static std::optional<std::string> 
MakeLLDBFuncAsmLabel(const DWARFDIE &die) {
   if (die_id == LLDB_INVALID_UID)
     return std::nullopt;
 
-  return llvm::formatv("{0}:{1}:{2:x}:{3:x}", FunctionCallLabelPrefix, name,
-                       module_id, die_id)
-      .str();
+  return FunctionCallLabel{/*.lookup_name=*/name,
+                           /*module_id=*/module_id,
+                           /*symbol_id=*/die_id}
+      .toString();
 }
 
 TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc,

>From 1b8d66b66ebcfe057157e82569e1fc3c20599885 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Mon, 28 Jul 2025 15:25:16 +0100
Subject: [PATCH 10/19] fixup! make mangled name last component in label;
 remove need for splitting helper

---
 lldb/include/lldb/Expression/Expression.h     | 26 ++++++++-----------
 lldb/source/Expression/Expression.cpp         | 25 +++++++++++-------
 .../SymbolFile/DWARF/DWARFASTParserClang.cpp  |  8 +++---
 .../TypeSystem/Clang/TypeSystemClang.cpp      |  8 +++---
 4 files changed, 35 insertions(+), 32 deletions(-)

diff --git a/lldb/include/lldb/Expression/Expression.h 
b/lldb/include/lldb/Expression/Expression.h
index 83d3dc75620ba..7dce9aa21e5d2 100644
--- a/lldb/include/lldb/Expression/Expression.h
+++ b/lldb/include/lldb/Expression/Expression.h
@@ -102,17 +102,11 @@ class Expression {
 ///
 /// The format being:
 ///
-///   <prefix>:<mangled name>:<module uid>:<symbol uid>
+///   <prefix>:<module uid>:<symbol uid>:<mangled name>
 ///
 /// The label string needs to stay valid for the entire lifetime
 /// of this object.
 struct FunctionCallLabel {
-  /// Name to use when searching for the function symbol in
-  /// \c module_id. For most function calls this will be a
-  /// mangled name. In cases where a mangled name can't be used,
-  /// this will be the function name.
-  llvm::StringRef lookup_name;
-
   /// Unique identifier of the lldb_private::Module
   /// which contains the symbol identified by \c symbol_id.
   lldb::user_id_t module_id;
@@ -122,6 +116,15 @@ struct FunctionCallLabel {
   /// be the DIE UID.
   lldb::user_id_t symbol_id;
 
+  /// Name to use when searching for the function symbol in
+  /// \c module_id. For most function calls this will be a
+  /// mangled name. In cases where a mangled name can't be used,
+  /// this will be the function name.
+  ///
+  /// NOTE: kept as last element so we don't have to worry about
+  /// ':' in the mangled name when parsing the label.
+  llvm::StringRef lookup_name;
+
   /// Decodes the specified function \c label into a \c FunctionCallLabel.
   static llvm::Expected<FunctionCallLabel> fromString(llvm::StringRef label);
 
@@ -129,7 +132,7 @@ struct FunctionCallLabel {
   ///
   /// The representation roundtrips through \c fromString:
   /// \code{.cpp}
-  /// llvm::StringRef encoded = "$__lldb_func:_Z3foov:0x0:0x0";
+  /// llvm::StringRef encoded = "$__lldb_func:0x0:0x0:_Z3foov";
   /// FunctionCallLabel label = *fromString(label);
   ///
   /// assert (label.toString() == encoded);
@@ -142,13 +145,6 @@ struct FunctionCallLabel {
 /// from JITted expressions.
 inline constexpr llvm::StringRef FunctionCallLabelPrefix = "$__lldb_func";
 
-/// Returns the components of the specified function call label.
-///
-/// The format of \c label is described in \c FunctionCallLabel.
-/// The label prefix is not one of the components.
-llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>>
-splitFunctionCallLabel(llvm::StringRef label);
-
 } // namespace lldb_private
 
 #endif // LLDB_EXPRESSION_EXPRESSION_H
diff --git a/lldb/source/Expression/Expression.cpp 
b/lldb/source/Expression/Expression.cpp
index 1ea18dce772ba..dc2d6bf520f05 100644
--- a/lldb/source/Expression/Expression.cpp
+++ b/lldb/source/Expression/Expression.cpp
@@ -31,8 +31,12 @@ Expression::Expression(ExecutionContextScope &exe_scope)
   assert(m_target_wp.lock());
 }
 
-llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>>
-lldb_private::splitFunctionCallLabel(llvm::StringRef label) {
+/// Returns the components of the specified function call label.
+///
+/// The format of \c label is described in \c FunctionCallLabel.
+/// The label prefix is not one of the components.
+static llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>>
+splitFunctionCallLabel(llvm::StringRef label) {
   if (!label.consume_front(FunctionCallLabelPrefix))
     return llvm::createStringError(
         "expected function call label prefix not found in %s", label.data());
@@ -60,25 +64,26 @@ lldb_private::FunctionCallLabel::fromString(llvm::StringRef 
label) {
 
   const auto &components = *components_or_err;
 
-  llvm::StringRef module_label = components[1];
-  llvm::StringRef die_label = components[2];
+  llvm::StringRef module_label = components[0];
+  llvm::StringRef die_label = components[1];
 
   lldb::user_id_t module_id = 0;
   if (module_label.consumeInteger(0, module_id))
     return llvm::createStringError(
-        llvm::formatv("failed to parse module ID from '{0}'.", components[1]));
+        llvm::formatv("failed to parse module ID from '{0}'.", components[0]));
 
   lldb::user_id_t die_id;
   if (die_label.consumeInteger(/*Radix=*/0, die_id))
     return llvm::createStringError(
-        llvm::formatv("failed to parse DIE ID from '{0}'.", components[2]));
+        llvm::formatv("failed to parse DIE ID from '{0}'.", components[1]));
 
-  return FunctionCallLabel{/*.lookup_name=*/components[0],
-                           /*.module_id=*/module_id, /*.symbol_id=*/die_id};
+  return FunctionCallLabel{/*.module_id=*/module_id,
+                           /*.symbol_id=*/die_id,
+                           /*.lookup_name=*/components[2]};
 }
 
 std::string lldb_private::FunctionCallLabel::toString() const {
-  return llvm::formatv("{0}:{1}:{2:x}:{3:x}", FunctionCallLabelPrefix,
-                       lookup_name, module_id, symbol_id)
+  return llvm::formatv("{0}:{1:x}:{2:x}:{3}", FunctionCallLabelPrefix,
+                       module_id, symbol_id, lookup_name)
       .str();
 }
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp 
b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 5cacc97039726..98c07f4a2b94f 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -267,9 +267,11 @@ static std::optional<std::string> 
MakeLLDBFuncAsmLabel(const DWARFDIE &die) {
   if (die_id == LLDB_INVALID_UID)
     return std::nullopt;
 
-  return FunctionCallLabel{/*.lookup_name=*/name,
-                           /*module_id=*/module_id,
-                           /*symbol_id=*/die_id}
+  return FunctionCallLabel{
+      /*module_id=*/module_id,
+      /*symbol_id=*/die_id,
+      /*.lookup_name=*/name
+  }
       .toString();
 }
 
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp 
b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 2e9311bdd930c..84e3320ab70ba 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -9048,13 +9048,13 @@ ConstString TypeSystemClang::DeclGetName(void 
*opaque_decl) {
 
 static ConstString
 ExtractMangledNameFromFunctionCallLabel(llvm::StringRef label) {
-  auto components_or_err = splitFunctionCallLabel(label);
-  if (!components_or_err) {
-    llvm::consumeError(components_or_err.takeError());
+  auto label_or_err = FunctionCallLabel::fromString(label);
+  if (!label_or_err) {
+    llvm::consumeError(label_or_err.takeError());
     return {};
   }
 
-  llvm::StringRef mangled = (*components_or_err)[0];
+  llvm::StringRef mangled = label_or_err->lookup_name;
   if (Mangled::IsMangledName(mangled))
     return ConstString(mangled);
 

>From 1becf7dd7bdacb2d8a20ade83993c04a13d93e6d Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Mon, 28 Jul 2025 15:44:13 +0100
Subject: [PATCH 11/19] fixup! rebase on latest ModuleList changes

---
 lldb/source/Core/ModuleList.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp
index e3dfa799ebb65..01f46b62b57bd 100644
--- a/lldb/source/Core/ModuleList.cpp
+++ b/lldb/source/Core/ModuleList.cpp
@@ -589,10 +589,10 @@ ModuleSP ModuleList::FindModule(lldb::user_id_t uid) 
const {
   ForEach([&](const ModuleSP &m) {
     if (m->GetID() == uid) {
       module_sp = m;
-      return true;
+      return IterationAction::Stop;
     }
 
-    return false;
+    return IterationAction::Continue;
   });
 
   return module_sp;

>From 9aec4ecbf291460d97270f18c6d8b79e11b91f7c Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Mon, 28 Jul 2025 15:44:54 +0100
Subject: [PATCH 12/19] fixup! remove mention of mangled name from
 FunctionCallLabel doc

---
 lldb/include/lldb/Expression/Expression.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lldb/include/lldb/Expression/Expression.h 
b/lldb/include/lldb/Expression/Expression.h
index 7dce9aa21e5d2..4dc74b13fa8f9 100644
--- a/lldb/include/lldb/Expression/Expression.h
+++ b/lldb/include/lldb/Expression/Expression.h
@@ -102,7 +102,7 @@ class Expression {
 ///
 /// The format being:
 ///
-///   <prefix>:<module uid>:<symbol uid>:<mangled name>
+///   <prefix>:<module uid>:<symbol uid>:<name>
 ///
 /// The label string needs to stay valid for the entire lifetime
 /// of this object.

>From d5bda43899a36441f135d25d657e807ab28158bb Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Mon, 28 Jul 2025 16:35:47 +0100
Subject: [PATCH 13/19] fixup! add format_provider for FunctionCallLabel

---
 lldb/include/lldb/Expression/Expression.h | 8 ++++++++
 lldb/source/Expression/Expression.cpp     | 9 ++++++++-
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/lldb/include/lldb/Expression/Expression.h 
b/lldb/include/lldb/Expression/Expression.h
index 4dc74b13fa8f9..a6c49bcc10ad0 100644
--- a/lldb/include/lldb/Expression/Expression.h
+++ b/lldb/include/lldb/Expression/Expression.h
@@ -13,6 +13,7 @@
 #include <string>
 #include <vector>
 
+#include "llvm/Support/FormatProviders.h"
 
 #include "lldb/Expression/ExpressionTypeSystemHelper.h"
 #include "lldb/lldb-forward.h"
@@ -147,4 +148,11 @@ inline constexpr llvm::StringRef FunctionCallLabelPrefix = 
"$__lldb_func";
 
 } // namespace lldb_private
 
+namespace llvm {
+template <> struct format_provider<lldb_private::FunctionCallLabel> {
+  static void format(const lldb_private::FunctionCallLabel &label,
+                     raw_ostream &OS, StringRef Style);
+};
+} // namespace llvm
+
 #endif // LLDB_EXPRESSION_EXPRESSION_H
diff --git a/lldb/source/Expression/Expression.cpp 
b/lldb/source/Expression/Expression.cpp
index dc2d6bf520f05..251904fbc7dcb 100644
--- a/lldb/source/Expression/Expression.cpp
+++ b/lldb/source/Expression/Expression.cpp
@@ -10,8 +10,8 @@
 #include "lldb/Target/ExecutionContextScope.h"
 #include "lldb/Target/Target.h"
 
-#include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Error.h"
 
 using namespace lldb_private;
@@ -87,3 +87,10 @@ std::string lldb_private::FunctionCallLabel::toString() 
const {
                        module_id, symbol_id, lookup_name)
       .str();
 }
+
+void llvm::format_provider<FunctionCallLabel>::format(
+    const FunctionCallLabel &label, raw_ostream &OS, StringRef Style) {
+  OS << llvm::formatv("FunctionCallLabel{ module_id: {0:x}, symbol_id: {1:x}, "
+                      "lookup_name: {2} }",
+                      label.module_id, label.symbol_id, label.lookup_name);
+}

>From 785e96a4ac2e2f08bf37a57f60fb43661d877490 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Mon, 28 Jul 2025 16:36:12 +0100
Subject: [PATCH 14/19] fixup! only do name lookup for declaration DIE cases

---
 lldb/include/lldb/Symbol/SymbolFile.h         | 12 ++--
 lldb/source/Expression/IRExecutionUnit.cpp    |  3 +-
 .../SymbolFile/DWARF/SymbolFileDWARF.cpp      | 61 +++++++++++--------
 .../SymbolFile/DWARF/SymbolFileDWARF.h        |  4 +-
 4 files changed, 46 insertions(+), 34 deletions(-)

diff --git a/lldb/include/lldb/Symbol/SymbolFile.h 
b/lldb/include/lldb/Symbol/SymbolFile.h
index 6aca276fc85b6..45798f667cb22 100644
--- a/lldb/include/lldb/Symbol/SymbolFile.h
+++ b/lldb/include/lldb/Symbol/SymbolFile.h
@@ -329,16 +329,18 @@ class SymbolFile : public PluginInterface {
   GetMangledNamesForFunction(const std::string &scope_qualified_name,
                              std::vector<ConstString> &mangled_names);
 
-  /// Resolves the function DIE identified by \c lookup_name within
-  /// this SymbolFile.
+  /// Resolves the function corresponding to the specified LLDB function
+  /// call \c label.
   ///
   /// \param[in,out] sc_list The resolved functions will be appended to this
   /// list.
   ///
-  /// \param[in] lookup_name The UID of the function DIE to resolve.
+  /// \param[in] label The FunctionCallLabel to be resolved.
   ///
-  virtual llvm::Error FindAndResolveFunction(SymbolContextList &sc_list,
-                                             llvm::StringRef lookup_name) {
+  /// \returns An llvm::Error if the specified \c label couldn't be resolved.
+  ///          Returns \c llvm::ErrorSuccess otherwise.
+  virtual llvm::Error ResolveFunctionCallLabel(SymbolContextList &sc_list,
+                                               const FunctionCallLabel &label) 
{
     return llvm::createStringError("Not implemented");
   }
 
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp 
b/lldb/source/Expression/IRExecutionUnit.cpp
index a1d8f30f373eb..ef119f6875870 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -811,8 +811,7 @@ ResolveFunctionCallLabel(llvm::StringRef name,
         llvm::formatv("no SymbolFile found on module {0:x}.", 
module_sp.get()));
 
   SymbolContextList sc_list;
-  if (auto err =
-          symbol_file->FindAndResolveFunction(sc_list, label.lookup_name))
+  if (auto err = symbol_file->ResolveFunctionCallLabel(sc_list, label))
     return llvm::joinErrors(
         llvm::createStringError("failed to resolve function by UID"),
         std::move(err));
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp 
b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index a1164646cbb29..a87126acfcc6a 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -2472,42 +2472,53 @@ bool SymbolFileDWARF::ResolveFunction(const DWARFDIE 
&orig_die,
 }
 
 llvm::Error
-SymbolFileDWARF::FindAndResolveFunction(SymbolContextList &sc_list,
-                                        llvm::StringRef lookup_name) {
+SymbolFileDWARF::ResolveFunctionCallLabel(SymbolContextList &sc_list,
+                                          const FunctionCallLabel &label) {
   std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
 
-  DWARFDIE die;
-  Module::LookupInfo info(ConstString(lookup_name), 
lldb::eFunctionNameTypeFull,
-                          lldb::eLanguageTypeUnknown);
+  DWARFDIE die = GetDIE(label.symbol_id);
+  if (!die.IsValid())
+    return llvm::createStringError(
+        llvm::formatv("invalid DIE ID in {0}", label));
 
-  m_index->GetFunctions(info, *this, {}, [&](DWARFDIE entry) {
-    if (entry.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0))
-      return true;
+  // Label was created using a declaration DIE. Need to fetch the definition
+  // to resolve the function call.
+  if (die.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0)) {
+    Module::LookupInfo info(ConstString(label.lookup_name),
+                            lldb::eFunctionNameTypeFull,
+                            lldb::eLanguageTypeUnknown);
 
-    // We don't check whether the specification DIE for this function
-    // corresponds to the declaration DIE because the declaration might be in
-    // a type-unit but the definition in the compile-unit (and it's
-    // specifcation would point to the declaration in the compile-unit). We
-    // rely on the mangled name within the module to be enough to find us the
-    // unique definition.
-    die = entry;
-    return false;
-  });
+    m_index->GetFunctions(info, *this, {}, [&](DWARFDIE entry) {
+      if (entry.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0))
+        return true;
 
-  if (!die.IsValid())
-    return llvm::createStringError(
-        llvm::formatv("failed to find definition DIE for '{0}'", lookup_name));
+      // We don't check whether the specification DIE for this function
+      // corresponds to the declaration DIE because the declaration might be in
+      // a type-unit but the definition in the compile-unit (and it's
+      // specifcation would point to the declaration in the compile-unit). We
+      // rely on the mangled name within the module to be enough to find us the
+      // unique definition.
+      die = entry;
+      return false;
+    });
 
-  if (!ResolveFunction(die, false, sc_list))
-    return llvm::createStringError("failed to resolve function DIE");
+    if (die.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0))
+      return llvm::createStringError(
+          llvm::formatv("failed to find definition DIE for {0}", label));
+  }
+
+  if (!ResolveFunction(die, /*include_inlines=*/false, sc_list))
+    return llvm::createStringError(
+        llvm::formatv("failed to resolve function for {0}", label));
 
   if (sc_list.IsEmpty())
-    return llvm::createStringError("no definition DIE found");
+    return llvm::createStringError(
+        llvm::formatv("failed to find function for {0}", label));
 
   if (sc_list.GetSize() > 1)
     return llvm::createStringError(
-        "found %d functions for %s but expected only 1", sc_list.GetSize(),
-        lookup_name.data());
+        llvm::formatv("found {0} functions for {1} but expected only 1",
+                      sc_list.GetSize(), label));
 
   return llvm::Error::success();
 }
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h 
b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index ee966366d3f2b..bf83eb332a8c3 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -434,8 +434,8 @@ class SymbolFileDWARF : public SymbolFileCommon {
   DIEArray MergeBlockAbstractParameters(const DWARFDIE &block_die,
                                         DIEArray &&variable_dies);
 
-  llvm::Error FindAndResolveFunction(SymbolContextList &sc_list,
-                                     llvm::StringRef lookup_name) override;
+  llvm::Error ResolveFunctionCallLabel(SymbolContextList &sc_list,
+                                       const FunctionCallLabel &label) 
override;
 
   // Given a die_offset, figure out the symbol context representing that die.
   bool ResolveFunction(const DWARFDIE &die, bool include_inlines,

>From 609af2af3ff28db879ea5024c8d4168a07e28cdc Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Tue, 29 Jul 2025 12:08:45 +0100
Subject: [PATCH 15/19] fixup! add tests; account for ':' in mangled name;
 adjust error messages

---
 lldb/source/Expression/Expression.cpp         |  25 ++--
 .../SymbolFile/DWARF/DWARFASTParserClang.cpp  |  10 +-
 lldb/unittests/Expression/CMakeLists.txt      |   1 +
 lldb/unittests/Expression/ExpressionTest.cpp  | 109 ++++++++++++++++++
 4 files changed, 135 insertions(+), 10 deletions(-)
 create mode 100644 lldb/unittests/Expression/ExpressionTest.cpp

diff --git a/lldb/source/Expression/Expression.cpp 
b/lldb/source/Expression/Expression.cpp
index 251904fbc7dcb..a57bcbe97e117 100644
--- a/lldb/source/Expression/Expression.cpp
+++ b/lldb/source/Expression/Expression.cpp
@@ -39,17 +39,23 @@ static llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>>
 splitFunctionCallLabel(llvm::StringRef label) {
   if (!label.consume_front(FunctionCallLabelPrefix))
     return llvm::createStringError(
-        "expected function call label prefix not found in %s", label.data());
+        "expected function call label prefix not found.");
   if (!label.consume_front(":"))
     return llvm::createStringError(
-        "incorrect format: expected ':' as the first character.");
+        "expected ':' as the first character after prefix.");
 
-  llvm::SmallVector<llvm::StringRef, 3> components;
-  label.split(components, ":");
+  auto sep1 = label.find_first_of(":");
+  if (sep1 == llvm::StringRef::npos)
+    return llvm::createStringError("no ':' separator found.");
 
-  if (components.size() != 3)
-    return llvm::createStringError(
-        "incorrect format: too many label subcomponents.");
+  auto sep2 = label.find_first_of(":", sep1 + 1);
+  if (sep2 == llvm::StringRef::npos)
+    return llvm::createStringError("only single ':' separator found.");
+
+  llvm::SmallVector<llvm::StringRef, 3> components;
+  components.push_back(label.slice(0, sep1));
+  components.push_back(label.slice(sep1 + 1, sep2));
+  components.push_back(label.slice(sep2 + 1, llvm::StringRef::npos));
 
   return components;
 }
@@ -59,7 +65,8 @@ lldb_private::FunctionCallLabel::fromString(llvm::StringRef 
label) {
   auto components_or_err = splitFunctionCallLabel(label);
   if (!components_or_err)
     return llvm::joinErrors(
-        llvm::createStringError("Failed to decode function call label"),
+        llvm::createStringError("failed to split function call label '%s'",
+                                label.data()),
         components_or_err.takeError());
 
   const auto &components = *components_or_err;
@@ -75,7 +82,7 @@ lldb_private::FunctionCallLabel::fromString(llvm::StringRef 
label) {
   lldb::user_id_t die_id;
   if (die_label.consumeInteger(/*Radix=*/0, die_id))
     return llvm::createStringError(
-        llvm::formatv("failed to parse DIE ID from '{0}'.", components[1]));
+        llvm::formatv("failed to parse symbol ID from '{0}'.", components[1]));
 
   return FunctionCallLabel{/*.module_id=*/module_id,
                            /*.symbol_id=*/die_id,
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp 
b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 98c07f4a2b94f..c92d95e2b18da 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -255,7 +255,15 @@ static std::optional<std::string> 
MakeLLDBFuncAsmLabel(const DWARFDIE &die) {
   if (!name)
     return std::nullopt;
 
-  auto module_sp = die.GetModule();
+  SymbolFileDWARF *dwarf = die.GetDWARF();
+  if (!dwarf)
+    return std::nullopt;
+
+  ObjectFile *main_obj = dwarf->GetMainObjectFile();
+  if (!main_obj)
+    return std::nullopt;
+
+  auto module_sp = main_obj->GetModule();
   if (!module_sp)
     return std::nullopt;
 
diff --git a/lldb/unittests/Expression/CMakeLists.txt 
b/lldb/unittests/Expression/CMakeLists.txt
index 185b19f84cae7..3970f5ab7e5d9 100644
--- a/lldb/unittests/Expression/CMakeLists.txt
+++ b/lldb/unittests/Expression/CMakeLists.txt
@@ -4,6 +4,7 @@ add_lldb_unittest(ExpressionTests
   DiagnosticManagerTest.cpp
   DWARFExpressionTest.cpp
   CppModuleConfigurationTest.cpp
+  ExpressionTest.cpp
 
   LINK_LIBS
     lldbCore
diff --git a/lldb/unittests/Expression/ExpressionTest.cpp 
b/lldb/unittests/Expression/ExpressionTest.cpp
new file mode 100644
index 0000000000000..542ce5005d7d9
--- /dev/null
+++ b/lldb/unittests/Expression/ExpressionTest.cpp
@@ -0,0 +1,109 @@
+//===-- ExpressionTest.cpp 
------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include "TestingSupport/TestUtilities.h"
+#include "lldb/Expression/Expression.h"
+#include "llvm/Testing/Support/Error.h"
+
+using namespace lldb_private;
+
+struct LabelTestCase {
+  llvm::StringRef encoded;
+  FunctionCallLabel label;
+  llvm::SmallVector<llvm::StringRef> error_pattern;
+};
+
+static LabelTestCase g_label_test_cases[] = {
+    // Failure modes
+    {"0x0:0x0:_Z3foov",
+     {},
+     {"failed to split function call label '0x0:0x0:_Z3foov'",
+      "expected function call label prefix not found."}},
+    {"$__lldb_func0x0:0x0:_Z3foov",
+     {},
+     {"failed to split function call label '$__lldb_func0x0:0x0:_Z3foov'",
+      "expected ':' as the first character after prefix."}},
+    {"$__lldb_func:",
+     {},
+     {"failed to split function call label '$__lldb_func:'",
+      "no ':' separator found."}},
+    {"$__lldb_func:0x0:0x0",
+     {},
+     {"failed to split function call label '$__lldb_func:0x0:0x0'",
+      "only single ':' separator found."}},
+    {"$__lldb_func:abc:0x0:_Z3foov",
+     {},
+     {"failed to parse module ID from 'abc'."}},
+    {"$__lldb_func:-1:0x0:_Z3foov",
+     {},
+     {"failed to parse module ID from '-1'."}},
+    {"$__lldb_func:0x0:abc:_Z3foov",
+     {},
+     {"failed to parse symbol ID from 'abc'."}},
+    {"$__lldb_func:0x5:-1:_Z3foov",
+     {},
+     {"failed to parse symbol ID from '-1'."}},
+    {"$__lldb_func:0x0:0x0:_Z3foov",
+     {
+         /*.module_id=*/0x0,
+         /*.symbol_id=*/0x0,
+         /*.lookup_name=*/"_Z3foov",
+     },
+     {}},
+    {"$__lldb_func:0x0:0x0:abc:def:::a",
+     {
+         /*.module_id=*/0x0,
+         /*.symbol_id=*/0x0,
+         /*.lookup_name=*/"abc:def:::a",
+     },
+     {}},
+    {"$__lldb_func:0xd2:0xf0:$__lldb_func",
+     {
+         /*.module_id=*/0xd2,
+         /*.symbol_id=*/0xf0,
+         /*.lookup_name=*/"$__lldb_func",
+     },
+     {}},
+};
+
+struct ExpressionTestFixture : public testing::TestWithParam<LabelTestCase> {};
+
+TEST_P(ExpressionTestFixture, FunctionCallLabel) {
+  const auto &[encoded, label, errors] = GetParam();
+
+  auto decoded_or_err = FunctionCallLabel::fromString(encoded);
+  if (!errors.empty()) {
+    EXPECT_THAT_EXPECTED(
+        decoded_or_err,
+        llvm::FailedWithMessageArray(testing::ElementsAreArray(errors)));
+    return;
+  }
+
+  EXPECT_THAT_EXPECTED(decoded_or_err, llvm::Succeeded());
+
+  auto label_str = label.toString();
+  EXPECT_EQ(decoded_or_err->toString(), encoded);
+  EXPECT_EQ(label_str, encoded);
+
+  EXPECT_EQ(decoded_or_err->module_id, label.module_id);
+  EXPECT_EQ(decoded_or_err->symbol_id, label.symbol_id);
+  EXPECT_EQ(decoded_or_err->lookup_name, label.lookup_name);
+
+  auto roundtrip_or_err = FunctionCallLabel::fromString(label_str);
+  EXPECT_THAT_EXPECTED(roundtrip_or_err, llvm::Succeeded());
+
+  EXPECT_EQ(roundtrip_or_err->module_id, label.module_id);
+  EXPECT_EQ(roundtrip_or_err->symbol_id, label.symbol_id);
+  EXPECT_EQ(roundtrip_or_err->lookup_name, label.lookup_name);
+}
+
+INSTANTIATE_TEST_SUITE_P(FunctionCallLabelTest, ExpressionTestFixture,
+                         testing::ValuesIn(g_label_test_cases));

>From fc60861e1b020cf91ff8a37e0a2cdc3658e2299c Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Wed, 30 Jul 2025 10:11:05 +0100
Subject: [PATCH 16/19] fixup! drop \01 mangling prefix when searching using IR
 function name

---
 lldb/source/Expression/IRInterpreter.cpp | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/lldb/source/Expression/IRInterpreter.cpp 
b/lldb/source/Expression/IRInterpreter.cpp
index fa74e8828a574..91404831aeb9b 100644
--- a/lldb/source/Expression/IRInterpreter.cpp
+++ b/lldb/source/Expression/IRInterpreter.cpp
@@ -259,7 +259,9 @@ class InterpreterStackFrame {
       break;
     case Value::FunctionVal:
       if (const Function *constant_func = dyn_cast<Function>(constant)) {
-        lldb_private::ConstString name(constant_func->getName());
+        lldb_private::ConstString name(
+            llvm::GlobalValue::dropLLVMManglingEscape(
+                constant_func->getName()));
         bool missing_weak = false;
         lldb::addr_t addr = m_execution_unit.FindSymbol(name, missing_weak);
         if (addr == LLDB_INVALID_ADDRESS)

>From dd9a69cdf324b8470aa8a3470655924084e05e0e Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Wed, 30 Jul 2025 10:13:44 +0100
Subject: [PATCH 17/19] fixup! search .o files when searching for module by UID

---
 lldb/include/lldb/Core/ModuleList.h        |  8 ------
 lldb/source/Core/ModuleList.cpp            | 14 ---------
 lldb/source/Expression/IRExecutionUnit.cpp | 33 ++++++++++++++++++++--
 3 files changed, 31 insertions(+), 24 deletions(-)

diff --git a/lldb/include/lldb/Core/ModuleList.h 
b/lldb/include/lldb/Core/ModuleList.h
index 6ecdcf10fa85f..d5e291f3380a8 100644
--- a/lldb/include/lldb/Core/ModuleList.h
+++ b/lldb/include/lldb/Core/ModuleList.h
@@ -352,14 +352,6 @@ class ModuleList {
   // UUID values is very efficient and accurate.
   lldb::ModuleSP FindModule(const UUID &uuid) const;
 
-  /// Find a module by LLDB-specific unique identifier.
-  ///
-  /// \param[in] uid The UID of the module assigned to it on construction.
-  ///
-  /// \returns ModuleSP of module with \c uid. Returns nullptr if no such
-  /// module could be found.
-  lldb::ModuleSP FindModule(lldb::user_id_t uid) const;
-
   /// Finds the first module whose file specification matches \a module_spec.
   lldb::ModuleSP FindFirstModule(const ModuleSpec &module_spec) const;
 
diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp
index 01f46b62b57bd..d2e5be8c79b17 100644
--- a/lldb/source/Core/ModuleList.cpp
+++ b/lldb/source/Core/ModuleList.cpp
@@ -584,20 +584,6 @@ ModuleSP ModuleList::FindModule(const UUID &uuid) const {
   return module_sp;
 }
 
-ModuleSP ModuleList::FindModule(lldb::user_id_t uid) const {
-  ModuleSP module_sp;
-  ForEach([&](const ModuleSP &m) {
-    if (m->GetID() == uid) {
-      module_sp = m;
-      return IterationAction::Stop;
-    }
-
-    return IterationAction::Continue;
-  });
-
-  return module_sp;
-}
-
 void ModuleList::FindTypes(Module *search_first, const TypeQuery &query,
                            TypeResults &results) const {
   std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp 
b/lldb/source/Expression/IRExecutionUnit.cpp
index ef119f6875870..128e1beb76991 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -774,6 +774,36 @@ class LoadAddressResolver {
   lldb::addr_t m_best_internal_load_address = LLDB_INVALID_ADDRESS;
 };
 
+/// Find a module by LLDB-specific unique identifier.
+///
+/// \param[in] uid The UID of the module assigned to it on construction.
+///
+/// \returns ModuleSP of module with \c uid. Returns nullptr if no such
+/// module could be found.
+static lldb::ModuleSP FindDebugModule(lldb::user_id_t uid,
+                                      const ModuleList &modules) {
+  lldb::ModuleSP module_sp;
+  modules.ForEach([&](const lldb::ModuleSP &m) {
+    if (m->GetID() == uid) {
+      module_sp = m;
+      return IterationAction::Stop;
+    }
+
+    auto *sym = m->GetSymbolFile();
+    if (!sym)
+      return IterationAction::Continue;
+
+    auto debug_modules = sym->GetDebugInfoModules();
+    module_sp = FindDebugModule(uid, debug_modules);
+    if (module_sp)
+      return IterationAction::Stop;
+
+    return IterationAction::Continue;
+  });
+
+  return module_sp;
+}
+
 /// Returns address of the function referred to by the special function call
 /// label \c label.
 ///
@@ -799,8 +829,7 @@ ResolveFunctionCallLabel(llvm::StringRef name,
 
   const auto &label = *label_or_err;
 
-  auto module_sp = sc.target_sp->GetImages().FindModule(label.module_id);
-
+  auto module_sp = FindDebugModule(label.module_id, sc.target_sp->GetImages());
   if (!module_sp)
     return llvm::createStringError(
         llvm::formatv("failed to find module by UID {0}", label.module_id));

>From 3256170dab1eabc9871020af81220458e417706a Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Wed, 30 Jul 2025 10:15:14 +0100
Subject: [PATCH 18/19] fixup! revert whitespace change

---
 lldb/include/lldb/Symbol/TypeSystem.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/lldb/include/lldb/Symbol/TypeSystem.h 
b/lldb/include/lldb/Symbol/TypeSystem.h
index 40bd59056a5df..cb1f0130b548d 100644
--- a/lldb/include/lldb/Symbol/TypeSystem.h
+++ b/lldb/include/lldb/Symbol/TypeSystem.h
@@ -548,7 +548,6 @@ class TypeSystem : public PluginInterface,
   bool GetHasForcefullyCompletedTypes() const {
     return m_has_forcefully_completed_types;
   }
-
 protected:
   SymbolFile *m_sym_file = nullptr;
   /// Used for reporting statistics.

>From 632508f708da918a673bfba6868cf969ed029390 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Wed, 30 Jul 2025 10:26:42 +0100
Subject: [PATCH 19/19] fixup! remove stale comment

---
 lldb/source/Expression/IRExecutionUnit.cpp | 2 --
 1 file changed, 2 deletions(-)

diff --git a/lldb/source/Expression/IRExecutionUnit.cpp 
b/lldb/source/Expression/IRExecutionUnit.cpp
index 128e1beb76991..448a3cb649c0d 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -809,8 +809,6 @@ static lldb::ModuleSP FindDebugModule(lldb::user_id_t uid,
 ///
 /// \param[in] label Function call label encoding the unique location of the
 /// function to look up.
-///                  Assumes that the \c FunctionCallLabelPrefix has been
-///                  stripped from the front of the label.
 static llvm::Expected<lldb::addr_t>
 ResolveFunctionCallLabel(llvm::StringRef name,
                          const lldb_private::SymbolContext &sc,

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

Reply via email to