aboutsummaryrefslogtreecommitdiff
path: root/gdb/gdbserver/linux-low.c
diff options
context:
space:
mode:
authorVladimir Prus <vladimir@codesourcery.com>2010-01-12 21:40:25 +0000
committerVladimir Prus <vladimir@codesourcery.com>2010-01-12 21:40:25 +0000
commitdc146f7c09d1369f5621e4aac23d410d40d3a6f0 (patch)
tree801e78e7bbd124f1c503f26bf1173741e224cb33 /gdb/gdbserver/linux-low.c
parent837504c42dbf7cb67ee328fb0bdf594b70c90209 (diff)
downloadgdb-dc146f7c09d1369f5621e4aac23d410d40d3a6f0.zip
gdb-dc146f7c09d1369f5621e4aac23d410d40d3a6f0.tar.gz
gdb-dc146f7c09d1369f5621e4aac23d410d40d3a6f0.tar.bz2
Implement core awareness.
* bcache.c (compare_ints): Remove (print_percentage): Use compare_positive_ints. * defs.h (compare_positive_ints): Declare. * linux-nat.h (struct lin_lwp): New field core. (linux_nat_core_of_thread_1): Declare. * linux-nat.c (add_lwp): Init the 'core' field. (linux_nat_wait_1): Record the core. (linux_nat_core_of_thread_1, linux_nat_core_of_thread): New. (linux_nat_add_target): Register the above. * linux-thread-db.c (update_thread_core): New. (thread_db_find_new_threads): Update core information for every thread. * remote.c (struct private_thread_info): New. (free_private_thread_info, demand_private_info): New. (PACKET_qXfer_threads, use_osdata_threads): New. (struct thread_item, threads_parsing_context (start_thread, end_thread, thread_attributes) (thread_children, threads_children, threads_elements): New. (remote_threads_info): Try qXfer:threads before anything else. (remote_protocol_packets): Register qXfer:threads. (remote_open_1): Init use_osdata_threads. (struct stop_reply): New field 'core'. (remote_parse_stop_reply): Parse core number. (process_stop_reply): Record core number. (remote_xfer_partial): Handle qXfer:threads. (remote_core_of_thread): New. (init_remote_ops): Register remote_core_of_thread. (_initialize_remote): Register qXfer:read. * target.c (target_core_of_thread): New * target.h (enum target_object): New value TARGET_OBJECT_THREADS. (struct target_ops): New field to_core_of_threads. (target_core_of_thread): Declare. * gdbthread.h (struct thread_info): New field private_dtor. * thread.c (print_thread_info): Report the core. * ui-out.c (MAX_UI_OUT_LEVELS): Increase. * utils.c (compare_positive_ints): New. * features/threads.dtd: New. * mi/mi-interp.c (mi_on_normal_stop): Report the core. * mi/mi-main.c (struct collect_cores_data, collect_cores) (do_nothing, free_vector_of_osdata_items) (splay_tree_int_comparator, free_splay_tree): New. (print_one_inferior_data): Implemented printing of selected inferiors. Collect and print cores. (output_cores): New. (mi_cmd_list_thread_groups): Support --recurse. Permit specifying thread groups together with --available.
Diffstat (limited to 'gdb/gdbserver/linux-low.c')
-rw-r--r--gdb/gdbserver/linux-low.c274
1 files changed, 241 insertions, 33 deletions
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index c20322e6..5584691 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -140,6 +140,7 @@ static int check_removed_breakpoint (struct lwp_info *event_child);
static void *add_lwp (ptid_t ptid);
static int linux_stopped_by_watchpoint (void);
static void mark_lwp_dead (struct lwp_info *lwp, int wstat);
+static int linux_core_of_thread (ptid_t ptid);
struct pending_signals
{
@@ -2802,6 +2803,175 @@ linux_read_offsets (CORE_ADDR *text_p, CORE_ADDR *data_p)
#endif
static int
+compare_ints (const void *xa, const void *xb)
+{
+ int a = *(const int *)xa;
+ int b = *(const int *)xb;
+
+ return a - b;
+}
+
+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. BUFFER is assumed to be already
+ initialized, and the caller is responsible for finishing and appending '\0'
+ to it.
+
+ The list of cores that threads are running on is assigned to *CORES, if it
+ is not NULL. If no cores are found, *CORES will be set to NULL. Caller
+ should free *CORES. */
+
+static void
+list_threads (int pid, struct buffer *buffer, char **cores)
+{
+ int count = 0;
+ int allocated = 10;
+ int *core_numbers = xmalloc (sizeof (int) * allocated);
+ char pathname[128];
+ DIR *dir;
+ struct dirent *dp;
+ struct stat statbuf;
+
+ sprintf (pathname, "/proc/%d/task", pid);
+ if (stat (pathname, &statbuf) == 0 && S_ISDIR (statbuf.st_mode))
+ {
+ dir = opendir (pathname);
+ if (!dir)
+ {
+ free (core_numbers);
+ return;
+ }
+
+ 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[sizeof ("4294967295")];
+ sprintf (s, "%u", core);
+
+ if (count == allocated)
+ {
+ allocated *= 2;
+ core_numbers = realloc (core_numbers,
+ sizeof (int) * allocated);
+ }
+ core_numbers[count++] = core;
+ if (buffer)
+ buffer_xml_printf (buffer,
+ "<item>"
+ "<column name=\"pid\">%d</column>"
+ "<column name=\"tid\">%s</column>"
+ "<column name=\"core\">%s</column>"
+ "</item>", pid, dp->d_name, s);
+ }
+ else
+ {
+ if (buffer)
+ buffer_xml_printf (buffer,
+ "<item>"
+ "<column name=\"pid\">%d</column>"
+ "<column name=\"tid\">%s</column>"
+ "</item>", pid, dp->d_name);
+ }
+ }
+ }
+ }
+
+ if (cores)
+ {
+ *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 = unique (b, core_numbers + count);
+
+ buffer_init (&buffer2);
+
+ for (b = core_numbers; b != e; ++b)
+ {
+ char number[sizeof ("4294967295")];
+ sprintf (number, "%u", *b);
+ buffer_xml_printf (&buffer2, "%s%s",
+ (b == core_numbers) ? "" : ",", number);
+ }
+ buffer_grow_str0 (&buffer2, "");
+
+ *cores = buffer_finish (&buffer2);
+ }
+ }
+ free (core_numbers);
+}
+
+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,
+ "<item>"
+ "<column name=\"pid\">%d</column>"
+ "<column name=\"user\">%s</column>"
+ "<column name=\"command\">%s</column>",
+ pid,
+ username,
+ cmd);
+
+ /* This only collects core numbers, and does not print threads. */
+ list_threads (pid, NULL, &cores);
+
+ if (cores)
+ {
+ buffer_xml_printf (buffer,
+ "<column name=\"cores\">%s</column>", cores);
+ free (cores);
+ }
+
+ buffer_xml_printf (buffer, "</item>");
+ }
+ fclose (f);
+ }
+}
+
+static int
linux_qxfer_osdata (const char *annex,
unsigned char *readbuf, unsigned const char *writebuf,
CORE_ADDR offset, int len)
@@ -2811,10 +2981,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)
@@ -2827,7 +3003,10 @@ linux_qxfer_osdata (const char *annex,
len_avail = 0;
buf = NULL;
buffer_init (&buffer);
- buffer_grow_str (&buffer, "<osdata type=\"processes\">");
+ if (processes)
+ buffer_grow_str (&buffer, "<osdata type=\"processes\">");
+ else if (threads)
+ buffer_grow_str (&buffer, "<osdata type=\"threads\">");
dirp = opendir ("/proc");
if (dirp)
@@ -2846,37 +3025,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;
-
- sprintf (pathname, "/proc/%s/cmdline", dp->d_name);
- entry = getpwuid (statbuf.st_uid);
+ int 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)
- {
- 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);
+ struct passwd *entry = getpwuid (statbuf.st_uid);
+ show_process (pid, entry ? entry->pw_name : "?", &buffer);
+ }
+ else if (threads)
+ {
+ list_threads (pid, &buffer, NULL);
}
}
}
@@ -3152,6 +3310,55 @@ linux_qxfer_spu (const char *annex, unsigned char *readbuf,
return ret;
}
+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 */
+ + 1];
+ FILE *f;
+ char *content = NULL;
+ char *p;
+ char *ts = 0;
+ int content_read = 0;
+ int i;
+ int core;
+
+ sprintf (filename, "/proc/%d/task/%ld/stat",
+ ptid_get_pid (ptid), ptid_get_lwp (ptid));
+ f = fopen (filename, "r");
+ if (!f)
+ return -1;
+
+ for (;;)
+ {
+ int n;
+ content = realloc (content, content_read + 1024);
+ n = fread (content + content_read, 1, 1024, f);
+ content_read += n;
+ if (n < 1024)
+ {
+ 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);
+
+ return core;
+}
+
static struct target_ops linux_target_ops = {
linux_create_inferior,
linux_attach,
@@ -3191,10 +3398,11 @@ static struct target_ops linux_target_ops = {
linux_start_non_stop,
linux_supports_multi_process,
#ifdef USE_THREAD_DB
- thread_db_handle_monitor_command
+ thread_db_handle_monitor_command,
#else
- NULL
+ NULL,
#endif
+ linux_core_of_thread
};
static void