[Lldb-commits] [lldb] [lldb] Add setting to specify (by name) which module's scripting resources can be auto-loaded (PR #188722)

Michael Buch via lldb-commits lldb-commits at lists.llvm.org
Wed Apr 1 00:08:50 PDT 2026


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

>From 12a8e6dc28f00c35b6338ca850c54a3c53758ba0 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Tue, 31 Mar 2026 11:59:22 +0200
Subject: [PATCH 1/3] [lldb][Platform] Handle LoadScriptFromSymFile per-module
 FileSpec

This patch changes the `Platform::LocateXXX` to return a map from `FileSpec` to `LoadScriptFromSymFile` enum.

This is needed for https://github.com/llvm/llvm-project/pull/188722, where I intend to set `LoadScriptFromSymFile` per-module.

By default the `Platform::LocateXXX` set the value to whatever the target's current `target.load-script-from-symbol-file` is set to. In https://github.com/llvm/llvm-project/pull/188722 we'll allow overriding this per-target setting on a per-module basis.

Drive-by:
* Added logging when we fail to load a script.
---
 .../Plugins/Platform/MacOSX/PlatformDarwin.cpp     | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
index c4865c4664651..0f7475591d5a0 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
@@ -256,13 +256,13 @@ PlatformDarwin::LocateExecutableScriptingResourcesFromDSYM(
 llvm::SmallDenseMap<FileSpec, LoadScriptFromSymFile>
 PlatformDarwin::LocateExecutableScriptingResourcesForPlatform(
     Target *target, Module &module, Stream &feedback_stream) {
-  llvm::SmallDenseMap<FileSpec, LoadScriptFromSymFile> empty;
+  llvm::SmallDenseMap<FileSpec, LoadScriptFromSymFile> file_specs;
   if (!target)
-    return empty;
+    return file_specs;
 
   // For now only Python scripts supported for auto-loading.
   if (target->GetDebugger().GetScriptLanguage() != eScriptLanguagePython)
-    return empty;
+    return file_specs;
 
   // NB some extensions might be meaningful and should not be stripped -
   // "this.binary.file"
@@ -274,15 +274,15 @@ PlatformDarwin::LocateExecutableScriptingResourcesForPlatform(
   const FileSpec &module_spec = module.GetFileSpec();
 
   if (!module_spec)
-    return empty;
+    return file_specs;
 
   SymbolFile *symfile = module.GetSymbolFile();
   if (!symfile)
-    return empty;
+    return file_specs;
 
   ObjectFile *objfile = symfile->GetObjectFile();
   if (!objfile)
-    return empty;
+    return file_specs;
 
   const FileSpec &symfile_spec = objfile->GetFileSpec();
   if (symfile_spec &&
@@ -292,7 +292,7 @@ PlatformDarwin::LocateExecutableScriptingResourcesForPlatform(
     return LocateExecutableScriptingResourcesFromDSYM(
         feedback_stream, module_spec, *target, symfile_spec);
 
-  return empty;
+  return file_specs;
 }
 
 Status PlatformDarwin::ResolveSymbolFile(Target &target,

>From 3c3e0fd2c9ef745b22c3f7565a3b5bc0d76644f4 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Thu, 26 Mar 2026 09:13:03 +0000
Subject: [PATCH 2/3] [lldb] Add setting to specify (by name) which module's
 scripting resources can be auto-loaded

This is part of [this RFC](https://discourse.llvm.org/t/rfc-lldb-moving-libc-data-formatters-out-of-lldb/89591) which is about turning the libc++ data-formatters into auto-loadable Python scripts.

Eventually we want the Python data-formatters for `libc++` to be automatically loaded without requiring user opt-in (since that's how the builtin formatters have always worked and, in my opinion, we can't transition to an opt-in model if users have always had the data-formatters available). To do so we need a way to distinguish which modules we can *always* auto-load from safe-paths, and which require `target.load-script-from-symbol-file` to be set to `true`.

This patch adds a setting (`target.auto-load-modules`) that is a dictionary from module-name to a boolean indicating whether the scripts for that module can be automatically loaded.

Making this a setting also means a user can disable any auto-loading by clearing it. By default the setting is currently empty. Eventually we'll want it to contain `libc++.1=true` (and possibly other names which the `libc++` dylib can commonly have).

**AI Usage**:
* Used Claude to generate the unit-test cases and shell tests. Reviewed and cleaned them up myself.
---
 lldb/include/lldb/Target/Platform.h           |   7 +
 lldb/include/lldb/Target/Target.h             |   5 +
 lldb/source/Core/Module.cpp                   |   3 +-
 .../Platform/MacOSX/PlatformDarwin.cpp        |   5 +-
 lldb/source/Target/Platform.cpp               |  29 +++-
 lldb/source/Target/Target.cpp                 |  14 ++
 lldb/source/Target/TargetProperties.td        |   6 +
 .../UNIX/auto-load-modules-false.test         |  25 +++
 .../UNIX/auto-load-modules-multiple.test      |  38 +++++
 .../UNIX/auto-load-modules-not-in-dict.test   |  29 ++++
 .../AutoLoad/UNIX/auto-load-modules-true.test |  26 ++++
 lldb/unittests/Platform/PlatformTest.cpp      | 146 ++++++++++++++++++
 12 files changed, 327 insertions(+), 6 deletions(-)
 create mode 100644 lldb/test/Shell/Platform/AutoLoad/UNIX/auto-load-modules-false.test
 create mode 100644 lldb/test/Shell/Platform/AutoLoad/UNIX/auto-load-modules-multiple.test
 create mode 100644 lldb/test/Shell/Platform/AutoLoad/UNIX/auto-load-modules-not-in-dict.test
 create mode 100644 lldb/test/Shell/Platform/AutoLoad/UNIX/auto-load-modules-true.test

diff --git a/lldb/include/lldb/Target/Platform.h b/lldb/include/lldb/Target/Platform.h
index 6bdaf10ef0713..39c5466c95330 100644
--- a/lldb/include/lldb/Target/Platform.h
+++ b/lldb/include/lldb/Target/Platform.h
@@ -1086,6 +1086,13 @@ class Platform : public PluginInterface {
       const ScriptInterpreter::SanitizedScriptingModuleName &sanitized_name,
       const FileSpec &original_fspec, const FileSpec &fspec);
 
+  /// Returns the \c LoadScriptFromSymFile of scripting resource associated
+  /// with the specified module \c FileSpec. If the load style wasn't explicitly
+  /// set for a module, returns the target-wide default.
+  static LoadScriptFromSymFile
+  GetScriptLoadStyleForModule(const FileSpec &module_fspec,
+                              const Target &target);
+
 private:
   typedef std::function<Status(const ModuleSpec &)> ModuleResolver;
 
diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h
index 77b8f04a4b3b8..66d79ad4dd277 100644
--- a/lldb/include/lldb/Target/Target.h
+++ b/lldb/include/lldb/Target/Target.h
@@ -278,6 +278,11 @@ class TargetProperties : public Properties {
 
   bool GetDebugUtilityExpression() const;
 
+  OptionValueDictionary *GetAutoLoadScriptsForModules() const;
+
+  void SetAutoLoadScriptsForModules(llvm::StringRef module_name,
+                                    bool should_load);
+
 private:
   std::optional<bool>
   GetExperimentalPropertyValue(size_t prop_idx,
diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp
index 808c8a347e9b2..c81912fa35a43 100644
--- a/lldb/source/Core/Module.cpp
+++ b/lldb/source/Core/Module.cpp
@@ -1490,7 +1490,8 @@ To run all discovered debug scripts in this session:
           debugger.GetID());
       // clang-format on
 
-      return false;
+      // TODO: test this
+      continue;
     }
 
     LLDB_LOG(log, "Auto-loading {0}", scripting_fspec.GetPath());
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
index 0f7475591d5a0..c71a8956013d8 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
@@ -235,8 +235,9 @@ PlatformDarwin::LocateExecutableScriptingResourcesFromDSYM(
                                          orig_script_fspec, script_fspec);
 
     if (FileSystem::Instance().Exists(script_fspec)) {
-      file_specs.try_emplace(std::move(script_fspec),
-                             target.GetLoadScriptFromSymbolFile());
+      LoadScriptFromSymFile load_style =
+          Platform::GetScriptLoadStyleForModule(script_fspec, target);
+      file_specs.try_emplace(std::move(script_fspec), load_style);
       break;
     }
 
diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp
index 55eaa88b562d4..33b3805780f0e 100644
--- a/lldb/source/Target/Platform.cpp
+++ b/lldb/source/Target/Platform.cpp
@@ -24,6 +24,7 @@
 #include "lldb/Host/Host.h"
 #include "lldb/Host/HostInfo.h"
 #include "lldb/Host/OptionParser.h"
+#include "lldb/Interpreter/OptionValueDictionary.h"
 #include "lldb/Interpreter/OptionValueFileSpec.h"
 #include "lldb/Interpreter/OptionValueProperties.h"
 #include "lldb/Interpreter/Property.h"
@@ -40,6 +41,7 @@
 #include "lldb/Utility/Log.h"
 #include "lldb/Utility/Status.h"
 #include "lldb/Utility/StructuredData.h"
+#include "lldb/lldb-private-enumerations.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/FormatVariadic.h"
@@ -157,6 +159,25 @@ Status Platform::GetFileWithUUID(const FileSpec &platform_file,
   return Status();
 }
 
+LoadScriptFromSymFile
+Platform::GetScriptLoadStyleForModule(const FileSpec &module_fspec,
+                                      const Target &target) {
+  LoadScriptFromSymFile default_load_style =
+      target.GetLoadScriptFromSymbolFile();
+
+  OptionValueDictionary *names = target.GetAutoLoadScriptsForModules();
+  if (!names)
+    return default_load_style;
+
+  OptionValueSP value_sp =
+      names->GetValueForKey(module_fspec.GetFileNameStrippingExtension());
+  if (!value_sp)
+    return default_load_style;
+
+  return value_sp->GetValueAs<LoadScriptFromSymFile>().value_or(
+      default_load_style);
+}
+
 llvm::SmallDenseMap<FileSpec, LoadScriptFromSymFile>
 Platform::LocateExecutableScriptingResourcesFromSafePaths(
     Stream &feedback_stream, FileSpec module_spec, const Target &target) {
@@ -198,9 +219,11 @@ Platform::LocateExecutableScriptingResourcesFromSafePaths(
     WarnIfInvalidUnsanitizedScriptExists(feedback_stream, sanitized_name,
                                          orig_script_fspec, script_fspec);
 
-    if (FileSystem::Instance().Exists(script_fspec))
-      file_specs.try_emplace(std::move(script_fspec),
-                             target.GetLoadScriptFromSymbolFile());
+    if (FileSystem::Instance().Exists(script_fspec)) {
+      LoadScriptFromSymFile load_style =
+          Platform::GetScriptLoadStyleForModule(script_fspec, target);
+      file_specs.try_emplace(std::move(script_fspec), load_style);
+    }
 
     // If we successfully found a directory in a safe auto-load path
     // stop looking at any other paths.
diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
index 2a3832225f9b7..249657eb04a21 100644
--- a/lldb/source/Target/Target.cpp
+++ b/lldb/source/Target/Target.cpp
@@ -5278,6 +5278,20 @@ void TargetProperties::SetDebugUtilityExpression(bool debug) {
   SetPropertyAtIndex(idx, debug);
 }
 
+OptionValueDictionary *TargetProperties::GetAutoLoadScriptsForModules() const {
+  return m_collection_sp->GetPropertyAtIndexAsOptionValueDictionary(
+      ePropertyAutoLoadScriptsForModules);
+}
+
+void TargetProperties::SetAutoLoadScriptsForModules(llvm::StringRef module_name,
+                                                    bool should_load) {
+  OptionValueDictionary *dict = GetAutoLoadScriptsForModules();
+  if (!dict)
+    return;
+  dict->SetValueForKey(module_name,
+                       std::make_shared<OptionValueBoolean>(should_load));
+}
+
 // Target::TargetEventData
 
 Target::TargetEventData::TargetEventData(const lldb::TargetSP &target_sp)
diff --git a/lldb/source/Target/TargetProperties.td b/lldb/source/Target/TargetProperties.td
index 2361314d506ac..d74fcd35c690d 100644
--- a/lldb/source/Target/TargetProperties.td
+++ b/lldb/source/Target/TargetProperties.td
@@ -220,6 +220,12 @@ let Definition = "target", Path = "target" in {
   def ParallelModuleLoad: Property<"parallel-module-load", "Boolean">,
     DefaultTrue,
     Desc<"Enable loading of modules in parallel for the dynamic loader.">;
+  def AutoLoadScriptsForModules
+      : Property<"auto-load-scripts-for-modules", "Dictionary">,
+        ElementType<"Enum">,
+        EnumValues<"OptionEnumValues(g_load_script_from_sym_file_values)">,
+        Desc<"A list of module names and whether LLDB will auto-load scripting "
+             "resources for it from safe paths.">;
 }
 
 let Definition = "process_experimental", Path = "target.process.experimental" in {
diff --git a/lldb/test/Shell/Platform/AutoLoad/UNIX/auto-load-modules-false.test b/lldb/test/Shell/Platform/AutoLoad/UNIX/auto-load-modules-false.test
new file mode 100644
index 0000000000000..7154d52e8f6a2
--- /dev/null
+++ b/lldb/test/Shell/Platform/AutoLoad/UNIX/auto-load-modules-false.test
@@ -0,0 +1,25 @@
+# REQUIRES: python, asserts, !system-windows
+
+# Test that when a module is listed in target.auto-load-scripts-for-modules with 'false',
+# its scripting resources are NOT loaded even when target.load-script-from-symbol-file
+# is true.
+
+# RUN: split-file %s %t
+# RUN: %clang_host %t/main.c -o %t/TestModule.out
+# RUN: mkdir -p %t/safe-path/TestModule
+
+# RUN: cp %t/script.py %t/safe-path/TestModule/TestModule.py
+# RUN: %lldb -b \
+# RUN:   -o 'settings set target.load-script-from-symbol-file true' \
+# RUN:   -o 'settings append testing.safe-auto-load-paths %t/safe-path' \
+# RUN:   -o 'settings set target.auto-load-scripts-for-modules TestModule=false' \
+# RUN:   -o 'target create %t/TestModule.out' 2>&1 \
+# RUN:   | FileCheck %s --implicit-check-not=AUTOLOAD_SUCCESS --implicit-check-not=warning
+
+#--- main.c
+int main() { return 0; }
+
+#--- script.py
+import sys
+def __lldb_init_module(debugger, internal_dict):
+    print("AUTOLOAD_SUCCESS", file=sys.stderr)
diff --git a/lldb/test/Shell/Platform/AutoLoad/UNIX/auto-load-modules-multiple.test b/lldb/test/Shell/Platform/AutoLoad/UNIX/auto-load-modules-multiple.test
new file mode 100644
index 0000000000000..d26c574ff2d5c
--- /dev/null
+++ b/lldb/test/Shell/Platform/AutoLoad/UNIX/auto-load-modules-multiple.test
@@ -0,0 +1,38 @@
+# REQUIRES: python, asserts, !system-windows
+
+# Test that multiple modules listed in target.auto-load-scripts-for-modules are all
+# auto-loaded.
+
+# RUN: split-file %s %t
+# RUN: %clang_host -shared %t/lib.c -o %t/libFoo.dylib
+# RUN: %clang_host %t/main.c -o %t/TestModule.out %t/libFoo.dylib
+# RUN: mkdir -p %t/safe-path/TestModule
+# RUN: mkdir -p %t/safe-path/libFoo
+
+# RUN: cp %t/main_script.py %t/safe-path/TestModule/TestModule.py
+# RUN: cp %t/lib_script.py %t/safe-path/libFoo/libFoo.py
+# RUN: %lldb -b \
+# RUN:   -o 'settings set target.load-script-from-symbol-file false' \
+# RUN:   -o 'settings append testing.safe-auto-load-paths %t/safe-path' \
+# RUN:   -o 'settings set target.auto-load-scripts-for-modules TestModule=true libFoo=true' \
+# RUN:   -o 'target create %t/TestModule.out' 2>&1 | FileCheck %s
+
+# CHECK-DAG: MAIN_AUTOLOAD_SUCCESS
+# CHECK-DAG: LIB_AUTOLOAD_SUCCESS
+
+#--- main.c
+extern int foo(void);
+int main() { return foo(); }
+
+#--- lib.c
+int foo(void) { return 0; }
+
+#--- main_script.py
+import sys
+def __lldb_init_module(debugger, internal_dict):
+    print("MAIN_AUTOLOAD_SUCCESS", file=sys.stderr)
+
+#--- lib_script.py
+import sys
+def __lldb_init_module(debugger, internal_dict):
+    print("LIB_AUTOLOAD_SUCCESS", file=sys.stderr)
diff --git a/lldb/test/Shell/Platform/AutoLoad/UNIX/auto-load-modules-not-in-dict.test b/lldb/test/Shell/Platform/AutoLoad/UNIX/auto-load-modules-not-in-dict.test
new file mode 100644
index 0000000000000..3213ae61558dd
--- /dev/null
+++ b/lldb/test/Shell/Platform/AutoLoad/UNIX/auto-load-modules-not-in-dict.test
@@ -0,0 +1,29 @@
+# REQUIRES: python, asserts, !system-windows
+
+# Test that when a module is NOT in target.auto-load-scripts-for-modules, the existing
+# target.load-script-from-symbol-file setting controls whether scripts load.
+# With load-script-from-symbol-file=true and no dictionary entry, scripts
+# should still load normally.
+
+# RUN: split-file %s %t
+# RUN: %clang_host %t/main.c -o %t/TestModule.out
+# RUN: mkdir -p %t/safe-path/TestModule
+
+# RUN: cp %t/script.py %t/safe-path/TestModule/TestModule.py
+
+## A different module is in the dictionary; TestModule is not.
+# RUN: %lldb -b \
+# RUN:   -o 'settings set target.load-script-from-symbol-file warn' \
+# RUN:   -o 'settings append testing.safe-auto-load-paths %t/safe-path' \
+# RUN:   -o 'settings set target.auto-load-scripts-for-modules SomeOtherModule=true' \
+# RUN:   -o 'target create %t/TestModule.out' 2>&1 | FileCheck %s --implicit-check-not=AUTOLOAD_SUCCESS
+
+# CHECK: warning: 'TestModule' contains a debug script. To run this script in this debug session
+
+#--- main.c
+int main() { return 0; }
+
+#--- script.py
+import sys
+def __lldb_init_module(debugger, internal_dict):
+    print("AUTOLOAD_SUCCESS", file=sys.stderr)
diff --git a/lldb/test/Shell/Platform/AutoLoad/UNIX/auto-load-modules-true.test b/lldb/test/Shell/Platform/AutoLoad/UNIX/auto-load-modules-true.test
new file mode 100644
index 0000000000000..f1f2932cac55b
--- /dev/null
+++ b/lldb/test/Shell/Platform/AutoLoad/UNIX/auto-load-modules-true.test
@@ -0,0 +1,26 @@
+# REQUIRES: python, asserts, !system-windows
+
+# Test that when a module is listed in target.auto-load-scripts-for-modules with 'true',
+# its scripting resources are loaded even when target.load-script-from-symbol-file
+# is false.
+
+# RUN: split-file %s %t
+# RUN: %clang_host %t/main.c -o %t/TestModule.out
+# RUN: mkdir -p %t/safe-path/TestModule
+
+# RUN: cp %t/script.py %t/safe-path/TestModule/TestModule.py
+# RUN: %lldb -b \
+# RUN:   -o 'settings set target.load-script-from-symbol-file false' \
+# RUN:   -o 'settings append testing.safe-auto-load-paths %t/safe-path' \
+# RUN:   -o 'settings set target.auto-load-scripts-for-modules TestModule=true' \
+# RUN:   -o 'target create %t/TestModule.out' 2>&1 | FileCheck %s
+
+# CHECK: AUTOLOAD_SUCCESS
+
+#--- main.c
+int main() { return 0; }
+
+#--- script.py
+import sys
+def __lldb_init_module(debugger, internal_dict):
+    print("AUTOLOAD_SUCCESS", file=sys.stderr)
diff --git a/lldb/unittests/Platform/PlatformTest.cpp b/lldb/unittests/Platform/PlatformTest.cpp
index 1769282459eee..c0b7cf1678293 100644
--- a/lldb/unittests/Platform/PlatformTest.cpp
+++ b/lldb/unittests/Platform/PlatformTest.cpp
@@ -672,4 +672,150 @@ TEST_F(PlatformLocateSafePathTest,
   EXPECT_EQ(file_specs.size(), 1u);
   EXPECT_TRUE(ss.GetString().empty());
 }
+
+TEST_F(PlatformLocateSafePathTest,
+       LocateScriptingResourcesFromSafePaths_AutoLoadModule_True) {
+  // When a module is in target.auto-load-scripts-for-modules with value 'true',
+  // its script should be returned in the auto-load list.
+
+  TestingProperties::GetGlobalTestingProperties().AppendSafeAutoLoadPaths(
+      FileSpec(m_tmp_root_dir));
+
+  FileSpec module_fspec(CreateFile("TestModule.o", m_tmp_root_dir));
+  ASSERT_TRUE(module_fspec);
+
+  llvm::SmallString<128> module_dir(m_tmp_root_dir);
+  llvm::sys::path::append(module_dir, "TestModule");
+  ASSERT_FALSE(llvm::sys::fs::create_directory(module_dir));
+
+  CreateFile("TestModule.py", module_dir);
+
+  m_target_sp->SetAutoLoadScriptsForModules("TestModule", true);
+
+  StreamString ss;
+  auto file_specs = Platform::LocateExecutableScriptingResourcesFromSafePaths(
+      ss, module_fspec, *m_target_sp);
+
+  EXPECT_EQ(file_specs.size(), 1u);
+
+  auto [fspec, load_style] = *file_specs.begin();
+
+  EXPECT_EQ(fspec.GetFilename(), "TestModule.py");
+  EXPECT_EQ(load_style, m_target_sp->GetLoadScriptFromSymbolFile());
+}
+
+TEST_F(PlatformLocateSafePathTest,
+       LocateScriptingResourcesFromSafePaths_AutoLoadModule_False) {
+  // When a module is in target.auto-load-scripts-for-modules with value
+  // 'false', its script should not appear in either list.
+
+  TestingProperties::GetGlobalTestingProperties().AppendSafeAutoLoadPaths(
+      FileSpec(m_tmp_root_dir));
+
+  FileSpec module_fspec(CreateFile("TestModule.o", m_tmp_root_dir));
+  ASSERT_TRUE(module_fspec);
+
+  llvm::SmallString<128> module_dir(m_tmp_root_dir);
+  llvm::sys::path::append(module_dir, "TestModule");
+  ASSERT_FALSE(llvm::sys::fs::create_directory(module_dir));
+
+  CreateFile("TestModule.py", module_dir);
+
+  m_target_sp->SetAutoLoadScriptsForModules("TestModule", false);
+
+  StreamString ss;
+  auto file_specs = Platform::LocateExecutableScriptingResourcesFromSafePaths(
+      ss, module_fspec, *m_target_sp);
+
+  EXPECT_EQ(file_specs.size(), 0);
+}
+
+TEST_F(PlatformLocateSafePathTest,
+       LocateScriptingResourcesFromSafePaths_AutoLoadModule_NotInDict) {
+  // When a module is NOT in the dictionary, its script should end up
+  // in the non-auto-load list (the existing behavior).
+
+  TestingProperties::GetGlobalTestingProperties().AppendSafeAutoLoadPaths(
+      FileSpec(m_tmp_root_dir));
+
+  FileSpec module_fspec(CreateFile("TestModule.o", m_tmp_root_dir));
+  ASSERT_TRUE(module_fspec);
+
+  llvm::SmallString<128> module_dir(m_tmp_root_dir);
+  llvm::sys::path::append(module_dir, "TestModule");
+  ASSERT_FALSE(llvm::sys::fs::create_directory(module_dir));
+
+  CreateFile("TestModule.py", module_dir);
+
+  // Set a different module in the dictionary; TestModule is not present.
+  m_target_sp->SetAutoLoadScriptsForModules("SomeOtherModule", true);
+
+  StreamString ss;
+  auto file_specs = Platform::LocateExecutableScriptingResourcesFromSafePaths(
+      ss, module_fspec, *m_target_sp);
+
+  EXPECT_EQ(file_specs.size(), 1u);
+
+  auto [fspec, load_style] = *file_specs.begin();
+
+  EXPECT_EQ(fspec.GetFilename(), "TestModule.py");
+  EXPECT_EQ(load_style, m_target_sp->GetLoadScriptFromSymbolFile());
+}
+
+TEST_F(PlatformLocateSafePathTest,
+       LocateScriptingResourcesFromSafePaths_AutoLoadModule_Multiple) {
+  // When multiple modules are in target.auto-load-scripts-for-modules with
+  // value 'true', each module's script should be returned in its respective
+  // auto-load list.
+
+  TestingProperties::GetGlobalTestingProperties().AppendSafeAutoLoadPaths(
+      FileSpec(m_tmp_root_dir));
+
+  // Set up ModuleA.
+  FileSpec module_a_fspec(CreateFile("ModuleA.o", m_tmp_root_dir));
+  ASSERT_TRUE(module_a_fspec);
+
+  llvm::SmallString<128> module_a_dir(m_tmp_root_dir);
+  llvm::sys::path::append(module_a_dir, "ModuleA");
+  ASSERT_FALSE(llvm::sys::fs::create_directory(module_a_dir));
+  CreateFile("ModuleA.py", module_a_dir);
+
+  // Set up ModuleB.
+  FileSpec module_b_fspec(CreateFile("ModuleB.o", m_tmp_root_dir));
+  ASSERT_TRUE(module_b_fspec);
+
+  llvm::SmallString<128> module_b_dir(m_tmp_root_dir);
+  llvm::sys::path::append(module_b_dir, "ModuleB");
+  ASSERT_FALSE(llvm::sys::fs::create_directory(module_b_dir));
+  CreateFile("ModuleB.py", module_b_dir);
+
+  m_target_sp->SetAutoLoadScriptsForModules("ModuleA", true);
+  m_target_sp->SetAutoLoadScriptsForModules("ModuleB", true);
+
+  {
+    StreamString ss;
+    auto file_specs = Platform::LocateExecutableScriptingResourcesFromSafePaths(
+        ss, module_a_fspec, *m_target_sp);
+
+    EXPECT_EQ(file_specs.size(), 1u);
+
+    auto [fspec, load_style] = *file_specs.begin();
+
+    EXPECT_EQ(fspec.GetFilename(), "ModuleA.py");
+    EXPECT_EQ(load_style, m_target_sp->GetLoadScriptFromSymbolFile());
+  }
+
+  {
+    StreamString ss;
+    auto file_specs = Platform::LocateExecutableScriptingResourcesFromSafePaths(
+        ss, module_b_fspec, *m_target_sp);
+
+    EXPECT_EQ(file_specs.size(), 1u);
+
+    auto [fspec, load_style] = *file_specs.begin();
+
+    EXPECT_EQ(fspec.GetFilename(), "ModuleB.py");
+    EXPECT_EQ(load_style, m_target_sp->GetLoadScriptFromSymbolFile());
+  }
+}
 #endif // NDEBUG

>From c6ec21667bfe787839794443a911a808d9985303 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 1 Apr 2026 08:08:37 +0100
Subject: [PATCH 3/3] fixup! revert mismerge

---
 .../Plugins/Platform/MacOSX/PlatformDarwin.cpp     | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
index c71a8956013d8..200bf7c222935 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
@@ -257,13 +257,13 @@ PlatformDarwin::LocateExecutableScriptingResourcesFromDSYM(
 llvm::SmallDenseMap<FileSpec, LoadScriptFromSymFile>
 PlatformDarwin::LocateExecutableScriptingResourcesForPlatform(
     Target *target, Module &module, Stream &feedback_stream) {
-  llvm::SmallDenseMap<FileSpec, LoadScriptFromSymFile> file_specs;
+  llvm::SmallDenseMap<FileSpec, LoadScriptFromSymFile> empty;
   if (!target)
-    return file_specs;
+    return empty;
 
   // For now only Python scripts supported for auto-loading.
   if (target->GetDebugger().GetScriptLanguage() != eScriptLanguagePython)
-    return file_specs;
+    return empty;
 
   // NB some extensions might be meaningful and should not be stripped -
   // "this.binary.file"
@@ -275,15 +275,15 @@ PlatformDarwin::LocateExecutableScriptingResourcesForPlatform(
   const FileSpec &module_spec = module.GetFileSpec();
 
   if (!module_spec)
-    return file_specs;
+    return empty;
 
   SymbolFile *symfile = module.GetSymbolFile();
   if (!symfile)
-    return file_specs;
+    return empty;
 
   ObjectFile *objfile = symfile->GetObjectFile();
   if (!objfile)
-    return file_specs;
+    return empty;
 
   const FileSpec &symfile_spec = objfile->GetFileSpec();
   if (symfile_spec &&
@@ -293,7 +293,7 @@ PlatformDarwin::LocateExecutableScriptingResourcesForPlatform(
     return LocateExecutableScriptingResourcesFromDSYM(
         feedback_stream, module_spec, *target, symfile_spec);
 
-  return file_specs;
+  return empty;
 }
 
 Status PlatformDarwin::ResolveSymbolFile(Target &target,



More information about the lldb-commits mailing list