diff options
Diffstat (limited to 'gdb/mi/mi-main.c')
-rw-r--r-- | gdb/mi/mi-main.c | 357 |
1 files changed, 310 insertions, 47 deletions
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c index 16f6102..aee246c 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 <ctype.h> #include <sys/time.h> @@ -360,11 +361,55 @@ mi_cmd_thread_info (char *command, char **argv, int argc) print_thread_info (uiout, thread, -1); } +struct collect_cores_data +{ + int pid; + + VEC (int) *cores; +}; + +static int +collect_cores (struct thread_info *ti, void *xdata) +{ + struct collect_cores_data *data = xdata; + + if (ptid_get_pid (ti->ptid) == data->pid) + { + int core = target_core_of_thread (ti->ptid); + if (core != -1) + VEC_safe_push (int, data->cores, core); + } + + 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; + VEC (int) *inferiors; +}; + static int -print_one_inferior (struct inferior *inferior, void *arg) +print_one_inferior (struct inferior *inferior, void *xdata) { - if (inferior->pid != 0) + struct print_one_inferior_data *top_data = xdata; + + if (VEC_empty (int, top_data->inferiors) + || bsearch (&(inferior->pid), VEC_address (int, top_data->inferiors), + VEC_length (int, top_data->inferiors), sizeof (int), + compare_positive_ints)) { + struct collect_cores_data data; struct cleanup *back_to = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); @@ -372,81 +417,299 @@ print_one_inferior (struct inferior *inferior, void *arg) ui_out_field_string (uiout, "type", "process"); ui_out_field_int (uiout, "pid", inferior->pid); + data.pid = inferior->pid; + data.cores = 0; + iterate_over_threads (collect_cores, &data); + + if (!VEC_empty (int, data.cores)) + { + int elt; + int i; + int *b, *e; + struct cleanup *back_to_2 = + make_cleanup_ui_out_list_begin_end (uiout, "cores"); + + qsort (VEC_address (int, data.cores), + VEC_length (int, data.cores), sizeof (int), + compare_positive_ints); + + b = VEC_address (int, data.cores); + e = b + VEC_length (int, data.cores); + e = unique (b, e); + + 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); + do_cleanups (back_to); } return 0; } -void -mi_cmd_list_thread_groups (char *command, char **argv, int argc) +/* 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; - int available = 0; - char *id = NULL; + struct cleanup *back_to = make_cleanup_ui_out_list_begin_end (uiout, + field_name); + char *cores = xstrdup (xcores); + char *p = cores; - if (argc > 0 && strcmp (argv[0], "--available") == 0) - { - ++argv; - --argc; - available = 1; - } + make_cleanup (xfree, cores); - if (argc > 0) - id = argv[0]; + for (p = strtok (p, ","); p; p = strtok (NULL, ",")) + ui_out_field_string (uiout, NULL, p); - back_to = make_cleanup (null_cleanup, NULL); + do_cleanups (back_to); +} - if (available && id) - { - error (_("Can only report top-level available thread groups")); - } - else if (available) - { - struct osdata *data; - struct osdata_item *item; - int ix_items; +static void +free_vector_of_ints (void *xvector) +{ + VEC (int) **vector = xvector; + VEC_free (int, *vector); +} - data = get_osdata ("processes"); - make_cleanup_osdata_free (data); +static void +do_nothing (splay_tree_key k) +{ +} - make_cleanup_ui_out_list_begin_end (uiout, "groups"); +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, data->items, + VEC_iterate (osdata_item_s, threads->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"); + 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; + - 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); + back_to = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); - do_cleanups (back_to); + 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); } - else if (id) +} + +void +mi_cmd_list_thread_groups (char *command, char **argv, int argc) +{ + struct cleanup *back_to; + int available = 0; + int recurse = 0; + VEC (int) *ids = 0; + + enum opt { - int pid = atoi (id); + AVAILABLE_OPT, RECURSE_OPT + }; + static struct mi_opt opts[] = + { + {"-available", AVAILABLE_OPT, 0}, + {"-recurse", RECURSE_OPT, 1}, + { 0, 0, 0 } + }; + + int optind = 0; + char *optarg; + + while (1) + { + 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; + break; + case RECURSE_OPT: + 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; + } + } + + for (; optind < argc; ++optind) + { + char *end; + int inf = strtoul (argv[optind], &end, 0); + if (*end != '\0') + error ("invalid group id '%s'", argv[optind]); + VEC_safe_push (int, ids, inf); + } + if (VEC_length (int, ids) > 1) + qsort (VEC_address (int, ids), + VEC_length (int, ids), + sizeof (int), compare_positive_ints); + + back_to = make_cleanup (free_vector_of_ints, &ids); + + if (available) + { + list_available_thread_groups (ids, recurse); + } + else if (VEC_length (int, ids) == 1) + { + /* Local thread groups, single id. */ + int pid = *VEC_address (int, ids); if (!in_inferior_list (pid)) - error ("Invalid thread group id '%s'", id); - print_thread_info (uiout, -1, pid); + error ("Invalid thread group id '%d'", pid); + print_thread_info (uiout, -1, pid); } else { + struct print_one_inferior_data data; + data.recurse = recurse; + data.inferiors = ids; + + /* 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"); - iterate_over_inferiors (print_one_inferior, NULL); + update_thread_list (); + iterate_over_inferiors (print_one_inferior, &data); } - + do_cleanups (back_to); } |