gdb: process early initialization files and command line options

Adds the ability to process commands at a new phase during GDB's
startup.  This phase is earlier than the current initialisation file
processing, before GDB has produced any output.

The number of commands that can be processed at this early stage will
be limited, and it is expected that the only commands that would be
processed at this stage will relate to some of the fundamentals of how
GDB starts up.

Currently the only commands that it makes sense to add to this early
initialization file are those like 'set style version ....' as the
version string is displayed during startup before the standard
initialization files are parsed.  As such this commit fully resolved
bug cli/25956.

This commit adds a mechanism to execute these early initialization
files from a users HOME directory, as well as some corresponding
command line flags for GDB.

The early initialization files that GDB will currently check for are
~/.config/gdb/gdbearlyinit (on Linux like systems) or ~/.gdbearlyinit
if the former is not found.

The output of 'gdb --help' has been extended to include a list of the
early initialization files being processed.

gdb/ChangeLog:

	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.

gdb/doc/ChangeLog:

	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.

gdb/testsuite/ChangeLog:

	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'.
This commit is contained in:
Andrew Burgess 2020-09-25 16:28:05 +01:00
parent 54b4dcc530
commit 92e4e97a9f
12 changed files with 357 additions and 11 deletions

View file

@ -1,3 +1,17 @@
2021-04-15 Andrew Burgess <andrew.burgess@embecosm.com>
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 <andrew.burgess@embecosm.com>
* main.c (relocate_gdbinit_path_maybe_in_datadir): Rename to...

View file

@ -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

View file

@ -43,6 +43,9 @@
language is requested. */
#undef ENABLE_NLS
/* The .gdbearlyinit filename. */
#undef GDBEARLYINIT
/* The .gdbinit filename. */
#undef GDBINIT

6
gdb/configure vendored
View file

@ -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.

View file

@ -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,

View file

@ -1,3 +1,12 @@
2021-04-15 Andrew Burgess <andrew.burgess@embecosm.com>
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 <andrew.burgess@embecosm.com>
* gdb.texinfo (GDB/MI Miscellaneous Commands): Add missing

View file

@ -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

View file

@ -386,6 +386,22 @@ get_init_files (std::vector<std::string> *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<gdb_initfile_finder> 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<std::string> 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 ())

View file

@ -1,3 +1,10 @@
2021-04-15 Andrew Burgess <andrew.burgess@embecosm.com>
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 <tankut.baris.aktemur@intel.com>
* gdb.dwarf2/dw2-inline-with-lexical-scope.exp: Use

View file

@ -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 <http://www.gnu.org/licenses/>. */
int
main ()
{
return 0;
}

View file

@ -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 <http://www.gnu.org/licenses/>.
# 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"
}
}

View file

@ -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"
}