X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fgdbserver%2Fserver.c;h=a170d85283e0632d6b15d703b4f86044cfefa1a0;hb=1c79eb8a7d7126b5fcb734fb374be42a717d4373;hp=423a993f2be1065249e8dacbe77f48fc9ce548b4;hpb=505106cdc7c816a44bbfee11daf500f4e5e14072;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index 423a993f2b..a170d85283 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -1,6 +1,7 @@ /* Main code for remote server for GDB. Copyright (C) 1989, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2002, 2003, - 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. + 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 + Free Software Foundation, Inc. This file is part of GDB. @@ -28,9 +29,6 @@ #if HAVE_SYS_WAIT_H #include #endif -#if HAVE_MALLOC_H -#include -#endif ptid_t cont_thread; ptid_t general_thread; @@ -158,6 +156,8 @@ queue_stop_reply (ptid_t ptid, struct target_waitstatus *status) void push_event (ptid_t ptid, struct target_waitstatus *status) { + gdb_assert (status->kind != TARGET_WAITKIND_IGNORE); + queue_stop_reply (ptid, status); /* If this is the first stop reply in the queue, then inform GDB @@ -241,6 +241,14 @@ start_inferior (char **argv) new_argv[count] = NULL; } + if (debug_threads) + { + int i; + for (i = 0; new_argv[i]; ++i) + fprintf (stderr, "new_argv[%d] = \"%s\"\n", i, new_argv[i]); + fflush (stderr); + } + #ifdef SIGTTOU signal (SIGTTOU, SIG_DFL); signal (SIGTTIN, SIG_DFL); @@ -266,13 +274,12 @@ start_inferior (char **argv) if (wrapper_argv != NULL) { struct thread_resume resume_info; - ptid_t ptid; resume_info.thread = pid_to_ptid (signal_pid); resume_info.kind = resume_continue; resume_info.sig = 0; - ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0); + mywait (pid_to_ptid (signal_pid), &last_status, 0, 0); if (last_status.kind != TARGET_WAITKIND_STOPPED) return signal_pid; @@ -284,9 +291,14 @@ start_inferior (char **argv) mywait (pid_to_ptid (signal_pid), &last_status, 0, 0); if (last_status.kind != TARGET_WAITKIND_STOPPED) return signal_pid; + + current_inferior->last_resume_kind = resume_stop; + current_inferior->last_status = last_status; } while (last_status.value.sig != TARGET_SIGNAL_TRAP); + current_inferior->last_resume_kind = resume_stop; + current_inferior->last_status = last_status; return signal_pid; } @@ -294,6 +306,13 @@ start_inferior (char **argv) (assuming success). */ last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0); + if (last_status.kind != TARGET_WAITKIND_EXITED + && last_status.kind != TARGET_WAITKIND_SIGNALLED) + { + current_inferior->last_resume_kind = resume_stop; + current_inferior->last_status = last_status; + } + return signal_pid; } @@ -324,6 +343,9 @@ attach_inferior (int pid) if (last_status.kind == TARGET_WAITKIND_STOPPED && last_status.value.sig == TARGET_SIGNAL_STOP) last_status.value.sig = TARGET_SIGNAL_TRAP; + + current_inferior->last_resume_kind = resume_stop; + current_inferior->last_status = last_status; } return 0; @@ -335,8 +357,34 @@ extern int remote_debug; or -1 otherwise. */ static int -decode_xfer_read (char *buf, char **annex, CORE_ADDR *ofs, unsigned int *len) +decode_xfer_read (char *buf, CORE_ADDR *ofs, unsigned int *len) +{ + /* After the read marker and annex, qXfer looks like a + traditional 'm' packet. */ + decode_m_packet (buf, ofs, len); + + return 0; +} + +static int +decode_xfer (char *buf, char **object, char **rw, char **annex, char **offset) { + /* Extract and NUL-terminate the object. */ + *object = buf; + while (*buf && *buf != ':') + buf++; + if (*buf == '\0') + return -1; + *buf++ = 0; + + /* Extract and NUL-terminate the read/write action. */ + *rw = buf; + while (*buf && *buf != ':') + buf++; + if (*buf == '\0') + return -1; + *buf++ = 0; + /* Extract and NUL-terminate the annex. */ *annex = buf; while (*buf && *buf != ':') @@ -345,10 +393,7 @@ decode_xfer_read (char *buf, char **annex, CORE_ADDR *ofs, unsigned int *len) return -1; *buf++ = 0; - /* After the read marker and annex, qXfer looks like a - traditional 'm' packet. */ - decode_m_packet (buf, ofs, len); - + *offset = buf; return 0; } @@ -371,7 +416,8 @@ write_qxfer_response (char *buf, const void *data, int len, int is_more) } /* Handle all of the extended 'Q' packets. */ -void + +static void handle_general_set (char *own_buf) { if (strncmp ("QPassSignals:", own_buf, strlen ("QPassSignals:")) == 0) @@ -513,8 +559,10 @@ monitor_show_help (void) /* Read trace frame or inferior memory. */ static int -read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) +gdb_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) { + int ret; + if (current_traceframe >= 0) { ULONGEST nbytes; @@ -532,19 +580,36 @@ read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) /* (assume no half-trace half-real blocks for now) */ } - return read_inferior_memory (memaddr, myaddr, len); + ret = prepare_to_access_memory (); + if (ret == 0) + { + ret = read_inferior_memory (memaddr, myaddr, len); + done_accessing_memory (); + } + + return ret; } /* Write trace frame or inferior memory. Actually, writing to trace frames is forbidden. */ static int -write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len) +gdb_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len) { if (current_traceframe >= 0) return EIO; else - return write_inferior_memory (memaddr, myaddr, len); + { + int ret; + + ret = prepare_to_access_memory (); + if (ret == 0) + { + ret = write_inferior_memory (memaddr, myaddr, len); + done_accessing_memory (); + } + return ret; + } } /* Subroutine of handle_search_memory to simplify it. */ @@ -558,7 +623,7 @@ handle_search_memory_1 (CORE_ADDR start_addr, CORE_ADDR search_space_len, { /* Prime the search buffer. */ - if (read_memory (start_addr, search_buf, search_buf_size) != 0) + if (gdb_read_memory (start_addr, search_buf, search_buf_size) != 0) { warning ("Unable to access target memory at 0x%lx, halting search.", (long) start_addr); @@ -609,10 +674,11 @@ handle_search_memory_1 (CORE_ADDR start_addr, CORE_ADDR search_space_len, ? search_space_len - keep_len : chunk_size); - if (read_memory (read_addr, search_buf + keep_len, - nr_to_read) != 0) + if (gdb_read_memory (read_addr, search_buf + keep_len, + nr_to_read) != 0) { - warning ("Unable to access target memory at 0x%lx, halting search.", + warning ("Unable to access target memory " + "at 0x%lx, halting search.", (long) read_addr); return -1; } @@ -748,8 +814,216 @@ handle_monitor_command (char *mon) } } +/* Associates a callback with each supported qXfer'able object. */ + +struct qxfer +{ + /* The object this handler handles. */ + const char *object; + + /* Request that the target transfer up to LEN 8-bit bytes of the + target's OBJECT. The OFFSET, for a seekable object, specifies + the starting point. The ANNEX can be used to provide additional + 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. + + One, and only one, of readbuf or writebuf must be non-NULL. */ + int (*xfer) (const char *annex, + gdb_byte *readbuf, const gdb_byte *writebuf, + ULONGEST offset, LONGEST len); +}; + +/* Handle qXfer:auxv:read. */ + +static int +handle_qxfer_auxv (const char *annex, + gdb_byte *readbuf, const gdb_byte *writebuf, + ULONGEST offset, LONGEST len) +{ + if (the_target->read_auxv == NULL || writebuf != NULL) + return -2; + + if (annex[0] != '\0' || !target_running ()) + return -1; + + return (*the_target->read_auxv) (offset, readbuf, len); +} + +/* Handle qXfer:features:read. */ + +static int +handle_qxfer_features (const char *annex, + gdb_byte *readbuf, const gdb_byte *writebuf, + ULONGEST offset, LONGEST len) +{ + const char *document; + size_t total_len; + + if (writebuf != NULL) + return -2; + + if (!target_running ()) + return -1; + + /* Grab the correct annex. */ + document = get_features_xml (annex); + if (document == NULL) + return -1; + + total_len = strlen (document); + + if (offset > total_len) + return -1; + + if (offset + len > total_len) + len = total_len - offset; + + memcpy (readbuf, document + offset, len); + return len; +} + +/* Handle qXfer:libraries:read. */ + +static int +handle_qxfer_libraries (const char *annex, + gdb_byte *readbuf, const gdb_byte *writebuf, + ULONGEST offset, LONGEST len) +{ + unsigned int total_len; + char *document, *p; + struct inferior_list_entry *dll_ptr; + + if (writebuf != NULL) + return -2; + + if (annex[0] != '\0' || !target_running ()) + return -1; + + /* Over-estimate the necessary memory. Assume that every character + in the library name must be escaped. */ + total_len = 64; + for (dll_ptr = all_dlls.head; dll_ptr != NULL; dll_ptr = dll_ptr->next) + total_len += 128 + 6 * strlen (((struct dll_info *) dll_ptr)->name); + + document = malloc (total_len); + if (document == NULL) + return -1; + + strcpy (document, "\n"); + p = document + strlen (document); + + for (dll_ptr = all_dlls.head; dll_ptr != NULL; dll_ptr = dll_ptr->next) + { + struct dll_info *dll = (struct dll_info *) dll_ptr; + char *name; + + strcpy (p, " name); + strcpy (p, name); + free (name); + p = p + strlen (p); + strcpy (p, "\">base_addr); + p = p + strlen (p); + strcpy (p, "\"/>\n"); + p = p + strlen (p); + } + + strcpy (p, "\n"); + + total_len = strlen (document); + + if (offset > total_len) + { + free (document); + return -1; + } + + if (offset + len > total_len) + len = total_len - offset; + + memcpy (readbuf, document + offset, len); + free (document); + return len; +} + +/* Handle qXfer:osadata:read. */ + +static int +handle_qxfer_osdata (const char *annex, + gdb_byte *readbuf, const gdb_byte *writebuf, + ULONGEST offset, LONGEST len) +{ + if (the_target->qxfer_osdata == NULL || writebuf != NULL) + return -2; + + return (*the_target->qxfer_osdata) (annex, readbuf, NULL, offset, len); +} + +/* Handle qXfer:siginfo:read and qXfer:siginfo:write. */ + +static int +handle_qxfer_siginfo (const char *annex, + gdb_byte *readbuf, const gdb_byte *writebuf, + ULONGEST offset, LONGEST len) +{ + if (the_target->qxfer_siginfo == NULL) + return -2; + + if (annex[0] != '\0' || !target_running ()) + return -1; + + return (*the_target->qxfer_siginfo) (annex, readbuf, writebuf, offset, len); +} + +/* Handle qXfer:spu:read and qXfer:spu:write. */ + +static int +handle_qxfer_spu (const char *annex, + gdb_byte *readbuf, const gdb_byte *writebuf, + ULONGEST offset, LONGEST len) +{ + if (the_target->qxfer_spu == NULL) + return -2; + + if (!target_running ()) + return -1; + + return (*the_target->qxfer_spu) (annex, readbuf, writebuf, offset, len); +} + +/* Handle qXfer:statictrace:read. */ + +static int +handle_qxfer_statictrace (const char *annex, + gdb_byte *readbuf, const gdb_byte *writebuf, + ULONGEST offset, LONGEST len) +{ + ULONGEST nbytes; + + if (writebuf != NULL) + return -2; + + if (annex[0] != '\0' || !target_running () || current_traceframe == -1) + return -1; + + if (traceframe_read_sdata (current_traceframe, offset, + readbuf, len, &nbytes)) + return -1; + return nbytes; +} + +/* Helper for handle_qxfer_threads. */ + static void -handle_threads_qxfer_proper (struct buffer *buffer) +handle_qxfer_threads_proper (struct buffer *buffer) { struct inferior_list_entry *thread; @@ -783,16 +1057,21 @@ handle_threads_qxfer_proper (struct buffer *buffer) buffer_grow_str0 (buffer, "\n"); } +/* Handle qXfer:threads:read. */ + static int -handle_threads_qxfer (const char *annex, - unsigned char *readbuf, - CORE_ADDR offset, int length) +handle_qxfer_threads (const char *annex, + gdb_byte *readbuf, const gdb_byte *writebuf, + ULONGEST offset, LONGEST len) { static char *result = 0; static unsigned int result_length = 0; - if (annex && strcmp (annex, "") != 0) - return 0; + if (writebuf != NULL) + return -2; + + if (!target_running () || annex[0] != '\0') + return -1; if (offset == 0) { @@ -804,7 +1083,7 @@ handle_threads_qxfer (const char *annex, buffer_init (&buffer); - handle_threads_qxfer_proper (&buffer); + handle_qxfer_threads_proper (&buffer); result = buffer_finish (&buffer); result_length = strlen (result); @@ -820,13 +1099,135 @@ handle_threads_qxfer (const char *annex, return 0; } - if (length > result_length - offset) - length = result_length - offset; + if (len > result_length - offset) + len = result_length - offset; + + memcpy (readbuf, result + offset, len); + + return len; +} + +static const struct qxfer qxfer_packets[] = + { + { "auxv", handle_qxfer_auxv }, + { "features", handle_qxfer_features }, + { "libraries", handle_qxfer_libraries }, + { "osdata", handle_qxfer_osdata }, + { "siginfo", handle_qxfer_siginfo }, + { "spu", handle_qxfer_spu }, + { "statictrace", handle_qxfer_statictrace }, + { "threads", handle_qxfer_threads }, + }; + +static int +handle_qxfer (char *own_buf, int packet_len, int *new_packet_len_p) +{ + int i; + char *object; + char *rw; + char *annex; + char *offset; + + if (strncmp (own_buf, "qXfer:", 6) != 0) + return 0; + + /* Grab the object, r/w and annex. */ + if (decode_xfer (own_buf + 6, &object, &rw, &annex, &offset) < 0) + { + write_enn (own_buf); + return 1; + } + + for (i = 0; + i < sizeof (qxfer_packets) / sizeof (qxfer_packets[0]); + i++) + { + const struct qxfer *q = &qxfer_packets[i]; + + if (strcmp (object, q->object) == 0) + { + if (strcmp (rw, "read") == 0) + { + unsigned char *data; + int n; + CORE_ADDR ofs; + unsigned int len; + + /* Grab the offset and length. */ + if (decode_xfer_read (offset, &ofs, &len) < 0) + { + write_enn (own_buf); + return 1; + } + + /* Read one extra byte, as an indicator of whether there is + more. */ + if (len > PBUFSIZ - 2) + len = PBUFSIZ - 2; + data = malloc (len + 1); + if (data == NULL) + { + write_enn (own_buf); + return 1; + } + n = (*q->xfer) (annex, data, NULL, ofs, len + 1); + if (n == -2) + { + free (data); + return 0; + } + else if (n < 0) + write_enn (own_buf); + else if (n > len) + *new_packet_len_p = write_qxfer_response (own_buf, data, len, 1); + else + *new_packet_len_p = write_qxfer_response (own_buf, data, n, 0); + + free (data); + return 1; + } + else if (strcmp (rw, "write") == 0) + { + int n; + unsigned int len; + CORE_ADDR ofs; + unsigned char *data; + + strcpy (own_buf, "E00"); + data = malloc (packet_len - (offset - own_buf)); + if (data == NULL) + { + write_enn (own_buf); + return 1; + } + if (decode_xfer_write (offset, packet_len - (offset - own_buf), + &ofs, &len, data) < 0) + { + free (data); + write_enn (own_buf); + return 1; + } + + n = (*q->xfer) (annex, NULL, data, ofs, len); + if (n == -2) + { + free (data); + return 0; + } + else if (n < 0) + write_enn (own_buf); + else + sprintf (own_buf, "%x", n); - memcpy (readbuf, result + offset, length); + free (data); + return 1; + } - return length; + return 0; + } + } + return 0; } /* Table used by the crc32 function to calcuate the checksum. */ @@ -871,6 +1272,7 @@ crc32 (CORE_ADDR base, int len, unsigned int crc) } /* Handle all of the extended 'q' packets. */ + void handle_query (char *own_buf, int packet_len, int *new_packet_len_p) { @@ -911,6 +1313,9 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) we access breakpoint shadows. */ validate_breakpoints (); + if (target_supports_tracepoints ()) + tracepoint_look_up_symbols (); + if (target_running () && the_target->look_up_symbols != NULL) (*the_target->look_up_symbols) (); @@ -970,365 +1375,12 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) return; } - if (the_target->qxfer_spu != NULL - && strncmp ("qXfer:spu:read:", own_buf, 15) == 0) - { - char *annex; - int n; - unsigned int len; - CORE_ADDR ofs; - unsigned char *spu_buf; - - require_running (own_buf); - strcpy (own_buf, "E00"); - if (decode_xfer_read (own_buf + 15, &annex, &ofs, &len) < 0) - return; - if (len > PBUFSIZ - 2) - len = PBUFSIZ - 2; - spu_buf = malloc (len + 1); - if (!spu_buf) - return; - - n = (*the_target->qxfer_spu) (annex, spu_buf, NULL, ofs, len + 1); - if (n < 0) - write_enn (own_buf); - else if (n > len) - *new_packet_len_p = write_qxfer_response (own_buf, spu_buf, len, 1); - else - *new_packet_len_p = write_qxfer_response (own_buf, spu_buf, n, 0); - - free (spu_buf); - return; - } - - if (the_target->qxfer_spu != NULL - && strncmp ("qXfer:spu:write:", own_buf, 16) == 0) - { - char *annex; - int n; - unsigned int len; - CORE_ADDR ofs; - unsigned char *spu_buf; - - require_running (own_buf); - strcpy (own_buf, "E00"); - spu_buf = malloc (packet_len - 15); - if (!spu_buf) - return; - if (decode_xfer_write (own_buf + 16, packet_len - 16, &annex, - &ofs, &len, spu_buf) < 0) - { - free (spu_buf); - return; - } - - n = (*the_target->qxfer_spu) - (annex, NULL, (unsigned const char *)spu_buf, ofs, len); - if (n < 0) - write_enn (own_buf); - else - sprintf (own_buf, "%x", n); - - free (spu_buf); - return; - } - - if (the_target->read_auxv != NULL - && strncmp ("qXfer:auxv:read:", own_buf, 16) == 0) - { - unsigned char *data; - int n; - CORE_ADDR ofs; - unsigned int len; - char *annex; - - require_running (own_buf); - - /* Reject any annex; grab the offset and length. */ - if (decode_xfer_read (own_buf + 16, &annex, &ofs, &len) < 0 - || annex[0] != '\0') - { - strcpy (own_buf, "E00"); - return; - } - - /* Read one extra byte, as an indicator of whether there is - more. */ - if (len > PBUFSIZ - 2) - len = PBUFSIZ - 2; - data = malloc (len + 1); - if (data == NULL) - { - write_enn (own_buf); - return; - } - n = (*the_target->read_auxv) (ofs, data, len + 1); - if (n < 0) - write_enn (own_buf); - else if (n > len) - *new_packet_len_p = write_qxfer_response (own_buf, data, len, 1); - else - *new_packet_len_p = write_qxfer_response (own_buf, data, n, 0); - - free (data); - - return; - } - - if (strncmp ("qXfer:features:read:", own_buf, 20) == 0) - { - CORE_ADDR ofs; - unsigned int len, total_len; - const char *document; - char *annex; - - require_running (own_buf); - - /* Grab the annex, offset, and length. */ - if (decode_xfer_read (own_buf + 20, &annex, &ofs, &len) < 0) - { - strcpy (own_buf, "E00"); - return; - } - - /* Now grab the correct annex. */ - document = get_features_xml (annex); - if (document == NULL) - { - strcpy (own_buf, "E00"); - return; - } - - total_len = strlen (document); - if (len > PBUFSIZ - 2) - len = PBUFSIZ - 2; - - if (ofs > total_len) - write_enn (own_buf); - else if (len < total_len - ofs) - *new_packet_len_p = write_qxfer_response (own_buf, document + ofs, - len, 1); - else - *new_packet_len_p = write_qxfer_response (own_buf, document + ofs, - total_len - ofs, 0); - - return; - } - - if (strncmp ("qXfer:libraries:read:", own_buf, 21) == 0) - { - CORE_ADDR ofs; - unsigned int len, total_len; - char *document, *p; - struct inferior_list_entry *dll_ptr; - char *annex; - - require_running (own_buf); - - /* Reject any annex; grab the offset and length. */ - if (decode_xfer_read (own_buf + 21, &annex, &ofs, &len) < 0 - || annex[0] != '\0') - { - strcpy (own_buf, "E00"); - return; - } - - /* Over-estimate the necessary memory. Assume that every character - in the library name must be escaped. */ - total_len = 64; - for (dll_ptr = all_dlls.head; dll_ptr != NULL; dll_ptr = dll_ptr->next) - total_len += 128 + 6 * strlen (((struct dll_info *) dll_ptr)->name); - - document = malloc (total_len); - if (document == NULL) - { - write_enn (own_buf); - return; - } - strcpy (document, "\n"); - p = document + strlen (document); - - for (dll_ptr = all_dlls.head; dll_ptr != NULL; dll_ptr = dll_ptr->next) - { - struct dll_info *dll = (struct dll_info *) dll_ptr; - char *name; - - strcpy (p, " name); - strcpy (p, name); - free (name); - p = p + strlen (p); - strcpy (p, "\">base_addr); - p = p + strlen (p); - strcpy (p, "\"/>\n"); - p = p + strlen (p); - } - - strcpy (p, "\n"); - - total_len = strlen (document); - if (len > PBUFSIZ - 2) - len = PBUFSIZ - 2; - - if (ofs > total_len) - write_enn (own_buf); - else if (len < total_len - ofs) - *new_packet_len_p = write_qxfer_response (own_buf, document + ofs, - len, 1); - else - *new_packet_len_p = write_qxfer_response (own_buf, document + ofs, - total_len - ofs, 0); - - free (document); - return; - } - - if (the_target->qxfer_osdata != NULL - && strncmp ("qXfer:osdata:read:", own_buf, 18) == 0) - { - char *annex; - int n; - unsigned int len; - CORE_ADDR ofs; - unsigned char *workbuf; - - strcpy (own_buf, "E00"); - if (decode_xfer_read (own_buf + 18, &annex, &ofs, &len) < 0) - return; - if (len > PBUFSIZ - 2) - len = PBUFSIZ - 2; - workbuf = malloc (len + 1); - if (!workbuf) - return; - - n = (*the_target->qxfer_osdata) (annex, workbuf, NULL, ofs, len + 1); - if (n < 0) - write_enn (own_buf); - else if (n > len) - *new_packet_len_p = write_qxfer_response (own_buf, workbuf, len, 1); - else - *new_packet_len_p = write_qxfer_response (own_buf, workbuf, n, 0); - - free (workbuf); - return; - } - - if (the_target->qxfer_siginfo != NULL - && strncmp ("qXfer:siginfo:read:", own_buf, 19) == 0) - { - unsigned char *data; - int n; - CORE_ADDR ofs; - unsigned int len; - char *annex; - - require_running (own_buf); - - /* Reject any annex; grab the offset and length. */ - if (decode_xfer_read (own_buf + 19, &annex, &ofs, &len) < 0 - || annex[0] != '\0') - { - strcpy (own_buf, "E00"); - return; - } - - /* Read one extra byte, as an indicator of whether there is - more. */ - if (len > PBUFSIZ - 2) - len = PBUFSIZ - 2; - data = malloc (len + 1); - if (!data) - return; - n = (*the_target->qxfer_siginfo) (annex, data, NULL, ofs, len + 1); - if (n < 0) - write_enn (own_buf); - else if (n > len) - *new_packet_len_p = write_qxfer_response (own_buf, data, len, 1); - else - *new_packet_len_p = write_qxfer_response (own_buf, data, n, 0); - - free (data); - return; - } - - if (the_target->qxfer_siginfo != NULL - && strncmp ("qXfer:siginfo:write:", own_buf, 20) == 0) - { - char *annex; - int n; - unsigned int len; - CORE_ADDR ofs; - unsigned char *data; - - require_running (own_buf); - - strcpy (own_buf, "E00"); - data = malloc (packet_len - 19); - if (!data) - return; - if (decode_xfer_write (own_buf + 20, packet_len - 20, &annex, - &ofs, &len, data) < 0) - { - free (data); - return; - } - - n = (*the_target->qxfer_siginfo) - (annex, NULL, (unsigned const char *)data, ofs, len); - if (n < 0) - write_enn (own_buf); - else - sprintf (own_buf, "%x", n); - - free (data); - return; - } - - if (strncmp ("qXfer:threads:read:", own_buf, 19) == 0) - { - unsigned char *data; - int n; - CORE_ADDR ofs; - unsigned int len; - char *annex; - - require_running (own_buf); - - /* Reject any annex; grab the offset and length. */ - if (decode_xfer_read (own_buf + 19, &annex, &ofs, &len) < 0 - || annex[0] != '\0') - { - strcpy (own_buf, "E00"); - return; - } - - /* Read one extra byte, as an indicator of whether there is - more. */ - if (len > PBUFSIZ - 2) - len = PBUFSIZ - 2; - data = malloc (len + 1); - if (!data) - return; - n = handle_threads_qxfer (annex, data, ofs, len + 1); - if (n < 0) - write_enn (own_buf); - else if (n > len) - *new_packet_len_p = write_qxfer_response (own_buf, data, len, 1); - else - *new_packet_len_p = write_qxfer_response (own_buf, data, n, 0); - - free (data); - return; - } - /* Protocol features query. */ if (strncmp ("qSupported", own_buf, 10) == 0 && (own_buf[10] == ':' || own_buf[10] == '\0')) { char *p = &own_buf[10]; + int gdb_supports_qRelocInsn = 0; /* Start processing qSupported packet. */ target_process_qsupported (NULL); @@ -1337,20 +1389,45 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) feature will follow a ':', and latter features will follow ';'. */ if (*p == ':') - for (p = strtok (p + 1, ";"); - p != NULL; - p = strtok (NULL, ";")) - { - if (strcmp (p, "multiprocess+") == 0) - { - /* GDB supports and wants multi-process support if - possible. */ - if (target_supports_multi_process ()) - multi_process = 1; - } - else - target_process_qsupported (p); - } + { + char **qsupported = NULL; + int count = 0; + int i; + + /* Two passes, to avoid nested strtok calls in + target_process_qsupported. */ + for (p = strtok (p + 1, ";"); + p != NULL; + p = strtok (NULL, ";")) + { + count++; + qsupported = xrealloc (qsupported, count * sizeof (char *)); + qsupported[count - 1] = xstrdup (p); + } + + for (i = 0; i < count; i++) + { + p = qsupported[i]; + if (strcmp (p, "multiprocess+") == 0) + { + /* GDB supports and wants multi-process support if + possible. */ + if (target_supports_multi_process ()) + multi_process = 1; + } + else if (strcmp (p, "qRelocInsn+") == 0) + { + /* GDB supports relocate instruction requests. */ + gdb_supports_qRelocInsn = 1; + } + else + target_process_qsupported (p); + + free (p); + } + + free (qsupported); + } sprintf (own_buf, "PacketSize=%x;QPassSignals+", PBUFSIZ - 1); @@ -1393,6 +1470,10 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) strcat (own_buf, ";TraceStateVariables+"); strcat (own_buf, ";TracepointSource+"); strcat (own_buf, ";DisconnectedTracing+"); + if (gdb_supports_qRelocInsn && target_supports_fast_tracepoints ()) + strcat (own_buf, ";FastTracepoints+"); + strcat (own_buf, ";StaticTracepoints+"); + strcat (own_buf, ";qXfer:statictrace:read+"); } return; @@ -1451,7 +1532,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) if (err == 0) { - sprintf (own_buf, "%llx", address); + strcpy (own_buf, paddress(address)); return; } else if (err > 0) @@ -1463,6 +1544,29 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) /* Otherwise, pretend we do not understand this packet. */ } + /* Windows OS Thread Information Block address support. */ + if (the_target->get_tib_address != NULL + && strncmp ("qGetTIBAddr:", own_buf, 12) == 0) + { + char *annex; + int n; + CORE_ADDR tlb; + ptid_t ptid = read_ptid (own_buf + 12, &annex); + + n = (*the_target->get_tib_address) (ptid, &tlb); + if (n == 1) + { + strcpy (own_buf, paddress(tlb)); + return; + } + else if (n == 0) + { + write_enn (own_buf); + return; + } + return; + } + /* Handle "monitor" commands. */ if (strncmp ("qRcmd,", own_buf, 6) == 0) { @@ -1494,7 +1598,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) return; } - if (strncmp ("qSearch:memory:", own_buf, sizeof ("qSearch:memory:") - 1) == 0) + if (strncmp ("qSearch:memory:", own_buf, + sizeof ("qSearch:memory:") - 1) == 0) { require_running (own_buf); handle_search_memory (own_buf, packet_len); @@ -1555,6 +1660,9 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) return; } + if (handle_qxfer (own_buf, packet_len, new_packet_len_p)) + return; + if (target_supports_tracepoints () && handle_tracepoint_query (own_buf)) return; @@ -1563,6 +1671,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) own_buf[0] = 0; } +static void gdb_wants_all_threads_stopped (void); + /* Parse vCont packets. */ void handle_v_cont (char *own_buf) @@ -1666,8 +1776,22 @@ handle_v_cont (char *own_buf) else { last_ptid = mywait (minus_one_ptid, &last_status, 0, 1); + + if (last_status.kind != TARGET_WAITKIND_EXITED + && last_status.kind != TARGET_WAITKIND_SIGNALLED) + current_inferior->last_status = last_status; + + /* From the client's perspective, all-stop mode always stops all + threads implicitly (and the target backend has already done + so by now). Tag all threads as "want-stopped", so we don't + resume them implicitly without the client telling us to. */ + gdb_wants_all_threads_stopped (); prepare_resume_reply (own_buf, last_ptid, &last_status); disable_async_io (); + + if (last_status.kind == TARGET_WAITKIND_EXITED + || last_status.kind == TARGET_WAITKIND_SIGNALLED) + mourn_inferior (find_process_pid (ptid_get_pid (last_ptid))); } return; @@ -1924,7 +2048,7 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len) /* Resume inferior and wait for another event. In non-stop mode, don't really wait here, but return immediatelly to the event loop. */ -void +static void myresume (char *own_buf, int step, int sig) { struct thread_resume resume_info[2]; @@ -1966,8 +2090,20 @@ myresume (char *own_buf, int step, int sig) else { last_ptid = mywait (minus_one_ptid, &last_status, 0, 1); + + if (last_status.kind != TARGET_WAITKIND_EXITED + && last_status.kind != TARGET_WAITKIND_SIGNALLED) + { + current_inferior->last_resume_kind = resume_stop; + current_inferior->last_status = last_status; + } + prepare_resume_reply (own_buf, last_ptid, &last_status); disable_async_io (); + + if (last_status.kind == TARGET_WAITKIND_EXITED + || last_status.kind == TARGET_WAITKIND_SIGNALLED) + mourn_inferior (find_process_pid (ptid_get_pid (last_ptid))); } } @@ -1983,11 +2119,6 @@ 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 target_waitstatus status; - - status.kind = TARGET_WAITKIND_STOPPED; - status.value.sig = TARGET_SIGNAL_TRAP; - /* Pass the last stop reply back to GDB, but don't notify yet. */ queue_stop_reply (entry->id, &thread->last_status); @@ -1997,10 +2128,13 @@ queue_stop_reply_callback (struct inferior_list_entry *entry, void *arg) if (thread_stopped (thread)) { if (debug_threads) - fprintf (stderr, "Reporting thread %s as already stopped with %s\n", + fprintf (stderr, + "Reporting thread %s as already stopped with %s\n", target_pid_to_str (entry->id), target_waitstatus_to_string (&thread->last_status)); + gdb_assert (thread->last_status.kind != TARGET_WAITKIND_IGNORE); + /* Pass the last stop reply back to GDB, but don't notify yet. */ queue_stop_reply (entry->id, &thread->last_status); @@ -2010,8 +2144,9 @@ queue_stop_reply_callback (struct inferior_list_entry *entry, void *arg) return 0; } -/* Set this inferior LWP's state as "want-stopped". We won't resume - this LWP until the client gives us another action for it. */ +/* Set this inferior threads's state as "want-stopped". We won't + resume this thread until the client gives us another action for + it. */ static void gdb_wants_thread_stopped (struct inferior_list_entry *entry) @@ -2022,6 +2157,8 @@ gdb_wants_thread_stopped (struct inferior_list_entry *entry) if (thread->last_status.kind == TARGET_WAITKIND_IGNORE) { + /* Most threads are stopped implicitly (all-stop); tag that with + signal 0. */ thread->last_status.kind = TARGET_WAITKIND_STOPPED; thread->last_status.value.sig = TARGET_SIGNAL_0; } @@ -2069,7 +2206,8 @@ handle_status (char *own_buf) } else { - pause_all (); + pause_all (0); + stabilize_threads (); gdb_wants_all_threads_stopped (); if (all_threads.head) @@ -2090,8 +2228,9 @@ static void gdbserver_version (void) { printf ("GNU gdbserver %s%s\n" - "Copyright (C) 2010 Free Software Foundation, Inc.\n" - "gdbserver is free software, covered by the GNU General Public License.\n" + "Copyright (C) 2011 Free Software Foundation, Inc.\n" + "gdbserver is free software, covered by the " + "GNU General Public License.\n" "This gdbserver was configured as \"%s\"\n", PKGVERSION, version, host_name); } @@ -2122,7 +2261,8 @@ gdbserver_show_disableable (FILE *stream) " vCont \tAll vCont packets\n" " qC \tQuerying the current thread\n" " qfThreadInfo\tThread listing\n" - " Tthread \tPassing the thread specifier in the T stop reply packet\n" + " Tthread \tPassing the thread specifier in the " + "T stop reply packet\n" " threads \tAll of the above\n"); } @@ -2762,15 +2902,15 @@ process_serial_event (void) case 'm': require_running (own_buf); decode_m_packet (&own_buf[1], &mem_addr, &len); - if (read_memory (mem_addr, mem_buf, len) == 0) + if (gdb_read_memory (mem_addr, mem_buf, len) == 0) convert_int_to_ascii (mem_buf, own_buf, len); else write_enn (own_buf); break; case 'M': require_running (own_buf); - decode_M_packet (&own_buf[1], &mem_addr, &len, mem_buf); - if (write_memory (mem_addr, mem_buf, len) == 0) + decode_M_packet (&own_buf[1], &mem_addr, &len, &mem_buf); + if (gdb_write_memory (mem_addr, mem_buf, len) == 0) write_ok (own_buf); else write_enn (own_buf); @@ -2778,8 +2918,8 @@ process_serial_event (void) case 'X': require_running (own_buf); if (decode_X_packet (&own_buf[1], packet_len - 1, - &mem_addr, &len, mem_buf) < 0 - || write_memory (mem_addr, mem_buf, len) != 0) + &mem_addr, &len, &mem_buf) < 0 + || gdb_write_memory (mem_addr, mem_buf, len) != 0) write_enn (own_buf); else write_ok (own_buf); @@ -2999,7 +3139,18 @@ handle_target_event (int err, gdb_client_data client_data) if (last_status.kind == TARGET_WAITKIND_EXITED || last_status.kind == TARGET_WAITKIND_SIGNALLED) - mourn_inferior (process); + { + mark_breakpoints_out (process); + mourn_inferior (process); + } + else + { + /* We're reporting this thread as stopped. Update its + "want-stopped" state to what the client wants, until it + gets a new resume action. */ + current_inferior->last_resume_kind = resume_stop; + current_inferior->last_status = last_status; + } if (forward_event) { @@ -3024,7 +3175,7 @@ handle_target_event (int err, gdb_client_data client_data) resume_info.thread = last_ptid; resume_info.kind = resume_continue; - resume_info.sig = last_status.value.sig; + resume_info.sig = target_signal_to_host (last_status.value.sig); (*the_target->resume) (&resume_info, 1); } else if (debug_threads)