diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index d1d5075..4a2f44e 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -21825,8 +21825,8 @@ If all threads are stopped, the @var{stopped} field will have the
value of @code{"all"}. Otherwise, the value of the @var{stopped}
field will be a list of thread identifiers. Presently, this list will
always include a single thread, but frontend should be prepared to see
-several threads in the list. The @var{core} field reports on which
-processor core the stop event has happened. This field may be absent
+several threads in the list. The @var{core} field reports the
+processor core on which the stop event has happened. This field may be absent
if such information is not available.
@item =thread-group-created,id="@var{id}"
@@ -21907,12 +21907,12 @@ corresponds to the frame's code address. This field may be absent.
@node GDB/MI Thread Information
@subsection @sc{gdb/mi} Thread Information
-Whenver @value{GDBN} has to report an information about a thread, it
+Whenever @value{GDBN} has to report an information about a thread, it
uses a tuple with the following fields:
@table @code
@item id
-The numeric id assigned to the thread by @value{GDBN}. This field is
+The numeric id assigned to the thread by @value{GDBN}. This field is
always present.
@item target-id
@@ -21921,13 +21921,13 @@ Target-specific string identifying the thread. This field is always present.
@item details
Additional information about the thread provided by the target.
It is supposed to be human-readable and not interpreted by the
-frontend. This field is optional.
+frontend. This field is optional.
@item state
Either @samp{stopped} or @samp{running}, depending on whether the
thread is presently running. This field is always present.
-@item cores
+@item core
The value of this field is an integer number of the processor core the
thread was last seen on. This field is optional.
@end table
@@ -26240,8 +26240,8 @@ while the target is running.
-list-thread-groups [ --available ] [ --recurse 1 ] [ @var{group} ... ]
@end smallexample
-Lists thread groups (@pxref{Thread groups}). When a single thread
-group is passed as the argument, lists the children specified one.
+Lists thread groups (@pxref{Thread groups}). When a single thread
+group is passed as the argument, lists the children of that group.
When several thread group are passed, lists information about those
thread groups. Without any parameters, lists information about all
top-level thread groups.
@@ -26251,18 +26251,18 @@ With the @samp{--available} option, @value{GDBN} reports thread groups
available on the target.
The output of this command may have either a @samp{threads} result or
-a @samp{groups} result. The @samp{thread} result has a list of tuples
+a @samp{groups} result. The @samp{thread} result has a list of tuples
as value, with each tuple describing a thread (@pxref{GDB/MI Thread
-Information}). The @samp{groups} result has a list of tuples as value,
+Information}). The @samp{groups} result has a list of tuples as value,
each tuple describing a thread group. If top-level groups are
requested (that is, no parameter is passed), or when several groups
-are passed, the output always have a @samp{groups} result. The format
+are passed, the output always has a @samp{groups} result. The format
of the @samp{group} result is described below.
To reduce the number of roundtrips it's possible to list thread groups
together with their children, by passing the @samp{--recurse} option
-and the recursion depth. Presently, only recursion depth of 1 is
-permitted. If this option is present, then every reported thread group
+and the recursion depth. Presently, only recursion depth of 1 is
+permitted. If this option is present, then every reported thread group
will also include its children, either as @samp{group} or
@samp{threads} field.
@@ -26270,7 +26270,7 @@ In general, any combination of option and parameters is permitted, with
the following caveats:
@itemize @bullet
-@item
+@item
When a single thread group is passed, the output will typically
be the @samp{threads} result. Because threads may not contain
anything, the @samp{recurse} option will be ignored.
@@ -26293,7 +26293,7 @@ have the following fields:
Identifier of the thread group. This field is always present.
@item type
-The type of the thread group. At present, only @samp{process} is a
+The type of the thread group. At present, only @samp{process} is a
valid type.
@item pid
@@ -26306,7 +26306,8 @@ absent for an available thread group.
@item threads
This field has a list of tuples as value, each tuple describing a
-thread. It may be present
+thread. It may be present if the @samp{--recurse} option is
+specified, and it's actually possible to obtain the threads.
@item cores
This field is a list of integers, each identifying a core that one
@@ -31845,26 +31846,24 @@ The formal DTD for memory map format is given below:
@cindex thread list format
To efficiently update the list of threads and their attributes,
-@value{GDBN} gdb requests, using the @samp{qXfer:threads:read}
-package (@pxref{qXfer threads read}) and XML document with the
-format described below.
-
-The top-level structure of the document is shown below:
+@value{GDBN} issues the @samp{qXfer:threads:read} packet
+(@pxref{qXfer threads read}) and obtains the XML document with
+the following structure:
@smallexample
- some details
-
-
+ ... description ...
+
+
@end smallexample
Each @samp{thread} element must have the @samp{id} attribute that
-identifies the thread (@pxref{thread-id syntax}). The
-@samp{core} attribute, if present, specifies which process core
+identifies the thread (@pxref{thread-id syntax}). The
+@samp{core} attribute, if present, specifies which processor core
the thread was last executing on. The content of the of @samp{thread}
-element is interpreted as hunam-readable auxilliary information.
+element is interpreted as human-readable auxilliary information.
@include agentexpr.texi
@@ -32437,9 +32436,9 @@ An example document is:
@end smallexample
The document has an @samp{osdata} element that contains a number of
-@samp{item} elements describing processes. Each process @samp{item}
+@samp{item} elements describing processes. Each process @samp{item}
may contain @samp{threads} element with items describing threads of
-that process. Both process and thread items contain a number of
+that process. Both process and thread items contain a number of
@samp{column} elements with various information.
Each process item should include a column whose name is @samp{pid}. The value
@@ -32451,7 +32450,7 @@ is running on.
Each thread item should include a column whose name is @samp{tid}.
The value of that is a thread identifier, specific to the operating
-system. The @samp{core} column, if present, is the integer number of
+system. The @samp{core} column, if present, is the integer number of
the core the thread is running on.
@include gpl.texi
diff --git a/gdb/features/osdata.dtd b/gdb/features/osdata.dtd
index 67de837..a04506b 100644
--- a/gdb/features/osdata.dtd
+++ b/gdb/features/osdata.dtd
@@ -10,10 +10,7 @@
-
+
-
-
-
diff --git a/gdb/features/threads.dtd b/gdb/features/threads.dtd
index e7c3a11..20308ee 100644
--- a/gdb/features/threads.dtd
+++ b/gdb/features/threads.dtd
@@ -11,4 +11,3 @@
-
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index d1d853d..f042338 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -2798,10 +2798,27 @@ compare_ints (const void *xa, const void *xb)
return a - b;
}
-/* Given PID, print information about every thread in that process to BUFFER.
- Set *CORES to a string with a comma-separated list of cores that threads
- of PID execute on. The string must be freed by the caller. BUFFER must
- be initialized. If no cores are found, *CORES will be set to NULL. */
+static int *
+unique (int *b, int *e)
+{
+ int *d = b;
+ while (++b != e)
+ if (*d != *b)
+ *++d = *b;
+ return ++d;
+}
+
+/* Given PID, iterates over all threads in that process.
+
+ Information about each thread, in a format suitable for qXfer:osdata:thread
+ is printed to BUFFER, if it's not NULL. The buffer will not be either
+ initialized, or finished, or have '\0' written to it. Caller is responsible
+ for such things.
+
+ The list of cores that threads are running on is assigned to *CORES, if it
+ is not NULL. If not cores are found, *CORES will be set to NULL.
+*/
+
static void
list_threads (int pid, struct buffer *buffer, char **cores)
{
@@ -2820,78 +2837,121 @@ list_threads (int pid, struct buffer *buffer, char **cores)
if (!dir)
return;
- buffer_xml_printf (buffer, "");
while ((dp = readdir (dir)) != NULL)
{
unsigned long lwp = strtoul (dp->d_name, NULL, 10);
-
+
if (lwp != 0)
{
unsigned core = linux_core_of_thread (ptid_build (pid, lwp, 0));
if (core != -1)
{
- char s[11];
+ char s[sizeof ("4294967295") + 1];
sprintf (s, "%u", core);
- if (count == allocated)
- core_numbers = realloc (core_numbers,
- sizeof (int ) * (allocated *= 2));
+ if (count == allocated) {
+ allocated *= 2;
+ core_numbers = realloc (core_numbers,
+ sizeof (int ) * allocated);
+
+ }
core_numbers[count++] = core;
- buffer_xml_printf (buffer,
- "- "
- "%s"
- "%s"
- "
", dp->d_name, s);
+ if (buffer)
+ buffer_xml_printf (buffer,
+ "- "
+ "%d"
+ "%s"
+ "%s"
+ "
", pid, dp->d_name, s);
}
else
{
- buffer_xml_printf (buffer,
- "- "
- "%s"
- "
", dp->d_name);
+ if (buffer)
+ buffer_xml_printf (buffer,
+ "- "
+ "%d"
+ "%s"
+ "
", pid, dp->d_name);
}
- }
+ }
}
- buffer_xml_printf (buffer, "");
- }
-
- *cores = NULL;
- if (count > 0)
- {
- struct buffer buffer2;
- int *b;
- int *e;
- qsort (core_numbers, count, sizeof (int), compare_ints);
-
- /* Remove duplicates. */
- b = core_numbers;
- e = core_numbers + count;
-
- while (b != e) {
- if ((b + 1 < e) && (*b == *(b+1)))
- {
- *(b + 1) = *(e - 1);
- --e;
- }
- else
- {
- ++b;
- }
- }
+ }
+
+ if (cores)
+ {
+ *cores = NULL;
+ if (count > 0)
+ {
+ struct buffer buffer2;
+ int *b;
+ int *e;
+ qsort (core_numbers, count, sizeof (int), compare_ints);
- buffer_init (&buffer2);
+ /* Remove duplicates. */
+ b = core_numbers;
+ e = unique (b, core_numbers + count);
- for (b = core_numbers; b != e; ++b) {
- char number[11];
- sprintf (number, "%u", *b);
- buffer_xml_printf (&buffer2, "%s%s",
- (b == core_numbers) ? "" : ",", number);
- }
- buffer_grow_str0 (&buffer2, "");
-
- *cores = buffer_finish (&buffer2);
- }
+ buffer_init (&buffer2);
+
+ for (b = core_numbers; b != e; ++b)
+ {
+ char number[sizeof ("4294967295") + 1];
+ sprintf (number, "%u", *b);
+ buffer_xml_printf (&buffer2, "%s%s",
+ (b == core_numbers) ? "" : ",", number);
+ }
+ buffer_grow_str0 (&buffer2, "");
+
+ *cores = buffer_finish (&buffer2);
+ }
+ }
+}
+
+static void
+show_process (int pid, const char *username, struct buffer *buffer)
+{
+ char pathname[128];
+ FILE *f;
+ char cmd[MAXPATHLEN + 1];
+
+ sprintf (pathname, "/proc/%d/cmdline", pid);
+
+ if ((f = fopen (pathname, "r")) != NULL)
+ {
+ size_t len = fread (cmd, 1, sizeof (cmd) - 1, f);
+ if (len > 0)
+ {
+ char *cores = 0;
+ int i;
+ for (i = 0; i < len; i++)
+ if (cmd[i] == '\0')
+ cmd[i] = ' ';
+ cmd[len] = '\0';
+
+ buffer_xml_printf (buffer,
+ "- "
+ "%d"
+ "%s"
+ "%s",
+ pid,
+ username,
+ cmd);
+
+ /* This only collects core numbers, and does not print threads. */
+ list_threads (pid, NULL, &cores);
+
+ if (cores)
+ {
+ buffer_xml_printf (buffer,
+ "%s", cores);
+ free (cores);
+ }
+
+ buffer_xml_printf (buffer, "
");
+ }
+ fclose (f);
+ }
}
static int
@@ -2904,10 +2964,16 @@ linux_qxfer_osdata (const char *annex,
static const char *buf;
static long len_avail = -1;
static struct buffer buffer;
+ int processes = 0;
+ int threads = 0;
DIR *dirp;
- if (strcmp (annex, "processes") != 0)
+ if (strcmp (annex, "processes") == 0)
+ processes = 1;
+ else if (strcmp (annex, "threads") == 0)
+ threads = 1;
+ else
return 0;
if (!readbuf || writebuf)
@@ -2920,7 +2986,10 @@ linux_qxfer_osdata (const char *annex,
len_avail = 0;
buf = NULL;
buffer_init (&buffer);
- buffer_grow_str (&buffer, "");
+ if (processes)
+ buffer_grow_str (&buffer, "");
+ else if (threads)
+ buffer_grow_str (&buffer, "");
dirp = opendir ("/proc");
if (dirp)
@@ -2939,60 +3008,16 @@ linux_qxfer_osdata (const char *annex,
if (stat (procentry, &statbuf) == 0
&& S_ISDIR (statbuf.st_mode))
{
- char pathname[128];
- FILE *f;
- char cmd[MAXPATHLEN + 1];
- struct passwd *entry;
- int pid;
-
- sprintf (pathname, "/proc/%s/cmdline", dp->d_name);
- entry = getpwuid (statbuf.st_uid);
+ int pid = (int) strtoul (dp->d_name, NULL, 10);
- pid = (int)strtoul (dp->d_name, NULL, 10);
-
- if ((f = fopen (pathname, "r")) != NULL)
+ if (processes)
{
- size_t len = fread (cmd, 1, sizeof (cmd) - 1, f);
- if (len > 0)
- {
- struct buffer thread_buffer;
- char *cores = 0;
- int i;
- for (i = 0; i < len; i++)
- if (cmd[i] == '\0')
- cmd[i] = ' ';
- cmd[len] = '\0';
-
- buffer_xml_printf (
- &buffer,
- "- "
- "%s"
- "%s"
- "%s",
- dp->d_name,
- entry ? entry->pw_name : "?",
- cmd);
-
- buffer_init (&thread_buffer);
- list_threads (pid, &thread_buffer, &cores);
-
- if (cores)
- {
- buffer_xml_printf (
- &buffer,
- "%s", cores);
- free (cores);
- }
-
- buffer_grow (&buffer,
- thread_buffer.buffer,
- thread_buffer.used_size);
- free (buffer_finish (&thread_buffer));
-
-
- buffer_xml_printf (&buffer, "
");
- }
- fclose (f);
+ struct passwd *entry = getpwuid (statbuf.st_uid);
+ show_process (pid, entry ? entry->pw_name : "?", &buffer);
+ }
+ else if (threads)
+ {
+ list_threads (pid, &buffer, NULL);
}
}
}
@@ -3271,8 +3296,8 @@ linux_qxfer_spu (const char *annex, unsigned char *readbuf,
static int
linux_core_of_thread (ptid_t ptid)
{
- char filename[sizeof ("/proc//task//stat")
- + 2*20 /* decimal digits for 2 numbers, max 2^64 bit each */
+ char filename[sizeof ("/proc//task//stat")
+ + 2 * 20 /* decimal digits for 2 numbers, max 2^64 bit each */
+ 1];
FILE *f;
char *content = NULL;
@@ -3281,10 +3306,12 @@ linux_core_of_thread (ptid_t ptid)
int content_read = 0;
int i;
int core;
-
- sprintf (filename, "/proc/%d/task/%ld/stat",
+
+ sprintf (filename, "/proc/%d/task/%ld/stat",
ptid_get_pid (ptid), ptid_get_lwp (ptid));
f = fopen (filename, "r");
+ if (!f)
+ return -1;
for (;;)
{
@@ -3296,19 +3323,19 @@ linux_core_of_thread (ptid_t ptid)
{
content[content_read] = '\0';
break;
- }
+ }
}
p = strchr (content, '(');
p = strchr (p, ')') + 2; /* skip ")" and a whitespace. */
-
+
p = strtok_r (p, " ", &ts);
for (i = 0; i != 36; ++i)
p = strtok_r (NULL, " ", &ts);
if (sscanf (p, "%d", &core) == 0)
core = -1;
-
+
free (content);
fclose (f);
diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c
index 97c076d..4e17ba1 100644
--- a/gdb/gdbserver/remote-utils.c
+++ b/gdb/gdbserver/remote-utils.c
@@ -1616,6 +1616,16 @@ buffer_xml_printf (struct buffer *buffer, const char *format, ...)
prev = f + 1;
}
break;
+ case 'd':
+ {
+ int i = va_arg (ap, char *);
+ char b[sizeof ("4294967295") + 1];
+
+ buffer_grow (buffer, prev, f - prev - 1);
+ sprintf (b, "%d", i);
+ buffer_grow_str (buffer, b);
+ prev = f + 1;
+ }
}
percent = 0;
}
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 62e3e3d..56806e2 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -726,15 +726,15 @@ handle_threads_qxfer_proper (struct buffer *buffer)
if (the_target->core_for_thread)
core = (*the_target->core_for_thread) (ptid);
- if (core != -1)
+ if (core != -1)
{
sprintf (core_s, "%d", core);
- buffer_xml_printf (buffer, "\n",
+ buffer_xml_printf (buffer, "\n",
ptid_s, core_s);
}
else
{
- buffer_xml_printf (buffer, "\n",
+ buffer_xml_printf (buffer, "\n",
ptid_s);
}
}
@@ -757,19 +757,19 @@ handle_threads_qxfer (const char *annex,
{
struct buffer buffer;
/* When asked for data at offset 0, generate everything and store into
- 'result'. Successive reads will be served off 'result'. */
+ 'result'. Successive reads will be served off 'result'. */
if (result)
free (result);
-
+
buffer_init (&buffer);
handle_threads_qxfer_proper (&buffer);
-
+
result = buffer_finish (&buffer);
result_length = strlen (result);
- buffer_free (&buffer);
+ buffer_free (&buffer);
}
-
+
if (offset >= result_length)
{
/* We're out of data. */
@@ -778,10 +778,10 @@ handle_threads_qxfer (const char *annex,
result_length = 0;
return 0;
}
-
+
if (length > result_length - offset)
length = result_length - offset;
-
+
memcpy (readbuf, result + offset, length);
return length;
@@ -1227,7 +1227,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
*new_packet_len_p = write_qxfer_response (own_buf, data, n, 0);
free (data);
- return;
+ return;
}
/* Protocol features query. */
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index b232caf..7c528f2 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -5440,6 +5440,9 @@ linux_nat_core_of_thread (struct target_ops *ops, ptid_t ptid)
back_to = make_cleanup (xfree, filename);
f = fopen (filename, "r");
+ if (!f)
+ return -1;
+
make_cleanup_fclose (f);
for (;;)
@@ -5461,7 +5464,7 @@ linux_nat_core_of_thread (struct target_ops *ops, ptid_t ptid)
p = strchr (p, ')') + 2; /* skip ")" and a whitespace. */
/* If the first field after program name has index 0, then core number is
- the field with index 36. There's no constant for that anywhere. */
+ the field with index 36. There's no constant for that anywhere. */
p = strtok_r (p, " ", &ts);
for (i = 0; i != 36; ++i)
p = strtok_r (NULL, " ", &ts);
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
index b152d98..96bc39e 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -50,6 +50,7 @@
#include "valprint.h"
#include "inferior.h"
#include "osdata.h"
+#include "splay-tree.h"
#include
#include
@@ -366,7 +367,8 @@ struct collect_cores_data
VEC (int) *cores;
};
-static int collect_cores (struct thread_info *ti, void *xdata)
+static int
+collect_cores (struct thread_info *ti, void *xdata)
{
struct collect_cores_data *data = xdata;
@@ -380,6 +382,16 @@ static int collect_cores (struct thread_info *ti, void *xdata)
return 0;
}
+static int *
+unique (int *b, int *e)
+{
+ int *d = b;
+ while (++b != e)
+ if (*d != *b)
+ *++d = *b;
+ return ++d;
+}
+
struct print_one_inferior_data
{
int recurse;
@@ -390,7 +402,7 @@ static int
print_one_inferior (struct inferior *inferior, void *xdata)
{
struct print_one_inferior_data *top_data = xdata;
-
+
if (VEC_length (int, top_data->inferiors) == 0
|| bsearch (&(inferior->pid), VEC_address (int, top_data->inferiors),
VEC_length (int, top_data->inferiors), sizeof (int),
@@ -408,7 +420,7 @@ print_one_inferior (struct inferior *inferior, void *xdata)
data.cores = 0;
iterate_over_threads (collect_cores, &data);
- if (VEC_length (int, data.cores))
+ if (!VEC_empty (int, data.cores))
{
int elt;
int i;
@@ -422,28 +434,16 @@ print_one_inferior (struct inferior *inferior, void *xdata)
b = VEC_address (int, data.cores);
e = b + VEC_length (int, data.cores);
+ e = unique (b, e);
- /* Remove duplicates. */
- while (b != e) {
- if ((b + 1 < e) && (*b == *(b+1)))
- {
- *(b + 1) = *(e - 1);
- --e;
- }
- else
- {
- ++b;
- }
- }
-
- for (i = 0; VEC_iterate (int, data.cores, i, elt); ++i)
- ui_out_field_int (uiout, NULL, elt);
+ for (; b != e; ++b)
+ ui_out_field_int (uiout, NULL, *b);
do_cleanups (back_to_2);
}
if (top_data->recurse)
- print_thread_info (uiout, -1, inferior->pid);
+ print_thread_info (uiout, -1, inferior->pid);
do_cleanups (back_to);
}
@@ -451,25 +451,178 @@ print_one_inferior (struct inferior *inferior, void *xdata)
return 0;
}
-/* Output a field named 'cores' with a list as the value. The elements of
+/* Output a field named 'cores' with a list as the value. The elements of
the list are obtained by splitting 'cores' on comma. */
+
static void
output_cores (struct ui_out *uiout, const char *field_name, const char *xcores)
{
- struct cleanup *back_to = make_cleanup_ui_out_list_begin_end (uiout,
+ struct cleanup *back_to = make_cleanup_ui_out_list_begin_end (uiout,
field_name);
char *cores = xstrdup (xcores);
char *p = cores;
- char *ts = 0;
make_cleanup (xfree, cores);
- for (p = strtok_r (p, ",", &ts); p; p = strtok_r (NULL, ",", &ts))
+ for (p = strtok (p, ","); p; p = strtok (NULL, ","))
ui_out_field_string (uiout, NULL, p);
-
+
do_cleanups (back_to);
}
+static void
+free_vector_of_ints (void *xvector)
+{
+ VEC (int) **vector = xvector;
+ VEC_free (int, *vector);
+}
+
+static void
+do_nothing (splay_tree_key k)
+{
+}
+
+static void
+free_vector_of_osdata_items (splay_tree_value xvalue)
+{
+ VEC (osdata_item_s) *value = (VEC (osdata_item_s) *) xvalue;
+ /* We don't free the items itself, it will be done separately. */
+ VEC_free (osdata_item_s, value);
+}
+
+static int
+splay_tree_int_comparator (splay_tree_key xa, splay_tree_key xb)
+{
+ int a = xa;
+ int b = xb;
+ return a - b;
+}
+
+static void
+free_splay_tree (void *xt)
+{
+ splay_tree t = xt;
+ splay_tree_delete (t);
+}
+
+static void
+list_available_thread_groups (VEC (int) *ids, int recurse)
+{
+ struct osdata *data;
+ struct osdata_item *item;
+ int ix_items;
+ /* This keeps a map from integer (pid) to VEC (struct osdata_item *)*
+ The vector contains information about all threads for the given
+ pid. */
+ splay_tree tree;
+
+ /* get_osdata will throw if it cannot return data. */
+ data = get_osdata ("processes");
+ make_cleanup_osdata_free (data);
+
+ if (recurse)
+ {
+ struct osdata *threads = get_osdata ("threads");
+ make_cleanup_osdata_free (threads);
+
+ tree = splay_tree_new (splay_tree_int_comparator,
+ do_nothing,
+ free_vector_of_osdata_items);
+ make_cleanup (free_splay_tree, tree);
+
+ for (ix_items = 0;
+ VEC_iterate (osdata_item_s, threads->items,
+ ix_items, item);
+ ix_items++)
+ {
+ const char *pid = get_osdata_column (item, "pid");
+ int pid_i = strtoul (pid, NULL, 0);
+ VEC (osdata_item_s) *vec = 0;
+
+ splay_tree_node n = splay_tree_lookup (tree, pid_i);
+ if (!n)
+ {
+ VEC_safe_push (osdata_item_s, vec, item);
+ splay_tree_insert (tree, pid_i, (splay_tree_value)vec);
+ }
+ else
+ {
+ vec = (VEC (osdata_item_s) *) n->value;
+ VEC_safe_push (osdata_item_s, vec, item);
+ n->value = (splay_tree_value) vec;
+ }
+ }
+ }
+
+ 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;
+
+ const char *pid = get_osdata_column (item, "pid");
+ const char *cmd = get_osdata_column (item, "command");
+ const char *user = get_osdata_column (item, "user");
+ const char *cores = get_osdata_column (item, "cores");
+
+ int pid_i = strtoul (pid, NULL, 0);
+
+ /* At present, the target will return all available processes
+ and if information about specific ones was required, we filter
+ undesired processes here. */
+ if (ids && bsearch (&pid_i, VEC_address (int, ids),
+ VEC_length (int, ids),
+ sizeof (int), compare_positive_ints) == NULL)
+ continue;
+
+
+ back_to = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
+
+ 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);
+ if (cores)
+ output_cores (uiout, "cores", cores);
+
+ if (recurse)
+ {
+ splay_tree_node n = splay_tree_lookup (tree, pid_i);
+ if (n)
+ {
+ VEC (osdata_item_s) *children = (VEC (osdata_item_s) *) n->value;
+ struct osdata_item *child;
+ int ix_child;
+
+ make_cleanup_ui_out_list_begin_end (uiout, "threads");
+
+ for (ix_child = 0;
+ VEC_iterate (osdata_item_s, children, ix_child, child);
+ ++ix_child)
+ {
+ struct cleanup *back_to_2 =
+ make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
+
+ const char *tid = get_osdata_column (child, "tid");
+ const char *tcore = get_osdata_column (child, "core");
+ ui_out_field_string (uiout, "id", tid);
+ if (tcore)
+ ui_out_field_string (uiout, "core", tcore);
+
+ do_cleanups (back_to_2);
+ }
+ }
+ }
+
+ do_cleanups (back_to);
+ }
+}
+
void
mi_cmd_list_thread_groups (char *command, char **argv, int argc)
{
@@ -494,19 +647,22 @@ mi_cmd_list_thread_groups (char *command, char **argv, int argc)
while (1)
{
- int opt = mi_getopt ("-list-thread-groups", argc, argv, opts,
+ int opt = mi_getopt ("-list-thread-groups", argc, argv, opts,
&optind, &optarg);
if (opt < 0)
break;
switch ((enum opt) opt)
{
- case AVAILABLE_OPT:
- available = 1;
+ case AVAILABLE_OPT:
+ available = 1;
break;
case RECURSE_OPT:
- if (strcmp (optarg, "1") != 0)
- error ("only '1' is permitted value for the '--recurse' option");
- recurse = 1;
+ if (strcmp (optarg, "0") == 0)
+ ;
+ else if (strcmp (optarg, "1") == 0)
+ recurse = 1;
+ else
+ error ("only '0' and '1' are valid values for the '--recurse' option");
break;
}
}
@@ -516,86 +672,18 @@ mi_cmd_list_thread_groups (char *command, char **argv, int argc)
char *end;
int inf = strtoul (argv[optind], &end, 0);
if (*end != '\0')
- error ("invalid group id '%s'", argv[optind]);
+ error ("invalid group id '%s'", argv[optind]);
VEC_safe_push (int, ids, inf);
}
- qsort (VEC_address (int, ids),
+ qsort (VEC_address (int, ids),
VEC_length (int, ids),
sizeof (int), compare_positive_ints);
- back_to = make_cleanup ((void (*)(void *))VEC_OP (int, free), &ids);
+ back_to = make_cleanup (free_vector_of_ints, &ids);
if (available)
{
- struct osdata *data;
- struct osdata_item *item;
- int ix_items;
-
- data = get_osdata ("processes");
- make_cleanup_osdata_free (data);
-
- 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;
-
- const char *pid = get_osdata_column (item, "pid");
- const char *cmd = get_osdata_column (item, "command");
- const char *user = get_osdata_column (item, "user");
- const char *cores = get_osdata_column (item, "cores");
-
- int pid_i = strtoul (pid, NULL, 0);
-
- /* At present, the target will return all available processes
- and if information about specific ones was required, we filter
- undesired processes here. */
- if (ids && bsearch (&pid_i, VEC_address (int, ids),
- VEC_length (int, ids),
- sizeof (int), compare_positive_ints) == NULL)
- continue;
-
-
- back_to = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
-
- 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);
- if (cores)
- output_cores (uiout, "cores", cores);
-
- if (item->children && recurse)
- {
- struct osdata_item *child;
- int ix_child;
-
- make_cleanup_ui_out_list_begin_end (uiout, "threads");
-
- for (ix_child = 0; VEC_iterate (osdata_item_s,
- item->children->items,
- ix_child, child); ++ix_child)
- {
- struct cleanup *back_to_2 =
- make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
-
- const char *tid = get_osdata_column (child, "tid");
- const char *tcore = get_osdata_column (child, "core");
- ui_out_field_string (uiout, "id", tid);
- if (tcore)
- ui_out_field_string (uiout, "core", tcore);
-
- do_cleanups (back_to_2);
- }
- }
-
- do_cleanups (back_to);
- }
+ list_available_thread_groups (ids, recurse);
}
else if (VEC_length (int, ids) == 1)
{
@@ -603,7 +691,7 @@ mi_cmd_list_thread_groups (char *command, char **argv, int argc)
int pid = *VEC_address (int, ids);
if (!in_inferior_list (pid))
error ("Invalid thread group id '%d'", pid);
- print_thread_info (uiout, -1, pid);
+ print_thread_info (uiout, -1, pid);
}
else
{
@@ -611,15 +699,15 @@ mi_cmd_list_thread_groups (char *command, char **argv, int argc)
data.recurse = recurse;
data.inferiors = ids;
- /* Local thread groups. Either no explicit ids -- and we
- print everything, or several explicit ids. In both cases,
+ /* Local thread groups. Either no explicit ids -- and we
+ print everything, or several explicit ids. In both cases,
we print more than one group, and have to use 'groups'
as the top-level element. */
make_cleanup_ui_out_list_begin_end (uiout, "groups");
update_thread_list ();
iterate_over_inferiors (print_one_inferior, &data);
}
-
+
do_cleanups (back_to);
}
diff --git a/gdb/osdata.c b/gdb/osdata.c
index 394fc4d..3d2c23c 100644
--- a/gdb/osdata.c
+++ b/gdb/osdata.c
@@ -50,10 +50,8 @@ osdata_parse (const char *xml)
/* Internal parsing data passed to all XML callbacks. */
struct osdata_parsing_data
{
- struct osdata *top_osdata;
struct osdata *osdata;
char *property_name;
- struct osdata_item *current_item;
};
/* Handle the start of a element. */
@@ -73,37 +71,9 @@ osdata_start_osdata (struct gdb_xml_parser *parser,
type = VEC_index (gdb_xml_value_s, attributes, 0)->value;
osdata = XZALLOC (struct osdata);
osdata->type = xstrdup (type);
- data->top_osdata = data->osdata = osdata;
-}
-
-/* Handle the start of a element. */
-
-static void
-osdata_start_threads (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;
-
- osdata = XZALLOC (struct osdata);
- osdata->type = xstrdup ("threads");
data->osdata = osdata;
}
-static void
-osdata_end_threads (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;
-
- data->current_item->children = data->osdata;
- data->osdata = data->top_osdata;
-}
-
-
/* Handle the start of a - element. */
static void
@@ -114,8 +84,6 @@ osdata_start_item (struct gdb_xml_parser *parser,
struct osdata_parsing_data *data = user_data;
struct osdata_item item = { NULL };
VEC_safe_push (osdata_item_s, data->osdata->items, &item);
- if (data->osdata == data->top_osdata)
- data->current_item = VEC_last (osdata_item_s, data->osdata->items);
}
/* Handle the start of a element. */
@@ -169,15 +137,10 @@ const struct gdb_xml_attribute column_attributes[] = {
{ NULL, GDB_XML_AF_NONE, NULL, NULL }
};
-extern const struct gdb_xml_element osdata_children[];
-
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 },
- { "threads", NULL, osdata_children,
- GDB_XML_EF_OPTIONAL, osdata_start_threads,
- osdata_end_threads },
{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
};
diff --git a/gdb/osdata.h b/gdb/osdata.h
index 485789e..4ada454 100644
--- a/gdb/osdata.h
+++ b/gdb/osdata.h
@@ -22,9 +22,6 @@
#include "vec.h"
-typedef struct osdata *osdata_p;
-DEF_VEC_P(osdata_p);
-
typedef struct osdata_column
{
char *name;
@@ -35,13 +32,6 @@ DEF_VEC_O(osdata_column_s);
typedef struct osdata_item
{
VEC(osdata_column_s) *columns;
-
- /* Nested items. Presently, a given item may only contain
- children of specific kind, and children->type gives
- the kind of children. In fact, only 'threads' may be
- the kind of children right now. */
- osdata_p children;
-
} osdata_item_s;
DEF_VEC_O(osdata_item_s);
@@ -51,7 +41,8 @@ struct osdata
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 *);
diff --git a/gdb/remote.c b/gdb/remote.c
index eb47713..e393e47 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -311,6 +311,12 @@ struct private_thread_info
int core;
};
+/* The core number that was last seed by process_stop_reply. */
+static int last_core = -1;
+
+/* The thread that corresponds to last_core. */
+static ptid_t thread_of_last_core;
+
/* Returns true if the multi-process extensions are in effect. */
static int
remote_multi_process_p (struct remote_state *rs)
@@ -2312,6 +2318,8 @@ remote_find_new_threads (void)
CRAZY_MAX_THREADS);
}
+#if defined(HAVE_LIBEXPAT)
+
typedef struct thread_item
{
ptid_t ptid;
@@ -2348,8 +2356,8 @@ start_thread (struct gdb_xml_parser *parser,
VEC_safe_push (thread_item_t, data->items, &item);
}
-static void
-end_thread (struct gdb_xml_parser *parser,
+static void
+end_thread (struct gdb_xml_parser *parser,
const struct gdb_xml_element *element,
void *user_data, const char *body_text)
{
@@ -2382,6 +2390,8 @@ const struct gdb_xml_element threads_elements[] = {
{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
};
+#endif
+
/*
* Find all threads for info threads command.
* Uses new thread protocol contributed by Cisco.
@@ -2399,13 +2409,14 @@ remote_threads_info (struct target_ops *ops)
if (remote_desc == 0) /* paranoia */
error (_("Command can only be used when connected to the remote target."));
+#if defined(HAVE_LIBEXPAT)
if (remote_protocol_packets[PACKET_qXfer_threads].support == PACKET_ENABLE)
{
- char *xml = target_read_stralloc (¤t_target,
+ char *xml = target_read_stralloc (¤t_target,
TARGET_OBJECT_THREADS, NULL);
struct cleanup *back_to = make_cleanup (xfree, xml);
- if (xml && *xml)
+ if (xml && *xml)
{
struct gdb_xml_parser *parser;
struct threads_parsing_context context;
@@ -2417,7 +2428,7 @@ remote_threads_info (struct target_ops *ops)
&context);
gdb_xml_use_dtd (parser, "threads.dtd");
-
+
if (gdb_xml_parse (parser, xml) == 0)
{
int i;
@@ -2449,15 +2460,16 @@ remote_threads_info (struct target_ops *ops)
}
}
xfree (item->extra);
- }
+ }
}
-
- VEC_free (thread_item_t, context.items);
+
+ VEC_free (thread_item_t, context.items);
}
do_cleanups (back_to);
return;
}
+#endif
if (use_threadinfo_query)
{
@@ -4901,7 +4913,14 @@ process_stop_reply (struct stop_reply *stop_reply,
event in that thread. */
info = find_thread_ptid (ptid);
if (info && info->private)
- info->private->core = stop_reply->core;
+ {
+ info->private->core = stop_reply->core;
+ }
+ else
+ {
+ last_core = stop_reply->core;
+ thread_of_last_core = ptid;
+ }
remote_notice_new_inferior (ptid, 0);
}
@@ -9073,6 +9092,8 @@ remote_core_of_thread (struct target_ops *ops, ptid_t ptid)
struct thread_info *info = find_thread_ptid (ptid);
if (info && info->private)
return info->private->core;
+ else if (ptid_equal (ptid, thread_of_last_core))
+ return last_core;
return -1;
}
diff --git a/gdb/target.h b/gdb/target.h
index 7435433..55e0e84 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -257,7 +257,7 @@ enum target_object
TARGET_OBJECT_SIGNAL_INFO,
/* The list of threads that are being debugged. */
TARGET_OBJECT_THREADS,
- /* Possible future objects: TARGET_OBJECT_FILE, ... */
+ /* Possible future objects: TARGET_OBJECT_FILE, ... */
};
/* Request that OPS transfer up to LEN 8-bit bytes of the target's
@@ -600,8 +600,8 @@ struct target_ops
ptid_t);
/* Return the core that thread PTID is on, or -1 if such information
- is not available. For a stopped thread, this is supposed to return
- the core the thread was last running on. For running threads, it
+ is not available. For a stopped thread, this is supposed to return
+ the core the thread was last running on. For a running thread, it
should return one of the cores that the thread was running between
the call to this function and return -- and if it was running on
several cores, any other may be returned. */