---
include/mcdstub/mcdstub.h | 41 +++++++++++++++
mcdstub/mcdstub.c | 103 ++++++++++++++++++++++++++++++++++++++
2 files changed, 144 insertions(+)
diff --git a/include/mcdstub/mcdstub.h b/include/mcdstub/mcdstub.h
index d38106e973..eb46917d00 100644
--- a/include/mcdstub/mcdstub.h
+++ b/include/mcdstub/mcdstub.h
@@ -36,6 +36,20 @@
/* tcp query packet values templates */
#define DEVICE_NAME_TEMPLATE(s) "qemu-" #s "-device"
+/* state strings */
+#define STATE_STR_UNKNOWN(d) "cpu " #d " in unknown state"
+#define STATE_STR_DEBUG(d) "cpu " #d " in debug state"
+#define STATE_STR_RUNNING(d) "cpu " #d " running"
+#define STATE_STR_HALTED(d) "cpu " #d " currently halted"
+#define STATE_STR_INIT_HALTED "vm halted since boot"
+#define STATE_STR_INIT_RUNNING "vm running since boot"
+#define STATE_STR_BREAK_HW "stopped beacuse of HW breakpoint"
+#define STATE_STEP_PERFORMED "stopped beacuse of single step"
+#define STATE_STR_BREAK_READ(d) "stopped beacuse of read access at " #d
+#define STATE_STR_BREAK_WRITE(d) "stopped beacuse of write access at " #d
+#define STATE_STR_BREAK_RW(d) "stopped beacuse of read or write access at " #d
+#define STATE_STR_BREAK_UNKNOWN "stopped for unknown reason"
+
typedef struct MCDProcess {
uint32_t pid;
bool attached;
@@ -67,6 +81,12 @@ enum RSState {
RS_DATAEND,
};
+typedef struct breakpoint_st {
+ uint32_t type;
+ uint64_t address;
+ uint32_t id;
+} breakpoint_st;
+
typedef struct mcd_trigger_into_st {
char type[ARGUMENT_STRING_LENGTH];
char option[ARGUMENT_STRING_LENGTH];
@@ -74,6 +94,17 @@ typedef struct mcd_trigger_into_st {
uint32_t nr_trigger;
} mcd_trigger_into_st;
+typedef struct mcd_cpu_state_st {
+ const char *state;
+ bool memory_changed;
+ bool registers_changed;
+ bool target_was_stopped;
+ uint32_t bp_type;
+ uint64_t bp_address;
+ const char *stop_str;
+ const char *info_str;
+} mcd_cpu_state_st;
+
typedef struct MCDState {
bool init; /* have we been initialised? */
CPUState *c_cpu; /* current CPU for everything */
@@ -506,6 +537,16 @@ void handle_close_core(GArray *params, void *user_ctx);
*/
void handle_open_server(GArray *params, void *user_ctx);
+/**
+ * handle_query_state() - Handler for the state query.
+ *
+ * This function collects all data stored in the
+ * cpu_state member of the mcdserver_state and formats and sends it to the
+ * library.
+ * @params: GArray with all TCP packet parameters.
+ */
+void handle_query_state(GArray *params, void *user_ctx);
+
/* helpers */
/**
diff --git a/mcdstub/mcdstub.c b/mcdstub/mcdstub.c
index ca98d01ee7..657f80d2a2 100644
--- a/mcdstub/mcdstub.c
+++ b/mcdstub/mcdstub.c
@@ -95,6 +95,15 @@ void init_query_cmds_table(MCDCmdParseEntry *mcd_query_cmds_table)
mcd_query_cmds_table[cmd_number] = query_cores;
cmd_number++;
+
+ MCDCmdParseEntry query_state = {
+ .handler = handle_query_state,
+ .cmd = QUERY_ARG_STATE,
+ };
+ strcpy(query_state.schema, (char[2]) { ARG_SCHEMA_CORENUM, '\0' });
+ mcd_query_cmds_table[cmd_number] = query_state;
+}
+
void reset_mcdserver_state(void)
{
g_free(mcdserver_state.processes);
@@ -605,6 +614,100 @@ void mcd_sigterm_handler(int signal)
}
#endif
+void mcd_vm_state_change(void *opaque, bool running, RunState state)
+{
+ CPUState *cpu = mcdserver_state.c_cpu;
+
+ if (mcdserver_state.state == RS_INACTIVE) {
+ return;
+ }
+
+ if (cpu == NULL) {
+ if (running) {
+ /*
+ * this is the case if qemu starts the vm
+ * before a mcd client is connected
+ */
+ const char *mcd_state;
+ mcd_state = CORE_STATE_RUNNING;
+ const char *info_str;
+ info_str = STATE_STR_INIT_RUNNING;
+ mcdserver_state.cpu_state.state = mcd_state;
+ mcdserver_state.cpu_state.info_str = info_str;
+ }
+ return;
+ }
+
+ const char *mcd_state;
+ const char *stop_str;
+ const char *info_str;
+ uint32_t bp_type = 0;
+ uint64_t bp_address = 0;
+ switch (state) {
+ case RUN_STATE_RUNNING:
+ mcd_state = CORE_STATE_RUNNING;
+ info_str = STATE_STR_RUNNING(cpu->cpu_index);
+ stop_str = "";
+ break;
+ case RUN_STATE_DEBUG:
+ mcd_state = CORE_STATE_DEBUG;
+ info_str = STATE_STR_DEBUG(cpu->cpu_index);
+ if (cpu->watchpoint_hit) {
+ switch (cpu->watchpoint_hit->flags & BP_MEM_ACCESS) {
+ case BP_MEM_READ:
+ bp_type = MCD_BREAKPOINT_READ;
+ stop_str = STATE_STR_BREAK_READ(cpu->watchpoint_hit->hitaddr);
+ break;
+ case BP_MEM_WRITE:
+ bp_type = MCD_BREAKPOINT_WRITE;
+ stop_str = STATE_STR_BREAK_WRITE(cpu->watchpoint_hit->hitaddr);
+ break;
+ case BP_MEM_ACCESS:
+ bp_type = MCD_BREAKPOINT_RW;
+ stop_str = STATE_STR_BREAK_RW(cpu->watchpoint_hit->hitaddr);
+ break;
+ default:
+ stop_str = STATE_STR_BREAK_UNKNOWN;
+ break;
+ }
+ bp_address = cpu->watchpoint_hit->hitaddr;
+ cpu->watchpoint_hit = NULL;
+ } else if (cpu->singlestep_enabled) {
+ /* we land here when a single step is performed */
+ stop_str = STATE_STEP_PERFORMED;
+ } else {
+ bp_type = MCD_BREAKPOINT_HW;
+ stop_str = STATE_STR_BREAK_HW;
+ tb_flush(cpu);
+ }
+ /* deactivate single step */
+ cpu_single_step(cpu, 0);
+ break;
+ case RUN_STATE_PAUSED:
+ info_str = STATE_STR_HALTED(cpu->cpu_index);
+ mcd_state = CORE_STATE_HALTED;
+ stop_str = "";
+ break;
+ case RUN_STATE_WATCHDOG:
+ info_str = STATE_STR_UNKNOWN(cpu->cpu_index);
+ mcd_state = CORE_STATE_UNKNOWN;
+ stop_str = "";
+ break;
+ default:
+ info_str = STATE_STR_UNKNOWN(cpu->cpu_index);
+ mcd_state = CORE_STATE_UNKNOWN;
+ stop_str = "";
+ break;
+ }
+
+ /* set state for c_cpu */
+ mcdserver_state.cpu_state.state = mcd_state;
+ mcdserver_state.cpu_state.bp_type = bp_type;
+ mcdserver_state.cpu_state.bp_address = bp_address;
+ mcdserver_state.cpu_state.stop_str = stop_str;
+ mcdserver_state.cpu_state.info_str = info_str;
+}
+
int mcd_put_packet(const char *buf)
{
return mcd_put_packet_binary(buf, strlen(buf));
--
2.34.1