+ 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 ()
+{
+ struct ui *ui = current_ui;
+
+ /* Top-level execution commands can be run in the background from
+ here on. */
+ current_ui->async = 1;
+
+ /* Give the interpreter a chance to print a prompt, if necessary */
+ if (ui->prompt_state != PROMPT_BLOCKED)
+ interp_pre_command_loop (top_level_interpreter ());
+
+ /* Now it's time to start the event loop. */
+ start_event_loop ();
+