X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fmi%2Fmi-main.c;h=b016436f6f510a159abbf5151845f247de416456;hb=f197e0f1b1c70895aae1395b96d780379ec695ab;hp=13d69285f57d2d3b76b00af7000b9caa23196d72;hpb=a42616899b4f89a1bc1177c8edb27e890af40a82;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c index 13d69285f5..b016436f6f 100644 --- a/gdb/mi/mi-main.c +++ b/gdb/mi/mi-main.c @@ -1,6 +1,6 @@ /* MI Command Set. - Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009 + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. Contributed by Cygnus Solutions (a Red Hat company). @@ -23,6 +23,7 @@ /* Work in progress. */ #include "defs.h" +#include "arch-utils.h" #include "target.h" #include "inferior.h" #include "gdb_string.h" @@ -49,6 +50,8 @@ #include "valprint.h" #include "inferior.h" #include "osdata.h" +#include "splay-tree.h" +#include "tracepoint.h" #include #include @@ -76,6 +79,11 @@ static struct mi_timestamp *current_command_ts; static int do_timings = 0; char *current_token; +/* Few commands would like to know if options like --thread-group + were explicitly specified. This variable keeps the current + parsed command including all option, and make it possible. */ +static struct mi_parse *current_context; + int running_result_record_printed = 1; /* Flag indicating that the target has proceeded since the last @@ -91,7 +99,7 @@ static void mi_execute_async_cli_command (char *cli_command, char **argv, int argc); static int register_changed_p (int regnum, struct regcache *, struct regcache *); -static void get_register (int regnum, int format); +static void get_register (struct frame_info *, int regnum, int format); /* Command implementations. FIXME: Is this libgdb? No. This is the MI layer that calls libgdb. Any operation used in the below should be @@ -110,6 +118,7 @@ mi_cmd_gdb_exit (char *command, char **argv, int argc) fputs_unfiltered (current_token, raw_stdout); fputs_unfiltered ("^exit\n", raw_stdout); mi_out_put (uiout, raw_stdout); + gdb_flush (raw_stdout); /* FIXME: The function called is not yet a formal libgdb function. */ quit_force (NULL, FROM_TTY); } @@ -118,35 +127,50 @@ void mi_cmd_exec_next (char *command, char **argv, int argc) { /* FIXME: Should call a libgdb function, not a cli wrapper. */ - mi_execute_async_cli_command ("next", argv, argc); + if (argc > 0 && strcmp(argv[0], "--reverse") == 0) + mi_execute_async_cli_command ("reverse-next", argv + 1, argc - 1); + else + mi_execute_async_cli_command ("next", argv, argc); } void mi_cmd_exec_next_instruction (char *command, char **argv, int argc) { /* FIXME: Should call a libgdb function, not a cli wrapper. */ - mi_execute_async_cli_command ("nexti", argv, argc); + if (argc > 0 && strcmp(argv[0], "--reverse") == 0) + mi_execute_async_cli_command ("reverse-nexti", argv + 1, argc - 1); + else + mi_execute_async_cli_command ("nexti", argv, argc); } void mi_cmd_exec_step (char *command, char **argv, int argc) { /* FIXME: Should call a libgdb function, not a cli wrapper. */ - mi_execute_async_cli_command ("step", argv, argc); + if (argc > 0 && strcmp(argv[0], "--reverse") == 0) + mi_execute_async_cli_command ("reverse-step", argv + 1, argc - 1); + else + mi_execute_async_cli_command ("step", argv, argc); } void mi_cmd_exec_step_instruction (char *command, char **argv, int argc) { /* FIXME: Should call a libgdb function, not a cli wrapper. */ - mi_execute_async_cli_command ("stepi", argv, argc); + if (argc > 0 && strcmp(argv[0], "--reverse") == 0) + mi_execute_async_cli_command ("reverse-stepi", argv + 1, argc - 1); + else + mi_execute_async_cli_command ("stepi", argv, argc); } void mi_cmd_exec_finish (char *command, char **argv, int argc) { /* FIXME: Should call a libgdb function, not a cli wrapper. */ - mi_execute_async_cli_command ("finish", argv, argc); + if (argc > 0 && strcmp(argv[0], "--reverse") == 0) + mi_execute_async_cli_command ("reverse-finish", argv + 1, argc - 1); + else + mi_execute_async_cli_command ("finish", argv, argc); } void @@ -172,49 +196,113 @@ void mi_cmd_exec_jump (char *args, char **argv, int argc) { /* FIXME: Should call a libgdb function, not a cli wrapper. */ - return mi_execute_async_cli_command ("jump", argv, argc); + mi_execute_async_cli_command ("jump", argv, argc); } -static int -proceed_thread_callback (struct thread_info *thread, void *arg) +static void +proceed_thread (struct thread_info *thread, int pid) { - int pid = *(int *)arg; - if (!is_stopped (thread->ptid)) - return 0; + return; - if (PIDGET (thread->ptid) != pid) - return 0; + if (pid != 0 && PIDGET (thread->ptid) != pid) + return; switch_to_thread (thread->ptid); clear_proceed_status (); proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0); +} + + +static int +proceed_thread_callback (struct thread_info *thread, void *arg) +{ + int pid = *(int *)arg; + proceed_thread (thread, pid); return 0; } -void -mi_cmd_exec_continue (char *command, char **argv, int argc) +static void +exec_continue (char **argv, int argc) { - if (argc == 0) - continue_1 (0); - else if (argc == 1 && strcmp (argv[0], "--all") == 0) - continue_1 (1); - else if (argc == 2 && strcmp (argv[0], "--thread-group") == 0) + if (non_stop) { - struct cleanup *old_chain; - int pid; - if (argv[1] == NULL || argv[1] == '\0') - error ("Thread group id not specified"); - pid = atoi (argv[1]); - if (!in_inferior_list (pid)) - error ("Invalid thread group id '%s'", argv[1]); + /* In non-stop mode, 'resume' always resumes a single thread. Therefore, + to resume all threads of the current inferior, or all threads in all + inferiors, we need to iterate over threads. - old_chain = make_cleanup_restore_current_thread (); - iterate_over_threads (proceed_thread_callback, &pid); - do_cleanups (old_chain); + See comment on infcmd.c:proceed_thread_callback for rationale. */ + if (current_context->all || current_context->thread_group != -1) + { + int pid = 0; + struct cleanup *back_to = make_cleanup_restore_current_thread (); + + if (!current_context->all) + { + struct inferior *inf = find_inferior_id (current_context->thread_group); + pid = inf->pid; + } + iterate_over_threads (proceed_thread_callback, &pid); + do_cleanups (back_to); + } + else + { + continue_1 (0); + } + } + else + { + struct cleanup *back_to = make_cleanup_restore_integer (&sched_multi); + if (current_context->all) + { + sched_multi = 1; + continue_1 (0); + } + else + { + /* In all-stop mode, -exec-continue traditionally resumed either + all threads, or one thread, depending on the 'scheduler-locking' + variable. Let's continue to do the same. */ + continue_1 (1); + } + do_cleanups (back_to); } +} + +static void +exec_direction_forward (void *notused) +{ + execution_direction = EXEC_FORWARD; +} + +static void +exec_reverse_continue (char **argv, int argc) +{ + enum exec_direction_kind dir = execution_direction; + struct cleanup *old_chain; + + if (dir == EXEC_ERROR) + error (_("Target %s does not support this command."), target_shortname); + + if (dir == EXEC_REVERSE) + error (_("Already in reverse mode.")); + + if (!target_can_execute_reverse) + error (_("Target %s does not support this command."), target_shortname); + + old_chain = make_cleanup (exec_direction_forward, NULL); + execution_direction = EXEC_REVERSE; + exec_continue (argv, argc); + do_cleanups (old_chain); +} + +void +mi_cmd_exec_continue (char *command, char **argv, int argc) +{ + if (argc > 0 && strcmp (argv[0], "--reverse") == 0) + exec_reverse_continue (argv + 1, argc - 1); else - error ("Usage: -exec-continue [--all|--thread-group id]"); + exec_continue (argv, argc); } static int @@ -240,38 +328,79 @@ interrupt_thread_callback (struct thread_info *thread, void *arg) void mi_cmd_exec_interrupt (char *command, char **argv, int argc) { - if (argc == 0) + /* In all-stop mode, everything stops, so we don't need to try + anything specific. */ + if (!non_stop) { - if (!is_running (inferior_ptid)) - error ("Current thread is not running."); - interrupt_target_1 (0); + return; } - else if (argc == 1 && strcmp (argv[0], "--all") == 0) + + if (current_context->all) { - if (!any_running ()) - error ("Inferior not running."); - + /* This will interrupt all threads in all inferiors. */ interrupt_target_1 (1); } - else if (argc == 2 && strcmp (argv[0], "--thread-group") == 0) + else if (current_context->thread_group != -1) { - struct cleanup *old_chain; - int pid; - if (argv[1] == NULL || argv[1] == '\0') - error ("Thread group id not specified"); - pid = atoi (argv[1]); - if (!in_inferior_list (pid)) - error ("Invalid thread group id '%s'", argv[1]); + struct inferior *inf = find_inferior_id (current_context->thread_group); + iterate_over_threads (interrupt_thread_callback, &inf->pid); + } + else + { + /* Interrupt just the current thread -- either explicitly + specified via --thread or whatever was current before + MI command was sent. */ + interrupt_target_1 (0); + } +} + +static int +run_one_inferior (struct inferior *inf, void *arg) +{ + struct thread_info *tp = 0; + + if (inf->pid != 0) + { + if (inf->pid != ptid_get_pid (inferior_ptid)) + { + struct thread_info *tp; + + tp = any_thread_of_process (inf->pid); + if (!tp) + error (_("Inferior has no threads.")); - old_chain = make_cleanup_restore_current_thread (); - iterate_over_threads (interrupt_thread_callback, &pid); - do_cleanups (old_chain); + switch_to_thread (tp->ptid); + } } else - error ("Usage: -exec-interrupt [--all|--thread-group id]"); + { + set_current_inferior (inf); + switch_to_thread (null_ptid); + set_current_program_space (inf->pspace); + } + mi_execute_cli_command ("run", target_can_async_p (), + target_can_async_p () ? "&" : NULL); + return 0; } +void +mi_cmd_exec_run (char *command, char **argv, int argc) +{ + if (current_context->all) + { + struct cleanup *back_to = save_current_space_and_thread (); + iterate_over_inferiors (run_one_inferior, NULL); + do_cleanups (back_to); + } + else + { + mi_execute_cli_command ("run", target_can_async_p (), + target_can_async_p () ? "&" : NULL); + } +} + + static int find_thread_of_process (struct thread_info *ti, void *p) { @@ -358,94 +487,373 @@ 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 -print_one_inferior (struct inferior *inferior, void *arg) +collect_cores (struct thread_info *ti, void *xdata) { - struct cleanup *back_to = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); + 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); + } - ui_out_field_fmt (uiout, "id", "%d", inferior->pid); - ui_out_field_string (uiout, "type", "process"); - ui_out_field_int (uiout, "pid", inferior->pid); - - do_cleanups (back_to); return 0; } -void -mi_cmd_list_thread_groups (char *command, char **argv, int argc) +static int * +unique (int *b, int *e) { - struct cleanup *back_to; - int available = 0; - char *id = NULL; + 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 *xdata) +{ + struct print_one_inferior_data *top_data = xdata; - if (argc > 0 && strcmp (argv[0], "--available") == 0) + 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)) { - ++argv; - --argc; - available = 1; - } + struct collect_cores_data data; + struct cleanup *back_to + = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); - if (argc > 0) - id = argv[0]; + ui_out_field_fmt (uiout, "id", "i%d", inferior->num); + ui_out_field_string (uiout, "type", "process"); + if (inferior->pid != 0) + ui_out_field_int (uiout, "pid", inferior->pid); - back_to = make_cleanup (null_cleanup, NULL); + if (inferior->pspace->ebfd) + { + ui_out_field_string (uiout, "executable", + bfd_get_filename (inferior->pspace->ebfd)); + } - if (available && id) - { - error (_("Can only report top-level available thread groups")); + data.cores = 0; + if (inferior->pid != 0) + { + data.pid = inferior->pid; + 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); } - else if (available) - { - struct osdata *data; - struct osdata_item *item; - int ix_items; - data = get_osdata ("processes"); - make_cleanup_osdata_free (data); + return 0; +} - make_cleanup_ui_out_list_begin_end (uiout, "groups"); +/* 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, + field_name); + char *cores = xstrdup (xcores); + char *p = cores; + + make_cleanup (xfree, cores); + + 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. + This is assigned an initial value to avoid "may be used uninitialized" + warning from gcc. */ + splay_tree tree = NULL; + + /* 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; - 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); + 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; + } + } + } - do_cleanups (back_to); + 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); } - 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); } void mi_cmd_data_list_register_names (char *command, char **argv, int argc) { + struct gdbarch *gdbarch; int regnum, numregs; int i; struct cleanup *cleanup; @@ -456,8 +864,8 @@ mi_cmd_data_list_register_names (char *command, char **argv, int argc) In this case, some entries of gdbarch_register_name will change depending upon the particular processor being debugged. */ - numregs = gdbarch_num_regs (current_gdbarch) - + gdbarch_num_pseudo_regs (current_gdbarch); + gdbarch = get_current_arch (); + numregs = gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch); cleanup = make_cleanup_ui_out_list_begin_end (uiout, "register-names"); @@ -467,13 +875,12 @@ mi_cmd_data_list_register_names (char *command, char **argv, int argc) regnum < numregs; regnum++) { - if (gdbarch_register_name (current_gdbarch, regnum) == NULL - || *(gdbarch_register_name (current_gdbarch, regnum)) == '\0') + if (gdbarch_register_name (gdbarch, regnum) == NULL + || *(gdbarch_register_name (gdbarch, regnum)) == '\0') ui_out_field_string (uiout, NULL, ""); else ui_out_field_string (uiout, NULL, - gdbarch_register_name - (current_gdbarch, regnum)); + gdbarch_register_name (gdbarch, regnum)); } } @@ -484,12 +891,12 @@ mi_cmd_data_list_register_names (char *command, char **argv, int argc) if (regnum < 0 || regnum >= numregs) error ("bad register number"); - if (gdbarch_register_name (current_gdbarch, regnum) == NULL - || *(gdbarch_register_name (current_gdbarch, regnum)) == '\0') + if (gdbarch_register_name (gdbarch, regnum) == NULL + || *(gdbarch_register_name (gdbarch, regnum)) == '\0') ui_out_field_string (uiout, NULL, ""); else ui_out_field_string (uiout, NULL, - gdbarch_register_name (current_gdbarch, regnum)); + gdbarch_register_name (gdbarch, regnum)); } do_cleanups (cleanup); } @@ -499,6 +906,7 @@ mi_cmd_data_list_changed_registers (char *command, char **argv, int argc) { static struct regcache *this_regs = NULL; struct regcache *prev_regs; + struct gdbarch *gdbarch; int regnum, numregs, changed; int i; struct cleanup *cleanup; @@ -517,8 +925,8 @@ mi_cmd_data_list_changed_registers (char *command, char **argv, int argc) In this case, some entries of gdbarch_register_name will change depending upon the particular processor being debugged. */ - numregs = gdbarch_num_regs (current_gdbarch) - + gdbarch_num_pseudo_regs (current_gdbarch); + gdbarch = get_regcache_arch (this_regs); + numregs = gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch); make_cleanup_ui_out_list_begin_end (uiout, "changed-registers"); @@ -528,8 +936,8 @@ mi_cmd_data_list_changed_registers (char *command, char **argv, int argc) regnum < numregs; regnum++) { - if (gdbarch_register_name (current_gdbarch, regnum) == NULL - || *(gdbarch_register_name (current_gdbarch, regnum)) == '\0') + if (gdbarch_register_name (gdbarch, regnum) == NULL + || *(gdbarch_register_name (gdbarch, regnum)) == '\0') continue; changed = register_changed_p (regnum, prev_regs, this_regs); if (changed < 0) @@ -546,8 +954,8 @@ mi_cmd_data_list_changed_registers (char *command, char **argv, int argc) if (regnum >= 0 && regnum < numregs - && gdbarch_register_name (current_gdbarch, regnum) != NULL - && *gdbarch_register_name (current_gdbarch, regnum) != '\000') + && gdbarch_register_name (gdbarch, regnum) != NULL + && *gdbarch_register_name (gdbarch, regnum) != '\000') { changed = register_changed_p (regnum, prev_regs, this_regs); if (changed < 0) @@ -597,6 +1005,8 @@ register_changed_p (int regnum, struct regcache *prev_regs, void mi_cmd_data_list_register_values (char *command, char **argv, int argc) { + struct frame_info *frame; + struct gdbarch *gdbarch; int regnum, numregs, format; int i; struct cleanup *list_cleanup, *tuple_cleanup; @@ -607,14 +1017,15 @@ mi_cmd_data_list_register_values (char *command, char **argv, int argc) In this case, some entries of gdbarch_register_name will change depending upon the particular processor being debugged. */ - numregs = gdbarch_num_regs (current_gdbarch) - + gdbarch_num_pseudo_regs (current_gdbarch); - if (argc == 0) error ("mi_cmd_data_list_register_values: Usage: -data-list-register-values [...]"); format = (int) argv[0][0]; + frame = get_selected_frame (NULL); + gdbarch = get_frame_arch (frame); + numregs = gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch); + list_cleanup = make_cleanup_ui_out_list_begin_end (uiout, "register-values"); if (argc == 1) /* No args, beside the format: do all the regs. */ @@ -623,12 +1034,12 @@ mi_cmd_data_list_register_values (char *command, char **argv, int argc) regnum < numregs; regnum++) { - if (gdbarch_register_name (current_gdbarch, regnum) == NULL - || *(gdbarch_register_name (current_gdbarch, regnum)) == '\0') + if (gdbarch_register_name (gdbarch, regnum) == NULL + || *(gdbarch_register_name (gdbarch, regnum)) == '\0') continue; tuple_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); ui_out_field_int (uiout, "number", regnum); - get_register (regnum, format); + get_register (frame, regnum, format); do_cleanups (tuple_cleanup); } } @@ -640,12 +1051,12 @@ mi_cmd_data_list_register_values (char *command, char **argv, int argc) if (regnum >= 0 && regnum < numregs - && gdbarch_register_name (current_gdbarch, regnum) != NULL - && *gdbarch_register_name (current_gdbarch, regnum) != '\000') + && gdbarch_register_name (gdbarch, regnum) != NULL + && *gdbarch_register_name (gdbarch, regnum) != '\000') { tuple_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); ui_out_field_int (uiout, "number", regnum); - get_register (regnum, format); + get_register (frame, regnum, format); do_cleanups (tuple_cleanup); } else @@ -656,8 +1067,9 @@ mi_cmd_data_list_register_values (char *command, char **argv, int argc) /* Output one register's contents in the desired format. */ static void -get_register (int regnum, int format) +get_register (struct frame_info *frame, int regnum, int format) { + struct gdbarch *gdbarch = get_frame_arch (frame); gdb_byte buffer[MAX_REGISTER_SIZE]; int optim; int realnum; @@ -670,8 +1082,7 @@ get_register (int regnum, int format) if (format == 'N') format = 0; - frame_register (get_selected_frame (NULL), regnum, &optim, &lval, &addr, - &realnum, buffer); + frame_register (frame, regnum, &optim, &lval, &addr, &realnum, buffer); if (optim) error ("Optimized out"); @@ -683,10 +1094,10 @@ get_register (int regnum, int format) strcpy (buf, "0x"); ptr = buf + 2; - for (j = 0; j < register_size (current_gdbarch, regnum); j++) + for (j = 0; j < register_size (gdbarch, regnum); j++) { - int idx = gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG ? j - : register_size (current_gdbarch, regnum) - 1 - j; + int idx = gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG ? + j : register_size (gdbarch, regnum) - 1 - j; sprintf (ptr, "%02x", (unsigned char) buffer[idx]); ptr += 2; } @@ -698,7 +1109,7 @@ get_register (int regnum, int format) struct value_print_options opts; get_formatted_print_options (&opts, format); opts.deref_ref = 1; - val_print (register_type (current_gdbarch, regnum), buffer, 0, 0, + val_print (register_type (gdbarch, regnum), buffer, 0, 0, stb->stream, 0, &opts, current_language); ui_out_field_stream (uiout, "value", stb); ui_out_stream_delete (stb); @@ -711,6 +1122,8 @@ get_register (int regnum, int format) void mi_cmd_data_write_register_values (char *command, char **argv, int argc) { + struct regcache *regcache; + struct gdbarch *gdbarch; int numregs, i; char format; @@ -720,8 +1133,9 @@ mi_cmd_data_write_register_values (char *command, char **argv, int argc) In this case, some entries of gdbarch_register_name will change depending upon the particular processor being debugged. */ - numregs = gdbarch_num_regs (current_gdbarch) - + gdbarch_num_pseudo_regs (current_gdbarch); + regcache = get_current_regcache (); + gdbarch = get_regcache_arch (regcache); + numregs = gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch); if (argc == 0) error ("mi_cmd_data_write_register_values: Usage: -data-write-register-values [ ... ]"); @@ -742,8 +1156,8 @@ mi_cmd_data_write_register_values (char *command, char **argv, int argc) int regnum = atoi (argv[i]); if (regnum >= 0 && regnum < numregs - && gdbarch_register_name (current_gdbarch, regnum) - && *gdbarch_register_name (current_gdbarch, regnum)) + && gdbarch_register_name (gdbarch, regnum) + && *gdbarch_register_name (gdbarch, regnum)) { LONGEST value; @@ -751,7 +1165,7 @@ mi_cmd_data_write_register_values (char *command, char **argv, int argc) value = parse_and_eval_address (argv[i + 1]); /* Write it down. */ - regcache_cooked_write_signed (get_current_regcache (), regnum, value); + regcache_cooked_write_signed (regcache, regnum, value); } else error ("bad register number"); @@ -819,6 +1233,7 @@ mi_cmd_data_evaluate_expression (char *command, char **argv, int argc) void mi_cmd_data_read_memory (char *command, char **argv, int argc) { + struct gdbarch *gdbarch = get_current_arch (); struct cleanup *cleanups = make_cleanup (null_cleanup, NULL); CORE_ADDR addr; long total_bytes; @@ -875,23 +1290,23 @@ mi_cmd_data_read_memory (char *command, char **argv, int argc) switch (word_size) { case 1: - word_type = builtin_type_int8; + word_type = builtin_type (gdbarch)->builtin_int8; word_asize = 'b'; break; case 2: - word_type = builtin_type_int16; + word_type = builtin_type (gdbarch)->builtin_int16; word_asize = 'h'; break; case 4: - word_type = builtin_type_int32; + word_type = builtin_type (gdbarch)->builtin_int32; word_asize = 'w'; break; case 8: - word_type = builtin_type_int64; + word_type = builtin_type (gdbarch)->builtin_int64; word_asize = 'g'; break; default: - word_type = builtin_type_int8; + word_type = builtin_type (gdbarch)->builtin_int8; word_asize = 'b'; } /* The number of rows. */ @@ -924,13 +1339,15 @@ mi_cmd_data_read_memory (char *command, char **argv, int argc) error ("Unable to read memory."); /* Output the header information. */ - ui_out_field_core_addr (uiout, "addr", addr); + ui_out_field_core_addr (uiout, "addr", gdbarch, addr); ui_out_field_int (uiout, "nr-bytes", nr_bytes); ui_out_field_int (uiout, "total-bytes", total_bytes); - ui_out_field_core_addr (uiout, "next-row", addr + word_size * nr_cols); - ui_out_field_core_addr (uiout, "prev-row", addr - word_size * nr_cols); - ui_out_field_core_addr (uiout, "next-page", addr + total_bytes); - ui_out_field_core_addr (uiout, "prev-page", addr - total_bytes); + ui_out_field_core_addr (uiout, "next-row", + gdbarch, addr + word_size * nr_cols); + ui_out_field_core_addr (uiout, "prev-row", + gdbarch, addr - word_size * nr_cols); + ui_out_field_core_addr (uiout, "next-page", gdbarch, addr + total_bytes); + ui_out_field_core_addr (uiout, "prev-page", gdbarch, addr - total_bytes); /* Build the result as a two dimentional table. */ { @@ -950,7 +1367,7 @@ mi_cmd_data_read_memory (char *command, char **argv, int argc) struct value_print_options opts; cleanup_tuple = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); - ui_out_field_core_addr (uiout, "addr", addr + row_byte); + ui_out_field_core_addr (uiout, "addr", gdbarch, addr + row_byte); /* ui_out_field_core_addr_symbolic (uiout, "saddr", addr + row_byte); */ cleanup_list_data = make_cleanup_ui_out_list_begin_end (uiout, "data"); get_formatted_print_options (&opts, word_format); @@ -1017,6 +1434,8 @@ mi_cmd_data_read_memory (char *command, char **argv, int argc) void mi_cmd_data_write_memory (char *command, char **argv, int argc) { + struct gdbarch *gdbarch = get_current_arch (); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); CORE_ADDR addr; char word_format; long word_size; @@ -1074,7 +1493,7 @@ mi_cmd_data_write_memory (char *command, char **argv, int argc) /* Get the value into an array. */ buffer = xmalloc (word_size); old_chain = make_cleanup (xfree, buffer); - store_signed_integer (buffer, word_size, value); + store_signed_integer (buffer, word_size, byte_order, value); /* Write it down to memory. */ write_memory (addr, buffer, word_size); /* Free the buffer. */ @@ -1145,6 +1564,40 @@ mi_cmd_list_target_features (char *command, char **argv, int argc) error ("-list-target-features should be passed no arguments"); } +void +mi_cmd_add_inferior (char *command, char **argv, int argc) +{ + struct inferior *inf; + + if (argc != 0) + error (_("-add-inferior should be passed no arguments")); + + inf = add_inferior_with_spaces (); + + ui_out_field_fmt (uiout, "inferior", "i%d", inf->num); +} + +void +mi_cmd_remove_inferior (char *command, char **argv, int argc) +{ + int id; + struct inferior *inf; + + if (argc != 1) + error ("-remove-inferior should be passed a single argument"); + + if (sscanf (argv[1], "i%d", &id) != 1) + error ("the thread group id is syntactically invalid"); + + inf = find_inferior_id (id); + if (!inf) + error ("the specified thread group does not exist"); + + delete_inferior_1 (inf, 1 /* silent */); +} + + + /* Execute a command within a safe environment. Return <0 for error; >=0 for ok. @@ -1256,6 +1709,8 @@ mi_execute_command (char *cmd, int from_tty) if (cmd == 0) quit_force (NULL, from_tty); + target_log_command (cmd); + command = mi_parse (cmd); if (command != NULL) @@ -1286,6 +1741,8 @@ mi_execute_command (char *cmd, int from_tty) mi_out_rewind (uiout); } + bpstat_do_actions (); + if (/* The notifications are only output when the top-level interpreter (specified on the command line) is MI. */ ui_out_is_mi_like_p (interp_ui_out (top_level_interpreter ())) @@ -1338,12 +1795,41 @@ mi_cmd_execute (struct mi_parse *parse) struct cleanup *cleanup; int i; - free_all_values (); + prepare_execute_command (); + cleanup = make_cleanup (null_cleanup, NULL); + if (parse->all && parse->thread_group != -1) + error (_("Cannot specify --thread-group together with --all")); + + if (parse->all && parse->thread != -1) + error (_("Cannot specify --thread together with --all")); + + if (parse->thread_group != -1 && parse->thread != -1) + error (_("Cannot specify --thread together with --thread-group")); + if (parse->frame != -1 && parse->thread == -1) error (_("Cannot specify --frame without --thread")); + if (parse->thread_group != -1) + { + struct inferior *inf = find_inferior_id (parse->thread_group); + struct thread_info *tp = 0; + + if (!inf) + error (_("Invalid thread group for the --thread-group option")); + + set_current_inferior (inf); + /* This behaviour means that if --thread-group option identifies + an inferior with multiple threads, then a random one will be picked. + This is not a problem -- frontend should always provide --thread if + it wishes to operate on a specific thread. */ + if (inf->pid != 0) + tp = any_thread_of_process (inf->pid); + switch_to_thread (tp ? tp->ptid : null_ptid); + set_current_program_space (inf->pspace); + } + if (parse->thread != -1) { struct thread_info *tp = find_thread_id (parse->thread); @@ -1368,6 +1854,8 @@ mi_cmd_execute (struct mi_parse *parse) error (_("Invalid frame id: %d"), frame); } + current_context = parse; + if (parse->cmd->argv_func != NULL) parse->cmd->argv_func (parse->command, parse->argv, parse->argc); else if (parse->cmd->cli.cmd != 0) @@ -1590,3 +2078,153 @@ print_diff (struct mi_timestamp *start, struct mi_timestamp *end) timeval_diff (start->utime, end->utime) / 1000000.0, timeval_diff (start->stime, end->stime) / 1000000.0); } + +void +mi_cmd_trace_define_variable (char *command, char **argv, int argc) +{ + struct expression *expr; + struct cleanup *back_to; + LONGEST initval = 0; + struct trace_state_variable *tsv; + char *name = 0; + + if (argc != 1 && argc != 2) + error (_("Usage: -trace-define-variable VARIABLE [VALUE]")); + + expr = parse_expression (argv[0]); + back_to = make_cleanup (xfree, expr); + + if (expr->nelts == 3 && expr->elts[0].opcode == OP_INTERNALVAR) + { + struct internalvar *intvar = expr->elts[1].internalvar; + if (intvar) + name = internalvar_name (intvar); + } + + if (!name || *name == '\0') + error (_("Invalid name of trace variable")); + + tsv = find_trace_state_variable (name); + if (!tsv) + tsv = create_trace_state_variable (name); + + if (argc == 2) + initval = value_as_long (parse_and_eval (argv[1])); + + tsv->initial_value = initval; + + do_cleanups (back_to); +} + +void +mi_cmd_trace_list_variables (char *command, char **argv, int argc) +{ + if (argc != 0) + error (_("-trace-list-variables: no arguments are allowed")); + + tvariables_info_1 (); +} + +void +mi_cmd_trace_find (char *command, char **argv, int argc) +{ + char *mode; + + if (argc == 0) + error (_("trace selection mode is required")); + + mode = argv[0]; + + if (strcmp (mode, "none") == 0) + { + tfind_1 (tfind_number, -1, 0, 0, 0); + return; + } + + if (current_trace_status ()->running) + error (_("May not look at trace frames while trace is running.")); + + if (strcmp (mode, "frame-number") == 0) + { + if (argc != 2) + error (_("frame number is required")); + tfind_1 (tfind_number, atoi (argv[1]), 0, 0, 0); + } + else if (strcmp (mode, "tracepoint-number") == 0) + { + if (argc != 2) + error (_("tracepoint number is required")); + tfind_1 (tfind_tp, atoi (argv[1]), 0, 0, 0); + } + else if (strcmp (mode, "pc") == 0) + { + if (argc != 2) + error (_("PC is required")); + tfind_1 (tfind_pc, 0, parse_and_eval_address (argv[1]), 0, 0); + } + else if (strcmp (mode, "pc-inside-range") == 0) + { + if (argc != 3) + error (_("Start and end PC are required")); + tfind_1 (tfind_range, 0, parse_and_eval_address (argv[1]), + parse_and_eval_address (argv[2]), 0); + } + else if (strcmp (mode, "pc-outside-range") == 0) + { + if (argc != 3) + error (_("Start and end PC are required")); + tfind_1 (tfind_outside, 0, parse_and_eval_address (argv[1]), + parse_and_eval_address (argv[2]), 0); + } + else if (strcmp (mode, "line") == 0) + { + struct symtabs_and_lines sals; + struct symtab_and_line sal; + static CORE_ADDR start_pc, end_pc; + struct cleanup *back_to; + + if (argc != 2) + error (_("Line is required")); + + sals = decode_line_spec (argv[1], 1); + back_to = make_cleanup (xfree, sals.sals); + + sal = sals.sals[0]; + + if (sal.symtab == 0) + error (_("Could not find the specified line")); + + if (sal.line > 0 && find_line_pc_range (sal, &start_pc, &end_pc)) + tfind_1 (tfind_range, 0, start_pc, end_pc - 1, 0); + else + error (_("Could not find the specified line")); + + do_cleanups (back_to); + } + else + error (_("Invalid mode '%s'"), mode); + + if (has_stack_frames () || get_traceframe_number () >= 0) + { + print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC); + } +} + +void +mi_cmd_trace_start (char *command, char **argv, int argc) +{ + start_tracing (); +} + +void +mi_cmd_trace_status (char *command, char **argv, int argc) +{ + trace_status_mi (0); +} + +void +mi_cmd_trace_stop (char *command, char **argv, int argc) +{ + stop_tracing (); + trace_status_mi (1); +}