diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 136b95d7cee..ee3aeb888ac 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,17 @@ +2021-04-15 Andrew Burgess + + PR cli/25956 + * NEWS: Mention new early init files and command line options. + * config.in: Regenerate. + * configure: Regenerate. + * configure.ac: Define GDBEARLYINIT. + * main.c (get_earlyinit_files): New function. + (enum cmdarg_kind): Add CMDARG_EARLYINIT_FILE and + CMDARG_EARLYINIT_COMMAND. + (captured_main_1): Add support for new command line flags, and for + processing startup files. + (print_gdb_help): Include startup files in the output. + 2021-04-15 Andrew Burgess * main.c (relocate_gdbinit_path_maybe_in_datadir): Rename to... diff --git a/gdb/NEWS b/gdb/NEWS index 6cf76a14317..c5f8605ab41 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -48,6 +48,18 @@ the use of the GNAT encoding (based on information added to the type's name following a GNAT-specific format). +* GDB will now load and process commands from ~/.config/gdb/gdbearlyinit + or ~/.gdbearlyinit if these files are present. These files are + processed earlier than any of the other initialization files and + can affect parts of GDB's startup that previously had already been + completed before the initialization files were read, for example + styling of the initial GDB greeting. + +* GDB now has two new options "--early-init-command" and + "--early-init-eval-command" with corresponding short options "-eix" + and "-eiex" that allow options (that would normally appear in a + gdbearlyinit file) to be passed on the command line. + * New commands set debug event-loop diff --git a/gdb/config.in b/gdb/config.in index 14a77c661d5..db860c7cea0 100644 --- a/gdb/config.in +++ b/gdb/config.in @@ -43,6 +43,9 @@ language is requested. */ #undef ENABLE_NLS +/* The .gdbearlyinit filename. */ +#undef GDBEARLYINIT + /* The .gdbinit filename. */ #undef GDBINIT diff --git a/gdb/configure b/gdb/configure index 4c80350596c..95fd6b09202 100755 --- a/gdb/configure +++ b/gdb/configure @@ -16778,6 +16778,12 @@ _ACEOF +cat >>confdefs.h <<_ACEOF +#define GDBEARLYINIT ".gdbearlyinit" +_ACEOF + + + # Support for --with-sysroot is a copy of GDB_AC_WITH_DIR, # except that the argument to --with-sysroot is optional. # --with-sysroot (or --with-sysroot=yes) sets the default sysroot path. diff --git a/gdb/configure.ac b/gdb/configure.ac index 7035014484e..12a59ee45e5 100644 --- a/gdb/configure.ac +++ b/gdb/configure.ac @@ -1819,6 +1819,9 @@ case $host_os in esac AC_DEFINE_UNQUOTED(GDBINIT,"$gdbinit",[The .gdbinit filename.]) +dnl Set the host's .gdbearlyinit filename +AC_DEFINE_UNQUOTED(GDBEARLYINIT,".gdbearlyinit",[The .gdbearlyinit filename.]) + dnl Handle optional features that can be enabled. # Support for --with-sysroot is a copy of GDB_AC_WITH_DIR, diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 2482c54c912..b27bd18ab72 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,12 @@ +2021-04-15 Andrew Burgess + + PR cli/25956 + * gdb.texinfo (File Options): Mention new command line options. + (Startup): Discuss when early init files are processed. + (Initialization Files): Add description of early init files. + (Output Styling): Update description of 'version' style. + (gdb man): Mention early init files. + 2021-04-14 Andrew Burgess * gdb.texinfo (GDB/MI Miscellaneous Commands): Add missing diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 51e1c64a98a..4351378fd05 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -1040,6 +1040,20 @@ Execute a single @value{GDBN} command before loading the inferior (but after loading gdbinit files). @xref{Startup}. +@item -early-init-command @var{file} +@itemx -eix @var{file} +@cindex @code{--early-init-command} +@cindex @code{-eix} +Execute commands from @var{file} very early in the initialization +process, before any output is produced. @xref{Startup}. + +@item -early-init-eval-command @var{command} +@itemx -eiex @var{command} +@cindex @code{--early-init-eval-command} +@cindex @code{-eiex} +Execute a single @value{GDBN} command very early in the initialization +process, before any output is produced. + @item -directory @var{directory} @itemx -d @var{directory} @cindex @code{--directory} @@ -1291,6 +1305,23 @@ important when reporting @value{GDBN} bugs (@pxref{GDB Bugs}). Here's the description of what @value{GDBN} does during session startup: @enumerate + +@item +Performs minimal setup required to initialize basic internal state. + +@item +@cindex early initialization file +Reads commands from the early initialization file (if any) in your +home directory. Only a restricted set of commands can be placed into +an early initialization file, see @ref{Initialization Files}, for +details. + +@item +Executes commands and command files specified by the @samp{-eiex} and +@samp{-eix} command line options in their specified order. Only a +restricted set of commands can be used with @samp{-eiex} and +@samp{eix}, see @ref{Initialization Files}, for details. + @item Sets up the command interpreter as specified by the command line (@pxref{Mode Options, interpreter}). @@ -1367,13 +1398,82 @@ To display the list of initialization files loaded by @value{GDBN} at startup, in the order they will be loaded, you can use @kbd{gdb --help}. +@cindex early initialization +The @dfn{early initialization} file is loaded very early in +@value{GDBN}'s initialization process, before the interpreter +(@pxref{Interpreters}) has been initialized, and before the default +target (@pxref{Targets}) is initialized. Only @code{set} or +@code{source} commands should be placed into an early initialization +file, and the only @code{set} commands that can be used are those that +control how @value{GDBN} starts up. + +Commands that can be placed into an early initialization file will be +documented as such throughout this manual. Any command that is not +documented as being suitable for an early initialization file should +instead be placed into a general initialization file. Command files +passed to @code{--early-init-command} or @code{-eix} are also early +initialization files, with the same command restrictions. Only +commands that can appear in an early initialization file should be +passed to @code{--early-init-eval-command} or @code{-eiex}. + +@cindex general initialization +In contrast, the @dfn{general initialization} files are processed +later, after @value{GDBN} has finished its own internal initialization +process, any valid command can be used in these files. + +@cindex initialization file +Throughout the rest of this document the term @dfn{initialization +file} refers to one of the general initialization files, not the early +initialization file. Any discussion of the early initialization file +will specifically mention that it is the early initialization file +being discussed. + As the system wide and home directory initialization files are processed before most command line options, changes to settings (e.g. @samp{set complaints}) can affect subsequent processing of command line options and operands. -The following sections describe where @value{GDBN} looks for the -initialization and the order that the files are searched for. +The following sections describe where @value{GDBN} looks for the early +initialization and initialization files, and the order that the files +are searched for. + +@subsubsection Home directory early initialization files + +@value{GDBN} initially looks for an early initialization file in the +users home directory@footnote{On DOS/Windows systems, the home +directory is the one pointed to by the @code{HOME} environment +variable.}. There are a number of locations that @value{GDBN} will +search in the home directory, these locations are searched in order +and @value{GDBN} will load the first file that it finds, and +subsequent locations will not be checked. + +On non-macOS hosts the locations searched are: +@itemize +@item +The file @file{gdb/gdbearlyinit} within the directory pointed to by the +environment variable @env{XDG_CONFIG_HOME}, if it is defined. +@item +The file @file{.config/gdb/gdbearlyinit} within the directory pointed to +by the environment variable @env{HOME}, if it is defined. +@item +The file @file{.gdbearlyinit} within the directory pointed to by the +environment variable @env{HOME}, if it is defined. +@end itemize + +By contrast, on macOS hosts the locations searched are: +@itemize +@item +The file @file{Library/Preferences/gdb/gdbearlyinit} within the +directory pointed to by the environment variable @env{HOME}, if it is +defined. +@item +The file @file{.gdbearlyinit} within the directory pointed to by the +environment variable @env{HOME}, if it is defined. +@end itemize + +It is possible to prevent the home directory early initialization file +from being loaded using the @samp{-nx} or @samp{-nh} command line +options, @pxref{Mode Options,,Choosing Modes}. @anchor{System Wide Init Files} @subsubsection System wide initialization files @@ -25954,11 +26054,10 @@ default, this style's foreground color is magenta and it has bold intensity. The version number is displayed in two places, the output of @command{show version}, and when @value{GDBN} starts up. -Currently the version string displayed at startup is printed before -@value{GDBN} has parsed any command line options, or parsed any -command files, so there is currently no way to control the styling of -this string. However, @value{GDBN}'s @code{--quiet} command line option -can be used to disable printing of the version string on startup. +In order to control how @value{GDBN} styles the version number at +startup, add the @code{set style version} family of commands to the +early initialization command file (@pxref{Initialization +Files}). @item title Control the styling of titles. These are managed with the @@ -46877,12 +46976,14 @@ Execute given @value{GDBN} @var{command}. Add @var{directory} to the path to search for source files. @item -nh -Do not execute commands from @file{~/.config/gdb/gdbinit} or -@file{~/.gdbinit}. +Do not execute commands from @file{~/.config/gdb/gdbinit}, +@file{~/.gdbinit}, @file{~/.config/gdb/gdbearlyinit}, or +@file{~/.gdbearlyinit} @item -nx @itemx -n -Do not execute commands from any @file{.gdbinit} initialization files. +Do not execute commands from any @file{.gdbinit} or +@file{.gdbearlyinit} initialization files. @item -quiet @itemx -q diff --git a/gdb/main.c b/gdb/main.c index 2ba39273d07..5633381fdd5 100644 --- a/gdb/main.c +++ b/gdb/main.c @@ -386,6 +386,22 @@ get_init_files (std::vector *system_gdbinit, *local_gdbinit = init_files->local_file (); } +/* Compute the location of the early init file GDB should source and return + it in HOME_GDBEARLYINIT. HOME_GDBEARLYINIT could be returned as an + empty string if there is no early init file found. */ + +static void +get_earlyinit_files (std::string *home_gdbearlyinit) +{ + /* Cache the file lookup object so we only actually search for the files + once. */ + static gdb::optional init_files; + if (!init_files.has_value ()) + init_files.emplace (GDBEARLYINIT, nullptr, false, nullptr, false, false); + + *home_gdbearlyinit = init_files->home_file (); +} + /* Start up the event loop. This is the entry point to the event loop from the command loop. */ @@ -560,7 +576,13 @@ enum cmdarg_kind CMDARG_INIT_FILE, /* Option type -iex. */ - CMDARG_INIT_COMMAND + CMDARG_INIT_COMMAND, + + /* Option type -sx. */ + CMDARG_EARLYINIT_FILE, + + /* Option type -sex. */ + CMDARG_EARLYINIT_COMMAND }; /* Arguments of --command option and its counterpart. */ @@ -738,6 +760,8 @@ captured_main_1 (struct captured_main_args *context) OPT_WINDOWS, OPT_IX, OPT_IEX, + OPT_EIX, + OPT_EIEX, OPT_READNOW, OPT_READNEVER }; @@ -787,6 +811,10 @@ captured_main_1 (struct captured_main_args *context) {"init-eval-command", required_argument, 0, OPT_IEX}, {"ix", required_argument, 0, OPT_IX}, {"iex", required_argument, 0, OPT_IEX}, + {"early-init-command", required_argument, 0, OPT_EIX}, + {"early-init-eval-command", required_argument, 0, OPT_EIEX}, + {"eix", required_argument, 0, OPT_EIX}, + {"eiex", required_argument, 0, OPT_EIEX}, #ifdef GDBTK {"tclcommand", required_argument, 0, 'z'}, {"enable-external-editor", no_argument, 0, 'y'}, @@ -899,6 +927,12 @@ captured_main_1 (struct captured_main_args *context) case OPT_IEX: cmdarg_vec.emplace_back (CMDARG_INIT_COMMAND, optarg); break; + case OPT_EIX: + cmdarg_vec.emplace_back (CMDARG_EARLYINIT_FILE, optarg); + break; + case OPT_EIEX: + cmdarg_vec.emplace_back (CMDARG_EARLYINIT_COMMAND, optarg); + break; case 'B': batch_flag = batch_silent = 1; gdb_stdout = new null_file (); @@ -1007,6 +1041,18 @@ captured_main_1 (struct captured_main_args *context) /* Initialize all files. */ gdb_init (gdb_program_name); + /* Process early init files and early init options from the command line. */ + if (!inhibit_gdbinit) + { + std::string home_gdbearlyinit; + get_earlyinit_files (&home_gdbearlyinit); + if (!home_gdbearlyinit.empty () && !inhibit_home_gdbinit) + ret = catch_command_errors (source_script, + home_gdbearlyinit.c_str (), 0); + } + execute_cmdargs (&cmdarg_vec, CMDARG_EARLYINIT_FILE, + CMDARG_EARLYINIT_COMMAND, &ret); + /* Now that gdb_init has created the initial inferior, we're in position to set args for that inferior. */ if (set_args) @@ -1334,8 +1380,10 @@ print_gdb_help (struct ui_file *stream) std::vector system_gdbinit; std::string home_gdbinit; std::string local_gdbinit; + std::string home_gdbearlyinit; get_init_files (&system_gdbinit, &home_gdbinit, &local_gdbinit); + get_earlyinit_files (&home_gdbearlyinit); /* Note: The options in the list below are only approximately sorted in the alphabetical order, so as to group closely related options @@ -1409,6 +1457,17 @@ Other options:\n\n\ Set GDB's data-directory to DIR.\n\ "), stream); fputs_unfiltered (_("\n\ +At startup, GDB reads the following early init files and executes their\n\ +commands:\n\ +"), stream); + if (!home_gdbearlyinit.empty ()) + fprintf_unfiltered (stream, _("\ + * user-specific early init file: %s\n\ +"), home_gdbearlyinit.c_str ()); + if (home_gdbearlyinit.empty ()) + fprintf_unfiltered (stream, _("\ + None found.\n")); + fputs_unfiltered (_("\n\ At startup, GDB reads the following init files and executes their commands:\n\ "), stream); if (!system_gdbinit.empty ()) diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index c06e7eebd39..04872d85ab0 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2021-04-15 Andrew Burgess + + PR cli/25956 + * gdb.base/early-init-file.c: New file. + * gdb.base/early-init-file.exp: New file. + * lib/gdb-utils.exp (style): Handle style 'none'. + 2021-04-14 Tankut Baris Aktemur * gdb.dwarf2/dw2-inline-with-lexical-scope.exp: Use diff --git a/gdb/testsuite/gdb.base/early-init-file.c b/gdb/testsuite/gdb.base/early-init-file.c new file mode 100644 index 00000000000..9811b15f06d --- /dev/null +++ b/gdb/testsuite/gdb.base/early-init-file.c @@ -0,0 +1,22 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2021 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 . */ + +int +main () +{ + return 0; +} diff --git a/gdb/testsuite/gdb.base/early-init-file.exp b/gdb/testsuite/gdb.base/early-init-file.exp new file mode 100644 index 00000000000..4873e5be3ae --- /dev/null +++ b/gdb/testsuite/gdb.base/early-init-file.exp @@ -0,0 +1,109 @@ +# Copyright 2021 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 . + +# Test GDB's early init file mechanism. + +standard_testfile + +# Compile the test executable. +if {[build_executable "failed to build" $testfile $srcfile]} { + return -1 +} + +# Start gdb and ensure that the initial version string is styled in +# STYLE, use MESSAGE as the name of the test. +proc check_gdb_startup_version_string { style { message "" } } { + if { $message == "" } { + set message "check startup version string has style $style" + } + + gdb_exit + gdb_spawn + set vers [style "GNU gdb.*" $style] + gdb_test "" "^${vers}.*" $message +} + +# Return a list containing two directory paths for newly created home +# directories. +# +# The first directory is a HOME style home directory, it contains a +# .gdbearlyinit file containing CONTENT. +# +# The second directory is an XDG_CONFIG_HOME style home directory, it +# contains a sub-directory gdb/, inside which is a file gdbearlyinit +# that also contains CONTENT. +# +# The PREFIX is used in both directory names and should be unique for +# each call to this function. +proc setup_home_directories { prefix content } { + set home_dir [standard_output_file "${prefix}-home"] + set xdg_home_dir [standard_output_file "${prefix}-xdg"] + + file mkdir $home_dir + file mkdir "$xdg_home_dir/gdb" + + # Write the content into the HOME directory. + set fd [open "$home_dir/.gdbearlyinit" w] + puts $fd $content + close $fd + + # Copy this from the HOME directory into the XDG_CONFIG_HOME + # directory. + file copy -force "$home_dir/.gdbearlyinit" "$xdg_home_dir/gdb/gdbearlyinit" + + return [list $home_dir $xdg_home_dir] +} + +save_vars { env(TERM) } { + # We need an ANSI-capable terminal to get the output. + setenv TERM ansi + + # Start GDB and confirm that the version string is styled. + check_gdb_startup_version_string version + + # Create an empty directory we can use as HOME for some of the + # tests below. When we set XDG_CONFIG_HOME we still need to point + # HOME at something otherwise GDB complains that it doesn't know + # where to create the index cache. + set empty_home_dir [standard_output_file fake-empty-home] + + # Create two directories to use for the style setting test. + set dirs [setup_home_directories "style" \ + [multi_line_input \ + "set style version foreground none" \ + "set style version background none" \ + "set style version intensity normal"]] + set home_dir [lindex $dirs 0] + set xdg_home_dir [lindex $dirs 1] + + # Now arrange to use the fake home directory early init file. + save_vars { INTERNAL_GDBFLAGS env(HOME) env(XDG_CONFIG_HOME) } { + set INTERNAL_GDBFLAGS [string map {"-nx" ""} $INTERNAL_GDBFLAGS] + + # Now test GDB when using the HOME directory. + set env(HOME) $home_dir + unset -nocomplain env(XDG_CONFIG_HOME) + check_gdb_startup_version_string none \ + "check version string is unstyled using HOME" + + # Now test using the XDG_CONFIG_HOME folder. We still need to + # have a HOME directory set otherwise GDB will issue an error + # about not knowing where to place the index cache. + set env(XDG_CONFIG_HOME) $xdg_home_dir + set env(HOME) $empty_home_dir + check_gdb_startup_version_string none \ + "check version string is unstyled using XDG_CONFIG_HOME" + } +} diff --git a/gdb/testsuite/lib/gdb-utils.exp b/gdb/testsuite/lib/gdb-utils.exp index ad7d2884aae..cec157196b3 100644 --- a/gdb/testsuite/lib/gdb-utils.exp +++ b/gdb/testsuite/lib/gdb-utils.exp @@ -56,6 +56,7 @@ proc style {str style} { address { set style 34 } metadata { set style 2 } version { set style "35;1" } + none { return $str } } return "\033\\\[${style}m${str}\033\\\[m" }