[Lldb-commits] [lldb] [lldb][Module] Make eLoadScriptFromSymFileWarn behave as a "dry-run" (PR #189943)
Michael Buch via lldb-commits
lldb-commits at lists.llvm.org
Sat Apr 4 00:13:55 PDT 2026
https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/189943
>From c52bc70b6d2d0bf60b6df46ad51efe9fe335b60e Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 1 Apr 2026 09:32:13 +0100
Subject: [PATCH] [lldb][Module] Make eLoadScriptFromSymFileWarn behave as a
"dry-run"
This patch is a follow-up to https://github.com/llvm/llvm-project/pull/189444#issuecomment-4165226875
We want `eLoadScriptFromSymFileWarn` to be a "dry-run" mode which warns but all possible module loads but doesn't actually load them. To do so, this patch removes the short-circuit in the current module loading loop.
The previous warning is verbose and contains instructions that don't need to be printed for every module. So this patch ensures LLDB only prints the verbose warning once per debugger-session. The script paths that would have been loaded are accumulated and printed at the end of the function. We `return false` to preserve the previous semantics of `LoadScriptingResourceInTarget`.
Eventually we want the warning to also indicate whether the module in consideration is a safe/trusted module or not but I wanted to keep that for a separate PR.
---
lldb/include/lldb/Core/ModuleList.h | 6 +-
lldb/source/Core/ModuleList.cpp | 62 ++++++++++++-------
lldb/source/Target/Target.cpp | 3 +
.../dsym-python-script-name-warnings.test | 2 +-
.../AutoLoad/Darwin/dsym-python-script.test | 4 +-
.../Darwin/dsym-warn-batch-dependents.test | 42 +++++++++++++
.../Darwin/dsym-warn-multiple-modules.test | 54 ++++++++++++++++
.../UNIX/safe-path-warn-batch-dependents.test | 44 +++++++++++++
.../UNIX/safe-path-warn-multiple-modules.test | 55 ++++++++++++++++
9 files changed, 245 insertions(+), 27 deletions(-)
create mode 100644 lldb/test/Shell/Platform/AutoLoad/Darwin/dsym-warn-batch-dependents.test
create mode 100644 lldb/test/Shell/Platform/AutoLoad/Darwin/dsym-warn-multiple-modules.test
create mode 100644 lldb/test/Shell/Platform/AutoLoad/UNIX/safe-path-warn-batch-dependents.test
create mode 100644 lldb/test/Shell/Platform/AutoLoad/UNIX/safe-path-warn-multiple-modules.test
diff --git a/lldb/include/lldb/Core/ModuleList.h b/lldb/include/lldb/Core/ModuleList.h
index bea88a6cf1f51..279a6baf30c99 100644
--- a/lldb/include/lldb/Core/ModuleList.h
+++ b/lldb/include/lldb/Core/ModuleList.h
@@ -560,9 +560,9 @@ class ModuleList {
static constexpr long kUseCountModuleListOrphaned = 1;
private:
- static bool LoadScriptingResourceInTargetForModule(Module &module,
- Target &target,
- Status &error);
+ static bool LoadScriptingResourceInTargetForModule(
+ Module &module, Target &target, Status &error,
+ std::vector<std::string> &warned_script_paths);
public:
typedef LockingAdaptedIterable<std::recursive_mutex, collection>
diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp
index fae42cb90a7fb..05034bfc4fe5a 100644
--- a/lldb/source/Core/ModuleList.cpp
+++ b/lldb/source/Core/ModuleList.cpp
@@ -36,8 +36,10 @@
#endif
#include "clang/Driver/Driver.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/Threading.h"
#include "llvm/Support/raw_ostream.h"
@@ -1330,6 +1332,33 @@ bool ModuleList::RemoveSharedModuleIfOrphaned(const ModuleWP module_wp) {
return GetSharedModuleList().RemoveIfOrphaned(module_wp);
}
+static void
+ReportScriptLoading(Debugger &debugger,
+ llvm::ArrayRef<std::string> warned_script_paths) {
+ if (warned_script_paths.empty())
+ return;
+
+ static std::once_flag s_warn_once;
+
+ // clang-format off
+ debugger.ReportWarning(
+R"(Found executable debug scripts. To run a script in this debug session:
+
+ command script import "/path/to/script.py"
+
+To run all discovered debug scripts in this session:
+
+ settings set target.load-script-from-symbol-file true
+)", debugger.GetID(), &s_warn_once);
+
+ debugger.ReportWarning(llvm::formatv(
+R"(The following debug scripts were detected but not loaded:
+
+ - {0}
+)", llvm::join(warned_script_paths, "\n - ")), debugger.GetID());
+ // clang-format on
+}
+
static bool LoadScriptingModule(const FileSpec &scripting_fspec,
ScriptInterpreter &script_interpreter,
Target &target, Status &error) {
@@ -1343,9 +1372,9 @@ static bool LoadScriptingModule(const FileSpec &scripting_fspec,
/*module_sp*/ nullptr, /*extra_path*/ {}, target.shared_from_this());
}
-bool ModuleList::LoadScriptingResourceInTargetForModule(Module &module,
- Target &target,
- Status &error) {
+bool ModuleList::LoadScriptingResourceInTargetForModule(
+ Module &module, Target &target, Status &error,
+ std::vector<std::string> &warned_script_paths) {
Log *log = GetLog(LLDBLog::Modules);
Debugger &debugger = target.GetDebugger();
@@ -1387,23 +1416,8 @@ bool ModuleList::LoadScriptingResourceInTargetForModule(Module &module,
continue;
break;
case eLoadScriptFromSymFileWarn:
- debugger.ReportWarning(
- llvm::formatv(
- // clang-format off
-R"('{0}' contains a debug script. To run this script in this debug session:
-
- command script import "{1}"
-
-To run all discovered debug scripts in this session:
-
- settings set target.load-script-from-symbol-file true
-)",
- // clang-format on
- module.GetFileSpec().GetFileNameStrippingExtension(),
- scripting_fspec.GetPath()),
- debugger.GetID());
-
- return false;
+ warned_script_paths.emplace_back(scripting_fspec.GetPath());
+ continue;
}
LLDB_LOG(log, "Auto-loading {0}", scripting_fspec.GetPath());
@@ -1431,10 +1445,13 @@ bool ModuleList::LoadScriptingResourcesInTarget(Target *target,
const ModuleList tmp_module_list(*this);
m_modules_mutex.unlock();
+ std::vector<std::string> warned_script_paths;
+
for (auto module : tmp_module_list.ModulesNoLocking()) {
if (module) {
Status error;
- if (!LoadScriptingResourceInTargetForModule(*module, *target, error)) {
+ if (!LoadScriptingResourceInTargetForModule(*module, *target, error,
+ warned_script_paths)) {
if (error.Fail() && error.AsCString()) {
error = Status::FromErrorStringWithFormat(
"unable to load scripting data for "
@@ -1450,6 +1467,9 @@ bool ModuleList::LoadScriptingResourcesInTarget(Target *target,
}
}
}
+
+ ReportScriptLoading(target->GetDebugger(), warned_script_paths);
+
return errors.empty();
}
diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
index 0168c7d686e37..ad2ad14684ca2 100644
--- a/lldb/source/Target/Target.cpp
+++ b/lldb/source/Target/Target.cpp
@@ -70,7 +70,9 @@
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/ErrorExtras.h"
+#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/ThreadPool.h"
#include <memory>
@@ -1854,6 +1856,7 @@ void Target::ModulesDidLoad(ModuleList &module_list) {
LoadTypeSummariesForModule(module_sp);
LoadFormattersForModule(module_sp);
}
+
m_breakpoint_list.UpdateBreakpoints(module_list, true, false);
m_internal_breakpoint_list.UpdateBreakpoints(module_list, true, false);
if (m_process_sp) {
diff --git a/lldb/test/Shell/Platform/AutoLoad/Darwin/dsym-python-script-name-warnings.test b/lldb/test/Shell/Platform/AutoLoad/Darwin/dsym-python-script-name-warnings.test
index 9c84045d75932..cb494c4436a4f 100644
--- a/lldb/test/Shell/Platform/AutoLoad/Darwin/dsym-python-script-name-warnings.test
+++ b/lldb/test/Shell/Platform/AutoLoad/Darwin/dsym-python-script-name-warnings.test
@@ -33,7 +33,7 @@
## Also confirm that the warning message about auto-loading scripts is printed afterwards.
-# CHECK-REMOVE: warning: 'Test-Module2' contains a debug script. To run this script in this
+# CHECK-REMOVE: warning: Found executable debug scripts. To run a script in this debug session
#--- main.c
int main() { return 0; }
diff --git a/lldb/test/Shell/Platform/AutoLoad/Darwin/dsym-python-script.test b/lldb/test/Shell/Platform/AutoLoad/Darwin/dsym-python-script.test
index d19199f7e55be..fc28d4737422e 100644
--- a/lldb/test/Shell/Platform/AutoLoad/Darwin/dsym-python-script.test
+++ b/lldb/test/Shell/Platform/AutoLoad/Darwin/dsym-python-script.test
@@ -23,9 +23,9 @@
# RUN: -o 'target create %t/TestModule.out' 2>&1 \
# RUN: | FileCheck %s --implicit-check-not=warning --check-prefix=CHECK-LOADED
-# CHECK-WARN: warning: 'TestModule' contains a debug script. To run this script in this debug session:
+# CHECK-WARN: warning: Found executable debug scripts. To run a script in this debug session:
# CHECK-WARN-EMPTY:
-# CHECK-WARN-NEXT:{{^}} command script import "{{.*}}/TestModule.out.dSYM/Contents/Resources/Python/TestModule.py"
+# CHECK-WARN-NEXT:{{^}} command script import "/path/to/script.py"
# CHECK-WARN-EMPTY:
# CHECK-WARN-NEXT: To run all discovered debug scripts in this session:
# CHECK-WARN-EMPTY:
diff --git a/lldb/test/Shell/Platform/AutoLoad/Darwin/dsym-warn-batch-dependents.test b/lldb/test/Shell/Platform/AutoLoad/Darwin/dsym-warn-batch-dependents.test
new file mode 100644
index 0000000000000..2e202dc1fb008
--- /dev/null
+++ b/lldb/test/Shell/Platform/AutoLoad/Darwin/dsym-warn-batch-dependents.test
@@ -0,0 +1,42 @@
+# REQUIRES: python, system-darwin
+#
+# Test that when load-script-from-symbol-file is set to 'warn' and multiple
+# dependent modules with dSYM scripts are loaded in a single batch (via
+# target create), LLDB emits a single warning listing all detected scripts.
+
+# RUN: split-file %s %t
+# RUN: %clang_host -g -shared %t/lib.c -o %t/libTestLib1.dylib
+# RUN: %clang_host -g -shared %t/lib.c -o %t/libTestLib2.dylib
+# RUN: %clang_host -g %t/main.c -o %t/main.out %t/libTestLib1.dylib %t/libTestLib2.dylib
+# RUN: mkdir -p %t/libTestLib1.dylib.dSYM/Contents/Resources/Python
+# RUN: mkdir -p %t/libTestLib2.dylib.dSYM/Contents/Resources/Python
+# RUN: cp %t/dsym_script1.py %t/libTestLib1.dylib.dSYM/Contents/Resources/Python/libTestLib1.py
+# RUN: cp %t/dsym_script2.py %t/libTestLib2.dylib.dSYM/Contents/Resources/Python/libTestLib2.py
+# RUN: %lldb -b \
+# RUN: -o 'settings set target.load-script-from-symbol-file warn' \
+# RUN: -o 'target create %t/main.out' 2>&1 \
+# RUN: | FileCheck %s --strict-whitespace \
+# RUN: --implicit-check-not=DSYM_SCRIPT1 --implicit-check-not=DSYM_SCRIPT2
+
+# Both dependent libraries should appear in a single warning.
+# CHECK: warning: {{.*}}The following debug scripts were detected but not loaded:
+# CHECK-EMPTY:
+# CHECK-DAG:{{^}} - {{.*}}/libTestLib1.dylib.dSYM/Contents/Resources/Python/libTestLib1.py
+# CHECK-DAG:{{^}} - {{.*}}/libTestLib2.dylib.dSYM/Contents/Resources/Python/libTestLib2.py
+
+#--- main.c
+extern int lib_func(void);
+int main() { return lib_func(); }
+
+#--- lib.c
+int lib_func(void) { return 0; }
+
+#--- dsym_script1.py
+import sys
+def __lldb_init_module(debugger, internal_dict):
+ print("DSYM_SCRIPT1", file=sys.stderr)
+
+#--- dsym_script2.py
+import sys
+def __lldb_init_module(debugger, internal_dict):
+ print("DSYM_SCRIPT2", file=sys.stderr)
diff --git a/lldb/test/Shell/Platform/AutoLoad/Darwin/dsym-warn-multiple-modules.test b/lldb/test/Shell/Platform/AutoLoad/Darwin/dsym-warn-multiple-modules.test
new file mode 100644
index 0000000000000..40a284dbea393
--- /dev/null
+++ b/lldb/test/Shell/Platform/AutoLoad/Darwin/dsym-warn-multiple-modules.test
@@ -0,0 +1,54 @@
+# REQUIRES: python, system-darwin
+#
+# Test that when load-script-from-symbol-file is set to 'warn', LLDB emits a
+# warning for each dSYM script without executing them. Verify that warnings
+# are emitted for all modules, not just the first.
+
+# RUN: split-file %s %t
+# RUN: %clang_host -g %t/main.c -o %t/TestModule.out
+# RUN: %clang_host -g %t/main.c -o %t/TestModule2.out
+# RUN: %clang_host -g %t/main.c -o %t/TestModule3.out
+# RUN: mkdir -p %t/TestModule.out.dSYM/Contents/Resources/Python
+# RUN: mkdir -p %t/TestModule2.out.dSYM/Contents/Resources/Python
+# RUN: mkdir -p %t/TestModule3.out.dSYM/Contents/Resources/Python
+
+# RUN: cp %t/dsym_script.py %t/TestModule.out.dSYM/Contents/Resources/Python/TestModule.py
+# RUN: cp %t/dsym_script2.py %t/TestModule2.out.dSYM/Contents/Resources/Python/TestModule2.py
+# RUN: cp %t/dsym_script3.py %t/TestModule3.out.dSYM/Contents/Resources/Python/TestModule3.py
+# RUN: %lldb -b \
+# RUN: -o 'settings set target.load-script-from-symbol-file warn' \
+# RUN: -o 'target create %t/TestModule.out' \
+# RUN: -o 'target modules add %t/TestModule2.out %t/TestModule3.out' 2>&1 \
+# RUN: | FileCheck %s --strict-whitespace \
+# RUN: --implicit-check-not=DSYM_SCRIPT --implicit-check-not=DSYM_SCRIPT2 --implicit-check-not=DSYM_SCRIPT3
+
+# CHECK: (lldb) target create
+# CHECK: warning: {{.*}}The following debug scripts were detected but not loaded:
+# CHECK-EMPTY:
+# CHECK-NEXT:{{^}} - {{.*}}/TestModule.out.dSYM/Contents/Resources/Python/TestModule.py
+
+# CHECK: (lldb) target modules add
+# CHECK: warning: {{.*}}The following debug scripts were detected but not loaded:
+# CHECK-EMPTY:
+# CHECK-NEXT:{{^}} - {{.*}}/TestModule2.out.dSYM/Contents/Resources/Python/TestModule2.py
+# CHECK: warning: {{.*}}The following debug scripts were detected but not loaded:
+# CHECK-EMPTY:
+# CHECK-NEXT:{{^}} - {{.*}}/TestModule3.out.dSYM/Contents/Resources/Python/TestModule3.py
+
+#--- main.c
+int main() { return 0; }
+
+#--- dsym_script.py
+import sys
+def __lldb_init_module(debugger, internal_dict):
+ print("DSYM_SCRIPT", file=sys.stderr)
+
+#--- dsym_script2.py
+import sys
+def __lldb_init_module(debugger, internal_dict):
+ print("DSYM_SCRIPT2", file=sys.stderr)
+
+#--- dsym_script3.py
+import sys
+def __lldb_init_module(debugger, internal_dict):
+ print("DSYM_SCRIPT3", file=sys.stderr)
diff --git a/lldb/test/Shell/Platform/AutoLoad/UNIX/safe-path-warn-batch-dependents.test b/lldb/test/Shell/Platform/AutoLoad/UNIX/safe-path-warn-batch-dependents.test
new file mode 100644
index 0000000000000..f46e725338131
--- /dev/null
+++ b/lldb/test/Shell/Platform/AutoLoad/UNIX/safe-path-warn-batch-dependents.test
@@ -0,0 +1,44 @@
+# REQUIRES: python, asserts, !system-windows
+#
+# Test that when load-script-from-symbol-file is set to 'warn' and multiple
+# dependent modules with safe-path scripts are loaded in a single batch (via
+# target create), LLDB emits a single warning listing all detected scripts.
+
+# RUN: split-file %s %t
+# RUN: %clang_host -shared -fPIC %t/lib.c -o %t/libTestLib1.so
+# RUN: %clang_host -shared -fPIC %t/lib.c -o %t/libTestLib2.so
+# RUN: %clang_host %t/main.c -o %t/main.out %t/libTestLib1.so %t/libTestLib2.so \
+# RUN: -Wl,-rpath,%t
+# RUN: mkdir -p %t/safe-path/libTestLib1
+# RUN: mkdir -p %t/safe-path/libTestLib2
+# RUN: cp %t/script1.py %t/safe-path/libTestLib1/libTestLib1.py
+# RUN: cp %t/script2.py %t/safe-path/libTestLib2/libTestLib2.py
+# 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 'target create %t/main.out' 2>&1 \
+# RUN: | FileCheck %s --strict-whitespace \
+# RUN: --implicit-check-not=SCRIPT_LOADED1 --implicit-check-not=SCRIPT_LOADED2
+
+# Both dependent libraries should appear in a single warning.
+# CHECK: warning: {{.*}}The following debug scripts were detected but not loaded:
+# CHECK-EMPTY:
+# CHECK-DAG:{{^}} - {{.*}}/safe-path/libTestLib1/libTestLib1.py
+# CHECK-DAG:{{^}} - {{.*}}/safe-path/libTestLib2/libTestLib2.py
+
+#--- main.c
+extern int lib_func(void);
+int main() { return lib_func(); }
+
+#--- lib.c
+int lib_func(void) { return 0; }
+
+#--- script1.py
+import sys
+def __lldb_init_module(debugger, internal_dict):
+ print("SCRIPT_LOADED1", file=sys.stderr)
+
+#--- script2.py
+import sys
+def __lldb_init_module(debugger, internal_dict):
+ print("SCRIPT_LOADED2", file=sys.stderr)
diff --git a/lldb/test/Shell/Platform/AutoLoad/UNIX/safe-path-warn-multiple-modules.test b/lldb/test/Shell/Platform/AutoLoad/UNIX/safe-path-warn-multiple-modules.test
new file mode 100644
index 0000000000000..10c18583eb813
--- /dev/null
+++ b/lldb/test/Shell/Platform/AutoLoad/UNIX/safe-path-warn-multiple-modules.test
@@ -0,0 +1,55 @@
+# REQUIRES: python, asserts, !system-windows
+#
+# Test that when load-script-from-symbol-file is set to 'warn', LLDB emits a
+# warning for each safe-path script without executing them. Verify that warnings
+# are emitted for all modules, not just the first.
+
+# RUN: split-file %s %t
+# RUN: %clang_host %t/main.c -o %t/TestModule.out
+# RUN: %clang_host %t/main.c -o %t/TestModule2.out
+# RUN: %clang_host %t/main.c -o %t/TestModule3.out
+# RUN: mkdir -p %t/safe-path/TestModule
+# RUN: mkdir -p %t/safe-path/TestModule2
+# RUN: mkdir -p %t/safe-path/TestModule3
+
+# RUN: cp %t/script.py %t/safe-path/TestModule/TestModule.py
+# RUN: cp %t/script2.py %t/safe-path/TestModule2/TestModule2.py
+# RUN: cp %t/script3.py %t/safe-path/TestModule3/TestModule3.py
+# 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 'target create %t/TestModule.out' \
+# RUN: -o 'target modules add %t/TestModule2.out %t/TestModule3.out' 2>&1 \
+# RUN: | FileCheck %s --strict-whitespace \
+# RUN: --implicit-check-not=SCRIPT_LOADED --implicit-check-not=SCRIPT2_LOADED --implicit-check-not=SCRIPT3_LOADED
+
+# CHECK: (lldb) target create
+# CHECK: warning: {{.*}}The following debug scripts were detected but not loaded:
+# CHECK-EMPTY:
+# CHECK-NEXT:{{^}} - {{.*}}/safe-path/TestModule/TestModule.py
+
+# CHECK: (lldb) target modules add
+# CHECK: warning: {{.*}}The following debug scripts were detected but not loaded:
+# CHECK-EMPTY:
+# CHECK-NEXT:{{^}} - {{.*}}/safe-path/TestModule2/TestModule2.py
+# CHECK: warning: {{.*}}The following debug scripts were detected but not loaded:
+# CHECK-EMPTY:
+# CHECK-NEXT:{{^}} - {{.*}}/safe-path/TestModule3/TestModule3.py
+
+#--- main.c
+int main() { return 0; }
+
+#--- script.py
+import sys
+def __lldb_init_module(debugger, internal_dict):
+ print("SCRIPT_LOADED", file=sys.stderr)
+
+#--- script2.py
+import sys
+def __lldb_init_module(debugger, internal_dict):
+ print("SCRIPT2_LOADED", file=sys.stderr)
+
+#--- script3.py
+import sys
+def __lldb_init_module(debugger, internal_dict):
+ print("SCRIPT3_LOADED", file=sys.stderr)
More information about the lldb-commits
mailing list