mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2024-11-25 05:00:01 +00:00
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.
This commit is contained in:
parent
f3c85de60a
commit
07e059b5a9
@ -1,3 +1,33 @@
|
||||
2008-12-02 Pedro Alves <pedro@codesourcery.com>
|
||||
Vladimir Prus <vladimir@codesourcery.com>
|
||||
|
||||
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.
|
||||
|
||||
2008-12-01 Doug Evans <dje@google.com>
|
||||
|
||||
* infrun.c (proceed): Delete unused local stop_signal.
|
||||
|
@ -434,7 +434,7 @@ RUNTESTFLAGS=
|
||||
|
||||
# XML files to build in to GDB.
|
||||
XMLFILES = $(srcdir)/features/gdb-target.dtd $(srcdir)/features/xinclude.dtd \
|
||||
$(srcdir)/features/library-list.dtd
|
||||
$(srcdir)/features/library-list.dtd $(srcdir)/features/osdata.dtd
|
||||
|
||||
# This is ser-unix.o for any system which supports a v7/BSD/SYSV/POSIX
|
||||
# interface to the serial port. Hopefully if get ported to OS/2, VMS,
|
||||
@ -637,7 +637,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
|
||||
macrotab.c macroexp.c macrocmd.c macroscope.c main.c maint.c \
|
||||
mdebugread.c memattr.c mem-break.c minsyms.c mipsread.c memory-map.c \
|
||||
objc-exp.y objc-lang.c \
|
||||
objfiles.c osabi.c observer.c \
|
||||
objfiles.c osabi.c observer.c osdata.c \
|
||||
p-exp.y p-lang.c p-typeprint.c p-valprint.c parse.c printcmd.c \
|
||||
prologue-value.c \
|
||||
regcache.c reggroups.c remote.c remote-fileio.c reverse.c \
|
||||
@ -808,7 +808,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
|
||||
solib.o solib-null.o \
|
||||
prologue-value.o memory-map.o xml-support.o \
|
||||
target-descriptions.o target-memory.o xml-tdesc.o xml-builtin.o \
|
||||
inferior.o
|
||||
inferior.o osdata.o
|
||||
|
||||
TSOBS = inflow.o
|
||||
|
||||
|
6
gdb/NEWS
6
gdb/NEWS
@ -36,6 +36,9 @@ QStartNoAckMode
|
||||
operation over reliable transport links. Use of this packet is
|
||||
controlled by the `set remote noack-packet' command.
|
||||
|
||||
qXfer:osdata:read
|
||||
Obtains additional operating system information
|
||||
|
||||
* Removed remote protocol undocumented extension
|
||||
|
||||
An undocumented extension to the remote protocol's `S' stop reply
|
||||
@ -176,6 +179,9 @@ macro undef
|
||||
|
||||
x86/x86_64 Darwin i[34567]86-*-darwin*
|
||||
|
||||
info os processes
|
||||
Show operating system information about processes.
|
||||
|
||||
* New targets
|
||||
|
||||
x86 DICOS i[34567]86-*-dicos*
|
||||
|
@ -1,3 +1,10 @@
|
||||
2008-12-02 Vladimir Prus <vladimir@codesourcery.com>
|
||||
|
||||
* gdb.texinfo (Operating System Information): New appendix.
|
||||
(Operating System Auxiliary Information): Document 'info os processes'
|
||||
(Remote Configuration): Document 'osdata'
|
||||
(General Query Packets): Document qXfer:osdata:read.
|
||||
|
||||
2008-11-27 Tristan Gingold <gingold@adacore.com>
|
||||
|
||||
* gdb.texinfo (Darwin): Document Darwin specific features.
|
||||
|
@ -178,6 +178,8 @@ software in general. We will miss him.
|
||||
* Agent Expressions:: The GDB Agent Expression Mechanism
|
||||
* Target Descriptions:: How targets can describe themselves to
|
||||
@value{GDBN}
|
||||
* Operating System Information:: Getting additional information from
|
||||
the operating system
|
||||
* Copying:: GNU General Public License says
|
||||
how you can copy and share GDB
|
||||
* GNU Free Documentation License:: The license for this documentation
|
||||
@ -7595,6 +7597,18 @@ most appropriate form for a recognized tag, and in hexadecimal for
|
||||
an unrecognized tag.
|
||||
@end table
|
||||
|
||||
On some targets, @value{GDBN} can access operating-system-specific information
|
||||
and display it to user, without interpretation. For remote targets,
|
||||
this functionality depends on the remote stub's support of the
|
||||
@samp{qXfer:osdata:read} packet, see @ref{qXfer osdata read}.
|
||||
|
||||
@table @code
|
||||
@kindex info os processes
|
||||
@item info os processes
|
||||
Display the list of processes on the target. For each process,
|
||||
@value{GDBN} prints the process identifier, the name of the user, and
|
||||
the command corresponding to the process.
|
||||
@end table
|
||||
|
||||
@node Memory Region Attributes
|
||||
@section Memory Region Attributes
|
||||
@ -14332,6 +14346,10 @@ are:
|
||||
@item @code{noack-packet}
|
||||
@tab @code{QStartNoAckMode}
|
||||
@tab Packet acknowledgment
|
||||
|
||||
@item @code{osdata}
|
||||
@tab @code{qXfer:osdata:read}
|
||||
@tab @code{info os}
|
||||
@end multitable
|
||||
|
||||
@node Remote Stub
|
||||
@ -26243,6 +26261,10 @@ debugging of more than one process at a time. The stub must not use
|
||||
multiprocess extensions in packet replies unless @value{GDBN} has also
|
||||
indicated it supports them in its @samp{qSupported} request.
|
||||
|
||||
@item qXfer:osdata:read
|
||||
The remote stub understands the @samp{qXfer:osdata:read} packet
|
||||
((@pxref{qXfer osdata read}).
|
||||
|
||||
@end table
|
||||
|
||||
@item qSymbol::
|
||||
@ -26381,7 +26403,14 @@ in the target process, and @var{name} identifes the @code{spufs} file
|
||||
in that context to be accessed.
|
||||
|
||||
This packet is not probed by default; the remote stub must request it,
|
||||
by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}).
|
||||
by supplying an appropriate @samp{qSupported} response
|
||||
(@pxref{qSupported}).
|
||||
|
||||
@item qXfer:osdata:read::@var{offset},@var{length}
|
||||
@anchor{qXfer osdata read}
|
||||
Access the target's @dfn{operating system information}.
|
||||
@xref{Operating System Information}.
|
||||
|
||||
@end table
|
||||
|
||||
Reply:
|
||||
@ -28780,6 +28809,55 @@ contain registers @samp{ev0h} through @samp{ev31h}, @samp{acc}, and
|
||||
these to present registers @samp{ev0} through @samp{ev31} to the
|
||||
user.
|
||||
|
||||
@node Operating System Information
|
||||
@appendix Operating System Information
|
||||
@cindex operating system information
|
||||
|
||||
@menu
|
||||
* Process list::
|
||||
@end menu
|
||||
|
||||
Users of @value{GDBN} often wish to obtain information about the state of
|
||||
the operating system running on the target---for example the list of
|
||||
processes, or the list of open files. This section describes the
|
||||
mechanism that makes it possible. This mechanism is similar to the
|
||||
target features mechanism (@pxref{Target Descriptions}), but focuses
|
||||
on a different aspect of target.
|
||||
|
||||
Operating system information is retrived from the target via the
|
||||
remote protocol, using @samp{qXfer} requests (@pxref{qXfer osdata
|
||||
read}). The object name in the request should be @samp{osdata}, and
|
||||
the @var{annex} identifies the data to be fetched.
|
||||
|
||||
@node Process list
|
||||
@appendixsection Process list
|
||||
@cindex operating system information, process list
|
||||
|
||||
When requesting the process list, the @var{annex} field in the
|
||||
@samp{qXfer} request should be @samp{processes}. The returned data is
|
||||
an XML document. The formal syntax of this document is defined in
|
||||
@file{gdb/features/osdata.dtd}.
|
||||
|
||||
An example document is:
|
||||
|
||||
@smallexample
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE target SYSTEM "osdata.dtd">
|
||||
<osdata type="processes">
|
||||
<item>
|
||||
<column name="pid">1</column>
|
||||
<column name="user">root</column>
|
||||
<column name="command">/sbin/init</column>
|
||||
</item>
|
||||
</osdata>
|
||||
@end smallexample
|
||||
|
||||
Each item should include a column whose name is @samp{pid}. The value
|
||||
of that column should identify the process on the target. The
|
||||
@samp{user} and @samp{command} columns are optional, and will be
|
||||
displayed by @value{GDBN}. Target may provide additional columns,
|
||||
which @value{GDBN} currently ignores.
|
||||
|
||||
@include gpl.texi
|
||||
|
||||
@raisesections
|
||||
|
16
gdb/features/osdata.dtd
Normal file
16
gdb/features/osdata.dtd
Normal file
@ -0,0 +1,16 @@
|
||||
<!-- Copyright (C) 2008 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. -->
|
||||
|
||||
<!-- osdata: Root element with versioning -->
|
||||
|
||||
<!ELEMENT osdata (item*)>
|
||||
<!ATTLIST osdata version CDATA #FIXED "1.0">
|
||||
<!ATTLIST osdata type CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT item (column*)>
|
||||
|
||||
<!ELEMENT column (#PCDATA)>
|
||||
<!ATTLIST column name CDATA #REQUIRED>
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
115
gdb/linux-nat.c
115
gdb/linux-nat.c
@ -49,6 +49,10 @@
|
||||
#include "inf-loop.h"
|
||||
#include "event-loop.h"
|
||||
#include "event-top.h"
|
||||
#include <pwd.h>
|
||||
#include <sys/types.h>
|
||||
#include "gdb_dirent.h"
|
||||
#include "xml-support.h"
|
||||
|
||||
#ifdef HAVE_PERSONALITY
|
||||
# include <sys/personality.h>
|
||||
@ -3994,6 +3998,113 @@ linux_proc_pending_signals (int pid, sigset_t *pending, sigset_t *blocked, sigse
|
||||
do_cleanups (cleanup);
|
||||
}
|
||||
|
||||
static LONGEST
|
||||
linux_nat_xfer_osdata (struct target_ops *ops, enum target_object object,
|
||||
const char *annex, gdb_byte *readbuf,
|
||||
const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
|
||||
{
|
||||
/* We make the process list snapshot when the object starts to be
|
||||
read. */
|
||||
static const char *buf;
|
||||
static LONGEST len_avail = -1;
|
||||
static struct obstack obstack;
|
||||
|
||||
DIR *dirp;
|
||||
|
||||
gdb_assert (object == TARGET_OBJECT_OSDATA);
|
||||
|
||||
if (strcmp (annex, "processes") != 0)
|
||||
return 0;
|
||||
|
||||
gdb_assert (readbuf && !writebuf);
|
||||
|
||||
if (offset == 0)
|
||||
{
|
||||
if (len_avail != -1 && len_avail != 0)
|
||||
obstack_free (&obstack, NULL);
|
||||
len_avail = 0;
|
||||
buf = NULL;
|
||||
obstack_init (&obstack);
|
||||
obstack_grow_str (&obstack, "<osdata type=\"processes\">\n");
|
||||
|
||||
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;
|
||||
FILE *f;
|
||||
char cmd[MAXPATHLEN + 1];
|
||||
struct passwd *entry;
|
||||
|
||||
pathname = xstrprintf ("/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';
|
||||
|
||||
obstack_xml_printf (
|
||||
&obstack,
|
||||
"<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);
|
||||
}
|
||||
|
||||
xfree (pathname);
|
||||
}
|
||||
}
|
||||
|
||||
closedir (dirp);
|
||||
}
|
||||
|
||||
obstack_grow_str0 (&obstack, "</osdata>\n");
|
||||
buf = obstack_finish (&obstack);
|
||||
len_avail = strlen (buf);
|
||||
}
|
||||
|
||||
if (offset >= len_avail)
|
||||
{
|
||||
/* Done. Get rid of the obstack. */
|
||||
obstack_free (&obstack, NULL);
|
||||
buf = NULL;
|
||||
len_avail = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len > len_avail - offset)
|
||||
len = len_avail - offset;
|
||||
memcpy (readbuf, buf + offset, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static LONGEST
|
||||
linux_xfer_partial (struct target_ops *ops, enum target_object object,
|
||||
const char *annex, gdb_byte *readbuf,
|
||||
@ -4005,6 +4116,10 @@ linux_xfer_partial (struct target_ops *ops, enum target_object object,
|
||||
return procfs_xfer_auxv (ops, object, annex, readbuf, writebuf,
|
||||
offset, len);
|
||||
|
||||
if (object == TARGET_OBJECT_OSDATA)
|
||||
return linux_nat_xfer_osdata (ops, object, annex, readbuf, writebuf,
|
||||
offset, len);
|
||||
|
||||
xfer = linux_proc_xfer_partial (ops, object, annex, readbuf, writebuf,
|
||||
offset, len);
|
||||
if (xfer != 0)
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include "language.h"
|
||||
#include "valprint.h"
|
||||
#include "inferior.h"
|
||||
#include "osdata.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <sys/time.h>
|
||||
@ -378,7 +379,41 @@ mi_cmd_list_thread_groups (char *command, char **argv, int argc)
|
||||
|
||||
back_to = make_cleanup (&null_cleanup, NULL);
|
||||
|
||||
if (id)
|
||||
if (available && id)
|
||||
{
|
||||
error (_("Can only report top-level available thread groups"));
|
||||
}
|
||||
else if (available)
|
||||
{
|
||||
struct osdata *data = get_osdata ("processes");
|
||||
struct osdata_item *item;
|
||||
int ix_items;
|
||||
|
||||
make_cleanup_ui_out_list_begin_end (uiout, "groups");
|
||||
|
||||
for (ix_items = 0;
|
||||
VEC_iterate (osdata_item_s, data->items,
|
||||
ix_items, item);
|
||||
ix_items++)
|
||||
{
|
||||
struct cleanup *back_to =
|
||||
make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
|
||||
|
||||
const char *pid = get_osdata_column (item, "pid");
|
||||
const char *cmd = get_osdata_column (item, "command");
|
||||
const char *user = get_osdata_column (item, "user");
|
||||
|
||||
ui_out_field_fmt (uiout, "id", "%s", pid);
|
||||
ui_out_field_string (uiout, "type", "process");
|
||||
if (cmd)
|
||||
ui_out_field_string (uiout, "description", cmd);
|
||||
if (user)
|
||||
ui_out_field_string (uiout, "user", user);
|
||||
|
||||
do_cleanups (back_to);
|
||||
}
|
||||
}
|
||||
else if (id)
|
||||
{
|
||||
int pid = atoi (id);
|
||||
if (!in_inferior_list (pid))
|
||||
|
357
gdb/osdata.c
Normal file
357
gdb/osdata.c
Normal file
@ -0,0 +1,357 @@
|
||||
/* Routines for handling XML generic OS data provided by target.
|
||||
|
||||
Copyright (C) 2008 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "target.h"
|
||||
#include "vec.h"
|
||||
#include "xml-support.h"
|
||||
#include "osdata.h"
|
||||
#include "gdb_string.h"
|
||||
#include "ui-out.h"
|
||||
#include "gdbcmd.h"
|
||||
|
||||
#if !defined(HAVE_LIBEXPAT)
|
||||
|
||||
struct osdata *
|
||||
osdata_parse (const char *xml)
|
||||
{
|
||||
static int have_warned;
|
||||
|
||||
if (!have_warned)
|
||||
{
|
||||
have_warned = 1;
|
||||
warning (_("Can not parse XML OS data; XML support was disabled "
|
||||
"at compile time"));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#else /* HAVE_LIBEXPAT */
|
||||
|
||||
#include "xml-support.h"
|
||||
|
||||
/* Internal parsing data passed to all XML callbacks. */
|
||||
struct osdata_parsing_data
|
||||
{
|
||||
struct osdata *osdata;
|
||||
char *property_name;
|
||||
};
|
||||
|
||||
static void
|
||||
osdata_item_clear (struct osdata_item *item)
|
||||
{
|
||||
if (item->columns != NULL)
|
||||
{
|
||||
struct osdata_column *col;
|
||||
int ix;
|
||||
for (ix = 0;
|
||||
VEC_iterate (osdata_column_s, item->columns,
|
||||
ix, col);
|
||||
ix++)
|
||||
{
|
||||
xfree (col->name);
|
||||
xfree (col->value);
|
||||
}
|
||||
VEC_free (osdata_column_s, item->columns);
|
||||
item->columns = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle the start of a <osdata> element. */
|
||||
|
||||
static void
|
||||
osdata_start_osdata (struct gdb_xml_parser *parser,
|
||||
const struct gdb_xml_element *element,
|
||||
void *user_data, VEC(gdb_xml_value_s) *attributes)
|
||||
{
|
||||
struct osdata_parsing_data *data = user_data;
|
||||
char *type;
|
||||
struct osdata *osdata;
|
||||
|
||||
if (data->osdata)
|
||||
gdb_xml_error (parser, _("Seen more than on osdata element"));
|
||||
|
||||
type = VEC_index (gdb_xml_value_s, attributes, 0)->value;
|
||||
osdata = XZALLOC (struct osdata);
|
||||
osdata->type = xstrdup (type);
|
||||
data->osdata = osdata;
|
||||
}
|
||||
|
||||
/* Handle the start of a <item> element. */
|
||||
|
||||
static void
|
||||
osdata_start_item (struct gdb_xml_parser *parser,
|
||||
const struct gdb_xml_element *element,
|
||||
void *user_data, VEC(gdb_xml_value_s) *attributes)
|
||||
{
|
||||
struct osdata_parsing_data *data = user_data;
|
||||
struct osdata_item item = { NULL };
|
||||
VEC_safe_push (osdata_item_s, data->osdata->items, &item);
|
||||
}
|
||||
|
||||
/* Handle the start of a <column> element. */
|
||||
|
||||
static void
|
||||
osdata_start_column (struct gdb_xml_parser *parser,
|
||||
const struct gdb_xml_element *element,
|
||||
void *user_data, VEC(gdb_xml_value_s) *attributes)
|
||||
{
|
||||
struct osdata_parsing_data *data = user_data;
|
||||
const char *name = VEC_index (gdb_xml_value_s, attributes, 0)->value;
|
||||
data->property_name = xstrdup (name);
|
||||
}
|
||||
|
||||
/* Handle the end of a <column> element. */
|
||||
|
||||
static void
|
||||
osdata_end_column (struct gdb_xml_parser *parser,
|
||||
const struct gdb_xml_element *element,
|
||||
void *user_data, const char *body_text)
|
||||
{
|
||||
struct osdata_parsing_data *data = user_data;
|
||||
struct osdata *osdata = data->osdata;
|
||||
struct osdata_item *item = VEC_last (osdata_item_s, osdata->items);
|
||||
struct osdata_column *col = VEC_safe_push (osdata_column_s,
|
||||
item->columns, NULL);
|
||||
|
||||
/* Transfer memory ownership. NAME was already strdup'ed. */
|
||||
col->name = data->property_name;
|
||||
col->value = xstrdup (body_text);
|
||||
data->property_name = NULL;
|
||||
}
|
||||
|
||||
/* Discard the constructed osdata (if an error occurs). */
|
||||
|
||||
static void
|
||||
clear_parsing_data (void *p)
|
||||
{
|
||||
struct osdata_parsing_data *data = p;
|
||||
osdata_free (data->osdata);
|
||||
data->osdata = NULL;
|
||||
xfree (data->property_name);
|
||||
data->property_name = NULL;
|
||||
}
|
||||
|
||||
/* The allowed elements and attributes for OS data object.
|
||||
The root element is a <osdata>. */
|
||||
|
||||
const struct gdb_xml_attribute column_attributes[] = {
|
||||
{ "name", GDB_XML_AF_NONE, NULL, NULL },
|
||||
{ NULL, GDB_XML_AF_NONE, NULL, NULL }
|
||||
};
|
||||
|
||||
const struct gdb_xml_element item_children[] = {
|
||||
{ "column", column_attributes, NULL,
|
||||
GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL,
|
||||
osdata_start_column, osdata_end_column },
|
||||
{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
|
||||
};
|
||||
|
||||
const struct gdb_xml_attribute osdata_attributes[] = {
|
||||
{ "type", GDB_XML_AF_NONE, NULL, NULL },
|
||||
{ NULL, GDB_XML_AF_NONE, NULL, NULL }
|
||||
};
|
||||
|
||||
const struct gdb_xml_element osdata_children[] = {
|
||||
{ "item", NULL, item_children,
|
||||
GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL,
|
||||
osdata_start_item, NULL },
|
||||
{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
|
||||
};
|
||||
|
||||
const struct gdb_xml_element osdata_elements[] = {
|
||||
{ "osdata", osdata_attributes, osdata_children,
|
||||
GDB_XML_EF_NONE, osdata_start_osdata, NULL },
|
||||
{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
|
||||
};
|
||||
|
||||
struct osdata *
|
||||
osdata_parse (const char *xml)
|
||||
{
|
||||
struct gdb_xml_parser *parser;
|
||||
struct cleanup *before_deleting_result, *back_to;
|
||||
struct osdata_parsing_data data = { NULL };
|
||||
|
||||
back_to = make_cleanup (null_cleanup, NULL);
|
||||
parser = gdb_xml_create_parser_and_cleanup (_("osdata"),
|
||||
osdata_elements, &data);
|
||||
gdb_xml_use_dtd (parser, "osdata.dtd");
|
||||
|
||||
before_deleting_result = make_cleanup (clear_parsing_data, &data);
|
||||
|
||||
if (gdb_xml_parse (parser, xml) == 0)
|
||||
/* Parsed successfully, don't need to delete the result. */
|
||||
discard_cleanups (before_deleting_result);
|
||||
|
||||
do_cleanups (back_to);
|
||||
return data.osdata;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
osdata_free (struct osdata *osdata)
|
||||
{
|
||||
if (osdata == NULL)
|
||||
return;
|
||||
|
||||
if (osdata->items != NULL)
|
||||
{
|
||||
struct osdata_item *item;
|
||||
int ix;
|
||||
for (ix = 0;
|
||||
VEC_iterate (osdata_item_s, osdata->items,
|
||||
ix, item);
|
||||
ix++)
|
||||
osdata_item_clear (item);
|
||||
VEC_free (osdata_item_s, osdata->items);
|
||||
}
|
||||
|
||||
xfree (osdata);
|
||||
}
|
||||
|
||||
struct osdata *get_osdata (const char *type)
|
||||
{
|
||||
struct osdata * osdata = NULL;
|
||||
char *xml = target_get_osdata (type);
|
||||
if (xml)
|
||||
{
|
||||
if (xml[0] == '\0')
|
||||
warning (_("Empty data returned by target. Wrong osdata type?"));
|
||||
|
||||
osdata = osdata_parse (xml);
|
||||
}
|
||||
|
||||
if (!osdata)
|
||||
error (_("Can not fetch data now.\n"));
|
||||
|
||||
return osdata;
|
||||
}
|
||||
|
||||
const char *
|
||||
get_osdata_column (struct osdata_item *item, const char *name)
|
||||
{
|
||||
struct osdata_column *col;
|
||||
int ix_cols;
|
||||
|
||||
for (ix_cols = 0;
|
||||
VEC_iterate (osdata_column_s, item->columns,
|
||||
ix_cols, col);
|
||||
ix_cols++)
|
||||
if (strcmp (col->name, name) == 0)
|
||||
return col->value;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
info_osdata_command (char *type, int from_tty)
|
||||
{
|
||||
struct osdata * osdata = NULL;
|
||||
struct cleanup *proc_tbl_chain;
|
||||
struct osdata_item *last;
|
||||
int ncols;
|
||||
int nprocs;
|
||||
|
||||
if (type == 0)
|
||||
/* TODO: No type could mean "list availables types". */
|
||||
error (_("Argument required."));
|
||||
|
||||
osdata = get_osdata (type);
|
||||
|
||||
nprocs = VEC_length (osdata_item_s, osdata->items);
|
||||
|
||||
last = VEC_last (osdata_item_s, osdata->items);
|
||||
if (last && last->columns)
|
||||
ncols = VEC_length (osdata_column_s, last->columns);
|
||||
else
|
||||
ncols = 0;
|
||||
|
||||
proc_tbl_chain
|
||||
= make_cleanup_ui_out_table_begin_end (uiout, ncols, nprocs,
|
||||
"OSDataTable");
|
||||
|
||||
if (last && last->columns)
|
||||
{
|
||||
struct osdata_column *col;
|
||||
int ix;
|
||||
for (ix = 0;
|
||||
VEC_iterate (osdata_column_s, last->columns,
|
||||
ix, col);
|
||||
ix++)
|
||||
ui_out_table_header (uiout, 10, ui_left,
|
||||
col->name, col->name);
|
||||
}
|
||||
|
||||
ui_out_table_body (uiout);
|
||||
|
||||
if (nprocs != 0)
|
||||
{
|
||||
struct osdata_item *item;
|
||||
int ix_items;
|
||||
for (ix_items = 0;
|
||||
VEC_iterate (osdata_item_s, osdata->items,
|
||||
ix_items, item);
|
||||
ix_items++)
|
||||
{
|
||||
struct cleanup *old_chain, *chain;
|
||||
struct ui_stream *stb;
|
||||
int ix_cols;
|
||||
struct osdata_column *col;
|
||||
|
||||
stb = ui_out_stream_new (uiout);
|
||||
old_chain = make_cleanup_ui_out_stream_delete (stb);
|
||||
chain = make_cleanup_ui_out_tuple_begin_end (uiout, "item");
|
||||
|
||||
for (ix_cols = 0;
|
||||
VEC_iterate (osdata_column_s, item->columns,
|
||||
ix_cols, col);
|
||||
ix_cols++)
|
||||
ui_out_field_string (uiout, col->name, col->value);
|
||||
|
||||
do_cleanups (chain);
|
||||
do_cleanups (old_chain);
|
||||
|
||||
ui_out_text (uiout, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
do_cleanups (proc_tbl_chain);
|
||||
|
||||
osdata_free (osdata);
|
||||
}
|
||||
|
||||
static void
|
||||
info_processes_command (char *args, int from_tty)
|
||||
{
|
||||
info_osdata_command ("processes", from_tty);
|
||||
}
|
||||
|
||||
extern initialize_file_ftype _initialize_osdata; /* -Wmissing-prototypes */
|
||||
|
||||
void
|
||||
_initialize_osdata (void)
|
||||
{
|
||||
add_info ("os", info_osdata_command,
|
||||
_("Show OS data ARG."));
|
||||
|
||||
/* An alias for "info osdata processes". */
|
||||
add_info ("processes", info_processes_command,
|
||||
_("List running processes on the target."));
|
||||
}
|
52
gdb/osdata.h
Normal file
52
gdb/osdata.h
Normal file
@ -0,0 +1,52 @@
|
||||
/* Routines for handling XML generic OS data provided by target.
|
||||
|
||||
Copyright (C) 2008 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef OSDATA_H
|
||||
#define OSDATA_H
|
||||
|
||||
#include "vec.h"
|
||||
|
||||
typedef struct osdata_column
|
||||
{
|
||||
char *name;
|
||||
char *value;
|
||||
} osdata_column_s;
|
||||
DEF_VEC_O(osdata_column_s);
|
||||
|
||||
typedef struct osdata_item
|
||||
{
|
||||
VEC(osdata_column_s) *columns;
|
||||
} osdata_item_s;
|
||||
DEF_VEC_O(osdata_item_s);
|
||||
|
||||
struct osdata
|
||||
{
|
||||
char *type;
|
||||
|
||||
VEC(osdata_item_s) *items;
|
||||
};
|
||||
typedef struct osdata *osdata_p;
|
||||
DEF_VEC_P(osdata_p);
|
||||
|
||||
struct osdata *osdata_parse (const char *xml);
|
||||
void osdata_free (struct osdata *);
|
||||
struct osdata *get_osdata (const char *type);
|
||||
const char *get_osdata_column (struct osdata_item *item, const char *name);
|
||||
|
||||
#endif /* OSDATA_H */
|
23
gdb/remote.c
23
gdb/remote.c
@ -992,6 +992,7 @@ enum {
|
||||
PACKET_qXfer_memory_map,
|
||||
PACKET_qXfer_spu_read,
|
||||
PACKET_qXfer_spu_write,
|
||||
PACKET_qXfer_osdata,
|
||||
PACKET_qGetTLSAddr,
|
||||
PACKET_qSupported,
|
||||
PACKET_QPassSignals,
|
||||
@ -2958,6 +2959,8 @@ static struct protocol_feature remote_protocol_features[] = {
|
||||
PACKET_qXfer_spu_read },
|
||||
{ "qXfer:spu:write", PACKET_DISABLE, remote_supported_packet,
|
||||
PACKET_qXfer_spu_write },
|
||||
{ "qXfer:osdata:read", PACKET_DISABLE, remote_supported_packet,
|
||||
PACKET_qXfer_osdata },
|
||||
{ "QPassSignals", PACKET_DISABLE, remote_supported_packet,
|
||||
PACKET_QPassSignals },
|
||||
{ "QStartNoAckMode", PACKET_DISABLE, remote_supported_packet,
|
||||
@ -7355,6 +7358,13 @@ remote_xfer_partial (struct target_ops *ops, enum target_object object,
|
||||
return remote_read_qxfer (ops, "memory-map", annex, readbuf, offset, len,
|
||||
&remote_protocol_packets[PACKET_qXfer_memory_map]);
|
||||
|
||||
case TARGET_OBJECT_OSDATA:
|
||||
/* Should only get here if we're connected. */
|
||||
gdb_assert (remote_desc);
|
||||
return remote_read_qxfer
|
||||
(ops, "osdata", annex, readbuf, offset, len,
|
||||
&remote_protocol_packets[PACKET_qXfer_osdata]);
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
@ -8647,6 +8657,15 @@ remote_supports_multi_process (void)
|
||||
return remote_multi_process_p (rs);
|
||||
}
|
||||
|
||||
static int
|
||||
extended_remote_can_run (void)
|
||||
{
|
||||
if (remote_desc != NULL)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
init_remote_ops (void)
|
||||
{
|
||||
@ -8732,6 +8751,7 @@ Specify the serial device it is connected to (e.g. /dev/ttya).";
|
||||
extended_remote_ops.to_detach = extended_remote_detach;
|
||||
extended_remote_ops.to_attach = extended_remote_attach;
|
||||
extended_remote_ops.to_kill = extended_remote_kill;
|
||||
extended_remote_ops.to_can_run = extended_remote_can_run;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -9041,6 +9061,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
|
||||
add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_spu_write],
|
||||
"qXfer:spu:write", "write-spu-object", 0);
|
||||
|
||||
add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_osdata],
|
||||
"qXfer:osdata:read", "osdata", 0);
|
||||
|
||||
add_packet_config_cmd (&remote_protocol_packets[PACKET_qGetTLSAddr],
|
||||
"qGetTLSAddr", "get-thread-local-storage-address",
|
||||
0);
|
||||
|
20
gdb/target.c
20
gdb/target.c
@ -2224,6 +2224,26 @@ target_supports_non_stop ()
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
target_get_osdata (const char *type)
|
||||
{
|
||||
char *document;
|
||||
struct target_ops *t;
|
||||
|
||||
if (target_can_run (¤t_target))
|
||||
t = ¤t_target;
|
||||
else
|
||||
t = find_default_run_target ("get OS data");
|
||||
|
||||
if (!t)
|
||||
return NULL;
|
||||
|
||||
document = target_read_stralloc (t,
|
||||
TARGET_OBJECT_OSDATA,
|
||||
type);
|
||||
return document;
|
||||
}
|
||||
|
||||
static int
|
||||
default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
|
||||
{
|
||||
|
@ -214,8 +214,11 @@ enum target_object
|
||||
See "target-descriptions.c". ANNEX should never be empty. */
|
||||
TARGET_OBJECT_AVAILABLE_FEATURES,
|
||||
/* Currently loaded libraries, in XML format. */
|
||||
TARGET_OBJECT_LIBRARIES
|
||||
/* Possible future objects: TARGET_OBJECT_FILE, TARGET_OBJECT_PROC, ... */
|
||||
TARGET_OBJECT_LIBRARIES,
|
||||
/* Get OS specific data. The ANNEX specifies the type (running
|
||||
processes, etc.). */
|
||||
TARGET_OBJECT_OSDATA
|
||||
/* Possible future objects: TARGET_OBJECT_FILE, ... */
|
||||
};
|
||||
|
||||
/* Request that OPS transfer up to LEN 8-bit bytes of the target's
|
||||
@ -1283,6 +1286,8 @@ extern int target_resize_to_sections (struct target_ops *target,
|
||||
|
||||
extern void remove_target_sections (bfd *abfd);
|
||||
|
||||
extern char *target_get_osdata (const char *type);
|
||||
|
||||
|
||||
/* Stuff that should be shared among the various remote targets. */
|
||||
|
||||
|
@ -44,5 +44,10 @@ gdb_test "set remote exec-file $target_exec" "" "set remote exec-file"
|
||||
gdb_breakpoint main
|
||||
gdb_test "run" "Breakpoint.* main .*" "continue to main"
|
||||
|
||||
if { [istarget *-*-linux*] } {
|
||||
# On Linux, gdbserver can also report the list of processes.
|
||||
gdb_test "info os processes" ".*pid +user +command.*1 +root +/sbin/init.*" "get process list"
|
||||
}
|
||||
|
||||
gdb_test "kill" "" "kill" "Kill the program being debugged.*" "y"
|
||||
gdb_test "monitor exit" ""
|
||||
|
@ -997,6 +997,45 @@ xml_escape_text (const char *text)
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
obstack_xml_printf (struct obstack *obstack, 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 *);
|
||||
obstack_grow (obstack, prev, f - prev - 1);
|
||||
p = xml_escape_text (a);
|
||||
obstack_grow_str (obstack, p);
|
||||
xfree (p);
|
||||
prev = f + 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
percent = 0;
|
||||
}
|
||||
else if (*f == '%')
|
||||
percent = 1;
|
||||
}
|
||||
|
||||
obstack_grow_str (obstack, prev);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
void _initialize_xml_support (void);
|
||||
|
||||
void
|
||||
|
@ -233,4 +233,11 @@ extern gdb_xml_attribute_handler gdb_xml_parse_attr_enum;
|
||||
ULONGEST gdb_xml_parse_ulongest (struct gdb_xml_parser *parser,
|
||||
const char *value);
|
||||
|
||||
/* Simple printf to obstack function. Current implemented formatters:
|
||||
%s - grow an xml escaped text in OBSTACK. */
|
||||
|
||||
extern void obstack_xml_printf (struct obstack *obstack,
|
||||
const char *format, ...)
|
||||
ATTRIBUTE_PRINTF_2;
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user