* [PATCH] [gdb] Fix auto-load script re-execution on subsequent runs
@ 2026-09-01 14:06 Tudor-Stefan Magirescu
2026-09-03 9:21 ` [PATCH v2 0/2] Fix auto-load script loading after safe-path is widened Tudor-Stefan Magirescu
0 siblings, 1 reply; 4+ messages in thread
From: Tudor-Stefan Magirescu @ 2026-09-01 14:06 UTC (permalink / raw)
To: gdb-patches; +Cc: Tudor-Stefan Magirescu
Update maybe_add_script_file and maybe_add_script_text to
unconditionally update the loaded field of an existing hash table entry,
and change callers to gate script execution on whether the script is on
the safe-path, independently of hash table state.
This fixes two related behaviors. For companion -gdb.py scripts, the
Loaded field shown by "info auto-load" could become stale if the script
was initially blocked by the safe-path but loaded in a subsequent run.
For scripts referenced via .debug_gdb_scripts sections, GDB would not
re-execute the script the second time the associated object file was
loaded, causing per-objfile registered pretty-printers to stop working
after the first run of the inferior.
Add test variants for the .debug_gdb_scripts filename and inline-text
cases to gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event,
verifying that a script blocked on the first run is loaded correctly on
a subsequent run after the safe-path is widened.
Tested on x86_64-linux-gnu and found no regressions.
---
gdb/auto-load.c | 43 ++---
...ers-in-newobjfile-event-objfile.so-gdb.py} | 0
...s-in-newobjfile-event-dotdebug-filename.py | 43 +++++
...-newobjfile-event-lib-dotdebug-filename.cc | 39 +++++
...s-in-newobjfile-event-lib-dotdebug-text.cc | 49 ++++++
...inters-in-newobjfile-event-lib-objfile.cc} | 0
...ed-pretty-printers-in-newobjfile-event.exp | 158 ++++++++++++------
7 files changed, 255 insertions(+), 77 deletions(-)
rename gdb/testsuite/gdb.python/{libpy-autoloaded-pretty-printers-in-newobjfile-event.so-gdb.py => libpy-autoloaded-pretty-printers-in-newobjfile-event-objfile.so-gdb.py} (100%)
create mode 100644 gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-dotdebug-filename.py
create mode 100644 gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-lib-dotdebug-filename.cc
create mode 100644 gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-lib-dotdebug-text.cc
rename gdb/testsuite/gdb.python/{py-autoloaded-pretty-printers-in-newobjfile-event-lib.cc => py-autoloaded-pretty-printers-in-newobjfile-event-lib-objfile.cc} (100%)
diff --git a/gdb/auto-load.c b/gdb/auto-load.c
index ccbd091e1c2..dba60628223 100644
--- a/gdb/auto-load.c
+++ b/gdb/auto-load.c
@@ -675,11 +675,9 @@ get_auto_load_pspace_data_for_loading (struct program_space *pspace)
/* Add script file NAME in LANGUAGE to hash table of PSPACE_INFO.
LOADED is true if the script has been (is going to) be loaded, false
otherwise (such as if it has not been found).
- FULL_PATH is NULL if the script wasn't found.
+ FULL_PATH is NULL if the script wasn't found. */
- The result is true if the script was already in the hash table. */
-
-static bool
+static void
maybe_add_script_file (struct auto_load_pspace_info *pspace_info, bool loaded,
const char *name, const char *full_path,
const struct extension_language_defn *language)
@@ -714,20 +712,17 @@ maybe_add_script_file (struct auto_load_pspace_info *pspace_info, bool loaded,
}
else
(*slot)->full_path = NULL;
- (*slot)->loaded = loaded;
(*slot)->language = language;
}
- return in_hash_table;
+ (*slot)->loaded = loaded;
}
/* Add script contents NAME in LANGUAGE to hash table of PSPACE_INFO.
LOADED is true if the script has been (is going to) be loaded, false
- otherwise (such as if it has not been found).
-
- The result is true if the script was already in the hash table. */
+ otherwise (such as if it has not been found). */
-static bool
+static void
maybe_add_script_text (struct auto_load_pspace_info *pspace_info,
bool loaded, const char *name,
const struct extension_language_defn *language)
@@ -753,11 +748,10 @@ maybe_add_script_text (struct auto_load_pspace_info *pspace_info,
strcpy (p, name);
(*slot)->name = p;
(*slot)->full_path = NULL;
- (*slot)->loaded = loaded;
(*slot)->language = language;
}
- return in_hash_table;
+ (*slot)->loaded = loaded;
}
/* Clear the table of loaded section scripts. */
@@ -845,12 +839,7 @@ auto_load_objfile_script_1 (struct objfile *objfile, const char *realname,
= get_auto_load_pspace_data_for_loading (objfile->pspace ());
maybe_add_script_file (pspace_info, is_safe, debugfile, debugfile,
language);
-
- /* To preserve existing behavior we don't check for whether the
- script was already in the table, and always load it.
- It's highly unlikely that we'd ever load it twice,
- and these scripts are required to be idempotent under multiple
- loads anyway. */
+ /* Execute the script if it is on the safe path. */
if (is_safe)
{
objfile_script_sourcer_func *sourcer
@@ -1003,13 +992,12 @@ source_script_file (struct auto_load_pspace_info *pspace_info,
section_name, offset);
}
- bool in_hash_table
- = maybe_add_script_file (pspace_info, bool (opened), file,
- (opened ? opened->full_path.get (): NULL),
- language);
+ maybe_add_script_file (pspace_info, bool (opened), file,
+ (opened ? opened->full_path.get (): NULL),
+ language);
- /* If this file is not currently loaded, load it. */
- if (opened && !in_hash_table)
+ /* Execute the script if it is on the safe path. */
+ if (opened)
sourcer (language, objfile, opened->stream.get (),
opened->full_path.get ());
}
@@ -1087,11 +1075,10 @@ of file %ps."),
bool is_safe = file_is_auto_load_safe (objfile_name (objfile));
- bool in_hash_table
- = maybe_add_script_text (pspace_info, is_safe, name, language);
+ maybe_add_script_text (pspace_info, is_safe, name, language);
- /* If this file is not currently loaded, load it. */
- if (is_safe && !in_hash_table)
+ /* Execute the script if it is on the safe path. */
+ if (is_safe)
executor (language, objfile, name, script_text);
}
diff --git a/gdb/testsuite/gdb.python/libpy-autoloaded-pretty-printers-in-newobjfile-event.so-gdb.py b/gdb/testsuite/gdb.python/libpy-autoloaded-pretty-printers-in-newobjfile-event-objfile.so-gdb.py
similarity index 100%
rename from gdb/testsuite/gdb.python/libpy-autoloaded-pretty-printers-in-newobjfile-event.so-gdb.py
rename to gdb/testsuite/gdb.python/libpy-autoloaded-pretty-printers-in-newobjfile-event-objfile.so-gdb.py
diff --git a/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-dotdebug-filename.py b/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-dotdebug-filename.py
new file mode 100644
index 00000000000..a353358c20d
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-dotdebug-filename.py
@@ -0,0 +1,43 @@
+# Copyright (C) 2026 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# This file is part of the GDB testsuite. It tests that python pretty
+# printers defined in a python script that is autoloaded have been
+# registered when a custom event handler for the new_objfile event
+# is called.
+
+import gdb.printing
+
+
+class MyClassTestLibPrinter(object):
+ "Print a MyClassTestLib"
+
+ def __init__(self, val):
+ self.val = val
+
+ def to_string(self):
+ return "MyClassTestLib object, id: {}".format(self.val["id"])
+
+ def display_hint(self):
+ return "string"
+
+
+def build_pretty_printer():
+ pp = gdb.printing.RegexpCollectionPrettyPrinter("my_library")
+ pp.add_printer("MyClassTestLib", "^MyClassTestLib$", MyClassTestLibPrinter)
+ return pp
+
+
+gdb.printing.register_pretty_printer(gdb.current_objfile(), build_pretty_printer())
diff --git a/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-lib-dotdebug-filename.cc b/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-lib-dotdebug-filename.cc
new file mode 100644
index 00000000000..fe31f7083a0
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-lib-dotdebug-filename.cc
@@ -0,0 +1,39 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2026 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "py-autoloaded-pretty-printers-in-newobjfile-event-lib.h"
+
+#ifndef SCRIPT_FILE
+#error "SCRIPT_FILE not defined"
+#endif
+
+asm(
+".pushsection \".debug_gdb_scripts\",\"MS\",@progbits,1\n"
+".byte 1\n"
+".asciz \"" SCRIPT_FILE "\"\n"
+".popsection\n"
+);
+
+MyClassTestLib::MyClassTestLib (int theId)
+{
+ id = theId;
+}
+
+int MyClassTestLib::getId ()
+{
+ return id;
+}
diff --git a/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-lib-dotdebug-text.cc b/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-lib-dotdebug-text.cc
new file mode 100644
index 00000000000..12d663b362a
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-lib-dotdebug-text.cc
@@ -0,0 +1,49 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2026 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "py-autoloaded-pretty-printers-in-newobjfile-event-lib.h"
+
+asm(
+".pushsection \".debug_gdb_scripts\",\"MS\",@progbits,1\n"
+".byte 4\n"
+".ascii \"gdb.inlined-script\\n\"\n"
+".ascii \"import gdb.printing\\n\"\n"
+".ascii \"class MyClassTestLibPrinter(object):\\n\"\n"
+".ascii \" def __init__(self, val):\\n\"\n"
+".ascii \" self.val = val\\n\"\n"
+".ascii \" def to_string(self):\\n\"\n"
+".ascii \" return \\\"MyClassTestLib object, id: {}\\\".format(self.val[\\\"id\\\"])\\n\"\n"
+".ascii \" def display_hint(self):\\n\"\n"
+".ascii \" return \\\"string\\\"\\n\"\n"
+".ascii \"def build_pretty_printer():\\n\"\n"
+".ascii \" pp = gdb.printing.RegexpCollectionPrettyPrinter(\\\"my_library\\\")\\n\"\n"
+".ascii \" pp.add_printer(\\\"MyClassTestLib\\\", \\\"^MyClassTestLib$\\\", MyClassTestLibPrinter)\\n\"\n"
+".ascii \" return pp\\n\"\n"
+".ascii \"gdb.printing.register_pretty_printer(gdb.current_objfile(), build_pretty_printer())\\n\"\n"
+".byte 0\n"
+".popsection\n"
+);
+
+MyClassTestLib::MyClassTestLib (int theId)
+{
+ id = theId;
+}
+
+int MyClassTestLib::getId ()
+{
+ return id;
+}
diff --git a/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-lib.cc b/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-lib-objfile.cc
similarity index 100%
rename from gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-lib.cc
rename to gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-lib-objfile.cc
diff --git a/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event.exp b/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event.exp
index 9b8a10cf84f..cf0bdb80c51 100644
--- a/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event.exp
+++ b/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event.exp
@@ -15,7 +15,9 @@
# This file is part of the GDB testsuite. It tests that Python pretty-printers
# defined in a Python script that is autoloaded are registered when an event
-# handler for the new_objfile event is called.
+# handler for the new_objfile event is called. It also tests that scripts
+# which were not loaded because the auto-load safe-path did not cover them are
+# loaded on the next run once the safe-path is widened.
load_lib gdb-python.exp
@@ -23,70 +25,128 @@ require allow_python_tests
standard_testfile -main.cc
-set srcfile_lib "${testfile}-lib.cc"
set python_event_handler_file "${srcdir}/${subdir}/${testfile}.py"
-set libname "lib${testfile}"
-set python_autoload_file "${srcdir}/${subdir}/${libname}.so-gdb.py"
-set binfile_lib [standard_output_file "${libname}.so"]
-
-# Compile library.
-if { [gdb_compile_shlib ${srcdir}/${subdir}/${srcfile_lib} ${binfile_lib} \
- {debug c++}] != "" } {
- return
-}
-
-# Compile main program.
-if { [gdb_compile ${srcdir}/${subdir}/${srcfile} \
- ${binfile} \
- executable \
- [list debug c++ shlib=$binfile_lib]] != "" } {
- return
-}
-
-clean_restart
+set libscript "lib${testfile}-objfile.so-gdb.py"
+set python_autoload_file "${srcdir}/${subdir}/${libscript}"
# Make the -gdb.py script available to gdb, it is automatically loaded by
# gdb if it is put in the same directory as the library.
set remote_python_autoload_file \
[gdb_remote_download host $python_autoload_file]
-gdb_test_no_output \
- "set auto-load safe-path ${remote_python_autoload_file}" \
- "set auto-load safe-path"
-
# Load the Python file that defines a handler for the new_objfile event.
set remote_python_event_handler_file\
[gdb_remote_download host $python_event_handler_file]
-gdb_test_no_output "source ${remote_python_event_handler_file}" "load python file"
-gdb_load ${binfile}
-gdb_load_shlib $binfile_lib
+proc newobjfile_event_test { variant } {
+ global srcdir subdir testfile srcfile
+ global remote_python_autoload_file remote_python_event_handler_file libscript
+ global decimal
-if { ![runto_main] } {
- return
-}
+ with_test_prefix $variant {
+ if { $variant ne "objfile" && [is_remote host] } {
+ unsupported "$variant requires non-remote host"
+ return
+ }
-if { [is_remote target ] } {
- set target_sysroot 0
- gdb_test_multiple "show sysroot" "" {
- -re -wrap "\r\nThe current system root is \"target:.*\"\\." {
- set target_sysroot 1
+ set libname "lib${testfile}-${variant}"
+ set binfile_lib [standard_output_file "${libname}.so"]
+ set binfile [standard_output_file "${testfile}-${variant}"]
+
+ set shlib_flags [list debug c++]
+ if { $variant eq "dotdebug-filename" } {
+ set quoted "\"${srcdir}/${subdir}/${testfile}-${variant}.py\""
+ lappend shlib_flags additional_flags=-DSCRIPT_FILE=$quoted
}
- -re -wrap "" {
+
+ # Compile library.
+ if { [gdb_compile_shlib \
+ "${srcdir}/${subdir}/${testfile}-lib-${variant}.cc" \
+ ${binfile_lib} $shlib_flags] != "" } {
+ return
+ }
+
+ # Compile main program.
+ if { [gdb_compile ${srcdir}/${subdir}/${srcfile} \
+ ${binfile} \
+ executable \
+ [list debug c++ shlib=$binfile_lib]] != "" } {
+ return
+ }
+
+ if { $variant eq "objfile" } {
+ set safe_path_allow $remote_python_autoload_file
+ set script_name $libscript
+ } elseif { $variant eq "dotdebug-filename" } {
+ set safe_path_allow "${srcdir}/${subdir}/${testfile}-${variant}.py"
+ set script_name "${testfile}-${variant}.py"
+ } else {
+ set safe_path_allow $binfile_lib
+ set script_name "gdb.inlined-script"
}
- }
- if { $target_sysroot } {
- unsupported "sysroot start with target: -- auto-load not supported"
- return
+ clean_restart
+ gdb_test_no_output "source $remote_python_event_handler_file" "load python file"
+ gdb_load ${binfile}
+ gdb_load_shlib $binfile_lib
+
+ if { [is_remote target ] } {
+ set target_sysroot 0
+ gdb_test_multiple "show sysroot" "" {
+ -re -wrap "\r\nThe current system root is \"target:.*\"\\." {
+ set target_sysroot 1
+ }
+ -re -wrap "" {
+ }
+ }
+
+ if { $target_sysroot } {
+ unsupported "sysroot start with target: -- auto-load not supported"
+ return
+ }
+ }
+
+ gdb_test_no_output "set auto-load safe-path /restricted" \
+ "set restricted auto-load safe-path"
+
+ if { ![runto_main] } {
+ return
+ }
+
+ gdb_test_multiple "info auto-load python-scripts" "verify script not loaded" {
+ -re -wrap "Yes.*${script_name}.*" {
+ fail $gdb_test_name
+ }
+ -re -wrap "No.*${script_name}.*" {
+ pass $gdb_test_name
+ }
+ }
+
+ gdb_test_no_output \
+ "set auto-load safe-path ${safe_path_allow}" \
+ "set auto-load safe-path"
+
+ if { ![runto_main] } {
+ return
+ }
+
+ gdb_test_multiple "info auto-load python-scripts" "verify script loaded" {
+ -re -wrap "Yes.*${script_name}.*" {
+ pass $gdb_test_name
+ }
+ -re -wrap "No.*${script_name}.*" {
+ fail $gdb_test_name
+ }
+ }
+
+ gdb_test "print all_good" " = true"
+ gdb_test "info pretty-printer" "my_library.*MyClassTestLib.*"
+ gdb_breakpoint [gdb_get_line_number "break to inspect"]
+ gdb_test "continue" "Breakpoint $decimal, main .*"
+ gdb_test "print test" "MyClassTestLib object, id: 1.*"
}
}
-# Check that the new_objfile handler saw the pretty-printer.
-gdb_test "print all_good" " = true"
-
-# Check that the pretty-printer actually works.
-gdb_test "info pretty-printer" "my_library.*MyClassTestLib.*"
-gdb_breakpoint [gdb_get_line_number "break to inspect"]
-gdb_test "continue" "Breakpoint $decimal, main .*"
-gdb_test "print test" "MyClassTestLib object, id: 1.*"
+newobjfile_event_test "objfile"
+newobjfile_event_test "dotdebug-filename"
+newobjfile_event_test "dotdebug-text"
--
2.43.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 0/2] Fix auto-load script loading after safe-path is widened
2026-09-01 14:06 [PATCH] [gdb] Fix auto-load script re-execution on subsequent runs Tudor-Stefan Magirescu
@ 2026-09-03 9:21 ` Tudor-Stefan Magirescu
2026-09-03 9:22 ` [PATCH v2 1/2] [gdb] Fix auto-load script re-execution on subsequent runs Tudor-Stefan Magirescu
2026-09-03 9:22 ` [PATCH v2 2/2] [gdb] Retry blocked auto-load scripts when safe-path is widened Tudor-Stefan Magirescu
0 siblings, 2 replies; 4+ messages in thread
From: Tudor-Stefan Magirescu @ 2026-09-03 9:21 UTC (permalink / raw)
To: gdb-patches; +Cc: tudor.magirescu
GDB's safe-path mechanism makes it inconvenient to work with scripts
embedded in .debug_gdb_scripts sections. Once a script is blocked, GDB
never retries loading it even if the safe-path is widened. This occurs
because the hash table entry inserted for the first declined load prevents
any further attempt. Working around this requires reloading the binary
via the file command or restarting GDB entirely.
Patch 1 fixes the hash table issue. For shared library scripts, which
are re-examined on each run of the inferior, a re-run after widening the
safe-path is sufficient. Scripts embedded in the main executable still
require a reload via file or a GDB restart, since their objfile is not
reloaded for a re-run.
Patch 2 further addresses the problem by changing add-auto-load-safe-path
to immediately retry previously blocked scripts. This allows the user to
load a rejected script without exiting the current GDB session or
re-running the inferior.
Changes since v1:
- Change the return type of maybe_add_script_file and
maybe_add_script_text to bool, making it return whether the script
was previously loaded.
- Add Patch 2 (add-auto-load-safe-path immediate retry).
Tudor-Stefan Magirescu (2):
[gdb] Fix auto-load script re-execution on subsequent runs
[gdb] Retry blocked auto-load scripts when safe-path is widened
gdb/auto-load.c | 130 +++++++-----
gdb/auto-load.h | 13 +-
gdb/extension.c | 7 +-
gdb/extension.h | 3 +-
...ers-in-newobjfile-event-objfile.so-gdb.py} | 0
...s-in-newobjfile-event-dotdebug-filename.py | 43 ++++
...-newobjfile-event-lib-dotdebug-filename.cc | 39 ++++
...s-in-newobjfile-event-lib-dotdebug-text.cc | 49 +++++
...inters-in-newobjfile-event-lib-objfile.cc} | 0
...ed-pretty-printers-in-newobjfile-event.exp | 187 +++++++++++++-----
10 files changed, 361 insertions(+), 110 deletions(-)
rename gdb/testsuite/gdb.python/{libpy-autoloaded-pretty-printers-in-newobjfile-event.so-gdb.py => libpy-autoloaded-pretty-printers-in-newobjfile-event-objfile.so-gdb.py} (100%)
create mode 100644 gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-dotdebug-filename.py
create mode 100644 gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-lib-dotdebug-filename.cc
create mode 100644 gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-lib-dotdebug-text.cc
rename gdb/testsuite/gdb.python/{py-autoloaded-pretty-printers-in-newobjfile-event-lib.cc => py-autoloaded-pretty-printers-in-newobjfile-event-lib-objfile.cc} (100%)
--
2.43.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 1/2] [gdb] Fix auto-load script re-execution on subsequent runs
2026-09-03 9:21 ` [PATCH v2 0/2] Fix auto-load script loading after safe-path is widened Tudor-Stefan Magirescu
@ 2026-09-03 9:22 ` Tudor-Stefan Magirescu
2026-09-03 9:22 ` [PATCH v2 2/2] [gdb] Retry blocked auto-load scripts when safe-path is widened Tudor-Stefan Magirescu
1 sibling, 0 replies; 4+ messages in thread
From: Tudor-Stefan Magirescu @ 2026-09-03 9:22 UTC (permalink / raw)
To: gdb-patches; +Cc: tudor.magirescu
Update maybe_add_script_file and maybe_add_script_text to
unconditionally update the loaded field of an existing hash table entry,
and change callers to gate script execution on whether the script is on
the safe-path, independently of hash table state.
This fixes two related behaviors. For companion -gdb.py scripts, the
Loaded field shown by "info auto-load" could become stale if the script
was initially blocked by the safe-path but loaded in a subsequent run.
For scripts referenced via .debug_gdb_scripts sections, GDB would not
re-execute the script the second time the associated object file was
loaded, causing per-objfile registered pretty-printers to stop working
after the first run of the inferior.
Add test variants for the .debug_gdb_scripts filename and inline-text
cases to gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event,
verifying that a script blocked on the first run is loaded correctly on
a subsequent run after the safe-path is widened.
Tested on x86_64-linux-gnu and found no regressions.
---
gdb/auto-load.c | 43 +++--
...ers-in-newobjfile-event-objfile.so-gdb.py} | 0
...s-in-newobjfile-event-dotdebug-filename.py | 43 +++++
...-newobjfile-event-lib-dotdebug-filename.cc | 39 +++++
...s-in-newobjfile-event-lib-dotdebug-text.cc | 49 ++++++
...inters-in-newobjfile-event-lib-objfile.cc} | 0
...ed-pretty-printers-in-newobjfile-event.exp | 158 ++++++++++++------
7 files changed, 259 insertions(+), 73 deletions(-)
rename gdb/testsuite/gdb.python/{libpy-autoloaded-pretty-printers-in-newobjfile-event.so-gdb.py => libpy-autoloaded-pretty-printers-in-newobjfile-event-objfile.so-gdb.py} (100%)
create mode 100644 gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-dotdebug-filename.py
create mode 100644 gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-lib-dotdebug-filename.cc
create mode 100644 gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-lib-dotdebug-text.cc
rename gdb/testsuite/gdb.python/{py-autoloaded-pretty-printers-in-newobjfile-event-lib.cc => py-autoloaded-pretty-printers-in-newobjfile-event-lib-objfile.cc} (100%)
diff --git a/gdb/auto-load.c b/gdb/auto-load.c
index ccbd091e1c2..8a6e818fd69 100644
--- a/gdb/auto-load.c
+++ b/gdb/auto-load.c
@@ -676,8 +676,8 @@ get_auto_load_pspace_data_for_loading (struct program_space *pspace)
LOADED is true if the script has been (is going to) be loaded, false
otherwise (such as if it has not been found).
FULL_PATH is NULL if the script wasn't found.
-
- The result is true if the script was already in the hash table. */
+ Returns the previous value of the loaded field, or false if the entry
+ did not exist yet. */
static bool
maybe_add_script_file (struct auto_load_pspace_info *pspace_info, bool loaded,
@@ -714,18 +714,19 @@ maybe_add_script_file (struct auto_load_pspace_info *pspace_info, bool loaded,
}
else
(*slot)->full_path = NULL;
- (*slot)->loaded = loaded;
(*slot)->language = language;
}
- return in_hash_table;
+ bool was_loaded = (*slot)->loaded;
+ (*slot)->loaded = loaded;
+ return was_loaded;
}
/* Add script contents NAME in LANGUAGE to hash table of PSPACE_INFO.
LOADED is true if the script has been (is going to) be loaded, false
otherwise (such as if it has not been found).
-
- The result is true if the script was already in the hash table. */
+ Returns the previous value of the loaded field, or false if the entry
+ did not exist yet. */
static bool
maybe_add_script_text (struct auto_load_pspace_info *pspace_info,
@@ -753,11 +754,12 @@ maybe_add_script_text (struct auto_load_pspace_info *pspace_info,
strcpy (p, name);
(*slot)->name = p;
(*slot)->full_path = NULL;
- (*slot)->loaded = loaded;
(*slot)->language = language;
}
- return in_hash_table;
+ bool was_loaded = (*slot)->loaded;
+ (*slot)->loaded = loaded;
+ return was_loaded;
}
/* Clear the table of loaded section scripts. */
@@ -845,12 +847,7 @@ auto_load_objfile_script_1 (struct objfile *objfile, const char *realname,
= get_auto_load_pspace_data_for_loading (objfile->pspace ());
maybe_add_script_file (pspace_info, is_safe, debugfile, debugfile,
language);
-
- /* To preserve existing behavior we don't check for whether the
- script was already in the table, and always load it.
- It's highly unlikely that we'd ever load it twice,
- and these scripts are required to be idempotent under multiple
- loads anyway. */
+ /* Execute the script if it is on the safe path. */
if (is_safe)
{
objfile_script_sourcer_func *sourcer
@@ -1003,13 +1000,12 @@ source_script_file (struct auto_load_pspace_info *pspace_info,
section_name, offset);
}
- bool in_hash_table
- = maybe_add_script_file (pspace_info, bool (opened), file,
- (opened ? opened->full_path.get (): NULL),
- language);
+ maybe_add_script_file (pspace_info, bool (opened), file,
+ (opened ? opened->full_path.get (): NULL),
+ language);
- /* If this file is not currently loaded, load it. */
- if (opened && !in_hash_table)
+ /* Execute the script if it is on the safe path. */
+ if (opened)
sourcer (language, objfile, opened->stream.get (),
opened->full_path.get ());
}
@@ -1087,11 +1083,10 @@ of file %ps."),
bool is_safe = file_is_auto_load_safe (objfile_name (objfile));
- bool in_hash_table
- = maybe_add_script_text (pspace_info, is_safe, name, language);
+ maybe_add_script_text (pspace_info, is_safe, name, language);
- /* If this file is not currently loaded, load it. */
- if (is_safe && !in_hash_table)
+ /* Execute the script if it is on the safe path. */
+ if (is_safe)
executor (language, objfile, name, script_text);
}
diff --git a/gdb/testsuite/gdb.python/libpy-autoloaded-pretty-printers-in-newobjfile-event.so-gdb.py b/gdb/testsuite/gdb.python/libpy-autoloaded-pretty-printers-in-newobjfile-event-objfile.so-gdb.py
similarity index 100%
rename from gdb/testsuite/gdb.python/libpy-autoloaded-pretty-printers-in-newobjfile-event.so-gdb.py
rename to gdb/testsuite/gdb.python/libpy-autoloaded-pretty-printers-in-newobjfile-event-objfile.so-gdb.py
diff --git a/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-dotdebug-filename.py b/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-dotdebug-filename.py
new file mode 100644
index 00000000000..a353358c20d
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-dotdebug-filename.py
@@ -0,0 +1,43 @@
+# Copyright (C) 2026 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# This file is part of the GDB testsuite. It tests that python pretty
+# printers defined in a python script that is autoloaded have been
+# registered when a custom event handler for the new_objfile event
+# is called.
+
+import gdb.printing
+
+
+class MyClassTestLibPrinter(object):
+ "Print a MyClassTestLib"
+
+ def __init__(self, val):
+ self.val = val
+
+ def to_string(self):
+ return "MyClassTestLib object, id: {}".format(self.val["id"])
+
+ def display_hint(self):
+ return "string"
+
+
+def build_pretty_printer():
+ pp = gdb.printing.RegexpCollectionPrettyPrinter("my_library")
+ pp.add_printer("MyClassTestLib", "^MyClassTestLib$", MyClassTestLibPrinter)
+ return pp
+
+
+gdb.printing.register_pretty_printer(gdb.current_objfile(), build_pretty_printer())
diff --git a/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-lib-dotdebug-filename.cc b/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-lib-dotdebug-filename.cc
new file mode 100644
index 00000000000..fe31f7083a0
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-lib-dotdebug-filename.cc
@@ -0,0 +1,39 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2026 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "py-autoloaded-pretty-printers-in-newobjfile-event-lib.h"
+
+#ifndef SCRIPT_FILE
+#error "SCRIPT_FILE not defined"
+#endif
+
+asm(
+".pushsection \".debug_gdb_scripts\",\"MS\",@progbits,1\n"
+".byte 1\n"
+".asciz \"" SCRIPT_FILE "\"\n"
+".popsection\n"
+);
+
+MyClassTestLib::MyClassTestLib (int theId)
+{
+ id = theId;
+}
+
+int MyClassTestLib::getId ()
+{
+ return id;
+}
diff --git a/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-lib-dotdebug-text.cc b/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-lib-dotdebug-text.cc
new file mode 100644
index 00000000000..12d663b362a
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-lib-dotdebug-text.cc
@@ -0,0 +1,49 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2026 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "py-autoloaded-pretty-printers-in-newobjfile-event-lib.h"
+
+asm(
+".pushsection \".debug_gdb_scripts\",\"MS\",@progbits,1\n"
+".byte 4\n"
+".ascii \"gdb.inlined-script\\n\"\n"
+".ascii \"import gdb.printing\\n\"\n"
+".ascii \"class MyClassTestLibPrinter(object):\\n\"\n"
+".ascii \" def __init__(self, val):\\n\"\n"
+".ascii \" self.val = val\\n\"\n"
+".ascii \" def to_string(self):\\n\"\n"
+".ascii \" return \\\"MyClassTestLib object, id: {}\\\".format(self.val[\\\"id\\\"])\\n\"\n"
+".ascii \" def display_hint(self):\\n\"\n"
+".ascii \" return \\\"string\\\"\\n\"\n"
+".ascii \"def build_pretty_printer():\\n\"\n"
+".ascii \" pp = gdb.printing.RegexpCollectionPrettyPrinter(\\\"my_library\\\")\\n\"\n"
+".ascii \" pp.add_printer(\\\"MyClassTestLib\\\", \\\"^MyClassTestLib$\\\", MyClassTestLibPrinter)\\n\"\n"
+".ascii \" return pp\\n\"\n"
+".ascii \"gdb.printing.register_pretty_printer(gdb.current_objfile(), build_pretty_printer())\\n\"\n"
+".byte 0\n"
+".popsection\n"
+);
+
+MyClassTestLib::MyClassTestLib (int theId)
+{
+ id = theId;
+}
+
+int MyClassTestLib::getId ()
+{
+ return id;
+}
diff --git a/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-lib.cc b/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-lib-objfile.cc
similarity index 100%
rename from gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-lib.cc
rename to gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event-lib-objfile.cc
diff --git a/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event.exp b/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event.exp
index 9b8a10cf84f..cf0bdb80c51 100644
--- a/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event.exp
+++ b/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event.exp
@@ -15,7 +15,9 @@
# This file is part of the GDB testsuite. It tests that Python pretty-printers
# defined in a Python script that is autoloaded are registered when an event
-# handler for the new_objfile event is called.
+# handler for the new_objfile event is called. It also tests that scripts
+# which were not loaded because the auto-load safe-path did not cover them are
+# loaded on the next run once the safe-path is widened.
load_lib gdb-python.exp
@@ -23,70 +25,128 @@ require allow_python_tests
standard_testfile -main.cc
-set srcfile_lib "${testfile}-lib.cc"
set python_event_handler_file "${srcdir}/${subdir}/${testfile}.py"
-set libname "lib${testfile}"
-set python_autoload_file "${srcdir}/${subdir}/${libname}.so-gdb.py"
-set binfile_lib [standard_output_file "${libname}.so"]
-
-# Compile library.
-if { [gdb_compile_shlib ${srcdir}/${subdir}/${srcfile_lib} ${binfile_lib} \
- {debug c++}] != "" } {
- return
-}
-
-# Compile main program.
-if { [gdb_compile ${srcdir}/${subdir}/${srcfile} \
- ${binfile} \
- executable \
- [list debug c++ shlib=$binfile_lib]] != "" } {
- return
-}
-
-clean_restart
+set libscript "lib${testfile}-objfile.so-gdb.py"
+set python_autoload_file "${srcdir}/${subdir}/${libscript}"
# Make the -gdb.py script available to gdb, it is automatically loaded by
# gdb if it is put in the same directory as the library.
set remote_python_autoload_file \
[gdb_remote_download host $python_autoload_file]
-gdb_test_no_output \
- "set auto-load safe-path ${remote_python_autoload_file}" \
- "set auto-load safe-path"
-
# Load the Python file that defines a handler for the new_objfile event.
set remote_python_event_handler_file\
[gdb_remote_download host $python_event_handler_file]
-gdb_test_no_output "source ${remote_python_event_handler_file}" "load python file"
-gdb_load ${binfile}
-gdb_load_shlib $binfile_lib
+proc newobjfile_event_test { variant } {
+ global srcdir subdir testfile srcfile
+ global remote_python_autoload_file remote_python_event_handler_file libscript
+ global decimal
-if { ![runto_main] } {
- return
-}
+ with_test_prefix $variant {
+ if { $variant ne "objfile" && [is_remote host] } {
+ unsupported "$variant requires non-remote host"
+ return
+ }
-if { [is_remote target ] } {
- set target_sysroot 0
- gdb_test_multiple "show sysroot" "" {
- -re -wrap "\r\nThe current system root is \"target:.*\"\\." {
- set target_sysroot 1
+ set libname "lib${testfile}-${variant}"
+ set binfile_lib [standard_output_file "${libname}.so"]
+ set binfile [standard_output_file "${testfile}-${variant}"]
+
+ set shlib_flags [list debug c++]
+ if { $variant eq "dotdebug-filename" } {
+ set quoted "\"${srcdir}/${subdir}/${testfile}-${variant}.py\""
+ lappend shlib_flags additional_flags=-DSCRIPT_FILE=$quoted
}
- -re -wrap "" {
+
+ # Compile library.
+ if { [gdb_compile_shlib \
+ "${srcdir}/${subdir}/${testfile}-lib-${variant}.cc" \
+ ${binfile_lib} $shlib_flags] != "" } {
+ return
+ }
+
+ # Compile main program.
+ if { [gdb_compile ${srcdir}/${subdir}/${srcfile} \
+ ${binfile} \
+ executable \
+ [list debug c++ shlib=$binfile_lib]] != "" } {
+ return
+ }
+
+ if { $variant eq "objfile" } {
+ set safe_path_allow $remote_python_autoload_file
+ set script_name $libscript
+ } elseif { $variant eq "dotdebug-filename" } {
+ set safe_path_allow "${srcdir}/${subdir}/${testfile}-${variant}.py"
+ set script_name "${testfile}-${variant}.py"
+ } else {
+ set safe_path_allow $binfile_lib
+ set script_name "gdb.inlined-script"
}
- }
- if { $target_sysroot } {
- unsupported "sysroot start with target: -- auto-load not supported"
- return
+ clean_restart
+ gdb_test_no_output "source $remote_python_event_handler_file" "load python file"
+ gdb_load ${binfile}
+ gdb_load_shlib $binfile_lib
+
+ if { [is_remote target ] } {
+ set target_sysroot 0
+ gdb_test_multiple "show sysroot" "" {
+ -re -wrap "\r\nThe current system root is \"target:.*\"\\." {
+ set target_sysroot 1
+ }
+ -re -wrap "" {
+ }
+ }
+
+ if { $target_sysroot } {
+ unsupported "sysroot start with target: -- auto-load not supported"
+ return
+ }
+ }
+
+ gdb_test_no_output "set auto-load safe-path /restricted" \
+ "set restricted auto-load safe-path"
+
+ if { ![runto_main] } {
+ return
+ }
+
+ gdb_test_multiple "info auto-load python-scripts" "verify script not loaded" {
+ -re -wrap "Yes.*${script_name}.*" {
+ fail $gdb_test_name
+ }
+ -re -wrap "No.*${script_name}.*" {
+ pass $gdb_test_name
+ }
+ }
+
+ gdb_test_no_output \
+ "set auto-load safe-path ${safe_path_allow}" \
+ "set auto-load safe-path"
+
+ if { ![runto_main] } {
+ return
+ }
+
+ gdb_test_multiple "info auto-load python-scripts" "verify script loaded" {
+ -re -wrap "Yes.*${script_name}.*" {
+ pass $gdb_test_name
+ }
+ -re -wrap "No.*${script_name}.*" {
+ fail $gdb_test_name
+ }
+ }
+
+ gdb_test "print all_good" " = true"
+ gdb_test "info pretty-printer" "my_library.*MyClassTestLib.*"
+ gdb_breakpoint [gdb_get_line_number "break to inspect"]
+ gdb_test "continue" "Breakpoint $decimal, main .*"
+ gdb_test "print test" "MyClassTestLib object, id: 1.*"
}
}
-# Check that the new_objfile handler saw the pretty-printer.
-gdb_test "print all_good" " = true"
-
-# Check that the pretty-printer actually works.
-gdb_test "info pretty-printer" "my_library.*MyClassTestLib.*"
-gdb_breakpoint [gdb_get_line_number "break to inspect"]
-gdb_test "continue" "Breakpoint $decimal, main .*"
-gdb_test "print test" "MyClassTestLib object, id: 1.*"
+newobjfile_event_test "objfile"
+newobjfile_event_test "dotdebug-filename"
+newobjfile_event_test "dotdebug-text"
--
2.43.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 2/2] [gdb] Retry blocked auto-load scripts when safe-path is widened
2026-09-03 9:21 ` [PATCH v2 0/2] Fix auto-load script loading after safe-path is widened Tudor-Stefan Magirescu
2026-09-03 9:22 ` [PATCH v2 1/2] [gdb] Fix auto-load script re-execution on subsequent runs Tudor-Stefan Magirescu
@ 2026-09-03 9:22 ` Tudor-Stefan Magirescu
1 sibling, 0 replies; 4+ messages in thread
From: Tudor-Stefan Magirescu @ 2026-09-03 9:22 UTC (permalink / raw)
To: gdb-patches; +Cc: tudor.magirescu
Extend add-auto-load-safe-path to immediately retry scripts that were
previously blocked by the safe-path. Enhance the warning printed when
auto-loading is declined to inform the user that add-auto-load-safe-path
can be used to load the script in the current session.
A new boolean parameter, from_objfile_load, is propagated through the
auto-load call chain to distinguish a new objfile load from a safe-path
refresh. Scripts already loaded are skipped during a refresh to avoid
re-execution. Safe-path warnings are suppressed during the refresh pass
since no new information would be conveyed.
Extend gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event
to verify that after a script is blocked on the first run, calling
add-auto-load-safe-path immediately loads it without a re-run of the
inferior.
Tested on x86_64-linux-gnu and found no regressions.
---
gdb/auto-load.c | 105 ++++++++++++------
gdb/auto-load.h | 13 ++-
gdb/extension.c | 7 +-
gdb/extension.h | 3 +-
...ed-pretty-printers-in-newobjfile-event.exp | 31 +++++-
5 files changed, 112 insertions(+), 47 deletions(-)
diff --git a/gdb/auto-load.c b/gdb/auto-load.c
index 8a6e818fd69..35d6ae3d8f2 100644
--- a/gdb/auto-load.c
+++ b/gdb/auto-load.c
@@ -358,6 +358,10 @@ Use 'set auto-load safe-path /' for disabling the auto-load safe-path security.\
DIRNAME_SEPARATOR, args);
auto_load_safe_path_vec_update ();
+
+ if (current_program_space != NULL)
+ for (struct objfile &objfile : current_program_space->objfiles ())
+ load_auto_scripts_for_objfile (objfile, false);
}
/* "add-auto-load-scripts-directory" command for the auto_load_dir configuration
@@ -495,7 +499,7 @@ filename_is_in_auto_load_safe_path_vec (const char *filename,
/* See auto-load.h. */
bool
-file_is_auto_load_safe (const char *filename)
+file_is_auto_load_safe (const char *filename, bool print_warning)
{
gdb::unique_xmalloc_ptr<char> filename_real;
static bool advice_printed = false;
@@ -507,6 +511,9 @@ file_is_auto_load_safe (const char *filename)
if (filename_is_in_auto_load_safe_path_vec (filename, &filename_real))
return true;
+ if (!print_warning)
+ return false;
+
warning (_("File \"%ps\" auto-loading has been declined by your "
"`auto-load safe-path' set to \"%s\"."),
styled_string (file_name_style.style (), filename_real.get ()),
@@ -538,7 +545,8 @@ file_is_auto_load_safe (const char *filename)
gdb_printf (_("\
To enable execution of this file add\n\
\t%p[add-auto-load-safe-path %s%p]\n\
-line to your configuration file \"%ps\".\n\
+line to your configuration file \"%ps\", or run that command to load it\n\
+in the current session.\n\
To completely disable this security protection add\n\
\t%ps\n\
line to your configuration file \"%ps\".\n\
@@ -778,7 +786,8 @@ clear_section_scripts (program_space *pspace)
static int
auto_load_objfile_script_1 (struct objfile *objfile, const char *realname,
- const struct extension_language_defn *language)
+ const struct extension_language_defn *language,
+ bool from_objfile_load)
{
const char *debugfile;
int retval;
@@ -839,16 +848,18 @@ auto_load_objfile_script_1 (struct objfile *objfile, const char *realname,
("Loading %s script \"%s\" by extension for objfile \"%s\".",
ext_lang_name (language), debugfile, objfile_name (objfile));
- bool is_safe = file_is_auto_load_safe (debugfile);
+ bool is_safe = file_is_auto_load_safe (debugfile, from_objfile_load);
/* Add this script to the hash table too so
"info auto-load ${lang}-scripts" can print it. */
pspace_info
= get_auto_load_pspace_data_for_loading (objfile->pspace ());
- maybe_add_script_file (pspace_info, is_safe, debugfile, debugfile,
- language);
- /* Execute the script if it is on the safe path. */
- if (is_safe)
+ bool was_loaded = maybe_add_script_file (pspace_info, is_safe, debugfile,
+ debugfile, language);
+ /* Execute the script if it is on the safe path. When called from
+ add-auto-load-safe-path, skip scripts that were already loaded to
+ avoid re-executing them. */
+ if (is_safe && (from_objfile_load || !was_loaded))
{
objfile_script_sourcer_func *sourcer
= ext_lang_objfile_script_sourcer (language);
@@ -873,7 +884,8 @@ auto_load_objfile_script_1 (struct objfile *objfile, const char *realname,
void
auto_load_objfile_script (struct objfile *objfile,
- const struct extension_language_defn *language)
+ const struct extension_language_defn *language,
+ bool from_objfile_load)
{
AUTO_LOAD_SCOPED_DEBUG_ENTER_EXIT;
auto_load_debug_printf ("objfile: %s, language: %s",
@@ -883,7 +895,8 @@ auto_load_objfile_script (struct objfile *objfile,
gdb::unique_xmalloc_ptr<char> realname
= gdb_realpath (objfile_name (objfile));
- if (auto_load_objfile_script_1 (objfile, realname.get (), language))
+ if (auto_load_objfile_script_1 (objfile, realname.get (), language,
+ from_objfile_load))
return;
/* For Windows/DOS .exe executables, strip the .exe suffix, so that
@@ -900,7 +913,8 @@ auto_load_objfile_script (struct objfile *objfile,
auto_load_debug_printf
("Stripped .exe suffix, retrying with \"%s\".", realname.get ());
- auto_load_objfile_script_1 (objfile, realname.get (), language);
+ auto_load_objfile_script_1 (objfile, realname.get (), language,
+ from_objfile_load);
return;
}
@@ -934,8 +948,8 @@ auto_load_objfile_script (struct objfile *objfile,
("Debug filename mismatch, retrying with \"%s\".",
p_realname.c_str ());
- auto_load_objfile_script_1 (objfile,
- p_realname.c_str (), language);
+ auto_load_objfile_script_1 (objfile, p_realname.c_str (),
+ language, from_objfile_load);
}
}
}
@@ -950,7 +964,7 @@ source_script_file (struct auto_load_pspace_info *pspace_info,
struct objfile *objfile,
const struct extension_language_defn *language,
const char *section_name, unsigned int offset,
- const char *file)
+ const char *file, bool from_objfile_load)
{
objfile_script_sourcer_func *sourcer;
@@ -983,7 +997,7 @@ source_script_file (struct auto_load_pspace_info *pspace_info,
ext_lang_name (language), opened->full_path.get (),
section_name, objfile_name (objfile));
- if (!file_is_auto_load_safe (opened->full_path.get ()))
+ if (!file_is_auto_load_safe (opened->full_path.get (), from_objfile_load))
opened.reset ();
}
else
@@ -1000,12 +1014,14 @@ source_script_file (struct auto_load_pspace_info *pspace_info,
section_name, offset);
}
- maybe_add_script_file (pspace_info, bool (opened), file,
- (opened ? opened->full_path.get (): NULL),
- language);
+ bool was_loaded = maybe_add_script_file (pspace_info, bool (opened), file,
+ (opened ? opened->full_path.get ()
+ : NULL), language);
- /* Execute the script if it is on the safe path. */
- if (opened)
+ /* Execute the script if it is on the safe path. When called from
+ add-auto-load-safe-path, skip scripts that were already loaded to
+ avoid re-executing them. */
+ if (opened && (from_objfile_load || !was_loaded))
sourcer (language, objfile, opened->stream.get (),
opened->full_path.get ());
}
@@ -1019,7 +1035,7 @@ execute_script_contents (struct auto_load_pspace_info *pspace_info,
struct objfile *objfile,
const struct extension_language_defn *language,
const char *section_name, unsigned int offset,
- const char *script)
+ const char *script, bool from_objfile_load)
{
objfile_script_executor_func *executor;
const char *newline, *script_text;
@@ -1081,12 +1097,16 @@ of file %ps."),
("Loading %s script \"%s\" from section \"%s\" of objfile \"%s\".",
ext_lang_name (language), name, section_name, objfile_name (objfile));
- bool is_safe = file_is_auto_load_safe (objfile_name (objfile));
+ bool is_safe = file_is_auto_load_safe (objfile_name (objfile),
+ from_objfile_load);
- maybe_add_script_text (pspace_info, is_safe, name, language);
+ bool was_loaded = maybe_add_script_text (pspace_info, is_safe, name,
+ language);
- /* Execute the script if it is on the safe path. */
- if (is_safe)
+ /* Execute the script if it is on the safe path. When called from
+ add-auto-load-safe-path, skip scripts that were already loaded to
+ avoid re-executing them. */
+ if (is_safe && (from_objfile_load || !was_loaded))
executor (language, objfile, name, script_text);
}
@@ -1104,7 +1124,8 @@ of file %ps."),
static void
source_section_scripts (struct objfile *objfile, const char *section_name,
- const char *start, const char *end)
+ const char *start, const char *end,
+ bool from_objfile_load)
{
auto_load_pspace_info *pspace_info
= get_auto_load_pspace_data_for_loading (objfile->pspace ());
@@ -1155,12 +1176,13 @@ source_section_scripts (struct objfile *objfile, const char *section_name,
continue;
}
source_script_file (pspace_info, objfile, language,
- section_name, offset, entry);
+ section_name, offset, entry, from_objfile_load);
break;
case SECTION_SCRIPT_ID_PYTHON_TEXT:
case SECTION_SCRIPT_ID_SCHEME_TEXT:
execute_script_contents (pspace_info, objfile, language,
- section_name, offset, entry);
+ section_name, offset, entry,
+ from_objfile_load);
break;
}
}
@@ -1169,7 +1191,8 @@ source_section_scripts (struct objfile *objfile, const char *section_name,
/* Load scripts specified in section SECTION_NAME of OBJFILE. */
static void
-auto_load_section_scripts (struct objfile *objfile, const char *section_name)
+auto_load_section_scripts (struct objfile *objfile, const char *section_name,
+ bool from_objfile_load)
{
bfd *abfd = objfile->obfd.get ();
asection *scripts_sect;
@@ -1188,7 +1211,8 @@ auto_load_section_scripts (struct objfile *objfile, const char *section_name)
else
{
const char *p = (const char *) data.data ();
- source_section_scripts (objfile, section_name, p, p + data.size ());
+ source_section_scripts (objfile, section_name, p, p + data.size (),
+ from_objfile_load);
}
}
@@ -1196,10 +1220,17 @@ auto_load_section_scripts (struct objfile *objfile, const char *section_name)
Two flavors of auto-loaded scripts are supported.
1) based on the path to the objfile
- 2) from .debug_gdb_scripts section */
+ 2) from .debug_gdb_scripts section
+
+ This function is called either when OBJFILE is loaded by GDB, or when the
+ user runs add-auto-load-safe-path to retry scripts that were previously
+ blocked by the safe-path. FROM_OBJFILE_LOAD distinguishes the two cases:
+ 1) true: the objfile was just loaded, scripts are always executed if safe.
+ 2) false: add-auto-load-safe-path was run, scripts that were already loaded
+ are skipped to avoid re-executing them. */
void
-load_auto_scripts_for_objfile (struct objfile &objfile)
+load_auto_scripts_for_objfile (struct objfile &objfile, bool from_objfile_load)
{
/* Return immediately if auto-loading has been globally disabled.
This is to handle sequencing of operations during gdb startup.
@@ -1212,10 +1243,10 @@ load_auto_scripts_for_objfile (struct objfile &objfile)
/* Load any extension language scripts for this objfile.
E.g., foo-gdb.gdb, foo-gdb.py. */
- auto_load_ext_lang_scripts_for_objfile (&objfile);
+ auto_load_ext_lang_scripts_for_objfile (&objfile, from_objfile_load);
/* Load any scripts mentioned in AUTO_SECTION_NAME (.debug_gdb_scripts). */
- auto_load_section_scripts (&objfile, AUTO_SECTION_NAME);
+ auto_load_section_scripts (&objfile, AUTO_SECTION_NAME, from_objfile_load);
}
/* Collect scripts to be printed in a vec. */
@@ -1567,9 +1598,9 @@ INIT_GDB_FILE (auto_load)
python_name_help, guile_name_help;
const char *suffix;
- gdb::observers::new_objfile.attach (load_auto_scripts_for_objfile,
- auto_load_new_objfile_observer_token,
- "auto-load");
+ gdb::observers::new_objfile.attach ([] (struct objfile &objfile)
+ { load_auto_scripts_for_objfile (objfile); },
+ auto_load_new_objfile_observer_token, "auto-load");
gdb::observers::all_objfiles_removed.attach (clear_section_scripts,
"auto-load");
add_setshow_boolean_cmd ("gdb-scripts", class_support,
diff --git a/gdb/auto-load.h b/gdb/auto-load.h
index d0da69373c3..26d364efb77 100644
--- a/gdb/auto-load.h
+++ b/gdb/auto-load.h
@@ -58,8 +58,10 @@ extern gdb::observers::token auto_load_new_objfile_observer_token;
extern struct auto_load_pspace_info *
get_auto_load_pspace_data_for_loading (struct program_space *pspace);
extern void auto_load_objfile_script (struct objfile *objfile,
- const struct extension_language_defn *);
-extern void load_auto_scripts_for_objfile (struct objfile &objfile);
+ const struct extension_language_defn *,
+ bool from_objfile_load = true);
+extern void load_auto_scripts_for_objfile (struct objfile &objfile,
+ bool from_objfile_load = true);
extern char auto_load_info_scripts_pattern_nl[];
extern void auto_load_info_scripts (program_space *pspace, const char *pattern,
int from_tty,
@@ -70,14 +72,15 @@ extern struct cmd_list_element **auto_load_show_cmdlist_get (void);
extern struct cmd_list_element **auto_load_info_cmdlist_get (void);
/* Return true if FILENAME is located in one of the directories of
- AUTO_LOAD_SAFE_PATH. Otherwise call warning and return false. FILENAME does
- not have to be an absolute path.
+ AUTO_LOAD_SAFE_PATH. Otherwise call warning if PRINT_WARNING and return
+ false. FILENAME does not have to be an absolute path.
Existence of FILENAME is not checked. Function will still give a warning
even if the caller would quietly skip non-existing file in unsafe
directory. */
-extern bool file_is_auto_load_safe (const char *filename);
+extern bool file_is_auto_load_safe (const char *filename,
+ bool print_warning = true);
/* Return true if auto-loading gdb scripts is enabled. */
diff --git a/gdb/extension.c b/gdb/extension.c
index d8ef8123ab5..c5cdad4c9f7 100644
--- a/gdb/extension.c
+++ b/gdb/extension.c
@@ -372,17 +372,18 @@ eval_ext_lang_from_control_command (struct command_line *cmd)
OBJFILE-gdb.gdb. */
void
-auto_load_ext_lang_scripts_for_objfile (struct objfile *objfile)
+auto_load_ext_lang_scripts_for_objfile (struct objfile *objfile,
+ bool from_objfile_load)
{
const struct extension_language_defn *gdb = &extension_language_gdb;
if (ext_lang_auto_load_enabled (gdb))
- auto_load_objfile_script (objfile, gdb);
+ auto_load_objfile_script (objfile, gdb, from_objfile_load);
for (const struct extension_language_defn *extlang : extension_languages)
{
if (extlang->ops != nullptr
&& ext_lang_auto_load_enabled (extlang))
- auto_load_objfile_script (objfile, extlang);
+ auto_load_objfile_script (objfile, extlang, from_objfile_load);
}
}
\f
diff --git a/gdb/extension.h b/gdb/extension.h
index 38a2ca5f887..82456bd2527 100644
--- a/gdb/extension.h
+++ b/gdb/extension.h
@@ -289,7 +289,8 @@ extern void ext_lang_shutdown ();
extern void eval_ext_lang_from_control_command (struct command_line *cmd);
-extern void auto_load_ext_lang_scripts_for_objfile (struct objfile *);
+extern void auto_load_ext_lang_scripts_for_objfile (struct objfile *,
+ bool from_objfile_load = true);
extern gdb::unique_xmalloc_ptr<char> apply_ext_lang_type_printers
(struct ext_lang_type_printers *, struct type *);
diff --git a/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event.exp b/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event.exp
index cf0bdb80c51..63d070d1b20 100644
--- a/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event.exp
+++ b/gdb/testsuite/gdb.python/py-autoloaded-pretty-printers-in-newobjfile-event.exp
@@ -17,7 +17,9 @@
# defined in a Python script that is autoloaded are registered when an event
# handler for the new_objfile event is called. It also tests that scripts
# which were not loaded because the auto-load safe-path did not cover them are
-# loaded on the next run once the safe-path is widened.
+# loaded on the next run once the safe-path is widened. Finally, it tests that
+# add-auto-load-safe-path immediately retries previously blocked scripts without
+# requiring a re-run.
load_lib gdb-python.exp
@@ -144,6 +146,33 @@ proc newobjfile_event_test { variant } {
gdb_breakpoint [gdb_get_line_number "break to inspect"]
gdb_test "continue" "Breakpoint $decimal, main .*"
gdb_test "print test" "MyClassTestLib object, id: 1.*"
+
+ # Test that add-auto-load-safe-path immediately retries previously blocked
+ # scripts without requiring a re-run.
+ clean_restart
+ gdb_load ${binfile}
+ gdb_load_shlib $binfile_lib
+
+ gdb_test_no_output "set auto-load safe-path /restricted" \
+ "set restricted auto-load safe-path for refresh"
+
+ if { ![runto_main] } {
+ return
+ }
+
+ gdb_test_no_output \
+ "add-auto-load-safe-path ${safe_path_allow}" \
+ "add auto-load safe-path"
+
+ gdb_test_multiple "info auto-load python-scripts" \
+ "verify script loaded after refresh" {
+ -re -wrap "Yes.*${script_name}.*" {
+ pass $gdb_test_name
+ }
+ -re -wrap "No.*${script_name}.*" {
+ fail $gdb_test_name
+ }
+ }
}
}
--
2.43.0
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-09-03 9:26 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-01 14:06 [PATCH] [gdb] Fix auto-load script re-execution on subsequent runs Tudor-Stefan Magirescu
2026-09-03 9:21 ` [PATCH v2 0/2] Fix auto-load script loading after safe-path is widened Tudor-Stefan Magirescu
2026-09-03 9:22 ` [PATCH v2 1/2] [gdb] Fix auto-load script re-execution on subsequent runs Tudor-Stefan Magirescu
2026-09-03 9:22 ` [PATCH v2 2/2] [gdb] Retry blocked auto-load scripts when safe-path is widened Tudor-Stefan Magirescu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox