* [PATCH v3 01/20] mcdstub: initial file structure for new mcdstub created. -mcd QEMU startup option added. Functions for initializing the mcdstub added. Basic helper functions for processes/cpus in the mcdstub added
2023-11-07 13:03 [PATCH v3 00/20] first version of mcdstub Nicolas Eder
@ 2023-11-07 13:03 ` Nicolas Eder
2023-11-29 15:23 ` Alex Bennée
2023-11-07 13:03 ` [PATCH v3 02/20] mcdstub gdbstub: new DebugClass and DebugState introduced. They are used to abstract the debugger details behind a QOM. This is currently used in the cpu_handle_guest_debug function Nicolas Eder
` (20 subsequent siblings)
21 siblings, 1 reply; 32+ messages in thread
From: Nicolas Eder @ 2023-11-07 13:03 UTC (permalink / raw)
To: qemu-devel
Cc: Nicolas Eder, Alex Bennée, Philippe Mathieu-Daudé,
Christian Boenig
---
include/mcdstub/arm_mcdstub.h | 10 +
include/mcdstub/mcdstub.h | 239 +++++++++++++++++++
include/mcdstub/mcdstub_common.h | 7 +
mcdstub/mcdstub.c | 383 +++++++++++++++++++++++++++++++
qemu-options.hx | 18 ++
system/vl.c | 13 ++
6 files changed, 670 insertions(+)
create mode 100644 include/mcdstub/arm_mcdstub.h
create mode 100644 include/mcdstub/mcdstub.h
create mode 100644 include/mcdstub/mcdstub_common.h
create mode 100644 mcdstub/mcdstub.c
diff --git a/include/mcdstub/arm_mcdstub.h b/include/mcdstub/arm_mcdstub.h
new file mode 100644
index 0000000000..a57aa8e9f2
--- /dev/null
+++ b/include/mcdstub/arm_mcdstub.h
@@ -0,0 +1,10 @@
+#ifndef ARM_MCDSTUB_H
+#define ARM_MCDSTUB_H
+
+#include "hw/core/cpu.h"
+#include "mcdstub_common.h"
+/* just used for the register xml files */
+#include "exec/gdbstub.h"
+
+
+#endif /* ARM_MCDSTUB_H */
diff --git a/include/mcdstub/mcdstub.h b/include/mcdstub/mcdstub.h
new file mode 100644
index 0000000000..36058157ae
--- /dev/null
+++ b/include/mcdstub/mcdstub.h
@@ -0,0 +1,239 @@
+#ifndef MCDSTUB_INTERNALS_H
+#define MCDSTUB_INTERNALS_H
+
+#include "exec/cpu-common.h"
+#include "chardev/char.h"
+#include "hw/core/cpu.h"
+#include "mcdstub_common.h"
+
+#define MAX_PACKET_LENGTH 1024
+/* misc */
+#define QUERY_TOTAL_NUMBER 12
+#define CMD_SCHEMA_LENGTH 6
+#define MCD_SYSTEM_NAME "qemu-system"
+
+/* supported architectures */
+#define MCDSTUB_ARCH_ARM "arm"
+
+/* tcp query packet values templates */
+#define DEVICE_NAME_TEMPLATE(s) "qemu-" #s "-device"
+
+typedef struct MCDProcess {
+ uint32_t pid;
+ bool attached;
+
+ char target_xml[1024];
+} MCDProcess;
+
+#define get_param(p, i) (&g_array_index(p, MCDCmdVariant, i))
+
+enum RSState {
+ RS_INACTIVE,
+ RS_IDLE,
+ RS_GETLINE,
+ RS_DATAEND,
+};
+
+typedef struct MCDState {
+ bool init; /* have we been initialised? */
+ CPUState *c_cpu; /* current CPU for everything */
+ enum RSState state; /* parsing state */
+ char line_buf[MAX_PACKET_LENGTH];
+ int line_buf_index;
+ int line_sum; /* running checksum */
+ int line_csum; /* checksum at the end of the packet */
+ GByteArray *last_packet;
+ int signal;
+
+ MCDProcess *processes;
+ int process_num;
+ GString *str_buf;
+ GByteArray *mem_buf;
+ int sstep_flags;
+ int supported_sstep_flags;
+
+ uint32_t query_cpu_id;
+ GList *all_memspaces;
+ GList *all_reggroups;
+ GList *all_registers;
+ GList *all_breakpoints;
+ GArray *resets;
+ mcd_trigger_into_st trigger;
+ mcd_cpu_state_st cpu_state;
+ MCDCmdParseEntry mcd_query_cmds_table[QUERY_TOTAL_NUMBER];
+} MCDState;
+
+/* lives in main mcdstub.c */
+extern MCDState mcdserver_state;
+
+#ifndef _WIN32
+void mcd_sigterm_handler(int signal);
+#endif
+
+/**
+ * mcdserver_start() - initializes the mcdstub and opens a TCP port
+ * @device: TCP port (e.g. tcp::1235)
+ */
+int mcdserver_start(const char *device);
+
+/**
+ * mcd_init_mcdserver_state() - Initializes the mcdserver_state struct.
+ *
+ * This function allocates memory for the mcdserver_state struct and sets
+ * all of its members to their inital values. This includes setting the
+ * cpu_state to halted and initializing the query functions with
+ * :c:func:`init_query_cmds_table`.
+ */
+void mcd_init_mcdserver_state(void);
+
+/**
+ * init_query_cmds_table() - Initializes all query functions.
+ *
+ * This function adds all query functions to the mcd_query_cmds_table. This
+ * includes their command string, handler function and parameter schema.
+ * @mcd_query_cmds_table: Lookup table with all query commands.
+ */
+void init_query_cmds_table(MCDCmdParseEntry *mcd_query_cmds_table);
+/**
+ * create_processes() - Sorts all processes and calls
+ * :c:func:`mcd_create_default_process`.
+ *
+ * This function sorts all connected processes with the qsort function.
+ * Afterwards, it creates a new process with
+ * :c:func:`mcd_create_default_process`.
+ * @s: A MCDState object.
+ */
+void create_processes(MCDState *s);
+
+/**
+ * mcd_create_default_process() - Creates a default process for debugging.
+ *
+ * This function creates a new, not yet attached, process with an ID one above
+ * the previous maximum ID.
+ * @s: A MCDState object.
+ */
+void mcd_create_default_process(MCDState *s);
+
+/**
+ * find_cpu_clusters() - Returns the CPU cluster of the child object.
+ *
+ * @param[in] child Object with unknown CPU cluster.
+ * @param[in] opaque Pointer to an MCDState object.
+ */
+int find_cpu_clusters(Object *child, void *opaque);
+
+/**
+ * pid_order() - Compares process IDs.
+ *
+ * This function returns -1 if process "a" has a ower process ID than "b".
+ * If "b" has a lower ID than "a" 1 is returned and if they are qual 0 is
+ * returned.
+ * @a: Process a.
+ * @b: Process b.
+ */
+int pid_order(const void *a, const void *b);
+
+/**
+ * mcd_chr_can_receive() - Returns the maximum packet length of a TCP packet.
+ */
+int mcd_chr_can_receive(void *opaque);
+
+/**
+ * mcd_chr_receive() - Handles receiving a TCP packet.
+ *
+ * This function gets called by QEMU when a TCP packet is received.
+ * It iterates over that packet an calls :c:func:`mcd_read_byte` for each char
+ * of the packet.
+ * @buf: Content of the packet.
+ * @size: Length of the packet.
+ */
+void mcd_chr_receive(void *opaque, const uint8_t *buf, int size);
+
+/**
+ * mcd_chr_event() - Handles a TCP client connect.
+ *
+ * This function gets called by QEMU when a TCP cliet connects to the opened
+ * TCP port. It attaches the first process. From here on TCP packets can be
+ * exchanged.
+ * @event: Type of event.
+ */
+void mcd_chr_event(void *opaque, QEMUChrEvent event);
+
+/**
+ * mcd_supports_guest_debug() - Returns true if debugging the selected
+ * accelerator is supported.
+ */
+bool mcd_supports_guest_debug(void);
+
+/**
+ * mcd_vm_state_change() - Handles a state change of the QEMU VM.
+ *
+ * This function is called when the QEMU VM goes through a state transition.
+ * It stores the runstate the CPU is in to the cpu_state and when in
+ * RUN_STATE_DEBUG it collects additional data on what watchpoint was hit.
+ * This function also resets the singlestep behavior.
+ * @running: True if he VM is running.
+ * @state: The new (and active) VM run state.
+ */
+void mcd_vm_state_change(void *opaque, bool running, RunState state);
+/**
+ * mcd_get_cpu_process() - Returns the process of the provided CPU.
+ *
+ * @cpu: The CPU state.
+ */
+MCDProcess *mcd_get_cpu_process(CPUState *cpu);
+
+/**
+ * mcd_set_stop_cpu() - Sets c_cpu to the just stopped CPU.
+ *
+ * @cpu: The CPU state.
+ */
+void mcd_set_stop_cpu(CPUState *cpu);
+
+/**
+ * mcd_get_cpu_pid() - Returns the process ID of the provided CPU.
+ *
+ * @cpu: The CPU state.
+ */
+uint32_t mcd_get_cpu_pid(CPUState *cpu);
+
+/**
+ * mcd_get_process() - Returns the process of the provided pid.
+ *
+ * @pid: The process ID.
+ */
+MCDProcess *mcd_get_process(uint32_t pid);
+
+/**
+ * mcd_first_attached_cpu() - Returns the first CPU with an attached process.
+ */
+CPUState *mcd_first_attached_cpu(void);
+
+/**
+ * mcd_next_attached_cpu() - Returns the first CPU with an attached process
+ * starting after the
+ * provided cpu.
+ *
+ * @cpu: The CPU to start from.
+ */
+CPUState *mcd_next_attached_cpu(CPUState *cpu);
+
+/**
+ * mcd_get_cpu() - Returns the CPU the index i_cpu_index.
+ *
+ * @cpu_index: Index of the desired CPU.
+ */
+CPUState *mcd_get_cpu(uint32_t cpu_index);
+/**
+ * get_first_cpu_in_process() - Returns the first CPU in the provided process.
+ *
+ * @process: The process to look in.
+ */
+CPUState *get_first_cpu_in_process(MCDProcess *process);
+
+/**
+ * find_cpu() - Returns the CPU with an index equal to the thread_id.
+ *
+ * @thread_id: ID of the desired CPU.
+ */
+CPUState *find_cpu(uint32_t thread_id);
diff --git a/include/mcdstub/mcdstub_common.h b/include/mcdstub/mcdstub_common.h
new file mode 100644
index 0000000000..3bae2c3b6f
--- /dev/null
+++ b/include/mcdstub/mcdstub_common.h
@@ -0,0 +1,7 @@
+#ifndef MCDSTUB_COMMON_H
+#define MCDSTUB_COMMON_H
+
+#define ARGUMENT_STRING_LENGTH 64
+#define TCP_CONFIG_STRING_LENGTH 128
+
+#endif /* MCDSTUB_COMMON_H */
diff --git a/mcdstub/mcdstub.c b/mcdstub/mcdstub.c
new file mode 100644
index 0000000000..4cdf2e42ed
--- /dev/null
+++ b/mcdstub/mcdstub.c
@@ -0,0 +1,383 @@
+/*
+ * This is the main mcdstub.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/ctype.h"
+#include "qemu/cutils.h"
+#include "qemu/module.h"
+#include "qemu/error-report.h"
+#include "qemu/debug.h"
+#include "hw/cpu/cluster.h"
+#include "hw/boards.h"
+#include "sysemu/hw_accel.h"
+#include "sysemu/runstate.h"
+#include "exec/replay-core.h"
+#include "exec/hwaddr.h"
+#include "qapi/error.h"
+#include "exec/tb-flush.h"
+#include "sysemu/cpus.h"
+#include "sysemu/replay.h"
+#include "chardev/char.h"
+#include "chardev/char-fe.h"
+#include "monitor/monitor.h"
+#include "cutils.h"
+
+/* mcdstub header files */
+#include "mcdstub/mcd_shared_defines.h"
+#include "mcdstub/mcdstub.h"
+
+/* architecture specific stubs */
+#include "mcdstub/arm_mcdstub.h"
+
+typedef struct {
+ CharBackend chr;
+} MCDSystemState;
+
+MCDSystemState mcdserver_system_state;
+
+MCDState mcdserver_state;
+
+void mcd_init_mcdserver_state(void)
+{
+ g_assert(!mcdserver_state.init);
+ memset(&mcdserver_state, 0, sizeof(MCDState));
+ mcdserver_state.init = true;
+ mcdserver_state.str_buf = g_string_new(NULL);
+ mcdserver_state.mem_buf = g_byte_array_sized_new(MAX_PACKET_LENGTH);
+ mcdserver_state.last_packet = g_byte_array_sized_new(MAX_PACKET_LENGTH + 4);
+
+ /*
+ * What single-step modes are supported is accelerator dependent.
+ * By default try to use no IRQs and no timers while single
+ * stepping so as to make single stepping like a typical ICE HW step.
+ */
+ mcdserver_state.supported_sstep_flags =
+ accel_supported_gdbstub_sstep_flags();
+ mcdserver_state.sstep_flags = SSTEP_ENABLE | SSTEP_NOIRQ | SSTEP_NOTIMER;
+ mcdserver_state.sstep_flags &= mcdserver_state.supported_sstep_flags;
+
+ /* init query table */
+ init_query_cmds_table(mcdserver_state.mcd_query_cmds_table);
+
+ /* at this time the cpu hans't been started! -> set cpu_state */
+ mcd_cpu_state_st cpu_state = {
+ .state = CORE_STATE_HALTED,
+ .info_str = STATE_STR_INIT_HALTED,
+ };
+ mcdserver_state.cpu_state = cpu_state;
+
+ /* create new debug object */
+ mcd_init_debug_class();
+ }
+
+void mcd_set_stop_cpu(CPUState *cpu)
+{
+ mcdserver_state.c_cpu = cpu;
+}
+
+void init_query_cmds_table(MCDCmdParseEntry *mcd_query_cmds_table)
+{
+ /* initalizes a list of all query commands */
+ int cmd_number = 0;
+}
+void create_processes(MCDState *s)
+{
+ object_child_foreach(object_get_root(), find_cpu_clusters, s);
+
+ if (mcdserver_state.processes) {
+ /* Sort by PID */
+ qsort(mcdserver_state.processes,
+ mcdserver_state.process_num,
+ sizeof(mcdserver_state.processes[0]),
+ pid_order);
+ }
+
+ mcd_create_default_process(s);
+}
+
+void mcd_create_default_process(MCDState *s)
+{
+ MCDProcess *process;
+ int max_pid = 0;
+
+ if (mcdserver_state.process_num) {
+ max_pid = s->processes[s->process_num - 1].pid;
+ }
+
+ s->processes = g_renew(MCDProcess, s->processes, ++s->process_num);
+ process = &s->processes[s->process_num - 1];
+
+ /* We need an available PID slot for this process */
+ assert(max_pid < UINT32_MAX);
+
+ process->pid = max_pid + 1;
+ process->attached = false;
+ process->target_xml[0] = '\0';
+}
+
+int find_cpu_clusters(Object *child, void *opaque)
+{
+ if (object_dynamic_cast(child, TYPE_CPU_CLUSTER)) {
+ MCDState *s = (MCDState *) opaque;
+ CPUClusterState *cluster = CPU_CLUSTER(child);
+ MCDProcess *process;
+
+ s->processes = g_renew(MCDProcess, s->processes, ++s->process_num);
+
+ process = &s->processes[s->process_num - 1];
+ assert(cluster->cluster_id != UINT32_MAX);
+ process->pid = cluster->cluster_id + 1;
+ process->attached = false;
+ process->target_xml[0] = '\0';
+
+ return 0;
+ }
+
+ return object_child_foreach(child, find_cpu_clusters, opaque);
+}
+
+int pid_order(const void *a, const void *b)
+{
+ MCDProcess *pa = (MCDProcess *) a;
+ MCDProcess *pb = (MCDProcess *) b;
+
+ if (pa->pid < pb->pid) {
+ return -1;
+ } else if (pa->pid > pb->pid) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+int mcdserver_start(const char *device)
+{
+ char mcd_device_config[TCP_CONFIG_STRING_LENGTH];
+ char mcd_tcp_port[TCP_CONFIG_STRING_LENGTH];
+ Chardev *chr = NULL;
+
+ if (!first_cpu) {
+ error_report("mcdstub: meaningless to attach to a "
+ "machine without any CPU.");
+ return -1;
+ }
+
+ if (!mcd_supports_guest_debug()) {
+ error_report("mcdstub: current accelerator doesn't "
+ "support guest debugging");
+ return -1;
+ }
+
+ if (!device) {
+ return -1;
+ }
+
+ /* if device == default -> set tcp_port = tcp::<MCD_DEFAULT_TCP_PORT> */
+ if (strcmp(device, "default") == 0) {
+ snprintf(mcd_tcp_port, sizeof(mcd_tcp_port), "tcp::%s",
+ MCD_DEFAULT_TCP_PORT);
+ device = mcd_tcp_port;
+ }
+
+ if (strcmp(device, "none") != 0) {
+ if (strstart(device, "tcp:", NULL)) {
+ /* enforce required TCP attributes */
+ snprintf(mcd_device_config, sizeof(mcd_device_config),
+ "%s,wait=off,nodelay=on,server=on", device);
+ device = mcd_device_config;
+ }
+#ifndef _WIN32
+ else if (strcmp(device, "stdio") == 0) {
+ struct sigaction act;
+
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = mcd_sigterm_handler;
+ sigaction(SIGINT, &act, NULL);
+ strcpy(mcd_device_config, device);
+ }
+#endif
+ chr = qemu_chr_new_noreplay("mcd", device, true, NULL);
+ if (!chr) {
+ return -1;
+ }
+ }
+
+ if (!mcdserver_state.init) {
+ mcd_init_mcdserver_state();
+
+ qemu_add_vm_change_state_handler(mcd_vm_state_change, NULL);
+ } else {
+ qemu_chr_fe_deinit(&mcdserver_system_state.chr, true);
+ reset_mcdserver_state();
+ }
+
+ create_processes(&mcdserver_state);
+
+ if (chr) {
+ qemu_chr_fe_init(&mcdserver_system_state.chr, chr, &error_abort);
+ qemu_chr_fe_set_handlers(&mcdserver_system_state.chr,
+ mcd_chr_can_receive,
+ mcd_chr_receive, mcd_chr_event,
+ NULL, &mcdserver_state, NULL, true);
+ }
+ mcdserver_state.state = chr ? RS_IDLE : RS_INACTIVE;
+
+ return 0;
+}
+
+int mcd_chr_can_receive(void *opaque)
+{
+ return MAX_PACKET_LENGTH;
+}
+
+void mcd_chr_receive(void *opaque, const uint8_t *buf, int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ mcd_read_byte(buf[i]);
+ if (buf[i] == 0) {
+ break;
+ }
+ }
+}
+
+
+void mcd_chr_event(void *opaque, QEMUChrEvent event)
+{
+ int i;
+ MCDState *s = (MCDState *) opaque;
+
+ switch (event) {
+ case CHR_EVENT_OPENED:
+ /* Start with first process attached, others detached */
+ for (i = 0; i < s->process_num; i++) {
+ s->processes[i].attached = !i;
+ }
+
+ s->c_cpu = mcd_first_attached_cpu();
+ break;
+ default:
+ break;
+ }
+}
+
+bool mcd_supports_guest_debug(void)
+{
+ const AccelOpsClass *ops = cpus_get_accel();
+ if (ops->supports_guest_debug) {
+ return ops->supports_guest_debug();
+ }
+ return false;
+}
+
+#ifndef _WIN32
+void mcd_sigterm_handler(int signal)
+{
+ if (runstate_is_running()) {
+ vm_stop(RUN_STATE_PAUSED);
+ }
+}
+#endif
+
+uint32_t mcd_get_cpu_pid(CPUState *cpu)
+{
+ if (cpu->cluster_index == UNASSIGNED_CLUSTER_INDEX) {
+ /* Return the default process' PID */
+ int index = mcdserver_state.process_num - 1;
+ return mcdserver_state.processes[index].pid;
+ }
+ return cpu->cluster_index + 1;
+}
+
+MCDProcess *mcd_get_process(uint32_t pid)
+{
+ int i;
+
+ if (!pid) {
+ /* 0 means any process, we take the first one */
+ return &mcdserver_state.processes[0];
+ }
+
+ for (i = 0; i < mcdserver_state.process_num; i++) {
+ if (mcdserver_state.processes[i].pid == pid) {
+ return &mcdserver_state.processes[i];
+ }
+ }
+
+ return NULL;
+}
+
+CPUState *mcd_get_cpu(uint32_t cpu_index)
+{
+ CPUState *cpu = first_cpu;
+
+ while (cpu) {
+ if (cpu->cpu_index == cpu_index) {
+ return cpu;
+ }
+ cpu = mcd_next_attached_cpu(cpu);
+ }
+
+ return cpu;
+}
+
+CPUState *mcd_first_attached_cpu(void)
+{
+ CPUState *cpu = first_cpu;
+ MCDProcess *process = mcd_get_cpu_process(cpu);
+
+ if (!process->attached) {
+ return mcd_next_attached_cpu(cpu);
+ }
+
+ return cpu;
+}
+
+CPUState *mcd_next_attached_cpu(CPUState *cpu)
+{
+ cpu = CPU_NEXT(cpu);
+
+ while (cpu) {
+ if (mcd_get_cpu_process(cpu)->attached) {
+ break;
+ }
+
+ cpu = CPU_NEXT(cpu);
+ }
+
+ return cpu;
+}
+
+int mcd_get_cpu_index(CPUState *cpu)
+{
+ return cpu->cpu_index + 1;
+}
+
+CPUState *get_first_cpu_in_process(MCDProcess *process)
+{
+ CPUState *cpu;
+
+ CPU_FOREACH(cpu) {
+ if (mcd_get_cpu_pid(cpu) == process->pid) {
+ return cpu;
+ }
+ }
+
+ return NULL;
+}
+
+CPUState *find_cpu(uint32_t thread_id)
+{
+ CPUState *cpu;
+
+ CPU_FOREACH(cpu) {
+ if (mcd_get_cpu_index(cpu) == thread_id) {
+ return cpu;
+ }
+ }
+
+ return NULL;
+}
+
diff --git a/qemu-options.hx b/qemu-options.hx
index e26230bac5..accf92642c 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -4430,6 +4430,24 @@ SRST
(see the :ref:`GDB usage` chapter in the System Emulation Users Guide).
ERST
+DEF("mcd", HAS_ARG, QEMU_OPTION_mcd, \
+ "-mcd dev accept mcd connection on 'dev'. (QEMU defaults to starting\n"
+ " the guest without waiting for a mcd client to connect; use -S too\n"
+ " if you want it to not start execution.)\n"
+ " To use the default Port write '-mcd default'\n",
+ QEMU_ARCH_ALL)
+SRST
+``-mcd dev``
+ Accept a mcd connection on device dev. Note that this option does not pause QEMU
+ execution -- if you want QEMU to not start the guest until you
+ connect with mcd and issue a ``run`` command, you will need to
+ also pass the ``-S`` option to QEMU.
+
+ The most usual configuration is to listen on a local TCP socket::
+
+ -mcd tcp::1235
+ERST
+
DEF("d", HAS_ARG, QEMU_OPTION_d, \
"-d item1,... enable logging of specified items (use '-d help' for a list of log items)\n",
QEMU_ARCH_ALL)
diff --git a/system/vl.c b/system/vl.c
index 92d29bf521..b657c77ea4 100644
--- a/system/vl.c
+++ b/system/vl.c
@@ -68,6 +68,7 @@
#include "sysemu/numa.h"
#include "sysemu/hostmem.h"
#include "exec/gdbstub.h"
+#include "mcdstub/mcdstub.h"
#include "qemu/timer.h"
#include "chardev/char.h"
#include "qemu/bitmap.h"
@@ -1266,6 +1267,7 @@ struct device_config {
DEV_PARALLEL, /* -parallel */
DEV_DEBUGCON, /* -debugcon */
DEV_GDB, /* -gdb, -s */
+ DEV_MCD, /* -mcd */
DEV_SCLP, /* s390 sclp */
} type;
const char *cmdline;
@@ -2673,6 +2675,14 @@ static void qemu_machine_creation_done(void)
if (foreach_device_config(DEV_GDB, gdbserver_start) < 0) {
exit(1);
}
+
+ if (foreach_device_config(DEV_MCD, mcdserver_start) < 0) {
+ /*
+ * starts the mcdserver if the mcd option was set
+ */
+ exit(1);
+ }
+
if (!vga_interface_created && !default_vga &&
vga_interface_type != VGA_NONE) {
warn_report("A -vga option was passed but this machine "
@@ -3028,6 +3038,9 @@ void qemu_init(int argc, char **argv)
case QEMU_OPTION_gdb:
add_device_config(DEV_GDB, optarg);
break;
+ case QEMU_OPTION_mcd:
+ add_device_config(DEV_MCD, optarg);
+ break;
case QEMU_OPTION_L:
if (is_help_option(optarg)) {
list_data_dirs = true;
--
2.34.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* Re: [PATCH v3 01/20] mcdstub: initial file structure for new mcdstub created. -mcd QEMU startup option added. Functions for initializing the mcdstub added. Basic helper functions for processes/cpus in the mcdstub added
2023-11-07 13:03 ` [PATCH v3 01/20] mcdstub: initial file structure for new mcdstub created. -mcd QEMU startup option added. Functions for initializing the mcdstub added. Basic helper functions for processes/cpus in the mcdstub added Nicolas Eder
@ 2023-11-29 15:23 ` Alex Bennée
0 siblings, 0 replies; 32+ messages in thread
From: Alex Bennée @ 2023-11-29 15:23 UTC (permalink / raw)
To: Nicolas Eder; +Cc: qemu-devel, Philippe Mathieu-Daudé, Christian Boenig
Nicolas Eder <nicolas.eder@lauterbach.com> writes:
I think you need to ensure an extra line in you git commit messages
because currently the whole commit runs into your subject.
foo/bar: summary of change made
longer description of the problem and how the patch solves it. This can
continue to be multiple lines of text.
Signed-off-by: Name <email>
> ---
> include/mcdstub/arm_mcdstub.h | 10 +
> include/mcdstub/mcdstub.h | 239 +++++++++++++++++++
> include/mcdstub/mcdstub_common.h | 7 +
> mcdstub/mcdstub.c | 383 +++++++++++++++++++++++++++++++
> qemu-options.hx | 18 ++
> system/vl.c | 13 ++
> 6 files changed, 670 insertions(+)
> create mode 100644 include/mcdstub/arm_mcdstub.h
> create mode 100644 include/mcdstub/mcdstub.h
> create mode 100644 include/mcdstub/mcdstub_common.h
> create mode 100644 mcdstub/mcdstub.c
>
> diff --git a/include/mcdstub/arm_mcdstub.h b/include/mcdstub/arm_mcdstub.h
> new file mode 100644
> index 0000000000..a57aa8e9f2
> --- /dev/null
> +++ b/include/mcdstub/arm_mcdstub.h
> @@ -0,0 +1,10 @@
> +#ifndef ARM_MCDSTUB_H
> +#define ARM_MCDSTUB_H
> +
> +#include "hw/core/cpu.h"
> +#include "mcdstub_common.h"
> +/* just used for the register xml files */
> +#include "exec/gdbstub.h"
> +
> +
> +#endif /* ARM_MCDSTUB_H */
> diff --git a/include/mcdstub/mcdstub.h b/include/mcdstub/mcdstub.h
> new file mode 100644
> index 0000000000..36058157ae
> --- /dev/null
> +++ b/include/mcdstub/mcdstub.h
> @@ -0,0 +1,239 @@
> +#ifndef MCDSTUB_INTERNALS_H
> +#define MCDSTUB_INTERNALS_H
> +
> +#include "exec/cpu-common.h"
> +#include "chardev/char.h"
> +#include "hw/core/cpu.h"
> +#include "mcdstub_common.h"
> +
> +#define MAX_PACKET_LENGTH 1024
> +/* misc */
> +#define QUERY_TOTAL_NUMBER 12
> +#define CMD_SCHEMA_LENGTH 6
> +#define MCD_SYSTEM_NAME "qemu-system"
> +
> +/* supported architectures */
> +#define MCDSTUB_ARCH_ARM "arm"
> +
> +/* tcp query packet values templates */
> +#define DEVICE_NAME_TEMPLATE(s) "qemu-" #s "-device"
> +
> +typedef struct MCDProcess {
> + uint32_t pid;
> + bool attached;
> +
> + char target_xml[1024];
Is this even used?
> +} MCDProcess;
> +
> +#define get_param(p, i) (&g_array_index(p, MCDCmdVariant, i))
> +
> +enum RSState {
> + RS_INACTIVE,
> + RS_IDLE,
> + RS_GETLINE,
> + RS_DATAEND,
> +};
> +
> +typedef struct MCDState {
> + bool init; /* have we been initialised? */
> + CPUState *c_cpu; /* current CPU for everything */
> + enum RSState state; /* parsing state */
> + char line_buf[MAX_PACKET_LENGTH];
> + int line_buf_index;
> + int line_sum; /* running checksum */
> + int line_csum; /* checksum at the end of the packet */
> + GByteArray *last_packet;
> + int signal;
> +
> + MCDProcess *processes;
> + int process_num;
> + GString *str_buf;
> + GByteArray *mem_buf;
> + int sstep_flags;
> + int supported_sstep_flags;
> +
> + uint32_t query_cpu_id;
> + GList *all_memspaces;
> + GList *all_reggroups;
> + GList *all_registers;
> + GList *all_breakpoints;
> + GArray *resets;
> + mcd_trigger_into_st trigger;
> + mcd_cpu_state_st cpu_state;
> + MCDCmdParseEntry mcd_query_cmds_table[QUERY_TOTAL_NUMBER];
> +} MCDState;
Hmm this doesn't even compile:
cc -m64 -mcx16 -Ilibcommon.fa.p -I../../common-user/host/x86_64 -I../../linux-user/include/host/x86_64 -I../../linux-user/include -Iui -I../../ui -I/usr/include/capstone -I/usr/include/p11-kit-1 -I/usr/include/pixman-1 -I/usr/include/libpng16 -I/usr/include/spice-server -I/usr/include/spice-1 -I/usr/include/libusb-1.0 -I/usr/include/SDL2 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/gio-unix-2.0 -I/usr/include/slirp -I/usr/include/gtk-3.0 -I/usr/include/pango-1.0 -I/usr/include/harfbuzz -I/usr/include/freetype2 -I/usr/include/fribidi -I/usr/include/cairo -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/x86_64-linux-gnu -I/usr/include/atk-1.0 -I/usr/include/at-spi2-atk/2.0 -I/usr/include/at-spi-2.0 -I/usr/include/dbus-1.0 -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include -I/usr/include/vte-2.91 -I/usr/include/virgl -I/usr/include/cacard -I/usr/include/nss -I/usr/include/nspr -I/usr/include/PCSC -fdiagnostics-color=auto -Wall -Winvalid-pch -Werror -std=gnu11 -O2 -g -fstack-protector-strong -Wundef -Wwrite-strings -Wmissing-prototypes -Wstrict-prototypes -Wredundant-decls -Wold-style-declaration -Wold-style-definition -Wtype-limits -Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers -Wempty-body -Wnested-externs -Wendif-labels -Wexpansion-to-defined -Wimplicit-fallthrough=2 -Wmissing-format-attribute -Wno-missing-include-dirs -Wno-shift-negative-value -Wno-psabi -Wshadow=local -isystem /home/alex/lsrc/qemu.git/linux-headers -isystem linux-headers -iquote . -iquote /home/alex/lsrc/qemu.git -iquote /home/alex/lsrc/qemu.git/include -iquote /home/alex/lsrc/qemu.git/host/include/x86_64 -iquote /home/alex/lsrc/qemu.git/host/include/generic -iquote /home/alex/lsrc/qemu.git/tcg/i386 -pthread -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -fno-strict-aliasing -fno-common -fwrapv -fPIE -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -DNCURSES_WIDECHAR=1 -D_REENTRANT -DSTRUCT_IOVEC_DEFINED -MD -MQ libcommon.fa.p/system_vl.c.o -MF libcommon.fa.p/system_vl.c.o.d -o libcommon.fa.p/system_vl.c.o -c ../../system/vl.c
In file included from ../../system/vl.c:71:
/home/alex/lsrc/qemu.git/include/mcdstub/mcdstub.h:61:5: error: unknown type name ‘mcd_trigger_into_st’
61 | mcd_trigger_into_st trigger;
| ^~~~~~~~~~~~~~~~~~~
/home/alex/lsrc/qemu.git/include/mcdstub/mcdstub.h:62:5: error: unknown type name ‘mcd_cpu_state_st’
62 | mcd_cpu_state_st cpu_state;
| ^~~~~~~~~~~~~~~~
/home/alex/lsrc/qemu.git/include/mcdstub/mcdstub.h:63:5: error: unknown type name ‘MCDCmdParseEntry’
63 | MCDCmdParseEntry mcd_query_cmds_table[QUERY_TOTAL_NUMBER];
| ^~~~~~~~~~~~~~~~
/home/alex/lsrc/qemu.git/include/mcdstub/mcdstub.h:96:28: error: unknown type name ‘MCDCmdParseEntry’
96 | void init_query_cmds_table(MCDCmdParseEntry *mcd_query_cmds_table);
| ^~~~~~~~~~~~~~~~
/home/alex/lsrc/qemu.git/include/mcdstub/mcdstub.h:1: error: unterminated #ifndef
1 | #ifndef MCDSTUB_INTERNALS_H
|
Each patch in the series should be able to compile cleanly for the
purposes of bisection.
If we need external headers you'll need to tweak configure/meson to make
sure they are available and gate the feature if its not.
> +
> +/* lives in main mcdstub.c */
> +extern MCDState mcdserver_state;
> +
> +#ifndef _WIN32
> +void mcd_sigterm_handler(int signal);
> +#endif
> +
> +/**
> + * mcdserver_start() - initializes the mcdstub and opens a TCP port
> + * @device: TCP port (e.g. tcp::1235)
> + */
> +int mcdserver_start(const char *device);
> +
> +/**
> + * mcd_init_mcdserver_state() - Initializes the mcdserver_state struct.
> + *
> + * This function allocates memory for the mcdserver_state struct and sets
> + * all of its members to their inital values. This includes setting the
> + * cpu_state to halted and initializing the query functions with
> + * :c:func:`init_query_cmds_table`.
> + */
> +void mcd_init_mcdserver_state(void);
> +
> +/**
> + * init_query_cmds_table() - Initializes all query functions.
> + *
> + * This function adds all query functions to the mcd_query_cmds_table. This
> + * includes their command string, handler function and parameter schema.
> + * @mcd_query_cmds_table: Lookup table with all query commands.
> + */
> +void init_query_cmds_table(MCDCmdParseEntry *mcd_query_cmds_table);
No MCDCmdParseEntry defined. However this doesn't seem to be an exported
function. If it was it should be prefixed.
> +/**
> + * create_processes() - Sorts all processes and calls
> + * :c:func:`mcd_create_default_process`.
> + *
> + * This function sorts all connected processes with the qsort function.
> + * Afterwards, it creates a new process with
> + * :c:func:`mcd_create_default_process`.
> + * @s: A MCDState object.
> + */
> +void create_processes(MCDState *s);
this is definitely internal.
> +
> +/**
> + * mcd_create_default_process() - Creates a default process for debugging.
> + *
> + * This function creates a new, not yet attached, process with an ID one above
> + * the previous maximum ID.
> + * @s: A MCDState object.
> + */
> +void mcd_create_default_process(MCDState *s);
> +
> +/**
> + * find_cpu_clusters() - Returns the CPU cluster of the child object.
> + *
> + * @param[in] child Object with unknown CPU cluster.
> + * @param[in] opaque Pointer to an MCDState object.
> + */
> +int find_cpu_clusters(Object *child, void *opaque);
> +
> +/**
> + * pid_order() - Compares process IDs.
> + *
> + * This function returns -1 if process "a" has a ower process ID than "b".
> + * If "b" has a lower ID than "a" 1 is returned and if they are qual 0 is
> + * returned.
> + * @a: Process a.
> + * @b: Process b.
> + */
> +int pid_order(const void *a, const void *b);
> +
> +/**
> + * mcd_chr_can_receive() - Returns the maximum packet length of a TCP packet.
> + */
> +int mcd_chr_can_receive(void *opaque);
> +
> +/**
> + * mcd_chr_receive() - Handles receiving a TCP packet.
> + *
> + * This function gets called by QEMU when a TCP packet is received.
> + * It iterates over that packet an calls :c:func:`mcd_read_byte` for each char
> + * of the packet.
> + * @buf: Content of the packet.
> + * @size: Length of the packet.
> + */
> +void mcd_chr_receive(void *opaque, const uint8_t *buf, int size);
> +
> +/**
> + * mcd_chr_event() - Handles a TCP client connect.
> + *
> + * This function gets called by QEMU when a TCP cliet connects to the opened
> + * TCP port. It attaches the first process. From here on TCP packets can be
> + * exchanged.
> + * @event: Type of event.
> + */
> +void mcd_chr_event(void *opaque, QEMUChrEvent event);
> +
> +/**
> + * mcd_supports_guest_debug() - Returns true if debugging the selected
> + * accelerator is supported.
> + */
> +bool mcd_supports_guest_debug(void);
> +
> +/**
> + * mcd_vm_state_change() - Handles a state change of the QEMU VM.
> + *
> + * This function is called when the QEMU VM goes through a state transition.
> + * It stores the runstate the CPU is in to the cpu_state and when in
> + * RUN_STATE_DEBUG it collects additional data on what watchpoint was hit.
> + * This function also resets the singlestep behavior.
> + * @running: True if he VM is running.
> + * @state: The new (and active) VM run state.
> + */
> +void mcd_vm_state_change(void *opaque, bool running, RunState state);
> +/**
> + * mcd_get_cpu_process() - Returns the process of the provided CPU.
> + *
> + * @cpu: The CPU state.
> + */
> +MCDProcess *mcd_get_cpu_process(CPUState *cpu);
> +
> +/**
> + * mcd_set_stop_cpu() - Sets c_cpu to the just stopped CPU.
> + *
> + * @cpu: The CPU state.
> + */
> +void mcd_set_stop_cpu(CPUState *cpu);
> +
> +/**
> + * mcd_get_cpu_pid() - Returns the process ID of the provided CPU.
> + *
> + * @cpu: The CPU state.
> + */
> +uint32_t mcd_get_cpu_pid(CPUState *cpu);
> +
> +/**
> + * mcd_get_process() - Returns the process of the provided pid.
> + *
> + * @pid: The process ID.
> + */
> +MCDProcess *mcd_get_process(uint32_t pid);
> +
> +/**
> + * mcd_first_attached_cpu() - Returns the first CPU with an attached process.
> + */
> +CPUState *mcd_first_attached_cpu(void);
> +
> +/**
> + * mcd_next_attached_cpu() - Returns the first CPU with an attached process
> + * starting after the
> + * provided cpu.
> + *
> + * @cpu: The CPU to start from.
> + */
> +CPUState *mcd_next_attached_cpu(CPUState *cpu);
> +
> +/**
> + * mcd_get_cpu() - Returns the CPU the index i_cpu_index.
> + *
> + * @cpu_index: Index of the desired CPU.
> + */
> +CPUState *mcd_get_cpu(uint32_t cpu_index);
> +/**
> + * get_first_cpu_in_process() - Returns the first CPU in the provided process.
> + *
> + * @process: The process to look in.
> + */
> +CPUState *get_first_cpu_in_process(MCDProcess *process);
> +
> +/**
> + * find_cpu() - Returns the CPU with an index equal to the thread_id.
> + *
> + * @thread_id: ID of the desired CPU.
> + */
> +CPUState *find_cpu(uint32_t thread_id);
> diff --git a/include/mcdstub/mcdstub_common.h b/include/mcdstub/mcdstub_common.h
> new file mode 100644
> index 0000000000..3bae2c3b6f
> --- /dev/null
> +++ b/include/mcdstub/mcdstub_common.h
> @@ -0,0 +1,7 @@
> +#ifndef MCDSTUB_COMMON_H
> +#define MCDSTUB_COMMON_H
> +
> +#define ARGUMENT_STRING_LENGTH 64
> +#define TCP_CONFIG_STRING_LENGTH 128
> +
> +#endif /* MCDSTUB_COMMON_H */
> diff --git a/mcdstub/mcdstub.c b/mcdstub/mcdstub.c
> new file mode 100644
> index 0000000000..4cdf2e42ed
> --- /dev/null
> +++ b/mcdstub/mcdstub.c
> @@ -0,0 +1,383 @@
> +/*
> + * This is the main mcdstub.
> + */
Can we have an author, copyright date and SPDX header for this file
please.
> +
> +#include "qemu/osdep.h"
> +#include "qemu/ctype.h"
> +#include "qemu/cutils.h"
> +#include "qemu/module.h"
> +#include "qemu/error-report.h"
> +#include "qemu/debug.h"
> +#include "hw/cpu/cluster.h"
> +#include "hw/boards.h"
> +#include "sysemu/hw_accel.h"
> +#include "sysemu/runstate.h"
> +#include "exec/replay-core.h"
> +#include "exec/hwaddr.h"
> +#include "qapi/error.h"
> +#include "exec/tb-flush.h"
> +#include "sysemu/cpus.h"
> +#include "sysemu/replay.h"
> +#include "chardev/char.h"
> +#include "chardev/char-fe.h"
> +#include "monitor/monitor.h"
> +#include "cutils.h"
I'm sure half of these includes aren't needed. Try and keep them minimal please.
> +
> +/* mcdstub header files */
> +#include "mcdstub/mcd_shared_defines.h"
> +#include "mcdstub/mcdstub.h"
> +
> +/* architecture specific stubs */
> +#include "mcdstub/arm_mcdstub.h"
> +
> +typedef struct {
> + CharBackend chr;
> +} MCDSystemState;
> +
> +MCDSystemState mcdserver_system_state;
> +
> +MCDState mcdserver_state;
> +
> +void mcd_init_mcdserver_state(void)
> +{
> + g_assert(!mcdserver_state.init);
> + memset(&mcdserver_state, 0, sizeof(MCDState));
> + mcdserver_state.init = true;
> + mcdserver_state.str_buf = g_string_new(NULL);
> + mcdserver_state.mem_buf = g_byte_array_sized_new(MAX_PACKET_LENGTH);
> + mcdserver_state.last_packet = g_byte_array_sized_new(MAX_PACKET_LENGTH + 4);
> +
> + /*
> + * What single-step modes are supported is accelerator dependent.
> + * By default try to use no IRQs and no timers while single
> + * stepping so as to make single stepping like a typical ICE HW step.
> + */
> + mcdserver_state.supported_sstep_flags =
> + accel_supported_gdbstub_sstep_flags();
> + mcdserver_state.sstep_flags = SSTEP_ENABLE | SSTEP_NOIRQ | SSTEP_NOTIMER;
> + mcdserver_state.sstep_flags &= mcdserver_state.supported_sstep_flags;
> +
> + /* init query table */
> + init_query_cmds_table(mcdserver_state.mcd_query_cmds_table);
> +
> + /* at this time the cpu hans't been started! -> set cpu_state */
> + mcd_cpu_state_st cpu_state = {
> + .state = CORE_STATE_HALTED,
> + .info_str = STATE_STR_INIT_HALTED,
> + };
> + mcdserver_state.cpu_state = cpu_state;
> +
> + /* create new debug object */
> + mcd_init_debug_class();
> + }
> +
> +void mcd_set_stop_cpu(CPUState *cpu)
> +{
> + mcdserver_state.c_cpu = cpu;
> +}
> +
> +void init_query_cmds_table(MCDCmdParseEntry *mcd_query_cmds_table)
> +{
> + /* initalizes a list of all query commands */
> + int cmd_number = 0;
> +}
> +void create_processes(MCDState *s)
> +{
> + object_child_foreach(object_get_root(), find_cpu_clusters, s);
> +
> + if (mcdserver_state.processes) {
> + /* Sort by PID */
> + qsort(mcdserver_state.processes,
> + mcdserver_state.process_num,
> + sizeof(mcdserver_state.processes[0]),
> + pid_order);
> + }
> +
> + mcd_create_default_process(s);
> +}
> +
> +void mcd_create_default_process(MCDState *s)
> +{
> + MCDProcess *process;
> + int max_pid = 0;
> +
> + if (mcdserver_state.process_num) {
> + max_pid = s->processes[s->process_num - 1].pid;
> + }
> +
> + s->processes = g_renew(MCDProcess, s->processes, ++s->process_num);
> + process = &s->processes[s->process_num - 1];
> +
> + /* We need an available PID slot for this process */
> + assert(max_pid < UINT32_MAX);
> +
> + process->pid = max_pid + 1;
> + process->attached = false;
> + process->target_xml[0] = '\0';
> +}
> +
> +int find_cpu_clusters(Object *child, void *opaque)
> +{
> + if (object_dynamic_cast(child, TYPE_CPU_CLUSTER)) {
> + MCDState *s = (MCDState *) opaque;
> + CPUClusterState *cluster = CPU_CLUSTER(child);
> + MCDProcess *process;
> +
> + s->processes = g_renew(MCDProcess, s->processes, ++s->process_num);
> +
> + process = &s->processes[s->process_num - 1];
> + assert(cluster->cluster_id != UINT32_MAX);
> + process->pid = cluster->cluster_id + 1;
> + process->attached = false;
> + process->target_xml[0] = '\0';
> +
> + return 0;
> + }
> +
> + return object_child_foreach(child, find_cpu_clusters, opaque);
> +}
> +
> +int pid_order(const void *a, const void *b)
> +{
> + MCDProcess *pa = (MCDProcess *) a;
> + MCDProcess *pb = (MCDProcess *) b;
> +
> + if (pa->pid < pb->pid) {
> + return -1;
> + } else if (pa->pid > pb->pid) {
> + return 1;
> + } else {
> + return 0;
> + }
> +}
> +
> +int mcdserver_start(const char *device)
> +{
> + char mcd_device_config[TCP_CONFIG_STRING_LENGTH];
> + char mcd_tcp_port[TCP_CONFIG_STRING_LENGTH];
> + Chardev *chr = NULL;
> +
> + if (!first_cpu) {
> + error_report("mcdstub: meaningless to attach to a "
> + "machine without any CPU.");
> + return -1;
> + }
> +
> + if (!mcd_supports_guest_debug()) {
> + error_report("mcdstub: current accelerator doesn't "
> + "support guest debugging");
> + return -1;
> + }
> +
> + if (!device) {
> + return -1;
> + }
> +
> + /* if device == default -> set tcp_port = tcp::<MCD_DEFAULT_TCP_PORT> */
> + if (strcmp(device, "default") == 0) {
> + snprintf(mcd_tcp_port, sizeof(mcd_tcp_port), "tcp::%s",
> + MCD_DEFAULT_TCP_PORT);
> + device = mcd_tcp_port;
> + }
> +
> + if (strcmp(device, "none") != 0) {
> + if (strstart(device, "tcp:", NULL)) {
> + /* enforce required TCP attributes */
> + snprintf(mcd_device_config, sizeof(mcd_device_config),
> + "%s,wait=off,nodelay=on,server=on", device);
> + device = mcd_device_config;
> + }
> +#ifndef _WIN32
> + else if (strcmp(device, "stdio") == 0) {
> + struct sigaction act;
> +
> + memset(&act, 0, sizeof(act));
> + act.sa_handler = mcd_sigterm_handler;
> + sigaction(SIGINT, &act, NULL);
> + strcpy(mcd_device_config, device);
> + }
> +#endif
> + chr = qemu_chr_new_noreplay("mcd", device, true, NULL);
> + if (!chr) {
> + return -1;
> + }
> + }
> +
> + if (!mcdserver_state.init) {
> + mcd_init_mcdserver_state();
> +
> + qemu_add_vm_change_state_handler(mcd_vm_state_change, NULL);
> + } else {
> + qemu_chr_fe_deinit(&mcdserver_system_state.chr, true);
> + reset_mcdserver_state();
> + }
> +
> + create_processes(&mcdserver_state);
> +
> + if (chr) {
> + qemu_chr_fe_init(&mcdserver_system_state.chr, chr, &error_abort);
> + qemu_chr_fe_set_handlers(&mcdserver_system_state.chr,
> + mcd_chr_can_receive,
> + mcd_chr_receive, mcd_chr_event,
> + NULL, &mcdserver_state, NULL, true);
> + }
> + mcdserver_state.state = chr ? RS_IDLE : RS_INACTIVE;
> +
> + return 0;
> +}
> +
> +int mcd_chr_can_receive(void *opaque)
> +{
> + return MAX_PACKET_LENGTH;
> +}
> +
> +void mcd_chr_receive(void *opaque, const uint8_t *buf, int size)
> +{
> + int i;
> +
> + for (i = 0; i < size; i++) {
> + mcd_read_byte(buf[i]);
> + if (buf[i] == 0) {
> + break;
> + }
> + }
> +}
> +
> +
> +void mcd_chr_event(void *opaque, QEMUChrEvent event)
> +{
> + int i;
> + MCDState *s = (MCDState *) opaque;
> +
> + switch (event) {
> + case CHR_EVENT_OPENED:
> + /* Start with first process attached, others detached */
> + for (i = 0; i < s->process_num; i++) {
> + s->processes[i].attached = !i;
> + }
> +
> + s->c_cpu = mcd_first_attached_cpu();
> + break;
> + default:
> + break;
> + }
> +}
> +
> +bool mcd_supports_guest_debug(void)
> +{
> + const AccelOpsClass *ops = cpus_get_accel();
> + if (ops->supports_guest_debug) {
> + return ops->supports_guest_debug();
> + }
> + return false;
> +}
> +
> +#ifndef _WIN32
> +void mcd_sigterm_handler(int signal)
> +{
> + if (runstate_is_running()) {
> + vm_stop(RUN_STATE_PAUSED);
> + }
> +}
> +#endif
> +
> +uint32_t mcd_get_cpu_pid(CPUState *cpu)
> +{
> + if (cpu->cluster_index == UNASSIGNED_CLUSTER_INDEX) {
> + /* Return the default process' PID */
> + int index = mcdserver_state.process_num - 1;
> + return mcdserver_state.processes[index].pid;
> + }
> + return cpu->cluster_index + 1;
> +}
> +
> +MCDProcess *mcd_get_process(uint32_t pid)
> +{
> + int i;
> +
> + if (!pid) {
> + /* 0 means any process, we take the first one */
> + return &mcdserver_state.processes[0];
> + }
> +
> + for (i = 0; i < mcdserver_state.process_num; i++) {
> + if (mcdserver_state.processes[i].pid == pid) {
> + return &mcdserver_state.processes[i];
> + }
> + }
> +
> + return NULL;
> +}
> +
> +CPUState *mcd_get_cpu(uint32_t cpu_index)
> +{
> + CPUState *cpu = first_cpu;
> +
> + while (cpu) {
> + if (cpu->cpu_index == cpu_index) {
> + return cpu;
> + }
> + cpu = mcd_next_attached_cpu(cpu);
> + }
> +
> + return cpu;
> +}
> +
> +CPUState *mcd_first_attached_cpu(void)
> +{
> + CPUState *cpu = first_cpu;
> + MCDProcess *process = mcd_get_cpu_process(cpu);
> +
> + if (!process->attached) {
> + return mcd_next_attached_cpu(cpu);
> + }
> +
> + return cpu;
> +}
> +
> +CPUState *mcd_next_attached_cpu(CPUState *cpu)
> +{
> + cpu = CPU_NEXT(cpu);
> +
> + while (cpu) {
> + if (mcd_get_cpu_process(cpu)->attached) {
> + break;
> + }
> +
> + cpu = CPU_NEXT(cpu);
> + }
> +
> + return cpu;
> +}
> +
> +int mcd_get_cpu_index(CPUState *cpu)
> +{
> + return cpu->cpu_index + 1;
> +}
> +
> +CPUState *get_first_cpu_in_process(MCDProcess *process)
> +{
> + CPUState *cpu;
> +
> + CPU_FOREACH(cpu) {
> + if (mcd_get_cpu_pid(cpu) == process->pid) {
> + return cpu;
> + }
> + }
> +
> + return NULL;
> +}
> +
> +CPUState *find_cpu(uint32_t thread_id)
> +{
> + CPUState *cpu;
> +
> + CPU_FOREACH(cpu) {
> + if (mcd_get_cpu_index(cpu) == thread_id) {
> + return cpu;
> + }
> + }
> +
> + return NULL;
> +}
> +
> diff --git a/qemu-options.hx b/qemu-options.hx
> index e26230bac5..accf92642c 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -4430,6 +4430,24 @@ SRST
> (see the :ref:`GDB usage` chapter in the System Emulation Users Guide).
> ERST
>
> +DEF("mcd", HAS_ARG, QEMU_OPTION_mcd, \
> + "-mcd dev accept mcd connection on 'dev'. (QEMU defaults to starting\n"
> + " the guest without waiting for a mcd client to connect; use -S too\n"
> + " if you want it to not start execution.)\n"
> + " To use the default Port write '-mcd default'\n",
> + QEMU_ARCH_ALL)
> +SRST
> +``-mcd dev``
> + Accept a mcd connection on device dev. Note that this option does not pause QEMU
> + execution -- if you want QEMU to not start the guest until you
> + connect with mcd and issue a ``run`` command, you will need to
> + also pass the ``-S`` option to QEMU.
> +
> + The most usual configuration is to listen on a local TCP socket::
> +
> + -mcd tcp::1235
> +ERST
> +
> DEF("d", HAS_ARG, QEMU_OPTION_d, \
> "-d item1,... enable logging of specified items (use '-d help' for a list of log items)\n",
> QEMU_ARCH_ALL)
> diff --git a/system/vl.c b/system/vl.c
> index 92d29bf521..b657c77ea4 100644
> --- a/system/vl.c
> +++ b/system/vl.c
> @@ -68,6 +68,7 @@
> #include "sysemu/numa.h"
> #include "sysemu/hostmem.h"
> #include "exec/gdbstub.h"
> +#include "mcdstub/mcdstub.h"
> #include "qemu/timer.h"
> #include "chardev/char.h"
> #include "qemu/bitmap.h"
> @@ -1266,6 +1267,7 @@ struct device_config {
> DEV_PARALLEL, /* -parallel */
> DEV_DEBUGCON, /* -debugcon */
> DEV_GDB, /* -gdb, -s */
> + DEV_MCD, /* -mcd */
> DEV_SCLP, /* s390 sclp */
> } type;
> const char *cmdline;
> @@ -2673,6 +2675,14 @@ static void qemu_machine_creation_done(void)
> if (foreach_device_config(DEV_GDB, gdbserver_start) < 0) {
> exit(1);
> }
> +
> + if (foreach_device_config(DEV_MCD, mcdserver_start) < 0) {
> + /*
> + * starts the mcdserver if the mcd option was set
> + */
> + exit(1);
> + }
> +
More compile failures:
FAILED: qemu-system-alpha
cc -m64 -mcx16 -o qemu-system-alpha libcommon.fa.p/hw_core_cpu-common.c.o libcommon.fa.p/hw_core_machine-smp.c.o libcommon.fa.p/gdbstub_syscalls.c.o libcommon.fa.p/cpu-common.c.o libcommon.fa.p/page-vary-common.c.o libcommon.fa.p/disas_alpha.c.o libcommon.fa.p/disas_capstone.c.o libcommon.fa.p/disas_disas.c.o libcommon.fa.p/accel_tcg_cpu-exec-common.c.o libcommon.fa.p/trace_trace-hmp-cmds.c.o libcommon.fa.p/qom_qom-hmp-cmds.c.o libcommon.fa.p/crypto_tls-cipher-suites.c.o libcommon.fa.p/ui_clipboard.c.o libcommon.fa.p/ui_console.c.o libcommon.fa.p/ui_cursor.c.o libcommon.fa.p/ui_input-keymap.c.o libcommon.fa.p/ui_input-legacy.c.o libcommon.fa.p/ui_input-barrier.c.o libcommon.fa.p/ui_input.c.o libcommon.fa.p/ui_kbd-state.c.o libcommon.fa.p/ui_keymaps.c.o libcommon.fa.p/ui_qemu-pixman.c.o libcommon.fa.p/ui_ui-hmp-cmds.c.o libcommon.fa.p/ui_ui-qmp-cmds.c.o libcommon.fa.p/ui_util.c.o libcommon.fa.p/ui_console-vc.c.o libcommon.fa.p/ui_dbus-module.c.o libcommon.fa.p/ui_spice-module.c.o libcommon.fa.p/ui_vdagent.c.o libcommon.fa.p/ui_input-linux.c.o libcommon.fa.p/ui_udmabuf.c.o libcommon.fa.p/ui_vnc.c.o libcommon.fa.p/ui_vnc-enc-zlib.c.o libcommon.fa.p/ui_vnc-enc-hextile.c.o libcommon.fa.p/ui_vnc-enc-tight.c.o libcommon.fa.p/ui_vnc-palette.c.o libcommon.fa.p/ui_vnc-enc-zrle.c.o libcommon.fa.p/ui_vnc-auth-vencrypt.c.o libcommon.fa.p/ui_vnc-ws.c.o libcommon.fa.p/ui_vnc-jobs.c.o libcommon.fa.p/ui_vnc-clipboard.c.o libcommon.fa.p/ui_vnc-auth-sasl.c.o libcommon.fa.p/hw_9pfs_9p-local.c.o libcommon.fa.p/hw_9pfs_9p-posix-acl.c.o libcommon.fa.p/hw_9pfs_9p-proxy.c.o libcommon.fa.p/hw_9pfs_9p-synth.c.o libcommon.fa.p/hw_9pfs_9p-xattr-user.c.o libcommon.fa.p/hw_9pfs_9p-xattr.c.o libcommon.fa.p/hw_9pfs_9p.c.o libcommon.fa.p/hw_9pfs_codir.c.o libcommon.fa.p/hw_9pfs_cofile.c.o libcommon.fa.p/hw_9pfs_cofs.c.o libcommon.fa.p/hw_9pfs_coth.c.o libcommon.fa.p/hw_9pfs_coxattr.c.o libcommon.fa.p/hw_9pfs_9p-util-linux.c.o libcommon.fa.p/hw_acpi_acpi-stub.c.o libcommon.fa.p/hw_acpi_aml-build-stub.c.o libcommon.fa.p/hw_acpi_ghes-stub.c.o libcommon.fa.p/hw_acpi_acpi_interface.c.o libcommon.fa.p/hw_acpi_pci-bridge-stub.c.o libcommon.fa.p/hw_acpi_acpi-qmp-cmds.c.o libcommon.fa.p/hw_audio_soundhw.c.o libcommon.fa.p/hw_audio_ac97.c.o libcommon.fa.p/hw_audio_fmopl.c.o libcommon.fa.p/hw_audio_adlib.c.o libcommon.fa.p/hw_audio_cs4231a.c.o libcommon.fa.p/hw_audio_es1370.c.o libcommon.fa.p/hw_audio_gus.c.o libcommon.fa.p/hw_audio_gusemu_hal.c.o libcommon.fa.p/hw_audio_gusemu_mixer.c.o libcommon.fa.p/hw_audio_intel-hda.c.o libcommon.fa.p/hw_audio_hda-codec.c.o libcommon.fa.p/hw_audio_pcspk.c.o libcommon.fa.p/hw_audio_sb16.c.o libcommon.fa.p/hw_audio_virtio-snd.c.o libcommon.fa.p/hw_audio_virtio-snd-pci.c.o libcommon.fa.p/hw_block_block.c.o libcommon.fa.p/hw_block_cdrom.c.o libcommon.fa.p/hw_block_hd-geometry.c.o libcommon.fa.p/hw_block_fdc.c.o libcommon.fa.p/hw_block_fdc-isa.c.o libcommon.fa.p/hw_block_dataplane_virtio-blk.c.o libcommon.fa.p/hw_char_ipoctal232.c.o libcommon.fa.p/hw_char_parallel-isa.c.o libcommon.fa.p/hw_char_parallel.c.o libcommon.fa.p/hw_char_serial.c.o libcommon.fa.p/hw_char_serial-isa.c.o libcommon.fa.p/hw_char_serial-pci.c.o libcommon.fa.p/hw_char_serial-pci-multi.c.o libcommon.fa.p/hw_char_virtio-console.c.o libcommon.fa.p/hw_core_generic-loader.c.o libcommon.fa.p/hw_core_guest-loader.c.o libcommon.fa.p/hw_core_cpu-sysemu.c.o libcommon.fa.p/hw_core_fw-path-provider.c.o libcommon.fa.p/hw_core_gpio.c.o libcommon.fa.p/hw_core_loader.c.o libcommon.fa.p/hw_core_machine-hmp-cmds.c.o libcommon.fa.p/hw_core_machine-qmp-cmds.c.o libcommon.fa.p/hw_core_machine.c.o libcommon.fa.p/hw_core_nmi.c.o libcommon.fa.p/hw_core_null-machine.c.o libcommon.fa.p/hw_core_numa.c.o libcommon.fa.p/hw_core_qdev-fw.c.o libcommon.fa.p/hw_core_qdev-properties-system.c.o libcommon.fa.p/hw_core_sysbus.c.o libcommon.fa.p/hw_core_vm-change-state-handler.c.o libcommon.fa.p/hw_core_clock-vmstate.c.o libcommon.fa.p/hw_cpu_core.c.o libcommon.fa.p/hw_cpu_cluster.c.o libcommon.fa.p/hw_cxl_cxl-host-stubs.c.o libcommon.fa.p/hw_display_i2c-ddc.c.o libcommon.fa.p/hw_display_edid-generate.c.o libcommon.fa.p/hw_display_edid-region.c.o libcommon.fa.p/hw_display_cirrus_vga.c.o libcommon.fa.p/hw_display_vga-pci.c.o libcommon.fa.p/hw_display_bochs-display.c.o libcommon.fa.p/hw_display_vga.c.o libcommon.fa.p/hw_display_virtio-dmabuf.c.o libcommon.fa.p/hw_display_acpi-vga-stub.c.o libcommon.fa.p/hw_display_ati.c.o libcommon.fa.p/hw_display_ati_2d.c.o libcommon.fa.p/hw_display_ati_dbg.c.o libcommon.fa.p/hw_dma_i82374.c.o libcommon.fa.p/hw_dma_i8257.c.o libcommon.fa.p/hw_i2c_core.c.o libcommon.fa.p/hw_i2c_bitbang_i2c.c.o libcommon.fa.p/hw_ide_ahci.c.o libcommon.fa.p/hw_ide_ich.c.o libcommon.fa.p/hw_ide_cmd646.c.o libcommon.fa.p/hw_ide_core.c.o libcommon.fa.p/hw_ide_atapi.c.o libcommon.fa.p/hw_ide_pci.c.o libcommon.fa.p/hw_ide_qdev.c.o libcommon.fa.p/hw_input_hid.c.o libcommon.fa.p/hw_input_pckbd.c.o libcommon.fa.p/hw_input_ps2.c.o libcommon.fa.p/hw_input_virtio-input.c.o libcommon.fa.p/hw_input_virtio-input-hid.c.o libcommon.fa.p/hw_input_virtio-input-host.c.o libcommon.fa.p/hw_input_vhost-user-input.c.o libcommon.fa.p/hw_intc_intc.c.o libcommon.fa.p/hw_intc_i8259_common.c.o libcommon.fa.p/hw_intc_i8259.c.o libcommon.fa.p/hw_intc_kvm_irqcount.c.o libcommon.fa.p/hw_ipack_ipack.c.o libcommon.fa.p/hw_ipack_tpci200.c.o libcommon.fa.p/hw_isa_i82378.c.o libcommon.fa.p/hw_isa_isa-bus.c.o libcommon.fa.p/hw_isa_isa-superio.c.o libcommon.fa.p/hw_isa_smc37c669-superio.c.o libcommon.fa.p/hw_mem_cxl_type3_stubs.c.o libcommon.fa.p/hw_misc_pc-testdev.c.o libcommon.fa.p/hw_misc_pci-testdev.c.o libcommon.fa.p/hw_misc_pvpanic.c.o libcommon.fa.p/hw_misc_pvpanic-pci.c.o libcommon.fa.p/hw_misc_i2c-echo.c.o libcommon.fa.p/hw_net_ne2000.c.o libcommon.fa.p/hw_net_ne2000-pci.c.o libcommon.fa.p/hw_net_eepro100.c.o libcommon.fa.p/hw_net_pcnet-pci.c.o libcommon.fa.p/hw_net_pcnet.c.o libcommon.fa.p/hw_net_e1000.c.o libcommon.fa.p/hw_net_e1000x_common.c.o libcommon.fa.p/hw_net_rtl8139.c.o libcommon.fa.p/hw_net_tulip.c.o libcommon.fa.p/hw_net_net_tx_pkt.c.o libcommon.fa.p/hw_net_net_rx_pkt.c.o libcommon.fa.p/hw_net_vmxnet3.c.o libcommon.fa.p/hw_net_ne2000-isa.c.o libcommon.fa.p/hw_net_vhost_net.c.o libcommon.fa.p/hw_net_rocker_qmp-norocker.c.o libcommon.fa.p/hw_net_rocker_rocker-hmp-cmds.c.o libcommon.fa.p/hw_net_can_can_sja1000.c.o libcommon.fa.p/hw_net_can_can_kvaser_pci.c.o libcommon.fa.p/hw_net_can_can_pcm3680_pci.c.o libcommon.fa.p/hw_net_can_can_mioe3680_pci.c.o libcommon.fa.p/hw_net_can_ctucan_core.c.o libcommon.fa.p/hw_net_can_ctucan_pci.c.o libcommon.fa.p/hw_nvme_ctrl.c.o libcommon.fa.p/hw_nvme_dif.c.o libcommon.fa.p/hw_nvme_ns.c.o libcommon.fa.p/hw_nvme_subsys.c.o libcommon.fa.p/hw_nvram_fw_cfg-interface.c.o libcommon.fa.p/hw_nvram_fw_cfg.c.o libcommon.fa.p/hw_nvram_eeprom93xx.c.o libcommon.fa.p/hw_pci_msi.c.o libcommon.fa.p/hw_pci_msix.c.o libcommon.fa.p/hw_pci_pci.c.o libcommon.fa.p/hw_pci_pci_bridge.c.o libcommon.fa.p/hw_pci_pci_host.c.o libcommon.fa.p/hw_pci_pci-hmp-cmds.c.o libcommon.fa.p/hw_pci_pci-qmp-cmds.c.o libcommon.fa.p/hw_pci_pcie_sriov.c.o libcommon.fa.p/hw_pci_shpc.c.o libcommon.fa.p/hw_pci_slotid_cap.c.o libcommon.fa.p/hw_pci_pcie.c.o libcommon.fa.p/hw_pci_pcie_aer.c.o libcommon.fa.p/hw_pci_pcie_doe.c.o libcommon.fa.p/hw_pci-bridge_pci_bridge_dev.c.o libcommon.fa.p/hw_pci-bridge_pci_expander_bridge_stubs.c.o libcommon.fa.p/hw_rtc_mc146818rtc.c.o libcommon.fa.p/hw_scsi_emulation.c.o libcommon.fa.p/hw_scsi_scsi-bus.c.o libcommon.fa.p/hw_scsi_scsi-disk.c.o libcommon.fa.p/hw_scsi_scsi-generic.c.o libcommon.fa.p/hw_scsi_esp.c.o libcommon.fa.p/hw_scsi_esp-pci.c.o libcommon.fa.p/hw_scsi_lsi53c895a.c.o libcommon.fa.p/hw_scsi_megasas.c.o libcommon.fa.p/hw_scsi_mptsas.c.o libcommon.fa.p/hw_scsi_mptconfig.c.o libcommon.fa.p/hw_scsi_mptendian.c.o libcommon.fa.p/hw_scsi_vmw_pvscsi.c.o libcommon.fa.p/hw_scsi_virtio-scsi-dataplane.c.o libcommon.fa.p/hw_scsi_vhost-scsi.c.o libcommon.fa.p/hw_scsi_vhost-user-scsi.c.o libcommon.fa.p/hw_sd_sd.c.o libcommon.fa.p/hw_sd_core.c.o libcommon.fa.p/hw_sd_sdmmc-internal.c.o libcommon.fa.p/hw_sd_sdhci.c.o libcommon.fa.p/hw_sd_sdhci-pci.c.o libcommon.fa.p/hw_smbios_smbios-stub.c.o libcommon.fa.p/hw_timer_i8254_common.c.o libcommon.fa.p/hw_timer_i8254.c.o libcommon.fa.p/hw_ufs_ufs.c.o libcommon.fa.p/hw_ufs_lu.c.o libcommon.fa.p/hw_usb_bus.c.o libcommon.fa.p/hw_usb_combined-packet.c.o libcommon.fa.p/hw_usb_core.c.o libcommon.fa.p/hw_usb_desc.c.o libcommon.fa.p/hw_usb_desc-msos.c.o libcommon.fa.p/hw_usb_libhw.c.o libcommon.fa.p/hw_usb_pcap.c.o libcommon.fa.p/hw_usb_hcd-uhci.c.o libcommon.fa.p/hw_usb_hcd-ohci.c.o libcommon.fa.p/hw_usb_hcd-ohci-pci.c.o libcommon.fa.p/hw_usb_hcd-ehci.c.o libcommon.fa.p/hw_usb_hcd-ehci-pci.c.o libcommon.fa.p/hw_usb_hcd-xhci.c.o libcommon.fa.p/hw_usb_hcd-xhci-pci.c.o libcommon.fa.p/hw_usb_hcd-xhci-nec.c.o libcommon.fa.p/hw_usb_imx-usb-phy.c.o libcommon.fa.p/hw_usb_dev-hub.c.o libcommon.fa.p/hw_usb_dev-hid.c.o libcommon.fa.p/hw_usb_dev-wacom.c.o libcommon.fa.p/hw_usb_dev-storage.c.o libcommon.fa.p/hw_usb_dev-storage-bot.c.o libcommon.fa.p/hw_usb_dev-storage-classic.c.o libcommon.fa.p/hw_usb_dev-uas.c.o libcommon.fa.p/hw_usb_dev-audio.c.o libcommon.fa.p/hw_usb_dev-serial.c.o libcommon.fa.p/hw_usb_dev-network.c.o libcommon.fa.p/hw_usb_dev-mtp.c.o libcommon.fa.p/hw_usb_dev-smartcard-reader.c.o libcommon.fa.p/hw_usb_u2f.c.o libcommon.fa.p/hw_usb_u2f-passthru.c.o libcommon.fa.p/hw_virtio_virtio-bus.c.o libcommon.fa.p/hw_virtio_virtio-pci.c.o libcommon.fa.p/hw_virtio_virtio-crypto.c.o libcommon.fa.p/hw_virtio_vhost-vsock-common.c.o libcommon.fa.p/hw_virtio_virtio-iommu.c.o libcommon.fa.p/hw_virtio_vdpa-dev.c.o libcommon.fa.p/hw_virtio_vhost.c.o libcommon.fa.p/hw_virtio_vhost-user-device.c.o libcommon.fa.p/hw_virtio_vhost-user-device-pci.c.o libcommon.fa.p/hw_virtio_vhost-vdpa.c.o libcommon.fa.p/hw_virtio_virtio-hmp-cmds.c.o libcommon.fa.p/hw_watchdog_watchdog.c.o libcommon.fa.p/hw_watchdog_wdt_i6300esb.c.o libcommon.fa.p/hw_watchdog_wdt_ib700.c.o libcommon.fa.p/audio_audio.c.o libcommon.fa.p/audio_audio-hmp-cmds.c.o libcommon.fa.p/audio_mixeng.c.o libcommon.fa.p/audio_noaudio.c.o libcommon.fa.p/audio_wavaudio.c.o libcommon.fa.p/audio_wavcapture.c.o libcommon.fa.p/chardev_char-hmp-cmds.c.o libcommon.fa.p/chardev_msmouse.c.o libcommon.fa.p/chardev_wctablet.c.o libcommon.fa.p/chardev_testdev.c.o libcommon.fa.p/fsdev_qemu-fsdev-opts.c.o libcommon.fa.p/fsdev_qemu-fsdev-throttle.c.o libcommon.fa.p/fsdev_9p-iov-marshal.c.o libcommon.fa.p/fsdev_9p-marshal.c.o libcommon.fa.p/fsdev_qemu-fsdev.c.o libcommon.fa.p/dump_dump.c.o libcommon.fa.p/dump_dump-hmp-cmds.c.o libcommon.fa.p/block_blkreplay.c.o libcommon.fa.p/block_block-ram-registrar.c.o libcommon.fa.p/block_qapi-sysemu.c.o libcommon.fa.p/block_monitor_block-hmp-cmds.c.o libcommon.fa.p/system_balloon.c.o libcommon.fa.p/system_bootdevice.c.o libcommon.fa.p/system_cpus.c.o libcommon.fa.p/system_cpu-throttle.c.o libcommon.fa.p/system_cpu-timers.c.o libcommon.fa.p/system_datadir.c.o libcommon.fa.p/system_dirtylimit.c.o libcommon.fa.p/system_dma-helpers.c.o libcommon.fa.p/system_globals.c.o libcommon.fa.p/system_memory_mapping.c.o libcommon.fa.p/system_qdev-monitor.c.o libcommon.fa.p/system_qtest.c.o libcommon.fa.p/system_rtc.c.o libcommon.fa.p/system_runstate-action.c.o libcommon.fa.p/system_runstate-hmp-cmds.c.o libcommon.fa.p/system_runstate.c.o libcommon.fa.p/system_tpm-hmp-cmds.c.o libcommon.fa.p/system_vl.c.o libcommon.fa.p/system_tpm.c.o libcommon.fa.p/system_qemu-seccomp.c.o libcommon.fa.p/system_device_tree.c.o libcommon.fa.p/system_async-teardown.c.o libcommon.fa.p/backends_cryptodev-builtin.c.o libcommon.fa.p/backends_cryptodev-hmp-cmds.c.o libcommon.fa.p/backends_cryptodev.c.o libcommon.fa.p/backends_hostmem-ram.c.o libcommon.fa.p/backends_hostmem.c.o libcommon.fa.p/backends_rng-builtin.c.o libcommon.fa.p/backends_rng-egd.c.o libcommon.fa.p/backends_rng.c.o libcommon.fa.p/backends_confidential-guest-support.c.o libcommon.fa.p/backends_rng-random.c.o libcommon.fa.p/backends_hostmem-file.c.o libcommon.fa.p/backends_hostmem-memfd.c.o libcommon.fa.p/backends_vhost-user.c.o libcommon.fa.p/backends_cryptodev-vhost.c.o libcommon.fa.p/backends_cryptodev-vhost-user.c.o libcommon.fa.p/backends_dbus-vmstate.c.o libcommon.fa.p/backends_tpm_tpm_backend.c.o libcommon.fa.p/backends_tpm_tpm_util.c.o libcommon.fa.p/disas_disas-mon.c.o libcommon.fa.p/migration_block-dirty-bitmap.c.o libcommon.fa.p/migration_channel.c.o libcommon.fa.p/migration_channel-block.c.o libcommon.fa.p/migration_dirtyrate.c.o libcommon.fa.p/migration_exec.c.o libcommon.fa.p/migration_fd.c.o libcommon.fa.p/migration_file.c.o libcommon.fa.p/migration_global_state.c.o libcommon.fa.p/migration_migration-hmp-cmds.c.o libcommon.fa.p/migration_migration.c.o libcommon.fa.p/migration_multifd.c.o libcommon.fa.p/migration_multifd-zlib.c.o libcommon.fa.p/migration_ram-compress.c.o libcommon.fa.p/migration_options.c.o libcommon.fa.p/migration_postcopy-ram.c.o libcommon.fa.p/migration_savevm.c.o libcommon.fa.p/migration_socket.c.o libcommon.fa.p/migration_tls.c.o libcommon.fa.p/migration_threadinfo.c.o libcommon.fa.p/migration_colo-failover.c.o libcommon.fa.p/migration_colo.c.o libcommon.fa.p/migration_rdma.c.o libcommon.fa.p/migration_block.c.o libcommon.fa.p/migration_multifd-zstd.c.o libcommon.fa.p/monitor_fds.c.o libcommon.fa.p/monitor_hmp-cmds.c.o libcommon.fa.p/monitor_hmp.c.o libcommon.fa.p/monitor_qmp-cmds.c.o libcommon.fa.p/net_announce.c.o libcommon.fa.p/net_checksum.c.o libcommon.fa.p/net_dump.c.o libcommon.fa.p/net_eth.c.o libcommon.fa.p/net_filter-buffer.c.o libcommon.fa.p/net_filter-mirror.c.o libcommon.fa.p/net_filter.c.o libcommon.fa.p/net_hub.c.o libcommon.fa.p/net_net-hmp-cmds.c.o libcommon.fa.p/net_net.c.o libcommon.fa.p/net_queue.c.o libcommon.fa.p/net_socket.c.o libcommon.fa.p/net_stream.c.o libcommon.fa.p/net_dgram.c.o libcommon.fa.p/net_util.c.o libcommon.fa.p/net_colo-compare.c.o libcommon.fa.p/net_colo.c.o libcommon.fa.p/net_filter-rewriter.c.o libcommon.fa.p/net_filter-replay.c.o libcommon.fa.p/net_l2tpv3.c.o libcommon.fa.p/net_slirp.c.o libcommon.fa.p/net_vde.c.o libcommon.fa.p/net_vhost-user.c.o libcommon.fa.p/net_tap.c.o libcommon.fa.p/net_tap-linux.c.o libcommon.fa.p/net_vhost-vdpa.c.o libcommon.fa.p/net_can_can_core.c.o libcommon.fa.p/net_can_can_host.c.o libcommon.fa.p/net_can_can_socketcan.c.o libcommon.fa.p/replay_replay.c.o libcommon.fa.p/replay_replay-internal.c.o libcommon.fa.p/replay_replay-events.c.o libcommon.fa.p/replay_replay-time.c.o libcommon.fa.p/replay_replay-input.c.o libcommon.fa.p/replay_replay-char.c.o libcommon.fa.p/replay_replay-snapshot.c.o libcommon.fa.p/replay_replay-net.c.o libcommon.fa.p/replay_replay-audio.c.o libcommon.fa.p/replay_replay-random.c.o libcommon.fa.p/replay_replay-debugging.c.o libcommon.fa.p/stats_stats-hmp-cmds.c.o libcommon.fa.p/stats_stats-qmp-cmds.c.o libcommon.fa.p/accel_accel-system.c.o libcommon.fa.p/accel_accel-blocker.c.o libcommon.fa.p/accel_tcg_icount-common.c.o libcommon.fa.p/accel_tcg_monitor.c.o libcommon.fa.p/accel_dummy-cpus.c.o libcommon.fa.p/ebpf_ebpf_rss.c.o libcommon.fa.p/ui_curses.c.o libcommon.fa.p/ui_shader.c.o libcommon.fa.p/ui_console-gl.c.o libcommon.fa.p/ui_egl-helpers.c.o libcommon.fa.p/ui_egl-context.c.o libcommon.fa.p/ui_egl-headless.c.o libcommon.fa.p/ui_dbus-chardev.c.o libcommon.fa.p/ui_dbus-clipboard.c.o libcommon.fa.p/ui_dbus-console.c.o libcommon.fa.p/ui_dbus-error.c.o libcommon.fa.p/ui_dbus-listener.c.o libcommon.fa.p/ui_dbus.c.o libcommon.fa.p/ui_gtk.c.o libcommon.fa.p/ui_x_keymap.c.o libcommon.fa.p/ui_gtk-gl-area.c.o libcommon.fa.p/ui_gtk-egl.c.o libcommon.fa.p/ui_sdl2-2d.c.o libcommon.fa.p/ui_sdl2-input.c.o libcommon.fa.p/ui_sdl2.c.o libcommon.fa.p/ui_sdl2-gl.c.o libcommon.fa.p/ui_spice-core.c.o libcommon.fa.p/ui_spice-input.c.o libcommon.fa.p/ui_spice-display.c.o libcommon.fa.p/ui_spice-app.c.o libcommon.fa.p/hw_display_virtio-gpu-base.c.o libcommon.fa.p/hw_display_virtio-gpu.c.o libcommon.fa.p/hw_display_virtio-gpu-udmabuf.c.o libcommon.fa.p/hw_display_vhost-user-gpu.c.o libcommon.fa.p/hw_display_virtio-gpu-gl.c.o libcommon.fa.p/hw_display_virtio-gpu-virgl.c.o libcommon.fa.p/hw_display_virtio-gpu-pci.c.o libcommon.fa.p/hw_display_vhost-user-gpu-pci.c.o libcommon.fa.p/hw_display_virtio-gpu-pci-gl.c.o libcommon.fa.p/hw_usb_ccid-card-emulated.c.o libcommon.fa.p/hw_usb_ccid-card-passthru.c.o libcommon.fa.p/hw_usb_redirect.c.o libcommon.fa.p/hw_usb_quirks.c.o libcommon.fa.p/hw_usb_host-libusb.c.o libcommon.fa.p/audio_alsaaudio.c.o libcommon.fa.p/audio_ossaudio.c.o libcommon.fa.p/audio_paaudio.c.o libcommon.fa.p/audio_sdlaudio.c.o libcommon.fa.p/audio_jackaudio.c.o libcommon.fa.p/audio_sndioaudio.c.o libcommon.fa.p/audio_spiceaudio.c.o libcommon.fa.p/audio_dbusaudio.c.o libcommon.fa.p/chardev_baum.c.o libcommon.fa.p/chardev_spice.c.o libqemu-alpha-softmmu.fa.p/target_alpha_machine.c.o libqemu-alpha-softmmu.fa.p/hw_alpha_dp264.c.o libqemu-alpha-softmmu.fa.p/hw_alpha_pci.c.o libqemu-alpha-softmmu.fa.p/hw_alpha_typhoon.c.o libqemu-alpha-softmmu.fa.p/target_alpha_cpu.c.o libqemu-alpha-softmmu.fa.p/target_alpha_fpu_helper.c.o libqemu-alpha-softmmu.fa.p/target_alpha_gdbstub.c.o libqemu-alpha-softmmu.fa.p/target_alpha_helper.c.o libqemu-alpha-softmmu.fa.p/target_alpha_int_helper.c.o libqemu-alpha-softmmu.fa.p/target_alpha_mem_helper.c.o libqemu-alpha-softmmu.fa.p/target_alpha_sys_helper.c.o libqemu-alpha-softmmu.fa.p/target_alpha_translate.c.o libqemu-alpha-softmmu.fa.p/target_alpha_vax_helper.c.o libqemu-alpha-softmmu.fa.p/trace_control-target.c.o libqemu-alpha-softmmu.fa.p/hw_9pfs_virtio-9p-device.c.o libqemu-alpha-softmmu.fa.p/hw_block_virtio-blk.c.o libqemu-alpha-softmmu.fa.p/hw_block_virtio-blk-common.c.o libqemu-alpha-softmmu.fa.p/hw_block_vhost-user-blk.c.o libqemu-alpha-softmmu.fa.p/hw_char_virtio-serial-bus.c.o libqemu-alpha-softmmu.fa.p/hw_hyperv_hv-balloon-stub.c.o libqemu-alpha-softmmu.fa.p/hw_net_virtio-net.c.o libqemu-alpha-softmmu.fa.p/hw_scsi_virtio-scsi.c.o libqemu-alpha-softmmu.fa.p/hw_scsi_vhost-scsi-common.c.o libqemu-alpha-softmmu.fa.p/hw_vfio_helpers.c.o libqemu-alpha-softmmu.fa.p/hw_vfio_common.c.o libqemu-alpha-softmmu.fa.p/hw_vfio_container.c.o libqemu-alpha-softmmu.fa.p/hw_vfio_spapr.c.o libqemu-alpha-softmmu.fa.p/hw_vfio_migration.c.o libqemu-alpha-softmmu.fa.p/hw_vfio_display.c.o libqemu-alpha-softmmu.fa.p/hw_vfio_pci-quirks.c.o libqemu-alpha-softmmu.fa.p/hw_vfio_pci.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_virtio.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_virtio-config-io.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_virtio-qmp.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_vhost-backend.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_vhost-iova-tree.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_vhost-user.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_vhost-shadow-virtqueue.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_virtio-balloon.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_vhost-user-fs.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_vhost-vsock.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_vhost-user-vsock.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_virtio-rng.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_vhost-user-i2c.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_vhost-user-rng.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_vhost-user-gpio.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_vhost-user-gpio-pci.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_vhost-user-scmi.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_vhost-user-scmi-pci.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_vhost-vsock-pci.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_vhost-user-vsock-pci.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_vhost-user-blk-pci.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_vhost-user-i2c-pci.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_vhost-user-input-pci.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_vhost-user-rng-pci.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_vhost-user-scsi-pci.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_vhost-scsi-pci.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_vhost-user-fs-pci.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_virtio-crypto-pci.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_virtio-input-host-pci.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_virtio-input-pci.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_virtio-rng-pci.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_virtio-balloon-pci.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_virtio-9p-pci.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_virtio-scsi-pci.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_virtio-blk-pci.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_virtio-net-pci.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_virtio-serial-pci.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_virtio-iommu-pci.c.o libqemu-alpha-softmmu.fa.p/hw_virtio_vdpa-dev-pci.c.o libqemu-alpha-softmmu.fa.p/hw_i386_kvm_xen-stubs.c.o libqemu-alpha-softmmu.fa.p/dump_win_dump.c.o libqemu-alpha-softmmu.fa.p/cpu-target.c.o libqemu-alpha-softmmu.fa.p/system_arch_init.c.o libqemu-alpha-softmmu.fa.p/system_ioport.c.o libqemu-alpha-softmmu.fa.p/system_memory.c.o libqemu-alpha-softmmu.fa.p/system_physmem.c.o libqemu-alpha-softmmu.fa.p/system_watchpoint.c.o libqemu-alpha-softmmu.fa.p/page-vary-target.c.o libqemu-alpha-softmmu.fa.p/migration_ram.c.o libqemu-alpha-softmmu.fa.p/migration_target.c.o libqemu-alpha-softmmu.fa.p/monitor_hmp-cmds-target.c.o libqemu-alpha-softmmu.fa.p/monitor_hmp-target.c.o libqemu-alpha-softmmu.fa.p/fpu_softfloat.c.o libqemu-alpha-softmmu.fa.p/accel_accel-target.c.o libqemu-alpha-softmmu.fa.p/accel_tcg_tcg-all.c.o libqemu-alpha-softmmu.fa.p/accel_tcg_cpu-exec.c.o libqemu-alpha-softmmu.fa.p/accel_tcg_tb-maint.c.o libqemu-alpha-softmmu.fa.p/accel_tcg_tcg-runtime-gvec.c.o libqemu-alpha-softmmu.fa.p/accel_tcg_tcg-runtime.c.o libqemu-alpha-softmmu.fa.p/accel_tcg_translate-all.c.o libqemu-alpha-softmmu.fa.p/accel_tcg_translator.c.o libqemu-alpha-softmmu.fa.p/accel_tcg_plugin-gen.c.o libqemu-alpha-softmmu.fa.p/accel_tcg_perf.c.o libqemu-alpha-softmmu.fa.p/accel_tcg_cputlb.c.o libqemu-alpha-softmmu.fa.p/accel_stubs_xen-stub.c.o libqemu-alpha-softmmu.fa.p/accel_stubs_kvm-stub.c.o libqemu-alpha-softmmu.fa.p/plugins_loader.c.o libqemu-alpha-softmmu.fa.p/plugins_core.c.o libqemu-alpha-softmmu.fa.p/plugins_api.c.o libqemu-alpha-softmmu.fa.p/accel_tcg_tcg-accel-ops.c.o libqemu-alpha-softmmu.fa.p/accel_tcg_tcg-accel-ops-mttcg.c.o libqemu-alpha-softmmu.fa.p/accel_tcg_tcg-accel-ops-icount.c.o libqemu-alpha-softmmu.fa.p/accel_tcg_tcg-accel-ops-rr.c.o libqemu-alpha-softmmu.fa.p/accel_qtest_qtest.c.o libqemu-alpha-softmmu.fa.p/meson-generated_.._qapi_qapi-types-machine-target.c.o libqemu-alpha-softmmu.fa.p/meson-generated_.._qapi_qapi-visit-machine-target.c.o libqemu-alpha-softmmu.fa.p/meson-generated_.._qapi_qapi-events-machine-target.c.o libqemu-alpha-softmmu.fa.p/meson-generated_.._qapi_qapi-commands-machine-target.c.o libqemu-alpha-softmmu.fa.p/meson-generated_.._qapi_qapi-types-misc-target.c.o libqemu-alpha-softmmu.fa.p/meson-generated_.._qapi_qapi-visit-misc-target.c.o libqemu-alpha-softmmu.fa.p/meson-generated_.._qapi_qapi-events-misc-target.c.o libqemu-alpha-softmmu.fa.p/meson-generated_.._qapi_qapi-commands-misc-target.c.o libqemu-alpha-softmmu.fa.p/meson-generated_.._qapi_qapi-introspect.c.o libqemu-alpha-softmmu.fa.p/meson-generated_.._qapi_qapi-types.c.o libqemu-alpha-softmmu.fa.p/meson-generated_.._qapi_qapi-visit.c.o libqemu-alpha-softmmu.fa.p/meson-generated_.._qapi_qapi-commands.c.o libqemu-alpha-softmmu.fa.p/meson-generated_.._qapi_qapi-init-commands.c.o libqemu-alpha-softmmu.fa.p/meson-generated_.._qapi_qapi-events.c.o libqemu-alpha-softmmu.fa.p/meson-generated_.._qapi_qapi-emit-events.c.o qemu-system-alpha.p/system_main.c.o -Wl,--as-needed -Wl,--no-undefined -pie -Wl,--whole-archive libhwcore.fa libqom.fa libevent-loop-base.fa gdbstub/libgdb_system.fa libio.fa libcrypto.fa libauthz.fa libblockdev.fa libblock.fa libchardev.fa libqmp.fa -Wl,--no-whole-archive -fstack-protector-strong -Wl,-z,relro -Wl,-z,now -Wl,--warn-common -Wl,--start-group libqemuutil.a subprojects/libvhost-user/libvhost-user-glib.a subprojects/libvhost-user/libvhost-user.a tcg/libtcg_system.fa ui/libdbus-display1.a libmigration.fa libhwcore.fa libqom.fa libevent-loop-base.fa gdbstub/libgdb_system.fa libio.fa libcrypto.fa libauthz.fa libblockdev.fa subprojects/libvduse/libvduse.a libblock.fa libchardev.fa libqmp.fa @block.syms @qemu.syms /usr/lib/x86_64-linux-gnu/libpixman-1.so /usr/lib/x86_64-linux-gnu/libepoxy.so /usr/lib/x86_64-linux-gnu/libcapstone.so /usr/lib/x86_64-linux-gnu/libspice-server.so -Xlinker --dynamic-list=/home/alex/lsrc/qemu.git/plugins/qemu-plugins.symbols /usr/lib/x86_64-linux-gnu/libgnutls.so /usr/lib/x86_64-linux-gnu/libpng16.so /usr/lib/x86_64-linux-gnu/libz.so /usr/lib/x86_64-linux-gnu/libjpeg.so -lsasl2 -lfdt /usr/lib/x86_64-linux-gnu/libudev.so /usr/lib/x86_64-linux-gnu/libSDL2.so /usr/lib/x86_64-linux-gnu/libpmem.so /usr/lib/x86_64-linux-gnu/libseccomp.so -lnuma /usr/lib/x86_64-linux-gnu/libgio-2.0.so /usr/lib/x86_64-linux-gnu/libgobject-2.0.so /usr/lib/x86_64-linux-gnu/libglib-2.0.so -lrdmacm -libverbs -libumad /usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/libzstd.so /usr/lib/x86_64-linux-gnu/libslirp.so -lvdeplug /usr/lib/x86_64-linux-gnu/libbpf.so /usr/lib/x86_64-linux-gnu/libncursesw.so /usr/lib/x86_64-linux-gnu/libtinfo.so /usr/lib/x86_64-linux-gnu/libgmodule-2.0.so -pthread /usr/lib/x86_64-linux-gnu/libgbm.so /usr/lib/x86_64-linux-gnu/libgtk-3.so /usr/lib/x86_64-linux-gnu/libgdk-3.so /usr/lib/x86_64-linux-gnu/libpangocairo-1.0.so /usr/lib/x86_64-linux-gnu/libpango-1.0.so /usr/lib/x86_64-linux-gnu/libharfbuzz.so /usr/lib/x86_64-linux-gnu/libatk-1.0.so /usr/lib/x86_64-linux-gnu/libcairo-gobject.so /usr/lib/x86_64-linux-gnu/libcairo.so /usr/lib/x86_64-linux-gnu/libgdk_pixbuf-2.0.so /usr/lib/x86_64-linux-gnu/libvte-2.91.so /usr/lib/x86_64-linux-gnu/libX11.so /usr/lib/x86_64-linux-gnu/libvirglrenderer.so /usr/lib/x86_64-linux-gnu/libcacard.so /usr/lib/x86_64-linux-gnu/libusbredirparser.so /usr/lib/x86_64-linux-gnu/libusb-1.0.so /usr/lib/x86_64-linux-gnu/libasound.so /usr/lib/x86_64-linux-gnu/libpulse.so /usr/lib/x86_64-linux-gnu/libjack.so -lpthread /usr/lib/x86_64-linux-gnu/libsndio.so -lbrlapi @block.syms -lnuma /usr/lib/x86_64-linux-gnu/liburing.so -lm /usr/lib/x86_64-linux-gnu/libfuse3.so /usr/lib/x86_64-linux-gnu/libiscsi.so -laio /usr/lib/x86_64-linux-gnu/libcurl.so /usr/lib/x86_64-linux-gnu/libacl.so /usr/lib/x86_64-linux-gnu/libgfapi.so /usr/lib/x86_64-linux-gnu/libglusterfs.so /usr/lib/x86_64-linux-gnu/libgfrpc.so /usr/lib/x86_64-linux-gnu/libgfxdr.so /usr/lib/x86_64-linux-gnu/libuuid.so /usr/lib/x86_64-linux-gnu/libnfs.so /usr/lib/x86_64-linux-gnu/libssh.so -lrbd -lrados -lutil -Wl,--end-group
/usr/bin/ld: libcommon.fa.p/system_vl.c.o: in function `foreach_device_config':
/home/alex/lsrc/qemu.git/builds/all/../../system/vl.c:1306: undefined reference to `mcdserver_start'
collect2: error: ld returned 1 exit status
I think because you are missing the meson integration to add this to the
build. Is it in a later patch?
> if (!vga_interface_created && !default_vga &&
> vga_interface_type != VGA_NONE) {
> warn_report("A -vga option was passed but this machine "
> @@ -3028,6 +3038,9 @@ void qemu_init(int argc, char **argv)
> case QEMU_OPTION_gdb:
> add_device_config(DEV_GDB, optarg);
> break;
> + case QEMU_OPTION_mcd:
> + add_device_config(DEV_MCD, optarg);
> + break;
> case QEMU_OPTION_L:
> if (is_help_option(optarg)) {
> list_data_dirs = true;
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v3 02/20] mcdstub gdbstub: new DebugClass and DebugState introduced. They are used to abstract the debugger details behind a QOM. This is currently used in the cpu_handle_guest_debug function
2023-11-07 13:03 [PATCH v3 00/20] first version of mcdstub Nicolas Eder
2023-11-07 13:03 ` [PATCH v3 01/20] mcdstub: initial file structure for new mcdstub created. -mcd QEMU startup option added. Functions for initializing the mcdstub added. Basic helper functions for processes/cpus in the mcdstub added Nicolas Eder
@ 2023-11-07 13:03 ` Nicolas Eder
2023-11-07 13:03 ` [PATCH v3 03/20] gdbstub: moving code so that it can be easier accessed from outside the gdbstub: fromhex and tohex functions moved to a cutils header. GDBRegisterState moved to gdbstub.h Nicolas Eder
` (19 subsequent siblings)
21 siblings, 0 replies; 32+ messages in thread
From: Nicolas Eder @ 2023-11-07 13:03 UTC (permalink / raw)
To: qemu-devel
Cc: Nicolas Eder, Alex Bennée, Philippe Mathieu-Daudé,
Christian Boenig
---
debug/debug-common.c | 42 +++++++++++++++++++++++++++++++++++++++++
debug/debug-gdb.c | 24 +++++++++++++++++++++++
debug/debug-mcd.c | 25 ++++++++++++++++++++++++
gdbstub/meson.build | 4 ++--
gdbstub/system.c | 4 ++++
gdbstub/user.c | 2 ++
include/exec/gdbstub.h | 5 +++++
include/hw/boards.h | 1 +
include/qemu/debug.h | 19 +++++++++++++++++++
include/qemu/typedefs.h | 2 ++
system/cpus.c | 9 ++++++++-
11 files changed, 134 insertions(+), 3 deletions(-)
create mode 100644 debug/debug-common.c
create mode 100644 debug/debug-gdb.c
create mode 100644 debug/debug-mcd.c
create mode 100644 include/qemu/debug.h
diff --git a/debug/debug-common.c b/debug/debug-common.c
new file mode 100644
index 0000000000..8f41b4e6cb
--- /dev/null
+++ b/debug/debug-common.c
@@ -0,0 +1,42 @@
+#include "qemu/osdep.h"
+#include "qemu/ctype.h"
+#include "qemu/cutils.h"
+#include "qemu/module.h"
+#include "qemu/error-report.h"
+#include "hw/cpu/cluster.h"
+#include "hw/boards.h"
+#include "sysemu/hw_accel.h"
+#include "sysemu/runstate.h"
+#include "exec/replay-core.h"
+#include "exec/hwaddr.h"
+#include "qemu/debug.h"
+#include "qom/object_interfaces.h"
+
+static void debug_instance_init(Object *obj)
+{
+}
+
+static void debug_finalize(Object *obj)
+{
+}
+
+static void debug_class_init(ObjectClass *oc, void *data)
+{
+}
+
+static const TypeInfo debug_info = {
+ .name = TYPE_DEBUG,
+ .parent = TYPE_OBJECT,
+ .instance_size = sizeof(DebugState),
+ .instance_init = debug_instance_init,
+ .instance_finalize = debug_finalize,
+ .class_size = sizeof(DebugClass),
+ .class_init = debug_class_init
+};
+
+static void debug_register_types(void)
+{
+ type_register_static(&debug_info);
+}
+
+type_init(debug_register_types);
diff --git a/debug/debug-gdb.c b/debug/debug-gdb.c
new file mode 100644
index 0000000000..9c7bcda95f
--- /dev/null
+++ b/debug/debug-gdb.c
@@ -0,0 +1,24 @@
+#include "qemu/osdep.h"
+#include "qemu/ctype.h"
+#include "qemu/cutils.h"
+#include "qemu/module.h"
+#include "qemu/error-report.h"
+#include "hw/cpu/cluster.h"
+#include "hw/boards.h"
+#include "sysemu/hw_accel.h"
+#include "sysemu/runstate.h"
+#include "exec/replay-core.h"
+#include "exec/hwaddr.h"
+#include "exec/gdbstub.h"
+#include "qemu/debug.h"
+
+void gdb_init_debug_class(void)
+{
+ Object *obj;
+ obj = object_new(TYPE_DEBUG);
+ DebugState *ds = DEBUG(obj);
+ DebugClass *dc = DEBUG_GET_CLASS(ds);
+ dc->set_stop_cpu = gdb_set_stop_cpu;
+ MachineState *ms = MACHINE(qdev_get_machine());
+ ms->debug_state = ds;
+}
diff --git a/debug/debug-mcd.c b/debug/debug-mcd.c
new file mode 100644
index 0000000000..2d3a31be15
--- /dev/null
+++ b/debug/debug-mcd.c
@@ -0,0 +1,25 @@
+#include "qemu/osdep.h"
+#include "qemu/ctype.h"
+#include "qemu/cutils.h"
+#include "qemu/module.h"
+#include "qemu/error-report.h"
+#include "hw/cpu/cluster.h"
+#include "hw/boards.h"
+#include "sysemu/hw_accel.h"
+#include "sysemu/runstate.h"
+#include "exec/replay-core.h"
+#include "exec/hwaddr.h"
+#include "mcdstub/mcdstub.h"
+#include "qemu/debug.h"
+#include "qom/object_interfaces.h"
+
+void mcd_init_debug_class(void)
+{
+ Object *obj;
+ obj = object_new(TYPE_DEBUG);
+ DebugState *ds = DEBUG(obj);
+ DebugClass *dc = DEBUG_GET_CLASS(ds);
+ dc->set_stop_cpu = mcd_set_stop_cpu;
+ MachineState *ms = MACHINE(qdev_get_machine());
+ ms->debug_state = ds;
+}
diff --git a/gdbstub/meson.build b/gdbstub/meson.build
index e5bccba34e..359234595a 100644
--- a/gdbstub/meson.build
+++ b/gdbstub/meson.build
@@ -11,8 +11,8 @@ gdb_user_ss = ss.source_set()
gdb_system_ss = ss.source_set()
# We build two versions of gdbstub, one for each mode
-gdb_user_ss.add(files('gdbstub.c', 'user.c'))
-gdb_system_ss.add(files('gdbstub.c', 'system.c'))
+gdb_user_ss.add(files('gdbstub.c', 'user.c', '../debug/debug-gdb.c'))
+gdb_system_ss.add(files('gdbstub.c', 'system.c', '../debug/debug-gdb.c'))
gdb_user_ss = gdb_user_ss.apply(config_targetos, strict: false)
gdb_system_ss = gdb_system_ss.apply(config_targetos, strict: false)
diff --git a/gdbstub/system.c b/gdbstub/system.c
index 783ac140b9..02ec4875f5 100644
--- a/gdbstub/system.c
+++ b/gdbstub/system.c
@@ -14,6 +14,7 @@
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "qemu/cutils.h"
+#include "qemu/debug.h"
#include "exec/gdbstub.h"
#include "gdbstub/syscalls.h"
#include "exec/hwaddr.h"
@@ -405,6 +406,9 @@ int gdbserver_start(const char *device)
gdbserver_system_state.mon_chr = mon_chr;
gdb_syscall_reset();
+ /* create new debug object */
+ gdb_init_debug_class();
+
return 0;
}
diff --git a/gdbstub/user.c b/gdbstub/user.c
index dbe1d9b887..f8207aa9ef 100644
--- a/gdbstub/user.c
+++ b/gdbstub/user.c
@@ -332,8 +332,10 @@ int gdbserver_start(const char *port_or_path)
}
if (port > 0 && gdb_accept_tcp(gdb_fd)) {
+ gdb_init_debug_class();
return 0;
} else if (gdb_accept_socket(gdb_fd)) {
+ gdb_init_debug_class();
gdbserver_user_state.socket_path = g_strdup(port_or_path);
return 0;
}
diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index 1a01c35f8e..f696e29477 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -48,4 +48,9 @@ void gdb_set_stop_cpu(CPUState *cpu);
/* in gdbstub-xml.c, generated by scripts/feature_to_c.py */
extern const GDBFeature gdb_static_features[];
+/**
+ * gdb_init_debug_class() - initialize gdb-specific DebugClass
+ */
+void gdb_init_debug_class(void);
+
#endif
diff --git a/include/hw/boards.h b/include/hw/boards.h
index a735999298..ffc7756b89 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -400,6 +400,7 @@ struct MachineState {
CpuTopology smp;
struct NVDIMMState *nvdimms_state;
struct NumaState *numa_state;
+ DebugState *debug_state;
};
#define DEFINE_MACHINE(namestr, machine_initfn) \
diff --git a/include/qemu/debug.h b/include/qemu/debug.h
new file mode 100644
index 0000000000..870f3ea152
--- /dev/null
+++ b/include/qemu/debug.h
@@ -0,0 +1,19 @@
+#ifndef QEMU_DEBUG_H
+#define QEMU_DEBUG_H
+
+#include "qom/object.h"
+#include "qemu/typedefs.h"
+
+struct DebugClass {
+ ObjectClass parent_class;
+ void (*set_stop_cpu)(CPUState *cpu);
+};
+
+struct DebugState {
+ Object parent_obj;
+};
+
+#define TYPE_DEBUG "debug"
+OBJECT_DECLARE_TYPE(DebugState, DebugClass, DEBUG)
+
+#endif /* QEMU_DEBUG_H */
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
index 5abdbc3874..e48b544173 100644
--- a/include/qemu/typedefs.h
+++ b/include/qemu/typedefs.h
@@ -46,6 +46,8 @@ typedef struct CpuInfoFast CpuInfoFast;
typedef struct CPUJumpCache CPUJumpCache;
typedef struct CPUState CPUState;
typedef struct CPUTLBEntryFull CPUTLBEntryFull;
+typedef struct DebugClass DebugClass;
+typedef struct DebugState DebugState;
typedef struct DeviceListener DeviceListener;
typedef struct DeviceState DeviceState;
typedef struct DirtyBitmapSnapshot DirtyBitmapSnapshot;
diff --git a/system/cpus.c b/system/cpus.c
index 0848e0dbdb..734173096a 100644
--- a/system/cpus.c
+++ b/system/cpus.c
@@ -25,6 +25,7 @@
#include "qemu/osdep.h"
#include "monitor/monitor.h"
#include "qemu/coroutine-tls.h"
+#include "qemu/debug.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-machine.h"
#include "qapi/qapi-commands-misc.h"
@@ -306,7 +307,13 @@ void cpu_handle_guest_debug(CPUState *cpu)
cpu_single_step(cpu, 0);
}
} else {
- gdb_set_stop_cpu(cpu);
+ MachineState *ms = MACHINE(qdev_get_machine());
+ DebugState *ds = ms->debug_state;
+ DebugClass *dc = DEBUG_GET_CLASS(ds);
+
+ if (dc->set_stop_cpu) {
+ dc->set_stop_cpu(cpu);
+ }
qemu_system_debug_request();
cpu->stopped = true;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 03/20] gdbstub: moving code so that it can be easier accessed from outside the gdbstub: fromhex and tohex functions moved to a cutils header. GDBRegisterState moved to gdbstub.h
2023-11-07 13:03 [PATCH v3 00/20] first version of mcdstub Nicolas Eder
2023-11-07 13:03 ` [PATCH v3 01/20] mcdstub: initial file structure for new mcdstub created. -mcd QEMU startup option added. Functions for initializing the mcdstub added. Basic helper functions for processes/cpus in the mcdstub added Nicolas Eder
2023-11-07 13:03 ` [PATCH v3 02/20] mcdstub gdbstub: new DebugClass and DebugState introduced. They are used to abstract the debugger details behind a QOM. This is currently used in the cpu_handle_guest_debug function Nicolas Eder
@ 2023-11-07 13:03 ` Nicolas Eder
2023-11-29 15:51 ` Alex Bennée
2023-11-07 13:03 ` [PATCH v3 04/20] mcdstub: added header with defines specific to the mcd tcp packet communication Nicolas Eder
` (18 subsequent siblings)
21 siblings, 1 reply; 32+ messages in thread
From: Nicolas Eder @ 2023-11-07 13:03 UTC (permalink / raw)
To: qemu-devel
Cc: Nicolas Eder, Alex Bennée, Philippe Mathieu-Daudé,
Christian Boenig
---
gdbstub/gdbstub.c | 9 +--------
gdbstub/internals.h | 26 --------------------------
include/cutils.h | 30 ++++++++++++++++++++++++++++++
include/exec/gdbstub.h | 9 ++++++++-
4 files changed, 39 insertions(+), 35 deletions(-)
create mode 100644 include/cutils.h
diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
index 1e96a71c0c..c43ff89393 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -44,14 +44,7 @@
#include "exec/hwaddr.h"
#include "internals.h"
-
-typedef struct GDBRegisterState {
- int base_reg;
- int num_regs;
- gdb_get_reg_cb get_reg;
- gdb_set_reg_cb set_reg;
- const char *xml;
-} GDBRegisterState;
+#include "cutils.h"
GDBState gdbserver_state;
diff --git a/gdbstub/internals.h b/gdbstub/internals.h
index 465c24b36e..011e6f1858 100644
--- a/gdbstub/internals.h
+++ b/gdbstub/internals.h
@@ -74,32 +74,6 @@ typedef struct GDBState {
/* lives in main gdbstub.c */
extern GDBState gdbserver_state;
-/*
- * Inline utility function, convert from int to hex and back
- */
-
-static inline int fromhex(int v)
-{
- if (v >= '0' && v <= '9') {
- return v - '0';
- } else if (v >= 'A' && v <= 'F') {
- return v - 'A' + 10;
- } else if (v >= 'a' && v <= 'f') {
- return v - 'a' + 10;
- } else {
- return 0;
- }
-}
-
-static inline int tohex(int v)
-{
- if (v < 10) {
- return v + '0';
- } else {
- return v - 10 + 'a';
- }
-}
-
/*
* Connection helpers for both system and user backends
*/
diff --git a/include/cutils.h b/include/cutils.h
new file mode 100644
index 0000000000..a6b8dc3690
--- /dev/null
+++ b/include/cutils.h
@@ -0,0 +1,30 @@
+#ifndef CUTILS_H
+#define CUTILS_H
+
+/*
+ * Inline utility function, convert from int to hex and back
+ */
+
+static inline int fromhex(int v)
+{
+ if (v >= '0' && v <= '9') {
+ return v - '0';
+ } else if (v >= 'A' && v <= 'F') {
+ return v - 'A' + 10;
+ } else if (v >= 'a' && v <= 'f') {
+ return v - 'a' + 10;
+ } else {
+ return 0;
+ }
+}
+
+static inline int tohex(int v)
+{
+ if (v < 10) {
+ return v + '0';
+ } else {
+ return v - 10 + 'a';
+ }
+}
+
+#endif /* CUTILS_H */
diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index f696e29477..cb70ebd7b4 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -15,11 +15,18 @@ typedef struct GDBFeature {
const char *xml;
} GDBFeature;
-
/* Get or set a register. Returns the size of the register. */
typedef int (*gdb_get_reg_cb)(CPUArchState *env, GByteArray *buf, int reg);
typedef int (*gdb_set_reg_cb)(CPUArchState *env, uint8_t *buf, int reg);
+typedef struct GDBRegisterState {
+ int base_reg;
+ int num_regs;
+ gdb_get_reg_cb get_reg;
+ gdb_set_reg_cb set_reg;
+ const char *xml;
+} GDBRegisterState;
+
/**
* gdb_register_coprocessor() - register a supplemental set of registers
* @cpu - the CPU associated with registers
--
2.34.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* Re: [PATCH v3 03/20] gdbstub: moving code so that it can be easier accessed from outside the gdbstub: fromhex and tohex functions moved to a cutils header. GDBRegisterState moved to gdbstub.h
2023-11-07 13:03 ` [PATCH v3 03/20] gdbstub: moving code so that it can be easier accessed from outside the gdbstub: fromhex and tohex functions moved to a cutils header. GDBRegisterState moved to gdbstub.h Nicolas Eder
@ 2023-11-29 15:51 ` Alex Bennée
0 siblings, 0 replies; 32+ messages in thread
From: Alex Bennée @ 2023-11-29 15:51 UTC (permalink / raw)
To: Nicolas Eder; +Cc: qemu-devel, Philippe Mathieu-Daudé, Christian Boenig
Nicolas Eder <nicolas.eder@lauterbach.com> writes:
> ---
> gdbstub/gdbstub.c | 9 +--------
> gdbstub/internals.h | 26 --------------------------
> include/cutils.h | 30 ++++++++++++++++++++++++++++++
> include/exec/gdbstub.h | 9 ++++++++-
Please split into the utils and the reg state patches as they are unrelated.
> 4 files changed, 39 insertions(+), 35 deletions(-)
> create mode 100644 include/cutils.h
>
> diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
> index 1e96a71c0c..c43ff89393 100644
> --- a/gdbstub/gdbstub.c
> +++ b/gdbstub/gdbstub.c
> @@ -44,14 +44,7 @@
> #include "exec/hwaddr.h"
>
> #include "internals.h"
> -
> -typedef struct GDBRegisterState {
> - int base_reg;
> - int num_regs;
> - gdb_get_reg_cb get_reg;
> - gdb_set_reg_cb set_reg;
> - const char *xml;
> -} GDBRegisterState;
> +#include "cutils.h"
>
> GDBState gdbserver_state;
>
> diff --git a/gdbstub/internals.h b/gdbstub/internals.h
> index 465c24b36e..011e6f1858 100644
> --- a/gdbstub/internals.h
> +++ b/gdbstub/internals.h
> @@ -74,32 +74,6 @@ typedef struct GDBState {
> /* lives in main gdbstub.c */
> extern GDBState gdbserver_state;
>
> -/*
> - * Inline utility function, convert from int to hex and back
> - */
> -
> -static inline int fromhex(int v)
> -{
> - if (v >= '0' && v <= '9') {
> - return v - '0';
> - } else if (v >= 'A' && v <= 'F') {
> - return v - 'A' + 10;
> - } else if (v >= 'a' && v <= 'f') {
> - return v - 'a' + 10;
> - } else {
> - return 0;
> - }
> -}
> -
> -static inline int tohex(int v)
> -{
> - if (v < 10) {
> - return v + '0';
> - } else {
> - return v - 10 + 'a';
> - }
> -}
> -
> /*
> * Connection helpers for both system and user backends
> */
> diff --git a/include/cutils.h b/include/cutils.h
> new file mode 100644
> index 0000000000..a6b8dc3690
> --- /dev/null
> +++ b/include/cutils.h
> @@ -0,0 +1,30 @@
> +#ifndef CUTILS_H
> +#define CUTILS_H
We already have include/qemu/cutils.h where I think these can go.
> +
> +/*
> + * Inline utility function, convert from int to hex and back
> + */
Becoming common util functions they could do with a little cleaning up
before wider use.
- kdoc comment string
- rename to be clearer, maybe:
- hexchar_to_nibble
- nibble_to_hexchar
> +
> +static inline int fromhex(int v)
> +{
> + if (v >= '0' && v <= '9') {
> + return v - '0';
> + } else if (v >= 'A' && v <= 'F') {
> + return v - 'A' + 10;
> + } else if (v >= 'a' && v <= 'f') {
> + return v - 'a' + 10;
> + } else {
> + return 0;
g_assert_not_reached()? or document invalid chars are squashed to 0
> + }
> +}
> +
> +static inline int tohex(int v)
> +{
g_assert(v =< 0xf)
> + if (v < 10) {
> + return v + '0';
> + } else {
> + return v - 10 + 'a';
> + }
> +}
> +
> +#endif /* CUTILS_H */
> diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
> index f696e29477..cb70ebd7b4 100644
> --- a/include/exec/gdbstub.h
> +++ b/include/exec/gdbstub.h
> @@ -15,11 +15,18 @@ typedef struct GDBFeature {
> const char *xml;
> } GDBFeature;
>
> -
> /* Get or set a register. Returns the size of the register. */
> typedef int (*gdb_get_reg_cb)(CPUArchState *env, GByteArray *buf, int reg);
> typedef int (*gdb_set_reg_cb)(CPUArchState *env, uint8_t *buf, int reg);
>
> +typedef struct GDBRegisterState {
> + int base_reg;
> + int num_regs;
> + gdb_get_reg_cb get_reg;
> + gdb_set_reg_cb set_reg;
> + const char *xml;
> +} GDBRegisterState;
> +
> /**
> * gdb_register_coprocessor() - register a supplemental set of registers
> * @cpu - the CPU associated with registers
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v3 04/20] mcdstub: added header with defines specific to the mcd tcp packet communication
2023-11-07 13:03 [PATCH v3 00/20] first version of mcdstub Nicolas Eder
` (2 preceding siblings ...)
2023-11-07 13:03 ` [PATCH v3 03/20] gdbstub: moving code so that it can be easier accessed from outside the gdbstub: fromhex and tohex functions moved to a cutils header. GDBRegisterState moved to gdbstub.h Nicolas Eder
@ 2023-11-07 13:03 ` Nicolas Eder
2023-11-29 16:02 ` Alex Bennée
2023-11-07 13:03 ` [PATCH v3 05/20] mcdstub: tcp packet processing added Nicolas Eder
` (17 subsequent siblings)
21 siblings, 1 reply; 32+ messages in thread
From: Nicolas Eder @ 2023-11-07 13:03 UTC (permalink / raw)
To: qemu-devel
Cc: Nicolas Eder, Alex Bennée, Philippe Mathieu-Daudé,
Christian Boenig
---
include/mcdstub/mcd_shared_defines.h | 108 +++++++++++++++++++++++++++
1 file changed, 108 insertions(+)
create mode 100644 include/mcdstub/mcd_shared_defines.h
diff --git a/include/mcdstub/mcd_shared_defines.h b/include/mcdstub/mcd_shared_defines.h
new file mode 100644
index 0000000000..fa1adb5c77
--- /dev/null
+++ b/include/mcdstub/mcd_shared_defines.h
@@ -0,0 +1,108 @@
+/*
+ *this file is shared between the mcd dll and the mcd stub.
+ *it has to be kept exectly the same!
+ */
+
+#ifndef MCD_SHARED_DEFINES
+#define MCD_SHARED_DEFINES
+
+/* default tcp port */
+#define MCD_DEFAULT_TCP_PORT "1235"
+
+/* tcp data characters */
+#define TCP_CHAR_OPEN_SERVER 'I'
+#define TCP_CHAR_OPEN_CORE 'i'
+#define TCP_CHAR_GO 'C'
+#define TCP_CHAR_STEP 'c'
+#define TCP_CHAR_BREAK 'b'
+#define TCP_CHAR_QUERY 'q'
+#define TCP_CHAR_CLOSE_SERVER 'D'
+#define TCP_CHAR_CLOSE_CORE 'd'
+#define TCP_CHAR_KILLQEMU 'k'
+#define TCP_CHAR_RESET 'r'
+#define TCP_CHAR_READ_REGISTER 'p'
+#define TCP_CHAR_WRITE_REGISTER 'P'
+#define TCP_CHAR_READ_MEMORY 'm'
+#define TCP_CHAR_WRITE_MEMORY 'M'
+#define TCP_CHAR_BREAKPOINT_INSERT 't'
+#define TCP_CHAR_BREAKPOINT_REMOVE 'T'
+
+/* tcp protocol chars */
+#define TCP_ACKNOWLEDGED '+'
+#define TCP_NOT_ACKNOWLEDGED '-'
+#define TCP_COMMAND_START '$'
+#define TCP_COMMAND_END '#'
+#define TCP_WAS_LAST '|'
+#define TCP_WAS_NOT_LAST '~'
+#define TCP_HANDSHAKE_SUCCESS "shaking your hand"
+#define TCP_EXECUTION_SUCCESS "success"
+#define TCP_EXECUTION_ERROR "error"
+
+/* tcp query arguments */
+#define QUERY_FIRST "f"
+#define QUERY_CONSEQUTIVE "c"
+#define QUERY_END_INDEX "!"
+
+#define QUERY_ARG_SYSTEM "system"
+#define QUERY_ARG_CORES "cores"
+#define QUERY_ARG_RESET "reset"
+#define QUERY_ARG_TRIGGER "trigger"
+#define QUERY_ARG_MEMORY "memory"
+#define QUERY_ARG_REGGROUP "reggroup"
+#define QUERY_ARG_REG "reg"
+#define QUERY_ARG_STATE "state"
+
+/* tcp query packet argument list */
+#define TCP_ARGUMENT_NAME "name"
+#define TCP_ARGUMENT_DATA "data"
+#define TCP_ARGUMENT_ID "id"
+#define TCP_ARGUMENT_TYPE "type"
+#define TCP_ARGUMENT_BITS_PER_MAU "bpm"
+#define TCP_ARGUMENT_INVARIANCE "i"
+#define TCP_ARGUMENT_ENDIAN "e"
+#define TCP_ARGUMENT_MIN "min"
+#define TCP_ARGUMENT_MAX "max"
+#define TCP_ARGUMENT_SUPPORTED_ACCESS_OPTIONS "sao"
+#define TCP_ARGUMENT_REGGROUPID "reggroupid"
+#define TCP_ARGUMENT_MEMSPACEID "memspaceid"
+#define TCP_ARGUMENT_SIZE "size"
+#define TCP_ARGUMENT_THREAD "thread"
+#define TCP_ARGUMENT_ADDRESS "address"
+#define TCP_ARGUMENT_STOP_STRING "stop_str"
+#define TCP_ARGUMENT_INFO_STRING "info_str"
+#define TCP_ARGUMENT_STATE "state"
+#define TCP_ARGUMENT_EVENT "event"
+#define TCP_ARGUMENT_DEVICE "device"
+#define TCP_ARGUMENT_CORE "core"
+#define TCP_ARGUMENT_AMOUNT_CORE "nr_cores"
+#define TCP_ARGUMENT_AMOUNT_TRIGGER "nr_trigger"
+#define TCP_ARGUMENT_OPTION "option"
+#define TCP_ARGUMENT_ACTION "action"
+#define TCP_ARGUMENT_OPCODE "opcode"
+
+/* for packets sent to qemu */
+#define ARGUMENT_SEPARATOR ';'
+#define NEGATIVE_FLAG 0
+#define POSITIVE_FLAG 1
+
+/* core states */
+#define CORE_STATE_RUNNING "running"
+#define CORE_STATE_HALTED "halted"
+#define CORE_STATE_DEBUG "debug"
+#define CORE_STATE_UNKNOWN "unknown"
+
+/* breakpoint types */
+#define MCD_BREAKPOINT_HW 1
+#define MCD_BREAKPOINT_READ 2
+#define MCD_BREAKPOINT_WRITE 3
+#define MCD_BREAKPOINT_RW 4
+
+/* trigger data */
+#define MCD_TRIG_ACT_BREAK "check_data_value"
+#define MCD_TRIG_OPT_VALUE "break_on_trigger"
+
+/* register mem space key words */
+#define MCD_GRP_KEYWORD "GPR"
+#define MCD_CP_KEYWORD "CP"
+
+#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* Re: [PATCH v3 04/20] mcdstub: added header with defines specific to the mcd tcp packet communication
2023-11-07 13:03 ` [PATCH v3 04/20] mcdstub: added header with defines specific to the mcd tcp packet communication Nicolas Eder
@ 2023-11-29 16:02 ` Alex Bennée
0 siblings, 0 replies; 32+ messages in thread
From: Alex Bennée @ 2023-11-29 16:02 UTC (permalink / raw)
To: Nicolas Eder; +Cc: qemu-devel, Philippe Mathieu-Daudé, Christian Boenig
Nicolas Eder <nicolas.eder@lauterbach.com> writes:
> ---
> include/mcdstub/mcd_shared_defines.h | 108 +++++++++++++++++++++++++++
> 1 file changed, 108 insertions(+)
> create mode 100644 include/mcdstub/mcd_shared_defines.h
>
> diff --git a/include/mcdstub/mcd_shared_defines.h b/include/mcdstub/mcd_shared_defines.h
> new file mode 100644
> index 0000000000..fa1adb5c77
> --- /dev/null
> +++ b/include/mcdstub/mcd_shared_defines.h
> @@ -0,0 +1,108 @@
> +/*
> + *this file is shared between the mcd dll and the mcd stub.
> + *it has to be kept exectly the same!
> + */
If this comes from the published API headers it needs clear attribution
and a license header. I assume it won't update anything like as
frequently as our linux and Xen headers so I don't think we need special
tooling to handle updates.
> +
> +#ifndef MCD_SHARED_DEFINES
> +#define MCD_SHARED_DEFINES
> +
> +/* default tcp port */
> +#define MCD_DEFAULT_TCP_PORT "1235"
> +
> +/* tcp data characters */
> +#define TCP_CHAR_OPEN_SERVER 'I'
> +#define TCP_CHAR_OPEN_CORE 'i'
> +#define TCP_CHAR_GO 'C'
> +#define TCP_CHAR_STEP 'c'
> +#define TCP_CHAR_BREAK 'b'
> +#define TCP_CHAR_QUERY 'q'
> +#define TCP_CHAR_CLOSE_SERVER 'D'
> +#define TCP_CHAR_CLOSE_CORE 'd'
> +#define TCP_CHAR_KILLQEMU 'k'
> +#define TCP_CHAR_RESET 'r'
> +#define TCP_CHAR_READ_REGISTER 'p'
> +#define TCP_CHAR_WRITE_REGISTER 'P'
> +#define TCP_CHAR_READ_MEMORY 'm'
> +#define TCP_CHAR_WRITE_MEMORY 'M'
> +#define TCP_CHAR_BREAKPOINT_INSERT 't'
> +#define TCP_CHAR_BREAKPOINT_REMOVE 'T'
> +
> +/* tcp protocol chars */
> +#define TCP_ACKNOWLEDGED '+'
> +#define TCP_NOT_ACKNOWLEDGED '-'
> +#define TCP_COMMAND_START '$'
> +#define TCP_COMMAND_END '#'
> +#define TCP_WAS_LAST '|'
> +#define TCP_WAS_NOT_LAST '~'
> +#define TCP_HANDSHAKE_SUCCESS "shaking your hand"
> +#define TCP_EXECUTION_SUCCESS "success"
> +#define TCP_EXECUTION_ERROR "error"
> +
> +/* tcp query arguments */
> +#define QUERY_FIRST "f"
> +#define QUERY_CONSEQUTIVE "c"
> +#define QUERY_END_INDEX "!"
> +
> +#define QUERY_ARG_SYSTEM "system"
> +#define QUERY_ARG_CORES "cores"
> +#define QUERY_ARG_RESET "reset"
> +#define QUERY_ARG_TRIGGER "trigger"
> +#define QUERY_ARG_MEMORY "memory"
> +#define QUERY_ARG_REGGROUP "reggroup"
> +#define QUERY_ARG_REG "reg"
> +#define QUERY_ARG_STATE "state"
> +
> +/* tcp query packet argument list */
> +#define TCP_ARGUMENT_NAME "name"
> +#define TCP_ARGUMENT_DATA "data"
> +#define TCP_ARGUMENT_ID "id"
> +#define TCP_ARGUMENT_TYPE "type"
> +#define TCP_ARGUMENT_BITS_PER_MAU "bpm"
> +#define TCP_ARGUMENT_INVARIANCE "i"
> +#define TCP_ARGUMENT_ENDIAN "e"
> +#define TCP_ARGUMENT_MIN "min"
> +#define TCP_ARGUMENT_MAX "max"
> +#define TCP_ARGUMENT_SUPPORTED_ACCESS_OPTIONS "sao"
> +#define TCP_ARGUMENT_REGGROUPID "reggroupid"
> +#define TCP_ARGUMENT_MEMSPACEID "memspaceid"
> +#define TCP_ARGUMENT_SIZE "size"
> +#define TCP_ARGUMENT_THREAD "thread"
> +#define TCP_ARGUMENT_ADDRESS "address"
> +#define TCP_ARGUMENT_STOP_STRING "stop_str"
> +#define TCP_ARGUMENT_INFO_STRING "info_str"
> +#define TCP_ARGUMENT_STATE "state"
> +#define TCP_ARGUMENT_EVENT "event"
> +#define TCP_ARGUMENT_DEVICE "device"
> +#define TCP_ARGUMENT_CORE "core"
> +#define TCP_ARGUMENT_AMOUNT_CORE "nr_cores"
> +#define TCP_ARGUMENT_AMOUNT_TRIGGER "nr_trigger"
> +#define TCP_ARGUMENT_OPTION "option"
> +#define TCP_ARGUMENT_ACTION "action"
> +#define TCP_ARGUMENT_OPCODE "opcode"
> +
> +/* for packets sent to qemu */
> +#define ARGUMENT_SEPARATOR ';'
> +#define NEGATIVE_FLAG 0
> +#define POSITIVE_FLAG 1
> +
> +/* core states */
> +#define CORE_STATE_RUNNING "running"
> +#define CORE_STATE_HALTED "halted"
> +#define CORE_STATE_DEBUG "debug"
> +#define CORE_STATE_UNKNOWN "unknown"
> +
> +/* breakpoint types */
> +#define MCD_BREAKPOINT_HW 1
> +#define MCD_BREAKPOINT_READ 2
> +#define MCD_BREAKPOINT_WRITE 3
> +#define MCD_BREAKPOINT_RW 4
> +
> +/* trigger data */
> +#define MCD_TRIG_ACT_BREAK "check_data_value"
> +#define MCD_TRIG_OPT_VALUE "break_on_trigger"
> +
> +/* register mem space key words */
> +#define MCD_GRP_KEYWORD "GPR"
> +#define MCD_CP_KEYWORD "CP"
> +
> +#endif
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v3 05/20] mcdstub: tcp packet processing added
2023-11-07 13:03 [PATCH v3 00/20] first version of mcdstub Nicolas Eder
` (3 preceding siblings ...)
2023-11-07 13:03 ` [PATCH v3 04/20] mcdstub: added header with defines specific to the mcd tcp packet communication Nicolas Eder
@ 2023-11-07 13:03 ` Nicolas Eder
2023-11-08 14:33 ` Philippe Mathieu-Daudé
2023-11-29 16:25 ` Alex Bennée
2023-11-07 13:03 ` [PATCH v3 06/20] mcdstub: open/close server functions and trigger/reset data added. User for initial connection with an mcd client Nicolas Eder
` (16 subsequent siblings)
21 siblings, 2 replies; 32+ messages in thread
From: Nicolas Eder @ 2023-11-07 13:03 UTC (permalink / raw)
To: qemu-devel
Cc: Nicolas Eder, Alex Bennée, Philippe Mathieu-Daudé,
Christian Boenig
---
include/mcdstub/mcdstub.h | 144 ++++++++++++++++++++
mcdstub/mcdstub.c | 277 ++++++++++++++++++++++++++++++++++++++
2 files changed, 421 insertions(+)
diff --git a/include/mcdstub/mcdstub.h b/include/mcdstub/mcdstub.h
index 36058157ae..1461d0e1cb 100644
--- a/include/mcdstub/mcdstub.h
+++ b/include/mcdstub/mcdstub.h
@@ -25,6 +25,21 @@ typedef struct MCDProcess {
char target_xml[1024];
} MCDProcess;
+typedef void (*MCDCmdHandler)(GArray *params, void *user_ctx);
+typedef struct MCDCmdParseEntry {
+ MCDCmdHandler handler;
+ const char *cmd;
+ char schema[CMD_SCHEMA_LENGTH];
+} MCDCmdParseEntry;
+
+typedef union MCDCmdVariant {
+ const char *data;
+ uint32_t data_uint32_t;
+ uint64_t data_uint64_t;
+ uint32_t query_handle;
+ uint32_t cpu_id;
+} MCDCmdVariant;
+
#define get_param(p, i) (&g_array_index(p, MCDCmdVariant, i))
enum RSState {
@@ -176,6 +191,35 @@ bool mcd_supports_guest_debug(void);
* @state: The new (and active) VM run state.
*/
void mcd_vm_state_change(void *opaque, bool running, RunState state);
+
+/**
+ * mcd_put_packet() - Calls :c:func:`mcd_put_packet_binary` with buf and length
+ * of buf.
+ *
+ * @buf: TCP packet data.
+ */
+int mcd_put_packet(const char *buf);
+
+/**
+ * mcd_put_packet_binary() - Adds footer and header to the TCP packet data in
+ * buf.
+ *
+ * Besides adding header and footer, this function also stores the complete TCP
+ * packet in the last_packet member of the mcdserver_state. Then the packet
+ * gets send with the :c:func:`mcd_put_buffer` function.
+ * @buf: TCP packet data.
+ * @len: TCP packet length.
+ */
+int mcd_put_packet_binary(const char *buf, int len);
+
+/**
+ * mcd_put_buffer() - Sends the buf as TCP packet with qemu_chr_fe_write_all.
+ *
+ * @buf: TCP packet data.
+ * @len: TCP packet length.
+ */
+void mcd_put_buffer(const uint8_t *buf, int len);
+
/**
* mcd_get_cpu_process() - Returns the process of the provided CPU.
*
@@ -218,6 +262,82 @@ CPUState *mcd_first_attached_cpu(void);
*/
CPUState *mcd_next_attached_cpu(CPUState *cpu);
+/**
+ * mcd_read_byte() - Resends the last packet if not acknowledged and extracts
+ * the data from a received TCP packet.
+ *
+ * In case the last sent packet was not acknowledged from the mcdstub,
+ * this function resends it.
+ * If it was acknowledged this function parses the incoming packet
+ * byte by byte.
+ * It extracts the data in the packet and sends an
+ * acknowledging response when finished. Then :c:func:`mcd_handle_packet` gets
+ * called.
+ * @ch: Character of the received TCP packet, which should be parsed.
+ */
+void mcd_read_byte(uint8_t ch);
+
+/**
+ * mcd_handle_packet() - Evaluates the type of received packet and chooses the
+ * correct handler.
+ *
+ * This function takes the first character of the line_buf to determine the
+ * type of packet. Then it selects the correct handler function and parameter
+ * schema. With this info it calls :c:func:`run_cmd_parser`.
+ * @line_buf: TCP packet data.
+ */
+int mcd_handle_packet(const char *line_buf);
+
+/**
+ * mcd_put_strbuf() - Calls :c:func:`mcd_put_packet` with the str_buf of the
+ * mcdserver_state.
+ */
+void mcd_put_strbuf(void);
+
+/**
+ * run_cmd_parser() - Prepares the mcdserver_state before executing TCP packet
+ * functions.
+ *
+ * This function empties the str_buf and mem_buf of the mcdserver_state and
+ * then calls :c:func:`process_string_cmd`. In case this function fails, an
+ * empty TCP packet is sent back the MCD Shared Library.
+ * @data: TCP packet data.
+ * @cmd: Handler function (can be an array of functions).
+ */
+void run_cmd_parser(const char *data, const MCDCmdParseEntry *cmd);
+
+/**
+ * process_string_cmd() - Collects all parameters from the data and calls the
+ * correct handler.
+ *
+ * The parameters are extracted with the :c:func:`cmd_parse_params function.
+ * This function selects the command in the cmds array, which fits the start of
+ * the data string. This way the correct commands is selected.
+ * @data: TCP packet data.
+ * @cmds: Array of possible commands.
+ * @num_cmds: Number of commands in the cmds array.
+ */
+int process_string_cmd(void *user_ctx, const char *data,
+ const MCDCmdParseEntry *cmds, int num_cmds);
+
+/**
+ * cmd_parse_params() - Extracts all parameters from a TCP packet.
+ *
+ * This function uses the schema parameter to determine which type of parameter
+ * to expect. It then extracts that parameter from the data and stores it in
+ * the params GArray.
+ * @data: TCP packet data.
+ * @schema: List of expected parameters for the packet.
+ * @params: GArray with all extracted parameters.
+ */
+int cmd_parse_params(const char *data, const char *schema, GArray *params);
+/**
+ * mcd_get_cpu_index() - Returns the internal CPU index plus one.
+ *
+ * @cpu: CPU of interest.
+ */
+int mcd_get_cpu_index(CPUState *cpu);
+
/**
* mcd_get_cpu() - Returns the CPU the index i_cpu_index.
*
@@ -237,3 +357,27 @@ CPUState *get_first_cpu_in_process(MCDProcess *process);
* @thread_id: ID of the desired CPU.
*/
CPUState *find_cpu(uint32_t thread_id);
+/* helpers */
+
+/**
+ * int_cmp() - Compares a and b and returns zero if they are equal.
+ *
+ * @a: Pointer to integer a.
+ * @b: Pointer to integer b.
+ */
+int int_cmp(gconstpointer a, gconstpointer b);
+/**
+ * atouint64_t() - Converts a string into a unsigned 64 bit integer.
+ *
+ * @in: Pointer to input string.
+ */
+uint64_t atouint64_t(const char *in);
+
+/**
+ * atouint32_t() - Converts a string into a unsigned 32 bit integer.
+ *
+ * @in: Pointer to input string.
+ */
+uint32_t atouint32_t(const char *in);
+
+#endif /* MCDSTUB_INTERNALS_H */
diff --git a/mcdstub/mcdstub.c b/mcdstub/mcdstub.c
index 4cdf2e42ed..6900dcd0ea 100644
--- a/mcdstub/mcdstub.c
+++ b/mcdstub/mcdstub.c
@@ -80,7 +80,14 @@ void init_query_cmds_table(MCDCmdParseEntry *mcd_query_cmds_table)
{
/* initalizes a list of all query commands */
int cmd_number = 0;
+
+void reset_mcdserver_state(void)
+{
+ g_free(mcdserver_state.processes);
+ mcdserver_state.processes = NULL;
+ mcdserver_state.process_num = 0;
}
+
void create_processes(MCDState *s)
{
object_child_foreach(object_get_root(), find_cpu_clusters, s);
@@ -243,6 +250,228 @@ void mcd_chr_receive(void *opaque, const uint8_t *buf, int size)
}
}
+void mcd_read_byte(uint8_t ch)
+{
+ uint8_t reply;
+
+ if (mcdserver_state.last_packet->len) {
+ if (ch == TCP_NOT_ACKNOWLEDGED) {
+ /* the previous packet was not akcnowledged */
+ mcd_put_buffer(mcdserver_state.last_packet->data,
+ mcdserver_state.last_packet->len);
+ } else if (ch == TCP_ACKNOWLEDGED) {
+ /* the previous packet was acknowledged */
+ }
+
+ if (ch == TCP_ACKNOWLEDGED || ch == TCP_COMMAND_START) {
+ /*
+ * either acknowledged or a new communication starts
+ * -> discard previous packet
+ */
+ g_byte_array_set_size(mcdserver_state.last_packet, 0);
+ }
+ if (ch != TCP_COMMAND_START) {
+ /* skip to the next char */
+ return;
+ }
+ }
+
+ switch (mcdserver_state.state) {
+ case RS_IDLE:
+ if (ch == TCP_COMMAND_START) {
+ /* start of command packet */
+ mcdserver_state.line_buf_index = 0;
+ mcdserver_state.line_sum = 0;
+ mcdserver_state.state = RS_GETLINE;
+ }
+ break;
+ case RS_GETLINE:
+ if (ch == TCP_COMMAND_END) {
+ /* end of command */
+ mcdserver_state.line_buf[mcdserver_state.line_buf_index++] = 0;
+ mcdserver_state.state = RS_DATAEND;
+ } else if (mcdserver_state.line_buf_index >=
+ sizeof(mcdserver_state.line_buf) - 1) {
+ /* the input string is too long for the linebuffer! */
+ mcdserver_state.state = RS_IDLE;
+ } else {
+ /* copy the content to the line_buf */
+ mcdserver_state.line_buf[mcdserver_state.line_buf_index++] = ch;
+ mcdserver_state.line_sum += ch;
+ }
+ break;
+ case RS_DATAEND:
+ if (ch == TCP_WAS_NOT_LAST) {
+ reply = TCP_ACKNOWLEDGED;
+ mcd_put_buffer(&reply, 1);
+ mcdserver_state.state = mcd_handle_packet(mcdserver_state.line_buf);
+ } else if (ch == TCP_WAS_LAST) {
+ reply = TCP_ACKNOWLEDGED;
+ mcd_put_buffer(&reply, 1);
+ mcdserver_state.state = mcd_handle_packet(mcdserver_state.line_buf);
+ } else {
+ /* not acknowledged! */
+ reply = TCP_NOT_ACKNOWLEDGED;
+ mcd_put_buffer(&reply, 1);
+ /* waiting for package to get resent */
+ mcdserver_state.state = RS_IDLE;
+ }
+ break;
+ default:
+ abort();
+ }
+}
+
+int mcd_handle_packet(const char *line_buf)
+{
+ /*
+ * decides what function (handler) to call depending on
+ * the first character in the line_buf
+ */
+ const MCDCmdParseEntry *cmd_parser = NULL;
+
+ switch (line_buf[0]) {
+ default:
+ /* command not supported */
+ mcd_put_packet("");
+ break;
+ }
+
+ if (cmd_parser) {
+ /* parse commands and run the selected handler function */
+ run_cmd_parser(line_buf, cmd_parser);
+ }
+
+ return RS_IDLE;
+}
+void run_cmd_parser(const char *data, const MCDCmdParseEntry *cmd)
+{
+ if (!data) {
+ return;
+ }
+
+ g_string_set_size(mcdserver_state.str_buf, 0);
+ g_byte_array_set_size(mcdserver_state.mem_buf, 0);
+
+ if (process_string_cmd(NULL, data, cmd, 1)) {
+ mcd_put_packet("");
+ }
+}
+
+uint64_t atouint64_t(const char *in)
+{
+ uint64_t res = 0;
+ for (int i = 0; i < strlen(in); ++i) {
+ const char c = in[i];
+ res *= 10;
+ res += c - '0';
+ }
+
+ return res;
+}
+
+uint32_t atouint32_t(const char *in)
+{
+ uint32_t res = 0;
+ for (int i = 0; i < strlen(in); ++i) {
+ const char c = in[i];
+ res *= 10;
+ res += c - '0';
+ }
+
+ return res;
+}
+
+int cmd_parse_params(const char *data, const char *schema, GArray *params)
+{
+
+ char data_buffer[64] = {0};
+ const char *remaining_data = data;
+
+ for (int i = 0; i < strlen(schema); i++) {
+ /* get correct part of data */
+ char *separator = strchr(remaining_data, ARGUMENT_SEPARATOR);
+
+ if (separator) {
+ /* multiple arguments */
+ int seperator_index = (int)(separator - remaining_data);
+ strncpy(data_buffer, remaining_data, seperator_index);
+ data_buffer[seperator_index] = 0;
+ /* update remaining data for the next run */
+ remaining_data = &(remaining_data[seperator_index + 1]);
+ } else {
+ strncpy(data_buffer, remaining_data, strlen(remaining_data));
+ data_buffer[strlen(remaining_data)] = 0;
+ }
+
+ /* store right data */
+ MCDCmdVariant this_param;
+ switch (schema[i]) {
+ case ARG_SCHEMA_STRING:
+ /* this has to be the last argument */
+ this_param.data = remaining_data;
+ g_array_append_val(params, this_param);
+ break;
+ case ARG_SCHEMA_HEXDATA:
+ g_string_printf(mcdserver_state.str_buf, "%s", data_buffer);
+ break;
+ case ARG_SCHEMA_INT:
+ this_param.data_uint32_t = atouint32_t(data_buffer);
+ g_array_append_val(params, this_param);
+ break;
+ case ARG_SCHEMA_UINT64_T:
+ this_param.data_uint64_t = atouint64_t(data_buffer);
+ g_array_append_val(params, this_param);
+ break;
+ case ARG_SCHEMA_QRYHANDLE:
+ this_param.query_handle = atouint32_t(data_buffer);
+ g_array_append_val(params, this_param);
+ break;
+ case ARG_SCHEMA_CORENUM:
+ this_param.cpu_id = atouint32_t(data_buffer);
+ g_array_append_val(params, this_param);
+ break;
+ default:
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int process_string_cmd(void *user_ctx, const char *data,
+ const MCDCmdParseEntry *cmds, int num_cmds)
+{
+ int i;
+ g_autoptr(GArray) params = g_array_new(false, true, sizeof(MCDCmdVariant));
+
+ if (!cmds) {
+ return -1;
+ }
+
+ for (i = 0; i < num_cmds; i++) {
+ const MCDCmdParseEntry *cmd = &cmds[i];
+ g_assert(cmd->handler && cmd->cmd);
+
+ /* continue if data and command are different */
+ if (strncmp(data, cmd->cmd, strlen(cmd->cmd))) {
+ continue;
+ }
+
+ if (strlen(cmd->schema)) {
+ /* extract data for parameters */
+ if (cmd_parse_params(&data[strlen(cmd->cmd)], cmd->schema, params))
+ {
+ return -1;
+ }
+ }
+
+ /* call handler */
+ cmd->handler(params, user_ctx);
+ return 0;
+ }
+
+ return -1;
+}
void mcd_chr_event(void *opaque, QEMUChrEvent event)
{
@@ -281,6 +510,43 @@ void mcd_sigterm_handler(int signal)
}
#endif
+int mcd_put_packet(const char *buf)
+{
+ return mcd_put_packet_binary(buf, strlen(buf));
+}
+
+void mcd_put_strbuf(void)
+{
+ mcd_put_packet(mcdserver_state.str_buf->str);
+}
+
+int mcd_put_packet_binary(const char *buf, int len)
+{
+ g_byte_array_set_size(mcdserver_state.last_packet, 0);
+ g_byte_array_append(mcdserver_state.last_packet,
+ (const uint8_t *) (char[2]) { TCP_COMMAND_START, '\0' }, 1);
+ g_byte_array_append(mcdserver_state.last_packet,
+ (const uint8_t *) buf, len);
+ g_byte_array_append(mcdserver_state.last_packet,
+ (const uint8_t *) (char[2]) { TCP_COMMAND_END, '\0' }, 1);
+ g_byte_array_append(mcdserver_state.last_packet,
+ (const uint8_t *) (char[2]) { TCP_WAS_LAST, '\0' }, 1);
+
+ mcd_put_buffer(mcdserver_state.last_packet->data,
+ mcdserver_state.last_packet->len);
+ return 0;
+}
+
+void mcd_put_buffer(const uint8_t *buf, int len)
+{
+ qemu_chr_fe_write_all(&mcdserver_system_state.chr, buf, len);
+}
+
+MCDProcess *mcd_get_cpu_process(CPUState *cpu)
+{
+ return mcd_get_process(mcd_get_cpu_pid(cpu));
+}
+
uint32_t mcd_get_cpu_pid(CPUState *cpu)
{
if (cpu->cluster_index == UNASSIGNED_CLUSTER_INDEX) {
@@ -381,3 +647,14 @@ CPUState *find_cpu(uint32_t thread_id)
return NULL;
}
+
+int int_cmp(gconstpointer a, gconstpointer b)
+{
+ int int_a = *(int *)a;
+ int int_b = *(int *)b;
+ if (int_a == int_b) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
--
2.34.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* Re: [PATCH v3 05/20] mcdstub: tcp packet processing added
2023-11-07 13:03 ` [PATCH v3 05/20] mcdstub: tcp packet processing added Nicolas Eder
@ 2023-11-08 14:33 ` Philippe Mathieu-Daudé
2023-11-13 9:18 ` nicolas.eder
2023-11-29 16:25 ` Alex Bennée
1 sibling, 1 reply; 32+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-11-08 14:33 UTC (permalink / raw)
To: Nicolas Eder, qemu-devel; +Cc: Alex Bennée, Christian Boenig
Hi Nicolas,
On 7/11/23 14:03, Nicolas Eder wrote:
> ---
> include/mcdstub/mcdstub.h | 144 ++++++++++++++++++++
> mcdstub/mcdstub.c | 277 ++++++++++++++++++++++++++++++++++++++
> 2 files changed, 421 insertions(+)
>
> diff --git a/include/mcdstub/mcdstub.h b/include/mcdstub/mcdstub.h
> index 36058157ae..1461d0e1cb 100644
> --- a/include/mcdstub/mcdstub.h
> +++ b/include/mcdstub/mcdstub.h
> @@ -25,6 +25,21 @@ typedef struct MCDProcess {
> char target_xml[1024];
> } MCDProcess;
>
> +typedef void (*MCDCmdHandler)(GArray *params, void *user_ctx);
> +typedef struct MCDCmdParseEntry {
> + MCDCmdHandler handler;
> + const char *cmd;
> + char schema[CMD_SCHEMA_LENGTH];
> +} MCDCmdParseEntry;
> +
> +typedef union MCDCmdVariant {
> + const char *data;
> + uint32_t data_uint32_t;
> + uint64_t data_uint64_t;
> + uint32_t query_handle;
> + uint32_t cpu_id;
> +} MCDCmdVariant;
[...]
Can we add an URL to the spec in this file header?
It should be relatively easy to add a qtest for MCB, with raw
packets to:
- read memory
- write memory
- read register
- write register
- register breakpoint
- run vcpu
- stop vcpu
Maybe we can write a tiny code that loop incrementing a static
variable, run for few ms and check the variable got incremented?
That would exercise most of these commands.
Regards,
Phil.
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 05/20] mcdstub: tcp packet processing added
2023-11-08 14:33 ` Philippe Mathieu-Daudé
@ 2023-11-13 9:18 ` nicolas.eder
0 siblings, 0 replies; 32+ messages in thread
From: nicolas.eder @ 2023-11-13 9:18 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, qemu-devel
Cc: Alex Bennée, Christian Boenig
Hi Phil,
as of right now, there is no official spec for the TCP packet contents.
However, in the client code it is rather easy see how the packets are
constructed. I hope I will get the client code online by the end of the
week.
I will also look into qtest. We definetely need a test like this and I
think your example is a good idea.
Best Regards,
Nicolas
On 08/11/2023 15:33, Philippe Mathieu-Daudé wrote:
> Hi Nicolas,
>
> On 7/11/23 14:03, Nicolas Eder wrote:
>> ---
>> include/mcdstub/mcdstub.h | 144 ++++++++++++++++++++
>> mcdstub/mcdstub.c | 277 ++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 421 insertions(+)
>>
>> diff --git a/include/mcdstub/mcdstub.h b/include/mcdstub/mcdstub.h
>> index 36058157ae..1461d0e1cb 100644
>> --- a/include/mcdstub/mcdstub.h
>> +++ b/include/mcdstub/mcdstub.h
>> @@ -25,6 +25,21 @@ typedef struct MCDProcess {
>> char target_xml[1024];
>> } MCDProcess;
>> +typedef void (*MCDCmdHandler)(GArray *params, void *user_ctx);
>> +typedef struct MCDCmdParseEntry {
>> + MCDCmdHandler handler;
>> + const char *cmd;
>> + char schema[CMD_SCHEMA_LENGTH];
>> +} MCDCmdParseEntry;
>> +
>> +typedef union MCDCmdVariant {
>> + const char *data;
>> + uint32_t data_uint32_t;
>> + uint64_t data_uint64_t;
>> + uint32_t query_handle;
>> + uint32_t cpu_id;
>> +} MCDCmdVariant;
>
> [...]
>
> Can we add an URL to the spec in this file header?
>
> It should be relatively easy to add a qtest for MCB, with raw
> packets to:
> - read memory
> - write memory
> - read register
> - write register
> - register breakpoint
> - run vcpu
> - stop vcpu
>
> Maybe we can write a tiny code that loop incrementing a static
> variable, run for few ms and check the variable got incremented?
> That would exercise most of these commands.
>
> Regards,
>
> Phil.
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 05/20] mcdstub: tcp packet processing added
2023-11-07 13:03 ` [PATCH v3 05/20] mcdstub: tcp packet processing added Nicolas Eder
2023-11-08 14:33 ` Philippe Mathieu-Daudé
@ 2023-11-29 16:25 ` Alex Bennée
1 sibling, 0 replies; 32+ messages in thread
From: Alex Bennée @ 2023-11-29 16:25 UTC (permalink / raw)
To: Nicolas Eder; +Cc: qemu-devel, Philippe Mathieu-Daudé, Christian Boenig
Nicolas Eder <nicolas.eder@lauterbach.com> writes:
> ---
> include/mcdstub/mcdstub.h | 144 ++++++++++++++++++++
> mcdstub/mcdstub.c | 277 ++++++++++++++++++++++++++++++++++++++
> 2 files changed, 421 insertions(+)
>
> diff --git a/include/mcdstub/mcdstub.h b/include/mcdstub/mcdstub.h
> index 36058157ae..1461d0e1cb 100644
> --- a/include/mcdstub/mcdstub.h
> +++ b/include/mcdstub/mcdstub.h
> @@ -25,6 +25,21 @@ typedef struct MCDProcess {
> char target_xml[1024];
> } MCDProcess;
>
> +typedef void (*MCDCmdHandler)(GArray *params, void *user_ctx);
> +typedef struct MCDCmdParseEntry {
> + MCDCmdHandler handler;
> + const char *cmd;
> + char schema[CMD_SCHEMA_LENGTH];
> +} MCDCmdParseEntry;
> +
> +typedef union MCDCmdVariant {
> + const char *data;
> + uint32_t data_uint32_t;
> + uint64_t data_uint64_t;
> + uint32_t query_handle;
> + uint32_t cpu_id;
> +} MCDCmdVariant;
> +
These need to be in an earlier patch to keep the build working.
> #define get_param(p, i) (&g_array_index(p, MCDCmdVariant, i))
>
> enum RSState {
> @@ -176,6 +191,35 @@ bool mcd_supports_guest_debug(void);
> * @state: The new (and active) VM run state.
> */
> void mcd_vm_state_change(void *opaque, bool running, RunState state);
> +
> +/**
> + * mcd_put_packet() - Calls :c:func:`mcd_put_packet_binary` with buf and length
> + * of buf.
> + *
> + * @buf: TCP packet data.
> + */
> +int mcd_put_packet(const char *buf);
> +
> +/**
> + * mcd_put_packet_binary() - Adds footer and header to the TCP packet data in
> + * buf.
> + *
> + * Besides adding header and footer, this function also stores the complete TCP
> + * packet in the last_packet member of the mcdserver_state. Then the packet
> + * gets send with the :c:func:`mcd_put_buffer` function.
> + * @buf: TCP packet data.
> + * @len: TCP packet length.
> + */
> +int mcd_put_packet_binary(const char *buf, int len);
> +
> +/**
> + * mcd_put_buffer() - Sends the buf as TCP packet with qemu_chr_fe_write_all.
> + *
> + * @buf: TCP packet data.
> + * @len: TCP packet length.
> + */
> +void mcd_put_buffer(const uint8_t *buf, int len);
> +
> /**
> * mcd_get_cpu_process() - Returns the process of the provided CPU.
> *
> @@ -218,6 +262,82 @@ CPUState *mcd_first_attached_cpu(void);
> */
> CPUState *mcd_next_attached_cpu(CPUState *cpu);
>
> +/**
> + * mcd_read_byte() - Resends the last packet if not acknowledged and extracts
> + * the data from a received TCP packet.
> + *
> + * In case the last sent packet was not acknowledged from the mcdstub,
> + * this function resends it.
> + * If it was acknowledged this function parses the incoming packet
> + * byte by byte.
> + * It extracts the data in the packet and sends an
> + * acknowledging response when finished. Then :c:func:`mcd_handle_packet` gets
> + * called.
> + * @ch: Character of the received TCP packet, which should be parsed.
> + */
> +void mcd_read_byte(uint8_t ch);
> +
> +/**
> + * mcd_handle_packet() - Evaluates the type of received packet and chooses the
> + * correct handler.
> + *
> + * This function takes the first character of the line_buf to determine the
> + * type of packet. Then it selects the correct handler function and parameter
> + * schema. With this info it calls :c:func:`run_cmd_parser`.
> + * @line_buf: TCP packet data.
> + */
> +int mcd_handle_packet(const char *line_buf);
> +
> +/**
> + * mcd_put_strbuf() - Calls :c:func:`mcd_put_packet` with the str_buf of the
> + * mcdserver_state.
> + */
> +void mcd_put_strbuf(void);
> +
> +/**
> + * run_cmd_parser() - Prepares the mcdserver_state before executing TCP packet
> + * functions.
> + *
> + * This function empties the str_buf and mem_buf of the mcdserver_state and
> + * then calls :c:func:`process_string_cmd`. In case this function fails, an
> + * empty TCP packet is sent back the MCD Shared Library.
> + * @data: TCP packet data.
> + * @cmd: Handler function (can be an array of functions).
> + */
> +void run_cmd_parser(const char *data, const MCDCmdParseEntry *cmd);
> +
> +/**
> + * process_string_cmd() - Collects all parameters from the data and calls the
> + * correct handler.
> + *
> + * The parameters are extracted with the :c:func:`cmd_parse_params function.
> + * This function selects the command in the cmds array, which fits the start of
> + * the data string. This way the correct commands is selected.
> + * @data: TCP packet data.
> + * @cmds: Array of possible commands.
> + * @num_cmds: Number of commands in the cmds array.
> + */
> +int process_string_cmd(void *user_ctx, const char *data,
> + const MCDCmdParseEntry *cmds, int num_cmds);
> +
> +/**
> + * cmd_parse_params() - Extracts all parameters from a TCP packet.
> + *
> + * This function uses the schema parameter to determine which type of parameter
> + * to expect. It then extracts that parameter from the data and stores it in
> + * the params GArray.
> + * @data: TCP packet data.
> + * @schema: List of expected parameters for the packet.
> + * @params: GArray with all extracted parameters.
> + */
> +int cmd_parse_params(const char *data, const char *schema, GArray *params);
> +/**
> + * mcd_get_cpu_index() - Returns the internal CPU index plus one.
> + *
> + * @cpu: CPU of interest.
> + */
> +int mcd_get_cpu_index(CPUState *cpu);
> +
Aren't these all internal to mcdstub? We can keep the kdoc comments and
just make the functions static.
> /**
> * mcd_get_cpu() - Returns the CPU the index i_cpu_index.
> *
> @@ -237,3 +357,27 @@ CPUState *get_first_cpu_in_process(MCDProcess *process);
> * @thread_id: ID of the desired CPU.
> */
> CPUState *find_cpu(uint32_t thread_id);
> +/* helpers */
> +
> +/**
> + * int_cmp() - Compares a and b and returns zero if they are equal.
> + *
> + * @a: Pointer to integer a.
> + * @b: Pointer to integer b.
> + */
> +int int_cmp(gconstpointer a, gconstpointer b);
This especially will clash with local definitions.
> +/**
> + * atouint64_t() - Converts a string into a unsigned 64 bit integer.
> + *
> + * @in: Pointer to input string.
> + */
> +uint64_t atouint64_t(const char *in);
> +
No _t prefixes for functions please.
> +/**
> + * atouint32_t() - Converts a string into a unsigned 32 bit integer.
> + *
> + * @in: Pointer to input string.
> + */
> +uint32_t atouint32_t(const char *in);
> +
> +#endif /* MCDSTUB_INTERNALS_H */
> diff --git a/mcdstub/mcdstub.c b/mcdstub/mcdstub.c
> index 4cdf2e42ed..6900dcd0ea 100644
> --- a/mcdstub/mcdstub.c
> +++ b/mcdstub/mcdstub.c
> @@ -80,7 +80,14 @@ void init_query_cmds_table(MCDCmdParseEntry *mcd_query_cmds_table)
> {
> /* initalizes a list of all query commands */
> int cmd_number = 0;
> +
> +void reset_mcdserver_state(void)
> +{
> + g_free(mcdserver_state.processes);
> + mcdserver_state.processes = NULL;
> + mcdserver_state.process_num = 0;
> }
> +
> void create_processes(MCDState *s)
> {
> object_child_foreach(object_get_root(), find_cpu_clusters, s);
> @@ -243,6 +250,228 @@ void mcd_chr_receive(void *opaque, const uint8_t *buf, int size)
> }
> }
>
> +void mcd_read_byte(uint8_t ch)
> +{
> + uint8_t reply;
> +
> + if (mcdserver_state.last_packet->len) {
> + if (ch == TCP_NOT_ACKNOWLEDGED) {
> + /* the previous packet was not akcnowledged */
> + mcd_put_buffer(mcdserver_state.last_packet->data,
> + mcdserver_state.last_packet->len);
> + } else if (ch == TCP_ACKNOWLEDGED) {
> + /* the previous packet was acknowledged */
> + }
> +
> + if (ch == TCP_ACKNOWLEDGED || ch == TCP_COMMAND_START) {
> + /*
> + * either acknowledged or a new communication starts
> + * -> discard previous packet
> + */
> + g_byte_array_set_size(mcdserver_state.last_packet, 0);
> + }
> + if (ch != TCP_COMMAND_START) {
> + /* skip to the next char */
> + return;
> + }
> + }
> +
> + switch (mcdserver_state.state) {
> + case RS_IDLE:
> + if (ch == TCP_COMMAND_START) {
> + /* start of command packet */
> + mcdserver_state.line_buf_index = 0;
> + mcdserver_state.line_sum = 0;
> + mcdserver_state.state = RS_GETLINE;
> + }
> + break;
> + case RS_GETLINE:
> + if (ch == TCP_COMMAND_END) {
> + /* end of command */
> + mcdserver_state.line_buf[mcdserver_state.line_buf_index++] = 0;
> + mcdserver_state.state = RS_DATAEND;
> + } else if (mcdserver_state.line_buf_index >=
> + sizeof(mcdserver_state.line_buf) - 1) {
> + /* the input string is too long for the linebuffer! */
> + mcdserver_state.state = RS_IDLE;
> + } else {
> + /* copy the content to the line_buf */
> + mcdserver_state.line_buf[mcdserver_state.line_buf_index++] = ch;
> + mcdserver_state.line_sum += ch;
> + }
> + break;
> + case RS_DATAEND:
> + if (ch == TCP_WAS_NOT_LAST) {
> + reply = TCP_ACKNOWLEDGED;
> + mcd_put_buffer(&reply, 1);
> + mcdserver_state.state = mcd_handle_packet(mcdserver_state.line_buf);
> + } else if (ch == TCP_WAS_LAST) {
> + reply = TCP_ACKNOWLEDGED;
> + mcd_put_buffer(&reply, 1);
> + mcdserver_state.state = mcd_handle_packet(mcdserver_state.line_buf);
> + } else {
> + /* not acknowledged! */
> + reply = TCP_NOT_ACKNOWLEDGED;
> + mcd_put_buffer(&reply, 1);
> + /* waiting for package to get resent */
> + mcdserver_state.state = RS_IDLE;
> + }
> + break;
> + default:
> + abort();
> + }
> +}
> +
> +int mcd_handle_packet(const char *line_buf)
> +{
> + /*
> + * decides what function (handler) to call depending on
> + * the first character in the line_buf
> + */
> + const MCDCmdParseEntry *cmd_parser = NULL;
> +
> + switch (line_buf[0]) {
> + default:
> + /* command not supported */
> + mcd_put_packet("");
> + break;
> + }
> +
> + if (cmd_parser) {
> + /* parse commands and run the selected handler function */
> + run_cmd_parser(line_buf, cmd_parser);
> + }
> +
> + return RS_IDLE;
> +}
> +void run_cmd_parser(const char *data, const MCDCmdParseEntry *cmd)
> +{
> + if (!data) {
> + return;
> + }
> +
> + g_string_set_size(mcdserver_state.str_buf, 0);
> + g_byte_array_set_size(mcdserver_state.mem_buf, 0);
> +
> + if (process_string_cmd(NULL, data, cmd, 1)) {
> + mcd_put_packet("");
> + }
> +}
> +
> +uint64_t atouint64_t(const char *in)
> +{
> + uint64_t res = 0;
> + for (int i = 0; i < strlen(in); ++i) {
> + const char c = in[i];
> + res *= 10;
> + res += c - '0';
> + }
> +
> + return res;
> +}
> +
> +uint32_t atouint32_t(const char *in)
> +{
> + uint32_t res = 0;
> + for (int i = 0; i < strlen(in); ++i) {
> + const char c = in[i];
> + res *= 10;
> + res += c - '0';
> + }
> +
> + return res;
> +}
You could use qemu_strtou64 with error checking instead. We could add
qemu_strtou32 if needed.
> +
> +int cmd_parse_params(const char *data, const char *schema, GArray *params)
> +{
> +
> + char data_buffer[64] = {0};
> + const char *remaining_data = data;
> +
> + for (int i = 0; i < strlen(schema); i++) {
> + /* get correct part of data */
> + char *separator = strchr(remaining_data, ARGUMENT_SEPARATOR);
> +
> + if (separator) {
> + /* multiple arguments */
> + int seperator_index = (int)(separator - remaining_data);
> + strncpy(data_buffer, remaining_data, seperator_index);
> + data_buffer[seperator_index] = 0;
> + /* update remaining data for the next run */
> + remaining_data = &(remaining_data[seperator_index + 1]);
> + } else {
> + strncpy(data_buffer, remaining_data, strlen(remaining_data));
> + data_buffer[strlen(remaining_data)] = 0;
> + }
> +
> + /* store right data */
> + MCDCmdVariant this_param;
> + switch (schema[i]) {
> + case ARG_SCHEMA_STRING:
> + /* this has to be the last argument */
> + this_param.data = remaining_data;
> + g_array_append_val(params, this_param);
> + break;
> + case ARG_SCHEMA_HEXDATA:
> + g_string_printf(mcdserver_state.str_buf, "%s", data_buffer);
> + break;
> + case ARG_SCHEMA_INT:
> + this_param.data_uint32_t = atouint32_t(data_buffer);
> + g_array_append_val(params, this_param);
> + break;
> + case ARG_SCHEMA_UINT64_T:
> + this_param.data_uint64_t = atouint64_t(data_buffer);
> + g_array_append_val(params, this_param);
> + break;
> + case ARG_SCHEMA_QRYHANDLE:
> + this_param.query_handle = atouint32_t(data_buffer);
> + g_array_append_val(params, this_param);
> + break;
> + case ARG_SCHEMA_CORENUM:
> + this_param.cpu_id = atouint32_t(data_buffer);
> + g_array_append_val(params, this_param);
> + break;
> + default:
> + return -1;
> + }
> + }
> + return 0;
> +}
> +
> +int process_string_cmd(void *user_ctx, const char *data,
> + const MCDCmdParseEntry *cmds, int num_cmds)
> +{
> + int i;
> + g_autoptr(GArray) params = g_array_new(false, true, sizeof(MCDCmdVariant));
> +
> + if (!cmds) {
> + return -1;
> + }
> +
> + for (i = 0; i < num_cmds; i++) {
> + const MCDCmdParseEntry *cmd = &cmds[i];
> + g_assert(cmd->handler && cmd->cmd);
> +
> + /* continue if data and command are different */
> + if (strncmp(data, cmd->cmd, strlen(cmd->cmd))) {
> + continue;
> + }
> +
> + if (strlen(cmd->schema)) {
> + /* extract data for parameters */
> + if (cmd_parse_params(&data[strlen(cmd->cmd)], cmd->schema, params))
> + {
> + return -1;
> + }
> + }
> +
> + /* call handler */
> + cmd->handler(params, user_ctx);
> + return 0;
> + }
> +
> + return -1;
> +}
>
> void mcd_chr_event(void *opaque, QEMUChrEvent event)
> {
> @@ -281,6 +510,43 @@ void mcd_sigterm_handler(int signal)
> }
> #endif
>
> +int mcd_put_packet(const char *buf)
> +{
> + return mcd_put_packet_binary(buf, strlen(buf));
> +}
> +
> +void mcd_put_strbuf(void)
> +{
> + mcd_put_packet(mcdserver_state.str_buf->str);
> +}
> +
> +int mcd_put_packet_binary(const char *buf, int len)
> +{
> + g_byte_array_set_size(mcdserver_state.last_packet, 0);
> + g_byte_array_append(mcdserver_state.last_packet,
> + (const uint8_t *) (char[2]) { TCP_COMMAND_START, '\0' }, 1);
> + g_byte_array_append(mcdserver_state.last_packet,
> + (const uint8_t *) buf, len);
> + g_byte_array_append(mcdserver_state.last_packet,
> + (const uint8_t *) (char[2]) { TCP_COMMAND_END, '\0' }, 1);
> + g_byte_array_append(mcdserver_state.last_packet,
> + (const uint8_t *) (char[2]) { TCP_WAS_LAST, '\0' }, 1);
> +
> + mcd_put_buffer(mcdserver_state.last_packet->data,
> + mcdserver_state.last_packet->len);
> + return 0;
> +}
> +
> +void mcd_put_buffer(const uint8_t *buf, int len)
> +{
> + qemu_chr_fe_write_all(&mcdserver_system_state.chr, buf, len);
> +}
> +
> +MCDProcess *mcd_get_cpu_process(CPUState *cpu)
> +{
> + return mcd_get_process(mcd_get_cpu_pid(cpu));
> +}
> +
> uint32_t mcd_get_cpu_pid(CPUState *cpu)
> {
> if (cpu->cluster_index == UNASSIGNED_CLUSTER_INDEX) {
> @@ -381,3 +647,14 @@ CPUState *find_cpu(uint32_t thread_id)
> return NULL;
> }
>
> +
> +int int_cmp(gconstpointer a, gconstpointer b)
> +{
> + int int_a = *(int *)a;
> + int int_b = *(int *)b;
> + if (int_a == int_b) {
> + return 0;
> + } else {
> + return 1;
> + }
> +}
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v3 06/20] mcdstub: open/close server functions and trigger/reset data added. User for initial connection with an mcd client
2023-11-07 13:03 [PATCH v3 00/20] first version of mcdstub Nicolas Eder
` (4 preceding siblings ...)
2023-11-07 13:03 ` [PATCH v3 05/20] mcdstub: tcp packet processing added Nicolas Eder
@ 2023-11-07 13:03 ` Nicolas Eder
2023-11-07 13:03 ` [PATCH v3 07/20] mcdstub: quitting QEMU via mcd command added Nicolas Eder
` (15 subsequent siblings)
21 siblings, 0 replies; 32+ messages in thread
From: Nicolas Eder @ 2023-11-07 13:03 UTC (permalink / raw)
To: qemu-devel
Cc: Nicolas Eder, Alex Bennée, Philippe Mathieu-Daudé,
Christian Boenig
---
include/mcdstub/mcdstub.h | 84 ++++++++++++++++++++++++++++++++++++
mcdstub/mcdstub.c | 90 +++++++++++++++++++++++++++++++++++++++
2 files changed, 174 insertions(+)
diff --git a/include/mcdstub/mcdstub.h b/include/mcdstub/mcdstub.h
index 1461d0e1cb..c7e34673a6 100644
--- a/include/mcdstub/mcdstub.h
+++ b/include/mcdstub/mcdstub.h
@@ -7,6 +7,24 @@
#include "mcdstub_common.h"
#define MAX_PACKET_LENGTH 1024
+
+/* trigger defines */
+#define MCD_TRIG_OPT_DATA_IS_CONDITION 0x00000008
+#define MCD_TRIG_ACTION_DBG_DEBUG 0x00000001
+
+/* schema defines */
+#define ARG_SCHEMA_QRYHANDLE 'q'
+#define ARG_SCHEMA_STRING 's'
+#define ARG_SCHEMA_INT 'd'
+#define ARG_SCHEMA_UINT64_T 'l'
+#define ARG_SCHEMA_CORENUM 'c'
+#define ARG_SCHEMA_HEXDATA 'h'
+
+/* resets */
+#define RESET_SYSTEM "full_system_reset"
+#define RESET_GPR "gpr_reset"
+#define RESET_MEMORY "memory_reset"
+
/* misc */
#define QUERY_TOTAL_NUMBER 12
#define CMD_SCHEMA_LENGTH 6
@@ -49,6 +67,13 @@ enum RSState {
RS_DATAEND,
};
+typedef struct mcd_trigger_into_st {
+ char type[ARGUMENT_STRING_LENGTH];
+ char option[ARGUMENT_STRING_LENGTH];
+ char action[ARGUMENT_STRING_LENGTH];
+ uint32_t nr_trigger;
+} mcd_trigger_into_st;
+
typedef struct MCDState {
bool init; /* have we been initialised? */
CPUState *c_cpu; /* current CPU for everything */
@@ -81,6 +106,11 @@ typedef struct MCDState {
/* lives in main mcdstub.c */
extern MCDState mcdserver_state;
+typedef struct mcd_reset_st {
+ const char *name;
+ uint8_t id;
+} mcd_reset_st;
+
#ifndef _WIN32
void mcd_sigterm_handler(int signal);
#endif
@@ -109,6 +139,38 @@ void mcd_init_mcdserver_state(void);
* @mcd_query_cmds_table: Lookup table with all query commands.
*/
void init_query_cmds_table(MCDCmdParseEntry *mcd_query_cmds_table);
+
+/**
+ * init_resets() - Initializes the resets info.
+ *
+ * This function currently only adds all theoretical possible resets to the
+ * resets GArray. None of the resets work at the moment. The resets are:
+ * "full_system_reset", "gpr_reset" and "memory_reset".
+ * @resets: GArray with possible resets.
+ */
+int init_resets(GArray *resets);
+
+/**
+ * init_trigger() - Initializes the trigger info.
+ *
+ * This function adds the types of trigger, their possible options and actions
+ * to the trigger struct.
+ * @trigger: Struct with all trigger info.
+ */
+int init_trigger(mcd_trigger_into_st *trigger);
+
+/**
+ * mcd_init_debug_class() - initialize mcd-specific DebugClass
+ */
+void mcd_init_debug_class(void);
+
+/**
+ * reset_mcdserver_state() - Resets the mcdserver_state struct.
+ *
+ * This function deletes all processes connected to the mcdserver_state.
+ */
+void reset_mcdserver_state(void);
+
/**
* create_processes() - Sorts all processes and calls
* :c:func:`mcd_create_default_process`.
@@ -357,6 +419,28 @@ CPUState *get_first_cpu_in_process(MCDProcess *process);
* @thread_id: ID of the desired CPU.
*/
CPUState *find_cpu(uint32_t thread_id);
+
+/**
+ * handle_close_server() - Handler for closing the MCD server.
+ *
+ * This function detaches the debugger (process) and frees up memory.
+ * Then it start the QEMU VM with :c:func:`mcd_vm_start`.
+ * @params: GArray with all TCP packet parameters.
+ */
+void handle_close_server(GArray *params, void *user_ctx);
+
+/**
+ * handle_open_server() - Handler for opening the MCD server.
+ *
+ * This is the first function that gets called from the MCD Shared Library.
+ * It initializes core indepent data with the :c:func:`init_resets` and
+ * \reg init_trigger functions. It also send the TCP_HANDSHAKE_SUCCESS
+ * packet back to the library to confirm the mcdstub is ready for further
+ * communication.
+ * @params: GArray with all TCP packet parameters.
+ */
+void handle_open_server(GArray *params, void *user_ctx);
+
/* helpers */
/**
diff --git a/mcdstub/mcdstub.c b/mcdstub/mcdstub.c
index 6900dcd0ea..d2f6df04c0 100644
--- a/mcdstub/mcdstub.c
+++ b/mcdstub/mcdstub.c
@@ -331,6 +331,25 @@ int mcd_handle_packet(const char *line_buf)
const MCDCmdParseEntry *cmd_parser = NULL;
switch (line_buf[0]) {
+ case TCP_CHAR_OPEN_SERVER:
+ {
+ static MCDCmdParseEntry open_server_cmd_desc = {
+ .handler = handle_open_server,
+ };
+ open_server_cmd_desc.cmd = (char[2]) { TCP_CHAR_OPEN_SERVER, '\0' };
+ cmd_parser = &open_server_cmd_desc;
+ }
+ break;
+ case TCP_CHAR_CLOSE_SERVER:
+ {
+ static MCDCmdParseEntry close_server_cmd_desc = {
+ .handler = handle_close_server,
+ };
+ close_server_cmd_desc.cmd =
+ (char[2]) { TCP_CHAR_CLOSE_SERVER, '\0' };
+ cmd_parser = &close_server_cmd_desc;
+ }
+ break;
default:
/* command not supported */
mcd_put_packet("");
@@ -658,3 +677,74 @@ int int_cmp(gconstpointer a, gconstpointer b)
return 1;
}
}
+
+int init_resets(GArray *resets)
+{
+ mcd_reset_st system_reset = { .id = 0, .name = RESET_SYSTEM};
+ mcd_reset_st gpr_reset = { .id = 1, .name = RESET_GPR};
+ mcd_reset_st memory_reset = { .id = 2, .name = RESET_MEMORY};
+ g_array_append_vals(resets, (gconstpointer)&system_reset, 1);
+ g_array_append_vals(resets, (gconstpointer)&gpr_reset, 1);
+ g_array_append_vals(resets, (gconstpointer)&memory_reset, 1);
+ return 0;
+}
+
+int init_trigger(mcd_trigger_into_st *trigger)
+{
+ snprintf(trigger->type, sizeof(trigger->type),
+ "%d,%d,%d,%d", MCD_BREAKPOINT_HW, MCD_BREAKPOINT_READ,
+ MCD_BREAKPOINT_WRITE, MCD_BREAKPOINT_RW);
+ snprintf(trigger->option, sizeof(trigger->option),
+ "%s", MCD_TRIG_OPT_VALUE);
+ snprintf(trigger->action, sizeof(trigger->action),
+ "%s", MCD_TRIG_ACT_BREAK);
+ /* there can be 16 breakpoints and 16 watchpoints each */
+ trigger->nr_trigger = 16;
+ return 0;
+}
+
+void handle_open_server(GArray *params, void *user_ctx)
+{
+ /* initialize core-independent data */
+ int return_value = 0;
+ mcdserver_state.resets = g_array_new(false, true, sizeof(mcd_reset_st));
+ return_value = init_resets(mcdserver_state.resets);
+ if (return_value != 0) {
+ g_assert_not_reached();
+ }
+ return_value = init_trigger(&mcdserver_state.trigger);
+ if (return_value != 0) {
+ g_assert_not_reached();
+ }
+
+ mcd_put_packet(TCP_HANDSHAKE_SUCCESS);
+}
+
+
+void handle_close_server(GArray *params, void *user_ctx)
+{
+ uint32_t pid = 1;
+ MCDProcess *process = mcd_get_process(pid);
+
+ /*
+ * 1. free memory
+ * TODO: do this only if there are no processes attached anymore!
+ */
+ g_list_free(mcdserver_state.all_memspaces);
+ g_list_free(mcdserver_state.all_reggroups);
+ g_list_free(mcdserver_state.all_registers);
+ g_array_free(mcdserver_state.resets, TRUE);
+
+ /* 2. detach */
+ process->attached = false;
+
+ /* 3. reset process */
+ if (pid == mcd_get_cpu_pid(mcdserver_state.c_cpu)) {
+ mcdserver_state.c_cpu = mcd_first_attached_cpu();
+ }
+ if (!mcdserver_state.c_cpu) {
+ /* no more processes attached */
+ mcd_vm_start();
+ }
+}
+
--
2.34.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 07/20] mcdstub: quitting QEMU via mcd command added
2023-11-07 13:03 [PATCH v3 00/20] first version of mcdstub Nicolas Eder
` (5 preceding siblings ...)
2023-11-07 13:03 ` [PATCH v3 06/20] mcdstub: open/close server functions and trigger/reset data added. User for initial connection with an mcd client Nicolas Eder
@ 2023-11-07 13:03 ` Nicolas Eder
2023-11-07 13:03 ` [PATCH v3 08/20] mcdstub: query packet processing added and core/system querie added Nicolas Eder
` (14 subsequent siblings)
21 siblings, 0 replies; 32+ messages in thread
From: Nicolas Eder @ 2023-11-07 13:03 UTC (permalink / raw)
To: qemu-devel
Cc: Nicolas Eder, Alex Bennée, Philippe Mathieu-Daudé,
Christian Boenig
---
include/mcdstub/mcdstub.h | 9 +++++++++
mcdstub/mcdstub.c | 15 +++++++++++++++
2 files changed, 24 insertions(+)
diff --git a/include/mcdstub/mcdstub.h b/include/mcdstub/mcdstub.h
index c7e34673a6..c3e9c7e9dc 100644
--- a/include/mcdstub/mcdstub.h
+++ b/include/mcdstub/mcdstub.h
@@ -356,6 +356,15 @@ int mcd_handle_packet(const char *line_buf);
*/
void mcd_put_strbuf(void);
+/**
+ * mcd_exit() - Terminates QEMU.
+ *
+ * If the mcdserver_state has not been initialized the function exits before
+ * terminating QEMU. Terminting is done with the qemu_chr_fe_deinit function.
+ * @code: An exitcode, which can be used in the future.
+ */
+void mcd_exit(int code);
+
/**
* run_cmd_parser() - Prepares the mcdserver_state before executing TCP packet
* functions.
diff --git a/mcdstub/mcdstub.c b/mcdstub/mcdstub.c
index d2f6df04c0..858e79632b 100644
--- a/mcdstub/mcdstub.c
+++ b/mcdstub/mcdstub.c
@@ -340,6 +340,11 @@ int mcd_handle_packet(const char *line_buf)
cmd_parser = &open_server_cmd_desc;
}
break;
+ case TCP_CHAR_KILLQEMU:
+ /* kill qemu completely */
+ error_report("QEMU: Terminated via MCDstub");
+ mcd_exit(0);
+ exit(0);
case TCP_CHAR_CLOSE_SERVER:
{
static MCDCmdParseEntry close_server_cmd_desc = {
@@ -492,6 +497,16 @@ int process_string_cmd(void *user_ctx, const char *data,
return -1;
}
+void mcd_exit(int code)
+{
+ /* terminate qemu */
+ if (!mcdserver_state.init) {
+ return;
+ }
+
+ qemu_chr_fe_deinit(&mcdserver_system_state.chr, true);
+}
+
void mcd_chr_event(void *opaque, QEMUChrEvent event)
{
int i;
--
2.34.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 08/20] mcdstub: query packet processing added and core/system querie added
2023-11-07 13:03 [PATCH v3 00/20] first version of mcdstub Nicolas Eder
` (6 preceding siblings ...)
2023-11-07 13:03 ` [PATCH v3 07/20] mcdstub: quitting QEMU via mcd command added Nicolas Eder
@ 2023-11-07 13:03 ` Nicolas Eder
2023-11-07 13:03 ` [PATCH v3 09/20] mcdstub: open/close core added. This includes core specific data preparation: memory spaces, register groups and registers. This data preparation is done in the arm mcdstub Nicolas Eder
` (13 subsequent siblings)
21 siblings, 0 replies; 32+ messages in thread
From: Nicolas Eder @ 2023-11-07 13:03 UTC (permalink / raw)
To: qemu-devel
Cc: Nicolas Eder, Alex Bennée, Philippe Mathieu-Daudé,
Christian Boenig
---
include/mcdstub/mcdstub.h | 30 +++++++++++++++++
mcdstub/mcdstub.c | 70 +++++++++++++++++++++++++++++++++++++++
2 files changed, 100 insertions(+)
diff --git a/include/mcdstub/mcdstub.h b/include/mcdstub/mcdstub.h
index c3e9c7e9dc..c4370bb177 100644
--- a/include/mcdstub/mcdstub.h
+++ b/include/mcdstub/mcdstub.h
@@ -402,6 +402,18 @@ int process_string_cmd(void *user_ctx, const char *data,
* @params: GArray with all extracted parameters.
*/
int cmd_parse_params(const char *data, const char *schema, GArray *params);
+
+/**
+ * handle_gen_query() - Handler for all TCP query packets.
+ *
+ * Calls :c:func:`process_string_cmd` with all query functions in the
+ * mcd_query_cmds_table. :c:func:`process_string_cmd` then selects the correct
+ * one. This function just passes on the TCP packet data string from the
+ * parameters.
+ * @params: GArray with all TCP packet parameters.
+ */
+void handle_gen_query(GArray *params, void *user_ctx);
+
/**
* mcd_get_cpu_index() - Returns the internal CPU index plus one.
*
@@ -415,6 +427,24 @@ int mcd_get_cpu_index(CPUState *cpu);
* @cpu_index: Index of the desired CPU.
*/
CPUState *mcd_get_cpu(uint32_t cpu_index);
+
+/**
+ * handle_query_cores() - Handler for the core query.
+ *
+ * This function sends the type of core and number of cores currently
+ * simulated by QEMU. It also sends a device name for the MCD data structure.
+ * @params: GArray with all TCP packet parameters.
+ */
+void handle_query_cores(GArray *params, void *user_ctx);
+
+/**
+ * handle_query_system() - Handler for the system query.
+ *
+ * Sends the system name, which is "qemu-system".
+ * @params: GArray with all TCP packet parameters.
+ */
+void handle_query_system(GArray *params, void *user_ctx);
+
/**
* get_first_cpu_in_process() - Returns the first CPU in the provided process.
*
diff --git a/mcdstub/mcdstub.c b/mcdstub/mcdstub.c
index 858e79632b..a090268e70 100644
--- a/mcdstub/mcdstub.c
+++ b/mcdstub/mcdstub.c
@@ -81,6 +81,20 @@ void init_query_cmds_table(MCDCmdParseEntry *mcd_query_cmds_table)
/* initalizes a list of all query commands */
int cmd_number = 0;
+ MCDCmdParseEntry query_system = {
+ .handler = handle_query_system,
+ .cmd = QUERY_ARG_SYSTEM,
+ };
+ mcd_query_cmds_table[cmd_number] = query_system;
+ cmd_number++;
+
+ MCDCmdParseEntry query_cores = {
+ .handler = handle_query_cores,
+ .cmd = QUERY_ARG_CORES,
+ };
+ mcd_query_cmds_table[cmd_number] = query_cores;
+ cmd_number++;
+
void reset_mcdserver_state(void)
{
g_free(mcdserver_state.processes);
@@ -345,6 +359,17 @@ int mcd_handle_packet(const char *line_buf)
error_report("QEMU: Terminated via MCDstub");
mcd_exit(0);
exit(0);
+ case TCP_CHAR_QUERY:
+ {
+ static MCDCmdParseEntry query_cmd_desc = {
+ .handler = handle_gen_query,
+ };
+ query_cmd_desc.cmd = (char[2]) { TCP_CHAR_QUERY, '\0' };
+ strcpy(query_cmd_desc.schema,
+ (char[2]) { ARG_SCHEMA_STRING, '\0' });
+ cmd_parser = &query_cmd_desc;
+ }
+ break;
case TCP_CHAR_CLOSE_SERVER:
{
static MCDCmdParseEntry close_server_cmd_desc = {
@@ -368,6 +393,20 @@ int mcd_handle_packet(const char *line_buf)
return RS_IDLE;
}
+
+void handle_gen_query(GArray *params, void *user_ctx)
+{
+ if (!params->len) {
+ return;
+ }
+ /* iterate over all possible query functions and execute the right one */
+ if (process_string_cmd(NULL, get_param(params, 0)->data,
+ mcdserver_state.mcd_query_cmds_table,
+ ARRAY_SIZE(mcdserver_state.mcd_query_cmds_table))) {
+ mcd_put_packet("");
+ }
+}
+
void run_cmd_parser(const char *data, const MCDCmdParseEntry *cmd)
{
if (!data) {
@@ -735,6 +774,37 @@ void handle_open_server(GArray *params, void *user_ctx)
mcd_put_packet(TCP_HANDSHAKE_SUCCESS);
}
+void handle_query_system(GArray *params, void *user_ctx)
+{
+ mcd_put_packet(MCD_SYSTEM_NAME);
+}
+
+void handle_query_cores(GArray *params, void *user_ctx)
+{
+ /* get first cpu */
+ CPUState *cpu = mcd_first_attached_cpu();
+ if (!cpu) {
+ return;
+ }
+
+ ObjectClass *oc = object_get_class(OBJECT(cpu));
+ const char *cpu_model = object_class_get_name(oc);
+
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+ const gchar *arch = cc->gdb_arch_name(cpu);
+
+ uint32_t nr_cores = cpu->nr_cores;
+ char device_name[ARGUMENT_STRING_LENGTH] = {0};
+ if (arch) {
+ snprintf(device_name, sizeof(device_name), "%s",
+ DEVICE_NAME_TEMPLATE(arch));
+ }
+ g_string_printf(mcdserver_state.str_buf, "%s=%s.%s=%s.%s=%u.",
+ TCP_ARGUMENT_DEVICE, device_name, TCP_ARGUMENT_CORE, cpu_model,
+ TCP_ARGUMENT_AMOUNT_CORE, nr_cores);
+ mcd_put_strbuf();
+}
+
void handle_close_server(GArray *params, void *user_ctx)
{
--
2.34.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 09/20] mcdstub: open/close core added. This includes core specific data preparation: memory spaces, register groups and registers. This data preparation is done in the arm mcdstub
2023-11-07 13:03 [PATCH v3 00/20] first version of mcdstub Nicolas Eder
` (7 preceding siblings ...)
2023-11-07 13:03 ` [PATCH v3 08/20] mcdstub: query packet processing added and core/system querie added Nicolas Eder
@ 2023-11-07 13:03 ` Nicolas Eder
2023-11-07 13:03 ` [PATCH v3 10/20] mcdstub: state query added: this query collects information about the state of a specific core. This commit also includes mcd_vm_state_change, which is called when the cpu state changes because it collects data for the query Nicolas Eder
` (12 subsequent siblings)
21 siblings, 0 replies; 32+ messages in thread
From: Nicolas Eder @ 2023-11-07 13:03 UTC (permalink / raw)
To: qemu-devel
Cc: Nicolas Eder, Alex Bennée, Philippe Mathieu-Daudé,
Christian Boenig
---
include/mcdstub/arm_mcdstub.h | 81 +++++++++
include/mcdstub/mcdstub.h | 26 +++
include/mcdstub/mcdstub_common.h | 52 ++++++
mcdstub/mcdstub.c | 111 ++++++++++++
target/arm/mcdstub.c | 278 +++++++++++++++++++++++++++++++
5 files changed, 548 insertions(+)
create mode 100644 target/arm/mcdstub.c
diff --git a/include/mcdstub/arm_mcdstub.h b/include/mcdstub/arm_mcdstub.h
index a57aa8e9f2..c71f6c3356 100644
--- a/include/mcdstub/arm_mcdstub.h
+++ b/include/mcdstub/arm_mcdstub.h
@@ -6,5 +6,86 @@
/* just used for the register xml files */
#include "exec/gdbstub.h"
+/* ids for each different type of register */
+enum {
+ MCD_ARM_REG_TYPE_GPR,
+ MCD_ARM_REG_TYPE_VFP,
+ MCD_ARM_REG_TYPE_VFP_SYS,
+ MCD_ARM_REG_TYPE_MVE,
+ MCD_ARM_REG_TYPE_CPR,
+};
+
+/**
+ * arm_mcd_get_dynamic_xml() - Returns the contents of the desired XML file.
+ *
+ * @xmlname: Name of the desired XML file.
+ * @cs: CPU state.
+ */
+const char *arm_mcd_get_dynamic_xml(CPUState *cs, const char *xmlname);
+
+/**
+ * arm_mcd_get_opcode() - Returns the opcode for a coprocessor register.
+ *
+ * This function uses the opc1, opc2, crm and crn members of the register to
+ * create the opcode. The formular for creating the opcode is determined by ARM.
+ * @n: The register ID of the CP register.
+ * @cs: CPU state.
+ */
+uint16_t arm_mcd_get_opcode(CPUState *cs, uint32_t n);
+
+/**
+ * arm_mcd_store_mem_spaces() - Stores all 32-Bit ARM specific memory spaces.
+ *
+ * This function stores the memory spaces into the memspaces GArray.
+ * It only stores secure memory spaces if the CPU has more than one address
+ * space. It also stores a GPR and a CP15 register memory space.
+ * @memspaces: GArray of memory spaces.
+ * @cpu: CPU state.
+ */
+int arm_mcd_store_mem_spaces(CPUState *cpu, GArray *memspaces);
+
+/**
+ * arm_mcd_parse_core_xml_file() - Parses the GPR registers.
+ *
+ * This function parses the core XML file, which includes the GPR registers.
+ * The regsters get stored in a GArray and a GPR register group is stored in a
+ * second GArray.
+ * @reggroups: GArray of register groups.
+ * @registers: GArray of registers.
+ * @cc: The CPU class.
+ * @current_group_id: The current group ID. It increases after
+ * each group.
+ */
+int arm_mcd_parse_core_xml_file(CPUClass *cc, GArray *reggroups,
+ GArray *registers, int *current_group_id);
+
+/**
+ * arm_mcd_parse_general_xml_files() - Parses all but the GPR registers.
+ *
+ * This function parses all XML files except for the core XML file.
+ * The regsters get stored in a GArray and if the system-registers.xml file is
+ * parsed, it also adds a CP15 register group.
+ * @reggroups: GArray of register groups.
+ * @registers: GArray of registers.
+ * @cpu: The CPU state.
+ * @current_group_id: The current group ID. It increases after
+ * each added group.
+ */
+int arm_mcd_parse_general_xml_files(CPUState *cpu, GArray* reggroups,
+ GArray *registers, int *current_group_id);
+
+/**
+ * arm_mcd_get_additional_register_info() - Adds additional data to parsed
+ * registers.
+ *
+ * This function is called, after :c:func:`arm_mcd_parse_core_xml_file` and
+ * :c:func:`arm_mcd_parse_general_xml_files`. It adds additional data for all
+ * already parsed registers. The registers get a correct ID, group, memory
+ * space and opcode, if they are CP15 registers.
+ * @reggroups: GArray of register groups.
+ * @registers: GArray of registers.
+ * @cpu: The CPU state.
+ */
+int arm_mcd_get_additional_register_info(GArray *reggroups, GArray *registers,
#endif /* ARM_MCDSTUB_H */
diff --git a/include/mcdstub/mcdstub.h b/include/mcdstub/mcdstub.h
index c4370bb177..d38106e973 100644
--- a/include/mcdstub/mcdstub.h
+++ b/include/mcdstub/mcdstub.h
@@ -106,6 +106,11 @@ typedef struct MCDState {
/* lives in main mcdstub.c */
extern MCDState mcdserver_state;
+typedef struct xml_attrib {
+ char argument[ARGUMENT_STRING_LENGTH];
+ char value[ARGUMENT_STRING_LENGTH];
+} xml_attrib;
+
typedef struct mcd_reset_st {
const char *name;
uint8_t id;
@@ -459,6 +464,18 @@ CPUState *get_first_cpu_in_process(MCDProcess *process);
*/
CPUState *find_cpu(uint32_t thread_id);
+/**
+ * handle_open_core() - Handler for opening a core.
+ *
+ * This function initializes all data for the core with the ID provided in
+ * the first parameter. In has a swtich case for different architectures.
+ * Currently only 32-Bit ARM is supported. The data includes memory spaces,
+ * register groups and registers themselves. They get stored into GLists where
+ * every entry in the list corresponds to one opened core.
+ * @params: GArray with all TCP packet parameters.
+ */
+void handle_open_core(GArray *params, void *user_ctx);
+
/**
* handle_close_server() - Handler for closing the MCD server.
*
@@ -468,6 +485,15 @@ CPUState *find_cpu(uint32_t thread_id);
*/
void handle_close_server(GArray *params, void *user_ctx);
+/**
+ * handle_close_core() - Handler for closing a core.
+ *
+ * Frees all memory allocated for core specific information. This includes
+ * memory spaces, register groups and registers.
+ * @params: GArray with all TCP packet parameters.
+ */
+void handle_close_core(GArray *params, void *user_ctx);
+
/**
* handle_open_server() - Handler for opening the MCD server.
*
diff --git a/include/mcdstub/mcdstub_common.h b/include/mcdstub/mcdstub_common.h
index 3bae2c3b6f..633d9b0f70 100644
--- a/include/mcdstub/mcdstub_common.h
+++ b/include/mcdstub/mcdstub_common.h
@@ -4,4 +4,56 @@
#define ARGUMENT_STRING_LENGTH 64
#define TCP_CONFIG_STRING_LENGTH 128
+typedef struct mcd_mem_space_st {
+ const char *name;
+ uint32_t id;
+ uint32_t type;
+ uint32_t bits_per_mau;
+ uint8_t invariance;
+ uint32_t endian;
+ uint64_t min_addr;
+ uint64_t max_addr;
+ uint32_t supported_access_options;
+ /* internal */
+ bool is_secure;
+ bool is_physical;
+} mcd_mem_space_st;
+
+typedef struct mcd_reg_st {
+ /* xml info */
+ char name[ARGUMENT_STRING_LENGTH];
+ char group[ARGUMENT_STRING_LENGTH];
+ char type[ARGUMENT_STRING_LENGTH];
+ uint32_t bitsize;
+ uint32_t id; /* id used by the mcd interface */
+ uint32_t internal_id; /* id inside reg type */
+ uint8_t reg_type;
+ /* mcd metadata */
+ uint32_t mcd_reg_group_id;
+ uint32_t mcd_mem_space_id;
+ uint32_t mcd_reg_type;
+ uint32_t mcd_hw_thread_id;
+ /* data for op-code */
+ uint32_t opcode;
+} mcd_reg_st;
+
+typedef struct mcd_reg_group_st {
+ const char *name;
+ uint32_t id;
+} mcd_reg_group_st;
+
+/**
+ * parse_reg_xml() - Parses a GDB register XML file
+ *
+ * This fuction extracts all registers from the provided xml file and stores
+ * them into the registers GArray. It extracts the register name, bitsize, type
+ * and group if they are set.
+ * @xml: String with contents of the XML file.
+ * @registers: GArray with stored registers.
+ * @reg_type: Register type (depending on file).
+ * @size: Number of characters in the xml string.
+ */
+void parse_reg_xml(const char *xml, int size, GArray* registers,
+ uint8_t reg_type, uint32_t reg_id_offset);
+
#endif /* MCDSTUB_COMMON_H */
diff --git a/mcdstub/mcdstub.c b/mcdstub/mcdstub.c
index a090268e70..ca98d01ee7 100644
--- a/mcdstub/mcdstub.c
+++ b/mcdstub/mcdstub.c
@@ -370,6 +370,17 @@ int mcd_handle_packet(const char *line_buf)
cmd_parser = &query_cmd_desc;
}
break;
+ case TCP_CHAR_OPEN_CORE:
+ {
+ static MCDCmdParseEntry open_core_cmd_desc = {
+ .handler = handle_open_core,
+ };
+ open_core_cmd_desc.cmd = (char[2]) { TCP_CHAR_OPEN_CORE, '\0' };
+ strcpy(open_core_cmd_desc.schema,
+ (char[2]) { ARG_SCHEMA_CORENUM, '\0' });
+ cmd_parser = &open_core_cmd_desc;
+ }
+ break;
case TCP_CHAR_CLOSE_SERVER:
{
static MCDCmdParseEntry close_server_cmd_desc = {
@@ -380,6 +391,17 @@ int mcd_handle_packet(const char *line_buf)
cmd_parser = &close_server_cmd_desc;
}
break;
+ case TCP_CHAR_CLOSE_CORE:
+ {
+ static MCDCmdParseEntry close_core_cmd_desc = {
+ .handler = handle_close_core,
+ };
+ close_core_cmd_desc.cmd = (char[2]) { TCP_CHAR_CLOSE_CORE, '\0' };
+ strcpy(close_core_cmd_desc.schema,
+ (char[2]) { ARG_SCHEMA_CORENUM, '\0' });
+ cmd_parser = &close_core_cmd_desc;
+ }
+ break;
default:
/* command not supported */
mcd_put_packet("");
@@ -805,6 +827,95 @@ void handle_query_cores(GArray *params, void *user_ctx)
mcd_put_strbuf();
}
+void handle_open_core(GArray *params, void *user_ctx)
+{
+ uint32_t cpu_id = get_param(params, 0)->cpu_id;
+ CPUState *cpu = mcd_get_cpu(cpu_id);
+ mcdserver_state.c_cpu = cpu;
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+ const gchar *arch = cc->gdb_arch_name(cpu);
+ int return_value = 0;
+
+ /* prepare data strucutures */
+ GArray *memspaces = g_array_new(false, true, sizeof(mcd_mem_space_st));
+ GArray *reggroups = g_array_new(false, true, sizeof(mcd_reg_group_st));
+ GArray *registers = g_array_new(false, true, sizeof(mcd_reg_st));
+
+ if (strcmp(arch, MCDSTUB_ARCH_ARM) == 0) {
+ /* TODO: make group and memspace ids dynamic */
+ int current_group_id = 1;
+ /* 1. store mem spaces */
+ return_value = arm_mcd_store_mem_spaces(cpu, memspaces);
+ if (return_value != 0) {
+ g_assert_not_reached();
+ }
+ /* 2. parse core xml */
+ return_value = arm_mcd_parse_core_xml_file(cc, reggroups,
+ registers, ¤t_group_id);
+ if (return_value != 0) {
+ g_assert_not_reached();
+ }
+ /* 3. parse other xmls */
+ return_value = arm_mcd_parse_general_xml_files(cpu, reggroups,
+ registers, ¤t_group_id);
+ if (return_value != 0) {
+ g_assert_not_reached();
+ }
+ /* 4. add additional data the the regs from the xmls */
+ return_value = arm_mcd_get_additional_register_info(reggroups,
+ registers, cpu);
+ if (return_value != 0) {
+ g_assert_not_reached();
+ }
+ /* 5. store all found data */
+ if (g_list_nth(mcdserver_state.all_memspaces, cpu_id)) {
+ GList *memspaces_ptr =
+ g_list_nth(mcdserver_state.all_memspaces, cpu_id);
+ memspaces_ptr->data = memspaces;
+ } else {
+ mcdserver_state.all_memspaces =
+ g_list_insert(mcdserver_state.all_memspaces, memspaces, cpu_id);
+ }
+ if (g_list_nth(mcdserver_state.all_reggroups, cpu_id)) {
+ GList *reggroups_ptr =
+ g_list_nth(mcdserver_state.all_reggroups, cpu_id);
+ reggroups_ptr->data = reggroups;
+ } else {
+ mcdserver_state.all_reggroups =
+ g_list_insert(mcdserver_state.all_reggroups, reggroups, cpu_id);
+ }
+ if (g_list_nth(mcdserver_state.all_registers, cpu_id)) {
+ GList *registers_ptr =
+ g_list_nth(mcdserver_state.all_registers, cpu_id);
+ registers_ptr->data = registers;
+ } else {
+ mcdserver_state.all_registers =
+ g_list_insert(mcdserver_state.all_registers, registers, cpu_id);
+ }
+ } else {
+ /* we don't support other architectures */
+ g_assert_not_reached();
+ }
+}
+
+
+void handle_close_core(GArray *params, void *user_ctx)
+{
+ /* free memory for correct core */
+ uint32_t cpu_id = get_param(params, 0)->cpu_id;
+ GArray *memspaces = g_list_nth_data(mcdserver_state.all_memspaces, cpu_id);
+ mcdserver_state.all_memspaces =
+ g_list_remove(mcdserver_state.all_memspaces, memspaces);
+ g_array_free(memspaces, TRUE);
+ GArray *reggroups = g_list_nth_data(mcdserver_state.all_reggroups, cpu_id);
+ mcdserver_state.all_reggroups =
+ g_list_remove(mcdserver_state.all_reggroups, reggroups);
+ g_array_free(reggroups, TRUE);
+ GArray *registers = g_list_nth_data(mcdserver_state.all_registers, cpu_id);
+ mcdserver_state.all_registers =
+ g_list_remove(mcdserver_state.all_registers, registers);
+ g_array_free(registers, TRUE);
+}
void handle_close_server(GArray *params, void *user_ctx)
{
diff --git a/target/arm/mcdstub.c b/target/arm/mcdstub.c
new file mode 100644
index 0000000000..ff1350831b
--- /dev/null
+++ b/target/arm/mcdstub.c
@@ -0,0 +1,278 @@
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "exec/memory.h"
+#include "sysemu/tcg.h"
+#include "internals.h"
+#include "cpregs.h"
+#include "qemu/debug.h"
+#include "mcdstub/arm_mcdstub.h"
+
+const char *arm_mcd_get_dynamic_xml(CPUState *cs, const char *xmlname)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+
+ if (strcmp(xmlname, "system-registers.xml") == 0) {
+ return cpu->dyn_sysreg_xml.desc;
+ } else if (strcmp(xmlname, "sve-registers.xml") == 0) {
+ return cpu->dyn_svereg_xml.desc;
+ } else if (strcmp(xmlname, "arm-m-system.xml") == 0) {
+ return cpu->dyn_m_systemreg_xml.desc;
+#ifndef CONFIG_USER_ONLY
+ } else if (strcmp(xmlname, "arm-m-secext.xml") == 0) {
+ return cpu->dyn_m_secextreg_xml.desc;
+#endif
+ }
+ return NULL;
+}
+
+uint16_t arm_mcd_get_opcode(CPUState *cs, uint32_t n)
+{
+ /*gets the opcode for a cp register*/
+ ARMCPU *cpu = ARM_CPU(cs);
+ const ARMCPRegInfo *ri;
+ uint32_t key;
+
+ key = cpu->dyn_sysreg_xml.data.cpregs.keys[n];
+ ri = get_arm_cp_reginfo(cpu->cp_regs, key);
+ if (ri) {
+ uint16_t opcode = 0;
+ opcode |= ri->opc1 << 14;
+ opcode |= ri->opc2 << 10;
+ opcode |= ri->crm << 7;
+ opcode |= ri->crn << 3;
+ return opcode;
+ }
+ return 0;
+}
+
+int arm_mcd_store_mem_spaces(CPUState *cpu, GArray *memspaces)
+{
+ int nr_address_spaces = cpu->num_ases;
+ uint32_t mem_space_id = 0;
+
+ mem_space_id++;
+ mcd_mem_space_st non_secure = {
+ .name = "Non Secure",
+ .id = mem_space_id,
+ .type = 34,
+ .bits_per_mau = 8,
+ .invariance = 1,
+ .endian = 1,
+ .min_addr = 0,
+ .max_addr = -1,
+ .supported_access_options = 0,
+ .is_secure = false,
+ .is_physical = false,
+ };
+ g_array_append_vals(memspaces, (gconstpointer)&non_secure, 1);
+ mem_space_id++;
+ mcd_mem_space_st phys_non_secure = {
+ .name = "Physical (Non Secure)",
+ .id = mem_space_id,
+ .type = 18,
+ .bits_per_mau = 8,
+ .invariance = 1,
+ .endian = 1,
+ .min_addr = 0,
+ .max_addr = -1,
+ .supported_access_options = 0,
+ .is_secure = false,
+ .is_physical = true,
+ };
+ g_array_append_vals(memspaces, (gconstpointer)&phys_non_secure, 1);
+ if (nr_address_spaces > 1) {
+ mem_space_id++;
+ mcd_mem_space_st secure = {
+ .name = "Secure",
+ .id = mem_space_id,
+ .type = 34,
+ .bits_per_mau = 8,
+ .invariance = 1,
+ .endian = 1,
+ .min_addr = 0,
+ .max_addr = -1,
+ .supported_access_options = 0,
+ .is_secure = true,
+ .is_physical = false,
+ };
+ g_array_append_vals(memspaces, (gconstpointer)&secure, 1);
+ mem_space_id++;
+ mcd_mem_space_st phys_secure = {
+ .name = "Physical (Secure)",
+ .id = mem_space_id,
+ .type = 18,
+ .bits_per_mau = 8,
+ .invariance = 1,
+ .endian = 1,
+ .min_addr = 0,
+ .max_addr = -1,
+ .supported_access_options = 0,
+ .is_secure = true,
+ .is_physical = true,
+ };
+ g_array_append_vals(memspaces, (gconstpointer)&phys_secure, 1);
+ }
+ mem_space_id++;
+ mcd_mem_space_st gpr = {
+ .name = "GPR Registers",
+ .id = mem_space_id,
+ .type = 1,
+ .bits_per_mau = 8,
+ .invariance = 1,
+ .endian = 1,
+ .min_addr = 0,
+ .max_addr = -1,
+ .supported_access_options = 0,
+ };
+ g_array_append_vals(memspaces, (gconstpointer)&gpr, 1);
+ mem_space_id++;
+ mcd_mem_space_st cpr = {
+ .name = "CP15 Registers",
+ .id = mem_space_id,
+ .type = 1,
+ .bits_per_mau = 8,
+ .invariance = 1,
+ .endian = 1,
+ .min_addr = 0,
+ .max_addr = -1,
+ .supported_access_options = 0,
+ };
+ g_array_append_vals(memspaces, (gconstpointer)&cpr, 1);
+ return 0;
+}
+
+int arm_mcd_parse_core_xml_file(CPUClass *cc, GArray *reggroups,
+ GArray *registers, int *current_group_id)
+{
+ const char *xml_filename = NULL;
+ const char *current_xml_filename = NULL;
+ const char *xml_content = NULL;
+ int i = 0;
+
+ /* 1. get correct file */
+ xml_filename = cc->gdb_core_xml_file;
+ for (i = 0; ; i++) {
+ current_xml_filename = gdb_static_features[i].xmlname;
+ if (!current_xml_filename || (strncmp(current_xml_filename,
+ xml_filename, strlen(xml_filename)) == 0
+ && strlen(current_xml_filename) == strlen(xml_filename)))
+ break;
+ }
+ /* without gpr registers we can do nothing */
+ if (!current_xml_filename) {
+ return -1;
+ }
+
+ /* 2. add group for gpr registers */
+ mcd_reg_group_st gprregs = {
+ .name = "GPR Registers",
+ .id = *current_group_id
+ };
+ g_array_append_vals(reggroups, (gconstpointer)&gprregs, 1);
+ *current_group_id = *current_group_id + 1;
+
+ /* 3. parse xml */
+ /* the offset for gpr is always zero */
+ xml_content = gdb_static_features[i].xml;
+ parse_reg_xml(xml_content, strlen(xml_content), registers,
+ MCD_ARM_REG_TYPE_GPR, 0);
+ return 0;
+}
+
+int arm_mcd_parse_general_xml_files(CPUState *cpu, GArray *reggroups,
+ GArray *registers, int *current_group_id) {
+ const char *xml_filename = NULL;
+ const char *current_xml_filename = NULL;
+ const char *xml_content = NULL;
+ uint8_t reg_type;
+
+ /* iterate over all gdb xml files*/
+ GDBRegisterState *r;
+ for (guint i = 0; i < cpu->gdb_regs->len; i++) {
+ r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
+
+ xml_filename = r->xml;
+ xml_content = NULL;
+
+ /* 1. get xml content */
+ xml_content = arm_mcd_get_dynamic_xml(cpu, xml_filename);
+ if (xml_content) {
+ if (strcmp(xml_filename, "system-registers.xml") == 0) {
+ /* these are the coprocessor register */
+ mcd_reg_group_st corprocessorregs = {
+ .name = "CP15 Registers",
+ .id = *current_group_id
+ };
+ g_array_append_vals(reggroups,
+ (gconstpointer)&corprocessorregs, 1);
+ *current_group_id = *current_group_id + 1;
+ reg_type = MCD_ARM_REG_TYPE_CPR;
+ }
+ } else {
+ /* its not a coprocessor xml -> it is a static xml file */
+ int j = 0;
+ for (j = 0; ; j++) {
+ current_xml_filename = gdb_static_features[j].xmlname;
+ if (!current_xml_filename || (strncmp(current_xml_filename,
+ xml_filename, strlen(xml_filename)) == 0
+ && strlen(current_xml_filename) == strlen(xml_filename)))
+ break;
+ }
+ if (current_xml_filename) {
+ xml_content = gdb_static_features[j].xml;
+ /* select correct reg_type */
+ if (strcmp(current_xml_filename, "arm-vfp.xml") == 0) {
+ reg_type = MCD_ARM_REG_TYPE_VFP;
+ } else if (strcmp(current_xml_filename, "arm-vfp3.xml") == 0) {
+ reg_type = MCD_ARM_REG_TYPE_VFP;
+ } else if (strcmp(current_xml_filename,
+ "arm-vfp-sysregs.xml") == 0) {
+ reg_type = MCD_ARM_REG_TYPE_VFP_SYS;
+ } else if (strcmp(current_xml_filename,
+ "arm-neon.xml") == 0) {
+ reg_type = MCD_ARM_REG_TYPE_VFP;
+ } else if (strcmp(current_xml_filename,
+ "arm-m-profile-mve.xml") == 0) {
+ reg_type = MCD_ARM_REG_TYPE_MVE;
+ }
+ } else {
+ continue;
+ }
+ }
+ /* 2. parse xml */
+ parse_reg_xml(xml_content, strlen(xml_content), registers, reg_type,
+ r->base_reg);
+ }
+ return 0;
+}
+
+int arm_mcd_get_additional_register_info(GArray *reggroups, GArray *registers,
+ CPUState *cpu)
+{
+ mcd_reg_st *current_register;
+ uint32_t i = 0;
+
+ /* iterate over all registers */
+ for (i = 0; i < registers->len; i++) {
+ current_register = &(g_array_index(registers, mcd_reg_st, i));
+ /* add mcd_reg_group_id and mcd_mem_space_id */
+ if (strcmp(current_register->group, "cp_regs") == 0) {
+ /* coprocessor registers */
+ current_register->mcd_reg_group_id = 2;
+ current_register->mcd_mem_space_id = 6;
+ /*
+ * get info for opcode
+ * for 32bit the opcode is only 16 bit long
+ * for 64bit it is 32 bit long
+ */
+ current_register->opcode |=
+ arm_mcd_get_opcode(cpu, current_register->internal_id);
+ } else {
+ /* gpr register */
+ current_register->mcd_reg_group_id = 1;
+ current_register->mcd_mem_space_id = 5;
+ }
+ }
+ return 0;
+}
+
--
2.34.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 10/20] mcdstub: state query added: this query collects information about the state of a specific core. This commit also includes mcd_vm_state_change, which is called when the cpu state changes because it collects data for the query
2023-11-07 13:03 [PATCH v3 00/20] first version of mcdstub Nicolas Eder
` (8 preceding siblings ...)
2023-11-07 13:03 ` [PATCH v3 09/20] mcdstub: open/close core added. This includes core specific data preparation: memory spaces, register groups and registers. This data preparation is done in the arm mcdstub Nicolas Eder
@ 2023-11-07 13:03 ` Nicolas Eder
2023-11-07 13:03 ` [PATCH v3 11/20] mcdstub: reset and trigger queries added Nicolas Eder
` (11 subsequent siblings)
21 siblings, 0 replies; 32+ messages in thread
From: Nicolas Eder @ 2023-11-07 13:03 UTC (permalink / raw)
To: qemu-devel
Cc: Nicolas Eder, Alex Bennée, Philippe Mathieu-Daudé,
Christian Boenig
---
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
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 11/20] mcdstub: reset and trigger queries added
2023-11-07 13:03 [PATCH v3 00/20] first version of mcdstub Nicolas Eder
` (9 preceding siblings ...)
2023-11-07 13:03 ` [PATCH v3 10/20] mcdstub: state query added: this query collects information about the state of a specific core. This commit also includes mcd_vm_state_change, which is called when the cpu state changes because it collects data for the query Nicolas Eder
@ 2023-11-07 13:03 ` Nicolas Eder
2023-11-07 13:03 ` [PATCH v3 12/20] mcdstub: missing parse_reg_xml function for parsing gdb register xml files added Nicolas Eder
` (10 subsequent siblings)
21 siblings, 0 replies; 32+ messages in thread
From: Nicolas Eder @ 2023-11-07 13:03 UTC (permalink / raw)
To: qemu-devel
Cc: Nicolas Eder, Alex Bennée, Philippe Mathieu-Daudé,
Christian Boenig
---
include/mcdstub/mcdstub.h | 25 ++++++++++++++
mcdstub/mcdstub.c | 69 +++++++++++++++++++++++++++++++++++++++
2 files changed, 94 insertions(+)
diff --git a/include/mcdstub/mcdstub.h b/include/mcdstub/mcdstub.h
index eb46917d00..62394e7c12 100644
--- a/include/mcdstub/mcdstub.h
+++ b/include/mcdstub/mcdstub.h
@@ -507,6 +507,23 @@ CPUState *find_cpu(uint32_t thread_id);
*/
void handle_open_core(GArray *params, void *user_ctx);
+/**
+ * handle_query_reset_f() - Handler for the first reset query.
+ *
+ * This function sends the first reset name and ID.
+ * @params: GArray with all TCP packet parameters.
+ */
+void handle_query_reset_f(GArray *params, void *user_ctx);
+
+/**
+ * handle_query_reset_c() - Handler for all consecutive reset queries.
+ *
+ * This functions sends all consecutive reset names and IDs. It uses the
+ * query_index parameter to determine which reset is queried next.
+ * @params: GArray with all TCP packet parameters.
+ */
+void handle_query_reset_c(GArray *params, void *user_ctx);
+
/**
* handle_close_server() - Handler for closing the MCD server.
*
@@ -525,6 +542,14 @@ void handle_close_server(GArray *params, void *user_ctx);
*/
void handle_close_core(GArray *params, void *user_ctx);
+/**
+ * handle_query_trigger() - Handler for trigger query.
+ *
+ * Sends data on the different types of trigger and their options and actions.
+ * @params: GArray with all TCP packet parameters.
+ */
+void handle_query_trigger(GArray *params, void *user_ctx);
+
/**
* handle_open_server() - Handler for opening the MCD server.
*
diff --git a/mcdstub/mcdstub.c b/mcdstub/mcdstub.c
index 657f80d2a2..d71dff633a 100644
--- a/mcdstub/mcdstub.c
+++ b/mcdstub/mcdstub.c
@@ -95,6 +95,27 @@ void init_query_cmds_table(MCDCmdParseEntry *mcd_query_cmds_table)
mcd_query_cmds_table[cmd_number] = query_cores;
cmd_number++;
+ MCDCmdParseEntry query_reset_f = {
+ .handler = handle_query_reset_f,
+ .cmd = QUERY_ARG_RESET QUERY_FIRST,
+ };
+ mcd_query_cmds_table[cmd_number] = query_reset_f;
+ cmd_number++;
+
+ MCDCmdParseEntry query_reset_c = {
+ .handler = handle_query_reset_c,
+ .cmd = QUERY_ARG_RESET QUERY_CONSEQUTIVE,
+ };
+ strcpy(query_reset_c.schema, (char[2]) { ARG_SCHEMA_QRYHANDLE, '\0' });
+ mcd_query_cmds_table[cmd_number] = query_reset_c;
+ cmd_number++;
+
+ MCDCmdParseEntry query_trigger = {
+ .handler = handle_query_trigger,
+ .cmd = QUERY_ARG_TRIGGER,
+ };
+ mcd_query_cmds_table[cmd_number] = query_trigger;
+ cmd_number++;
MCDCmdParseEntry query_state = {
.handler = handle_query_state,
@@ -1001,6 +1022,44 @@ void handle_open_core(GArray *params, void *user_ctx)
}
}
+void handle_query_reset_f(GArray *params, void *user_ctx)
+{
+ /* 1. check length */
+ int nb_resets = mcdserver_state.resets->len;
+ if (nb_resets == 1) {
+ /* indicates this is the last packet */
+ g_string_printf(mcdserver_state.str_buf, "0%s", QUERY_END_INDEX);
+ } else {
+ g_string_printf(mcdserver_state.str_buf, "1%s", QUERY_END_INDEX);
+ }
+ /* 2. send data */
+ mcd_reset_st reset = g_array_index(mcdserver_state.resets, mcd_reset_st, 0);
+ g_string_append_printf(mcdserver_state.str_buf, "%s=%s.%s=%u.",
+ TCP_ARGUMENT_NAME, reset.name, TCP_ARGUMENT_ID, reset.id);
+ mcd_put_strbuf();
+}
+
+void handle_query_reset_c(GArray *params, void *user_ctx)
+{
+ /* reset options are the same for every cpu! */
+ uint32_t query_index = get_param(params, 0)->query_handle;
+
+ /* 1. check weather this was the last mem space */
+ int nb_groups = mcdserver_state.resets->len;
+ if (query_index + 1 == nb_groups) {
+ /* indicates this is the last packet */
+ g_string_printf(mcdserver_state.str_buf, "0%s", QUERY_END_INDEX);
+ } else {
+ g_string_printf(mcdserver_state.str_buf, "%u!", query_index + 1);
+ }
+
+ /* 2. send data */
+ mcd_reset_st reset = g_array_index(mcdserver_state.resets,
+ mcd_reset_st, query_index);
+ g_string_append_printf(mcdserver_state.str_buf, "%s=%s.%s=%u.",
+ TCP_ARGUMENT_NAME, reset.name, TCP_ARGUMENT_ID, reset.id);
+ mcd_put_strbuf();
+}
void handle_close_core(GArray *params, void *user_ctx)
{
@@ -1047,3 +1106,13 @@ void handle_close_server(GArray *params, void *user_ctx)
}
}
+void handle_query_trigger(GArray *params, void *user_ctx)
+{
+ mcd_trigger_into_st trigger = mcdserver_state.trigger;
+ g_string_printf(mcdserver_state.str_buf, "%s=%u.%s=%s.%s=%s.%s=%s.",
+ TCP_ARGUMENT_AMOUNT_TRIGGER, trigger.nr_trigger,
+ TCP_ARGUMENT_TYPE, trigger.type,
+ TCP_ARGUMENT_OPTION, trigger.option,
+ TCP_ARGUMENT_ACTION, trigger.action);
+ mcd_put_strbuf();
+}
--
2.34.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 12/20] mcdstub: missing parse_reg_xml function for parsing gdb register xml files added
2023-11-07 13:03 [PATCH v3 00/20] first version of mcdstub Nicolas Eder
` (10 preceding siblings ...)
2023-11-07 13:03 ` [PATCH v3 11/20] mcdstub: reset and trigger queries added Nicolas Eder
@ 2023-11-07 13:03 ` Nicolas Eder
2023-11-07 13:03 ` [PATCH v3 13/20] mcdstub: added queries for memory spaces, register groups and registers Nicolas Eder
` (9 subsequent siblings)
21 siblings, 0 replies; 32+ messages in thread
From: Nicolas Eder @ 2023-11-07 13:03 UTC (permalink / raw)
To: qemu-devel
Cc: Nicolas Eder, Alex Bennée, Philippe Mathieu-Daudé,
Christian Boenig
---
mcdstub/mcdstub.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 121 insertions(+)
diff --git a/mcdstub/mcdstub.c b/mcdstub/mcdstub.c
index d71dff633a..3e87378b45 100644
--- a/mcdstub/mcdstub.c
+++ b/mcdstub/mcdstub.c
@@ -867,6 +867,127 @@ CPUState *find_cpu(uint32_t thread_id)
}
+void parse_reg_xml(const char *xml, int size, GArray *registers,
+ uint8_t reg_type, uint32_t reg_id_offset)
+{
+ /* iterates over the complete xml file */
+ int i, j;
+ uint32_t current_reg_id = reg_id_offset;
+ uint32_t internal_id;
+ int still_to_skip = 0;
+ char argument[64] = {0};
+ char value[64] = {0};
+ bool is_reg = false;
+ bool is_argument = false;
+ bool is_value = false;
+ GArray *reg_data;
+
+ char c;
+ char *c_ptr;
+
+ xml_attrib attribute_j;
+ const char *argument_j;
+ const char *value_j;
+
+ for (i = 0; i < size; i++) {
+ c = xml[i];
+ c_ptr = &c;
+
+ if (still_to_skip > 0) {
+ /* skip unwanted chars */
+ still_to_skip--;
+ continue;
+ }
+
+ if (strncmp(&xml[i], "<reg", 4) == 0) {
+ /* start of a register */
+ still_to_skip = 3;
+ is_reg = true;
+ reg_data = g_array_new(false, true, sizeof(xml_attrib));
+ } else if (is_reg) {
+ if (strncmp(&xml[i], "/>", 2) == 0) {
+ /* end of register info */
+ still_to_skip = 1;
+ is_reg = false;
+
+ /* create empty register */
+ mcd_reg_st my_register = (const struct mcd_reg_st){ 0 };
+
+ /* add found attribtues */
+ for (j = 0; j < reg_data->len; j++) {
+ attribute_j = g_array_index(reg_data, xml_attrib, j);
+
+ argument_j = attribute_j.argument;
+ value_j = attribute_j.value;
+
+ if (strcmp(argument_j, "name") == 0) {
+ strcpy(my_register.name, value_j);
+ } else if (strcmp(argument_j, "regnum") == 0) {
+ my_register.id = atoi(value_j);
+ } else if (strcmp(argument_j, "bitsize") == 0) {
+ my_register.bitsize = atoi(value_j);
+ } else if (strcmp(argument_j, "type") == 0) {
+ strcpy(my_register.type, value_j);
+ } else if (strcmp(argument_j, "group") == 0) {
+ strcpy(my_register.group, value_j);
+ }
+ }
+ /* add reg_type, internal_id and id*/
+ my_register.reg_type = reg_type;
+ my_register.internal_id = internal_id;
+ internal_id++;
+ if (!my_register.id) {
+ my_register.id = current_reg_id;
+ current_reg_id++;
+ } else {
+ /* set correct ID for the next register */
+ current_reg_id = my_register.id + 1;
+ }
+ /* store register */
+ g_array_append_vals(registers, (gconstpointer)&my_register, 1);
+ /* free memory */
+ g_array_free(reg_data, false);
+ } else {
+ /* store info for register */
+ switch (c) {
+ case ' ':
+ break;
+ case '=':
+ is_argument = false;
+ break;
+ case '"':
+ if (is_value) {
+ /* end of value reached */
+ is_value = false;
+ /* store arg-val combo */
+ xml_attrib current_attribute;
+ strcpy(current_attribute.argument, argument);
+ strcpy(current_attribute.value, value);
+ g_array_append_vals(reg_data,
+ (gconstpointer)¤t_attribute, 1);
+ memset(argument, 0, sizeof(argument));
+ memset(value, 0, sizeof(value));
+ } else {
+ /*start of value */
+ is_value = true;
+ }
+ break;
+ default:
+ if (is_argument) {
+ strncat(argument, c_ptr, 1);
+ } else if (is_value) {
+ strncat(value, c_ptr, 1);
+ } else {
+ is_argument = true;
+ strncat(argument, c_ptr, 1);
+ }
+ break;
+ }
+ }
+ }
+ }
+}
+
int int_cmp(gconstpointer a, gconstpointer b)
{
int int_a = *(int *)a;
--
2.34.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 13/20] mcdstub: added queries for memory spaces, register groups and registers
2023-11-07 13:03 [PATCH v3 00/20] first version of mcdstub Nicolas Eder
` (11 preceding siblings ...)
2023-11-07 13:03 ` [PATCH v3 12/20] mcdstub: missing parse_reg_xml function for parsing gdb register xml files added Nicolas Eder
@ 2023-11-07 13:03 ` Nicolas Eder
2023-11-07 13:03 ` [PATCH v3 14/20] mcdstub: missing handle_query_state function added Nicolas Eder
` (8 subsequent siblings)
21 siblings, 0 replies; 32+ messages in thread
From: Nicolas Eder @ 2023-11-07 13:03 UTC (permalink / raw)
To: qemu-devel
Cc: Nicolas Eder, Alex Bennée, Philippe Mathieu-Daudé,
Christian Boenig
---
include/mcdstub/mcdstub.h | 57 ++++++++++
mcdstub/mcdstub.c | 229 ++++++++++++++++++++++++++++++++++++++
2 files changed, 286 insertions(+)
diff --git a/include/mcdstub/mcdstub.h b/include/mcdstub/mcdstub.h
index 62394e7c12..85ca8b3b62 100644
--- a/include/mcdstub/mcdstub.h
+++ b/include/mcdstub/mcdstub.h
@@ -550,6 +550,63 @@ void handle_close_core(GArray *params, void *user_ctx);
*/
void handle_query_trigger(GArray *params, void *user_ctx);
+/**
+ * handle_query_reg_groups_f() - Handler for the first register group query.
+ *
+ * This function sends the first register group name and ID.
+ * @params: GArray with all TCP packet parameters.
+ */
+void handle_query_reg_groups_f(GArray *params, void *user_ctx);
+
+/**
+ * handle_query_reg_groups_c() - Handler for all consecutive register group
+ * queries.
+ *
+ * This function sends all consecutive register group names and IDs. It uses
+ * the query_index parameter to determine which register group is queried next.
+ * @params: GArray with all TCP packet parameters.
+ */
+void handle_query_reg_groups_c(GArray *params, void *user_ctx);
+
+/**
+ * handle_query_mem_spaces_f() Handler for the first memory space query.
+ *
+ * This function sends the first memory space name, ID, type and accessing
+ * options.
+ * @params: GArray with all TCP packet parameters.
+ */
+void handle_query_mem_spaces_f(GArray *params, void *user_ctx);
+
+/**
+ * handle_query_mem_spaces_c() - Handler for all consecutive memory space
+ * queries.
+ *
+ * This function sends all consecutive memory space names, IDs, types and
+ * accessing options.
+ * It uses the query_index parameter to determine
+ * which memory space is queried next.
+ * @params: GArray with all TCP packet parameters.
+ */
+void handle_query_mem_spaces_c(GArray *params, void *user_ctx);
+
+/**
+ * handle_query_regs_f() - Handler for the first register query.
+ *
+ * This function sends the first register with all its information.
+ * @params: GArray with all TCP packet parameters.
+ */
+void handle_query_regs_f(GArray *params, void *user_ctx);
+
+/**
+ * handle_query_regs_c() - Handler for all consecutive register queries.
+ *
+ * This function sends all consecutive registers with all their information.
+ * It uses the query_index parameter to determine
+ * which register is queried next.
+ * @params: GArray with all TCP packet parameters.
+ */
+void handle_query_regs_c(GArray *params, void *user_ctx);
+
/**
* handle_open_server() - Handler for opening the MCD server.
*
diff --git a/mcdstub/mcdstub.c b/mcdstub/mcdstub.c
index 3e87378b45..56854c4c76 100644
--- a/mcdstub/mcdstub.c
+++ b/mcdstub/mcdstub.c
@@ -117,6 +117,54 @@ void init_query_cmds_table(MCDCmdParseEntry *mcd_query_cmds_table)
mcd_query_cmds_table[cmd_number] = query_trigger;
cmd_number++;
+ MCDCmdParseEntry query_mem_spaces_f = {
+ .handler = handle_query_mem_spaces_f,
+ .cmd = QUERY_ARG_MEMORY QUERY_FIRST,
+ };
+ strcpy(query_mem_spaces_f.schema, (char[2]) { ARG_SCHEMA_CORENUM, '\0' });
+ mcd_query_cmds_table[cmd_number] = query_mem_spaces_f;
+ cmd_number++;
+
+ MCDCmdParseEntry query_mem_spaces_c = {
+ .handler = handle_query_mem_spaces_c,
+ .cmd = QUERY_ARG_MEMORY QUERY_CONSEQUTIVE,
+ };
+ strcpy(query_mem_spaces_c.schema, (char[2]) { ARG_SCHEMA_QRYHANDLE, '\0' });
+ mcd_query_cmds_table[cmd_number] = query_mem_spaces_c;
+ cmd_number++;
+
+ MCDCmdParseEntry query_reg_groups_f = {
+ .handler = handle_query_reg_groups_f,
+ .cmd = QUERY_ARG_REGGROUP QUERY_FIRST,
+ };
+ strcpy(query_reg_groups_f.schema, (char[2]) { ARG_SCHEMA_CORENUM, '\0' });
+ mcd_query_cmds_table[cmd_number] = query_reg_groups_f;
+ cmd_number++;
+
+ MCDCmdParseEntry query_reg_groups_c = {
+ .handler = handle_query_reg_groups_c,
+ .cmd = QUERY_ARG_REGGROUP QUERY_CONSEQUTIVE,
+ };
+ strcpy(query_reg_groups_c.schema, (char[2]) { ARG_SCHEMA_QRYHANDLE, '\0' });
+ mcd_query_cmds_table[cmd_number] = query_reg_groups_c;
+ cmd_number++;
+
+ MCDCmdParseEntry query_regs_f = {
+ .handler = handle_query_regs_f,
+ .cmd = QUERY_ARG_REG QUERY_FIRST,
+ };
+ strcpy(query_regs_f.schema, (char[2]) { ARG_SCHEMA_CORENUM, '\0' });
+ mcd_query_cmds_table[cmd_number] = query_regs_f;
+ cmd_number++;
+
+ MCDCmdParseEntry query_regs_c = {
+ .handler = handle_query_regs_c,
+ .cmd = QUERY_ARG_REG QUERY_CONSEQUTIVE,
+ };
+ strcpy(query_regs_c.schema, (char[2]) { ARG_SCHEMA_QRYHANDLE, '\0' });
+ mcd_query_cmds_table[cmd_number] = query_regs_c;
+ cmd_number++;
+
MCDCmdParseEntry query_state = {
.handler = handle_query_state,
.cmd = QUERY_ARG_STATE,
@@ -1237,3 +1285,184 @@ void handle_query_trigger(GArray *params, void *user_ctx)
TCP_ARGUMENT_ACTION, trigger.action);
mcd_put_strbuf();
}
+
+void handle_query_mem_spaces_f(GArray *params, void *user_ctx)
+{
+ /* 1. get correct memspaces and set the query_cpu */
+ uint32_t cpu_id = get_param(params, 0)->cpu_id;
+ mcdserver_state.query_cpu_id = cpu_id;
+ GArray *memspaces = g_list_nth_data(mcdserver_state.all_memspaces, cpu_id);
+
+ /* 2. check length */
+ int nb_groups = memspaces->len;
+ if (nb_groups == 1) {
+ /* indicates this is the last packet */
+ g_string_printf(mcdserver_state.str_buf, "0%s", QUERY_END_INDEX);
+ } else {
+ g_string_printf(mcdserver_state.str_buf, "1%s", QUERY_END_INDEX);
+ }
+
+ /* 3. send data */
+ mcd_mem_space_st space = g_array_index(memspaces, mcd_mem_space_st, 0);
+ g_string_append_printf(mcdserver_state.str_buf,
+ "%s=%s.%s=%u.%s=%u.%s=%u.%s=%u.%s=%u.%s=%ld.%s=%ld.%s=%u.",
+ TCP_ARGUMENT_NAME, space.name,
+ TCP_ARGUMENT_ID, space.id,
+ TCP_ARGUMENT_TYPE, space.type,
+ TCP_ARGUMENT_BITS_PER_MAU, space.bits_per_mau,
+ TCP_ARGUMENT_INVARIANCE, space.invariance,
+ TCP_ARGUMENT_ENDIAN, space.endian,
+ TCP_ARGUMENT_MIN, space.min_addr,
+ TCP_ARGUMENT_MAX, space.max_addr,
+ TCP_ARGUMENT_SUPPORTED_ACCESS_OPTIONS, space.supported_access_options);
+ mcd_put_strbuf();
+}
+
+void handle_query_mem_spaces_c(GArray *params, void *user_ctx)
+{
+ /*
+ * this funcitons send all mem spaces except for the first
+ * 1. get parameter and memspace
+ */
+ uint32_t query_index = get_param(params, 0)->query_handle;
+ uint32_t cpu_id = mcdserver_state.query_cpu_id;
+ GArray *memspaces = g_list_nth_data(mcdserver_state.all_memspaces, cpu_id);
+
+ /* 2. check weather this was the last mem space */
+ int nb_groups = memspaces->len;
+ if (query_index + 1 == nb_groups) {
+ /* indicates this is the last packet */
+ g_string_printf(mcdserver_state.str_buf, "0%s", QUERY_END_INDEX);
+ } else {
+ g_string_printf(mcdserver_state.str_buf, "%u!", query_index + 1);
+ }
+
+ /* 3. send the correct memspace */
+ mcd_mem_space_st space = g_array_index(memspaces,
+ mcd_mem_space_st, query_index);
+ g_string_append_printf(mcdserver_state.str_buf,
+ "%s=%s.%s=%u.%s=%u.%s=%u.%s=%u.%s=%u.%s=%ld.%s=%ld.%s=%u.",
+ TCP_ARGUMENT_NAME, space.name,
+ TCP_ARGUMENT_ID, space.id,
+ TCP_ARGUMENT_TYPE, space.type,
+ TCP_ARGUMENT_BITS_PER_MAU, space.bits_per_mau,
+ TCP_ARGUMENT_INVARIANCE, space.invariance,
+ TCP_ARGUMENT_ENDIAN, space.endian,
+ TCP_ARGUMENT_MIN, space.min_addr,
+ TCP_ARGUMENT_MAX, space.max_addr,
+ TCP_ARGUMENT_SUPPORTED_ACCESS_OPTIONS, space.supported_access_options);
+ mcd_put_strbuf();
+}
+
+void handle_query_reg_groups_f(GArray *params, void *user_ctx)
+{
+ /* 1. get correct reggroups and set the query_cpu */
+ uint32_t cpu_id = get_param(params, 0)->cpu_id;
+ mcdserver_state.query_cpu_id = cpu_id;
+ GArray *reggroups = g_list_nth_data(mcdserver_state.all_reggroups, cpu_id);
+
+ /* 2. check length */
+ int nb_groups = reggroups->len;
+ if (nb_groups == 1) {
+ /* indicates this is the last packet */
+ g_string_printf(mcdserver_state.str_buf, "0%s", QUERY_END_INDEX);
+ } else {
+ g_string_printf(mcdserver_state.str_buf, "1%s", QUERY_END_INDEX);
+ }
+ /* 3. send data */
+ mcd_reg_group_st group = g_array_index(reggroups, mcd_reg_group_st, 0);
+ g_string_append_printf(mcdserver_state.str_buf, "%s=%u.%s=%s.",
+ TCP_ARGUMENT_ID, group.id, TCP_ARGUMENT_NAME, group.name);
+ mcd_put_strbuf();
+}
+
+void handle_query_reg_groups_c(GArray *params, void *user_ctx)
+{
+ /*
+ * this funcitons send all reg groups except for the first
+ * 1. get parameter and memspace
+ */
+ uint32_t query_index = get_param(params, 0)->query_handle;
+ uint32_t cpu_id = mcdserver_state.query_cpu_id;
+ GArray *reggroups = g_list_nth_data(mcdserver_state.all_reggroups, cpu_id);
+
+ /* 2. check weather this was the last reg group */
+ int nb_groups = reggroups->len;
+ if (query_index + 1 == nb_groups) {
+ /* indicates this is the last packet */
+ g_string_printf(mcdserver_state.str_buf, "0%s", QUERY_END_INDEX);
+ } else {
+ g_string_printf(mcdserver_state.str_buf, "%u!", query_index + 1);
+ }
+
+ /* 3. send the correct reggroup */
+ mcd_reg_group_st group = g_array_index(reggroups, mcd_reg_group_st,
+ query_index);
+ g_string_append_printf(mcdserver_state.str_buf, "%s=%u.%s=%s.",
+ TCP_ARGUMENT_ID, group.id, TCP_ARGUMENT_NAME, group.name);
+ mcd_put_strbuf();
+}
+
+void handle_query_regs_f(GArray *params, void *user_ctx)
+{
+ /* 1. get correct registers and set the query_cpu */
+ uint32_t cpu_id = get_param(params, 0)->cpu_id;
+ mcdserver_state.query_cpu_id = cpu_id;
+ GArray *registers = g_list_nth_data(mcdserver_state.all_registers, cpu_id);
+
+ /* 2. check length */
+ int nb_regs = registers->len;
+ if (nb_regs == 1) {
+ /* indicates this is the last packet */
+ g_string_printf(mcdserver_state.str_buf, "0%s", QUERY_END_INDEX);
+ } else {
+ g_string_printf(mcdserver_state.str_buf, "1%s", QUERY_END_INDEX);
+ }
+ /* 3. send data */
+ mcd_reg_st my_register = g_array_index(registers, mcd_reg_st, 0);
+ g_string_append_printf(mcdserver_state.str_buf,
+ "%s=%u.%s=%s.%s=%u.%s=%u.%s=%u.%s=%u.%s=%u.%s=%u.",
+ TCP_ARGUMENT_ID, my_register.id,
+ TCP_ARGUMENT_NAME, my_register.name,
+ TCP_ARGUMENT_SIZE, my_register.bitsize,
+ TCP_ARGUMENT_REGGROUPID, my_register.mcd_reg_group_id,
+ TCP_ARGUMENT_MEMSPACEID, my_register.mcd_mem_space_id,
+ TCP_ARGUMENT_TYPE, my_register.mcd_reg_type,
+ TCP_ARGUMENT_THREAD, my_register.mcd_hw_thread_id,
+ TCP_ARGUMENT_OPCODE, my_register.opcode);
+ mcd_put_strbuf();
+}
+
+void handle_query_regs_c(GArray *params, void *user_ctx)
+{
+ /*
+ * this funcitons send all regs except for the first
+ * 1. get parameter and registers
+ */
+ uint32_t query_index = get_param(params, 0)->query_handle;
+ uint32_t cpu_id = mcdserver_state.query_cpu_id;
+ GArray *registers = g_list_nth_data(mcdserver_state.all_registers, cpu_id);
+
+ /* 2. check weather this was the last register */
+ int nb_regs = registers->len;
+ if (query_index + 1 == nb_regs) {
+ /* indicates this is the last packet */
+ g_string_printf(mcdserver_state.str_buf, "0%s", QUERY_END_INDEX);
+ } else {
+ g_string_printf(mcdserver_state.str_buf, "%u!", query_index + 1);
+ }
+
+ /* 3. send the correct register */
+ mcd_reg_st my_register = g_array_index(registers, mcd_reg_st, query_index);
+ g_string_append_printf(mcdserver_state.str_buf,
+ "%s=%u.%s=%s.%s=%u.%s=%u.%s=%u.%s=%u.%s=%u.%s=%u.",
+ TCP_ARGUMENT_ID, my_register.id,
+ TCP_ARGUMENT_NAME, my_register.name,
+ TCP_ARGUMENT_SIZE, my_register.bitsize,
+ TCP_ARGUMENT_REGGROUPID, my_register.mcd_reg_group_id,
+ TCP_ARGUMENT_MEMSPACEID, my_register.mcd_mem_space_id,
+ TCP_ARGUMENT_TYPE, my_register.mcd_reg_type,
+ TCP_ARGUMENT_THREAD, my_register.mcd_hw_thread_id,
+ TCP_ARGUMENT_OPCODE, my_register.opcode);
+ mcd_put_strbuf();
+}
--
2.34.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 14/20] mcdstub: missing handle_query_state function added
2023-11-07 13:03 [PATCH v3 00/20] first version of mcdstub Nicolas Eder
` (12 preceding siblings ...)
2023-11-07 13:03 ` [PATCH v3 13/20] mcdstub: added queries for memory spaces, register groups and registers Nicolas Eder
@ 2023-11-07 13:03 ` Nicolas Eder
2023-11-07 13:03 ` [PATCH v3 15/20] mcdstub: added go, break and step functionality and all corresponding functions Nicolas Eder
` (7 subsequent siblings)
21 siblings, 0 replies; 32+ messages in thread
From: Nicolas Eder @ 2023-11-07 13:03 UTC (permalink / raw)
To: qemu-devel
Cc: Nicolas Eder, Alex Bennée, Philippe Mathieu-Daudé,
Christian Boenig
---
mcdstub/mcdstub.c | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/mcdstub/mcdstub.c b/mcdstub/mcdstub.c
index 56854c4c76..cd2f5db8e4 100644
--- a/mcdstub/mcdstub.c
+++ b/mcdstub/mcdstub.c
@@ -1466,3 +1466,32 @@ void handle_query_regs_c(GArray *params, void *user_ctx)
TCP_ARGUMENT_OPCODE, my_register.opcode);
mcd_put_strbuf();
}
+
+void handle_query_state(GArray *params, void *user_ctx)
+{
+ /*
+ * TODO: multicore support
+ * get state info
+ */
+ mcd_cpu_state_st state_info = mcdserver_state.cpu_state;
+ /* TODO: add event information */
+ uint32_t event = 0;
+ /* send data */
+ g_string_printf(mcdserver_state.str_buf,
+ "%s=%s.%s=%u.%s=%u.%s=%u.%s=%lu.%s=%s.%s=%s.",
+ TCP_ARGUMENT_STATE, state_info.state,
+ TCP_ARGUMENT_EVENT, event, TCP_ARGUMENT_THREAD, 0,
+ TCP_ARGUMENT_TYPE, state_info.bp_type,
+ TCP_ARGUMENT_ADDRESS, state_info.bp_address,
+ TCP_ARGUMENT_STOP_STRING, state_info.stop_str,
+ TCP_ARGUMENT_INFO_STRING, state_info.info_str);
+ mcd_put_strbuf();
+
+ /* reset debug info after first query */
+ if (strcmp(state_info.state, CORE_STATE_DEBUG) == 0) {
+ mcdserver_state.cpu_state.stop_str = "";
+ mcdserver_state.cpu_state.info_str = "";
+ mcdserver_state.cpu_state.bp_type = 0;
+ mcdserver_state.cpu_state.bp_address = 0;
+ }
+}
--
2.34.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 15/20] mcdstub: added go, break and step functionality and all corresponding functions
2023-11-07 13:03 [PATCH v3 00/20] first version of mcdstub Nicolas Eder
` (13 preceding siblings ...)
2023-11-07 13:03 ` [PATCH v3 14/20] mcdstub: missing handle_query_state function added Nicolas Eder
@ 2023-11-07 13:03 ` Nicolas Eder
2023-11-07 13:03 ` [PATCH v3 16/20] mcdstub: function construct for resets added Nicolas Eder
` (6 subsequent siblings)
21 siblings, 0 replies; 32+ messages in thread
From: Nicolas Eder @ 2023-11-07 13:03 UTC (permalink / raw)
To: qemu-devel
Cc: Nicolas Eder, Alex Bennée, Philippe Mathieu-Daudé,
Christian Boenig
---
include/mcdstub/mcdstub.h | 53 ++++++++++++++++++++
mcdstub/mcdstub.c | 101 ++++++++++++++++++++++++++++++++++++++
2 files changed, 154 insertions(+)
diff --git a/include/mcdstub/mcdstub.h b/include/mcdstub/mcdstub.h
index 85ca8b3b62..0375cf7311 100644
--- a/include/mcdstub/mcdstub.h
+++ b/include/mcdstub/mcdstub.h
@@ -439,6 +439,33 @@ int process_string_cmd(void *user_ctx, const char *data,
*/
int cmd_parse_params(const char *data, const char *schema, GArray *params);
+/**
+ * handle_vm_start() - Handler for the VM start TCP packet.
+ *
+ * Evaluates whether all cores or just a perticular core should get started and
+ * calls :c:func:`mcd_vm_start` or :c:func:`mcd_cpu_start` respectively.
+ * @params: GArray with all TCP packet parameters.
+ */
+void handle_vm_start(GArray *params, void *user_ctx);
+
+/**
+ * handle_vm_step() - Handler for the VM step TCP packet.
+ *
+ * Calls :c:func:`mcd_cpu_sstep` for the CPU which sould be stepped.
+ * Stepping all CPUs is currently not supported.
+ * @params: GArray with all TCP packet parameters.
+ */
+void handle_vm_step(GArray *params, void *user_ctx);
+
+/**
+ * handle_vm_stop() - Handler for the VM stop TCP packet.
+ *
+ * Always calls :c:func:`mcd_vm_stop` and stops all cores. Stopping individual
+ * cores is currently not supported.
+ * @params: GArray with all TCP packet parameters.
+ */
+void handle_vm_stop(GArray *params, void *user_ctx);
+
/**
* handle_gen_query() - Handler for all TCP query packets.
*
@@ -550,6 +577,32 @@ void handle_close_core(GArray *params, void *user_ctx);
*/
void handle_query_trigger(GArray *params, void *user_ctx);
+/**
+ * mcd_vm_start() - Starts all CPUs with the vm_start function.
+ */
+void mcd_vm_start(void);
+
+/**
+ * mcd_cpu_start() - Starts the selected CPU with the cpu_resume function.
+ *
+ * @cpu: The CPU about to be started.
+ */
+void mcd_cpu_start(CPUState *cpu);
+
+/**
+ * mcd_cpu_sstep() - Performes a step on the selected CPU.
+ *
+ * This function first sets the correct single step flags for the CPU with
+ * cpu_single_step and then starts the CPU with cpu_resume.
+ * @cpu: The CPU about to be stepped.
+ */
+int mcd_cpu_sstep(CPUState *cpu);
+
+/**
+ * mcd_vm_stop() - Brings all CPUs in debug state with the vm_stop function.
+ */
+void mcd_vm_stop(void);
+
/**
* handle_query_reg_groups_f() - Handler for the first register group query.
*
diff --git a/mcdstub/mcdstub.c b/mcdstub/mcdstub.c
index cd2f5db8e4..6313459bac 100644
--- a/mcdstub/mcdstub.c
+++ b/mcdstub/mcdstub.c
@@ -432,6 +432,37 @@ int mcd_handle_packet(const char *line_buf)
cmd_parser = &open_server_cmd_desc;
}
break;
+ case TCP_CHAR_GO:
+ {
+ static MCDCmdParseEntry go_cmd_desc = {
+ .handler = handle_vm_start,
+ };
+ go_cmd_desc.cmd = (char[2]) { TCP_CHAR_GO, '\0' };
+ strcpy(go_cmd_desc.schema,
+ (char[3]) { ARG_SCHEMA_INT, ARG_SCHEMA_CORENUM, '\0' });
+ cmd_parser = &go_cmd_desc;
+ }
+ break;
+ case TCP_CHAR_STEP:
+ {
+ static MCDCmdParseEntry step_cmd_desc = {
+ .handler = handle_vm_step,
+ };
+ step_cmd_desc.cmd = (char[2]) { TCP_CHAR_STEP, '\0' };
+ strcpy(step_cmd_desc.schema,
+ (char[3]) { ARG_SCHEMA_INT, ARG_SCHEMA_CORENUM, '\0' });
+ cmd_parser = &step_cmd_desc;
+ }
+ break;
+ case TCP_CHAR_BREAK:
+ {
+ static MCDCmdParseEntry break_cmd_desc = {
+ .handler = handle_vm_stop,
+ };
+ break_cmd_desc.cmd = (char[2]) { TCP_CHAR_BREAK, '\0' };
+ cmd_parser = &break_cmd_desc;
+ }
+ break;
case TCP_CHAR_KILLQEMU:
/* kill qemu completely */
error_report("QEMU: Terminated via MCDstub");
@@ -494,6 +525,40 @@ int mcd_handle_packet(const char *line_buf)
return RS_IDLE;
}
+void handle_vm_start(GArray *params, void *user_ctx)
+{
+ uint32_t global = get_param(params, 0)->data_uint32_t;
+ if (global == 1) {
+ mcd_vm_start();
+ } else{
+ uint32_t cpu_id = get_param(params, 1)->cpu_id;
+ CPUState *cpu = mcd_get_cpu(cpu_id);
+ mcd_cpu_start(cpu);
+ }
+}
+
+void handle_vm_step(GArray *params, void *user_ctx)
+{
+ uint32_t global = get_param(params, 0)->data_uint32_t;
+ if (global == 1) {
+ /* TODO: add multicore support */
+ } else{
+ uint32_t cpu_id = get_param(params, 1)->cpu_id;
+ CPUState *cpu = mcd_get_cpu(cpu_id);
+ int return_value = mcd_cpu_sstep(cpu);
+ if (return_value != 0) {
+ g_assert_not_reached();
+ }
+ }
+}
+
+
+void handle_vm_stop(GArray *params, void *user_ctx)
+{
+ /* TODO: add core dependant break option */
+ mcd_vm_stop();
+}
+
void handle_gen_query(GArray *params, void *user_ctx)
{
if (!params->len) {
@@ -1286,6 +1351,42 @@ void handle_query_trigger(GArray *params, void *user_ctx)
mcd_put_strbuf();
}
+void mcd_vm_start(void)
+{
+ if (!runstate_needs_reset() && !runstate_is_running()) {
+ vm_start();
+ }
+}
+
+void mcd_cpu_start(CPUState *cpu)
+{
+ if (!runstate_needs_reset() && !runstate_is_running() &&
+ !vm_prepare_start(false)) {
+ mcdserver_state.c_cpu = cpu;
+ qemu_clock_enable(QEMU_CLOCK_VIRTUAL, true);
+ cpu_resume(cpu);
+ }
+}
+
+int mcd_cpu_sstep(CPUState *cpu)
+{
+ mcdserver_state.c_cpu = cpu;
+ cpu_single_step(cpu, mcdserver_state.sstep_flags);
+ if (!runstate_needs_reset() && !runstate_is_running() &&
+ !vm_prepare_start(true)) {
+ qemu_clock_enable(QEMU_CLOCK_VIRTUAL, true);
+ cpu_resume(cpu);
+ }
+ return 0;
+}
+
+void mcd_vm_stop(void)
+{
+ if (runstate_is_running()) {
+ vm_stop(RUN_STATE_DEBUG);
+ }
+}
+
void handle_query_mem_spaces_f(GArray *params, void *user_ctx)
{
/* 1. get correct memspaces and set the query_cpu */
--
2.34.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 16/20] mcdstub: function construct for resets added
2023-11-07 13:03 [PATCH v3 00/20] first version of mcdstub Nicolas Eder
` (14 preceding siblings ...)
2023-11-07 13:03 ` [PATCH v3 15/20] mcdstub: added go, break and step functionality and all corresponding functions Nicolas Eder
@ 2023-11-07 13:03 ` Nicolas Eder
2023-11-07 13:03 ` [PATCH v3 17/20] mcdstub: reading/writing registers added Nicolas Eder
` (5 subsequent siblings)
21 siblings, 0 replies; 32+ messages in thread
From: Nicolas Eder @ 2023-11-07 13:03 UTC (permalink / raw)
To: qemu-devel
Cc: Nicolas Eder, Alex Bennée, Philippe Mathieu-Daudé,
Christian Boenig
---
include/mcdstub/mcdstub.h | 8 ++++++++
mcdstub/mcdstub.c | 18 ++++++++++++++++++
2 files changed, 26 insertions(+)
diff --git a/include/mcdstub/mcdstub.h b/include/mcdstub/mcdstub.h
index 0375cf7311..000d832a39 100644
--- a/include/mcdstub/mcdstub.h
+++ b/include/mcdstub/mcdstub.h
@@ -672,6 +672,14 @@ void handle_query_regs_c(GArray *params, void *user_ctx);
*/
void handle_open_server(GArray *params, void *user_ctx);
+/**
+ * handle_reset() - Handler for performing resets.
+ *
+ * This function is currently not in use.
+ * @params: GArray with all TCP packet parameters.
+ */
+void handle_reset(GArray *params, void *user_ctx);
+
/**
* handle_query_state() - Handler for the state query.
*
diff --git a/mcdstub/mcdstub.c b/mcdstub/mcdstub.c
index 6313459bac..1a10bc6c98 100644
--- a/mcdstub/mcdstub.c
+++ b/mcdstub/mcdstub.c
@@ -511,6 +511,16 @@ int mcd_handle_packet(const char *line_buf)
cmd_parser = &close_core_cmd_desc;
}
break;
+ case TCP_CHAR_RESET:
+ {
+ static MCDCmdParseEntry reset_cmd_desc = {
+ .handler = handle_reset,
+ };
+ reset_cmd_desc.cmd = (char[2]) { TCP_CHAR_RESET, '\0' };
+ strcpy(reset_cmd_desc.schema, (char[2]) { ARG_SCHEMA_INT, '\0' });
+ cmd_parser = &reset_cmd_desc;
+ }
+ break;
default:
/* command not supported */
mcd_put_packet("");
@@ -1568,6 +1578,14 @@ void handle_query_regs_c(GArray *params, void *user_ctx)
mcd_put_strbuf();
}
+void handle_reset(GArray *params, void *user_ctx)
+{
+ /*
+ * int reset_id = get_param(params, 0)->data_int;
+ * TODO: implement resets
+ */
+}
+
void handle_query_state(GArray *params, void *user_ctx)
{
/*
--
2.34.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 17/20] mcdstub: reading/writing registers added
2023-11-07 13:03 [PATCH v3 00/20] first version of mcdstub Nicolas Eder
` (15 preceding siblings ...)
2023-11-07 13:03 ` [PATCH v3 16/20] mcdstub: function construct for resets added Nicolas Eder
@ 2023-11-07 13:03 ` Nicolas Eder
2023-11-07 13:03 ` [PATCH v3 18/20] mcdstub: read/write to memory added: This also includes various helper functions in the QEMU memory code Nicolas Eder
` (4 subsequent siblings)
21 siblings, 0 replies; 32+ messages in thread
From: Nicolas Eder @ 2023-11-07 13:03 UTC (permalink / raw)
To: qemu-devel
Cc: Nicolas Eder, Alex Bennée, Philippe Mathieu-Daudé,
Christian Boenig
---
include/mcdstub/mcdstub.h | 62 +++++++++++++++++++++
mcdstub/mcdstub.c | 113 ++++++++++++++++++++++++++++++++++++++
2 files changed, 175 insertions(+)
diff --git a/include/mcdstub/mcdstub.h b/include/mcdstub/mcdstub.h
index 000d832a39..6b2249f8fb 100644
--- a/include/mcdstub/mcdstub.h
+++ b/include/mcdstub/mcdstub.h
@@ -690,6 +690,49 @@ void handle_reset(GArray *params, void *user_ctx);
*/
void handle_query_state(GArray *params, void *user_ctx);
+/**
+ * handle_read_register() - Handler for reading a register.
+ *
+ * This function calls :c:func:`mcd_read_register` to read a register. The
+ * register data gets stored in the mem_buf byte array. The data then gets
+ * converted into a hex string with :c:func:`mcd_memtohex` and then send.
+ * @params: GArray with all TCP packet parameters.
+ */
+void handle_read_register(GArray *params, void *user_ctx);
+
+/**
+ * handle_write_register() - Handler for writing a register.
+ *
+ * This function converts the incoming hex string data into a byte array with
+ * :c:func:`mcd_hextomem`. Then it calls :c:func:`mcd_write_register` to write
+ * to the register.
+ * @params: GArray with all TCP packet parameters.
+ */
+void handle_write_register(GArray *params, void *user_ctx);
+/**
+ * mcd_read_register() - Reads a registers data and stores it into the buf.
+ *
+ * This function collects the register type and internal ID
+ * (depending on the XML file). Then it calls the architecture specific
+ * read function. For ARM this is :c:func:`arm_mcd_read_register`.
+ * @cpu: CPU to which the register belongs.
+ * @buf: Byte array with register data.
+ * @reg: General ID of the register.
+ */
+int mcd_read_register(CPUState *cpu, GByteArray *buf, int reg);
+
+/**
+ * mcd_write_register() - Writes data from the buf to a register.
+ *
+ * This function collects the register type and internal ID
+ * (depending on the XML file). Then it calls the architecture specific
+ * write function. For ARM this is :c:func:`arm_mcd_write_register`.
+ * @cpu: CPU to which the register belongs.
+ * @mem_buf: Byte array with register data.
+ * @reg: General ID of the register.
+ */
+int mcd_write_register(CPUState *cpu, uint8_t *mem_buf, int reg);
+
/* helpers */
/**
@@ -699,6 +742,25 @@ void handle_query_state(GArray *params, void *user_ctx);
* @b: Pointer to integer b.
*/
int int_cmp(gconstpointer a, gconstpointer b);
+
+/**
+ * mcd_memtohex() - Converts a byte array into a hex string.
+ *
+ * @mem: Pointer to byte array.
+ * @buf: Pointer to hex string.
+ * @len: Number of bytes.
+ */
+void mcd_memtohex(GString *buf, const uint8_t *mem, int len);
+
+/**
+ * mcd_hextomem() - Converts a hex string into a byte array.
+ *
+ * @mem: Pointer to byte array.
+ * @buf: Pointer to hex string.
+ * @len: Number of bytes.
+ */
+void mcd_hextomem(GByteArray *mem, const char *buf, int len);
+
/**
* atouint64_t() - Converts a string into a unsigned 64 bit integer.
*
diff --git a/mcdstub/mcdstub.c b/mcdstub/mcdstub.c
index 1a10bc6c98..018900e914 100644
--- a/mcdstub/mcdstub.c
+++ b/mcdstub/mcdstub.c
@@ -521,6 +521,30 @@ int mcd_handle_packet(const char *line_buf)
cmd_parser = &reset_cmd_desc;
}
break;
+ case TCP_CHAR_READ_REGISTER:
+ {
+ static MCDCmdParseEntry read_reg_cmd_desc = {
+ .handler = handle_read_register,
+ };
+ read_reg_cmd_desc.cmd = (char[2]) { TCP_CHAR_READ_REGISTER, '\0' };
+ strcpy(read_reg_cmd_desc.schema,
+ (char[3]) { ARG_SCHEMA_CORENUM, ARG_SCHEMA_UINT64_T, '\0' });
+ cmd_parser = &read_reg_cmd_desc;
+ }
+ break;
+ case TCP_CHAR_WRITE_REGISTER:
+ {
+ static MCDCmdParseEntry write_reg_cmd_desc = {
+ .handler = handle_write_register,
+ };
+ write_reg_cmd_desc.cmd =
+ (char[2]) { TCP_CHAR_WRITE_REGISTER, '\0' };
+ strcpy(write_reg_cmd_desc.schema,
+ (char[5]) { ARG_SCHEMA_CORENUM, ARG_SCHEMA_UINT64_T,
+ ARG_SCHEMA_INT, ARG_SCHEMA_HEXDATA, '\0' });
+ cmd_parser = &write_reg_cmd_desc;
+ }
+ break;
default:
/* command not supported */
mcd_put_packet("");
@@ -1614,3 +1638,92 @@ void handle_query_state(GArray *params, void *user_ctx)
mcdserver_state.cpu_state.bp_address = 0;
}
}
+
+int mcd_read_register(CPUState *cpu, GByteArray *buf, int reg)
+{
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+ CPUArchState *env = cpu_env(cpu);
+ GDBRegisterState *r;
+
+ if (reg < cc->gdb_num_core_regs) {
+ return cc->gdb_read_register(cpu, buf, reg);
+ }
+
+ for (guint i = 0; i < cpu->gdb_regs->len; i++) {
+ r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
+ if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) {
+ return r->get_reg(env, buf, reg - r->base_reg);
+ }
+ }
+ return 0;
+}
+
+int mcd_write_register(CPUState *cpu, uint8_t *mem_buf, int reg)
+{
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+ CPUArchState *env = cpu_env(cpu);
+ GDBRegisterState *r;
+
+ if (reg < cc->gdb_num_core_regs) {
+ return cc->gdb_write_register(cpu, mem_buf, reg);
+ }
+
+ for (guint i = 0; i < cpu->gdb_regs->len; i++) {
+ r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i);
+ if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) {
+ return r->set_reg(env, mem_buf, reg - r->base_reg);
+ }
+ }
+ return 0;
+}
+
+void mcd_memtohex(GString *buf, const uint8_t *mem, int len)
+{
+ int i, c;
+ for (i = 0; i < len; i++) {
+ c = mem[i];
+ g_string_append_c(buf, tohex(c >> 4));
+ g_string_append_c(buf, tohex(c & 0xf));
+ }
+ g_string_append_c(buf, '\0');
+}
+
+void mcd_hextomem(GByteArray *mem, const char *buf, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ guint8 byte = fromhex(buf[0]) << 4 | fromhex(buf[1]);
+ g_byte_array_append(mem, &byte, 1);
+ buf += 2;
+ }
+}
+
+void handle_read_register(GArray *params, void *user_ctx)
+{
+ uint32_t cpu_id = get_param(params, 0)->cpu_id;
+ uint64_t reg_num = get_param(params, 1)->data_uint64_t;
+ int reg_size;
+
+ CPUState *cpu = mcd_get_cpu(cpu_id);
+ reg_size = mcd_read_register(cpu, mcdserver_state.mem_buf, reg_num);
+ mcd_memtohex(mcdserver_state.str_buf,
+ mcdserver_state.mem_buf->data, reg_size);
+ mcd_put_strbuf();
+}
+
+void handle_write_register(GArray *params, void *user_ctx)
+{
+ uint32_t cpu_id = get_param(params, 0)->cpu_id;
+ uint64_t reg_num = get_param(params, 1)->data_uint64_t;
+ uint32_t reg_size = get_param(params, 2)->data_uint32_t;
+
+ CPUState *cpu = mcd_get_cpu(cpu_id);
+ mcd_hextomem(mcdserver_state.mem_buf,
+ mcdserver_state.str_buf->str, reg_size);
+ if (mcd_write_register(cpu, mcdserver_state.mem_buf->data, reg_num) == 0) {
+ mcd_put_packet(TCP_EXECUTION_ERROR);
+ } else {
+ mcd_put_packet(TCP_EXECUTION_SUCCESS);
+ }
+}
--
2.34.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 18/20] mcdstub: read/write to memory added: This also includes various helper functions in the QEMU memory code
2023-11-07 13:03 [PATCH v3 00/20] first version of mcdstub Nicolas Eder
` (16 preceding siblings ...)
2023-11-07 13:03 ` [PATCH v3 17/20] mcdstub: reading/writing registers added Nicolas Eder
@ 2023-11-07 13:03 ` Nicolas Eder
2023-11-07 13:03 ` [PATCH v3 19/20] mcdstub: break/watchpoints added Nicolas Eder
` (3 subsequent siblings)
21 siblings, 0 replies; 32+ messages in thread
From: Nicolas Eder @ 2023-11-07 13:03 UTC (permalink / raw)
To: qemu-devel
Cc: Nicolas Eder, Alex Bennée, Philippe Mathieu-Daudé,
Christian Boenig
---
include/exec/cpu-common.h | 2 +
include/exec/memory.h | 9 ++
include/mcdstub/arm_mcdstub.h | 16 ++++
include/mcdstub/mcdstub.h | 69 +++++++++++++++
mcdstub/mcdstub.c | 153 ++++++++++++++++++++++++++++++++++
system/memory.c | 11 +++
system/physmem.c | 26 ++++++
target/arm/mcdstub.c | 26 ++++++
8 files changed, 312 insertions(+)
diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h
index 30c376a4de..86b3176de5 100644
--- a/include/exec/cpu-common.h
+++ b/include/exec/cpu-common.h
@@ -185,6 +185,8 @@ int ram_block_discard_range(RAMBlock *rb, uint64_t start, size_t length);
int cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
void *ptr, size_t len, bool is_write);
+int cpu_memory_get_physical_address(CPUState *cpu, vaddr *addr, size_t *len);
+
/* vl.c */
void list_cpus(void);
diff --git a/include/exec/memory.h b/include/exec/memory.h
index 9087d02769..ff8642d883 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -3110,6 +3110,15 @@ bool ram_block_discard_is_disabled(void);
*/
bool ram_block_discard_is_required(void);
+/*
+ * mcd_find_address_space() - Find the address spaces with the corresponding
+ * name.
+ *
+ * Currently only used by the mcd debugger.
+ * @as_name: Name to look for.
+ */
+AddressSpace *mcd_find_address_space(const char *as_name);
+
#endif
#endif
diff --git a/include/mcdstub/arm_mcdstub.h b/include/mcdstub/arm_mcdstub.h
index c71f6c3356..fb9abaaf7d 100644
--- a/include/mcdstub/arm_mcdstub.h
+++ b/include/mcdstub/arm_mcdstub.h
@@ -87,5 +87,21 @@ int arm_mcd_parse_general_xml_files(CPUState *cpu, GArray* reggroups,
* @cpu: The CPU state.
*/
int arm_mcd_get_additional_register_info(GArray *reggroups, GArray *registers,
+ CPUState *cpu);
+
+/**
+ * arm_mcd_get_address_space() - Returnes the correct QEMU address space name
+ * @cpu_id: Correct CPU ID
+ * @mem_space: Desired mcd specific memory space.
+ */
+AddressSpace *arm_mcd_get_address_space(uint32_t cpu_id,
+ mcd_mem_space_st mem_space);
+
+/**
+ * arm_mcd_get_memtxattrs() - Returnes the correct QEMU address space access
+ * attributes
+ * @mem_space: Desired mcd specific memory space.
+ */
+MemTxAttrs arm_mcd_get_memtxattrs(mcd_mem_space_st mem_space);
#endif /* ARM_MCDSTUB_H */
diff --git a/include/mcdstub/mcdstub.h b/include/mcdstub/mcdstub.h
index 6b2249f8fb..c55d52d2a7 100644
--- a/include/mcdstub/mcdstub.h
+++ b/include/mcdstub/mcdstub.h
@@ -709,6 +709,31 @@ void handle_read_register(GArray *params, void *user_ctx);
* @params: GArray with all TCP packet parameters.
*/
void handle_write_register(GArray *params, void *user_ctx);
+
+/**
+ * handle_read_memory() - Handler for reading memory.
+ *
+ * First, this function checks whether reading a secure memory space is
+ * requested and changes the access mode with :c:func:`arm_mcd_set_scr`.
+ * Then it calls :c:func:`mcd_read_memory` to read memory. The collected
+ * data gets stored in the mem_buf byte array. The data then gets converted
+ * into a hex string with :c:func:`mcd_memtohex` and then send.
+ * @params: GArray with all TCP packet parameters.
+ */
+void handle_read_memory(GArray *params, void *user_ctx);
+
+/**
+ * handle_write_memory() - Handler for writing memory.
+ *
+ * First, this function checks whether reading a secure memory space is
+ * requested and changes the access mode with :c:func:`arm_mcd_set_scr`.
+ * Then it converts the incoming hex string data into a byte array with
+ * :c:func:`mcd_hextomem`. Then it calls :c:func:`mcd_write_memory` to write to
+ * the register.
+ * @params: GArray with all TCP packet parameters.
+ */
+void handle_write_memory(GArray *params, void *user_ctx);
+
/**
* mcd_read_register() - Reads a registers data and stores it into the buf.
*
@@ -733,6 +758,50 @@ int mcd_read_register(CPUState *cpu, GByteArray *buf, int reg);
*/
int mcd_write_register(CPUState *cpu, uint8_t *mem_buf, int reg);
+/**
+ * mcd_read_write_physical_memory() - Reades or writes from/to a logical
+ * memory address.
+ * @address_space: Desired QEMU address space (e.g. secure/non-secure)
+ * @attributes: Access attributes
+ * @addr: (physical) memory address
+ * @buf: Buffer for memory data
+ * @len: Length of the memory access
+ * @is_write: True for writing and false for reading
+ */
+int mcd_read_write_physical_memory(AddressSpace *address_space,
+ MemTxAttrs attributes, hwaddr addr, uint8_t *buf, int len, bool is_write);
+
+/**
+ * mcd_read_write_memory() - Reades or writes from/to a logical memory address.
+ * @cpu: CPUState
+ * @address_space: Desired QEMU address space (e.g. secure/non-secure)
+ * @attributes: Access attributes
+ * @addr: (logical) memory address
+ * @buf: Buffer for memory data
+ * @len: Length of the memory access
+ * @is_write: True for writing and false for reading
+ */
+int mcd_read_write_memory(CPUState *cpu, AddressSpace *address_space,
+ MemTxAttrs attributes, vaddr addr, uint8_t *buf, uint64_t len,
+ bool is_write);
+
+/**
+ * mcd_get_address_space() - Returnes the correct QEMU address space name
+ * @cpu: CPUState
+ * @cpu_id: Correct CPU ID
+ * @mem_space: Desired mcd specific memory space.
+ */
+AddressSpace *mcd_get_address_space(CPUState *cpu, uint32_t cpu_id,
+ mcd_mem_space_st mem_space);
+
+/**
+ * mcd_get_memtxattrs() - Returnes the correct QEMU address space access
+ * attributes
+ * @cpu: CPUState
+ * @mem_space: Desired mcd specific memory space.
+ */
+MemTxAttrs mcd_get_memtxattrs(CPUState *cpu, mcd_mem_space_st mem_space);
+
/* helpers */
/**
diff --git a/mcdstub/mcdstub.c b/mcdstub/mcdstub.c
index 018900e914..8dc1e6a71d 100644
--- a/mcdstub/mcdstub.c
+++ b/mcdstub/mcdstub.c
@@ -545,6 +545,31 @@ int mcd_handle_packet(const char *line_buf)
cmd_parser = &write_reg_cmd_desc;
}
break;
+ case TCP_CHAR_READ_MEMORY:
+ {
+ static MCDCmdParseEntry read_mem_cmd_desc = {
+ .handler = handle_read_memory,
+ };
+ read_mem_cmd_desc.cmd = (char[2]) { TCP_CHAR_READ_MEMORY, '\0' };
+ strcpy(read_mem_cmd_desc.schema,
+ (char[5]) { ARG_SCHEMA_CORENUM, ARG_SCHEMA_INT,
+ ARG_SCHEMA_UINT64_T, ARG_SCHEMA_INT, '\0' });
+ cmd_parser = &read_mem_cmd_desc;
+ }
+ break;
+ case TCP_CHAR_WRITE_MEMORY:
+ {
+ static MCDCmdParseEntry write_mem_cmd_desc = {
+ .handler = handle_write_memory,
+ };
+ write_mem_cmd_desc.cmd = (char[2]) { TCP_CHAR_WRITE_MEMORY, '\0' };
+ strcpy(write_mem_cmd_desc.schema,
+ (char[6]) { ARG_SCHEMA_CORENUM, ARG_SCHEMA_INT,
+ ARG_SCHEMA_UINT64_T, ARG_SCHEMA_INT,
+ ARG_SCHEMA_HEXDATA, '\0' });
+ cmd_parser = &write_mem_cmd_desc;
+ }
+ break;
default:
/* command not supported */
mcd_put_packet("");
@@ -1727,3 +1752,131 @@ void handle_write_register(GArray *params, void *user_ctx)
mcd_put_packet(TCP_EXECUTION_SUCCESS);
}
}
+
+int mcd_read_write_physical_memory(AddressSpace *address_space,
+ MemTxAttrs attributes, hwaddr addr, uint8_t *buf, int len, bool is_write)
+{
+ if (is_write) {
+ return address_space_write_rom(address_space, addr, attributes, buf,
+ len);
+ } else {
+ return address_space_read_full(address_space, addr, attributes, buf,
+ len);
+ }
+}
+
+int mcd_read_write_memory(CPUState *cpu, AddressSpace *address_space,
+ MemTxAttrs attributes, vaddr addr, uint8_t *buf, uint64_t len,
+ bool is_write)
+{
+ /* get physical address */
+ if (cpu_memory_get_physical_address(cpu, &addr, &len) != 0) {
+ return -1;
+ }
+ /* read memory */
+ return mcd_read_write_physical_memory(address_space, attributes, addr, buf,
+ len, is_write);
+}
+
+AddressSpace *mcd_get_address_space(CPUState *cpu, uint32_t cpu_id,
+ mcd_mem_space_st mem_space)
+{
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+ const gchar *arch = cc->gdb_arch_name(cpu);
+ if (strcmp(arch, MCDSTUB_ARCH_ARM) == 0) {
+ return arm_mcd_get_address_space(cpu_id, mem_space);
+ } else {
+ g_assert_not_reached();
+ }
+}
+
+MemTxAttrs mcd_get_memtxattrs(CPUState *cpu, mcd_mem_space_st mem_space)
+{
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+ const gchar *arch = cc->gdb_arch_name(cpu);
+ if (strcmp(arch, MCDSTUB_ARCH_ARM) == 0) {
+ return arm_mcd_get_memtxattrs(mem_space);
+ } else {
+ g_assert_not_reached();
+ }
+}
+
+void handle_read_memory(GArray *params, void *user_ctx)
+{
+ /* read input parameters */
+ uint32_t cpu_id = get_param(params, 0)->cpu_id;
+ uint32_t mem_space_id = get_param(params, 1)->data_uint32_t;
+ uint64_t mem_address = get_param(params, 2)->data_uint64_t;
+ uint32_t len = get_param(params, 3)->data_uint32_t;
+ /* check which memory space was requested */
+ CPUState *cpu = mcd_get_cpu(cpu_id);
+ GArray *memspaces =
+ g_list_nth_data(mcdserver_state.all_memspaces, cpu_id);
+ mcd_mem_space_st space = g_array_index(memspaces, mcd_mem_space_st,
+ mem_space_id - 1);
+ /* get data in the QEMU address space and access attributes */
+ AddressSpace *address_space = mcd_get_address_space(cpu, cpu_id, space);
+ MemTxAttrs attributes = mcd_get_memtxattrs(cpu, space);
+ /* read memory data */
+ g_byte_array_set_size(mcdserver_state.mem_buf, len);
+ if (space.is_physical) {
+ /* physical memory */
+ if (mcd_read_write_physical_memory(address_space, attributes,
+ mem_address, mcdserver_state.mem_buf->data,
+ mcdserver_state.mem_buf->len, false) != 0) {
+ mcd_put_packet(TCP_EXECUTION_ERROR);
+ return;
+ }
+ } else {
+ /* user space memory */
+ if (mcd_read_write_memory(cpu, address_space, attributes, mem_address,
+ mcdserver_state.mem_buf->data, mcdserver_state.mem_buf->len,
+ false) != 0) {
+ mcd_put_packet(TCP_EXECUTION_ERROR);
+ return;
+ }
+ }
+ /* send data */
+ mcd_memtohex(mcdserver_state.str_buf, mcdserver_state.mem_buf->data,
+ mcdserver_state.mem_buf->len);
+ mcd_put_strbuf();
+}
+
+void handle_write_memory(GArray *params, void *user_ctx)
+{
+ /* read input parameters */
+ uint32_t cpu_id = get_param(params, 0)->cpu_id;
+ uint32_t mem_space_id = get_param(params, 1)->data_uint32_t;
+ uint64_t mem_address = get_param(params, 2)->data_uint64_t;
+ uint32_t len = get_param(params, 3)->data_uint32_t;
+ /* check which memory space was requested */
+ CPUState *cpu = mcd_get_cpu(cpu_id);
+ GArray *memspaces =
+ g_list_nth_data(mcdserver_state.all_memspaces, cpu_id);
+ mcd_mem_space_st space = g_array_index(memspaces, mcd_mem_space_st,
+ mem_space_id - 1);
+ /* get data in the QEMU address space and access attributes */
+ AddressSpace *address_space = mcd_get_address_space(cpu, cpu_id, space);
+ MemTxAttrs attributes = mcd_get_memtxattrs(cpu, space);
+ /* write memory data */
+ mcd_hextomem(mcdserver_state.mem_buf, mcdserver_state.str_buf->str, len);
+ if (space.is_physical) {
+ /* physical memory */
+ if (mcd_read_write_physical_memory(address_space, attributes,
+ mem_address, mcdserver_state.mem_buf->data,
+ mcdserver_state.mem_buf->len, true) != 0) {
+ mcd_put_packet(TCP_EXECUTION_ERROR);
+ return;
+ }
+ } else {
+ /* user space memory */
+ if (mcd_read_write_memory(cpu, address_space, attributes, mem_address,
+ mcdserver_state.mem_buf->data, mcdserver_state.mem_buf->len,
+ true) != 0) {
+ mcd_put_packet(TCP_EXECUTION_ERROR);
+ return;
+ }
+ }
+ /* send acknowledge */
+ mcd_put_packet(TCP_EXECUTION_SUCCESS);
+}
diff --git a/system/memory.c b/system/memory.c
index 4928f2525d..bb3d2067c4 100644
--- a/system/memory.c
+++ b/system/memory.c
@@ -3577,6 +3577,17 @@ void mtree_info(bool flatview, bool dispatch_tree, bool owner, bool disabled)
}
}
+AddressSpace *mcd_find_address_space(const char *as_name)
+{
+ AddressSpace *as;
+ QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
+ if (strcmp(as->name, as_name) == 0) {
+ return as;
+ }
+ }
+ return NULL;
+}
+
void memory_region_init_ram(MemoryRegion *mr,
Object *owner,
const char *name,
diff --git a/system/physmem.c b/system/physmem.c
index fc2b0fee01..60c15546f8 100644
--- a/system/physmem.c
+++ b/system/physmem.c
@@ -3400,6 +3400,32 @@ int cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
return 0;
}
+int cpu_memory_get_physical_address(CPUState *cpu, vaddr *addr, size_t *len)
+{
+ hwaddr phys_addr;
+ vaddr l, page;
+
+ cpu_synchronize_state(cpu);
+ MemTxAttrs attrs;
+
+ page = *addr & TARGET_PAGE_MASK;
+ phys_addr = cpu_get_phys_page_attrs_debug(cpu, page, &attrs);
+ /* if no physical page mapped, return an error */
+ if (phys_addr == -1) {
+ return -1;
+ }
+ l = (page + TARGET_PAGE_SIZE) - *addr;
+ if (l > *len) {
+ l = *len;
+ }
+ phys_addr += (*addr & ~TARGET_PAGE_MASK);
+
+ /* set output values */
+ *addr = phys_addr;
+ *len = l;
+ return 0;
+}
+
/*
* Allows code that needs to deal with migration bitmaps etc to still be built
* target independent.
diff --git a/target/arm/mcdstub.c b/target/arm/mcdstub.c
index ff1350831b..c87e0e4784 100644
--- a/target/arm/mcdstub.c
+++ b/target/arm/mcdstub.c
@@ -276,3 +276,29 @@ int arm_mcd_get_additional_register_info(GArray *reggroups, GArray *registers,
return 0;
}
+AddressSpace *arm_mcd_get_address_space(uint32_t cpu_id,
+ mcd_mem_space_st mem_space)
+{
+ /* get correct address space name */
+ char as_name[ARGUMENT_STRING_LENGTH] = {0};
+ if (mem_space.is_secure) {
+ sprintf(as_name, "cpu-secure-memory-%u", cpu_id);
+ } else {
+ sprintf(as_name, "cpu-memory-%u", cpu_id);
+ }
+ /* return correct address space */
+ AddressSpace *as = mcd_find_address_space(as_name);
+ return as;
+}
+
+MemTxAttrs arm_mcd_get_memtxattrs(mcd_mem_space_st mem_space)
+{
+ MemTxAttrs attributes = {0};
+ if (mem_space.is_secure) {
+ attributes.secure = 1;
+ attributes.space = 2;
+ } else {
+ attributes.space = 1;
+ }
+ return attributes;
+}
--
2.34.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 19/20] mcdstub: break/watchpoints added
2023-11-07 13:03 [PATCH v3 00/20] first version of mcdstub Nicolas Eder
` (17 preceding siblings ...)
2023-11-07 13:03 ` [PATCH v3 18/20] mcdstub: read/write to memory added: This also includes various helper functions in the QEMU memory code Nicolas Eder
@ 2023-11-07 13:03 ` Nicolas Eder
2023-11-07 13:03 ` [PATCH v3 20/20] mcdstub: updated MAINTAINERS file and fully activated the mcdstub in the meson build system Nicolas Eder
` (2 subsequent siblings)
21 siblings, 0 replies; 32+ messages in thread
From: Nicolas Eder @ 2023-11-07 13:03 UTC (permalink / raw)
To: qemu-devel
Cc: Nicolas Eder, Alex Bennée, Philippe Mathieu-Daudé,
Christian Boenig
---
include/mcdstub/mcdstub.h | 46 +++++++++++++++
mcdstub/mcdstub.c | 116 ++++++++++++++++++++++++++++++++++++++
2 files changed, 162 insertions(+)
diff --git a/include/mcdstub/mcdstub.h b/include/mcdstub/mcdstub.h
index c55d52d2a7..53e5926ff5 100644
--- a/include/mcdstub/mcdstub.h
+++ b/include/mcdstub/mcdstub.h
@@ -785,6 +785,52 @@ int mcd_read_write_memory(CPUState *cpu, AddressSpace *address_space,
MemTxAttrs attributes, vaddr addr, uint8_t *buf, uint64_t len,
bool is_write);
+/**
+ * handle_breakpoint_insert() - Handler for inserting a break- or watchpoint.
+ *
+ * This function extracts the CPU, breakpoint type and address from the
+ * parameters and calls :c:func:`mcd_breakpoint_insert` to insert the
+ * breakpoint.
+ * @params: GArray with all TCP packet parameters.
+ */
+void handle_breakpoint_insert(GArray *params, void *user_ctx);
+
+/**
+ * handle_breakpoint_remove() - Handler for inserting a break- or watchpoint.
+ *
+ * This function extracts the CPU, breakpoint type and address from the
+ * parameters and calls :c:func:`mcd_breakpoint_remove` to insert the
+ * breakpoint.
+ * @params: GArray with all TCP packet parameters.
+ */
+void handle_breakpoint_remove(GArray *params, void *user_ctx);
+
+/**
+ * mcd_breakpoint_insert() - Inserts a break- or watchpoint.
+ *
+ * This function evaluates the received breakpoint type and translates it
+ * to a known GDB breakpoint type.
+ * Then it calls cpu_breakpoint_insert or cpu_watchpoint_insert depending on
+ * the type.
+ * @cpu: CPU to which the breakpoint should be added.
+ * @addr: Address of the breakpoint.
+ * @type: Breakpoint type.
+ */
+int mcd_breakpoint_insert(CPUState *cpu, int type, vaddr addr);
+
+/**
+ * mcd_breakpoint_remove() - Removes a break- or watchpoint.
+ *
+ * This function evaluates the received breakpoint type and translates it
+ * to a known GDB breakpoint type.
+ * Then it calls cpu_breakpoint_remove or cpu_watchpoint_remove depending on
+ * the type.
+ * @cpu: CPU from which the breakpoint should be removed.
+ * @addr: Address of the breakpoint.
+ * @type: Breakpoint type.
+ */
+int mcd_breakpoint_remove(CPUState *cpu, int type, vaddr addr);
+
/**
* mcd_get_address_space() - Returnes the correct QEMU address space name
* @cpu: CPUState
diff --git a/mcdstub/mcdstub.c b/mcdstub/mcdstub.c
index 8dc1e6a71d..68e9cdf531 100644
--- a/mcdstub/mcdstub.c
+++ b/mcdstub/mcdstub.c
@@ -570,6 +570,32 @@ int mcd_handle_packet(const char *line_buf)
cmd_parser = &write_mem_cmd_desc;
}
break;
+ case TCP_CHAR_BREAKPOINT_INSERT:
+ {
+ static MCDCmdParseEntry handle_breakpoint_insert_cmd_desc = {
+ .handler = handle_breakpoint_insert,
+ };
+ handle_breakpoint_insert_cmd_desc.cmd =
+ (char[2]) { TCP_CHAR_BREAKPOINT_INSERT, '\0' };
+ strcpy(handle_breakpoint_insert_cmd_desc.schema,
+ (char[4]) { ARG_SCHEMA_CORENUM, ARG_SCHEMA_INT,
+ ARG_SCHEMA_UINT64_T, '\0' });
+ cmd_parser = &handle_breakpoint_insert_cmd_desc;
+ }
+ break;
+ case TCP_CHAR_BREAKPOINT_REMOVE:
+ {
+ static MCDCmdParseEntry handle_breakpoint_remove_cmd_desc = {
+ .handler = handle_breakpoint_remove,
+ };
+ handle_breakpoint_remove_cmd_desc.cmd =
+ (char[2]) { TCP_CHAR_BREAKPOINT_REMOVE, '\0' };
+ strcpy(handle_breakpoint_remove_cmd_desc.schema,
+ (char[4]) { ARG_SCHEMA_CORENUM, ARG_SCHEMA_INT,
+ ARG_SCHEMA_UINT64_T, '\0' });
+ cmd_parser = &handle_breakpoint_remove_cmd_desc;
+ }
+ break;
default:
/* command not supported */
mcd_put_packet("");
@@ -1880,3 +1906,93 @@ void handle_write_memory(GArray *params, void *user_ctx)
/* send acknowledge */
mcd_put_packet(TCP_EXECUTION_SUCCESS);
}
+
+int mcd_breakpoint_insert(CPUState *cpu, int type, vaddr addr)
+{
+ /* translate the type to known gdb types and function call*/
+ int bp_type = 0;
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+ if (cc->gdb_stop_before_watchpoint) {
+ /* bp_type |= BP_STOP_BEFORE_ACCESS; */
+ }
+ int return_value = 0;
+ switch (type) {
+ case MCD_BREAKPOINT_HW:
+ return_value = cpu_breakpoint_insert(cpu, addr, BP_GDB, NULL);
+ return return_value;
+ case MCD_BREAKPOINT_READ:
+ bp_type |= BP_GDB | BP_MEM_READ;
+ return_value = cpu_watchpoint_insert(cpu, addr, 4, bp_type, NULL);
+ return return_value;
+ case MCD_BREAKPOINT_WRITE:
+ bp_type |= BP_GDB | BP_MEM_WRITE;
+ return_value = cpu_watchpoint_insert(cpu, addr, 4, bp_type, NULL);
+ return return_value;
+ case MCD_BREAKPOINT_RW:
+ bp_type |= BP_GDB | BP_MEM_ACCESS;
+ return_value = cpu_watchpoint_insert(cpu, addr, 4, bp_type, NULL);
+ return return_value;
+ default:
+ return -ENOSYS;
+ }
+}
+
+int mcd_breakpoint_remove(CPUState *cpu, int type, vaddr addr)
+{
+ /* translate the type to known gdb types and function call*/
+ int bp_type = 0;
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+ if (cc->gdb_stop_before_watchpoint) {
+ /* bp_type |= BP_STOP_BEFORE_ACCESS; */
+ }
+ int return_value = 0;
+ switch (type) {
+ case MCD_BREAKPOINT_HW:
+ return_value = cpu_breakpoint_remove(cpu, addr, BP_GDB);
+ return return_value;
+ case MCD_BREAKPOINT_READ:
+ bp_type |= BP_GDB | BP_MEM_READ;
+ return_value = cpu_watchpoint_remove(cpu, addr, 4, bp_type);
+ return return_value;
+ case MCD_BREAKPOINT_WRITE:
+ bp_type |= BP_GDB | BP_MEM_WRITE;
+ return_value = cpu_watchpoint_remove(cpu, addr, 4, bp_type);
+ return return_value;
+ case MCD_BREAKPOINT_RW:
+ bp_type |= BP_GDB | BP_MEM_ACCESS;
+ return_value = cpu_watchpoint_remove(cpu, addr, 4, bp_type);
+ return return_value;
+ default:
+ return -ENOSYS;
+ }
+}
+
+void handle_breakpoint_insert(GArray *params, void *user_ctx)
+{
+ /* 1. get parameter data */
+ uint32_t cpu_id = get_param(params, 0)->cpu_id;
+ uint32_t type = get_param(params, 1)->data_uint32_t;
+ uint64_t address = get_param(params, 2)->data_uint64_t;
+ /* 2. insert breakpoint and send reply */
+ CPUState *cpu = mcd_get_cpu(cpu_id);
+ if (mcd_breakpoint_insert(cpu, type, address) != 0) {
+ mcd_put_packet(TCP_EXECUTION_ERROR);
+ } else {
+ mcd_put_packet(TCP_EXECUTION_SUCCESS);
+ }
+}
+
+void handle_breakpoint_remove(GArray *params, void *user_ctx)
+{
+ /* 1. get parameter data */
+ uint32_t cpu_id = get_param(params, 0)->cpu_id;
+ uint32_t type = get_param(params, 1)->data_uint32_t;
+ uint64_t address = get_param(params, 2)->data_uint64_t;
+ /* 2. remove breakpoint and send reply */
+ CPUState *cpu = mcd_get_cpu(cpu_id);
+ if (mcd_breakpoint_remove(cpu, type, address) != 0) {
+ mcd_put_packet(TCP_EXECUTION_ERROR);
+ } else {
+ mcd_put_packet(TCP_EXECUTION_SUCCESS);
+ }
+}
--
2.34.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 20/20] mcdstub: updated MAINTAINERS file and fully activated the mcdstub in the meson build system
2023-11-07 13:03 [PATCH v3 00/20] first version of mcdstub Nicolas Eder
` (18 preceding siblings ...)
2023-11-07 13:03 ` [PATCH v3 19/20] mcdstub: break/watchpoints added Nicolas Eder
@ 2023-11-07 13:03 ` Nicolas Eder
2023-11-29 16:31 ` Alex Bennée
2023-11-08 14:27 ` [PATCH v3 00/20] first version of mcdstub Philippe Mathieu-Daudé
2023-11-29 14:44 ` Alex Bennée
21 siblings, 1 reply; 32+ messages in thread
From: Nicolas Eder @ 2023-11-07 13:03 UTC (permalink / raw)
To: qemu-devel
Cc: Nicolas Eder, Alex Bennée, Philippe Mathieu-Daudé,
Christian Boenig
---
MAINTAINERS | 11 +++++++++++
mcdstub/meson.build | 15 +++++++++++++++
meson.build | 1 +
target/arm/meson.build | 1 +
4 files changed, 28 insertions(+)
create mode 100644 mcdstub/meson.build
diff --git a/MAINTAINERS b/MAINTAINERS
index cd8d6b140f..58decd218c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2908,6 +2908,17 @@ F: tests/tcg/multiarch/gdbstub/
F: scripts/feature_to_c.py
F: scripts/probe-gdb-support.py
+MCD stub
+M: Nicolas Eder <nicolas.eder@lauterbach.com>
+R: Alex Bennée <alex.bennee@linaro.org>
+S: Maintained
+F: mcdstub/*
+F: include/mcdstub/*
+F: include/qemu/debug.h
+F: debug/debug-common.c
+F: debug/debug-mcd.c
+F: target/arm/mcdstub.c
+
Memory API
M: Paolo Bonzini <pbonzini@redhat.com>
M: Peter Xu <peterx@redhat.com>
diff --git a/mcdstub/meson.build b/mcdstub/meson.build
new file mode 100644
index 0000000000..1f9315f9f5
--- /dev/null
+++ b/mcdstub/meson.build
@@ -0,0 +1,15 @@
+# only system emulation is supported over mcd
+mcd_system_ss = ss.source_set()
+mcd_system_ss.add(files('mcdstub.c', '../debug/debug-mcd.c'))
+mcd_system_ss = mcd_system_ss.apply(config_host, strict: false)
+
+libmcd_system = static_library('mcd_system',
+ mcd_system_ss.sources() + genh,
+ name_suffix: 'fa',
+ build_by_default: have_system)
+
+mcd_system = declare_dependency(link_whole: libmcd_system)
+system_ss.add(mcd_system)
+
+# used for gdb (user/system) and mcd:
+common_ss.add(files('../debug/debug-common.c'))
diff --git a/meson.build b/meson.build
index dcef8b1e79..6dfa49160c 100644
--- a/meson.build
+++ b/meson.build
@@ -3348,6 +3348,7 @@ subdir('crypto')
subdir('ui')
subdir('hw')
subdir('gdbstub')
+subdir('mcdstub')
if enable_modules
libmodulecommon = static_library('module-common', files('module-common.c') + genh, pic: true, c_args: '-DBUILD_DSO')
diff --git a/target/arm/meson.build b/target/arm/meson.build
index 5d04a8e94f..84fedbc6e1 100644
--- a/target/arm/meson.build
+++ b/target/arm/meson.build
@@ -3,6 +3,7 @@ arm_ss.add(files(
'cpu.c',
'debug_helper.c',
'gdbstub.c',
+ 'mcdstub.c',
'helper.c',
'vfp_helper.c',
))
--
2.34.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* Re: [PATCH v3 20/20] mcdstub: updated MAINTAINERS file and fully activated the mcdstub in the meson build system
2023-11-07 13:03 ` [PATCH v3 20/20] mcdstub: updated MAINTAINERS file and fully activated the mcdstub in the meson build system Nicolas Eder
@ 2023-11-29 16:31 ` Alex Bennée
0 siblings, 0 replies; 32+ messages in thread
From: Alex Bennée @ 2023-11-29 16:31 UTC (permalink / raw)
To: Nicolas Eder; +Cc: qemu-devel, Philippe Mathieu-Daudé, Christian Boenig
Nicolas Eder <nicolas.eder@lauterbach.com> writes:
> ---
> MAINTAINERS | 11 +++++++++++
> mcdstub/meson.build | 15 +++++++++++++++
> meson.build | 1 +
> target/arm/meson.build | 1 +
> 4 files changed, 28 insertions(+)
> create mode 100644 mcdstub/meson.build
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index cd8d6b140f..58decd218c 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -2908,6 +2908,17 @@ F: tests/tcg/multiarch/gdbstub/
> F: scripts/feature_to_c.py
> F: scripts/probe-gdb-support.py
>
> +MCD stub
> +M: Nicolas Eder <nicolas.eder@lauterbach.com>
> +R: Alex Bennée <alex.bennee@linaro.org>
> +S: Maintained
> +F: mcdstub/*
> +F: include/mcdstub/*
> +F: include/qemu/debug.h
> +F: debug/debug-common.c
> +F: debug/debug-mcd.c
> +F: target/arm/mcdstub.c
> +
> Memory API
> M: Paolo Bonzini <pbonzini@redhat.com>
> M: Peter Xu <peterx@redhat.com>
> diff --git a/mcdstub/meson.build b/mcdstub/meson.build
> new file mode 100644
> index 0000000000..1f9315f9f5
> --- /dev/null
> +++ b/mcdstub/meson.build
> @@ -0,0 +1,15 @@
> +# only system emulation is supported over mcd
> +mcd_system_ss = ss.source_set()
> +mcd_system_ss.add(files('mcdstub.c', '../debug/debug-mcd.c'))
> +mcd_system_ss = mcd_system_ss.apply(config_host, strict: false)
> +
> +libmcd_system = static_library('mcd_system',
> + mcd_system_ss.sources() + genh,
> + name_suffix: 'fa',
> + build_by_default: have_system)
> +
> +mcd_system = declare_dependency(link_whole: libmcd_system)
> +system_ss.add(mcd_system)
> +
> +# used for gdb (user/system) and mcd:
> +common_ss.add(files('../debug/debug-common.c'))
> diff --git a/meson.build b/meson.build
> index dcef8b1e79..6dfa49160c 100644
> --- a/meson.build
> +++ b/meson.build
> @@ -3348,6 +3348,7 @@ subdir('crypto')
> subdir('ui')
> subdir('hw')
> subdir('gdbstub')
> +subdir('mcdstub')
OK this is fine *if* you haven't already got code attempting to link to
bits of your stub. You can either deal with this by declaring stub
functions where the real symbol doesn't exist or having empty inlines
when the feature isn't enabled.
That said even here the build fails for me:
FAILED: mcdstub/libmcd_system.fa.p/mcdstub.c.o
cc -m64 -mcx16 -Imcdstub/libmcd_system.fa.p -Imcdstub -I../../mcdstub -I. -Iqapi -Itrace -Iui -Iui/shader -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -fdiagnostics-color=auto -Wall -Winvalid-pch -Werror -std=gnu11 -O2 -g -fstack-protector-strong -Wundef -Wwrite-strings -Wmissing-prototypes -Wstrict-prototypes -Wredundant-decls -Wold-style-declaration -Wold-style-definition -Wtype-limits -Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers -Wempty-body -Wnested-externs -Wendif-labels -Wexpansion-to-defined -Wimplicit-fallthrough=2 -Wmissing-format-attribute -Wno-missing-include-dirs -Wno-shift-negative-value -Wno-psabi -Wshadow=local -isystem /home/alex/lsrc/qemu.git/linux-headers -isystem linux-headers -iquote . -iquote /home/alex/lsrc/qemu.git -iquote /home/alex/lsrc/qemu.git/include -iquote /home/alex/lsrc/qemu.git/host/include/x86_64 -iquote /home/alex/lsrc/qemu.git/host/include/generic -iquote /home/alex/lsrc/qemu.git/tcg/i386 -pthread -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -fno-strict-aliasing -fno-common -fwrapv -fPIE -MD -MQ mcdstub/libmcd_system.fa.p/mcdstub.c.o -MF mcdstub/libmcd_system.fa.p/mcdstub.c.o.d -o mcdstub/libmcd_system.fa.p/mcdstub.c.o -c ../../mcdstub/mcdstub.c
../../mcdstub/mcdstub.c: In function ‘mcdserver_start’:
../../mcdstub/mcdstub.c:286:25: error: ‘,wait=off,nodelay=on,server=on’ directive output may be truncated writing 30 bytes into a region of size between 1 and 128 [-Werror=format-truncation=]
286 | "%s,wait=off,nodelay=on,server=on", device);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/stdio.h:906,
from /home/alex/lsrc/qemu.git/include/qemu/osdep.h:114,
from ../../mcdstub/mcdstub.c:5:
In function ‘snprintf’,
inlined from ‘mcdserver_start’ at ../../mcdstub/mcdstub.c:285:13:
/usr/include/x86_64-linux-gnu/bits/stdio2.h:54:10: note: ‘__builtin___snprintf_chk’ output between 31 and 158 bytes into a destination of size 128
54 | return __builtin___snprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
55 | __glibc_objsize (__s), __fmt,
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
56 | __va_arg_pack ());
| ~~~~~~~~~~~~~~~~~
../../mcdstub/mcdstub.c: In function ‘cmd_parse_params’:
../../mcdstub/mcdstub.c:716:13: error: ‘__builtin___strncpy_chk’ output truncated before terminating nul copying as many bytes from a string as its length [-Werror=stringop-truncation]
716 | strncpy(data_buffer, remaining_data, strlen(remaining_data));
| ^
../../mcdstub/mcdstub.c:716:13: note: length computed here
716 | strncpy(data_buffer, remaining_data, strlen(remaining_data));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/glib-2.0/glib.h:33,
from /home/alex/lsrc/qemu.git/include/glib-compat.h:32,
from /home/alex/lsrc/qemu.git/include/qemu/osdep.h:161:
/usr/include/glib-2.0/glib/garray.h: In function ‘parse_reg_xml’:
/usr/include/glib-2.0/glib/garray.h:69:54: error: ‘reg_data’ may be used uninitialized [-Werror=maybe-uninitialized]
69 | #define g_array_index(a,t,i) (((t*) (void *) (a)->data) [(i)])
| ^~
../../mcdstub/mcdstub.c:1081:13: note: ‘reg_data’ was declared here
1081 | GArray *reg_data;
| ^~~~~~~~
../../mcdstub/mcdstub.c:1136:28: error: ‘internal_id’ may be used uninitialized [-Werror=maybe-uninitialized]
1136 | internal_id++;
| ~~~~~~~~~~~^~
../../mcdstub/mcdstub.c:1074:14: note: ‘internal_id’ was declared here
1074 | uint32_t internal_id;
| ^~~~~~~~~~~
cc1: all warnings being treated as errors
See also:
https://gitlab.com/stsquad/qemu/-/pipelines/1089441465/failures
Please ensure next post that you can at least pass a "make all" of a
normally configured build and that each intermediate stage also builds.
>
> if enable_modules
> libmodulecommon = static_library('module-common', files('module-common.c') + genh, pic: true, c_args: '-DBUILD_DSO')
> diff --git a/target/arm/meson.build b/target/arm/meson.build
> index 5d04a8e94f..84fedbc6e1 100644
> --- a/target/arm/meson.build
> +++ b/target/arm/meson.build
> @@ -3,6 +3,7 @@ arm_ss.add(files(
> 'cpu.c',
> 'debug_helper.c',
> 'gdbstub.c',
> + 'mcdstub.c',
> 'helper.c',
> 'vfp_helper.c',
> ))
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 00/20] first version of mcdstub
2023-11-07 13:03 [PATCH v3 00/20] first version of mcdstub Nicolas Eder
` (19 preceding siblings ...)
2023-11-07 13:03 ` [PATCH v3 20/20] mcdstub: updated MAINTAINERS file and fully activated the mcdstub in the meson build system Nicolas Eder
@ 2023-11-08 14:27 ` Philippe Mathieu-Daudé
2023-11-13 9:20 ` nicolas.eder
2023-11-29 14:44 ` Alex Bennée
21 siblings, 1 reply; 32+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-11-08 14:27 UTC (permalink / raw)
To: Nicolas Eder, qemu-devel; +Cc: Alex Bennée, Christian Boenig
Hi Nicolas,
On 7/11/23 14:03, Nicolas Eder wrote:
> SUMMARY
> =======
>
> This patch-set introduces the first version of the mcdstub.
> 30 files changed, 3749 insertions(+), 38 deletions(-)
> create mode 100644 debug/debug-common.c
> create mode 100644 debug/debug-gdb.c
> create mode 100644 debug/debug-mcd.c
> create mode 100644 include/cutils.h
> create mode 100644 include/mcdstub/arm_mcdstub.h
> create mode 100644 include/mcdstub/mcd_shared_defines.h
> create mode 100644 include/mcdstub/mcdstub.h
> create mode 100644 include/mcdstub/mcdstub_common.h
> create mode 100644 include/qemu/debug.h
> create mode 100644 mcdstub/mcdstub.c
> create mode 100644 mcdstub/meson.build
> create mode 100644 target/arm/mcdstub.c
These files are missing a license. Adding:
/* SPDX-License-Identifier: GPL-2.0-or-later */
on the first line is usually enough.
No need to respin a v4 yet, let's wait for technical
comments on your patches.
Regards,
Phil.
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 00/20] first version of mcdstub
2023-11-08 14:27 ` [PATCH v3 00/20] first version of mcdstub Philippe Mathieu-Daudé
@ 2023-11-13 9:20 ` nicolas.eder
0 siblings, 0 replies; 32+ messages in thread
From: nicolas.eder @ 2023-11-13 9:20 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, qemu-devel
Cc: Alex Bennée, Christian Boenig
Hi Phil,
okay thanks! I'll add the license.
Regards,
Nicolas
On 08/11/2023 15:27, Philippe Mathieu-Daudé wrote:
> Hi Nicolas,
>
> On 7/11/23 14:03, Nicolas Eder wrote:
>> SUMMARY
>> =======
>>
>> This patch-set introduces the first version of the mcdstub.
>
>
>> 30 files changed, 3749 insertions(+), 38 deletions(-)
>> create mode 100644 debug/debug-common.c
>> create mode 100644 debug/debug-gdb.c
>> create mode 100644 debug/debug-mcd.c
>> create mode 100644 include/cutils.h
>> create mode 100644 include/mcdstub/arm_mcdstub.h
>> create mode 100644 include/mcdstub/mcd_shared_defines.h
>> create mode 100644 include/mcdstub/mcdstub.h
>> create mode 100644 include/mcdstub/mcdstub_common.h
>> create mode 100644 include/qemu/debug.h
>> create mode 100644 mcdstub/mcdstub.c
>> create mode 100644 mcdstub/meson.build
>> create mode 100644 target/arm/mcdstub.c
>
> These files are missing a license. Adding:
> /* SPDX-License-Identifier: GPL-2.0-or-later */
> on the first line is usually enough.
>
> No need to respin a v4 yet, let's wait for technical
> comments on your patches.
>
> Regards,
>
> Phil.
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 00/20] first version of mcdstub
2023-11-07 13:03 [PATCH v3 00/20] first version of mcdstub Nicolas Eder
` (20 preceding siblings ...)
2023-11-08 14:27 ` [PATCH v3 00/20] first version of mcdstub Philippe Mathieu-Daudé
@ 2023-11-29 14:44 ` Alex Bennée
2023-11-29 15:01 ` nicolas.eder
21 siblings, 1 reply; 32+ messages in thread
From: Alex Bennée @ 2023-11-29 14:44 UTC (permalink / raw)
To: Nicolas Eder; +Cc: qemu-devel, Philippe Mathieu-Daudé, Christian Boenig
Nicolas Eder <nicolas.eder@lauterbach.com> writes:
> SUMMARY
> =======
>
> This patch-set introduces the first version of the mcdstub.
> The mcdstub is a debug interface, which enables debugging QEMU
> using the MCD (Multi-Core Debug) API.
> The mcdstub uses TCP to communicate with the host debug software. However,
> because MCD is merely an API, the TCP communication is not part of
> the MCD spec but specific to this project.
>
> To translate between the MCD API and the TCP data stream coming from the mcdstub,
> the host has to use a shared library (.dll/.so).
> Such a shared library will be available soon Lauterbach's open source site
> and will be linked to from inside this project in a future patch.
Do you have a timeline for this? Its impossible to test without some
sort of open implementation of the library.
> The MCD API itself can be downloaded here: https://repo.lauterbach.com/sprint_mcd_api_v1_0.zip
>
> QUICK START
> ===========
>
> Attention: MCD is currently only supported for qemu-system-arm !
>
> Three components are required to Debug QEMU via MCD:
>
> 1. qemu-system-arm (built with this patch series applied).
> 2. MCD shared library (translates between the MCD API and TCP data).
> 3. Host debugging software with support for the MCD API (e.g.
> Lauterbach TRACE32).
We will need some sort of basic implementation to exercise the API as I
assume TRACE32 is a paid for binary.
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 00/20] first version of mcdstub
2023-11-29 14:44 ` Alex Bennée
@ 2023-11-29 15:01 ` nicolas.eder
0 siblings, 0 replies; 32+ messages in thread
From: nicolas.eder @ 2023-11-29 15:01 UTC (permalink / raw)
To: Alex Bennée
Cc: qemu-devel, Philippe Mathieu-Daudé, Christian Boenig
[-- Attachment #1: Type: text/plain, Size: 1740 bytes --]
On 29/11/2023 15:44, Alex Bennée wrote:
> Nicolas Eder<nicolas.eder@lauterbach.com> writes:
>
>> SUMMARY
>> =======
>>
>> This patch-set introduces the first version of the mcdstub.
>> The mcdstub is a debug interface, which enables debugging QEMU
>> using the MCD (Multi-Core Debug) API.
>> The mcdstub uses TCP to communicate with the host debug software. However,
>> because MCD is merely an API, the TCP communication is not part of
>> the MCD spec but specific to this project.
>>
>> To translate between the MCD API and the TCP data stream coming from the mcdstub,
>> the host has to use a shared library (.dll/.so).
>> Such a shared library will be available soon Lauterbach's open source site
>> and will be linked to from inside this project in a future patch.
> Do you have a timeline for this? Its impossible to test without some
> sort of open implementation of the library.
You can find the library source code here:
https://gitlab.com/lauterbach/mcdrefsrv
It can be built using CMake.
>
>> The MCD API itself can be downloaded here:https://repo.lauterbach.com/sprint_mcd_api_v1_0.zip
>>
>> QUICK START
>> ===========
>>
>> Attention: MCD is currently only supported for qemu-system-arm !
>>
>> Three components are required to Debug QEMU via MCD:
>>
>> 1. qemu-system-arm (built with this patch series applied).
>> 2. MCD shared library (translates between the MCD API and TCP data).
>> 3. Host debugging software with support for the MCD API (e.g.
>> Lauterbach TRACE32).
> We will need some sort of basic implementation to exercise the API as I
> assume TRACE32 is a paid for binary.
I am working on a python script, which directly calls the API functions.
Upon completion it will be added to the mcdrefsrv gitlab.
[-- Attachment #2: Type: text/html, Size: 2818 bytes --]
^ permalink raw reply [flat|nested] 32+ messages in thread