/* MI Interpreter Definitions and Commands for GDB, the GNU debugger.
- Copyright (C) 2002-2005, 2007-2012 Free Software Foundation, Inc.
+ Copyright (C) 2002-2013 Free Software Foundation, Inc.
This file is part of GDB.
#include "gdbthread.h"
#include "solist.h"
#include "gdb.h"
+#include "objfiles.h"
+#include "tracepoint.h"
/* These are the interpreter setup, etc. functions for the MI
interpreter. */
-static void mi_execute_command_wrapper (char *cmd);
+static void mi_execute_command_wrapper (const char *cmd);
static void mi_execute_command_input_handler (char *cmd);
static void mi_command_loop (int mi_version);
static void mi_new_thread (struct thread_info *t);
static void mi_thread_exit (struct thread_info *t, int silent);
+static void mi_record_changed (struct inferior*, int);
static void mi_inferior_added (struct inferior *inf);
static void mi_inferior_appeared (struct inferior *inf);
static void mi_inferior_exit (struct inferior *inf);
static void mi_solib_loaded (struct so_list *solib);
static void mi_solib_unloaded (struct so_list *solib);
static void mi_about_to_proceed (void);
+static void mi_traceframe_changed (int tfnum, int tpnum);
+static void mi_tsv_created (const struct trace_state_variable *tsv);
+static void mi_tsv_deleted (const struct trace_state_variable *tsv);
+static void mi_tsv_modified (const struct trace_state_variable *tsv);
static void mi_breakpoint_created (struct breakpoint *b);
static void mi_breakpoint_deleted (struct breakpoint *b);
static void mi_breakpoint_modified (struct breakpoint *b);
static void mi_command_param_changed (const char *param, const char *value);
+static void mi_memory_changed (struct inferior *inf, CORE_ADDR memaddr,
+ ssize_t len, const bfd_byte *myaddr);
static int report_initial_inferior (struct inferior *inf, void *closure);
observer_attach_inferior_appeared (mi_inferior_appeared);
observer_attach_inferior_exit (mi_inferior_exit);
observer_attach_inferior_removed (mi_inferior_removed);
+ observer_attach_record_changed (mi_record_changed);
observer_attach_normal_stop (mi_on_normal_stop);
observer_attach_target_resumed (mi_on_resume);
observer_attach_solib_loaded (mi_solib_loaded);
observer_attach_solib_unloaded (mi_solib_unloaded);
observer_attach_about_to_proceed (mi_about_to_proceed);
+ observer_attach_traceframe_changed (mi_traceframe_changed);
+ observer_attach_tsv_created (mi_tsv_created);
+ observer_attach_tsv_deleted (mi_tsv_deleted);
+ observer_attach_tsv_modified (mi_tsv_modified);
observer_attach_breakpoint_created (mi_breakpoint_created);
observer_attach_breakpoint_deleted (mi_breakpoint_deleted);
observer_attach_breakpoint_modified (mi_breakpoint_modified);
observer_attach_command_param_changed (mi_command_param_changed);
+ observer_attach_memory_changed (mi_memory_changed);
/* The initial inferior is created before this function is
called, so we need to report it explicitly. Use iteration in
static struct gdb_exception
mi_interpreter_exec (void *data, const char *command)
{
- char *tmp = alloca (strlen (command) + 1);
-
- strcpy (tmp, command);
- mi_execute_command_wrapper (tmp);
+ mi_execute_command_wrapper (command);
return exception_none;
}
}
static void
-mi_execute_command_wrapper (char *cmd)
+mi_execute_command_wrapper (const char *cmd)
{
mi_execute_command (cmd, stdin == instream);
}
gdb_flush (mi->event_channel);
}
+/* Emit notification on changing the state of record. */
+
+static void
+mi_record_changed (struct inferior *inferior, int started)
+{
+ struct mi_interp *mi = top_level_interpreter_data ();
+
+ fprintf_unfiltered (mi->event_channel, "record-%s,thread-group=\"i%d\"",
+ started ? "started" : "stopped", inferior->num);
+
+ gdb_flush (mi->event_channel);
+}
+
static void
mi_inferior_added (struct inferior *inf)
{
{
0,
0,
+ 0,
};
+/* Emit notification on changing a traceframe. */
+
+static void
+mi_traceframe_changed (int tfnum, int tpnum)
+{
+ struct mi_interp *mi = top_level_interpreter_data ();
+
+ if (mi_suppress_notification.traceframe)
+ return;
+
+ target_terminal_ours ();
+
+ if (tfnum >= 0)
+ fprintf_unfiltered (mi->event_channel, "traceframe-changed,"
+ "num=\"%d\",tracepoint=\"%d\"\n",
+ tfnum, tpnum);
+ else
+ fprintf_unfiltered (mi->event_channel, "traceframe-changed,end");
+
+ gdb_flush (mi->event_channel);
+}
+
+/* Emit notification on creating a trace state variable. */
+
+static void
+mi_tsv_created (const struct trace_state_variable *tsv)
+{
+ struct mi_interp *mi = top_level_interpreter_data ();
+
+ target_terminal_ours ();
+
+ fprintf_unfiltered (mi->event_channel, "tsv-created,"
+ "name=\"%s\",initial=\"%s\"\n",
+ tsv->name, plongest (tsv->initial_value));
+
+ gdb_flush (mi->event_channel);
+}
+
+/* Emit notification on deleting a trace state variable. */
+
+static void
+mi_tsv_deleted (const struct trace_state_variable *tsv)
+{
+ struct mi_interp *mi = top_level_interpreter_data ();
+
+ target_terminal_ours ();
+
+ if (tsv != NULL)
+ fprintf_unfiltered (mi->event_channel, "tsv-deleted,"
+ "name=\"%s\"\n", tsv->name);
+ else
+ fprintf_unfiltered (mi->event_channel, "tsv-deleted\n");
+
+ gdb_flush (mi->event_channel);
+}
+
+/* Emit notification on modifying a trace state variable. */
+
+static void
+mi_tsv_modified (const struct trace_state_variable *tsv)
+{
+ struct mi_interp *mi = top_level_interpreter_data ();
+ struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ());
+
+ target_terminal_ours ();
+
+ fprintf_unfiltered (mi->event_channel,
+ "tsv-modified");
+
+ ui_out_redirect (mi_uiout, mi->event_channel);
+
+ ui_out_field_string (mi_uiout, "name", tsv->name);
+ ui_out_field_string (mi_uiout, "initial",
+ plongest (tsv->initial_value));
+ if (tsv->value_known)
+ ui_out_field_string (mi_uiout, "current", plongest (tsv->value));
+
+ ui_out_redirect (mi_uiout, NULL);
+
+ gdb_flush (mi->event_channel);
+}
+
/* Emit notification about a created breakpoint. */
static void
struct mi_interp *mi = top_level_interpreter_data ();
target_terminal_ours ();
- if (gdbarch_has_global_solist (target_gdbarch))
+ if (gdbarch_has_global_solist (target_gdbarch ()))
fprintf_unfiltered (mi->event_channel,
"library-loaded,id=\"%s\",target-name=\"%s\","
"host-name=\"%s\",symbols-loaded=\"%d\"",
struct mi_interp *mi = top_level_interpreter_data ();
target_terminal_ours ();
- if (gdbarch_has_global_solist (target_gdbarch))
+ if (gdbarch_has_global_solist (target_gdbarch ()))
fprintf_unfiltered (mi->event_channel,
"library-unloaded,id=\"%s\",target-name=\"%s\","
"host-name=\"%s\"",
gdb_flush (mi->event_channel);
}
+/* Emit notification about the target memory change. */
+
+static void
+mi_memory_changed (struct inferior *inferior, CORE_ADDR memaddr,
+ ssize_t len, const bfd_byte *myaddr)
+{
+ struct mi_interp *mi = top_level_interpreter_data ();
+ struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ());
+ struct obj_section *sec;
+
+ if (mi_suppress_notification.memory)
+ return;
+
+ target_terminal_ours ();
+
+ fprintf_unfiltered (mi->event_channel,
+ "memory-changed");
+
+ ui_out_redirect (mi_uiout, mi->event_channel);
+
+ ui_out_field_fmt (mi_uiout, "thread-group", "i%d", inferior->num);
+ ui_out_field_core_addr (mi_uiout, "addr", target_gdbarch (), memaddr);
+ ui_out_field_fmt (mi_uiout, "len", "0x%zx", len);
+
+ /* Append 'type=code' into notification if MEMADDR falls in the range of
+ sections contain code. */
+ sec = find_pc_section (memaddr);
+ if (sec != NULL && sec->objfile != NULL)
+ {
+ flagword flags = bfd_get_section_flags (sec->objfile->obfd,
+ sec->the_bfd_section);
+
+ if (flags & SEC_CODE)
+ ui_out_field_string (mi_uiout, "type", "code");
+ }
+
+ ui_out_redirect (mi_uiout, NULL);
+
+ gdb_flush (mi->event_channel);
+}
+
static int
report_initial_inferior (struct inferior *inf, void *closure)
{