| 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);
|
| }
|
| }
|
|
|
|
|