#include "defs.h"
#include "target.h"
#include "inferior.h"
#include "gdb_string.h"
#include "top.h"
#include "gdbthread.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 "interpreter.h"
#include "event-loop.h"
#include "event-top.h"
#include "gdbcore.h"
#include "value.h"
#include "varobj.h"
#include "wrapper.h"
#include "regcache.h"
#include "gdb.h"
#include <ctype.h>
#include <sys/time.h>
#include <signal.h>
enum
{
FROM_TTY = 0
};
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;
static char *last_async_command;
static char *previous_async_command;
static char *mi_error_message;
static char *old_regs;
struct gdb_interpreter *mi_interp;
struct gdb_interpreter *mi0_interp;
struct gdb_interpreter *mi1_interp;
extern void _initialize_mi_main (void);
static char *mi_input (char *);
static void mi_execute_command (char *cmd, int from_tty);
static enum mi_cmd_result mi_cmd_execute (struct mi_parse *parse);
static void mi_execute_cli_command (const char *cli, char *args);
static enum mi_cmd_result mi_execute_async_cli_command (char *mi, char *args, int from_tty);
static void mi_execute_command_wrapper (char *cmd);
void mi_exec_async_cli_cmd_continuation (struct continuation_arg *arg);
static int register_changed_p (int regnum);
static int get_register (int regnum, int format);
static void mi_load_progress (const char *section_name,
unsigned long sent_so_far,
unsigned long total_section,
unsigned long total_sent,
unsigned long grand_total);
extern void interrupt_target_command_wrapper (char *, int);
extern void return_command_wrapper (char *, int);
int mi_interpreter_init (void *data);
int mi_interpreter_resume (void *data);
int mi_interpreter_do_one_event (void *data);
int mi_interpreter_suspend (void *data);
int mi_interpreter_delete (void *data);
int mi_interpreter_prompt(void *data, char *new_prompt);
int mi_interpreter_exec(void *data, char *command);
extern void mi_print_frame_more_info (struct ui_out *uiout,
struct symtab_and_line *sal,
struct frame_info *fi);
extern void mi_interp_create_breakpoint_hook (struct breakpoint *bpt);
extern void mi_interp_delete_breakpoint_hook (struct breakpoint *bpt);
extern void mi_interp_modify_breakpoint_hook (struct breakpoint *bpt);
extern int mi_interp_query_hook (const char *ctlstr, va_list ap);
extern void mi_interp_stack_changed_hook (void);
extern void mi_interp_frame_changed_hook (int new_frame_number);
extern void mi_interp_context_hook (int thread_id);
extern char * mi_interp_read_one_line_hook (char *prompt, int repeat, char *anno);
extern void mi_interp_stepping_command_hook(void);
extern void mi_interp_continue_command_hook(void);
extern int mi_interp_run_command_hook(void);
void mi_insert_notify_hooks (void);
void mi_remove_notify_hooks (void);
enum mi_cmd_result
mi_cmd_gdb_exit (char *command, char **argv, int argc)
{
if (last_async_command)
fputs_unfiltered (last_async_command, 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_wrapper (args, 0);
else
return_command_wrapper (NULL, 0);
show_and_print_stack_frame (selected_frame,
selected_frame_level,
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)
{
xasprintf (&mi_error_message,
"mi_cmd_exec_interrupt: Inferior not executing.");
return MI_CMD_ERROR;
}
if (0)
{
interrupt_target_command_wrapper (args, from_tty);
}
else
{
int pid = PIDGET (inferior_ptid);
kill (pid, SIGINT);
}
if (last_async_command) {
fputs_unfiltered (last_async_command, raw_stdout);
xfree (last_async_command);
last_async_command = NULL;
}
fputs_unfiltered ("^done", raw_stdout);
if (previous_async_command)
{
last_async_command = xstrdup (previous_async_command);
xfree (previous_async_command);
}
previous_async_command = NULL;
mi_out_put (uiout, raw_stdout);
mi_out_rewind (uiout);
fputs_unfiltered ("\n", raw_stdout);
return MI_CMD_QUIET;
}
enum mi_cmd_result
mi_cmd_thread_select (char *command, char **argv, int argc)
{
enum gdb_rc rc;
if (argc != 1)
{
xasprintf (&mi_error_message,
"mi_cmd_thread_select: USAGE: threadnum.");
return MI_CMD_ERROR;
}
else
rc = gdb_thread_select (uiout, argv[0]);
if (rc == GDB_RC_FAIL)
return MI_CMD_CAUGHT_ERROR;
else
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)
{
xasprintf (&mi_error_message,
"mi_cmd_thread_list_ids: No arguments required.");
return MI_CMD_ERROR;
}
else
rc = gdb_list_thread_ids (uiout);
if (rc == GDB_RC_FAIL)
return MI_CMD_CAUGHT_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;
numregs = NUM_REGS + NUM_PSEUDO_REGS;
ui_out_list_begin (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)
{
xasprintf (&mi_error_message, "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));
}
ui_out_list_end (uiout);
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;
numregs = NUM_REGS;
ui_out_list_begin (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)
{
xasprintf (&mi_error_message,
"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)
{
xasprintf (&mi_error_message,
"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
{
xasprintf (&mi_error_message, "bad register number");
return MI_CMD_ERROR;
}
}
ui_out_list_end (uiout);
return MI_CMD_DONE;
}
static int
register_changed_p (int regnum)
{
char *raw_buffer = alloca (MAX_REGISTER_RAW_SIZE);
if (read_relative_register_raw_bytes (regnum, raw_buffer))
return -1;
if (memcmp (&old_regs[REGISTER_BYTE (regnum)], raw_buffer,
REGISTER_RAW_SIZE (regnum)) == 0)
return 0;
memcpy (&old_regs[REGISTER_BYTE (regnum)], raw_buffer,
REGISTER_RAW_SIZE (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;
numregs = NUM_REGS;
if (argc == 0)
{
xasprintf (&mi_error_message,
"mi_cmd_data_list_register_values: Usage: -data-list-register-values <format> [<regnum1>...<regnumN>]");
return MI_CMD_ERROR;
}
format = (int) argv[0][0];
if (!target_has_registers)
{
xasprintf (&mi_error_message,
"mi_cmd_data_list_register_values: No registers.");
return MI_CMD_ERROR;
}
ui_out_list_begin (uiout, "register-values");
if (argc == 1)
{
for (regnum = 0;
regnum < numregs;
regnum++)
{
if (REGISTER_NAME (regnum) == NULL
|| *(REGISTER_NAME (regnum)) == '\0')
continue;
ui_out_tuple_begin (uiout, NULL);
ui_out_field_int (uiout, "number", regnum);
result = get_register (regnum, format);
if (result == -1)
return MI_CMD_ERROR;
ui_out_tuple_end (uiout);
}
}
for (i = 1; i < argc; i++)
{
regnum = atoi (argv[i]);
if (regnum >= 0
&& regnum < numregs
&& REGISTER_NAME (regnum) != NULL
&& *REGISTER_NAME (regnum) != '\000')
{
ui_out_tuple_begin (uiout, NULL);
ui_out_field_int (uiout, "number", regnum);
result = get_register (regnum, format);
if (result == -1)
return MI_CMD_ERROR;
ui_out_tuple_end (uiout);
}
else
{
xasprintf (&mi_error_message, "bad register number");
return MI_CMD_ERROR;
}
}
ui_out_list_end (uiout);
return MI_CMD_DONE;
}
static int
get_register (int regnum, int format)
{
char *raw_buffer = alloca (MAX_REGISTER_RAW_SIZE);
char *virtual_buffer = alloca (MAX_REGISTER_VIRTUAL_SIZE);
int optim;
static struct ui_stream *stb = NULL;
stb = ui_out_stream_new (uiout);
if (format == 'N')
format = 0;
get_saved_register (raw_buffer, &optim, (CORE_ADDR *) NULL, selected_frame,
regnum, (enum lval_type *) NULL);
if (optim)
{
xasprintf (&mi_error_message, "Optimized out");
return -1;
}
if (REGISTER_CONVERTIBLE (regnum))
{
REGISTER_CONVERT_TO_VIRTUAL (regnum, REGISTER_VIRTUAL_TYPE (regnum),
raw_buffer, virtual_buffer);
}
else
memcpy (virtual_buffer, raw_buffer, REGISTER_VIRTUAL_SIZE (regnum));
if (format == 'r')
{
int j;
char *ptr, buf[1024];
strcpy (buf, "0x");
ptr = buf + 2;
for (j = 0; j < REGISTER_RAW_SIZE (regnum); j++)
{
register int idx = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? j
: REGISTER_RAW_SIZE (regnum) - 1 - j;
sprintf (ptr, "%02x", (unsigned char) raw_buffer[idx]);
ptr += 2;
}
ui_out_field_string (uiout, "value", buf);
}
else
{
val_print (REGISTER_VIRTUAL_TYPE (regnum), virtual_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;
if (argc == 0)
{
xasprintf (&mi_error_message,
"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)
{
xasprintf (&mi_error_message,
"mi_cmd_data_write_register_values: No registers.");
return MI_CMD_ERROR;
}
if (!(argc - 1))
{
xasprintf (&mi_error_message,
"mi_cmd_data_write_register_values: No regs and values specified.");
return MI_CMD_ERROR;
}
if ((argc - 1) % 2)
{
xasprintf (&mi_error_message,
"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 (REGISTER_SIZE);
old_chain = make_cleanup (xfree, buffer);
store_signed_integer (buffer, REGISTER_SIZE, value);
write_register_bytes (REGISTER_BYTE (regnum), buffer, REGISTER_RAW_SIZE (regnum));
do_cleanups (old_chain);
}
else
{
xasprintf (&mi_error_message, "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)
{
xasprintf (&mi_error_message,
"mi_cmd_data_assign: Usage: -data-assign expression");
return MI_CMD_ERROR;
}
expr = parse_expression (argv[0]);
old_chain = 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 unwind = 0;
char *expr_string;
stb = ui_out_stream_new (uiout);
if (argc == 1)
{
expr_string = argv[0];
unwind = 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
{
unwind = 1;
expr_string = argv[1];
}
}
else
{
xasprintf (&mi_error_message,
"mi_cmd_data_evaluate_expression: Usage: -data-evaluate-expression [-u] expression");
return MI_CMD_ERROR;
}
unwind = set_unwind_on_signal (unwind);
old_chain = make_cleanup (set_unwind_on_signal, unwind);
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_download (char *args, int from_tty)
{
char *run;
struct cleanup *old_cleanups = NULL;
xasprintf (&run, "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;
xasprintf (&run, "target %s", args);
old_cleanups = make_cleanup (xfree, run);
execute_command (run, from_tty);
do_cleanups (old_cleanups);
if (last_async_command)
fputs_unfiltered (last_async_command, raw_stdout);
fputs_unfiltered ("^connected", raw_stdout);
mi_out_put (uiout, raw_stdout);
mi_out_rewind (uiout);
fputs_unfiltered ("\n", 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
};
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)
{
xasprintf (&mi_error_message,
"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)
{
xasprintf (&mi_error_message,
"mi_cmd_data_read_memory: invalid number of rows.");
return MI_CMD_ERROR;
}
nr_cols = atol (argv[4]);
if (nr_cols <= 0)
{
xasprintf (&mi_error_message,
"mi_cmd_data_read_memory: invalid number of columns.");
}
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);
if (mbuf == NULL)
{
xasprintf (&mi_error_message,
"mi_cmd_data_read_memory: out of memory.");
return MI_CMD_ERROR;
}
nr_bytes = 0;
while (nr_bytes < total_bytes)
{
int error;
long num = target_read_memory_partial (addr + nr_bytes, mbuf + nr_bytes,
total_bytes - nr_bytes,
&error);
if (num <= 0)
break;
nr_bytes += num;
}
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);
int row;
int row_byte;
ui_out_list_begin (uiout, "memory");
for (row = 0, row_byte = 0;
row < nr_rows;
row++, row_byte += nr_cols * word_size)
{
int col;
int col_byte;
ui_out_tuple_begin (uiout, NULL);
ui_out_field_core_addr (uiout, "addr", addr + row_byte);
ui_out_list_begin (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);
}
}
ui_out_list_end (uiout);
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);
}
ui_out_tuple_end (uiout);
}
ui_out_stream_delete (stream);
ui_out_list_end (uiout);
}
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
};
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)
{
xasprintf (&mi_error_message,
"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_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 != 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_mi_no_op (char *command, char **argv, int argc)
{
return MI_CMD_DONE;
}
static int
captured_mi_execute_command (void *data)
{
struct mi_parse *context = data;
struct ui_out *saved_uiout = uiout;
enum mi_cmd_result rc = MI_CMD_DONE;
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);
rc = mi_cmd_execute (context);
if (!target_can_async_p () || !target_executing)
{
if (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);
fputs_unfiltered ("\n", raw_stdout);
}
else if (rc == MI_CMD_ERROR)
{
if (mi_error_message)
{
fputs_unfiltered (context->token, raw_stdout);
fputs_unfiltered ("^error,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 if (rc == MI_CMD_CAUGHT_ERROR)
{
mi_out_rewind (saved_uiout);
return 0;
}
else
mi_out_rewind (saved_uiout);
}
else if (sync_execution)
return -1;
break;
case CLI_COMMAND:
fprintf_unfiltered (gdb_stdlog, "%s\n", context->command);
mi_execute_cli_command ("%s", context->command);
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);
break;
}
return rc;
}
void
mi_execute_command (char *cmd, int from_tty)
{
struct mi_parse *command;
struct ui_out *saved_uiout = uiout;
int rc = MI_CMD_DONE;
if (cmd == 0)
quit_force (NULL, from_tty);
command = mi_parse (cmd);
if (command != NULL)
{
rc = catch_errors (captured_mi_execute_command, command, "",
RETURN_MASK_ALL);
if (rc < 0)
{
mi_parse_free (command);
return;
}
if (rc == 0)
{
char *msg = error_last_message ();
struct cleanup *cleanup = make_cleanup (xfree, msg);
ui_out_cleanup_after_error (saved_uiout);
fputs_unfiltered (command->token, raw_stdout);
fputs_unfiltered ("^error,msg=\"", raw_stdout);
fputstr_unfiltered (msg, '"', 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 (rc != MI_CMD_QUIET)
{
fputs_unfiltered ("(gdb) \n", raw_stdout);
gdb_flush (raw_stdout);
}
gdb_flush (raw_stdout);
}
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 (!previous_async_command && last_async_command)
previous_async_command = xstrdup (last_async_command);
if (strcmp (parse->command, "exec-interrupt"))
{
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;
}
}
last_async_command = xstrdup (parse->token);
make_exec_cleanup (free_current_contents, &last_async_command);
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 != 0)
{
mi_execute_cli_command (parse->cmd->cli, 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;
}
}
static void
mi_execute_command_wrapper (char *cmd)
{
mi_execute_command (cmd, stdin == instream);
}
void
mi_execute_cli_command (const char *cli, char *args)
{
if (cli != 0)
{
struct cleanup *old_cleanups;
char *run;
xasprintf (&run, cli, args);
if (mi_debug_p)
fprintf_unfiltered (gdb_stdout, "cli=%s run=%s\n",
cli, 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)
{
struct cleanup *old_cleanups;
char *run;
char *async_args;
if (target_can_async_p ())
{
async_args = (char *) xmalloc (strlen (args) + 2);
make_exec_cleanup (free, async_args);
strcpy (async_args, args);
strcat (async_args, "&");
xasprintf (&run, "%s %s", mi, async_args);
make_exec_cleanup (free, run);
add_continuation (mi_exec_async_cli_cmd_continuation, NULL);
old_cleanups = NULL;
}
else
{
xasprintf (&run, "%s %s", mi, args);
old_cleanups = make_cleanup (xfree, run);
}
if (!target_can_async_p ())
{
if (last_async_command)
fputs_unfiltered (last_async_command, raw_stdout);
fputs_unfiltered ("^running\n", raw_stdout);
fputs_unfiltered ("(gdb) \n", raw_stdout);
gdb_flush (raw_stdout);
}
else
{
if (last_async_command)
fputs_unfiltered (last_async_command, raw_stdout);
fputs_unfiltered ("^running\n", raw_stdout);
}
execute_command ( run, 0 );
if (!target_can_async_p ())
{
do_cleanups (old_cleanups);
if (last_async_command)
fputs_unfiltered (last_async_command, raw_stdout);
fputs_unfiltered ("*stopped", raw_stdout);
mi_out_put (uiout, raw_stdout);
mi_out_rewind (uiout);
fputs_unfiltered ("\n", raw_stdout);
return MI_CMD_QUIET;
}
return MI_CMD_DONE;
}
void
mi_exec_async_cli_cmd_continuation (struct continuation_arg *arg)
{
if (last_async_command)
fputs_unfiltered (last_async_command, raw_stdout);
if (!target_executing)
{
do_exec_cleanups (ALL_CLEANUPS);
fputs_unfiltered ("*stopped", raw_stdout);
mi_out_put (uiout, raw_stdout);
fputs_unfiltered ("\n", raw_stdout);
bpstat_do_actions (&stop_bpstat);
if (!target_executing)
{
fputs_unfiltered ("(gdb) \n", raw_stdout);
gdb_flush (raw_stdout);
}
else
{
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, NULL);
}
}
static char *
mi_input (char *buf)
{
return gdb_readline (NULL);
}
static void
mi_load_progress (const char *section_name,
unsigned long sent_so_far,
unsigned long total_section,
unsigned long total_sent,
unsigned long grand_total)
{
struct timeval time_now, delta, update_threshold;
static struct timeval last_update;
static char *previous_sect_name = NULL;
int new_section;
if (!interpreter_p || strncmp (interpreter_p, "mi", 2) != 0)
return;
update_threshold.tv_sec = 0;
update_threshold.tv_usec = 500000;
gettimeofday (&time_now, NULL);
delta.tv_usec = time_now.tv_usec - last_update.tv_usec;
delta.tv_sec = time_now.tv_sec - last_update.tv_sec;
if (delta.tv_usec < 0)
{
delta.tv_sec -= 1;
delta.tv_usec += 1000000;
}
new_section = (previous_sect_name ?
strcmp (previous_sect_name, section_name) : 1);
if (new_section)
{
xfree (previous_sect_name);
previous_sect_name = xstrdup (section_name);
if (last_async_command)
fputs_unfiltered (last_async_command, raw_stdout);
fputs_unfiltered ("+download", raw_stdout);
ui_out_tuple_begin (uiout, NULL);
ui_out_field_string (uiout, "section", section_name);
ui_out_field_int (uiout, "section-size", total_section);
ui_out_field_int (uiout, "total-size", grand_total);
ui_out_tuple_end (uiout);
mi_out_put (uiout, raw_stdout);
fputs_unfiltered ("\n", raw_stdout);
gdb_flush (raw_stdout);
}
if (delta.tv_sec >= update_threshold.tv_sec &&
delta.tv_usec >= update_threshold.tv_usec)
{
last_update.tv_sec = time_now.tv_sec;
last_update.tv_usec = time_now.tv_usec;
if (last_async_command)
fputs_unfiltered (last_async_command, raw_stdout);
fputs_unfiltered ("+download", raw_stdout);
ui_out_tuple_begin (uiout, NULL);
ui_out_field_string (uiout, "section", section_name);
ui_out_field_int (uiout, "section-sent", sent_so_far);
ui_out_field_int (uiout, "section-size", total_section);
ui_out_field_int (uiout, "total-sent", total_sent);
ui_out_field_int (uiout, "total-size", grand_total);
ui_out_tuple_end (uiout);
mi_out_put (uiout, raw_stdout);
fputs_unfiltered ("\n", raw_stdout);
gdb_flush (raw_stdout);
}
}
static void
mi_command_loop ()
{
raw_stdout = stdio_fileopen (stdout);
gdb_stdout = mi_console_file_new (raw_stdout, "~");
gdb_stderr = mi_console_file_new (raw_stdout, "&");
gdb_stdlog = gdb_stderr;
gdb_stdtarg = mi_console_file_new (raw_stdout, "@");
uiout = gdb_interpreter_ui_out (gdb_current_interpreter ());
init_ui_hook = 0;
print_frame_info_listing_hook = 0;
query_hook = 0;
warning_hook = 0;
create_breakpoint_hook = 0;
delete_breakpoint_hook = 0;
modify_breakpoint_hook = 0;
interactive_hook = 0;
registers_changed_hook = 0;
readline_begin_hook = 0;
readline_hook = 0;
readline_end_hook = 0;
register_changed_hook = 0;
memory_changed_hook = 0;
context_hook = 0;
target_wait_hook = 0;
call_command_hook = 0;
error_hook = 0;
error_begin_hook = 0;
show_load_progress = mi_load_progress;
sevenbit_strings = 1;
fputs_unfiltered ("(gdb) \n", raw_stdout);
gdb_flush (raw_stdout);
if (!event_loop_p)
simplified_command_loop (mi_input, mi_execute_command);
else
start_event_loop ();
}
static void
setup_architecture_data (void)
{
old_regs = xmalloc (REGISTER_BYTES + 1);
memset (old_regs, 0, REGISTER_BYTES + 1);
}
static void
mi_init_ui (char *arg0)
{
}
static struct gdb_interpreter *
mi_create_interpreter (char *name, int mi_version)
{
struct gdb_interpreter *interp;
interp = gdb_new_interpreter (name, (void *) mi_version,
mi_out_new (mi_version),
mi_interpreter_init,
mi_interpreter_resume,
NULL ,
mi_interpreter_suspend,
mi_interpreter_delete,
mi_interpreter_exec,
mi_interpreter_prompt);
if (interp == NULL)
error ("Couldn't allocate a new interpreter for the mi interpreter\n");
if (gdb_add_interpreter (interp) != 1)
error ("Couldn't add the mi interpreter to gdb.\n");
return interp;
}
void
_initialize_mi_main (void)
{
static int init = 0;
if (init)
return;
init = 1;
mi_interp = mi_create_interpreter ("mi", 0);
mi0_interp = mi_create_interpreter ("mi0", 0);
mi1_interp = mi_create_interpreter ("mi1", 1);
}
int
mi_interpreter_init (void *data)
{
setup_architecture_data ();
raw_stdout = stdio_fileopen (stdout);
mi_stdout = mi_console_file_new (raw_stdout, "~");
mi_stderr = mi_console_file_new (raw_stdout, "&");
mi_stdlog = mi_stderr;
mi_stdtarg = mi_console_file_new (raw_stdout, "@");
return 1;
}
int
mi_interpreter_resume (void *data)
{
gdb_setup_readline ();
register_gdbarch_swap (&old_regs, sizeof (old_regs), NULL);
register_gdbarch_swap (NULL, 0, setup_architecture_data);
if (event_loop_p)
{
call_readline = gdb_readline2;
input_handler = mi_execute_command_wrapper;
add_file_handler (input_fd, stdin_event_handler, 0);
async_command_editing_p = 0;
sync_execution = 0;
}
gdb_stdout = mi_stdout;
gdb_stderr = mi_stderr;
gdb_stdlog = mi_stdlog;
gdb_stdtarg = mi_stdtarg;
clear_interpreter_hooks ();
command_loop_hook = mi_command_loop;
show_load_progress = mi_load_progress;
print_frame_more_info_hook = mi_print_frame_more_info;
sevenbit_strings = 1;
return 1;
}
int
mi_interpreter_suspend (void *data)
{
gdb_disable_readline ();
return 1;
}
int
mi_interpreter_delete (void *data)
{
return 1;
}
int
mi_interpreter_prompt(void *data, char *new_prompt)
{
return 1;
}
int
mi_interpreter_exec(void *data, char *command)
{
mi_execute_command (command, 0);
return 1;
}
int
mi_do_one_event (void *data)
{
return 1;
}
void
mi_interpreter_exec_continuation (struct continuation_arg *arg)
{
if (!target_executing)
{
do_exec_cleanups (ALL_CLEANUPS);
fputs_unfiltered ("*stopped", raw_stdout);
mi_out_put (uiout, raw_stdout);
fputs_unfiltered ("\n", raw_stdout);
bpstat_do_actions (&stop_bpstat);
if (!target_executing)
{
fputs_unfiltered ("(gdb) \n", raw_stdout);
}
else
{
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_interpreter_exec_continuation, NULL);
}
}
enum mi_cmd_result
mi_cmd_interpreter_exec (char *command, char **argv, int argc)
{
struct gdb_interpreter *old_interp, *interp_to_use;
enum mi_cmd_result result = MI_CMD_DONE;
int i, old_quiet;
if (argc < 2)
{
asprintf (&mi_error_message,
"Wrong # or arguments, should be \"%s interp cmd <cmd ...>\".",
command);
return MI_CMD_ERROR;
}
old_interp = gdb_current_interpreter ();
interp_to_use = gdb_lookup_interpreter (argv[0]);
if (interp_to_use == NULL)
{
asprintf (&mi_error_message,
"Could not find interpreter \"%s\".", argv[0]);
return MI_CMD_ERROR;
}
if (!interp_to_use->exec_proc)
{
asprintf (&mi_error_message, "Interpreter \"%s\" does not support command execution.",
argv[0]);
return MI_CMD_ERROR;
}
old_quiet = gdb_interpreter_set_quiet (interp_to_use, 1);
if (!gdb_set_interpreter (interp_to_use))
{
asprintf (&mi_error_message,
"Could not switch to interpreter \"%s\".", argv[0]);
return MI_CMD_ERROR;
}
mi_insert_notify_hooks ();
for (i = 1; i < argc; i++) {
char *buff = NULL;
if (target_can_async_p () && (strcmp (argv[0], "console") == 0))
{
int len = strlen (argv[i]);
buff = xmalloc (len + 2);
memcpy (buff, argv[i], len);
buff[len] = '&';
buff[len + 1] = '\0';
}
sync_execution = 1;
if (!interp_to_use->exec_proc (interp_to_use->data, argv[i]))
{
asprintf (&mi_error_message,
"mi_interpreter_execute: error in command: \"%s\".",
argv[i]);
result = MI_CMD_ERROR;
break;
}
xfree (buff);
do_exec_error_cleanups (ALL_CLEANUPS);
sync_execution = 0;
}
gdb_set_interpreter (old_interp);
mi_remove_notify_hooks ();
gdb_interpreter_set_quiet (interp_to_use, old_quiet);
if (target_can_async_p () && target_executing)
{
fputs_unfiltered ("^running\n", raw_stdout);
add_continuation (mi_interpreter_exec_continuation, NULL);
}
return result;
}
enum mi_cmd_result
mi_cmd_interpreter_set (char *command, char **argv, int argc)
{
struct gdb_interpreter *interp;
int result;
if (argc != 1)
{
asprintf (&mi_error_message, "mi_cmd_interpreter_set: wrong #of args, should be 1");
return MI_CMD_ERROR;
}
interp = gdb_lookup_interpreter (argv[0]);
if (interp == NULL)
{
asprintf (&mi_error_message, "mi_cmd_interpreter_set: could not find interpreter %s", argv[0]);
return MI_CMD_ERROR;
}
result = gdb_set_interpreter (interp);
if (result != 1)
{
asprintf (&mi_error_message, "mi_cmd_interpreter_set: error setting interpreter %s", argv[0]);
return MI_CMD_ERROR;
}
return MI_CMD_QUIET;
}
void
mi_insert_notify_hooks (void)
{
create_breakpoint_hook = mi_interp_create_breakpoint_hook;
delete_breakpoint_hook = mi_interp_delete_breakpoint_hook;
modify_breakpoint_hook = mi_interp_modify_breakpoint_hook;
frame_changed_hook = mi_interp_frame_changed_hook;
context_hook = mi_interp_context_hook;
query_hook = mi_interp_query_hook;
command_line_input_hook = mi_interp_read_one_line_hook;
stepping_command_hook = mi_interp_stepping_command_hook;
continue_command_hook = mi_interp_continue_command_hook;
run_command_hook = mi_interp_run_command_hook;
}
void
mi_remove_notify_hooks ()
{
create_breakpoint_hook = NULL;
delete_breakpoint_hook = NULL;
modify_breakpoint_hook = NULL;
frame_changed_hook = NULL;
context_hook = NULL;
query_hook = NULL;
command_line_input_hook = NULL;
stepping_command_hook = NULL;
continue_command_hook = NULL;
run_command_hook = NULL;
}
int
mi_interp_query_hook (const char * ctlstr, va_list ap)
{
return 1;
}
char *
mi_interp_read_one_line_hook (char *prompt, int repeat, char *anno)
{
static char buff[256];
printf_unfiltered ("=read-one-line,prompt=\"%s\"\n", prompt);
gdb_flush (gdb_stdout);
(void) fgets(buff, sizeof(buff), stdin);
buff[(strlen(buff) - 1)] = 0;
return buff;
}
static void
output_control_change_notification(char *notification)
{
printf_unfiltered ("^");
printf_unfiltered ("%s\n", notification);
gdb_flush (gdb_stdout);
}
void
mi_interp_stepping_command_hook ()
{
output_control_change_notification("stepping");
}
void
mi_interp_continue_command_hook ()
{
output_control_change_notification("continuing");
}
int
mi_interp_run_command_hook ()
{
printf_unfiltered ("=rerun\n");
gdb_flush (gdb_stdout);
return 0;
}