https://github.com/GeorgeHuyubo updated 
https://github.com/llvm/llvm-project/pull/176266

>From eee5126ce82961af950b4888c7e923ed2e4d0463 Mon Sep 17 00:00:00 2001
From: George Hu <[email protected]>
Date: Thu, 15 Jan 2026 15:01:33 -0800
Subject: [PATCH] [lldb] Enable locate module callback for main executable in
 launch mode

---
 lldb/include/lldb/Core/ModuleSpec.h           |  15 +++
 lldb/source/Core/ModuleList.cpp               |  30 ++++--
 lldb/source/Target/TargetList.cpp             |   4 +
 .../Target/LocateModuleCallbackTest.cpp       | 101 ++++++++++++++++++
 4 files changed, 139 insertions(+), 11 deletions(-)

diff --git a/lldb/include/lldb/Core/ModuleSpec.h 
b/lldb/include/lldb/Core/ModuleSpec.h
index acbc85b48f02c..1ce857c9765cb 100644
--- a/lldb/include/lldb/Core/ModuleSpec.h
+++ b/lldb/include/lldb/Core/ModuleSpec.h
@@ -138,6 +138,17 @@ class ModuleSpec {
   /// the specified module.
   void SetTarget(std::shared_ptr<Target> target) { m_target_wp = target; }
 
+  lldb::PlatformSP GetPlatformSP() const { return m_platform_wp.lock(); }
+
+  /// Set the platform to be used when resolving a module.
+  ///
+  /// This is useful when a Target is not yet available (e.g., during target
+  /// creation) but a Platform is. The platform can be used to invoke locate
+  /// module callbacks and other platform-specific module resolution logic.
+  void SetPlatform(std::shared_ptr<Platform> platform) {
+    m_platform_wp = platform;
+  }
+
   void Clear() {
     m_file.Clear();
     m_platform_file.Clear();
@@ -150,6 +161,7 @@ class ModuleSpec {
     m_source_mappings.Clear(false);
     m_object_mod_time = llvm::sys::TimePoint<>();
     m_target_wp.reset();
+    m_platform_wp.reset();
   }
 
   explicit operator bool() const {
@@ -283,6 +295,9 @@ class ModuleSpec {
   /// debug info search paths, can be essential. The target's platform can also
   /// be used to locate or download the specified module.
   std::weak_ptr<Target> m_target_wp;
+  /// The platform used when resolving a module. This is useful when a Target
+  /// is not yet available (e.g., during target creation) but a Platform is.
+  std::weak_ptr<Platform> m_platform_wp;
   uint64_t m_object_offset = 0;
   uint64_t m_object_size = 0;
   llvm::sys::TimePoint<> m_object_mod_time;
diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp
index be6ff723e0ffa..e6d8192ea4a55 100644
--- a/lldb/source/Core/ModuleList.cpp
+++ b/lldb/source/Core/ModuleList.cpp
@@ -1103,18 +1103,26 @@ ModuleList::GetSharedModule(const ModuleSpec 
&module_spec, ModuleSP &module_sp,
   if (module_sp)
     return error;
 
-  // Try target's platform locate module callback before second attempt.
+  // Try platform's locate module callback before second attempt.
+  // The platform can come from either the Target (if available) or directly
+  // from the ModuleSpec (useful when Target is not yet created, e.g., during
+  // target creation for launch mode).
   if (invoke_locate_callback) {
-    TargetSP target_sp = module_spec.GetTargetSP();
-    if (target_sp && target_sp->IsValid()) {
-      if (PlatformSP platform_sp = target_sp->GetPlatform()) {
-        FileSpec symbol_file_spec;
-        platform_sp->CallLocateModuleCallbackIfSet(
-            module_spec, module_sp, symbol_file_spec, did_create_ptr);
-        if (module_sp) {
-          // The callback found a module.
-          return error;
-        }
+    PlatformSP platform_sp;
+    if (TargetSP target_sp = module_spec.GetTargetSP()) {
+      if (target_sp->IsValid())
+        platform_sp = target_sp->GetPlatform();
+    }
+    if (!platform_sp)
+      platform_sp = module_spec.GetPlatformSP();
+
+    if (platform_sp) {
+      FileSpec symbol_file_spec;
+      platform_sp->CallLocateModuleCallbackIfSet(
+          module_spec, module_sp, symbol_file_spec, did_create_ptr);
+      if (module_sp) {
+        // The callback found a module.
+        return error;
       }
     }
   }
diff --git a/lldb/source/Target/TargetList.cpp 
b/lldb/source/Target/TargetList.cpp
index ce04e9c1209b8..623f8c4cf8324 100644
--- a/lldb/source/Target/TargetList.cpp
+++ b/lldb/source/Target/TargetList.cpp
@@ -306,6 +306,10 @@ Status TargetList::CreateTargetInternal(Debugger &debugger,
     if (platform_sp) {
       ModuleSpec module_spec(file, arch);
       module_spec.SetTarget(target_sp);
+      // Set the platform so that GetSharedModule can use it for the locate
+      // module callback, even when Target is not yet available (during target
+      // creation for launch mode).
+      module_spec.SetPlatform(platform_sp);
       error = platform_sp->ResolveExecutable(module_spec, exe_module_sp);
     }
 
diff --git a/lldb/unittests/Target/LocateModuleCallbackTest.cpp 
b/lldb/unittests/Target/LocateModuleCallbackTest.cpp
index d727cea9f6eae..f5792e6ce4890 100644
--- a/lldb/unittests/Target/LocateModuleCallbackTest.cpp
+++ b/lldb/unittests/Target/LocateModuleCallbackTest.cpp
@@ -896,3 +896,104 @@ TEST_F(LocateModuleCallbackTest,
   CheckUnstrippedSymbol(m_module_sp);
   ModuleList::RemoveSharedModule(m_module_sp);
 }
+
+TEST_F(LocateModuleCallbackTest,
+       GetSharedModuleWithPlatformFallbackWhenTargetNotAvailable) {
+  // Test that when a Target is not available but Platform is set on 
ModuleSpec,
+  // the locate module callback is still invoked via the Platform fallback.
+  // This is the key functionality added for launch mode support where the
+  // Target is not yet created but we need to resolve the main executable.
+  BuildEmptyCacheDir(m_test_dir);
+
+  int callback_call_count = 0;
+  m_platform_sp->SetLocateModuleCallback(
+      [this, &callback_call_count](const ModuleSpec &module_spec,
+                                   FileSpec &module_file_spec,
+                                   FileSpec &symbol_file_spec) {
+        CheckCallbackArgsWithUUID(module_spec, module_file_spec,
+                                  symbol_file_spec, ++callback_call_count);
+        module_file_spec.SetPath(GetInputFilePath(k_module_file));
+        return Status();
+      });
+
+  // Create a ModuleSpec without Target but with Platform set
+  ModuleSpec module_spec_with_platform = m_module_spec;
+  module_spec_with_platform.SetPlatform(m_platform_sp);
+
+  // Call GetSharedModule directly (simulating the path taken during
+  // target creation in launch mode)
+  bool always_create = true;
+  Status error = ModuleList::GetSharedModule(
+      module_spec_with_platform, m_module_sp, nullptr, nullptr, always_create);
+
+  ASSERT_TRUE(error.Success());
+  ASSERT_EQ(callback_call_count, 1);
+  CheckModule(m_module_sp);
+  ASSERT_EQ(m_module_sp->GetFileSpec(),
+            FileSpec(GetInputFilePath(k_module_file)));
+  ModuleList::RemoveSharedModule(m_module_sp);
+}
+
+TEST_F(LocateModuleCallbackTest,
+       GetSharedModulePreferTargetPlatformOverModuleSpecPlatform) {
+  // Test that when both Target and Platform are available on ModuleSpec,
+  // the Target's platform is preferred. This ensures backward compatibility
+  // and that the existing behavior is maintained for cases where Target
+  // is available.
+  FileSpec uuid_view = BuildCacheDir(m_test_dir);
+
+  int callback_call_count = 0;
+  m_platform_sp->SetLocateModuleCallback(
+      [this, &callback_call_count](const ModuleSpec &module_spec,
+                                   FileSpec &module_file_spec,
+                                   FileSpec &symbol_file_spec) {
+        CheckCallbackArgsWithUUID(module_spec, module_file_spec,
+                                  symbol_file_spec, ++callback_call_count);
+        return Status();
+      });
+
+  // Set both Target and Platform on ModuleSpec
+  ModuleSpec module_spec_with_both = m_module_spec;
+  module_spec_with_both.SetTarget(m_target_sp);
+  module_spec_with_both.SetPlatform(m_platform_sp);
+
+  m_module_sp =
+      m_target_sp->GetOrCreateModule(module_spec_with_both, /*notify=*/false);
+  ASSERT_EQ(callback_call_count, 3);
+  CheckModule(m_module_sp);
+  ASSERT_EQ(m_module_sp->GetFileSpec(), uuid_view);
+  ModuleList::RemoveSharedModule(m_module_sp);
+}
+
+TEST_F(LocateModuleCallbackTest,
+       GetSharedModuleWithPlatformFallbackNoCallback) {
+  // Test that when Platform is set on ModuleSpec but no callback is
+  // registered, GetSharedModule still works and finds the module through
+  // normal resolution (using the file path in ModuleSpec).
+  // This verifies the no-callback case is handled gracefully and
+  // doesn't break normal module resolution.
+  BuildEmptyCacheDir(m_test_dir);
+
+  CheckNoCallback();
+
+  // Create a ModuleSpec with an actual file path that exists, and Platform set
+  ModuleSpec module_spec_with_platform(
+      FileSpec(GetInputFilePath(k_module_file)), ArchSpec(k_arch));
+  module_spec_with_platform.GetUUID().SetFromStringRef(k_module_uuid);
+  module_spec_with_platform.SetObjectSize(k_module_size);
+  module_spec_with_platform.SetPlatform(m_platform_sp);
+
+  Status error = ModuleList::GetSharedModule(
+      module_spec_with_platform, m_module_sp, nullptr, nullptr, false);
+
+  // Without a callback, the module should still be found via the file path
+  // in the ModuleSpec. The platform fallback code path is exercised (checking
+  // for callback) but since there's none, it falls through to normal
+  // resolution.
+  ASSERT_TRUE(error.Success());
+  ASSERT_TRUE(m_module_sp);
+  ASSERT_EQ(m_module_sp->GetUUID().GetAsString(), k_module_uuid);
+  ASSERT_EQ(m_module_sp->GetFileSpec(),
+            FileSpec(GetInputFilePath(k_module_file)));
+  ModuleList::RemoveSharedModule(m_module_sp);
+}

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to