gdb: resume ongoing step after handling fork or vfork
[deliverable/binutils-gdb.git] / gdb / main.c
index e67efc7bcdf04365da8f8af10dcf0747eb68a5ca..aa7a6f6951619643dfe4fbcb0da3ebced995e70d 100644 (file)
@@ -1,6 +1,6 @@
 /* Top level stuff for GDB, the GNU debugger.
 
-   Copyright (C) 1986-2019 Free Software Foundation, Inc.
+   Copyright (C) 1986-2022 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -28,7 +28,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <ctype.h>
-#include "event-loop.h"
+#include "gdbsupport/event-loop.h"
 #include "ui-out.h"
 
 #include "interps.h"
 #include "maint.h"
 
 #include "filenames.h"
-#include "common/filestuff.h"
+#include "gdbsupport/filestuff.h"
 #include <signal.h>
 #include "event-top.h"
 #include "infrun.h"
-#include "common/signals-state-save-restore.h"
+#include "gdbsupport/signals-state-save-restore.h"
+#include <algorithm>
 #include <vector>
-#include "common/pathstuff.h"
+#include "gdbsupport/pathstuff.h"
 #include "cli/cli-style.h"
+#ifdef GDBTK
+#include "gdbtk/generic/gdbtk.h"
+#endif
+#include "gdbsupport/alt-stack.h"
+#include "observable.h"
+#include "serial.h"
 
 /* The selected interpreter.  This will be used as a set command
    variable, so it should always be malloc'ed - since
@@ -61,7 +68,7 @@ int dbx_commands = 0;
 char *gdb_sysroot = 0;
 
 /* GDB datadir, used to store data files.  */
-char *gdb_datadir = 0;
+std::string gdb_datadir;
 
 /* Non-zero if GDB_DATADIR was provided on the command line.
    This doesn't track whether data-directory is set later from the
@@ -70,7 +77,7 @@ static int gdb_datadir_provided = 0;
 
 /* If gdb was configured with --with-python=/path,
    the possibly relocated path to python's lib directory.  */
-char *python_libdir = 0;
+std::string python_libdir;
 
 /* Target IO streams.  */
 struct ui_file *gdb_stdtargin;
@@ -119,135 +126,188 @@ set_gdb_data_directory (const char *new_datadir)
       print_sys_errmsg (new_datadir, save_errno);
     }
   else if (!S_ISDIR (st.st_mode))
-    warning (_("%s is not a directory."), new_datadir);
+    warning (_("%ps is not a directory."),
+            styled_string (file_name_style.style (), new_datadir));
 
-  xfree (gdb_datadir);
-  gdb_datadir = gdb_realpath (new_datadir).release ();
+  gdb_datadir = gdb_realpath (new_datadir).get ();
 
   /* gdb_realpath won't return an absolute path if the path doesn't exist,
      but we still want to record an absolute path here.  If the user entered
      "../foo" and "../foo" doesn't exist then we'll record $(pwd)/../foo which
      isn't canonical, but that's ok.  */
-  if (!IS_ABSOLUTE_PATH (gdb_datadir))
+  if (!IS_ABSOLUTE_PATH (gdb_datadir.c_str ()))
     {
-      gdb::unique_xmalloc_ptr<char> abs_datadir = gdb_abspath (gdb_datadir);
+      gdb::unique_xmalloc_ptr<char> abs_datadir
+       = gdb_abspath (gdb_datadir.c_str ());
 
-      xfree (gdb_datadir);
-      gdb_datadir = abs_datadir.release ();
+      gdb_datadir = abs_datadir.get ();
     }
 }
 
 /* Relocate a file or directory.  PROGNAME is the name by which gdb
    was invoked (i.e., argv[0]).  INITIAL is the default value for the
-   file or directory.  FLAG is true if the value is relocatable, false
-   otherwise.  Returns a newly allocated string; this may return NULL
-   under the same conditions as make_relative_prefix.  */
+   file or directory.  RELOCATABLE is true if the value is relocatable,
+   false otherwise.  This may return an empty string under the same
+   conditions as make_relative_prefix returning NULL.  */
 
-static char *
-relocate_path (const char *progname, const char *initial, int flag)
+static std::string
+relocate_path (const char *progname, const char *initial, bool relocatable)
 {
-  if (flag)
-    return make_relative_prefix (progname, BINDIR, initial);
-  return xstrdup (initial);
+  if (relocatable)
+    {
+      gdb::unique_xmalloc_ptr<char> str (make_relative_prefix (progname,
+                                                              BINDIR,
+                                                              initial));
+      if (str != nullptr)
+       return str.get ();
+      return std::string ();
+    }
+  return initial;
 }
 
 /* Like relocate_path, but specifically checks for a directory.
    INITIAL is relocated according to the rules of relocate_path.  If
    the result is a directory, it is used; otherwise, INITIAL is used.
-   The chosen directory is then canonicalized using lrealpath.  This
-   function always returns a newly-allocated string.  */
+   The chosen directory is then canonicalized using lrealpath.  */
 
-char *
-relocate_gdb_directory (const char *initial, int flag)
+std::string
+relocate_gdb_directory (const char *initial, bool relocatable)
 {
-  char *dir;
-
-  dir = relocate_path (gdb_program_name, initial, flag);
-  if (dir)
+  std::string dir = relocate_path (gdb_program_name, initial, relocatable);
+  if (!dir.empty ())
     {
       struct stat s;
 
-      if (*dir == '\0' || stat (dir, &s) != 0 || !S_ISDIR (s.st_mode))
+      if (stat (dir.c_str (), &s) != 0 || !S_ISDIR (s.st_mode))
        {
-         xfree (dir);
-         dir = NULL;
+         dir.clear ();
        }
     }
-  if (!dir)
-    dir = xstrdup (initial);
+  if (dir.empty ())
+    dir = initial;
 
   /* Canonicalize the directory.  */
-  if (*dir)
+  if (!dir.empty ())
     {
-      char *canon_sysroot = lrealpath (dir);
+      gdb::unique_xmalloc_ptr<char> canon_sysroot (lrealpath (dir.c_str ()));
 
       if (canon_sysroot)
-       {
-         xfree (dir);
-         dir = canon_sysroot;
-       }
+       dir = canon_sysroot.get ();
     }
 
   return dir;
 }
 
-/* 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 NULL.  */
-static void
-get_init_files (const char **system_gdbinit,
-               const char **home_gdbinit,
-               const char **local_gdbinit)
+/* Given a gdbinit path in FILE, adjusts it according to the gdb_datadir
+   parameter if it is in the data dir, or passes it through relocate_path
+   otherwise.  */
+
+static std::string
+relocate_file_path_maybe_in_datadir (const std::string &file,
+                                    bool relocatable)
 {
-  static const char *sysgdbinit = NULL;
-  static char *homeinit = NULL;
-  static const char *localinit = NULL;
-  static int initialized = 0;
+  size_t datadir_len = strlen (GDB_DATADIR);
 
-  if (!initialized)
+  std::string relocated_path;
+
+  /* If SYSTEM_GDBINIT lives in data-directory, and data-directory
+     has been provided, search for SYSTEM_GDBINIT there.  */
+  if (gdb_datadir_provided
+      && datadir_len < file.length ()
+      && filename_ncmp (file.c_str (), GDB_DATADIR, datadir_len) == 0
+      && IS_DIR_SEPARATOR (file[datadir_len]))
     {
-      struct stat homebuf, cwdbuf, s;
-      const char *homedir;
+      /* Append the part of SYSTEM_GDBINIT that follows GDB_DATADIR
+        to gdb_datadir.  */
 
-      if (SYSTEM_GDBINIT[0])
-       {
-         int datadir_len = strlen (GDB_DATADIR);
-         int sys_gdbinit_len = strlen (SYSTEM_GDBINIT);
-         char *relocated_sysgdbinit;
-
-         /* If SYSTEM_GDBINIT lives in data-directory, and data-directory
-            has been provided, search for SYSTEM_GDBINIT there.  */
-         if (gdb_datadir_provided
-             && datadir_len < sys_gdbinit_len
-             && filename_ncmp (SYSTEM_GDBINIT, GDB_DATADIR, datadir_len) == 0
-             && IS_DIR_SEPARATOR (SYSTEM_GDBINIT[datadir_len]))
-           {
-             /* Append the part of SYSTEM_GDBINIT that follows GDB_DATADIR
-                to gdb_datadir.  */
-             char *tmp_sys_gdbinit = xstrdup (&SYSTEM_GDBINIT[datadir_len]);
-             char *p;
+      size_t start = datadir_len;
+      for (; IS_DIR_SEPARATOR (file[start]); ++start)
+       ;
+      relocated_path = gdb_datadir + SLASH_STRING + file.substr (start);
+    }
+  else
+    {
+      relocated_path = relocate_path (gdb_program_name, file.c_str (),
+                                     relocatable);
+    }
+    return relocated_path;
+}
 
-             for (p = tmp_sys_gdbinit; IS_DIR_SEPARATOR (*p); ++p)
-               continue;
-             relocated_sysgdbinit = concat (gdb_datadir, SLASH_STRING, p,
-                                            (char *) NULL);
-             xfree (tmp_sys_gdbinit);
-           }
-         else
-           {
-             relocated_sysgdbinit = relocate_path (gdb_program_name,
-                                                   SYSTEM_GDBINIT,
-                                                   SYSTEM_GDBINIT_RELOCATABLE);
-           }
-         if (relocated_sysgdbinit && stat (relocated_sysgdbinit, &s) == 0)
-           sysgdbinit = relocated_sysgdbinit;
-         else
-           xfree (relocated_sysgdbinit);
-       }
+/* 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.  */
 
-      homedir = getenv ("HOME");
+class gdb_initfile_finder
+{
+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,
+                               bool lookup_local_file)
+  {
+    struct stat 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_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<std::string> files;
+               while (true)
+                 {
+                   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 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 (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.  */
+                   if (extlang != nullptr && ext_lang_present_p (extlang))
+                     files.push_back (std::move (tmp_filename));
+                 }
+               std::sort (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
@@ -255,56 +315,146 @@ get_init_files (const char **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));
 
-      if (homedir)
-       {
-         homeinit = xstrprintf ("%s/%s", homedir, gdbinit);
-         if (stat (homeinit, &homebuf) != 0)
-           {
-             xfree (homeinit);
-             homeinit = NULL;
-           }
-       }
+    m_home_file = find_gdb_home_config_file (filename, &homebuf);
 
-      if (stat (gdbinit, &cwdbuf) == 0)
-       {
-         if (!homeinit
-             || memcmp ((char *) &homebuf, (char *) &cwdbuf,
-                        sizeof (struct stat)))
-           localinit = gdbinit;
-       }
-      
-      initialized = 1;
-    }
+    if (lookup_local_file && stat (filename, &cwdbuf) == 0)
+      {
+       if (m_home_file.empty ()
+           || memcmp ((char *) &homebuf, (char *) &cwdbuf,
+                      sizeof (struct stat)))
+         m_local_file = filename;
+      }
+  }
+
+  DISABLE_COPY_AND_ASSIGN (gdb_initfile_finder);
+
+  /* Return a list of system initialisation files.  The list could be
+     empty.  */
+  const std::vector<std::string> &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; }
+
+private:
+
+  /* Vector of all system init files in the order they should be processed.
+     Could be empty.  */
+  std::vector<std::string> 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;
+};
 
-  *system_gdbinit = sysgdbinit;
-  *home_gdbinit = homeinit;
-  *local_gdbinit = localinit;
+/* 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<std::string> *system_gdbinit,
+               std::string *home_gdbinit,
+               std::string *local_gdbinit)
+{
+  /* 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 (GDBINIT, SYSTEM_GDBINIT, SYSTEM_GDBINIT_RELOCATABLE,
+                       SYSTEM_GDBINIT_DIR, SYSTEM_GDBINIT_DIR_RELOCATABLE,
+                       true);
+
+  *system_gdbinit = init_files->system_files ();
+  *home_gdbinit = init_files->home_file ();
+  *local_gdbinit = init_files->local_file ();
 }
 
-/* Try to set up an alternate signal stack for SIGSEGV handlers.
-   This allows us to handle SIGSEGV signals generated when the
-   normal process stack is exhausted.  If this stack is not set
-   up (sigaltstack is unavailable or fails) and a SIGSEGV is
-   generated when the normal stack is exhausted then the program
-   will behave as though no SIGSEGV handler was installed.  */
+/* 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
-setup_alternate_signal_stack (void)
+get_earlyinit_files (std::string *home_gdbearlyinit)
 {
-#ifdef HAVE_SIGALTSTACK
-  stack_t ss;
+  /* 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);
 
-  /* FreeBSD versions older than 11.0 use char * for ss_sp instead of
-     void *.  This cast works with both types.  */
-  ss.ss_sp = (char *) xmalloc (SIGSTKSZ);
-  ss.ss_size = SIGSTKSZ;
-  ss.ss_flags = 0;
+  *home_gdbearlyinit = init_files->home_file ();
+}
 
-  sigaltstack(&ss, NULL);
-#endif
+/* Start up the event loop.  This is the entry point to the event loop
+   from the command loop.  */
+
+static void
+start_event_loop ()
+{
+  /* Loop until there is nothing to do.  This is the entry point to
+     the event loop engine.  gdb_do_one_event will process one event
+     for each invocation.  It blocks waiting for an event and then
+     processes it.  */
+  while (1)
+    {
+      int result = 0;
+
+      try
+       {
+         result = gdb_do_one_event ();
+       }
+      catch (const gdb_exception &ex)
+       {
+         exception_print (gdb_stderr, ex);
+
+         /* If any exception escaped to here, we better enable
+            stdin.  Otherwise, any command that calls async_disable_stdin,
+            and then throws, will leave stdin inoperable.  */
+         SWITCH_THRU_ALL_UIS ()
+           {
+             async_enable_stdin ();
+           }
+         /* If we long-jumped out of do_one_event, we probably didn't
+            get around to resetting the prompt, which leaves readline
+            in a messed-up state.  Reset it here.  */
+         current_ui->prompt_state = PROMPT_NEEDED;
+         gdb::observers::command_error.notify ();
+         /* This call looks bizarre, but it is required.  If the user
+            entered a command that caused an error,
+            after_char_processing_hook won't be called from
+            rl_callback_read_char_wrapper.  Using a cleanup there
+            won't work, since we want this function to be called
+            after a new prompt is printed.  */
+         if (after_char_processing_hook)
+           (*after_char_processing_hook) ();
+         /* Maybe better to set a flag to be checked somewhere as to
+            whether display the prompt or not.  */
+       }
+
+      if (result < 0)
+       break;
+    }
+
+  /* We are done with the event loop.  There are no more event sources
+     to listen to.  So we exit GDB.  */
+  return;
 }
 
 /* Call command_loop.  */
@@ -339,7 +489,7 @@ captured_command_loop ()
 /* Handle command errors thrown from within catch_command_errors.  */
 
 static int
-handle_command_errors (struct gdb_exception e)
+handle_command_errors (const struct gdb_exception &e)
 {
   if (e.reason < 0)
     {
@@ -363,7 +513,8 @@ typedef void (catch_command_errors_const_ftype) (const char *, int);
 
 static int
 catch_command_errors (catch_command_errors_const_ftype command,
-                     const char *arg, int from_tty)
+                     const char *arg, int from_tty,
+                     bool do_bp_actions = false)
 {
   try
     {
@@ -372,6 +523,10 @@ catch_command_errors (catch_command_errors_const_ftype command,
       command (arg, from_tty);
 
       maybe_wait_sync_command_done (was_sync);
+
+      /* Do any commands attached to breakpoint we stopped at.  */
+      if (do_bp_actions)
+       bpstat_do_actions ();
     }
   catch (const gdb_exception &e)
     {
@@ -419,9 +574,15 @@ enum cmdarg_kind
 
   /* Option type -ix.  */
   CMDARG_INIT_FILE,
-    
+
   /* Option type -iex.  */
-  CMDARG_INIT_COMMAND
+  CMDARG_INIT_COMMAND,
+
+  /* Option type -eix.  */
+  CMDARG_EARLYINIT_FILE,
+
+  /* Option type -eiex.  */
+  CMDARG_EARLYINIT_COMMAND
 };
 
 /* Arguments of --command option and its counterpart.  */
@@ -439,6 +600,26 @@ struct cmdarg
   char *string;
 };
 
+/* From CMDARG_VEC execute command files (matching FILE_TYPE) or commands
+   (matching CMD_TYPE).  Update the value in *RET if and scripts or
+   commands are executed.  */
+
+static void
+execute_cmdargs (const std::vector<struct cmdarg> *cmdarg_vec,
+                cmdarg_kind file_type, cmdarg_kind cmd_type,
+                int *ret)
+{
+  for (const auto &cmdarg_p : *cmdarg_vec)
+    {
+      if (cmdarg_p.type == file_type)
+       *ret = catch_command_errors (source_script, cmdarg_p.string,
+                                    !batch_flag);
+      else if (cmdarg_p.type == cmd_type)
+       *ret = catch_command_errors (execute_command, cmdarg_p.string,
+                                    !batch_flag, true);
+    }
+}
+
 static void
 captured_main_1 (struct captured_main_args *context)
 {
@@ -470,11 +651,6 @@ captured_main_1 (struct captured_main_args *context)
   /* All arguments of --directory option.  */
   std::vector<char *> dirarg;
 
-  /* gdb init files.  */
-  const char *system_gdbinit;
-  const char *home_gdbinit;
-  const char *local_gdbinit;
-
   int i;
   int save_auto_load;
   int ret = 1;
@@ -499,8 +675,6 @@ captured_main_1 (struct captured_main_args *context)
 
   notice_open_fds ();
 
-  saved_command_line = (char *) xstrdup ("");
-
 #ifdef __MINGW32__
   /* Ensure stderr is unbuffered.  A Cygwin pty or pipe is implemented
      as a Windows pipe, and Windows buffers on pipes.  */
@@ -536,29 +710,26 @@ captured_main_1 (struct captured_main_args *context)
     perror_warning_with_name (_("error finding working directory"));
 
   /* Set the sysroot path.  */
-  gdb_sysroot = relocate_gdb_directory (TARGET_SYSTEM_ROOT,
-                                       TARGET_SYSTEM_ROOT_RELOCATABLE);
+  gdb_sysroot
+    = xstrdup (relocate_gdb_directory (TARGET_SYSTEM_ROOT,
+                                    TARGET_SYSTEM_ROOT_RELOCATABLE).c_str ());
 
-  if (gdb_sysroot == NULL || *gdb_sysroot == '\0')
+  if (*gdb_sysroot == '\0')
     {
       xfree (gdb_sysroot);
       gdb_sysroot = xstrdup (TARGET_SYSROOT_PREFIX);
     }
 
-  debug_file_directory = relocate_gdb_directory (DEBUGDIR,
-                                                DEBUGDIR_RELOCATABLE);
+  debug_file_directory
+    = xstrdup (relocate_gdb_directory (DEBUGDIR,
+                                    DEBUGDIR_RELOCATABLE).c_str ());
 
   gdb_datadir = relocate_gdb_directory (GDB_DATADIR,
                                        GDB_DATADIR_RELOCATABLE);
 
-#ifdef WITH_PYTHON_PATH
-  {
-    /* For later use in helping Python find itself.  */
-    char *tmp = concat (WITH_PYTHON_PATH, SLASH_STRING, "lib", (char *) NULL);
-
-    python_libdir = relocate_gdb_directory (tmp, PYTHON_PATH_RELOCATABLE);
-    xfree (tmp);
-  }
+#ifdef WITH_PYTHON_LIBDIR
+  python_libdir = relocate_gdb_directory (WITH_PYTHON_LIBDIR,
+                                         PYTHON_LIBDIR_RELOCATABLE);
 #endif
 
 #ifdef RELOC_SRCDIR
@@ -589,9 +760,14 @@ captured_main_1 (struct captured_main_args *context)
       OPT_WINDOWS,
       OPT_IX,
       OPT_IEX,
+      OPT_EIX,
+      OPT_EIEX,
       OPT_READNOW,
       OPT_READNEVER
     };
+    /* This struct requires int* in the struct, but write_files is a bool.
+       So use this temporary int that we write back after argument parsing.  */
+    int write_files_1 = 0;
     static struct option long_options[] =
     {
       {"tui", no_argument, 0, OPT_TUI},
@@ -635,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'},
@@ -656,7 +836,7 @@ captured_main_1 (struct captured_main_args *context)
       {"w", no_argument, NULL, OPT_WINDOWS},
       {"windows", no_argument, NULL, OPT_WINDOWS},
       {"statistics", no_argument, 0, OPT_STATISTICS},
-      {"write", no_argument, &write_files, 1},
+      {"write", no_argument, &write_files_1, 1},
       {"args", no_argument, &set_args, 1},
       {"l", required_argument, 0, 'l'},
       {"return-child-result", no_argument, &return_child_result, 1},
@@ -708,7 +888,7 @@ captured_main_1 (struct captured_main_args *context)
            break;
          case OPT_WINDOWS:
            /* FIXME: cagney/2003-03-01: Not sure if this option is
-               actually useful, and if it is, what it should do.  */
+              actually useful, and if it is, what it should do.  */
 #ifdef GDBTK
            /* --windows is equivalent to -i=insight.  */
            xfree (interpreter_p);
@@ -747,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 ();
@@ -761,8 +947,6 @@ captured_main_1 (struct captured_main_args *context)
 #ifdef GDBTK
          case 'z':
            {
-             extern int gdbtk_test (char *);
-
              if (!gdbtk_test (optarg))
                error (_("%s: unable to load tclcommand file \"%s\""),
                       gdb_program_name, optarg);
@@ -775,8 +959,6 @@ captured_main_1 (struct captured_main_args *context)
            {
              /* Set the external editor commands when gdb is farming out files
                 to be edited by another program.  */
-             extern char *external_editor_command;
-
              external_editor_command = xstrdup (optarg);
              break;
            }
@@ -806,7 +988,7 @@ captured_main_1 (struct captured_main_args *context)
              else
                baud_rate = rate;
            }
-            break;
+           break;
          case 'l':
            {
              int timeout;
@@ -840,6 +1022,7 @@ captured_main_1 (struct captured_main_args *context)
                   gdb_program_name);
          }
       }
+    write_files = (write_files_1 != 0);
 
     if (batch_flag)
       {
@@ -853,10 +1036,30 @@ captured_main_1 (struct captured_main_args *context)
   save_original_signals_state (quiet);
 
   /* Try to set up an alternate signal stack for SIGSEGV handlers.  */
-  setup_alternate_signal_stack ();
+  gdb::alternate_signal_stack signal_stack;
 
   /* Initialize all files.  */
-  gdb_init (gdb_program_name);
+  gdb_init ();
+
+  /* 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);
+
+  /* Initialize the extension languages.  */
+  ext_lang_initialization ();
+
+  /* Recheck if we're starting up quietly after processing the startup
+     scripts and commands.  */
+  if (!quiet)
+    quiet = check_quiet_mode ();
 
   /* Now that gdb_init has created the initial inferior, we're in
      position to set args for that inferior.  */
@@ -908,8 +1111,11 @@ 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
+     overridden during file initialization, so get_init_files should be
      called after gdb_init.  */
+  std::vector<std::string> system_gdbinit;
+  std::string home_gdbinit;
+  std::string local_gdbinit;
   get_init_files (&system_gdbinit, &home_gdbinit, &local_gdbinit);
 
   /* Do these (and anything which might call wrap_here or *_filtered)
@@ -928,7 +1134,6 @@ captured_main_1 (struct captured_main_args *context)
   if (print_help)
     {
       print_gdb_help (gdb_stdout);
-      fputs_unfiltered ("\n", gdb_stdout);
       exit (0);
     }
 
@@ -947,7 +1152,7 @@ captured_main_1 (struct captured_main_args *context)
   if (!quiet && strcmp (interpreter_p, INTERP_MI1) == 0)
     {
       /* Print all the junk at the top, with trailing "..." if we are
-         about to read a symbol file (possibly slowly).  */
+        about to read a symbol file (possibly slowly).  */
       print_gdb_version (gdb_stdout, true);
       if (symarg)
        printf_filtered ("..");
@@ -968,7 +1173,7 @@ captured_main_1 (struct captured_main_args *context)
   if (!quiet && !current_interp_named_p (INTERP_MI1))
     {
       /* Print all the junk at the top, with trailing "..." if we are
-         about to read a symbol file (possibly slowly).  */
+        about to read a symbol file (possibly slowly).  */
       print_gdb_version (gdb_stdout, true);
       if (symarg)
        printf_filtered ("..");
@@ -986,34 +1191,22 @@ captured_main_1 (struct captured_main_args *context)
      This is done *before* all the command line arguments are
      processed; it sets global parameters, which are independent of
      what file you are debugging or what directory you are in.  */
-  if (system_gdbinit && !inhibit_gdbinit)
-    ret = catch_command_errors (source_script, system_gdbinit, 0);
+  if (!system_gdbinit.empty () && !inhibit_gdbinit)
+    {
+      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
      global parameters, which are independent of what file you are
      debugging or what directory you are in.  */
 
-  if (home_gdbinit && !inhibit_gdbinit && !inhibit_home_gdbinit)
-    ret = catch_command_errors (source_script, home_gdbinit, 0);
+  if (!home_gdbinit.empty () && !inhibit_gdbinit && !inhibit_home_gdbinit)
+    ret = catch_command_errors (source_script, home_gdbinit.c_str (), 0);
 
   /* Process '-ix' and '-iex' options early.  */
-  for (i = 0; i < cmdarg_vec.size (); i++)
-    {
-      const struct cmdarg &cmdarg_p = cmdarg_vec[i];
-
-      switch (cmdarg_p.type)
-       {
-       case CMDARG_INIT_FILE:
-         ret = catch_command_errors (source_script, cmdarg_p.string,
-                                     !batch_flag);
-         break;
-       case CMDARG_INIT_COMMAND:
-         ret = catch_command_errors (execute_command, cmdarg_p.string,
-                                     !batch_flag);
-         break;
-       }
-    }
+  execute_cmdargs (&cmdarg_vec, CMDARG_INIT_FILE, CMDARG_INIT_COMMAND, &ret);
 
   /* Now perform all the actions indicated by the arguments.  */
   if (cdarg != NULL)
@@ -1035,8 +1228,8 @@ captured_main_1 (struct captured_main_args *context)
       && strcmp (execarg, symarg) == 0)
     {
       /* The exec file and the symbol-file are the same.  If we can't
-         open it, better only print one error message.
-         catch_command_errors returns non-zero on success!  */
+        open it, better only print one error message.
+        catch_command_errors returns non-zero on success!  */
       ret = catch_command_errors (exec_file_attach, execarg,
                                  !batch_flag);
       if (ret != 0)
@@ -1091,27 +1284,29 @@ captured_main_1 (struct captured_main_args *context)
     }
 
   if (ttyarg != NULL)
-    set_inferior_io_terminal (ttyarg);
+    current_inferior ()->set_tty (ttyarg);
 
   /* Error messages should no longer be distinguished with extra output.  */
   warning_pre_print = _("warning: ");
 
   /* Read the .gdbinit file in the current directory, *if* it isn't
      the same as the $HOME/.gdbinit file (it should exist, also).  */
-  if (local_gdbinit)
+  if (!local_gdbinit.empty ())
     {
       auto_load_local_gdbinit_pathname
-       = gdb_realpath (local_gdbinit).release ();
+       = gdb_realpath (local_gdbinit.c_str ()).release ();
 
-      if (!inhibit_gdbinit && auto_load_local_gdbinit
-         && file_is_auto_load_safe (local_gdbinit,
-                                    _("auto-load: Loading .gdbinit "
-                                      "file \"%s\".\n"),
-                                    local_gdbinit))
+      if (!inhibit_gdbinit && auto_load_local_gdbinit)
        {
-         auto_load_local_gdbinit_loaded = 1;
+         auto_load_debug_printf ("Loading .gdbinit file \"%s\".",
+                                 local_gdbinit.c_str ());
+
+         if (file_is_auto_load_safe (local_gdbinit.c_str ()))
+           {
+             auto_load_local_gdbinit_loaded = 1;
 
-         ret = catch_command_errors (source_script, local_gdbinit, 0);
+             ret = catch_command_errors (source_script, local_gdbinit.c_str (), 0);
+           }
        }
     }
 
@@ -1124,22 +1319,7 @@ captured_main_1 (struct captured_main_args *context)
     load_auto_scripts_for_objfile (objfile);
 
   /* Process '-x' and '-ex' options.  */
-  for (i = 0; i < cmdarg_vec.size (); i++)
-    {
-      const struct cmdarg &cmdarg_p = cmdarg_vec[i];
-
-      switch (cmdarg_p.type)
-       {
-       case CMDARG_FILE:
-         ret = catch_command_errors (source_script, cmdarg_p.string,
-                                     !batch_flag);
-         break;
-       case CMDARG_COMMAND:
-         ret = catch_command_errors (execute_command, cmdarg_p.string,
-                                     !batch_flag);
-         break;
-       }
-    }
+  execute_cmdargs (&cmdarg_vec, CMDARG_FILE, CMDARG_COMMAND, &ret);
 
   /* Read in the old history after all the command files have been
      read.  */
@@ -1205,11 +1385,13 @@ gdb_main (struct captured_main_args *args)
 static void
 print_gdb_help (struct ui_file *stream)
 {
-  const char *system_gdbinit;
-  const char *home_gdbinit;
-  const char *local_gdbinit;
+  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
@@ -1221,7 +1403,7 @@ This is the GNU debugger.  Usage:\n\n\
 "), stream);
   fputs_unfiltered (_("\
 Selection of debuggee and its files:\n\n\
-  --args             Arguments after executable-file are passed to inferior\n\
+  --args             Arguments after executable-file are passed to inferior.\n\
   --core=COREFILE    Analyze the core dump COREFILE.\n\
   --exec=EXECFILE    Use EXECFILE as the executable.\n\
   --pid=PID          Attach to running process PID.\n\
@@ -1236,13 +1418,13 @@ Selection of debuggee and its files:\n\n\
 Initial commands and command files:\n\n\
   --command=FILE, -x Execute GDB commands from FILE.\n\
   --init-command=FILE, -ix\n\
-                     Like -x but execute commands before loading inferior.\n\
+                    Like -x but execute commands before loading inferior.\n\
   --eval-command=COMMAND, -ex\n\
-                     Execute a single GDB command.\n\
-                     May be used multiple times and in conjunction\n\
-                     with --command.\n\
+                    Execute a single GDB command.\n\
+                    May be used multiple times and in conjunction\n\
+                    with --command.\n\
   --init-eval-command=COMMAND, -iex\n\
-                     Like -ex but before loading inferior.\n\
+                    Like -ex but before loading inferior.\n\
   --nh               Do not read ~/.gdbinit.\n\
   --nx               Do not read any .gdbinit files in any directory.\n\n\
 "), stream);
@@ -1250,7 +1432,7 @@ Initial commands and command files:\n\n\
 Output and user interface control:\n\n\
   --fullname         Output information used by emacs-GDB interface.\n\
   --interpreter=INTERP\n\
-                     Select a specific interpreter / user interface\n\
+                    Select a specific interpreter / user interface.\n\
   --tty=TTY          Use TTY for input/output by the program being debugged.\n\
   -w                 Use the GUI interface.\n\
   --nw               Do not use the GUI interface.\n\
@@ -1263,14 +1445,14 @@ Output and user interface control:\n\n\
   fputs_unfiltered (_("\
   --dbx              DBX compatibility mode.\n\
   -q, --quiet, --silent\n\
-                     Do not print version number on startup.\n\n\
+                    Do not print version number on startup.\n\n\
 "), stream);
   fputs_unfiltered (_("\
 Operating modes:\n\n\
   --batch            Exit after processing options.\n\
   --batch-silent     Like --batch, but suppress all gdb stdout output.\n\
   --return-child-result\n\
-                     GDB exit code will be the child's exit code.\n\
+                    GDB exit code will be the child's exit code.\n\
   --configuration    Print details about GDB configuration and then exit.\n\
   --help             Print this message and then exit.\n\
   --version          Print version information and then exit.\n\n\
@@ -1280,29 +1462,57 @@ Remote debugging options:\n\n\
 Other options:\n\n\
   --cd=DIR           Change current directory to DIR.\n\
   --data-directory=DIR, -D\n\
-                     Set GDB's data-directory to DIR.\n\
+                    Set GDB's data-directory to DIR.\n\
 "), stream);
   fputs_unfiltered (_("\n\
-At startup, GDB reads the following init files and executes their commands:\n\
+At startup, GDB reads the following early init files and executes their\n\
+commands:\n\
 "), stream);
-  if (system_gdbinit)
+  if (!home_gdbearlyinit.empty ())
     fprintf_unfiltered (stream, _("\
-   * system-wide init file: %s\n\
-"), system_gdbinit);
-  if (home_gdbinit)
+   * 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 ())
+    {
+      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\
-"), home_gdbinit);
-  if (local_gdbinit)
+"), home_gdbinit.c_str ());
+  if (!local_gdbinit.empty ())
     fprintf_unfiltered (stream, _("\
    * local init file (see also 'set auto-load local-gdbinit'): ./%s\n\
-"), local_gdbinit);
+"), 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\
 "), stream);
   if (REPORT_BUGS_TO[0] && stream == gdb_stdout)
-    fprintf_unfiltered (stream, _("\
-Report bugs to \"%s\".\n\
+    fprintf_unfiltered (stream, _("\n\
+Report bugs to %s.\n\
 "), REPORT_BUGS_TO);
+  if (stream == gdb_stdout)
+    fprintf_unfiltered (stream, _("\n\
+You can ask GDB-related questions on the GDB users mailing list\n\
+(gdb@sourceware.org) or on GDB's IRC channel (#gdb on Freenode).\n"));
 }
This page took 0.037636 seconds and 4 git commands to generate.