mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-23 18:14:13 +08:00
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:
parent
7f9f62ba18
commit
82f7388440
@ -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.
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
540
gdb/remote.c
540
gdb/remote.c
@ -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);
|
||||
}
|
||||
|
11
gdb/thread.c
11
gdb/thread.c
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user