mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-21 04:42:53 +08:00
a9deee17d3
For every stop, Linux GDB and GDBserver save the stopped thread's PC, in lwp->stop_pc. This is done in save_stop_reason, in both gdb/linux-nat.c and gdbserver/linux-low.cc. However, while we're going through the shell after "run", in startup_inferior, we shouldn't be reading registers, as we haven't yet determined the target's architecture -- the shell's architecture may not even be the same as the final inferior's. In gdb/linux-nat.c, lwp->stop_pc is only needed when the thread has stopped for a breakpoint, and since when going through the shell, no breakpoint is going to hit, we could simply teach save_stop_reason to only record the stop pc when the thread stopped for a breakpoint. However, in gdbserver/linux-low.cc, lwp->stop_pc is used in more cases than breakpoint hits (e.g., it's used in tracepoints & the "while-stepping" feature). So to avoid GDB vs GDBserver divergence, we apply the same approach to both implementations. We set a flag in the inferior (process in GDBserver) whenever it is being nursed through the shell, and when that flag is set, save_stop_reason bails out early. While going through the shell, we'll only ever get process exits (normal or signalled), random signals, and exec events, so nothing is lost. Change-Id: If0f01831514d3a74d17efd102875de7d2c6401ad
181 lines
4.8 KiB
C
181 lines
4.8 KiB
C
/* Fork a Unix child process, and set up to debug it, for GDB.
|
|
|
|
Copyright (C) 1990-2022 Free Software Foundation, Inc.
|
|
|
|
Contributed by Cygnus Support.
|
|
|
|
This file is part of GDB.
|
|
|
|
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/>. */
|
|
|
|
#include "defs.h"
|
|
#include "inferior.h"
|
|
#include "gdbcmd.h"
|
|
#include "terminal.h"
|
|
#include "gdbthread.h"
|
|
#include "top.h"
|
|
#include "gdbsupport/job-control.h"
|
|
#include "gdbsupport/filestuff.h"
|
|
#include "nat/fork-inferior.h"
|
|
#include "gdbsupport/common-inferior.h"
|
|
|
|
/* The exec-wrapper, if any, that will be used when starting the
|
|
inferior. */
|
|
|
|
static std::string exec_wrapper;
|
|
|
|
/* See gdbsupport/common-inferior.h. */
|
|
|
|
const char *
|
|
get_exec_wrapper ()
|
|
{
|
|
return !exec_wrapper.empty () ? exec_wrapper.c_str () : nullptr;
|
|
}
|
|
|
|
/* See nat/fork-inferior.h. */
|
|
|
|
void
|
|
gdb_flush_out_err ()
|
|
{
|
|
gdb_flush (main_ui->m_gdb_stdout);
|
|
gdb_flush (main_ui->m_gdb_stderr);
|
|
}
|
|
|
|
/* The ui structure that will be saved on 'prefork_hook' and
|
|
restored on 'postfork_hook'. */
|
|
static struct ui *saved_ui = NULL;
|
|
|
|
/* See nat/fork-inferior.h. */
|
|
|
|
void
|
|
prefork_hook (const char *args)
|
|
{
|
|
gdb_assert (saved_ui == NULL);
|
|
/* Retain a copy of our UI, since the child will replace this value
|
|
and if we're vforked, we have to restore it. */
|
|
saved_ui = current_ui;
|
|
|
|
/* Tell the terminal handling subsystem what tty we plan to run on;
|
|
it will just record the information for later. */
|
|
new_tty_prefork (current_inferior ()->tty ());
|
|
}
|
|
|
|
/* See nat/fork-inferior.h. */
|
|
|
|
void
|
|
postfork_hook (pid_t pid)
|
|
{
|
|
inferior *inf = current_inferior ();
|
|
|
|
inferior_appeared (inf, pid);
|
|
|
|
gdb_assert (saved_ui != NULL);
|
|
current_ui = saved_ui;
|
|
saved_ui = NULL;
|
|
|
|
new_tty_postfork ();
|
|
}
|
|
|
|
/* See nat/fork-inferior.h. */
|
|
|
|
void
|
|
postfork_child_hook ()
|
|
{
|
|
/* This is set to the result of setpgrp, which if vforked, will be
|
|
visible to you in the parent process. It's only used by humans
|
|
for debugging. */
|
|
static int debug_setpgrp = 657473;
|
|
|
|
/* Make sure we switch to main_ui here in order to be able to
|
|
use the gdb_printf/warning/error functions. */
|
|
current_ui = main_ui;
|
|
|
|
/* Create a new session for the inferior process, if necessary.
|
|
It will also place the inferior in a separate process group. */
|
|
if (create_tty_session () <= 0)
|
|
{
|
|
/* No session was created, but we still want to run the inferior
|
|
in a separate process group. */
|
|
debug_setpgrp = gdb_setpgid ();
|
|
if (debug_setpgrp == -1)
|
|
perror (_("setpgrp failed in child"));
|
|
}
|
|
|
|
/* Ask the tty subsystem to switch to the one we specified
|
|
earlier (or to share the current terminal, if none was
|
|
specified). */
|
|
new_tty ();
|
|
}
|
|
|
|
/* See inferior.h. */
|
|
|
|
ptid_t
|
|
gdb_startup_inferior (pid_t pid, int num_traps)
|
|
{
|
|
inferior *inf = current_inferior ();
|
|
process_stratum_target *proc_target = inf->process_target ();
|
|
|
|
scoped_restore save_starting_up
|
|
= make_scoped_restore (&inf->starting_up, true);
|
|
|
|
ptid_t ptid = startup_inferior (proc_target, pid, num_traps, NULL, NULL);
|
|
|
|
/* Mark all threads non-executing. */
|
|
set_executing (proc_target, ptid, false);
|
|
|
|
return ptid;
|
|
}
|
|
|
|
/* Implement the "unset exec-wrapper" command. */
|
|
|
|
static void
|
|
unset_exec_wrapper_command (const char *args, int from_tty)
|
|
{
|
|
exec_wrapper.clear ();
|
|
}
|
|
|
|
static void
|
|
show_startup_with_shell (struct ui_file *file, int from_tty,
|
|
struct cmd_list_element *c, const char *value)
|
|
{
|
|
gdb_printf (file,
|
|
_("Use of shell to start subprocesses is %s.\n"),
|
|
value);
|
|
}
|
|
|
|
void _initialize_fork_child ();
|
|
void
|
|
_initialize_fork_child ()
|
|
{
|
|
add_setshow_filename_cmd ("exec-wrapper", class_run, &exec_wrapper, _("\
|
|
Set a wrapper for running programs.\n\
|
|
The wrapper prepares the system and environment for the new program."),
|
|
_("\
|
|
Show the wrapper for running programs."), NULL,
|
|
NULL, NULL,
|
|
&setlist, &showlist);
|
|
|
|
add_cmd ("exec-wrapper", class_run, unset_exec_wrapper_command,
|
|
_("Disable use of an execution wrapper."),
|
|
&unsetlist);
|
|
|
|
add_setshow_boolean_cmd ("startup-with-shell", class_support,
|
|
&startup_with_shell, _("\
|
|
Set use of shell to start subprocesses. The default is on."), _("\
|
|
Show use of shell to start subprocesses."), NULL,
|
|
NULL,
|
|
show_startup_with_shell,
|
|
&setlist, &showlist);
|
|
}
|