Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Tudor-Stefan Magirescu <tudor.magirescu@gmail.com>
To: gdb-patches@sourceware.org
Cc: tudor.magirescu@gmail.com
Subject: [PATCH v2 2/2] [gdb] Retry blocked auto-load scripts when safe-path is widened
Date: Thu,  3 Sep 2026 11:22:01 +0200	[thread overview]
Message-ID: <20260903092201.663063-3-tudor.magirescu@gmail.com> (raw)
In-Reply-To: <20260903092201.663063-1-tudor.magirescu@gmail.com>

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


      parent reply	other threads:[~2026-09-03  9:26 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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   ` Tudor-Stefan Magirescu [this message]

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=20260903092201.663063-3-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