From: Tudor-Stefan Magirescu <tudor.magirescu@gmail.com>
To: gdb-patches@sourceware.org
Cc: Tudor-Stefan Magirescu <tudor.magirescu@gmail.com>
Subject: [PATCH] [gdb] Fix auto-load script re-execution on subsequent runs
Date: Tue, 1 Sep 2026 16:06:02 +0200 [thread overview]
Message-ID: <20260901140602.3287196-1-tudor.magirescu@gmail.com> (raw)
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
next reply other threads:[~2026-09-01 14:09 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-01 14:06 Tudor-Stefan Magirescu [this message]
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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260901140602.3287196-1-tudor.magirescu@gmail.com \
--to=tudor.magirescu@gmail.com \
--cc=gdb-patches@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox