[3/3,v2] Load system gdbinit files from a directory

Message ID 20190826003310.86830-1-cbiesinger@google.com
State New, archived
Headers

Commit Message

Terekhov, Mikhail via Gdb-patches Aug. 26, 2019, 12:33 a.m. UTC
  [Adds NEWS entry, documentation, and fixes Sergio's review comments. This
should also be suitable to replace Fedora's custom gdbinit because it does
support loading .py files correctly, because it calls source_script (this
was also the case in the previous version.

I don't know how to write a test for this]

Adds a configure option --with-system-gdbinit-dir to specify a directory
in which to look for gdbinit files. All files in this directory are
loaded on startup (subject to -n/-nx as usual).

gdb/ChangeLog:

2019-08-20  Christian Biesinger  <cbiesinger@google.com>

	* NEWS: Mention new --with-system-gdbinit-dir option.
	* config.in: Regenerate.
	* configure: Regenerate.
	* configure.ac: Add new option --with-system-gdbinit-dir.
	* main.c (get_init_files): Change system_gdbinit argument to
	a vector and return the files in SYSTEM_GDBINIT_DIR in
	addition to SYSTEM_GDBINIT.
	(captured_main_1): Update.
	(print_gdb_help): Update.

gdb/doc/ChangeLog:

2019-08-25  Christian Biesinger  <cbiesinger@google.com>

	* gdb.texinfo (many sections): Document new --with-system-gdbinit-dir
	option.
---
 gdb/NEWS            |  5 ++++
 gdb/config.in       |  7 ++++++
 gdb/configure       | 51 +++++++++++++++++++++++++++++++++++++
 gdb/configure.ac    |  3 +++
 gdb/doc/gdb.texinfo | 61 +++++++++++++++++++++++++++++++++++++++------
 gdb/main.c          | 56 ++++++++++++++++++++++++++++++++++-------
 6 files changed, 166 insertions(+), 17 deletions(-)
  

Comments

Eli Zaretskii Aug. 26, 2019, 7:22 a.m. UTC | #1
> Date: Sun, 25 Aug 2019 19:33:10 -0500
> From: "Christian Biesinger via gdb-patches" <gdb-patches@sourceware.org>
> Cc: Christian Biesinger <cbiesinger@google.com>
> 
> Adds a configure option --with-system-gdbinit-dir to specify a directory
> in which to look for gdbinit files. All files in this directory are
> loaded on startup (subject to -n/-nx as usual).

I think this option's value should be displayed by "show
configuration" and by "gdb --config".

> +* If configured with --with-system-gdbinit-dir, GDB will now also load

I think "also" here might be confusing, because it lacks context.  I
think we should say explicitly "in addition to the system-wide gdbinit
file" instead.

> +  all files in that directory as system gdbinit files, unless the -nx
> +  or -n flag is provided. These files can be written in any supported

Two spaces between sentences (here and elsewhere throughout the
patch).

> +@item @file{system.gdbinit.d}
> +This is the system-wide init directory.
> +Its location is specified with the @code{--with-system-gdbinit-dir}
> +configure option (@pxref{System-wide configuration}).
> +Files in this directory are loaded immediately after system.gdbinit (if
> +enabled) when @value{GDBN} starts, before command line options have been
> +processed.

I'm not sure I understand: _all_ files in that directory will be
loaded, regardless of how they are named?  If so, I think we should
say that explicitly.  We should probably also say that the order the
files are loaded is arbitrary.  Also, we should say something about
that directory including subdirectories, because I think the reader
might wonder about that.

>  @cindex init file
>  Reads the system-wide @dfn{init file} (if @option{--with-system-gdbinit} was
>  used when building @value{GDBN}; @pxref{System-wide configuration,
> - ,System-wide configuration and settings}) and executes all the commands in
> -that file.
> + ,System-wide configuration and settings}) and the files in the system-wide
> +gdbinit directory (if @option{--with-system-gdbinit-dir} was used) and executes
> +all the commands in those files. If scripting languages are enabled, the files
> +can be written in any of the supported languages as long as the extension matches
> +the language.

Is the order of reading as described, i.e. the file first, then the
files in the directory?

Btw, how does this option interact with auto-load safe-path?  Would
GDB refuse to load init files from this directory if it considers them
"unsafe"?

> +@item --with-system-gdbinit-dir=@var{directory}
> +Configure @value{GDBN} to automatically load init files from a
> +system-wide directory.  @var{directory} should be an absolute path.
                                                        ^^^^^^^^^^^^^
"absolute file name".  The Gnu Coding Standards frown on using "path"
for anything that is not PATH-style lists of directories.

> +@ifset SYSTEM_GDBINIT
> +@value{SYSTEM_GDBINIT_DIR}/*
> +@end ifset

@ifset SYSTEM_GDBINIT or @ifset SYSTEM_GDBINIT_DIR?

Thanks.
  
Terekhov, Mikhail via Gdb-patches Sept. 12, 2019, 10:11 p.m. UTC | #2
Thanks for the review!

On Mon, Aug 26, 2019 at 2:22 AM Eli Zaretskii <eliz@gnu.org> wrote:
>
> > Date: Sun, 25 Aug 2019 19:33:10 -0500
> > From: "Christian Biesinger via gdb-patches" <gdb-patches@sourceware.org>
> > Cc: Christian Biesinger <cbiesinger@google.com>
> >
> > Adds a configure option --with-system-gdbinit-dir to specify a directory
> > in which to look for gdbinit files. All files in this directory are
> > loaded on startup (subject to -n/-nx as usual).
>
> I think this option's value should be displayed by "show
> configuration" and by "gdb --config".

Done.

> > +* If configured with --with-system-gdbinit-dir, GDB will now also load
>
> I think "also" here might be confusing, because it lacks context.  I
> think we should say explicitly "in addition to the system-wide gdbinit
> file" instead.

Done.

> > +  all files in that directory as system gdbinit files, unless the -nx
> > +  or -n flag is provided. These files can be written in any supported
>
> Two spaces between sentences (here and elsewhere throughout the
> patch).

I think I fixed all occurrences. (searching gdb.texinfo for "\. [^ ]"
found a lot of existing places that do it wrong :( )

> > +@item @file{system.gdbinit.d}
> > +This is the system-wide init directory.
> > +Its location is specified with the @code{--with-system-gdbinit-dir}
> > +configure option (@pxref{System-wide configuration}).
> > +Files in this directory are loaded immediately after system.gdbinit (if
> > +enabled) when @value{GDBN} starts, before command line options have been
> > +processed.
>
> I'm not sure I understand: _all_ files in that directory will be
> loaded, regardless of how they are named?  If so, I think we should
> say that explicitly.

I changed it now so that only .gdb/.py/.scm is loaded, and documented that.

> We should probably also say that the order the
> files are loaded is arbitrary.

They're actually alphabetically sorted; added a note in the
documentation about that.

>  Also, we should say something about
> that directory including subdirectories, because I think the reader
> might wonder about that.

Done.

> >  @cindex init file
> >  Reads the system-wide @dfn{init file} (if @option{--with-system-gdbinit} was
> >  used when building @value{GDBN}; @pxref{System-wide configuration,
> > - ,System-wide configuration and settings}) and executes all the commands in
> > -that file.
> > + ,System-wide configuration and settings}) and the files in the system-wide
> > +gdbinit directory (if @option{--with-system-gdbinit-dir} was used) and executes
> > +all the commands in those files. If scripting languages are enabled, the files
> > +can be written in any of the supported languages as long as the extension matches
> > +the language.
>
> Is the order of reading as described, i.e. the file first, then the
> files in the directory?

Yes.

> Btw, how does this option interact with auto-load safe-path?  Would
> GDB refuse to load init files from this directory if it considers them
> "unsafe"?

No, that is not consulted for these files (if it were, the system
gdbinit file or ~/.gdbinit would not work in the common case, because
the auto-load path is $debugdir:$datadir/auto-load)

> > +@item --with-system-gdbinit-dir=@var{directory}
> > +Configure @value{GDBN} to automatically load init files from a
> > +system-wide directory.  @var{directory} should be an absolute path.
>                                                         ^^^^^^^^^^^^^
> "absolute file name".  The Gnu Coding Standards frown on using "path"
> for anything that is not PATH-style lists of directories.

Changed to "absolute directory name"; I didn't want to use "file name"
for a directory.

(looks like a number of other occurrences in gdb.texinfo should be
changed too...)

> > +@ifset SYSTEM_GDBINIT
> > +@value{SYSTEM_GDBINIT_DIR}/*
> > +@end ifset
>
> @ifset SYSTEM_GDBINIT or @ifset SYSTEM_GDBINIT_DIR?

Thanks, fixed.

Will send a new patch in a second.

Christian
  

Patch

diff --git a/gdb/NEWS b/gdb/NEWS
index 0a4e0f260f..fcc9c6f41f 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -27,6 +27,11 @@ 
   provide the exitcode or exit status of the shell commands launched by
   GDB commands such as "shell", "pipe" and "make".
 
+* If configured with --with-system-gdbinit-dir, GDB will now also load
+  all files in that directory as system gdbinit files, unless the -nx
+  or -n flag is provided. These files can be written in any supported
+  scripting language as long as they have a matching file extension.
+
 * Python API
 
   ** The gdb.Value type has a new method 'format_string' which returns a
diff --git a/gdb/config.in b/gdb/config.in
index 26ca02f6a3..c0745c90a3 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -684,6 +684,13 @@ 
 /* automatically load a system-wide gdbinit file */
 #undef SYSTEM_GDBINIT
 
+/* automatically load system-wide gdbinit files from this directory */
+#undef SYSTEM_GDBINIT_DIR
+
+/* Define if the system-gdbinit-dir directory should be relocated when GDB is
+   moved. */
+#undef SYSTEM_GDBINIT_DIR_RELOCATABLE
+
 /* Define if the system-gdbinit directory should be relocated when GDB is
    moved. */
 #undef SYSTEM_GDBINIT_RELOCATABLE
diff --git a/gdb/configure b/gdb/configure
index 22a5f6051d..8436f06c9f 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -693,6 +693,7 @@  WIN32LIBS
 SER_HARDWIRE
 WERROR_CFLAGS
 WARN_CFLAGS
+SYSTEM_GDBINIT_DIR
 SYSTEM_GDBINIT
 TARGET_SYSTEM_ROOT
 CONFIG_LDFLAGS
@@ -884,6 +885,7 @@  with_libipt_prefix
 with_included_regex
 with_sysroot
 with_system_gdbinit
+with_system_gdbinit_dir
 enable_werror
 enable_build_warnings
 enable_gdb_build_warnings
@@ -1618,6 +1620,9 @@  Optional Packages:
   --with-sysroot[=DIR]    search for usr/lib et al within DIR
   --with-system-gdbinit=PATH
                           automatically load a system-wide gdbinit file
+  --with-system-gdbinit-dir=PATH
+                          automatically load system-wide gdbinit files from
+                          this directory
   --with-lzma             support lzma compression (auto/yes/no)
   --with-liblzma-prefix[=DIR]  search for liblzma in DIR/include and DIR/lib
   --without-liblzma-prefix     don't search for liblzma in includedir and libdir
@@ -15238,6 +15243,52 @@  _ACEOF
 
 
 
+# Check whether --with-system-gdbinit-dir was given.
+if test "${with_system_gdbinit_dir+set}" = set; then :
+  withval=$with_system_gdbinit_dir;
+    SYSTEM_GDBINIT_DIR=$withval
+else
+  SYSTEM_GDBINIT_DIR=
+fi
+
+
+  test "x$prefix" = xNONE && prefix="$ac_default_prefix"
+  test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+  ac_define_dir=`eval echo $SYSTEM_GDBINIT_DIR`
+  ac_define_dir=`eval echo $ac_define_dir`
+
+cat >>confdefs.h <<_ACEOF
+#define SYSTEM_GDBINIT_DIR "$ac_define_dir"
+_ACEOF
+
+
+
+
+  if test "x$exec_prefix" = xNONE || test "x$exec_prefix" = 'x${prefix}'; then
+     if test "x$prefix" = xNONE; then
+     	test_prefix=/usr/local
+     else
+	test_prefix=$prefix
+     fi
+  else
+     test_prefix=$exec_prefix
+  fi
+  value=0
+  case ${ac_define_dir} in
+     "${test_prefix}"|"${test_prefix}/"*|\
+	'${exec_prefix}'|'${exec_prefix}/'*)
+     value=1
+     ;;
+  esac
+
+cat >>confdefs.h <<_ACEOF
+#define SYSTEM_GDBINIT_DIR_RELOCATABLE $value
+_ACEOF
+
+
+
+
+
 # Check whether --enable-werror was given.
 if test "${enable_werror+set}" = set; then :
   enableval=$enable_werror; case "${enableval}" in
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 9da8818fb5..f3f5bd0635 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -1843,6 +1843,9 @@  GDB_AC_DEFINE_RELOCATABLE(TARGET_SYSTEM_ROOT, sysroot, ${ac_define_dir})
 GDB_AC_WITH_DIR(SYSTEM_GDBINIT, system-gdbinit,
     [automatically load a system-wide gdbinit file],
     [])
+GDB_AC_WITH_DIR(SYSTEM_GDBINIT_DIR, system-gdbinit-dir,
+    [automatically load system-wide gdbinit files from this directory],
+    [])
 
 AM_GDB_WARNINGS
 AM_GDB_UBSAN
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index bcf0420779..a43c4651c0 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -1083,6 +1083,13 @@  Its location is specified with the @code{--with-system-gdbinit}
 configure option (@pxref{System-wide configuration}).
 It is loaded first when @value{GDBN} starts, before command line options
 have been processed.
+@item @file{system.gdbinit.d}
+This is the system-wide init directory.
+Its location is specified with the @code{--with-system-gdbinit-dir}
+configure option (@pxref{System-wide configuration}).
+Files in this directory are loaded immediately after system.gdbinit (if
+enabled) when @value{GDBN} starts, before command line options have been
+processed.
 @item @file{~/.gdbinit}
 This is the init file in your home directory.
 It is loaded next, after @file{system.gdbinit}, and before
@@ -1315,8 +1322,11 @@  Sets up the command interpreter as specified by the command line
 @cindex init file
 Reads the system-wide @dfn{init file} (if @option{--with-system-gdbinit} was
 used when building @value{GDBN}; @pxref{System-wide configuration,
- ,System-wide configuration and settings}) and executes all the commands in
-that file.
+ ,System-wide configuration and settings}) and the files in the system-wide
+gdbinit directory (if @option{--with-system-gdbinit-dir} was used) and executes
+all the commands in those files. If scripting languages are enabled, the files
+can be written in any of the supported languages as long as the extension matches
+the language.
 
 @anchor{Home Directory Init File}
 @item
@@ -37010,6 +37020,14 @@  directory under the configured prefix, and @value{GDBN} is moved to
 another location after being built, the location of the system-wide
 init file will be adjusted accordingly.
 
+@item --with-system-gdbinit-dir=@var{directory}
+Configure @value{GDBN} to automatically load init files from a
+system-wide directory.  @var{directory} should be an absolute path.
+If @var{directory} is in a directory under the configured prefix, and
+@value{GDBN} is moved to another location after being built, the
+location of the system-wide init directory will be adjusted
+accordingly.
+
 @item --enable-build-warnings
 When building the @value{GDBN} sources, ask the compiler to warn about
 any code which looks even vaguely suspicious.  It passes many
@@ -37035,24 +37053,27 @@  was first introduced in GCC 4.9.
 @section System-wide configuration and settings
 @cindex system-wide init file
 
-@value{GDBN} can be configured to have a system-wide init file;
-this file will be read and executed at startup (@pxref{Startup, , What
-@value{GDBN} does during startup}).
+@value{GDBN} can be configured to have a system-wide init file and a system-wide
+init file directory; this file and files in that directory will be read and
+executed at startup (@pxref{Startup, , What @value{GDBN} does during startup}).
 
-Here is the corresponding configure option:
+Here are the corresponding configure options:
 
 @table @code
 @item --with-system-gdbinit=@var{file}
 Specify that the default location of the system-wide init file is
 @var{file}.
+@item --with-system-gdbinit-dir=@var{directory}
+Specify that the default location of the system-wide init file directory
+is @var{directory}.
 @end table
 
 If @value{GDBN} has been configured with the option @option{--prefix=$prefix},
-it may be subject to relocation.  Two possible cases:
+they may be subject to relocation.  Two possible cases:
 
 @itemize @bullet
 @item 
-If the default location of this init file contains @file{$prefix},
+If the default location of this init file/directory contains @file{$prefix},
 it will be subject to relocation.  Suppose that the configure options
 are @option{--prefix=$prefix --with-system-gdbinit=$prefix/etc/gdbinit};
 if @value{GDBN} is moved from @file{$prefix} to @file{$install}, the system
@@ -37078,6 +37099,12 @@  initialization.  If the data-directory is changed after @value{GDBN} has
 started with the @code{set data-directory} command, the file will not be
 reread.
 
+This applies similarly to the system-wide directory specified in
+@option{--with-system-gdbinit-dir}.
+
+Any supported scripting language can be used for these init files, as long
+as the file extension matches the scripting language.
+
 @menu
 * System-wide Configuration Scripts::  Installed System-wide Configuration Scripts
 @end menu
@@ -45598,6 +45625,10 @@  Richard M. Stallman and Roland H. Pesch, July 1991.
 @value{SYSTEM_GDBINIT}
 @end ifset
 
+@ifset SYSTEM_GDBINIT
+@value{SYSTEM_GDBINIT_DIR}/*
+@end ifset
+
 ~/.gdbinit
 
 ./.gdbinit
@@ -45639,6 +45670,20 @@  See more in
 the @value{GDBN} manual in node @code{System-wide configuration}
 -- shell command @code{info -f gdb -n 'System-wide configuration'}.
 @end ifset
+@ifset SYSTEM_GDBINIT_DIR
+@item @value{SYSTEM_GDBINIT_DIR}
+@end ifset
+@ifclear SYSTEM_GDBINIT_DIR
+@item (not enabled with @code{--with-system-gdbinit-dir} during compilation)
+@end ifclear
+System-wide initialization directory.  All files in this directory are
+executed on startup unless user specified @value{GDBN} option @code{-nx} or
+@code{-n}.
+See more in
+@ifset man
+the @value{GDBN} manual in node @code{System-wide configuration}
+-- shell command @code{info -f gdb -n 'System-wide configuration'}.
+@end ifset
 @ifclear man
 @ref{System-wide configuration}.
 @end ifclear
diff --git a/gdb/main.c b/gdb/main.c
index 089a7628e5..19cd723ba8 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -45,6 +45,7 @@ 
 #include "event-top.h"
 #include "infrun.h"
 #include "gdbsupport/signals-state-save-restore.h"
+#include <algorithm>
 #include <vector>
 #include "gdbsupport/pathstuff.h"
 #include "cli/cli-style.h"
@@ -234,11 +235,11 @@  relocate_gdbinit_path_maybe_in_datadir (const std::string& file)
    to be loaded, then SYSTEM_GDBINIT (resp. HOME_GDBINIT and
    LOCAL_GDBINIT) is set to the empty string.  */
 static void
-get_init_files (std::string *system_gdbinit,
+get_init_files (std::vector<std::string> *system_gdbinit,
 		std::string *home_gdbinit,
 		std::string *local_gdbinit)
 {
-  static std::string sysgdbinit;
+  static std::vector<std::string> sysgdbinit;
   static std::string homeinit;
   static std::string localinit;
   static int initialized = 0;
@@ -253,7 +254,32 @@  get_init_files (std::string *system_gdbinit,
 	    relocate_gdbinit_path_maybe_in_datadir (SYSTEM_GDBINIT);
 	  if (!relocated_sysgdbinit.empty () &&
 	      stat (relocated_sysgdbinit.c_str (), &s) == 0)
-	    sysgdbinit = relocated_sysgdbinit;
+	    sysgdbinit.push_back(relocated_sysgdbinit);
+	}
+      if (SYSTEM_GDBINIT_DIR[0])
+        {
+	  std::string relocated_gdbinit_dir =
+	    relocate_gdbinit_path_maybe_in_datadir (SYSTEM_GDBINIT_DIR);
+	  DIR* dir = nullptr;
+	  if (!relocated_gdbinit_dir.empty ())
+	    dir = opendir (relocated_gdbinit_dir.c_str ());
+	  if (dir != nullptr) 
+	    {
+	      std::vector<std::string> files;
+	      struct dirent* ent;
+	      for (;;)
+	        {
+		  ent = readdir (dir);
+		  if (ent == nullptr)
+		    break;
+		  if (ent->d_type == DT_REG && ent->d_name[0] != '.')
+		    files.push_back (relocated_gdbinit_dir + SLASH_STRING +
+				     ent->d_name);
+		}
+	      closedir (dir);
+	      std::sort (files.begin (), files.end ());
+	      sysgdbinit.insert (sysgdbinit.end (), files.begin (), files.end ());
+	    }
 	}
 
       const char *homedir = getenv ("HOME");
@@ -911,7 +937,7 @@  captured_main_1 (struct captured_main_args *context)
   /* Lookup gdbinit files.  Note that the gdbinit file name may be
      overriden during file initialization, so get_init_files should be
      called after gdb_init.  */
-  std::string system_gdbinit;
+  std::vector<std::string> system_gdbinit;
   std::string home_gdbinit;
   std::string local_gdbinit;
   get_init_files (&system_gdbinit, &home_gdbinit, &local_gdbinit);
@@ -991,7 +1017,10 @@  captured_main_1 (struct captured_main_args *context)
      processed; it sets global parameters, which are independent of
      what file you are debugging or what directory you are in.  */
   if (!system_gdbinit.empty () && !inhibit_gdbinit)
-    ret = catch_command_errors (source_script, system_gdbinit.c_str (), 0);
+    {
+      for (const std::string& file : system_gdbinit)
+	ret = catch_command_errors (source_script, file.c_str (), 0);
+    }
 
   /* Read and execute $HOME/.gdbinit file, if it exists.  This is done
      *before* all the command line arguments are processed; it sets
@@ -1209,7 +1238,7 @@  gdb_main (struct captured_main_args *args)
 static void
 print_gdb_help (struct ui_file *stream)
 {
-  std::string system_gdbinit;
+  std::vector<std::string> system_gdbinit;
   std::string home_gdbinit;
   std::string local_gdbinit;
 
@@ -1290,9 +1319,18 @@  Other options:\n\n\
 At startup, GDB reads the following init files and executes their commands:\n\
 "), stream);
   if (!system_gdbinit.empty ())
-    fprintf_unfiltered (stream, _("\
-   * system-wide init file: %s\n\
-"), system_gdbinit.c_str ());
+    {
+      std::string output;
+      for (size_t idx = 0; idx < system_gdbinit.size (); ++idx)
+        {
+	  output += system_gdbinit[idx];
+	  if (idx < system_gdbinit.size () - 1)
+	    output += ", ";
+	}
+      fprintf_unfiltered (stream, _("\
+   * system-wide init files: %s\n\
+"), output.c_str ());
+    }
   if (!home_gdbinit.empty ())
     fprintf_unfiltered (stream, _("\
    * user-specific init file: %s\n\