[clang] [libcxxabi] [lldb] [llvm] [DRAFT] [lldb][Expression] Add structor variant to LLDB's function call labels (PR #149827)

Michael Buch via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 31 06:20:21 PDT 2025


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

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

---
 lldb/include/lldb/Core/Module.h               |  4 +-
 lldb/include/lldb/Expression/Expression.h     | 25 +++++++
 lldb/include/lldb/Symbol/SymbolFile.h         | 14 ++++
 lldb/include/lldb/Symbol/TypeSystem.h         | 16 ++++
 lldb/source/Core/Module.cpp                   | 19 ++++-
 lldb/source/Expression/Expression.cpp         | 16 ++++
 lldb/source/Expression/IRExecutionUnit.cpp    | 74 +++++++++++++++++++
 .../SymbolFile/DWARF/DWARFASTParserClang.cpp  | 21 +++++-
 .../SymbolFile/DWARF/SymbolFileDWARF.cpp      | 41 ++++++++++
 .../SymbolFile/DWARF/SymbolFileDWARF.h        |  3 +
 .../TypeSystem/Clang/TypeSystemClang.cpp      | 56 ++++++++++++++
 .../TypeSystem/Clang/TypeSystemClang.h        |  6 ++
 lldb/unittests/Symbol/TestTypeSystemClang.cpp | 24 ++++++
 13 files changed, 312 insertions(+), 7 deletions(-)

diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h
index 8bb55c95773bc..3991a12997541 100644
--- a/lldb/include/lldb/Core/Module.h
+++ b/lldb/include/lldb/Core/Module.h
@@ -86,7 +86,8 @@ struct ModuleFunctionSearchOptions {
 ///
 /// The module will parse more detailed information as more queries are made.
 class Module : public std::enable_shared_from_this<Module>,
-               public SymbolContextScope {
+               public SymbolContextScope,
+               public UserID {
 public:
   class LookupInfo;
   // Static functions that can track the lifetime of module objects. This is
@@ -97,6 +98,7 @@ class Module : public std::enable_shared_from_this<Module>,
   // using the "--global" (-g for short).
   static size_t GetNumberAllocatedModules();
 
+  static Module *GetAllocatedModuleWithUID(lldb::user_id_t uid);
   static Module *GetAllocatedModuleAtIndex(size_t idx);
 
   static std::recursive_mutex &GetAllocationModuleCollectionMutex();
diff --git a/lldb/include/lldb/Expression/Expression.h b/lldb/include/lldb/Expression/Expression.h
index 8de9364436ccf..f32878c9bf876 100644
--- a/lldb/include/lldb/Expression/Expression.h
+++ b/lldb/include/lldb/Expression/Expression.h
@@ -96,6 +96,31 @@ class Expression {
                                  ///invalid.
 };
 
+/// Holds parsed information about a function call label that
+/// LLDB attaches as an AsmLabel to function AST nodes it parses
+/// from debug-info.
+///
+/// The format being:
+///
+///   <prefix>:<mangled name>:<module id>:<DIE id>
+///
+/// The label string needs to stay valid for the entire lifetime
+/// of this object.
+struct FunctionCallLabel {
+  llvm::StringRef m_lookup_name;
+  lldb::user_id_t m_module_id;
+
+  /// Mostly for debuggability.
+  lldb::user_id_t m_die_id;
+};
+
+/// LLDB attaches this prefix to mangled names of functions that it get called
+/// from JITted expressions.
+inline constexpr llvm::StringRef FunctionCallLabelPrefix = "$__lldb_func";
+
+bool consumeFunctionCallLabelPrefix(llvm::StringRef &name);
+bool hasFunctionCallLabelPrefix(llvm::StringRef name);
+
 } // namespace lldb_private
 
 #endif // LLDB_EXPRESSION_EXPRESSION_H
diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h
index e95f95553c17c..6aca276fc85b6 100644
--- a/lldb/include/lldb/Symbol/SymbolFile.h
+++ b/lldb/include/lldb/Symbol/SymbolFile.h
@@ -18,6 +18,7 @@
 #include "lldb/Symbol/CompilerType.h"
 #include "lldb/Symbol/Function.h"
 #include "lldb/Symbol/SourceModule.h"
+#include "lldb/Symbol/SymbolContext.h"
 #include "lldb/Symbol/Type.h"
 #include "lldb/Symbol/TypeList.h"
 #include "lldb/Symbol/TypeSystem.h"
@@ -328,6 +329,19 @@ class SymbolFile : public PluginInterface {
   GetMangledNamesForFunction(const std::string &scope_qualified_name,
                              std::vector<ConstString> &mangled_names);
 
+  /// Resolves the function DIE identified by \c lookup_name within
+  /// this SymbolFile.
+  ///
+  /// \param[in,out] sc_list The resolved functions will be appended to this
+  /// list.
+  ///
+  /// \param[in] lookup_name The UID of the function DIE to resolve.
+  ///
+  virtual llvm::Error FindAndResolveFunction(SymbolContextList &sc_list,
+                                             llvm::StringRef lookup_name) {
+    return llvm::createStringError("Not implemented");
+  }
+
   virtual void GetTypes(lldb_private::SymbolContextScope *sc_scope,
                         lldb::TypeClass type_mask,
                         lldb_private::TypeList &type_list) = 0;
diff --git a/lldb/include/lldb/Symbol/TypeSystem.h b/lldb/include/lldb/Symbol/TypeSystem.h
index cb1f0130b548d..742c09251ea2f 100644
--- a/lldb/include/lldb/Symbol/TypeSystem.h
+++ b/lldb/include/lldb/Symbol/TypeSystem.h
@@ -548,6 +548,22 @@ class TypeSystem : public PluginInterface,
   bool GetHasForcefullyCompletedTypes() const {
     return m_has_forcefully_completed_types;
   }
+
+  /// Returns the components of the specified function call label.
+  ///
+  /// The format of \c label is described in \c FunctionCallLabel.
+  /// The label prefix is not one of the components.
+  virtual llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>>
+  splitFunctionCallLabel(llvm::StringRef label) const {
+    return llvm::createStringError("Not implemented.");
+  }
+
+  // Decodes the function label into a \c FunctionCallLabel.
+  virtual llvm::Expected<FunctionCallLabel>
+  makeFunctionCallLabel(llvm::StringRef label) const {
+    return llvm::createStringError("Not implemented.");
+  }
+
 protected:
   SymbolFile *m_sym_file = nullptr;
   /// Used for reporting statistics.
diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp
index 90997dada3666..edd79aff5d065 100644
--- a/lldb/source/Core/Module.cpp
+++ b/lldb/source/Core/Module.cpp
@@ -121,6 +121,15 @@ size_t Module::GetNumberAllocatedModules() {
   return GetModuleCollection().size();
 }
 
+Module *Module::GetAllocatedModuleWithUID(lldb::user_id_t uid) {
+  std::lock_guard<std::recursive_mutex> guard(
+      GetAllocationModuleCollectionMutex());
+  for (Module *mod : GetModuleCollection())
+    if (mod->GetID() == uid)
+      return mod;
+  return nullptr;
+}
+
 Module *Module::GetAllocatedModuleAtIndex(size_t idx) {
   std::lock_guard<std::recursive_mutex> guard(
       GetAllocationModuleCollectionMutex());
@@ -130,8 +139,11 @@ Module *Module::GetAllocatedModuleAtIndex(size_t idx) {
   return nullptr;
 }
 
+// TODO: needs a mutex
+static lldb::user_id_t g_unique_id = 1;
+
 Module::Module(const ModuleSpec &module_spec)
-    : m_unwind_table(*this), m_file_has_changed(false),
+    : UserID(g_unique_id++), m_unwind_table(*this), m_file_has_changed(false),
       m_first_file_changed_log(false) {
   // Scope for locker below...
   {
@@ -236,7 +248,8 @@ Module::Module(const ModuleSpec &module_spec)
 Module::Module(const FileSpec &file_spec, const ArchSpec &arch,
                ConstString object_name, lldb::offset_t object_offset,
                const llvm::sys::TimePoint<> &object_mod_time)
-    : m_mod_time(FileSystem::Instance().GetModificationTime(file_spec)),
+    : UserID(g_unique_id++),
+      m_mod_time(FileSystem::Instance().GetModificationTime(file_spec)),
       m_arch(arch), m_file(file_spec), m_object_name(object_name),
       m_object_offset(object_offset), m_object_mod_time(object_mod_time),
       m_unwind_table(*this), m_file_has_changed(false),
@@ -257,7 +270,7 @@ Module::Module(const FileSpec &file_spec, const ArchSpec &arch,
 }
 
 Module::Module()
-    : m_unwind_table(*this), m_file_has_changed(false),
+    : UserID(g_unique_id++), m_unwind_table(*this), m_file_has_changed(false),
       m_first_file_changed_log(false) {
   std::lock_guard<std::recursive_mutex> guard(
       GetAllocationModuleCollectionMutex());
diff --git a/lldb/source/Expression/Expression.cpp b/lldb/source/Expression/Expression.cpp
index 93f585edfce3d..e19c804caa3c6 100644
--- a/lldb/source/Expression/Expression.cpp
+++ b/lldb/source/Expression/Expression.cpp
@@ -10,6 +10,10 @@
 #include "lldb/Target/ExecutionContextScope.h"
 #include "lldb/Target/Target.h"
 
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+
 using namespace lldb_private;
 
 Expression::Expression(Target &target)
@@ -26,3 +30,15 @@ Expression::Expression(ExecutionContextScope &exe_scope)
       m_jit_end_addr(LLDB_INVALID_ADDRESS) {
   assert(m_target_wp.lock());
 }
+
+bool lldb_private::consumeFunctionCallLabelPrefix(llvm::StringRef &name) {
+  // On Darwin mangled names get a '_' prefix.
+  name.consume_front("_");
+  return name.consume_front(FunctionCallLabelPrefix);
+}
+
+bool lldb_private::hasFunctionCallLabelPrefix(llvm::StringRef name) {
+  // On Darwin mangled names get a '_' prefix.
+  name.consume_front("_");
+  return name.starts_with(FunctionCallLabelPrefix);
+}
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp
index 6f812b91a8b1d..a9ea244889cce 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -13,6 +13,7 @@
 #include "llvm/IR/DiagnosticInfo.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Module.h"
+#include "llvm/Support/Error.h"
 #include "llvm/Support/SourceMgr.h"
 #include "llvm/Support/raw_ostream.h"
 
@@ -20,6 +21,7 @@
 #include "lldb/Core/Disassembler.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Core/Section.h"
+#include "lldb/Expression/Expression.h"
 #include "lldb/Expression/IRExecutionUnit.h"
 #include "lldb/Expression/ObjectFileJIT.h"
 #include "lldb/Host/HostInfo.h"
@@ -36,6 +38,7 @@
 #include "lldb/Utility/LLDBAssert.h"
 #include "lldb/Utility/LLDBLog.h"
 #include "lldb/Utility/Log.h"
+#include "lldb/lldb-defines.h"
 
 #include <optional>
 
@@ -771,6 +774,63 @@ class LoadAddressResolver {
   lldb::addr_t m_best_internal_load_address = LLDB_INVALID_ADDRESS;
 };
 
+/// Returns address of the function referred to by the special function call
+/// label \c label.
+///
+/// \param[in] label Function call label encoding the unique location of the
+/// function to look up.
+///                  Assumes that the \c FunctionCallLabelPrefix has been
+///                  stripped from the front of the label.
+static llvm::Expected<lldb::addr_t>
+ResolveFunctionCallLabel(llvm::StringRef name,
+                         const lldb_private::SymbolContext &sc,
+                         bool &symbol_was_missing_weak) {
+  symbol_was_missing_weak = false;
+
+  if (!sc.target_sp)
+    return llvm::createStringError("target not available.");
+
+  auto ts_or_err = sc.target_sp->GetScratchTypeSystemForLanguage(
+      lldb::eLanguageTypeC_plus_plus);
+  if (!ts_or_err || !*ts_or_err)
+    return llvm::joinErrors(
+        llvm::createStringError(
+            "failed to find scratch C++ TypeSystem for current target."),
+        ts_or_err.takeError());
+
+  auto ts_sp = *ts_or_err;
+
+  auto label_or_err = ts_sp->makeFunctionCallLabel(name);
+  if (!label_or_err)
+    return llvm::joinErrors(
+        llvm::createStringError("failed to create FunctionCallLabel from: %s",
+                                name.data()),
+        label_or_err.takeError());
+
+  const auto &label = *label_or_err;
+
+  Module *module = Module::GetAllocatedModuleWithUID(label.m_module_id);
+
+  if (!module)
+    return llvm::createStringError(
+        llvm::formatv("failed to find module by UID {0}", label.m_module_id));
+
+  auto *symbol_file = module->GetSymbolFile();
+  if (!symbol_file)
+    return llvm::createStringError(
+        llvm::formatv("no SymbolFile found on module {0:x}.", module));
+
+  SymbolContextList sc_list;
+  if (auto err =
+          symbol_file->FindAndResolveFunction(sc_list, label.m_lookup_name))
+    return llvm::joinErrors(
+        llvm::createStringError("failed to resolve function by UID"),
+        std::move(err));
+
+  LoadAddressResolver resolver(*sc.target_sp, symbol_was_missing_weak);
+  return resolver.Resolve(sc_list).value_or(LLDB_INVALID_ADDRESS);
+}
+
 lldb::addr_t
 IRExecutionUnit::FindInSymbols(const std::vector<ConstString> &names,
                                const lldb_private::SymbolContext &sc,
@@ -906,6 +966,20 @@ lldb::addr_t IRExecutionUnit::FindInUserDefinedSymbols(
 
 lldb::addr_t IRExecutionUnit::FindSymbol(lldb_private::ConstString name,
                                          bool &missing_weak) {
+  if (hasFunctionCallLabelPrefix(name.GetStringRef())) {
+    if (auto addr_or_err = ResolveFunctionCallLabel(name.GetStringRef(),
+                                                    m_sym_ctx, missing_weak)) {
+      return *addr_or_err;
+    } else {
+      LLDB_LOG_ERROR(GetLog(LLDBLog::Expressions), addr_or_err.takeError(),
+                     "Failed to resolve function call label {1}: {0}",
+                     name.GetStringRef());
+      return LLDB_INVALID_ADDRESS;
+    }
+  }
+
+  // TODO: do we still need the following lookups?
+
   std::vector<ConstString> candidate_C_names;
   std::vector<ConstString> candidate_CPlusPlus_names;
 
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index e58e28a260ab0..6bf3b91c900c9 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -24,6 +24,7 @@
 #include "Plugins/Language/ObjC/ObjCLanguage.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Core/Value.h"
+#include "lldb/Expression/Expression.h"
 #include "lldb/Host/Host.h"
 #include "lldb/Symbol/CompileUnit.h"
 #include "lldb/Symbol/Function.h"
@@ -249,12 +250,26 @@ static unsigned GetCXXMethodCVQuals(const DWARFDIE &subprogram,
   return cv_quals;
 }
 
-static std::string MakeLLDBFuncAsmLabel(const DWARFDIE &die) {
+static std::optional<std::string> MakeLLDBFuncAsmLabel(const DWARFDIE &die) {
   char const *name = die.GetMangledName(/*substitute_name_allowed*/ false);
   if (!name)
-    return {};
+    return std::nullopt;
 
-  return name;
+  auto module_sp = die.GetModule();
+  if (!module_sp)
+    return std::nullopt;
+
+  lldb::user_id_t module_id = module_sp->GetID();
+  if (module_id == LLDB_INVALID_UID)
+    return std::nullopt;
+
+  const auto die_id = die.GetID();
+  if (die_id == LLDB_INVALID_UID)
+    return std::nullopt;
+
+  return llvm::formatv("{0}:{1}:{2:x}:{3:x}", FunctionCallLabelPrefix, name,
+                       module_id, die_id)
+      .str();
 }
 
 TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc,
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 41ab8d1b75b34..552a675c833c7 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -2475,6 +2475,47 @@ bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die,
   return false;
 }
 
+llvm::Error
+SymbolFileDWARF::FindAndResolveFunction(SymbolContextList &sc_list,
+                                        llvm::StringRef lookup_name) {
+  std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+
+  DWARFDIE die;
+  Module::LookupInfo info(ConstString(lookup_name), lldb::eFunctionNameTypeFull,
+                          lldb::eLanguageTypeUnknown);
+
+  m_index->GetFunctions(info, *this, {}, [&](DWARFDIE entry) {
+    if (entry.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0))
+      return true;
+
+    // We don't check whether the specification DIE for this function
+    // corresponds to the declaration DIE because the declaration might be in
+    // a type-unit but the definition in the compile-unit (and it's
+    // specifcation would point to the declaration in the compile-unit). We
+    // rely on the mangled name within the module to be enough to find us the
+    // unique definition.
+    die = entry;
+    return false;
+  });
+
+  if (!die.IsValid())
+    return llvm::createStringError(
+        llvm::formatv("failed to find definition DIE for '{0}'", lookup_name));
+
+  if (!ResolveFunction(die, false, sc_list))
+    return llvm::createStringError("failed to resolve function DIE");
+
+  if (sc_list.IsEmpty())
+    return llvm::createStringError("no definition DIE found");
+
+  if (sc_list.GetSize() > 1)
+    return llvm::createStringError(
+        "found %d functions for %s but expected only 1", sc_list.GetSize(),
+        lookup_name.data());
+
+  return llvm::Error::success();
+}
+
 bool SymbolFileDWARF::DIEInDeclContext(const CompilerDeclContext &decl_ctx,
                                        const DWARFDIE &die,
                                        bool only_root_namespaces) {
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index 56d8ccbd97e46..94463fa2dc2e3 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -436,6 +436,9 @@ class SymbolFileDWARF : public SymbolFileCommon {
   DIEArray MergeBlockAbstractParameters(const DWARFDIE &block_die,
                                         DIEArray &&variable_dies);
 
+  llvm::Error FindAndResolveFunction(SymbolContextList &sc_list,
+                                     llvm::StringRef lookup_name) override;
+
   // Given a die_offset, figure out the symbol context representing that die.
   bool ResolveFunction(const DWARFDIE &die, bool include_inlines,
                        SymbolContextList &sc_list);
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 836f9feebb27a..3d33c9728b8af 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -60,6 +60,7 @@
 #include "lldb/Core/Module.h"
 #include "lldb/Core/PluginManager.h"
 #include "lldb/Core/UniqueCStringMap.h"
+#include "lldb/Expression/Expression.h"
 #include "lldb/Host/StreamFile.h"
 #include "lldb/Symbol/ObjectFile.h"
 #include "lldb/Symbol/SymbolFile.h"
@@ -9055,6 +9056,13 @@ ConstString TypeSystemClang::DeclGetMangledName(void *opaque_decl) {
   if (!mc || !mc->shouldMangleCXXName(nd))
     return {};
 
+  if (const auto *label = nd->getAttr<AsmLabelAttr>()) {
+    if (auto components_or_err = splitFunctionCallLabel(label->getLabel()))
+      return ConstString((*components_or_err)[0]);
+    else
+      llvm::consumeError(components_or_err.takeError());
+  }
+
   llvm::SmallVector<char, 1024> buf;
   llvm::raw_svector_ostream llvm_ostrm(buf);
   if (llvm::isa<clang::CXXConstructorDecl>(nd)) {
@@ -9777,3 +9785,51 @@ void TypeSystemClang::LogCreation() const {
     LLDB_LOG(log, "Created new TypeSystem for (ASTContext*){0:x} '{1}'",
              &getASTContext(), getDisplayName());
 }
+
+// Expected format is:
+// $__lldb_func:<mangled name>:<module id>:<definition/declaration DIE id>
+llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>>
+TypeSystemClang::splitFunctionCallLabel(llvm::StringRef label) const {
+  if (!consumeFunctionCallLabelPrefix(label))
+    return llvm::createStringError(
+        "expected function call label prefix not found in %s", label.data());
+  if (!label.consume_front(":"))
+    return llvm::createStringError(
+        "incorrect format: expected ':' as the first character.");
+
+  llvm::SmallVector<llvm::StringRef, 3> components;
+  label.split(components, ":");
+
+  if (components.size() != 3)
+    return llvm::createStringError(
+        "incorrect format: too many label subcomponents.");
+
+  return components;
+}
+
+llvm::Expected<FunctionCallLabel>
+TypeSystemClang::makeFunctionCallLabel(llvm::StringRef label) const {
+  auto components_or_err = splitFunctionCallLabel(label);
+  if (!components_or_err)
+    return llvm::joinErrors(
+        llvm::createStringError("Failed to decode function call label"),
+        components_or_err.takeError());
+
+  const auto &components = *components_or_err;
+
+  llvm::StringRef module_label = components[1];
+  llvm::StringRef die_label = components[2];
+
+  lldb::user_id_t module_id = 0;
+  if (module_label.consumeInteger(0, module_id))
+    return llvm::createStringError(
+        llvm::formatv("failed to parse module ID from '{0}'.", components[1]));
+
+  lldb::user_id_t die_id;
+  if (die_label.consumeInteger(/*Radix=*/0, die_id))
+    return llvm::createStringError(
+        llvm::formatv("failed to parse DIE ID from '{0}'.", components[2]));
+
+  return FunctionCallLabel{/*.m_lookup_name =*/components[0],
+                           /*.m_module_id =*/module_id, /*.m_die_id =*/die_id};
+}
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index de66bb68c6a4c..4e92a452af815 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -1098,6 +1098,12 @@ class TypeSystemClang : public TypeSystem {
       lldb::opaque_compiler_type_t type, Stream &s,
       lldb::DescriptionLevel level = lldb::eDescriptionLevelFull) override;
 
+  llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>>
+  splitFunctionCallLabel(llvm::StringRef label) const override;
+
+  llvm::Expected<FunctionCallLabel>
+  makeFunctionCallLabel(llvm::StringRef label) const override;
+
   static void DumpTypeName(const CompilerType &type);
 
   static clang::EnumDecl *GetAsEnumDecl(const CompilerType &type);
diff --git a/lldb/unittests/Symbol/TestTypeSystemClang.cpp b/lldb/unittests/Symbol/TestTypeSystemClang.cpp
index 57857676c7df9..228ee2ed9b6ea 100644
--- a/lldb/unittests/Symbol/TestTypeSystemClang.cpp
+++ b/lldb/unittests/Symbol/TestTypeSystemClang.cpp
@@ -869,7 +869,11 @@ TEST_F(TestTypeSystemClang, TestFunctionTemplateConstruction) {
   CompilerType clang_type = m_ast->CreateFunctionType(int_type, {}, false, 0U);
   FunctionDecl *func = m_ast->CreateFunctionDeclaration(
       TU, OptionalClangModuleID(), "foo", clang_type, StorageClass::SC_None,
+<<<<<<< HEAD
       false, /*asm_label=*/{});
+=======
+      false, std::nullopt);
+>>>>>>> 382395408c4b ([lldb][Expression] Encode Module and DIE UIDs into function AsmLabels)
   TypeSystemClang::TemplateParameterInfos empty_params;
 
   // Create the actual function template.
@@ -900,7 +904,11 @@ TEST_F(TestTypeSystemClang, TestFunctionTemplateInRecordConstruction) {
   // 2. It is mirroring the behavior of DWARFASTParserClang::ParseSubroutine.
   FunctionDecl *func = m_ast->CreateFunctionDeclaration(
       TU, OptionalClangModuleID(), "foo", clang_type, StorageClass::SC_None,
+<<<<<<< HEAD
       false, /*asm_label=*/{});
+=======
+      false, std::nullopt);
+>>>>>>> 382395408c4b ([lldb][Expression] Encode Module and DIE UIDs into function AsmLabels)
   TypeSystemClang::TemplateParameterInfos empty_params;
 
   // Create the actual function template.
@@ -938,7 +946,11 @@ TEST_F(TestTypeSystemClang, TestDeletingImplicitCopyCstrDueToMoveCStr) {
   bool is_attr_used = false;
   bool is_artificial = false;
   m_ast->AddMethodToCXXRecordType(
+<<<<<<< HEAD
       t.GetOpaqueQualType(), class_name, /*asm_label=*/{}, function_type,
+=======
+      t.GetOpaqueQualType(), class_name, std::nullopt, function_type,
+>>>>>>> 382395408c4b ([lldb][Expression] Encode Module and DIE UIDs into function AsmLabels)
       lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline,
       is_explicit, is_attr_used, is_artificial);
 
@@ -975,7 +987,11 @@ TEST_F(TestTypeSystemClang, TestNotDeletingUserCopyCstrDueToMoveCStr) {
     CompilerType function_type = m_ast->CreateFunctionType(
         return_type, args, /*variadic=*/false, /*quals*/ 0U);
     m_ast->AddMethodToCXXRecordType(
+<<<<<<< HEAD
         t.GetOpaqueQualType(), class_name, /*asm_label=*/{}, function_type,
+=======
+        t.GetOpaqueQualType(), class_name, std::nullopt, function_type,
+>>>>>>> 382395408c4b ([lldb][Expression] Encode Module and DIE UIDs into function AsmLabels)
         lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline,
         is_explicit, is_attr_used, is_artificial);
   }
@@ -987,7 +1003,11 @@ TEST_F(TestTypeSystemClang, TestNotDeletingUserCopyCstrDueToMoveCStr) {
         m_ast->CreateFunctionType(return_type, args,
                                   /*variadic=*/false, /*quals*/ 0U);
     m_ast->AddMethodToCXXRecordType(
+<<<<<<< HEAD
         t.GetOpaqueQualType(), class_name, /*asm_label=*/{}, function_type,
+=======
+        t.GetOpaqueQualType(), class_name, std::nullopt, function_type,
+>>>>>>> 382395408c4b ([lldb][Expression] Encode Module and DIE UIDs into function AsmLabels)
         lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline,
         is_explicit, is_attr_used, is_artificial);
   }
@@ -1098,7 +1118,11 @@ TEST_F(TestTypeSystemClang, AddMethodToCXXRecordType_ParmVarDecls) {
       m_ast->CreateFunctionType(return_type, param_types,
                                 /*variadic=*/false, /*quals*/ 0U);
   m_ast->AddMethodToCXXRecordType(
+<<<<<<< HEAD
       t.GetOpaqueQualType(), "myFunc", /*asm_label=*/{}, function_type,
+=======
+      t.GetOpaqueQualType(), "myFunc", std::nullopt, function_type,
+>>>>>>> 382395408c4b ([lldb][Expression] Encode Module and DIE UIDs into function AsmLabels)
       lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline,
       is_explicit, is_attr_used, is_artificial);
 

>From 818cf2287f8f7ef79af92de8d955ed1397e7ca74 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Mon, 21 Jul 2025 12:15:24 +0100
Subject: [PATCH 02/36] fixup! add quotes

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

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

>From 53a43aaf5b83b9416af2f2a6bb5960e2e499b4f9 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Mon, 28 Jul 2025 11:43:17 +0100
Subject: [PATCH 03/36] fixup! create literal AsmLabels

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

diff --git a/lldb/include/lldb/Expression/Expression.h b/lldb/include/lldb/Expression/Expression.h
index f32878c9bf876..9044d26cf6670 100644
--- a/lldb/include/lldb/Expression/Expression.h
+++ b/lldb/include/lldb/Expression/Expression.h
@@ -118,9 +118,6 @@ struct FunctionCallLabel {
 /// from JITted expressions.
 inline constexpr llvm::StringRef FunctionCallLabelPrefix = "$__lldb_func";
 
-bool consumeFunctionCallLabelPrefix(llvm::StringRef &name);
-bool hasFunctionCallLabelPrefix(llvm::StringRef name);
-
 } // namespace lldb_private
 
 #endif // LLDB_EXPRESSION_EXPRESSION_H
diff --git a/lldb/source/Expression/Expression.cpp b/lldb/source/Expression/Expression.cpp
index e19c804caa3c6..f85a3284d7eda 100644
--- a/lldb/source/Expression/Expression.cpp
+++ b/lldb/source/Expression/Expression.cpp
@@ -30,15 +30,3 @@ Expression::Expression(ExecutionContextScope &exe_scope)
       m_jit_end_addr(LLDB_INVALID_ADDRESS) {
   assert(m_target_wp.lock());
 }
-
-bool lldb_private::consumeFunctionCallLabelPrefix(llvm::StringRef &name) {
-  // On Darwin mangled names get a '_' prefix.
-  name.consume_front("_");
-  return name.consume_front(FunctionCallLabelPrefix);
-}
-
-bool lldb_private::hasFunctionCallLabelPrefix(llvm::StringRef name) {
-  // On Darwin mangled names get a '_' prefix.
-  name.consume_front("_");
-  return name.starts_with(FunctionCallLabelPrefix);
-}
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp
index 40635d0829168..9a545c40eacd0 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -966,7 +966,7 @@ lldb::addr_t IRExecutionUnit::FindInUserDefinedSymbols(
 
 lldb::addr_t IRExecutionUnit::FindSymbol(lldb_private::ConstString name,
                                          bool &missing_weak) {
-  if (hasFunctionCallLabelPrefix(name.GetStringRef())) {
+  if (name.GetStringRef().starts_with(FunctionCallLabelPrefix)) {
     if (auto addr_or_err = ResolveFunctionCallLabel(name.GetStringRef(),
                                                     m_sym_ctx, missing_weak)) {
       return *addr_or_err;
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 3d33c9728b8af..94beb4af97335 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -9790,7 +9790,7 @@ void TypeSystemClang::LogCreation() const {
 // $__lldb_func:<mangled name>:<module id>:<definition/declaration DIE id>
 llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>>
 TypeSystemClang::splitFunctionCallLabel(llvm::StringRef label) const {
-  if (!consumeFunctionCallLabelPrefix(label))
+  if (!label.consume_front(FunctionCallLabelPrefix))
     return llvm::createStringError(
         "expected function call label prefix not found in %s", label.data());
   if (!label.consume_front(":"))

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

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

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

>From 6741c7b4d27ce82f589b828916e033943515093f Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Mon, 28 Jul 2025 12:16:22 +0100
Subject: [PATCH 05/36] fixup! rename FunctionCallLabel members

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

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

>From 96cbb48bfe43b22e0002d99243666fb77b265750 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Mon, 28 Jul 2025 12:29:44 +0100
Subject: [PATCH 06/36] fixup! remove unused headers

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

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

>From 65f8706b5a9d68f1f33508340c4204c86bd45391 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Mon, 28 Jul 2025 12:41:58 +0100
Subject: [PATCH 07/36] fixup! move FunctionCallLabel APIs into Expression
 component

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

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

>From 3e27e98e94abeaa3bab948a899f688f15efbee27 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Mon, 28 Jul 2025 12:54:20 +0100
Subject: [PATCH 08/36] fixup! adjust TypeSystemClang::DeclGetMangledName

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

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

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

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

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

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

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

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

>From 73768e663f0cc09a08199f2ded1fcf4a79dc5209 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Mon, 28 Jul 2025 15:44:13 +0100
Subject: [PATCH 11/36] fixup! rebase on latest ModuleList changes

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

>From 0ce95bd4c1c59b48fe11d3b3b62d71e9f6809897 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 10:15:14 +0100
Subject: [PATCH 18/36] fixup! revert whitespace change

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

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

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

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

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

>From 6973ac27c406070a516b7788b8b59ac7465e6490 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 11:50:23 +0100
Subject: [PATCH 20/36] fixup! implement
 SymbolFileDWARFDebugMap::ResolveFunctionCallLabel

---
 lldb/include/lldb/Core/ModuleList.h           |  8 +++++++
 lldb/source/Core/ModuleList.cpp               | 14 +++++++++++
 lldb/source/Expression/IRExecutionUnit.cpp    |  2 +-
 .../SymbolFile/DWARF/DWARFASTParserClang.cpp  | 24 +++++++++++++------
 .../DWARF/SymbolFileDWARFDebugMap.cpp         | 11 +++++++++
 .../DWARF/SymbolFileDWARFDebugMap.h           |  3 +++
 6 files changed, 54 insertions(+), 8 deletions(-)

diff --git a/lldb/include/lldb/Core/ModuleList.h b/lldb/include/lldb/Core/ModuleList.h
index d5e291f3380a8..6ecdcf10fa85f 100644
--- a/lldb/include/lldb/Core/ModuleList.h
+++ b/lldb/include/lldb/Core/ModuleList.h
@@ -352,6 +352,14 @@ class ModuleList {
   // UUID values is very efficient and accurate.
   lldb::ModuleSP FindModule(const UUID &uuid) const;
 
+  /// Find a module by LLDB-specific unique identifier.
+  ///
+  /// \param[in] uid The UID of the module assigned to it on construction.
+  ///
+  /// \returns ModuleSP of module with \c uid. Returns nullptr if no such
+  /// module could be found.
+  lldb::ModuleSP FindModule(lldb::user_id_t uid) const;
+
   /// Finds the first module whose file specification matches \a module_spec.
   lldb::ModuleSP FindFirstModule(const ModuleSpec &module_spec) const;
 
diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp
index d2e5be8c79b17..01f46b62b57bd 100644
--- a/lldb/source/Core/ModuleList.cpp
+++ b/lldb/source/Core/ModuleList.cpp
@@ -584,6 +584,20 @@ ModuleSP ModuleList::FindModule(const UUID &uuid) const {
   return module_sp;
 }
 
+ModuleSP ModuleList::FindModule(lldb::user_id_t uid) const {
+  ModuleSP module_sp;
+  ForEach([&](const ModuleSP &m) {
+    if (m->GetID() == uid) {
+      module_sp = m;
+      return IterationAction::Stop;
+    }
+
+    return IterationAction::Continue;
+  });
+
+  return module_sp;
+}
+
 void ModuleList::FindTypes(Module *search_first, const TypeQuery &query,
                            TypeResults &results) const {
   std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp
index 448a3cb649c0d..90d087553b35b 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -827,7 +827,7 @@ ResolveFunctionCallLabel(llvm::StringRef name,
 
   const auto &label = *label_or_err;
 
-  auto module_sp = FindDebugModule(label.module_id, sc.target_sp->GetImages());
+  auto module_sp = sc.target_sp->GetImages().FindModule(label.module_id);
   if (!module_sp)
     return llvm::createStringError(
         llvm::formatv("failed to find module by UID {0}", label.module_id));
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index e76b599fd5f9c..f1a8433842bab 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -259,15 +259,25 @@ static std::optional<std::string> MakeLLDBFuncAsmLabel(const DWARFDIE &die) {
   if (!dwarf)
     return std::nullopt;
 
-  ObjectFile *main_obj = dwarf->GetMainObjectFile();
-  if (!main_obj)
-    return std::nullopt;
+  auto get_module_id = [&](SymbolFile *sym) {
+    if (!sym)
+      return LLDB_INVALID_UID;
 
-  auto module_sp = main_obj->GetModule();
-  if (!module_sp)
-    return std::nullopt;
+    auto *obj = sym->GetMainObjectFile();
+    if (!obj)
+      return LLDB_INVALID_UID;
+
+    auto module_sp = obj->GetModule();
+    if (!module_sp)
+      return LLDB_INVALID_UID;
+
+    return module_sp->GetID();
+  };
+
+  lldb::user_id_t module_id = get_module_id(dwarf->GetDebugMapSymfile());
+  if (module_id == LLDB_INVALID_UID)
+    module_id = get_module_id(dwarf);
 
-  lldb::user_id_t module_id = module_sp->GetID();
   if (module_id == LLDB_INVALID_UID)
     return std::nullopt;
 
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
index dd94f0b36f2b2..b532e4d8c83e1 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
@@ -1602,3 +1602,14 @@ void SymbolFileDWARFDebugMap::GetCompileOptions(
     return IterationAction::Continue;
   });
 }
+
+llvm::Error SymbolFileDWARFDebugMap::ResolveFunctionCallLabel(
+    SymbolContextList &sc_list, const FunctionCallLabel &label) {
+  const uint64_t oso_idx = GetOSOIndexFromUserID(label.symbol_id);
+  SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex(oso_idx);
+  if (!oso_dwarf)
+    return llvm::createStringError(llvm::formatv(
+        "couldn't find symbol file for {0} in debug-map.", label));
+
+  return oso_dwarf->ResolveFunctionCallLabel(sc_list, label);
+}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
index f074b17082e62..31a2889cf3ff6 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
@@ -144,6 +144,9 @@ class SymbolFileDWARFDebugMap : public SymbolFileCommon {
   void
   GetCompileOptions(std::unordered_map<lldb::CompUnitSP, Args> &args) override;
 
+  llvm::Error ResolveFunctionCallLabel(SymbolContextList &sc_list,
+                                       const FunctionCallLabel &label) override;
+
 protected:
   enum { kHaveInitializedOSOs = (1 << 0), kNumFlags };
 

>From e43310a51b8ac37cf0cb2bd8c92c25ae16a8a305 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 12:38:48 +0100
Subject: [PATCH 21/36] fixup! add test for when definition is in different
 Module than declaration

---
 .../cpp/expr-definition-in-dylib/Makefile     |  6 ++++++
 .../TestExprDefinitionInDylib.py              | 19 +++++++++++++++++++
 .../lang/cpp/expr-definition-in-dylib/lib.cpp |  5 +++++
 .../lang/cpp/expr-definition-in-dylib/lib.h   |  8 ++++++++
 .../cpp/expr-definition-in-dylib/main.cpp     |  6 ++++++
 5 files changed, 44 insertions(+)
 create mode 100644 lldb/test/API/lang/cpp/expr-definition-in-dylib/Makefile
 create mode 100644 lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py
 create mode 100644 lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.cpp
 create mode 100644 lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.h
 create mode 100644 lldb/test/API/lang/cpp/expr-definition-in-dylib/main.cpp

diff --git a/lldb/test/API/lang/cpp/expr-definition-in-dylib/Makefile b/lldb/test/API/lang/cpp/expr-definition-in-dylib/Makefile
new file mode 100644
index 0000000000000..82daeb1dd3f90
--- /dev/null
+++ b/lldb/test/API/lang/cpp/expr-definition-in-dylib/Makefile
@@ -0,0 +1,6 @@
+CXX_SOURCES := main.cpp
+
+DYLIB_CXX_SOURCES := lib.cpp
+DYLIB_NAME := lib
+
+include Makefile.rules
diff --git a/lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py b/lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py
new file mode 100644
index 0000000000000..3a89eb01b3932
--- /dev/null
+++ b/lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py
@@ -0,0 +1,19 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class ExprDefinitionInDylibTestCase(TestBase):
+    def test(self):
+        """
+        Tests that we can call functions whose definition
+        is in a different LLDB module than it's declaration.
+        """
+        self.build()
+
+        lldbutil.run_to_source_breakpoint(
+            self, "return", lldb.SBFileSpec("main.cpp")
+        )
+
+        self.expect_expr("f.method()", result_value="-72", result_type="int")
diff --git a/lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.cpp b/lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.cpp
new file mode 100644
index 0000000000000..c4336d7b69be4
--- /dev/null
+++ b/lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.cpp
@@ -0,0 +1,5 @@
+#include "lib.h"
+
+int Foo::method() {
+  return -72;
+}
diff --git a/lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.h b/lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.h
new file mode 100644
index 0000000000000..9568db2166ec4
--- /dev/null
+++ b/lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.h
@@ -0,0 +1,8 @@
+#ifndef LIB_H_IN
+#define LIB_H_IN
+
+struct Foo {
+  int method();
+};
+
+#endif // LIB_H_IN
diff --git a/lldb/test/API/lang/cpp/expr-definition-in-dylib/main.cpp b/lldb/test/API/lang/cpp/expr-definition-in-dylib/main.cpp
new file mode 100644
index 0000000000000..2fddb2b7b3e74
--- /dev/null
+++ b/lldb/test/API/lang/cpp/expr-definition-in-dylib/main.cpp
@@ -0,0 +1,6 @@
+#include "lib.h"
+
+int main() {
+  Foo f;
+  return f.method();
+}

>From e8146d7457ddd599f1326cafe33883a2c3bbc37b Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 12:39:07 +0100
Subject: [PATCH 22/36] fixup! clang-format

---
 lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.cpp | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.cpp b/lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.cpp
index c4336d7b69be4..ad148cebb00d1 100644
--- a/lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.cpp
+++ b/lldb/test/API/lang/cpp/expr-definition-in-dylib/lib.cpp
@@ -1,5 +1,3 @@
 #include "lib.h"
 
-int Foo::method() {
-  return -72;
-}
+int Foo::method() { return -72; }

>From e4129ce205d6d397e461ee2c400c3649dbaaa6b7 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 12:51:45 +0100
Subject: [PATCH 23/36] fixup! python format

---
 .../cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py b/lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py
index 3a89eb01b3932..13480001dd82f 100644
--- a/lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py
+++ b/lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py
@@ -12,8 +12,6 @@ def test(self):
         """
         self.build()
 
-        lldbutil.run_to_source_breakpoint(
-            self, "return", lldb.SBFileSpec("main.cpp")
-        )
+        lldbutil.run_to_source_breakpoint(self, "return", lldb.SBFileSpec("main.cpp"))
 
         self.expect_expr("f.method()", result_value="-72", result_type="int")

>From 36b39a4483eb279367d50598547b1060472d0be4 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 12:54:00 +0100
Subject: [PATCH 24/36] fixup! clang-format

---
 .../Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp      | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index f1a8433842bab..4b386ac2093a7 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -285,11 +285,9 @@ static std::optional<std::string> MakeLLDBFuncAsmLabel(const DWARFDIE &die) {
   if (die_id == LLDB_INVALID_UID)
     return std::nullopt;
 
-  return FunctionCallLabel{
-      /*module_id=*/module_id,
-      /*symbol_id=*/die_id,
-      /*.lookup_name=*/name
-  }
+  return FunctionCallLabel{/*module_id=*/module_id,
+                           /*symbol_id=*/die_id,
+                           /*.lookup_name=*/name}
       .toString();
 }
 

>From e882765006208691a0c8f233718ab5d1ae71b73e Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 13:09:41 +0100
Subject: [PATCH 25/36] fixup! mark test NO_DEBUG_INFO_TESTCASE

---
 .../cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py   | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py b/lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py
index 13480001dd82f..84559155f3c4b 100644
--- a/lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py
+++ b/lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py
@@ -5,6 +5,8 @@
 
 
 class ExprDefinitionInDylibTestCase(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+
     def test(self):
         """
         Tests that we can call functions whose definition

>From a8a98902ded0dbf0632855f0bf24d2ff70fb4fda Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 13:10:11 +0100
Subject: [PATCH 26/36] fixup! fallback to name lookup if definition is in
 separate module from declaration

---
 lldb/source/Expression/IRExecutionUnit.cpp | 35 +++++++++++-----------
 1 file changed, 17 insertions(+), 18 deletions(-)

diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp
index 90d087553b35b..cea5ca90d7315 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -806,11 +806,8 @@ static lldb::ModuleSP FindDebugModule(lldb::user_id_t uid,
 
 /// Returns address of the function referred to by the special function call
 /// label \c label.
-///
-/// \param[in] label Function call label encoding the unique location of the
-/// function to look up.
 static llvm::Expected<lldb::addr_t>
-ResolveFunctionCallLabel(llvm::StringRef name,
+ResolveFunctionCallLabel(const FunctionCallLabel &label,
                          const lldb_private::SymbolContext &sc,
                          bool &symbol_was_missing_weak) {
   symbol_was_missing_weak = false;
@@ -818,15 +815,6 @@ ResolveFunctionCallLabel(llvm::StringRef name,
   if (!sc.target_sp)
     return llvm::createStringError("target not available.");
 
-  auto label_or_err = FunctionCallLabel::fromString(name);
-  if (!label_or_err)
-    return llvm::joinErrors(
-        llvm::createStringError("failed to create FunctionCallLabel from: %s",
-                                name.data()),
-        label_or_err.takeError());
-
-  const auto &label = *label_or_err;
-
   auto module_sp = sc.target_sp->GetImages().FindModule(label.module_id);
   if (!module_sp)
     return llvm::createStringError(
@@ -983,19 +971,30 @@ lldb::addr_t IRExecutionUnit::FindInUserDefinedSymbols(
 lldb::addr_t IRExecutionUnit::FindSymbol(lldb_private::ConstString name,
                                          bool &missing_weak) {
   if (name.GetStringRef().starts_with(FunctionCallLabelPrefix)) {
-    if (auto addr_or_err = ResolveFunctionCallLabel(name.GetStringRef(),
-                                                    m_sym_ctx, missing_weak)) {
+    auto label_or_err = FunctionCallLabel::fromString(name);
+    if (!label_or_err) {
+      LLDB_LOG_ERROR(GetLog(LLDBLog::Expressions), label_or_err.takeError(),
+                     "failed to create FunctionCallLabel from '{0}': {1}",
+                     name.GetStringRef());
+      return LLDB_INVALID_ADDRESS;
+    }
+
+    if (auto addr_or_err =
+            ResolveFunctionCallLabel(*label_or_err, m_sym_ctx, missing_weak)) {
       return *addr_or_err;
     } else {
       LLDB_LOG_ERROR(GetLog(LLDBLog::Expressions), addr_or_err.takeError(),
                      "Failed to resolve function call label '{1}': {0}",
                      name.GetStringRef());
-      return LLDB_INVALID_ADDRESS;
+
+      // Fall back to lookup by name despite error in resolving the label.
+      // May happen in practice if the definition of a function lives in
+      // a different lldb_private::Module than it's declaration. Meaning
+      // we couldn't pin-point it using the information encoded in the label.
+      name.SetString(label_or_err->lookup_name);
     }
   }
 
-  // TODO: do we still need the following lookups?
-
   std::vector<ConstString> candidate_C_names;
   std::vector<ConstString> candidate_CPlusPlus_names;
 

>From a5b2e26ba6d1af1d6a8c5787d3d05c093ac3cbf3 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 16:17:28 +0100
Subject: [PATCH 27/36] fixup! register dylib in test

Otherwise executable fails to launch on linux
---
 .../TestExprDefinitionInDylib.py                  | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py b/lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py
index 84559155f3c4b..1eddd265eab93 100644
--- a/lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py
+++ b/lldb/test/API/lang/cpp/expr-definition-in-dylib/TestExprDefinitionInDylib.py
@@ -14,6 +14,19 @@ def test(self):
         """
         self.build()
 
-        lldbutil.run_to_source_breakpoint(self, "return", lldb.SBFileSpec("main.cpp"))
+        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
+        self.assertTrue(target, VALID_TARGET)
+
+        env = self.registerSharedLibrariesWithTarget(target, ["lib"])
+
+        breakpoint = lldbutil.run_break_set_by_file_and_line(
+            self, "main.cpp", line_number("main.cpp", "return")
+        )
+
+        process = target.LaunchSimple(None, env, self.get_process_working_directory())
+
+        self.assertIsNotNone(
+            lldbutil.get_one_thread_stopped_at_breakpoint_id(self.process(), breakpoint)
+        )
 
         self.expect_expr("f.method()", result_value="-72", result_type="int")

>From 5aa13329d31fa5e1d16376b588578db188928099 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 15:34:01 +0100
Subject: [PATCH 28/36] fixup! fix typo

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

diff --git a/lldb/include/lldb/Expression/Expression.h b/lldb/include/lldb/Expression/Expression.h
index a6c49bcc10ad0..086aa1406a1c6 100644
--- a/lldb/include/lldb/Expression/Expression.h
+++ b/lldb/include/lldb/Expression/Expression.h
@@ -129,7 +129,7 @@ struct FunctionCallLabel {
   /// Decodes the specified function \c label into a \c FunctionCallLabel.
   static llvm::Expected<FunctionCallLabel> fromString(llvm::StringRef label);
 
-  /// Encode this FunctionCallLabel into it's string representation.
+  /// Encode this FunctionCallLabel into its string representation.
   ///
   /// The representation roundtrips through \c fromString:
   /// \code{.cpp}

>From 98d2c4bd96cb181680ac7be6ff37adc030d45767 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 15:42:03 +0100
Subject: [PATCH 29/36] fixup! SymbolContextList -> SymbolContext

---
 lldb/include/lldb/Symbol/SymbolFile.h               |  9 +++------
 lldb/source/Expression/IRExecutionUnit.cpp          |  9 ++++++---
 .../Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp    | 13 +++++--------
 .../Plugins/SymbolFile/DWARF/SymbolFileDWARF.h      |  4 ++--
 .../SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp    |  6 +++---
 .../SymbolFile/DWARF/SymbolFileDWARFDebugMap.h      |  4 ++--
 6 files changed, 21 insertions(+), 24 deletions(-)

diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h
index 45798f667cb22..bbc615d9fdc38 100644
--- a/lldb/include/lldb/Symbol/SymbolFile.h
+++ b/lldb/include/lldb/Symbol/SymbolFile.h
@@ -332,15 +332,12 @@ class SymbolFile : public PluginInterface {
   /// Resolves the function corresponding to the specified LLDB function
   /// call \c label.
   ///
-  /// \param[in,out] sc_list The resolved functions will be appended to this
-  /// list.
-  ///
   /// \param[in] label The FunctionCallLabel to be resolved.
   ///
   /// \returns An llvm::Error if the specified \c label couldn't be resolved.
-  ///          Returns \c llvm::ErrorSuccess otherwise.
-  virtual llvm::Error ResolveFunctionCallLabel(SymbolContextList &sc_list,
-                                               const FunctionCallLabel &label) {
+  ///          Returns the resolved function (as a SymbolContext) otherwise.
+  virtual llvm::Expected<SymbolContext>
+  ResolveFunctionCallLabel(const FunctionCallLabel &label) {
     return llvm::createStringError("Not implemented");
   }
 
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp
index cea5ca90d7315..870b71eee3c7c 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -825,11 +825,14 @@ ResolveFunctionCallLabel(const FunctionCallLabel &label,
     return llvm::createStringError(
         llvm::formatv("no SymbolFile found on module {0:x}.", module_sp.get()));
 
-  SymbolContextList sc_list;
-  if (auto err = symbol_file->ResolveFunctionCallLabel(sc_list, label))
+  auto sc_or_err = symbol_file->ResolveFunctionCallLabel(label);
+  if (!sc_or_err)
     return llvm::joinErrors(
         llvm::createStringError("failed to resolve function by UID"),
-        std::move(err));
+        sc_or_err.takeError());
+
+  SymbolContextList sc_list;
+  sc_list.Append(*sc_or_err);
 
   LoadAddressResolver resolver(*sc.target_sp, symbol_was_missing_weak);
   return resolver.Resolve(sc_list).value_or(LLDB_INVALID_ADDRESS);
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index c0a74c871c68f..874fbf7c160b8 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -2475,9 +2475,8 @@ bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die,
   return false;
 }
 
-llvm::Error
-SymbolFileDWARF::ResolveFunctionCallLabel(SymbolContextList &sc_list,
-                                          const FunctionCallLabel &label) {
+llvm::Expected<SymbolContext>
+SymbolFileDWARF::ResolveFunctionCallLabel(const FunctionCallLabel &label) {
   std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
 
   DWARFDIE die = GetDIE(label.symbol_id);
@@ -2511,6 +2510,7 @@ SymbolFileDWARF::ResolveFunctionCallLabel(SymbolContextList &sc_list,
           llvm::formatv("failed to find definition DIE for {0}", label));
   }
 
+  SymbolContextList sc_list;
   if (!ResolveFunction(die, /*include_inlines=*/false, sc_list))
     return llvm::createStringError(
         llvm::formatv("failed to resolve function for {0}", label));
@@ -2519,12 +2519,9 @@ SymbolFileDWARF::ResolveFunctionCallLabel(SymbolContextList &sc_list,
     return llvm::createStringError(
         llvm::formatv("failed to find function for {0}", label));
 
-  if (sc_list.GetSize() > 1)
-    return llvm::createStringError(
-        llvm::formatv("found {0} functions for {1} but expected only 1",
-                      sc_list.GetSize(), label));
+  assert(sc_list.GetSize() == 1);
 
-  return llvm::Error::success();
+  return sc_list[0];
 }
 
 bool SymbolFileDWARF::DIEInDeclContext(const CompilerDeclContext &decl_ctx,
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index 93b5b58ac0929..3ec538da8cf77 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -436,8 +436,8 @@ class SymbolFileDWARF : public SymbolFileCommon {
   DIEArray MergeBlockAbstractParameters(const DWARFDIE &block_die,
                                         DIEArray &&variable_dies);
 
-  llvm::Error ResolveFunctionCallLabel(SymbolContextList &sc_list,
-                                       const FunctionCallLabel &label) override;
+  llvm::Expected<SymbolContext>
+  ResolveFunctionCallLabel(const FunctionCallLabel &label) override;
 
   // Given a die_offset, figure out the symbol context representing that die.
   bool ResolveFunction(const DWARFDIE &die, bool include_inlines,
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
index b532e4d8c83e1..9d7452a1988fa 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
@@ -1603,13 +1603,13 @@ void SymbolFileDWARFDebugMap::GetCompileOptions(
   });
 }
 
-llvm::Error SymbolFileDWARFDebugMap::ResolveFunctionCallLabel(
-    SymbolContextList &sc_list, const FunctionCallLabel &label) {
+llvm::Expected<SymbolContext> SymbolFileDWARFDebugMap::ResolveFunctionCallLabel(
+    const FunctionCallLabel &label) {
   const uint64_t oso_idx = GetOSOIndexFromUserID(label.symbol_id);
   SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex(oso_idx);
   if (!oso_dwarf)
     return llvm::createStringError(llvm::formatv(
         "couldn't find symbol file for {0} in debug-map.", label));
 
-  return oso_dwarf->ResolveFunctionCallLabel(sc_list, label);
+  return oso_dwarf->ResolveFunctionCallLabel(label);
 }
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
index 31a2889cf3ff6..e1f1df23951c6 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
@@ -144,8 +144,8 @@ class SymbolFileDWARFDebugMap : public SymbolFileCommon {
   void
   GetCompileOptions(std::unordered_map<lldb::CompUnitSP, Args> &args) override;
 
-  llvm::Error ResolveFunctionCallLabel(SymbolContextList &sc_list,
-                                       const FunctionCallLabel &label) override;
+  llvm::Expected<SymbolContext>
+  ResolveFunctionCallLabel(const FunctionCallLabel &label) override;
 
 protected:
   enum { kHaveInitializedOSOs = (1 << 0), kNumFlags };

>From 2a0b79940994fd0ec85e352625b944b6bc611736 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 16:16:33 +0100
Subject: [PATCH 30/36] fixup! simplify label parsing

---
 lldb/source/Expression/Expression.cpp        | 60 ++++++--------------
 lldb/unittests/Expression/ExpressionTest.cpp | 39 ++++++++-----
 2 files changed, 43 insertions(+), 56 deletions(-)

diff --git a/lldb/source/Expression/Expression.cpp b/lldb/source/Expression/Expression.cpp
index a57bcbe97e117..796851ff15ca3 100644
--- a/lldb/source/Expression/Expression.cpp
+++ b/lldb/source/Expression/Expression.cpp
@@ -11,6 +11,7 @@
 #include "lldb/Target/Target.h"
 
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Error.h"
 
@@ -31,62 +32,35 @@ Expression::Expression(ExecutionContextScope &exe_scope)
   assert(m_target_wp.lock());
 }
 
-/// Returns the components of the specified function call label.
-///
-/// The format of \c label is described in \c FunctionCallLabel.
-/// The label prefix is not one of the components.
-static llvm::Expected<llvm::SmallVector<llvm::StringRef, 3>>
-splitFunctionCallLabel(llvm::StringRef label) {
-  if (!label.consume_front(FunctionCallLabelPrefix))
-    return llvm::createStringError(
-        "expected function call label prefix not found.");
-  if (!label.consume_front(":"))
-    return llvm::createStringError(
-        "expected ':' as the first character after prefix.");
-
-  auto sep1 = label.find_first_of(":");
-  if (sep1 == llvm::StringRef::npos)
-    return llvm::createStringError("no ':' separator found.");
-
-  auto sep2 = label.find_first_of(":", sep1 + 1);
-  if (sep2 == llvm::StringRef::npos)
-    return llvm::createStringError("only single ':' separator found.");
-
-  llvm::SmallVector<llvm::StringRef, 3> components;
-  components.push_back(label.slice(0, sep1));
-  components.push_back(label.slice(sep1 + 1, sep2));
-  components.push_back(label.slice(sep2 + 1, llvm::StringRef::npos));
-
-  return components;
-}
-
 llvm::Expected<FunctionCallLabel>
 lldb_private::FunctionCallLabel::fromString(llvm::StringRef label) {
-  auto components_or_err = splitFunctionCallLabel(label);
-  if (!components_or_err)
-    return llvm::joinErrors(
-        llvm::createStringError("failed to split function call label '%s'",
-                                label.data()),
-        components_or_err.takeError());
+  llvm::SmallVector<llvm::StringRef, 4> components;
+  label.split(components, ":", /*MaxSplit=*/3);
+
+  if (components.size() != 4)
+    return llvm::createStringError("malformed function call label.");
 
-  const auto &components = *components_or_err;
+  if (components[0] != FunctionCallLabelPrefix)
+    return llvm::createStringError(llvm::formatv(
+        "expected function call label prefix '{0}' but found '{1}' instead.",
+        FunctionCallLabelPrefix, components[0]));
 
-  llvm::StringRef module_label = components[0];
-  llvm::StringRef die_label = components[1];
+  llvm::StringRef module_label = components[1];
+  llvm::StringRef die_label = components[2];
 
   lldb::user_id_t module_id = 0;
-  if (module_label.consumeInteger(0, module_id))
+  if (!llvm::to_integer(module_label, module_id))
     return llvm::createStringError(
-        llvm::formatv("failed to parse module ID from '{0}'.", components[0]));
+        llvm::formatv("failed to parse module ID from '{0}'.", module_label));
 
   lldb::user_id_t die_id;
-  if (die_label.consumeInteger(/*Radix=*/0, die_id))
+  if (!llvm::to_integer(die_label, die_id))
     return llvm::createStringError(
-        llvm::formatv("failed to parse symbol ID from '{0}'.", components[1]));
+        llvm::formatv("failed to parse symbol ID from '{0}'.", die_label));
 
   return FunctionCallLabel{/*.module_id=*/module_id,
                            /*.symbol_id=*/die_id,
-                           /*.lookup_name=*/components[2]};
+                           /*.lookup_name=*/components[3]};
 }
 
 std::string lldb_private::FunctionCallLabel::toString() const {
diff --git a/lldb/unittests/Expression/ExpressionTest.cpp b/lldb/unittests/Expression/ExpressionTest.cpp
index 542ce5005d7d9..12f6dd515fd11 100644
--- a/lldb/unittests/Expression/ExpressionTest.cpp
+++ b/lldb/unittests/Expression/ExpressionTest.cpp
@@ -23,34 +23,47 @@ struct LabelTestCase {
 
 static LabelTestCase g_label_test_cases[] = {
     // Failure modes
-    {"0x0:0x0:_Z3foov",
+    {"bar:0x0:0x0:_Z3foov",
      {},
-     {"failed to split function call label '0x0:0x0:_Z3foov'",
-      "expected function call label prefix not found."}},
-    {"$__lldb_func0x0:0x0:_Z3foov",
+     {"expected function call label prefix '$__lldb_func' but found 'bar' "
+      "instead."}},
+    {"$__lldb_func :0x0:0x0:_Z3foov",
      {},
-     {"failed to split function call label '$__lldb_func0x0:0x0:_Z3foov'",
-      "expected ':' as the first character after prefix."}},
-    {"$__lldb_func:",
+     {"expected function call label prefix '$__lldb_func' but found "
+      "'$__lldb_func ' instead."}},
+    {"$__lldb_funcc:0x0:0x0:_Z3foov",
      {},
-     {"failed to split function call label '$__lldb_func:'",
-      "no ':' separator found."}},
-    {"$__lldb_func:0x0:0x0",
-     {},
-     {"failed to split function call label '$__lldb_func:0x0:0x0'",
-      "only single ':' separator found."}},
+     {"expected function call label prefix '$__lldb_func' but found "
+      "'$__lldb_funcc' instead."}},
+    {"", {}, {"malformed function call label."}},
+    {"foo", {}, {"malformed function call label."}},
+    {"$__lldb_func", {}, {"malformed function call label."}},
+    {"$__lldb_func:", {}, {"malformed function call label."}},
+    {"$__lldb_func:0x0:0x0", {}, {"malformed function call label."}},
     {"$__lldb_func:abc:0x0:_Z3foov",
      {},
      {"failed to parse module ID from 'abc'."}},
     {"$__lldb_func:-1:0x0:_Z3foov",
      {},
      {"failed to parse module ID from '-1'."}},
+    {"$__lldb_func:0x0invalid:0x0:_Z3foov",
+     {},
+     {"failed to parse module ID from '0x0invalid'."}},
+    {"$__lldb_func:0x0 :0x0:_Z3foov",
+     {},
+     {"failed to parse module ID from '0x0 '."}},
     {"$__lldb_func:0x0:abc:_Z3foov",
      {},
      {"failed to parse symbol ID from 'abc'."}},
     {"$__lldb_func:0x5:-1:_Z3foov",
      {},
      {"failed to parse symbol ID from '-1'."}},
+    {"$__lldb_func:0x5:0x0invalid:_Z3foov",
+     {},
+     {"failed to parse symbol ID from '0x0invalid'."}},
+    {"$__lldb_func:0x5:0x0 :_Z3foov",
+     {},
+     {"failed to parse symbol ID from '0x0 '."}},
     {"$__lldb_func:0x0:0x0:_Z3foov",
      {
          /*.module_id=*/0x0,

>From e080b6d5461e5eae9341c7458a92416c33346ae8 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 16:45:37 +0100
Subject: [PATCH 31/36] fixup! remove unused function

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

diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp
index 870b71eee3c7c..b50f5dcc0c61e 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -774,36 +774,6 @@ class LoadAddressResolver {
   lldb::addr_t m_best_internal_load_address = LLDB_INVALID_ADDRESS;
 };
 
-/// Find a module by LLDB-specific unique identifier.
-///
-/// \param[in] uid The UID of the module assigned to it on construction.
-///
-/// \returns ModuleSP of module with \c uid. Returns nullptr if no such
-/// module could be found.
-static lldb::ModuleSP FindDebugModule(lldb::user_id_t uid,
-                                      const ModuleList &modules) {
-  lldb::ModuleSP module_sp;
-  modules.ForEach([&](const lldb::ModuleSP &m) {
-    if (m->GetID() == uid) {
-      module_sp = m;
-      return IterationAction::Stop;
-    }
-
-    auto *sym = m->GetSymbolFile();
-    if (!sym)
-      return IterationAction::Continue;
-
-    auto debug_modules = sym->GetDebugInfoModules();
-    module_sp = FindDebugModule(uid, debug_modules);
-    if (module_sp)
-      return IterationAction::Stop;
-
-    return IterationAction::Continue;
-  });
-
-  return module_sp;
-}
-
 /// Returns address of the function referred to by the special function call
 /// label \c label.
 static llvm::Expected<lldb::addr_t>

>From 24fbf6c4666eb22dba61d4d5a88ec95726df10b4 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 16:46:29 +0100
Subject: [PATCH 32/36] fixup! add TODO

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

diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp
index b50f5dcc0c61e..6f16196373dbc 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -968,6 +968,9 @@ lldb::addr_t IRExecutionUnit::FindSymbol(lldb_private::ConstString name,
     }
   }
 
+  // TODO: now with function call labels, do we still need to
+  // generate alternate manglings?
+
   std::vector<ConstString> candidate_C_names;
   std::vector<ConstString> candidate_CPlusPlus_names;
 

>From fa0b004bac72ef50d0ccfdeb0835d6a4e3763413 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 17:39:16 +0100
Subject: [PATCH 33/36] fixup! fix docs

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

diff --git a/lldb/include/lldb/Expression/Expression.h b/lldb/include/lldb/Expression/Expression.h
index 086aa1406a1c6..20067f469895b 100644
--- a/lldb/include/lldb/Expression/Expression.h
+++ b/lldb/include/lldb/Expression/Expression.h
@@ -142,7 +142,7 @@ struct FunctionCallLabel {
   std::string toString() const;
 };
 
-/// LLDB attaches this prefix to mangled names of functions that it get called
+/// LLDB attaches this prefix to mangled names of functions that get called
 /// from JITted expressions.
 inline constexpr llvm::StringRef FunctionCallLabelPrefix = "$__lldb_func";
 

>From edd781de6f718814e6fe32d41fe294b0b88c3c54 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 30 Jul 2025 23:09:57 +0100
Subject: [PATCH 34/36] fixup! no need for std::optional

(cherry picked from commit 7aeed0f42b364ac4272f3cb7b526fcb6dbc38d33)
---
 .../SymbolFile/DWARF/DWARFASTParserClang.cpp  | 10 ++++----
 lldb/unittests/Symbol/TestTypeSystemClang.cpp | 24 -------------------
 2 files changed, 5 insertions(+), 29 deletions(-)

diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 4b386ac2093a7..781c1c6c5745d 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -250,14 +250,14 @@ static unsigned GetCXXMethodCVQuals(const DWARFDIE &subprogram,
   return cv_quals;
 }
 
-static std::optional<std::string> MakeLLDBFuncAsmLabel(const DWARFDIE &die) {
+static std::string MakeLLDBFuncAsmLabel(const DWARFDIE &die) {
   char const *name = die.GetMangledName(/*substitute_name_allowed*/ false);
   if (!name)
-    return std::nullopt;
+    return {};
 
   SymbolFileDWARF *dwarf = die.GetDWARF();
   if (!dwarf)
-    return std::nullopt;
+    return {};
 
   auto get_module_id = [&](SymbolFile *sym) {
     if (!sym)
@@ -279,11 +279,11 @@ static std::optional<std::string> MakeLLDBFuncAsmLabel(const DWARFDIE &die) {
     module_id = get_module_id(dwarf);
 
   if (module_id == LLDB_INVALID_UID)
-    return std::nullopt;
+    return {};
 
   const auto die_id = die.GetID();
   if (die_id == LLDB_INVALID_UID)
-    return std::nullopt;
+    return {};
 
   return FunctionCallLabel{/*module_id=*/module_id,
                            /*symbol_id=*/die_id,
diff --git a/lldb/unittests/Symbol/TestTypeSystemClang.cpp b/lldb/unittests/Symbol/TestTypeSystemClang.cpp
index 228ee2ed9b6ea..57857676c7df9 100644
--- a/lldb/unittests/Symbol/TestTypeSystemClang.cpp
+++ b/lldb/unittests/Symbol/TestTypeSystemClang.cpp
@@ -869,11 +869,7 @@ TEST_F(TestTypeSystemClang, TestFunctionTemplateConstruction) {
   CompilerType clang_type = m_ast->CreateFunctionType(int_type, {}, false, 0U);
   FunctionDecl *func = m_ast->CreateFunctionDeclaration(
       TU, OptionalClangModuleID(), "foo", clang_type, StorageClass::SC_None,
-<<<<<<< HEAD
       false, /*asm_label=*/{});
-=======
-      false, std::nullopt);
->>>>>>> 382395408c4b ([lldb][Expression] Encode Module and DIE UIDs into function AsmLabels)
   TypeSystemClang::TemplateParameterInfos empty_params;
 
   // Create the actual function template.
@@ -904,11 +900,7 @@ TEST_F(TestTypeSystemClang, TestFunctionTemplateInRecordConstruction) {
   // 2. It is mirroring the behavior of DWARFASTParserClang::ParseSubroutine.
   FunctionDecl *func = m_ast->CreateFunctionDeclaration(
       TU, OptionalClangModuleID(), "foo", clang_type, StorageClass::SC_None,
-<<<<<<< HEAD
       false, /*asm_label=*/{});
-=======
-      false, std::nullopt);
->>>>>>> 382395408c4b ([lldb][Expression] Encode Module and DIE UIDs into function AsmLabels)
   TypeSystemClang::TemplateParameterInfos empty_params;
 
   // Create the actual function template.
@@ -946,11 +938,7 @@ TEST_F(TestTypeSystemClang, TestDeletingImplicitCopyCstrDueToMoveCStr) {
   bool is_attr_used = false;
   bool is_artificial = false;
   m_ast->AddMethodToCXXRecordType(
-<<<<<<< HEAD
       t.GetOpaqueQualType(), class_name, /*asm_label=*/{}, function_type,
-=======
-      t.GetOpaqueQualType(), class_name, std::nullopt, function_type,
->>>>>>> 382395408c4b ([lldb][Expression] Encode Module and DIE UIDs into function AsmLabels)
       lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline,
       is_explicit, is_attr_used, is_artificial);
 
@@ -987,11 +975,7 @@ TEST_F(TestTypeSystemClang, TestNotDeletingUserCopyCstrDueToMoveCStr) {
     CompilerType function_type = m_ast->CreateFunctionType(
         return_type, args, /*variadic=*/false, /*quals*/ 0U);
     m_ast->AddMethodToCXXRecordType(
-<<<<<<< HEAD
         t.GetOpaqueQualType(), class_name, /*asm_label=*/{}, function_type,
-=======
-        t.GetOpaqueQualType(), class_name, std::nullopt, function_type,
->>>>>>> 382395408c4b ([lldb][Expression] Encode Module and DIE UIDs into function AsmLabels)
         lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline,
         is_explicit, is_attr_used, is_artificial);
   }
@@ -1003,11 +987,7 @@ TEST_F(TestTypeSystemClang, TestNotDeletingUserCopyCstrDueToMoveCStr) {
         m_ast->CreateFunctionType(return_type, args,
                                   /*variadic=*/false, /*quals*/ 0U);
     m_ast->AddMethodToCXXRecordType(
-<<<<<<< HEAD
         t.GetOpaqueQualType(), class_name, /*asm_label=*/{}, function_type,
-=======
-        t.GetOpaqueQualType(), class_name, std::nullopt, function_type,
->>>>>>> 382395408c4b ([lldb][Expression] Encode Module and DIE UIDs into function AsmLabels)
         lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline,
         is_explicit, is_attr_used, is_artificial);
   }
@@ -1118,11 +1098,7 @@ TEST_F(TestTypeSystemClang, AddMethodToCXXRecordType_ParmVarDecls) {
       m_ast->CreateFunctionType(return_type, param_types,
                                 /*variadic=*/false, /*quals*/ 0U);
   m_ast->AddMethodToCXXRecordType(
-<<<<<<< HEAD
       t.GetOpaqueQualType(), "myFunc", /*asm_label=*/{}, function_type,
-=======
-      t.GetOpaqueQualType(), "myFunc", std::nullopt, function_type,
->>>>>>> 382395408c4b ([lldb][Expression] Encode Module and DIE UIDs into function AsmLabels)
       lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline,
       is_explicit, is_attr_used, is_artificial);
 

>From f1e3ce118911757ecb0f379fa1c43c574f4462e4 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Thu, 31 Jul 2025 08:33:17 +0100
Subject: [PATCH 35/36] fixup! add tests for
 TypeSystemClang::DeclGetMangledName

---
 lldb/unittests/Symbol/TestTypeSystemClang.cpp | 116 ++++++++++++++++++
 1 file changed, 116 insertions(+)

diff --git a/lldb/unittests/Symbol/TestTypeSystemClang.cpp b/lldb/unittests/Symbol/TestTypeSystemClang.cpp
index 57857676c7df9..eb0780d068d36 100644
--- a/lldb/unittests/Symbol/TestTypeSystemClang.cpp
+++ b/lldb/unittests/Symbol/TestTypeSystemClang.cpp
@@ -17,6 +17,7 @@
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/ExprCXX.h"
+#include "llvm/IR/GlobalValue.h"
 #include "gtest/gtest.h"
 
 using namespace clang;
@@ -1116,3 +1117,118 @@ TEST_F(TestTypeSystemClang, AddMethodToCXXRecordType_ParmVarDecls) {
   EXPECT_EQ(method_it->getParamDecl(0)->getDeclContext(), *method_it);
   EXPECT_EQ(method_it->getParamDecl(1)->getDeclContext(), *method_it);
 }
+
+TEST_F(TestTypeSystemClang, AsmLabel_CtorDtor) {
+  // Tests TypeSystemClang::DeclGetMangledName for constructors/destructors
+  // with and without AsmLabels.
+
+  llvm::StringRef class_name = "S";
+  CompilerType t = clang_utils::createRecord(*m_ast, class_name);
+  m_ast->StartTagDeclarationDefinition(t);
+
+  CompilerType return_type = m_ast->GetBasicType(lldb::eBasicTypeVoid);
+  const bool is_virtual = false;
+  const bool is_static = false;
+  const bool is_inline = false;
+  const bool is_explicit = true;
+  const bool is_attr_used = false;
+  const bool is_artificial = false;
+
+  CompilerType function_type =
+      m_ast->CreateFunctionType(return_type, {},
+                                /*variadic=*/false, /*quals*/ 0U);
+  auto *ctor_nolabel = m_ast->AddMethodToCXXRecordType(
+      t.GetOpaqueQualType(), "S", /*asm_label=*/{}, function_type,
+      lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline,
+      is_explicit, is_attr_used, is_artificial);
+
+  auto *dtor_nolabel = m_ast->AddMethodToCXXRecordType(
+      t.GetOpaqueQualType(), "~S", /*asm_label=*/{}, function_type,
+      lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline,
+      is_explicit, is_attr_used, is_artificial);
+
+  auto *ctor = m_ast->AddMethodToCXXRecordType(
+      t.GetOpaqueQualType(), "S", /*asm_label=*/"$__lldb_func:0x0:0x0:S",
+      function_type, lldb::AccessType::eAccessPublic, is_virtual, is_static,
+      is_inline, is_explicit, is_attr_used, is_artificial);
+
+  auto *dtor = m_ast->AddMethodToCXXRecordType(
+      t.GetOpaqueQualType(), "~S", /*asm_label=*/"$__lldb_func:0x0:0x0:~S",
+      function_type, lldb::AccessType::eAccessPublic, is_virtual, is_static,
+      is_inline, is_explicit, is_attr_used, is_artificial);
+
+  m_ast->CompleteTagDeclarationDefinition(t);
+
+  ASSERT_TRUE(ctor_nolabel);
+  ASSERT_TRUE(dtor_nolabel);
+  ASSERT_TRUE(ctor);
+  ASSERT_TRUE(dtor);
+
+  ASSERT_STREQ(m_ast->DeclGetMangledName(ctor_nolabel).GetCString(),
+               "_ZN1SC1Ev");
+  ASSERT_STREQ(m_ast->DeclGetMangledName(dtor_nolabel).GetCString(),
+               "_ZN1SD1Ev");
+  ASSERT_STREQ(m_ast->DeclGetMangledName(ctor).GetCString(),
+               "\01$__lldb_func:0x0:0x0:S");
+  ASSERT_STREQ(m_ast->DeclGetMangledName(dtor).GetCString(),
+               "\01$__lldb_func:0x0:0x0:~S");
+}
+
+struct AsmLabelTestCase {
+  llvm::StringRef mangled;
+  llvm::StringRef expected;
+};
+
+class TestTypeSystemClangAsmLabel
+    : public testing::TestWithParam<AsmLabelTestCase> {
+public:
+  SubsystemRAII<FileSystem, HostInfo> subsystems;
+
+  void SetUp() override {
+    m_holder =
+        std::make_unique<clang_utils::TypeSystemClangHolder>("test ASTContext");
+    m_ast = m_holder->GetAST();
+  }
+
+  void TearDown() override {
+    m_ast = nullptr;
+    m_holder.reset();
+  }
+
+protected:
+  TypeSystemClang *m_ast = nullptr;
+  std::unique_ptr<clang_utils::TypeSystemClangHolder> m_holder;
+};
+
+static AsmLabelTestCase g_asm_label_test_cases[] = {
+    {/*mangled=*/"$__lldb_func:0x0:0x0:_Z3foov",
+     /*expected=*/"_Z3foov"},
+    {/*mangled=*/"$__lldb_func:0x0:0x0:foo",
+     /*expected=*/"$__lldb_func:0x0:0x0:foo"},
+    {/*mangled=*/"foo",
+     /*expected=*/"foo"},
+    {/*mangled=*/"_Z3foov",
+     /*expected=*/"_Z3foov"},
+    {/*mangled=*/"$__lldb_func:",
+     /*expected=*/"$__lldb_func:"},
+};
+
+TEST_P(TestTypeSystemClangAsmLabel, DeclGetMangledName) {
+  const auto &[mangled, expected] = GetParam();
+
+  CompilerType int_type = m_ast->GetBasicType(lldb::eBasicTypeInt);
+  clang::TranslationUnitDecl *TU = m_ast->GetTranslationUnitDecl();
+
+  // Prepare the declarations/types we need for the template.
+  CompilerType clang_type = m_ast->CreateFunctionType(int_type, {}, false, 0U);
+  FunctionDecl *func = m_ast->CreateFunctionDeclaration(
+      TU, OptionalClangModuleID(), "foo", clang_type, StorageClass::SC_None,
+      false, /*asm_label=*/mangled);
+
+  ASSERT_EQ(llvm::GlobalValue::dropLLVMManglingEscape(
+                m_ast->DeclGetMangledName(func).GetStringRef()),
+            expected);
+}
+
+INSTANTIATE_TEST_SUITE_P(AsmLabelTests, TestTypeSystemClangAsmLabel,
+                         testing::ValuesIn(g_asm_label_test_cases));

>From 44410a459303cab42a8d05bb6da3ebf1b64c7046 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Thu, 31 Jul 2025 09:52:44 +0100
Subject: [PATCH 36/36] Structors Init

---
 clang/lib/AST/Mangle.cpp                      | 15 +++
 libcxxabi/src/demangle/ItaniumDemangle.h      |  2 +
 lldb/include/lldb/Expression/Expression.h     |  6 +-
 lldb/source/Expression/Expression.cpp         | 22 +++--
 lldb/source/Expression/IRExecutionUnit.cpp    |  2 +-
 .../SymbolFile/DWARF/DWARFASTParserClang.cpp  | 34 ++++++-
 .../SymbolFile/DWARF/SymbolFileDWARF.cpp      | 95 +++++++++++++++++--
 .../TypeSystem/Clang/TypeSystemClang.cpp      |  1 +
 .../TypeSystem/Clang/TypeSystemClang.h        |  2 +
 llvm/include/llvm/Demangle/Demangle.h         |  3 +
 llvm/include/llvm/Demangle/ItaniumDemangle.h  |  2 +
 llvm/lib/Demangle/ItaniumDemangle.cpp         | 10 +-
 12 files changed, 171 insertions(+), 23 deletions(-)

diff --git a/clang/lib/AST/Mangle.cpp b/clang/lib/AST/Mangle.cpp
index 9652fdbc4e125..eebf82aed3ec5 100644
--- a/clang/lib/AST/Mangle.cpp
+++ b/clang/lib/AST/Mangle.cpp
@@ -152,6 +152,14 @@ bool MangleContext::shouldMangleDeclName(const NamedDecl *D) {
   return shouldMangleCXXName(D);
 }
 
+static void tryEmitDebugStructorVariant(GlobalDecl GD, raw_ostream &Out) {
+  // TODO: shouldn't append but instead slice
+  if (llvm::isa<clang::CXXConstructorDecl>(GD.getDecl()))
+    Out << "C" << GD.getCtorType();
+  else if (llvm::isa<clang::CXXDestructorDecl>(GD.getDecl()))
+    Out << "D" << GD.getDtorType();
+}
+
 void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
   const ASTContext &ASTContext = getASTContext();
   const NamedDecl *D = cast<NamedDecl>(GD.getDecl());
@@ -161,10 +169,12 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
   if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) {
     // If we have an asm name, then we use it as the mangling.
 
+    // TODO: remove this getIsLiteralLabel branch
     // If the label isn't literal, or if this is an alias for an LLVM intrinsic,
     // do not add a "\01" prefix.
     if (!ALA->getIsLiteralLabel() || ALA->getLabel().starts_with("llvm.")) {
       Out << ALA->getLabel();
+
       return;
     }
 
@@ -186,6 +196,11 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
       Out << '\01'; // LLVM IR Marker for __asm("foo")
 
     Out << ALA->getLabel();
+
+    // TODO: ideally should have separate attribute for this?
+    if (ASTContext.getLangOpts().DebuggerSupport)
+      tryEmitDebugStructorVariant(GD, Out);
+
     return;
   }
 
diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h b/libcxxabi/src/demangle/ItaniumDemangle.h
index 6f27da7b9cadf..7b3983bc89367 100644
--- a/libcxxabi/src/demangle/ItaniumDemangle.h
+++ b/libcxxabi/src/demangle/ItaniumDemangle.h
@@ -1766,6 +1766,8 @@ class CtorDtorName final : public Node {
 
   template<typename Fn> void match(Fn F) const { F(Basename, IsDtor, Variant); }
 
+  int getVariant() const { return Variant; }
+
   void printLeft(OutputBuffer &OB) const override {
     if (IsDtor)
       OB += "~";
diff --git a/lldb/include/lldb/Expression/Expression.h b/lldb/include/lldb/Expression/Expression.h
index 20067f469895b..c2702bd9dca96 100644
--- a/lldb/include/lldb/Expression/Expression.h
+++ b/lldb/include/lldb/Expression/Expression.h
@@ -103,7 +103,7 @@ class Expression {
 ///
 /// The format being:
 ///
-///   <prefix>:<module uid>:<symbol uid>:<name>
+///   <prefix>:<module uid>:<symbol uid>:<discriminator>:<name>
 ///
 /// The label string needs to stay valid for the entire lifetime
 /// of this object.
@@ -126,6 +126,8 @@ struct FunctionCallLabel {
   /// ':' in the mangled name when parsing the label.
   llvm::StringRef lookup_name;
 
+  llvm::StringRef discriminator;
+
   /// Decodes the specified function \c label into a \c FunctionCallLabel.
   static llvm::Expected<FunctionCallLabel> fromString(llvm::StringRef label);
 
@@ -133,7 +135,7 @@ struct FunctionCallLabel {
   ///
   /// The representation roundtrips through \c fromString:
   /// \code{.cpp}
-  /// llvm::StringRef encoded = "$__lldb_func:0x0:0x0:_Z3foov";
+  /// llvm::StringRef encoded = "$__lldb_func:0x0:0x0:_Z3foov:";
   /// FunctionCallLabel label = *fromString(label);
   ///
   /// assert (label.toString() == encoded);
diff --git a/lldb/source/Expression/Expression.cpp b/lldb/source/Expression/Expression.cpp
index 796851ff15ca3..c9baa228fe888 100644
--- a/lldb/source/Expression/Expression.cpp
+++ b/lldb/source/Expression/Expression.cpp
@@ -34,10 +34,10 @@ Expression::Expression(ExecutionContextScope &exe_scope)
 
 llvm::Expected<FunctionCallLabel>
 lldb_private::FunctionCallLabel::fromString(llvm::StringRef label) {
-  llvm::SmallVector<llvm::StringRef, 4> components;
-  label.split(components, ":", /*MaxSplit=*/3);
+  llvm::SmallVector<llvm::StringRef, 5> components;
+  label.split(components, ":", /*MaxSplit=*/4);
 
-  if (components.size() != 4)
+  if (components.size() != 5)
     return llvm::createStringError("malformed function call label.");
 
   if (components[0] != FunctionCallLabelPrefix)
@@ -47,6 +47,10 @@ lldb_private::FunctionCallLabel::fromString(llvm::StringRef label) {
 
   llvm::StringRef module_label = components[1];
   llvm::StringRef die_label = components[2];
+  llvm::StringRef lookup_name =
+      components[3]; // TODO: mangled name should come last...clang should
+                     // splice it into the label?
+  llvm::StringRef discriminator = components[4];
 
   lldb::user_id_t module_id = 0;
   if (!llvm::to_integer(module_label, module_id))
@@ -60,18 +64,20 @@ lldb_private::FunctionCallLabel::fromString(llvm::StringRef label) {
 
   return FunctionCallLabel{/*.module_id=*/module_id,
                            /*.symbol_id=*/die_id,
-                           /*.lookup_name=*/components[3]};
+                           /*.lookup_name=*/lookup_name,
+                           /*.discriminator=*/discriminator};
 }
 
 std::string lldb_private::FunctionCallLabel::toString() const {
-  return llvm::formatv("{0}:{1:x}:{2:x}:{3}", FunctionCallLabelPrefix,
-                       module_id, symbol_id, lookup_name)
+  return llvm::formatv("{0}:{1:x}:{2:x}:{3}:{4}", FunctionCallLabelPrefix,
+                       module_id, symbol_id, lookup_name, discriminator)
       .str();
 }
 
 void llvm::format_provider<FunctionCallLabel>::format(
     const FunctionCallLabel &label, raw_ostream &OS, StringRef Style) {
   OS << llvm::formatv("FunctionCallLabel{ module_id: {0:x}, symbol_id: {1:x}, "
-                      "lookup_name: {2} }",
-                      label.module_id, label.symbol_id, label.lookup_name);
+                      "lookup_name: {2}, discriminator: {3} }",
+                      label.module_id, label.symbol_id, label.lookup_name,
+                      label.discriminator);
 }
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp
index 6f16196373dbc..5e40df282e7b0 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -947,7 +947,7 @@ lldb::addr_t IRExecutionUnit::FindSymbol(lldb_private::ConstString name,
     auto label_or_err = FunctionCallLabel::fromString(name);
     if (!label_or_err) {
       LLDB_LOG_ERROR(GetLog(LLDBLog::Expressions), label_or_err.takeError(),
-                     "failed to create FunctionCallLabel from '{0}': {1}",
+                     "failed to create FunctionCallLabel from '{1}': {0}",
                      name.GetStringRef());
       return LLDB_INVALID_ADDRESS;
     }
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 781c1c6c5745d..3a7c34f545a2e 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -250,8 +250,36 @@ static unsigned GetCXXMethodCVQuals(const DWARFDIE &subprogram,
   return cv_quals;
 }
 
+static const char *GetMangledOrStructorName(const DWARFDIE &die) {
+  const char *name = die.GetMangledName(/*substitute_name_allowed*/ false);
+  if (name)
+    return name;
+
+  name = die.GetName();
+  if (!name)
+    return nullptr;
+
+  DWARFDIE parent = die.GetParent();
+  if (!parent.IsStructUnionOrClass())
+    return nullptr;
+
+  const char *parent_name = parent.GetName();
+  if (!parent_name)
+    return nullptr;
+
+  // Constructor.
+  if (::strcmp(parent_name, name) == 0)
+    return name;
+
+  // Destructor.
+  if (name[0] == '~' && ::strcmp(parent_name, name + 1))
+    return name;
+
+  return nullptr;
+}
+
 static std::string MakeLLDBFuncAsmLabel(const DWARFDIE &die) {
-  char const *name = die.GetMangledName(/*substitute_name_allowed*/ false);
+  char const *name = GetMangledOrStructorName(die);
   if (!name)
     return {};
 
@@ -285,9 +313,11 @@ static std::string MakeLLDBFuncAsmLabel(const DWARFDIE &die) {
   if (die_id == LLDB_INVALID_UID)
     return {};
 
+  // Note, discriminator is added by Clang during mangling.
   return FunctionCallLabel{/*module_id=*/module_id,
                            /*symbol_id=*/die_id,
-                           /*.lookup_name=*/name}
+                           /*.lookup_name=*/name,
+                           /*discriminator=*/{}}
       .toString();
 }
 
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 874fbf7c160b8..f189547585011 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -7,7 +7,9 @@
 //===----------------------------------------------------------------------===//
 
 #include "SymbolFileDWARF.h"
+#include "clang/Basic/ABI.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/DebugInfo/DWARF/DWARFAddressRange.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
 #include "llvm/Support/Casting.h"
@@ -77,6 +79,7 @@
 
 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
+#include "llvm/Demangle/Demangle.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/FormatVariadic.h"
 
@@ -2475,6 +2478,56 @@ bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die,
   return false;
 }
 
+static uint8_t ClangToItaniumCtorKind(clang::CXXCtorType kind) {
+  switch (kind) {
+  case clang::CXXCtorType::Ctor_Complete:
+    return 1;
+  case clang::CXXCtorType::Ctor_Base:
+    return 2;
+  case clang::CXXCtorType::Ctor_CopyingClosure:
+  case clang::CXXCtorType::Ctor_DefaultClosure:
+  case clang::CXXCtorType::Ctor_Comdat:
+    llvm_unreachable("Unexpected constructor kind.");
+  }
+}
+
+static uint8_t ClangToItaniumDtorKind(clang::CXXDtorType kind) {
+  switch (kind) {
+  case clang::CXXDtorType::Dtor_Deleting:
+    return 0;
+  case clang::CXXDtorType::Dtor_Complete:
+    return 1;
+  case clang::CXXDtorType::Dtor_Base:
+    return 2;
+  case clang::CXXDtorType::Dtor_Comdat:
+    llvm_unreachable("Unexpected destructor kind.");
+  }
+}
+
+static std::optional<uint8_t>
+GetItaniumCtorDtorVariant(llvm::StringRef discriminator) {
+  const bool is_ctor = discriminator.consume_front("C");
+  if (!is_ctor && !discriminator.consume_front("D"))
+    return std::nullopt;
+
+  uint64_t structor_kind;
+  if (!llvm::to_integer(discriminator, structor_kind))
+    return std::nullopt;
+
+  if (is_ctor) {
+    if (structor_kind > clang::CXXCtorType::Ctor_DefaultClosure)
+      return std::nullopt;
+
+    return ClangToItaniumCtorKind(
+        static_cast<clang::CXXCtorType>(structor_kind));
+  }
+
+  if (structor_kind > clang::CXXDtorType::Dtor_Deleting)
+    return std::nullopt;
+
+  return ClangToItaniumDtorKind(static_cast<clang::CXXDtorType>(structor_kind));
+}
+
 llvm::Expected<SymbolContext>
 SymbolFileDWARF::ResolveFunctionCallLabel(const FunctionCallLabel &label) {
   std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
@@ -2487,21 +2540,49 @@ SymbolFileDWARF::ResolveFunctionCallLabel(const FunctionCallLabel &label) {
   // Label was created using a declaration DIE. Need to fetch the definition
   // to resolve the function call.
   if (die.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0)) {
+    // eFunctionNameTypeFull for mangled name lookup.
+    // eFunctionNameTypeMethod is required for structor lookups (since we look
+    // those up by DW_AT_name).
     Module::LookupInfo info(ConstString(label.lookup_name),
-                            lldb::eFunctionNameTypeFull,
+                            lldb::eFunctionNameTypeFull |
+                                lldb::eFunctionNameTypeMethod,
                             lldb::eLanguageTypeUnknown);
 
     m_index->GetFunctions(info, *this, {}, [&](DWARFDIE entry) {
       if (entry.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0))
         return true;
 
-      // We don't check whether the specification DIE for this function
-      // corresponds to the declaration DIE because the declaration might be in
-      // a type-unit but the definition in the compile-unit (and it's
-      // specifcation would point to the declaration in the compile-unit). We
-      // rely on the mangled name within the module to be enough to find us the
-      // unique definition.
+      // TODO: this specification check doesn't work if declaration DIE was in a
+      // type-unit (we should only encode DIEs from .debug_info).
+      auto spec = entry.GetAttributeValueAsReferenceDIE(DW_AT_specification);
+      if (!spec)
+        return true;
+
+      if (spec != die)
+        return true;
+
+      // We're not picking a specific structor variant DIE, so we're done here.
+      if (label.discriminator.empty()) {
+        die = entry;
+        return false;
+      }
+
+      const char *mangled =
+          entry.GetMangledName(/*substitute_name_allowed=*/false);
+      if (!mangled)
+        return true;
+
+      llvm::ItaniumPartialDemangler D;
+      if (D.partialDemangle(mangled))
+        return true;
+
+      // TODO: account for constructor alias (only an issue on Linux)
+      if (D.getCtorOrDtorVariant() !=
+          GetItaniumCtorDtorVariant(label.discriminator).value_or(-1))
+        return true;
+
       die = entry;
+
       return false;
     });
 
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index ab5f4138187ed..fdc50375c03ec 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -10,6 +10,7 @@
 
 #include "clang/AST/DeclBase.h"
 #include "clang/AST/ExprCXX.h"
+#include "clang/Basic/ABI.h"
 #include "clang/Frontend/ASTConsumers.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/FormatAdapters.h"
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index de66bb68c6a4c..ab979129f21cc 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -18,6 +18,7 @@
 #include <set>
 #include <string>
 #include <utility>
+#include <variant>
 #include <vector>
 
 #include "clang/AST/ASTContext.h"
@@ -26,6 +27,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/AST/TemplateBase.h"
 #include "clang/AST/Type.h"
+#include "clang/Basic/ABI.h"
 #include "clang/Basic/TargetInfo.h"
 #include "llvm/ADT/APSInt.h"
 #include "llvm/ADT/SmallVector.h"
diff --git a/llvm/include/llvm/Demangle/Demangle.h b/llvm/include/llvm/Demangle/Demangle.h
index d9b08b2d856dc..6af8fad9ceb86 100644
--- a/llvm/include/llvm/Demangle/Demangle.h
+++ b/llvm/include/llvm/Demangle/Demangle.h
@@ -127,6 +127,9 @@ struct ItaniumPartialDemangler {
   /// If this symbol describes a constructor or destructor.
   DEMANGLE_ABI bool isCtorOrDtor() const;
 
+  /// If this symbol describes a constructor or destructor.
+  std::optional<int> getCtorOrDtorVariant() const;
+
   /// If this symbol describes a function.
   DEMANGLE_ABI bool isFunction() const;
 
diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h b/llvm/include/llvm/Demangle/ItaniumDemangle.h
index 62d427c3966bb..c0db02f8e7fef 100644
--- a/llvm/include/llvm/Demangle/ItaniumDemangle.h
+++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h
@@ -1766,6 +1766,8 @@ class CtorDtorName final : public Node {
 
   template<typename Fn> void match(Fn F) const { F(Basename, IsDtor, Variant); }
 
+  int getVariant() const { return Variant; }
+
   void printLeft(OutputBuffer &OB) const override {
     if (IsDtor)
       OB += "~";
diff --git a/llvm/lib/Demangle/ItaniumDemangle.cpp b/llvm/lib/Demangle/ItaniumDemangle.cpp
index 1009cc91ca12a..a5d7a5576fccf 100644
--- a/llvm/lib/Demangle/ItaniumDemangle.cpp
+++ b/llvm/lib/Demangle/ItaniumDemangle.cpp
@@ -560,13 +560,17 @@ bool ItaniumPartialDemangler::hasFunctionQualifiers() const {
 }
 
 bool ItaniumPartialDemangler::isCtorOrDtor() const {
+  return getCtorOrDtorVariant().has_value();
+}
+
+std::optional<int> ItaniumPartialDemangler::getCtorOrDtorVariant() const {
   const Node *N = static_cast<const Node *>(RootNode);
   while (N) {
     switch (N->getKind()) {
     default:
-      return false;
+      return std::nullopt;
     case Node::KCtorDtorName:
-      return true;
+      return static_cast<const CtorDtorName *>(N)->getVariant();
 
     case Node::KAbiTagAttr:
       N = static_cast<const AbiTagAttr *>(N)->Base;
@@ -588,7 +592,7 @@ bool ItaniumPartialDemangler::isCtorOrDtor() const {
       break;
     }
   }
-  return false;
+  return std::nullopt;
 }
 
 bool ItaniumPartialDemangler::isFunction() const {



More information about the llvm-commits mailing list