* inferior.h: Forward declare struct ui_out.
	Forward declare struct private_inferior.
	(struct inferior): New.
	(init_inferior_list, add_inferior, add_inferior_silent)
	(delete_inferior, delete_inferior_silent, detach_inferior)
	(gdb_inferior_id_to_pid, pid_to_gdb_inferior_id, in_inferior_list)
	(valid_inferior_id, find_inferior_pid): New functions.
	(inferior_callback_func): New typedef.
	(iterate_over_inferiors, print_inferior, have_inferiors)
	(current_inferior): New functions.
	* inferior.c: New file.

	* Makefile.in (SFILES): Add inferior.c.
	(COMMON_OBS): Add inferior.o.

gdb/doc/
	* gdb.texinfo (Inferiors): New section.
This commit is contained in:
Pedro Alves 2008-09-22 15:12:19 +00:00
parent d8c3d48d73
commit b77209e000
6 changed files with 502 additions and 2 deletions

View File

@ -1,3 +1,20 @@
2008-09-22 Pedro Alves <pedro@codesourcery.com>
* inferior.h: Forward declare struct ui_out.
Forward declare struct private_inferior.
(struct inferior): New.
(init_inferior_list, add_inferior, add_inferior_silent)
(delete_inferior, delete_inferior_silent, detach_inferior)
(gdb_inferior_id_to_pid, pid_to_gdb_inferior_id, in_inferior_list)
(valid_inferior_id, find_inferior_pid): New functions.
(inferior_callback_func): New typedef.
(iterate_over_inferiors, print_inferior, have_inferiors)
(current_inferior): New functions.
* inferior.c: New file.
* Makefile.in (SFILES): Add inferior.c.
(COMMON_OBS): Add inferior.o.
2008-09-22 Jonathan Larmour <jifl@eCosCentric.com>
* arm-tdep.c (arm_skip_prologue): Call skip_prologue_using_sal

View File

@ -655,7 +655,8 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c \
user-regs.c \
valarith.c valops.c valprint.c value.c varobj.c vec.c \
wrapper.c \
xml-tdesc.c xml-support.c
xml-tdesc.c xml-support.c \
inferior.c
LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
@ -803,7 +804,8 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
tramp-frame.o \
solib.o solib-null.o \
prologue-value.o memory-map.o xml-support.o \
target-descriptions.o target-memory.o xml-tdesc.o xml-builtin.o
target-descriptions.o target-memory.o xml-tdesc.o xml-builtin.o \
inferior.o
TSOBS = inflow.o

View File

@ -1,3 +1,7 @@
2008-09-22 Stan Shebs <stan@codesourcery.com>
* gdb.texinfo (Inferiors): New section.
2008-09-12 Pedro Alves <pedro@codesourcery.com>
* gdbint.texinfo (Native Debugging): Mention NAT_GENERATED_FILES.

View File

@ -1785,6 +1785,7 @@ kill a child process.
* Attach:: Debugging an already-running process
* Kill Process:: Killing the child process
* Inferiors:: Debugging multiple inferiors
* Threads:: Debugging programs with multiple threads
* Processes:: Debugging programs with multiple processes
* Checkpoint/Restart:: Setting a @emph{bookmark} to return to later
@ -2354,6 +2355,52 @@ next type @code{run}, @value{GDBN} notices that the file has changed, and
reads the symbol table again (while trying to preserve your current
breakpoint settings).
@node Inferiors
@section Debugging Multiple Inferiors
Some @value{GDBN} targets are able to run multiple processes created
from a single executable. This can happen, for instance, with an
embedded system reporting back several processes via the remote
protocol.
@cindex inferior
@value{GDBN} represents the state of each program execution with an
object called an @dfn{inferior}. An inferior typically corresponds to
a process, but is more general and applies also to targets that do not
have processes. Inferiors may be created before a process runs, and
may (in future) be retained after a process exits. Each run of an
executable creates a new inferior, as does each attachment to an
existing process. Inferiors have unique identifiers that are
different from process ids, and may optionally be named as well.
Usually each inferior will also have its own distinct address space,
although some embedded targets may have several inferiors running in
different parts of a single space.
Each inferior may in turn have multiple threads running in it.
To find out what inferiors exist at any moment, use @code{info inferiors}:
@table @code
@kindex info inferiors
@item info inferiors
Print a list of all inferiors currently being managed by @value{GDBN}.
@kindex set print inferior-events
@cindex print messages on inferior start and exit
@item set print inferior-events
@itemx set print inferior-events on
@itemx set print inferior-events off
The @code{set print inferior-events} command allows you to enable or
disable printing of messages when @value{GDBN} notices that new
inferiors have started or that inferiors have exited or have been
detached. By default, these messages will not be printed.
@kindex show print inferior-events
@item show print inferior-events
Show whether messages will be printed when @value{GDBN} detects that
inferiors have started, exited or have been detached.
@end table
@node Threads
@section Debugging Programs with Multiple Threads

332
gdb/inferior.c Normal file
View File

@ -0,0 +1,332 @@
/* Multi-process control for GDB, the GNU debugger.
Copyright (C) 2008 Free Software Foundation, Inc.
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 "target.h"
#include "command.h"
#include "gdbcmd.h"
#include "gdbthread.h"
#include "ui-out.h"
void _initialize_inferiors (void);
static struct inferior *inferior_list = NULL;
static int highest_inferior_num;
/* Print notices on inferior events (attach, detach, etc.), set with
`set print inferior-events'. */
static int print_inferior_events = 0;
struct inferior*
current_inferior (void)
{
struct inferior *inf = find_inferior_pid (ptid_get_pid (inferior_ptid));
gdb_assert (inf);
return inf;
}
static void
free_inferior (struct inferior *inf)
{
xfree (inf->private);
xfree (inf);
}
void
init_inferior_list (void)
{
struct inferior *inf, *infnext;
highest_inferior_num = 0;
if (!inferior_list)
return;
for (inf = inferior_list; inf; inf = infnext)
{
infnext = inf->next;
free_inferior (inf);
}
inferior_list = NULL;
}
struct inferior *
add_inferior_silent (int pid)
{
struct inferior *inf;
inf = xmalloc (sizeof (*inf));
memset (inf, 0, sizeof (*inf));
inf->pid = pid;
inf->num = ++highest_inferior_num;
inf->next = inferior_list;
inferior_list = inf;
return inf;
}
struct inferior *
add_inferior (int pid)
{
struct inferior *inf = add_inferior_silent (pid);
if (print_inferior_events)
printf_unfiltered (_("[New inferior %d]\n"), pid);
return inf;
}
struct delete_thread_of_inferior_arg
{
int pid;
int silent;
};
static int
delete_thread_of_inferior (struct thread_info *tp, void *data)
{
struct delete_thread_of_inferior_arg *arg = data;
if (ptid_get_pid (tp->ptid) == arg->pid)
{
if (arg->silent)
delete_thread_silent (tp->ptid);
else
delete_thread (tp->ptid);
}
return 0;
}
/* If SILENT then be quiet -- don't announce a inferior death, or the
exit of its threads. */
static void
delete_inferior_1 (int pid, int silent)
{
struct inferior *inf, *infprev;
struct delete_thread_of_inferior_arg arg = { pid, silent };
infprev = NULL;
for (inf = inferior_list; inf; infprev = inf, inf = inf->next)
if (inf->pid == pid)
break;
if (!inf)
return;
if (infprev)
infprev->next = inf->next;
else
inferior_list = inf->next;
free_inferior (inf);
arg.pid = pid;
arg.silent = silent;
iterate_over_threads (delete_thread_of_inferior, &arg);
}
void
delete_inferior (int pid)
{
delete_inferior_1 (pid, 0);
if (print_inferior_events)
printf_unfiltered (_("[Inferior %d exited]\n"), pid);
}
void
delete_inferior_silent (int pid)
{
delete_inferior_1 (pid, 1);
}
void
detach_inferior (int pid)
{
delete_inferior_1 (pid, 1);
if (print_inferior_events)
printf_unfiltered (_("[Inferior %d detached]\n"), pid);
}
static struct inferior *
find_inferior_id (int num)
{
struct inferior *inf;
for (inf = inferior_list; inf; inf = inf->next)
if (inf->num == num)
return inf;
return NULL;
}
struct inferior *
find_inferior_pid (int pid)
{
struct inferior *inf;
for (inf = inferior_list; inf; inf = inf->next)
if (inf->pid == pid)
return inf;
return NULL;
}
struct inferior *
iterate_over_inferiors (int (*callback) (struct inferior *, void *),
void *data)
{
struct inferior *inf, *infnext;
for (inf = inferior_list; inf; inf = infnext)
{
infnext = inf->next;
if ((*callback) (inf, data))
return inf;
}
return NULL;
}
int
valid_gdb_inferior_id (int num)
{
struct inferior *inf;
for (inf = inferior_list; inf; inf = inf->next)
if (inf->num == num)
return 1;
return 0;
}
int
pid_to_gdb_inferior_id (int pid)
{
struct inferior *inf;
for (inf = inferior_list; inf; inf = inf->next)
if (inf->pid == pid)
return inf->num;
return 0;
}
int
gdb_inferior_id_to_pid (int num)
{
struct inferior *inferior = find_inferior_id (num);
if (inferior)
return inferior->pid;
else
return -1;
}
int
in_inferior_list (int pid)
{
struct inferior *inf;
for (inf = inferior_list; inf; inf = inf->next)
if (inf->pid == pid)
return 1;
return 0;
}
int
have_inferiors (void)
{
return inferior_list != NULL;
}
/* Prints the list of inferiors and their details on UIOUT. This is a
version of 'info_inferior_command' suitable for use from MI.
If REQUESTED_INFERIOR is not -1, it's the GDB id of the inferior that
should be printed. Otherwise, all inferiors are printed. */
void
print_inferior (struct ui_out *uiout, int requested_inferior)
{
struct inferior *inf;
struct cleanup *old_chain;
old_chain = make_cleanup_ui_out_list_begin_end (uiout, "inferiors");
for (inf = inferior_list; inf; inf = inf->next)
{
struct cleanup *chain2;
if (requested_inferior != -1 && inf->num != requested_inferior)
continue;
chain2 = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
if (inf->pid == ptid_get_pid (inferior_ptid))
ui_out_text (uiout, "* ");
else
ui_out_text (uiout, " ");
ui_out_field_int (uiout, "id", inf->num);
ui_out_text (uiout, " ");
ui_out_field_int (uiout, "target-id", inf->pid);
ui_out_text (uiout, "\n");
do_cleanups (chain2);
}
do_cleanups (old_chain);
}
/* Print information about currently known inferiors. */
static void
info_inferiors_command (char *arg, int from_tty)
{
print_inferior (uiout, -1);
}
/* Print notices when new inferiors are created and die. */
static void
show_print_inferior_events (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("Printing of inferior events is %s.\n"), value);
}
void
_initialize_inferiors (void)
{
add_info ("inferiors", info_inferiors_command,
_("IDs of currently known inferiors."));
add_setshow_boolean_cmd ("inferior-events", no_class,
&print_inferior_events, _("\
Set printing of inferior events (e.g., inferior start and exit)."), _("\
Show printing of inferior events (e.g., inferior start and exit)."), NULL,
NULL,
show_print_inferior_events,
&setprintlist, &showprintlist);
}

View File

@ -29,6 +29,7 @@ struct ui_file;
struct type;
struct gdbarch;
struct regcache;
struct ui_out;
/* For bpstat. */
#include "breakpoint.h"
@ -397,4 +398,101 @@ extern int suppress_resume_observer;
#if !defined(START_INFERIOR_TRAPS_EXPECTED)
#define START_INFERIOR_TRAPS_EXPECTED 2
#endif
struct private_inferior;
/* GDB represents the state of each program execution with an object
called an inferior. An inferior typically corresponds to a process
but is more general and applies also to targets that do not have a
notion of processes. Each run of an executable creates a new
inferior, as does each attachment to an existing process.
Inferiors have unique internal identifiers that are different from
target process ids. Each inferior may in turn have multiple
threads running in it. */
struct inferior
{
/* Pointer to next inferior in singly-linked list of inferiors. */
struct inferior *next;
/* Convenient handle (GDB inferior id). Unique across all
inferiors. */
int num;
/* Actual target inferior id, usually, a process id. This matches
the ptid_t.pid member of threads of this inferior. */
int pid;
/* Private data used by the target vector implementation. */
struct private_inferior *private;
};
/* Create an empty inferior list, or empty the existing one. */
extern void init_inferior_list (void);
/* Add an inferior to the inferior list, print a message that a new
inferior is found, and return the pointer to the new inferior.
Caller may use this pointer to initialize the private inferior
data. */
extern struct inferior *add_inferior (int pid);
/* Same as add_inferior, but don't print new inferior notifications to
the CLI. */
extern struct inferior *add_inferior_silent (int pid);
/* Delete an existing inferior list entry, due to inferior exit. */
extern void delete_inferior (int pid);
/* Same as delete_inferior, but don't print new inferior notifications
to the CLI. */
extern void delete_inferior_silent (int pid);
/* Delete an existing inferior list entry, due to inferior detaching. */
extern void detach_inferior (int pid);
/* Translate the integer inferior id (GDB's homegrown id, not the system's)
into a "pid" (which may be overloaded with extra inferior information). */
extern int gdb_inferior_id_to_pid (int);
/* Translate a target 'pid' into the integer inferior id (GDB's
homegrown id, not the system's). */
extern int pid_to_gdb_inferior_id (int pid);
/* Boolean test for an already-known pid. */
extern int in_inferior_list (int pid);
/* Boolean test for an already-known inferior id (GDB's homegrown id,
not the system's). */
extern int valid_inferior_id (int num);
/* Search function to lookup a inferior by target 'pid'. */
extern struct inferior *find_inferior_pid (int pid);
/* Inferior iterator function.
Calls a callback function once for each inferior, so long as the
callback function returns false. If the callback function returns
true, the iteration will end and the current inferior will be
returned. This can be useful for implementing a search for a
inferior with arbitrary attributes, or for applying some operation
to every inferior.
It is safe to delete the iterated inferior from the callback. */
extern struct inferior *iterate_over_inferiors (int (*) (struct inferior *,
void *),
void *);
/* Prints the list of inferiors and their details on UIOUT.
If REQUESTED_INFERIOR is not -1, it's the GDB id of the inferior
that should be printed. Otherwise, all inferiors are printed. */
extern void print_inferior (struct ui_out *uiout, int requested_inferior);
/* Returns true if the inferior list is not empty. */
extern int have_inferiors (void);
/* Return a pointer to the current inferior. It is an error to call
this if there is no current inferior. */
extern struct inferior *current_inferior (void);
#endif /* !defined (INFERIOR_H) */