diff options
author | Pedro Alves <palves@redhat.com> | 2011-01-25 10:09:19 +0000 |
---|---|---|
committer | Pedro Alves <palves@redhat.com> | 2011-01-25 10:09:19 +0000 |
commit | d08aafeffe7dcdff4c4f876c6b8f730ce0270847 (patch) | |
tree | 6d1be3ef6bfa5408fcf5c8e7ac8344c04869328e /gdb/gdbserver/server.c | |
parent | efc0eabd6019406ff92286a36713d41a42515e09 (diff) | |
download | gdb-d08aafeffe7dcdff4c4f876c6b8f730ce0270847.zip gdb-d08aafeffe7dcdff4c4f876c6b8f730ce0270847.tar.gz gdb-d08aafeffe7dcdff4c4f876c6b8f730ce0270847.tar.bz2 |
2011-01-25 Pedro Alves <pedro@codesourcery.com>
* server.h (decode_xfer_write): Change prototype.
* remote-utils.c (decode_xfer_write): Remove `annex' parameter,
and don't extract the annex here.
* server.c (decode_xfer_read): Remove `annex' parameter,
and don't extract the annex here.
(decode_xfer): New.
(struct qxfer): New.
(handle_qxfer_auxv, handle_qxfer_features, handle_qxfer_libraries)
(handle_qxfer_osdata, handle_qxfer_siginfo, handle_qxfer_spu)
(handle_qxfer_statictrace): New functions, abstracted out from
handle_query, and made to use the struct qxfer interface.
(handle_threads_qxfer_proper): Rename to ...
(handle_qxfer_threads_proper): ... this.
(handle_threads_qxfer): Rename to ...
(handle_qxfer_threads): ... this. Adjust.
(qxfer_packets): New array.
(handle_qxfer): New function.
(handle_query): Use handle_qxfer.
Diffstat (limited to 'gdb/gdbserver/server.c')
-rw-r--r-- | gdb/gdbserver/server.c | 794 |
1 files changed, 378 insertions, 416 deletions
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index d236cc4..a170d85 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -357,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 != ':') @@ -367,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; } @@ -791,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, "<library-list>\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, " <library name=\""); + p = p + strlen (p); + name = xml_escape_text (dll->name); + strcpy (p, name); + free (name); + p = p + strlen (p); + strcpy (p, "\"><segment address=\""); + p = p + strlen (p); + sprintf (p, "0x%lx", (long) dll->base_addr); + p = p + strlen (p); + strcpy (p, "\"/></library>\n"); + p = p + strlen (p); + } + + strcpy (p, "</library-list>\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; @@ -826,16 +1057,21 @@ handle_threads_qxfer_proper (struct buffer *buffer) buffer_grow_str0 (buffer, "</threads>\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) { @@ -847,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); @@ -863,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; - memcpy (readbuf, result + offset, length); + /* 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); - return length; + 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); + + free (data); + return 1; + } + + return 0; + } + } + + return 0; } /* Table used by the crc32 function to calcuate the checksum. */ @@ -914,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) { @@ -1016,406 +1375,6 @@ 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, "<library-list>\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, " <library name=\""); - p = p + strlen (p); - name = xml_escape_text (dll->name); - strcpy (p, name); - free (name); - p = p + strlen (p); - strcpy (p, "\"><segment address=\""); - p = p + strlen (p); - sprintf (p, "0x%lx", (long) dll->base_addr); - p = p + strlen (p); - strcpy (p, "\"/></library>\n"); - p = p + strlen (p); - } - - strcpy (p, "</library-list>\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; - } - - if (strncmp ("qXfer:statictrace:read:", own_buf, - sizeof ("qXfer:statictrace:read:") -1) == 0) - { - unsigned char *data; - CORE_ADDR ofs; - unsigned int len; - char *annex; - ULONGEST nbytes; - - require_running (own_buf); - - if (current_traceframe == -1) - { - write_enn (own_buf); - return; - } - - /* Reject any annex; grab the offset and length. */ - if (decode_xfer_read (own_buf + sizeof ("qXfer:statictrace:read:") -1, - &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; - - if (traceframe_read_sdata (current_traceframe, ofs, - data, len + 1, &nbytes)) - write_enn (own_buf); - else if (nbytes > len) - *new_packet_len_p = write_qxfer_response (own_buf, data, len, 1); - else - *new_packet_len_p = write_qxfer_response (own_buf, data, nbytes, 0); - - free (data); - return; - } - /* Protocol features query. */ if (strncmp ("qSupported", own_buf, 10) == 0 && (own_buf[10] == ':' || own_buf[10] == '\0')) @@ -1701,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; |