diff options
Diffstat (limited to 'gdb/gdbserver/linux-low.c')
-rw-r--r-- | gdb/gdbserver/linux-low.c | 274 |
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 |