diff options
author | Vladimir Prus <vladimir@codesourcery.com> | 2008-12-02 07:57:38 +0000 |
---|---|---|
committer | Vladimir Prus <vladimir@codesourcery.com> | 2008-12-02 07:57:38 +0000 |
commit | 07e059b5a9cbdeab8bf2980e07e79f892a2da854 (patch) | |
tree | 065ba2dfb548976f2d0691a8753a54d03148c1d5 /gdb/gdbserver | |
parent | f3c85de60aa06c1f075332c95fb2c32de79d50d3 (diff) | |
download | gdb-07e059b5a9cbdeab8bf2980e07e79f892a2da854.zip gdb-07e059b5a9cbdeab8bf2980e07e79f892a2da854.tar.gz gdb-07e059b5a9cbdeab8bf2980e07e79f892a2da854.tar.bz2 |
Implement -list-thread-groups --available
* Makefile.in (XMLFILES): Add osdata.dtd.
(SFILES): Add osdata.c.
(COMMON_OBS): Add osdata.o.
* linux-nat.c: Include pwd.h, sys/types.h, gdb_dirent.h and xml-support.h.
(linux_nat_xfer_osdata): New function.
(linux_xfer_partial): Handle TARGET_OBJECT_OSDATA.
* osdata.c: New file.
* osdata.h: New file.
* remote.c (PACKET_qXfer_osdata): New packet enum.
(remote_protocol_features): Add "qXfer:osdata:read".
(remote_read_qxfer): Handle TARGET_OBJECT_OSDATA.
(extended_remote_can_run): New.
(init_extended_remote_ops): Set to_can_run to
extended_remote_can_run.
(_initialize_remote): Add packet config command for
"qXfer:osdata:read".
* xml-support.c (obstack_xml_printf): New function.
* xml-support.h (obstack_xml_printf): Declare.
* target.c (target_get_osdata): New function.
* target.h (enum target_object): Add TARGET_OBJECT_OSDATA.
(target_os_data): Declare.
* features/osdata.dtd: New file.
* mi/mi-main.c (mi_list_thread_groups): Handle the --available
option.
Diffstat (limited to 'gdb/gdbserver')
-rw-r--r-- | gdb/gdbserver/ChangeLog | 16 | ||||
-rw-r--r-- | gdb/gdbserver/linux-low.c | 108 | ||||
-rw-r--r-- | gdb/gdbserver/remote-utils.c | 92 | ||||
-rw-r--r-- | gdb/gdbserver/server.c | 36 | ||||
-rw-r--r-- | gdb/gdbserver/server.h | 34 | ||||
-rw-r--r-- | gdb/gdbserver/target.h | 5 |
6 files changed, 291 insertions, 0 deletions
diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index 66a66f4..b5afa51 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,19 @@ +2008-12-02 Pedro Alves <pedro@codesourcery.com> + + * target.h (struct target_ops): Add qxfer_osdata member. + * linux-low.c: Include ctype.h and pwd.h and sys/types.h + and dirent.h. + (linux_qxfer_osdata): New functions. + (linux_target_ops): Register linux_qxfer_osdata as qxfer_osdata + callback. + * server.c (handle_query): Handle "qXfer:osdata:read:". + * remote-utils.c (buffer_grow, buffer_free, buffer_init, buffer_finish) + (buffer_xml_printf): New functions. + * server.h (struct buffer): New. + (buffer_grow_str, buffer_grow_str0): New macros. + (buffer_grow, buffer_free, buffer_init, buffer_finish) + (buffer_xml_printf): Declare. + 2008-11-24 Doug Evans <dje@google.com> * Makefile.in (VERSION,DIST,LINT,LINTFLAGS): Delete, unused. diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 4766cc9..a518217 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -33,6 +33,10 @@ #include <errno.h> #include <sys/syscall.h> #include <sched.h> +#include <ctype.h> +#include <pwd.h> +#include <sys/types.h> +#include <dirent.h> #ifndef PTRACE_GETSIGINFO # define PTRACE_GETSIGINFO 0x4202 @@ -2049,6 +2053,109 @@ linux_read_offsets (CORE_ADDR *text_p, CORE_ADDR *data_p) } #endif +static int +linux_qxfer_osdata (const char *annex, + unsigned char *readbuf, unsigned const char *writebuf, + CORE_ADDR offset, int len) +{ + /* We make the process list snapshot when the object starts to be + read. */ + static const char *buf; + static long len_avail = -1; + static struct buffer buffer; + + DIR *dirp; + + if (strcmp (annex, "processes") != 0) + return 0; + + if (!readbuf || writebuf) + return 0; + + if (offset == 0) + { + if (len_avail != -1 && len_avail != 0) + buffer_free (&buffer); + len_avail = 0; + buf = NULL; + buffer_init (&buffer); + buffer_grow_str (&buffer, "<osdata type=\"processes\">"); + + dirp = opendir ("/proc"); + if (dirp) + { + struct dirent *dp; + while ((dp = readdir (dirp)) != NULL) + { + struct stat statbuf; + char procentry[sizeof ("/proc/4294967295")]; + + if (!isdigit (dp->d_name[0]) + || strlen (dp->d_name) > sizeof ("4294967295") - 1) + continue; + + sprintf (procentry, "/proc/%s", dp->d_name); + if (stat (procentry, &statbuf) == 0 + && S_ISDIR (statbuf.st_mode)) + { + char pathname[128]; + FILE *f; + char cmd[MAXPATHLEN + 1]; + struct passwd *entry; + + sprintf (pathname, "/proc/%s/cmdline", dp->d_name); + entry = getpwuid (statbuf.st_uid); + + if ((f = fopen (pathname, "r")) != NULL) + { + size_t len = fread (cmd, 1, sizeof (cmd) - 1, f); + if (len > 0) + { + int i; + for (i = 0; i < len; i++) + if (cmd[i] == '\0') + cmd[i] = ' '; + cmd[len] = '\0'; + + buffer_xml_printf ( + &buffer, + "<item>" + "<column name=\"pid\">%s</column>" + "<column name=\"user\">%s</column>" + "<column name=\"command\">%s</column>" + "</item>", + dp->d_name, + entry ? entry->pw_name : "?", + cmd); + } + fclose (f); + } + } + } + + closedir (dirp); + } + buffer_grow_str0 (&buffer, "</osdata>\n"); + buf = buffer_finish (&buffer); + len_avail = strlen (buf); + } + + if (offset >= len_avail) + { + /* Done. Get rid of the data. */ + buffer_free (&buffer); + buf = NULL; + len_avail = 0; + return 0; + } + + if (len > len_avail - offset) + len = len_avail - offset; + memcpy (readbuf, buf + offset, len); + + return len; +} + static struct target_ops linux_target_ops = { linux_create_inferior, linux_attach, @@ -2081,6 +2188,7 @@ static struct target_ops linux_target_ops = { #endif NULL, hostio_last_error_from_errno, + linux_qxfer_osdata, }; static void diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c index b5665f5..d37d56d 100644 --- a/gdb/gdbserver/remote-utils.c +++ b/gdb/gdbserver/remote-utils.c @@ -1291,3 +1291,95 @@ xml_escape_text (const char *text) return result; } + +void +buffer_grow (struct buffer *buffer, const char *data, size_t size) +{ + char *new_buffer; + size_t new_buffer_size; + + if (size == 0) + return; + + new_buffer_size = buffer->buffer_size; + + if (new_buffer_size == 0) + new_buffer_size = 1; + + while (buffer->used_size + size > new_buffer_size) + new_buffer_size *= 2; + new_buffer = realloc (buffer->buffer, new_buffer_size); + if (!new_buffer) + abort (); + memcpy (new_buffer + buffer->used_size, data, size); + buffer->buffer = new_buffer; + buffer->buffer_size = new_buffer_size; + buffer->used_size += size; +} + +void +buffer_free (struct buffer *buffer) +{ + if (!buffer) + return; + + free (buffer->buffer); + buffer->buffer = NULL; + buffer->buffer_size = 0; + buffer->used_size = 0; +} + +void +buffer_init (struct buffer *buffer) +{ + memset (buffer, 0, sizeof (*buffer)); +} + +char* +buffer_finish (struct buffer *buffer) +{ + char *ret = buffer->buffer; + buffer->buffer = NULL; + buffer->buffer_size = 0; + buffer->used_size = 0; + return ret; +} + +void +buffer_xml_printf (struct buffer *buffer, const char *format, ...) +{ + va_list ap; + const char *f; + const char *prev; + int percent = 0; + + va_start (ap, format); + + prev = format; + for (f = format; *f; f++) + { + if (percent) + { + switch (*f) + { + case 's': + { + char *p; + char *a = va_arg (ap, char *); + buffer_grow (buffer, prev, f - prev - 1); + p = xml_escape_text (a); + buffer_grow_str (buffer, p); + free (p); + prev = f + 1; + } + break; + } + percent = 0; + } + else if (*f == '%') + percent = 1; + } + + buffer_grow_str (buffer, prev); + va_end (ap); +} diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index f8059e4..33db8a7 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -768,6 +768,38 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) 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; + } + /* Protocol features query. */ if (strncmp ("qSupported", own_buf, 10) == 0 && (own_buf[10] == ':' || own_buf[10] == '\0')) @@ -792,6 +824,10 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) if (transport_is_reliable) strcat (own_buf, ";QStartNoAckMode+"); + + if (the_target->qxfer_osdata != NULL) + strcat (own_buf, ";qXfer:osdata:read+"); + return; } diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h index 817b5c4..ca5530d 100644 --- a/gdb/gdbserver/server.h +++ b/gdb/gdbserver/server.h @@ -223,6 +223,40 @@ void monitor_output (const char *msg); char *xml_escape_text (const char *text); +/* Simple growing buffer. */ + +struct buffer +{ + char *buffer; + size_t buffer_size; /* allocated size */ + size_t used_size; /* actually used size */ +}; + +/* Append DATA of size SIZE to the end of BUFFER. Grows the buffer to + accommodate the new data. */ +void buffer_grow (struct buffer *buffer, const char *data, size_t size); + +/* Release any memory held by BUFFER. */ +void buffer_free (struct buffer *buffer); + +/* Initialize BUFFER. BUFFER holds no memory afterwards. */ +void buffer_init (struct buffer *buffer); + +/* Return a pointer into BUFFER data, effectivelly transfering + ownership of the buffer memory to the caller. Calling buffer_free + afterwards has no effect on the returned data. */ +char* buffer_finish (struct buffer *buffer); + +/* Simple printf to BUFFER function. Current implemented formatters: + %s - grow an xml escaped text in OBSTACK. */ +void buffer_xml_printf (struct buffer *buffer, const char *format, ...) + ATTR_FORMAT (printf, 2, 3);; + +#define buffer_grow_str(BUFFER,STRING) \ + buffer_grow (BUFFER, STRING, strlen (STRING)) +#define buffer_grow_str0(BUFFER,STRING) \ + buffer_grow (BUFFER, STRING, strlen (STRING) + 1) + /* Functions from ``signals.c''. */ enum target_signal target_signal_from_host (int hostsig); int target_signal_to_host_p (enum target_signal oursig); diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h index 9f3b899..8b45f29 100644 --- a/gdb/gdbserver/target.h +++ b/gdb/gdbserver/target.h @@ -188,6 +188,11 @@ struct target_ops /* Fill BUF with an hostio error packet representing the last hostio error. */ void (*hostio_last_error) (char *buf); + + /* Read/Write OS data using qXfer packets. */ + int (*qxfer_osdata) (const char *annex, unsigned char *readbuf, + unsigned const char *writebuf, CORE_ADDR offset, + int len); }; extern struct target_ops *the_target; |