From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id kI0fFpQRfl9gUQAAWB0awg (envelope-from ) for ; Wed, 07 Oct 2020 15:05:56 -0400 Received: by simark.ca (Postfix, from userid 112) id 225031EF79; Wed, 7 Oct 2020 15:05:55 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-0.9 required=5.0 tests=DKIM_SIGNED, MAILING_LIST_MULTI,T_DKIM_INVALID,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 0DFF21E58D for ; Wed, 7 Oct 2020 15:05:39 -0400 (EDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id CAB50386F036; Wed, 7 Oct 2020 19:05:38 +0000 (GMT) Received: from mail-wr1-x430.google.com (mail-wr1-x430.google.com [IPv6:2a00:1450:4864:20::430]) by sourceware.org (Postfix) with ESMTPS id 0903E38618BD for ; Wed, 7 Oct 2020 19:05:35 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 0903E38618BD Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embecosm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=andrew.burgess@embecosm.com Received: by mail-wr1-x430.google.com with SMTP id t9so3520478wrq.11 for ; Wed, 07 Oct 2020 12:05:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=9gU4x5zAea+o1dT8Remx/xpHgyvOgb3Ki4AO4YA1q40=; b=ER2hYEOxsVUyJcDD//bhTJmrf24TG4bkIbNAnYPi7z+Db78bEMLcoTMp2n9xPIsB4d CW/bNX6i7RzcvtrqOMjLRLPZcvoaWEL6oxW9nXov8GfbI4lpk4qfj0BQ3mQ7Gx5267PF ea8exzf09hlxsliQzWQi9mIL5t06CtHY79XuadTuhdjNPJR2S9A2z7LIUM69mR/kOPdV zVxxVUN34Ji+DmAvRJeshLTp/ukPg64jltSg859slG3EgtWiTmO/VtSEAYrTsuBn/Ixb XJH7UE+vsWAGF47+x7iQeYAvL0RdRfyanGoImxpGnGmhuVdvFzwfdi+IBaTSE/oP3KHI CUqA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=9gU4x5zAea+o1dT8Remx/xpHgyvOgb3Ki4AO4YA1q40=; b=pfBZPkoOv8S1HVPVRtXUrtiF6oEsNEXqKse57+yXQYWdyQiUVFNC06W+9AVQPNlf8q J9YBNsOBP+dNqH7UG7m5sZRsS6+WfBuf7KumldCUi+cb4+N6Px5Wde2r9H+kB7GpBHxH EVmQ2k7R6eGnvM+avbrlxmO48ckPmVeC8UBXIJgRLFjUJ0ieKoUkAD/y9k9lpEWR2LyW EZkziXwS+0AmQL3jhyNUIGkblb96ge4eHnzCjCBdguu24Ordhl9KkPmR2f2yrNKsvlq2 rHWvHjYaFTlPDlV+J1oCRd/6qOcYrlY0IKaOVG08TSqsZEN1IihXloUneyFdsqZpoK8j rc9w== X-Gm-Message-State: AOAM531Vbs44uNLLh1TeDg6XtfLpa/wnWMAx8S/+k5h4qONwKV+Cfh5s lEKLH45tBtD3ZupkhRSCsD26bOWSeYCC4A== X-Google-Smtp-Source: ABdhPJzw88xtHMWLIzYyMsOROmv8uRt3gXLTAlyEev9hABuSABsQlct+MkF8X0kKChoqiyc+xExX6Q== X-Received: by 2002:a5d:6149:: with SMTP id y9mr5224269wrt.352.1602097532957; Wed, 07 Oct 2020 12:05:32 -0700 (PDT) Received: from localhost (host109-151-14-50.range109-151.btcentralplus.com. [109.151.14.50]) by smtp.gmail.com with ESMTPSA id f14sm3891242wme.22.2020.10.07.12.05.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 07 Oct 2020 12:05:32 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Subject: [PATCH 4/7] gdb: process startup files and startup command line options Date: Wed, 7 Oct 2020 21:05:08 +0100 Message-Id: X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Tom Tromey Errors-To: gdb-patches-bounces@sourceware.org Sender: "Gdb-patches" 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. This commit adds a mechanism to find these startup files as well as some corresponding command line flags. Later commits will add commands that require this functionality in order to do what the user might want. The startup files that GDB will currently check for are ~/.config/gdb/gdbstartup (on Linux like systems) or ~/.gdbstartup if the former is not found. GDB will also look for ./.gdbstartup, a local startup file, with the usual auto-loading restrictions. The output of 'gdb --help' has been extended to include a list of the startup files being processed, as well as better handling the case where no startup files are found, so you might now see: At startup, GDB reads the following startup files and executes their commands: None found. The printing of 'None found.' has also been applied to .gdbinit files too. There are no tests yet for this functionality, as there are no options that really make use of it, but later commits will add some tests. gdb/ChangeLog: * NEWS: Mention new startup files and command line options. * config.in: Regenerate. * configure: Regenerate. * configure.ac: Define GDBSTARTUP. * main.c (relocate_gdbinit_path_maybe_in_datadir): Rename to... (relocate_file_path_maybe_in_datadir): ...this. (class gdb_initfile_finder): New class. (get_init_files): New uses gdb_initfile_finder. (get_startup_files): New function. (enum cmdarg_kind): Add CMDARG_STARTUP_FILE and CMDARG_STARTUP_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, print 'None found' when there are no startup files, or no init files. gdb/doc/ChangeLog: * gdb.texinfo (File Options): Mention new command line options. (Startup): Discuss when startup files are processed. (Initialization Files): Add description of startup files. (Auto-loading): Mention startup files. (gdb man): Likewise. --- gdb/ChangeLog | 18 +++ gdb/NEWS | 11 ++ gdb/config.in | 3 + gdb/configure | 6 + gdb/configure.ac | 3 + gdb/doc/ChangeLog | 8 ++ gdb/doc/gdb.texinfo | 104 ++++++++++++++-- gdb/main.c | 289 ++++++++++++++++++++++++++++++++++---------- 8 files changed, 369 insertions(+), 73 deletions(-) diff --git a/gdb/NEWS b/gdb/NEWS index c64dda7bbcb..bd3aca84d51 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -21,6 +21,17 @@ $HOME/.gdbinit. On Apple hosts the search order is instead: $HOME/Library/Preferences/gdb/gdbinit, $HOME/.gdbinit. +* GDB will now load and process commands from + ~/.config/gdb/gdbstartup, ~/.gdbstartup, or a local file + ./.gdbstartup if these files are present. These files are processed + earlier than any of the previous initialization files and can effect + parts of GDB's startup that previously had already been completed + before the initialization files were read. + +* GDB now has two new options "--startup-command" and + "--startup-eval-command" with corresponding short options "-sx" and + "-sex" that allow startup options to be passed on the command line. + * New commands set debug event-loop diff --git a/gdb/config.in b/gdb/config.in index 3e741c6ee71..a345125dd35 100644 --- a/gdb/config.in +++ b/gdb/config.in @@ -46,6 +46,9 @@ /* The .gdbinit filename. */ #undef GDBINIT +/* The .gdbstartup filename. */ +#undef GDBSTARTUP + /* look for global separate data files in this path [DATADIR/gdb] */ #undef GDB_DATADIR diff --git a/gdb/configure b/gdb/configure index a8942ecbd5d..0f426fcf52b 100755 --- a/gdb/configure +++ b/gdb/configure @@ -16315,6 +16315,12 @@ _ACEOF +cat >>confdefs.h <<_ACEOF +#define GDBSTARTUP ".gdbstartup" +_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 6b4b0fa8510..6a357cbfa30 100644 --- a/gdb/configure.ac +++ b/gdb/configure.ac @@ -1701,6 +1701,9 @@ case $host_os in esac AC_DEFINE_UNQUOTED(GDBINIT,"$gdbinit",[The .gdbinit filename.]) +dnl Set the host's .gdbstartup filename +AC_DEFINE_UNQUOTED(GDBSTARTUP,".gdbstartup",[The .gdbstartup 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/gdb.texinfo b/gdb/doc/gdb.texinfo index af5f27f8a8a..f141616bea1 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -1040,6 +1040,22 @@ after loading gdbinit files). @xref{Startup}. +@item -startup-command @var{file} +@itemx -sx @var{file} +@cindex @code{--startup-command} +@cindex @code{-sx} +Execute commands from file @var{file} as early as possible during the +initialization process, before any output is produced. +@xref{Startup}. + +@item -startup-eval-command @var{command} +@itemx -sex @var{command} +@cindex @code{--startup-eval-command} +@cindex @code{-sex} +Execute a single @value{GDBN} command as early as possible during the +initialization process, before any output is produced. +@xref{Startup}. + @item -directory @var{directory} @itemx -d @var{directory} @cindex @code{--directory} @@ -1291,6 +1307,22 @@ Here's the description of what @value{GDBN} does during session startup: @enumerate + +@item +Performs minimal setup required to initialise basic internal state. + +@item +@cindex startup file +Reads startup options from the startup file (if any) in your home +directory, followed by any startup options contained in a startup file +(if any) in the local directory as long as @samp{set auto-load +local-gdbinit} is set to @samp{on} (@pxref{Init File in the Current +Directory}), @pxref{Local directory startup file}. + +@item +Any startup command line options (@samp{startup-command} and +@samp{startup-eval-command}) are processed. + @item Sets up the command interpreter as specified by the command line (@pxref{Mode Options, interpreter}). @@ -1367,13 +1399,63 @@ startup, in the order they will be loaded, you can use @kbd{gdb --help}. +The files processed are split into two categories @dfn{startup files} +and @dfn{initialization files}. The startup files are loaded as +early as possible during @value{GDBN}'s startup and allow a limited +set of settings to be configured that can affect how the rest of +@value{GDBN} starts up. The more general initialization files are +processed later after @value{GDBN} has finished its own internal +startup process, any commands can be used in these files. + 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. +startup and initialization files, and the order that the files are +searched for. + +@subsubsection Home directory startup files + +@value{GDBN} initially looks for startup files 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-Apple hosts the locations searched are: +@table @file +@item $XDG_CONFIG_HOME/gdb/gdbstartup +@item $HOME/.config/gdb/gdbstartup +@item $HOME/.gdbstartup +@end table + +While on Apple hosts the locations searched are: +@table @file +@item $HOME/Library/Preferences/gdb/gdbstartup +@item $HOME/.gdbstartup +@end table + +It is possible to prevent the home directory startup file from +being loaded using the @samp{-nx} or @samp{-nh} command line options, +@pxref{Mode Options,,Choosing Modes}. + +@anchor{Local directory startup file} +@subsubsection Local directory startup file + +@value{GDBN} will check the current directory for a file called +@file{./.gdbstartup}. It is loaded after the home directory startup +file. + +If the file in the current directory was already loaded as the home +directory startup file then it will not be loaded a second time. + +It is possible to prevent the local directory startup file from being +loaded using the @samp{-nx} command line option, @pxref{Mode +Options,,Choosing Modes}. @anchor{System Wide Init Files} @subsubsection System wide initialization files @@ -25975,9 +26057,10 @@ In addition to these files, @value{GDBN} supports auto-loading code written in various extension languages. @xref{Auto-loading extensions}. -Note that loading of these associated files (including the local @file{.gdbinit} -file) requires accordingly configured @code{auto-load safe-path} -(@pxref{Auto-loading safe path}). +Note that loading of these associated files (including the local +@file{.gdbinit} and @file{.gdbstartup} files) requires accordingly +configured @code{auto-load safe-path} (@pxref{Auto-loading safe +path}). For these reasons, @value{GDBN} includes commands and options to let you control when to auto-load files and which files should be auto-loaded. @@ -26100,8 +26183,9 @@ from init file (if any) in the current working directory, see @ref{Init File in the Current Directory during Startup}. -Note that loading of this local @file{.gdbinit} file also requires accordingly -configured @code{auto-load safe-path} (@pxref{Auto-loading safe path}). +Note that loading of this local @file{.gdbinit} (and likewise of +@file{.gdbstartup}) file also requires accordingly configured +@code{auto-load safe-path} (@pxref{Auto-loading safe path}). @table @code @anchor{set auto-load local-gdbinit} @@ -46452,12 +46536,14 @@ 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/gdbstartup}, or +@file{~/.gdbstartup} @item -nx @itemx -n -Do not execute commands from any @file{.gdbinit} initialization files. +Do not execute commands from any @file{.gdbinit} or @file{.gdbstartup} +initialization files. @item -quiet @itemx -q diff --git a/gdb/main.c b/gdb/main.c index f85b7dbfdaa..8c2240085f7 100644 --- a/gdb/main.c +++ b/gdb/main.c @@ -202,8 +202,8 @@ relocate_gdb_directory (const char *initial, bool relocatable) otherwise. */ static std::string -relocate_gdbinit_path_maybe_in_datadir (const std::string &file, - bool relocatable) +relocate_file_path_maybe_in_datadir (const std::string &file, + bool relocatable) { size_t datadir_len = strlen (GDB_DATADIR); @@ -232,45 +232,51 @@ relocate_gdbinit_path_maybe_in_datadir (const std::string &file, return relocated_path; } -/* Compute the locations of init files that GDB should source and - return them in SYSTEM_GDBINIT, HOME_GDBINIT, LOCAL_GDBINIT. If - there is no system gdbinit (resp. home gdbinit and local gdbinit) - to be loaded, then SYSTEM_GDBINIT (resp. HOME_GDBINIT and - LOCAL_GDBINIT) is set to the empty string. */ -static void -get_init_files (std::vector *system_gdbinit, - std::string *home_gdbinit, - std::string *local_gdbinit) +/* A class to wrap up the logic for finding the three different types of + initialisation files GDB uses, system wide, home directory, and current + working directory. */ + +class gdb_initfile_finder { - static std::vector sysgdbinit; - static std::string homeinit; - static std::string localinit; - static int initialized = 0; +public: + /* Constructor. Finds initialisation files named FILENAME in the home + directory or local (current working) directory. System initialisation + files are found in both SYSTEM_FILENAME and SYSTEM_DIRNAME if these + are not nullptr (either or both can be). The matching *_RELOCATABLE + flag is passed through to RELOCATE_FILE_PATH_MAYBE_IN_DATADIR. + + If FILENAME starts with a '.' then when looking in the home directory + this first '.' can be ignored in some cases. */ + explicit gdb_initfile_finder (const char *filename, + const char *system_filename, + bool system_filename_relocatable, + const char *system_dirname, + bool system_dirname_relocatable) + { + struct stat s; - if (!initialized) - { - struct stat homebuf, cwdbuf, s; + if (system_filename != nullptr && system_filename[0] != '\0') + { + std::string relocated_filename + = relocate_file_path_maybe_in_datadir (system_filename, + system_filename_relocatable); + if (!relocated_filename.empty () + && stat (relocated_filename.c_str (), &s) == 0) + m_system_files.push_back (relocated_filename); + } - if (SYSTEM_GDBINIT[0]) - { - std::string relocated_sysgdbinit - = relocate_gdbinit_path_maybe_in_datadir - (SYSTEM_GDBINIT, SYSTEM_GDBINIT_RELOCATABLE); - if (!relocated_sysgdbinit.empty () - && stat (relocated_sysgdbinit.c_str (), &s) == 0) - 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 (system_dirname != nullptr && system_dirname[0] != '\0') + { + std::string relocated_dirname + = relocate_file_path_maybe_in_datadir (system_dirname, + system_dirname_relocatable); + if (!relocated_dirname.empty ()) + { + gdb_dir_up dir (opendir (relocated_dirname.c_str ())); if (dir != nullptr) { std::vector files; - for (;;) + while (true) { struct dirent *ent = readdir (dir.get ()); if (ent == nullptr) @@ -278,28 +284,28 @@ get_init_files (std::vector *system_gdbinit, 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 + /* ent->d_type is not available on all systems + (e.g. mingw, Solaris), so we have to call stat(). */ + std::string tmp_filename + = relocated_dirname + SLASH_STRING + name; + if (stat (tmp_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 ()); + = get_ext_lang_of_file (tmp_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. */ + 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)); + files.push_back (std::move (tmp_filename)); } std::sort (files.begin (), files.end ()); - sysgdbinit.insert (sysgdbinit.end (), - files.begin (), files.end ()); + m_system_files.insert (m_system_files.end (), + files.begin (), files.end ()); } } - } + } /* If the .gdbinit file in the current directory is the same as the $HOME/.gdbinit file, it should not be sourced. homebuf @@ -307,25 +313,98 @@ get_init_files (std::vector *system_gdbinit, are zero in case one of them fails (this guarantees that they won't match if either exists). */ - memset (&homebuf, 0, sizeof (struct stat)); - memset (&cwdbuf, 0, sizeof (struct stat)); + struct stat homebuf, cwdbuf; + memset (&homebuf, 0, sizeof (struct stat)); + memset (&cwdbuf, 0, sizeof (struct stat)); - homeinit = find_gdb_home_config_file (GDBINIT, &homebuf); + m_home_file = find_gdb_home_config_file (filename, &homebuf); - if (stat (GDBINIT, &cwdbuf) == 0) - { - if (homeinit.empty () - || memcmp ((char *) &homebuf, (char *) &cwdbuf, - sizeof (struct stat))) - localinit = GDBINIT; - } + if (stat (filename, &cwdbuf) == 0) + { + if (m_home_file.empty () + || memcmp ((char *) &homebuf, (char *) &cwdbuf, + sizeof (struct stat))) + m_local_file = filename; + } + } - initialized = 1; - } + DISABLE_COPY_AND_ASSIGN (gdb_initfile_finder); + + /* Return a list of system initialisation files. The list could be + empty. */ + const std::vector &system_files () const + { return m_system_files; } + + /* Return the path to the home initialisation file. The string can be + empty if there is no such file. */ + const std::string &home_file () const + { return m_home_file; } + + /* Return the path to the local initialisation file. The string can be + empty if there is no such file. */ + const std::string &local_file () const + { return m_local_file; } - *system_gdbinit = sysgdbinit; - *home_gdbinit = homeinit; - *local_gdbinit = localinit; +private: + + /* Vector of all system init files in the order they should be processed. + Could be empty. */ + std::vector m_system_files; + + /* Initialization file from the home directory. Could be the empty + string if there is no such file found. */ + std::string m_home_file; + + /* Initialization file from the current working directory. Could be the + empty string if there is no such file found. */ + std::string m_local_file; +}; + +/* Compute the locations of init files that GDB should source and return + them in SYSTEM_GDBINIT, HOME_GDBINIT, LOCAL_GDBINIT. The SYSTEM_GDBINIT + can be returned as an empty vector, and HOME_GDBINIT and LOCAL_GDBINIT + can be returned as empty strings if there is no init file of that + type. */ + +static void +get_init_files (std::vector *system_gdbinit, + std::string *home_gdbinit, + std::string *local_gdbinit) +{ + static std::unique_ptr init_files; + if (init_files == nullptr) + init_files = std::unique_ptr + (new gdb_initfile_finder (GDBINIT, + SYSTEM_GDBINIT, + SYSTEM_GDBINIT_RELOCATABLE, + SYSTEM_GDBINIT_DIR, + SYSTEM_GDBINIT_DIR_RELOCATABLE)); + + *system_gdbinit = init_files->system_files (); + *home_gdbinit = init_files->home_file (); + *local_gdbinit = init_files->local_file (); +} + +/* Compute the locations of startup files that GDB should source and return + them in SYSTEM_GDBSTARTUP, HOME_GDBSTARTUP, LOCAL_GDBSTARTUP. The + SYSTEM_GDBSTARTUP can be returned as an empty vector, and + HOME_GDBSTARTUP and LOCAL_GDBSTARTUP can be returned as empty strings if + there is no startup file of that type. */ + +static void +get_startup_files (std::vector *system_gdbstartup, + std::string *home_gdbstartup, + std::string *local_gdbstartup) +{ + static std::unique_ptr init_files; + if (init_files == nullptr) + init_files = std::unique_ptr + (new gdb_initfile_finder (GDBSTARTUP, + nullptr, false, nullptr, false)); + + *system_gdbstartup = init_files->system_files (); + *home_gdbstartup = init_files->home_file (); + *local_gdbstartup = init_files->local_file (); } /* Start up the event loop. This is the entry point to the event loop @@ -497,7 +576,13 @@ enum cmdarg_kind CMDARG_INIT_FILE, /* Option type -iex. */ - CMDARG_INIT_COMMAND + CMDARG_INIT_COMMAND, + + /* Option type -sx. */ + CMDARG_STARTUP_FILE, + + /* Option type -sex. */ + CMDARG_STARTUP_COMMAND }; /* Arguments of --command option and its counterpart. */ @@ -674,6 +759,8 @@ captured_main_1 (struct captured_main_args *context) OPT_WINDOWS, OPT_IX, OPT_IEX, + OPT_SX, + OPT_SEX, OPT_READNOW, OPT_READNEVER }; @@ -723,6 +810,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}, + {"startup-command", required_argument, 0, OPT_SX}, + {"startup-eval-command", required_argument, 0, OPT_SEX}, + {"sx", required_argument, 0, OPT_SX}, + {"sex", required_argument, 0, OPT_SEX}, #ifdef GDBTK {"tclcommand", required_argument, 0, 'z'}, {"enable-external-editor", no_argument, 0, 'y'}, @@ -835,6 +926,12 @@ captured_main_1 (struct captured_main_args *context) case OPT_IEX: cmdarg_vec.emplace_back (CMDARG_INIT_COMMAND, optarg); break; + case OPT_SX: + cmdarg_vec.emplace_back (CMDARG_STARTUP_FILE, optarg); + break; + case OPT_SEX: + cmdarg_vec.emplace_back (CMDARG_STARTUP_COMMAND, optarg); + break; case 'B': batch_flag = batch_silent = 1; gdb_stdout = new null_file (); @@ -943,6 +1040,34 @@ captured_main_1 (struct captured_main_args *context) /* Initialize all files. */ gdb_init (gdb_program_name); + /* Process startup files and startup options from the command line. */ + if (!inhibit_gdbinit) + { + std::vector system_gdbstartup; + std::string home_gdbstartup; + std::string local_gdbstartup; + get_startup_files (&system_gdbstartup, &home_gdbstartup, + &local_gdbstartup); + if (!system_gdbstartup.empty () && !inhibit_gdbinit) + { + for (const std::string &file : system_gdbstartup) + ret = catch_command_errors (source_script, file.c_str (), 0); + } + if (!home_gdbstartup.empty () && !inhibit_home_gdbinit) + ret = catch_command_errors (source_script, + home_gdbstartup.c_str (), 0); + if (!local_gdbstartup.empty () + && file_is_auto_load_safe (local_gdbstartup.c_str (), + _("auto-load: Loading %s " + "file \"%s\".\n"), + GDBSTARTUP, + local_gdbstartup.c_str ())) + ret = catch_command_errors (source_script, + local_gdbstartup.c_str (), 0); + } + execute_cmdargs (&cmdarg_vec, CMDARG_STARTUP_FILE, + CMDARG_STARTUP_COMMAND, &ret); + /* Now that gdb_init has created the initial inferior, we're in position to set args for that inferior. */ if (set_args) @@ -1268,8 +1393,12 @@ print_gdb_help (struct ui_file *stream) std::vector system_gdbinit; std::string home_gdbinit; std::string local_gdbinit; + std::vector system_gdbstartup; + std::string home_gdbstartup; + std::string local_gdbstartup; get_init_files (&system_gdbinit, &home_gdbinit, &local_gdbinit); + get_startup_files (&system_gdbstartup, &home_gdbstartup, &local_gdbstartup); /* Note: The options in the list below are only approximately sorted in the alphabetical order, so as to group closely related options @@ -1343,6 +1472,34 @@ Other options:\n\n\ Set GDB's data-directory to DIR.\n\ "), stream); fputs_unfiltered (_("\n\ +At startup, GDB reads the following startup files and executes their commands:\n\ +"), stream); + if (!system_gdbstartup.empty ()) + { + std::string output; + for (size_t idx = 0; idx < system_gdbstartup.size (); ++idx) + { + output += system_gdbstartup[idx]; + if (idx < system_gdbstartup.size () - 1) + output += ", "; + } + fprintf_unfiltered (stream, _("\ + * system-wide startup files: %s\n\ +"), output.c_str ()); + } + if (!home_gdbstartup.empty ()) + fprintf_unfiltered (stream, _("\ + * user-specific startup file: %s\n\ +"), home_gdbstartup.c_str ()); + if (!local_gdbstartup.empty ()) + fprintf_unfiltered (stream, _("\ + * local startup file (see also 'set auto-load local-gdbinit'): ./%s\n\ +"), local_gdbstartup.c_str ()); + if (system_gdbstartup.empty () && home_gdbstartup.empty () + && local_gdbstartup.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 ()) @@ -1366,6 +1523,10 @@ At startup, GDB reads the following init files and executes their commands:\n\ fprintf_unfiltered (stream, _("\ * local init file (see also 'set auto-load local-gdbinit'): ./%s\n\ "), local_gdbinit.c_str ()); + if (system_gdbinit.empty () && home_gdbinit.empty () + && local_gdbinit.empty ()) + fprintf_unfiltered (stream, _("\ + None found.\n")); fputs_unfiltered (_("\n\ For more information, type \"help\" from within GDB, or consult the\n\ GDB manual (available as on-line info or a printed manual).\n\ -- 2.25.4