* [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