[Lldb-commits] [lldb] [lldb] Skip symbol-script discovery when autoload is disabled (PR #232691)

Karim Alweheshy via lldb-commits lldb-commits at lists.llvm.org
Fri Oct 16 04:22:14 PDT 2026


https://github.com/karim-alweheshy created https://github.com/llvm/llvm-project/pull/232691

Disabling symbol-script autoload still discovers scripting resources and creates a symbol vendor. Check the existing effective per-module policy before discovery, and defer symbol-file trust checks until a trusted/warn resource needs them.

Explicit module overrides retain priority over the target-wide default. Source lookup can still load debug information after skipped script discovery; enabled, trusted and warn policies retain their behavior.

History checked: [D132803](https://reviews.llvm.org/D132803) documents the cost of symbol-script discovery. This preserves the per-module policy and locator-map contracts introduced by #188722 and #189696. It leaves the prompt and warning behavior discussed in open #187027 and #189943 unchanged.

Validation: Built current-main LLDB with this change. All four dSYM-module policy tests and the ad-hoc signing test pass; the trusted signing test skips because the required lldb_codesign certificate is absent. All 23 Platform/AutoLoad shell tests pass. As a negative control, the unchanged current-main client fails both new disabled-policy laziness checks and passes the two enabled-autoload cases. Repository-pinned darker formatting preserves the test AST.

Assisted-by: OpenAI Codex


>From 46539c614ff176fd207a0799587b06832fc9235b Mon Sep 17 00:00:00 2001
From: Karim Alweheshy <karim.alweheshy at reddit.com>
Date: Fri, 16 Oct 2026 11:12:18 +0200
Subject: [PATCH] [lldb] Skip symbol-script discovery when autoload is disabled

Check the effective per-module load policy before locating scripting resources. Query symbol-file trust only for resources whose policy needs it, preserving explicit module overrides and existing warnings.

Assisted-by: OpenAI Codex
---
 lldb/include/lldb/Target/Platform.h           | 15 ++---
 lldb/source/Core/ModuleList.cpp               | 17 ++++--
 .../macosx/dsym_modules/TestdSYMModuleInit.py | 57 +++++++++++++++++++
 3 files changed, 77 insertions(+), 12 deletions(-)

diff --git a/lldb/include/lldb/Target/Platform.h b/lldb/include/lldb/Target/Platform.h
index 4fd8c287104cae..257868edef3964 100644
--- a/lldb/include/lldb/Target/Platform.h
+++ b/lldb/include/lldb/Target/Platform.h
@@ -273,6 +273,14 @@ class Platform : public PluginInterface {
   virtual Status GetFileWithUUID(const FileSpec &platform_file,
                                  const UUID *uuid_ptr, FileSpec &local_file);
 
+  /// Return the effective scripting policy for the specified module, using
+  /// its explicit override or the target-wide default. This query does not
+  /// locate symbol files or scripting resources, so callers can honor a
+  /// disabled policy before discovering resources.
+  static LoadScriptFromSymFile
+  GetScriptLoadStyleForModule(const FileSpec &module_fspec,
+                              const Target &target);
+
   /// Locate the scripting resource given a module specification.
   ///
   /// Returns a map from a located script's \c FileSpec to the
@@ -1125,13 +1133,6 @@ 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/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp
index 9f5614538a9874..e6afa6e5a60500 100644
--- a/lldb/source/Core/ModuleList.cpp
+++ b/lldb/source/Core/ModuleList.cpp
@@ -1378,6 +1378,12 @@ bool ModuleList::LoadScriptingResourceInTargetForModule(Module &module,
   if (script_language == eScriptLanguageNone)
     return true;
 
+  // Discovering scripts can create the module's symbol vendor. Honor the
+  // effective policy before doing that work, including per-module overrides.
+  if (Platform::GetScriptLoadStyleForModule(module.GetFileSpec(), target) ==
+      eLoadScriptFromSymFileFalse)
+    return true;
+
   ScriptInterpreter *script_interpreter = debugger.GetScriptInterpreter();
   if (!script_interpreter) {
     error = Status::FromErrorString("invalid ScriptInterpreter");
@@ -1398,7 +1404,7 @@ bool ModuleList::LoadScriptingResourceInTargetForModule(Module &module,
   if (!feedback_stream.Empty())
     debugger.ReportWarning(feedback_stream.GetString().str(), debugger.GetID());
 
-  const bool trusted = platform_sp->IsSymbolFileTrusted(module);
+  std::optional<bool> trusted;
 
   for (const auto &[scripting_fspec, load_style] : file_specs) {
     if (load_style == eLoadScriptFromSymFileFalse)
@@ -1413,10 +1419,11 @@ bool ModuleList::LoadScriptingResourceInTargetForModule(Module &module,
     case eLoadScriptFromSymFileTrue:
       break;
     case eLoadScriptFromSymFileTrusted:
-      if (trusted)
-        break;
-      LLVM_FALLTHROUGH;
     case eLoadScriptFromSymFileWarn:
+      if (!trusted.has_value())
+        trusted = platform_sp->IsSymbolFileTrusted(module);
+      if (load_style == eLoadScriptFromSymFileTrusted && *trusted)
+        break;
       debugger.ReportWarning(
           llvm::formatv(
               // clang-format off
@@ -1430,7 +1437,7 @@ To run all discovered debug scripts in this session:
 )",
               // clang-format on
               module.GetFileSpec().GetFileNameStrippingExtension(),
-              trusted ? "a trusted" : "an untrusted",
+              *trusted ? "a trusted" : "an untrusted",
               scripting_fspec.GetPath()),
           debugger.GetID());
 
diff --git a/lldb/test/API/macosx/dsym_modules/TestdSYMModuleInit.py b/lldb/test/API/macosx/dsym_modules/TestdSYMModuleInit.py
index c3ced18dcf049b..19024fad8f0f8c 100644
--- a/lldb/test/API/macosx/dsym_modules/TestdSYMModuleInit.py
+++ b/lldb/test/API/macosx/dsym_modules/TestdSYMModuleInit.py
@@ -3,6 +3,7 @@
 init in debugger and the init in target routines.
 """
 
+import json
 import os, shutil
 
 import lldb
@@ -35,6 +36,62 @@ def test_add_module(self):
         target_2 = self.createTestTarget(file_path=executable_2)
         self.check_answers(executable_2, ["2", "2", "has_dsym_2"])
 
+    @no_debug_info_test
+    def test_disabled_autoload_keeps_symbols_lazy(self):
+        self.check_autoload_policy("false")
+
+    @no_debug_info_test
+    def test_disabled_module_override_keeps_symbols_lazy(self):
+        self.check_autoload_policy("true", "false")
+
+    @no_debug_info_test
+    def test_enabled_module_override_loads_script(self):
+        self.check_autoload_policy("false", "true")
+
+    def check_autoload_policy(self, default_policy, module_policy=None):
+        self.py_name = "has_dsym.py"
+        name = f"has_dsym_1_{default_policy}_{module_policy}"
+        executable = self.build_dsym(name)
+
+        self.runCmd("settings set target.preload-symbols false")
+        self.runCmd(
+            f"settings set target.load-script-from-symbol-file {default_policy}"
+        )
+        if module_policy is not None:
+            self.runCmd(
+                "settings set target.auto-load-scripts-for-modules "
+                f"{name}={module_policy}"
+            )
+        self.interp = self.dbg.GetCommandInterpreter()
+        target = self.createTestTarget(
+            file_path=executable, load_dependent_modules=False
+        )
+
+        if module_policy == "true":
+            self.check_answers(executable, ["1", "1", name])
+            return
+
+        # GetStatistics does not create the symbol file. Inspecting symbols
+        # through SBModule would itself defeat the laziness being tested.
+        stream = lldb.SBStream()
+        target.GetStatistics().GetAsJSON(stream)
+        stats = json.loads(stream.GetData())
+        module = next(m for m in stats["modules"] if m["path"] == executable)
+        self.assertNotIn("symbolFilePath", module)
+        self.assertEqual(module["debugInfoByteSize"], 0)
+
+        # Disabling script autoload must not disable subsequent source lookup.
+        breakpoint = target.BreakpointCreateByLocation(
+            "main.c", line_number("main.c", "Set a breakpoint here")
+        )
+        self.assertEqual(breakpoint.GetNumLocations(), 1)
+        stream = lldb.SBStream()
+        target.GetStatistics().GetAsJSON(stream)
+        stats = json.loads(stream.GetData())
+        module = next(m for m in stats["modules"] if m["path"] == executable)
+        self.assertIn("symbolFilePath", module)
+        self.assertGreater(module["debugInfoByteSize"], 0)
+
     def check_answers(self, name, answers):
         result = lldb.SBCommandReturnObject()
         self.interp.HandleCommand("report_command", result)



More information about the lldb-commits mailing list