+ fprintf_unfiltered (gdb_stderr, "Warning: ");
+ print_sys_errmsg (new_datadir, save_errno);
+ }
+ else if (!S_ISDIR (st.st_mode))
+ warning (_("%ps is not a directory."),
+ styled_string (file_name_style.style (), new_datadir));
+
+ 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.c_str ()))
+ {
+ gdb::unique_xmalloc_ptr<char> abs_datadir
+ = gdb_abspath (gdb_datadir.c_str ());
+
+ 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. 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 std::string
+relocate_path (const char *progname, const char *initial, bool relocatable)
+{
+ 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. */
+
+std::string
+relocate_gdb_directory (const char *initial, bool relocatable)
+{
+ std::string dir = relocate_path (gdb_program_name, initial, relocatable);
+ if (!dir.empty ())
+ {
+ struct stat s;
+
+ if (stat (dir.c_str (), &s) != 0 || !S_ISDIR (s.st_mode))
+ {
+ dir.clear ();
+ }
+ }
+ if (dir.empty ())
+ dir = initial;
+
+ /* Canonicalize the directory. */
+ if (!dir.empty ())
+ {
+ gdb::unique_xmalloc_ptr<char> canon_sysroot (lrealpath (dir.c_str ()));
+
+ if (canon_sysroot)
+ dir = canon_sysroot.get ();
+ }
+
+ return dir;
+}
+
+/* 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_gdbinit_path_maybe_in_datadir (const std::string &file,
+ bool relocatable)
+{
+ size_t datadir_len = strlen (GDB_DATADIR);
+
+ 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]))
+ {
+ /* Append the part of SYSTEM_GDBINIT that follows GDB_DATADIR
+ to gdb_datadir. */
+
+ 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;
+}
+
+/* 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<std::string> *system_gdbinit,
+ std::string *home_gdbinit,
+ std::string *local_gdbinit)
+{
+ static std::vector<std::string> sysgdbinit;
+ static std::string homeinit;
+ static std::string localinit;
+ static int initialized = 0;
+
+ if (!initialized)
+ {
+ struct stat homebuf, cwdbuf, s;
+
+ 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 (dir != nullptr)
+ {
+ std::vector<std::string> files;
+ for (;;)
+ {
+ struct dirent *ent = readdir (dir.get ());
+ if (ent == nullptr)
+ break;
+ std::string name (ent->d_name);
+ if (name == "." || name == "..")
+ continue;
+ /* ent->d_type is not available on all systems (e.g. mingw,
+ Solaris), so we have to call stat(). */
+ std::string filename
+ = relocated_gdbinit_dir + SLASH_STRING + name;
+ if (stat (filename.c_str (), &s) != 0
+ || !S_ISREG (s.st_mode))
+ continue;
+ const struct extension_language_defn *extlang
+ = get_ext_lang_of_file (filename.c_str ());
+ /* We effectively don't support "set script-extension
+ off/soft", because we are loading system init files here,
+ so it does not really make sense to depend on a
+ setting. */
+ if (extlang != nullptr && ext_lang_present_p (extlang))
+ files.push_back (std::move (filename));
+ }
+ std::sort (files.begin (), files.end ());
+ sysgdbinit.insert (sysgdbinit.end (),
+ files.begin (), files.end ());
+ }
+ }
+ }
+
+ const char *homedir = getenv ("HOME");
+
+ /* If the .gdbinit file in the current directory is the same as
+ the $HOME/.gdbinit file, it should not be sourced. homebuf
+ and cwdbuf are used in that purpose. Make sure that the stats
+ 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));
+
+ if (homedir)
+ {
+ homeinit = std::string (homedir) + SLASH_STRING + GDBINIT;
+ if (stat (homeinit.c_str (), &homebuf) != 0)
+ {
+ homeinit = "";
+ }
+ }
+
+ if (stat (GDBINIT, &cwdbuf) == 0)
+ {
+ if (homeinit.empty ()
+ || memcmp ((char *) &homebuf, (char *) &cwdbuf,
+ sizeof (struct stat)))
+ localinit = GDBINIT;
+ }
+
+ initialized = 1;
+ }
+
+ *system_gdbinit = sysgdbinit;
+ *home_gdbinit = homeinit;
+ *local_gdbinit = localinit;
+}
+
+/* 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. */
+
+/* Prevent inlining this function for the benefit of GDB's selftests
+ in the testsuite. Those tests want to run GDB under GDB and stop
+ here. */
+static void captured_command_loop () __attribute__((noinline));
+
+static void
+captured_command_loop ()