Index: gdb/mi/mi-main.c |
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c |
index dfb489243cbe4a569e43a6f2f8681494bbac76da..63456cd443aa2bb04965764ba38f2fe2d25d3278 100644 |
--- a/gdb/mi/mi-main.c |
+++ b/gdb/mi/mi-main.c |
@@ -1,6 +1,6 @@ |
/* MI Command Set. |
- Copyright (C) 2000-2005, 2007-2012 Free Software Foundation, Inc. |
+ Copyright (C) 2000-2013 Free Software Foundation, Inc. |
Contributed by Cygnus Solutions (a Red Hat company). |
@@ -23,7 +23,7 @@ |
#include "arch-utils.h" |
#include "target.h" |
#include "inferior.h" |
-#include "gdb_string.h" |
+#include <string.h> |
#include "exceptions.h" |
#include "top.h" |
#include "gdbthread.h" |
@@ -49,8 +49,12 @@ |
#include "osdata.h" |
#include "splay-tree.h" |
#include "tracepoint.h" |
+#include "ctf.h" |
#include "ada-lang.h" |
#include "linespec.h" |
+#ifdef HAVE_PYTHON |
+#include "python/python-internal.h" |
+#endif |
#include <ctype.h> |
#include <sys/time.h> |
@@ -95,11 +99,12 @@ static void mi_cmd_execute (struct mi_parse *parse); |
static void mi_execute_cli_command (const char *cmd, int args_p, |
const char *args); |
-static void mi_execute_async_cli_command (char *cli_command, |
+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 (struct frame_info *, int regnum, int format); |
+static void output_register (struct frame_info *, int regnum, int format, |
+ int skip_unavailable); |
/* Command implementations. FIXME: Is this libgdb? No. This is the MI |
layer that calls libgdb. Any operation used in the below should be |
@@ -189,7 +194,7 @@ mi_cmd_exec_return (char *command, char **argv, int argc) |
/* Because we have called return_command with from_tty = 0, we need |
to print the frame here. */ |
- print_stack_frame (get_selected_frame (NULL), 1, LOC_AND_ADDRESS); |
+ print_stack_frame (get_selected_frame (NULL), 1, LOC_AND_ADDRESS, 1); |
} |
void |
@@ -198,14 +203,14 @@ mi_cmd_exec_jump (char *args, char **argv, int argc) |
/* FIXME: Should call a libgdb function, not a cli wrapper. */ |
mi_execute_async_cli_command ("jump", argv, argc); |
} |
- |
+ |
static void |
proceed_thread (struct thread_info *thread, int pid) |
{ |
if (!is_stopped (thread->ptid)) |
return; |
- if (pid != 0 && PIDGET (thread->ptid) != pid) |
+ if (pid != 0 && ptid_get_pid (thread->ptid) != pid) |
return; |
switch_to_thread (thread->ptid); |
@@ -315,7 +320,7 @@ interrupt_thread_callback (struct thread_info *thread, void *arg) |
if (!is_running (thread->ptid)) |
return 0; |
- if (PIDGET (thread->ptid) != pid) |
+ if (ptid_get_pid (thread->ptid) != pid) |
return 0; |
target_stop (thread->ptid); |
@@ -359,9 +364,19 @@ mi_cmd_exec_interrupt (char *command, char **argv, int argc) |
} |
} |
+/* Callback for iterate_over_inferiors which starts the execution |
+ of the given inferior. |
+ |
+ ARG is a pointer to an integer whose value, if non-zero, indicates |
+ that the program should be stopped when reaching the main subprogram |
+ (similar to what the CLI "start" command does). */ |
+ |
static int |
run_one_inferior (struct inferior *inf, void *arg) |
{ |
+ int start_p = *(int *) arg; |
+ const char *run_cmd = start_p ? "start" : "run"; |
+ |
if (inf->pid != 0) |
{ |
if (inf->pid != ptid_get_pid (inferior_ptid)) |
@@ -381,7 +396,7 @@ run_one_inferior (struct inferior *inf, void *arg) |
switch_to_thread (null_ptid); |
set_current_program_space (inf->pspace); |
} |
- mi_execute_cli_command ("run", target_can_async_p (), |
+ mi_execute_cli_command (run_cmd, target_can_async_p (), |
target_can_async_p () ? "&" : NULL); |
return 0; |
} |
@@ -389,16 +404,54 @@ run_one_inferior (struct inferior *inf, void *arg) |
void |
mi_cmd_exec_run (char *command, char **argv, int argc) |
{ |
+ int i; |
+ int start_p = 0; |
+ |
+ /* Parse the command options. */ |
+ enum opt |
+ { |
+ START_OPT, |
+ }; |
+ static const struct mi_opt opts[] = |
+ { |
+ {"-start", START_OPT, 0}, |
+ {NULL, 0, 0}, |
+ }; |
+ |
+ int oind = 0; |
+ char *oarg; |
+ |
+ while (1) |
+ { |
+ int opt = mi_getopt ("-exec-run", argc, argv, opts, &oind, &oarg); |
+ |
+ if (opt < 0) |
+ break; |
+ switch ((enum opt) opt) |
+ { |
+ case START_OPT: |
+ start_p = 1; |
+ break; |
+ } |
+ } |
+ |
+ /* This command does not accept any argument. Make sure the user |
+ did not provide any. */ |
+ if (oind != argc) |
+ error (_("Invalid argument: %s"), argv[oind]); |
+ |
if (current_context->all) |
{ |
struct cleanup *back_to = save_current_space_and_thread (); |
- iterate_over_inferiors (run_one_inferior, NULL); |
+ iterate_over_inferiors (run_one_inferior, &start_p); |
do_cleanups (back_to); |
} |
else |
{ |
- mi_execute_cli_command ("run", target_can_async_p (), |
+ const char *run_cmd = start_p ? "start" : "run"; |
+ |
+ mi_execute_cli_command (run_cmd, target_can_async_p (), |
target_can_async_p () ? "&" : NULL); |
} |
} |
@@ -409,7 +462,7 @@ find_thread_of_process (struct thread_info *ti, void *p) |
{ |
int pid = *(int *)p; |
- if (PIDGET (ti->ptid) == pid && !is_exited (ti->ptid)) |
+ if (ptid_get_pid (ti->ptid) == pid && !is_exited (ti->ptid)) |
return 1; |
return 0; |
@@ -508,8 +561,6 @@ mi_cmd_thread_info (char *command, char **argv, int argc) |
print_thread_info (current_uiout, argv[0], -1); |
} |
-DEF_VEC_I(int); |
- |
struct collect_cores_data |
{ |
int pid; |
@@ -570,10 +621,10 @@ print_one_inferior (struct inferior *inferior, void *xdata) |
if (inferior->pid != 0) |
ui_out_field_int (uiout, "pid", inferior->pid); |
- if (inferior->pspace->ebfd) |
+ if (inferior->pspace->pspace_exec_filename != NULL) |
{ |
ui_out_field_string (uiout, "executable", |
- bfd_get_filename (inferior->pspace->ebfd)); |
+ inferior->pspace->pspace_exec_filename); |
} |
data.cores = 0; |
@@ -677,6 +728,7 @@ list_available_thread_groups (VEC (int) *ids, int recurse) |
struct osdata_item *item; |
int ix_items; |
struct ui_out *uiout = current_uiout; |
+ struct cleanup *cleanup; |
/* This keeps a map from integer (pid) to VEC (struct osdata_item *)* |
The vector contains information about all threads for the given pid. |
@@ -686,7 +738,7 @@ list_available_thread_groups (VEC (int) *ids, int recurse) |
/* get_osdata will throw if it cannot return data. */ |
data = get_osdata ("processes"); |
- make_cleanup_osdata_free (data); |
+ cleanup = make_cleanup_osdata_free (data); |
if (recurse) |
{ |
@@ -789,6 +841,8 @@ list_available_thread_groups (VEC (int) *ids, int recurse) |
do_cleanups (back_to); |
} |
+ |
+ do_cleanups (cleanup); |
} |
void |
@@ -871,7 +925,7 @@ mi_cmd_list_thread_groups (char *command, char **argv, int argc) |
if (!inf) |
error (_("Non-existent thread group id '%d'"), id); |
- |
+ |
print_thread_info (uiout, NULL, inf->pid); |
} |
else |
@@ -1065,7 +1119,18 @@ mi_cmd_data_list_register_values (char *command, char **argv, int argc) |
struct gdbarch *gdbarch; |
int regnum, numregs, format; |
int i; |
- struct cleanup *list_cleanup, *tuple_cleanup; |
+ struct cleanup *list_cleanup; |
+ int skip_unavailable = 0; |
+ int oind = 0; |
+ enum opt |
+ { |
+ SKIP_UNAVAILABLE, |
+ }; |
+ static const struct mi_opt opts[] = |
+ { |
+ {"-skip-unavailable", SKIP_UNAVAILABLE, 0}, |
+ { 0, 0, 0 } |
+ }; |
/* Note that the test for a valid register must include checking the |
gdbarch_register_name because gdbarch_num_regs may be allocated |
@@ -1074,11 +1139,28 @@ mi_cmd_data_list_register_values (char *command, char **argv, int argc) |
will change depending upon the particular processor being |
debugged. */ |
- if (argc == 0) |
+ while (1) |
+ { |
+ char *oarg; |
+ int opt = mi_getopt ("-data-list-register-values", argc, argv, |
+ opts, &oind, &oarg); |
+ |
+ if (opt < 0) |
+ break; |
+ switch ((enum opt) opt) |
+ { |
+ case SKIP_UNAVAILABLE: |
+ skip_unavailable = 1; |
+ break; |
+ } |
+ } |
+ |
+ if (argc - oind < 1) |
error (_("-data-list-register-values: Usage: " |
- "-data-list-register-values <format> [<regnum1>...<regnumN>]")); |
+ "-data-list-register-values [--skip-unavailable] <format>" |
+ " [<regnum1>...<regnumN>]")); |
- format = (int) argv[0][0]; |
+ format = (int) argv[oind][0]; |
frame = get_selected_frame (NULL); |
gdbarch = get_frame_arch (frame); |
@@ -1086,7 +1168,7 @@ mi_cmd_data_list_register_values (char *command, char **argv, int argc) |
list_cleanup = make_cleanup_ui_out_list_begin_end (uiout, "register-values"); |
- if (argc == 1) |
+ if (argc - oind == 1) |
{ |
/* No args, beside the format: do all the regs. */ |
for (regnum = 0; |
@@ -1096,15 +1178,13 @@ mi_cmd_data_list_register_values (char *command, char **argv, int argc) |
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 (frame, regnum, format); |
- do_cleanups (tuple_cleanup); |
+ |
+ output_register (frame, regnum, format, skip_unavailable); |
} |
} |
/* Else, list of register #s, just do listed regs. */ |
- for (i = 1; i < argc; i++) |
+ for (i = 1 + oind; i < argc; i++) |
{ |
regnum = atoi (argv[i]); |
@@ -1112,75 +1192,56 @@ mi_cmd_data_list_register_values (char *command, char **argv, int argc) |
&& regnum < numregs |
&& 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 (frame, regnum, format); |
- do_cleanups (tuple_cleanup); |
- } |
+ output_register (frame, regnum, format, skip_unavailable); |
else |
error (_("bad register number")); |
} |
do_cleanups (list_cleanup); |
} |
-/* Output one register's contents in the desired format. */ |
+/* Output one register REGNUM's contents in the desired FORMAT. If |
+ SKIP_UNAVAILABLE is true, skip the register if it is |
+ unavailable. */ |
static void |
-get_register (struct frame_info *frame, int regnum, int format) |
+output_register (struct frame_info *frame, int regnum, int format, |
+ int skip_unavailable) |
{ |
struct gdbarch *gdbarch = get_frame_arch (frame); |
struct ui_out *uiout = current_uiout; |
- struct value *val; |
+ struct value *val = value_of_register (regnum, frame); |
+ struct cleanup *tuple_cleanup; |
+ struct value_print_options opts; |
+ struct ui_file *stb; |
- if (format == 'N') |
- format = 0; |
+ if (skip_unavailable && !value_entirely_available (val)) |
+ return; |
- val = get_frame_register_value (frame, regnum); |
+ tuple_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); |
+ ui_out_field_int (uiout, "number", regnum); |
- if (value_optimized_out (val)) |
- error (_("Optimized out")); |
+ if (format == 'N') |
+ format = 0; |
if (format == 'r') |
- { |
- int j; |
- char *ptr, buf[1024]; |
- const gdb_byte *valaddr = value_contents_for_printing (val); |
+ format = 'z'; |
- strcpy (buf, "0x"); |
- ptr = buf + 2; |
- for (j = 0; j < register_size (gdbarch, regnum); j++) |
- { |
- int idx = gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG ? |
- j : register_size (gdbarch, regnum) - 1 - j; |
- |
- sprintf (ptr, "%02x", (unsigned char) valaddr[idx]); |
- ptr += 2; |
- } |
- ui_out_field_string (uiout, "value", buf); |
- } |
- else |
- { |
- struct value_print_options opts; |
- struct ui_file *stb; |
- struct cleanup *old_chain; |
- |
- stb = mem_fileopen (); |
- old_chain = make_cleanup_ui_file_delete (stb); |
+ stb = mem_fileopen (); |
+ make_cleanup_ui_file_delete (stb); |
+ |
+ get_formatted_print_options (&opts, format); |
+ opts.deref_ref = 1; |
+ val_print (value_type (val), |
+ value_contents_for_printing (val), |
+ value_embedded_offset (val), 0, |
+ stb, 0, val, &opts, current_language); |
+ ui_out_field_stream (uiout, "value", stb); |
- get_formatted_print_options (&opts, format); |
- opts.deref_ref = 1; |
- val_print (value_type (val), |
- value_contents_for_printing (val), |
- value_embedded_offset (val), 0, |
- stb, 0, val, &opts, current_language); |
- ui_out_field_stream (uiout, "value", stb); |
- do_cleanups (old_chain); |
- } |
+ do_cleanups (tuple_cleanup); |
} |
/* Write given values into registers. The registers and values are |
- given as pairs. The corresponding MI command is |
+ given as pairs. The corresponding MI command is |
-data-write-register-values <format> |
[<regnum1> <value1>...<regnumN> <valueN>] */ |
void |
@@ -1189,7 +1250,6 @@ mi_cmd_data_write_register_values (char *command, char **argv, int argc) |
struct regcache *regcache; |
struct gdbarch *gdbarch; |
int numregs, i; |
- char format; |
/* Note that the test for a valid register must include checking the |
gdbarch_register_name because gdbarch_num_regs may be allocated |
@@ -1206,8 +1266,6 @@ mi_cmd_data_write_register_values (char *command, char **argv, int argc) |
error (_("-data-write-register-values: Usage: -data-write-register-" |
"values <format> [<regnum1> <value1>...<regnumN> <valueN>]")); |
- format = (int) argv[0][0]; |
- |
if (!target_has_registers) |
error (_("-data-write-register-values: No registers.")); |
@@ -1279,7 +1337,7 @@ mi_cmd_data_evaluate_expression (char *command, char **argv, int argc) |
/* This is the -data-read-memory command. |
ADDR: start address of data to be dumped. |
- WORD-FORMAT: a char indicating format for the ``word''. See |
+ WORD-FORMAT: a char indicating format for the ``word''. See |
the ``x'' command. |
WORD-SIZE: size of each ``word''; 1,2,4, or 8 bytes. |
NR_ROW: Number of rows. |
@@ -1292,7 +1350,7 @@ mi_cmd_data_evaluate_expression (char *command, char **argv, int argc) |
{addr="...",rowN={wordN="..." ,... [,ascii="..."]}, ...} |
- Returns: |
+ Returns: |
The number of bytes read is SIZE*ROW*COL. */ |
void |
@@ -1573,7 +1631,7 @@ mi_cmd_data_read_memory_bytes (char *command, char **argv, int argc) |
ADDR: start address of the row in the memory grid where the memory |
cell is, if OFFSET_COLUMN is specified. Otherwise, the address of |
the location to write to. |
- FORMAT: a char indicating format for the ``word''. See |
+ FORMAT: a char indicating format for the ``word''. See |
the ``x'' command. |
WORD_SIZE: size of each ``word''; 1,2,4, or 8 bytes |
VALUE: value to be written into the memory address. |
@@ -1588,7 +1646,6 @@ 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; |
/* FIXME: ezannoni 2000-02-17 LONGEST could possibly not be big |
enough when using a compiler other than GCC. */ |
@@ -1632,9 +1689,6 @@ mi_cmd_data_write_memory (char *command, char **argv, int argc) |
/* Extract all the arguments. */ |
/* Start address of the memory dump. */ |
addr = parse_and_eval_address (argv[0]); |
- /* The format character to use when displaying a memory word. See |
- the ``x'' command. */ |
- word_format = argv[1][0]; |
/* The size of the memory word. */ |
word_size = atol (argv[2]); |
@@ -1648,7 +1702,7 @@ mi_cmd_data_write_memory (char *command, char **argv, int argc) |
old_chain = make_cleanup (xfree, buffer); |
store_signed_integer (buffer, word_size, byte_order, value); |
/* Write it down to memory. */ |
- write_memory (addr, buffer, word_size); |
+ write_memory_with_notification (addr, buffer, word_size); |
/* Free the buffer. */ |
do_cleanups (old_chain); |
} |
@@ -1656,7 +1710,8 @@ mi_cmd_data_write_memory (char *command, char **argv, int argc) |
/* Implementation of the -data-write-memory-bytes command. |
ADDR: start address |
- DATA: string of bytes to write at that address. */ |
+ DATA: string of bytes to write at that address |
+ COUNT: number of bytes to be filled (decimal integer). */ |
void |
mi_cmd_data_write_memory_bytes (char *command, char **argv, int argc) |
@@ -1664,29 +1719,60 @@ mi_cmd_data_write_memory_bytes (char *command, char **argv, int argc) |
CORE_ADDR addr; |
char *cdata; |
gdb_byte *data; |
- int len, r, i; |
+ gdb_byte *databuf; |
+ size_t len, i, steps, remainder; |
+ long int count, j; |
struct cleanup *back_to; |
- if (argc != 2) |
- error (_("Usage: ADDR DATA.")); |
+ if (argc != 2 && argc != 3) |
+ error (_("Usage: ADDR DATA [COUNT].")); |
addr = parse_and_eval_address (argv[0]); |
cdata = argv[1]; |
+ if (strlen (cdata) % 2) |
+ error (_("Hex-encoded '%s' must have an even number of characters."), |
+ cdata); |
+ |
len = strlen (cdata)/2; |
+ if (argc == 3) |
+ count = strtoul (argv[2], NULL, 10); |
+ else |
+ count = len; |
- data = xmalloc (len); |
- back_to = make_cleanup (xfree, data); |
+ databuf = xmalloc (len * sizeof (gdb_byte)); |
+ back_to = make_cleanup (xfree, databuf); |
for (i = 0; i < len; ++i) |
{ |
int x; |
- sscanf (cdata + i * 2, "%02x", &x); |
- data[i] = (gdb_byte) x; |
+ if (sscanf (cdata + i * 2, "%02x", &x) != 1) |
+ error (_("Invalid argument")); |
+ databuf[i] = (gdb_byte) x; |
} |
- r = target_write_memory (addr, data, len); |
- if (r != 0) |
- error (_("Could not write memory")); |
+ if (len < count) |
+ { |
+ /* Pattern is made of less bytes than count: |
+ repeat pattern to fill memory. */ |
+ data = xmalloc (count); |
+ make_cleanup (xfree, data); |
+ |
+ steps = count / len; |
+ remainder = count % len; |
+ for (j = 0; j < steps; j++) |
+ memcpy (data + j * len, databuf, len); |
+ |
+ if (remainder > 0) |
+ memcpy (data + steps * len, databuf, remainder); |
+ } |
+ else |
+ { |
+ /* Pattern is longer than or equal to count: |
+ just copy len bytes. */ |
+ data = databuf; |
+ } |
+ |
+ write_memory_with_notification (addr, data, count); |
do_cleanups (back_to); |
} |
@@ -1707,7 +1793,7 @@ mi_cmd_enable_timings (char *command, char **argv, int argc) |
} |
else |
goto usage_error; |
- |
+ |
return; |
usage_error: |
@@ -1722,18 +1808,23 @@ mi_cmd_list_features (char *command, char **argv, int argc) |
struct cleanup *cleanup = NULL; |
struct ui_out *uiout = current_uiout; |
- cleanup = make_cleanup_ui_out_list_begin_end (uiout, "features"); |
+ cleanup = make_cleanup_ui_out_list_begin_end (uiout, "features"); |
ui_out_field_string (uiout, NULL, "frozen-varobjs"); |
ui_out_field_string (uiout, NULL, "pending-breakpoints"); |
ui_out_field_string (uiout, NULL, "thread-info"); |
ui_out_field_string (uiout, NULL, "data-read-memory-bytes"); |
ui_out_field_string (uiout, NULL, "breakpoint-notifications"); |
ui_out_field_string (uiout, NULL, "ada-task-info"); |
- |
+ ui_out_field_string (uiout, NULL, "language-option"); |
+ ui_out_field_string (uiout, NULL, "info-gdb-mi-command"); |
+ ui_out_field_string (uiout, NULL, "undefined-command-error-code"); |
+ ui_out_field_string (uiout, NULL, "exec-run-start-option"); |
+ |
#if HAVE_PYTHON |
- ui_out_field_string (uiout, NULL, "python"); |
+ if (gdb_python_initialized) |
+ ui_out_field_string (uiout, NULL, "python"); |
#endif |
- |
+ |
do_cleanups (cleanup); |
return; |
} |
@@ -1749,12 +1840,12 @@ mi_cmd_list_target_features (char *command, char **argv, int argc) |
struct cleanup *cleanup = NULL; |
struct ui_out *uiout = current_uiout; |
- cleanup = make_cleanup_ui_out_list_begin_end (uiout, "features"); |
+ cleanup = make_cleanup_ui_out_list_begin_end (uiout, "features"); |
if (target_can_async_p ()) |
ui_out_field_string (uiout, NULL, "async"); |
if (target_can_execute_reverse) |
ui_out_field_string (uiout, NULL, "reverse"); |
- |
+ |
do_cleanups (cleanup); |
return; |
} |
@@ -1777,7 +1868,7 @@ mi_cmd_add_inferior (char *command, char **argv, int argc) |
/* Callback used to find the first inferior other than the current |
one. */ |
- |
+ |
static int |
get_other_inferior (struct inferior *inf, void *arg) |
{ |
@@ -1809,7 +1900,7 @@ mi_cmd_remove_inferior (char *command, char **argv, int argc) |
if (inf == current_inferior ()) |
{ |
struct thread_info *tp = 0; |
- struct inferior *new_inferior |
+ struct inferior *new_inferior |
= iterate_over_inferiors (get_other_inferior, NULL); |
if (new_inferior == NULL) |
@@ -1910,7 +2001,7 @@ captured_mi_execute_command (struct ui_out *uiout, struct mi_parse *context) |
mi_out_put (uiout, raw_stdout); |
mi_out_rewind (uiout); |
mi_print_timing_maybe (); |
- fputs_unfiltered ("\n", raw_stdout); |
+ fputs_unfiltered ("\n", raw_stdout); |
} |
else |
mi_out_rewind (uiout); |
@@ -1933,11 +2024,20 @@ mi_print_exception (const char *token, struct gdb_exception exception) |
fputs_unfiltered ("unknown error", raw_stdout); |
else |
fputstr_unfiltered (exception.message, '"', raw_stdout); |
- fputs_unfiltered ("\"\n", raw_stdout); |
+ fputs_unfiltered ("\"", raw_stdout); |
+ |
+ switch (exception.error) |
+ { |
+ case UNDEFINED_COMMAND_ERROR: |
+ fputs_unfiltered (",code=\"undefined-command\"", raw_stdout); |
+ break; |
+ } |
+ |
+ fputs_unfiltered ("\n", raw_stdout); |
} |
void |
-mi_execute_command (char *cmd, int from_tty) |
+mi_execute_command (const char *cmd, int from_tty) |
{ |
char *token; |
struct mi_parse *command = NULL; |
@@ -1988,9 +2088,9 @@ mi_execute_command (char *cmd, int from_tty) |
bpstat_do_actions (); |
if (/* The notifications are only output when the top-level |
- interpreter (specified on the command line) is MI. */ |
+ interpreter (specified on the command line) is MI. */ |
ui_out_is_mi_like_p (interp_ui_out (top_level_interpreter ())) |
- /* Don't try report anything if there are no threads -- |
+ /* Don't try report anything if there are no threads -- |
the program is dead. */ |
&& thread_count () != 0 |
/* -thread-select explicitly changes thread. If frontend uses that |
@@ -2015,11 +2115,11 @@ mi_execute_command (char *cmd, int from_tty) |
} |
if (report_change) |
- { |
+ { |
struct thread_info *ti = inferior_thread (); |
target_terminal_ours (); |
- fprintf_unfiltered (mi->event_channel, |
+ fprintf_unfiltered (mi->event_channel, |
"thread-selected,id=\"%d\"", |
ti->num); |
gdb_flush (mi->event_channel); |
@@ -2034,6 +2134,7 @@ static void |
mi_cmd_execute (struct mi_parse *parse) |
{ |
struct cleanup *cleanup; |
+ enum language saved_language; |
cleanup = prepare_execute_command (); |
@@ -2095,12 +2196,18 @@ mi_cmd_execute (struct mi_parse *parse) |
error (_("Invalid frame id: %d"), frame); |
} |
+ if (parse->language != language_unknown) |
+ { |
+ make_cleanup_restore_current_language (); |
+ set_language (parse->language); |
+ } |
+ |
current_context = parse; |
- if (strncmp (parse->command, "break-", sizeof ("break-") - 1 ) == 0) |
+ if (parse->cmd->suppress_notification != NULL) |
{ |
- make_cleanup_restore_integer (&mi_suppress_breakpoint_notifications); |
- mi_suppress_breakpoint_notifications = 1; |
+ make_cleanup_restore_integer (parse->cmd->suppress_notification); |
+ *parse->cmd->suppress_notification = 1; |
} |
if (parse->cmd->argv_func != NULL) |
@@ -2169,7 +2276,7 @@ mi_execute_async_cli_command (char *cli_command, char **argv, int argc) |
run = xstrprintf ("%s %s&", cli_command, argc ? *argv : ""); |
else |
run = xstrprintf ("%s %s", cli_command, argc ? *argv : ""); |
- old_cleanups = make_cleanup (xfree, run); |
+ old_cleanups = make_cleanup (xfree, run); |
execute_command (run, 0 /* from_tty */ ); |
@@ -2270,7 +2377,7 @@ mi_load_progress (const char *section_name, |
current_uiout = saved_uiout; |
} |
-static void |
+static void |
timestamp (struct mi_timestamp *tv) |
{ |
gettimeofday (&tv->wallclock, NULL); |
@@ -2292,7 +2399,7 @@ timestamp (struct mi_timestamp *tv) |
#endif |
} |
-static void |
+static void |
print_diff_now (struct mi_timestamp *start) |
{ |
struct mi_timestamp now; |
@@ -2310,21 +2417,21 @@ mi_print_timing_maybe (void) |
print_diff_now (current_command_ts); |
} |
-static long |
+static long |
timeval_diff (struct timeval start, struct timeval end) |
{ |
return ((end.tv_sec - start.tv_sec) * 1000000L) |
+ (end.tv_usec - start.tv_usec); |
} |
-static void |
+static void |
print_diff (struct mi_timestamp *start, struct mi_timestamp *end) |
{ |
fprintf_unfiltered |
(raw_stdout, |
- ",time={wallclock=\"%0.5f\",user=\"%0.5f\",system=\"%0.5f\"}", |
- timeval_diff (start->wallclock, end->wallclock) / 1000000.0, |
- timeval_diff (start->utime, end->utime) / 1000000.0, |
+ ",time={wallclock=\"%0.5f\",user=\"%0.5f\",system=\"%0.5f\"}", |
+ timeval_diff (start->wallclock, end->wallclock) / 1000000.0, |
+ timeval_diff (start->utime, end->utime) / 1000000.0, |
timeval_diff (start->stime, end->stime) / 1000000.0); |
} |
@@ -2332,7 +2439,6 @@ 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; |
@@ -2340,19 +2446,11 @@ mi_cmd_trace_define_variable (char *command, char **argv, int argc) |
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); |
- } |
+ name = argv[0]; |
+ if (*name++ != '$') |
+ error (_("Name of trace variable should start with '$'")); |
- if (!name || *name == '\0') |
- error (_("Invalid name of trace variable")); |
+ validate_trace_state_variable_name (name); |
tsv = find_trace_state_variable (name); |
if (!tsv) |
@@ -2362,8 +2460,6 @@ mi_cmd_trace_define_variable (char *command, char **argv, int argc) |
initval = value_as_long (parse_and_eval (argv[1])); |
tsv->initial_value = initval; |
- |
- do_cleanups (back_to); |
} |
void |
@@ -2456,32 +2552,52 @@ mi_cmd_trace_find (char *command, char **argv, int argc) |
error (_("Invalid mode '%s'"), mode); |
if (has_stack_frames () || get_traceframe_number () >= 0) |
- print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC); |
+ print_stack_frame (get_selected_frame (NULL), 1, LOC_AND_ADDRESS, 1); |
} |
void |
mi_cmd_trace_save (char *command, char **argv, int argc) |
{ |
int target_saves = 0; |
+ int generate_ctf = 0; |
char *filename; |
+ int oind = 0; |
+ char *oarg; |
- if (argc != 1 && argc != 2) |
- error (_("Usage: -trace-save [-r] filename")); |
- |
- if (argc == 2) |
+ enum opt |
+ { |
+ TARGET_SAVE_OPT, CTF_OPT |
+ }; |
+ static const struct mi_opt opts[] = |
{ |
- filename = argv[1]; |
- if (strcmp (argv[0], "-r") == 0) |
- target_saves = 1; |
- else |
- error (_("Invalid option: %s"), argv[0]); |
- } |
- else |
+ {"r", TARGET_SAVE_OPT, 0}, |
+ {"ctf", CTF_OPT, 0}, |
+ { 0, 0, 0 } |
+ }; |
+ |
+ while (1) |
{ |
- filename = argv[0]; |
+ int opt = mi_getopt ("-trace-save", argc, argv, opts, |
+ &oind, &oarg); |
+ |
+ if (opt < 0) |
+ break; |
+ switch ((enum opt) opt) |
+ { |
+ case TARGET_SAVE_OPT: |
+ target_saves = 1; |
+ break; |
+ case CTF_OPT: |
+ generate_ctf = 1; |
+ break; |
+ } |
} |
+ filename = argv[oind]; |
- trace_save (filename, target_saves); |
+ if (generate_ctf) |
+ trace_save_ctf (filename, target_saves); |
+ else |
+ trace_save_tfile (filename, target_saves); |
} |
void |
@@ -2513,3 +2629,298 @@ mi_cmd_ada_task_info (char *command, char **argv, int argc) |
print_ada_task_info (current_uiout, argv[0], current_inferior ()); |
} |
+ |
+/* Print EXPRESSION according to VALUES. */ |
+ |
+static void |
+print_variable_or_computed (char *expression, enum print_values values) |
+{ |
+ struct expression *expr; |
+ struct cleanup *old_chain; |
+ struct value *val; |
+ struct ui_file *stb; |
+ struct value_print_options opts; |
+ struct type *type; |
+ struct ui_out *uiout = current_uiout; |
+ |
+ stb = mem_fileopen (); |
+ old_chain = make_cleanup_ui_file_delete (stb); |
+ |
+ expr = parse_expression (expression); |
+ |
+ make_cleanup (free_current_contents, &expr); |
+ |
+ if (values == PRINT_SIMPLE_VALUES) |
+ val = evaluate_type (expr); |
+ else |
+ val = evaluate_expression (expr); |
+ |
+ if (values != PRINT_NO_VALUES) |
+ make_cleanup_ui_out_tuple_begin_end (uiout, NULL); |
+ ui_out_field_string (uiout, "name", expression); |
+ |
+ switch (values) |
+ { |
+ case PRINT_SIMPLE_VALUES: |
+ type = check_typedef (value_type (val)); |
+ type_print (value_type (val), "", stb, -1); |
+ ui_out_field_stream (uiout, "type", stb); |
+ if (TYPE_CODE (type) != TYPE_CODE_ARRAY |
+ && TYPE_CODE (type) != TYPE_CODE_STRUCT |
+ && TYPE_CODE (type) != TYPE_CODE_UNION) |
+ { |
+ struct value_print_options opts; |
+ |
+ get_no_prettyformat_print_options (&opts); |
+ opts.deref_ref = 1; |
+ common_val_print (val, stb, 0, &opts, current_language); |
+ ui_out_field_stream (uiout, "value", stb); |
+ } |
+ break; |
+ case PRINT_ALL_VALUES: |
+ { |
+ struct value_print_options opts; |
+ |
+ get_no_prettyformat_print_options (&opts); |
+ opts.deref_ref = 1; |
+ common_val_print (val, stb, 0, &opts, current_language); |
+ ui_out_field_stream (uiout, "value", stb); |
+ } |
+ break; |
+ } |
+ |
+ do_cleanups (old_chain); |
+} |
+ |
+/* Implement the "-trace-frame-collected" command. */ |
+ |
+void |
+mi_cmd_trace_frame_collected (char *command, char **argv, int argc) |
+{ |
+ struct cleanup *old_chain; |
+ struct bp_location *tloc; |
+ int stepping_frame; |
+ struct collection_list *clist; |
+ struct collection_list tracepoint_list, stepping_list; |
+ struct traceframe_info *tinfo; |
+ int oind = 0; |
+ int var_print_values = PRINT_ALL_VALUES; |
+ int comp_print_values = PRINT_ALL_VALUES; |
+ int registers_format = 'x'; |
+ int memory_contents = 0; |
+ struct ui_out *uiout = current_uiout; |
+ enum opt |
+ { |
+ VAR_PRINT_VALUES, |
+ COMP_PRINT_VALUES, |
+ REGISTERS_FORMAT, |
+ MEMORY_CONTENTS, |
+ }; |
+ static const struct mi_opt opts[] = |
+ { |
+ {"-var-print-values", VAR_PRINT_VALUES, 1}, |
+ {"-comp-print-values", COMP_PRINT_VALUES, 1}, |
+ {"-registers-format", REGISTERS_FORMAT, 1}, |
+ {"-memory-contents", MEMORY_CONTENTS, 0}, |
+ { 0, 0, 0 } |
+ }; |
+ |
+ while (1) |
+ { |
+ char *oarg; |
+ int opt = mi_getopt ("-trace-frame-collected", argc, argv, opts, |
+ &oind, &oarg); |
+ if (opt < 0) |
+ break; |
+ switch ((enum opt) opt) |
+ { |
+ case VAR_PRINT_VALUES: |
+ var_print_values = mi_parse_print_values (oarg); |
+ break; |
+ case COMP_PRINT_VALUES: |
+ comp_print_values = mi_parse_print_values (oarg); |
+ break; |
+ case REGISTERS_FORMAT: |
+ registers_format = oarg[0]; |
+ case MEMORY_CONTENTS: |
+ memory_contents = 1; |
+ break; |
+ } |
+ } |
+ |
+ if (oind != argc) |
+ error (_("Usage: -trace-frame-collected " |
+ "[--var-print-values PRINT_VALUES] " |
+ "[--comp-print-values PRINT_VALUES] " |
+ "[--registers-format FORMAT]" |
+ "[--memory-contents]")); |
+ |
+ /* This throws an error is not inspecting a trace frame. */ |
+ tloc = get_traceframe_location (&stepping_frame); |
+ |
+ /* This command only makes sense for the current frame, not the |
+ selected frame. */ |
+ old_chain = make_cleanup_restore_current_thread (); |
+ select_frame (get_current_frame ()); |
+ |
+ encode_actions_and_make_cleanup (tloc, &tracepoint_list, |
+ &stepping_list); |
+ |
+ if (stepping_frame) |
+ clist = &stepping_list; |
+ else |
+ clist = &tracepoint_list; |
+ |
+ tinfo = get_traceframe_info (); |
+ |
+ /* Explicitly wholly collected variables. */ |
+ { |
+ struct cleanup *list_cleanup; |
+ char *p; |
+ int i; |
+ |
+ list_cleanup = make_cleanup_ui_out_list_begin_end (uiout, |
+ "explicit-variables"); |
+ for (i = 0; VEC_iterate (char_ptr, clist->wholly_collected, i, p); i++) |
+ print_variable_or_computed (p, var_print_values); |
+ do_cleanups (list_cleanup); |
+ } |
+ |
+ /* Computed expressions. */ |
+ { |
+ struct cleanup *list_cleanup; |
+ char *p; |
+ int i; |
+ |
+ list_cleanup |
+ = make_cleanup_ui_out_list_begin_end (uiout, |
+ "computed-expressions"); |
+ for (i = 0; VEC_iterate (char_ptr, clist->computed, i, p); i++) |
+ print_variable_or_computed (p, comp_print_values); |
+ do_cleanups (list_cleanup); |
+ } |
+ |
+ /* Registers. Given pseudo-registers, and that some architectures |
+ (like MIPS) actually hide the raw registers, we don't go through |
+ the trace frame info, but instead consult the register cache for |
+ register availability. */ |
+ { |
+ struct cleanup *list_cleanup; |
+ struct frame_info *frame; |
+ struct gdbarch *gdbarch; |
+ int regnum; |
+ int numregs; |
+ |
+ list_cleanup = make_cleanup_ui_out_list_begin_end (uiout, "registers"); |
+ |
+ frame = get_selected_frame (NULL); |
+ gdbarch = get_frame_arch (frame); |
+ numregs = gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch); |
+ |
+ for (regnum = 0; regnum < numregs; regnum++) |
+ { |
+ if (gdbarch_register_name (gdbarch, regnum) == NULL |
+ || *(gdbarch_register_name (gdbarch, regnum)) == '\0') |
+ continue; |
+ |
+ output_register (frame, regnum, registers_format, 1); |
+ } |
+ |
+ do_cleanups (list_cleanup); |
+ } |
+ |
+ /* Trace state variables. */ |
+ { |
+ struct cleanup *list_cleanup; |
+ int tvar; |
+ char *tsvname; |
+ int i; |
+ |
+ list_cleanup = make_cleanup_ui_out_list_begin_end (uiout, "tvars"); |
+ |
+ tsvname = NULL; |
+ make_cleanup (free_current_contents, &tsvname); |
+ |
+ for (i = 0; VEC_iterate (int, tinfo->tvars, i, tvar); i++) |
+ { |
+ struct cleanup *cleanup_child; |
+ struct trace_state_variable *tsv; |
+ |
+ tsv = find_trace_state_variable_by_number (tvar); |
+ |
+ cleanup_child = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); |
+ |
+ if (tsv != NULL) |
+ { |
+ tsvname = xrealloc (tsvname, strlen (tsv->name) + 2); |
+ tsvname[0] = '$'; |
+ strcpy (tsvname + 1, tsv->name); |
+ ui_out_field_string (uiout, "name", tsvname); |
+ |
+ tsv->value_known = target_get_trace_state_variable_value (tsv->number, |
+ &tsv->value); |
+ ui_out_field_int (uiout, "current", tsv->value); |
+ } |
+ else |
+ { |
+ ui_out_field_skip (uiout, "name"); |
+ ui_out_field_skip (uiout, "current"); |
+ } |
+ |
+ do_cleanups (cleanup_child); |
+ } |
+ |
+ do_cleanups (list_cleanup); |
+ } |
+ |
+ /* Memory. */ |
+ { |
+ struct cleanup *list_cleanup; |
+ VEC(mem_range_s) *available_memory = NULL; |
+ struct mem_range *r; |
+ int i; |
+ |
+ traceframe_available_memory (&available_memory, 0, ULONGEST_MAX); |
+ make_cleanup (VEC_cleanup(mem_range_s), &available_memory); |
+ |
+ list_cleanup = make_cleanup_ui_out_list_begin_end (uiout, "memory"); |
+ |
+ for (i = 0; VEC_iterate (mem_range_s, available_memory, i, r); i++) |
+ { |
+ struct cleanup *cleanup_child; |
+ gdb_byte *data; |
+ struct gdbarch *gdbarch = target_gdbarch (); |
+ |
+ cleanup_child = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); |
+ |
+ ui_out_field_core_addr (uiout, "address", gdbarch, r->start); |
+ ui_out_field_int (uiout, "length", r->length); |
+ |
+ data = xmalloc (r->length); |
+ make_cleanup (xfree, data); |
+ |
+ if (memory_contents) |
+ { |
+ if (target_read_memory (r->start, data, r->length) == 0) |
+ { |
+ int m; |
+ char *data_str, *p; |
+ |
+ data_str = xmalloc (r->length * 2 + 1); |
+ make_cleanup (xfree, data_str); |
+ |
+ for (m = 0, p = data_str; m < r->length; ++m, p += 2) |
+ sprintf (p, "%02x", data[m]); |
+ ui_out_field_string (uiout, "contents", data_str); |
+ } |
+ else |
+ ui_out_field_skip (uiout, "contents"); |
+ } |
+ do_cleanups (cleanup_child); |
+ } |
+ |
+ do_cleanups (list_cleanup); |
+ } |
+ |
+ do_cleanups (old_chain); |
+} |