From ed2a222951020d1117c5e1d4f37e82fd26761267 Mon Sep 17 00:00:00 2001 From: Christian Biesinger Date: Sun, 13 Oct 2019 07:12:34 -0500 Subject: [PATCH] Load system gdbinit files from a directory 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) as long as the extension matches a known and enabled scripting language (.gdb/.py/.scm). This also changes get_ext_lang_of_file to support ".gdb" files, similar to get_ext_lang_defn's handling of EXT_LANG_GDB. gdb/ChangeLog: 2019-10-29 Christian Biesinger * NEWS: Mention new --with-system-gdbinit-dir option. * config.in: Regenerate. * configure: Regenerate. * configure.ac: Add new option --with-system-gdbinit-dir. * extension.c (get_ext_lang_of_file): Return extension_language_gdb for a ".gdb" suffix. * 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. * top.c (print_gdb_configuration): Also print the value of SYSTEM_GDBINIT_DIR. gdb/doc/ChangeLog: 2019-10-29 Christian Biesinger * Makefile.in: Also set SYSTEM_GDBINIT_DIR for the info manual generation. * gdb.texinfo (many sections): Document new --with-system-gdbinit-dir option. Change-Id: If233859ecc21bc6421d589b37cd658a3c7d030f2 --- gdb/ChangeLog | 16 +++++++++ gdb/NEWS | 6 ++++ gdb/config.in | 7 ++++ gdb/configure | 51 ++++++++++++++++++++++++++++ gdb/configure.ac | 3 ++ gdb/doc/ChangeLog | 7 ++++ gdb/doc/Makefile.in | 4 +++ gdb/doc/gdb.texinfo | 74 +++++++++++++++++++++++++++++++++++----- gdb/extension.c | 3 ++ gdb/main.c | 82 +++++++++++++++++++++++++++++++++++++-------- gdb/top.c | 4 +++ 11 files changed, 235 insertions(+), 22 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 7059623788e..5cf1ae71af9 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,19 @@ +2019-10-29 Christian Biesinger + + * NEWS: Mention new --with-system-gdbinit-dir option. + * config.in: Regenerate. + * configure: Regenerate. + * configure.ac: Add new option --with-system-gdbinit-dir. + * extension.c (get_ext_lang_of_file): Return extension_language_gdb + for a ".gdb" suffix. + * 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. + * top.c (print_gdb_configuration): Also print the value of + SYSTEM_GDBINIT_DIR. + 2019-10-28 Christian Biesinger * gdbsupport/common-utils.h (startswith): Add an overloaded version diff --git a/gdb/NEWS b/gdb/NEWS index 25e67e43c88..761359862a3 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -46,6 +46,12 @@ The 'outer_function::' prefix is only needed if 'inner_function' is not visible in the current scope. +* In addition to the system-wide gdbinit file, if configured with + --with-system-gdbinit-dir, GDB will now also load files in that directory + as system gdbinit files, unless the -nx or -n flag is provided. Files + with extensions .gdb, .py and .scm are supported as long as GDB was + compiled with support for that language. + * 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 a76ac9f3e74..fc05f154b72 100644 --- a/gdb/config.in +++ b/gdb/config.in @@ -681,6 +681,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 4e2247d7cad..e8059039bd5 100755 --- a/gdb/configure +++ b/gdb/configure @@ -697,6 +697,7 @@ WIN32LIBS SER_HARDWIRE WERROR_CFLAGS WARN_CFLAGS +SYSTEM_GDBINIT_DIR SYSTEM_GDBINIT TARGET_SYSTEM_ROOT CONFIG_LDFLAGS @@ -888,6 +889,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 @@ -1624,6 +1626,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 @@ -15184,6 +15189,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 cb331be7aed..354bb7b4b68 100644 --- a/gdb/configure.ac +++ b/gdb/configure.ac @@ -1795,6 +1795,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/ChangeLog b/gdb/doc/ChangeLog index 0d0d9054941..c1538be6d4b 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,10 @@ +2019-10-29 Christian Biesinger + + * Makefile.in: Also set SYSTEM_GDBINIT_DIR for the info manual + generation. + * gdb.texinfo (many sections): Document new --with-system-gdbinit-dir + option. + 2019-10-23 Tom Tromey * Makefile.in (READLINE_DIR): Update. diff --git a/gdb/doc/Makefile.in b/gdb/doc/Makefile.in index 2673499a05b..6588a0c9fe7 100644 --- a/gdb/doc/Makefile.in +++ b/gdb/doc/Makefile.in @@ -41,6 +41,7 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ SYSTEM_GDBINIT = @SYSTEM_GDBINIT@ +SYSTEM_GDBINIT_DIR = @SYSTEM_GDBINIT_DIR@ mkinstalldirs = $(SHELL) $(srcdir)/../../mkinstalldirs @@ -425,6 +426,9 @@ GDBvn.texi : version.subst if [ -n "$(SYSTEM_GDBINIT)" ]; then \ echo "@set SYSTEM_GDBINIT $(SYSTEM_GDBINIT)" >> ./GDBvn.new; \ fi + if [ -n "$(SYSTEM_GDBINIT_DIR)" ]; then \ + echo "@set SYSTEM_GDBINIT_DIR $(SYSTEM_GDBINIT_DIR)" >> ./GDBvn.new; \ + fi mv GDBvn.new GDBvn.texi version.subst: $(gdbdir)/version.in $(gdbdir)/../bfd/version.h diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 1208e4f615e..db3d15b05e8 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -1083,6 +1083,16 @@ 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 in alphabetical order immediately after +system.gdbinit (if enabled) when @value{GDBN} starts, before command line +options have been processed. Files need to have a recognized scripting +language extension (@file{.py}/@file{.scm}) or be named with a @file{.gdb} +extension to be interpreted as regular @value{GDBN} commands. @value{GDBN} +will not recurse into any subdirectories of this directory. @item @file{~/.gdbinit} This is the init file in your home directory. It is loaded next, after @file{system.gdbinit}, and before @@ -1315,8 +1325,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. The files need to be named with a @file{.gdb} +extension to be interpreted as @value{GDBN} commands, or they can be written +in a supported scripting language with an appropriate file extension. @anchor{Home Directory Init File} @item @@ -26283,6 +26296,13 @@ Display the current value of the @code{script-extension} option. @end table +@ifset SYSTEM_GDBINIT_DIR +This setting is not used for files in the system-wide gdbinit directory. +Files in that directory must have an extension matching their language, +or have a @file{.gdb} extension to be interpreted as regular @value{GDBN} +commands. @xref{Startup}. +@end ifset + @node Sequences @section Canned Sequences of Commands @@ -37054,6 +37074,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 directory +name. 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 @@ -37079,24 +37107,28 @@ 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 +(if they have a recognized file extension) 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 @@ -37122,6 +37154,14 @@ 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. To be interpreted +as regular @value{GDBN} commands, the files needs to have a @file{.gdb} +extension. + @menu * System-wide Configuration Scripts:: Installed System-wide Configuration Scripts @end menu @@ -45611,6 +45651,10 @@ Richard M. Stallman and Roland H. Pesch, July 1991. @value{SYSTEM_GDBINIT} @end ifset +@ifset SYSTEM_GDBINIT_DIR +@value{SYSTEM_GDBINIT_DIR}/* +@end ifset + ~/.gdbinit ./.gdbinit @@ -45652,6 +45696,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}, as long as they have a recognized file extension. +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/extension.c b/gdb/extension.c index 8637bc53f2e..1fb4b48003a 100644 --- a/gdb/extension.c +++ b/gdb/extension.c @@ -154,6 +154,9 @@ get_ext_lang_of_file (const char *file) int i; const struct extension_language_defn *extlang; + if (has_extension (file, extension_language_gdb.suffix)) + return &extension_language_gdb; + ALL_EXTENSION_LANGUAGES (i, extlang) { if (has_extension (file, extlang->suffix)) diff --git a/gdb/main.c b/gdb/main.c index a77d6ec44c5..a0512549da5 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 #include #include "gdbsupport/pathstuff.h" #include "cli/cli-style.h" @@ -198,7 +199,8 @@ relocate_gdb_directory (const char *initial, bool relocatable) otherwise. */ static std::string -relocate_gdbinit_path_maybe_in_datadir (const std::string& file) +relocate_gdbinit_path_maybe_in_datadir (const std::string &file, + bool relocatable) { size_t datadir_len = strlen (GDB_DATADIR); @@ -221,9 +223,8 @@ relocate_gdbinit_path_maybe_in_datadir (const std::string& file) } else { - relocated_path = relocate_path (gdb_program_name, - file.c_str (), - SYSTEM_GDBINIT_RELOCATABLE); + relocated_path = relocate_path (gdb_program_name, file.c_str (), + relocatable); } return relocated_path; } @@ -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 *system_gdbinit, std::string *home_gdbinit, std::string *local_gdbinit) { - static std::string sysgdbinit; + static std::vector sysgdbinit; static std::string homeinit; static std::string localinit; static int initialized = 0; @@ -250,10 +251,51 @@ get_init_files (std::string *system_gdbinit, if (SYSTEM_GDBINIT[0]) { std::string relocated_sysgdbinit - = relocate_gdbinit_path_maybe_in_datadir (SYSTEM_GDBINIT); + = relocate_gdbinit_path_maybe_in_datadir + (SYSTEM_GDBINIT, SYSTEM_GDBINIT_RELOCATABLE); 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, SYSTEM_GDBINIT_DIR_RELOCATABLE); + if (!relocated_gdbinit_dir.empty ()) { + gdb_dir_up dir (opendir (relocated_gdbinit_dir.c_str ())); + if (dir != nullptr) + { + std::vector files; + for (;;) + { + struct dirent *ent = readdir (dir.get ()); + if (ent == nullptr) + break; + std::string name (ent->d_name); + if (name == "." || name == "..") + continue; + /* ent->d_type is not available on all systems (e.g. mingw, + Solaris), so we have to call stat(). */ + std::string filename + = relocated_gdbinit_dir + SLASH_STRING + name; + if (stat (filename.c_str (), &s) != 0 + || !S_ISREG (s.st_mode)) + continue; + const struct extension_language_defn *extlang + = get_ext_lang_of_file (filename.c_str ()); + /* We effectively don't support "set script-extension + off/soft", because we are loading system init files here, + so it does not really make sense to depend on a + setting. */ + if (extlang != nullptr && ext_lang_present_p (extlang)) + files.push_back (std::move (filename)); + } + std::sort (files.begin (), files.end ()); + sysgdbinit.insert (sysgdbinit.end (), + files.begin (), files.end ()); + } + } } const char *homedir = getenv ("HOME"); @@ -913,7 +955,7 @@ captured_main_1 (struct captured_main_args *context) /* Lookup gdbinit files. Note that the gdbinit file name may be overridden during file initialization, so get_init_files should be called after gdb_init. */ - std::string system_gdbinit; + std::vector system_gdbinit; std::string home_gdbinit; std::string local_gdbinit; get_init_files (&system_gdbinit, &home_gdbinit, &local_gdbinit); @@ -993,7 +1035,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 @@ -1211,7 +1256,7 @@ gdb_main (struct captured_main_args *args) static void print_gdb_help (struct ui_file *stream) { - std::string system_gdbinit; + std::vector system_gdbinit; std::string home_gdbinit; std::string local_gdbinit; @@ -1292,9 +1337,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\ diff --git a/gdb/top.c b/gdb/top.c index 15d4fab8beb..a443159e3e7 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -1513,6 +1513,10 @@ This GDB was configured as follows:\n\ fprintf_filtered (stream, _("\ --with-system-gdbinit=%s%s\n\ "), SYSTEM_GDBINIT, SYSTEM_GDBINIT_RELOCATABLE ? " (relocatable)" : ""); + if (SYSTEM_GDBINIT_DIR[0]) + fprintf_filtered (stream, _("\ + --with-system-gdbinit-dir=%s%s\n\ +"), SYSTEM_GDBINIT_DIR, SYSTEM_GDBINIT_DIR_RELOCATABLE ? " (relocatable)" : ""); /* We assume "relocatable" will be printed at least once, thus we always print this text. It's a reasonably safe assumption for now. */ fprintf_filtered (stream, _("\n\ -- 2.30.2