2009-07-02  Pedro Alves  <pedro@codesourcery.com>

	* linux-nat.c (linux_child_follow_fork): If we're staying attached
	to the child process, enable event reporting on it.  Don't handle
	checkpoints here.  Instead, add the child fork to the lwp thread
	and inferior lists without clobbering the previous inferior.  Let
	the thread_db layer learn about a new child process, even if
	following the parent.
	(linux_nat_switch_fork): Delete lwps of the current inferior only,
	instead of clearing the whole list.  Use thread_change_ptid to
	give the core the illusion the new checkpoint is still the same
	inferior.  Clear the register cache.
	(linux_handle_extended_wait): Handle checkpoints here.
	(linux_multi_process): Turn on.
	* linux-fork.c (struct fork_info) <pc>: Remove field.
	(init_fork_list): Do not delete the checkpoint from the inferior
	list (it is not there).
	(fork_load_infrun_state): Don't switch inferior_ptid here.  Pass
	the new checkpoint's ptid to linux_nat_switch_fork.
	(fork_save_infrun_state): Make static.  Don't stop the pc field of
	fork_info, it's gone.
	(linux_fork_mourn_inferior): Don't delete the checkpoint from the
	inferior list, it's not there.
	(linux_fork_detach): Ditto.
	(delete_fork_command): Replace mention of fork/checkpoint by
	checkpoint only.
	(detach_fork_command): Likewise.  Don't delete the checkpoint from
	the inferior list.
	(info_forks_command): Adjust.
	(restore_detach_fork): Delete.
	(checkpointing_pid): New.
	(linux_fork_checkpointing_p): New.
	(save_detach_fork): Delete.
	(checkpoint_command): Delete temp_detach_fork.  Don't remove
	breakpoints, that's a nop.  Store the pid of the process we're
	checkpointing, and use make_cleanup_restore_integer to restore it.
	Don't reinsert breakpoints here.
	(process_command, fork_command): Delete.
	(restart_command): Update comments to only mention checkpoints,
	not forks.
	(_initialize_linux_fork): Delete "fork", "process", "info forks"
	commands.
	* linux-fork.h (fork_save_infrun_state, fork_list): Delete
	declarations.
	(linux_fork_checkpointing_p): Declare.
	* cli/cli-cmds.c (killlist): New.
	* cli/cli-cmds.h (killlist): Declare.
	* gdbcmd.h (killlist): Declare.
	* inferior.c: Include "gdbthread.h".
	(detach_inferior_command, kill_inferior_command)
	(inferior_command): New.
	(info_inferiors_command): Allow specifying a specific inferior id.
	(_initialize_inferiors): Register "inferior", "kill inferior" and
	"detach inferior" commands.
	* infcmd.c (_initialize_infcmd): Make "kill" a prefix command.
	* gdbthread.h (any_thread_of_process): Declare.
	* thread.c (any_thread_of_process): New.

	* NEWS: Mention multi-inferior debugging.  Mention 'info
	inferiors', 'inferior', 'detach inferior' and 'kill inferior' as
	new commands.
	(Removed commands): New section, mentioning that 'info forks',
	'fork', 'process', 'delete fork' and 'detach fork' are now gone.

gdb/testsuite/
2009-07-02  Pedro Alves  <pedro@codesourcery.com>

	* gdb.base/multi-forks.exp: Only run detach-on-fork tests on
	linux.  Adjust to use "inferior", "info inferiors", "detach
	inferior" and "kill inferior" instead of "restart", "info fork",
	"detach fork" and "delete fork".
	* gdb.base/ending-run.exp: Spell out "info".
	* gdb.base/help.exp: Adjust to use test_prefix_command_help for
	the "kill" command.

gdb/doc/
2009-07-02  Pedro Alves  <pedro@codesourcery.com>

	* gdb.texinfo (Debugging multiple inferiors): Document the
	"inferior", "detach inferior" and "kill inferior" commands.
	(Debugging Programs with Multiple Processes): Adjust to mention
	generic "inferior" commands.  Delete mention of "detach fork" and
	"delete fork".  Cross reference to "Debugging multiple inferiors"
	section.
This commit is contained in:
Pedro Alves 2009-07-02 21:57:28 +00:00
parent 59837fe086
commit 2277426b30
18 changed files with 494 additions and 228 deletions

View File

@ -1,3 +1,67 @@
2009-07-02 Pedro Alves <pedro@codesourcery.com>
* linux-nat.c (linux_child_follow_fork): If we're staying attached
to the child process, enable event reporting on it. Don't handle
checkpoints here. Instead, add the child fork to the lwp thread
and inferior lists without clobbering the previous inferior. Let
the thread_db layer learn about a new child process, even if
following the parent.
(linux_nat_switch_fork): Delete lwps of the current inferior only,
instead of clearing the whole list. Use thread_change_ptid to
give the core the illusion the new checkpoint is still the same
inferior. Clear the register cache.
(linux_handle_extended_wait): Handle checkpoints here.
(linux_multi_process): Turn on.
* linux-fork.c (struct fork_info) <pc>: Remove field.
(init_fork_list): Do not delete the checkpoint from the inferior
list (it is not there).
(fork_load_infrun_state): Don't switch inferior_ptid here. Pass
the new checkpoint's ptid to linux_nat_switch_fork.
(fork_save_infrun_state): Make static. Don't stop the pc field of
fork_info, it's gone.
(linux_fork_mourn_inferior): Don't delete the checkpoint from the
inferior list, it's not there.
(linux_fork_detach): Ditto.
(delete_fork_command): Replace mention of fork/checkpoint by
checkpoint only.
(detach_fork_command): Likewise. Don't delete the checkpoint from
the inferior list.
(info_forks_command): Adjust.
(restore_detach_fork): Delete.
(checkpointing_pid): New.
(linux_fork_checkpointing_p): New.
(save_detach_fork): Delete.
(checkpoint_command): Delete temp_detach_fork. Don't remove
breakpoints, that's a nop. Store the pid of the process we're
checkpointing, and use make_cleanup_restore_integer to restore it.
Don't reinsert breakpoints here.
(process_command, fork_command): Delete.
(restart_command): Update comments to only mention checkpoints,
not forks.
(_initialize_linux_fork): Delete "fork", "process", "info forks"
commands.
* linux-fork.h (fork_save_infrun_state, fork_list): Delete
declarations.
(linux_fork_checkpointing_p): Declare.
* cli/cli-cmds.c (killlist): New.
* cli/cli-cmds.h (killlist): Declare.
* gdbcmd.h (killlist): Declare.
* inferior.c: Include "gdbthread.h".
(detach_inferior_command, kill_inferior_command)
(inferior_command): New.
(info_inferiors_command): Allow specifying a specific inferior id.
(_initialize_inferiors): Register "inferior", "kill inferior" and
"detach inferior" commands.
* infcmd.c (_initialize_infcmd): Make "kill" a prefix command.
* gdbthread.h (any_thread_of_process): Declare.
* thread.c (any_thread_of_process): New.
* NEWS: Mention multi-inferior debugging. Mention 'info
inferiors', 'inferior', 'detach inferior' and 'kill inferior' as
new commands.
(Removed commands): New section, mentioning that 'info forks',
'fork', 'process', 'delete fork' and 'detach fork' are now gone.
2009-07-02 Ulrich Weigand <uweigand@de.ibm.com>
* gdbarch.sh (current_gdbarch): Remove global variable.

View File

@ -175,6 +175,16 @@ GDB will now correctly handle all of:
* Support for user-defined prefixed commands. The "define" command can
add new commands to existing prefixes, e.g. "target".
* Multi-inferior, multi-process debugging.
GDB now has generalized support for multi-inferior debugging. See
"Debugging Multiple Inferiors" in the manual for more information.
Although availability still depends on target support, the command
set is more uniform now. The GNU/Linux specific multi-forks support
has been migrated to this new framework. This implied some user
visible changes; see "New commands" and also "Removed commands"
below.
* New commands (for set/show, see "New options" below)
find [/size-char] [/max-count] start-address, end-address|+search-space-size,
@ -197,6 +207,18 @@ macro undef
info os processes
Show operating system information about processes.
info inferiors
List the inferiors currently under GDB's control.
inferior NUM
Switch focus to inferior number NUM.
detach inferior NUM
Detach from inferior number NUM.
kill inferior NUM
Kill inferior number NUM.
* New options
set sh calling-convention
@ -320,6 +342,36 @@ show schedule-multiple
Allow GDB to resume all threads of all processes or only threads of
the current process.
* Removed commands
info forks
For program forks, this is replaced by the new more generic `info
inferiors' command. To list checkpoints, you can still use the
`info checkpoints' command, which was an alias for the `info forks'
command.
fork NUM
Replaced by the new `inferior' command. To switch between
checkpoints, you can still use the `restart' command, which was an
alias for the `fork' command.
process PID
This is removed, since some targets don't have a notion of
processes. To switch between processes, you can still use the
`inferior' command using GDB's own inferior number.
delete fork NUM
For program forks, this is replaced by the new more generic `kill
inferior' command. To delete a checkpoint, you can still use the
`delete checkpoint' command, which was an alias for the `delete
fork' command.
detach fork NUM
For program forks, this is replaced by the new more generic `detach
inferior' command. To detach a checkpoint, you can still use the
`detach checkpoint' command, which was an alias for the `detach
fork' command.
* New native configurations
x86/x86_64 Darwin i[34567]86-*-darwin*

View File

@ -125,6 +125,10 @@ struct cmd_list_element *deletelist;
struct cmd_list_element *detachlist;
/* Chain containing all defined kill subcommands. */
struct cmd_list_element *killlist;
/* Chain containing all defined "enable breakpoint" subcommands. */
struct cmd_list_element *enablebreaklist;

View File

@ -41,6 +41,10 @@ extern struct cmd_list_element *deletelist;
extern struct cmd_list_element *detachlist;
/* Chain containing all defined kill subcommands. */
extern struct cmd_list_element *killlist;
/* Chain containing all defined toggle subcommands. */
extern struct cmd_list_element *togglelist;

View File

@ -1,3 +1,12 @@
2009-07-02 Pedro Alves <pedro@codesourcery.com>
* gdb.texinfo (Debugging multiple inferiors): Document the
"inferior", "detach inferior" and "kill inferior" commands.
(Debugging Programs with Multiple Processes): Adjust to mention
generic "inferior" commands. Delete mention of "detach fork" and
"delete fork". Cross reference to "Debugging multiple inferiors"
section.
2009-07-02 Ulrich Weigand <uweigand@de.ibm.com>
* gdbint.texinfo (Item Output Functions): Update signature

View File

@ -2374,7 +2374,39 @@ To find out what inferiors exist at any moment, use @code{info inferiors}:
@kindex info inferiors
@item info inferiors
Print a list of all inferiors currently being managed by @value{GDBN}.
@end table
To switch focus between inferiors, use the @code{inferior} command:
@table @code
@kindex inferior @var{inferior-id}
@item inferior @var{inferior-id}
Make inferior number @var{inferior-id} the current inferior. The
argument @var{inferior-id} is the internal inferior number assigned by
@value{GDBN}, as shown in the first field of the @samp{info inferiors}
display.
@end table
To quit debugging one of the inferiors, you can either detach from it
by using the @w{@code{detach inferior}} command (allowing it to run
independently), or kill it using the @w{@code{kill inferior}} command:
@table @code
@kindex detach inferior @var{inferior-id}
@item detach inferior @var{inferior-id}
Detach from the inferior identified by @value{GDBN} inferior number
@var{inferior-id}, and remove it from the inferior list.
@kindex kill inferior @var{inferior-id}
@item kill inferior @var{inferior-id}
Kill the inferior identified by @value{GDBN} inferior number
@var{inferior-id}, and remove it from the inferior list.
@end table
To be notified when inferiors are started or exit under @value{GDBN}'s
control use @w{@code{set print inferior-events}}:
@table @code
@kindex set print inferior-events
@cindex print messages on inferior start and exit
@item set print inferior-events
@ -2758,51 +2790,17 @@ is held suspended.
Show whether detach-on-fork mode is on/off.
@end table
If you choose to set @samp{detach-on-fork} mode off, then
@value{GDBN} will retain control of all forked processes (including
nested forks). You can list the forked processes under the control of
@value{GDBN} by using the @w{@code{info forks}} command, and switch
from one fork to another by using the @w{@code{fork}} command.
@table @code
@kindex info forks
@item info forks
Print a list of all forked processes under the control of @value{GDBN}.
The listing will include a fork id, a process id, and the current
position (program counter) of the process.
@kindex fork @var{fork-id}
@item fork @var{fork-id}
Make fork number @var{fork-id} the current process. The argument
@var{fork-id} is the internal fork number assigned by @value{GDBN},
as shown in the first field of the @samp{info forks} display.
@kindex process @var{process-id}
@item process @var{process-id}
Make process number @var{process-id} the current process. The
argument @var{process-id} must be one that is listed in the output of
@samp{info forks}.
@end table
If you choose to set @samp{detach-on-fork} mode off, then @value{GDBN}
will retain control of all forked processes (including nested forks).
You can list the forked processes under the control of @value{GDBN} by
using the @w{@code{info inferiors}} command, and switch from one fork
to another by using the @code{inferior} command (@pxref{Inferiors,
,Debugging Multiple Inferiors}).
To quit debugging one of the forked processes, you can either detach
from it by using the @w{@code{detach fork}} command (allowing it to
run independently), or delete (and kill) it using the
@w{@code{delete fork}} command.
@table @code
@kindex detach fork @var{fork-id}
@item detach fork @var{fork-id}
Detach from the process identified by @value{GDBN} fork number
@var{fork-id}, and remove it from the fork list. The process will be
allowed to run independently.
@kindex delete fork @var{fork-id}
@item delete fork @var{fork-id}
Kill the process identified by @value{GDBN} fork number @var{fork-id},
and remove it from the fork list.
@end table
from it by using the @w{@code{detach inferior}} command (allowing it
to run independently), or kill it using the @w{@code{kill inferior}}
command. @xref{Inferiors, ,Debugging Multiple Inferiors}.
If you ask to debug a child process and a @code{vfork} is followed by an
@code{exec}, @value{GDBN} executes the new target up to the first
@ -2810,8 +2808,8 @@ breakpoint in the new target. If you have a breakpoint set on
@code{main} in your original program, the breakpoint will also be set on
the child process's @code{main}.
When a child process is spawned by @code{vfork}, you cannot debug the
child or parent until an @code{exec} call completes.
On some systems, when a child process is spawned by @code{vfork}, you
cannot debug the child or parent until an @code{exec} call completes.
If you issue a @code{run} command to @value{GDBN} after an @code{exec}
call executes, the new target restarts. To restart the parent process,

View File

@ -52,6 +52,10 @@ extern struct cmd_list_element *deletelist;
extern struct cmd_list_element *detachlist;
/* Chain containing all defined kill subcommands. */
extern struct cmd_list_element *killlist;
/* Chain containing all defined toggle subcommands. */
extern struct cmd_list_element *togglelist;

View File

@ -243,6 +243,9 @@ struct thread_info *find_thread_id (int num);
returns the first thread in the list. */
struct thread_info *first_thread_of_process (int pid);
/* Returns any thread of process PID. */
extern struct thread_info *any_thread_of_process (int pid);
/* Change the ptid of thread OLD_PTID to NEW_PTID. */
void thread_change_ptid (ptid_t old_ptid, ptid_t new_ptid);

View File

@ -2698,8 +2698,9 @@ fully linked executable files and separately compiled object files as needed."),
&showlist);
set_cmd_completer (c, noop_completer);
add_com ("kill", class_run, kill_command,
_("Kill execution of program being debugged."));
add_prefix_cmd ("kill", class_run, kill_command,
_("Kill execution of program being debugged."),
&killlist, "kill ", 0, &cmdlist);
add_com ("attach", class_run, attach_command, _("\
Attach to a process or file outside of GDB.\n\

View File

@ -25,6 +25,7 @@
#include "gdbthread.h"
#include "ui-out.h"
#include "observer.h"
#include "gdbthread.h"
void _initialize_inferiors (void);
@ -352,12 +353,112 @@ print_inferior (struct ui_out *uiout, int requested_inferior)
do_cleanups (old_chain);
}
static void
detach_inferior_command (char *args, int from_tty)
{
int num, pid;
struct thread_info *tp;
if (!args || !*args)
error (_("Requires argument (inferior id to detach)"));
num = parse_and_eval_long (args);
if (!valid_gdb_inferior_id (num))
error (_("Inferior ID %d not known."), num);
pid = gdb_inferior_id_to_pid (num);
tp = any_thread_of_process (pid);
if (!tp)
error (_("Inferior has no threads."));
switch_to_thread (tp->ptid);
detach_command (NULL, from_tty);
}
static void
kill_inferior_command (char *args, int from_tty)
{
int num, pid;
struct thread_info *tp;
if (!args || !*args)
error (_("Requires argument (inferior id to kill)"));
num = parse_and_eval_long (args);
if (!valid_gdb_inferior_id (num))
error (_("Inferior ID %d not known."), num);
pid = gdb_inferior_id_to_pid (num);
tp = any_thread_of_process (pid);
if (!tp)
error (_("Inferior has no threads."));
switch_to_thread (tp->ptid);
target_kill ();
bfd_cache_close_all ();
}
static void
inferior_command (char *args, int from_tty)
{
int num, pid;
if (!have_inferiors ())
error (_("No inferiors"));
num = parse_and_eval_long (args);
if (!valid_gdb_inferior_id (num))
error (_("Inferior ID %d not known."), num);
pid = gdb_inferior_id_to_pid (num);
if (pid != ptid_get_pid (inferior_ptid))
{
struct thread_info *tp;
tp = any_thread_of_process (pid);
if (!tp)
error (_("Inferior has no threads."));
switch_to_thread (tp->ptid);
}
printf_filtered (_("[Switching to thread %d (%s)] "),
pid_to_thread_id (inferior_ptid),
target_pid_to_str (inferior_ptid));
if (is_running (inferior_ptid))
ui_out_text (uiout, "(running)\n");
else
{
ui_out_text (uiout, "\n");
print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
}
}
/* Print information about currently known inferiors. */
static void
info_inferiors_command (char *arg, int from_tty)
info_inferiors_command (char *args, int from_tty)
{
print_inferior (uiout, -1);
int requested = -1;
if (args && *args)
{
requested = parse_and_eval_long (args);
if (!valid_gdb_inferior_id (requested))
error (_("Inferior ID %d not known."), requested);
}
print_inferior (uiout, requested);
}
/* Print notices when new inferiors are created and die. */
@ -381,4 +482,17 @@ Show printing of inferior events (e.g., inferior start and exit)."), NULL,
NULL,
show_print_inferior_events,
&setprintlist, &showprintlist);
add_cmd ("inferior", class_run, detach_inferior_command, _("\
Detach from inferior ID."),
&detachlist);
add_cmd ("inferior", class_run, kill_inferior_command, _("\
Kill inferior ID."),
&killlist);
add_cmd ("inferior", class_run, inferior_command, _("\
Use this command to switch between inferiors.\n\
The new inferior ID must be currently known."),
&cmdlist);
}

View File

@ -53,7 +53,6 @@ struct fork_info
struct regcache *savedregs; /* Convenient for info fork, saves
having to actually switch contexts. */
int clobber_regs; /* True if we should restore saved regs. */
ULONGEST pc; /* PC for info fork. */
off_t *filepos; /* Set of open file descriptors' offsets. */
int maxfd;
};
@ -211,7 +210,6 @@ init_fork_list (void)
for (fp = fork_list; fp; fp = fpnext)
{
fpnext = fp->next;
delete_inferior (ptid_get_pid (fp->ptid));
free_fork (fp);
}
@ -241,9 +239,7 @@ fork_load_infrun_state (struct fork_info *fp)
extern void nullify_last_target_wait_ptid ();
int i;
inferior_ptid = fp->ptid;
linux_nat_switch_fork (inferior_ptid);
linux_nat_switch_fork (fp->ptid);
if (fp->savedregs && fp->clobber_regs)
regcache_cpy (get_current_regcache (), fp->savedregs);
@ -269,7 +265,7 @@ fork_load_infrun_state (struct fork_info *fp)
/* Save infrun state for the fork PTID.
Exported for use by linux child_follow_fork. */
extern void
static void
fork_save_infrun_state (struct fork_info *fp, int clobber_regs)
{
char path[MAXPATHLEN];
@ -281,7 +277,6 @@ fork_save_infrun_state (struct fork_info *fp, int clobber_regs)
fp->savedregs = regcache_dup (get_current_regcache ());
fp->clobber_regs = clobber_regs;
fp->pc = regcache_read_pc (get_current_regcache ());
if (clobber_regs)
{
@ -371,8 +366,6 @@ linux_fork_mourn_inferior (void)
We need to delete that one from the fork_list, and switch
to the next available fork. */
delete_fork (inferior_ptid);
/* Delete process from GDB's inferior list. */
delete_inferior (ptid_get_pid (inferior_ptid));
/* There should still be a fork - if there's only one left,
delete_fork won't remove it, because we haven't updated
@ -403,8 +396,6 @@ linux_fork_detach (char *args, int from_tty)
error (_("Unable to detach %s"), target_pid_to_str (inferior_ptid));
delete_fork (inferior_ptid);
/* Delete process from GDB's inferior list. */
delete_inferior (ptid_get_pid (inferior_ptid));
/* There should still be a fork - if there's only one left,
delete_fork won't remove it, because we haven't updated
@ -430,14 +421,14 @@ delete_fork_command (char *args, int from_tty)
ptid_t ptid;
if (!args || !*args)
error (_("Requires argument (fork/checkpoint id to delete)"));
error (_("Requires argument (checkpoint id to delete)"));
ptid = fork_id_to_ptid (parse_and_eval_long (args));
if (ptid_equal (ptid, minus_one_ptid))
error (_("No such fork/checkpoint id, %s"), args);
error (_("No such checkpoint id, %s"), args);
if (ptid_equal (ptid, inferior_ptid))
error (_("Please switch to another fork/checkpoint before deleting the current one"));
error (_("Please switch to another checkpoint before deleting the current one"));
if (ptrace (PTRACE_KILL, PIDGET (ptid), 0, 0))
error (_("Unable to kill pid %s"), target_pid_to_str (ptid));
@ -446,8 +437,6 @@ delete_fork_command (char *args, int from_tty)
printf_filtered (_("Killed %s\n"), target_pid_to_str (ptid));
delete_fork (ptid);
/* Delete process from GDB's inferior list. */
delete_inferior (ptid_get_pid (ptid));
}
static void
@ -456,14 +445,15 @@ detach_fork_command (char *args, int from_tty)
ptid_t ptid;
if (!args || !*args)
error (_("Requires argument (fork id to detach)"));
error (_("Requires argument (checkpoint id to detach)"));
ptid = fork_id_to_ptid (parse_and_eval_long (args));
if (ptid_equal (ptid, minus_one_ptid))
error (_("No such fork id, %s"), args);
error (_("No such checkpoint id, %s"), args);
if (ptid_equal (ptid, inferior_ptid))
error (_("Please switch to another fork before detaching the current one"));
error (_("\
Please switch to another checkpoint before detaching the current one"));
if (ptrace (PTRACE_DETACH, PIDGET (ptid), 0, 0))
error (_("Unable to detach %s"), target_pid_to_str (ptid));
@ -472,8 +462,6 @@ detach_fork_command (char *args, int from_tty)
printf_filtered (_("Detached %s\n"), target_pid_to_str (ptid));
delete_fork (ptid);
/* Delete process from GDB's process table. */
detach_inferior (ptid_get_pid (ptid));
}
/* Print information about currently known forks. */
@ -508,7 +496,7 @@ info_forks_command (char *arg, int from_tty)
else
{
printf_filtered (" ");
pc = fp->pc;
pc = regcache_read_pc (fp->savedregs);
}
printf_filtered ("%d %s", fp->num, target_pid_to_str (fp->ptid));
if (fp->num == 0)
@ -542,31 +530,19 @@ info_forks_command (char *arg, int from_tty)
if (printed == NULL)
{
if (requested > 0)
printf_filtered (_("No fork number %d.\n"), requested);
printf_filtered (_("No checkpoint number %d.\n"), requested);
else
printf_filtered (_("No forks.\n"));
printf_filtered (_("No checkpoints.\n"));
}
}
/* Save/restore mode variable 'detach_fork':
We need to temporarily take over this mode variable, while
preserving the user-specified state, and make sure that it
gets restored in case of error.
/* The PID of the process we're checkpointing. */
static int checkpointing_pid = 0;
The int pointer that we use comes from the caller, so we can
be called more than once (even though currently we don't need to). */
static void
restore_detach_fork (void *arg)
int
linux_fork_checkpointing_p (int pid)
{
detach_fork = *(int *) arg;
}
static struct cleanup *
save_detach_fork (int *saved_val)
{
*saved_val = detach_fork;
return make_cleanup (restore_detach_fork, (void *) saved_val);
return (checkpointing_pid == pid);
}
static void
@ -581,12 +557,6 @@ checkpoint_command (char *args, int from_tty)
pid_t retpid;
struct cleanup *old_chain;
long i;
/* Make this temp var static, 'cause it's used in the error context. */
static int temp_detach_fork;
/* Remove breakpoints, so that they are not inserted
in the forked process. */
remove_breakpoints ();
/* Make the inferior fork, record its (and gdb's) state. */
@ -600,8 +570,11 @@ checkpoint_command (char *args, int from_tty)
gdbarch = get_objfile_arch (fork_objf);
ret = value_from_longest (builtin_type (gdbarch)->builtin_int, 0);
old_chain = save_detach_fork (&temp_detach_fork);
detach_fork = 0;
/* Tell linux-nat.c that we're checkpointing this inferior. */
old_chain = make_cleanup_restore_integer (&checkpointing_pid);
checkpointing_pid = PIDGET (inferior_ptid);
ret = call_function_by_hand (fork_fn, 0, &ret);
do_cleanups (old_chain);
if (!ret) /* Probably can't happen. */
@ -629,7 +602,6 @@ checkpoint_command (char *args, int from_tty)
if (!fp)
error (_("Failed to find new fork"));
fork_save_infrun_state (fp, 1);
insert_breakpoints ();
}
static void
@ -656,37 +628,7 @@ linux_fork_context (struct fork_info *newfp, int from_tty)
print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
}
/* Switch inferior process (fork) context, by process id. */
static void
process_command (char *args, int from_tty)
{
struct fork_info *fp;
if (!args || !*args)
error (_("Requires argument (process id to switch to)"));
if ((fp = find_fork_pid (parse_and_eval_long (args))) == NULL)
error (_("Not found: process id %s"), args);
linux_fork_context (fp, from_tty);
}
/* Switch inferior process (fork) context, by fork id. */
static void
fork_command (char *args, int from_tty)
{
struct fork_info *fp;
if (!args || !*args)
error (_("Requires argument (fork id to switch to)"));
if ((fp = find_fork_id (parse_and_eval_long (args))) == NULL)
error (_("Not found: fork id %s"), args);
linux_fork_context (fp, from_tty);
}
/* Switch inferior process (fork) context, by checkpoint id. */
/* Switch inferior process (checkpoint) context, by checkpoint id. */
static void
restart_command (char *args, int from_tty)
{
@ -727,9 +669,8 @@ Tells gdb whether to detach the child of a fork."),
add_com ("checkpoint", class_obscure, checkpoint_command, _("\
Fork a duplicate process (experimental)."));
/* Restart command: restore the context of a specified fork
process. May be used for "program forks" as well as for
"debugger forks" (checkpoints). */
/* Restart command: restore the context of a specified checkpoint
process. */
add_com ("restart", class_obscure, restart_command, _("\
restart <n>: restore program context from a checkpoint.\n\
@ -739,36 +680,19 @@ Argument 'n' is checkpoint ID, as displayed by 'info checkpoints'."));
fork list. */
add_cmd ("checkpoint", class_obscure, delete_fork_command, _("\
Delete a fork/checkpoint (experimental)."),
Delete a checkpoint (experimental)."),
&deletelist);
/* Detach checkpoint command: release the process to run independently,
and remove it from the fork list. */
add_cmd ("checkpoint", class_obscure, detach_fork_command, _("\
Detach from a fork/checkpoint (experimental)."),
Detach from a checkpoint (experimental)."),
&detachlist);
/* Info checkpoints command: list all forks/checkpoints
currently under gdb's control. */
add_info ("checkpoints", info_forks_command,
_("IDs of currently known forks/checkpoints."));
/* Command aliases (let "fork" and "checkpoint" be used
interchangeably). */
add_alias_cmd ("fork", "checkpoint", class_obscure, 1, &deletelist);
add_alias_cmd ("fork", "checkpoint", class_obscure, 1, &detachlist);
add_info_alias ("forks", "checkpoints", 0);
/* "fork <n>" (by analogy to "thread <n>"). */
add_com ("fork", class_obscure, fork_command, _("\
fork <n>: Switch between forked processes.\n\
Argument 'n' is fork ID, as displayed by 'info forks'."));
/* "process <proc id>" as opposed to "fork <fork id>". */
add_com ("process", class_obscure, process_command, _("\
process <pid>: Switch between forked processes.\n\
Argument 'pid' is process ID, as displayed by 'info forks' or 'shell ps'."));
_("IDs of currently known checkpoints."));
}

View File

@ -20,13 +20,11 @@
struct fork_info;
extern struct fork_info *add_fork (pid_t);
extern struct fork_info *find_fork_pid (pid_t);
extern void fork_save_infrun_state (struct fork_info *, int);
extern void linux_fork_killall (void);
extern void linux_fork_mourn_inferior (void);
extern void linux_fork_detach (char *, int);
extern int forks_exist_p (void);
struct fork_info *fork_list;
extern int forks_exist_p (void);
extern int linux_fork_checkpointing_p (int);
extern int detach_fork;

View File

@ -338,6 +338,12 @@ static int stop_callback (struct lwp_info *lp, void *data);
static void block_child_signals (sigset_t *prev_mask);
static void restore_child_signals_mask (sigset_t *prev_mask);
struct lwp_info;
static struct lwp_info *add_lwp (ptid_t ptid);
static void purge_lwp_list (int pid);
static struct lwp_info *find_lwp_pid (ptid_t ptid);
/* Trivial list manipulation functions to keep track of a list of
new stopped processes. */
@ -587,6 +593,9 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
parent_pid = ptid_get_pid (inferior_ptid);
child_pid = PIDGET (inferior_thread ()->pending_follow.value.related_pid);
if (!detach_fork)
linux_enable_event_reporting (pid_to_ptid (child_pid));
if (! follow_child)
{
/* We're already attached to the parent, by default. */
@ -617,8 +626,9 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
}
else
{
struct fork_info *fp;
struct inferior *parent_inf, *child_inf;
struct lwp_info *lp;
struct cleanup *old_chain;
/* Add process to GDB's tables. */
child_inf = add_inferior (child_pid);
@ -627,11 +637,16 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
child_inf->attach_flag = parent_inf->attach_flag;
copy_terminal_info (child_inf, parent_inf);
/* Retain child fork in ptrace (stopped) state. */
fp = find_fork_pid (child_pid);
if (!fp)
fp = add_fork (child_pid);
fork_save_infrun_state (fp, 0);
old_chain = save_inferior_ptid ();
inferior_ptid = ptid_build (child_pid, child_pid, 0);
add_thread (inferior_ptid);
lp = add_lwp (inferior_ptid);
lp->stopped = 1;
check_for_thread_db ();
do_cleanups (old_chain);
}
if (has_vforked)
@ -692,6 +707,7 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
{
struct thread_info *tp;
struct inferior *parent_inf, *child_inf;
struct lwp_info *lp;
/* Before detaching from the parent, remove all breakpoints from it. */
remove_breakpoints ();
@ -733,30 +749,33 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
if (has_vforked)
{
linux_parent_pid = parent_pid;
detach_inferior (parent_pid);
}
else if (!detach_fork)
{
struct fork_info *fp;
/* Retain parent fork in ptrace (stopped) state. */
fp = find_fork_pid (parent_pid);
if (!fp)
fp = add_fork (parent_pid);
fork_save_infrun_state (fp, 0);
struct lwp_info *parent_lwp;
/* Also add an entry for the child fork. */
fp = find_fork_pid (child_pid);
if (!fp)
fp = add_fork (child_pid);
fork_save_infrun_state (fp, 0);
linux_parent_pid = parent_pid;
/* Get rid of the inferior on the core side as well. */
inferior_ptid = null_ptid;
detach_inferior (parent_pid);
/* Also get rid of all its lwps. We will detach from this
inferior soon-ish, but, we will still get an exit event
reported through waitpid when it exits. If we didn't get
rid of the lwps from our list, we would end up reporting
the inferior exit to the core, which would then try to
mourn a non-existing (from the core's perspective)
inferior. */
parent_lwp = find_lwp_pid (pid_to_ptid (parent_pid));
purge_lwp_list (GET_PID (parent_lwp->ptid));
linux_parent_pid = parent_pid;
}
else
else if (detach_fork)
target_detach (NULL, 0);
inferior_ptid = ptid_build (child_pid, child_pid, 0);
add_thread (inferior_ptid);
lp = add_lwp (inferior_ptid);
lp->stopped = 1;
linux_nat_switch_fork (inferior_ptid);
check_for_thread_db ();
}
@ -1073,22 +1092,30 @@ iterate_over_lwps (ptid_t filter,
return NULL;
}
/* Update our internal state when changing from one fork (checkpoint,
et cetera) to another indicated by NEW_PTID. We can only switch
single-threaded applications, so we only create one new LWP, and
the previous list is discarded. */
/* Update our internal state when changing from one checkpoint to
another indicated by NEW_PTID. We can only switch single-threaded
applications, so we only create one new LWP, and the previous list
is discarded. */
void
linux_nat_switch_fork (ptid_t new_ptid)
{
struct lwp_info *lp;
init_lwp_list ();
purge_lwp_list (GET_PID (inferior_ptid));
lp = add_lwp (new_ptid);
lp->stopped = 1;
init_thread_list ();
add_thread_silent (new_ptid);
/* This changes the thread's ptid while preserving the gdb thread
num. Also changes the inferior pid, while preserving the
inferior num. */
thread_change_ptid (inferior_ptid, new_ptid);
/* We've just told GDB core that the thread changed target id, but,
in fact, it really is a different thread, with different register
contents. */
registers_changed ();
}
/* Handle the exit of a single thread LP. */
@ -1815,6 +1842,34 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
ourstatus->value.related_pid = ptid_build (new_pid, new_pid, 0);
if (event == PTRACE_EVENT_FORK
&& linux_fork_checkpointing_p (GET_PID (lp->ptid)))
{
struct fork_info *fp;
/* Handle checkpointing by linux-fork.c here as a special
case. We don't want the follow-fork-mode or 'catch fork'
to interfere with this. */
/* This won't actually modify the breakpoint list, but will
physically remove the breakpoints from the child. */
detach_breakpoints (new_pid);
/* Retain child fork in ptrace (stopped) state. */
fp = find_fork_pid (new_pid);
if (!fp)
fp = add_fork (new_pid);
/* Report as spurious, so that infrun doesn't want to follow
this fork. We're actually doing an infcall in
linux-fork.c. */
ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
linux_enable_event_reporting (pid_to_ptid (new_pid));
/* Report the stop to the core. */
return 0;
}
if (event == PTRACE_EVENT_FORK)
ourstatus->kind = TARGET_WAITKIND_FORKED;
else if (event == PTRACE_EVENT_VFORK)
@ -4295,7 +4350,7 @@ linux_nat_supports_non_stop (void)
/* True if we want to support multi-process. To be removed when GDB
supports multi-exec. */
int linux_multi_process = 0;
int linux_multi_process = 1;
static int
linux_nat_supports_multi_process (void)

View File

@ -1,3 +1,13 @@
2009-07-02 Pedro Alves <pedro@codesourcery.com>
* gdb.base/multi-forks.exp: Only run detach-on-fork tests on
linux. Adjust to use "inferior", "info inferiors", "detach
inferior" and "kill inferior" instead of "restart", "info fork",
"detach fork" and "delete fork".
* gdb.base/ending-run.exp: Spell out "info".
* gdb.base/help.exp: Adjust to use test_prefix_command_help for
the "kill" command.
2009-07-02 Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
* gdb.threads/tls-shared.exp: Update to locexpr_describe_location

View File

@ -71,7 +71,7 @@ gdb_test "b ending-run.c:14" ".*Note.*also.*Breakpoint.*5.*" "b ending-run.c:14,
gdb_test "cle ending-run.c:14" \
".*Deleted breakpoint 5.*" "Cleared 2 by line"
send_gdb "inf line ending-run.c:14\n"
send_gdb "info line ending-run.c:14\n"
gdb_expect {
-re ".*address (0x\[0-9a-fA-F]*).*$gdb_prompt $" {
set line_nine $expect_out(1,string)

View File

@ -300,7 +300,9 @@ gdb_test "help inspect" "Same as \"print\" command, except that if you are runni
# test help jump
gdb_test "help jump" "Continue program being debugged at specified line or address\.\[\r\n\]+Give as argument either LINENUM or \[*\]+ADDR, where ADDR is an expression\[\r\n\]+for an address to start at\." "help jump"
# test help kill
gdb_test "help kill" "Kill execution of program being debugged\." "help kill"
test_prefix_command_help "kill" {
"Kill execution of program being debugged\.\[\r\n\]+"
}
# test help list "l" abbreviation
gdb_test "help l" "List specified function or line\.\[\r\n\]+With no argument, lists ten more lines after or around previous listing\.\[\r\n\]+\"list -\" lists the ten lines before a previous ten-line listing\.\[\r\n\]+One argument specifies a line, and ten lines are listed around that line\.\[\r\n\]+Two arguments with comma between specify starting and ending lines to list\.\[\r\n\]+Lines can be specified in these ways:\[\r\n\]+ LINENUM, to list around that line in current file,\[\r\n\]+ FILE:LINENUM, to list around that line in that file,\[\r\n\]+ FUNCTION, to list around beginning of that function,\[\r\n\]+ FILE:FUNCTION, to distinguish among like-named static functions\.\[\r\n\]+ \[*\]ADDRESS, to list around the line containing that address\.\[\r\n\]+With two args if one is empty it stands for ten lines away from the other arg\." "help list \"l\" abbreviation"
# test help list

View File

@ -140,6 +140,19 @@ gdb_test "print pids\[0\]==0 || pids\[1\]==0 || pids\[2\]==0 || pids\[3\]==0" \
# Now test with detach-on-fork off.
#
# detach-on-fork isn't implemented on hpux.
#
if {![istarget "*-*-linux*"]} then {
continue
}
# Start with a fresh gdb
gdb_exit
gdb_start
gdb_reinitialize_dir $srcdir/$subdir
gdb_load ${binfile}
runto_main
gdb_breakpoint $exit_bp_loc
@ -152,60 +165,59 @@ gdb_test "set detach off" "" "set detach off"
#
# We will now run every fork up to the exit bp,
# eventually winding up with 16 forks.
# eventually winding up with 16 inferiors.
#
for {set i 1} {$i <= 15} {incr i} {
gdb_test "continue" "Breakpoint .* main .*exit.*" "Run to exit $i"
gdb_test "info fork" " 4 .* 3 .* 2 .* 1 .*" "info fork $i"
gdb_test "restart $i" "(_dl_sysinfo_int80|fork|__kernel_(v|)syscall).*" \
"restart $i"
gdb_test "info inferior" " 5 .* 4 .* 3 .* 2 .*" "info inferior $i"
gdb_test "inferior $i + 1" "(_dl_sysinfo_int80|fork|__kernel_(v|)syscall).*" \
"inferior $i"
}
gdb_test "continue" "Breakpoint .* main .*exit.*" "Run to exit 16"
gdb_test "info fork" " 4 .* 3 .* 2 .* 1 .*" "info fork 16"
gdb_test "restart 0" " main .*" "restart final"
gdb_test "info inferiors" " 5 .* 4 .* 3 .* 2 .*" "info inferior 16"
gdb_test "inferior 2" " main .*" "restart final"
#
# Now we should examine all the pids.
#
#
# Test detach fork
# Test detach inferior
#
# [assumes we're at #0]
gdb_test "detach fork 1" "Detached .*" "Detach 1"
gdb_test "detach fork 2" "Detached .*" "Detach 2"
gdb_test "detach fork 3" "Detached .*" "Detach 3"
gdb_test "detach fork 4" "Detached .*" "Detach 4"
# [assumes we're at #1]
gdb_test "detach inferior 2" "Detaching .*" "Detach 2"
gdb_test "detach inferior 3" "Detaching .*" "Detach 3"
gdb_test "detach inferior 4" "Detaching .*" "Detach 4"
gdb_test "detach inferior 5" "Detaching .*" "Detach 5"
#
# Test delete fork
#
# Test kill inferior
#
gdb_test "delete fork 5" "" "Delete 5"
gdb_test "info fork 5" "No fork number 5." "Did delete 5"
gdb_test "delete fork 6" "" "Delete 6"
gdb_test "info fork 6" "No fork number 6." "Did delete 6"
gdb_test "delete fork 7" "" "Delete 7"
gdb_test "info fork 7" "No fork number 7." "Did delete 7"
gdb_test "delete fork 8" "" "Delete 8"
gdb_test "info fork 8" "No fork number 8." "Did delete 8"
gdb_test "delete fork 9" "" "Delete 9"
gdb_test "info fork 9" "No fork number 9." "Did delete 9"
gdb_test "delete fork 10" "" "Delete 10"
gdb_test "info fork 10" "No fork number 10." "Did delete 10"
gdb_test "delete fork 11" "" "Delete 11"
gdb_test "info fork 11" "No fork number 11." "Did delete 11"
gdb_test "delete fork 12" "" "Delete 12"
gdb_test "info fork 12" "No fork number 12." "Did delete 12"
gdb_test "delete fork 13" "" "Delete 13"
gdb_test "info fork 13" "No fork number 13." "Did delete 13"
gdb_test "delete fork 14" "" "Delete 14"
gdb_test "info fork 14" "No fork number 14." "Did delete 14"
gdb_test "delete fork 15" "" "Delete 15"
gdb_test "info fork 15" "No fork number 15." "Did delete 15"
gdb_test "kill inferior 6" "" "Kill 6"
gdb_test "info inferior 6" "Inferior ID 6 not known." "Did kill 6"
gdb_test "kill inferior 7" "" "Kill 7"
gdb_test "info inferior 7" "Inferior ID 7 not known." "Did kill 7"
gdb_test "kill inferior 8" "" "Kill 8"
gdb_test "info inferior 8" "Inferior ID 8 not known." "Did kill 8"
gdb_test "kill inferior 9" "" "Kill 9"
gdb_test "info inferior 9" "Inferior ID 9 not known." "Did kill 9"
gdb_test "kill inferior 10" "" "Kill 10"
gdb_test "info inferior 10" "Inferior ID 10 not known." "Did kill 10"
gdb_test "kill inferior 11" "" "Kill 11"
gdb_test "info inferior 11" "Inferior ID 11 not known." "Did kill 11"
gdb_test "kill inferior 12" "" "Kill 12"
gdb_test "info inferior 12" "Inferior ID 12 not known." "Did kill 12"
gdb_test "kill inferior 13" "" "Kill 13"
gdb_test "info inferior 13" "Inferior ID 13 not known." "Did kill 13"
gdb_test "kill inferior 14" "" "Kill 14"
gdb_test "info inferior 14" "Inferior ID 14 not known." "Did kill 14"
gdb_test "kill inferior 15" "" "Kill 15"
gdb_test "info inferior 15" "Inferior ID 15 not known." "Did kill 15"
gdb_test "kill inferior 16" "" "Kill 16"
gdb_test "info inferior 16" "Inferior ID 16 not known." "Did kill 16"
return 0

View File

@ -428,6 +428,18 @@ first_thread_of_process (int pid)
return ret;
}
struct thread_info *
any_thread_of_process (int pid)
{
struct thread_info *tp;
for (tp = thread_list; tp; tp = tp->next)
if (ptid_get_pid (tp->ptid) == pid)
return tp;
return NULL;
}
/* Print a list of thread ids currently known, and the total number of
threads. To be used from within catch_errors. */
static int