diff options
author | Vladimir Prus <vladimir@codesourcery.com> | 2010-01-12 21:40:25 +0000 |
---|---|---|
committer | Vladimir Prus <vladimir@codesourcery.com> | 2010-01-12 21:40:25 +0000 |
commit | dc146f7c09d1369f5621e4aac23d410d40d3a6f0 (patch) | |
tree | 801e78e7bbd124f1c503f26bf1173741e224cb33 /gdb/gdbserver/linux-low.c | |
parent | 837504c42dbf7cb67ee328fb0bdf594b70c90209 (diff) | |
download | gdb-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.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 |