Index: gdb/gdbserver/server.c |
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c |
index 4e15b3c9fa977dd6551ce85a6b8418a7801c9d68..e0af78547e30ff38eaf68ddf998e7f696a367350 100644 |
--- a/gdb/gdbserver/server.c |
+++ b/gdb/gdbserver/server.c |
@@ -1,6 +1,5 @@ |
/* Main code for remote server for GDB. |
- Copyright (C) 1989, 1993-1995, 1997-2000, 2002-2012 Free Software |
- Foundation, Inc. |
+ Copyright (C) 1989-2013 Free Software Foundation, Inc. |
This file is part of GDB. |
@@ -20,16 +19,19 @@ |
#include "server.h" |
#include "gdbthread.h" |
#include "agent.h" |
+#include "notif.h" |
+#include "tdesc.h" |
-#if HAVE_UNISTD_H |
#include <unistd.h> |
-#endif |
#if HAVE_SIGNAL_H |
#include <signal.h> |
#endif |
-#if HAVE_SYS_WAIT_H |
-#include <sys/wait.h> |
-#endif |
+#include "gdb_wait.h" |
+#include "btrace-common.h" |
+#include "filestuff.h" |
+#include "tracepoint.h" |
+#include "dll.h" |
+#include "hostio.h" |
/* The thread set with an `Hc' packet. `Hc' is deprecated in favor of |
`vCont'. Note the multi-process extensions made `vCont' a |
@@ -77,8 +79,6 @@ int program_signals_p; |
jmp_buf toplevel; |
-const char *gdbserver_xmltarget; |
- |
/* The PID of the originally created or attached inferior. Used to |
send signals to the process when GDB sends us an asynchronous interrupt |
(user hitting Control-C in the client), and to wait for the child to exit |
@@ -117,13 +117,13 @@ static ptid_t last_ptid; |
static char *own_buf; |
static unsigned char *mem_buf; |
-/* Structure holding information relative to a single stop reply. We |
- keep a queue of these (really a singly-linked list) to push to GDB |
- in non-stop mode. */ |
+/* A sub-class of 'struct notif_event' for stop, holding information |
+ relative to a single stop reply. We keep a queue of these to |
+ push to GDB in non-stop mode. */ |
+ |
struct vstop_notif |
{ |
- /* Pointer to next in list. */ |
- struct vstop_notif *next; |
+ struct notif_event base; |
/* Thread or process that got the event. */ |
ptid_t ptid; |
@@ -132,66 +132,39 @@ struct vstop_notif |
struct target_waitstatus status; |
}; |
-/* The pending stop replies list head. */ |
-static struct vstop_notif *notif_queue = NULL; |
+DEFINE_QUEUE_P (notif_event_p); |
/* Put a stop reply to the stop reply queue. */ |
static void |
queue_stop_reply (ptid_t ptid, struct target_waitstatus *status) |
{ |
- struct vstop_notif *new_notif; |
+ struct vstop_notif *new_notif = xmalloc (sizeof (*new_notif)); |
- new_notif = xmalloc (sizeof (*new_notif)); |
- new_notif->next = NULL; |
new_notif->ptid = ptid; |
new_notif->status = *status; |
- if (notif_queue) |
- { |
- struct vstop_notif *tail; |
- for (tail = notif_queue; |
- tail && tail->next; |
- tail = tail->next) |
- ; |
- tail->next = new_notif; |
- } |
- else |
- notif_queue = new_notif; |
- |
- if (remote_debug) |
- { |
- int i = 0; |
- struct vstop_notif *n; |
- |
- for (n = notif_queue; n; n = n->next) |
- i++; |
- |
- fprintf (stderr, "pending stop replies: %d\n", i); |
- } |
+ notif_event_enque (¬if_stop, (struct notif_event *) new_notif); |
} |
-/* Place an event in the stop reply queue, and push a notification if |
- we aren't sending one yet. */ |
- |
-void |
-push_event (ptid_t ptid, struct target_waitstatus *status) |
+static int |
+remove_all_on_match_pid (QUEUE (notif_event_p) *q, |
+ QUEUE_ITER (notif_event_p) *iter, |
+ struct notif_event *event, |
+ void *data) |
{ |
- gdb_assert (status->kind != TARGET_WAITKIND_IGNORE); |
- |
- queue_stop_reply (ptid, status); |
+ int *pid = data; |
- /* If this is the first stop reply in the queue, then inform GDB |
- about it, by sending a Stop notification. */ |
- if (notif_queue->next == NULL) |
+ if (*pid == -1 |
+ || ptid_get_pid (((struct vstop_notif *) event)->ptid) == *pid) |
{ |
- char *p = own_buf; |
- strcpy (p, "Stop:"); |
- p += strlen (p); |
- prepare_resume_reply (p, |
- notif_queue->ptid, ¬if_queue->status); |
- putpkt_notif (own_buf); |
+ if (q->free_func != NULL) |
+ q->free_func (event); |
+ |
+ QUEUE_remove_elem (notif_event_p, q, iter); |
} |
+ |
+ return 1; |
} |
/* Get rid of the currently pending stop replies for PID. If PID is |
@@ -200,40 +173,23 @@ push_event (ptid_t ptid, struct target_waitstatus *status) |
static void |
discard_queued_stop_replies (int pid) |
{ |
- struct vstop_notif *prev = NULL, *reply, *next; |
- |
- for (reply = notif_queue; reply; reply = next) |
- { |
- next = reply->next; |
- |
- if (pid == -1 |
- || ptid_get_pid (reply->ptid) == pid) |
- { |
- if (reply == notif_queue) |
- notif_queue = next; |
- else |
- prev->next = reply->next; |
- |
- free (reply); |
- } |
- else |
- prev = reply; |
- } |
+ QUEUE_iterate (notif_event_p, notif_stop.queue, |
+ remove_all_on_match_pid, &pid); |
} |
-/* If there are more stop replies to push, push one now. */ |
- |
static void |
-send_next_stop_reply (char *own_buf) |
+vstop_notif_reply (struct notif_event *event, char *own_buf) |
{ |
- if (notif_queue) |
- prepare_resume_reply (own_buf, |
- notif_queue->ptid, |
- ¬if_queue->status); |
- else |
- write_ok (own_buf); |
+ struct vstop_notif *vstop = (struct vstop_notif *) event; |
+ |
+ prepare_resume_reply (own_buf, vstop->ptid, &vstop->status); |
} |
+struct notif_server notif_stop = |
+{ |
+ "vStopped", "Stop", NULL, vstop_notif_reply, |
+}; |
+ |
static int |
target_running (void) |
{ |
@@ -300,6 +256,7 @@ start_inferior (char **argv) |
{ |
struct thread_resume resume_info; |
+ memset (&resume_info, 0, sizeof (resume_info)); |
resume_info.thread = pid_to_ptid (signal_pid); |
resume_info.kind = resume_continue; |
resume_info.sig = 0; |
@@ -442,6 +399,88 @@ write_qxfer_response (char *buf, const void *data, int len, int is_more) |
PBUFSIZ - 2) + 1; |
} |
+/* Handle btrace enabling. */ |
+ |
+static const char * |
+handle_btrace_enable (struct thread_info *thread) |
+{ |
+ if (thread->btrace != NULL) |
+ return "E.Btrace already enabled."; |
+ |
+ thread->btrace = target_enable_btrace (thread->entry.id); |
+ if (thread->btrace == NULL) |
+ return "E.Could not enable btrace."; |
+ |
+ return NULL; |
+} |
+ |
+/* Handle btrace disabling. */ |
+ |
+static const char * |
+handle_btrace_disable (struct thread_info *thread) |
+{ |
+ |
+ if (thread->btrace == NULL) |
+ return "E.Branch tracing not enabled."; |
+ |
+ if (target_disable_btrace (thread->btrace) != 0) |
+ return "E.Could not disable branch tracing."; |
+ |
+ thread->btrace = NULL; |
+ return NULL; |
+} |
+ |
+/* Handle the "Qbtrace" packet. */ |
+ |
+static int |
+handle_btrace_general_set (char *own_buf) |
+{ |
+ struct thread_info *thread; |
+ const char *err; |
+ char *op; |
+ |
+ if (strncmp ("Qbtrace:", own_buf, strlen ("Qbtrace:")) != 0) |
+ return 0; |
+ |
+ op = own_buf + strlen ("Qbtrace:"); |
+ |
+ if (!target_supports_btrace ()) |
+ { |
+ strcpy (own_buf, "E.Target does not support branch tracing."); |
+ return -1; |
+ } |
+ |
+ if (ptid_equal (general_thread, null_ptid) |
+ || ptid_equal (general_thread, minus_one_ptid)) |
+ { |
+ strcpy (own_buf, "E.Must select a single thread."); |
+ return -1; |
+ } |
+ |
+ thread = find_thread_ptid (general_thread); |
+ if (thread == NULL) |
+ { |
+ strcpy (own_buf, "E.No such thread."); |
+ return -1; |
+ } |
+ |
+ err = NULL; |
+ |
+ if (strcmp (op, "bts") == 0) |
+ err = handle_btrace_enable (thread); |
+ else if (strcmp (op, "off") == 0) |
+ err = handle_btrace_disable (thread); |
+ else |
+ err = "E.Bad Qbtrace operation. Use bts or off."; |
+ |
+ if (err != 0) |
+ strcpy (own_buf, err); |
+ else |
+ write_ok (own_buf); |
+ |
+ return 1; |
+} |
+ |
/* Handle all of the extended 'Q' packets. */ |
static void |
@@ -598,6 +637,9 @@ handle_general_set (char *own_buf) |
return; |
} |
+ if (handle_btrace_general_set (own_buf)) |
+ return; |
+ |
/* Otherwise we didn't know what packet it was. Say we didn't |
understand it. */ |
own_buf[0] = 0; |
@@ -606,21 +648,22 @@ handle_general_set (char *own_buf) |
static const char * |
get_features_xml (const char *annex) |
{ |
- /* gdbserver_xmltarget defines what to return when looking |
- for the "target.xml" file. Its contents can either be |
- verbatim XML code (prefixed with a '@') or else the name |
- of the actual XML file to be used in place of "target.xml". |
+ const struct target_desc *desc = current_target_desc (); |
+ |
+ /* `desc->xmltarget' defines what to return when looking for the |
+ "target.xml" file. Its contents can either be verbatim XML code |
+ (prefixed with a '@') or else the name of the actual XML file to |
+ be used in place of "target.xml". |
This variable is set up from the auto-generated |
init_registers_... routine for the current target. */ |
- if (gdbserver_xmltarget |
- && strcmp (annex, "target.xml") == 0) |
+ if (desc->xmltarget != NULL && strcmp (annex, "target.xml") == 0) |
{ |
- if (*gdbserver_xmltarget == '@') |
- return gdbserver_xmltarget + 1; |
+ if (*desc->xmltarget == '@') |
+ return desc->xmltarget + 1; |
else |
- annex = gdbserver_xmltarget; |
+ annex = desc->xmltarget; |
} |
#ifdef USE_XML |
@@ -677,7 +720,7 @@ gdb_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) |
if (traceframe_read_mem (current_traceframe, |
memaddr, myaddr, len, &nbytes)) |
- return EIO; |
+ return -1; |
/* Data read from trace buffer, we're done. */ |
if (nbytes > 0) |
return nbytes; |
@@ -735,8 +778,9 @@ handle_search_memory_1 (CORE_ADDR start_addr, CORE_ADDR search_space_len, |
if (gdb_read_memory (start_addr, search_buf, search_buf_size) |
!= search_buf_size) |
{ |
- warning ("Unable to access target memory at 0x%lx, halting search.", |
- (long) start_addr); |
+ warning ("Unable to access %ld bytes of target " |
+ "memory at 0x%lx, halting search.", |
+ (long) search_buf_size, (long) start_addr); |
return -1; |
} |
@@ -787,9 +831,9 @@ handle_search_memory_1 (CORE_ADDR start_addr, CORE_ADDR search_space_len, |
if (gdb_read_memory (read_addr, search_buf + keep_len, |
nr_to_read) != search_buf_size) |
{ |
- warning ("Unable to access target memory " |
+ warning ("Unable to access %ld bytes of target memory " |
"at 0x%lx, halting search.", |
- (long) read_addr); |
+ (long) nr_to_read, (long) read_addr); |
return -1; |
} |
@@ -937,10 +981,10 @@ struct qxfer |
data-specific information to the target. |
Return the number of bytes actually transfered, zero when no |
- further transfer is possible, -1 on error, and -2 when the |
- transfer is not supported. Return of a positive value smaller |
- than LEN does not indicate the end of the object, only the end of |
- the transfer. |
+ further transfer is possible, -1 on error, -2 when the transfer |
+ is not supported, and -3 on a verbose error message that should |
+ be preserved. Return of a positive value smaller than LEN does |
+ not indicate the end of the object, only the end of the transfer. |
One, and only one, of readbuf or writebuf must be non-NULL. */ |
int (*xfer) (const char *annex, |
@@ -1074,8 +1118,7 @@ handle_qxfer_libraries_svr4 (const char *annex, |
if (writebuf != NULL) |
return -2; |
- if (annex[0] != '\0' || !target_running () |
- || the_target->qxfer_libraries_svr4 == NULL) |
+ if (!target_running () || the_target->qxfer_libraries_svr4 == NULL) |
return -1; |
return the_target->qxfer_libraries_svr4 (annex, readbuf, writebuf, offset, len); |
@@ -1296,9 +1339,77 @@ handle_qxfer_fdpic (const char *annex, gdb_byte *readbuf, |
return (*the_target->read_loadmap) (annex, offset, readbuf, len); |
} |
+/* Handle qXfer:btrace:read. */ |
+ |
+static int |
+handle_qxfer_btrace (const char *annex, |
+ gdb_byte *readbuf, const gdb_byte *writebuf, |
+ ULONGEST offset, LONGEST len) |
+{ |
+ static struct buffer cache; |
+ struct thread_info *thread; |
+ int type; |
+ |
+ if (the_target->read_btrace == NULL || writebuf != NULL) |
+ return -2; |
+ |
+ if (!target_running ()) |
+ return -1; |
+ |
+ if (ptid_equal (general_thread, null_ptid) |
+ || ptid_equal (general_thread, minus_one_ptid)) |
+ { |
+ strcpy (own_buf, "E.Must select a single thread."); |
+ return -3; |
+ } |
+ |
+ thread = find_thread_ptid (general_thread); |
+ if (thread == NULL) |
+ { |
+ strcpy (own_buf, "E.No such thread."); |
+ return -3; |
+ } |
+ |
+ if (thread->btrace == NULL) |
+ { |
+ strcpy (own_buf, "E.Btrace not enabled."); |
+ return -3; |
+ } |
+ |
+ if (strcmp (annex, "all") == 0) |
+ type = btrace_read_all; |
+ else if (strcmp (annex, "new") == 0) |
+ type = btrace_read_new; |
+ else |
+ { |
+ strcpy (own_buf, "E.Bad annex."); |
+ return -3; |
+ } |
+ |
+ if (offset == 0) |
+ { |
+ buffer_free (&cache); |
+ |
+ target_read_btrace (thread->btrace, &cache, type); |
+ } |
+ else if (offset > cache.used_size) |
+ { |
+ buffer_free (&cache); |
+ return -3; |
+ } |
+ |
+ if (len > cache.used_size - offset) |
+ len = cache.used_size - offset; |
+ |
+ memcpy (readbuf, cache.buffer + offset, len); |
+ |
+ return len; |
+} |
+ |
static const struct qxfer qxfer_packets[] = |
{ |
{ "auxv", handle_qxfer_auxv }, |
+ { "btrace", handle_qxfer_btrace }, |
{ "fdpic", handle_qxfer_fdpic}, |
{ "features", handle_qxfer_features }, |
{ "libraries", handle_qxfer_libraries }, |
@@ -1368,6 +1479,10 @@ handle_qxfer (char *own_buf, int packet_len, int *new_packet_len_p) |
free (data); |
return 0; |
} |
+ else if (n == -3) |
+ { |
+ /* Preserve error message. */ |
+ } |
else if (n < 0) |
write_enn (own_buf); |
else if (n > len) |
@@ -1406,6 +1521,10 @@ handle_qxfer (char *own_buf, int packet_len, int *new_packet_len_p) |
free (data); |
return 0; |
} |
+ else if (n == -3) |
+ { |
+ /* Preserve error message. */ |
+ } |
else if (n < 0) |
write_enn (own_buf); |
else |
@@ -1626,7 +1745,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) |
PBUFSIZ - 1); |
if (the_target->qxfer_libraries_svr4 != NULL) |
- strcat (own_buf, ";qXfer:libraries-svr4:read+"); |
+ strcat (own_buf, ";qXfer:libraries-svr4:read+" |
+ ";augmented-libraries-svr4-read+"); |
else |
{ |
/* We do not have any hook to indicate whether the non-SVR4 target |
@@ -1682,6 +1802,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) |
strcat (own_buf, ";qXfer:statictrace:read+"); |
strcat (own_buf, ";qXfer:traceframe-info:read+"); |
strcat (own_buf, ";EnableDisableTracepoints+"); |
+ strcat (own_buf, ";QTBuffer:size+"); |
strcat (own_buf, ";tracenz+"); |
} |
@@ -1692,6 +1813,13 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) |
if (target_supports_agent ()) |
strcat (own_buf, ";QAgent+"); |
+ if (target_supports_btrace ()) |
+ { |
+ strcat (own_buf, ";Qbtrace:bts+"); |
+ strcat (own_buf, ";Qbtrace:off+"); |
+ strcat (own_buf, ";qXfer:btrace:read+"); |
+ } |
+ |
return; |
} |
@@ -1853,12 +1981,12 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) |
{ |
/* CRC check (compare-section). */ |
char *comma; |
- CORE_ADDR base; |
+ ULONGEST base; |
int len; |
unsigned long long crc; |
require_running (own_buf); |
- base = strtoul (own_buf + 5, &comma, 16); |
+ comma = unpack_varlen_hex (own_buf + 5, &base); |
if (*comma++ != ',') |
{ |
write_enn (own_buf); |
@@ -1917,8 +2045,12 @@ handle_v_cont (char *own_buf) |
{ |
p++; |
+ memset (&resume_info[i], 0, sizeof resume_info[i]); |
+ |
if (p[0] == 's' || p[0] == 'S') |
resume_info[i].kind = resume_step; |
+ else if (p[0] == 'r') |
+ resume_info[i].kind = resume_step; |
else if (p[0] == 'c' || p[0] == 'C') |
resume_info[i].kind = resume_continue; |
else if (p[0] == 't') |
@@ -1938,9 +2070,21 @@ handle_v_cont (char *own_buf) |
goto err; |
resume_info[i].sig = gdb_signal_to_host (sig); |
} |
+ else if (p[0] == 'r') |
+ { |
+ ULONGEST addr; |
+ |
+ p = unpack_varlen_hex (p + 1, &addr); |
+ resume_info[i].step_range_start = addr; |
+ |
+ if (*p != ',') |
+ goto err; |
+ |
+ p = unpack_varlen_hex (p + 1, &addr); |
+ resume_info[i].step_range_end = addr; |
+ } |
else |
{ |
- resume_info[i].sig = 0; |
p = p + 1; |
} |
@@ -2170,29 +2314,6 @@ handle_v_kill (char *own_buf) |
} |
} |
-/* Handle a 'vStopped' packet. */ |
-static void |
-handle_v_stopped (char *own_buf) |
-{ |
- /* If we're waiting for GDB to acknowledge a pending stop reply, |
- consider that done. */ |
- if (notif_queue) |
- { |
- struct vstop_notif *head; |
- |
- if (remote_debug) |
- fprintf (stderr, "vStopped: acking %s\n", |
- target_pid_to_str (notif_queue->ptid)); |
- |
- head = notif_queue; |
- notif_queue = notif_queue->next; |
- free (head); |
- } |
- |
- /* Push another stop reply, or if there are no more left, an OK. */ |
- send_next_stop_reply (own_buf); |
-} |
- |
/* Handle all of the extended 'v' packets. */ |
void |
handle_v_requests (char *own_buf, int packet_len, int *new_packet_len) |
@@ -2209,6 +2330,11 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len) |
if (strncmp (own_buf, "vCont?", 6) == 0) |
{ |
strcpy (own_buf, "vCont;c;C;s;S;t"); |
+ if (target_supports_range_stepping ()) |
+ { |
+ own_buf = own_buf + strlen (own_buf); |
+ strcpy (own_buf, ";r"); |
+ } |
return; |
} |
} |
@@ -2253,11 +2379,8 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len) |
return; |
} |
- if (strncmp (own_buf, "vStopped", 8) == 0) |
- { |
- handle_v_stopped (own_buf); |
- return; |
- } |
+ if (handle_notif_ack (own_buf, packet_len)) |
+ return; |
/* Otherwise we didn't know what packet it was. Say we didn't |
understand it. */ |
@@ -2282,8 +2405,7 @@ myresume (char *own_buf, int step, int sig) |
if (step || sig || valid_cont_thread) |
{ |
- resume_info[0].thread |
- = ((struct inferior_list_entry *) current_inferior)->id; |
+ resume_info[0].thread = current_ptid; |
if (step) |
resume_info[0].kind = resume_step; |
else |
@@ -2339,19 +2461,31 @@ queue_stop_reply_callback (struct inferior_list_entry *entry, void *arg) |
manage the thread's last_status field. */ |
if (the_target->thread_stopped == NULL) |
{ |
+ struct vstop_notif *new_notif = xmalloc (sizeof (*new_notif)); |
+ |
+ new_notif->ptid = entry->id; |
+ new_notif->status = thread->last_status; |
/* Pass the last stop reply back to GDB, but don't notify |
yet. */ |
- queue_stop_reply (entry->id, &thread->last_status); |
+ notif_event_enque (¬if_stop, |
+ (struct notif_event *) new_notif); |
} |
else |
{ |
if (thread_stopped (thread)) |
{ |
if (debug_threads) |
- fprintf (stderr, |
- "Reporting thread %s as already stopped with %s\n", |
- target_pid_to_str (entry->id), |
- target_waitstatus_to_string (&thread->last_status)); |
+ { |
+ char *status_string |
+ = target_waitstatus_to_string (&thread->last_status); |
+ |
+ fprintf (stderr, |
+ "Reporting thread %s as already stopped with %s\n", |
+ target_pid_to_str (entry->id), |
+ status_string); |
+ |
+ xfree (status_string); |
+ } |
gdb_assert (thread->last_status.kind != TARGET_WAITKIND_IGNORE); |
@@ -2422,7 +2556,7 @@ handle_status (char *own_buf) |
/* The first is sent immediatly. OK is sent if there is no |
stopped thread, which is the same handling of the vStopped |
packet (by design). */ |
- send_next_stop_reply (own_buf); |
+ notif_write_event (¬if_stop, own_buf); |
} |
else |
{ |
@@ -2448,7 +2582,7 @@ static void |
gdbserver_version (void) |
{ |
printf ("GNU gdbserver %s%s\n" |
- "Copyright (C) 2012 Free Software Foundation, Inc.\n" |
+ "Copyright (C) 2013 Free Software Foundation, Inc.\n" |
"gdbserver is free software, covered by the " |
"GNU General Public License.\n" |
"This gdbserver was configured as \"%s\"\n", |
@@ -2721,6 +2855,10 @@ main (int argc, char *argv[]) |
exit (1); |
} |
+ /* Remember stdio descriptors. LISTEN_DESC must not be listed, it will be |
+ opened by remote_prepare. */ |
+ notice_open_fds (); |
+ |
/* We need to know whether the remote connection is stdio before |
starting the inferior. Inferiors created in this scenario have |
stdin,stdout redirected. So do this here before we call |
@@ -2754,6 +2892,7 @@ main (int argc, char *argv[]) |
initialize_async_io (); |
initialize_low (); |
+ initialize_event_loop (); |
if (target_supports_tracepoints ()) |
initialize_tracepoint (); |
@@ -2791,6 +2930,8 @@ main (int argc, char *argv[]) |
last_ptid = minus_one_ptid; |
} |
+ initialize_notif (); |
+ |
/* Don't report shared library events on the initial connection, |
even if some libraries are preloaded. Avoids the "stopped by |
shared library event" notice on gdb side. */ |
@@ -2924,7 +3065,8 @@ process_point_options (CORE_ADDR point_addr, char **packet) |
if (*dataptr == 'X') |
{ |
/* Conditional expression. */ |
- fprintf (stderr, "Found breakpoint condition.\n"); |
+ if (debug_threads) |
+ fprintf (stderr, "Found breakpoint condition.\n"); |
add_breakpoint_condition (point_addr, &dataptr); |
} |
else if (strncmp (dataptr, "cmds:", strlen ("cmds:")) == 0) |
@@ -2938,14 +3080,12 @@ process_point_options (CORE_ADDR point_addr, char **packet) |
} |
else |
{ |
- /* Unrecognized token, just skip it. */ |
fprintf (stderr, "Unknown token %c, ignoring.\n", |
*dataptr); |
+ /* Skip tokens until we find one that we recognize. */ |
+ while (*dataptr && *dataptr != ';') |
+ dataptr++; |
} |
- |
- /* Skip tokens until we find one that we recognize. */ |
- while (*dataptr && *dataptr != 'X' && *dataptr != ';') |
- dataptr++; |
} |
*packet = dataptr; |
} |
@@ -3007,8 +3147,7 @@ process_serial_event (void) |
pid = strtol (&own_buf[i], NULL, 16); |
} |
else |
- pid = |
- ptid_get_pid (((struct inferior_list_entry *) current_inferior)->id); |
+ pid = ptid_get_pid (current_ptid); |
if ((tracing && disconnected_tracing) || any_persistent_commands ()) |
{ |
@@ -3169,7 +3308,8 @@ process_serial_event (void) |
require_running (own_buf); |
if (current_traceframe >= 0) |
{ |
- struct regcache *regcache = new_register_cache (); |
+ struct regcache *regcache |
+ = new_register_cache (current_target_desc ()); |
if (fetch_traceframe_registers (current_traceframe, |
regcache, -1) == 0) |
@@ -3259,13 +3399,16 @@ process_serial_event (void) |
/* Fallthrough. */ |
case 'z': /* remove_ ... */ |
{ |
- char *lenptr; |
char *dataptr; |
- CORE_ADDR addr = strtoul (&own_buf[3], &lenptr, 16); |
- int len = strtol (lenptr + 1, &dataptr, 16); |
+ ULONGEST addr; |
+ int len; |
char type = own_buf[1]; |
int res; |
const int insert = ch == 'Z'; |
+ char *p = &own_buf[3]; |
+ |
+ p = unpack_varlen_hex (p, &addr); |
+ len = strtol (p + 1, &dataptr, 16); |
/* Default to unrecognized/unsupported. */ |
res = 1; |
@@ -3405,9 +3548,12 @@ process_serial_event (void) |
{ |
/* In non-stop, defer exiting until GDB had a chance to query |
the whole vStopped list (until it gets an OK). */ |
- if (!notif_queue) |
+ if (QUEUE_is_empty (notif_event_p, notif_stop.queue)) |
{ |
- fprintf (stderr, "GDBserver exiting\n"); |
+ /* Be transparent when GDB is connected through stdio -- no |
+ need to spam GDB's console. */ |
+ if (!remote_connection_is_stdio ()) |
+ fprintf (stderr, "GDBserver exiting\n"); |
remote_close (); |
exit (0); |
} |
@@ -3503,8 +3649,14 @@ handle_target_event (int err, gdb_client_data client_data) |
} |
else |
{ |
- /* Something interesting. Tell GDB about it. */ |
- push_event (last_ptid, &last_status); |
+ struct vstop_notif *vstop_notif |
+ = xmalloc (sizeof (struct vstop_notif)); |
+ |
+ vstop_notif->status = last_status; |
+ vstop_notif->ptid = last_ptid; |
+ /* Push Stop notification. */ |
+ notif_push (¬if_stop, |
+ (struct notif_event *) vstop_notif); |
} |
} |