#include <ctype.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/resource.h>
#include <signal.h>
#include "defs.h"
#include "target.h"
#include "inferior.h"
#include "gdb_string.h"
#include "exceptions.h"
#include "top.h"
#include "gdbthread.h"
#include "gdbcmd.h"
#include "mi-cmds.h"
#include "mi-parse.h"
#include "mi-getopt.h"
#include "mi-console.h"
#include "ui-out.h"
#include "mi-out.h"
#include "interps.h"
#include "event-loop.h"
#include "event-top.h"
#include "gdbcore.h"
#include "value.h"
#include "regcache.h"
#include "gdb.h"
#include "frame.h"
#include "wrapper.h"
#include "source.h"
#include "mi-main.h"
#include "block.h"
#include "version.h"
#include "mi-common.h"
#include "inlining.h"
enum
{
FROM_TTY = 0
};
enum captured_mi_execute_command_actions
{
EXECUTE_COMMAND_DISPLAY_PROMPT,
EXECUTE_COMMAND_SUPRESS_PROMPT
};
struct captured_mi_execute_command_args
{
enum mi_cmd_result rc;
enum captured_mi_execute_command_actions action;
struct mi_parse *command;
};
struct mi_continuation_arg
{
char *token;
struct mi_timestamp *timestamp;
struct cleanup *cleanups;
struct cleanup *exec_error_cleanups;
};
static void free_continuation_arg (struct mi_continuation_arg *arg);
int mi_debug_p;
struct ui_file *raw_stdout;
struct ui_file *mi_stdout;
struct ui_file *mi_stderr;
struct ui_file *mi_stdlog;
struct ui_file *mi_stdtarg;
char *current_command_token;
char *mi_error_message;
static char *old_regs;
struct mi_timestamp *current_command_ts;
static int do_timings = 1;
struct interp *mi_interp;
struct interp *miunspec_interp;
struct interp *mi0_interp;
struct interp *mi1_interp;
struct interp *mi2_interp;
extern void _initialize_mi_main (void);
static enum mi_cmd_result mi_cmd_execute (struct mi_parse *parse);
static void mi_execute_cli_command (const char *cmd, int arg_p, char *args);
static enum mi_cmd_result mi_execute_async_cli_command (char *mi, char *args, int from_tty);
void mi_exec_async_cli_cmd_continuation (struct continuation_arg *arg);
void mi_exec_error_cleanup (void *in_arg);
static int register_changed_p (int regnum);
static int get_register (int regnum, int format);
extern void interrupt_target_command_wrapper (char *, int);
extern void return_command_wrapper (char *, int);
extern void interrupt_target_command_wrapper (char *, int);
extern void return_command_wrapper (char *, int);
static void output_control_change_notification(char *notification);
static int mi_command_completes_while_target_executing (char *command);
static void timestamp (struct mi_timestamp *tv);
static void print_diff_now (struct mi_timestamp *start);
static void copy_timestamp (struct mi_timestamp *dst, struct mi_timestamp *src);
static void print_diff (struct mi_timestamp *start, struct mi_timestamp *end);
static long wallclock_diff (struct mi_timestamp *start, struct mi_timestamp *end);
static long user_diff (struct mi_timestamp *start, struct mi_timestamp *end);
static long system_diff (struct mi_timestamp *start, struct mi_timestamp *end);
static void start_remote_counts (struct mi_timestamp *tv, const char *token);
static void end_remote_counts (struct mi_timestamp *tv);
int mi_interp_exec_cmd_did_run;
enum mi_cmd_result
mi_cmd_gdb_exit (char *command, char **argv, int argc)
{
if (current_command_token)
fputs_unfiltered (current_command_token, raw_stdout);
fputs_unfiltered ("^exit\n", raw_stdout);
mi_out_put (uiout, raw_stdout);
quit_force (NULL, FROM_TTY);
return MI_CMD_DONE;
}
enum mi_cmd_result
mi_cmd_exec_run (char *args, int from_tty)
{
return mi_execute_async_cli_command ("run", args, from_tty);
}
enum mi_cmd_result
mi_cmd_exec_next (char *args, int from_tty)
{
return mi_execute_async_cli_command ("next", args, from_tty);
}
enum mi_cmd_result
mi_cmd_exec_next_instruction (char *args, int from_tty)
{
return mi_execute_async_cli_command ("nexti", args, from_tty);
}
enum mi_cmd_result
mi_cmd_exec_step (char *args, int from_tty)
{
return mi_execute_async_cli_command ("step", args, from_tty);
}
enum mi_cmd_result
mi_cmd_exec_step_instruction (char *args, int from_tty)
{
return mi_execute_async_cli_command ("stepi", args, from_tty);
}
enum mi_cmd_result
mi_cmd_exec_metrowerks_step (char *args, int from_tty)
{
return mi_execute_async_cli_command ("metrowerks-step", args, from_tty);
}
enum mi_cmd_result
mi_cmd_exec_finish (char *args, int from_tty)
{
return mi_execute_async_cli_command ("finish", args, from_tty);
}
enum mi_cmd_result
mi_cmd_exec_until (char *args, int from_tty)
{
return mi_execute_async_cli_command ("until", args, from_tty);
}
enum mi_cmd_result
mi_cmd_exec_return (char *args, int from_tty)
{
if (*args)
return_command (args, 0);
else
return_command (NULL, 0);
print_stack_frame (get_selected_frame (NULL), 1, LOC_AND_ADDRESS);
return MI_CMD_DONE;
}
enum mi_cmd_result
mi_cmd_exec_continue (char *args, int from_tty)
{
return mi_execute_async_cli_command ("continue", args, from_tty);
}
enum mi_cmd_result
mi_cmd_exec_interrupt (char *args, int from_tty)
{
if (!target_executing)
{
mi_error_message = xstrprintf ("mi_cmd_exec_interrupt: Inferior not executing.");
return MI_CMD_ERROR;
}
interrupt_target_command (args, from_tty);
if (current_command_token) {
fputs_unfiltered (current_command_token, raw_stdout);
}
fprintf_unfiltered (raw_stdout, "^done");
return MI_CMD_QUIET;
}
enum mi_cmd_result
mi_cmd_exec_status (char *command, char **argv, int argc)
{
char *status;
if (argc != 0)
{
xasprintf (&mi_error_message,
"mi_cmd_exec_status takes no arguments.");
return MI_CMD_ERROR;
}
if (!target_has_execution)
status = "not executing";
else
if (target_executing)
{
status = "running";
fputs_unfiltered ("^done", raw_stdout);
ui_out_field_string (uiout, "status", status);
mi_out_put (uiout, raw_stdout);
mi_out_rewind (uiout);
fputs_unfiltered ("\n", raw_stdout);
return MI_CMD_DONE;
}
else
status = "stopped";
ui_out_field_string (uiout, "status", status);
return MI_CMD_DONE;
}
enum mi_cmd_result
mi_cmd_exec_safe_call (char *command, char **argv, int argc)
{
enum mi_cmd_result rc = MI_CMD_DONE;
struct cleanup *old_cleanups;
ptid_t current_ptid = inferior_ptid;
int safe;
if (argc > 1)
{
xasprintf (&mi_error_message,
"mi_cmd_exec_safe_call: USAGE: <threadnum>");
return MI_CMD_ERROR;
}
if (!target_has_execution)
{
ui_out_field_int (uiout, "safe", 0);
ui_out_field_string (uiout, "reason", "program not running");
}
if (target_executing)
{
ui_out_field_int (uiout, "safe", 0);
ui_out_field_string (uiout, "reason", "program executing");
}
if (argc == 0)
{
old_cleanups = make_cleanup (null_cleanup, NULL);
}
else
{
old_cleanups = make_cleanup_restore_current_thread (current_ptid, 0);
rc = gdb_thread_select (uiout, argv[0], 0, 0);
if ((int) rc < 0 && (enum return_reason) rc == RETURN_ERROR)
return MI_CMD_ERROR;
else if ((int) rc >= 0 && rc == GDB_RC_FAIL)
return MI_CMD_ERROR;
}
safe = target_check_safe_call (current_ptid);
ui_out_field_int (uiout, "safe", safe);
do_cleanups (old_cleanups);
return rc;
}
enum mi_cmd_result
mi_cmd_show_version (char *command, char **argv, int argc)
{
int print_banner;
char *endptr;
if (argc > 1)
{
mi_error_message = xstrprintf ("mi_cmd_show_version: Usage: [PRINT-BANNER]");
return MI_CMD_ERROR;
}
if (argc == 0)
print_banner = 1;
else
{
print_banner = strtol (argv[0], &endptr, 0);
if (*endptr != '\0')
{
mi_error_message = xstrprintf ("mi_cmd_show_version: PRINT-BANNER must be 0 or 1");
return MI_CMD_ERROR;
}
}
if (print_banner)
{
print_gdb_version (gdb_stdout);
gdb_flush (gdb_stdout);
}
ui_out_field_string (uiout, "version", version);
ui_out_field_string (uiout, "rc_version", rc_version);
ui_out_field_string (uiout, "target", target_name);
ui_out_field_string (uiout, "build-date", build_date);
return MI_CMD_DONE;
}
enum mi_cmd_result
mi_cmd_thread_select (char *command, char **argv, int argc)
{
enum gdb_rc rc;
if (argc != 1)
{
mi_error_message = xstrprintf ("mi_cmd_thread_select: USAGE: threadnum.");
return MI_CMD_ERROR;
}
else
rc = gdb_thread_select (uiout, argv[0], 1, &mi_error_message);
if ((int) rc < 0 && (enum return_reason) rc == RETURN_ERROR)
return MI_CMD_ERROR;
else if ((int) rc >= 0 && rc == GDB_RC_FAIL)
return MI_CMD_ERROR;
else
return MI_CMD_DONE;
}
enum mi_cmd_result
mi_cmd_thread_set_pc (char *command, char **argv, int argc)
{
enum gdb_rc rc;
struct symtab *s;
struct symtab_and_line sal;
ptid_t current_ptid = inferior_ptid;
struct cleanup *old_cleanups;
struct symbol *old_fun = NULL, *new_fun = NULL;
int stay_in_function = 1;
int avoid_prologue = 1;
const char *filename;
int lineno;
CORE_ADDR new_pc;
if (argc >= 3)
{
while (argc > 2)
if (argv[0][0] == '-')
{
if (argv[0][1] == 'f')
{
stay_in_function = 0;
argc--;
argv++;
}
else if (argv[0][1] == 'n')
{
avoid_prologue = 0;
argc--;
argv++;
}
}
else
break;
}
if (argc != 2)
{
xasprintf (&mi_error_message,
"mi_cmd_thread_select: USAGE: [-f] [-n] threadnum file:line");
return MI_CMD_ERROR;
}
old_cleanups = make_cleanup_restore_current_thread (current_ptid, 0);
rc = gdb_thread_select (uiout, argv[0], 0, 0);
if ((int) rc < 0 && (enum return_reason) rc == RETURN_ERROR)
return MI_CMD_ERROR;
else if ((int) rc >= 0 && rc == GDB_RC_FAIL)
return MI_CMD_ERROR;
filename = argv[1];
while (filename != NULL && (*filename == '"' || *filename == '\\'))
filename++;
char *c = strrchr (filename, ':');
if (c == NULL)
error ("mi_cmd_thread_set_pc: Unable to find colon character in last argument, '%s'.", argv[1]);
errno = 0;
lineno = strtol (c + 1, NULL, 10);
if (errno != 0)
error ("mi_cmd_thread_set_pc: Error parsing line number part of argument, '%s'.", argv[1]);
*c = '\0';
s = lookup_symtab (filename);
if (s == NULL)
error ("mi_cmd_thread_set_pc: Unable to find source file name '%s'.", filename);
if (!find_line_pc (s, lineno, &new_pc))
error ("mi_cmd_thread_set_pc: Invalid line number '%d'", lineno);
sal = find_pc_line (new_pc, 0);
if (sal.symtab != s)
{
if (s == NULL || sal.symtab == NULL)
error ("mi_cmd_thread_set_pc: Found one symtab by filename lookup, but symtab another by PC lookup, and one of them is null.");
else
error ("mi_cmd_thread_set_pc: Found symtab '%s' by filename lookup, but symtab '%s' by PC lookup.", s->filename, sal.symtab->filename);
}
new_fun = find_pc_function (new_pc);
if (avoid_prologue && new_fun
&& BLOCK_LOWEST_PC (SYMBOL_BLOCK_VALUE (new_fun)) == new_pc)
{
sal = find_function_start_sal (new_fun, 1);
new_pc = sal.pc;
}
old_fun = get_frame_function (get_current_frame ());
if (stay_in_function)
{
if (old_fun == NULL)
error ("Can't find the function for old_pc: 0x%s",
paddr_nz (get_frame_pc (get_current_frame ())));
if (new_fun == NULL)
error ("Can't find the function for new pc 0x%s", paddr_nz (new_pc));
if (!SYMBOL_MATCHES_NATURAL_NAME (old_fun, SYMBOL_NATURAL_NAME (new_fun)))
error ("New pc: 0x%s outside of current function", paddr_nz (new_pc));
}
write_pc (new_pc);
stop_pc = new_pc;
if (stop_pc != inlined_function_call_stack_pc ())
inlined_function_update_call_stack (stop_pc);
set_current_source_symtab_and_line (&sal);
set_default_breakpoint (1, new_pc, sal.symtab, sal.line);
if (old_fun != NULL && old_fun != new_fun &&
SYMBOL_MATCHES_NATURAL_NAME (old_fun, SYMBOL_NATURAL_NAME (new_fun)))
{
update_picbase_register (new_fun);
}
flush_cached_frames ();
select_frame (get_current_frame ());
print_stack_frame (deprecated_selected_frame, 0, LOC_AND_ADDRESS);
do_cleanups (old_cleanups);
return MI_CMD_DONE;
}
enum mi_cmd_result
mi_cmd_file_fix_file (char *command, char **argv, int argc)
{
char *source_filename = NULL;
char *bundle_filename = NULL;
char *solib_filename = NULL;
int optind = 0;
char *optarg;
struct cleanup *wipe;
enum fff_opt
{
BUNDLE_OPT, SOURCE_OPT, OBJECT_OPT, SOLIB_OPT
};
static struct mi_opt fff_opts[] = {
{"b", BUNDLE_OPT, 1},
{"f", SOURCE_OPT, 1},
{"o", OBJECT_OPT, 1},
{"s", SOLIB_OPT, 1},
{0, 0, 0}
};
if (argc == 2 || argc == 3)
{
bundle_filename = argv[0];
source_filename = argv[1];
fix_command_1 (source_filename, bundle_filename, NULL);
return MI_CMD_DONE;
}
wipe = make_cleanup (null_cleanup, NULL);
while (1)
{
int opt = mi_getopt ("mi_cmd_file_fix_file", argc, argv, fff_opts,
&optind, &optarg);
if (opt < 0)
break;
switch ((enum fff_opt) opt)
{
case BUNDLE_OPT:
bundle_filename = xstrdup (optarg);
make_cleanup (xfree, bundle_filename);
break;
case SOURCE_OPT:
source_filename = xstrdup (optarg);
make_cleanup (xfree, source_filename);
break;
case OBJECT_OPT:
break;
case SOLIB_OPT:
solib_filename = xstrdup (optarg);
make_cleanup (xfree, solib_filename);
break;
}
}
argv += optind;
argc -= optind;
if (source_filename == NULL || bundle_filename == NULL)
error ("mi_cmd_file_fix_file: Usage -f source-filename -b bundle-filename "
"[-o object-filename] [-s dylib-filename]");
fix_command_1 (source_filename, bundle_filename, solib_filename);
do_cleanups (wipe);
return MI_CMD_DONE;
}
enum mi_cmd_result
mi_cmd_file_fix_file_is_grooved (char *command, char **argv, int argc)
{
int retval = fix_and_continue_supported ();
if (retval == 1 || retval == -1)
{
ui_out_field_int (uiout, "supported", 1);
ui_out_field_string (uiout, "details", "Yes grooved!");
}
else
{
ui_out_field_int (uiout, "supported", 0);
ui_out_field_string (uiout, "details", "Groove is gone.");
}
return MI_CMD_DONE;
}
enum mi_cmd_result
mi_cmd_thread_list_ids (char *command, char **argv, int argc)
{
enum gdb_rc rc = MI_CMD_DONE;
if (argc != 0)
{
mi_error_message = xstrprintf ("mi_cmd_thread_list_ids: No arguments required.");
return MI_CMD_ERROR;
}
else
rc = gdb_list_thread_ids (uiout, &mi_error_message);
if (rc == GDB_RC_FAIL)
return MI_CMD_ERROR;
else
return MI_CMD_DONE;
}
enum mi_cmd_result
mi_cmd_data_list_register_names (char *command, char **argv, int argc)
{
int regnum, numregs;
int i;
struct cleanup *cleanup;
numregs = NUM_REGS + NUM_PSEUDO_REGS;
cleanup = make_cleanup_ui_out_list_begin_end (uiout, "register-names");
if (argc == 0)
{
for (regnum = 0;
regnum < numregs;
regnum++)
{
if (REGISTER_NAME (regnum) == NULL
|| *(REGISTER_NAME (regnum)) == '\0')
ui_out_field_string (uiout, NULL, "");
else
ui_out_field_string (uiout, NULL, REGISTER_NAME (regnum));
}
}
for (i = 0; i < argc; i++)
{
regnum = atoi (argv[i]);
if (regnum < 0 || regnum >= numregs)
{
do_cleanups (cleanup);
mi_error_message = xstrprintf ("bad register number");
return MI_CMD_ERROR;
}
if (REGISTER_NAME (regnum) == NULL
|| *(REGISTER_NAME (regnum)) == '\0')
ui_out_field_string (uiout, NULL, "");
else
ui_out_field_string (uiout, NULL, REGISTER_NAME (regnum));
}
do_cleanups (cleanup);
return MI_CMD_DONE;
}
enum mi_cmd_result
mi_cmd_data_list_changed_registers (char *command, char **argv, int argc)
{
int regnum, numregs, changed;
int i;
struct cleanup *cleanup;
numregs = NUM_REGS + NUM_PSEUDO_REGS;
cleanup = make_cleanup_ui_out_list_begin_end (uiout, "changed-registers");
if (argc == 0)
{
for (regnum = 0;
regnum < numregs;
regnum++)
{
if (REGISTER_NAME (regnum) == NULL
|| *(REGISTER_NAME (regnum)) == '\0')
continue;
changed = register_changed_p (regnum);
if (changed < 0)
{
do_cleanups (cleanup);
mi_error_message = xstrprintf ("mi_cmd_data_list_changed_registers: Unable to read register contents.");
return MI_CMD_ERROR;
}
else if (changed)
ui_out_field_int (uiout, NULL, regnum);
}
}
for (i = 0; i < argc; i++)
{
regnum = atoi (argv[i]);
if (regnum >= 0
&& regnum < numregs
&& REGISTER_NAME (regnum) != NULL
&& *REGISTER_NAME (regnum) != '\000')
{
changed = register_changed_p (regnum);
if (changed < 0)
{
do_cleanups (cleanup);
mi_error_message = xstrprintf ("mi_cmd_data_list_register_change: Unable to read register contents.");
return MI_CMD_ERROR;
}
else if (changed)
ui_out_field_int (uiout, NULL, regnum);
}
else
{
do_cleanups (cleanup);
mi_error_message = xstrprintf ("bad register number");
return MI_CMD_ERROR;
}
}
do_cleanups (cleanup);
return MI_CMD_DONE;
}
static int
register_changed_p (int regnum)
{
gdb_byte raw_buffer[MAX_REGISTER_SIZE];
if (! frame_register_read (get_selected_frame (NULL), regnum, raw_buffer))
return -1;
if (memcmp (&old_regs[DEPRECATED_REGISTER_BYTE (regnum)], raw_buffer,
register_size (current_gdbarch, regnum)) == 0)
return 0;
memcpy (&old_regs[DEPRECATED_REGISTER_BYTE (regnum)], raw_buffer,
register_size (current_gdbarch, regnum));
return 1;
}
enum mi_cmd_result
mi_cmd_data_list_register_values (char *command, char **argv, int argc)
{
int regnum, numregs, format, result;
int i;
struct cleanup *list_cleanup, *tuple_cleanup;
numregs = NUM_REGS + NUM_PSEUDO_REGS;
if (argc == 0)
{
mi_error_message = xstrprintf ("mi_cmd_data_list_register_values: Usage: -data-list-register-values <format> [<regnum1>...<regnumN>]");
return MI_CMD_ERROR;
}
format = (int) argv[0][0];
list_cleanup = make_cleanup_ui_out_list_begin_end (uiout, "register-values");
if (argc == 1)
{
for (regnum = 0;
regnum < numregs;
regnum++)
{
if (REGISTER_NAME (regnum) == NULL
|| *(REGISTER_NAME (regnum)) == '\0')
continue;
tuple_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
ui_out_field_int (uiout, "number", regnum);
result = get_register (regnum, format);
if (result == -1)
{
do_cleanups (list_cleanup);
return MI_CMD_ERROR;
}
do_cleanups (tuple_cleanup);
}
}
for (i = 1; i < argc; i++)
{
regnum = atoi (argv[i]);
if (regnum >= 0
&& regnum < numregs
&& REGISTER_NAME (regnum) != NULL
&& *REGISTER_NAME (regnum) != '\000')
{
tuple_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
ui_out_field_int (uiout, "number", regnum);
result = get_register (regnum, format);
if (result == -1)
{
do_cleanups (list_cleanup);
return MI_CMD_ERROR;
}
do_cleanups (tuple_cleanup);
}
else
{
do_cleanups (list_cleanup);
mi_error_message = xstrprintf ("bad register number");
return MI_CMD_ERROR;
}
}
do_cleanups (list_cleanup);
return MI_CMD_DONE;
}
static int
get_register (int regnum, int format)
{
gdb_byte buffer[MAX_REGISTER_SIZE];
enum opt_state optim;
int realnum;
CORE_ADDR addr;
enum lval_type lval;
static struct ui_stream *stb = NULL;
stb = ui_out_stream_new (uiout);
if (format == 'N')
format = 0;
frame_register (get_selected_frame (NULL), regnum, &optim, &lval, &addr,
&realnum, buffer);
if (optim)
{
mi_error_message = xstrprintf ("Optimized out");
return -1;
}
if (format == 'r')
{
int j;
char *ptr, buf[1024];
strcpy (buf, "0x");
ptr = buf + 2;
for (j = 0; j < register_size (current_gdbarch, regnum); j++)
{
int idx = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? j
: register_size (current_gdbarch, regnum) - 1 - j;
sprintf (ptr, "%02x", (unsigned char) buffer[idx]);
ptr += 2;
}
ui_out_field_string (uiout, "value", buf);
}
else
{
val_print (register_type (current_gdbarch, regnum), buffer, 0, 0,
stb->stream, format, 1, 0, Val_pretty_default);
ui_out_field_stream (uiout, "value", stb);
ui_out_stream_delete (stb);
}
return 1;
}
enum mi_cmd_result
mi_cmd_data_write_register_values (char *command, char **argv, int argc)
{
int regnum;
int i;
int numregs;
LONGEST value;
char format;
numregs = NUM_REGS + NUM_PSEUDO_REGS;
if (argc == 0)
{
mi_error_message = xstrprintf ("mi_cmd_data_write_register_values: Usage: -data-write-register-values <format> [<regnum1> <value1>...<regnumN> <valueN>]");
return MI_CMD_ERROR;
}
format = (int) argv[0][0];
if (!target_has_registers)
{
mi_error_message = xstrprintf ("mi_cmd_data_write_register_values: No registers.");
return MI_CMD_ERROR;
}
if (!(argc - 1))
{
mi_error_message = xstrprintf ("mi_cmd_data_write_register_values: No regs and values specified.");
return MI_CMD_ERROR;
}
if ((argc - 1) % 2)
{
mi_error_message = xstrprintf ("mi_cmd_data_write_register_values: Regs and vals are not in pairs.");
return MI_CMD_ERROR;
}
for (i = 1; i < argc; i = i + 2)
{
regnum = atoi (argv[i]);
if (regnum >= 0
&& regnum < numregs
&& REGISTER_NAME (regnum) != NULL
&& *REGISTER_NAME (regnum) != '\000')
{
void *buffer;
struct cleanup *old_chain;
value = parse_and_eval_address (argv[i + 1]);
buffer = xmalloc (DEPRECATED_REGISTER_SIZE);
old_chain = make_cleanup (xfree, buffer);
store_signed_integer (buffer, DEPRECATED_REGISTER_SIZE, value);
deprecated_write_register_bytes
(DEPRECATED_REGISTER_BYTE (regnum),
buffer, register_size (current_gdbarch, regnum));
do_cleanups (old_chain);
}
else
{
mi_error_message = xstrprintf ("bad register number");
return MI_CMD_ERROR;
}
}
return MI_CMD_DONE;
}
#if 0
enum mi_cmd_result
mi_cmd_data_assign (char *command, char **argv, int argc)
{
struct expression *expr;
struct cleanup *old_chain;
if (argc != 1)
{
mi_error_message = xstrprintf ("mi_cmd_data_assign: Usage: -data-assign expression");
return MI_CMD_ERROR;
}
old_chain = make_cleanup_set_restore_scheduler_locking_mode (scheduler_locking_on);
expr = parse_expression (argv[0]);
make_cleanup (free_current_contents, &expr);
evaluate_expression (expr);
do_cleanups (old_chain);
return MI_CMD_DONE;
}
#endif
enum mi_cmd_result
mi_cmd_data_evaluate_expression (char *command, char **argv, int argc)
{
struct expression *expr;
struct cleanup *old_chain = NULL;
struct value *val;
struct ui_stream *stb = NULL;
int unwinding_was_requested = 0;
char *expr_string;
stb = ui_out_stream_new (uiout);
if (argc == 1)
{
expr_string = argv[0];
}
else if (argc == 2)
{
if (strcmp (argv[0], "-u") != 0)
{
xasprintf (&mi_error_message,
"mi_cmd_data_evaluate_expression: Usage: "
"-data-evaluate-expression [-u] expression");
return MI_CMD_ERROR;
}
else
{
unwinding_was_requested = 1;
expr_string = argv[1];
}
}
else
{
mi_error_message = xstrprintf ("mi_cmd_data_evaluate_expression: Usage: -data-evaluate-expression [-u] expression");
return MI_CMD_ERROR;
}
old_chain = make_cleanup_set_restore_scheduler_locking_mode (scheduler_locking_on);
if (unwinding_was_requested)
make_cleanup (set_unwind_on_signal, set_unwind_on_signal (1));
expr = parse_expression (expr_string);
make_cleanup (free_current_contents, &expr);
val = evaluate_expression (expr);
val_print (value_type (val), value_contents (val),
value_embedded_offset (val), VALUE_ADDRESS (val),
stb->stream, 0, 0, 0, 0);
ui_out_field_stream (uiout, "value", stb);
ui_out_stream_delete (stb);
do_cleanups (old_chain);
return MI_CMD_DONE;
}
enum mi_cmd_result
mi_cmd_target_attach (char *command, char **argv, int argc)
{
if (argc != 1)
error ("mi_cmd_target_attach: Usage PID");
if (target_has_execution)
error ("mi_cmd_target_attach: Already debugging - detach first");
attach_command (argv[0], 0);
return MI_CMD_DONE;
}
enum mi_cmd_result
mi_cmd_target_download (char *args, int from_tty)
{
char *run;
struct cleanup *old_cleanups = NULL;
run = xstrprintf ("load %s", args);
old_cleanups = make_cleanup (xfree, run);
execute_command (run, from_tty);
do_cleanups (old_cleanups);
return MI_CMD_DONE;
}
enum mi_cmd_result
mi_cmd_target_select (char *args, int from_tty)
{
char *run;
struct cleanup *old_cleanups = NULL;
run = xstrprintf ("target %s", args);
old_cleanups = make_cleanup (xfree, run);
execute_command (run, from_tty);
do_cleanups (old_cleanups);
if (current_command_token)
fputs_unfiltered (current_command_token, raw_stdout);
fputs_unfiltered ("^connected", raw_stdout);
do_exec_cleanups (ALL_CLEANUPS);
return MI_CMD_QUIET;
}
enum mi_cmd_result
mi_cmd_data_read_memory (char *command, char **argv, int argc)
{
struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
CORE_ADDR addr;
long total_bytes;
long nr_cols;
long nr_rows;
char word_format;
struct type *word_type;
long word_size;
char word_asize;
char aschar;
char *mbuf;
int nr_bytes;
long offset = 0;
int optind = 0;
char *optarg;
enum opt
{
OFFSET_OPT
};
static struct mi_opt opts[] =
{
{"o", OFFSET_OPT, 1},
{0, 0, 0},
};
while (1)
{
int opt = mi_getopt ("mi_cmd_data_read_memory", argc, argv, opts,
&optind, &optarg);
if (opt < 0)
break;
switch ((enum opt) opt)
{
case OFFSET_OPT:
offset = atol (optarg);
break;
}
}
argv += optind;
argc -= optind;
if (argc < 5 || argc > 6)
{
mi_error_message = xstrprintf ("mi_cmd_data_read_memory: Usage: ADDR WORD-FORMAT WORD-SIZE NR-ROWS NR-COLS [ASCHAR].");
return MI_CMD_ERROR;
}
addr = parse_and_eval_address (argv[0]) + offset;
word_format = argv[1][0];
word_size = atol (argv[2]);
switch (word_size)
{
case 1:
word_type = builtin_type_int8;
word_asize = 'b';
break;
case 2:
word_type = builtin_type_int16;
word_asize = 'h';
break;
case 4:
word_type = builtin_type_int32;
word_asize = 'w';
break;
case 8:
word_type = builtin_type_int64;
word_asize = 'g';
break;
default:
word_type = builtin_type_int8;
word_asize = 'b';
}
nr_rows = atol (argv[3]);
if (nr_rows <= 0)
{
mi_error_message = xstrprintf ("mi_cmd_data_read_memory: invalid number of rows.");
return MI_CMD_ERROR;
}
nr_cols = atol (argv[4]);
if (nr_cols <= 0)
{
mi_error_message = xstrprintf ("mi_cmd_data_read_memory: invalid number of columns.");
return MI_CMD_ERROR;
}
if (argc == 6)
aschar = *argv[5];
else
aschar = 0;
total_bytes = word_size * nr_rows * nr_cols;
mbuf = xcalloc (total_bytes, 1);
make_cleanup (xfree, mbuf);
nr_bytes = target_read (¤t_target, TARGET_OBJECT_MEMORY, NULL,
mbuf, addr, total_bytes);
if (nr_bytes <= 0)
{
do_cleanups (cleanups);
mi_error_message = xstrdup ("Unable to read memory.");
return MI_CMD_ERROR;
}
ui_out_field_core_addr (uiout, "addr", 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);
{
struct ui_stream *stream = ui_out_stream_new (uiout);
struct cleanup *cleanup_list_memory;
int row;
int row_byte;
cleanup_list_memory = make_cleanup_ui_out_list_begin_end (uiout, "memory");
for (row = 0, row_byte = 0;
row < nr_rows;
row++, row_byte += nr_cols * word_size)
{
int col;
int col_byte;
struct cleanup *cleanup_tuple;
struct cleanup *cleanup_list_data;
cleanup_tuple = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
ui_out_field_core_addr (uiout, "addr", addr + row_byte);
cleanup_list_data = make_cleanup_ui_out_list_begin_end (uiout, "data");
for (col = 0, col_byte = row_byte;
col < nr_cols;
col++, col_byte += word_size)
{
if (col_byte + word_size > nr_bytes)
{
ui_out_field_string (uiout, NULL, "N/A");
}
else
{
ui_file_rewind (stream->stream);
print_scalar_formatted (mbuf + col_byte, word_type, word_format,
word_asize, stream->stream);
ui_out_field_stream (uiout, NULL, stream);
}
}
do_cleanups (cleanup_list_data);
if (aschar)
{
int byte;
ui_file_rewind (stream->stream);
for (byte = row_byte; byte < row_byte + word_size * nr_cols; byte++)
{
if (byte >= nr_bytes)
{
fputc_unfiltered ('X', stream->stream);
}
else if (mbuf[byte] < 32 || mbuf[byte] > 126)
{
fputc_unfiltered (aschar, stream->stream);
}
else
fputc_unfiltered (mbuf[byte], stream->stream);
}
ui_out_field_stream (uiout, "ascii", stream);
}
do_cleanups (cleanup_tuple);
}
ui_out_stream_delete (stream);
do_cleanups (cleanup_list_memory);
}
do_cleanups (cleanups);
return MI_CMD_DONE;
}
enum mi_cmd_result
mi_cmd_data_write_memory (char *command, char **argv, int argc)
{
CORE_ADDR addr;
char word_format;
long word_size;
LONGEST value;
void *buffer;
struct cleanup *old_chain;
long offset = 0;
int optind = 0;
char *optarg;
enum opt
{
OFFSET_OPT
};
static struct mi_opt opts[] =
{
{"o", OFFSET_OPT, 1},
{0, 0, 0},
};
while (1)
{
int opt = mi_getopt ("mi_cmd_data_write_memory", argc, argv, opts,
&optind, &optarg);
if (opt < 0)
break;
switch ((enum opt) opt)
{
case OFFSET_OPT:
offset = atol (optarg);
break;
}
}
argv += optind;
argc -= optind;
if (argc != 4)
{
mi_error_message = xstrprintf ("mi_cmd_data_write_memory: Usage: [-o COLUMN_OFFSET] ADDR FORMAT WORD-SIZE VALUE.");
return MI_CMD_ERROR;
}
addr = parse_and_eval_address (argv[0]);
word_format = argv[1][0];
word_size = atol (argv[2]);
addr += (offset * word_size);
value = parse_and_eval_address (argv[3]);
buffer = xmalloc (word_size);
old_chain = make_cleanup (xfree, buffer);
store_signed_integer (buffer, word_size, value);
write_memory (addr, buffer, word_size);
do_cleanups (old_chain);
return MI_CMD_DONE;
}
enum mi_cmd_result
mi_cmd_enable_timings (char *command, char **argv, int argc)
{
if (argc == 0)
do_timings = 1;
else if (argc == 1)
{
if (strcmp (argv[0], "yes") == 0)
do_timings = 1;
else if (strcmp (argv[0], "no") == 0)
do_timings = 0;
else
goto usage_error;
}
else
goto usage_error;
return MI_CMD_DONE;
usage_error:
error ("mi_cmd_enable_timings: Usage: %s {yes|no}", command);
return MI_CMD_ERROR;
}
enum mi_cmd_result
mi_cmd_mi_verify_command (char *command, char **argv, int argc)
{
char *command_name = argv[0];
struct mi_cmd *cmd;
if (argc != 1)
{
error ("mi_cmd_mi_verify_command: Usage: MI_COMMAND_NAME.");
}
cmd = mi_lookup (command_name);
ui_out_field_string (uiout, "name", command_name);
if (cmd != NULL)
{
ui_out_field_string (uiout, "defined", "true");
ui_out_field_string (uiout, "implemented",
((cmd->cli.cmd != NULL) ||
(cmd->argv_func != NULL) ||
(cmd->args_func != NULL)) ? "true" : "false");
}
else
{
ui_out_field_string (uiout, "defined", "false");
}
return MI_CMD_DONE;
}
enum mi_cmd_result
mi_cmd_pid_info (char *command, char **argv, int argc)
{
if (argc != 0)
{
error ("mi_cmd_pid_info: Usage: -pid-info");
}
pid_info (NULL, 1);
return MI_CMD_DONE;
}
enum mi_cmd_result
mi_cmd_mi_no_op (char *command, char **argv, int argc)
{
return MI_CMD_DONE;
}
static void
captured_mi_execute_command (struct ui_out *uiout, void *data)
{
struct captured_mi_execute_command_args *args =
(struct captured_mi_execute_command_args *) data;
struct mi_parse *context = args->command;
struct ui_out *saved_uiout = uiout;
struct mi_timestamp cmd_finished;
switch (context->op)
{
case MI_COMMAND:
if (mi_debug_p)
fprintf_unfiltered (raw_stdout, " token=`%s' command=`%s' args=`%s'\n",
context->token, context->command, context->args);
args->action = EXECUTE_COMMAND_DISPLAY_PROMPT;
current_command_token = context->token;
if (do_timings)
current_command_ts = context->cmd_start;
mi_interp_exec_cmd_did_run = 0;
args->rc = mi_cmd_execute (context);
if (current_command_ts == NULL)
context->cmd_start = NULL;
if (do_timings)
{
timestamp (&cmd_finished);
if (context->cmd_start)
end_remote_counts (context->cmd_start);
}
if (!target_can_async_p () && mi_interp_exec_cmd_did_run)
{
fputs_unfiltered ("(gdb) \n", raw_stdout);
gdb_flush (raw_stdout);
if (current_command_token)
{
fputs_unfiltered (current_command_token, raw_stdout);
}
fputs_unfiltered ("*stopped", raw_stdout);
mi_out_put (saved_uiout, raw_stdout);
mi_out_rewind (saved_uiout);
fputs_unfiltered ("\n", raw_stdout);
}
else if (!target_can_async_p () || !target_executing
|| mi_command_completes_while_target_executing (context->command))
{
if (args->rc == MI_CMD_DONE)
{
fputs_unfiltered (context->token, raw_stdout);
fputs_unfiltered ("^done", raw_stdout);
mi_out_put (saved_uiout, raw_stdout);
mi_out_rewind (saved_uiout);
if (do_timings && context->cmd_start)
{
print_diff (context->cmd_start, &cmd_finished);
}
fputs_unfiltered ("\n", raw_stdout);
}
else if (args->rc == MI_CMD_QUIET)
{
mi_out_put (saved_uiout, raw_stdout);
mi_out_rewind (saved_uiout);
if (do_timings && context->cmd_start)
print_diff (context->cmd_start, &cmd_finished);
fputs_unfiltered ("\n", raw_stdout);
}
else if (args->rc == MI_CMD_ERROR)
{
fputs_unfiltered (context->token, raw_stdout);
fputs_unfiltered ("^error", raw_stdout);
if (mi_error_message)
{
fputs_unfiltered (",msg=\"", raw_stdout);
fputstr_unfiltered (mi_error_message, '"', raw_stdout);
xfree (mi_error_message);
}
fputs_unfiltered ("\"\n", raw_stdout);
mi_out_rewind (saved_uiout);
}
else
mi_out_rewind (saved_uiout);
}
else if (sync_execution)
{
args->action = EXECUTE_COMMAND_SUPRESS_PROMPT;
return;
}
break;
case CLI_COMMAND:
{
char *argv[2];
fprintf_unfiltered (gdb_stdlog, "%s\n", context->command);
#if 0
argv[0] = "console";
argv[1] = context->command;
mi_cmd_interpreter_exec ("-interpreter-exec", argv, 2);
#endif
mi_execute_cli_command (context->command, 0, NULL);
if (1
|| current_interp_named_p (INTERP_MI)
|| current_interp_named_p (INTERP_MI1)
|| current_interp_named_p (INTERP_MI2)
|| current_interp_named_p (INTERP_MI3))
{
fputs_unfiltered (context->token, raw_stdout);
fputs_unfiltered ("^done", raw_stdout);
mi_out_put (saved_uiout, raw_stdout);
mi_out_rewind (saved_uiout);
fputs_unfiltered ("\n", raw_stdout);
args->action = EXECUTE_COMMAND_DISPLAY_PROMPT;
args->rc = MI_CMD_DONE;
}
break;
}
}
return;
}
void
mi_interpreter_exec_continuation (struct continuation_arg *in_arg)
{
struct mi_continuation_arg *arg
= (struct mi_continuation_arg *) in_arg;
if (!target_executing)
{
if (arg->cleanups != NULL)
do_exec_cleanups (arg->cleanups);
if (arg && arg->token)
fputs_unfiltered (arg->token, raw_stdout);
fputs_unfiltered ("*stopped", raw_stdout);
if (do_timings && arg && arg->timestamp)
{
end_remote_counts (arg->timestamp);
print_diff_now (arg->timestamp);
}
mi_out_put (uiout, raw_stdout);
fputs_unfiltered ("\n", raw_stdout);
if (target_can_async_p())
{
if (arg && arg->timestamp)
{
timestamp (arg->timestamp);
start_remote_counts (arg->timestamp, arg->token);
}
add_continuation (mi_interpreter_exec_continuation,
(struct continuation_arg *) arg);
}
bpstat_do_actions (&stop_bpstat);
if (!target_executing)
{
if (target_can_async_p ())
{
discard_all_continuations ();
free_continuation_arg (arg);
}
fputs_unfiltered ("(gdb) \n", raw_stdout);
}
else
{
ui_out_field_string (uiout, "reason", "breakpoint-command");
if (arg && arg->token)
fputs_unfiltered (arg->token, raw_stdout);
fputs_unfiltered ("*started", raw_stdout);
if (do_timings && arg && arg->timestamp)
{
end_remote_counts (arg->timestamp);
print_diff_now (arg->timestamp);
}
mi_out_put (uiout, raw_stdout);
fputs_unfiltered ("\n", raw_stdout);
}
gdb_flush (raw_stdout);
}
else if (target_can_async_p())
{
add_continuation (mi_interpreter_exec_continuation, in_arg);
}
}
void
mi_execute_command (char *cmd, int from_tty)
{
struct mi_parse *command;
struct ui_out *saved_uiout = uiout;
struct captured_mi_execute_command_args args;
args.rc = MI_CMD_DONE;
if (cmd == 0)
quit_force (NULL, from_tty);
command = mi_parse (cmd);
if (command != NULL)
{
struct gdb_exception result;
if (do_timings)
{
command->cmd_start = (struct mi_timestamp *)
xmalloc (sizeof (struct mi_timestamp));
timestamp (command->cmd_start);
start_remote_counts (command->cmd_start, command->token);
}
args.command = command;
result = catch_exception (uiout, captured_mi_execute_command, &args,
RETURN_MASK_ALL);
exception_print (gdb_stderr, result);
if (args.action == EXECUTE_COMMAND_SUPRESS_PROMPT)
{
mi_parse_free (command);
return;
}
if (result.reason < 0)
{
ui_out_cleanup_after_error (saved_uiout);
fputs_unfiltered (command->token, raw_stdout);
fputs_unfiltered ("^error,msg=\"", raw_stdout);
fputstr_unfiltered (result.message, '"', raw_stdout);
fputs_unfiltered ("\"", raw_stdout);
mi_out_put (saved_uiout, raw_stdout);
mi_out_rewind (saved_uiout);
fputs_unfiltered ("\n", raw_stdout);
}
mi_parse_free (command);
}
if (args.rc != MI_CMD_QUIET)
{
if (current_interp_named_p (INTERP_MI)
|| current_interp_named_p (INTERP_MI1)
|| current_interp_named_p (INTERP_MI2)
|| current_interp_named_p (INTERP_MI3))
fputs_unfiltered ("(gdb) \n", raw_stdout);
else
display_gdb_prompt (NULL);
}
gdb_flush (raw_stdout);
}
static int
mi_command_completes_while_target_executing (char *command)
{
if (strcmp (command, "exec-interrupt")
&& strcmp (command, "exec-status")
&& strcmp (command, "pid-info"))
return 0;
else
return 1;
}
static enum mi_cmd_result
mi_cmd_execute (struct mi_parse *parse)
{
if (parse->cmd->argv_func != NULL
|| parse->cmd->args_func != NULL)
{
if (target_executing)
{
if (!mi_command_completes_while_target_executing(parse->command))
{
fputs_unfiltered (parse->token, raw_stdout);
fputs_unfiltered ("^error,msg=\"", raw_stdout);
fputs_unfiltered ("Cannot execute command ", raw_stdout);
fputstr_unfiltered (parse->command, '"', raw_stdout);
fputs_unfiltered (" while target running", raw_stdout);
fputs_unfiltered ("\"\n", raw_stdout);
return MI_CMD_ERROR;
}
}
if (parse->cmd->args_func != NULL)
return parse->cmd->args_func (parse->args, 0 );
return parse->cmd->argv_func (parse->command, parse->argv, parse->argc);
}
else if (parse->cmd->cli.cmd != 0)
{
mi_execute_cli_command (parse->cmd->cli.cmd, parse->cmd->cli.args_p,
parse->args);
return MI_CMD_DONE;
}
else
{
fputs_unfiltered (parse->token, raw_stdout);
fputs_unfiltered ("^error,msg=\"", raw_stdout);
fputs_unfiltered ("Undefined mi command: ", raw_stdout);
fputstr_unfiltered (parse->command, '"', raw_stdout);
fputs_unfiltered (" (missing implementation)", raw_stdout);
fputs_unfiltered ("\"\n", raw_stdout);
return MI_CMD_ERROR;
}
}
void
mi_execute_command_wrapper (char *cmd)
{
mi_execute_command (cmd, stdin == instream);
}
void
mi_execute_cli_command (const char *cmd, int args_p, char *args)
{
if (cmd != 0)
{
struct cleanup *old_cleanups;
char *run;
if (args_p)
run = xstrprintf ("%s %s", cmd, args);
else
run = xstrdup (cmd);
if (mi_debug_p)
fprintf_unfiltered (gdb_stdout, "cli=%s run=%s\n",
cmd, run);
old_cleanups = make_cleanup (xfree, run);
execute_command ( run, 0 );
do_cleanups (old_cleanups);
return;
}
}
enum mi_cmd_result
mi_execute_async_cli_command (char *mi, char *args, int from_tty)
{
char *run;
char *async_args;
if (!target_can_async_p ())
{
struct cleanup *old_cleanups;
xasprintf (&run, "%s %s", mi, args);
old_cleanups = make_cleanup (xfree, run);
if (current_command_token)
fputs_unfiltered (current_command_token, raw_stdout);
fputs_unfiltered ("^running\n", raw_stdout);
fputs_unfiltered ("(gdb) \n", raw_stdout);
gdb_flush (raw_stdout);
execute_command ( run, 0 );
do_cleanups (old_cleanups);
bpstat_do_actions (&stop_bpstat);
if (current_command_token)
{
fputs_unfiltered (current_command_token, raw_stdout);
}
fputs_unfiltered ("*stopped", raw_stdout);
if (current_command_ts)
{
end_remote_counts (current_command_ts);
print_diff_now (current_command_ts);
xfree (current_command_ts);
current_command_ts = NULL;
}
return MI_CMD_QUIET;
}
else
{
struct mi_continuation_arg *arg = NULL;
struct cleanup *old_cleanups = NULL;
volatile struct gdb_exception except;
async_args = (char *) xmalloc (strlen (args) + 2);
old_cleanups = make_cleanup (free, async_args);
strcpy (async_args, args);
strcat (async_args, "&");
xasprintf (&run, "%s %s", mi, async_args);
make_cleanup (free, run);
arg = mi_setup_continuation_arg (NULL);
add_continuation (mi_exec_async_cli_cmd_continuation,
(struct continuation_arg *) arg);
arg->exec_error_cleanups
= make_exec_error_cleanup (mi_exec_error_cleanup, (void *) arg);
except = safe_execute_command (uiout, run, 0 );
do_cleanups (old_cleanups);
if (target_executing)
{
if (current_command_token)
fputs_unfiltered (current_command_token, raw_stdout);
fputs_unfiltered ("^running\n", raw_stdout);
}
else if (strcmp (mi, "step") == 0
&& stepping_into_inlined_subroutine)
{
stop_step = 1;
if (current_command_token)
fputs_unfiltered (current_command_token, raw_stdout);
fputs_unfiltered ("^running\n", raw_stdout);
ui_out_field_string (uiout, "reason",
async_reason_lookup
(EXEC_ASYNC_END_STEPPING_RANGE));
mi_exec_async_cli_cmd_continuation (arg);
}
else
{
discard_all_continuations ();
if (arg->exec_error_cleanups != (struct cleanups *) -1)
discard_exec_error_cleanups (arg->exec_error_cleanups);
free_continuation_arg (arg);
if (except.message != NULL)
mi_error_message = xstrdup (except.message);
else
mi_error_message = NULL;
return MI_CMD_ERROR;
}
}
return MI_CMD_DONE;
}
void
mi_exec_error_cleanup (void *in_arg)
{
struct mi_continuation_arg *arg =
(struct mi_continuation_arg *) in_arg;
struct ui_out *saved_ui_out = uiout;
uiout = interp_ui_out (mi_interp);
if (arg && arg->token)
{
fputs_unfiltered (arg->token, raw_stdout);
}
fputs_unfiltered ("*stopped", raw_stdout);
ui_out_field_string (uiout, "reason", "error");
if (do_timings && arg && arg->timestamp)
{
end_remote_counts (arg->timestamp);
print_diff_now (arg->timestamp);
}
mi_out_put (uiout, raw_stdout);
fputs_unfiltered ("\n", raw_stdout);
fputs_unfiltered ("(gdb) \n", raw_stdout);
gdb_flush (raw_stdout);
uiout = saved_ui_out;
}
void
mi_exec_async_cli_cmd_continuation (struct continuation_arg *in_arg)
{
struct mi_continuation_arg *arg =
(struct mi_continuation_arg *) in_arg;
if (!target_executing)
{
if (arg && arg->token)
{
fputs_unfiltered (arg->token, raw_stdout);
}
if (arg->cleanups)
{
do_exec_cleanups (arg->cleanups);
arg->cleanups = NULL;
}
if (arg->exec_error_cleanups != (struct cleanups *) -1)
{
discard_exec_error_cleanups (arg->exec_error_cleanups);
arg->exec_error_cleanups = -1;
}
fputs_unfiltered ("*stopped", raw_stdout);
if (do_timings && arg && arg->timestamp)
{
end_remote_counts (arg->timestamp);
print_diff_now (arg->timestamp);
}
mi_out_put (uiout, raw_stdout);
fputs_unfiltered ("\n", raw_stdout);
if (target_can_async_p ())
{
if (do_timings && arg && arg->timestamp)
{
timestamp (arg->timestamp);
start_remote_counts (arg->timestamp, arg->token);
}
add_continuation (mi_exec_async_cli_cmd_continuation,
(struct continuation_arg *) arg);
}
bpstat_do_actions (&stop_bpstat);
if (!target_executing)
{
if (target_can_async_p ())
{
discard_all_continuations ();
free_continuation_arg (arg);
}
fputs_unfiltered ("(gdb) \n", raw_stdout);
gdb_flush (raw_stdout);
}
else
{
if (arg && arg->token)
fputs_unfiltered (arg->token, raw_stdout);
ui_out_field_string (uiout, "reason", "breakpoint-command");
fputs_unfiltered ("*started", raw_stdout);
mi_out_put (uiout, raw_stdout);
fputs_unfiltered ("\n", raw_stdout);
gdb_flush (raw_stdout);
}
}
else if (target_can_async_p ())
{
add_continuation (mi_exec_async_cli_cmd_continuation, in_arg);
}
}
void
mi_setup_architecture_data (void)
{
old_regs = xmalloc ((NUM_REGS + NUM_PSEUDO_REGS) * MAX_REGISTER_SIZE + 1);
memset (old_regs, 0, (NUM_REGS + NUM_PSEUDO_REGS) * MAX_REGISTER_SIZE + 1);
}
void
_initialize_mi_main (void)
{
DEPRECATED_REGISTER_GDBARCH_SWAP (old_regs);
deprecated_register_gdbarch_swap (NULL, 0, mi_setup_architecture_data);
add_setshow_boolean_cmd ("mi-timings-enabled", class_obscure,
&do_timings, _("\
Set whether timing information is displayed for mi commands."), _("\
Show whether timing information is displayed for mi commands."), NULL,
NULL, NULL,
&setlist, &showlist);
}
int mi_dont_register_continuation = 0;
void
mi_interpreter_exec_bp_cmd (char *command, char **argv, int argc)
{
mi_dont_register_continuation = 1;
mi_cmd_interpreter_exec (command, argv, argc);
mi_dont_register_continuation = 0;
}
static void
route_output_through_mi (char *prefix, char *notification)
{
static struct ui_file *rerouting_ui_file = NULL;
if (rerouting_ui_file == NULL)
{
rerouting_ui_file = stdio_fileopen (stdout);
}
fprintf_unfiltered (rerouting_ui_file, "%s%s\n", prefix, notification);
gdb_flush (rerouting_ui_file);
}
static void
route_output_to_mi_result (const char *name, const char *string)
{
struct ui_out *mi_uiout;
if (mi_interp != NULL)
{
mi_uiout = interp_ui_out (mi_interp);
ui_out_field_string (mi_uiout, name, string);
}
}
void
mi_output_async_notification (char *notification)
{
route_output_through_mi ("=", notification);
}
static void
output_control_change_notification(char *notification)
{
route_output_through_mi ("^", notification);
}
void
mi_interp_stepping_command_hook ()
{
output_control_change_notification("stepping");
}
void
mi_interp_continue_command_hook ()
{
output_control_change_notification("continuing");
}
static void
mi_interp_sync_fake_running ()
{
char *prefix;
int free_me = 0;
if (current_command_token)
{
prefix = xmalloc (strlen (current_command_token) + 2);
sprintf (prefix, "%s^", current_command_token);
free_me = 1;
}
else
prefix = "^";
route_output_through_mi (prefix,"running");
if (free_me)
xfree (prefix);
ui_out_set_annotation_printer (route_output_to_mi_result);
}
void
mi_interp_sync_stepping_command_hook ()
{
mi_interp_exec_cmd_did_run = 1;
output_control_change_notification("stepping");
mi_interp_sync_fake_running ();
}
void
mi_interp_sync_continue_command_hook ()
{
mi_interp_exec_cmd_did_run = 1;
output_control_change_notification("continuing");
mi_interp_sync_fake_running ();
}
int
mi_interp_run_command_hook ()
{
mi_output_async_notification ("rerun");
return 0;
}
void
mi_interp_hand_call_function_hook ()
{
if (!scheduler_lock_on_p ())
{
struct cleanup *list_cleanup;
struct ui_out *saved_ui_out = uiout;
uiout = interp_ui_out (mi_interp);
list_cleanup = make_cleanup_ui_out_list_begin_end (uiout, "MI_HOOK_RESULT");
ui_out_field_string (uiout, "HOOK_TYPE", "function-called");
do_cleanups (list_cleanup);
uiout = saved_ui_out;
#if 0
mi_output_async_notification ("rerun");
#endif
}
}
struct mi_continuation_arg *
mi_setup_continuation_arg (struct cleanup *cleanups)
{
struct mi_continuation_arg *arg
= (struct mi_continuation_arg *)
xmalloc (sizeof (struct mi_continuation_arg));
if (current_command_token)
{
arg->token = xstrdup (current_command_token);
}
else
arg->token = NULL;
if (do_timings && current_command_ts)
{
arg->timestamp = (struct mi_timestamp *)
xmalloc (sizeof (struct mi_timestamp));
copy_timestamp (arg->timestamp, current_command_ts);
current_command_ts = NULL;
}
else
arg->timestamp = NULL;
arg->cleanups = cleanups;
arg->exec_error_cleanups = (struct cleanup *) -1;
return arg;
}
static void
free_continuation_arg (struct mi_continuation_arg *arg)
{
if (arg)
{
if (arg->token)
xfree (arg->token);
if (arg->timestamp)
{
end_remote_counts (arg->timestamp);
xfree (arg->timestamp);
arg->timestamp = NULL;
}
xfree (arg);
}
}
static void
timestamp (struct mi_timestamp *tv)
{
gettimeofday (&tv->wallclock, NULL);
getrusage (RUSAGE_SELF, &tv->rusage);
tv->remotestats.mi_token[0] = '\0';
tv->remotestats.assigned_to_global = 0;
}
static void
start_remote_counts (struct mi_timestamp *tv, const char *token)
{
tv->remotestats.pkt_sent = 0;
tv->remotestats.pkt_recvd = 0;
tv->remotestats.acks_sent = 0;
tv->remotestats.acks_recvd = 0;
timerclear (&tv->remotestats.totaltime);
tv->saved_remotestats = current_remote_stats;
if (token)
{
int bufsz = sizeof (tv->remotestats.mi_token);
strncpy (tv->remotestats.mi_token, token, bufsz - 1);
tv->remotestats.mi_token[bufsz - 1] = '\0';
}
else
tv->remotestats.mi_token[0] = '\0';
current_remote_stats = &tv->remotestats;
tv->remotestats.assigned_to_global = 1;
}
static void
end_remote_counts (struct mi_timestamp *tv)
{
if (tv && tv->remotestats.assigned_to_global)
{
current_remote_stats = tv->saved_remotestats;
tv->remotestats.assigned_to_global = 0;
}
}
static void
print_diff_now (struct mi_timestamp *start)
{
struct mi_timestamp now;
timestamp (&now);
print_diff (start, &now);
}
static void
copy_timestamp (struct mi_timestamp *dst, struct mi_timestamp *src)
{
memcpy (dst, src, sizeof (struct mi_timestamp));
}
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\",start=\"%d.%06d\",end=\"%d.%06d\"}",
wallclock_diff (start, end) / 1000000.0,
user_diff (start, end) / 1000000.0,
system_diff (start, end) / 1000000.0,
(int) start->wallclock.tv_sec, (int) start->wallclock.tv_usec,
(int) end->wallclock.tv_sec, (int) end->wallclock.tv_usec);
if (start->remotestats.pkt_sent != 0 || start->remotestats.pkt_recvd != 0)
{
fprintf_unfiltered (raw_stdout,
",remotestats={packets_sent=\"%d\",packets_received=\"%d\","
"acks_sent=\"%d\",acks_received=\"%d\","
"time=\"%0.5f\","
"total_packets_sent=\"%lld\",total_packets_received=\"%lld\"}",
start->remotestats.pkt_sent, start->remotestats.pkt_recvd,
start->remotestats.acks_sent, start->remotestats.acks_recvd,
(double) ((start->remotestats.totaltime.tv_sec * 1000000) + start->remotestats.totaltime.tv_usec) / 1000000.0,
total_packets_sent, total_packets_received);
}
}
static long
wallclock_diff (struct mi_timestamp *start, struct mi_timestamp *end)
{
struct timeval result;
timersub (&end->wallclock, &start->wallclock, &result);
return result.tv_sec * 1000000 + result.tv_usec;
}
static long
user_diff (struct mi_timestamp *start, struct mi_timestamp *end)
{
struct timeval result;
timersub (&(end->rusage.ru_utime), &(start->rusage.ru_utime), &result);
return result.tv_sec * 1000000 + result.tv_usec;
}
static long
system_diff (struct mi_timestamp *start, struct mi_timestamp *end)
{
struct timeval result;
timersub (&(end->rusage.ru_stime), &(start->rusage.ru_stime), &result);
return result.tv_sec * 1000000 + result.tv_usec;
}