#include <sys/time.h>
#include "defs.h"
#include "gdb_string.h"
#include "interps.h"
#include "event-top.h"
#include "event-loop.h"
#include "inferior.h"
#include "ui-out.h"
#include "top.h"
#include "mi-main.h"
#include "mi-cmds.h"
#include "mi-out.h"
#include "mi-console.h"
struct mi_interp
{
struct ui_file *out;
struct ui_file *err;
struct ui_file *log;
struct ui_file *targ;
struct ui_file *event_channel;
struct interp *mi2_interp;
struct interp *mi1_interp;
struct interp *mi_interp;
};
struct gdb_events mi_async_hooks =
{
NULL,
NULL,
NULL,
mi_async_breakpoint_resolve_event
};
static void mi_command_loop (int mi_version);
static char *mi_input (char *);
static int mi_interp_query_hook (const char *ctlstr, va_list ap);
static void mi3_command_loop (void);
static void mi2_command_loop (void);
static void mi1_command_loop (void);
static void mi0_command_loop (void);
static char *
mi_interp_read_one_line_hook (char *prompt, int repeat, char *anno);
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);
static void *
mi_interpreter_init (void)
{
struct mi_interp *mi = XMALLOC (struct mi_interp);
mi_setup_architecture_data ();
raw_stdout = stdio_fileopen (stdout);
mi->out = mi_console_file_new (raw_stdout, "~", '"');
mi->err = mi_console_file_new (raw_stdout, "&", '"');
mi->log = mi->err;
mi->targ = mi_console_file_new (raw_stdout, "@", '"');
mi->event_channel = mi_console_file_new (raw_stdout, "=", 0);
return mi;
}
static int
mi_interpreter_resume (void *data)
{
struct mi_interp *mi = data;
gdb_setup_readline ();
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->out;
gdb_stderr = mi->err;
gdb_stdlog = mi->log;
gdb_stdtarg = mi->targ;
clear_interpreter_hooks ();
show_load_progress = mi_load_progress;
print_frame_more_info_hook = mi_print_frame_more_info;
if (current_interp_named_p (INTERP_MI1))
command_loop_hook = mi1_command_loop;
else if (current_interp_named_p (INTERP_MI2))
command_loop_hook = mi2_command_loop;
else if (current_interp_named_p (INTERP_MI3))
command_loop_hook = mi3_command_loop;
else
command_loop_hook = mi0_command_loop;
set_gdb_event_hooks (&mi_async_hooks);
return 1;
}
static int
mi_interpreter_suspend (void *data)
{
gdb_disable_readline ();
return 1;
}
static int
mi_interpreter_exec (void *data, const char *command)
{
char *tmp = alloca (strlen (command) + 1);
strcpy (tmp, command);
mi_execute_command_wrapper (tmp);
return 1;
}
static int
mi_interpreter_prompt_p (void *data)
{
return 0;
}
enum mi_cmd_result
mi_cmd_interpreter_exec (char *command, char **argv, int argc)
{
struct interp *interp_to_use;
struct interp *old_interp;
enum mi_cmd_result result = MI_CMD_DONE;
int i;
int old_quiet;
if (argc < 2)
{
xasprintf (&mi_error_message,
"mi_cmd_interpreter_exec: Usage: -interpreter-exec interp command");
return MI_CMD_ERROR;
}
interp_to_use = interp_lookup (argv[0]);
if (interp_to_use == NULL)
{
xasprintf (&mi_error_message,
"mi_cmd_interpreter_exec: could not find interpreter \"%s\"",
argv[0]);
return MI_CMD_ERROR;
}
if (!interp_exec_p (interp_to_use))
{
xasprintf (&mi_error_message,
"mi_cmd_interpreter_exec: interpreter \"%s\" does not support command execution",
argv[0]);
return MI_CMD_ERROR;
}
old_quiet = interp_set_quiet (interp_to_use, 1);
old_interp = interp_set (interp_to_use);
if (old_interp == NULL)
{
asprintf (&mi_error_message,
"Could not switch to interpreter \"%s\".", argv[0]);
return MI_CMD_ERROR;
}
mi_interp = old_interp;
mi_insert_notify_hooks ();
for (i = 1; i < argc; i++)
{
char *buff = NULL;
if (target_can_async_p () && (strncmp (argv[0], "console", 7) == 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_exec (interp_to_use, argv[i]) < 0)
{
mi_error_last_message ();
result = MI_CMD_ERROR;
break;
}
xfree (buff);
do_exec_error_cleanups (ALL_CLEANUPS);
sync_execution = 0;
}
interp_set (old_interp);
mi_interp = NULL;
mi_remove_notify_hooks ();
interp_set_quiet (interp_to_use, old_quiet);
if (target_can_async_p () && target_executing
&& !mi_dont_register_continuation)
{
struct mi_continuation_arg *cont_args =
mi_setup_continuation_arg (NULL);
if (current_command_token)
fputs_unfiltered (current_command_token, raw_stdout);
fputs_unfiltered ("^running\n", raw_stdout);
add_continuation (mi_interpreter_exec_continuation,
(void *) cont_args);
}
return result;
}
enum mi_cmd_result
mi_cmd_interpreter_set (char *command, char **argv, int argc)
{
struct interp *interp;
if (argc != 1)
{
asprintf (&mi_error_message, "mi_cmd_interpreter_set: "
"wrong #of args, should be 1");
return MI_CMD_ERROR;
}
interp = interp_lookup (argv[0]);
if (interp == NULL)
{
asprintf (&mi_error_message, "mi_cmd_interpreter_set: "
"could not find interpreter %s", argv[0]);
return MI_CMD_ERROR;
}
if (interp_set (interp) == NULL)
{
asprintf (&mi_error_message, "mi_cmd_interpreter_set: "
"error setting interpreter %s", argv[0]);
return MI_CMD_ERROR;
}
return MI_CMD_DONE;
}
enum mi_cmd_result
mi_cmd_interpreter_complete (char *command, char **argv, int argc)
{
struct interp *interp_to_use;
int cursor;
if (argc < 2 || argc > 3)
{
asprintf (&mi_error_message,
"Wrong # or arguments, should be \"%s interp command <cursor>\".",
command);
return MI_CMD_ERROR;
}
interp_to_use = interp_lookup (argv[0]);
if (interp_to_use == NULL)
{
asprintf (&mi_error_message,
"Could not find interpreter \"%s\".", argv[0]);
return MI_CMD_ERROR;
}
if (argc == 3)
{
cursor = atoi (argv[2]);
}
else
{
cursor = strlen (argv[1]);
}
if (interp_complete (interp_to_use, argv[1], argv[1], cursor) == 0)
return MI_CMD_ERROR;
else
return MI_CMD_DONE;
}
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;
stack_changed_hook = mi_interp_stack_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;
stack_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;
}
static char *
mi_interp_read_one_line_hook (char *prompt, int repeat, char *anno)
{
static char buff[256];
if (strlen (prompt) > 200)
internal_error (__FILE__, __LINE__,
"Prompt \"%s\" ridiculously long.", prompt);
sprintf (buff, "read-one-line,prompt=\"%s\"", prompt);
mi_output_async_notification (buff);
(void) fgets(buff, sizeof(buff), stdin);
buff[(strlen(buff) - 1)] = 0;
return buff;
}
static void
mi0_command_loop (void)
{
mi_command_loop (0);
}
static void
mi1_command_loop (void)
{
mi_command_loop (1);
}
static void
mi2_command_loop (void)
{
mi_command_loop (2);
}
static void
mi3_command_loop (void)
{
mi_command_loop (3);
}
static void
mi_command_loop (int mi_version)
{
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, "@", '"');
#if 0
uiout = mi_out_new (mi_version);
#endif
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;
print_frame_more_info_hook = mi_print_frame_more_info;
uiout = interp_ui_out (NULL);
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 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)
{
struct cleanup *cleanup_tuple;
xfree (previous_sect_name);
previous_sect_name = xstrdup (section_name);
if (current_command_token)
fputs_unfiltered (current_command_token, raw_stdout);
fputs_unfiltered ("+download", raw_stdout);
cleanup_tuple = make_cleanup_ui_out_tuple_begin_end (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);
do_cleanups (cleanup_tuple);
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)
{
struct cleanup *cleanup_tuple;
last_update.tv_sec = time_now.tv_sec;
last_update.tv_usec = time_now.tv_usec;
if (current_command_token)
fputs_unfiltered (current_command_token, raw_stdout);
fputs_unfiltered ("+download", raw_stdout);
cleanup_tuple = make_cleanup_ui_out_tuple_begin_end (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);
do_cleanups (cleanup_tuple);
mi_out_put (uiout, raw_stdout);
fputs_unfiltered ("\n", raw_stdout);
gdb_flush (raw_stdout);
}
}
extern initialize_file_ftype _initialize_mi_interp;
void
_initialize_mi_interp (void)
{
static const struct interp_procs procs =
{
mi_interpreter_init,
mi_interpreter_resume,
mi_interpreter_suspend,
mi_interpreter_exec,
mi_interpreter_prompt_p
};
interp_add (interp_new (INTERP_MI1, NULL, mi_out_new (1), &procs));
interp_add (interp_new (INTERP_MI2, NULL, mi_out_new (2), &procs));
interp_add (interp_new (INTERP_MI3, NULL, mi_out_new (3), &procs));
interp_add (interp_new (INTERP_MI, NULL, mi_out_new (0), &procs));
}