Implement remote multi-process extensions.

* remote.c (struct remote_state): Add extended and
	multi_process_aware fields.
	(remote_multi_process_p): New.
	(PACKET_vKill): New.
	(record_currthread): Use thread_change_ptid.  Notice new
	inferiors.
	(set_thread, remote_thread_alive): Use write_ptid.
	(write_ptid, read_ptid): New.
	(remote_current_thread, remote_threads_extra_info): Use them.
	(remote_threads_info): Likewise.  Detect new inferiors.
	(remote_start_remote): Add inferior to inferior list.
	(remote_multi_process_feature): New.
	(remote_protocol_features): Add "multiprocess" feature.
	(remote_query_supported): Pass "multiprocess+" as supported
	features.
	(remote_open_1): Clear multi_process_aware.  Set extended
	accordingly.
	(remote_detach_1): Detach current process.  Use extended packet
	format for extended-remote multi-process.  Detach process from the
	inferior list.  Only mourn after printing output.
	(extended_remote_attach_1): Add process to the inferior list.
	(remote_vcont_resume): Use write_ptid to pass the thread ids.
	(remote_wait): Use read_ptid.  Implement the extended
	multi-process extension format of the 'W' and 'X' reply packets.
	Remove exited inferiors from inferior list.
	(remote_xfer_memory): Set general thread.
	(remote_vkill): New.
	(extended_remote_kill): New.
	(remote_mourn_1): Discard all inferiors.
	(select_new_thread_callback): New.
	(extended_remote_mourn_1): If there are more processes to debug,
	switch to a thread in another process, and don't pop the target.
	(extended_remote_create_inferior_1): Add the new process to the
	inferior list.
	(remote_stopped_by_watchpoint): Indenting.
	(remote_xfer_partial): Set the general thread.
	(remote_pid_to_str): If the remote is multi-process aware, print
	the process id as well as the thread id.
	(remote_get_thread_local_address): Use write_ptid.
	(init_extended_remote_ops): Register extended_remote_kill.
	(_initialize_remote): Register new packets.  Change
	magic_null_ptid's, not_sent_ptid's and any_thread_ptid's pid
	member to 42000.

	* thread.c (thread_change_ptid): Also account for the inferior pid
	changing.

	* inferior.h (discard_all_inferiors): Declare.
	* inferior.c (discard_all_inferiors): New.
This commit is contained in:
Pedro Alves 2008-09-22 15:18:30 +00:00
parent 7f9f62ba18
commit 82f7388440
5 changed files with 502 additions and 118 deletions

View File

@ -1,3 +1,57 @@
2008-09-22 Pedro Alves <pedro@codesourcery.com>
Implement remote multi-process extensions.
* remote.c (struct remote_state): Add extended and
multi_process_aware fields.
(remote_multi_process_p): New.
(PACKET_vKill): New.
(record_currthread): Use thread_change_ptid. Notice new
inferiors.
(set_thread, remote_thread_alive): Use write_ptid.
(write_ptid, read_ptid): New.
(remote_current_thread, remote_threads_extra_info): Use them.
(remote_threads_info): Likewise. Detect new inferiors.
(remote_start_remote): Add inferior to inferior list.
(remote_multi_process_feature): New.
(remote_protocol_features): Add "multiprocess" feature.
(remote_query_supported): Pass "multiprocess+" as supported
features.
(remote_open_1): Clear multi_process_aware. Set extended
accordingly.
(remote_detach_1): Detach current process. Use extended packet
format for extended-remote multi-process. Detach process from the
inferior list. Only mourn after printing output.
(extended_remote_attach_1): Add process to the inferior list.
(remote_vcont_resume): Use write_ptid to pass the thread ids.
(remote_wait): Use read_ptid. Implement the extended
multi-process extension format of the 'W' and 'X' reply packets.
Remove exited inferiors from inferior list.
(remote_xfer_memory): Set general thread.
(remote_vkill): New.
(extended_remote_kill): New.
(remote_mourn_1): Discard all inferiors.
(select_new_thread_callback): New.
(extended_remote_mourn_1): If there are more processes to debug,
switch to a thread in another process, and don't pop the target.
(extended_remote_create_inferior_1): Add the new process to the
inferior list.
(remote_stopped_by_watchpoint): Indenting.
(remote_xfer_partial): Set the general thread.
(remote_pid_to_str): If the remote is multi-process aware, print
the process id as well as the thread id.
(remote_get_thread_local_address): Use write_ptid.
(init_extended_remote_ops): Register extended_remote_kill.
(_initialize_remote): Register new packets. Change
magic_null_ptid's, not_sent_ptid's and any_thread_ptid's pid
member to 42000.
* thread.c (thread_change_ptid): Also account for the inferior pid
changing.
* inferior.h (discard_all_inferiors): Declare.
* inferior.c (discard_all_inferiors): New.
2008-09-22 Pedro Alves <pedro@codesourcery.com>
* gnu-nat.c (gnu_attach): Add process to inferiors table.

View File

@ -170,6 +170,18 @@ detach_inferior (int pid)
printf_unfiltered (_("[Inferior %d detached]\n"), pid);
}
void
discard_all_inferiors (void)
{
struct inferior *inf, *infnext;
for (inf = inferior_list; inf; inf = infnext)
{
infnext = inf->next;
delete_inferior_silent (inf->pid);
}
}
static struct inferior *
find_inferior_id (int num)
{

View File

@ -450,6 +450,9 @@ extern void delete_inferior_silent (int pid);
/* Delete an existing inferior list entry, due to inferior detaching. */
extern void detach_inferior (int pid);
/* Get rid of all inferiors. */
extern void discard_all_inferiors (void);
/* 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);

View File

@ -208,6 +208,9 @@ static void show_remote_protocol_packet_cmd (struct ui_file *file,
struct cmd_list_element *c,
const char *value);
static char *write_ptid (char *buf, const char *endbuf, ptid_t ptid);
static ptid_t read_ptid (char *buf, char **obuf);
void _initialize_remote (void);
/* For "remote". */
@ -253,8 +256,22 @@ struct remote_state
expect acks from each other. The connection is assumed to be
reliable. */
int noack_mode;
/* True if we're connected in extended remote mode. */
int extended;
/* True if the stub reported support for multi-process
extensions. */
int multi_process_aware;
};
/* Returns true if the multi-process extensions are in effect. */
static int
remote_multi_process_p (struct remote_state *rs)
{
return rs->extended && rs->multi_process_aware;
}
/* This data could be associated with a target, but we do not always
have access to the current target when we need it, so for now it is
static. This will be fine for as long as only one target is in use
@ -940,6 +957,7 @@ enum {
PACKET_vAttach,
PACKET_vRun,
PACKET_QStartNoAckMode,
PACKET_vKill,
PACKET_MAX
};
@ -1068,6 +1086,15 @@ record_currthread (ptid_t currthread)
/* If this is a new thread, add it to GDB's thread list.
If we leave it up to WFI to do this, bad things will happen. */
if (in_thread_list (currthread) && is_exited (currthread))
{
/* We're seeing an event on a thread id we knew had exited.
This has to be a new thread reusing the old id. Add it. */
add_thread (currthread);
return;
}
if (!in_thread_list (currthread))
{
if (ptid_equal (pid_to_ptid (ptid_get_pid (currthread)), inferior_ptid))
@ -1077,23 +1104,30 @@ record_currthread (ptid_t currthread)
stub doesn't support qC. This is the first stop reported
after an attach, so this is the main thread. Update the
ptid in the thread list. */
struct thread_info *th = find_thread_pid (inferior_ptid);
inferior_ptid = th->ptid = currthread;
thread_change_ptid (inferior_ptid, currthread);
return;
}
else if (ptid_equal (magic_null_ptid, inferior_ptid))
if (ptid_equal (magic_null_ptid, inferior_ptid))
{
/* inferior_ptid is not set yet. This can happen with the
vRun -> remote_wait,"TAAthread:" path if the stub
doesn't support qC. This is the first stop reported
after an attach, so this is the main thread. Update the
ptid in the thread list. */
struct thread_info *th = find_thread_pid (inferior_ptid);
inferior_ptid = th->ptid = currthread;
thread_change_ptid (inferior_ptid, currthread);
return;
}
else
/* This is really a new thread. Add it. */
add_thread (currthread);
/* This is really a new thread. Add it. */
add_thread (currthread);
}
if (!in_inferior_list (ptid_get_pid (currthread)))
/* When connecting to a target remote, or to a target
extended-remote which already was debugging an inferior, we may
not know about it yet --- add it. */
add_inferior (ptid_get_pid (currthread));
}
static char *last_pass_packet;
@ -1179,13 +1213,7 @@ set_thread (struct ptid ptid, int gen)
else if (ptid_equal (ptid, minus_one_ptid))
xsnprintf (buf, endbuf - buf, "-1");
else
{
int tid = ptid_get_tid (ptid);
if (tid < 0)
xsnprintf (buf, endbuf - buf, "-%x", -tid);
else
xsnprintf (buf, endbuf - buf, "%x", tid);
}
write_ptid (buf, endbuf, ptid);
putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
if (gen)
@ -1215,6 +1243,7 @@ remote_thread_alive (ptid_t ptid)
{
struct remote_state *rs = get_remote_state ();
int tid = ptid_get_tid (ptid);
char *p, *endp;
if (ptid_equal (ptid, magic_null_ptid))
/* The main thread is always alive. */
@ -1226,10 +1255,12 @@ remote_thread_alive (ptid_t ptid)
multi-threading. */
return 1;
if (tid < 0)
xsnprintf (rs->buf, get_remote_packet_size (), "T-%08x", -tid);
else
xsnprintf (rs->buf, get_remote_packet_size (), "T%08x", tid);
p = rs->buf;
endp = rs->buf + get_remote_packet_size ();
*p++ = 'T';
write_ptid (p, endp, ptid);
putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
return (rs->buf[0] == 'O' && rs->buf[1] == 'K');
@ -1350,6 +1381,71 @@ static int remote_threadlist_iterator (rmt_thread_action stepfunction,
static int remote_newthread_step (threadref *ref, void *context);
/* Write a PTID to BUF. ENDBUF points to one-passed-the-end of the
buffer we're allowed to write to. Returns
BUF+CHARACTERS_WRITTEN. */
static char *
write_ptid (char *buf, const char *endbuf, ptid_t ptid)
{
int pid, tid;
struct remote_state *rs = get_remote_state ();
if (remote_multi_process_p (rs))
{
pid = ptid_get_pid (ptid);
if (pid < 0)
buf += xsnprintf (buf, endbuf - buf, "p-%x.", -pid);
else
buf += xsnprintf (buf, endbuf - buf, "p%x.", pid);
}
tid = ptid_get_tid (ptid);
if (tid < 0)
buf += xsnprintf (buf, endbuf - buf, "-%x", -tid);
else
buf += xsnprintf (buf, endbuf - buf, "%x", tid);
return buf;
}
/* Extract a PTID from BUF. If non-null, OBUF is set to the to one
passed the last parsed char. Returns null_ptid on error. */
static ptid_t
read_ptid (char *buf, char **obuf)
{
char *p = buf;
char *pp;
ULONGEST pid = 0, tid = 0;
ptid_t ptid;
if (*p == 'p')
{
/* Multi-process ptid. */
pp = unpack_varlen_hex (p + 1, &pid);
if (*pp != '.')
error (_("invalid remote ptid: %s\n"), p);
p = pp;
pp = unpack_varlen_hex (p + 1, &tid);
if (obuf)
*obuf = pp;
return ptid_build (pid, 0, tid);
}
/* No multi-process. Just a tid. */
pp = unpack_varlen_hex (p, &tid);
/* Since the stub is not sending a process id, then default to
what's in inferior_ptid. */
pid = ptid_get_pid (inferior_ptid);
if (obuf)
*obuf = pp;
return ptid_build (pid, 0, tid);
}
/* Encode 64 bits in 16 chars of hex. */
static const char hexchars[] = "0123456789abcdef";
@ -1916,16 +2012,7 @@ remote_current_thread (ptid_t oldpid)
putpkt ("qC");
getpkt (&rs->buf, &rs->buf_size, 0);
if (rs->buf[0] == 'Q' && rs->buf[1] == 'C')
{
/* Use strtoul here, so we'll correctly parse values whose
highest bit is set. The protocol carries them as a simple
series of hex digits; in the absence of a sign, strtol will
see such values as positive numbers out of range for signed
'long', and return LONG_MAX to indicate an overflow. */
tid = strtoul (&rs->buf[2], NULL, 16);
pid = ptid_get_pid (oldpid);
return ptid_build (pid, 0, tid);
}
return read_ptid (&rs->buf[2], NULL);
else
return oldpid;
}
@ -1953,8 +2040,6 @@ remote_threads_info (void)
{
struct remote_state *rs = get_remote_state ();
char *bufp;
int tid;
int pid;
ptid_t new_thread;
if (remote_desc == 0) /* paranoia */
@ -1971,17 +2056,19 @@ remote_threads_info (void)
{
do
{
/* Use strtoul here, so we'll correctly parse values
whose highest bit is set. The protocol carries
them as a simple series of hex digits; in the
absence of a sign, strtol will see such values as
positive numbers out of range for signed 'long',
and return LONG_MAX to indicate an overflow. */
tid = strtoul (bufp, &bufp, 16);
pid = ptid_get_pid (inferior_ptid);
new_thread = ptid_build (pid, 0, tid);
if (tid != 0 && !in_thread_list (new_thread))
add_thread (new_thread);
new_thread = read_ptid (bufp, &bufp);
if (!ptid_equal (new_thread, null_ptid)
&& !in_thread_list (new_thread))
{
if (!in_inferior_list (ptid_get_pid (new_thread)))
/* When connected to a multi-process aware
stub, "info threads" may show up threads of
inferiors we didn't know about yet. Add
them. */
add_inferior (ptid_get_pid (new_thread));
add_thread (new_thread);
}
}
while (*bufp++ == ','); /* comma-separated list */
putpkt ("qsThreadInfo");
@ -2030,8 +2117,13 @@ remote_threads_extra_info (struct thread_info *tp)
if (use_threadextra_query)
{
xsnprintf (rs->buf, get_remote_packet_size (), "qThreadExtraInfo,%lx",
ptid_get_tid (tp->ptid));
char *b = rs->buf;
char *endb = rs->buf + get_remote_packet_size ();
xsnprintf (b, endb - b, "qThreadExtraInfo,");
b += strlen (b);
write_ptid (b, endb, tp->ptid);
putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
if (rs->buf[0] != 0)
@ -2321,6 +2413,8 @@ remote_start_remote (struct ui_out *uiout, void *opaque)
/* Now, if we have thread information, update inferior_ptid. */
inferior_ptid = remote_current_thread (inferior_ptid);
add_inferior (ptid_get_pid (inferior_ptid));
/* Always add the main thread. */
add_thread_silent (inferior_ptid);
@ -2518,6 +2612,14 @@ remote_packet_size (const struct protocol_feature *feature,
rs->explicit_packet_size = packet_size;
}
static void
remote_multi_process_feature (const struct protocol_feature *feature,
enum packet_support support, const char *value)
{
struct remote_state *rs = get_remote_state ();
rs->multi_process_aware = (support == PACKET_ENABLE);
}
static struct protocol_feature remote_protocol_features[] = {
{ "PacketSize", PACKET_DISABLE, remote_packet_size, -1 },
{ "qXfer:auxv:read", PACKET_DISABLE, remote_supported_packet,
@ -2536,6 +2638,7 @@ static struct protocol_feature remote_protocol_features[] = {
PACKET_QPassSignals },
{ "QStartNoAckMode", PACKET_DISABLE, remote_supported_packet,
PACKET_QStartNoAckMode },
{ "multiprocess", PACKET_DISABLE, remote_multi_process_feature, -1 },
};
static void
@ -2556,7 +2659,11 @@ remote_query_supported (void)
rs->buf[0] = 0;
if (remote_protocol_packets[PACKET_qSupported].support != PACKET_DISABLE)
{
putpkt ("qSupported");
if (rs->extended)
putpkt ("qSupported:multiprocess+");
else
putpkt ("qSupported");
getpkt (&rs->buf, &rs->buf_size, 0);
/* If an error occured, warn, but do not return - just reset the
@ -2753,6 +2860,8 @@ remote_open_1 (char *name, int from_tty, struct target_ops *target, int extended
init_all_packet_configs ();
rs->explicit_packet_size = 0;
rs->noack_mode = 0;
rs->multi_process_aware = 0;
rs->extended = extended_p;
general_thread = not_sent_ptid;
continue_thread = not_sent_ptid;
@ -2875,6 +2984,7 @@ remote_open_1 (char *name, int from_tty, struct target_ops *target, int extended
static void
remote_detach_1 (char *args, int from_tty, int extended)
{
int pid = ptid_get_pid (inferior_ptid);
struct remote_state *rs = get_remote_state ();
if (args)
@ -2884,25 +2994,41 @@ remote_detach_1 (char *args, int from_tty, int extended)
error (_("No process to detach from."));
/* Tell the remote target to detach. */
strcpy (rs->buf, "D");
if (remote_multi_process_p (rs))
sprintf (rs->buf, "D;%x", pid);
else
strcpy (rs->buf, "D");
putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
if (rs->buf[0] == 'E')
if (rs->buf[0] == 'O' && rs->buf[1] == 'K')
;
else if (rs->buf[0] == '\0')
error (_("Remote doesn't know how to detach"));
else
error (_("Can't detach process."));
/* Unregister the file descriptor from the event loop. */
if (target_is_async_p ())
serial_async (remote_desc, NULL, 0);
target_mourn_inferior ();
if (from_tty)
{
if (extended)
puts_filtered ("Detached from remote process.\n");
if (remote_multi_process_p (rs))
printf_filtered (_("Detached from remote %s.\n"),
target_pid_to_str (pid_to_ptid (pid)));
else
puts_filtered ("Ending remote debugging.\n");
{
if (extended)
puts_filtered (_("Detached from remote process.\n"));
else
puts_filtered (_("Ending remote debugging.\n"));
}
}
detach_inferior (pid);
target_mourn_inferior ();
}
static void
@ -2987,6 +3113,8 @@ extended_remote_attach_1 (struct target_ops *target, char *args, int from_tty)
/* Now, if we have thread information, update inferior_ptid. */
inferior_ptid = remote_current_thread (inferior_ptid);
add_inferior (pid);
/* Now, add the main thread to the thread list. */
add_thread_silent (inferior_ptid);
@ -3131,8 +3259,8 @@ static int
remote_vcont_resume (ptid_t ptid, int step, enum target_signal siggnal)
{
struct remote_state *rs = get_remote_state ();
char *outbuf;
struct cleanup *old_cleanup;
char *p;
char *endp;
if (remote_protocol_packets[PACKET_vCont].support == PACKET_SUPPORT_UNKNOWN)
remote_vcont_probe (rs);
@ -3140,6 +3268,9 @@ remote_vcont_resume (ptid_t ptid, int step, enum target_signal siggnal)
if (remote_protocol_packets[PACKET_vCont].support == PACKET_DISABLE)
return 0;
p = rs->buf;
endp = rs->buf + get_remote_packet_size ();
/* If we could generate a wider range of packets, we'd have to worry
about overflowing BUF. Should there be a generic
"multi-part-packet" packet? */
@ -3151,47 +3282,75 @@ remote_vcont_resume (ptid_t ptid, int step, enum target_signal siggnal)
understand. Make sure to only send forms that do not specify
a TID. */
if (step && siggnal != TARGET_SIGNAL_0)
outbuf = xstrprintf ("vCont;S%02x", siggnal);
xsnprintf (p, endp - p, "vCont;S%02x", siggnal);
else if (step)
outbuf = xstrprintf ("vCont;s");
xsnprintf (p, endp - p, "vCont;s");
else if (siggnal != TARGET_SIGNAL_0)
outbuf = xstrprintf ("vCont;C%02x", siggnal);
xsnprintf (p, endp - p, "vCont;C%02x", siggnal);
else
outbuf = xstrprintf ("vCont;c");
xsnprintf (p, endp - p, "vCont;c");
}
else if (ptid_equal (ptid, minus_one_ptid))
{
/* Resume all threads, with preference for INFERIOR_PTID. */
int tid = ptid_get_tid (inferior_ptid);
if (step && siggnal != TARGET_SIGNAL_0)
outbuf = xstrprintf ("vCont;S%02x:%x;c", siggnal, tid);
{
/* Step inferior_ptid with signal. */
p += xsnprintf (p, endp - p, "vCont;S%02x:", siggnal);
p = write_ptid (p, endp, inferior_ptid);
/* And continue others. */
p += xsnprintf (p, endp - p, ";c");
}
else if (step)
outbuf = xstrprintf ("vCont;s:%x;c", tid);
{
/* Step inferior_ptid. */
p += xsnprintf (p, endp - p, "vCont;s:");
p = write_ptid (p, endp, inferior_ptid);
/* And continue others. */
p += xsnprintf (p, endp - p, ";c");
}
else if (siggnal != TARGET_SIGNAL_0)
outbuf = xstrprintf ("vCont;C%02x:%x;c", siggnal, tid);
{
/* Continue inferior_ptid with signal. */
p += xsnprintf (p, endp - p, "vCont;C%02x:", siggnal);
p = write_ptid (p, endp, inferior_ptid);
/* And continue others. */
p += xsnprintf (p, endp - p, ";c");
}
else
outbuf = xstrprintf ("vCont;c");
xsnprintf (p, endp - p, "vCont;c");
}
else
{
/* Scheduler locking; resume only PTID. */
int tid = ptid_get_tid (ptid);
if (step && siggnal != TARGET_SIGNAL_0)
outbuf = xstrprintf ("vCont;S%02x:%x", siggnal, tid);
{
/* Step ptid with signal. */
p += xsnprintf (p, endp - p, "vCont;S%02x:", siggnal);
p = write_ptid (p, endp, ptid);
}
else if (step)
outbuf = xstrprintf ("vCont;s:%x", tid);
{
/* Step ptid. */
p += xsnprintf (p, endp - p, "vCont;s:");
p = write_ptid (p, endp, ptid);
}
else if (siggnal != TARGET_SIGNAL_0)
outbuf = xstrprintf ("vCont;C%02x:%x", siggnal, tid);
{
/* Continue ptid with signal. */
p += xsnprintf (p, endp - p, "vCont;C%02x:", siggnal);
p = write_ptid (p, endp, ptid);
}
else
outbuf = xstrprintf ("vCont;c:%x", tid);
{
/* Continue ptid. */
p += xsnprintf (p, endp - p, "vCont;c:");
p = write_ptid (p, endp, ptid);
}
}
gdb_assert (outbuf && strlen (outbuf) < get_remote_packet_size ());
old_cleanup = make_cleanup (xfree, outbuf);
putpkt (outbuf);
do_cleanups (old_cleanup);
gdb_assert (strlen (rs->buf) < get_remote_packet_size ());
putpkt (rs->buf);
return 1;
}
@ -3446,8 +3605,7 @@ remote_wait (ptid_t ptid, struct target_waitstatus *status)
{
struct remote_state *rs = get_remote_state ();
struct remote_arch_state *rsa = get_remote_arch_state ();
ULONGEST thread_num = -1;
ULONGEST process_num = -1;
ptid_t event_ptid = null_ptid;
ULONGEST addr;
int solibs_changed = 0;
@ -3542,10 +3700,7 @@ remote_wait (ptid_t ptid, struct target_waitstatus *status)
Packet: '%s'\n"),
p, buf);
if (strncmp (p, "thread", p1 - p) == 0)
{
p_temp = unpack_varlen_hex (++p1, &thread_num);
p = p_temp;
}
event_ptid = read_ptid (++p1, &p);
else if ((strncmp (p, "watch", p1 - p) == 0)
|| (strncmp (p, "rwatch", p1 - p) == 0)
|| (strncmp (p, "awatch", p1 - p) == 0))
@ -3617,18 +3772,56 @@ Packet: '%s'\n"),
}
goto got_status;
case 'W': /* Target exited. */
case 'X':
{
/* The remote process exited. */
status->kind = TARGET_WAITKIND_EXITED;
status->value.integer = (fromhex (buf[1]) << 4) + fromhex (buf[2]);
char *p;
int pid;
ULONGEST value;
/* GDB used to accept only 2 hex chars here. Stubs should
only send more if they detect GDB supports
multi-process support. */
p = unpack_varlen_hex (&buf[1], &value);
if (buf[0] == 'W')
{
/* The remote process exited. */
status->kind = TARGET_WAITKIND_EXITED;
status->value.integer = value;
}
else
{
/* The remote process exited with a signal. */
status->kind = TARGET_WAITKIND_SIGNALLED;
status->value.sig = (enum target_signal) value;
}
/* If no process is specified, assume inferior_ptid. */
pid = ptid_get_pid (inferior_ptid);
if (*p == '\0')
;
else if (*p == ';')
{
p++;
if (p == '\0')
;
else if (strncmp (p,
"process:", sizeof ("process:") - 1) == 0)
{
ULONGEST upid;
p += sizeof ("process:") - 1;
unpack_varlen_hex (p, &upid);
pid = upid;
}
else
error (_("unknown stop reply packet: %s"), buf);
}
else
error (_("unknown stop reply packet: %s"), buf);
event_ptid = ptid_build (pid, 0, 0);
goto got_status;
}
case 'X':
status->kind = TARGET_WAITKIND_SIGNALLED;
status->value.sig = (enum target_signal)
(((fromhex (buf[1])) << 4) + (fromhex (buf[2])));
goto got_status;
case 'O': /* Console output. */
remote_console_output (buf + 1);
if (target_can_async_p ())
@ -3663,15 +3856,21 @@ Packet: '%s'\n"),
}
}
got_status:
if (thread_num != -1)
if (status->kind == TARGET_WAITKIND_EXITED
|| status->kind == TARGET_WAITKIND_SIGNALLED)
{
ptid_t ptid;
ptid = ptid_build (ptid_get_pid (inferior_ptid), 0, thread_num);
record_currthread (ptid);
return ptid;
int pid = ptid_get_pid (event_ptid);
delete_inferior (pid);
}
else
{
if (!ptid_equal (event_ptid, null_ptid))
record_currthread (event_ptid);
else
event_ptid = inferior_ptid;
}
return inferior_ptid;
return event_ptid;
}
/* Fetch a single register using a 'p' packet. */
@ -4563,6 +4762,8 @@ remote_xfer_memory (CORE_ADDR mem_addr, gdb_byte *buffer, int mem_len,
{
int res;
set_general_thread (inferior_ptid);
if (should_write)
res = remote_write_bytes (mem_addr, buffer, mem_len);
else
@ -5187,6 +5388,58 @@ remote_kill (void)
target_mourn_inferior ();
}
static int
remote_vkill (int pid, struct remote_state *rs)
{
if (remote_protocol_packets[PACKET_vKill].support == PACKET_DISABLE)
return -1;
/* Tell the remote target to detach. */
sprintf (rs->buf, "vKill;%x", pid);
putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
if (packet_ok (rs->buf,
&remote_protocol_packets[PACKET_vKill]) == PACKET_OK)
return 0;
else if (remote_protocol_packets[PACKET_vKill].support == PACKET_DISABLE)
return -1;
else
return 1;
}
static void
extended_remote_kill (void)
{
int res;
int pid = ptid_get_pid (inferior_ptid);
struct remote_state *rs = get_remote_state ();
res = remote_vkill (pid, rs);
if (res == -1 && !remote_multi_process_p (rs))
{
/* Don't try 'k' on a multi-process aware stub -- it has no way
to specify the pid. */
putpkt ("k");
#if 0
getpkt (&rs->buf, &rs->buf_size, 0);
if (rs->buf[0] != 'O' || rs->buf[0] != 'K')
res = 1;
#else
/* Don't wait for it to die. I'm not really sure it matters whether
we do or not. For the existing stubs, kill is a noop. */
res = 0;
#endif
}
if (res != 0)
error (_("Can't kill process"));
delete_inferior (pid);
target_mourn_inferior ();
}
static void
remote_mourn (void)
{
@ -5197,10 +5450,27 @@ remote_mourn (void)
static void
remote_mourn_1 (struct target_ops *target)
{
/* Get rid of all the inferiors and their threads we were
controlling. */
discard_all_inferiors ();
unpush_target (target);
generic_mourn_inferior ();
}
static int
select_new_thread_callback (struct thread_info *th, void* data)
{
if (!ptid_equal (th->ptid, minus_one_ptid))
{
switch_to_thread (th->ptid);
printf_filtered (_("[Switching to %s]\n"),
target_pid_to_str (inferior_ptid));
return 1;
}
return 0;
}
static void
extended_remote_mourn_1 (struct target_ops *target)
{
@ -5209,27 +5479,45 @@ extended_remote_mourn_1 (struct target_ops *target)
/* Unlike "target remote", we do not want to unpush the target; then
the next time the user says "run", we won't be connected. */
/* Call common code to mark the inferior as not running. */
generic_mourn_inferior ();
/* Check whether the target is running now - some remote stubs
automatically restart after kill. */
putpkt ("?");
getpkt (&rs->buf, &rs->buf_size, 0);
if (rs->buf[0] == 'S' || rs->buf[0] == 'T')
if (have_inferiors ())
{
/* Assume that the target has been restarted. Set inferior_ptid
so that bits of core GDB realizes there's something here, e.g.,
so that the user can say "kill" again. */
inferior_ptid = remote_current_thread (magic_null_ptid);
add_thread_silent (inferior_ptid);
extern void nullify_last_target_wait_ptid ();
/* Multi-process case. The current process has exited, but
there are other processes to debug. Switch to the first
available. */
iterate_over_threads (select_new_thread_callback, NULL);
nullify_last_target_wait_ptid ();
}
else
{
/* Mark this (still pushed) target as not executable until we
restart it. */
target_mark_exited (target);
struct remote_state *rs = get_remote_state ();
/* Call common code to mark the inferior as not running. */
generic_mourn_inferior ();
if (!remote_multi_process_p (rs))
{
/* Check whether the target is running now - some remote stubs
automatically restart after kill. */
putpkt ("?");
getpkt (&rs->buf, &rs->buf_size, 0);
if (rs->buf[0] == 'S' || rs->buf[0] == 'T')
{
/* Assume that the target has been restarted. Set inferior_ptid
so that bits of core GDB realizes there's something here, e.g.,
so that the user can say "kill" again. */
inferior_ptid = magic_null_ptid;
}
else
{
/* Mark this (still pushed) target as not executable until we
restart it. */
target_mark_exited (target);
}
}
else
/* Always remove execution if this was the last process. */
target_mark_exited (target);
}
}
@ -5339,6 +5627,7 @@ extended_remote_create_inferior_1 (char *exec_file, char *args,
attach_flag = 0;
inferior_ptid = magic_null_ptid;
add_inferior (ptid_get_pid (inferior_ptid));
add_thread_silent (inferior_ptid);
target_mark_running (&extended_remote_ops);
@ -5548,7 +5837,7 @@ remote_check_watch_resources (int type, int cnt, int ot)
static int
remote_stopped_by_watchpoint (void)
{
return remote_stopped_by_watchpoint_p;
return remote_stopped_by_watchpoint_p;
}
static int
@ -5906,11 +6195,15 @@ remote_xfer_partial (struct target_ops *ops, enum target_object object,
const char *annex, gdb_byte *readbuf,
const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
{
struct remote_state *rs = get_remote_state ();
struct remote_state *rs;
int i;
char *p2;
char query_type;
set_general_thread (inferior_ptid);
rs = get_remote_state ();
/* Handle memory using the standard memory routines. */
if (object == TARGET_OBJECT_MEMORY)
{
@ -6389,12 +6682,20 @@ static char *
remote_pid_to_str (ptid_t ptid)
{
static char buf[64];
struct remote_state *rs = get_remote_state ();
if (ptid_equal (magic_null_ptid, ptid))
{
xsnprintf (buf, sizeof buf, "Thread <main>");
return buf;
}
else if (remote_multi_process_p (rs)
&& ptid_get_tid (ptid) != 0 && ptid_get_pid (ptid) != 0)
{
xsnprintf (buf, sizeof buf, "Thread %d.%ld",
ptid_get_pid (ptid), ptid_get_tid (ptid));
return buf;
}
else if (ptid_get_tid (ptid) != 0)
{
xsnprintf (buf, sizeof buf, "Thread %ld",
@ -6415,11 +6716,12 @@ remote_get_thread_local_address (ptid_t ptid, CORE_ADDR lm, CORE_ADDR offset)
{
struct remote_state *rs = get_remote_state ();
char *p = rs->buf;
char *endp = rs->buf + get_remote_packet_size ();
enum packet_result result;
strcpy (p, "qGetTLSAddr:");
p += strlen (p);
p += hexnumstr (p, ptid_get_tid (ptid));
p = write_ptid (p, endp, ptid);
*p++ = ',';
p += hexnumstr (p, offset);
*p++ = ',';
@ -7325,6 +7627,7 @@ Specify the serial device it is connected to (e.g. /dev/ttya).";
extended_remote_ops.to_mourn_inferior = extended_remote_mourn;
extended_remote_ops.to_detach = extended_remote_detach;
extended_remote_ops.to_attach = extended_remote_attach;
extended_remote_ops.to_kill = extended_remote_kill;
}
static int
@ -7656,6 +7959,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
add_packet_config_cmd (&remote_protocol_packets[PACKET_QStartNoAckMode],
"QStartNoAckMode", "noack", 0);
add_packet_config_cmd (&remote_protocol_packets[PACKET_vKill],
"vKill", "kill", 0);
/* Keep the old ``set remote Z-packet ...'' working. Each individual
Z sub-packet has its own set and show commands, but users may
have sets to this variable in their .gdbinit files (or in their
@ -7700,7 +8006,7 @@ Show the remote pathname for \"run\""), NULL, NULL, NULL,
/* Take advantage of the fact that the LWP field is not used, to tag
special ptids with it set to != 0. */
magic_null_ptid = ptid_build (0, 1, -1);
not_sent_ptid = ptid_build (0, 1, -2);
any_thread_ptid = ptid_build (0, 1, 0);
magic_null_ptid = ptid_build (42000, 1, -1);
not_sent_ptid = ptid_build (42000, 1, -2);
any_thread_ptid = ptid_build (42000, 1, 0);
}

View File

@ -466,7 +466,16 @@ prune_threads (void)
void
thread_change_ptid (ptid_t old_ptid, ptid_t new_ptid)
{
struct thread_info * tp = find_thread_pid (old_ptid);
struct inferior *inf;
struct thread_info *tp;
/* It can happen that what we knew as the target inferior id
changes. E.g, target remote may only discover the remote process
pid after adding the inferior to GDB's list. */
inf = find_inferior_pid (ptid_get_pid (old_ptid));
inf->pid = ptid_get_pid (new_ptid);
tp = find_thread_pid (old_ptid);
tp->ptid = new_ptid;
observer_notify_thread_ptid_changed (old_ptid, new_ptid);