new file mode 100644
@@ -0,0 +1,31 @@
+#ifndef MCDSTUB_H
+#define MCDSTUB_H
+
+#define DEFAULT_MCDSTUB_PORT "1234"
+
+/* MCD breakpoint/watchpoint types */
+#define MCD_BREAKPOINT_SW 0
+#define MCD_BREAKPOINT_HW 1
+#define MCD_WATCHPOINT_WRITE 2
+#define MCD_WATCHPOINT_READ 3
+#define MCD_WATCHPOINT_ACCESS 4
+
+
+/* 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);
+void gdb_register_coprocessor(CPUState *cpu,
+ gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg,
+ int num_regs, const char *xml, int g_pos);
+
+/**
+ * mcdserver_start: start the mcd server
+ * @port_or_device: connection spec for mcd
+ *
+ * This is a TCP port
+ */
+int mcdserver_start(const char *port_or_device);
+
+void gdb_set_stop_cpu(CPUState *cpu);
+
+#endif
new file mode 100644
@@ -0,0 +1,85 @@
+/*
+ * this handeles all system emulation functions for the mcdstub
+ */
+
+#include "exec/mcdstub.h"
+
+int mcdserver_start(const char *device)
+{
+ trace_gdbstub_op_start(device);
+
+ char gdbstub_device_name[128];
+ Chardev *chr = NULL;
+ Chardev *mon_chr;
+
+ if (!first_cpu) {
+ error_report("gdbstub: meaningless to attach gdb to a "
+ "machine without any CPU.");
+ return -1;
+ }
+
+ if (!gdb_supports_guest_debug()) {
+ error_report("gdbstub: current accelerator doesn't "
+ "support guest debugging");
+ return -1;
+ }
+
+ if (!device) {
+ return -1;
+ }
+ if (strcmp(device, "none") != 0) {
+ if (strstart(device, "tcp:", NULL)) {
+ /* enforce required TCP attributes */
+ snprintf(gdbstub_device_name, sizeof(gdbstub_device_name),
+ "%s,wait=off,nodelay=on,server=on", device);
+ device = gdbstub_device_name;
+ }
+#ifndef _WIN32
+ else if (strcmp(device, "stdio") == 0) {
+ struct sigaction act;
+
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = gdb_sigterm_handler;
+ sigaction(SIGINT, &act, NULL);
+ }
+#endif
+ /*
+ * FIXME: it's a bit weird to allow using a mux chardev here
+ * and implicitly setup a monitor. We may want to break this.
+ */
+ chr = qemu_chr_new_noreplay("gdb", device, true, NULL);
+ if (!chr) {
+ return -1;
+ }
+ }
+
+ if (!gdbserver_state.init) {
+ gdb_init_gdbserver_state();
+
+ qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL);
+
+ /* Initialize a monitor terminal for gdb */
+ mon_chr = qemu_chardev_new(NULL, TYPE_CHARDEV_GDB,
+ NULL, NULL, &error_abort);
+ monitor_init_hmp(mon_chr, false, &error_abort);
+ } else {
+ qemu_chr_fe_deinit(&gdbserver_system_state.chr, true);
+ mon_chr = gdbserver_system_state.mon_chr;
+ reset_gdbserver_state();
+ }
+
+ create_processes(&gdbserver_state);
+
+ if (chr) {
+ qemu_chr_fe_init(&gdbserver_system_state.chr, chr, &error_abort);
+ qemu_chr_fe_set_handlers(&gdbserver_system_state.chr,
+ gdb_chr_can_receive,
+ gdb_chr_receive, gdb_chr_event,
+ NULL, &gdbserver_state, NULL, true);
+ }
+ gdbserver_state.state = chr ? RS_IDLE : RS_INACTIVE;
+ gdbserver_system_state.mon_chr = mon_chr;
+ gdb_syscall_reset();
+
+ return 0;
+}
\ No newline at end of file
new file mode 100644
new file mode 100644
@@ -0,0 +1,95 @@
+#include <stdio.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h> // read(), write(), close()
+#define MAX 80
+#define DEFAULT_MCDSTUB_PORT "1234"
+#define SA struct sockaddr
+
+// Function designed for chat between client and server.
+void func(int connfd)
+{
+ char buff[MAX];
+ int n;
+ // infinite loop for chat
+ for (;;) {
+ bzero(buff, MAX);
+
+ // read the message from client and copy it in buffer
+ read(connfd, buff, sizeof(buff));
+ // print buffer which contains the client contents
+ printf("From client: %s\t To client : ", buff);
+ bzero(buff, MAX);
+ n = 0;
+ // copy server message in the buffer
+ while ((buff[n++] = getchar()) != '\n')
+ ;
+
+ // and send that buffer to client
+ write(connfd, buff, sizeof(buff));
+
+ // if msg contains "Exit" then server exit and chat ended.
+ if (strncmp("exit", buff, 4) == 0) {
+ printf("Server Exit...\n");
+ break;
+ }
+ }
+}
+
+// Driver function
+int main()
+{
+ int sockfd, connfd, len;
+ struct sockaddr_in servaddr, cli;
+
+ // socket create and verification
+ sockfd = socket(AF_INET, SOCK_STREAM, 0);
+ if (sockfd == -1) {
+ printf("socket creation failed...\n");
+ exit(0);
+ }
+ else
+ printf("Socket successfully created..\n");
+ bzero(&servaddr, sizeof(servaddr));
+
+ // assign IP, PORT
+ servaddr.sin_family = AF_INET;
+ servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ servaddr.sin_port = htons(DEFAULT_MCDSTUB_PORT);
+
+ // Binding newly created socket to given IP and verification
+ if ((bind(sockfd, (SA*)&servaddr, sizeof(servaddr))) != 0) {
+ printf("socket bind failed...\n");
+ exit(0);
+ }
+ else
+ printf("Socket successfully binded..\n");
+
+ // Now server is ready to listen and verification
+ if ((listen(sockfd, 5)) != 0) {
+ printf("Listen failed...\n");
+ exit(0);
+ }
+ else
+ printf("Server listening..\n");
+ len = sizeof(cli);
+
+ // Accept the data packet from client and verification
+ connfd = accept(sockfd, (SA*)&cli, &len);
+ if (connfd < 0) {
+ printf("server accept failed...\n");
+ exit(0);
+ }
+ else
+ printf("server accept the client...\n");
+
+ // Function for chatting between client and server
+ func(connfd);
+
+ // After chatting close the socket
+ close(sockfd);
+}
new file mode 100644
@@ -1258,6 +1258,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;
@@ -3011,6 +3012,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
From f35f32173f89612158c5618f2e52f3371a004f3b Mon Sep 17 00:00:00 2001
From: Nicolas Eder <nicolas.eder@lauterbach.com>
Date: Fri, 28 Apr 2023 10:19:33 +0200
Subject: [PATCH 02/29] TCP chardev added, handshake with TRACE32 working
Signed-off-by: Nicolas Eder <nicolas.eder@lauterbach.com>
---
gdbstub/gdbstub.c | 2 +-
include/exec/mcdstub.h | 21 +-
include/mcdstub/syscalls.h | 6 +
mcdstub/internals.h | 135 ++++++++++
mcdstub/mcd_softmmu.c | 218 +++++++++++-----
mcdstub/mcd_syscalls.c | 20 ++
mcdstub/mcd_tcp_server.c | 2 +-
mcdstub/mcdstub.c | 519 +++++++++++++++++++++++++++++++++++++
mcdstub/meson.build | 25 ++
meson.build | 1 +
qemu-options.hx | 25 ++
softmmu/vl.c | 9 +
12 files changed, 901 insertions(+), 82 deletions(-)
create mode 100644 include/mcdstub/syscalls.h
create mode 100644 mcdstub/internals.h
create mode 100644 mcdstub/meson.build
@@ -857,7 +857,7 @@ static int process_string_cmd(const char *data,
if (cmd->schema) {
if (cmd_parse_params(&data[strlen(cmd->cmd)],
- cmd->schema, params)) {
+ cmd->schema, params)) {
return -1;
}
}
@@ -1,7 +1,10 @@
#ifndef MCDSTUB_H
#define MCDSTUB_H
-#define DEFAULT_MCDSTUB_PORT "1234"
+#define DEFAULT_MCDSTUB_PORT "1235"
+#define TYPE_CHARDEV_MCD "chardev-mcd"
+#define MX_INPUT_LENGTH 9
+#define MCD_TCP_DATALEN 80
/* MCD breakpoint/watchpoint types */
#define MCD_BREAKPOINT_SW 0
@@ -10,22 +13,12 @@
#define MCD_WATCHPOINT_READ 3
#define MCD_WATCHPOINT_ACCESS 4
-
-/* 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);
-void gdb_register_coprocessor(CPUState *cpu,
- gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg,
- int num_regs, const char *xml, int g_pos);
-
/**
- * mcdserver_start: start the mcd server
- * @port_or_device: connection spec for mcd
+ * mcd_tcp_server_start: start the tcp server to connect via mcd
+ * @device: connection spec for mcd
*
* This is a TCP port
*/
-int mcdserver_start(const char *port_or_device);
-
-void gdb_set_stop_cpu(CPUState *cpu);
+int mcdserver_start(const char *device);
#endif
new file mode 100644
@@ -0,0 +1,6 @@
+#ifndef _SYSCALLS_H_
+#define _SYSCALLS_H_
+
+typedef void (*gdb_syscall_complete_cb)(CPUState *cpu, uint64_t ret, int err);
+
+#endif /* _SYSCALLS_H_ */
\ No newline at end of file
new file mode 100644
@@ -0,0 +1,135 @@
+/*
+ * this header includes a lookup table for the transmitted messages over the tcp connection to trace32,
+ * as well as function declarations for all functios used inside the mcdstub
+ */
+
+#ifndef MCDSTUB_INTERNALS_H
+#define MCDSTUB_INTERNALS_H
+
+#include "exec/cpu-common.h"
+#include "chardev/char.h"
+
+#define MAX_PACKET_LENGTH 1024
+
+/*
+ * lookuptable for transmitted signals
+ */
+
+enum {
+ MCD_SIGNAL_HANDSHAKE = 0
+};
+
+
+/*
+ * struct for an MCD Process, each process can establish one connection
+ */
+
+typedef struct MCDProcess {
+ uint32_t pid;
+ bool attached;
+
+ char target_xml[1024];
+} MCDProcess;
+
+
+/*
+ * not sure for what this is used exactly
+ */
+
+
+enum RSState {
+ RS_INACTIVE,
+ RS_IDLE,
+ RS_GETLINE,
+ RS_GETLINE_ESC,
+ RS_GETLINE_RLE,
+ RS_CHKSUM1,
+ RS_CHKSUM2,
+};
+
+typedef struct MCDState {
+ bool init; /* have we been initialised? */
+ CPUState *c_cpu; /* current CPU for step/continue ops */
+ CPUState *g_cpu; /* current CPU for other ops */
+ CPUState *query_cpu; /* for q{f|s}ThreadInfo */
+ 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;
+ bool multiprocess;
+ MCDProcess *processes;
+ int process_num;
+ GString *str_buf;
+ GByteArray *mem_buf;
+ int sstep_flags;
+ int supported_sstep_flags;
+} MCDState;
+
+/* lives in main mcdstub.c */
+extern MCDState mcdserver_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';
+ }
+}
+
+
+/*old functions
+void mcd_init_mcdserver_state(void);
+int mcd_open_tcp_socket(int tcp_port);
+int mcd_extract_tcp_port_num(const char *in_string, char *out_string);
+*/
+#ifndef _WIN32
+void mcd_sigterm_handler(int signal);
+#endif
+
+void mcd_init_mcdserver_state(void);
+void reset_mcdserver_state(void);
+void create_processes(MCDState *s);
+void mcd_create_default_process(MCDState *s);
+int find_cpu_clusters(Object *child, void *opaque);
+int pid_order(const void *a, const void *b);
+int mcd_chr_can_receive(void *opaque);
+void mcd_chr_receive(void *opaque, const uint8_t *buf, int size);
+void mcd_chr_event(void *opaque, QEMUChrEvent event);
+bool mcd_supports_guest_debug(void);
+void mcd_vm_state_change(void *opaque, bool running, RunState state);
+int mcd_put_packet(const char *buf);
+int mcd_put_packet_binary(const char *buf, int len, bool dump);
+bool mcd_got_immediate_ack(void);
+void mcd_put_buffer(const uint8_t *buf, int len);
+void mcd_set_stop_cpu(CPUState *cpu);
+MCDProcess *mcd_get_cpu_process(CPUState *cpu);
+uint32_t mcd_get_cpu_pid(CPUState *cpu);
+MCDProcess *mcd_get_process(uint32_t pid);
+CPUState *mcd_first_attached_cpu(void);
+CPUState *mcd_next_attached_cpu(CPUState *cpu);
+
+/* sycall handling */
+void mcd_syscall_reset(void);
+
+#endif /* MCDSTUB_INTERNALS_H */
@@ -1,85 +1,171 @@
/*
- * this handeles all system emulation functions for the mcdstub
- */
+#if defined(WIN32)
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0600
+#endif
+#include <winsock2.h>
+#include <ws2tcpip.h>
+//#pragma comment(lib, "Ws2_32.lib")
+#define ISVALIDSOCKET(s) ((s) != INVALID_SOCKET)
+#define CLOSESOCKET(s) closesocket(s)
+#define GETSOCKETERRNO() (WSAGetLastError())
+#else
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <unistd.h>
+//#include <errno.h>
+#define SOCKET int
+#define ISVALIDSOCKET(s) ((s) >= 0)
+#define CLOSESOCKET(s) close(s)
+#define GETSOCKETERRNO() (errno)
+#endif
-#include "exec/mcdstub.h"
+#define SA struct sockaddr
-int mcdserver_start(const char *device)
-{
- trace_gdbstub_op_start(device);
- char gdbstub_device_name[128];
- Chardev *chr = NULL;
- Chardev *mon_chr;
- if (!first_cpu) {
- error_report("gdbstub: meaningless to attach gdb to a "
- "machine without any CPU.");
- return -1;
- }
+#include "exec/mcdstub.h"
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "qemu/cutils.h"
+#include "gdbstub/syscalls.h"
+#include "exec/hwaddr.h"
+#include "exec/tb-flush.h"
+#include "sysemu/cpus.h"
+#include "sysemu/runstate.h"
+#include "sysemu/replay.h"
+#include "hw/core/cpu.h"
+#include "hw/cpu/cluster.h"
+#include "hw/boards.h"
+#include "chardev/char.h"
+#include "chardev/char-fe.h"
+#include "monitor/monitor.h"
+#include "internals.h"
- if (!gdb_supports_guest_debug()) {
- error_report("gdbstub: current accelerator doesn't "
- "support guest debugging");
- return -1;
- }
+//here only deprecated code:
- if (!device) {
+int old_mcdserver_start(const char *device)
+{
+ //the device is a char array. if its "default" we use tcp with the default DEFAULT_MCDSTUB_PORT. Otherwise it has to look like "tcp::<tcpport>"
+ char tcp_port[MX_INPUT_LENGTH];
+ int error;
+ error = mcd_extract_tcp_port_num(device, tcp_port);
+ if (error != 0) {
return -1;
}
- if (strcmp(device, "none") != 0) {
- if (strstart(device, "tcp:", NULL)) {
- /* enforce required TCP attributes */
- snprintf(gdbstub_device_name, sizeof(gdbstub_device_name),
- "%s,wait=off,nodelay=on,server=on", device);
- device = gdbstub_device_name;
- }
-#ifndef _WIN32
- else if (strcmp(device, "stdio") == 0) {
- struct sigaction act;
-
- memset(&act, 0, sizeof(act));
- act.sa_handler = gdb_sigterm_handler;
- sigaction(SIGINT, &act, NULL);
- }
-#endif
- /*
- * FIXME: it's a bit weird to allow using a mux chardev here
- * and implicitly setup a monitor. We may want to break this.
- */
- chr = qemu_chr_new_noreplay("gdb", device, true, NULL);
- if (!chr) {
- return -1;
- }
+ int tcp_port_num = atoi(tcp_port);
+
+ if (!mcdserver_state.init) {
+ mcd_init_mcdserver_state();
}
+ return mcd_open_tcp_socket(tcp_port_num);
+}
+
+int mcd_open_tcp_socket(int tcp_port)
+//soon to be deprecated (hopefully)
+{
+ SOCKET socked_fd, connect_fd;
+ struct sockaddr_in server_address, client_address;
+
+#if defined(WIN32)
+ WSADATA d;
+ if (WSAStartup(MAKEWORD(2, 2), &d)) {
+ return -1;
+ }
+ int len;
+#else
+ unsigned int len;
+#endif
- if (!gdbserver_state.init) {
- gdb_init_gdbserver_state();
+ // socket create and verification
+ socked_fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (!ISVALIDSOCKET(socked_fd)) {
+ return -1;
+ }
+ memset(&server_address, 0, sizeof(server_address));
- qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL);
+ // assign IP, PORT
+ server_address.sin_family = AF_INET;
+ server_address.sin_port = htons(tcp_port);
+ server_address.sin_addr.s_addr = htonl(INADDR_ANY);
- /* Initialize a monitor terminal for gdb */
- mon_chr = qemu_chardev_new(NULL, TYPE_CHARDEV_GDB,
- NULL, NULL, &error_abort);
- monitor_init_hmp(mon_chr, false, &error_abort);
- } else {
- qemu_chr_fe_deinit(&gdbserver_system_state.chr, true);
- mon_chr = gdbserver_system_state.mon_chr;
- reset_gdbserver_state();
+ // Binding newly created socket to given IP and verification
+ if ((bind(socked_fd, (SA*)&server_address, sizeof(server_address))) != 0) {
+ CLOSESOCKET(socked_fd);
+ return -1;
+ }
+
+ // Now server is ready to listen and verification
+ if ((listen(socked_fd, 5)) != 0) {
+ CLOSESOCKET(socked_fd);
+ return -1;
+ }
+ else {
+ printf("TCP server listening on port %d\n", tcp_port);
+ }
+
+ //accepting connection
+ len = sizeof(client_address);
+ connect_fd = accept(socked_fd, (SA*)&client_address, &len);
+ if (!ISVALIDSOCKET(connect_fd)) {
+ CLOSESOCKET(socked_fd);
+ return -1;
}
- create_processes(&gdbserver_state);
+ //lets do the handshake
+
+ char buff[MCD_TCP_DATALEN];
+ char expected_buff[MCD_TCP_DATALEN];
- if (chr) {
- qemu_chr_fe_init(&gdbserver_system_state.chr, chr, &error_abort);
- qemu_chr_fe_set_handlers(&gdbserver_system_state.chr,
- gdb_chr_can_receive,
- gdb_chr_receive, gdb_chr_event,
- NULL, &gdbserver_state, NULL, true);
+ memset(buff, 0, sizeof(buff));
+ memset(expected_buff, 0, sizeof(buff));
+ strcpy((char*)expected_buff, "initializing handshake");
+
+ // read the message from client
+ recv(connect_fd, buff, MCD_TCP_DATALEN, 0);
+
+ if (strcmp(buff, expected_buff)==0) {
+ strcpy((char*)buff, "shaking your hand");
+ send(connect_fd, buff, MCD_TCP_DATALEN, 0);
+ printf("handshake complete\n");
+ return 0;
+ }
+ else {
+ CLOSESOCKET(socked_fd);
+ CLOSESOCKET(connect_fd);
+ return -1;
+ }
+}
+
+int mcd_extract_tcp_port_num(const char *in_string, char *out_string)
+{
+ int string_length = strlen(in_string);
+ if (string_length>MX_INPUT_LENGTH+1) {
+ return -1;
}
- gdbserver_state.state = chr ? RS_IDLE : RS_INACTIVE;
- gdbserver_system_state.mon_chr = mon_chr;
- gdb_syscall_reset();
+ const char default_str[] = "default";
+
+ if ((string_length==strlen(default_str)) && (strcmp(default_str, in_string)==0)) {
+ strcpy((char*)out_string, DEFAULT_MCDSTUB_PORT);
+ return 0;
+ }
+ else if (strcmp("tcp::", in_string)==0) {
+ for (int index = 5; index < string_length; index++) {
+ if (!isdigit(in_string[index])) {
+ return -1;
+ }
+ }
+ }
+ else {
+ return -1;
+ }
+ strcpy((char*)out_string, in_string+5);
return 0;
-}
\ No newline at end of file
+}
+
+*/
\ No newline at end of file
@@ -0,0 +1,20 @@
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "semihosting/semihost.h"
+#include "sysemu/runstate.h"
+#include "mcdstub/syscalls.h"
+//#include "trace.h"
+#include "internals.h"
+
+typedef struct {
+ char syscall_buf[256];
+ //TODO: this needs to be get fixed mcd_syscall_complete_cb
+ int current_syscall_cb;
+} MCDSyscallState;
+
+static MCDSyscallState mcdserver_syscall_state;
+
+void mcd_syscall_reset(void)
+{
+ mcdserver_syscall_state.current_syscall_cb = 0;
+}
\ No newline at end of file
@@ -6,8 +6,8 @@
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h> // read(), write(), close()
+#include "exec/mcdstub.h"
#define MAX 80
-#define DEFAULT_MCDSTUB_PORT "1234"
#define SA struct sockaddr
// Function designed for chat between client and server.
@@ -0,0 +1,519 @@
+/*
+ * This is the main mcdstub. It needs to be complemented by other mcd stubs for each target.
+ */
+
+//from original gdbstub.c
+#include "qemu/osdep.h"
+#include "qemu/ctype.h"
+#include "qemu/cutils.h"
+#include "qemu/module.h"
+#include "qemu/error-report.h"
+//#include "trace.h"
+#include "exec/mcdstub.h"
+#include "mcdstub/syscalls.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 "internals.h"
+
+//from original softmmu.c (minus what was already here)
+#include "qapi/error.h"
+#include "exec/tb-flush.h"
+#include "sysemu/cpus.h"
+#include "sysemu/replay.h"
+#include "hw/core/cpu.h"
+#include "chardev/char.h"
+#include "chardev/char-fe.h"
+#include "monitor/monitor.h"
+
+typedef struct {
+ CharBackend chr;
+ //Chardev *mon_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.
+ */
+ // TODO:
+ // this is weird and might be able to sit just like it is here with the same value as for gdb
+ 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;
+}
+
+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);
+
+ 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];
+
+ /*
+ * GDB process IDs -1 and 0 are reserved. To avoid subtle errors at
+ * runtime, we enforce here that the machine does not use a cluster ID
+ * that would lead to PID 0.
+ */
+ 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)
+{
+ //might wann add tracing later (no idea for what this is used)
+ //trace_gdbstub_op_start(device);
+
+ char mcdstub_device_name[128];
+ Chardev *chr = NULL;
+ //Chardev *mon_chr;
+
+ 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 device = tcp::1235
+ if (strcmp(device, "default") == 0) {
+ device = "tcp::1235";
+ }
+
+ if (strcmp(device, "none") != 0) {
+ if (strstart(device, "tcp:", NULL)) {
+ /* enforce required TCP attributes */
+ snprintf(mcdstub_device_name, sizeof(mcdstub_device_name),
+ "%s,wait=off,nodelay=on,server=on", device);
+ device = mcdstub_device_name;
+ }
+#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);
+ }
+#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);
+
+ /* Initialize a monitor terminal for mcd */
+ //mon_chr = qemu_chardev_new(NULL, TYPE_CHARDEV_MCD, NULL, NULL, &error_abort);
+ //monitor_init_hmp(mon_chr, false, &error_abort);
+ } else {
+ qemu_chr_fe_deinit(&mcdserver_system_state.chr, true);
+ //mon_chr = mcdserver_system_state.mon_chr;
+ 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;
+ //mcdserver_system_state.mon_chr = mon_chr;
+ mcd_syscall_reset();
+
+ 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)
+{
+ printf("incoming buffer: %s\n", buf);
+ char send_buffer[] = "shaking your hand";
+ mcd_put_packet(send_buffer);
+ //int i;
+ /*
+ for (i = 0; i < size; i++) {
+ //TODO: some byte reading or idk gdb_read_byte(buf[i]);
+ }*/
+}
+
+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();
+ s->g_cpu = s->c_cpu;
+
+ vm_stop(RUN_STATE_PAUSED);
+ //TODO: this might not be necessary
+ //replay_gdb_attached();
+ //gdb_has_xml = false;
+ 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
+
+void mcd_vm_state_change(void *opaque, bool running, RunState state)
+{
+ printf("this calls state_change\n");
+ /*
+ CPUState *cpu = mcdserver_state.c_cpu;
+ g_autoptr(GString) buf = g_string_new(NULL);
+ g_autoptr(GString) tid = g_string_new(NULL);
+ const char *type;
+ int ret;
+
+ if (running || mcdserver_state.state == RS_INACTIVE) {
+ return;
+ }
+
+ //Is there a GDB syscall waiting to be sent?
+ if (gdb_handled_syscall()) {
+ return;
+ }
+
+ if (cpu == NULL) {
+ //No process attached
+ return;
+ }
+
+ gdb_append_thread_id(cpu, tid);
+
+ switch (state) {
+ case RUN_STATE_DEBUG:
+ if (cpu->watchpoint_hit) {
+ switch (cpu->watchpoint_hit->flags & BP_MEM_ACCESS) {
+ case BP_MEM_READ:
+ type = "r";
+ break;
+ case BP_MEM_ACCESS:
+ type = "a";
+ break;
+ default:
+ type = "";
+ break;
+ }
+ trace_gdbstub_hit_watchpoint(type,
+ gdb_get_cpu_index(cpu),
+ cpu->watchpoint_hit->vaddr);
+ g_string_printf(buf, "T%02xthread:%s;%swatch:%" VADDR_PRIx ";",
+ GDB_SIGNAL_TRAP, tid->str, type,
+ cpu->watchpoint_hit->vaddr);
+ cpu->watchpoint_hit = NULL;
+ goto send_packet;
+ } else {
+ trace_gdbstub_hit_break();
+ }
+ tb_flush(cpu);
+ ret = GDB_SIGNAL_TRAP;
+ break;
+ case RUN_STATE_PAUSED:
+ trace_gdbstub_hit_paused();
+ ret = GDB_SIGNAL_INT;
+ break;
+ case RUN_STATE_SHUTDOWN:
+ trace_gdbstub_hit_shutdown();
+ ret = GDB_SIGNAL_QUIT;
+ break;
+ case RUN_STATE_IO_ERROR:
+ trace_gdbstub_hit_io_error();
+ ret = GDB_SIGNAL_IO;
+ break;
+ case RUN_STATE_WATCHDOG:
+ trace_gdbstub_hit_watchdog();
+ ret = GDB_SIGNAL_ALRM;
+ break;
+ case RUN_STATE_INTERNAL_ERROR:
+ trace_gdbstub_hit_internal_error();
+ ret = GDB_SIGNAL_ABRT;
+ break;
+ case RUN_STATE_SAVE_VM:
+ case RUN_STATE_RESTORE_VM:
+ return;
+ case RUN_STATE_FINISH_MIGRATE:
+ ret = GDB_SIGNAL_XCPU;
+ break;
+ default:
+ trace_gdbstub_hit_unknown(state);
+ ret = GDB_SIGNAL_UNKNOWN;
+ break;
+ }
+ mcd_set_stop_cpu(cpu);
+ g_string_printf(buf, "T%02xthread:%s;", ret, tid->str);
+
+send_packet:
+ mcd_put_packet(buf->str);
+
+ // disable single step if it was enabled
+ cpu_single_step(cpu, 0);
+*/
+}
+
+int mcd_put_packet(const char *buf)
+{
+ //tracing
+ //trace_gdbstub_io_reply(buf);
+
+ return mcd_put_packet_binary(buf, strlen(buf), false);
+}
+
+int mcd_put_packet_binary(const char *buf, int len, bool dump)
+{
+ //int csum, i;
+ //uint8_t footer[3];
+
+ //trace stuff
+ //if (dump && trace_event_get_state_backends(TRACE_GDBSTUB_IO_BINARYREPLY)) {
+ // hexdump(buf, len, trace_gdbstub_io_binaryreply);
+ //}
+
+ for(;;) {
+ //super interesting if we want a chekcsum or something like that here!!
+ g_byte_array_set_size(mcdserver_state.last_packet, 0);
+ //g_byte_array_append(mcdserver_state.last_packet, (const uint8_t *) "$", 1);
+ g_byte_array_append(mcdserver_state.last_packet,
+ (const uint8_t *) buf, len);
+ /*
+ csum = 0;
+ for(i = 0; i < len; i++) {
+ csum += buf[i];
+ }
+ footer[0] = '#';
+ footer[1] = tohex((csum >> 4) & 0xf);
+ footer[2] = tohex((csum) & 0xf);
+ g_byte_array_append(mcdserver_state.last_packet, footer, 3);
+ */
+ mcd_put_buffer(mcdserver_state.last_packet->data,
+ mcdserver_state.last_packet->len);
+
+ if (mcd_got_immediate_ack()) {
+ break;
+ }
+ }
+ return 0;
+}
+
+bool mcd_got_immediate_ack(void)
+{
+ return true;
+}
+
+void mcd_put_buffer(const uint8_t *buf, int len)
+{
+ /*
+ * XXX this blocks entire thread. Rewrite to use
+ * qemu_chr_fe_write and background I/O callbacks
+ */
+ qemu_chr_fe_write_all(&mcdserver_system_state.chr, buf, len);
+}
+
+void mcd_set_stop_cpu(CPUState *cpu)
+{
+ MCDProcess *p = mcd_get_cpu_process(cpu);
+
+ if (!p->attached) {
+ /*
+ * Having a stop CPU corresponding to a process that is not attached
+ * confuses GDB. So we ignore the request.
+ */
+ return;
+ }
+
+ mcdserver_state.c_cpu = cpu;
+ mcdserver_state.g_cpu = cpu;
+}
+
+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) {
+ /* 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_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;
+}
\ No newline at end of file
new file mode 100644
@@ -0,0 +1,25 @@
+#
+# The main gdbstub still relies on per-build definitions of various
+# types. The bits pushed to softmmu/user.c try to use guest agnostic
+# types such as hwaddr.
+#
+
+# We need to build the core mcd code via a library to be able to tweak
+# cflags so:
+
+mcd_softmmu_ss = ss.source_set()
+
+# We build one version of the mcdstub, because it only needs to work for system emulation
+mcd_softmmu_ss.add(files('mcdstub.c'))
+
+mcd_softmmu_ss = mcd_softmmu_ss.apply(config_host, strict: false)
+
+libmcd_softmmu = static_library('mcd_softmmu',
+ mcd_softmmu_ss.sources() + genh,
+ name_suffix: 'fa')
+
+mcd_softmmu = declare_dependency(link_whole: libmcd_softmmu)
+softmmu_ss.add(mcd_softmmu)
+
+# this might cause problems because we don't support user mode
+common_ss.add(files('mcd_syscalls.c'))
@@ -3356,6 +3356,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')
@@ -4414,6 +4414,31 @@ 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",
+ 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::1234
+ERST
+
+DEF("mcdd", 0, QEMU_OPTION_mcdd, \
+ "-mcdd shorthand for -mcd tcp::" DEFAULT_MCDSTUB_PORT "\n",
+ QEMU_ARCH_ALL)
+SRST
+``-mcdd``
+ Shorthand for -mcd tcp::1234, i.e. open a mcdserver on TCP port 1234
+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)
@@ -68,6 +68,7 @@
#include "sysemu/numa.h"
#include "sysemu/hostmem.h"
#include "exec/gdbstub.h"
+#include "exec/mcdstub.h"
#include "qemu/timer.h"
#include "chardev/char.h"
#include "qemu/bitmap.h"
@@ -2662,6 +2663,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 "
--
2.34.1
From 73eea6655ba8a7c79c7d3212e261e9744bbb8a87 Mon Sep 17 00:00:00 2001
From: Nicolas Eder <nicolas.eder@lauterbach.com>
Date: Fri, 2 Jun 2023 16:54:56 +0200
Subject: [PATCH 03/29] TCP packet handling added
Signed-off-by: Nicolas Eder <nicolas.eder@lauterbach.com>
---
mcdstub/internals.h | 64 ++++-
mcdstub/mcd_syscalls.c | 11 +
mcdstub/mcdstub.c | 541 +++++++++++++++++++++++++++++++++++++++--
3 files changed, 596 insertions(+), 20 deletions(-)
@@ -25,12 +25,42 @@ enum {
*/
typedef struct MCDProcess {
+ //this is probably what we would call a system (in qemu its a cluster)
uint32_t pid;
bool attached;
char target_xml[1024];
} MCDProcess;
+typedef void (*MCDCmdHandler)(GArray *params, void *user_ctx);
+typedef struct MCDCmdParseEntry {
+ MCDCmdHandler handler;
+ const char *cmd;
+ bool cmd_startswith;
+ const char *schema;
+} MCDCmdParseEntry;
+
+typedef enum MCDThreadIdKind {
+ GDB_ONE_THREAD = 0,
+ GDB_ALL_THREADS, /* One process, all threads */
+ GDB_ALL_PROCESSES,
+ GDB_READ_THREAD_ERR
+} MCDThreadIdKind;
+
+typedef union MCDCmdVariant {
+ const char *data;
+ uint8_t opcode;
+ unsigned long val_ul;
+ unsigned long long val_ull;
+ struct {
+ MCDThreadIdKind kind;
+ uint32_t pid;
+ uint32_t tid;
+ } thread_id;
+} MCDCmdVariant;
+
+#define get_param(p, i) (&g_array_index(p, MCDCmdVariant, i))
+
/*
* not sure for what this is used exactly
@@ -41,10 +71,11 @@ enum RSState {
RS_INACTIVE,
RS_IDLE,
RS_GETLINE,
- RS_GETLINE_ESC,
- RS_GETLINE_RLE,
- RS_CHKSUM1,
- RS_CHKSUM2,
+ RS_DATAEND,
+ //RS_GETLINE_ESC,
+ //RS_GETLINE_RLE,
+ //RS_CHKSUM1,
+ //RS_CHKSUM2,
};
typedef struct MCDState {
@@ -59,11 +90,13 @@ typedef struct MCDState {
int line_csum; /* checksum at the end of the packet */
GByteArray *last_packet;
int signal;
- bool multiprocess;
+ //the next one is about stub compatibility and we should be able to assume this is true anyway
+ //bool multiprocess;
MCDProcess *processes;
int process_num;
GString *str_buf;
GByteArray *mem_buf;
+ // maybe we don't need those flags
int sstep_flags;
int supported_sstep_flags;
} MCDState;
@@ -128,8 +161,29 @@ uint32_t mcd_get_cpu_pid(CPUState *cpu);
MCDProcess *mcd_get_process(uint32_t pid);
CPUState *mcd_first_attached_cpu(void);
CPUState *mcd_next_attached_cpu(CPUState *cpu);
+void mcd_read_byte(uint8_t ch);
+int mcd_handle_packet(const char *line_buf);
+void mcd_put_strbuf(void);
+void mcd_exit(int code);
+void run_cmd_parser(const char *data, const MCDCmdParseEntry *cmd);
+int process_string_cmd(void *user_ctx, const char *data, const MCDCmdParseEntry *cmds, int num_cmds);
+int cmd_parse_params(const char *data, const char *schema, GArray *params);
+void handle_continue(GArray *params, void *user_ctx);
+void handle_gen_query(GArray *params, void *user_ctx);
+void mcd_append_thread_id(CPUState *cpu, GString *buf);
+int mcd_get_cpu_index(CPUState *cpu);
+CPUState* mcd_get_cpu(uint32_t i_cpu_index);
+void handle_query_cores(GArray *params, void *user_ctx);
+void handle_query_system(GArray *params, void *user_ctx);
+CPUState *get_first_cpu_in_process(MCDProcess *process);
+CPUState *find_cpu(uint32_t thread_id);
+void handle_core_open(GArray *params, void *user_ctx);
+void handle_query_reset(GArray *params, void *user_ctx);
+void handle_detach(GArray *params, void *user_ctx);
+void mcd_continue(void);
/* sycall handling */
void mcd_syscall_reset(void);
+void mcd_disable_syscalls(void);
#endif /* MCDSTUB_INTERNALS_H */
@@ -12,9 +12,20 @@ typedef struct {
int current_syscall_cb;
} MCDSyscallState;
+static enum {
+ MCD_SYS_UNKNOWN,
+ MCD_SYS_ENABLED,
+ MCD_SYS_DISABLED,
+} mcd_syscall_mode;
+
static MCDSyscallState mcdserver_syscall_state;
void mcd_syscall_reset(void)
{
mcdserver_syscall_state.current_syscall_cb = 0;
+}
+
+void mcd_disable_syscalls(void)
+{
+ mcd_syscall_mode = MCD_SYS_DISABLED;
}
\ No newline at end of file
@@ -31,6 +31,9 @@
#include "chardev/char-fe.h"
#include "monitor/monitor.h"
+// just used for the xml_builtin stuff
+//#include "exec/gdbstub.h" /* xml_builtin */
+
typedef struct {
CharBackend chr;
//Chardev *mon_chr;
@@ -40,6 +43,22 @@ MCDSystemState mcdserver_system_state;
MCDState mcdserver_state;
+static const MCDCmdParseEntry mcd_gen_query_table[] = {
+ // this is a list of all query commands. it gets iterated over only the handler of the matching command will get executed
+ {
+ .handler = handle_query_system,
+ .cmd = "system",
+ },
+ {
+ .handler = handle_query_cores,
+ .cmd = "cores",
+ },
+ {
+ .handler = handle_query_reset,
+ .cmd = "reset",
+ },
+};
+
void mcd_init_mcdserver_state(void)
{
g_assert(!mcdserver_state.init);
@@ -55,7 +74,7 @@ void mcd_init_mcdserver_state(void)
* stepping so as to make single stepping like a typical ICE HW step.
*/
// TODO:
- // this is weird and might be able to sit just like it is here with the same value as for gdb
+ // this is weird and we might not actually need it after all
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;
@@ -235,14 +254,343 @@ int mcd_chr_can_receive(void *opaque)
void mcd_chr_receive(void *opaque, const uint8_t *buf, int size)
{
- printf("incoming buffer: %s\n", buf);
- char send_buffer[] = "shaking your hand";
- mcd_put_packet(send_buffer);
- //int i;
- /*
+ int i;
+
for (i = 0; i < size; i++) {
- //TODO: some byte reading or idk gdb_read_byte(buf[i]);
- }*/
+ mcd_read_byte(buf[i]);
+ }
+}
+
+void mcd_read_byte(uint8_t ch)
+{
+ uint8_t reply;
+
+ if (mcdserver_state.last_packet->len) {
+ /* Waiting for a response to the last packet. If we see the start
+ of a new command then abandon the previous response. */
+ if (ch == '-') {
+ //the previous packet was not akcnowledged
+ //trace_gdbstub_err_got_nack();
+ //we are resending the last packet
+ mcd_put_buffer(mcdserver_state.last_packet->data, mcdserver_state.last_packet->len);
+ }
+ else if (ch == '+') {
+ //the previous packet was acknowledged
+ //trace_gdbstub_io_got_ack();
+ }
+
+ if (ch == '+' || ch == '$') {
+ //either acknowledged or a new communication starts -> we discard previous communication
+ g_byte_array_set_size(mcdserver_state.last_packet, 0);
+ }
+ if (ch != '$') {
+ // we only continue if we are processing a new commant. otherwise we skip to ne next character in the packet which sould be a $
+ return;
+ }
+ }
+ if (runstate_is_running()) {
+ /* when the CPU is running, we cannot do anything except stop
+ it when receiving a char */
+ vm_stop(RUN_STATE_PAUSED);
+ }
+ else {
+ switch(mcdserver_state.state) {
+ case RS_IDLE:
+ if (ch == '$') {
+ /* start of command packet */
+ mcdserver_state.line_buf_index = 0;
+ mcdserver_state.line_sum = 0;
+ mcdserver_state.state = RS_GETLINE;
+ }
+ else {
+ //new communication has to start with a $
+ //trace_gdbstub_err_garbage(ch);
+ }
+ break;
+ case RS_GETLINE:
+ if (ch == '#') {
+ /* end of command, start of checksum*/
+ 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!
+ //trace_gdbstub_err_overrun();
+ mcdserver_state.state = RS_IDLE;
+ }
+ else {
+ /* unescaped command character */
+ //this means the character is part of the real content fo the packet and we copy it to the line_buf
+ mcdserver_state.line_buf[mcdserver_state.line_buf_index++] = ch;
+ mcdserver_state.line_sum += ch;
+ }
+ break;
+ case RS_DATAEND:
+ // we are now done with copying the data and in the suffix of the packet
+ // TODO: maybe wanna implement a checksum or sth like the gdb protocol has
+
+ if (ch == '~') {
+ // ~ indicates that there is an additional package coming
+ //acknowledged -> send +
+ reply = '+';
+ mcd_put_buffer(&reply, 1);
+ mcdserver_state.state = mcd_handle_packet(mcdserver_state.line_buf);
+ }
+ else if (ch == '|') {
+ //acknowledged -> send +
+ // | indicates that there is no additional package coming
+ reply = '+';
+ mcd_put_buffer(&reply, 1);
+ mcdserver_state.state = mcd_handle_packet(mcdserver_state.line_buf);
+ }
+ else {
+ //trace_gdbstub_err_checksum_incorrect(mcdserver_state.line_sum, mcdserver_state.line_csum);
+ //not acknowledged -> send -
+ reply = '-';
+ 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 what the first character in the line_buf is!
+ const MCDCmdParseEntry *cmd_parser = NULL;
+
+ //trace_gdbstub_io_command(line_buf);
+
+ switch (line_buf[0]) {
+ case 'i':
+ //handshake
+ mcd_put_packet("shaking your hand");
+ //gdb_put_packet("OK");
+ break;
+ case 'c':
+ //go command
+ {
+ static const MCDCmdParseEntry continue_cmd_desc = {
+ .handler = handle_continue,
+ .cmd = "c",
+ //.cmd_startswith = 1,
+ //.schema = "L0"
+ };
+ cmd_parser = &continue_cmd_desc;
+ }
+ break;
+ case 'k':
+ // kill qemu completely
+ error_report("QEMU: Terminated via MCDstub");
+ mcd_exit(0);
+ exit(0);
+ case 'q':
+ //query inquiry
+ {
+ static const MCDCmdParseEntry gen_query_cmd_desc = {
+ .handler = handle_gen_query,
+ .cmd = "q",
+ //.cmd_startswith = 1,
+ .schema = "ss"
+ };
+ cmd_parser = &gen_query_cmd_desc;
+ }
+ break;
+ case 'H':
+ //current alias for open core, later this will probably be a part of the 'i' requests
+ {
+ static const MCDCmdParseEntry gen_core_open = {
+ .handler = handle_core_open,
+ .cmd = "H",
+ //.cmd_startswith = 1,
+ .schema = "ss"
+ };
+ cmd_parser = &gen_core_open;
+ }
+ break;
+ case 'D':
+ {
+ static const MCDCmdParseEntry detach_cmd_desc = {
+ .handler = handle_detach,
+ .cmd = "D",
+ //.cmd_startswith = 1,
+ //.schema = "?.l0"
+ };
+ cmd_parser = &detach_cmd_desc;
+ }
+ break;
+ default:
+ //could not perform the command (because its unknown)
+ mcd_put_packet("");
+ break;
+ }
+
+ if (cmd_parser) {
+ //now parse commands and run the selected function (handler)
+ run_cmd_parser(line_buf, cmd_parser);
+ }
+
+ return RS_IDLE;
+}
+
+void handle_continue(GArray *params, void *user_ctx)
+{
+ /*
+ if (params->len) {
+ gdb_set_cpu_pc(get_param(params, 0)->val_ull);
+ }
+
+ mcdserver_state.signal = 0;
+ gdb_continue();
+ */
+}
+
+void handle_gen_query(GArray *params, void *user_ctx)
+{
+ if (!params->len) {
+ return;
+ }
+ //now iterate over all possible query functions and execute the right one
+ if (process_string_cmd(NULL, get_param(params, 0)->data,
+ mcd_gen_query_table,
+ ARRAY_SIZE(mcd_gen_query_table))) {
+ mcd_put_packet("");
+ }
+}
+
+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);
+
+ /* In case there was an error during the command parsing we must
+ * send a NULL packet to indicate the command is not supported */
+ if (process_string_cmd(NULL, data, cmd, 1)) {
+ mcd_put_packet("");
+ }
+}
+
+int cmd_parse_params(const char *data, const char *schema, GArray *params)
+{
+ MCDCmdVariant this_param;
+ this_param.data = data;
+ g_array_append_val(params, this_param);
+ /*
+ const char *curr_schema, *curr_data;
+
+ g_assert(schema);
+ g_assert(params->len == 0);
+
+ curr_schema = schema;
+ curr_data = data;
+ while (curr_schema[0] && curr_schema[1] && *curr_data) {
+ GdbCmdVariant this_param;
+
+ switch (curr_schema[0]) {
+ case 'l':
+ if (qemu_strtoul(curr_data, &curr_data, 16,
+ &this_param.val_ul)) {
+ return -EINVAL;
+ }
+ curr_data = cmd_next_param(curr_data, curr_schema[1]);
+ g_array_append_val(params, this_param);
+ break;
+ case 'L':
+ if (qemu_strtou64(curr_data, &curr_data, 16,
+ (uint64_t *)&this_param.val_ull)) {
+ return -EINVAL;
+ }
+ curr_data = cmd_next_param(curr_data, curr_schema[1]);
+ g_array_append_val(params, this_param);
+ break;
+ case 's':
+ this_param.data = curr_data;
+ curr_data = cmd_next_param(curr_data, curr_schema[1]);
+ g_array_append_val(params, this_param);
+ break;
+ case 'o':
+ this_param.opcode = *(uint8_t *)curr_data;
+ curr_data = cmd_next_param(curr_data, curr_schema[1]);
+ g_array_append_val(params, this_param);
+ break;
+ case 't':
+ this_param.thread_id.kind =
+ read_thread_id(curr_data, &curr_data,
+ &this_param.thread_id.pid,
+ &this_param.thread_id.tid);
+ curr_data = cmd_next_param(curr_data, curr_schema[1]);
+ g_array_append_val(params, this_param);
+ break;
+ case '?':
+ curr_data = cmd_next_param(curr_data, curr_schema[1]);
+ break;
+ default:
+ return -EINVAL;
+ }
+ curr_schema += 2;
+ }
+ */
+ 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];
+ //terminate if we don't have handler and cmd
+ g_assert(cmd->handler && cmd->cmd);
+
+ // if data and command are different continue
+ if (strncmp(data, cmd->cmd, strlen(cmd->cmd))) {
+ continue;
+ }
+
+ // if a schema is provided we need to extract parameters from the data string
+ if (cmd->schema) {
+ //currently doing nothing
+ if (cmd_parse_params(&data[strlen(cmd->cmd)], cmd->schema, params)) {
+ return -1;
+ }
+ }
+
+ // the correct handler function is called
+ cmd->handler(params, user_ctx);
+ return 0;
+ }
+
+ return -1;
+}
+
+void mcd_exit(int code)
+{
+ char buf[4];
+
+ if (!mcdserver_state.init) {
+ return;
+ }
+
+ //trace_gdbstub_op_exiting((uint8_t)code);
+
+ //need to check what is sent here and dapt it to my needs
+ snprintf(buf, sizeof(buf), "W%02x", (uint8_t)code);
+ mcd_put_packet(buf);
+
+ qemu_chr_fe_deinit(&mcdserver_system_state.chr, true);
}
void mcd_chr_event(void *opaque, QEMUChrEvent event)
@@ -392,6 +740,11 @@ int mcd_put_packet(const char *buf)
return mcd_put_packet_binary(buf, strlen(buf), false);
}
+void mcd_put_strbuf(void)
+{
+ mcd_put_packet(mcdserver_state.str_buf->str);
+}
+
int mcd_put_packet_binary(const char *buf, int len, bool dump)
{
//int csum, i;
@@ -405,9 +758,10 @@ int mcd_put_packet_binary(const char *buf, int len, bool dump)
for(;;) {
//super interesting if we want a chekcsum or something like that here!!
g_byte_array_set_size(mcdserver_state.last_packet, 0);
- //g_byte_array_append(mcdserver_state.last_packet, (const uint8_t *) "$", 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 *) "$", 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 *) "#", 1);
+ g_byte_array_append(mcdserver_state.last_packet, (const uint8_t *) "|", 1);
/*
csum = 0;
for(i = 0; i < len; i++) {
@@ -418,8 +772,7 @@ int mcd_put_packet_binary(const char *buf, int len, bool dump)
footer[2] = tohex((csum) & 0xf);
g_byte_array_append(mcdserver_state.last_packet, footer, 3);
*/
- mcd_put_buffer(mcdserver_state.last_packet->data,
- mcdserver_state.last_packet->len);
+ mcd_put_buffer(mcdserver_state.last_packet->data, mcdserver_state.last_packet->len);
if (mcd_got_immediate_ack()) {
break;
@@ -453,7 +806,7 @@ void mcd_set_stop_cpu(CPUState *cpu)
*/
return;
}
-
+ //FIXME: we probably can delete this because in the opern_core function we set these two anyway
mcdserver_state.c_cpu = cpu;
mcdserver_state.g_cpu = cpu;
}
@@ -470,6 +823,7 @@ uint32_t mcd_get_cpu_pid(CPUState *cpu)
int index = mcdserver_state.process_num - 1;
return mcdserver_state.processes[index].pid;
}
+ // TODO: maybe +1 because we start numbering at 1
return cpu->cluster_index + 1;
}
@@ -491,6 +845,19 @@ MCDProcess *mcd_get_process(uint32_t pid)
return NULL;
}
+CPUState* mcd_get_cpu(uint32_t i_cpu_index) {
+ CPUState *cpu = first_cpu;
+
+ while (cpu) {
+ if (cpu->cpu_index == i_cpu_index) {
+ return cpu;
+ }
+ cpu = mcd_next_attached_cpu(cpu);
+ }
+
+ return cpu;
+}
+
CPUState *mcd_first_attached_cpu(void)
{
CPUState *cpu = first_cpu;
@@ -516,4 +883,148 @@ CPUState *mcd_next_attached_cpu(CPUState *cpu)
}
return cpu;
-}
\ No newline at end of file
+}
+/*
+void handle_query_first_threads(GArray *params, void *user_ctx)
+{
+ // chache the first cpu
+ mcdserver_state.query_cpu = mcd_first_attached_cpu();
+ // new answer over tcp
+ handle_query_threads(params, user_ctx);
+}
+
+void handle_query_threads(GArray *params, void *user_ctx)
+{
+ if (!mcdserver_state.query_cpu) {
+ // send packet back that that there is no more threads
+ //gdb_put_packet("l");
+ return;
+ }
+
+ g_string_assign(mcdserver_state.str_buf, "m");
+ mcd_append_thread_id(mcdserver_state.query_cpu, mcdserver_state.str_buf);
+ mcd_put_strbuf();
+ mcdserver_state.query_cpu = mcd_next_attached_cpu(mcdserver_state.query_cpu);
+}
+
+
+void mcd_append_thread_id(CPUState *cpu, GString *buf)
+{
+ g_string_append_printf(buf, "p%02x.%02x", mcd_get_cpu_pid(cpu), mcd_get_cpu_index(cpu));
+}
+*/
+
+int mcd_get_cpu_index(CPUState *cpu)
+{
+ // TODO: maybe plus 1 because we start numbering at 1
+ 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;
+}
+
+void handle_query_system(GArray *params, void *user_ctx) {
+ mcd_put_packet("qemu-system");
+}
+
+void handle_query_cores(GArray *params, void *user_ctx) {
+ //TODO: add cluster support: in gdb each inferior (process) handles one cluster we might want to have sth similar here
+
+ // 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);
+ gchar *arch = cc->gdb_arch_name(cpu);
+
+ //const char *cpu_name = object_get_canonical_path_component(OBJECT(cpu));
+ //int process_id = mcd_get_cpu_pid(cpu);
+ //int cpu_index = cpu->cpu_index;
+ //int cpu_cluster = cpu->cluster_index;
+ int nr_cores = cpu->nr_cores;
+
+ g_string_append_printf(mcdserver_state.str_buf, "device=\"qemu-%s-device\",core=\"%s\",nr_cores=\"%d\"", arch, cpu_model, nr_cores);
+ mcd_put_strbuf();
+ g_free(arch);
+}
+
+void handle_core_open(GArray *params, void *user_ctx) {
+ // get the cpu whith the given id
+ uint32_t cpu_id = atoi(get_param(params, 0)->data);
+
+ CPUState *cpu = mcd_get_cpu(cpu_id);
+
+ // select the the cpu as the current cpu for all request from the mcd interface
+ mcdserver_state.c_cpu = cpu;
+ mcdserver_state.g_cpu = cpu;
+
+}
+
+void handle_query_reset(GArray *params, void *user_ctx) {
+ // resetting has to be done over a monitor (look ar Rcmd) so we tell MCD that we can reset but this still need to be implemented
+ // we only support one reset over this monitor and that would be a fully "system_restart"
+ mcd_put_packet("info_rst=\"results in a full system restart\"");
+}
+
+void handle_detach(GArray *params, void *user_ctx) {
+ uint32_t pid = 1;
+ MCDProcess *process = mcd_get_process(pid);
+
+ // 1. cleanup
+ // gdb_process_breakpoint_remove_all(process);
+
+ // 2. detach
+ process->attached = false;
+
+ // reset current cpus
+ // TODO: if we don't use c_cpu we can delete this
+ // this also checks to only reset THIS process we also probably don't need this since we only got one process!
+ if (pid == mcd_get_cpu_pid(mcdserver_state.c_cpu)) {
+ mcdserver_state.c_cpu = mcd_first_attached_cpu();
+ }
+
+ if (pid == mcd_get_cpu_pid(mcdserver_state.g_cpu)) {
+ mcdserver_state.g_cpu = mcd_first_attached_cpu();
+ }
+
+ if (!mcdserver_state.c_cpu) {
+ /* No more process attached */
+ mcd_disable_syscalls();
+ mcd_continue();
+ }
+}
+
+void mcd_continue(void)
+{
+ if (!runstate_needs_reset()) {
+ vm_start();
+ }
+}
--
2.34.1
From a05b2211045bc49a3788bfa952e9e2e26abb8dcb Mon Sep 17 00:00:00 2001
From: Nicolas Eder <nicolas.eder@lauterbach.com>
Date: Fri, 16 Jun 2023 17:27:57 +0200
Subject: [PATCH 04/29] queries for resets and triggers added
Signed-off-by: Nicolas Eder <nicolas.eder@lauterbach.com>
---
mcdstub/internals.h | 9 +++++++++
mcdstub/mcdstub.c | 19 ++++++++++++++++++-
2 files changed, 27 insertions(+), 1 deletion(-)
@@ -11,6 +11,14 @@
#define MAX_PACKET_LENGTH 1024
+// trigger defines
+#define MCD_TRIG_TYPE_IP 0x00000001
+#define MCD_TRIG_TYPE_READ 0x00000002
+#define MCD_TRIG_TYPE_WRITE 0x00000004
+#define MCD_TRIG_TYPE_RW 0x00000008
+#define MCD_TRIG_OPT_DATA_IS_CONDITION 0x00000008
+#define MCD_TRIG_ACTION_DBG_DEBUG 0x00000001
+
/*
* lookuptable for transmitted signals
*/
@@ -180,6 +188,7 @@ CPUState *find_cpu(uint32_t thread_id);
void handle_core_open(GArray *params, void *user_ctx);
void handle_query_reset(GArray *params, void *user_ctx);
void handle_detach(GArray *params, void *user_ctx);
+void handle_query_trigger(GArray *params, void *user_ctx);
void mcd_continue(void);
/* sycall handling */
@@ -57,6 +57,10 @@ static const MCDCmdParseEntry mcd_gen_query_table[] = {
.handler = handle_query_reset,
.cmd = "reset",
},
+ {
+ .handler = handle_query_trigger,
+ .cmd = "trigger",
+ },
};
void mcd_init_mcdserver_state(void)
@@ -991,7 +995,8 @@ void handle_core_open(GArray *params, void *user_ctx) {
void handle_query_reset(GArray *params, void *user_ctx) {
// resetting has to be done over a monitor (look ar Rcmd) so we tell MCD that we can reset but this still need to be implemented
// we only support one reset over this monitor and that would be a fully "system_restart"
- mcd_put_packet("info_rst=\"results in a full system restart\"");
+ mcd_put_packet("nr=\"3\",info=\"0,full_system_reset;1,gpr_reset;2,memory_reset;\"");
+ // TODO: we still need to implement the gpr and memory reset here!
}
void handle_detach(GArray *params, void *user_ctx) {
@@ -1022,6 +1027,18 @@ void handle_detach(GArray *params, void *user_ctx) {
}
}
+void handle_query_trigger(GArray *params, void *user_ctx) {
+ // set the type, option and action bitmask and send it
+
+ uint32_t type = (MCD_TRIG_TYPE_IP | MCD_TRIG_TYPE_READ | MCD_TRIG_TYPE_WRITE | MCD_TRIG_TYPE_RW);
+ uint32_t option = (MCD_TRIG_OPT_DATA_IS_CONDITION);
+ uint32_t action = (MCD_TRIG_ACTION_DBG_DEBUG);
+ uint32_t nr_trigger = 4;
+
+ g_string_append_printf(mcdserver_state.str_buf, "nr=\"%d\",info=\"%d;%d;%d;\"", nr_trigger, type, option, action);
+ mcd_put_strbuf();
+}
+
void mcd_continue(void)
{
if (!runstate_needs_reset()) {
--
2.34.1
From 7bad0ae1e10fc8641c24acee08706f9cf9de0131 Mon Sep 17 00:00:00 2001
From: Nicolas Eder <nicolas.eder@lauterbach.com>
Date: Tue, 20 Jun 2023 17:34:00 +0200
Subject: [PATCH 05/29] queries for memory spaces and register groups added
Signed-off-by: Nicolas Eder <nicolas.eder@lauterbach.com>
---
mcdstub/internals.h | 29 +++---
mcdstub/mcdstub.c | 240 ++++++++++++++++++++++++--------------------
2 files changed, 147 insertions(+), 122 deletions(-)
@@ -19,21 +19,13 @@
#define MCD_TRIG_OPT_DATA_IS_CONDITION 0x00000008
#define MCD_TRIG_ACTION_DBG_DEBUG 0x00000001
-/*
- * lookuptable for transmitted signals
- */
-
-enum {
- MCD_SIGNAL_HANDSHAKE = 0
-};
-
/*
* struct for an MCD Process, each process can establish one connection
*/
typedef struct MCDProcess {
- //this is probably what we would call a system (in qemu its a cluster)
+ //this is a relict from the gdb process, we might be able to delete this
uint32_t pid;
bool attached;
@@ -65,6 +57,9 @@ typedef union MCDCmdVariant {
uint32_t pid;
uint32_t tid;
} thread_id;
+
+ // used to synchronize stub and dll for functions with multiple packets
+ int index_handle;
} MCDCmdVariant;
#define get_param(p, i) (&g_array_index(p, MCDCmdVariant, i))
@@ -88,9 +83,7 @@ enum RSState {
typedef struct MCDState {
bool init; /* have we been initialised? */
- CPUState *c_cpu; /* current CPU for step/continue ops */
- CPUState *g_cpu; /* current CPU for other ops */
- CPUState *query_cpu; /* for q{f|s}ThreadInfo */
+ CPUState *c_cpu; /* current CPU for everything */
enum RSState state; /* parsing state */
char line_buf[MAX_PACKET_LENGTH];
int line_buf_index;
@@ -107,11 +100,19 @@ typedef struct MCDState {
// maybe we don't need those flags
int sstep_flags;
int supported_sstep_flags;
+
+ // my stuff
+ GArray *reggroups;
} MCDState;
/* lives in main mcdstub.c */
extern MCDState mcdserver_state;
+typedef struct mcd_reg_group_st {
+ const char *name;
+ const char *id;
+} mcd_reg_group_st;
+
// Inline utility function, convert from int to hex and back
@@ -190,6 +191,10 @@ void handle_query_reset(GArray *params, void *user_ctx);
void handle_detach(GArray *params, void *user_ctx);
void handle_query_trigger(GArray *params, void *user_ctx);
void mcd_continue(void);
+void handle_query_mem_spaces(GArray *params, void *user_ctx);
+void handle_query_reg_groups_f(GArray *params, void *user_ctx);
+void handle_query_reg_groups_c(GArray *params, void *user_ctx);
+void handle_init(GArray *params, void *user_ctx);
/* sycall handling */
void mcd_syscall_reset(void);
@@ -33,6 +33,7 @@
// just used for the xml_builtin stuff
//#include "exec/gdbstub.h" /* xml_builtin */
+#include "hw/core/sysemu-cpu-ops.h"
typedef struct {
CharBackend chr;
@@ -61,6 +62,19 @@ static const MCDCmdParseEntry mcd_gen_query_table[] = {
.handler = handle_query_trigger,
.cmd = "trigger",
},
+ {
+ .handler = handle_query_mem_spaces,
+ .cmd = "memory",
+ },
+ {
+ .handler = handle_query_reg_groups_f,
+ .cmd = "reggroupf",
+ },
+ {
+ .handler = handle_query_reg_groups_c,
+ .cmd = "reggroupc",
+ .schema = "i",
+ },
};
void mcd_init_mcdserver_state(void)
@@ -314,6 +328,8 @@ void mcd_read_byte(uint8_t ch)
case RS_GETLINE:
if (ch == '#') {
/* end of command, start of checksum*/
+ mcdserver_state.line_buf[mcdserver_state.line_buf_index++] = 0;
+ //mcdserver_state.line_sum += ch;
mcdserver_state.state = RS_DATAEND;
}
else if (mcdserver_state.line_buf_index >= sizeof(mcdserver_state.line_buf) - 1) {
@@ -363,25 +379,26 @@ void mcd_read_byte(uint8_t ch)
int mcd_handle_packet(const char *line_buf)
{
- //decides what function (handler) to call depending on what the first character in the line_buf is!
+ // decides what function (handler) to call depending on what the first character in the line_buf is!
const MCDCmdParseEntry *cmd_parser = NULL;
- //trace_gdbstub_io_command(line_buf);
-
switch (line_buf[0]) {
case 'i':
- //handshake
- mcd_put_packet("shaking your hand");
- //gdb_put_packet("OK");
+ // handshake and lookup initialization
+ {
+ static const MCDCmdParseEntry continue_cmd_desc = {
+ .handler = handle_init,
+ .cmd = "i",
+ };
+ cmd_parser = &continue_cmd_desc;
+ }
break;
case 'c':
- //go command
+ // go command
{
static const MCDCmdParseEntry continue_cmd_desc = {
.handler = handle_continue,
.cmd = "c",
- //.cmd_startswith = 1,
- //.schema = "L0"
};
cmd_parser = &continue_cmd_desc;
}
@@ -397,8 +414,7 @@ int mcd_handle_packet(const char *line_buf)
static const MCDCmdParseEntry gen_query_cmd_desc = {
.handler = handle_gen_query,
.cmd = "q",
- //.cmd_startswith = 1,
- .schema = "ss"
+ .schema = "s"
};
cmd_parser = &gen_query_cmd_desc;
}
@@ -409,8 +425,7 @@ int mcd_handle_packet(const char *line_buf)
static const MCDCmdParseEntry gen_core_open = {
.handler = handle_core_open,
.cmd = "H",
- //.cmd_startswith = 1,
- .schema = "ss"
+ .schema = "s"
};
cmd_parser = &gen_core_open;
}
@@ -420,20 +435,18 @@ int mcd_handle_packet(const char *line_buf)
static const MCDCmdParseEntry detach_cmd_desc = {
.handler = handle_detach,
.cmd = "D",
- //.cmd_startswith = 1,
- //.schema = "?.l0"
};
cmd_parser = &detach_cmd_desc;
}
break;
default:
- //could not perform the command (because its unknown)
+ // could not perform the command (because its unknown)
mcd_put_packet("");
break;
}
if (cmd_parser) {
- //now parse commands and run the selected function (handler)
+ // now parse commands and run the selected function (handler)
run_cmd_parser(line_buf, cmd_parser);
}
@@ -484,63 +497,16 @@ void run_cmd_parser(const char *data, const MCDCmdParseEntry *cmd)
int cmd_parse_params(const char *data, const char *schema, GArray *params)
{
MCDCmdVariant this_param;
- this_param.data = data;
- g_array_append_val(params, this_param);
- /*
- const char *curr_schema, *curr_data;
- g_assert(schema);
- g_assert(params->len == 0);
-
- curr_schema = schema;
- curr_data = data;
- while (curr_schema[0] && curr_schema[1] && *curr_data) {
- GdbCmdVariant this_param;
-
- switch (curr_schema[0]) {
- case 'l':
- if (qemu_strtoul(curr_data, &curr_data, 16,
- &this_param.val_ul)) {
- return -EINVAL;
- }
- curr_data = cmd_next_param(curr_data, curr_schema[1]);
- g_array_append_val(params, this_param);
- break;
- case 'L':
- if (qemu_strtou64(curr_data, &curr_data, 16,
- (uint64_t *)&this_param.val_ull)) {
- return -EINVAL;
- }
- curr_data = cmd_next_param(curr_data, curr_schema[1]);
- g_array_append_val(params, this_param);
- break;
- case 's':
- this_param.data = curr_data;
- curr_data = cmd_next_param(curr_data, curr_schema[1]);
- g_array_append_val(params, this_param);
- break;
- case 'o':
- this_param.opcode = *(uint8_t *)curr_data;
- curr_data = cmd_next_param(curr_data, curr_schema[1]);
- g_array_append_val(params, this_param);
- break;
- case 't':
- this_param.thread_id.kind =
- read_thread_id(curr_data, &curr_data,
- &this_param.thread_id.pid,
- &this_param.thread_id.tid);
- curr_data = cmd_next_param(curr_data, curr_schema[1]);
- g_array_append_val(params, this_param);
- break;
- case '?':
- curr_data = cmd_next_param(curr_data, curr_schema[1]);
- break;
- default:
- return -EINVAL;
- }
- curr_schema += 2;
+ if (schema[0] == 's') {
+ this_param.data = data;
+ g_array_append_val(params, this_param);
}
- */
+ else if (schema[0] == 'i') {
+ this_param.index_handle = atoi(data);
+ g_array_append_val(params, this_param);
+ }
+
return 0;
}
@@ -566,7 +532,7 @@ int process_string_cmd(void *user_ctx, const char *data, const MCDCmdParseEntry
// if a schema is provided we need to extract parameters from the data string
if (cmd->schema) {
- //currently doing nothing
+ // this only gets the data from data beginning after the command name
if (cmd_parse_params(&data[strlen(cmd->cmd)], cmd->schema, params)) {
return -1;
}
@@ -610,7 +576,6 @@ void mcd_chr_event(void *opaque, QEMUChrEvent event)
}
s->c_cpu = mcd_first_attached_cpu();
- s->g_cpu = s->c_cpu;
vm_stop(RUN_STATE_PAUSED);
//TODO: this might not be necessary
@@ -812,7 +777,6 @@ void mcd_set_stop_cpu(CPUState *cpu)
}
//FIXME: we probably can delete this because in the opern_core function we set these two anyway
mcdserver_state.c_cpu = cpu;
- mcdserver_state.g_cpu = cpu;
}
MCDProcess *mcd_get_cpu_process(CPUState *cpu)
@@ -888,35 +852,6 @@ CPUState *mcd_next_attached_cpu(CPUState *cpu)
return cpu;
}
-/*
-void handle_query_first_threads(GArray *params, void *user_ctx)
-{
- // chache the first cpu
- mcdserver_state.query_cpu = mcd_first_attached_cpu();
- // new answer over tcp
- handle_query_threads(params, user_ctx);
-}
-
-void handle_query_threads(GArray *params, void *user_ctx)
-{
- if (!mcdserver_state.query_cpu) {
- // send packet back that that there is no more threads
- //gdb_put_packet("l");
- return;
- }
-
- g_string_assign(mcdserver_state.str_buf, "m");
- mcd_append_thread_id(mcdserver_state.query_cpu, mcdserver_state.str_buf);
- mcd_put_strbuf();
- mcdserver_state.query_cpu = mcd_next_attached_cpu(mcdserver_state.query_cpu);
-}
-
-
-void mcd_append_thread_id(CPUState *cpu, GString *buf)
-{
- g_string_append_printf(buf, "p%02x.%02x", mcd_get_cpu_pid(cpu), mcd_get_cpu_index(cpu));
-}
-*/
int mcd_get_cpu_index(CPUState *cpu)
{
@@ -950,6 +885,34 @@ CPUState *find_cpu(uint32_t thread_id)
return NULL;
}
+void handle_init(GArray *params, void *user_ctx) {
+ CPUState *cpu = mcdserver_state.c_cpu;
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+
+ gchar *arch = cc->gdb_arch_name(cpu);
+
+ // store reg groups
+ if (strcmp(arch, "arm")==0) {
+ // at the moment we just assume there are 3 spaces (gpr, per and debug)
+ // TODO: this might cause a memory leak when called a second time -> maybe free the Garray first
+ mcdserver_state.reggroups = g_array_new(false, true, sizeof(mcd_reg_group_st));
+
+ mcd_reg_group_st group1 = { .name = "GPR Registers", .id = "1" };
+ g_array_append_vals(mcdserver_state.reggroups, (gconstpointer)&group1, 1);
+
+ mcd_reg_group_st group2 = { .name = "CP15 Registers", .id = "2" };
+ g_array_append_vals(mcdserver_state.reggroups, (gconstpointer)&group2, 1);
+ }
+ else {
+ // we don't support other architectures
+ assert(1);
+ }
+ g_free(arch);
+
+ // the mcdserver is set up and we return the handshake
+ mcd_put_packet("shaking your hand");
+}
+
void handle_query_system(GArray *params, void *user_ctx) {
mcd_put_packet("qemu-system");
}
@@ -988,7 +951,6 @@ void handle_core_open(GArray *params, void *user_ctx) {
// select the the cpu as the current cpu for all request from the mcd interface
mcdserver_state.c_cpu = cpu;
- mcdserver_state.g_cpu = cpu;
}
@@ -1016,10 +978,6 @@ void handle_detach(GArray *params, void *user_ctx) {
mcdserver_state.c_cpu = mcd_first_attached_cpu();
}
- if (pid == mcd_get_cpu_pid(mcdserver_state.g_cpu)) {
- mcdserver_state.g_cpu = mcd_first_attached_cpu();
- }
-
if (!mcdserver_state.c_cpu) {
/* No more process attached */
mcd_disable_syscalls();
@@ -1035,7 +993,7 @@ void handle_query_trigger(GArray *params, void *user_ctx) {
uint32_t action = (MCD_TRIG_ACTION_DBG_DEBUG);
uint32_t nr_trigger = 4;
- g_string_append_printf(mcdserver_state.str_buf, "nr=\"%d\",info=\"%d;%d;%d;\"", nr_trigger, type, option, action);
+ g_string_printf(mcdserver_state.str_buf, "nr=\"%d\",info=\"%d;%d;%d;\"", nr_trigger, type, option, action);
mcd_put_strbuf();
}
@@ -1045,3 +1003,65 @@ void mcd_continue(void)
vm_start();
}
}
+
+void handle_query_mem_spaces(GArray *params, void *user_ctx) {
+ // this returns the address spaces
+ // first we check if this is an arm architecture
+ // if it is arm we assume that if there are 2 address spaces, these are secure and non-secure (EL3 and EL0 for 64 bit)
+ CPUState *cpu = mcdserver_state.c_cpu;
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+
+ int nr_address_spaces = cpu->num_ases;
+ gchar *arch = cc->gdb_arch_name(cpu);
+
+ if (strcmp(arch, "arm")==0) {
+ // we got secure and non-secure
+ g_string_printf(mcdserver_state.str_buf, "Non Secure=id:1;type:34;bpm:8;i:1;e:1;min:0;max:-1;sao:0;.");
+ g_string_append_printf(mcdserver_state.str_buf, "Physical (Non Secure)=id:2;type:18;bpm:8;i:1;e:1;min:0;max:-1;sao:0;.");
+ if (nr_address_spaces==2) {
+ g_string_append_printf(mcdserver_state.str_buf, "Secure=id:3;type:34;bpm:8;i:1;e:1;min:0;max:-1;sao:0;.");
+ g_string_append_printf(mcdserver_state.str_buf, "Physical (Secure)=id:4;type:18;bpm:8;i:1;e:1;min:0;max:-1;sao:0;.");
+ }
+
+ // provide register spaces
+ // TODO: get dynamically how the per (CP15) space is called
+ g_string_append_printf(mcdserver_state.str_buf, "GPR Registers=id:5;type:1;bpm:64;i:1;e:1;min:0;max:-1;sao:0;.");
+ g_string_append_printf(mcdserver_state.str_buf, "CP15 Registers=id:6;type:1;bpm:32;i:1;e:1;min:0;max:-1;sao:0;."); //<-- per registers
+ //g_string_append_printf(mcdserver_state.str_buf, "CP14 Registers=type:1;bpm:32;i:1;e:1;min:0;max:-1;sao:0;."); // <-- debug registers
+ }
+ else {
+ // we don't support other architectures
+ assert(1);
+ }
+ g_free(arch);
+ mcd_put_strbuf();
+}
+
+void handle_query_reg_groups_f(GArray *params, void *user_ctx) {
+ // send the first reg group
+ mcd_reg_group_st group = g_array_index(mcdserver_state.reggroups, mcd_reg_group_st, 0);
+ g_string_printf(mcdserver_state.str_buf, "1!id=%s.name=%s.", group.id, group.name);
+ mcd_put_strbuf();
+}
+
+void handle_query_reg_groups_c(GArray *params, void *user_ctx) {
+ // this funcitons send all reg groups exept for the first
+ // 1. get parameter
+ int query_index = get_param(params, 0)->index_handle;
+
+ // 2. check weather this was the last reg group
+ int nb_groups = mcdserver_state.reggroups->len;
+ if (query_index+1 == nb_groups) {
+ // indicates this is the last packet
+ g_string_printf(mcdserver_state.str_buf, "0!");
+ }
+ else {
+ // provides
+ g_string_printf(mcdserver_state.str_buf, "%d!", query_index+1);
+ }
+
+ // 3. send the correct reggroup
+ mcd_reg_group_st group = g_array_index(mcdserver_state.reggroups, mcd_reg_group_st, query_index);
+ g_string_append_printf(mcdserver_state.str_buf, "id=%s.name=%s.", group.id, group.name);
+ mcd_put_strbuf();
+}
--
2.34.1
From 4e5b0cb290eddd633407bc37322e437422ee5897 Mon Sep 17 00:00:00 2001
From: Nicolas Eder <nicolas.eder@lauterbach.com>
Date: Fri, 23 Jun 2023 18:12:42 +0200
Subject: [PATCH 06/29] query for registers added
Signed-off-by: Nicolas Eder <nicolas.eder@lauterbach.com>
---
mcdstub/internals.h | 55 +++++--
mcdstub/mcdstub.c | 320 ++++++++++++++++++++++++++++++++++++++---
target/arm/meson.build | 1 +
3 files changed, 344 insertions(+), 32 deletions(-)
@@ -8,6 +8,8 @@
#include "exec/cpu-common.h"
#include "chardev/char.h"
+// just used for the register xml files
+#include "exec/gdbstub.h" /* xml_builtin */
#define MAX_PACKET_LENGTH 1024
@@ -19,6 +21,15 @@
#define MCD_TRIG_OPT_DATA_IS_CONDITION 0x00000008
#define MCD_TRIG_ACTION_DBG_DEBUG 0x00000001
+// GDB stuff thats needed for GDB function, which we use
+typedef struct GDBRegisterState {
+ int base_reg;
+ int num_regs;
+ gdb_get_reg_cb get_reg;
+ gdb_set_reg_cb set_reg;
+ const char *xml;
+ struct GDBRegisterState *next;
+} GDBRegisterState;
/*
* struct for an MCD Process, each process can establish one connection
@@ -75,10 +86,6 @@ enum RSState {
RS_IDLE,
RS_GETLINE,
RS_DATAEND,
- //RS_GETLINE_ESC,
- //RS_GETLINE_RLE,
- //RS_CHKSUM1,
- //RS_CHKSUM2,
};
typedef struct MCDState {
@@ -103,6 +110,7 @@ typedef struct MCDState {
// my stuff
GArray *reggroups;
+ GArray *registers;
} MCDState;
/* lives in main mcdstub.c */
@@ -110,9 +118,34 @@ extern MCDState mcdserver_state;
typedef struct mcd_reg_group_st {
const char *name;
- const char *id;
+ uint32_t id;
} mcd_reg_group_st;
+typedef struct xml_attrib {
+ char argument[64];
+ char value[64];
+} xml_attrib;
+
+typedef struct mcd_reg_st {
+ // xml info
+ char name[64];
+ char group[64];
+ char type[64];
+ uint32_t bitsize;
+ uint32_t id;
+ // 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
+ uint8_t cp;
+ uint8_t crn;
+ uint8_t crm;
+ uint8_t opc0; // <- might not be needed!
+ uint8_t opc1;
+ uint8_t opc2;
+} mcd_reg_st;
// Inline utility function, convert from int to hex and back
@@ -139,12 +172,6 @@ static inline int tohex(int v)
}
}
-
-/*old functions
-void mcd_init_mcdserver_state(void);
-int mcd_open_tcp_socket(int tcp_port);
-int mcd_extract_tcp_port_num(const char *in_string, char *out_string);
-*/
#ifndef _WIN32
void mcd_sigterm_handler(int signal);
#endif
@@ -194,10 +221,16 @@ void mcd_continue(void);
void handle_query_mem_spaces(GArray *params, void *user_ctx);
void handle_query_reg_groups_f(GArray *params, void *user_ctx);
void handle_query_reg_groups_c(GArray *params, void *user_ctx);
+void handle_query_regs_f(GArray *params, void *user_ctx);
+void handle_query_regs_c(GArray *params, void *user_ctx);
void handle_init(GArray *params, void *user_ctx);
+void parse_reg_xml(const char *xml, int size);
/* sycall handling */
void mcd_syscall_reset(void);
void mcd_disable_syscalls(void);
+// helpers
+int int_cmp(gconstpointer a, gconstpointer b);
+
#endif /* MCDSTUB_INTERNALS_H */
@@ -8,7 +8,6 @@
#include "qemu/cutils.h"
#include "qemu/module.h"
#include "qemu/error-report.h"
-//#include "trace.h"
#include "exec/mcdstub.h"
#include "mcdstub/syscalls.h"
#include "hw/cpu/cluster.h"
@@ -31,8 +30,10 @@
#include "chardev/char-fe.h"
#include "monitor/monitor.h"
-// just used for the xml_builtin stuff
-//#include "exec/gdbstub.h" /* xml_builtin */
+//architecture specific stuff
+#include "target/arm/mcdstub.h"
+
+// FIXME: delete the following line and check if it worked
#include "hw/core/sysemu-cpu-ops.h"
typedef struct {
@@ -75,6 +76,15 @@ static const MCDCmdParseEntry mcd_gen_query_table[] = {
.cmd = "reggroupc",
.schema = "i",
},
+ {
+ .handler = handle_query_regs_f,
+ .cmd = "regf",
+ },
+ {
+ .handler = handle_query_regs_c,
+ .cmd = "regc",
+ .schema = "i",
+ },
};
void mcd_init_mcdserver_state(void)
@@ -494,21 +504,21 @@ void run_cmd_parser(const char *data, const MCDCmdParseEntry *cmd)
}
}
-int cmd_parse_params(const char *data, const char *schema, GArray *params)
-{
+int cmd_parse_params(const char *data, const char *schema, GArray *params) {
MCDCmdVariant this_param;
+ char data_buffer[64] = {0};
if (schema[0] == 's') {
this_param.data = data;
g_array_append_val(params, this_param);
}
else if (schema[0] == 'i') {
- this_param.index_handle = atoi(data);
- g_array_append_val(params, this_param);
+ strncat(data_buffer, data, strlen(data));
+ this_param.index_handle = atoi(data_buffer);
+ g_array_append_val(params, this_param);
}
return 0;
-
}
int process_string_cmd(void *user_ctx, const char *data, const MCDCmdParseEntry *cmds, int num_cmds)
@@ -885,23 +895,248 @@ CPUState *find_cpu(uint32_t thread_id)
return NULL;
}
+
+void parse_reg_xml(const char *xml, int size) {
+ // iterates over the complete xml file
+ int i, j;
+ 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 chars 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);
+ }
+ }
+ // store register
+ g_array_append_vals(mcdserver_state.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 a_int = *(int*)a;
+ int b_int = *(int*)b;
+ if (a_int == b_int) {
+ return 0;
+ }
+ else {
+ return 1;
+ }
+}
+
void handle_init(GArray *params, void *user_ctx) {
CPUState *cpu = mcdserver_state.c_cpu;
CPUClass *cc = CPU_GET_CLASS(cpu);
gchar *arch = cc->gdb_arch_name(cpu);
- // store reg groups
+
if (strcmp(arch, "arm")==0) {
+ // store reg groups
+ uint32_t current_group_id = 0;
+
// at the moment we just assume there are 3 spaces (gpr, per and debug)
// TODO: this might cause a memory leak when called a second time -> maybe free the Garray first
mcdserver_state.reggroups = g_array_new(false, true, sizeof(mcd_reg_group_st));
- mcd_reg_group_st group1 = { .name = "GPR Registers", .id = "1" };
+ // store the registers themselves
+ mcdserver_state.registers = g_array_new(false, true, sizeof(mcd_reg_st));
+ GList *register_numbers = NULL;
+
+ const char *xml_filename = NULL;
+ const char *xml_content = NULL;
+ const char *name = NULL;
+ int i;
+
+ // 1. check out the core xml file
+ xml_filename = cc->gdb_core_xml_file;
+
+ for (i = 0; ; i++) {
+ name = xml_builtin[i][0];
+ if (!name || (strncmp(name, xml_filename, strlen(xml_filename)) == 0 && strlen(name) == strlen(xml_filename)))
+ break;
+ }
+ // without gpr registers we can do nothing
+ assert(name);
+ // add group for gpr registers
+ current_group_id = 1;
+ mcd_reg_group_st group1 = { .name = "GPR Registers", .id = current_group_id };
g_array_append_vals(mcdserver_state.reggroups, (gconstpointer)&group1, 1);
- mcd_reg_group_st group2 = { .name = "CP15 Registers", .id = "2" };
- g_array_append_vals(mcdserver_state.reggroups, (gconstpointer)&group2, 1);
+ // parse xml
+ xml_content = xml_builtin[i][1];
+ parse_reg_xml(xml_content, strlen(xml_content));
+
+ // 2. iterate over all other xml files
+ GDBRegisterState *r;
+ for (r = cpu->gdb_regs; r; r = r->next) {
+ xml_filename = r->xml;
+ xml_content = NULL;
+
+ // first, check if this is a coprocessor xml
+
+ // funciton call
+ 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
+ current_group_id = 2;
+ mcd_reg_group_st group2 = { .name = "CP15 Registers", .id = current_group_id };
+ g_array_append_vals(mcdserver_state.reggroups, (gconstpointer)&group2, 1);
+ }
+
+ }
+ else {
+ // its not a coprocessor xml -> it is a static xml file
+ for (i = 0; ; i++) {
+ name = xml_builtin[i][0];
+ if (!name || (strncmp(name, xml_filename, strlen(xml_filename)) == 0 && strlen(name) == strlen(xml_filename)))
+ break;
+ }
+ if (name) {
+ xml_content = xml_builtin[i][1];
+ }
+ else {
+ printf("no data found for %s\n", xml_filename);
+ continue;
+ }
+ }
+
+ // parse xml
+ parse_reg_xml(xml_content, strlen(xml_content));
+ }
+ // go over the register array and collect all additional data
+ mcd_reg_st *current_register;
+ int id_neg_offset = 0;
+ int effective_id;
+ for (i = 0; i < mcdserver_state.registers->len; i++) {
+ current_register = &(g_array_index(mcdserver_state.registers, mcd_reg_st, i));
+ // ad an id handle
+ if (current_register->id) {
+ // id is already in place
+ //FIXME: we are missing 10 registers (likely the FPA regs or sth)
+ int used_id = current_register->id;
+ register_numbers = g_list_append(register_numbers, &used_id);
+ id_neg_offset ++;
+ }
+ else {
+ effective_id = i - id_neg_offset;
+ if (g_list_find_custom(register_numbers, &effective_id, (GCompareFunc)int_cmp)!=NULL) {
+ id_neg_offset --;
+ }
+ current_register->id = i - id_neg_offset;
+ }
+ // sort into correct reg_group and according mem_space
+ if (strcmp(current_register->group, "cp_regs")==0) {
+ current_register->mcd_reg_group_id = 2;
+ current_register->mcd_mem_space_id = 6;
+ // get info for opcode
+ }
+ else {
+ // gpr register
+ current_register->mcd_reg_group_id = 1;
+ current_register->mcd_mem_space_id = 5;
+ }
+ }
+ // free memory
+ g_list_free(register_numbers);
}
else {
// we don't support other architectures
@@ -910,7 +1145,7 @@ void handle_init(GArray *params, void *user_ctx) {
g_free(arch);
// the mcdserver is set up and we return the handshake
- mcd_put_packet("shaking your hand");
+ mcd_put_packet("shaking your hand");
}
void handle_query_system(GArray *params, void *user_ctx) {
@@ -932,10 +1167,6 @@ void handle_query_cores(GArray *params, void *user_ctx) {
CPUClass *cc = CPU_GET_CLASS(cpu);
gchar *arch = cc->gdb_arch_name(cpu);
- //const char *cpu_name = object_get_canonical_path_component(OBJECT(cpu));
- //int process_id = mcd_get_cpu_pid(cpu);
- //int cpu_index = cpu->cpu_index;
- //int cpu_cluster = cpu->cluster_index;
int nr_cores = cpu->nr_cores;
g_string_append_printf(mcdserver_state.str_buf, "device=\"qemu-%s-device\",core=\"%s\",nr_cores=\"%d\"", arch, cpu_model, nr_cores);
@@ -1039,13 +1270,21 @@ void handle_query_mem_spaces(GArray *params, void *user_ctx) {
void handle_query_reg_groups_f(GArray *params, void *user_ctx) {
// send the first reg group
+ int nb_groups = mcdserver_state.reggroups->len;
+ if (nb_groups == 1) {
+ // indicates this is the last packet
+ g_string_printf(mcdserver_state.str_buf, "0!");
+ }
+ else {
+ g_string_printf(mcdserver_state.str_buf, "1!");
+ }
mcd_reg_group_st group = g_array_index(mcdserver_state.reggroups, mcd_reg_group_st, 0);
- g_string_printf(mcdserver_state.str_buf, "1!id=%s.name=%s.", group.id, group.name);
+ g_string_append_printf(mcdserver_state.str_buf, "id=%d.name=%s.", group.id, group.name);
mcd_put_strbuf();
}
void handle_query_reg_groups_c(GArray *params, void *user_ctx) {
- // this funcitons send all reg groups exept for the first
+ // this funcitons send all reg groups except for the first
// 1. get parameter
int query_index = get_param(params, 0)->index_handle;
@@ -1056,12 +1295,51 @@ void handle_query_reg_groups_c(GArray *params, void *user_ctx) {
g_string_printf(mcdserver_state.str_buf, "0!");
}
else {
- // provides
g_string_printf(mcdserver_state.str_buf, "%d!", query_index+1);
}
// 3. send the correct reggroup
mcd_reg_group_st group = g_array_index(mcdserver_state.reggroups, mcd_reg_group_st, query_index);
- g_string_append_printf(mcdserver_state.str_buf, "id=%s.name=%s.", group.id, group.name);
+ g_string_append_printf(mcdserver_state.str_buf, "id=%d.name=%s.", group.id, group.name);
+ mcd_put_strbuf();
+}
+
+void handle_query_regs_f(GArray *params, void *user_ctx) {
+ // send the first register
+ int nb_regs = mcdserver_state.registers->len;
+ if (nb_regs == 1) {
+ // indicates this is the last packet
+ g_string_printf(mcdserver_state.str_buf, "0!");
+ }
+ else {
+ g_string_printf(mcdserver_state.str_buf, "1!");
+ }
+ mcd_reg_st my_register = g_array_index(mcdserver_state.registers, mcd_reg_st, 0);
+ g_string_append_printf(mcdserver_state.str_buf, "id=%d.name=%s.size=%d.reggroupid=%d.memspaceid=%d.type=%d.thread=%d.",
+ my_register.id, my_register.name, my_register.bitsize, my_register.mcd_reg_group_id,
+ my_register.mcd_mem_space_id, my_register.mcd_reg_type, my_register.mcd_hw_thread_id);
+ mcd_put_strbuf();
+}
+
+void handle_query_regs_c(GArray *params, void *user_ctx) {
+ // this funcitons send all registers except for the first
+ // 1. get parameter
+ int query_index = get_param(params, 0)->index_handle;
+
+ // 2. check weather this was the last register
+ int nb_regs = mcdserver_state.registers->len;
+ if (query_index+1 == nb_regs) {
+ // indicates this is the last packet
+ g_string_printf(mcdserver_state.str_buf, "0!");
+ }
+ else {
+ g_string_printf(mcdserver_state.str_buf, "%d!", query_index+1);
+ }
+
+ // 3. send the correct register
+ mcd_reg_st my_register = g_array_index(mcdserver_state.registers, mcd_reg_st, query_index);
+ g_string_append_printf(mcdserver_state.str_buf, "id=%d.name=%s.size=%d.reggroupid=%d.memspaceid=%d.type=%d.thread=%d.",
+ my_register.id, my_register.name, my_register.bitsize, my_register.mcd_reg_group_id,
+ my_register.mcd_mem_space_id, my_register.mcd_reg_type, my_register.mcd_hw_thread_id);
mcd_put_strbuf();
}
@@ -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
From 304f3b11febb1a0f3350cbcdd362929746dc807a Mon Sep 17 00:00:00 2001
From: Nicolas Eder <nicolas.eder@lauterbach.com>
Date: Mon, 26 Jun 2023 17:19:41 +0200
Subject: [PATCH 07/29] query data preparation improved
Signed-off-by: Nicolas Eder <nicolas.eder@lauterbach.com>
---
mcdstub/internals.h | 35 +++-
mcdstub/mcdstub.c | 382 ++++++++++++++++++++++----------------------
2 files changed, 215 insertions(+), 202 deletions(-)
@@ -21,6 +21,11 @@
#define MCD_TRIG_OPT_DATA_IS_CONDITION 0x00000008
#define MCD_TRIG_ACTION_DBG_DEBUG 0x00000001
+// schema defines
+#define ARG_SCHEMA_QRY_HANDLE "q"
+#define ARG_SCHEMA_STRING "s"
+#define ARG_SCHEMA_CORE_NUM "c"
+
// GDB stuff thats needed for GDB function, which we use
typedef struct GDBRegisterState {
int base_reg;
@@ -60,17 +65,16 @@ typedef enum MCDThreadIdKind {
typedef union MCDCmdVariant {
const char *data;
- uint8_t opcode;
- unsigned long val_ul;
- unsigned long long val_ull;
+
struct {
MCDThreadIdKind kind;
uint32_t pid;
uint32_t tid;
} thread_id;
- // used to synchronize stub and dll for functions with multiple packets
- int index_handle;
+ int query_handle;
+ int cpu_id;
+
} MCDCmdVariant;
#define get_param(p, i) (&g_array_index(p, MCDCmdVariant, i))
@@ -109,6 +113,7 @@ typedef struct MCDState {
int supported_sstep_flags;
// my stuff
+ GArray *memspaces;
GArray *reggroups;
GArray *registers;
} MCDState;
@@ -116,6 +121,18 @@ typedef struct MCDState {
/* lives in main mcdstub.c */
extern MCDState mcdserver_state;
+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;
+} mcd_mem_space_st;
+
typedef struct mcd_reg_group_st {
const char *name;
uint32_t id;
@@ -213,19 +230,23 @@ void handle_query_cores(GArray *params, void *user_ctx);
void handle_query_system(GArray *params, void *user_ctx);
CPUState *get_first_cpu_in_process(MCDProcess *process);
CPUState *find_cpu(uint32_t thread_id);
-void handle_core_open(GArray *params, void *user_ctx);
+void handle_open_core(GArray *params, void *user_ctx);
void handle_query_reset(GArray *params, void *user_ctx);
void handle_detach(GArray *params, void *user_ctx);
void handle_query_trigger(GArray *params, void *user_ctx);
void mcd_continue(void);
-void handle_query_mem_spaces(GArray *params, void *user_ctx);
void handle_query_reg_groups_f(GArray *params, void *user_ctx);
void handle_query_reg_groups_c(GArray *params, void *user_ctx);
+void handle_query_mem_spaces_f(GArray *params, void *user_ctx);
+void handle_query_mem_spaces_c(GArray *params, void *user_ctx);
void handle_query_regs_f(GArray *params, void *user_ctx);
void handle_query_regs_c(GArray *params, void *user_ctx);
void handle_init(GArray *params, void *user_ctx);
void parse_reg_xml(const char *xml, int size);
+// arm specific functions
+void mcd_arm_store_mem_spaces(int nr_address_spaces);
+
/* sycall handling */
void mcd_syscall_reset(void);
void mcd_disable_syscalls(void);
@@ -2,6 +2,8 @@
* This is the main mcdstub. It needs to be complemented by other mcd stubs for each target.
*/
+#include "mcd_shared_defines.h"
+
//from original gdbstub.c
#include "qemu/osdep.h"
#include "qemu/ctype.h"
@@ -64,8 +66,13 @@ static const MCDCmdParseEntry mcd_gen_query_table[] = {
.cmd = "trigger",
},
{
- .handler = handle_query_mem_spaces,
- .cmd = "memory",
+ .handler = handle_query_mem_spaces_f,
+ .cmd = "memoryf",
+ },
+ {
+ .handler = handle_query_mem_spaces_c,
+ .cmd = "memoryc",
+ .schema = ARG_SCHEMA_QRY_HANDLE,
},
{
.handler = handle_query_reg_groups_f,
@@ -74,7 +81,7 @@ static const MCDCmdParseEntry mcd_gen_query_table[] = {
{
.handler = handle_query_reg_groups_c,
.cmd = "reggroupc",
- .schema = "i",
+ .schema = ARG_SCHEMA_QRY_HANDLE,
},
{
.handler = handle_query_regs_f,
@@ -83,7 +90,7 @@ static const MCDCmdParseEntry mcd_gen_query_table[] = {
{
.handler = handle_query_regs_c,
.cmd = "regc",
- .schema = "i",
+ .schema = ARG_SCHEMA_QRY_HANDLE,
},
};
@@ -424,20 +431,19 @@ int mcd_handle_packet(const char *line_buf)
static const MCDCmdParseEntry gen_query_cmd_desc = {
.handler = handle_gen_query,
.cmd = "q",
- .schema = "s"
+ .schema = ARG_SCHEMA_STRING
};
cmd_parser = &gen_query_cmd_desc;
}
break;
case 'H':
- //current alias for open core, later this will probably be a part of the 'i' requests
{
- static const MCDCmdParseEntry gen_core_open = {
- .handler = handle_core_open,
+ static const MCDCmdParseEntry gen_open_core = {
+ .handler = handle_open_core,
.cmd = "H",
- .schema = "s"
+ .schema = ARG_SCHEMA_CORE_NUM
};
- cmd_parser = &gen_core_open;
+ cmd_parser = &gen_open_core;
}
break;
case 'D':
@@ -508,13 +514,18 @@ int cmd_parse_params(const char *data, const char *schema, GArray *params) {
MCDCmdVariant this_param;
char data_buffer[64] = {0};
- if (schema[0] == 's') {
+ if (schema[0] == atoi(ARG_SCHEMA_STRING)) {
this_param.data = data;
g_array_append_val(params, this_param);
}
- else if (schema[0] == 'i') {
+ else if (schema[0] == atoi(ARG_SCHEMA_QRY_HANDLE)) {
strncat(data_buffer, data, strlen(data));
- this_param.index_handle = atoi(data_buffer);
+ this_param.query_handle = atoi(data_buffer);
+ g_array_append_val(params, this_param);
+ }
+ else if (schema[0] == atoi(ARG_SCHEMA_CORE_NUM)) {
+ strncat(data_buffer, data, strlen(data));
+ this_param.cpu_id = atoi(data_buffer);
g_array_append_val(params, this_param);
}
@@ -618,97 +629,6 @@ void mcd_sigterm_handler(int signal)
void mcd_vm_state_change(void *opaque, bool running, RunState state)
{
printf("this calls state_change\n");
- /*
- CPUState *cpu = mcdserver_state.c_cpu;
- g_autoptr(GString) buf = g_string_new(NULL);
- g_autoptr(GString) tid = g_string_new(NULL);
- const char *type;
- int ret;
-
- if (running || mcdserver_state.state == RS_INACTIVE) {
- return;
- }
-
- //Is there a GDB syscall waiting to be sent?
- if (gdb_handled_syscall()) {
- return;
- }
-
- if (cpu == NULL) {
- //No process attached
- return;
- }
-
- gdb_append_thread_id(cpu, tid);
-
- switch (state) {
- case RUN_STATE_DEBUG:
- if (cpu->watchpoint_hit) {
- switch (cpu->watchpoint_hit->flags & BP_MEM_ACCESS) {
- case BP_MEM_READ:
- type = "r";
- break;
- case BP_MEM_ACCESS:
- type = "a";
- break;
- default:
- type = "";
- break;
- }
- trace_gdbstub_hit_watchpoint(type,
- gdb_get_cpu_index(cpu),
- cpu->watchpoint_hit->vaddr);
- g_string_printf(buf, "T%02xthread:%s;%swatch:%" VADDR_PRIx ";",
- GDB_SIGNAL_TRAP, tid->str, type,
- cpu->watchpoint_hit->vaddr);
- cpu->watchpoint_hit = NULL;
- goto send_packet;
- } else {
- trace_gdbstub_hit_break();
- }
- tb_flush(cpu);
- ret = GDB_SIGNAL_TRAP;
- break;
- case RUN_STATE_PAUSED:
- trace_gdbstub_hit_paused();
- ret = GDB_SIGNAL_INT;
- break;
- case RUN_STATE_SHUTDOWN:
- trace_gdbstub_hit_shutdown();
- ret = GDB_SIGNAL_QUIT;
- break;
- case RUN_STATE_IO_ERROR:
- trace_gdbstub_hit_io_error();
- ret = GDB_SIGNAL_IO;
- break;
- case RUN_STATE_WATCHDOG:
- trace_gdbstub_hit_watchdog();
- ret = GDB_SIGNAL_ALRM;
- break;
- case RUN_STATE_INTERNAL_ERROR:
- trace_gdbstub_hit_internal_error();
- ret = GDB_SIGNAL_ABRT;
- break;
- case RUN_STATE_SAVE_VM:
- case RUN_STATE_RESTORE_VM:
- return;
- case RUN_STATE_FINISH_MIGRATE:
- ret = GDB_SIGNAL_XCPU;
- break;
- default:
- trace_gdbstub_hit_unknown(state);
- ret = GDB_SIGNAL_UNKNOWN;
- break;
- }
- mcd_set_stop_cpu(cpu);
- g_string_printf(buf, "T%02xthread:%s;", ret, tid->str);
-
-send_packet:
- mcd_put_packet(buf->str);
-
- // disable single step if it was enabled
- cpu_single_step(cpu, 0);
-*/
}
int mcd_put_packet(const char *buf)
@@ -726,14 +646,6 @@ void mcd_put_strbuf(void)
int mcd_put_packet_binary(const char *buf, int len, bool dump)
{
- //int csum, i;
- //uint8_t footer[3];
-
- //trace stuff
- //if (dump && trace_event_get_state_backends(TRACE_GDBSTUB_IO_BINARYREPLY)) {
- // hexdump(buf, len, trace_gdbstub_io_binaryreply);
- //}
-
for(;;) {
//super interesting if we want a chekcsum or something like that here!!
g_byte_array_set_size(mcdserver_state.last_packet, 0);
@@ -741,16 +653,7 @@ int mcd_put_packet_binary(const char *buf, int len, bool dump)
g_byte_array_append(mcdserver_state.last_packet, (const uint8_t *) buf, len);
g_byte_array_append(mcdserver_state.last_packet, (const uint8_t *) "#", 1);
g_byte_array_append(mcdserver_state.last_packet, (const uint8_t *) "|", 1);
- /*
- csum = 0;
- for(i = 0; i < len; i++) {
- csum += buf[i];
- }
- footer[0] = '#';
- footer[1] = tohex((csum >> 4) & 0xf);
- footer[2] = tohex((csum) & 0xf);
- g_byte_array_append(mcdserver_state.last_packet, footer, 3);
- */
+
mcd_put_buffer(mcdserver_state.last_packet->data, mcdserver_state.last_packet->len);
if (mcd_got_immediate_ack()) {
@@ -1021,23 +924,145 @@ int int_cmp(gconstpointer a, gconstpointer b) {
}
}
+void mcd_arm_store_mem_spaces(int nr_address_spaces) {
+ mcd_mem_space_st space1 = {
+ .name = "Non Secure",
+ .id = 1,
+ .type = 34,
+ .bits_per_mau = 8,
+ .invariance = 1,
+ .endian = 1,
+ .min_addr = 0,
+ .max_addr = -1,
+ .supported_access_options = 0,
+ };
+ g_array_append_vals(mcdserver_state.memspaces, (gconstpointer)&space1, 1);
+
+ mcd_mem_space_st space2 = {
+ .name = "Physical (Non Secure)",
+ .id = 2,
+ .type = 18,
+ .bits_per_mau = 8,
+ .invariance = 1,
+ .endian = 1,
+ .min_addr = 0,
+ .max_addr = -1,
+ .supported_access_options = 0,
+ };
+ g_array_append_vals(mcdserver_state.memspaces, (gconstpointer)&space2, 1);
+
+ if (nr_address_spaces==2) {
+ mcd_mem_space_st space3 = {
+ .name = "Secure",
+ .id = 3,
+ .type = 34,
+ .bits_per_mau = 8,
+ .invariance = 1,
+ .endian = 1,
+ .min_addr = 0,
+ .max_addr = -1,
+ .supported_access_options = 0,
+ };
+ g_array_append_vals(mcdserver_state.memspaces, (gconstpointer)&space3, 1);
+ mcd_mem_space_st space4 = {
+ .name = "Physical (Secure)",
+ .id = 4,
+ .type = 18,
+ .bits_per_mau = 8,
+ .invariance = 1,
+ .endian = 1,
+ .min_addr = 0,
+ .max_addr = -1,
+ .supported_access_options = 0,
+ };
+ g_array_append_vals(mcdserver_state.memspaces, (gconstpointer)&space4, 1);
+ }
+ // TODO: get dynamically how the per (CP15) space is called
+ mcd_mem_space_st space5 = {
+ .name = "GPR Registers",
+ .id = 5,
+ .type = 1,
+ .bits_per_mau = 8,
+ .invariance = 1,
+ .endian = 1,
+ .min_addr = 0,
+ .max_addr = -1,
+ .supported_access_options = 0,
+ };
+ g_array_append_vals(mcdserver_state.memspaces, (gconstpointer)&space5, 1);
+ mcd_mem_space_st space6 = {
+ .name = "CP15 Registers",
+ .id = 6,
+ .type = 1,
+ .bits_per_mau = 8,
+ .invariance = 1,
+ .endian = 1,
+ .min_addr = 0,
+ .max_addr = -1,
+ .supported_access_options = 0,
+ };
+ g_array_append_vals(mcdserver_state.memspaces, (gconstpointer)&space6, 1);
+}
+
void handle_init(GArray *params, void *user_ctx) {
- CPUState *cpu = mcdserver_state.c_cpu;
+ // the mcdserver is set up and we return the handshake
+ mcd_put_packet("shaking your hand");
+}
+
+void handle_query_system(GArray *params, void *user_ctx) {
+ mcd_put_packet("qemu-system");
+}
+
+void handle_query_cores(GArray *params, void *user_ctx) {
+ //TODO: add cluster support: in gdb each inferior (process) handles one cluster we might want to have sth similar here
+
+ // 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);
+ gchar *arch = cc->gdb_arch_name(cpu);
+
+ int nr_cores = cpu->nr_cores;
+
+ g_string_append_printf(mcdserver_state.str_buf, "device=\"qemu-%s-device\",core=\"%s\",nr_cores=\"%d\"", arch, cpu_model, nr_cores);
+ mcd_put_strbuf();
+ g_free(arch);
+}
+
+void handle_open_core(GArray *params, void *user_ctx) {
+ // get the cpu whith the given id
+ uint32_t cpu_id = get_param(params, 0)->cpu_id;
+
+ CPUState *cpu = mcd_get_cpu(cpu_id);
+
CPUClass *cc = CPU_GET_CLASS(cpu);
gchar *arch = cc->gdb_arch_name(cpu);
+ // TODO: this might cause a memory leak when called a second time -> maybe free the Garray first
+ mcdserver_state.memspaces = g_array_new(false, true, sizeof(mcd_mem_space_st));
+ mcdserver_state.reggroups = g_array_new(false, true, sizeof(mcd_reg_group_st));
+ mcdserver_state.registers = g_array_new(false, true, sizeof(mcd_reg_st));
+
if (strcmp(arch, "arm")==0) {
// store reg groups
uint32_t current_group_id = 0;
// at the moment we just assume there are 3 spaces (gpr, per and debug)
- // TODO: this might cause a memory leak when called a second time -> maybe free the Garray first
- mcdserver_state.reggroups = g_array_new(false, true, sizeof(mcd_reg_group_st));
+
+ // store mem spaces
+ int nr_address_spaces = cpu->num_ases;
+ mcd_arm_store_mem_spaces(nr_address_spaces);
+ // mem spaces done
+
- // store the registers themselves
- mcdserver_state.registers = g_array_new(false, true, sizeof(mcd_reg_st));
GList *register_numbers = NULL;
const char *xml_filename = NULL;
@@ -1140,49 +1165,9 @@ void handle_init(GArray *params, void *user_ctx) {
}
else {
// we don't support other architectures
- assert(1);
+ assert(0);
}
g_free(arch);
-
- // the mcdserver is set up and we return the handshake
- mcd_put_packet("shaking your hand");
-}
-
-void handle_query_system(GArray *params, void *user_ctx) {
- mcd_put_packet("qemu-system");
-}
-
-void handle_query_cores(GArray *params, void *user_ctx) {
- //TODO: add cluster support: in gdb each inferior (process) handles one cluster we might want to have sth similar here
-
- // 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);
- gchar *arch = cc->gdb_arch_name(cpu);
-
- int nr_cores = cpu->nr_cores;
-
- g_string_append_printf(mcdserver_state.str_buf, "device=\"qemu-%s-device\",core=\"%s\",nr_cores=\"%d\"", arch, cpu_model, nr_cores);
- mcd_put_strbuf();
- g_free(arch);
-}
-
-void handle_core_open(GArray *params, void *user_ctx) {
- // get the cpu whith the given id
- uint32_t cpu_id = atoi(get_param(params, 0)->data);
-
- CPUState *cpu = mcd_get_cpu(cpu_id);
-
- // select the the cpu as the current cpu for all request from the mcd interface
- mcdserver_state.c_cpu = cpu;
-
}
void handle_query_reset(GArray *params, void *user_ctx) {
@@ -1235,36 +1220,43 @@ void mcd_continue(void)
}
}
-void handle_query_mem_spaces(GArray *params, void *user_ctx) {
- // this returns the address spaces
- // first we check if this is an arm architecture
- // if it is arm we assume that if there are 2 address spaces, these are secure and non-secure (EL3 and EL0 for 64 bit)
- CPUState *cpu = mcdserver_state.c_cpu;
- CPUClass *cc = CPU_GET_CLASS(cpu);
-
- int nr_address_spaces = cpu->num_ases;
- gchar *arch = cc->gdb_arch_name(cpu);
+void handle_query_mem_spaces_f(GArray *params, void *user_ctx) {
+ // send the first mem space
+ int nb_groups = mcdserver_state.memspaces->len;
+ if (nb_groups == 1) {
+ // indicates this is the last packet
+ g_string_printf(mcdserver_state.str_buf, "0!");
+ }
+ else {
+ g_string_printf(mcdserver_state.str_buf, "1!");
+ }
+ mcd_mem_space_st space = g_array_index(mcdserver_state.memspaces, mcd_mem_space_st, 0);
+ g_string_append_printf(mcdserver_state.str_buf, "name=%s.id=%d.type=%d.bpm=%d.i=%d.e=%d.min=%ld.max=%ld.sao=%d.",
+ space.name, space.id, space.type, space.bits_per_mau, space.invariance, space.endian,
+ space.min_addr, space.max_addr, space.supported_access_options);
+ mcd_put_strbuf();
+}
- if (strcmp(arch, "arm")==0) {
- // we got secure and non-secure
- g_string_printf(mcdserver_state.str_buf, "Non Secure=id:1;type:34;bpm:8;i:1;e:1;min:0;max:-1;sao:0;.");
- g_string_append_printf(mcdserver_state.str_buf, "Physical (Non Secure)=id:2;type:18;bpm:8;i:1;e:1;min:0;max:-1;sao:0;.");
- if (nr_address_spaces==2) {
- g_string_append_printf(mcdserver_state.str_buf, "Secure=id:3;type:34;bpm:8;i:1;e:1;min:0;max:-1;sao:0;.");
- g_string_append_printf(mcdserver_state.str_buf, "Physical (Secure)=id:4;type:18;bpm:8;i:1;e:1;min:0;max:-1;sao:0;.");
- }
+void handle_query_mem_spaces_c(GArray *params, void *user_ctx) {
+ // this funcitons send all mem spaces except for the first
+ // 1. get parameter
+ int query_index = get_param(params, 0)->query_handle;
- // provide register spaces
- // TODO: get dynamically how the per (CP15) space is called
- g_string_append_printf(mcdserver_state.str_buf, "GPR Registers=id:5;type:1;bpm:64;i:1;e:1;min:0;max:-1;sao:0;.");
- g_string_append_printf(mcdserver_state.str_buf, "CP15 Registers=id:6;type:1;bpm:32;i:1;e:1;min:0;max:-1;sao:0;."); //<-- per registers
- //g_string_append_printf(mcdserver_state.str_buf, "CP14 Registers=type:1;bpm:32;i:1;e:1;min:0;max:-1;sao:0;."); // <-- debug registers
+ // 2. check weather this was the last mem space
+ int nb_groups = mcdserver_state.memspaces->len;
+ if (query_index+1 == nb_groups) {
+ // indicates this is the last packet
+ g_string_printf(mcdserver_state.str_buf, "0!");
}
else {
- // we don't support other architectures
- assert(1);
+ g_string_printf(mcdserver_state.str_buf, "%d!", query_index+1);
}
- g_free(arch);
+
+ // 3. send the correct memspace
+ mcd_mem_space_st space = g_array_index(mcdserver_state.memspaces, mcd_mem_space_st, query_index);
+ g_string_append_printf(mcdserver_state.str_buf, "name=%s.id=%d.type=%d.bpm=%d.i=%d.e=%d.min=%ld.max=%ld.sao=%d.",
+ space.name, space.id, space.type, space.bits_per_mau, space.invariance, space.endian,
+ space.min_addr, space.max_addr, space.supported_access_options);
mcd_put_strbuf();
}
@@ -1286,7 +1278,7 @@ void handle_query_reg_groups_f(GArray *params, void *user_ctx) {
void handle_query_reg_groups_c(GArray *params, void *user_ctx) {
// this funcitons send all reg groups except for the first
// 1. get parameter
- int query_index = get_param(params, 0)->index_handle;
+ int query_index = get_param(params, 0)->query_handle;
// 2. check weather this was the last reg group
int nb_groups = mcdserver_state.reggroups->len;
@@ -1324,7 +1316,7 @@ void handle_query_regs_f(GArray *params, void *user_ctx) {
void handle_query_regs_c(GArray *params, void *user_ctx) {
// this funcitons send all registers except for the first
// 1. get parameter
- int query_index = get_param(params, 0)->index_handle;
+ int query_index = get_param(params, 0)->query_handle;
// 2. check weather this was the last register
int nb_regs = mcdserver_state.registers->len;
--
2.34.1
From 499ed6ab8d47ef63c584a489265bf2b24a3fd680 Mon Sep 17 00:00:00 2001
From: Nicolas Eder <nicolas.eder@lauterbach.com>
Date: Tue, 27 Jun 2023 12:47:57 +0200
Subject: [PATCH 08/29] shared header file added, used for TCP packet data
Signed-off-by: Nicolas Eder <nicolas.eder@lauterbach.com>
---
mcdstub/internals.h | 4 +-
mcdstub/mcd_shared_defines.h | 24 ++++++++++++
mcdstub/mcdstub.c | 72 ++++++++++++++++++------------------
3 files changed, 62 insertions(+), 38 deletions(-)
create mode 100644 mcdstub/mcd_shared_defines.h
@@ -22,9 +22,9 @@
#define MCD_TRIG_ACTION_DBG_DEBUG 0x00000001
// schema defines
-#define ARG_SCHEMA_QRY_HANDLE "q"
+#define ARG_SCHEMA_QRYHANDLE "q"
#define ARG_SCHEMA_STRING "s"
-#define ARG_SCHEMA_CORE_NUM "c"
+#define ARG_SCHEMA_CORENUM "c"
// GDB stuff thats needed for GDB function, which we use
typedef struct GDBRegisterState {
new file mode 100644
@@ -0,0 +1,24 @@
+// 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
+
+// tcp characters
+#define TCP_CHAR_INIT 'i'
+#define TCP_CHAR_GO 'c'
+#define TCP_CHAR_QUERY 'q'
+#define TCP_CHAR_OPEN_CORE 'H'
+#define TCP_CHAR_DETACH 'D'
+#define TCP_CHAR_KILLQEMU 'k'
+
+// 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 '~'
+
+
+
+#endif
\ No newline at end of file
@@ -72,7 +72,7 @@ static const MCDCmdParseEntry mcd_gen_query_table[] = {
{
.handler = handle_query_mem_spaces_c,
.cmd = "memoryc",
- .schema = ARG_SCHEMA_QRY_HANDLE,
+ .schema = ARG_SCHEMA_QRYHANDLE,
},
{
.handler = handle_query_reg_groups_f,
@@ -81,7 +81,7 @@ static const MCDCmdParseEntry mcd_gen_query_table[] = {
{
.handler = handle_query_reg_groups_c,
.cmd = "reggroupc",
- .schema = ARG_SCHEMA_QRY_HANDLE,
+ .schema = ARG_SCHEMA_QRYHANDLE,
},
{
.handler = handle_query_regs_f,
@@ -90,7 +90,7 @@ static const MCDCmdParseEntry mcd_gen_query_table[] = {
{
.handler = handle_query_regs_c,
.cmd = "regc",
- .schema = ARG_SCHEMA_QRY_HANDLE,
+ .schema = ARG_SCHEMA_QRYHANDLE,
},
};
@@ -303,22 +303,22 @@ void mcd_read_byte(uint8_t ch)
if (mcdserver_state.last_packet->len) {
/* Waiting for a response to the last packet. If we see the start
of a new command then abandon the previous response. */
- if (ch == '-') {
+ if (ch == TCP_NOT_ACKNOWLEDGED) {
//the previous packet was not akcnowledged
//trace_gdbstub_err_got_nack();
//we are resending the last packet
mcd_put_buffer(mcdserver_state.last_packet->data, mcdserver_state.last_packet->len);
}
- else if (ch == '+') {
+ else if (ch == TCP_ACKNOWLEDGED) {
//the previous packet was acknowledged
//trace_gdbstub_io_got_ack();
}
- if (ch == '+' || ch == '$') {
+ if (ch == TCP_ACKNOWLEDGED || ch == TCP_COMMAND_START) {
//either acknowledged or a new communication starts -> we discard previous communication
g_byte_array_set_size(mcdserver_state.last_packet, 0);
}
- if (ch != '$') {
+ if (ch != TCP_COMMAND_START) {
// we only continue if we are processing a new commant. otherwise we skip to ne next character in the packet which sould be a $
return;
}
@@ -331,7 +331,7 @@ void mcd_read_byte(uint8_t ch)
else {
switch(mcdserver_state.state) {
case RS_IDLE:
- if (ch == '$') {
+ if (ch == TCP_COMMAND_START) {
/* start of command packet */
mcdserver_state.line_buf_index = 0;
mcdserver_state.line_sum = 0;
@@ -343,7 +343,7 @@ void mcd_read_byte(uint8_t ch)
}
break;
case RS_GETLINE:
- if (ch == '#') {
+ if (ch == TCP_COMMAND_END) {
/* end of command, start of checksum*/
mcdserver_state.line_buf[mcdserver_state.line_buf_index++] = 0;
//mcdserver_state.line_sum += ch;
@@ -365,24 +365,24 @@ void mcd_read_byte(uint8_t ch)
// we are now done with copying the data and in the suffix of the packet
// TODO: maybe wanna implement a checksum or sth like the gdb protocol has
- if (ch == '~') {
+ if (ch == TCP_WAS_NOT_LAST) {
// ~ indicates that there is an additional package coming
//acknowledged -> send +
- reply = '+';
+ reply = TCP_ACKNOWLEDGED;
mcd_put_buffer(&reply, 1);
mcdserver_state.state = mcd_handle_packet(mcdserver_state.line_buf);
}
- else if (ch == '|') {
+ else if (ch == TCP_WAS_LAST) {
//acknowledged -> send +
// | indicates that there is no additional package coming
- reply = '+';
+ reply = TCP_ACKNOWLEDGED;
mcd_put_buffer(&reply, 1);
mcdserver_state.state = mcd_handle_packet(mcdserver_state.line_buf);
}
else {
//trace_gdbstub_err_checksum_incorrect(mcdserver_state.line_sum, mcdserver_state.line_csum);
//not acknowledged -> send -
- reply = '-';
+ reply = TCP_NOT_ACKNOWLEDGED;
mcd_put_buffer(&reply, 1);
//waiting for package to get resent
mcdserver_state.state = RS_IDLE;
@@ -400,58 +400,58 @@ int mcd_handle_packet(const char *line_buf)
const MCDCmdParseEntry *cmd_parser = NULL;
switch (line_buf[0]) {
- case 'i':
+ case TCP_CHAR_INIT:
// handshake and lookup initialization
{
- static const MCDCmdParseEntry continue_cmd_desc = {
+ static MCDCmdParseEntry init_cmd_desc = {
.handler = handle_init,
- .cmd = "i",
};
- cmd_parser = &continue_cmd_desc;
+ init_cmd_desc.cmd = (char[2]) { (char) TCP_CHAR_INIT, '\0' };
+ cmd_parser = &init_cmd_desc;
}
break;
- case 'c':
+ case TCP_CHAR_GO:
// go command
{
- static const MCDCmdParseEntry continue_cmd_desc = {
+ static MCDCmdParseEntry go_cmd_desc = {
.handler = handle_continue,
- .cmd = "c",
};
- cmd_parser = &continue_cmd_desc;
+ go_cmd_desc.cmd = (char[2]) { (char) TCP_CHAR_GO, '\0' };
+ cmd_parser = &go_cmd_desc;
}
break;
- case 'k':
+ case TCP_CHAR_KILLQEMU:
// kill qemu completely
error_report("QEMU: Terminated via MCDstub");
mcd_exit(0);
exit(0);
- case 'q':
+ case TCP_CHAR_QUERY:
//query inquiry
{
- static const MCDCmdParseEntry gen_query_cmd_desc = {
+ static MCDCmdParseEntry query_cmd_desc = {
.handler = handle_gen_query,
- .cmd = "q",
.schema = ARG_SCHEMA_STRING
};
- cmd_parser = &gen_query_cmd_desc;
+ query_cmd_desc.cmd = (char[2]) { (char) TCP_CHAR_QUERY, '\0' };
+ cmd_parser = &query_cmd_desc;
}
break;
- case 'H':
+ case TCP_CHAR_OPEN_CORE:
{
- static const MCDCmdParseEntry gen_open_core = {
+ static MCDCmdParseEntry gen_open_core = {
.handler = handle_open_core,
- .cmd = "H",
- .schema = ARG_SCHEMA_CORE_NUM
+ .schema = ARG_SCHEMA_CORENUM
};
+ gen_open_core.cmd = (char[2]) { (char) TCP_CHAR_OPEN_CORE, '\0' };
cmd_parser = &gen_open_core;
}
break;
- case 'D':
+ case TCP_CHAR_DETACH:
{
- static const MCDCmdParseEntry detach_cmd_desc = {
+ static MCDCmdParseEntry detach_cmd_desc = {
.handler = handle_detach,
- .cmd = "D",
};
+ detach_cmd_desc.cmd = (char[2]) { (char) TCP_CHAR_DETACH, '\0' };
cmd_parser = &detach_cmd_desc;
}
break;
@@ -518,12 +518,12 @@ int cmd_parse_params(const char *data, const char *schema, GArray *params) {
this_param.data = data;
g_array_append_val(params, this_param);
}
- else if (schema[0] == atoi(ARG_SCHEMA_QRY_HANDLE)) {
+ else if (schema[0] == atoi(ARG_SCHEMA_QRYHANDLE)) {
strncat(data_buffer, data, strlen(data));
this_param.query_handle = atoi(data_buffer);
g_array_append_val(params, this_param);
}
- else if (schema[0] == atoi(ARG_SCHEMA_CORE_NUM)) {
+ else if (schema[0] == atoi(ARG_SCHEMA_CORENUM)) {
strncat(data_buffer, data, strlen(data));
this_param.cpu_id = atoi(data_buffer);
g_array_append_val(params, this_param);
--
2.34.1
From e448b636347739b964d2f24a343c8c009205a82e Mon Sep 17 00:00:00 2001
From: Nicolas Eder <nicolas.eder@lauterbach.com>
Date: Tue, 27 Jun 2023 17:23:05 +0200
Subject: [PATCH 09/29] memory and register query data now stored per core
Signed-off-by: Nicolas Eder <nicolas.eder@lauterbach.com>
---
mcdstub/internals.h | 63 +++-
mcdstub/mcd_shared_defines.h | 43 ++-
mcdstub/mcdstub.c | 693 ++++++++++++++++++++++-------------
3 files changed, 533 insertions(+), 266 deletions(-)
@@ -8,6 +8,7 @@
#include "exec/cpu-common.h"
#include "chardev/char.h"
+#include "hw/core/cpu.h"
// just used for the register xml files
#include "exec/gdbstub.h" /* xml_builtin */
@@ -22,9 +23,22 @@
#define MCD_TRIG_ACTION_DBG_DEBUG 0x00000001
// schema defines
-#define ARG_SCHEMA_QRYHANDLE "q"
-#define ARG_SCHEMA_STRING "s"
-#define ARG_SCHEMA_CORENUM "c"
+#define ARG_SCHEMA_QRYHANDLE 'q'
+#define ARG_SCHEMA_STRING 's'
+#define ARG_SCHEMA_CORENUM 'c'
+
+// resets
+#define RESET_SYSTEM "full_system_reset"
+#define RESET_GPR "gpr_reset"
+#define RESET_MEMORY "memory_reset"
+
+// more
+#define QUERY_TOTAL_NUMBER 11 //FIXME: set this to a usefull value in the end
+#define CMD_SCHEMA_LENGTH 2
+#define MCD_MAX_CORES 128
+#define MCD_SYSTEM_NAME "qemu-system"
+// tcp query packet values templates
+#define DEVICE_NAME_TEMPLATE(s) "qemu-" #s "-device"
// GDB stuff thats needed for GDB function, which we use
typedef struct GDBRegisterState {
@@ -52,8 +66,7 @@ typedef void (*MCDCmdHandler)(GArray *params, void *user_ctx);
typedef struct MCDCmdParseEntry {
MCDCmdHandler handler;
const char *cmd;
- bool cmd_startswith;
- const char *schema;
+ char schema[CMD_SCHEMA_LENGTH];
} MCDCmdParseEntry;
typedef enum MCDThreadIdKind {
@@ -92,6 +105,13 @@ enum RSState {
RS_DATAEND,
};
+typedef struct mcd_trigger_st {
+ uint32_t type;
+ uint32_t option;
+ uint32_t action;
+ uint32_t nr_trigger;
+} mcd_trigger_st;
+
typedef struct MCDState {
bool init; /* have we been initialised? */
CPUState *c_cpu; /* current CPU for everything */
@@ -113,9 +133,13 @@ typedef struct MCDState {
int supported_sstep_flags;
// my stuff
- GArray *memspaces;
- GArray *reggroups;
- GArray *registers;
+ uint32_t query_cpu_id;
+ GList *all_memspaces;
+ GList *all_reggroups;
+ GList *all_registers;
+ GArray *resets;
+ mcd_trigger_st trigger;
+ MCDCmdParseEntry mcd_query_cmds_table[QUERY_TOTAL_NUMBER];
} MCDState;
/* lives in main mcdstub.c */
@@ -164,6 +188,11 @@ typedef struct mcd_reg_st {
uint8_t opc2;
} mcd_reg_st;
+typedef struct mcd_reset_st {
+ const char *name;
+ uint8_t id;
+} mcd_reset_st;
+
// Inline utility function, convert from int to hex and back
@@ -194,6 +223,9 @@ void mcd_sigterm_handler(int signal);
#endif
void mcd_init_mcdserver_state(void);
+void init_query_cmds_table(MCDCmdParseEntry* mcd_query_cmds_table);
+int init_resets(GArray* resets);
+int init_trigger(mcd_trigger_st* trigger);
void reset_mcdserver_state(void);
void create_processes(MCDState *s);
void mcd_create_default_process(MCDState *s);
@@ -231,8 +263,10 @@ void handle_query_system(GArray *params, void *user_ctx);
CPUState *get_first_cpu_in_process(MCDProcess *process);
CPUState *find_cpu(uint32_t thread_id);
void handle_open_core(GArray *params, void *user_ctx);
-void handle_query_reset(GArray *params, void *user_ctx);
-void handle_detach(GArray *params, void *user_ctx);
+void handle_query_reset_f(GArray *params, void *user_ctx);
+void handle_query_reset_c(GArray *params, void *user_ctx);
+void handle_close_server(GArray *params, void *user_ctx);
+void handle_close_core(GArray *params, void *user_ctx);
void handle_query_trigger(GArray *params, void *user_ctx);
void mcd_continue(void);
void handle_query_reg_groups_f(GArray *params, void *user_ctx);
@@ -241,11 +275,14 @@ void handle_query_mem_spaces_f(GArray *params, void *user_ctx);
void handle_query_mem_spaces_c(GArray *params, void *user_ctx);
void handle_query_regs_f(GArray *params, void *user_ctx);
void handle_query_regs_c(GArray *params, void *user_ctx);
-void handle_init(GArray *params, void *user_ctx);
-void parse_reg_xml(const char *xml, int size);
+void handle_open_server(GArray *params, void *user_ctx);
+void parse_reg_xml(const char *xml, int size, GArray* registers);
// arm specific functions
-void mcd_arm_store_mem_spaces(int nr_address_spaces);
+int mcd_arm_store_mem_spaces(CPUState *cpu, GArray* memspaces);
+int mcd_arm_parse_core_xml_file(CPUClass *cc, GArray* reggroups, GArray* registers, int* current_group_id);
+int mcd_arm_parse_general_xml_files(CPUState *cpu, GArray* reggroups, GArray* registers, int* current_group_id);
+int mcd_arm_get_additional_register_info(GArray* reggroups, GArray* registers);
/* sycall handling */
void mcd_syscall_reset(void);
@@ -3,12 +3,13 @@
#ifndef MCD_SHARED_DEFINES
#define MCD_SHARED_DEFINES
-// tcp characters
-#define TCP_CHAR_INIT 'i'
+// tcp data characters
+#define TCP_CHAR_OPEN_SERVER 'I'
+#define TCP_CHAR_OPEN_CORE 'i'
#define TCP_CHAR_GO 'c'
#define TCP_CHAR_QUERY 'q'
-#define TCP_CHAR_OPEN_CORE 'H'
-#define TCP_CHAR_DETACH 'D'
+#define TCP_CHAR_CLOSE_SERVER 'D'
+#define TCP_CHAR_CLOSE_CORE 'd'
#define TCP_CHAR_KILLQEMU 'k'
// tcp protocol chars
@@ -18,7 +19,39 @@
#define TCP_COMMAND_END '#'
#define TCP_WAS_LAST '|'
#define TCP_WAS_NOT_LAST '~'
+#define TCP_HANDSHAKE_SUCCESS "shaking your hand"
+// tcp query arguments
+#define QUERY_FIRST "f"
+#define QUERY_CONSEQUTIVE "c"
+#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"
-#endif
\ No newline at end of file
+// tcp query packet argument list
+#define TCP_ARGUMENT_NAME "name"
+#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_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"
+
+#endif
@@ -27,7 +27,6 @@
#include "exec/tb-flush.h"
#include "sysemu/cpus.h"
#include "sysemu/replay.h"
-#include "hw/core/cpu.h"
#include "chardev/char.h"
#include "chardev/char-fe.h"
#include "monitor/monitor.h"
@@ -47,53 +46,6 @@ MCDSystemState mcdserver_system_state;
MCDState mcdserver_state;
-static const MCDCmdParseEntry mcd_gen_query_table[] = {
- // this is a list of all query commands. it gets iterated over only the handler of the matching command will get executed
- {
- .handler = handle_query_system,
- .cmd = "system",
- },
- {
- .handler = handle_query_cores,
- .cmd = "cores",
- },
- {
- .handler = handle_query_reset,
- .cmd = "reset",
- },
- {
- .handler = handle_query_trigger,
- .cmd = "trigger",
- },
- {
- .handler = handle_query_mem_spaces_f,
- .cmd = "memoryf",
- },
- {
- .handler = handle_query_mem_spaces_c,
- .cmd = "memoryc",
- .schema = ARG_SCHEMA_QRYHANDLE,
- },
- {
- .handler = handle_query_reg_groups_f,
- .cmd = "reggroupf",
- },
- {
- .handler = handle_query_reg_groups_c,
- .cmd = "reggroupc",
- .schema = ARG_SCHEMA_QRYHANDLE,
- },
- {
- .handler = handle_query_regs_f,
- .cmd = "regf",
- },
- {
- .handler = handle_query_regs_c,
- .cmd = "regc",
- .schema = ARG_SCHEMA_QRYHANDLE,
- },
-};
-
void mcd_init_mcdserver_state(void)
{
g_assert(!mcdserver_state.init);
@@ -113,6 +65,97 @@ void mcd_init_mcdserver_state(void)
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);
+}
+
+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++;
+
+ 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]) { (char) 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_mem_spaces_f = {
+ .handler = handle_query_mem_spaces_f,
+ .cmd = QUERY_ARG_MEMORY QUERY_FIRST,
+ };
+ strcpy(query_mem_spaces_f.schema, (char[2]) { (char) 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]) { (char) 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]) { (char) 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]) { (char) 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]) { (char) 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]) { (char) ARG_SCHEMA_QRYHANDLE, '\0' });
+ mcd_query_cmds_table[cmd_number] = query_regs_c;
}
void reset_mcdserver_state(void)
@@ -400,14 +443,14 @@ int mcd_handle_packet(const char *line_buf)
const MCDCmdParseEntry *cmd_parser = NULL;
switch (line_buf[0]) {
- case TCP_CHAR_INIT:
+ case TCP_CHAR_OPEN_SERVER:
// handshake and lookup initialization
{
- static MCDCmdParseEntry init_cmd_desc = {
- .handler = handle_init,
+ static MCDCmdParseEntry open_server_cmd_desc = {
+ .handler = handle_open_server,
};
- init_cmd_desc.cmd = (char[2]) { (char) TCP_CHAR_INIT, '\0' };
- cmd_parser = &init_cmd_desc;
+ open_server_cmd_desc.cmd = (char[2]) { (char) TCP_CHAR_OPEN_SERVER, '\0' };
+ cmd_parser = &open_server_cmd_desc;
}
break;
case TCP_CHAR_GO:
@@ -430,29 +473,39 @@ int mcd_handle_packet(const char *line_buf)
{
static MCDCmdParseEntry query_cmd_desc = {
.handler = handle_gen_query,
- .schema = ARG_SCHEMA_STRING
};
query_cmd_desc.cmd = (char[2]) { (char) TCP_CHAR_QUERY, '\0' };
+ strcpy(query_cmd_desc.schema, (char[2]) { (char) ARG_SCHEMA_STRING, '\0' });
cmd_parser = &query_cmd_desc;
}
break;
case TCP_CHAR_OPEN_CORE:
{
- static MCDCmdParseEntry gen_open_core = {
+ static MCDCmdParseEntry open_core_cmd_desc = {
.handler = handle_open_core,
- .schema = ARG_SCHEMA_CORENUM
};
- gen_open_core.cmd = (char[2]) { (char) TCP_CHAR_OPEN_CORE, '\0' };
- cmd_parser = &gen_open_core;
+ open_core_cmd_desc.cmd = (char[2]) { (char) TCP_CHAR_OPEN_CORE, '\0' };
+ strcpy(open_core_cmd_desc.schema, (char[2]) { (char) ARG_SCHEMA_CORENUM, '\0' });
+ cmd_parser = &open_core_cmd_desc;
}
break;
- case TCP_CHAR_DETACH:
+ case TCP_CHAR_CLOSE_SERVER:
{
- static MCDCmdParseEntry detach_cmd_desc = {
- .handler = handle_detach,
+ static MCDCmdParseEntry close_server_cmd_desc = {
+ .handler = handle_close_server,
};
- detach_cmd_desc.cmd = (char[2]) { (char) TCP_CHAR_DETACH, '\0' };
- cmd_parser = &detach_cmd_desc;
+ close_server_cmd_desc.cmd = (char[2]) { (char) TCP_CHAR_CLOSE_SERVER, '\0' };
+ 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]) { (char) TCP_CHAR_CLOSE_CORE, '\0' };
+ strcpy(close_core_cmd_desc.schema, (char[2]) { (char) ARG_SCHEMA_CORENUM, '\0' });
+ cmd_parser = &close_core_cmd_desc;
}
break;
default:
@@ -488,8 +541,8 @@ void handle_gen_query(GArray *params, void *user_ctx)
}
//now iterate over all possible query functions and execute the right one
if (process_string_cmd(NULL, get_param(params, 0)->data,
- mcd_gen_query_table,
- ARRAY_SIZE(mcd_gen_query_table))) {
+ mcdserver_state.mcd_query_cmds_table,
+ ARRAY_SIZE(mcdserver_state.mcd_query_cmds_table))) {
mcd_put_packet("");
}
}
@@ -514,16 +567,16 @@ int cmd_parse_params(const char *data, const char *schema, GArray *params) {
MCDCmdVariant this_param;
char data_buffer[64] = {0};
- if (schema[0] == atoi(ARG_SCHEMA_STRING)) {
+ if (schema[0] == ARG_SCHEMA_STRING) {
this_param.data = data;
g_array_append_val(params, this_param);
}
- else if (schema[0] == atoi(ARG_SCHEMA_QRYHANDLE)) {
+ else if (schema[0] == ARG_SCHEMA_QRYHANDLE) {
strncat(data_buffer, data, strlen(data));
this_param.query_handle = atoi(data_buffer);
g_array_append_val(params, this_param);
}
- else if (schema[0] == atoi(ARG_SCHEMA_CORENUM)) {
+ else if (schema[0] == ARG_SCHEMA_CORENUM) {
strncat(data_buffer, data, strlen(data));
this_param.cpu_id = atoi(data_buffer);
g_array_append_val(params, this_param);
@@ -799,7 +852,7 @@ CPUState *find_cpu(uint32_t thread_id)
}
-void parse_reg_xml(const char *xml, int size) {
+void parse_reg_xml(const char *xml, int size, GArray* registers) {
// iterates over the complete xml file
int i, j;
int still_to_skip = 0;
@@ -866,7 +919,7 @@ void parse_reg_xml(const char *xml, int size) {
}
}
// store register
- g_array_append_vals(mcdserver_state.registers, (gconstpointer)&my_register, 1);
+ g_array_append_vals(registers, (gconstpointer)&my_register, 1);
// free memory
g_array_free(reg_data, false);
}
@@ -924,7 +977,9 @@ int int_cmp(gconstpointer a, gconstpointer b) {
}
}
-void mcd_arm_store_mem_spaces(int nr_address_spaces) {
+int mcd_arm_store_mem_spaces(CPUState *cpu, GArray* memspaces) {
+ int nr_address_spaces = cpu->num_ases;
+
mcd_mem_space_st space1 = {
.name = "Non Secure",
.id = 1,
@@ -936,7 +991,7 @@ void mcd_arm_store_mem_spaces(int nr_address_spaces) {
.max_addr = -1,
.supported_access_options = 0,
};
- g_array_append_vals(mcdserver_state.memspaces, (gconstpointer)&space1, 1);
+ g_array_append_vals(memspaces, (gconstpointer)&space1, 1);
mcd_mem_space_st space2 = {
.name = "Physical (Non Secure)",
@@ -949,7 +1004,7 @@ void mcd_arm_store_mem_spaces(int nr_address_spaces) {
.max_addr = -1,
.supported_access_options = 0,
};
- g_array_append_vals(mcdserver_state.memspaces, (gconstpointer)&space2, 1);
+ g_array_append_vals(memspaces, (gconstpointer)&space2, 1);
if (nr_address_spaces==2) {
mcd_mem_space_st space3 = {
@@ -963,7 +1018,7 @@ void mcd_arm_store_mem_spaces(int nr_address_spaces) {
.max_addr = -1,
.supported_access_options = 0,
};
- g_array_append_vals(mcdserver_state.memspaces, (gconstpointer)&space3, 1);
+ g_array_append_vals(memspaces, (gconstpointer)&space3, 1);
mcd_mem_space_st space4 = {
.name = "Physical (Secure)",
.id = 4,
@@ -975,7 +1030,7 @@ void mcd_arm_store_mem_spaces(int nr_address_spaces) {
.max_addr = -1,
.supported_access_options = 0,
};
- g_array_append_vals(mcdserver_state.memspaces, (gconstpointer)&space4, 1);
+ g_array_append_vals(memspaces, (gconstpointer)&space4, 1);
}
// TODO: get dynamically how the per (CP15) space is called
mcd_mem_space_st space5 = {
@@ -989,7 +1044,7 @@ void mcd_arm_store_mem_spaces(int nr_address_spaces) {
.max_addr = -1,
.supported_access_options = 0,
};
- g_array_append_vals(mcdserver_state.memspaces, (gconstpointer)&space5, 1);
+ g_array_append_vals(memspaces, (gconstpointer)&space5, 1);
mcd_mem_space_st space6 = {
.name = "CP15 Registers",
.id = 6,
@@ -1001,16 +1056,43 @@ void mcd_arm_store_mem_spaces(int nr_address_spaces) {
.max_addr = -1,
.supported_access_options = 0,
};
- g_array_append_vals(mcdserver_state.memspaces, (gconstpointer)&space6, 1);
+ g_array_append_vals(memspaces, (gconstpointer)&space6, 1);
+
+ return 0;
+}
+
+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;
}
-void handle_init(GArray *params, void *user_ctx) {
- // the mcdserver is set up and we return the handshake
- mcd_put_packet("shaking your hand");
+int init_trigger(mcd_trigger_st* trigger) {
+ trigger->type = (MCD_TRIG_TYPE_IP | MCD_TRIG_TYPE_READ | MCD_TRIG_TYPE_WRITE | MCD_TRIG_TYPE_RW);
+ trigger->option = (MCD_TRIG_OPT_DATA_IS_CONDITION);
+ trigger->action = (MCD_TRIG_ACTION_DBG_DEBUG);
+ trigger->nr_trigger = 4;
+ return 0;
+}
+
+void handle_open_server(GArray *params, void *user_ctx) {
+ // initialize some 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) assert(0);
+ return_value = init_trigger(&mcdserver_state.trigger);
+ if (return_value!=0) assert(0);
+
+ mcd_put_packet(TCP_HANDSHAKE_SUCCESS);
}
void handle_query_system(GArray *params, void *user_ctx) {
- mcd_put_packet("qemu-system");
+ mcd_put_packet(MCD_SYSTEM_NAME);
}
void handle_query_cores(GArray *params, void *user_ctx) {
@@ -1030,138 +1112,179 @@ void handle_query_cores(GArray *params, void *user_ctx) {
int nr_cores = cpu->nr_cores;
- g_string_append_printf(mcdserver_state.str_buf, "device=\"qemu-%s-device\",core=\"%s\",nr_cores=\"%d\"", arch, cpu_model, nr_cores);
+ char device_name[] = DEVICE_NAME_TEMPLATE(arch);
+ g_string_printf(mcdserver_state.str_buf, "%s=%s.%s=%s.%s=%d.",
+ TCP_ARGUMENT_DEVICE, device_name, TCP_ARGUMENT_CORE, cpu_model, TCP_ARGUMENT_AMOUNT_CORE, nr_cores);
mcd_put_strbuf();
g_free(arch);
}
-void handle_open_core(GArray *params, void *user_ctx) {
- // get the cpu whith the given id
- uint32_t cpu_id = get_param(params, 0)->cpu_id;
-
- CPUState *cpu = mcd_get_cpu(cpu_id);
-
- CPUClass *cc = CPU_GET_CLASS(cpu);
-
- gchar *arch = cc->gdb_arch_name(cpu);
-
- // TODO: this might cause a memory leak when called a second time -> maybe free the Garray first
- mcdserver_state.memspaces = g_array_new(false, true, sizeof(mcd_mem_space_st));
- mcdserver_state.reggroups = g_array_new(false, true, sizeof(mcd_reg_group_st));
- mcdserver_state.registers = g_array_new(false, true, sizeof(mcd_reg_st));
-
-
- if (strcmp(arch, "arm")==0) {
- // store reg groups
- uint32_t current_group_id = 0;
-
- // at the moment we just assume there are 3 spaces (gpr, per and debug)
-
- // store mem spaces
- int nr_address_spaces = cpu->num_ases;
- mcd_arm_store_mem_spaces(nr_address_spaces);
- // mem spaces done
-
-
- GList *register_numbers = NULL;
+int mcd_arm_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 = xml_builtin[i][0];
+ 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;
+ }
- const char *xml_filename = NULL;
- const char *xml_content = NULL;
- const char *name = NULL;
- int i;
+ // 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;
- // 1. check out the core xml file
- xml_filename = cc->gdb_core_xml_file;
+ // 3. parse xml
+ xml_content = xml_builtin[i][1];
+ parse_reg_xml(xml_content, strlen(xml_content), registers);
+ return 0;
+}
- for (i = 0; ; i++) {
- name = xml_builtin[i][0];
- if (!name || (strncmp(name, xml_filename, strlen(xml_filename)) == 0 && strlen(name) == strlen(xml_filename)))
+int mcd_arm_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;
+ int i = 0;
+
+ // iterate over all gdb xml files
+ GDBRegisterState *r;
+ for (r = cpu->gdb_regs; r; r = r->next) {
+ 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;
+ }
+ }
+ else {
+ // its not a coprocessor xml -> it is a static xml file
+ for (i = 0; ; i++) {
+ current_xml_filename = xml_builtin[i][0];
+ 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
- assert(name);
- // add group for gpr registers
- current_group_id = 1;
- mcd_reg_group_st group1 = { .name = "GPR Registers", .id = current_group_id };
- g_array_append_vals(mcdserver_state.reggroups, (gconstpointer)&group1, 1);
-
- // parse xml
- xml_content = xml_builtin[i][1];
- parse_reg_xml(xml_content, strlen(xml_content));
-
- // 2. iterate over all other xml files
- GDBRegisterState *r;
- for (r = cpu->gdb_regs; r; r = r->next) {
- xml_filename = r->xml;
- xml_content = NULL;
-
- // first, check if this is a coprocessor xml
-
- // funciton call
- 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
- current_group_id = 2;
- mcd_reg_group_st group2 = { .name = "CP15 Registers", .id = current_group_id };
- g_array_append_vals(mcdserver_state.reggroups, (gconstpointer)&group2, 1);
- }
-
+ if (current_xml_filename) {
+ xml_content = xml_builtin[i][1];
}
else {
- // its not a coprocessor xml -> it is a static xml file
- for (i = 0; ; i++) {
- name = xml_builtin[i][0];
- if (!name || (strncmp(name, xml_filename, strlen(xml_filename)) == 0 && strlen(name) == strlen(xml_filename)))
- break;
- }
- if (name) {
- xml_content = xml_builtin[i][1];
- }
- else {
- printf("no data found for %s\n", xml_filename);
- continue;
- }
+ printf("no data found for %s\n", xml_filename);
+ continue;
}
+ }
+ // 2. parse xml
+ parse_reg_xml(xml_content, strlen(xml_content), registers);
+ }
+ return 0;
+}
- // parse xml
- parse_reg_xml(xml_content, strlen(xml_content));
+int mcd_arm_get_additional_register_info(GArray* reggroups, GArray* registers) {
+ GList *register_numbers = NULL;
+ mcd_reg_st *current_register;
+ int i = 0;
+ int id_neg_offset = 0;
+ int effective_id = 0;
+
+ // iterate over all registers
+ for (i = 0; i < registers->len; i++) {
+ current_register = &(g_array_index(registers, mcd_reg_st, i));
+ // 1. ad the id
+ if (current_register->id) {
+ // id is already in place
+ // NOTE: qemu doesn't emulate the FPA regs (so we are missing the indices 16 to 24)
+ int used_id = current_register->id;
+ register_numbers = g_list_append(register_numbers, &used_id);
+ id_neg_offset ++;
}
- // go over the register array and collect all additional data
- mcd_reg_st *current_register;
- int id_neg_offset = 0;
- int effective_id;
- for (i = 0; i < mcdserver_state.registers->len; i++) {
- current_register = &(g_array_index(mcdserver_state.registers, mcd_reg_st, i));
- // ad an id handle
- if (current_register->id) {
- // id is already in place
- //FIXME: we are missing 10 registers (likely the FPA regs or sth)
- int used_id = current_register->id;
- register_numbers = g_list_append(register_numbers, &used_id);
- id_neg_offset ++;
- }
- else {
- effective_id = i - id_neg_offset;
- if (g_list_find_custom(register_numbers, &effective_id, (GCompareFunc)int_cmp)!=NULL) {
- id_neg_offset --;
- }
- current_register->id = i - id_neg_offset;
- }
- // sort into correct reg_group and according mem_space
- if (strcmp(current_register->group, "cp_regs")==0) {
- current_register->mcd_reg_group_id = 2;
- current_register->mcd_mem_space_id = 6;
- // get info for opcode
- }
- else {
- // gpr register
- current_register->mcd_reg_group_id = 1;
- current_register->mcd_mem_space_id = 5;
+ else {
+ effective_id = i - id_neg_offset;
+ if (g_list_find_custom(register_numbers, &effective_id, (GCompareFunc)int_cmp)!=NULL) {
+ id_neg_offset --;
}
+ current_register->id = i - id_neg_offset;
+ }
+ // 2. 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;
+ // TODO: get info for opcode
+ }
+ else {
+ // gpr register
+ current_register->mcd_reg_group_id = 1;
+ current_register->mcd_mem_space_id = 5;
+ }
+ }
+ g_list_free(register_numbers);
+ return 0;
+}
+
+void handle_open_core(GArray *params, void *user_ctx) {
+ // get the cpu whith the given id
+ uint32_t cpu_id = get_param(params, 0)->cpu_id;
+ CPUState *cpu = mcd_get_cpu(cpu_id);
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+ 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, "arm")==0) {
+ // TODO: make group and memspace ids dynamic
+ int current_group_id = 1;
+ // 1. store mem spaces
+ return_value = mcd_arm_store_mem_spaces(cpu, memspaces);
+ if (return_value!=0) assert(0);
+ // 2. parse core xml
+ return_value = mcd_arm_parse_core_xml_file(cc, reggroups, registers, ¤t_group_id);
+ if (return_value!=0) assert(0);
+ // 3. parse other xmls
+ return_value = mcd_arm_parse_general_xml_files(cpu, reggroups, registers, ¤t_group_id);
+ if (return_value!=0) assert(0);
+ // 4. add additional data the the regs from the xmls
+ return_value = mcd_arm_get_additional_register_info(reggroups, registers);
+ if (return_value!=0) assert(0);
+ // 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);
}
- // free memory
- g_list_free(register_numbers);
}
else {
// we don't support other architectures
@@ -1170,30 +1293,77 @@ void handle_open_core(GArray *params, void *user_ctx) {
g_free(arch);
}
-void handle_query_reset(GArray *params, void *user_ctx) {
+void handle_query_reset_f(GArray *params, void *user_ctx) {
// resetting has to be done over a monitor (look ar Rcmd) so we tell MCD that we can reset but this still need to be implemented
- // we only support one reset over this monitor and that would be a fully "system_restart"
- mcd_put_packet("nr=\"3\",info=\"0,full_system_reset;1,gpr_reset;2,memory_reset;\"");
+ // we only support one reset over this monitor and that would be a full "system_restart"
+ // reset options are the same for every cpu!
+
+ // 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!");
+ }
+ else {
+ g_string_printf(mcdserver_state.str_buf, "1!");
+ }
+ // 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=%d.", TCP_ARGUMENT_NAME, reset.name, TCP_ARGUMENT_ID, reset.id);
+ mcd_put_strbuf();
+ // TODO: we still need to implement the gpr and memory reset here!
+}
+
+void handle_query_reset_c(GArray *params, void *user_ctx) {
+ // reset options are the same for every cpu!
+ int 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!");
+ }
+ else {
+ g_string_printf(mcdserver_state.str_buf, "%d!", 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=%d.", TCP_ARGUMENT_NAME, reset.name, TCP_ARGUMENT_ID, reset.id);
+ mcd_put_strbuf();
// TODO: we still need to implement the gpr and memory reset here!
}
-void handle_detach(GArray *params, void *user_ctx) {
+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);
+ g_array_free(memspaces, TRUE);
+ GArray* reggroups = g_list_nth_data(mcdserver_state.all_reggroups, cpu_id);
+ g_array_free(reggroups, TRUE);
+ GArray* registers = g_list_nth_data(mcdserver_state.all_registers, cpu_id);
+ g_array_free(registers, TRUE);
+}
+
+void handle_close_server(GArray *params, void *user_ctx) {
uint32_t pid = 1;
MCDProcess *process = mcd_get_process(pid);
- // 1. cleanup
- // gdb_process_breakpoint_remove_all(process);
+ // 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;
- // reset current cpus
- // TODO: if we don't use c_cpu we can delete this
- // this also checks to only reset THIS process we also probably don't need this since we only got one process!
+ // 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 process attached */
mcd_disable_syscalls();
@@ -1202,14 +1372,10 @@ void handle_detach(GArray *params, void *user_ctx) {
}
void handle_query_trigger(GArray *params, void *user_ctx) {
- // set the type, option and action bitmask and send it
-
- uint32_t type = (MCD_TRIG_TYPE_IP | MCD_TRIG_TYPE_READ | MCD_TRIG_TYPE_WRITE | MCD_TRIG_TYPE_RW);
- uint32_t option = (MCD_TRIG_OPT_DATA_IS_CONDITION);
- uint32_t action = (MCD_TRIG_ACTION_DBG_DEBUG);
- uint32_t nr_trigger = 4;
-
- g_string_printf(mcdserver_state.str_buf, "nr=\"%d\",info=\"%d;%d;%d;\"", nr_trigger, type, option, action);
+ mcd_trigger_st trigger = mcdserver_state.trigger;
+ g_string_printf(mcdserver_state.str_buf, "%s=%d.%s=%d.%s=%d.%s=%d.",
+ 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();
}
@@ -1221,8 +1387,13 @@ void mcd_continue(void)
}
void handle_query_mem_spaces_f(GArray *params, void *user_ctx) {
- // send the first mem space
- int nb_groups = mcdserver_state.memspaces->len;
+ // 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!");
@@ -1230,20 +1401,26 @@ void handle_query_mem_spaces_f(GArray *params, void *user_ctx) {
else {
g_string_printf(mcdserver_state.str_buf, "1!");
}
- mcd_mem_space_st space = g_array_index(mcdserver_state.memspaces, mcd_mem_space_st, 0);
- g_string_append_printf(mcdserver_state.str_buf, "name=%s.id=%d.type=%d.bpm=%d.i=%d.e=%d.min=%ld.max=%ld.sao=%d.",
- space.name, space.id, space.type, space.bits_per_mau, space.invariance, space.endian,
- space.min_addr, space.max_addr, space.supported_access_options);
+
+ // 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=%d.%s=%d.%s=%d.%s=%d.%s=%d.%s=%ld.%s=%ld.%s=%d.",
+ 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
+ // 1. get parameter and memspace
int 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 = mcdserver_state.memspaces->len;
+ 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!");
@@ -1253,16 +1430,23 @@ void handle_query_mem_spaces_c(GArray *params, void *user_ctx) {
}
// 3. send the correct memspace
- mcd_mem_space_st space = g_array_index(mcdserver_state.memspaces, mcd_mem_space_st, query_index);
- g_string_append_printf(mcdserver_state.str_buf, "name=%s.id=%d.type=%d.bpm=%d.i=%d.e=%d.min=%ld.max=%ld.sao=%d.",
- space.name, space.id, space.type, space.bits_per_mau, space.invariance, space.endian,
- space.min_addr, space.max_addr, space.supported_access_options);
+ 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=%d.%s=%d.%s=%d.%s=%d.%s=%d.%s=%ld.%s=%ld.%s=%d.",
+ 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) {
- // send the first reg group
- int nb_groups = mcdserver_state.reggroups->len;
+ // 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!");
@@ -1270,18 +1454,21 @@ void handle_query_reg_groups_f(GArray *params, void *user_ctx) {
else {
g_string_printf(mcdserver_state.str_buf, "1!");
}
- mcd_reg_group_st group = g_array_index(mcdserver_state.reggroups, mcd_reg_group_st, 0);
- g_string_append_printf(mcdserver_state.str_buf, "id=%d.name=%s.", group.id, group.name);
+ // 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=%d.%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
+ // 1. get parameter and memspace
int 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 = mcdserver_state.reggroups->len;
+ 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!");
@@ -1291,14 +1478,19 @@ void handle_query_reg_groups_c(GArray *params, void *user_ctx) {
}
// 3. send the correct reggroup
- mcd_reg_group_st group = g_array_index(mcdserver_state.reggroups, mcd_reg_group_st, query_index);
- g_string_append_printf(mcdserver_state.str_buf, "id=%d.name=%s.", group.id, group.name);
+ mcd_reg_group_st group = g_array_index(reggroups, mcd_reg_group_st, query_index);
+ g_string_append_printf(mcdserver_state.str_buf, "%s=%d.%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) {
- // send the first register
- int nb_regs = mcdserver_state.registers->len;
+ // 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!");
@@ -1306,20 +1498,24 @@ void handle_query_regs_f(GArray *params, void *user_ctx) {
else {
g_string_printf(mcdserver_state.str_buf, "1!");
}
- mcd_reg_st my_register = g_array_index(mcdserver_state.registers, mcd_reg_st, 0);
- g_string_append_printf(mcdserver_state.str_buf, "id=%d.name=%s.size=%d.reggroupid=%d.memspaceid=%d.type=%d.thread=%d.",
- my_register.id, my_register.name, my_register.bitsize, my_register.mcd_reg_group_id,
- my_register.mcd_mem_space_id, my_register.mcd_reg_type, my_register.mcd_hw_thread_id);
+ // 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=%d.%s=%s.%s=%d.%s=%d.%s=%d.%s=%d.%s=%d.",
+ 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);
mcd_put_strbuf();
}
void handle_query_regs_c(GArray *params, void *user_ctx) {
- // this funcitons send all registers except for the first
- // 1. get parameter
+ // this funcitons send all reg groups except for the first
+ // 1. get parameter and registers
int 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 = mcdserver_state.registers->len;
+ 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!");
@@ -1329,9 +1525,10 @@ void handle_query_regs_c(GArray *params, void *user_ctx) {
}
// 3. send the correct register
- mcd_reg_st my_register = g_array_index(mcdserver_state.registers, mcd_reg_st, query_index);
- g_string_append_printf(mcdserver_state.str_buf, "id=%d.name=%s.size=%d.reggroupid=%d.memspaceid=%d.type=%d.thread=%d.",
- my_register.id, my_register.name, my_register.bitsize, my_register.mcd_reg_group_id,
- my_register.mcd_mem_space_id, my_register.mcd_reg_type, my_register.mcd_hw_thread_id);
+ mcd_reg_st my_register = g_array_index(registers, mcd_reg_st, query_index);
+ g_string_append_printf(mcdserver_state.str_buf, "%s=%d.%s=%s.%s=%d.%s=%d.%s=%d.%s=%d.%s=%d.",
+ 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);
mcd_put_strbuf();
}
--
2.34.1
From e6c686ad758340f1545b928ee54fb4929402ced7 Mon Sep 17 00:00:00 2001
From: Nicolas Eder <nicolas.eder@lauterbach.com>
Date: Wed, 28 Jun 2023 18:01:44 +0200
Subject: [PATCH 10/29] handler for resets added
Signed-off-by: Nicolas Eder <nicolas.eder@lauterbach.com>
---
mcdstub/internals.h | 14 ++++----
mcdstub/mcd_shared_defines.h | 4 +++
mcdstub/mcdstub.c | 65 ++++++++++++++++++++++++++++--------
3 files changed, 63 insertions(+), 20 deletions(-)
@@ -25,6 +25,7 @@
// schema defines
#define ARG_SCHEMA_QRYHANDLE 'q'
#define ARG_SCHEMA_STRING 's'
+#define ARG_SCHEMA_INT 'd'
#define ARG_SCHEMA_CORENUM 'c'
// resets
@@ -34,8 +35,8 @@
// more
#define QUERY_TOTAL_NUMBER 11 //FIXME: set this to a usefull value in the end
-#define CMD_SCHEMA_LENGTH 2
-#define MCD_MAX_CORES 128
+#define CMD_SCHEMA_LENGTH 3
+#define MAX_SCHEMA_ARGS CMD_SCHEMA_LENGTH-1
#define MCD_SYSTEM_NAME "qemu-system"
// tcp query packet values templates
#define DEVICE_NAME_TEMPLATE(s) "qemu-" #s "-device"
@@ -77,17 +78,17 @@ typedef enum MCDThreadIdKind {
} MCDThreadIdKind;
typedef union MCDCmdVariant {
- const char *data;
+ const char *data;
+ int data_int;
+ int query_handle;
+ int cpu_id;
struct {
MCDThreadIdKind kind;
uint32_t pid;
uint32_t tid;
} thread_id;
- int query_handle;
- int cpu_id;
-
} MCDCmdVariant;
#define get_param(p, i) (&g_array_index(p, MCDCmdVariant, i))
@@ -277,6 +278,7 @@ void handle_query_regs_f(GArray *params, void *user_ctx);
void handle_query_regs_c(GArray *params, void *user_ctx);
void handle_open_server(GArray *params, void *user_ctx);
void parse_reg_xml(const char *xml, int size, GArray* registers);
+void handle_reset(GArray *params, void *user_ctx);
// arm specific functions
int mcd_arm_store_mem_spaces(CPUState *cpu, GArray* memspaces);
@@ -11,6 +11,7 @@
#define TCP_CHAR_CLOSE_SERVER 'D'
#define TCP_CHAR_CLOSE_CORE 'd'
#define TCP_CHAR_KILLQEMU 'k'
+#define TCP_CHAR_RESET 'r'
// tcp protocol chars
#define TCP_ACKNOWLEDGED '+'
@@ -54,4 +55,7 @@
#define TCP_ARGUMENT_OPTION "option"
#define TCP_ARGUMENT_ACTION "action"
+// for packets sent to qemu
+#define ARGUMENT_SEPARATOR ';'
+
#endif
@@ -508,6 +508,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]) { (char) TCP_CHAR_RESET, '\0' };
+ strcpy(reset_cmd_desc.schema, (char[3]) { (char) ARG_SCHEMA_INT, ARG_SCHEMA_INT, '\0' });
+ cmd_parser = &reset_cmd_desc;
+ }
+ break;
default:
// could not perform the command (because its unknown)
mcd_put_packet("");
@@ -564,24 +574,42 @@ void run_cmd_parser(const char *data, const MCDCmdParseEntry *cmd)
}
int cmd_parse_params(const char *data, const char *schema, GArray *params) {
- MCDCmdVariant this_param;
-
+
char data_buffer[64] = {0};
- if (schema[0] == ARG_SCHEMA_STRING) {
- this_param.data = data;
- g_array_append_val(params, this_param);
- }
- else if (schema[0] == ARG_SCHEMA_QRYHANDLE) {
- strncat(data_buffer, data, strlen(data));
- this_param.query_handle = atoi(data_buffer);
- g_array_append_val(params, this_param);
+ char *separator = strchr(data_buffer, ARGUMENT_SEPARATOR);
+ int seperator_index = (int)(separator - data);
+
+ if (separator) {
+ // we got two arguments
+ strncpy(data_buffer, data, seperator_index);
}
- else if (schema[0] == ARG_SCHEMA_CORENUM) {
- strncat(data_buffer, data, strlen(data));
- this_param.cpu_id = atoi(data_buffer);
- g_array_append_val(params, this_param);
+ else {
+ strncpy(data_buffer, data, strlen(data));
}
+ for (int i = 0; i<MAX_SCHEMA_ARGS; i++) {
+ MCDCmdVariant this_param;
+ if (schema[i] == ARG_SCHEMA_STRING) {
+ this_param.data = data_buffer;
+ g_array_append_val(params, this_param);
+ }
+ else if (schema[i] == ARG_SCHEMA_INT) {
+ this_param.data_int = atoi(data_buffer);
+ g_array_append_val(params, this_param);
+ }
+ else if (schema[i] == ARG_SCHEMA_QRYHANDLE) {
+ this_param.query_handle = atoi(data_buffer);
+ g_array_append_val(params, this_param);
+ }
+ else if (schema[i] == ARG_SCHEMA_CORENUM) {
+ this_param.cpu_id = atoi(data_buffer);
+ g_array_append_val(params, this_param);
+ }
+ if (separator) {
+ // we got two arguments
+ strncpy(data_buffer, &data[seperator_index+1], strlen(&data[seperator_index+1]));
+ }
+ }
return 0;
}
@@ -1532,3 +1560,12 @@ void handle_query_regs_c(GArray *params, void *user_ctx) {
TCP_ARGUMENT_TYPE, my_register.mcd_reg_type, TCP_ARGUMENT_THREAD, my_register.mcd_hw_thread_id);
mcd_put_strbuf();
}
+
+void handle_reset(GArray *params, void *user_ctx) {
+ int reset_id = get_param(params, 0)->data_int;
+ int bool_halt_after_reset = get_param(params, 1)->data_int;
+ if (reset_id>=0 && bool_halt_after_reset) {
+ //fun for the compiler
+ }
+
+}
--
2.34.1
From cade07c1cd8929a4116711a2e798b5983a2aaec2 Mon Sep 17 00:00:00 2001
From: Nicolas Eder <nicolas.eder@lauterbach.com>
Date: Thu, 29 Jun 2023 16:06:28 +0200
Subject: [PATCH 11/29] query for the VM state added
Signed-off-by: Nicolas Eder <nicolas.eder@lauterbach.com>
---
mcdstub/internals.h | 54 ++++++++-
mcdstub/mcd_shared_defines.h | 13 ++
mcdstub/mcdstub.c | 229 ++++++++++++++++++++++++++++-------
3 files changed, 249 insertions(+), 47 deletions(-)
@@ -22,6 +22,21 @@
#define MCD_TRIG_OPT_DATA_IS_CONDITION 0x00000008
#define MCD_TRIG_ACTION_DBG_DEBUG 0x00000001
+typedef uint32_t mcd_core_event_et;
+enum {
+ MCD_CORE_EVENT_NONE = 0x00000000, /**< No since the last poll. */
+ MCD_CORE_EVENT_MEMORY_CHANGE = 0x00000001, /**< Memory content has changed. */
+ MCD_CORE_EVENT_REGISTER_CHANGE = 0x00000002, /**< Register contents have changed. */
+ MCD_CORE_EVENT_TRACE_CHANGE = 0x00000004, /**< Trace contents or states have changed. */
+ MCD_CORE_EVENT_TRIGGER_CHANGE = 0x00000008, /**< Triggers or trigger states have changed. */
+ MCD_CORE_EVENT_STOPPED = 0x00000010, /**< Target was stopped at least once since the last poll,
+ it may already be running again. */
+ MCD_CORE_EVENT_CHL_PENDING = 0x00000020, /**< A target communication channel request from the target
+ is pending. */
+ MCD_CORE_EVENT_CUSTOM_LO = 0x00010000, /**< Begin Range: User defined core events. */
+ MCD_CORE_EVENT_CUSTOM_HI = 0x40000000, /**< End Range: User defined core events. */
+};
+
// schema defines
#define ARG_SCHEMA_QRYHANDLE 'q'
#define ARG_SCHEMA_STRING 's'
@@ -34,13 +49,25 @@
#define RESET_MEMORY "memory_reset"
// more
-#define QUERY_TOTAL_NUMBER 11 //FIXME: set this to a usefull value in the end
-#define CMD_SCHEMA_LENGTH 3
-#define MAX_SCHEMA_ARGS CMD_SCHEMA_LENGTH-1
+#define QUERY_TOTAL_NUMBER 12 //FIXME: set this to a usefull value in the end
+#define CMD_SCHEMA_LENGTH 2
#define MCD_SYSTEM_NAME "qemu-system"
// 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_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"
+
// GDB stuff thats needed for GDB function, which we use
typedef struct GDBRegisterState {
int base_reg;
@@ -113,6 +140,16 @@ typedef struct mcd_trigger_st {
uint32_t nr_trigger;
} mcd_trigger_st;
+typedef struct mcd_cpu_state_st {
+ const char *state;
+ bool memory_changed;
+ bool registers_changed;
+ bool target_was_stopped;
+ uint32_t trig_id;
+ 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 */
@@ -134,12 +171,15 @@ typedef struct MCDState {
int supported_sstep_flags;
// my stuff
+ RunState vm_current_state;
+ RunState vm_previous_state;
uint32_t query_cpu_id;
GList *all_memspaces;
GList *all_reggroups;
GList *all_registers;
GArray *resets;
mcd_trigger_st trigger;
+ mcd_cpu_state_st cpu_state;
MCDCmdParseEntry mcd_query_cmds_table[QUERY_TOTAL_NUMBER];
} MCDState;
@@ -254,9 +294,9 @@ void mcd_exit(int code);
void run_cmd_parser(const char *data, const MCDCmdParseEntry *cmd);
int process_string_cmd(void *user_ctx, const char *data, const MCDCmdParseEntry *cmds, int num_cmds);
int cmd_parse_params(const char *data, const char *schema, GArray *params);
-void handle_continue(GArray *params, void *user_ctx);
+void handle_vm_start(GArray *params, void *user_ctx);
+void handle_vm_stop(GArray *params, void *user_ctx);
void handle_gen_query(GArray *params, void *user_ctx);
-void mcd_append_thread_id(CPUState *cpu, GString *buf);
int mcd_get_cpu_index(CPUState *cpu);
CPUState* mcd_get_cpu(uint32_t i_cpu_index);
void handle_query_cores(GArray *params, void *user_ctx);
@@ -269,7 +309,8 @@ void handle_query_reset_c(GArray *params, void *user_ctx);
void handle_close_server(GArray *params, void *user_ctx);
void handle_close_core(GArray *params, void *user_ctx);
void handle_query_trigger(GArray *params, void *user_ctx);
-void mcd_continue(void);
+void mcd_vm_start(void);
+void mcd_vm_stop(void);
void handle_query_reg_groups_f(GArray *params, void *user_ctx);
void handle_query_reg_groups_c(GArray *params, void *user_ctx);
void handle_query_mem_spaces_f(GArray *params, void *user_ctx);
@@ -279,6 +320,7 @@ void handle_query_regs_c(GArray *params, void *user_ctx);
void handle_open_server(GArray *params, void *user_ctx);
void parse_reg_xml(const char *xml, int size, GArray* registers);
void handle_reset(GArray *params, void *user_ctx);
+void handle_query_state(GArray *params, void *user_ctx);
// arm specific functions
int mcd_arm_store_mem_spaces(CPUState *cpu, GArray* memspaces);
@@ -7,6 +7,7 @@
#define TCP_CHAR_OPEN_SERVER 'I'
#define TCP_CHAR_OPEN_CORE 'i'
#define TCP_CHAR_GO 'c'
+#define TCP_CHAR_BREAK 'b'
#define TCP_CHAR_QUERY 'q'
#define TCP_CHAR_CLOSE_SERVER 'D'
#define TCP_CHAR_CLOSE_CORE 'd'
@@ -33,6 +34,7 @@
#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"
@@ -48,6 +50,11 @@
#define TCP_ARGUMENT_MEMSPACEID "memspaceid"
#define TCP_ARGUMENT_SIZE "size"
#define TCP_ARGUMENT_THREAD "thread"
+#define TCP_ARGUMENT_TRIGGER_ID "trig_id"
+#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"
@@ -58,4 +65,10 @@
// for packets sent to qemu
#define ARGUMENT_SEPARATOR ';'
+// core states
+#define CORE_STATE_RUNNING "running"
+#define CORE_STATE_HALTED "halted"
+#define CORE_STATE_DEBUG "debug"
+#define CORE_STATE_UNKNOWN "unknown"
+
#endif
@@ -68,6 +68,13 @@ void mcd_init_mcdserver_state(void)
// 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;
}
void init_query_cmds_table(MCDCmdParseEntry* mcd_query_cmds_table) {
@@ -156,6 +163,14 @@ void init_query_cmds_table(MCDCmdParseEntry* mcd_query_cmds_table) {
};
strcpy(query_regs_c.schema, (char[2]) { (char) 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,
+ };
+ strcpy(query_state.schema, (char[2]) { (char) ARG_SCHEMA_CORENUM, '\0' });
+ mcd_query_cmds_table[cmd_number] = query_state;
}
void reset_mcdserver_state(void)
@@ -336,6 +351,7 @@ void mcd_chr_receive(void *opaque, const uint8_t *buf, int size)
for (i = 0; i < size; i++) {
mcd_read_byte(buf[i]);
+ if (buf[i]==0) break;
}
}
@@ -366,12 +382,12 @@ void mcd_read_byte(uint8_t ch)
return;
}
}
- if (runstate_is_running()) {
+ //if (runstate_is_running()) {
/* when the CPU is running, we cannot do anything except stop
it when receiving a char */
- vm_stop(RUN_STATE_PAUSED);
- }
- else {
+ //vm_stop(RUN_STATE_PAUSED);
+ //}
+ //else {
switch(mcdserver_state.state) {
case RS_IDLE:
if (ch == TCP_COMMAND_START) {
@@ -434,7 +450,7 @@ void mcd_read_byte(uint8_t ch)
default:
abort();
}
- }
+ //}
}
int mcd_handle_packet(const char *line_buf)
@@ -457,12 +473,22 @@ int mcd_handle_packet(const char *line_buf)
// go command
{
static MCDCmdParseEntry go_cmd_desc = {
- .handler = handle_continue,
+ .handler = handle_vm_start,
};
go_cmd_desc.cmd = (char[2]) { (char) TCP_CHAR_GO, '\0' };
cmd_parser = &go_cmd_desc;
}
break;
+ case TCP_CHAR_BREAK:
+ // go command
+ {
+ static MCDCmdParseEntry break_cmd_desc = {
+ .handler = handle_vm_stop,
+ };
+ break_cmd_desc.cmd = (char[2]) { (char) TCP_CHAR_BREAK, '\0' };
+ cmd_parser = &break_cmd_desc;
+ }
+ break;
case TCP_CHAR_KILLQEMU:
// kill qemu completely
error_report("QEMU: Terminated via MCDstub");
@@ -514,7 +540,7 @@ int mcd_handle_packet(const char *line_buf)
.handler = handle_reset,
};
reset_cmd_desc.cmd = (char[2]) { (char) TCP_CHAR_RESET, '\0' };
- strcpy(reset_cmd_desc.schema, (char[3]) { (char) ARG_SCHEMA_INT, ARG_SCHEMA_INT, '\0' });
+ strcpy(reset_cmd_desc.schema, (char[2]) { (char) ARG_SCHEMA_INT, '\0' });
cmd_parser = &reset_cmd_desc;
}
break;
@@ -532,16 +558,14 @@ int mcd_handle_packet(const char *line_buf)
return RS_IDLE;
}
-void handle_continue(GArray *params, void *user_ctx)
-{
- /*
- if (params->len) {
- gdb_set_cpu_pc(get_param(params, 0)->val_ull);
- }
+void handle_vm_start(GArray *params, void *user_ctx) {
+ // todo add partial restart with arguments and so on
+ mcd_vm_start();
+}
- mcdserver_state.signal = 0;
- gdb_continue();
- */
+void handle_vm_stop(GArray *params, void *user_ctx) {
+ // todo add partial stop with arguments and so on
+ mcd_vm_stop();
}
void handle_gen_query(GArray *params, void *user_ctx)
@@ -576,7 +600,7 @@ void run_cmd_parser(const char *data, const MCDCmdParseEntry *cmd)
int cmd_parse_params(const char *data, const char *schema, GArray *params) {
char data_buffer[64] = {0};
- char *separator = strchr(data_buffer, ARGUMENT_SEPARATOR);
+ char *separator = strchr(data, ARGUMENT_SEPARATOR);
int seperator_index = (int)(separator - data);
if (separator) {
@@ -586,25 +610,29 @@ int cmd_parse_params(const char *data, const char *schema, GArray *params) {
else {
strncpy(data_buffer, data, strlen(data));
}
- for (int i = 0; i<MAX_SCHEMA_ARGS; i++) {
- MCDCmdVariant this_param;
- if (schema[i] == ARG_SCHEMA_STRING) {
- this_param.data = data_buffer;
+ for (int i = 0; i<strlen(schema); i++) {
+ MCDCmdVariant this_param;
+ switch (schema[i]) {
+ case ARG_SCHEMA_STRING:
+ this_param.data = data;
g_array_append_val(params, this_param);
- }
- else if (schema[i] == ARG_SCHEMA_INT) {
+ break;
+ case ARG_SCHEMA_INT:
this_param.data_int = atoi(data_buffer);
g_array_append_val(params, this_param);
- }
- else if (schema[i] == ARG_SCHEMA_QRYHANDLE) {
+ break;
+ case ARG_SCHEMA_QRYHANDLE:
this_param.query_handle = atoi(data_buffer);
g_array_append_val(params, this_param);
- }
- else if (schema[i] == ARG_SCHEMA_CORENUM) {
+ break;
+ case ARG_SCHEMA_CORENUM:
this_param.cpu_id = atoi(data_buffer);
g_array_append_val(params, this_param);
+ break;
+ default:
+ return -1;
}
-
+
if (separator) {
// we got two arguments
strncpy(data_buffer, &data[seperator_index+1], strlen(&data[seperator_index+1]));
@@ -633,7 +661,7 @@ int process_string_cmd(void *user_ctx, const char *data, const MCDCmdParseEntry
}
// if a schema is provided we need to extract parameters from the data string
- if (cmd->schema) {
+ if (strlen(cmd->schema)) {
// this only gets the data from data beginning after the command name
if (cmd_parse_params(&data[strlen(cmd->cmd)], cmd->schema, params)) {
return -1;
@@ -679,7 +707,7 @@ void mcd_chr_event(void *opaque, QEMUChrEvent event)
s->c_cpu = mcd_first_attached_cpu();
- vm_stop(RUN_STATE_PAUSED);
+ //vm_stop(RUN_STATE_PAUSED);
//TODO: this might not be necessary
//replay_gdb_attached();
//gdb_has_xml = false;
@@ -709,14 +737,98 @@ void mcd_sigterm_handler(int signal)
void mcd_vm_state_change(void *opaque, bool running, RunState state)
{
- printf("this calls state_change\n");
+ CPUState *cpu = mcdserver_state.c_cpu;
+
+ // update cpu state
+ mcdserver_state.vm_previous_state = mcdserver_state.vm_current_state;
+ mcdserver_state.vm_current_state = state;
+
+ if (mcdserver_state.state == RS_INACTIVE) {
+ return;
+ }
+
+ if (cpu == NULL) {
+ if (running) {
+ // this is the case if qemu starts the vm before any mcd 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.state = info_str;
+ }
+ return;
+ }
+
+ const char *mcd_state;
+ const char *stop_str;
+ const char *info_str;
+ uint32_t trig_id = 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:
+ trig_id = MCD_TRIG_TYPE_READ;
+ stop_str = STATE_STR_BREAK_READ(cpu->watchpoint_hit->hitaddr);
+ break;
+ case BP_MEM_WRITE:
+ trig_id = MCD_TRIG_TYPE_WRITE;
+ stop_str = STATE_STR_BREAK_WRITE(cpu->watchpoint_hit->hitaddr);
+ break;
+ case BP_MEM_ACCESS:
+ trig_id = MCD_TRIG_TYPE_RW;
+ stop_str = STATE_STR_BREAK_RW(cpu->watchpoint_hit->hitaddr);
+ break;
+ default:
+ break;
+ stop_str = STATE_STR_BREAK_UNKNOWN;
+ }
+ cpu->watchpoint_hit = NULL;
+ } else {
+ // "hardware" breakpoint hit!
+ trig_id = MCD_TRIG_TYPE_IP;
+ stop_str = STATE_STR_BREAK_HW;
+ tb_flush(cpu);
+ }
+ 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 = "";
+ printf("runstate watchdog hit\n");
+ break;
+ default:
+ info_str = STATE_STR_UNKNOWN(cpu->cpu_index);
+ mcd_state = CORE_STATE_UNKNOWN;
+ stop_str = "";
+ // we don't care;
+ break;
+ }
+
+ mcdserver_state.cpu_state.state = mcd_state;
+ mcdserver_state.cpu_state.trig_id = trig_id;
+ mcdserver_state.cpu_state.stop_str = stop_str;
+ mcdserver_state.cpu_state.info_str = info_str;
+
+ /* disable single step if it was enabled */
+ cpu_single_step(cpu, 0);
}
int mcd_put_packet(const char *buf)
{
- //tracing
- //trace_gdbstub_io_reply(buf);
-
return mcd_put_packet_binary(buf, strlen(buf), false);
}
@@ -1267,6 +1379,7 @@ void handle_open_core(GArray *params, void *user_ctx) {
// get the cpu whith the given id
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);
gchar *arch = cc->gdb_arch_name(cpu);
int return_value = 0;
@@ -1318,6 +1431,7 @@ void handle_open_core(GArray *params, void *user_ctx) {
// we don't support other architectures
assert(0);
}
+
g_free(arch);
}
@@ -1367,10 +1481,13 @@ 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);
}
@@ -1395,7 +1512,7 @@ void handle_close_server(GArray *params, void *user_ctx) {
if (!mcdserver_state.c_cpu) {
/* No more process attached */
mcd_disable_syscalls();
- mcd_continue();
+ mcd_vm_start();
}
}
@@ -1407,13 +1524,19 @@ void handle_query_trigger(GArray *params, void *user_ctx) {
mcd_put_strbuf();
}
-void mcd_continue(void)
-{
- if (!runstate_needs_reset()) {
+void mcd_vm_start(void) {
+ if (!runstate_needs_reset() && !runstate_is_running()) {
vm_start();
}
}
+void mcd_vm_stop(void) {
+ if (runstate_is_running()) {
+ //might want to have DEBUG state here but idk
+ vm_stop(RUN_STATE_PAUSED);
+ }
+}
+
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;
@@ -1563,9 +1686,33 @@ void handle_query_regs_c(GArray *params, void *user_ctx) {
void handle_reset(GArray *params, void *user_ctx) {
int reset_id = get_param(params, 0)->data_int;
- int bool_halt_after_reset = get_param(params, 1)->data_int;
- if (reset_id>=0 && bool_halt_after_reset) {
+ //int bool_halt_after_reset = get_param(params, 1)->data_int;
+ if (reset_id>=0) {
//fun for the compiler
}
-
+}
+
+void handle_query_state(GArray *params, void *user_ctx) {
+ // send state from correct core
+ //uint32_t cpu_id = get_param(params, 0)->cpu_id;
+ // get state info
+ mcd_cpu_state_st state_info = mcdserver_state.cpu_state;
+ mcd_core_event_et event = MCD_CORE_EVENT_NONE;
+ if (state_info.memory_changed) {
+ event = event | MCD_CORE_EVENT_MEMORY_CHANGE;
+ state_info.memory_changed = false;
+ }
+ if (state_info.registers_changed) {
+ event = event | MCD_CORE_EVENT_REGISTER_CHANGE;
+ state_info.registers_changed = false;
+ }
+ if (state_info.target_was_stopped) {
+ event = event | MCD_CORE_EVENT_STOPPED;
+ state_info.target_was_stopped = false;
+ }
+ // send data
+ g_string_printf(mcdserver_state.str_buf, "%s=%s.%s=%d.%s=%d.%s=%d.%s=%s.%s=%s.", TCP_ARGUMENT_STATE, state_info.state,
+ TCP_ARGUMENT_EVENT, event, TCP_ARGUMENT_THREAD, 0, TCP_ARGUMENT_TRIGGER_ID, state_info.trig_id,
+ TCP_ARGUMENT_STOP_STRING, state_info.stop_str, TCP_ARGUMENT_INFO_STRING, state_info.info_str);
+ mcd_put_strbuf();
}
--
2.34.1
From f7175242512470cccc930f10759327553e1e4b03 Mon Sep 17 00:00:00 2001
From: Nicolas Eder <nicolas.eder@lauterbach.com>
Date: Sun, 2 Jul 2023 14:44:05 +0200
Subject: [PATCH 12/29] handler for reading registers added
Signed-off-by: Nicolas Eder <nicolas.eder@lauterbach.com>
---
mcdstub/internals.h | 11 ++-
mcdstub/mcd_shared_defines.h | 7 ++
mcdstub/mcdstub.c | 129 +++++++++++++++++++++++++++++++++++
target/arm/mcdstub.c | 75 ++++++++++++++++++++
target/arm/mcdstub.h | 7 ++
5 files changed, 228 insertions(+), 1 deletion(-)
create mode 100644 target/arm/mcdstub.c
create mode 100644 target/arm/mcdstub.h
@@ -41,6 +41,7 @@ enum {
#define ARG_SCHEMA_QRYHANDLE 'q'
#define ARG_SCHEMA_STRING 's'
#define ARG_SCHEMA_INT 'd'
+#define ARG_SCHEMA_UINT32_T 'l'
#define ARG_SCHEMA_CORENUM 'c'
// resets
@@ -50,7 +51,7 @@ enum {
// more
#define QUERY_TOTAL_NUMBER 12 //FIXME: set this to a usefull value in the end
-#define CMD_SCHEMA_LENGTH 2
+#define CMD_SCHEMA_LENGTH 3
#define MCD_SYSTEM_NAME "qemu-system"
// tcp query packet values templates
#define DEVICE_NAME_TEMPLATE(s) "qemu-" #s "-device"
@@ -108,6 +109,7 @@ typedef union MCDCmdVariant {
const char *data;
int data_int;
+ uint64_t data_uint64_t;
int query_handle;
int cpu_id;
struct {
@@ -321,6 +323,12 @@ void handle_open_server(GArray *params, void *user_ctx);
void parse_reg_xml(const char *xml, int size, GArray* registers);
void handle_reset(GArray *params, void *user_ctx);
void handle_query_state(GArray *params, void *user_ctx);
+void handle_read_register(GArray *params, void *user_ctx);
+void handle_write_register(GArray *params, void *user_ctx);
+void handle_read_memory(GArray *params, void *user_ctx);
+void handle_write_memory(GArray *params, void *user_ctx);
+int mcd_read_register(CPUState *cpu, GByteArray *buf, int reg);
+int mcd_read_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len);
// arm specific functions
int mcd_arm_store_mem_spaces(CPUState *cpu, GArray* memspaces);
@@ -334,5 +342,6 @@ void mcd_disable_syscalls(void);
// helpers
int int_cmp(gconstpointer a, gconstpointer b);
+void mcd_memtohex(GString *buf, const uint8_t *mem, int len);
#endif /* MCDSTUB_INTERNALS_H */
@@ -13,6 +13,10 @@
#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'
// tcp protocol chars
#define TCP_ACKNOWLEDGED '+'
@@ -22,6 +26,8 @@
#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 ""
// tcp query arguments
#define QUERY_FIRST "f"
@@ -38,6 +44,7 @@
// 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"
@@ -544,6 +544,46 @@ 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]) { (char) TCP_CHAR_READ_REGISTER, '\0' };
+ strcpy(read_reg_cmd_desc.schema, (char[3]) { ARG_SCHEMA_CORENUM, ARG_SCHEMA_INT, '\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]) { (char) TCP_CHAR_WRITE_REGISTER, '\0' };
+ strcpy(write_reg_cmd_desc.schema, (char[3]) { ARG_SCHEMA_CORENUM, ARG_SCHEMA_INT, '\0' });
+ 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]) { (char) TCP_CHAR_READ_MEMORY, '\0' };
+ strcpy(read_mem_cmd_desc.schema, (char[3]) { ARG_SCHEMA_CORENUM, 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]) { (char) TCP_CHAR_WRITE_MEMORY, '\0' };
+ strcpy(write_mem_cmd_desc.schema, (char[3]) { ARG_SCHEMA_CORENUM, ARG_SCHEMA_INT, '\0' });
+ cmd_parser = &write_mem_cmd_desc;
+ }
+ break;
default:
// could not perform the command (because its unknown)
mcd_put_packet("");
@@ -597,6 +637,18 @@ void run_cmd_parser(const char *data, const MCDCmdParseEntry *cmd)
}
}
+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;
+}
+
int cmd_parse_params(const char *data, const char *schema, GArray *params) {
char data_buffer[64] = {0};
@@ -621,6 +673,10 @@ int cmd_parse_params(const char *data, const char *schema, GArray *params) {
this_param.data_int = atoi(data_buffer);
g_array_append_val(params, this_param);
break;
+ case ARG_SCHEMA_UINT32_T:
+ this_param.data_int = atoi(data_buffer);
+ g_array_append_val(params, this_param);
+ break;
case ARG_SCHEMA_QRYHANDLE:
this_param.query_handle = atoi(data_buffer);
g_array_append_val(params, this_param);
@@ -1716,3 +1772,76 @@ void handle_query_state(GArray *params, void *user_ctx) {
TCP_ARGUMENT_STOP_STRING, state_info.stop_str, TCP_ARGUMENT_INFO_STRING, state_info.info_str);
mcd_put_strbuf();
}
+
+int mcd_read_register(CPUState *cpu, GByteArray *buf, int reg) {
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+ gchar *arch = cc->gdb_arch_name(cpu);
+ if (strcmp(arch, "arm")==0) {
+ g_free(arch);
+ return arm_mcd_read_register(cpu, buf, reg);
+ }
+ else {
+ g_free(arch);
+ 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 handle_read_register(GArray *params, void *user_ctx) {
+ uint32_t cpu_id = get_param(params, 0)->cpu_id;
+ int reg_num = get_param(params, 1)->data_int;
+ 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);
+ //g_string_printf(mcdserver_state.str_buf, "%s=%d;%d.%s=%d.",
+ // TCP_ARGUMENT_DATA, *mcdserver_state.mem_buf->data, mcdserver_state.mem_buf->data[1], TCP_ARGUMENT_SIZE, reg_size);
+ mcd_put_strbuf();
+}
+
+void handle_write_register(GArray *params, void *user_ctx) {
+
+}
+
+int mcd_read_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len)
+{
+ CPUClass *cc;
+ //TODO: add physical mem cpu_physical_memory_read(addr, buf, len);
+ cc = CPU_GET_CLASS(cpu);
+ if (cc->memory_rw_debug) {
+ // TODO: check out the difference between those two calls
+ return cc->memory_rw_debug(cpu, addr, buf, len, false);
+ }
+
+ return cpu_memory_rw_debug(cpu, addr, buf, len, false);
+}
+
+void handle_read_memory(GArray *params, void *user_ctx) {
+ uint32_t cpu_id = get_param(params, 0)->cpu_id;
+ uint64_t mem_address = get_param(params, 1)->data_uint64_t;
+ int len = get_param(params, 2)->data_int;
+
+ CPUState *cpu = mcd_get_cpu(cpu_id);
+ if (mcd_read_memory(cpu, mem_address, mcdserver_state.mem_buf, len)!=0) {
+ mcd_put_packet(TCP_EXECUTION_ERROR);
+ }
+ else {
+ mcd_memtohex(mcdserver_state.str_buf, mcdserver_state.mem_buf->data, len);
+ mcd_put_strbuf();
+ }
+}
+
+void handle_write_memory(GArray *params, void *user_ctx) {
+
+}
new file mode 100644
@@ -0,0 +1,75 @@
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "exec/mcdstub.h"
+#include "sysemu/tcg.h"
+#include "internals.h"
+#include "cpregs.h"
+#include "mcdstub.h"
+
+static inline int mcd_get_reg32(GByteArray *buf, uint32_t val)
+{
+ //FIXME: move this to a separate file
+ // convert endianess if necessary
+ uint32_t to_long = tswap32(val);
+ g_byte_array_append(buf, (uint8_t *) &to_long, 4);
+ return 4;
+}
+
+static inline int mcd_get_zeroes(GByteArray *array, size_t len)
+{
+ //FIXME: move this to a separate file
+ guint oldlen = array->len;
+ g_byte_array_set_size(array, oldlen + len);
+ memset(array->data + oldlen, 0, len);
+
+ return len;
+}
+
+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;
+}
+
+int arm_mcd_read_register(CPUState *cs, GByteArray *mem_buf, int n) {
+ //CPUClass *cc = CPU_GET_CLASS(cpu);
+ //CPUArchState *env = cpu->env_ptr;
+
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+
+ if (n < 16) {
+ /* Core integer register. */
+ return mcd_get_reg32(mem_buf, env->regs[n]);
+ }
+ if (n < 24) {
+ // TODO: these numbers don't match mine
+ return mcd_get_zeroes(mem_buf, 12);
+ }
+ switch (n) {
+ case 24:
+ // TODO: these numbers don't match mine
+ return mcd_get_reg32(mem_buf, 0);
+ case 25:
+ /* CPSR, or XPSR for M-profile */
+ if (arm_feature(env, ARM_FEATURE_M)) {
+ return mcd_get_reg32(mem_buf, xpsr_read(env));
+ } else {
+ return mcd_get_reg32(mem_buf, cpsr_read(env));
+ }
+ }
+ //TODO: add funcitons for regs with higher numbers (including cp_regs)
+ return 0;
+}
\ No newline at end of file
new file mode 100644
@@ -0,0 +1,7 @@
+#ifndef ARM_MCDSTUB_H
+#define ARM_MCDSTUB_H
+
+const char *arm_mcd_get_dynamic_xml(CPUState *cs, const char *xmlname);
+int arm_mcd_read_register(CPUState *cs, GByteArray *mem_buf, int n);
+
+#endif /* ARM_MCDSTUB_H */
--
2.34.1
From 6fc5138b201233e306f60e06c51bdc63d08492b3 Mon Sep 17 00:00:00 2001
From: Nicolas Eder <nicolas.eder@lauterbach.com>
Date: Mon, 3 Jul 2023 17:08:44 +0200
Subject: [PATCH 13/29] handler for reading memory added
Signed-off-by: Nicolas Eder <nicolas.eder@lauterbach.com>
---
mcdstub/internals.h | 9 ++-
mcdstub/mcd_shared_defines.h | 2 +-
mcdstub/mcdstub.c | 124 +++++++++++++++++++++++------------
3 files changed, 89 insertions(+), 46 deletions(-)
@@ -41,8 +41,9 @@ enum {
#define ARG_SCHEMA_QRYHANDLE 'q'
#define ARG_SCHEMA_STRING 's'
#define ARG_SCHEMA_INT 'd'
-#define ARG_SCHEMA_UINT32_T 'l'
+#define ARG_SCHEMA_UINT64_T 'l'
#define ARG_SCHEMA_CORENUM 'c'
+#define ARG_SCHEMA_HEXDATA 'h'
// resets
#define RESET_SYSTEM "full_system_reset"
@@ -51,7 +52,7 @@ enum {
// more
#define QUERY_TOTAL_NUMBER 12 //FIXME: set this to a usefull value in the end
-#define CMD_SCHEMA_LENGTH 3
+#define CMD_SCHEMA_LENGTH 5
#define MCD_SYSTEM_NAME "qemu-system"
// tcp query packet values templates
#define DEVICE_NAME_TEMPLATE(s) "qemu-" #s "-device"
@@ -106,7 +107,6 @@ typedef enum MCDThreadIdKind {
} MCDThreadIdKind;
typedef union MCDCmdVariant {
-
const char *data;
int data_int;
uint64_t data_uint64_t;
@@ -329,6 +329,7 @@ void handle_read_memory(GArray *params, void *user_ctx);
void handle_write_memory(GArray *params, void *user_ctx);
int mcd_read_register(CPUState *cpu, GByteArray *buf, int reg);
int mcd_read_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len);
+int mcd_write_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len);
// arm specific functions
int mcd_arm_store_mem_spaces(CPUState *cpu, GArray* memspaces);
@@ -343,5 +344,7 @@ void mcd_disable_syscalls(void);
// helpers
int int_cmp(gconstpointer a, gconstpointer b);
void mcd_memtohex(GString *buf, const uint8_t *mem, int len);
+void mcd_hextomem(GByteArray *mem, const char *buf, int len);
+uint64_t atouint64_t(const char* in);
#endif /* MCDSTUB_INTERNALS_H */
@@ -27,7 +27,7 @@
#define TCP_WAS_NOT_LAST '~'
#define TCP_HANDSHAKE_SUCCESS "shaking your hand"
#define TCP_EXECUTION_SUCCESS "success"
-#define TCP_EXECUTION_ERROR ""
+#define TCP_EXECUTION_ERROR "error"
// tcp query arguments
#define QUERY_FIRST "f"
@@ -465,7 +465,7 @@ int mcd_handle_packet(const char *line_buf)
static MCDCmdParseEntry open_server_cmd_desc = {
.handler = handle_open_server,
};
- open_server_cmd_desc.cmd = (char[2]) { (char) TCP_CHAR_OPEN_SERVER, '\0' };
+ open_server_cmd_desc.cmd = (char[2]) { TCP_CHAR_OPEN_SERVER, '\0' };
cmd_parser = &open_server_cmd_desc;
}
break;
@@ -475,7 +475,7 @@ int mcd_handle_packet(const char *line_buf)
static MCDCmdParseEntry go_cmd_desc = {
.handler = handle_vm_start,
};
- go_cmd_desc.cmd = (char[2]) { (char) TCP_CHAR_GO, '\0' };
+ go_cmd_desc.cmd = (char[2]) { TCP_CHAR_GO, '\0' };
cmd_parser = &go_cmd_desc;
}
break;
@@ -485,7 +485,7 @@ int mcd_handle_packet(const char *line_buf)
static MCDCmdParseEntry break_cmd_desc = {
.handler = handle_vm_stop,
};
- break_cmd_desc.cmd = (char[2]) { (char) TCP_CHAR_BREAK, '\0' };
+ break_cmd_desc.cmd = (char[2]) { TCP_CHAR_BREAK, '\0' };
cmd_parser = &break_cmd_desc;
}
break;
@@ -500,8 +500,8 @@ int mcd_handle_packet(const char *line_buf)
static MCDCmdParseEntry query_cmd_desc = {
.handler = handle_gen_query,
};
- query_cmd_desc.cmd = (char[2]) { (char) TCP_CHAR_QUERY, '\0' };
- strcpy(query_cmd_desc.schema, (char[2]) { (char) ARG_SCHEMA_STRING, '\0' });
+ 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;
@@ -510,8 +510,8 @@ int mcd_handle_packet(const char *line_buf)
static MCDCmdParseEntry open_core_cmd_desc = {
.handler = handle_open_core,
};
- open_core_cmd_desc.cmd = (char[2]) { (char) TCP_CHAR_OPEN_CORE, '\0' };
- strcpy(open_core_cmd_desc.schema, (char[2]) { (char) ARG_SCHEMA_CORENUM, '\0' });
+ 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;
@@ -520,7 +520,7 @@ int mcd_handle_packet(const char *line_buf)
static MCDCmdParseEntry close_server_cmd_desc = {
.handler = handle_close_server,
};
- close_server_cmd_desc.cmd = (char[2]) { (char) TCP_CHAR_CLOSE_SERVER, '\0' };
+ close_server_cmd_desc.cmd = (char[2]) { TCP_CHAR_CLOSE_SERVER, '\0' };
cmd_parser = &close_server_cmd_desc;
}
break;
@@ -529,8 +529,8 @@ int mcd_handle_packet(const char *line_buf)
static MCDCmdParseEntry close_core_cmd_desc = {
.handler = handle_close_core,
};
- close_core_cmd_desc.cmd = (char[2]) { (char) TCP_CHAR_CLOSE_CORE, '\0' };
- strcpy(close_core_cmd_desc.schema, (char[2]) { (char) ARG_SCHEMA_CORENUM, '\0' });
+ 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;
@@ -539,8 +539,8 @@ int mcd_handle_packet(const char *line_buf)
static MCDCmdParseEntry reset_cmd_desc = {
.handler = handle_reset,
};
- reset_cmd_desc.cmd = (char[2]) { (char) TCP_CHAR_RESET, '\0' };
- strcpy(reset_cmd_desc.schema, (char[2]) { (char) ARG_SCHEMA_INT, '\0' });
+ 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;
@@ -549,7 +549,7 @@ int mcd_handle_packet(const char *line_buf)
static MCDCmdParseEntry read_reg_cmd_desc = {
.handler = handle_read_register,
};
- read_reg_cmd_desc.cmd = (char[2]) { (char) TCP_CHAR_READ_REGISTER, '\0' };
+ 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_INT, '\0' });
cmd_parser = &read_reg_cmd_desc;
}
@@ -559,7 +559,7 @@ int mcd_handle_packet(const char *line_buf)
static MCDCmdParseEntry write_reg_cmd_desc = {
.handler = handle_write_register,
};
- write_reg_cmd_desc.cmd = (char[2]) { (char) TCP_CHAR_WRITE_REGISTER, '\0' };
+ write_reg_cmd_desc.cmd = (char[2]) { TCP_CHAR_WRITE_REGISTER, '\0' };
strcpy(write_reg_cmd_desc.schema, (char[3]) { ARG_SCHEMA_CORENUM, ARG_SCHEMA_INT, '\0' });
cmd_parser = &write_reg_cmd_desc;
}
@@ -569,8 +569,8 @@ int mcd_handle_packet(const char *line_buf)
static MCDCmdParseEntry read_mem_cmd_desc = {
.handler = handle_read_memory,
};
- read_mem_cmd_desc.cmd = (char[2]) { (char) TCP_CHAR_READ_MEMORY, '\0' };
- strcpy(read_mem_cmd_desc.schema, (char[3]) { ARG_SCHEMA_CORENUM, ARG_SCHEMA_INT, '\0' });
+ read_mem_cmd_desc.cmd = (char[2]) { TCP_CHAR_READ_MEMORY, '\0' };
+ strcpy(read_mem_cmd_desc.schema, (char[4]) { ARG_SCHEMA_CORENUM, ARG_SCHEMA_UINT64_T, ARG_SCHEMA_INT, '\0' });
cmd_parser = &read_mem_cmd_desc;
}
break;
@@ -579,8 +579,8 @@ int mcd_handle_packet(const char *line_buf)
static MCDCmdParseEntry write_mem_cmd_desc = {
.handler = handle_write_memory,
};
- write_mem_cmd_desc.cmd = (char[2]) { (char) TCP_CHAR_WRITE_MEMORY, '\0' };
- strcpy(write_mem_cmd_desc.schema, (char[3]) { ARG_SCHEMA_CORENUM, ARG_SCHEMA_INT, '\0' });
+ write_mem_cmd_desc.cmd = (char[2]) { TCP_CHAR_WRITE_MEMORY, '\0' };
+ strcpy(write_mem_cmd_desc.schema, (char[5]) { ARG_SCHEMA_CORENUM, ARG_SCHEMA_UINT64_T, ARG_SCHEMA_INT, ARG_SCHEMA_HEXDATA, '\0' });
cmd_parser = &write_mem_cmd_desc;
}
break;
@@ -652,29 +652,43 @@ uint64_t atouint64_t(const char* in) {
int cmd_parse_params(const char *data, const char *schema, GArray *params) {
char data_buffer[64] = {0};
- char *separator = strchr(data, ARGUMENT_SEPARATOR);
- int seperator_index = (int)(separator - data);
-
- if (separator) {
- // we got two arguments
- strncpy(data_buffer, data, seperator_index);
- }
- else {
- strncpy(data_buffer, data, strlen(data));
- }
+ const char *remaining_data = data;
+
for (int i = 0; i<strlen(schema); i++) {
+ // get correct part of string
+ char *separator = strchr(remaining_data, ARGUMENT_SEPARATOR);
+
+ if (separator) {
+ // we multiple arguments left
+ 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_param.data = data;
+ // a string has to be the last argument
+ this_param.data = remaining_data;
g_array_append_val(params, this_param);
break;
+ case ARG_SCHEMA_HEXDATA:
+ // a string has to be the last argument
+ g_string_printf(mcdserver_state.str_buf, "%s", data_buffer);
+ break;
case ARG_SCHEMA_INT:
this_param.data_int = atoi(data_buffer);
g_array_append_val(params, this_param);
break;
- case ARG_SCHEMA_UINT32_T:
- this_param.data_int = atoi(data_buffer);
+ 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:
@@ -688,11 +702,6 @@ int cmd_parse_params(const char *data, const char *schema, GArray *params) {
default:
return -1;
}
-
- if (separator) {
- // we got two arguments
- strncpy(data_buffer, &data[seperator_index+1], strlen(&data[seperator_index+1]));
- }
}
return 0;
}
@@ -1796,6 +1805,16 @@ void mcd_memtohex(GString *buf, const uint8_t *mem, int len) {
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;
int reg_num = get_param(params, 1)->data_int;
@@ -1805,8 +1824,6 @@ void handle_read_register(GArray *params, void *user_ctx) {
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);
- //g_string_printf(mcdserver_state.str_buf, "%s=%d;%d.%s=%d.",
- // TCP_ARGUMENT_DATA, *mcdserver_state.mem_buf->data, mcdserver_state.mem_buf->data[1], TCP_ARGUMENT_SIZE, reg_size);
mcd_put_strbuf();
}
@@ -1814,8 +1831,7 @@ void handle_write_register(GArray *params, void *user_ctx) {
}
-int mcd_read_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len)
-{
+int mcd_read_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len) {
CPUClass *cc;
//TODO: add physical mem cpu_physical_memory_read(addr, buf, len);
cc = CPU_GET_CLASS(cpu);
@@ -1827,21 +1843,45 @@ int mcd_read_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len)
return cpu_memory_rw_debug(cpu, addr, buf, len, false);
}
+int mcd_write_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len) {
+ CPUClass *cc;
+ //TODO: add physical mem cpu_physical_memory_read(addr, buf, len);
+ cc = CPU_GET_CLASS(cpu);
+ if (cc->memory_rw_debug) {
+ // TODO: check out the difference between those two calls
+ return cc->memory_rw_debug(cpu, addr, buf, len, true);
+ }
+
+ return cpu_memory_rw_debug(cpu, addr, buf, len, true);
+}
+
void handle_read_memory(GArray *params, void *user_ctx) {
uint32_t cpu_id = get_param(params, 0)->cpu_id;
uint64_t mem_address = get_param(params, 1)->data_uint64_t;
int len = get_param(params, 2)->data_int;
CPUState *cpu = mcd_get_cpu(cpu_id);
- if (mcd_read_memory(cpu, mem_address, mcdserver_state.mem_buf, len)!=0) {
+ g_byte_array_set_size(mcdserver_state.mem_buf, len);
+ if (mcd_read_memory(cpu, mem_address, mcdserver_state.mem_buf->data, mcdserver_state.mem_buf->len)!=0) {
mcd_put_packet(TCP_EXECUTION_ERROR);
}
else {
- mcd_memtohex(mcdserver_state.str_buf, mcdserver_state.mem_buf->data, len);
+ 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) {
+ uint32_t cpu_id = get_param(params, 0)->cpu_id;
+ uint64_t mem_address = get_param(params, 1)->data_uint64_t;
+ int len = get_param(params, 2)->data_int;
+ CPUState *cpu = mcd_get_cpu(cpu_id);
+ mcd_hextomem(mcdserver_state.mem_buf, mcdserver_state.str_buf->str, len);
+ if (mcd_write_memory(cpu, mem_address, mcdserver_state.mem_buf->data, len)!=0) {
+ mcd_put_packet(TCP_EXECUTION_ERROR);
+ }
+ else {
+ mcd_put_packet(TCP_EXECUTION_SUCCESS);
+ }
}
--
2.34.1
From 0212c248b318acd70df2b68ae89204622a33996b Mon Sep 17 00:00:00 2001
From: Nicolas Eder <nicolas.eder@lauterbach.com>
Date: Wed, 5 Jul 2023 18:25:56 +0200
Subject: [PATCH 14/29] handler for single step added
Signed-off-by: Nicolas Eder <nicolas.eder@lauterbach.com>
---
include/exec/mcdstub.h | 6 +-
include/mcdstub/syscalls.h | 4 +-
mcdstub/internals.h | 77 +++----
mcdstub/mcd_shared_defines.h | 3 +-
mcdstub/mcdstub.c | 428 ++++++++++++++---------------------
softmmu/cpus.c | 2 +-
target/arm/mcdstub.c | 66 +++++-
target/arm/mcdstub.h | 1 +
8 files changed, 269 insertions(+), 318 deletions(-)
@@ -3,10 +3,8 @@
#define DEFAULT_MCDSTUB_PORT "1235"
#define TYPE_CHARDEV_MCD "chardev-mcd"
-#define MX_INPUT_LENGTH 9
-#define MCD_TCP_DATALEN 80
-/* MCD breakpoint/watchpoint types */
+// breakpoint defines
#define MCD_BREAKPOINT_SW 0
#define MCD_BREAKPOINT_HW 1
#define MCD_WATCHPOINT_WRITE 2
@@ -16,8 +14,6 @@
/**
* mcd_tcp_server_start: start the tcp server to connect via mcd
* @device: connection spec for mcd
- *
- * This is a TCP port
*/
int mcdserver_start(const char *device);
@@ -1,5 +1,5 @@
-#ifndef _SYSCALLS_H_
-#define _SYSCALLS_H_
+#ifndef _MCD_SYSCALLS_H_
+#define _MCD_SYSCALLS_H_
typedef void (*gdb_syscall_complete_cb)(CPUState *cpu, uint64_t ret, int err);
@@ -1,8 +1,3 @@
-/*
- * this header includes a lookup table for the transmitted messages over the tcp connection to trace32,
- * as well as function declarations for all functios used inside the mcdstub
- */
-
#ifndef MCDSTUB_INTERNALS_H
#define MCDSTUB_INTERNALS_H
@@ -10,19 +5,33 @@
#include "chardev/char.h"
#include "hw/core/cpu.h"
// just used for the register xml files
-#include "exec/gdbstub.h" /* xml_builtin */
+#include "exec/gdbstub.h"
#define MAX_PACKET_LENGTH 1024
// trigger defines
-#define MCD_TRIG_TYPE_IP 0x00000001
-#define MCD_TRIG_TYPE_READ 0x00000002
-#define MCD_TRIG_TYPE_WRITE 0x00000004
-#define MCD_TRIG_TYPE_RW 0x00000008
#define MCD_TRIG_OPT_DATA_IS_CONDITION 0x00000008
#define MCD_TRIG_ACTION_DBG_DEBUG 0x00000001
+typedef uint32_t mcd_trig_type_et;
+// TODO: replace mcd defines with custom layer
+enum {
+ MCD_TRIG_TYPE_UNDEFINED = 0x00000000, /**< Undefined trigger type. */
+ MCD_TRIG_TYPE_IP = 0x00000001, /**< Trigger on a changing instruction pointer. */
+ MCD_TRIG_TYPE_READ = 0x00000002, /**< Trigger on a read data access to a specific address or address range. */
+ MCD_TRIG_TYPE_WRITE = 0x00000004, /**< Trigger on a write data access to a specific address or address range. */
+ MCD_TRIG_TYPE_RW = 0x00000008, /**< Trigger on a read or a write data access to a specific address or
+ address range. */
+ MCD_TRIG_TYPE_NOCYCLE = 0x00000010, /**< Trigger on core information other than an IP or data compare trigger. */
+ MCD_TRIG_TYPE_TRIG_BUS = 0x00000020, /**< Trigger on a trigger bus combination. */
+ MCD_TRIG_TYPE_COUNTER = 0x00000040, /**< Trigger on an elapsed trigger counter. */
+ MCD_TRIG_TYPE_CUSTOM = 0x00000080, /**< Custom trigger using standard format as defined by \ref mcd_trig_custom_st. */
+ MCD_TRIG_TYPE_CUSTOM_LO = 0x00010000, /**< Begin Range: User defined trigger types. */
+ MCD_TRIG_TYPE_CUSTOM_HI = 0x40000000, /**< End Range: User defined trigger types. */
+};
+
typedef uint32_t mcd_core_event_et;
+// TODO: replace mcd defines with custom layer
enum {
MCD_CORE_EVENT_NONE = 0x00000000, /**< No since the last poll. */
MCD_CORE_EVENT_MEMORY_CHANGE = 0x00000001, /**< Memory content has changed. */
@@ -50,10 +59,11 @@ enum {
#define RESET_GPR "gpr_reset"
#define RESET_MEMORY "memory_reset"
-// more
-#define QUERY_TOTAL_NUMBER 12 //FIXME: set this to a usefull value in the end
+// misc
+#define QUERY_TOTAL_NUMBER 12
#define CMD_SCHEMA_LENGTH 5
#define MCD_SYSTEM_NAME "qemu-system"
+
// tcp query packet values templates
#define DEVICE_NAME_TEMPLATE(s) "qemu-" #s "-device"
@@ -65,13 +75,14 @@ enum {
#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"
-// GDB stuff thats needed for GDB function, which we use
typedef struct GDBRegisterState {
+ // needed for the used gdb functions
int base_reg;
int num_regs;
gdb_get_reg_cb get_reg;
@@ -80,12 +91,7 @@ typedef struct GDBRegisterState {
struct GDBRegisterState *next;
} GDBRegisterState;
-/*
- * struct for an MCD Process, each process can establish one connection
- */
-
typedef struct MCDProcess {
- //this is a relict from the gdb process, we might be able to delete this
uint32_t pid;
bool attached;
@@ -99,35 +105,16 @@ typedef struct MCDCmdParseEntry {
char schema[CMD_SCHEMA_LENGTH];
} MCDCmdParseEntry;
-typedef enum MCDThreadIdKind {
- GDB_ONE_THREAD = 0,
- GDB_ALL_THREADS, /* One process, all threads */
- GDB_ALL_PROCESSES,
- GDB_READ_THREAD_ERR
-} MCDThreadIdKind;
-
typedef union MCDCmdVariant {
const char *data;
int data_int;
uint64_t data_uint64_t;
int query_handle;
int cpu_id;
- struct {
- MCDThreadIdKind kind;
- uint32_t pid;
- uint32_t tid;
- } thread_id;
-
} MCDCmdVariant;
#define get_param(p, i) (&g_array_index(p, MCDCmdVariant, i))
-
-/*
- * not sure for what this is used exactly
- */
-
-
enum RSState {
RS_INACTIVE,
RS_IDLE,
@@ -162,19 +149,14 @@ typedef struct MCDState {
int line_csum; /* checksum at the end of the packet */
GByteArray *last_packet;
int signal;
- //the next one is about stub compatibility and we should be able to assume this is true anyway
- //bool multiprocess;
+
MCDProcess *processes;
int process_num;
GString *str_buf;
GByteArray *mem_buf;
- // maybe we don't need those flags
int sstep_flags;
int supported_sstep_flags;
- // my stuff
- RunState vm_current_state;
- RunState vm_previous_state;
uint32_t query_cpu_id;
GList *all_memspaces;
GList *all_reggroups;
@@ -236,9 +218,6 @@ typedef struct mcd_reset_st {
uint8_t id;
} mcd_reset_st;
-// Inline utility function, convert from int to hex and back
-
-
static inline int fromhex(int v)
{
if (v >= '0' && v <= '9') {
@@ -283,7 +262,6 @@ int mcd_put_packet(const char *buf);
int mcd_put_packet_binary(const char *buf, int len, bool dump);
bool mcd_got_immediate_ack(void);
void mcd_put_buffer(const uint8_t *buf, int len);
-void mcd_set_stop_cpu(CPUState *cpu);
MCDProcess *mcd_get_cpu_process(CPUState *cpu);
uint32_t mcd_get_cpu_pid(CPUState *cpu);
MCDProcess *mcd_get_process(uint32_t pid);
@@ -297,6 +275,7 @@ void run_cmd_parser(const char *data, const MCDCmdParseEntry *cmd);
int process_string_cmd(void *user_ctx, const char *data, const MCDCmdParseEntry *cmds, int num_cmds);
int cmd_parse_params(const char *data, const char *schema, GArray *params);
void handle_vm_start(GArray *params, void *user_ctx);
+void handle_vm_step(GArray *params, void *user_ctx);
void handle_vm_stop(GArray *params, void *user_ctx);
void handle_gen_query(GArray *params, void *user_ctx);
int mcd_get_cpu_index(CPUState *cpu);
@@ -312,6 +291,7 @@ void handle_close_server(GArray *params, void *user_ctx);
void handle_close_core(GArray *params, void *user_ctx);
void handle_query_trigger(GArray *params, void *user_ctx);
void mcd_vm_start(void);
+int mcd_vm_sstep(CPUState *cpu);
void mcd_vm_stop(void);
void handle_query_reg_groups_f(GArray *params, void *user_ctx);
void handle_query_reg_groups_c(GArray *params, void *user_ctx);
@@ -328,6 +308,7 @@ void handle_write_register(GArray *params, void *user_ctx);
void handle_read_memory(GArray *params, void *user_ctx);
void handle_write_memory(GArray *params, void *user_ctx);
int mcd_read_register(CPUState *cpu, GByteArray *buf, int reg);
+int mcd_write_register(CPUState *cpu, GByteArray *buf, int reg);
int mcd_read_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len);
int mcd_write_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len);
@@ -337,7 +318,7 @@ int mcd_arm_parse_core_xml_file(CPUClass *cc, GArray* reggroups, GArray* registe
int mcd_arm_parse_general_xml_files(CPUState *cpu, GArray* reggroups, GArray* registers, int* current_group_id);
int mcd_arm_get_additional_register_info(GArray* reggroups, GArray* registers);
-/* sycall handling */
+// sycall handling
void mcd_syscall_reset(void);
void mcd_disable_syscalls(void);
@@ -6,7 +6,8 @@
// tcp data characters
#define TCP_CHAR_OPEN_SERVER 'I'
#define TCP_CHAR_OPEN_CORE 'i'
-#define TCP_CHAR_GO 'c'
+#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'
@@ -1,10 +1,9 @@
/*
- * This is the main mcdstub. It needs to be complemented by other mcd stubs for each target.
+ * This is the main mcdstub.
*/
#include "mcd_shared_defines.h"
-//from original gdbstub.c
#include "qemu/osdep.h"
#include "qemu/ctype.h"
#include "qemu/cutils.h"
@@ -14,15 +13,12 @@
#include "mcdstub/syscalls.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 "internals.h"
-//from original softmmu.c (minus what was already here)
#include "qapi/error.h"
#include "exec/tb-flush.h"
#include "sysemu/cpus.h"
@@ -31,7 +27,7 @@
#include "chardev/char-fe.h"
#include "monitor/monitor.h"
-//architecture specific stuff
+// architecture specific stubs
#include "target/arm/mcdstub.h"
// FIXME: delete the following line and check if it worked
@@ -39,7 +35,6 @@
typedef struct {
CharBackend chr;
- //Chardev *mon_chr;
} MCDSystemState;
MCDSystemState mcdserver_system_state;
@@ -60,8 +55,6 @@ void mcd_init_mcdserver_state(void)
* 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.
*/
- // TODO:
- // this is weird and we might not actually need it after all
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;
@@ -106,7 +99,7 @@ void init_query_cmds_table(MCDCmdParseEntry* mcd_query_cmds_table) {
.handler = handle_query_reset_c,
.cmd = QUERY_ARG_RESET QUERY_CONSEQUTIVE,
};
- strcpy(query_reset_c.schema, (char[2]) { (char) ARG_SCHEMA_QRYHANDLE, '\0' });
+ strcpy(query_reset_c.schema, (char[2]) { ARG_SCHEMA_QRYHANDLE, '\0' });
mcd_query_cmds_table[cmd_number] = query_reset_c;
cmd_number++;
@@ -121,7 +114,7 @@ void init_query_cmds_table(MCDCmdParseEntry* mcd_query_cmds_table) {
.handler = handle_query_mem_spaces_f,
.cmd = QUERY_ARG_MEMORY QUERY_FIRST,
};
- strcpy(query_mem_spaces_f.schema, (char[2]) { (char) ARG_SCHEMA_CORENUM, '\0' });
+ strcpy(query_mem_spaces_f.schema, (char[2]) { ARG_SCHEMA_CORENUM, '\0' });
mcd_query_cmds_table[cmd_number] = query_mem_spaces_f;
cmd_number++;
@@ -129,7 +122,7 @@ void init_query_cmds_table(MCDCmdParseEntry* mcd_query_cmds_table) {
.handler = handle_query_mem_spaces_c,
.cmd = QUERY_ARG_MEMORY QUERY_CONSEQUTIVE,
};
- strcpy(query_mem_spaces_c.schema, (char[2]) { (char) ARG_SCHEMA_QRYHANDLE, '\0' });
+ strcpy(query_mem_spaces_c.schema, (char[2]) { ARG_SCHEMA_QRYHANDLE, '\0' });
mcd_query_cmds_table[cmd_number] = query_mem_spaces_c;
cmd_number++;
@@ -137,7 +130,7 @@ void init_query_cmds_table(MCDCmdParseEntry* mcd_query_cmds_table) {
.handler = handle_query_reg_groups_f,
.cmd = QUERY_ARG_REGGROUP QUERY_FIRST,
};
- strcpy(query_reg_groups_f.schema, (char[2]) { (char) ARG_SCHEMA_CORENUM, '\0' });
+ strcpy(query_reg_groups_f.schema, (char[2]) { ARG_SCHEMA_CORENUM, '\0' });
mcd_query_cmds_table[cmd_number] = query_reg_groups_f;
cmd_number++;
@@ -145,7 +138,7 @@ void init_query_cmds_table(MCDCmdParseEntry* mcd_query_cmds_table) {
.handler = handle_query_reg_groups_c,
.cmd = QUERY_ARG_REGGROUP QUERY_CONSEQUTIVE,
};
- strcpy(query_reg_groups_c.schema, (char[2]) { (char) ARG_SCHEMA_QRYHANDLE, '\0' });
+ strcpy(query_reg_groups_c.schema, (char[2]) { ARG_SCHEMA_QRYHANDLE, '\0' });
mcd_query_cmds_table[cmd_number] = query_reg_groups_c;
cmd_number++;
@@ -153,7 +146,7 @@ void init_query_cmds_table(MCDCmdParseEntry* mcd_query_cmds_table) {
.handler = handle_query_regs_f,
.cmd = QUERY_ARG_REG QUERY_FIRST,
};
- strcpy(query_regs_f.schema, (char[2]) { (char) ARG_SCHEMA_CORENUM, '\0' });
+ strcpy(query_regs_f.schema, (char[2]) { ARG_SCHEMA_CORENUM, '\0' });
mcd_query_cmds_table[cmd_number] = query_regs_f;
cmd_number++;
@@ -161,7 +154,7 @@ void init_query_cmds_table(MCDCmdParseEntry* mcd_query_cmds_table) {
.handler = handle_query_regs_c,
.cmd = QUERY_ARG_REG QUERY_CONSEQUTIVE,
};
- strcpy(query_regs_c.schema, (char[2]) { (char) ARG_SCHEMA_QRYHANDLE, '\0' });
+ strcpy(query_regs_c.schema, (char[2]) { ARG_SCHEMA_QRYHANDLE, '\0' });
mcd_query_cmds_table[cmd_number] = query_regs_c;
cmd_number++;
@@ -169,7 +162,7 @@ void init_query_cmds_table(MCDCmdParseEntry* mcd_query_cmds_table) {
.handler = handle_query_state,
.cmd = QUERY_ARG_STATE,
};
- strcpy(query_state.schema, (char[2]) { (char) ARG_SCHEMA_CORENUM, '\0' });
+ strcpy(query_state.schema, (char[2]) { ARG_SCHEMA_CORENUM, '\0' });
mcd_query_cmds_table[cmd_number] = query_state;
}
@@ -258,12 +251,8 @@ int pid_order(const void *a, const void *b)
int mcdserver_start(const char *device)
{
- //might wann add tracing later (no idea for what this is used)
- //trace_gdbstub_op_start(device);
-
char mcdstub_device_name[128];
Chardev *chr = NULL;
- //Chardev *mon_chr;
if (!first_cpu) {
error_report("mcdstub: meaningless to attach to a "
@@ -271,7 +260,6 @@ int mcdserver_start(const char *device)
return -1;
}
- //
if (!mcd_supports_guest_debug()) {
error_report("mcdstub: current accelerator doesn't "
"support guest debugging");
@@ -282,7 +270,7 @@ int mcdserver_start(const char *device)
return -1;
}
- //if device == default -> set device = tcp::1235
+ // if device == default -> set device = tcp::1235
if (strcmp(device, "default") == 0) {
device = "tcp::1235";
}
@@ -303,7 +291,6 @@ int mcdserver_start(const char *device)
sigaction(SIGINT, &act, NULL);
}
#endif
-
chr = qemu_chr_new_noreplay("mcd", device, true, NULL);
if (!chr) {
return -1;
@@ -314,13 +301,8 @@ int mcdserver_start(const char *device)
mcd_init_mcdserver_state();
qemu_add_vm_change_state_handler(mcd_vm_state_change, NULL);
-
- /* Initialize a monitor terminal for mcd */
- //mon_chr = qemu_chardev_new(NULL, TYPE_CHARDEV_MCD, NULL, NULL, &error_abort);
- //monitor_init_hmp(mon_chr, false, &error_abort);
} else {
qemu_chr_fe_deinit(&mcdserver_system_state.chr, true);
- //mon_chr = mcdserver_system_state.mon_chr;
reset_mcdserver_state();
}
@@ -334,7 +316,6 @@ int mcdserver_start(const char *device)
NULL, &mcdserver_state, NULL, true);
}
mcdserver_state.state = chr ? RS_IDLE : RS_INACTIVE;
- //mcdserver_system_state.mon_chr = mon_chr;
mcd_syscall_reset();
return 0;
@@ -360,107 +341,80 @@ void mcd_read_byte(uint8_t ch)
uint8_t reply;
if (mcdserver_state.last_packet->len) {
- /* Waiting for a response to the last packet. If we see the start
- of a new command then abandon the previous response. */
if (ch == TCP_NOT_ACKNOWLEDGED) {
- //the previous packet was not akcnowledged
- //trace_gdbstub_err_got_nack();
- //we are resending the last packet
+ // 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
- //trace_gdbstub_io_got_ack();
+ // the previous packet was acknowledged
}
if (ch == TCP_ACKNOWLEDGED || ch == TCP_COMMAND_START) {
- //either acknowledged or a new communication starts -> we discard previous communication
+ // 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) {
- // we only continue if we are processing a new commant. otherwise we skip to ne next character in the packet which sould be a $
+ // skip to the next char
return;
}
}
- //if (runstate_is_running()) {
- /* when the CPU is running, we cannot do anything except stop
- it when receiving a char */
- //vm_stop(RUN_STATE_PAUSED);
- //}
- //else {
- 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;
- }
- else {
- //new communication has to start with a $
- //trace_gdbstub_err_garbage(ch);
- }
- break;
- case RS_GETLINE:
- if (ch == TCP_COMMAND_END) {
- /* end of command, start of checksum*/
- mcdserver_state.line_buf[mcdserver_state.line_buf_index++] = 0;
- //mcdserver_state.line_sum += ch;
- 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!
- //trace_gdbstub_err_overrun();
- mcdserver_state.state = RS_IDLE;
- }
- else {
- /* unescaped command character */
- //this means the character is part of the real content fo the packet and we copy it to the line_buf
- mcdserver_state.line_buf[mcdserver_state.line_buf_index++] = ch;
- mcdserver_state.line_sum += ch;
- }
- break;
- case RS_DATAEND:
- // we are now done with copying the data and in the suffix of the packet
- // TODO: maybe wanna implement a checksum or sth like the gdb protocol has
-
- if (ch == TCP_WAS_NOT_LAST) {
- // ~ indicates that there is an additional package coming
- //acknowledged -> send +
- reply = TCP_ACKNOWLEDGED;
- mcd_put_buffer(&reply, 1);
- mcdserver_state.state = mcd_handle_packet(mcdserver_state.line_buf);
- }
- else if (ch == TCP_WAS_LAST) {
- //acknowledged -> send +
- // | indicates that there is no additional package coming
- reply = TCP_ACKNOWLEDGED;
- mcd_put_buffer(&reply, 1);
- mcdserver_state.state = mcd_handle_packet(mcdserver_state.line_buf);
- }
- else {
- //trace_gdbstub_err_checksum_incorrect(mcdserver_state.line_sum, mcdserver_state.line_csum);
- //not acknowledged -> send -
- reply = TCP_NOT_ACKNOWLEDGED;
- mcd_put_buffer(&reply, 1);
- //waiting for package to get resent
- mcdserver_state.state = RS_IDLE;
- }
- break;
- default:
- abort();
+
+ 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 what the first character in the line_buf is!
+ // decides what function (handler) to call depending on the first character in the line_buf
const MCDCmdParseEntry *cmd_parser = NULL;
switch (line_buf[0]) {
case TCP_CHAR_OPEN_SERVER:
- // handshake and lookup initialization
{
static MCDCmdParseEntry open_server_cmd_desc = {
.handler = handle_open_server,
@@ -470,7 +424,6 @@ int mcd_handle_packet(const char *line_buf)
}
break;
case TCP_CHAR_GO:
- // go command
{
static MCDCmdParseEntry go_cmd_desc = {
.handler = handle_vm_start,
@@ -479,8 +432,17 @@ int mcd_handle_packet(const char *line_buf)
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[2]) { ARG_SCHEMA_CORENUM, '\0' });
+ cmd_parser = &step_cmd_desc;
+ }
+ break;
case TCP_CHAR_BREAK:
- // go command
{
static MCDCmdParseEntry break_cmd_desc = {
.handler = handle_vm_stop,
@@ -495,7 +457,6 @@ int mcd_handle_packet(const char *line_buf)
mcd_exit(0);
exit(0);
case TCP_CHAR_QUERY:
- //query inquiry
{
static MCDCmdParseEntry query_cmd_desc = {
.handler = handle_gen_query,
@@ -550,7 +511,7 @@ int mcd_handle_packet(const char *line_buf)
.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_INT, '\0' });
+ strcpy(read_reg_cmd_desc.schema, (char[3]) { ARG_SCHEMA_CORENUM, ARG_SCHEMA_UINT64_T, '\0' });
cmd_parser = &read_reg_cmd_desc;
}
break;
@@ -560,7 +521,7 @@ int mcd_handle_packet(const char *line_buf)
.handler = handle_write_register,
};
write_reg_cmd_desc.cmd = (char[2]) { TCP_CHAR_WRITE_REGISTER, '\0' };
- strcpy(write_reg_cmd_desc.schema, (char[3]) { ARG_SCHEMA_CORENUM, ARG_SCHEMA_INT, '\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;
@@ -585,13 +546,13 @@ int mcd_handle_packet(const char *line_buf)
}
break;
default:
- // could not perform the command (because its unknown)
+ // command not supported
mcd_put_packet("");
break;
}
if (cmd_parser) {
- // now parse commands and run the selected function (handler)
+ // parse commands and run the selected handler function
run_cmd_parser(line_buf, cmd_parser);
}
@@ -599,21 +560,29 @@ int mcd_handle_packet(const char *line_buf)
}
void handle_vm_start(GArray *params, void *user_ctx) {
- // todo add partial restart with arguments and so on
+ // TODO: add partial restart with arguments and so on
mcd_vm_start();
}
+void handle_vm_step(GArray *params, void *user_ctx) {
+ // TODO: add partial restart with arguments and so on
+ uint32_t cpu_id = get_param(params, 0)->cpu_id;
+
+ CPUState *cpu = mcd_get_cpu(cpu_id);
+ mcd_vm_sstep(cpu);
+}
+
+
void handle_vm_stop(GArray *params, void *user_ctx) {
- // todo add partial stop with arguments and so on
+ // TODO: add partial stop with arguments and so on
mcd_vm_stop();
}
-void handle_gen_query(GArray *params, void *user_ctx)
-{
+void handle_gen_query(GArray *params, void *user_ctx) {
if (!params->len) {
return;
}
- //now iterate over all possible query functions and execute the right one
+ // 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))) {
@@ -621,8 +590,7 @@ void handle_gen_query(GArray *params, void *user_ctx)
}
}
-void run_cmd_parser(const char *data, const MCDCmdParseEntry *cmd)
-{
+void run_cmd_parser(const char *data, const MCDCmdParseEntry *cmd) {
if (!data) {
return;
}
@@ -630,8 +598,6 @@ void run_cmd_parser(const char *data, const MCDCmdParseEntry *cmd)
g_string_set_size(mcdserver_state.str_buf, 0);
g_byte_array_set_size(mcdserver_state.mem_buf, 0);
- /* In case there was an error during the command parsing we must
- * send a NULL packet to indicate the command is not supported */
if (process_string_cmd(NULL, data, cmd, 1)) {
mcd_put_packet("");
}
@@ -655,11 +621,11 @@ int cmd_parse_params(const char *data, const char *schema, GArray *params) {
const char *remaining_data = data;
for (int i = 0; i<strlen(schema); i++) {
- // get correct part of string
+ // get correct part of data
char *separator = strchr(remaining_data, ARGUMENT_SEPARATOR);
if (separator) {
- // we multiple arguments left
+ // multiple arguments
int seperator_index = (int)(separator - remaining_data);
strncpy(data_buffer, remaining_data, seperator_index);
data_buffer[seperator_index] = 0;
@@ -675,12 +641,11 @@ int cmd_parse_params(const char *data, const char *schema, GArray *params) {
MCDCmdVariant this_param;
switch (schema[i]) {
case ARG_SCHEMA_STRING:
- // a string has to be the last argument
+ // this has to be the last argument
this_param.data = remaining_data;
g_array_append_val(params, this_param);
break;
case ARG_SCHEMA_HEXDATA:
- // a string has to be the last argument
g_string_printf(mcdserver_state.str_buf, "%s", data_buffer);
break;
case ARG_SCHEMA_INT:
@@ -706,8 +671,7 @@ int cmd_parse_params(const char *data, const char *schema, GArray *params) {
return 0;
}
-int process_string_cmd(void *user_ctx, const char *data, const MCDCmdParseEntry *cmds, int num_cmds)
-{
+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));
@@ -717,23 +681,21 @@ int process_string_cmd(void *user_ctx, const char *data, const MCDCmdParseEntry
for (i = 0; i < num_cmds; i++) {
const MCDCmdParseEntry *cmd = &cmds[i];
- //terminate if we don't have handler and cmd
g_assert(cmd->handler && cmd->cmd);
- // if data and command are different continue
+ // continue if data and command are different
if (strncmp(data, cmd->cmd, strlen(cmd->cmd))) {
continue;
}
- // if a schema is provided we need to extract parameters from the data string
if (strlen(cmd->schema)) {
- // this only gets the data from data beginning after the command name
+ // extract data for parameters
if (cmd_parse_params(&data[strlen(cmd->cmd)], cmd->schema, params)) {
return -1;
}
}
- // the correct handler function is called
+ // call handler
cmd->handler(params, user_ctx);
return 0;
}
@@ -741,25 +703,16 @@ int process_string_cmd(void *user_ctx, const char *data, const MCDCmdParseEntry
return -1;
}
-void mcd_exit(int code)
-{
- char buf[4];
-
+void mcd_exit(int code) {
+ // terminate qemu
if (!mcdserver_state.init) {
return;
}
- //trace_gdbstub_op_exiting((uint8_t)code);
-
- //need to check what is sent here and dapt it to my needs
- snprintf(buf, sizeof(buf), "W%02x", (uint8_t)code);
- mcd_put_packet(buf);
-
qemu_chr_fe_deinit(&mcdserver_system_state.chr, true);
}
-void mcd_chr_event(void *opaque, QEMUChrEvent event)
-{
+void mcd_chr_event(void *opaque, QEMUChrEvent event) {
int i;
MCDState *s = (MCDState *) opaque;
@@ -771,19 +724,13 @@ void mcd_chr_event(void *opaque, QEMUChrEvent event)
}
s->c_cpu = mcd_first_attached_cpu();
-
- //vm_stop(RUN_STATE_PAUSED);
- //TODO: this might not be necessary
- //replay_gdb_attached();
- //gdb_has_xml = false;
break;
default:
break;
}
}
-bool mcd_supports_guest_debug(void)
-{
+bool mcd_supports_guest_debug(void) {
const AccelOpsClass *ops = cpus_get_accel();
if (ops->supports_guest_debug) {
return ops->supports_guest_debug();
@@ -792,29 +739,23 @@ bool mcd_supports_guest_debug(void)
}
#ifndef _WIN32
-void mcd_sigterm_handler(int signal)
-{
+void mcd_sigterm_handler(int signal) {
if (runstate_is_running()) {
vm_stop(RUN_STATE_PAUSED);
}
}
#endif
-void mcd_vm_state_change(void *opaque, bool running, RunState state)
-{
+void mcd_vm_state_change(void *opaque, bool running, RunState state) {
CPUState *cpu = mcdserver_state.c_cpu;
- // update cpu state
- mcdserver_state.vm_previous_state = mcdserver_state.vm_current_state;
- mcdserver_state.vm_current_state = state;
-
if (mcdserver_state.state == RS_INACTIVE) {
return;
}
if (cpu == NULL) {
if (running) {
- // this is the case if qemu starts the vm before any mcd is connected
+ // 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;
@@ -857,8 +798,13 @@ void mcd_vm_state_change(void *opaque, bool running, RunState state)
stop_str = STATE_STR_BREAK_UNKNOWN;
}
cpu->watchpoint_hit = NULL;
- } else {
- // "hardware" breakpoint hit!
+ }
+ else if (cpu->singlestep_enabled){
+ // we land here when a single step is performed
+ cpu_single_step(cpu, 0);
+ stop_str = STATE_STEP_PERFORMED;
+ }
+ else {
trig_id = MCD_TRIG_TYPE_IP;
stop_str = STATE_STR_BREAK_HW;
tb_flush(cpu);
@@ -870,47 +816,40 @@ void mcd_vm_state_change(void *opaque, bool running, RunState state)
stop_str = "";
break;
case RUN_STATE_WATCHDOG:
+ printf("runstate watchdog hit\n");
info_str = STATE_STR_UNKNOWN(cpu->cpu_index);
mcd_state = CORE_STATE_UNKNOWN;
stop_str = "";
- printf("runstate watchdog hit\n");
break;
default:
info_str = STATE_STR_UNKNOWN(cpu->cpu_index);
mcd_state = CORE_STATE_UNKNOWN;
stop_str = "";
- // we don't care;
break;
}
+ // set state for c_cpu
mcdserver_state.cpu_state.state = mcd_state;
mcdserver_state.cpu_state.trig_id = trig_id;
mcdserver_state.cpu_state.stop_str = stop_str;
mcdserver_state.cpu_state.info_str = info_str;
-
- /* disable single step if it was enabled */
- cpu_single_step(cpu, 0);
}
-int mcd_put_packet(const char *buf)
-{
+int mcd_put_packet(const char *buf) {
return mcd_put_packet_binary(buf, strlen(buf), false);
}
-void mcd_put_strbuf(void)
-{
+void mcd_put_strbuf(void) {
mcd_put_packet(mcdserver_state.str_buf->str);
}
-int mcd_put_packet_binary(const char *buf, int len, bool dump)
-{
+int mcd_put_packet_binary(const char *buf, int len, bool dump) {
for(;;) {
- //super interesting if we want a chekcsum or something like that here!!
g_byte_array_set_size(mcdserver_state.last_packet, 0);
- g_byte_array_append(mcdserver_state.last_packet, (const uint8_t *) "$", 1);
+ 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 *) "#", 1);
- g_byte_array_append(mcdserver_state.last_packet, (const uint8_t *) "|", 1);
+ 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);
@@ -921,53 +860,28 @@ int mcd_put_packet_binary(const char *buf, int len, bool dump)
return 0;
}
-bool mcd_got_immediate_ack(void)
-{
+bool mcd_got_immediate_ack(void) {
return true;
}
-void mcd_put_buffer(const uint8_t *buf, int len)
-{
- /*
- * XXX this blocks entire thread. Rewrite to use
- * qemu_chr_fe_write and background I/O callbacks
- */
+void mcd_put_buffer(const uint8_t *buf, int len) {
qemu_chr_fe_write_all(&mcdserver_system_state.chr, buf, len);
}
-void mcd_set_stop_cpu(CPUState *cpu)
-{
- MCDProcess *p = mcd_get_cpu_process(cpu);
-
- if (!p->attached) {
- /*
- * Having a stop CPU corresponding to a process that is not attached
- * confuses GDB. So we ignore the request.
- */
- return;
- }
- //FIXME: we probably can delete this because in the opern_core function we set these two anyway
- mcdserver_state.c_cpu = cpu;
-}
-
-MCDProcess *mcd_get_cpu_process(CPUState *cpu)
-{
+MCDProcess *mcd_get_cpu_process(CPUState *cpu) {
return mcd_get_process(mcd_get_cpu_pid(cpu));
}
-uint32_t mcd_get_cpu_pid(CPUState *cpu)
-{
+uint32_t mcd_get_cpu_pid(CPUState *cpu) {
if (cpu->cluster_index == UNASSIGNED_CLUSTER_INDEX) {
- /* Return the default process' PID */
+ // Return the default process' PID
int index = mcdserver_state.process_num - 1;
return mcdserver_state.processes[index].pid;
}
- // TODO: maybe +1 because we start numbering at 1
return cpu->cluster_index + 1;
}
-MCDProcess *mcd_get_process(uint32_t pid)
-{
+MCDProcess *mcd_get_process(uint32_t pid) {
int i;
if (!pid) {
@@ -997,8 +911,7 @@ CPUState* mcd_get_cpu(uint32_t i_cpu_index) {
return cpu;
}
-CPUState *mcd_first_attached_cpu(void)
-{
+CPUState *mcd_first_attached_cpu(void) {
CPUState *cpu = first_cpu;
MCDProcess *process = mcd_get_cpu_process(cpu);
@@ -1009,8 +922,7 @@ CPUState *mcd_first_attached_cpu(void)
return cpu;
}
-CPUState *mcd_next_attached_cpu(CPUState *cpu)
-{
+CPUState *mcd_next_attached_cpu(CPUState *cpu) {
cpu = CPU_NEXT(cpu);
while (cpu) {
@@ -1024,14 +936,11 @@ CPUState *mcd_next_attached_cpu(CPUState *cpu)
return cpu;
}
-int mcd_get_cpu_index(CPUState *cpu)
-{
- // TODO: maybe plus 1 because we start numbering at 1
+int mcd_get_cpu_index(CPUState *cpu) {
return cpu->cpu_index + 1;
}
-CPUState *get_first_cpu_in_process(MCDProcess *process)
-{
+CPUState *get_first_cpu_in_process(MCDProcess *process) {
CPUState *cpu;
CPU_FOREACH(cpu) {
@@ -1043,8 +952,7 @@ CPUState *get_first_cpu_in_process(MCDProcess *process)
return NULL;
}
-CPUState *find_cpu(uint32_t thread_id)
-{
+CPUState *find_cpu(uint32_t thread_id) {
CPUState *cpu;
CPU_FOREACH(cpu) {
@@ -1080,7 +988,7 @@ void parse_reg_xml(const char *xml, int size, GArray* registers) {
c_ptr = &c;
if (still_to_skip>0) {
- // skip chars unwanted chars
+ // skip unwanted chars
still_to_skip --;
continue;
}
@@ -1172,9 +1080,7 @@ void parse_reg_xml(const char *xml, int size, GArray* registers) {
}
int int_cmp(gconstpointer a, gconstpointer b) {
- int a_int = *(int*)a;
- int b_int = *(int*)b;
- if (a_int == b_int) {
+ if (*(int*)a == *(int*)b) {
return 0;
}
else {
@@ -1285,7 +1191,7 @@ int init_trigger(mcd_trigger_st* trigger) {
}
void handle_open_server(GArray *params, void *user_ctx) {
- // initialize some core-independent data
+ // 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);
@@ -1301,8 +1207,6 @@ void handle_query_system(GArray *params, void *user_ctx) {
}
void handle_query_cores(GArray *params, void *user_ctx) {
- //TODO: add cluster support: in gdb each inferior (process) handles one cluster we might want to have sth similar here
-
// get first cpu
CPUState *cpu = mcd_first_attached_cpu();
if (!cpu) {
@@ -1316,10 +1220,9 @@ void handle_query_cores(GArray *params, void *user_ctx) {
gchar *arch = cc->gdb_arch_name(cpu);
int nr_cores = cpu->nr_cores;
-
char device_name[] = DEVICE_NAME_TEMPLATE(arch);
g_string_printf(mcdserver_state.str_buf, "%s=%s.%s=%s.%s=%d.",
- TCP_ARGUMENT_DEVICE, device_name, TCP_ARGUMENT_CORE, cpu_model, TCP_ARGUMENT_AMOUNT_CORE, nr_cores);
+ TCP_ARGUMENT_DEVICE, device_name, TCP_ARGUMENT_CORE, cpu_model, TCP_ARGUMENT_AMOUNT_CORE, nr_cores);
mcd_put_strbuf();
g_free(arch);
}
@@ -1441,7 +1344,6 @@ int mcd_arm_get_additional_register_info(GArray* reggroups, GArray* registers) {
}
void handle_open_core(GArray *params, void *user_ctx) {
- // get the cpu whith the given id
uint32_t cpu_id = get_param(params, 0)->cpu_id;
CPUState *cpu = mcd_get_cpu(cpu_id);
mcdserver_state.c_cpu = cpu;
@@ -1501,9 +1403,7 @@ void handle_open_core(GArray *params, void *user_ctx) {
}
void handle_query_reset_f(GArray *params, void *user_ctx) {
- // resetting has to be done over a monitor (look ar Rcmd) so we tell MCD that we can reset but this still need to be implemented
- // we only support one reset over this monitor and that would be a full "system_restart"
- // reset options are the same for every cpu!
+ // TODO: vull reset over the qemu monitor
// 1. check length
int nb_resets = mcdserver_state.resets->len;
@@ -1518,7 +1418,6 @@ void handle_query_reset_f(GArray *params, void *user_ctx) {
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=%d.", TCP_ARGUMENT_NAME, reset.name, TCP_ARGUMENT_ID, reset.id);
mcd_put_strbuf();
- // TODO: we still need to implement the gpr and memory reset here!
}
void handle_query_reset_c(GArray *params, void *user_ctx) {
@@ -1539,7 +1438,6 @@ void handle_query_reset_c(GArray *params, void *user_ctx) {
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=%d.", TCP_ARGUMENT_NAME, reset.name, TCP_ARGUMENT_ID, reset.id);
mcd_put_strbuf();
- // TODO: we still need to implement the gpr and memory reset here!
}
void handle_close_core(GArray *params, void *user_ctx) {
@@ -1575,7 +1473,7 @@ void handle_close_server(GArray *params, void *user_ctx) {
mcdserver_state.c_cpu = mcd_first_attached_cpu();
}
if (!mcdserver_state.c_cpu) {
- /* No more process attached */
+ // no more processes attached
mcd_disable_syscalls();
mcd_vm_start();
}
@@ -1595,10 +1493,15 @@ void mcd_vm_start(void) {
}
}
+int mcd_vm_sstep(CPUState *cpu) {
+ cpu_single_step(mcdserver_state.c_cpu, mcdserver_state.sstep_flags);
+ mcd_vm_start();
+ return 0;
+}
+
void mcd_vm_stop(void) {
if (runstate_is_running()) {
- //might want to have DEBUG state here but idk
- vm_stop(RUN_STATE_PAUSED);
+ vm_stop(RUN_STATE_DEBUG);
}
}
@@ -1724,7 +1627,7 @@ void handle_query_regs_f(GArray *params, void *user_ctx) {
}
void handle_query_regs_c(GArray *params, void *user_ctx) {
- // this funcitons send all reg groups except for the first
+ // this funcitons send all regs except for the first
// 1. get parameter and registers
int query_index = get_param(params, 0)->query_handle;
uint32_t cpu_id = mcdserver_state.query_cpu_id;
@@ -1750,16 +1653,12 @@ void handle_query_regs_c(GArray *params, void *user_ctx) {
}
void handle_reset(GArray *params, void *user_ctx) {
- int reset_id = get_param(params, 0)->data_int;
- //int bool_halt_after_reset = get_param(params, 1)->data_int;
- if (reset_id>=0) {
- //fun for the compiler
- }
+ //int reset_id = get_param(params, 0)->data_int;
+ // TODO: implement resets
}
void handle_query_state(GArray *params, void *user_ctx) {
- // send state from correct core
- //uint32_t cpu_id = get_param(params, 0)->cpu_id;
+ // TODO: multicore support
// get state info
mcd_cpu_state_st state_info = mcdserver_state.cpu_state;
mcd_core_event_et event = MCD_CORE_EVENT_NONE;
@@ -1795,6 +1694,19 @@ int mcd_read_register(CPUState *cpu, GByteArray *buf, int reg) {
}
}
+int mcd_write_register(CPUState *cpu, GByteArray *buf, int reg) {
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+ gchar *arch = cc->gdb_arch_name(cpu);
+ if (strcmp(arch, "arm")==0) {
+ g_free(arch);
+ return arm_mcd_write_register(cpu, buf, reg);
+ }
+ else {
+ g_free(arch);
+ return 0;
+ }
+}
+
void mcd_memtohex(GString *buf, const uint8_t *mem, int len) {
int i, c;
for(i = 0; i < len; i++) {
@@ -1817,18 +1729,28 @@ void mcd_hextomem(GByteArray *mem, const char *buf, int len) {
void handle_read_register(GArray *params, void *user_ctx) {
uint32_t cpu_id = get_param(params, 0)->cpu_id;
- int reg_num = get_param(params, 1)->data_int;
+ uint64_t reg_num = get_param(params, 1)->data_int;
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_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_int;
+ uint32_t reg_size = get_param(params, 2)->data_int;
+ 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, reg_num)==0) {
+ mcd_put_packet(TCP_EXECUTION_ERROR);
+ }
+ else {
+ mcd_put_packet(TCP_EXECUTION_SUCCESS);
+ }
}
int mcd_read_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len) {
@@ -1836,7 +1758,6 @@ int mcd_read_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len) {
//TODO: add physical mem cpu_physical_memory_read(addr, buf, len);
cc = CPU_GET_CLASS(cpu);
if (cc->memory_rw_debug) {
- // TODO: check out the difference between those two calls
return cc->memory_rw_debug(cpu, addr, buf, len, false);
}
@@ -1848,7 +1769,6 @@ int mcd_write_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len) {
//TODO: add physical mem cpu_physical_memory_read(addr, buf, len);
cc = CPU_GET_CLASS(cpu);
if (cc->memory_rw_debug) {
- // TODO: check out the difference between those two calls
return cc->memory_rw_debug(cpu, addr, buf, len, true);
}
@@ -306,7 +306,7 @@ void cpu_handle_guest_debug(CPUState *cpu)
cpu_single_step(cpu, 0);
}
} else {
- gdb_set_stop_cpu(cpu);
+ //gdb_set_stop_cpu(cpu);
qemu_system_debug_request();
cpu->stopped = true;
}
@@ -8,7 +8,7 @@
static inline int mcd_get_reg32(GByteArray *buf, uint32_t val)
{
- //FIXME: move this to a separate file
+ //TODO: move this to a separate file
// convert endianess if necessary
uint32_t to_long = tswap32(val);
g_byte_array_append(buf, (uint8_t *) &to_long, 4);
@@ -17,7 +17,7 @@ static inline int mcd_get_reg32(GByteArray *buf, uint32_t val)
static inline int mcd_get_zeroes(GByteArray *array, size_t len)
{
- //FIXME: move this to a separate file
+ //TODO: move this to a separate file
guint oldlen = array->len;
g_byte_array_set_size(array, oldlen + len);
memset(array->data + oldlen, 0, len);
@@ -44,9 +44,6 @@ const char *arm_mcd_get_dynamic_xml(CPUState *cs, const char *xmlname)
}
int arm_mcd_read_register(CPUState *cs, GByteArray *mem_buf, int n) {
- //CPUClass *cc = CPU_GET_CLASS(cpu);
- //CPUArchState *env = cpu->env_ptr;
-
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
@@ -70,6 +67,61 @@ int arm_mcd_read_register(CPUState *cs, GByteArray *mem_buf, int n) {
return mcd_get_reg32(mem_buf, cpsr_read(env));
}
}
- //TODO: add funcitons for regs with higher numbers (including cp_regs)
+ //TODO: add funcitons for the remaining regs (including cp_regs)
+ return 0;
+}
+
+int arm_mcd_write_register(CPUState *cs, GByteArray *mem_buf, int n) {
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+ uint32_t tmp;
+
+ tmp = ldl_p(mem_buf);
+ tmp = *((uint32_t*)mem_buf->data);
+
+ /*
+ * Mask out low bits of PC to workaround gdb bugs.
+ * This avoids an assert in thumb_tr_translate_insn, because it is
+ * architecturally impossible to misalign the pc.
+ * This will probably cause problems if we ever implement the
+ * Jazelle DBX extensions.
+ */
+ if (n == 15) {
+ tmp &= ~1;
+ }
+
+ if (n < 16) {
+ /* Core integer register. */
+ if (n == 13 && arm_feature(env, ARM_FEATURE_M)) {
+ /* M profile SP low bits are always 0 */
+ tmp &= ~3;
+ }
+ env->regs[n] = tmp;
+ return 4;
+ }
+ if (n < 24) { /* 16-23 */
+ /* FPA registers (ignored). */
+ return 4;
+ }
+ switch (n) {
+ case 24:
+ /* FPA status register (ignored). */
+ return 4;
+ case 25:
+ /* CPSR, or XPSR for M-profile */
+ if (arm_feature(env, ARM_FEATURE_M)) {
+ /*
+ * Don't allow writing to XPSR.Exception as it can cause
+ * a transition into or out of handler mode (it's not
+ * writable via the MSR insn so this is a reasonable
+ * restriction). Other fields are safe to update.
+ */
+ xpsr_write(env, tmp, ~XPSR_EXCP);
+ } else {
+ cpsr_write(env, tmp, 0xffffffff, CPSRWriteByGDBStub);
+ }
+ return 4;
+ }
+ //TODO: add funcitons for the remaining regs (including cp_regs)
return 0;
-}
\ No newline at end of file
+}
@@ -3,5 +3,6 @@
const char *arm_mcd_get_dynamic_xml(CPUState *cs, const char *xmlname);
int arm_mcd_read_register(CPUState *cs, GByteArray *mem_buf, int n);
+int arm_mcd_write_register(CPUState *cs, GByteArray *mem_buf, int n);
#endif /* ARM_MCDSTUB_H */
--
2.34.1
From a0a4aacb667ec3161642bd1831b7ba359a87357a Mon Sep 17 00:00:00 2001
From: Nicolas Eder <nicolas.eder@lauterbach.com>
Date: Fri, 7 Jul 2023 15:25:15 +0200
Subject: [PATCH 15/29] adapting to the qemu coding style
Signed-off-by: Nicolas Eder <nicolas.eder@lauterbach.com>
---
gdbstub/gdbstub.c | 2 +-
include/exec/mcdstub.h | 3 +-
include/mcdstub/syscalls.h | 2 +-
mcdstub/mcd_shared_defines.h | 17 +-
mcdstub/mcd_softmmu.c | 171 -----
mcdstub/mcd_syscalls.c | 7 +-
mcdstub/mcd_tcp_server.c | 95 ---
mcdstub/mcdstub.c | 1037 ++++++++++++++++------------
mcdstub/{internals.h => mcdstub.h} | 102 +--
mcdstub/meson.build | 16 +-
softmmu/cpus.c | 2 +-
softmmu/vl.c | 4 +-
target/arm/mcdstub.c | 24 +-
13 files changed, 684 insertions(+), 798 deletions(-)
delete mode 100644 mcdstub/mcd_softmmu.c
delete mode 100644 mcdstub/mcd_tcp_server.c
rename mcdstub/{internals.h => mcdstub.h} (69%)
@@ -857,7 +857,7 @@ static int process_string_cmd(const char *data,
if (cmd->schema) {
if (cmd_parse_params(&data[strlen(cmd->cmd)],
- cmd->schema, params)) {
+ cmd->schema, params)) {
return -1;
}
}
@@ -2,9 +2,8 @@
#define MCDSTUB_H
#define DEFAULT_MCDSTUB_PORT "1235"
-#define TYPE_CHARDEV_MCD "chardev-mcd"
-// breakpoint defines
+/* breakpoint defines */
#define MCD_BREAKPOINT_SW 0
#define MCD_BREAKPOINT_HW 1
#define MCD_WATCHPOINT_WRITE 2
@@ -3,4 +3,4 @@
typedef void (*gdb_syscall_complete_cb)(CPUState *cpu, uint64_t ret, int err);
-#endif /* _SYSCALLS_H_ */
\ No newline at end of file
+#endif /* _SYSCALLS_H_ */
@@ -1,9 +1,12 @@
-// this file is shared between the mcd dll and the mcd stub. it has to be kept exectly the same!
+/*
+ *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
-// tcp data characters
+/* tcp data characters */
#define TCP_CHAR_OPEN_SERVER 'I'
#define TCP_CHAR_OPEN_CORE 'i'
#define TCP_CHAR_GO 'C'
@@ -19,7 +22,7 @@
#define TCP_CHAR_READ_MEMORY 'm'
#define TCP_CHAR_WRITE_MEMORY 'M'
-// tcp protocol chars
+/* tcp protocol chars */
#define TCP_ACKNOWLEDGED '+'
#define TCP_NOT_ACKNOWLEDGED '-'
#define TCP_COMMAND_START '$'
@@ -30,7 +33,7 @@
#define TCP_EXECUTION_SUCCESS "success"
#define TCP_EXECUTION_ERROR "error"
-// tcp query arguments
+/* tcp query arguments */
#define QUERY_FIRST "f"
#define QUERY_CONSEQUTIVE "c"
@@ -43,7 +46,7 @@
#define QUERY_ARG_REG "reg"
#define QUERY_ARG_STATE "state"
-// tcp query packet argument list
+/* tcp query packet argument list */
#define TCP_ARGUMENT_NAME "name"
#define TCP_ARGUMENT_DATA "data"
#define TCP_ARGUMENT_ID "id"
@@ -70,10 +73,10 @@
#define TCP_ARGUMENT_OPTION "option"
#define TCP_ARGUMENT_ACTION "action"
-// for packets sent to qemu
+/* for packets sent to qemu */
#define ARGUMENT_SEPARATOR ';'
-// core states
+/* core states */
#define CORE_STATE_RUNNING "running"
#define CORE_STATE_HALTED "halted"
#define CORE_STATE_DEBUG "debug"
deleted file mode 100644
@@ -1,171 +0,0 @@
-/*
-#if defined(WIN32)
-#ifndef _WIN32_WINNT
-#define _WIN32_WINNT 0x0600
-#endif
-#include <winsock2.h>
-#include <ws2tcpip.h>
-//#pragma comment(lib, "Ws2_32.lib")
-#define ISVALIDSOCKET(s) ((s) != INVALID_SOCKET)
-#define CLOSESOCKET(s) closesocket(s)
-#define GETSOCKETERRNO() (WSAGetLastError())
-#else
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <unistd.h>
-//#include <errno.h>
-#define SOCKET int
-#define ISVALIDSOCKET(s) ((s) >= 0)
-#define CLOSESOCKET(s) close(s)
-#define GETSOCKETERRNO() (errno)
-#endif
-
-#define SA struct sockaddr
-
-
-
-#include "exec/mcdstub.h"
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu/error-report.h"
-#include "qemu/cutils.h"
-#include "gdbstub/syscalls.h"
-#include "exec/hwaddr.h"
-#include "exec/tb-flush.h"
-#include "sysemu/cpus.h"
-#include "sysemu/runstate.h"
-#include "sysemu/replay.h"
-#include "hw/core/cpu.h"
-#include "hw/cpu/cluster.h"
-#include "hw/boards.h"
-#include "chardev/char.h"
-#include "chardev/char-fe.h"
-#include "monitor/monitor.h"
-#include "internals.h"
-
-//here only deprecated code:
-
-int old_mcdserver_start(const char *device)
-{
- //the device is a char array. if its "default" we use tcp with the default DEFAULT_MCDSTUB_PORT. Otherwise it has to look like "tcp::<tcpport>"
- char tcp_port[MX_INPUT_LENGTH];
- int error;
- error = mcd_extract_tcp_port_num(device, tcp_port);
- if (error != 0) {
- return -1;
- }
- int tcp_port_num = atoi(tcp_port);
-
- if (!mcdserver_state.init) {
- mcd_init_mcdserver_state();
- }
- return mcd_open_tcp_socket(tcp_port_num);
-}
-
-int mcd_open_tcp_socket(int tcp_port)
-//soon to be deprecated (hopefully)
-{
- SOCKET socked_fd, connect_fd;
- struct sockaddr_in server_address, client_address;
-
-#if defined(WIN32)
- WSADATA d;
- if (WSAStartup(MAKEWORD(2, 2), &d)) {
- return -1;
- }
- int len;
-#else
- unsigned int len;
-#endif
-
- // socket create and verification
- socked_fd = socket(AF_INET, SOCK_STREAM, 0);
- if (!ISVALIDSOCKET(socked_fd)) {
- return -1;
- }
- memset(&server_address, 0, sizeof(server_address));
-
- // assign IP, PORT
- server_address.sin_family = AF_INET;
- server_address.sin_port = htons(tcp_port);
- server_address.sin_addr.s_addr = htonl(INADDR_ANY);
-
- // Binding newly created socket to given IP and verification
- if ((bind(socked_fd, (SA*)&server_address, sizeof(server_address))) != 0) {
- CLOSESOCKET(socked_fd);
- return -1;
- }
-
- // Now server is ready to listen and verification
- if ((listen(socked_fd, 5)) != 0) {
- CLOSESOCKET(socked_fd);
- return -1;
- }
- else {
- printf("TCP server listening on port %d\n", tcp_port);
- }
-
- //accepting connection
- len = sizeof(client_address);
- connect_fd = accept(socked_fd, (SA*)&client_address, &len);
- if (!ISVALIDSOCKET(connect_fd)) {
- CLOSESOCKET(socked_fd);
- return -1;
- }
-
- //lets do the handshake
-
- char buff[MCD_TCP_DATALEN];
- char expected_buff[MCD_TCP_DATALEN];
-
- memset(buff, 0, sizeof(buff));
- memset(expected_buff, 0, sizeof(buff));
- strcpy((char*)expected_buff, "initializing handshake");
-
- // read the message from client
- recv(connect_fd, buff, MCD_TCP_DATALEN, 0);
-
- if (strcmp(buff, expected_buff)==0) {
- strcpy((char*)buff, "shaking your hand");
- send(connect_fd, buff, MCD_TCP_DATALEN, 0);
- printf("handshake complete\n");
- return 0;
- }
- else {
- CLOSESOCKET(socked_fd);
- CLOSESOCKET(connect_fd);
- return -1;
- }
-}
-
-int mcd_extract_tcp_port_num(const char *in_string, char *out_string)
-{
- int string_length = strlen(in_string);
- if (string_length>MX_INPUT_LENGTH+1) {
- return -1;
- }
-
- const char default_str[] = "default";
-
- if ((string_length==strlen(default_str)) && (strcmp(default_str, in_string)==0)) {
- strcpy((char*)out_string, DEFAULT_MCDSTUB_PORT);
- return 0;
- }
- else if (strcmp("tcp::", in_string)==0) {
- for (int index = 5; index < string_length; index++) {
- if (!isdigit(in_string[index])) {
- return -1;
- }
- }
- }
- else {
- return -1;
- }
- strcpy((char*)out_string, in_string+5);
- return 0;
-}
-
-*/
\ No newline at end of file
@@ -3,12 +3,11 @@
#include "semihosting/semihost.h"
#include "sysemu/runstate.h"
#include "mcdstub/syscalls.h"
-//#include "trace.h"
-#include "internals.h"
+#include "mcdstub.h"
typedef struct {
char syscall_buf[256];
- //TODO: this needs to be get fixed mcd_syscall_complete_cb
+ /* TODO: this needs to be get fixed mcd_syscall_complete_cb */
int current_syscall_cb;
} MCDSyscallState;
@@ -28,4 +27,4 @@ void mcd_syscall_reset(void)
void mcd_disable_syscalls(void)
{
mcd_syscall_mode = MCD_SYS_DISABLED;
-}
\ No newline at end of file
+}
deleted file mode 100644
@@ -1,95 +0,0 @@
-#include <stdio.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <unistd.h> // read(), write(), close()
-#include "exec/mcdstub.h"
-#define MAX 80
-#define SA struct sockaddr
-
-// Function designed for chat between client and server.
-void func(int connfd)
-{
- char buff[MAX];
- int n;
- // infinite loop for chat
- for (;;) {
- bzero(buff, MAX);
-
- // read the message from client and copy it in buffer
- read(connfd, buff, sizeof(buff));
- // print buffer which contains the client contents
- printf("From client: %s\t To client : ", buff);
- bzero(buff, MAX);
- n = 0;
- // copy server message in the buffer
- while ((buff[n++] = getchar()) != '\n')
- ;
-
- // and send that buffer to client
- write(connfd, buff, sizeof(buff));
-
- // if msg contains "Exit" then server exit and chat ended.
- if (strncmp("exit", buff, 4) == 0) {
- printf("Server Exit...\n");
- break;
- }
- }
-}
-
-// Driver function
-int main()
-{
- int sockfd, connfd, len;
- struct sockaddr_in servaddr, cli;
-
- // socket create and verification
- sockfd = socket(AF_INET, SOCK_STREAM, 0);
- if (sockfd == -1) {
- printf("socket creation failed...\n");
- exit(0);
- }
- else
- printf("Socket successfully created..\n");
- bzero(&servaddr, sizeof(servaddr));
-
- // assign IP, PORT
- servaddr.sin_family = AF_INET;
- servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
- servaddr.sin_port = htons(DEFAULT_MCDSTUB_PORT);
-
- // Binding newly created socket to given IP and verification
- if ((bind(sockfd, (SA*)&servaddr, sizeof(servaddr))) != 0) {
- printf("socket bind failed...\n");
- exit(0);
- }
- else
- printf("Socket successfully binded..\n");
-
- // Now server is ready to listen and verification
- if ((listen(sockfd, 5)) != 0) {
- printf("Listen failed...\n");
- exit(0);
- }
- else
- printf("Server listening..\n");
- len = sizeof(cli);
-
- // Accept the data packet from client and verification
- connfd = accept(sockfd, (SA*)&cli, &len);
- if (connfd < 0) {
- printf("server accept failed...\n");
- exit(0);
- }
- else
- printf("server accept the client...\n");
-
- // Function for chatting between client and server
- func(connfd);
-
- // After chatting close the socket
- close(sockfd);
-}
@@ -2,8 +2,6 @@
* This is the main mcdstub.
*/
-#include "mcd_shared_defines.h"
-
#include "qemu/osdep.h"
#include "qemu/ctype.h"
#include "qemu/cutils.h"
@@ -17,7 +15,6 @@
#include "sysemu/runstate.h"
#include "exec/replay-core.h"
#include "exec/hwaddr.h"
-#include "internals.h"
#include "qapi/error.h"
#include "exec/tb-flush.h"
@@ -27,11 +24,12 @@
#include "chardev/char-fe.h"
#include "monitor/monitor.h"
-// architecture specific stubs
-#include "target/arm/mcdstub.h"
+/* mcdstub header files */
+#include "mcd_shared_defines.h"
+#include "mcdstub.h"
-// FIXME: delete the following line and check if it worked
-#include "hw/core/sysemu-cpu-ops.h"
+/* architecture specific stubs */
+#include "target/arm/mcdstub.h"
typedef struct {
CharBackend chr;
@@ -43,7 +41,7 @@ MCDState mcdserver_state;
void mcd_init_mcdserver_state(void)
{
- g_assert(!mcdserver_state.init);
+ g_assert(!mcdserver_state.init);
memset(&mcdserver_state, 0, sizeof(MCDState));
mcdserver_state.init = true;
mcdserver_state.str_buf = g_string_new(NULL);
@@ -55,14 +53,15 @@ void mcd_init_mcdserver_state(void)
* 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.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 table */
init_query_cmds_table(mcdserver_state.mcd_query_cmds_table);
- // at this time the cpu hans't been started! -> set cpu_state
+ /* 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,
@@ -70,8 +69,9 @@ void mcd_init_mcdserver_state(void)
mcdserver_state.cpu_state = cpu_state;
}
-void init_query_cmds_table(MCDCmdParseEntry* mcd_query_cmds_table) {
- // initalizes a list of all query commands
+void init_query_cmds_table(MCDCmdParseEntry *mcd_query_cmds_table)
+{
+ /* initalizes a list of all query commands */
int cmd_number = 0;
MCDCmdParseEntry query_system = {
@@ -270,7 +270,7 @@ int mcdserver_start(const char *device)
return -1;
}
- // if device == default -> set device = tcp::1235
+ /* if device == default -> set device = tcp::1235 */
if (strcmp(device, "default") == 0) {
device = "tcp::1235";
}
@@ -329,10 +329,12 @@ int mcd_chr_can_receive(void *opaque)
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;
+ if (buf[i] == 0) {
+ break;
+ }
}
}
@@ -342,27 +344,30 @@ void mcd_read_byte(uint8_t ch)
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
+ /* 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
+ /*
+ * 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
+ /* skip to the next char */
return;
}
}
- switch(mcdserver_state.state) {
+ switch (mcdserver_state.state) {
case RS_IDLE:
if (ch == TCP_COMMAND_START) {
- // start of command packet
+ /* start of command packet */
mcdserver_state.line_buf_index = 0;
mcdserver_state.line_sum = 0;
mcdserver_state.state = RS_GETLINE;
@@ -370,16 +375,15 @@ void mcd_read_byte(uint8_t ch)
break;
case RS_GETLINE:
if (ch == TCP_COMMAND_END) {
- // end of command
+ /* 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!
+ } 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
+ } else {
+ /* copy the content to the line_buf */
mcdserver_state.line_buf[mcdserver_state.line_buf_index++] = ch;
mcdserver_state.line_sum += ch;
}
@@ -389,17 +393,15 @@ void mcd_read_byte(uint8_t ch)
reply = TCP_ACKNOWLEDGED;
mcd_put_buffer(&reply, 1);
mcdserver_state.state = mcd_handle_packet(mcdserver_state.line_buf);
- }
- else if (ch == TCP_WAS_LAST) {
+ } 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!
+ } else {
+ /* not acknowledged! */
reply = TCP_NOT_ACKNOWLEDGED;
mcd_put_buffer(&reply, 1);
- // waiting for package to get resent
+ /* waiting for package to get resent */
mcdserver_state.state = RS_IDLE;
}
break;
@@ -410,7 +412,10 @@ void mcd_read_byte(uint8_t ch)
int mcd_handle_packet(const char *line_buf)
{
- // decides what function (handler) to call depending on the first character in the 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]) {
@@ -438,7 +443,8 @@ int mcd_handle_packet(const char *line_buf)
.handler = handle_vm_step,
};
step_cmd_desc.cmd = (char[2]) { TCP_CHAR_STEP, '\0' };
- strcpy(step_cmd_desc.schema, (char[2]) { ARG_SCHEMA_CORENUM, '\0' });
+ strcpy(step_cmd_desc.schema,
+ (char[2]) { ARG_SCHEMA_CORENUM, '\0' });
cmd_parser = &step_cmd_desc;
}
break;
@@ -452,7 +458,7 @@ int mcd_handle_packet(const char *line_buf)
}
break;
case TCP_CHAR_KILLQEMU:
- // kill qemu completely
+ /* kill qemu completely */
error_report("QEMU: Terminated via MCDstub");
mcd_exit(0);
exit(0);
@@ -462,7 +468,8 @@ int mcd_handle_packet(const char *line_buf)
.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' });
+ strcpy(query_cmd_desc.schema,
+ (char[2]) { ARG_SCHEMA_STRING, '\0' });
cmd_parser = &query_cmd_desc;
}
break;
@@ -472,7 +479,8 @@ int mcd_handle_packet(const char *line_buf)
.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' });
+ strcpy(open_core_cmd_desc.schema,
+ (char[2]) { ARG_SCHEMA_CORENUM, '\0' });
cmd_parser = &open_core_cmd_desc;
}
break;
@@ -481,7 +489,8 @@ int mcd_handle_packet(const char *line_buf)
static MCDCmdParseEntry close_server_cmd_desc = {
.handler = handle_close_server,
};
- close_server_cmd_desc.cmd = (char[2]) { TCP_CHAR_CLOSE_SERVER, '\0' };
+ close_server_cmd_desc.cmd =
+ (char[2]) { TCP_CHAR_CLOSE_SERVER, '\0' };
cmd_parser = &close_server_cmd_desc;
}
break;
@@ -491,7 +500,8 @@ int mcd_handle_packet(const char *line_buf)
.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' });
+ strcpy(close_core_cmd_desc.schema,
+ (char[2]) { ARG_SCHEMA_CORENUM, '\0' });
cmd_parser = &close_core_cmd_desc;
}
break;
@@ -511,7 +521,8 @@ int mcd_handle_packet(const char *line_buf)
.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' });
+ strcpy(read_reg_cmd_desc.schema,
+ (char[3]) { ARG_SCHEMA_CORENUM, ARG_SCHEMA_UINT64_T, '\0' });
cmd_parser = &read_reg_cmd_desc;
}
break;
@@ -520,8 +531,11 @@ int mcd_handle_packet(const char *line_buf)
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' });
+ 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;
@@ -531,7 +545,9 @@ int mcd_handle_packet(const char *line_buf)
.handler = handle_read_memory,
};
read_mem_cmd_desc.cmd = (char[2]) { TCP_CHAR_READ_MEMORY, '\0' };
- strcpy(read_mem_cmd_desc.schema, (char[4]) { ARG_SCHEMA_CORENUM, ARG_SCHEMA_UINT64_T, ARG_SCHEMA_INT, '\0' });
+ strcpy(read_mem_cmd_desc.schema,
+ (char[4]) { ARG_SCHEMA_CORENUM, ARG_SCHEMA_UINT64_T,
+ ARG_SCHEMA_INT, '\0' });
cmd_parser = &read_mem_cmd_desc;
}
break;
@@ -541,48 +557,57 @@ int mcd_handle_packet(const char *line_buf)
.handler = handle_write_memory,
};
write_mem_cmd_desc.cmd = (char[2]) { TCP_CHAR_WRITE_MEMORY, '\0' };
- strcpy(write_mem_cmd_desc.schema, (char[5]) { ARG_SCHEMA_CORENUM, ARG_SCHEMA_UINT64_T, ARG_SCHEMA_INT, ARG_SCHEMA_HEXDATA, '\0' });
+ strcpy(write_mem_cmd_desc.schema,
+ (char[5]) { ARG_SCHEMA_CORENUM, ARG_SCHEMA_UINT64_T,
+ ARG_SCHEMA_INT, ARG_SCHEMA_HEXDATA, '\0' });
cmd_parser = &write_mem_cmd_desc;
}
break;
default:
- // command not supported
+ /* command not supported */
mcd_put_packet("");
break;
}
if (cmd_parser) {
- // parse commands and run the selected handler function
+ /* parse commands and run the selected handler function */
run_cmd_parser(line_buf, cmd_parser);
}
return RS_IDLE;
}
-void handle_vm_start(GArray *params, void *user_ctx) {
- // TODO: add partial restart with arguments and so on
+void handle_vm_start(GArray *params, void *user_ctx)
+{
+ /* TODO: add partial restart with arguments and so on */
mcd_vm_start();
}
-void handle_vm_step(GArray *params, void *user_ctx) {
- // TODO: add partial restart with arguments and so on
+void handle_vm_step(GArray *params, void *user_ctx)
+{
+ /* TODO: add partial restart with arguments and so on */
uint32_t cpu_id = get_param(params, 0)->cpu_id;
CPUState *cpu = mcd_get_cpu(cpu_id);
- mcd_vm_sstep(cpu);
+ int return_value = mcd_vm_sstep(cpu);
+ if (return_value != 0) {
+ g_assert_not_reached();
+ }
}
-void handle_vm_stop(GArray *params, void *user_ctx) {
- // TODO: add partial stop with arguments and so on
+void handle_vm_stop(GArray *params, void *user_ctx)
+{
+ /* TODO: add partial stop with arguments and so on */
mcd_vm_stop();
}
-void handle_gen_query(GArray *params, void *user_ctx) {
+void handle_gen_query(GArray *params, void *user_ctx)
+{
if (!params->len) {
return;
}
- // iterate over all possible query functions and execute the right one
+ /* 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))) {
@@ -590,7 +615,8 @@ void handle_gen_query(GArray *params, void *user_ctx) {
}
}
-void run_cmd_parser(const char *data, const MCDCmdParseEntry *cmd) {
+void run_cmd_parser(const char *data, const MCDCmdParseEntry *cmd)
+{
if (!data) {
return;
}
@@ -603,10 +629,10 @@ void run_cmd_parser(const char *data, const MCDCmdParseEntry *cmd) {
}
}
-uint64_t atouint64_t(const char* in) {
+uint64_t atouint64_t(const char *in)
+{
uint64_t res = 0;
- for (int i = 0; i < strlen(in); ++i)
- {
+ for (int i = 0; i < strlen(in); ++i) {
const char c = in[i];
res *= 10;
res += c - '0';
@@ -615,33 +641,33 @@ uint64_t atouint64_t(const char* in) {
return res;
}
-int cmd_parse_params(const char *data, const char *schema, GArray *params) {
-
+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
+
+ for (int i = 0; i < strlen(schema); i++) {
+ /* get correct part of data */
char *separator = strchr(remaining_data, ARGUMENT_SEPARATOR);
if (separator) {
- // multiple arguments
+ /* 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 {
+ /* 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;
+
+ /* store right data */
+ MCDCmdVariant this_param;
switch (schema[i]) {
case ARG_SCHEMA_STRING:
- // this has to be the last argument
+ /* this has to be the last argument */
this_param.data = remaining_data;
g_array_append_val(params, this_param);
break;
@@ -671,7 +697,9 @@ int cmd_parse_params(const char *data, const char *schema, GArray *params) {
return 0;
}
-int process_string_cmd(void *user_ctx, const char *data, const MCDCmdParseEntry *cmds, int num_cmds) {
+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));
@@ -683,19 +711,20 @@ int process_string_cmd(void *user_ctx, const char *data, const MCDCmdParseEntry
const MCDCmdParseEntry *cmd = &cmds[i];
g_assert(cmd->handler && cmd->cmd);
- // continue if data and command are different
+ /* 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)) {
+ /* extract data for parameters */
+ if (cmd_parse_params(&data[strlen(cmd->cmd)], cmd->schema, params))
+ {
return -1;
}
}
- // call handler
+ /* call handler */
cmd->handler(params, user_ctx);
return 0;
}
@@ -703,8 +732,9 @@ int process_string_cmd(void *user_ctx, const char *data, const MCDCmdParseEntry
return -1;
}
-void mcd_exit(int code) {
- // terminate qemu
+void mcd_exit(int code)
+{
+ /* terminate qemu */
if (!mcdserver_state.init) {
return;
}
@@ -712,13 +742,14 @@ void mcd_exit(int code) {
qemu_chr_fe_deinit(&mcdserver_system_state.chr, true);
}
-void mcd_chr_event(void *opaque, QEMUChrEvent event) {
+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
+ /* Start with first process attached, others detached */
for (i = 0; i < s->process_num; i++) {
s->processes[i].attached = !i;
}
@@ -730,7 +761,8 @@ void mcd_chr_event(void *opaque, QEMUChrEvent event) {
}
}
-bool mcd_supports_guest_debug(void) {
+bool mcd_supports_guest_debug(void)
+{
const AccelOpsClass *ops = cpus_get_accel();
if (ops->supports_guest_debug) {
return ops->supports_guest_debug();
@@ -739,15 +771,17 @@ bool mcd_supports_guest_debug(void) {
}
#ifndef _WIN32
-void mcd_sigterm_handler(int signal) {
+void mcd_sigterm_handler(int signal)
+{
if (runstate_is_running()) {
vm_stop(RUN_STATE_PAUSED);
}
}
#endif
-void mcd_vm_state_change(void *opaque, bool running, RunState state) {
- CPUState *cpu = mcdserver_state.c_cpu;
+void mcd_vm_state_change(void *opaque, bool running, RunState state)
+{
+ CPUState *cpu = mcdserver_state.c_cpu;
if (mcdserver_state.state == RS_INACTIVE) {
return;
@@ -755,7 +789,10 @@ void mcd_vm_state_change(void *opaque, bool running, RunState state) {
if (cpu == NULL) {
if (running) {
- // this is the case if qemu starts the vm before a mcd client is connected
+ /*
+ * 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;
@@ -798,13 +835,11 @@ void mcd_vm_state_change(void *opaque, bool running, RunState state) {
stop_str = STATE_STR_BREAK_UNKNOWN;
}
cpu->watchpoint_hit = NULL;
- }
- else if (cpu->singlestep_enabled){
- // we land here when a single step is performed
+ } else if (cpu->singlestep_enabled) {
+ /* we land here when a single step is performed */
cpu_single_step(cpu, 0);
stop_str = STATE_STEP_PERFORMED;
- }
- else {
+ } else {
trig_id = MCD_TRIG_TYPE_IP;
stop_str = STATE_STR_BREAK_HW;
tb_flush(cpu);
@@ -816,7 +851,6 @@ void mcd_vm_state_change(void *opaque, bool running, RunState state) {
stop_str = "";
break;
case RUN_STATE_WATCHDOG:
- printf("runstate watchdog hit\n");
info_str = STATE_STR_UNKNOWN(cpu->cpu_index);
mcd_state = CORE_STATE_UNKNOWN;
stop_str = "";
@@ -828,30 +862,38 @@ void mcd_vm_state_change(void *opaque, bool running, RunState state) {
break;
}
- // set state for c_cpu
+ /* set state for c_cpu */
mcdserver_state.cpu_state.state = mcd_state;
mcdserver_state.cpu_state.trig_id = trig_id;
mcdserver_state.cpu_state.stop_str = stop_str;
mcdserver_state.cpu_state.info_str = info_str;
}
-int mcd_put_packet(const char *buf) {
+int mcd_put_packet(const char *buf)
+{
return mcd_put_packet_binary(buf, strlen(buf), false);
}
-void mcd_put_strbuf(void) {
+void mcd_put_strbuf(void)
+{
mcd_put_packet(mcdserver_state.str_buf->str);
}
-int mcd_put_packet_binary(const char *buf, int len, bool dump) {
- for(;;) {
+int mcd_put_packet_binary(const char *buf, int len, bool dump)
+{
+ for (;;) {
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);
+ 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);
if (mcd_got_immediate_ack()) {
break;
@@ -860,28 +902,33 @@ int mcd_put_packet_binary(const char *buf, int len, bool dump) {
return 0;
}
-bool mcd_got_immediate_ack(void) {
+bool mcd_got_immediate_ack(void)
+{
return true;
}
-void mcd_put_buffer(const uint8_t *buf, int len) {
+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) {
+MCDProcess *mcd_get_cpu_process(CPUState *cpu)
+{
return mcd_get_process(mcd_get_cpu_pid(cpu));
}
-uint32_t mcd_get_cpu_pid(CPUState *cpu) {
+uint32_t mcd_get_cpu_pid(CPUState *cpu)
+{
if (cpu->cluster_index == UNASSIGNED_CLUSTER_INDEX) {
- // Return the default process' PID
+ /* 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) {
+MCDProcess *mcd_get_process(uint32_t pid)
+{
int i;
if (!pid) {
@@ -898,7 +945,8 @@ MCDProcess *mcd_get_process(uint32_t pid) {
return NULL;
}
-CPUState* mcd_get_cpu(uint32_t i_cpu_index) {
+CPUState *mcd_get_cpu(uint32_t i_cpu_index)
+{
CPUState *cpu = first_cpu;
while (cpu) {
@@ -911,7 +959,8 @@ CPUState* mcd_get_cpu(uint32_t i_cpu_index) {
return cpu;
}
-CPUState *mcd_first_attached_cpu(void) {
+CPUState *mcd_first_attached_cpu(void)
+{
CPUState *cpu = first_cpu;
MCDProcess *process = mcd_get_cpu_process(cpu);
@@ -922,7 +971,8 @@ CPUState *mcd_first_attached_cpu(void) {
return cpu;
}
-CPUState *mcd_next_attached_cpu(CPUState *cpu) {
+CPUState *mcd_next_attached_cpu(CPUState *cpu)
+{
cpu = CPU_NEXT(cpu);
while (cpu) {
@@ -936,11 +986,13 @@ CPUState *mcd_next_attached_cpu(CPUState *cpu) {
return cpu;
}
-int mcd_get_cpu_index(CPUState *cpu) {
+int mcd_get_cpu_index(CPUState *cpu)
+{
return cpu->cpu_index + 1;
}
-CPUState *get_first_cpu_in_process(MCDProcess *process) {
+CPUState *get_first_cpu_in_process(MCDProcess *process)
+{
CPUState *cpu;
CPU_FOREACH(cpu) {
@@ -952,7 +1004,8 @@ CPUState *get_first_cpu_in_process(MCDProcess *process) {
return NULL;
}
-CPUState *find_cpu(uint32_t thread_id) {
+CPUState *find_cpu(uint32_t thread_id)
+{
CPUState *cpu;
CPU_FOREACH(cpu) {
@@ -965,8 +1018,9 @@ CPUState *find_cpu(uint32_t thread_id) {
}
-void parse_reg_xml(const char *xml, int size, GArray* registers) {
- // iterates over the complete xml file
+void parse_reg_xml(const char *xml, int size, GArray *registers)
+{
+ /* iterates over the complete xml file */
int i, j;
int still_to_skip = 0;
char argument[64] = {0};
@@ -987,108 +1041,103 @@ void parse_reg_xml(const char *xml, int size, GArray* registers) {
c = xml[i];
c_ptr = &c;
- if (still_to_skip>0) {
- // skip unwanted chars
- still_to_skip --;
+ if (still_to_skip > 0) {
+ /* skip unwanted chars */
+ still_to_skip--;
continue;
}
- if (strncmp(&xml[i], "<reg", 4)==0) {
- // start of a register
+ 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
+ } else if (is_reg) {
+ if (strncmp(&xml[i], "/>", 2) == 0) {
+ /* end of register info */
still_to_skip = 1;
is_reg = false;
- // create empty register
+ /* 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++) {
+ /* 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) {
+ if (strcmp(argument_j, "name") == 0) {
strcpy(my_register.name, value_j);
- }
- else if (strcmp(argument_j, "regnum")==0) {
+ } else if (strcmp(argument_j, "regnum") == 0) {
my_register.id = atoi(value_j);
- }
- else if (strcmp(argument_j, "bitsize")==0) {
+ } else if (strcmp(argument_j, "bitsize") == 0) {
my_register.bitsize = atoi(value_j);
- }
- else if (strcmp(argument_j, "type")==0) {
+ } else if (strcmp(argument_j, "type") == 0) {
strcpy(my_register.type, value_j);
- }
- else if (strcmp(argument_j, "group")==0) {
+ } else if (strcmp(argument_j, "group") == 0) {
strcpy(my_register.group, value_j);
}
}
- // store register
+ /* store register */
g_array_append_vals(registers, (gconstpointer)&my_register, 1);
- // free memory
+ /* free memory */
g_array_free(reg_data, false);
- }
- else {
- // store info for register
+ } 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;
+ 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) {
- if (*(int*)a == *(int*)b) {
+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 {
+ } else {
return 1;
}
}
-int mcd_arm_store_mem_spaces(CPUState *cpu, GArray* memspaces) {
+int mcd_arm_store_mem_spaces(CPUState *cpu, GArray *memspaces)
+{
int nr_address_spaces = cpu->num_ases;
mcd_mem_space_st space1 = {
@@ -1117,7 +1166,7 @@ int mcd_arm_store_mem_spaces(CPUState *cpu, GArray* memspaces) {
};
g_array_append_vals(memspaces, (gconstpointer)&space2, 1);
- if (nr_address_spaces==2) {
+ if (nr_address_spaces == 2) {
mcd_mem_space_st space3 = {
.name = "Secure",
.id = 3,
@@ -1143,7 +1192,7 @@ int mcd_arm_store_mem_spaces(CPUState *cpu, GArray* memspaces) {
};
g_array_append_vals(memspaces, (gconstpointer)&space4, 1);
}
- // TODO: get dynamically how the per (CP15) space is called
+ /* TODO: get dynamically how the per (CP15) space is called */
mcd_mem_space_st space5 = {
.name = "GPR Registers",
.id = 5,
@@ -1172,7 +1221,8 @@ int mcd_arm_store_mem_spaces(CPUState *cpu, GArray* memspaces) {
return 0;
}
-int init_resets(GArray* resets) {
+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};
@@ -1182,32 +1232,41 @@ int init_resets(GArray* resets) {
return 0;
}
-int init_trigger(mcd_trigger_st* trigger) {
- trigger->type = (MCD_TRIG_TYPE_IP | MCD_TRIG_TYPE_READ | MCD_TRIG_TYPE_WRITE | MCD_TRIG_TYPE_RW);
+int init_trigger(mcd_trigger_st *trigger)
+{
+ trigger->type = (MCD_TRIG_TYPE_IP | MCD_TRIG_TYPE_READ |
+ MCD_TRIG_TYPE_WRITE | MCD_TRIG_TYPE_RW);
trigger->option = (MCD_TRIG_OPT_DATA_IS_CONDITION);
trigger->action = (MCD_TRIG_ACTION_DBG_DEBUG);
trigger->nr_trigger = 4;
return 0;
}
-void handle_open_server(GArray *params, void *user_ctx) {
- // initialize core-independent data
+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) assert(0);
+ if (return_value != 0) {
+ g_assert_not_reached();
+ }
return_value = init_trigger(&mcdserver_state.trigger);
- if (return_value!=0) assert(0);
+ if (return_value != 0) {
+ g_assert_not_reached();
+ }
- mcd_put_packet(TCP_HANDSHAKE_SUCCESS);
+ mcd_put_packet(TCP_HANDSHAKE_SUCCESS);
}
-void handle_query_system(GArray *params, void *user_ctx) {
+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
+void handle_query_cores(GArray *params, void *user_ctx)
+{
+ /* get first cpu */
CPUState *cpu = mcd_first_attached_cpu();
if (!cpu) {
return;
@@ -1218,123 +1277,136 @@ void handle_query_cores(GArray *params, void *user_ctx) {
CPUClass *cc = CPU_GET_CLASS(cpu);
gchar *arch = cc->gdb_arch_name(cpu);
-
+
int nr_cores = cpu->nr_cores;
char device_name[] = DEVICE_NAME_TEMPLATE(arch);
g_string_printf(mcdserver_state.str_buf, "%s=%s.%s=%s.%s=%d.",
- TCP_ARGUMENT_DEVICE, device_name, TCP_ARGUMENT_CORE, cpu_model, TCP_ARGUMENT_AMOUNT_CORE, nr_cores);
+ TCP_ARGUMENT_DEVICE, device_name, TCP_ARGUMENT_CORE, cpu_model,
+ TCP_ARGUMENT_AMOUNT_CORE, nr_cores);
mcd_put_strbuf();
g_free(arch);
}
-int mcd_arm_parse_core_xml_file(CPUClass *cc, GArray* reggroups, GArray* registers, int* current_group_id) {
+int mcd_arm_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
+ /* 1. get correct file */
xml_filename = cc->gdb_core_xml_file;
for (i = 0; ; i++) {
current_xml_filename = xml_builtin[i][0];
- if (!current_xml_filename || (strncmp(current_xml_filename, xml_filename, strlen(xml_filename)) == 0
+ if (!current_xml_filename || (strncmp(current_xml_filename,
+ xml_filename, strlen(xml_filename)) == 0
&& strlen(current_xml_filename) == strlen(xml_filename)))
- break;
+ break;
}
- // without gpr registers we can do nothing
+ /* 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 };
+ /* 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
+ /* 3. parse xml */
xml_content = xml_builtin[i][1];
parse_reg_xml(xml_content, strlen(xml_content), registers);
return 0;
}
-int mcd_arm_parse_general_xml_files(CPUState *cpu, GArray* reggroups, GArray* registers, int* current_group_id) {
+int mcd_arm_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;
int i = 0;
- // iterate over all gdb xml files
+ /* iterate over all gdb xml files*/
GDBRegisterState *r;
for (r = cpu->gdb_regs; r; r = r->next) {
xml_filename = r->xml;
xml_content = NULL;
- // 1. get xml content
+ /* 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);
+ 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;
- }
- }
- else {
- // its not a coprocessor xml -> it is a static xml file
+ }
+ } else {
+ /* its not a coprocessor xml -> it is a static xml file */
for (i = 0; ; i++) {
current_xml_filename = xml_builtin[i][0];
- if (!current_xml_filename || (strncmp(current_xml_filename, xml_filename, strlen(xml_filename)) == 0
+ if (!current_xml_filename || (strncmp(current_xml_filename,
+ xml_filename, strlen(xml_filename)) == 0
&& strlen(current_xml_filename) == strlen(xml_filename)))
- break;
+ break;
}
if (current_xml_filename) {
xml_content = xml_builtin[i][1];
- }
- else {
- printf("no data found for %s\n", xml_filename);
+ } else {
continue;
}
}
- // 2. parse xml
+ /* 2. parse xml */
parse_reg_xml(xml_content, strlen(xml_content), registers);
}
return 0;
}
-int mcd_arm_get_additional_register_info(GArray* reggroups, GArray* registers) {
+int mcd_arm_get_additional_register_info(GArray *reggroups, GArray *registers)
+{
GList *register_numbers = NULL;
mcd_reg_st *current_register;
int i = 0;
int id_neg_offset = 0;
int effective_id = 0;
- // iterate over all registers
+ /* iterate over all registers */
for (i = 0; i < registers->len; i++) {
current_register = &(g_array_index(registers, mcd_reg_st, i));
- // 1. ad the id
+ /* 1. ad the id */
if (current_register->id) {
- // id is already in place
- // NOTE: qemu doesn't emulate the FPA regs (so we are missing the indices 16 to 24)
+ /*
+ *id is already in place
+ *NOTE: qemu doesn't emulate the FPA regs
+ *(so we are missing the indices 16 to 24)
+ */
int used_id = current_register->id;
register_numbers = g_list_append(register_numbers, &used_id);
- id_neg_offset ++;
- }
- else {
+ id_neg_offset++;
+ } else {
effective_id = i - id_neg_offset;
- if (g_list_find_custom(register_numbers, &effective_id, (GCompareFunc)int_cmp)!=NULL) {
- id_neg_offset --;
+ if (g_list_find_custom(register_numbers, &effective_id,
+ (GCompareFunc)int_cmp) != NULL) {
+ id_neg_offset--;
}
current_register->id = i - id_neg_offset;
}
- // 2. add mcd_reg_group_id and mcd_mem_space_id
- if (strcmp(current_register->group, "cp_regs")==0) {
- // coprocessor registers
+ /* 2. 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;
- // TODO: get info for opcode
- }
- else {
- // gpr register
+ /* TODO: get info for opcode */
+ } else {
+ /* gpr register */
current_register->mcd_reg_group_id = 1;
current_register->mcd_mem_space_id = 5;
}
@@ -1343,7 +1415,8 @@ int mcd_arm_get_additional_register_info(GArray* reggroups, GArray* registers) {
return 0;
}
-void handle_open_core(GArray *params, void *user_ctx) {
+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;
@@ -1351,315 +1424,373 @@ void handle_open_core(GArray *params, void *user_ctx) {
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, "arm")==0) {
- // TODO: make group and memspace ids dynamic
+ /* 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, "arm") == 0) {
+ /* TODO: make group and memspace ids dynamic */
int current_group_id = 1;
- // 1. store mem spaces
+ /* 1. store mem spaces */
return_value = mcd_arm_store_mem_spaces(cpu, memspaces);
- if (return_value!=0) assert(0);
- // 2. parse core xml
- return_value = mcd_arm_parse_core_xml_file(cc, reggroups, registers, ¤t_group_id);
- if (return_value!=0) assert(0);
- // 3. parse other xmls
- return_value = mcd_arm_parse_general_xml_files(cpu, reggroups, registers, ¤t_group_id);
- if (return_value!=0) assert(0);
- // 4. add additional data the the regs from the xmls
- return_value = mcd_arm_get_additional_register_info(reggroups, registers);
- if (return_value!=0) assert(0);
- // 5. store all found data
+ if (return_value != 0) {
+ g_assert_not_reached();
+ }
+ /* 2. parse core xml */
+ return_value = mcd_arm_parse_core_xml_file(cc, reggroups,
+ registers, ¤t_group_id);
+ if (return_value != 0) {
+ g_assert_not_reached();
+ }
+ /* 3. parse other xmls */
+ return_value = mcd_arm_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 = mcd_arm_get_additional_register_info(reggroups,
+ registers);
+ 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);
+ 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);
+ } 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);
+ 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);
+ } 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);
+ 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 {
- mcdserver_state.all_registers = g_list_insert(mcdserver_state.all_registers, registers, cpu_id);
- }
- }
- else {
- // we don't support other architectures
- assert(0);
+ } else {
+ /* we don't support other architectures */
+ g_assert_not_reached();
}
g_free(arch);
}
-void handle_query_reset_f(GArray *params, void *user_ctx) {
- // TODO: vull reset over the qemu monitor
-
- // 1. check length
+void handle_query_reset_f(GArray *params, void *user_ctx)
+{
+ /* TODO: vull reset over the qemu monitor */
+
+ /* 1. check length */
int nb_resets = mcdserver_state.resets->len;
if (nb_resets == 1) {
- // indicates this is the last packet
+ /* indicates this is the last packet */
g_string_printf(mcdserver_state.str_buf, "0!");
- }
- else {
+ } else {
g_string_printf(mcdserver_state.str_buf, "1!");
}
- // 2. send data
+ /* 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=%d.", TCP_ARGUMENT_NAME, reset.name, TCP_ARGUMENT_ID, reset.id);
+ g_string_append_printf(mcdserver_state.str_buf, "%s=%s.%s=%d.",
+ 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!
+void handle_query_reset_c(GArray *params, void *user_ctx)
+{
+ /* reset options are the same for every cpu! */
int query_index = get_param(params, 0)->query_handle;
-
- // 1. check weather this was the last mem space
+
+ /* 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
+ if (query_index + 1 == nb_groups) {
+ /* indicates this is the last packet */
g_string_printf(mcdserver_state.str_buf, "0!");
- }
- else {
- g_string_printf(mcdserver_state.str_buf, "%d!", query_index+1);
+ } else {
+ g_string_printf(mcdserver_state.str_buf, "%d!", 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=%d.", TCP_ARGUMENT_NAME, reset.name, TCP_ARGUMENT_ID, reset.id);
+ /* 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=%d.",
+ TCP_ARGUMENT_NAME, reset.name, TCP_ARGUMENT_ID, reset.id);
mcd_put_strbuf();
}
-void handle_close_core(GArray *params, void *user_ctx) {
- // free memory for correct core
+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);
+ 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);
+ 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);
+ 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) {
+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!
+ /*
+ * 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
+ /* 2. detach */
process->attached = false;
- // 3. reset process
+ /* 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
+ /* no more processes attached */
mcd_disable_syscalls();
mcd_vm_start();
}
}
-void handle_query_trigger(GArray *params, void *user_ctx) {
+void handle_query_trigger(GArray *params, void *user_ctx)
+{
mcd_trigger_st trigger = mcdserver_state.trigger;
g_string_printf(mcdserver_state.str_buf, "%s=%d.%s=%d.%s=%d.%s=%d.",
- TCP_ARGUMENT_AMOUNT_TRIGGER, trigger.nr_trigger, TCP_ARGUMENT_TYPE, trigger.type,
- TCP_ARGUMENT_OPTION, trigger.option, TCP_ARGUMENT_ACTION, trigger.action);
+ 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();
}
-void mcd_vm_start(void) {
+void mcd_vm_start(void)
+{
if (!runstate_needs_reset() && !runstate_is_running()) {
vm_start();
}
}
-int mcd_vm_sstep(CPUState *cpu) {
+int mcd_vm_sstep(CPUState *cpu)
+{
cpu_single_step(mcdserver_state.c_cpu, mcdserver_state.sstep_flags);
mcd_vm_start();
return 0;
}
-void mcd_vm_stop(void) {
+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
+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);
+ GArray *memspaces = g_list_nth_data(mcdserver_state.all_memspaces, cpu_id);
- // 2. check length
+ /* 2. check length */
int nb_groups = memspaces->len;
if (nb_groups == 1) {
- // indicates this is the last packet
+ /* indicates this is the last packet */
g_string_printf(mcdserver_state.str_buf, "0!");
- }
- else {
+ } else {
g_string_printf(mcdserver_state.str_buf, "1!");
}
- // 3. send data
+ /* 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=%d.%s=%d.%s=%d.%s=%d.%s=%d.%s=%ld.%s=%ld.%s=%d.",
- 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);
+ g_string_append_printf(mcdserver_state.str_buf,
+ "%s=%s.%s=%d.%s=%d.%s=%d.%s=%d.%s=%d.%s=%ld.%s=%ld.%s=%d.",
+ 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
+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
+ */
int 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);
+ GArray *memspaces = g_list_nth_data(mcdserver_state.all_memspaces, cpu_id);
- // 2. check weather this was the last mem space
+ /* 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
+ if (query_index + 1 == nb_groups) {
+ /* indicates this is the last packet */
g_string_printf(mcdserver_state.str_buf, "0!");
- }
- else {
- g_string_printf(mcdserver_state.str_buf, "%d!", 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=%d.%s=%d.%s=%d.%s=%d.%s=%d.%s=%ld.%s=%ld.%s=%d.",
- 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);
+ } else {
+ g_string_printf(mcdserver_state.str_buf, "%d!", 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=%d.%s=%d.%s=%d.%s=%d.%s=%d.%s=%ld.%s=%ld.%s=%d.",
+ 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
+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);
+ GArray *reggroups = g_list_nth_data(mcdserver_state.all_reggroups, cpu_id);
- // 2. check length
+ /* 2. check length */
int nb_groups = reggroups->len;
if (nb_groups == 1) {
- // indicates this is the last packet
+ /* indicates this is the last packet */
g_string_printf(mcdserver_state.str_buf, "0!");
- }
- else {
+ } else {
g_string_printf(mcdserver_state.str_buf, "1!");
}
- // 3. send data
+ /* 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=%d.%s=%s.", TCP_ARGUMENT_ID, group.id, TCP_ARGUMENT_NAME, group.name);
+ g_string_append_printf(mcdserver_state.str_buf, "%s=%d.%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
+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
+ */
int 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);
+ GArray *reggroups = g_list_nth_data(mcdserver_state.all_reggroups, cpu_id);
- // 2. check weather this was the last reg group
+ /* 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
+ if (query_index + 1 == nb_groups) {
+ /* indicates this is the last packet */
g_string_printf(mcdserver_state.str_buf, "0!");
- }
- else {
- g_string_printf(mcdserver_state.str_buf, "%d!", query_index+1);
+ } else {
+ g_string_printf(mcdserver_state.str_buf, "%d!", 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=%d.%s=%s.", TCP_ARGUMENT_ID, group.id, TCP_ARGUMENT_NAME, group.name);
+ /* 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=%d.%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
+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);
+ GArray *registers = g_list_nth_data(mcdserver_state.all_registers, cpu_id);
- // 2. check length
+ /* 2. check length */
int nb_regs = registers->len;
if (nb_regs == 1) {
- // indicates this is the last packet
+ /* indicates this is the last packet */
g_string_printf(mcdserver_state.str_buf, "0!");
- }
- else {
+ } else {
g_string_printf(mcdserver_state.str_buf, "1!");
}
- // 3. send data
+ /* 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=%d.%s=%s.%s=%d.%s=%d.%s=%d.%s=%d.%s=%d.",
- 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);
+ g_string_append_printf(mcdserver_state.str_buf,
+ "%s=%d.%s=%s.%s=%d.%s=%d.%s=%d.%s=%d.%s=%d.",
+ 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);
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
+void handle_query_regs_c(GArray *params, void *user_ctx)
+{
+ /*
+ * this funcitons send all regs except for the first
+ * 1. get parameter and registers
+ */
int 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);
+ GArray *registers = g_list_nth_data(mcdserver_state.all_registers, cpu_id);
- // 2. check weather this was the last register
+ /* 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
+ if (query_index + 1 == nb_regs) {
+ /* indicates this is the last packet */
g_string_printf(mcdserver_state.str_buf, "0!");
- }
- else {
- g_string_printf(mcdserver_state.str_buf, "%d!", query_index+1);
+ } else {
+ g_string_printf(mcdserver_state.str_buf, "%d!", query_index + 1);
}
- // 3. send the correct register
+ /* 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=%d.%s=%s.%s=%d.%s=%d.%s=%d.%s=%d.%s=%d.",
- 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);
+ g_string_append_printf(mcdserver_state.str_buf,
+ "%s=%d.%s=%s.%s=%d.%s=%d.%s=%d.%s=%d.%s=%d.",
+ 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);
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_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) {
- // TODO: multicore support
- // get state info
+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;
mcd_core_event_et event = MCD_CORE_EVENT_NONE;
if (state_info.memory_changed) {
@@ -1674,42 +1805,47 @@ void handle_query_state(GArray *params, void *user_ctx) {
event = event | MCD_CORE_EVENT_STOPPED;
state_info.target_was_stopped = false;
}
- // send data
- g_string_printf(mcdserver_state.str_buf, "%s=%s.%s=%d.%s=%d.%s=%d.%s=%s.%s=%s.", TCP_ARGUMENT_STATE, state_info.state,
- TCP_ARGUMENT_EVENT, event, TCP_ARGUMENT_THREAD, 0, TCP_ARGUMENT_TRIGGER_ID, state_info.trig_id,
- TCP_ARGUMENT_STOP_STRING, state_info.stop_str, TCP_ARGUMENT_INFO_STRING, state_info.info_str);
+ /* send data */
+ g_string_printf(mcdserver_state.str_buf,
+ "%s=%s.%s=%d.%s=%d.%s=%d.%s=%s.%s=%s.",
+ TCP_ARGUMENT_STATE, state_info.state,
+ TCP_ARGUMENT_EVENT, event, TCP_ARGUMENT_THREAD, 0,
+ TCP_ARGUMENT_TRIGGER_ID, state_info.trig_id,
+ TCP_ARGUMENT_STOP_STRING, state_info.stop_str,
+ TCP_ARGUMENT_INFO_STRING, state_info.info_str);
mcd_put_strbuf();
}
-int mcd_read_register(CPUState *cpu, GByteArray *buf, int reg) {
+int mcd_read_register(CPUState *cpu, GByteArray *buf, int reg)
+{
CPUClass *cc = CPU_GET_CLASS(cpu);
gchar *arch = cc->gdb_arch_name(cpu);
- if (strcmp(arch, "arm")==0) {
+ if (strcmp(arch, "arm") == 0) {
g_free(arch);
return arm_mcd_read_register(cpu, buf, reg);
- }
- else {
+ } else {
g_free(arch);
return 0;
}
}
-int mcd_write_register(CPUState *cpu, GByteArray *buf, int reg) {
+int mcd_write_register(CPUState *cpu, GByteArray *buf, int reg)
+{
CPUClass *cc = CPU_GET_CLASS(cpu);
gchar *arch = cc->gdb_arch_name(cpu);
- if (strcmp(arch, "arm")==0) {
+ if (strcmp(arch, "arm") == 0) {
g_free(arch);
return arm_mcd_write_register(cpu, buf, reg);
- }
- else {
+ } else {
g_free(arch);
return 0;
}
}
-void mcd_memtohex(GString *buf, const uint8_t *mem, int len) {
+void mcd_memtohex(GString *buf, const uint8_t *mem, int len)
+{
int i, c;
- for(i = 0; i < len; i++) {
+ 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));
@@ -1717,45 +1853,50 @@ void mcd_memtohex(GString *buf, const uint8_t *mem, int len) {
g_string_append_c(buf, '\0');
}
-void mcd_hextomem(GByteArray *mem, const char *buf, int len) {
+void mcd_hextomem(GByteArray *mem, const char *buf, int len)
+{
int i;
- for(i = 0; i < len; 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) {
+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_int;
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_memtohex(mcdserver_state.str_buf,
+ mcdserver_state.mem_buf->data, reg_size);
mcd_put_strbuf();
}
-void handle_write_register(GArray *params, void *user_ctx) {
+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_int;
uint32_t reg_size = get_param(params, 2)->data_int;
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, reg_num)==0) {
+ mcd_hextomem(mcdserver_state.mem_buf,
+ mcdserver_state.str_buf->str, reg_size);
+ if (mcd_write_register(cpu, mcdserver_state.mem_buf, reg_num) == 0) {
mcd_put_packet(TCP_EXECUTION_ERROR);
- }
- else {
+ } else {
mcd_put_packet(TCP_EXECUTION_SUCCESS);
}
}
-int mcd_read_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len) {
+int mcd_read_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len)
+{
CPUClass *cc;
- //TODO: add physical mem cpu_physical_memory_read(addr, buf, len);
+ /*TODO: add physical mem cpu_physical_memory_read(addr, buf, len); */
cc = CPU_GET_CLASS(cpu);
if (cc->memory_rw_debug) {
return cc->memory_rw_debug(cpu, addr, buf, len, false);
@@ -1764,9 +1905,10 @@ int mcd_read_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len) {
return cpu_memory_rw_debug(cpu, addr, buf, len, false);
}
-int mcd_write_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len) {
+int mcd_write_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len)
+{
CPUClass *cc;
- //TODO: add physical mem cpu_physical_memory_read(addr, buf, len);
+ /*TODO: add physical mem cpu_physical_memory_read(addr, buf, len); */
cc = CPU_GET_CLASS(cpu);
if (cc->memory_rw_debug) {
return cc->memory_rw_debug(cpu, addr, buf, len, true);
@@ -1775,33 +1917,36 @@ int mcd_write_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len) {
return cpu_memory_rw_debug(cpu, addr, buf, len, true);
}
-void handle_read_memory(GArray *params, void *user_ctx) {
+void handle_read_memory(GArray *params, void *user_ctx)
+{
uint32_t cpu_id = get_param(params, 0)->cpu_id;
uint64_t mem_address = get_param(params, 1)->data_uint64_t;
int len = get_param(params, 2)->data_int;
CPUState *cpu = mcd_get_cpu(cpu_id);
g_byte_array_set_size(mcdserver_state.mem_buf, len);
- if (mcd_read_memory(cpu, mem_address, mcdserver_state.mem_buf->data, mcdserver_state.mem_buf->len)!=0) {
+ if (mcd_read_memory(cpu, mem_address, mcdserver_state.mem_buf->data,
+ mcdserver_state.mem_buf->len) != 0) {
mcd_put_packet(TCP_EXECUTION_ERROR);
- }
- else {
- mcd_memtohex(mcdserver_state.str_buf, mcdserver_state.mem_buf->data, mcdserver_state.mem_buf->len);
+ } else {
+ 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) {
+void handle_write_memory(GArray *params, void *user_ctx)
+{
uint32_t cpu_id = get_param(params, 0)->cpu_id;
uint64_t mem_address = get_param(params, 1)->data_uint64_t;
int len = get_param(params, 2)->data_int;
CPUState *cpu = mcd_get_cpu(cpu_id);
mcd_hextomem(mcdserver_state.mem_buf, mcdserver_state.str_buf->str, len);
- if (mcd_write_memory(cpu, mem_address, mcdserver_state.mem_buf->data, len)!=0) {
+ if (mcd_write_memory(cpu, mem_address,
+ mcdserver_state.mem_buf->data, len) != 0) {
mcd_put_packet(TCP_EXECUTION_ERROR);
- }
- else {
+ } else {
mcd_put_packet(TCP_EXECUTION_SUCCESS);
}
}
similarity index 69%
rename from mcdstub/internals.h
rename to mcdstub/mcdstub.h
@@ -4,49 +4,46 @@
#include "exec/cpu-common.h"
#include "chardev/char.h"
#include "hw/core/cpu.h"
-// just used for the register xml files
+/* just used for the register xml files */
#include "exec/gdbstub.h"
#define MAX_PACKET_LENGTH 1024
-// trigger defines
+/* trigger defines */
#define MCD_TRIG_OPT_DATA_IS_CONDITION 0x00000008
#define MCD_TRIG_ACTION_DBG_DEBUG 0x00000001
typedef uint32_t mcd_trig_type_et;
-// TODO: replace mcd defines with custom layer
+/* TODO: replace mcd defines with custom layer */
enum {
- MCD_TRIG_TYPE_UNDEFINED = 0x00000000, /**< Undefined trigger type. */
- MCD_TRIG_TYPE_IP = 0x00000001, /**< Trigger on a changing instruction pointer. */
- MCD_TRIG_TYPE_READ = 0x00000002, /**< Trigger on a read data access to a specific address or address range. */
- MCD_TRIG_TYPE_WRITE = 0x00000004, /**< Trigger on a write data access to a specific address or address range. */
- MCD_TRIG_TYPE_RW = 0x00000008, /**< Trigger on a read or a write data access to a specific address or
- address range. */
- MCD_TRIG_TYPE_NOCYCLE = 0x00000010, /**< Trigger on core information other than an IP or data compare trigger. */
- MCD_TRIG_TYPE_TRIG_BUS = 0x00000020, /**< Trigger on a trigger bus combination. */
- MCD_TRIG_TYPE_COUNTER = 0x00000040, /**< Trigger on an elapsed trigger counter. */
- MCD_TRIG_TYPE_CUSTOM = 0x00000080, /**< Custom trigger using standard format as defined by \ref mcd_trig_custom_st. */
- MCD_TRIG_TYPE_CUSTOM_LO = 0x00010000, /**< Begin Range: User defined trigger types. */
- MCD_TRIG_TYPE_CUSTOM_HI = 0x40000000, /**< End Range: User defined trigger types. */
+ MCD_TRIG_TYPE_UNDEFINED = 0x00000000,
+ MCD_TRIG_TYPE_IP = 0x00000001,
+ MCD_TRIG_TYPE_READ = 0x00000002,
+ MCD_TRIG_TYPE_WRITE = 0x00000004,
+ MCD_TRIG_TYPE_RW = 0x00000008,
+ MCD_TRIG_TYPE_NOCYCLE = 0x00000010,
+ MCD_TRIG_TYPE_TRIG_BUS = 0x00000020,
+ MCD_TRIG_TYPE_COUNTER = 0x00000040,
+ MCD_TRIG_TYPE_CUSTOM = 0x00000080,
+ MCD_TRIG_TYPE_CUSTOM_LO = 0x00010000,
+ MCD_TRIG_TYPE_CUSTOM_HI = 0x40000000,
};
typedef uint32_t mcd_core_event_et;
-// TODO: replace mcd defines with custom layer
+/* TODO: replace mcd defines with custom layer */
enum {
- MCD_CORE_EVENT_NONE = 0x00000000, /**< No since the last poll. */
- MCD_CORE_EVENT_MEMORY_CHANGE = 0x00000001, /**< Memory content has changed. */
- MCD_CORE_EVENT_REGISTER_CHANGE = 0x00000002, /**< Register contents have changed. */
- MCD_CORE_EVENT_TRACE_CHANGE = 0x00000004, /**< Trace contents or states have changed. */
- MCD_CORE_EVENT_TRIGGER_CHANGE = 0x00000008, /**< Triggers or trigger states have changed. */
- MCD_CORE_EVENT_STOPPED = 0x00000010, /**< Target was stopped at least once since the last poll,
- it may already be running again. */
- MCD_CORE_EVENT_CHL_PENDING = 0x00000020, /**< A target communication channel request from the target
- is pending. */
- MCD_CORE_EVENT_CUSTOM_LO = 0x00010000, /**< Begin Range: User defined core events. */
- MCD_CORE_EVENT_CUSTOM_HI = 0x40000000, /**< End Range: User defined core events. */
+ MCD_CORE_EVENT_NONE = 0x00000000,
+ MCD_CORE_EVENT_MEMORY_CHANGE = 0x00000001,
+ MCD_CORE_EVENT_REGISTER_CHANGE = 0x00000002,
+ MCD_CORE_EVENT_TRACE_CHANGE = 0x00000004,
+ MCD_CORE_EVENT_TRIGGER_CHANGE = 0x00000008,
+ MCD_CORE_EVENT_STOPPED = 0x00000010,
+ MCD_CORE_EVENT_CHL_PENDING = 0x00000020,
+ MCD_CORE_EVENT_CUSTOM_LO = 0x00010000,
+ MCD_CORE_EVENT_CUSTOM_HI = 0x40000000,
};
-// schema defines
+/* schema defines */
#define ARG_SCHEMA_QRYHANDLE 'q'
#define ARG_SCHEMA_STRING 's'
#define ARG_SCHEMA_INT 'd'
@@ -54,20 +51,20 @@ enum {
#define ARG_SCHEMA_CORENUM 'c'
#define ARG_SCHEMA_HEXDATA 'h'
-// resets
+/* resets */
#define RESET_SYSTEM "full_system_reset"
#define RESET_GPR "gpr_reset"
#define RESET_MEMORY "memory_reset"
-// misc
-#define QUERY_TOTAL_NUMBER 12
+/* misc */
+#define QUERY_TOTAL_NUMBER 12
#define CMD_SCHEMA_LENGTH 5
#define MCD_SYSTEM_NAME "qemu-system"
-// tcp query packet values templates
+/* tcp query packet values templates */
#define DEVICE_NAME_TEMPLATE(s) "qemu-" #s "-device"
-// state strings
+/* 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"
@@ -82,7 +79,7 @@ enum {
#define STATE_STR_BREAK_UNKNOWN "stopped for unknown reason"
typedef struct GDBRegisterState {
- // needed for the used gdb functions
+ /* needed for the used gdb functions */
int base_reg;
int num_regs;
gdb_get_reg_cb get_reg;
@@ -193,22 +190,22 @@ typedef struct xml_attrib {
} xml_attrib;
typedef struct mcd_reg_st {
- // xml info
+ /* xml info */
char name[64];
char group[64];
char type[64];
uint32_t bitsize;
uint32_t id;
- // mcd metadata
+ /* 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
+ /* data for op-code */
uint8_t cp;
uint8_t crn;
uint8_t crm;
- uint8_t opc0; // <- might not be needed!
+ uint8_t opc0; /* <- might not be needed! */
uint8_t opc1;
uint8_t opc2;
} mcd_reg_st;
@@ -245,9 +242,9 @@ void mcd_sigterm_handler(int signal);
#endif
void mcd_init_mcdserver_state(void);
-void init_query_cmds_table(MCDCmdParseEntry* mcd_query_cmds_table);
-int init_resets(GArray* resets);
-int init_trigger(mcd_trigger_st* trigger);
+void init_query_cmds_table(MCDCmdParseEntry *mcd_query_cmds_table);
+int init_resets(GArray *resets);
+int init_trigger(mcd_trigger_st *trigger);
void reset_mcdserver_state(void);
void create_processes(MCDState *s);
void mcd_create_default_process(MCDState *s);
@@ -272,14 +269,15 @@ int mcd_handle_packet(const char *line_buf);
void mcd_put_strbuf(void);
void mcd_exit(int code);
void run_cmd_parser(const char *data, const MCDCmdParseEntry *cmd);
-int process_string_cmd(void *user_ctx, const char *data, const MCDCmdParseEntry *cmds, int num_cmds);
+int process_string_cmd(void *user_ctx, const char *data,
+ const MCDCmdParseEntry *cmds, int num_cmds);
int cmd_parse_params(const char *data, const char *schema, GArray *params);
void handle_vm_start(GArray *params, void *user_ctx);
void handle_vm_step(GArray *params, void *user_ctx);
void handle_vm_stop(GArray *params, void *user_ctx);
void handle_gen_query(GArray *params, void *user_ctx);
int mcd_get_cpu_index(CPUState *cpu);
-CPUState* mcd_get_cpu(uint32_t i_cpu_index);
+CPUState *mcd_get_cpu(uint32_t i_cpu_index);
void handle_query_cores(GArray *params, void *user_ctx);
void handle_query_system(GArray *params, void *user_ctx);
CPUState *get_first_cpu_in_process(MCDProcess *process);
@@ -312,20 +310,22 @@ int mcd_write_register(CPUState *cpu, GByteArray *buf, int reg);
int mcd_read_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len);
int mcd_write_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len);
-// arm specific functions
-int mcd_arm_store_mem_spaces(CPUState *cpu, GArray* memspaces);
-int mcd_arm_parse_core_xml_file(CPUClass *cc, GArray* reggroups, GArray* registers, int* current_group_id);
-int mcd_arm_parse_general_xml_files(CPUState *cpu, GArray* reggroups, GArray* registers, int* current_group_id);
-int mcd_arm_get_additional_register_info(GArray* reggroups, GArray* registers);
+/* arm specific functions */
+int mcd_arm_store_mem_spaces(CPUState *cpu, GArray *memspaces);
+int mcd_arm_parse_core_xml_file(CPUClass *cc, GArray *reggroups,
+ GArray *registers, int *current_group_id);
+int mcd_arm_parse_general_xml_files(CPUState *cpu, GArray* reggroups,
+ GArray *registers, int *current_group_id);
+int mcd_arm_get_additional_register_info(GArray *reggroups, GArray *registers);
-// sycall handling
+/* sycall handling */
void mcd_syscall_reset(void);
void mcd_disable_syscalls(void);
-// helpers
+/* helpers */
int int_cmp(gconstpointer a, gconstpointer b);
void mcd_memtohex(GString *buf, const uint8_t *mem, int len);
void mcd_hextomem(GByteArray *mem, const char *buf, int len);
-uint64_t atouint64_t(const char* in);
+uint64_t atouint64_t(const char *in);
#endif /* MCDSTUB_INTERNALS_H */
@@ -7,19 +7,21 @@
# We need to build the core mcd code via a library to be able to tweak
# cflags so:
-mcd_softmmu_ss = ss.source_set()
+mcd_system_ss = ss.source_set()
-# We build one version of the mcdstub, because it only needs to work for system emulation
-mcd_softmmu_ss.add(files('mcdstub.c'))
+# We build one version of the mcdstub,
+#because it only needs to work for system emulation
+mcd_system_ss.add(files('mcdstub.c'))
-mcd_softmmu_ss = mcd_softmmu_ss.apply(config_host, strict: false)
+mcd_system_ss = mcd_system_ss.apply(config_host, strict: false)
libmcd_softmmu = static_library('mcd_softmmu',
- mcd_softmmu_ss.sources() + genh,
- name_suffix: 'fa')
+ mcd_system_ss.sources() + genh,
+ name_suffix: 'fa',
+ build_by_default: have_system)
mcd_softmmu = declare_dependency(link_whole: libmcd_softmmu)
-softmmu_ss.add(mcd_softmmu)
+system_ss.add(mcd_softmmu)
# this might cause problems because we don't support user mode
common_ss.add(files('mcd_syscalls.c'))
@@ -306,7 +306,7 @@ void cpu_handle_guest_debug(CPUState *cpu)
cpu_single_step(cpu, 0);
}
} else {
- //gdb_set_stop_cpu(cpu);
+ gdb_set_stop_cpu(cpu);
qemu_system_debug_request();
cpu->stopped = true;
}
@@ -2663,9 +2663,9 @@ 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);
@@ -8,8 +8,10 @@
static inline int mcd_get_reg32(GByteArray *buf, uint32_t val)
{
- //TODO: move this to a separate file
- // convert endianess if necessary
+ /*
+ *TODO: move this to a separate file
+ *convert endianess if necessary
+ */
uint32_t to_long = tswap32(val);
g_byte_array_append(buf, (uint8_t *) &to_long, 4);
return 4;
@@ -17,7 +19,7 @@ static inline int mcd_get_reg32(GByteArray *buf, uint32_t val)
static inline int mcd_get_zeroes(GByteArray *array, size_t len)
{
- //TODO: move this to a separate file
+ /*TODO: move this to a separate file */
guint oldlen = array->len;
g_byte_array_set_size(array, oldlen + len);
memset(array->data + oldlen, 0, len);
@@ -43,7 +45,8 @@ const char *arm_mcd_get_dynamic_xml(CPUState *cs, const char *xmlname)
return NULL;
}
-int arm_mcd_read_register(CPUState *cs, GByteArray *mem_buf, int n) {
+int arm_mcd_read_register(CPUState *cs, GByteArray *mem_buf, int n)
+{
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
@@ -52,12 +55,12 @@ int arm_mcd_read_register(CPUState *cs, GByteArray *mem_buf, int n) {
return mcd_get_reg32(mem_buf, env->regs[n]);
}
if (n < 24) {
- // TODO: these numbers don't match mine
+ /* TODO: these numbers don't match mine */
return mcd_get_zeroes(mem_buf, 12);
}
switch (n) {
case 24:
- // TODO: these numbers don't match mine
+ /* TODO: these numbers don't match mine */
return mcd_get_reg32(mem_buf, 0);
case 25:
/* CPSR, or XPSR for M-profile */
@@ -67,17 +70,18 @@ int arm_mcd_read_register(CPUState *cs, GByteArray *mem_buf, int n) {
return mcd_get_reg32(mem_buf, cpsr_read(env));
}
}
- //TODO: add funcitons for the remaining regs (including cp_regs)
+ /* TODO: add funcitons for the remaining regs (including cp_regs) */
return 0;
}
-int arm_mcd_write_register(CPUState *cs, GByteArray *mem_buf, int n) {
+int arm_mcd_write_register(CPUState *cs, GByteArray *mem_buf, int n)
+{
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
uint32_t tmp;
tmp = ldl_p(mem_buf);
- tmp = *((uint32_t*)mem_buf->data);
+ tmp = *((uint32_t *)mem_buf->data);
/*
* Mask out low bits of PC to workaround gdb bugs.
@@ -122,6 +126,6 @@ int arm_mcd_write_register(CPUState *cs, GByteArray *mem_buf, int n) {
}
return 4;
}
- //TODO: add funcitons for the remaining regs (including cp_regs)
+ /* TODO: add funcitons for the remaining regs (including cp_regs) */
return 0;
}
--
2.34.1
From 30dc5d9df62fdb38fb8fe7b06f0f84c8a614e18e Mon Sep 17 00:00:00 2001
From: Nicolas Eder <nicolas.eder@lauterbach.com>
Date: Mon, 10 Jul 2023 12:53:32 +0200
Subject: [PATCH 16/29] deleting the mcdd startup option
Signed-off-by: Nicolas Eder <nicolas.eder@lauterbach.com>
---
mcdstub/meson.build | 10 +---------
qemu-options.hx | 13 +++----------
2 files changed, 4 insertions(+), 19 deletions(-)
@@ -1,16 +1,9 @@
-#
-# The main gdbstub still relies on per-build definitions of various
-# types. The bits pushed to softmmu/user.c try to use guest agnostic
-# types such as hwaddr.
-#
-
# We need to build the core mcd code via a library to be able to tweak
# cflags so:
mcd_system_ss = ss.source_set()
-# We build one version of the mcdstub,
-#because it only needs to work for system emulation
+# only system emulation is supported over mcd
mcd_system_ss.add(files('mcdstub.c'))
mcd_system_ss = mcd_system_ss.apply(config_host, strict: false)
@@ -23,5 +16,4 @@ libmcd_softmmu = static_library('mcd_softmmu',
mcd_softmmu = declare_dependency(link_whole: libmcd_softmmu)
system_ss.add(mcd_softmmu)
-# this might cause problems because we don't support user mode
common_ss.add(files('mcd_syscalls.c'))
@@ -4417,7 +4417,8 @@ 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",
+ " if you want it to not start execution.)\n"
+ " To use the default Port write '-mcd default'\n",
QEMU_ARCH_ALL)
SRST
``-mcd dev``
@@ -4428,15 +4429,7 @@ SRST
The most usual configuration is to listen on a local TCP socket::
- -mcd tcp::1234
-ERST
-
-DEF("mcdd", 0, QEMU_OPTION_mcdd, \
- "-mcdd shorthand for -mcd tcp::" DEFAULT_MCDSTUB_PORT "\n",
- QEMU_ARCH_ALL)
-SRST
-``-mcdd``
- Shorthand for -mcd tcp::1234, i.e. open a mcdserver on TCP port 1234
+ -mcd tcp::1235
ERST
DEF("d", HAS_ARG, QEMU_OPTION_d, \
--
2.34.1
From 0c3a643cbe9923c26bb21e420f3a7ffa10a3cd6a Mon Sep 17 00:00:00 2001
From: Nicolas Eder <nicolas.eder@lauterbach.com>
Date: Mon, 10 Jul 2023 18:34:04 +0200
Subject: [PATCH 17/29] handler for breakpoints and watchpoints added
Signed-off-by: Nicolas Eder <nicolas.eder@lauterbach.com>
---
mcdstub/mcd_shared_defines.h | 8 +++
mcdstub/mcdstub.c | 124 ++++++++++++++++++++++++++++++++++-
mcdstub/mcdstub.h | 4 ++
softmmu/cpus.c | 2 +-
4 files changed, 135 insertions(+), 3 deletions(-)
@@ -21,6 +21,8 @@
#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 '+'
@@ -82,4 +84,10 @@
#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
+
#endif
@@ -563,6 +563,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[5]) { ARG_SCHEMA_CORENUM, ARG_SCHEMA_INT,
+ ARG_SCHEMA_UINT64_T, 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[5]) { ARG_SCHEMA_CORENUM, ARG_SCHEMA_INT,
+ ARG_SCHEMA_UINT64_T, ARG_SCHEMA_UINT64_T, '\0' });
+ cmd_parser = &handle_breakpoint_remove_cmd_desc;
+ }
+ break;
default:
/* command not supported */
mcd_put_packet("");
@@ -837,13 +863,14 @@ void mcd_vm_state_change(void *opaque, bool running, RunState state)
cpu->watchpoint_hit = NULL;
} else if (cpu->singlestep_enabled) {
/* we land here when a single step is performed */
- cpu_single_step(cpu, 0);
stop_str = STATE_STEP_PERFORMED;
} else {
trig_id = MCD_TRIG_TYPE_IP;
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);
@@ -1594,7 +1621,8 @@ void mcd_vm_start(void)
int mcd_vm_sstep(CPUState *cpu)
{
- cpu_single_step(mcdserver_state.c_cpu, mcdserver_state.sstep_flags);
+ mcdserver_state.c_cpu = cpu;
+ cpu_single_step(cpu, mcdserver_state.sstep_flags);
mcd_vm_start();
return 0;
}
@@ -1950,3 +1978,95 @@ void handle_write_memory(GArray *params, void *user_ctx)
mcd_put_packet(TCP_EXECUTION_SUCCESS);
}
}
+
+int mcd_breakpoint_insert(CPUState *cpu, int type, vaddr addr, vaddr len)
+{
+ /* 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, vaddr len)
+{
+ /* 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_int;
+ uint64_t address = get_param(params, 2)->data_uint64_t;
+ uint64_t len = get_param(params, 3)->data_uint64_t;
+ /* 2. insert breakpoint and send reply*/
+ CPUState *cpu = mcd_get_cpu(cpu_id);
+ if (mcd_breakpoint_insert(cpu, type, address, len) != 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_int;
+ uint64_t address = get_param(params, 2)->data_uint64_t;
+ uint64_t len = get_param(params, 3)->data_uint64_t;
+ /* 2. remove breakpoint and send reply*/
+ CPUState *cpu = mcd_get_cpu(cpu_id);
+ if (mcd_breakpoint_remove(cpu, type, address, len) != 0) {
+ mcd_put_packet(TCP_EXECUTION_ERROR);
+ } else {
+ mcd_put_packet(TCP_EXECUTION_SUCCESS);
+ }
+}
@@ -309,6 +309,10 @@ int mcd_read_register(CPUState *cpu, GByteArray *buf, int reg);
int mcd_write_register(CPUState *cpu, GByteArray *buf, int reg);
int mcd_read_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len);
int mcd_write_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len);
+void handle_breakpoint_insert(GArray *params, void *user_ctx);
+void handle_breakpoint_remove(GArray *params, void *user_ctx);
+int mcd_breakpoint_insert(CPUState *cpu, int type, vaddr addr, vaddr len);
+int mcd_breakpoint_remove(CPUState *cpu, int type, vaddr addr, vaddr len);
/* arm specific functions */
int mcd_arm_store_mem_spaces(CPUState *cpu, GArray *memspaces);
@@ -306,7 +306,7 @@ void cpu_handle_guest_debug(CPUState *cpu)
cpu_single_step(cpu, 0);
}
} else {
- gdb_set_stop_cpu(cpu);
+ /*gdb_set_stop_cpu(cpu);*/
qemu_system_debug_request();
cpu->stopped = true;
}
--
2.34.1
From 8d3d3659010bd71f94c506e0d859fba35f69b7ef Mon Sep 17 00:00:00 2001
From: Nicolas Eder <nicolas.eder@lauterbach.com>
Date: Wed, 12 Jul 2023 11:53:29 +0200
Subject: [PATCH 18/29] making step and go handlers core-specific
Signed-off-by: Nicolas Eder <nicolas.eder@lauterbach.com>
---
mcdstub/mcdstub.c | 26 ++++++++++++++++++++++----
mcdstub/mcdstub.h | 3 ++-
2 files changed, 24 insertions(+), 5 deletions(-)
@@ -434,6 +434,8 @@ int mcd_handle_packet(const char *line_buf)
.handler = handle_vm_start,
};
go_cmd_desc.cmd = (char[2]) { TCP_CHAR_GO, '\0' };
+ strcpy(go_cmd_desc.schema,
+ (char[2]) { ARG_SCHEMA_CORENUM, '\0' });
cmd_parser = &go_cmd_desc;
}
break;
@@ -606,7 +608,9 @@ int mcd_handle_packet(const char *line_buf)
void handle_vm_start(GArray *params, void *user_ctx)
{
/* TODO: add partial restart with arguments and so on */
- mcd_vm_start();
+ uint32_t cpu_id = get_param(params, 0)->cpu_id;
+ CPUState *cpu = mcd_get_cpu(cpu_id);
+ mcd_cpu_start(cpu);
}
void handle_vm_step(GArray *params, void *user_ctx)
@@ -615,7 +619,7 @@ void handle_vm_step(GArray *params, void *user_ctx)
uint32_t cpu_id = get_param(params, 0)->cpu_id;
CPUState *cpu = mcd_get_cpu(cpu_id);
- int return_value = mcd_vm_sstep(cpu);
+ int return_value = mcd_cpu_sstep(cpu);
if (return_value != 0) {
g_assert_not_reached();
}
@@ -1619,11 +1623,25 @@ void mcd_vm_start(void)
}
}
-int mcd_vm_sstep(CPUState *cpu)
+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);
- mcd_vm_start();
+ if (!runstate_needs_reset() && !runstate_is_running() &&
+ !vm_prepare_start(true)) {
+ qemu_clock_enable(QEMU_CLOCK_VIRTUAL, true);
+ cpu_resume(cpu);
+ }
return 0;
}
@@ -289,7 +289,8 @@ void handle_close_server(GArray *params, void *user_ctx);
void handle_close_core(GArray *params, void *user_ctx);
void handle_query_trigger(GArray *params, void *user_ctx);
void mcd_vm_start(void);
-int mcd_vm_sstep(CPUState *cpu);
+void mcd_cpu_start(CPUState *cpu);
+int mcd_cpu_sstep(CPUState *cpu);
void mcd_vm_stop(void);
void handle_query_reg_groups_f(GArray *params, void *user_ctx);
void handle_query_reg_groups_c(GArray *params, void *user_ctx);
--
2.34.1
From d8d56695e2c9fcab1bb2ecaa5d5fac994088adce Mon Sep 17 00:00:00 2001
From: Nicolas Eder <nicolas.eder@lauterbach.com>
Date: Thu, 13 Jul 2023 15:36:29 +0200
Subject: [PATCH 19/29] adding trigger ID handling for TRACE32
Signed-off-by: Nicolas Eder <nicolas.eder@lauterbach.com>
---
mcdstub/mcd_shared_defines.h | 2 +-
mcdstub/mcdstub.c | 101 +++++++++++++++++++++--------------
mcdstub/mcdstub.h | 29 ++++++----
3 files changed, 82 insertions(+), 50 deletions(-)
@@ -63,7 +63,7 @@
#define TCP_ARGUMENT_MEMSPACEID "memspaceid"
#define TCP_ARGUMENT_SIZE "size"
#define TCP_ARGUMENT_THREAD "thread"
-#define TCP_ARGUMENT_TRIGGER_ID "trig_id"
+#define TCP_ARGUMENT_ADDRESS "address"
#define TCP_ARGUMENT_STOP_STRING "stop_str"
#define TCP_ARGUMENT_INFO_STRING "info_str"
#define TCP_ARGUMENT_STATE "state"
@@ -573,8 +573,8 @@ int mcd_handle_packet(const char *line_buf)
handle_breakpoint_insert_cmd_desc.cmd =
(char[2]) { TCP_CHAR_BREAKPOINT_INSERT, '\0' };
strcpy(handle_breakpoint_insert_cmd_desc.schema,
- (char[5]) { ARG_SCHEMA_CORENUM, ARG_SCHEMA_INT,
- ARG_SCHEMA_UINT64_T, ARG_SCHEMA_UINT64_T, '\0' });
+ (char[4]) { ARG_SCHEMA_CORENUM, ARG_SCHEMA_INT,
+ ARG_SCHEMA_UINT64_T, '\0' });
cmd_parser = &handle_breakpoint_insert_cmd_desc;
}
break;
@@ -586,8 +586,8 @@ int mcd_handle_packet(const char *line_buf)
handle_breakpoint_remove_cmd_desc.cmd =
(char[2]) { TCP_CHAR_BREAKPOINT_REMOVE, '\0' };
strcpy(handle_breakpoint_remove_cmd_desc.schema,
- (char[5]) { ARG_SCHEMA_CORENUM, ARG_SCHEMA_INT,
- ARG_SCHEMA_UINT64_T, ARG_SCHEMA_UINT64_T, '\0' });
+ (char[4]) { ARG_SCHEMA_CORENUM, ARG_SCHEMA_INT,
+ ARG_SCHEMA_UINT64_T, '\0' });
cmd_parser = &handle_breakpoint_remove_cmd_desc;
}
break;
@@ -671,6 +671,18 @@ uint64_t atouint64_t(const char *in)
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)
{
@@ -705,7 +717,7 @@ int cmd_parse_params(const char *data, const char *schema, GArray *params)
g_string_printf(mcdserver_state.str_buf, "%s", data_buffer);
break;
case ARG_SCHEMA_INT:
- this_param.data_int = atoi(data_buffer);
+ this_param.data_uint32_t = atouint32_t(data_buffer);
g_array_append_val(params, this_param);
break;
case ARG_SCHEMA_UINT64_T:
@@ -713,11 +725,11 @@ int cmd_parse_params(const char *data, const char *schema, GArray *params)
g_array_append_val(params, this_param);
break;
case ARG_SCHEMA_QRYHANDLE:
- this_param.query_handle = atoi(data_buffer);
+ this_param.query_handle = atouint32_t(data_buffer);
g_array_append_val(params, this_param);
break;
case ARG_SCHEMA_CORENUM:
- this_param.cpu_id = atoi(data_buffer);
+ this_param.cpu_id = atouint32_t(data_buffer);
g_array_append_val(params, this_param);
break;
default:
@@ -828,7 +840,7 @@ void mcd_vm_state_change(void *opaque, bool running, RunState state)
const char *info_str;
info_str = STATE_STR_INIT_RUNNING;
mcdserver_state.cpu_state.state = mcd_state;
- mcdserver_state.cpu_state.state = info_str;
+ mcdserver_state.cpu_state.info_str = info_str;
}
return;
}
@@ -836,7 +848,8 @@ void mcd_vm_state_change(void *opaque, bool running, RunState state)
const char *mcd_state;
const char *stop_str;
const char *info_str;
- uint32_t trig_id = 0;
+ uint32_t bp_type = 0;
+ uint64_t bp_address = 0;
switch (state) {
case RUN_STATE_RUNNING:
mcd_state = CORE_STATE_RUNNING;
@@ -849,27 +862,28 @@ void mcd_vm_state_change(void *opaque, bool running, RunState state)
if (cpu->watchpoint_hit) {
switch (cpu->watchpoint_hit->flags & BP_MEM_ACCESS) {
case BP_MEM_READ:
- trig_id = MCD_TRIG_TYPE_READ;
+ bp_type = MCD_BREAKPOINT_READ;
stop_str = STATE_STR_BREAK_READ(cpu->watchpoint_hit->hitaddr);
break;
case BP_MEM_WRITE:
- trig_id = MCD_TRIG_TYPE_WRITE;
+ bp_type = MCD_BREAKPOINT_WRITE;
stop_str = STATE_STR_BREAK_WRITE(cpu->watchpoint_hit->hitaddr);
break;
case BP_MEM_ACCESS:
- trig_id = MCD_TRIG_TYPE_RW;
+ bp_type = MCD_BREAKPOINT_RW;
stop_str = STATE_STR_BREAK_RW(cpu->watchpoint_hit->hitaddr);
break;
default:
- break;
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 {
- trig_id = MCD_TRIG_TYPE_IP;
+ bp_type = MCD_BREAKPOINT_HW;
stop_str = STATE_STR_BREAK_HW;
tb_flush(cpu);
}
@@ -895,7 +909,8 @@ void mcd_vm_state_change(void *opaque, bool running, RunState state)
/* set state for c_cpu */
mcdserver_state.cpu_state.state = mcd_state;
- mcdserver_state.cpu_state.trig_id = trig_id;
+ 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;
}
@@ -1263,13 +1278,14 @@ int init_resets(GArray *resets)
return 0;
}
-int init_trigger(mcd_trigger_st *trigger)
+int init_trigger(mcd_trigger_into_st *trigger)
{
trigger->type = (MCD_TRIG_TYPE_IP | MCD_TRIG_TYPE_READ |
MCD_TRIG_TYPE_WRITE | MCD_TRIG_TYPE_RW);
trigger->option = (MCD_TRIG_OPT_DATA_IS_CONDITION);
trigger->action = (MCD_TRIG_ACTION_DBG_DEBUG);
- trigger->nr_trigger = 4;
+ /* there is no specific upper limit for trigger */
+ trigger->nr_trigger = 0;
return 0;
}
@@ -1541,7 +1557,7 @@ void handle_query_reset_f(GArray *params, void *user_ctx)
void handle_query_reset_c(GArray *params, void *user_ctx)
{
/* reset options are the same for every cpu! */
- int query_index = get_param(params, 0)->query_handle;
+ 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;
@@ -1608,7 +1624,7 @@ void handle_close_server(GArray *params, void *user_ctx)
void handle_query_trigger(GArray *params, void *user_ctx)
{
- mcd_trigger_st trigger = mcdserver_state.trigger;
+ mcd_trigger_into_st trigger = mcdserver_state.trigger;
g_string_printf(mcdserver_state.str_buf, "%s=%d.%s=%d.%s=%d.%s=%d.",
TCP_ARGUMENT_AMOUNT_TRIGGER, trigger.nr_trigger,
TCP_ARGUMENT_TYPE, trigger.type, TCP_ARGUMENT_OPTION, trigger.option,
@@ -1687,7 +1703,7 @@ 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
*/
- int query_index = get_param(params, 0)->query_handle;
+ 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);
@@ -1742,7 +1758,7 @@ 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
*/
- int query_index = get_param(params, 0)->query_handle;
+ 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);
@@ -1797,7 +1813,7 @@ void handle_query_regs_c(GArray *params, void *user_ctx)
* this funcitons send all regs except for the first
* 1. get parameter and registers
*/
- int query_index = get_param(params, 0)->query_handle;
+ 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);
@@ -1853,13 +1869,22 @@ void handle_query_state(GArray *params, void *user_ctx)
}
/* send data */
g_string_printf(mcdserver_state.str_buf,
- "%s=%s.%s=%d.%s=%d.%s=%d.%s=%s.%s=%s.",
+ "%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_TRIGGER_ID, state_info.trig_id,
+ 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;
+ }
}
int mcd_read_register(CPUState *cpu, GByteArray *buf, int reg)
@@ -1913,7 +1938,7 @@ void mcd_hextomem(GByteArray *mem, const char *buf, int len)
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_int;
+ uint64_t reg_num = get_param(params, 1)->data_uint64_t;
int reg_size;
CPUState *cpu = mcd_get_cpu(cpu_id);
@@ -1926,8 +1951,8 @@ void handle_read_register(GArray *params, void *user_ctx)
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_int;
- uint32_t reg_size = get_param(params, 2)->data_int;
+ 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,
@@ -1967,7 +1992,7 @@ void handle_read_memory(GArray *params, void *user_ctx)
{
uint32_t cpu_id = get_param(params, 0)->cpu_id;
uint64_t mem_address = get_param(params, 1)->data_uint64_t;
- int len = get_param(params, 2)->data_int;
+ uint32_t len = get_param(params, 2)->data_uint32_t;
CPUState *cpu = mcd_get_cpu(cpu_id);
g_byte_array_set_size(mcdserver_state.mem_buf, len);
@@ -1985,7 +2010,7 @@ void handle_write_memory(GArray *params, void *user_ctx)
{
uint32_t cpu_id = get_param(params, 0)->cpu_id;
uint64_t mem_address = get_param(params, 1)->data_uint64_t;
- int len = get_param(params, 2)->data_int;
+ uint32_t len = 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, len);
@@ -1997,7 +2022,7 @@ void handle_write_memory(GArray *params, void *user_ctx)
}
}
-int mcd_breakpoint_insert(CPUState *cpu, int type, vaddr addr, vaddr len)
+int mcd_breakpoint_insert(CPUState *cpu, int type, vaddr addr)
{
/* translate the type to known gdb types and function call*/
int bp_type = 0;
@@ -2027,7 +2052,7 @@ int mcd_breakpoint_insert(CPUState *cpu, int type, vaddr addr, vaddr len)
}
}
-int mcd_breakpoint_remove(CPUState *cpu, int type, vaddr addr, vaddr len)
+int mcd_breakpoint_remove(CPUState *cpu, int type, vaddr addr)
{
/* translate the type to known gdb types and function call*/
int bp_type = 0;
@@ -2061,12 +2086,11 @@ 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_int;
+ uint32_t type = get_param(params, 1)->data_uint32_t;
uint64_t address = get_param(params, 2)->data_uint64_t;
- uint64_t len = get_param(params, 3)->data_uint64_t;
- /* 2. insert breakpoint and send reply*/
+ /* 2. insert breakpoint and send reply */
CPUState *cpu = mcd_get_cpu(cpu_id);
- if (mcd_breakpoint_insert(cpu, type, address, len) != 0) {
+ if (mcd_breakpoint_insert(cpu, type, address) != 0) {
mcd_put_packet(TCP_EXECUTION_ERROR);
} else {
mcd_put_packet(TCP_EXECUTION_SUCCESS);
@@ -2077,12 +2101,11 @@ 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_int;
+ uint32_t type = get_param(params, 1)->data_uint32_t;
uint64_t address = get_param(params, 2)->data_uint64_t;
- uint64_t len = get_param(params, 3)->data_uint64_t;
- /* 2. remove breakpoint and send reply*/
+ /* 2. remove breakpoint and send reply */
CPUState *cpu = mcd_get_cpu(cpu_id);
- if (mcd_breakpoint_remove(cpu, type, address, len) != 0) {
+ if (mcd_breakpoint_remove(cpu, type, address) != 0) {
mcd_put_packet(TCP_EXECUTION_ERROR);
} else {
mcd_put_packet(TCP_EXECUTION_SUCCESS);
@@ -104,10 +104,10 @@ typedef struct MCDCmdParseEntry {
typedef union MCDCmdVariant {
const char *data;
- int data_int;
+ uint32_t data_uint32_t;
uint64_t data_uint64_t;
- int query_handle;
- int cpu_id;
+ uint32_t query_handle;
+ uint32_t cpu_id;
} MCDCmdVariant;
#define get_param(p, i) (&g_array_index(p, MCDCmdVariant, i))
@@ -119,19 +119,26 @@ enum RSState {
RS_DATAEND,
};
-typedef struct mcd_trigger_st {
+typedef struct breakpoint_st {
+ uint32_t type;
+ uint64_t address;
+ uint32_t id;
+} breakpoint_st;
+
+typedef struct mcd_trigger_into_st {
uint32_t type;
uint32_t option;
uint32_t action;
uint32_t nr_trigger;
-} mcd_trigger_st;
+} 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 trig_id;
+ uint32_t bp_type;
+ uint64_t bp_address;
const char *stop_str;
const char *info_str;
} mcd_cpu_state_st;
@@ -158,8 +165,9 @@ typedef struct MCDState {
GList *all_memspaces;
GList *all_reggroups;
GList *all_registers;
+ GList *all_breakpoints;
GArray *resets;
- mcd_trigger_st trigger;
+ mcd_trigger_into_st trigger;
mcd_cpu_state_st cpu_state;
MCDCmdParseEntry mcd_query_cmds_table[QUERY_TOTAL_NUMBER];
} MCDState;
@@ -244,7 +252,7 @@ void mcd_sigterm_handler(int signal);
void mcd_init_mcdserver_state(void);
void init_query_cmds_table(MCDCmdParseEntry *mcd_query_cmds_table);
int init_resets(GArray *resets);
-int init_trigger(mcd_trigger_st *trigger);
+int init_trigger(mcd_trigger_into_st *trigger);
void reset_mcdserver_state(void);
void create_processes(MCDState *s);
void mcd_create_default_process(MCDState *s);
@@ -312,8 +320,8 @@ int mcd_read_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len);
int mcd_write_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len);
void handle_breakpoint_insert(GArray *params, void *user_ctx);
void handle_breakpoint_remove(GArray *params, void *user_ctx);
-int mcd_breakpoint_insert(CPUState *cpu, int type, vaddr addr, vaddr len);
-int mcd_breakpoint_remove(CPUState *cpu, int type, vaddr addr, vaddr len);
+int mcd_breakpoint_insert(CPUState *cpu, int type, vaddr addr);
+int mcd_breakpoint_remove(CPUState *cpu, int type, vaddr addr);
/* arm specific functions */
int mcd_arm_store_mem_spaces(CPUState *cpu, GArray *memspaces);
@@ -332,5 +340,6 @@ int int_cmp(gconstpointer a, gconstpointer b);
void mcd_memtohex(GString *buf, const uint8_t *mem, int len);
void mcd_hextomem(GByteArray *mem, const char *buf, int len);
uint64_t atouint64_t(const char *in);
+uint32_t atouint32_t(const char *in);
#endif /* MCDSTUB_INTERNALS_H */
--
2.34.1
From ad46b0fb59ad4c191a5be656cb7adeaa4b68ea5b Mon Sep 17 00:00:00 2001
From: Nicolas Eder <nicolas.eder@lauterbach.com>
Date: Fri, 14 Jul 2023 13:06:46 +0200
Subject: [PATCH 20/29] cp register read/write added
Signed-off-by: Nicolas Eder <nicolas.eder@lauterbach.com>
---
mcdstub/mcd_shared_defines.h | 1 +
mcdstub/mcdstub.c | 117 ++++++++++------
mcdstub/mcdstub.h | 18 ++-
target/arm/mcdstub.c | 265 ++++++++++++++++++++++++++++++-----
target/arm/mcdstub.h | 16 ++-
5 files changed, 330 insertions(+), 87 deletions(-)
@@ -74,6 +74,7 @@
#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 ';'
@@ -1064,10 +1064,12 @@ CPUState *find_cpu(uint32_t thread_id)
}
-void parse_reg_xml(const char *xml, int size, GArray *registers)
+void parse_reg_xml(const char *xml, int size, GArray *registers,
+ uint8_t reg_type)
{
/* iterates over the complete xml file */
int i, j;
+ uint32_t internal_id = 0;
int still_to_skip = 0;
char argument[64] = {0};
char value[64] = {0};
@@ -1116,8 +1118,11 @@ void parse_reg_xml(const char *xml, int size, GArray *registers)
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);
+ /*
+ * we might want to read out the regnum
+ * } else if (strcmp(argument_j, "regnum") == 0) {
+ * my_register.internal_id = atoi(value_j);
+ */
} else if (strcmp(argument_j, "bitsize") == 0) {
my_register.bitsize = atoi(value_j);
} else if (strcmp(argument_j, "type") == 0) {
@@ -1126,6 +1131,10 @@ void parse_reg_xml(const char *xml, int size, GArray *registers)
strcpy(my_register.group, value_j);
}
}
+ /* add reg_type and internal id */
+ my_register.reg_type = reg_type;
+ my_register.internal_id = internal_id;
+ internal_id++;
/* store register */
g_array_append_vals(registers, (gconstpointer)&my_register, 1);
/* free memory */
@@ -1238,6 +1247,7 @@ int mcd_arm_store_mem_spaces(CPUState *cpu, GArray *memspaces)
};
g_array_append_vals(memspaces, (gconstpointer)&space4, 1);
}
+
/* TODO: get dynamically how the per (CP15) space is called */
mcd_mem_space_st space5 = {
.name = "GPR Registers",
@@ -1263,7 +1273,6 @@ int mcd_arm_store_mem_spaces(CPUState *cpu, GArray *memspaces)
.supported_access_options = 0,
};
g_array_append_vals(memspaces, (gconstpointer)&space6, 1);
-
return 0;
}
@@ -1366,7 +1375,8 @@ int mcd_arm_parse_core_xml_file(CPUClass *cc, GArray *reggroups,
/* 3. parse xml */
xml_content = xml_builtin[i][1];
- parse_reg_xml(xml_content, strlen(xml_content), registers);
+ parse_reg_xml(xml_content, strlen(xml_content), registers,
+ MCD_ARM_REG_TYPE_GPR);
return 0;
}
@@ -1376,6 +1386,7 @@ int mcd_arm_parse_general_xml_files(CPUState *cpu, GArray *reggroups,
const char *current_xml_filename = NULL;
const char *xml_content = NULL;
int i = 0;
+ uint8_t reg_type;
/* iterate over all gdb xml files*/
GDBRegisterState *r;
@@ -1395,6 +1406,7 @@ int mcd_arm_parse_general_xml_files(CPUState *cpu, GArray *reggroups,
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 */
@@ -1407,58 +1419,59 @@ int mcd_arm_parse_general_xml_files(CPUState *cpu, GArray *reggroups,
}
if (current_xml_filename) {
xml_content = xml_builtin[i][1];
+ /* 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);
+ parse_reg_xml(xml_content, strlen(xml_content), registers, reg_type);
}
return 0;
}
-int mcd_arm_get_additional_register_info(GArray *reggroups, GArray *registers)
+int mcd_arm_get_additional_register_info(GArray *reggroups, GArray *registers,
+ CPUState *cpu)
{
- GList *register_numbers = NULL;
mcd_reg_st *current_register;
- int i = 0;
- int id_neg_offset = 0;
- int effective_id = 0;
+ 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));
- /* 1. ad the id */
- if (current_register->id) {
- /*
- *id is already in place
- *NOTE: qemu doesn't emulate the FPA regs
- *(so we are missing the indices 16 to 24)
- */
- int used_id = current_register->id;
- register_numbers = g_list_append(register_numbers, &used_id);
- id_neg_offset++;
- } else {
- effective_id = i - id_neg_offset;
- if (g_list_find_custom(register_numbers, &effective_id,
- (GCompareFunc)int_cmp) != NULL) {
- id_neg_offset--;
- }
- current_register->id = i - id_neg_offset;
- }
- /* 2. add mcd_reg_group_id and mcd_mem_space_id */
+ current_register->id = 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;
- /* TODO: get info for opcode */
+ /*
+ * 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;
}
}
- g_list_free(register_numbers);
return 0;
}
@@ -1498,7 +1511,7 @@ void handle_open_core(GArray *params, void *user_ctx)
}
/* 4. add additional data the the regs from the xmls */
return_value = mcd_arm_get_additional_register_info(reggroups,
- registers);
+ registers, cpu);
if (return_value != 0) {
g_assert_not_reached();
}
@@ -1797,13 +1810,15 @@ void handle_query_regs_f(GArray *params, void *user_ctx)
/* 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=%d.%s=%s.%s=%d.%s=%d.%s=%d.%s=%d.%s=%d.",
- TCP_ARGUMENT_ID, my_register.id, TCP_ARGUMENT_NAME,
- my_register.name, TCP_ARGUMENT_SIZE, my_register.bitsize,
+ "%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_THREAD, my_register.mcd_hw_thread_id,
+ TCP_ARGUMENT_OPCODE, my_register.opcode);
mcd_put_strbuf();
}
@@ -1829,13 +1844,15 @@ void handle_query_regs_c(GArray *params, void *user_ctx)
/* 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=%d.%s=%s.%s=%d.%s=%d.%s=%d.%s=%d.%s=%d.",
- TCP_ARGUMENT_ID, my_register.id, TCP_ARGUMENT_NAME,
- my_register.name, TCP_ARGUMENT_SIZE, my_register.bitsize,
+ "%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_THREAD, my_register.mcd_hw_thread_id,
+ TCP_ARGUMENT_OPCODE, my_register.opcode);
mcd_put_strbuf();
}
@@ -1889,11 +1906,18 @@ void handle_query_state(GArray *params, void *user_ctx)
int mcd_read_register(CPUState *cpu, GByteArray *buf, int reg)
{
+ /* 1. get reg type and internal id */
+ GArray *registers =
+ g_list_nth_data(mcdserver_state.all_registers, cpu->cpu_index);
+ mcd_reg_st desired_register = g_array_index(registers, mcd_reg_st, reg);
+ uint8_t reg_type = desired_register.reg_type;
+ uint32_t internal_id = desired_register.internal_id;
+ /* 2. read register */
CPUClass *cc = CPU_GET_CLASS(cpu);
gchar *arch = cc->gdb_arch_name(cpu);
if (strcmp(arch, "arm") == 0) {
g_free(arch);
- return arm_mcd_read_register(cpu, buf, reg);
+ return arm_mcd_read_register(cpu, buf, reg_type, internal_id);
} else {
g_free(arch);
return 0;
@@ -1902,11 +1926,18 @@ int mcd_read_register(CPUState *cpu, GByteArray *buf, int reg)
int mcd_write_register(CPUState *cpu, GByteArray *buf, int reg)
{
+ /* 1. get reg type and internal id */
+ GArray *registers =
+ g_list_nth_data(mcdserver_state.all_registers, cpu->cpu_index);
+ mcd_reg_st desired_register = g_array_index(registers, mcd_reg_st, reg);
+ uint8_t reg_type = desired_register.reg_type;
+ uint32_t internal_id = desired_register.internal_id;
+ /* 2. write register */
CPUClass *cc = CPU_GET_CLASS(cpu);
gchar *arch = cc->gdb_arch_name(cpu);
if (strcmp(arch, "arm") == 0) {
g_free(arch);
- return arm_mcd_write_register(cpu, buf, reg);
+ return arm_mcd_write_register(cpu, buf, reg_type, internal_id);
} else {
g_free(arch);
return 0;
@@ -203,19 +203,16 @@ typedef struct mcd_reg_st {
char group[64];
char type[64];
uint32_t bitsize;
- uint32_t id;
+ 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 */
- uint8_t cp;
- uint8_t crn;
- uint8_t crm;
- uint8_t opc0; /* <- might not be needed! */
- uint8_t opc1;
- uint8_t opc2;
+ uint32_t opcode;
} mcd_reg_st;
typedef struct mcd_reset_st {
@@ -307,7 +304,8 @@ void handle_query_mem_spaces_c(GArray *params, void *user_ctx);
void handle_query_regs_f(GArray *params, void *user_ctx);
void handle_query_regs_c(GArray *params, void *user_ctx);
void handle_open_server(GArray *params, void *user_ctx);
-void parse_reg_xml(const char *xml, int size, GArray* registers);
+void parse_reg_xml(const char *xml, int size, GArray* registers,
+ uint8_t reg_type);
void handle_reset(GArray *params, void *user_ctx);
void handle_query_state(GArray *params, void *user_ctx);
void handle_read_register(GArray *params, void *user_ctx);
@@ -329,8 +327,8 @@ int mcd_arm_parse_core_xml_file(CPUClass *cc, GArray *reggroups,
GArray *registers, int *current_group_id);
int mcd_arm_parse_general_xml_files(CPUState *cpu, GArray* reggroups,
GArray *registers, int *current_group_id);
-int mcd_arm_get_additional_register_info(GArray *reggroups, GArray *registers);
-
+int mcd_arm_get_additional_register_info(GArray *reggroups, GArray *registers,
+ CPUState *cpu);
/* sycall handling */
void mcd_syscall_reset(void);
void mcd_disable_syscalls(void);
@@ -17,6 +17,31 @@ static inline int mcd_get_reg32(GByteArray *buf, uint32_t val)
return 4;
}
+static inline int mcd_get_reg64(GByteArray *buf, uint64_t val)
+{
+ uint64_t to_quad = tswap64(val);
+ g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
+ return 8;
+}
+
+static inline int mcd_get_reg128(GByteArray *buf, uint64_t val_hi,
+ uint64_t val_lo)
+{
+ uint64_t to_quad;
+#if TARGET_BIG_ENDIAN
+ to_quad = tswap64(val_hi);
+ g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
+ to_quad = tswap64(val_lo);
+ g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
+#else
+ to_quad = tswap64(val_lo);
+ g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
+ to_quad = tswap64(val_hi);
+ g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
+#endif
+ return 16;
+}
+
static inline int mcd_get_zeroes(GByteArray *array, size_t len)
{
/*TODO: move this to a separate file */
@@ -45,24 +70,13 @@ const char *arm_mcd_get_dynamic_xml(CPUState *cs, const char *xmlname)
return NULL;
}
-int arm_mcd_read_register(CPUState *cs, GByteArray *mem_buf, int n)
+static int arm_mcd_read_gpr_register(CPUARMState *env, GByteArray *mem_buf,
+ uint32_t n)
{
- ARMCPU *cpu = ARM_CPU(cs);
- CPUARMState *env = &cpu->env;
-
if (n < 16) {
/* Core integer register. */
return mcd_get_reg32(mem_buf, env->regs[n]);
- }
- if (n < 24) {
- /* TODO: these numbers don't match mine */
- return mcd_get_zeroes(mem_buf, 12);
- }
- switch (n) {
- case 24:
- /* TODO: these numbers don't match mine */
- return mcd_get_reg32(mem_buf, 0);
- case 25:
+ } else if (n == 16) {
/* CPSR, or XPSR for M-profile */
if (arm_feature(env, ARM_FEATURE_M)) {
return mcd_get_reg32(mem_buf, xpsr_read(env));
@@ -70,21 +84,17 @@ int arm_mcd_read_register(CPUState *cs, GByteArray *mem_buf, int n)
return mcd_get_reg32(mem_buf, cpsr_read(env));
}
}
- /* TODO: add funcitons for the remaining regs (including cp_regs) */
return 0;
}
-int arm_mcd_write_register(CPUState *cs, GByteArray *mem_buf, int n)
+static int arm_mcd_write_gpr_register(CPUARMState *env, uint8_t *mem_buf,
+ uint32_t n)
{
- ARMCPU *cpu = ARM_CPU(cs);
- CPUARMState *env = &cpu->env;
uint32_t tmp;
tmp = ldl_p(mem_buf);
- tmp = *((uint32_t *)mem_buf->data);
-
/*
- * Mask out low bits of PC to workaround gdb bugs.
+ * Mask out low bits of PC
* This avoids an assert in thumb_tr_translate_insn, because it is
* architecturally impossible to misalign the pc.
* This will probably cause problems if we ever implement the
@@ -102,16 +112,7 @@ int arm_mcd_write_register(CPUState *cs, GByteArray *mem_buf, int n)
}
env->regs[n] = tmp;
return 4;
- }
- if (n < 24) { /* 16-23 */
- /* FPA registers (ignored). */
- return 4;
- }
- switch (n) {
- case 24:
- /* FPA status register (ignored). */
- return 4;
- case 25:
+ } else if (n == 16) {
/* CPSR, or XPSR for M-profile */
if (arm_feature(env, ARM_FEATURE_M)) {
/*
@@ -126,6 +127,206 @@ int arm_mcd_write_register(CPUState *cs, GByteArray *mem_buf, int n)
}
return 4;
}
- /* TODO: add funcitons for the remaining regs (including cp_regs) */
+ return 0;
+}
+
+static int arm_mcd_read_vfp_register(CPUARMState *env, GByteArray *buf,
+ uint32_t reg)
+{
+ ARMCPU *cpu = env_archcpu(env);
+ int nregs = cpu_isar_feature(aa32_simd_r32, cpu) ? 32 : 16;
+
+ /* VFP data registers are always little-endian. */
+ if (reg < nregs) {
+ return mcd_get_reg64(buf, *aa32_vfp_dreg(env, reg));
+ }
+ if (arm_feature(env, ARM_FEATURE_NEON)) {
+ /* Aliases for Q regs. */
+ nregs += 16;
+ if (reg < nregs) {
+ uint64_t *q = aa32_vfp_qreg(env, reg - 32);
+ return mcd_get_reg128(buf, q[0], q[1]);
+ }
+ }
+ switch (reg - nregs) {
+ case 0:
+ return mcd_get_reg32(buf, vfp_get_fpscr(env));
+ }
+ return 0;
+}
+
+static int arm_mcd_write_vfp_register(CPUARMState *env, uint8_t *buf,
+ uint32_t reg)
+{
+ ARMCPU *cpu = env_archcpu(env);
+ int nregs = cpu_isar_feature(aa32_simd_r32, cpu) ? 32 : 16;
+
+ if (reg < nregs) {
+ *aa32_vfp_dreg(env, reg) = ldq_le_p(buf);
+ return 8;
+ }
+ if (arm_feature(env, ARM_FEATURE_NEON)) {
+ nregs += 16;
+ if (reg < nregs) {
+ uint64_t *q = aa32_vfp_qreg(env, reg - 32);
+ q[0] = ldq_le_p(buf);
+ q[1] = ldq_le_p(buf + 8);
+ return 16;
+ }
+ }
+ switch (reg - nregs) {
+ case 0:
+ vfp_set_fpscr(env, ldl_p(buf));
+ return 4;
+ }
+ return 0;
+}
+
+static int arm_mcd_read_vfp_sys_register(CPUARMState *env, GByteArray *buf,
+ uint32_t reg)
+{
+ switch (reg) {
+ case 0:
+ return mcd_get_reg32(buf, env->vfp.xregs[ARM_VFP_FPSID]);
+ case 1:
+ return mcd_get_reg32(buf, env->vfp.xregs[ARM_VFP_FPEXC]);
+ }
+ return 0;
+}
+
+static int arm_mcd_write_vfp_sys_register(CPUARMState *env, uint8_t *buf,
+ uint32_t reg)
+{
+ switch (reg) {
+ case 0:
+ env->vfp.xregs[ARM_VFP_FPSID] = ldl_p(buf);
+ return 4;
+ case 1:
+ env->vfp.xregs[ARM_VFP_FPEXC] = ldl_p(buf) & (1 << 30);
+ return 4;
+ }
+ return 0;
+}
+
+static int arm_mcd_read_mve_register(CPUARMState *env, GByteArray *buf,
+ uint32_t reg)
+{
+ switch (reg) {
+ case 0:
+ return mcd_get_reg32(buf, env->v7m.vpr);
+ default:
+ return 0;
+ }
+}
+
+static int arm_mcd_write_mve_register(CPUARMState *env, uint8_t *buf,
+ uint32_t reg)
+{
+ switch (reg) {
+ case 0:
+ env->v7m.vpr = ldl_p(buf);
+ return 4;
+ default:
+ return 0;
+ }
+}
+
+static int arm_mcd_read_cpr_register(CPUARMState *env, GByteArray *buf,
+ uint32_t reg)
+{
+ ARMCPU *cpu = env_archcpu(env);
+ const ARMCPRegInfo *ri;
+ uint32_t key;
+
+ key = cpu->dyn_sysreg_xml.data.cpregs.keys[reg];
+ ri = get_arm_cp_reginfo(cpu->cp_regs, key);
+ if (ri) {
+ if (cpreg_field_is_64bit(ri)) {
+ return mcd_get_reg64(buf, (uint64_t)read_raw_cp_reg(env, ri));
+ } else {
+ return mcd_get_reg32(buf, (uint32_t)read_raw_cp_reg(env, ri));
+ }
+ }
+ return 0;
+}
+
+static int arm_mcd_write_cpr_register(CPUARMState *env, uint8_t *buf,
+ uint32_t reg)
+{
+ /* try write_raw_cp_reg here*/
+ return 0;
+}
+
+int arm_mcd_read_register(CPUState *cs, GByteArray *mem_buf, uint8_t reg_type,
+ uint32_t n)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+ switch (reg_type) {
+ case MCD_ARM_REG_TYPE_GPR:
+ return arm_mcd_read_gpr_register(env, mem_buf, n);
+ break;
+ case MCD_ARM_REG_TYPE_VFP:
+ return arm_mcd_read_vfp_register(env, mem_buf, n);
+ break;
+ case MCD_ARM_REG_TYPE_VFP_SYS:
+ return arm_mcd_read_vfp_sys_register(env, mem_buf, n);
+ break;
+ case MCD_ARM_REG_TYPE_MVE:
+ return arm_mcd_read_mve_register(env, mem_buf, n);
+ break;
+ case MCD_ARM_REG_TYPE_CPR:
+ return arm_mcd_read_cpr_register(env, mem_buf, n);
+ break;
+ default:
+ /* unknown register type*/
+ return 0;
+ }
+}
+
+int arm_mcd_write_register(CPUState *cs, GByteArray *mem_buf, uint8_t reg_type,
+ uint32_t n)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+ switch (reg_type) {
+ case MCD_ARM_REG_TYPE_GPR:
+ return arm_mcd_write_gpr_register(env, mem_buf->data, n);
+ break;
+ case MCD_ARM_REG_TYPE_VFP:
+ return arm_mcd_write_vfp_register(env, mem_buf->data, n);
+ break;
+ case MCD_ARM_REG_TYPE_VFP_SYS:
+ return arm_mcd_write_vfp_sys_register(env, mem_buf->data, n);
+ break;
+ case MCD_ARM_REG_TYPE_MVE:
+ return arm_mcd_write_mve_register(env, mem_buf->data, n);
+ break;
+ case MCD_ARM_REG_TYPE_CPR:
+ return arm_mcd_write_cpr_register(env, mem_buf->data, n);
+ break;
+ default:
+ /* unknown register type*/
+ return 0;
+ }
+}
+
+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;
}
@@ -1,8 +1,20 @@
#ifndef ARM_MCDSTUB_H
#define ARM_MCDSTUB_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,
+};
+
const char *arm_mcd_get_dynamic_xml(CPUState *cs, const char *xmlname);
-int arm_mcd_read_register(CPUState *cs, GByteArray *mem_buf, int n);
-int arm_mcd_write_register(CPUState *cs, GByteArray *mem_buf, int n);
+int arm_mcd_read_register(CPUState *cs, GByteArray *mem_buf, uint8_t reg_type,
+ uint32_t n);
+int arm_mcd_write_register(CPUState *cs, GByteArray *mem_buf, uint8_t reg_type,
+ uint32_t n);
+uint16_t arm_mcd_get_opcode(CPUState *cs, uint32_t n);
#endif /* ARM_MCDSTUB_H */
--
2.34.1
From c59ef5b700e25c8f4b739354377117903b94ab08 Mon Sep 17 00:00:00 2001
From: Nicolas Eder <nicolas.eder@lauterbach.com>
Date: Wed, 19 Jul 2023 17:07:45 +0200
Subject: [PATCH 21/29] switching between secure and non-secure memory added
Signed-off-by: Nicolas Eder <nicolas.eder@lauterbach.com>
---
mcdstub/mcdstub.c | 131 +++++++++++++++++++++++++++----------------
mcdstub/mcdstub.h | 4 +-
target/arm/mcdstub.c | 14 +++++
target/arm/mcdstub.h | 1 +
4 files changed, 100 insertions(+), 50 deletions(-)
@@ -548,8 +548,8 @@ int mcd_handle_packet(const char *line_buf)
};
read_mem_cmd_desc.cmd = (char[2]) { TCP_CHAR_READ_MEMORY, '\0' };
strcpy(read_mem_cmd_desc.schema,
- (char[4]) { ARG_SCHEMA_CORENUM, ARG_SCHEMA_UINT64_T,
- ARG_SCHEMA_INT, '\0' });
+ (char[5]) { ARG_SCHEMA_CORENUM, ARG_SCHEMA_INT,
+ ARG_SCHEMA_UINT64_T, ARG_SCHEMA_INT, '\0' });
cmd_parser = &read_mem_cmd_desc;
}
break;
@@ -560,8 +560,9 @@ int mcd_handle_packet(const char *line_buf)
};
write_mem_cmd_desc.cmd = (char[2]) { TCP_CHAR_WRITE_MEMORY, '\0' };
strcpy(write_mem_cmd_desc.schema,
- (char[5]) { ARG_SCHEMA_CORENUM, ARG_SCHEMA_UINT64_T,
- ARG_SCHEMA_INT, ARG_SCHEMA_HEXDATA, '\0' });
+ (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;
@@ -1194,10 +1195,17 @@ int int_cmp(gconstpointer a, gconstpointer b)
int mcd_arm_store_mem_spaces(CPUState *cpu, GArray *memspaces)
{
int nr_address_spaces = cpu->num_ases;
+ uint32_t mem_space_id = 0;
+
+ /*
+ * TODO: atm we can only access physical memory addresses,
+ * but trace32 needs fake locical spaces to work with
+ */
- mcd_mem_space_st space1 = {
+ mem_space_id++;
+ mcd_mem_space_st non_secure = {
.name = "Non Secure",
- .id = 1,
+ .id = mem_space_id,
.type = 34,
.bits_per_mau = 8,
.invariance = 1,
@@ -1205,38 +1213,13 @@ int mcd_arm_store_mem_spaces(CPUState *cpu, GArray *memspaces)
.min_addr = 0,
.max_addr = -1,
.supported_access_options = 0,
+ .is_secure = false,
};
- g_array_append_vals(memspaces, (gconstpointer)&space1, 1);
-
- mcd_mem_space_st space2 = {
+ g_array_append_vals(memspaces, (gconstpointer)&non_secure, 1);
+ mem_space_id++;
+ mcd_mem_space_st phys_non_secure = {
.name = "Physical (Non Secure)",
- .id = 2,
- .type = 18,
- .bits_per_mau = 8,
- .invariance = 1,
- .endian = 1,
- .min_addr = 0,
- .max_addr = -1,
- .supported_access_options = 0,
- };
- g_array_append_vals(memspaces, (gconstpointer)&space2, 1);
-
- if (nr_address_spaces == 2) {
- mcd_mem_space_st space3 = {
- .name = "Secure",
- .id = 3,
- .type = 34,
- .bits_per_mau = 8,
- .invariance = 1,
- .endian = 1,
- .min_addr = 0,
- .max_addr = -1,
- .supported_access_options = 0,
- };
- g_array_append_vals(memspaces, (gconstpointer)&space3, 1);
- mcd_mem_space_st space4 = {
- .name = "Physical (Secure)",
- .id = 4,
+ .id = mem_space_id,
.type = 18,
.bits_per_mau = 8,
.invariance = 1,
@@ -1244,14 +1227,44 @@ int mcd_arm_store_mem_spaces(CPUState *cpu, GArray *memspaces)
.min_addr = 0,
.max_addr = -1,
.supported_access_options = 0,
+ .is_secure = false,
};
- g_array_append_vals(memspaces, (gconstpointer)&space4, 1);
+ 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,
+ };
+ 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,
+ };
+ g_array_append_vals(memspaces, (gconstpointer)&phys_secure, 1);
}
-
/* TODO: get dynamically how the per (CP15) space is called */
- mcd_mem_space_st space5 = {
+ mem_space_id++;
+ mcd_mem_space_st gpr = {
.name = "GPR Registers",
- .id = 5,
+ .id = mem_space_id,
.type = 1,
.bits_per_mau = 8,
.invariance = 1,
@@ -1260,10 +1273,11 @@ int mcd_arm_store_mem_spaces(CPUState *cpu, GArray *memspaces)
.max_addr = -1,
.supported_access_options = 0,
};
- g_array_append_vals(memspaces, (gconstpointer)&space5, 1);
- mcd_mem_space_st space6 = {
+ g_array_append_vals(memspaces, (gconstpointer)&gpr, 1);
+ mem_space_id++;
+ mcd_mem_space_st cpr = {
.name = "CP15 Registers",
- .id = 6,
+ .id = mem_space_id,
.type = 1,
.bits_per_mau = 8,
.invariance = 1,
@@ -1272,7 +1286,7 @@ int mcd_arm_store_mem_spaces(CPUState *cpu, GArray *memspaces)
.max_addr = -1,
.supported_access_options = 0,
};
- g_array_append_vals(memspaces, (gconstpointer)&space6, 1);
+ g_array_append_vals(memspaces, (gconstpointer)&cpr, 1);
return 0;
}
@@ -2022,10 +2036,20 @@ int mcd_write_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len)
void handle_read_memory(GArray *params, void *user_ctx)
{
uint32_t cpu_id = get_param(params, 0)->cpu_id;
- uint64_t mem_address = get_param(params, 1)->data_uint64_t;
- uint32_t len = get_param(params, 2)->data_uint32_t;
+ 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;
CPUState *cpu = mcd_get_cpu(cpu_id);
+ /* check if the mem space is secure */
+ 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);
+ if (arm_mcd_set_scr(cpu, space.is_secure)) {
+ mcd_put_packet(TCP_EXECUTION_ERROR);
+ return;
+ }
+ /* read memory */
g_byte_array_set_size(mcdserver_state.mem_buf, len);
if (mcd_read_memory(cpu, mem_address, mcdserver_state.mem_buf->data,
mcdserver_state.mem_buf->len) != 0) {
@@ -2040,10 +2064,19 @@ void handle_read_memory(GArray *params, void *user_ctx)
void handle_write_memory(GArray *params, void *user_ctx)
{
uint32_t cpu_id = get_param(params, 0)->cpu_id;
- uint64_t mem_address = get_param(params, 1)->data_uint64_t;
- uint32_t len = get_param(params, 2)->data_uint32_t;
-
+ 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;
CPUState *cpu = mcd_get_cpu(cpu_id);
+ /* check if the mem space is secure */
+ 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);
+ if (arm_mcd_set_scr(cpu, space.is_secure)) {
+ mcd_put_packet(TCP_EXECUTION_ERROR);
+ return;
+ }
+ /* read memory */
mcd_hextomem(mcdserver_state.mem_buf, mcdserver_state.str_buf->str, len);
if (mcd_write_memory(cpu, mem_address,
mcdserver_state.mem_buf->data, len) != 0) {
@@ -58,7 +58,7 @@ enum {
/* misc */
#define QUERY_TOTAL_NUMBER 12
-#define CMD_SCHEMA_LENGTH 5
+#define CMD_SCHEMA_LENGTH 6
#define MCD_SYSTEM_NAME "qemu-system"
/* tcp query packet values templates */
@@ -185,6 +185,8 @@ typedef struct mcd_mem_space_st {
uint64_t min_addr;
uint64_t max_addr;
uint32_t supported_access_options;
+ /* internal */
+ bool is_secure;
} mcd_mem_space_st;
typedef struct mcd_reg_group_st {
@@ -330,3 +330,17 @@ uint16_t arm_mcd_get_opcode(CPUState *cs, uint32_t n)
}
return 0;
}
+
+int arm_mcd_set_scr(CPUState *cs, bool secure)
+{
+ /* swtiches between secure and non secure mode */
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+ /* set bit 0 to 1 if non secure, to 0 if secure*/
+ if (secure) {
+ env->cp15.scr_el3 &= 0xFFFFFFFE;
+ } else {
+ env->cp15.scr_el3 |= 1;
+ }
+ return 0;
+}
@@ -16,5 +16,6 @@ int arm_mcd_read_register(CPUState *cs, GByteArray *mem_buf, uint8_t reg_type,
int arm_mcd_write_register(CPUState *cs, GByteArray *mem_buf, uint8_t reg_type,
uint32_t n);
uint16_t arm_mcd_get_opcode(CPUState *cs, uint32_t n);
+int arm_mcd_set_scr(CPUState *cs, bool secure);
#endif /* ARM_MCDSTUB_H */
--
2.34.1
From 64b4aacccd13fe0e642b5c233adc457bbc4c0c9e Mon Sep 17 00:00:00 2001
From: Nicolas Eder <nicolas.eder@lauterbach.com>
Date: Sat, 22 Jul 2023 16:55:45 +0200
Subject: [PATCH 22/29] transitioning to unsinged integers in TCP packets and
removing MCD-API-specific terms
Signed-off-by: Nicolas Eder <nicolas.eder@lauterbach.com>
---
mcdstub/mcd_shared_defines.h | 8 ++++
mcdstub/mcdstub.c | 74 ++++++++++++++++++++----------------
mcdstub/mcdstub.h | 33 +++++-----------
target/arm/mcdstub.c | 2 +-
4 files changed, 60 insertions(+), 57 deletions(-)
@@ -91,4 +91,12 @@
#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
@@ -1303,12 +1303,15 @@ int init_resets(GArray *resets)
int init_trigger(mcd_trigger_into_st *trigger)
{
- trigger->type = (MCD_TRIG_TYPE_IP | MCD_TRIG_TYPE_READ |
- MCD_TRIG_TYPE_WRITE | MCD_TRIG_TYPE_RW);
- trigger->option = (MCD_TRIG_OPT_DATA_IS_CONDITION);
- trigger->action = (MCD_TRIG_ACTION_DBG_DEBUG);
- /* there is no specific upper limit for trigger */
- trigger->nr_trigger = 0;
+ 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;
}
@@ -1348,9 +1351,9 @@ void handle_query_cores(GArray *params, void *user_ctx)
CPUClass *cc = CPU_GET_CLASS(cpu);
gchar *arch = cc->gdb_arch_name(cpu);
- int nr_cores = cpu->nr_cores;
+ uint32_t nr_cores = cpu->nr_cores;
char device_name[] = DEVICE_NAME_TEMPLATE(arch);
- g_string_printf(mcdserver_state.str_buf, "%s=%s.%s=%s.%s=%d.",
+ 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();
@@ -1576,7 +1579,7 @@ void handle_query_reset_f(GArray *params, void *user_ctx)
}
/* 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=%d.",
+ 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();
}
@@ -1592,13 +1595,13 @@ void handle_query_reset_c(GArray *params, void *user_ctx)
/* indicates this is the last packet */
g_string_printf(mcdserver_state.str_buf, "0!");
} else {
- g_string_printf(mcdserver_state.str_buf, "%d!", query_index + 1);
+ 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=%d.",
+ 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();
}
@@ -1652,9 +1655,10 @@ 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=%d.%s=%d.%s=%d.%s=%d.",
+ 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_TYPE, trigger.type,
+ TCP_ARGUMENT_OPTION, trigger.option,
TCP_ARGUMENT_ACTION, trigger.action);
mcd_put_strbuf();
}
@@ -1714,13 +1718,16 @@ void handle_query_mem_spaces_f(GArray *params, void *user_ctx)
/* 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=%d.%s=%d.%s=%d.%s=%d.%s=%d.%s=%ld.%s=%ld.%s=%d.",
- 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);
+ "%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();
}
@@ -1740,20 +1747,23 @@ void handle_query_mem_spaces_c(GArray *params, void *user_ctx)
/* indicates this is the last packet */
g_string_printf(mcdserver_state.str_buf, "0!");
} else {
- g_string_printf(mcdserver_state.str_buf, "%d!", query_index + 1);
+ 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=%d.%s=%d.%s=%d.%s=%d.%s=%d.%s=%ld.%s=%ld.%s=%d.",
- 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);
+ "%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();
}
@@ -1774,7 +1784,7 @@ void handle_query_reg_groups_f(GArray *params, void *user_ctx)
}
/* 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=%d.%s=%s.",
+ 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();
}
@@ -1795,13 +1805,13 @@ void handle_query_reg_groups_c(GArray *params, void *user_ctx)
/* indicates this is the last packet */
g_string_printf(mcdserver_state.str_buf, "0!");
} else {
- g_string_printf(mcdserver_state.str_buf, "%d!", query_index + 1);
+ 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=%d.%s=%s.",
+ 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();
}
@@ -1852,7 +1862,7 @@ void handle_query_regs_c(GArray *params, void *user_ctx)
/* indicates this is the last packet */
g_string_printf(mcdserver_state.str_buf, "0!");
} else {
- g_string_printf(mcdserver_state.str_buf, "%d!", query_index + 1);
+ g_string_printf(mcdserver_state.str_buf, "%u!", query_index + 1);
}
/* 3. send the correct register */
@@ -13,22 +13,6 @@
#define MCD_TRIG_OPT_DATA_IS_CONDITION 0x00000008
#define MCD_TRIG_ACTION_DBG_DEBUG 0x00000001
-typedef uint32_t mcd_trig_type_et;
-/* TODO: replace mcd defines with custom layer */
-enum {
- MCD_TRIG_TYPE_UNDEFINED = 0x00000000,
- MCD_TRIG_TYPE_IP = 0x00000001,
- MCD_TRIG_TYPE_READ = 0x00000002,
- MCD_TRIG_TYPE_WRITE = 0x00000004,
- MCD_TRIG_TYPE_RW = 0x00000008,
- MCD_TRIG_TYPE_NOCYCLE = 0x00000010,
- MCD_TRIG_TYPE_TRIG_BUS = 0x00000020,
- MCD_TRIG_TYPE_COUNTER = 0x00000040,
- MCD_TRIG_TYPE_CUSTOM = 0x00000080,
- MCD_TRIG_TYPE_CUSTOM_LO = 0x00010000,
- MCD_TRIG_TYPE_CUSTOM_HI = 0x40000000,
-};
-
typedef uint32_t mcd_core_event_et;
/* TODO: replace mcd defines with custom layer */
enum {
@@ -60,6 +44,7 @@ enum {
#define QUERY_TOTAL_NUMBER 12
#define CMD_SCHEMA_LENGTH 6
#define MCD_SYSTEM_NAME "qemu-system"
+#define ARGUMENT_STRING_LENGTH 64
/* tcp query packet values templates */
#define DEVICE_NAME_TEMPLATE(s) "qemu-" #s "-device"
@@ -126,9 +111,9 @@ typedef struct breakpoint_st {
} breakpoint_st;
typedef struct mcd_trigger_into_st {
- uint32_t type;
- uint32_t option;
- uint32_t action;
+ char type[ARGUMENT_STRING_LENGTH];
+ char option[ARGUMENT_STRING_LENGTH];
+ char action[ARGUMENT_STRING_LENGTH];
uint32_t nr_trigger;
} mcd_trigger_into_st;
@@ -195,15 +180,15 @@ typedef struct mcd_reg_group_st {
} mcd_reg_group_st;
typedef struct xml_attrib {
- char argument[64];
- char value[64];
+ char argument[ARGUMENT_STRING_LENGTH];
+ char value[ARGUMENT_STRING_LENGTH];
} xml_attrib;
typedef struct mcd_reg_st {
/* xml info */
- char name[64];
- char group[64];
- char type[64];
+ 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 */
@@ -333,7 +333,7 @@ uint16_t arm_mcd_get_opcode(CPUState *cs, uint32_t n)
int arm_mcd_set_scr(CPUState *cs, bool secure)
{
- /* swtiches between secure and non secure mode */
+ /* switches between secure and non secure mode */
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
/* set bit 0 to 1 if non secure, to 0 if secure*/
--
2.34.1
From 863b297e6e58d285098ca9d21f4a353b4b9658e7 Mon Sep 17 00:00:00 2001
From: Nicolas Eder <nicolas.eder@lauterbach.com>
Date: Wed, 9 Aug 2023 11:26:16 +0200
Subject: [PATCH 23/29] moved all ARM code to the ARM mcdstub and added now
commom header file
Signed-off-by: Nicolas Eder <nicolas.eder@lauterbach.com>
---
mcdstub/mcdstub.c | 244 ++-------------------------------------
mcdstub/mcdstub.h | 64 +---------
mcdstub/mcdstub_common.h | 46 ++++++++
target/arm/mcdstub.c | 231 ++++++++++++++++++++++++++++++++++++
target/arm/mcdstub.h | 22 ++++
5 files changed, 310 insertions(+), 297 deletions(-)
create mode 100644 mcdstub/mcdstub_common.h
@@ -1192,104 +1192,6 @@ int int_cmp(gconstpointer a, gconstpointer b)
}
}
-int mcd_arm_store_mem_spaces(CPUState *cpu, GArray *memspaces)
-{
- int nr_address_spaces = cpu->num_ases;
- uint32_t mem_space_id = 0;
-
- /*
- * TODO: atm we can only access physical memory addresses,
- * but trace32 needs fake locical spaces to work with
- */
-
- 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,
- };
- 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,
- };
- 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,
- };
- 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,
- };
- g_array_append_vals(memspaces, (gconstpointer)&phys_secure, 1);
- }
- /* TODO: get dynamically how the per (CP15) space is called */
- 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 init_resets(GArray *resets)
{
mcd_reset_st system_reset = { .id = 0, .name = RESET_SYSTEM};
@@ -1360,138 +1262,6 @@ void handle_query_cores(GArray *params, void *user_ctx)
g_free(arch);
}
-int mcd_arm_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 = xml_builtin[i][0];
- 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 */
- xml_content = xml_builtin[i][1];
- parse_reg_xml(xml_content, strlen(xml_content), registers,
- MCD_ARM_REG_TYPE_GPR);
- return 0;
-}
-
-int mcd_arm_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;
- int i = 0;
- uint8_t reg_type;
-
- /* iterate over all gdb xml files*/
- GDBRegisterState *r;
- for (r = cpu->gdb_regs; r; r = r->next) {
- 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 */
- for (i = 0; ; i++) {
- current_xml_filename = xml_builtin[i][0];
- 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 = xml_builtin[i][1];
- /* 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);
- }
- return 0;
-}
-
-int mcd_arm_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));
- current_register->id = 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;
-}
-
void handle_open_core(GArray *params, void *user_ctx)
{
uint32_t cpu_id = get_param(params, 0)->cpu_id;
@@ -1506,28 +1276,28 @@ void handle_open_core(GArray *params, void *user_ctx)
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, "arm") == 0) {
+ 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 = mcd_arm_store_mem_spaces(cpu, memspaces);
+ return_value = arm_mcd_store_mem_spaces(cpu, memspaces);
if (return_value != 0) {
g_assert_not_reached();
}
/* 2. parse core xml */
- return_value = mcd_arm_parse_core_xml_file(cc, reggroups,
+ 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 = mcd_arm_parse_general_xml_files(cpu, reggroups,
+ 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 = mcd_arm_get_additional_register_info(reggroups,
+ return_value = arm_mcd_get_additional_register_info(reggroups,
registers, cpu);
if (return_value != 0) {
g_assert_not_reached();
@@ -1939,7 +1709,7 @@ int mcd_read_register(CPUState *cpu, GByteArray *buf, int reg)
/* 2. read register */
CPUClass *cc = CPU_GET_CLASS(cpu);
gchar *arch = cc->gdb_arch_name(cpu);
- if (strcmp(arch, "arm") == 0) {
+ if (strcmp(arch, MCDSTUB_ARCH_ARM) == 0) {
g_free(arch);
return arm_mcd_read_register(cpu, buf, reg_type, internal_id);
} else {
@@ -1959,7 +1729,7 @@ int mcd_write_register(CPUState *cpu, GByteArray *buf, int reg)
/* 2. write register */
CPUClass *cc = CPU_GET_CLASS(cpu);
gchar *arch = cc->gdb_arch_name(cpu);
- if (strcmp(arch, "arm") == 0) {
+ if (strcmp(arch, MCDSTUB_ARCH_ARM) == 0) {
g_free(arch);
return arm_mcd_write_register(cpu, buf, reg_type, internal_id);
} else {
@@ -4,8 +4,7 @@
#include "exec/cpu-common.h"
#include "chardev/char.h"
#include "hw/core/cpu.h"
-/* just used for the register xml files */
-#include "exec/gdbstub.h"
+#include "mcdstub_common.h"
#define MAX_PACKET_LENGTH 1024
@@ -44,7 +43,9 @@ enum {
#define QUERY_TOTAL_NUMBER 12
#define CMD_SCHEMA_LENGTH 6
#define MCD_SYSTEM_NAME "qemu-system"
-#define ARGUMENT_STRING_LENGTH 64
+
+/* supported architectures */
+#define MCDSTUB_ARCH_ARM "arm"
/* tcp query packet values templates */
#define DEVICE_NAME_TEMPLATE(s) "qemu-" #s "-device"
@@ -63,16 +64,6 @@ enum {
#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 GDBRegisterState {
- /* needed for the used gdb functions */
- int base_reg;
- int num_regs;
- gdb_get_reg_cb get_reg;
- gdb_set_reg_cb set_reg;
- const char *xml;
- struct GDBRegisterState *next;
-} GDBRegisterState;
-
typedef struct MCDProcess {
uint32_t pid;
bool attached;
@@ -160,48 +151,11 @@ typedef struct MCDState {
/* lives in main mcdstub.c */
extern MCDState mcdserver_state;
-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;
-} mcd_mem_space_st;
-
-typedef struct mcd_reg_group_st {
- const char *name;
- uint32_t id;
-} mcd_reg_group_st;
-
typedef struct xml_attrib {
char argument[ARGUMENT_STRING_LENGTH];
char value[ARGUMENT_STRING_LENGTH];
} xml_attrib;
-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_reset_st {
const char *name;
uint8_t id;
@@ -291,8 +245,6 @@ void handle_query_mem_spaces_c(GArray *params, void *user_ctx);
void handle_query_regs_f(GArray *params, void *user_ctx);
void handle_query_regs_c(GArray *params, void *user_ctx);
void handle_open_server(GArray *params, void *user_ctx);
-void parse_reg_xml(const char *xml, int size, GArray* registers,
- uint8_t reg_type);
void handle_reset(GArray *params, void *user_ctx);
void handle_query_state(GArray *params, void *user_ctx);
void handle_read_register(GArray *params, void *user_ctx);
@@ -308,14 +260,6 @@ void handle_breakpoint_remove(GArray *params, void *user_ctx);
int mcd_breakpoint_insert(CPUState *cpu, int type, vaddr addr);
int mcd_breakpoint_remove(CPUState *cpu, int type, vaddr addr);
-/* arm specific functions */
-int mcd_arm_store_mem_spaces(CPUState *cpu, GArray *memspaces);
-int mcd_arm_parse_core_xml_file(CPUClass *cc, GArray *reggroups,
- GArray *registers, int *current_group_id);
-int mcd_arm_parse_general_xml_files(CPUState *cpu, GArray* reggroups,
- GArray *registers, int *current_group_id);
-int mcd_arm_get_additional_register_info(GArray *reggroups, GArray *registers,
- CPUState *cpu);
/* sycall handling */
void mcd_syscall_reset(void);
void mcd_disable_syscalls(void);
new file mode 100644
@@ -0,0 +1,46 @@
+#ifndef MCDSTUB_COMMON_H
+#define MCDSTUB_COMMON_H
+
+#define ARGUMENT_STRING_LENGTH 64
+
+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;
+} 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;
+
+void parse_reg_xml(const char *xml, int size, GArray* registers,
+ uint8_t reg_type);
+
+#endif /* MCDSTUB_COMMON_H */
@@ -344,3 +344,234 @@ int arm_mcd_set_scr(CPUState *cs, bool secure)
}
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;
+
+ /*
+ * TODO: atm we can only access physical memory addresses,
+ * but trace32 needs fake locical spaces to work with
+ */
+
+ 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,
+ };
+ 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,
+ };
+ 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,
+ };
+ 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,
+ };
+ g_array_append_vals(memspaces, (gconstpointer)&phys_secure, 1);
+ }
+ /* TODO: get dynamically how the per (CP15) space is called */
+ 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 = xml_builtin[i][0];
+ 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 */
+ xml_content = xml_builtin[i][1];
+ parse_reg_xml(xml_content, strlen(xml_content), registers,
+ MCD_ARM_REG_TYPE_GPR);
+ 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;
+ int i = 0;
+ uint8_t reg_type;
+
+ /* iterate over all gdb xml files*/
+ GDBRegisterState *r;
+ for (r = cpu->gdb_regs; r; r = r->next) {
+ 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 */
+ for (i = 0; ; i++) {
+ current_xml_filename = xml_builtin[i][0];
+ 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 = xml_builtin[i][1];
+ /* 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);
+ }
+ 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));
+ current_register->id = 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;
+}
+
@@ -1,6 +1,21 @@
#ifndef ARM_MCDSTUB_H
#define ARM_MCDSTUB_H
+#include "hw/core/cpu.h"
+#include "mcdstub/mcdstub_common.h"
+/* just used for the register xml files */
+#include "exec/gdbstub.h"
+
+typedef struct GDBRegisterState {
+ /* needed for the used gdb functions */
+ int base_reg;
+ int num_regs;
+ gdb_get_reg_cb get_reg;
+ gdb_set_reg_cb set_reg;
+ const char *xml;
+ struct GDBRegisterState *next;
+} GDBRegisterState;
+
/* ids for each different type of register */
enum {
MCD_ARM_REG_TYPE_GPR,
@@ -17,5 +32,12 @@ int arm_mcd_write_register(CPUState *cs, GByteArray *mem_buf, uint8_t reg_type,
uint32_t n);
uint16_t arm_mcd_get_opcode(CPUState *cs, uint32_t n);
int arm_mcd_set_scr(CPUState *cs, bool secure);
+int arm_mcd_store_mem_spaces(CPUState *cpu, GArray *memspaces);
+int arm_mcd_parse_core_xml_file(CPUClass *cc, GArray *reggroups,
+ GArray *registers, int *current_group_id);
+int arm_mcd_parse_general_xml_files(CPUState *cpu, GArray* reggroups,
+ GArray *registers, int *current_group_id);
+int arm_mcd_get_additional_register_info(GArray *reggroups, GArray *registers,
+ CPUState *cpu);
#endif /* ARM_MCDSTUB_H */
--
2.34.1
From 011ef906c4fbe79c188caad6591ddcd30b90026f Mon Sep 17 00:00:00 2001
From: Nicolas Eder <nicolas.eder@lauterbach.com>
Date: Fri, 18 Aug 2023 15:56:21 +0200
Subject: [PATCH 24/29] step and go handlers now propperly perform global
operations
Signed-off-by: Nicolas Eder <nicolas.eder@lauterbach.com>
---
mcdstub/mcd_shared_defines.h | 2 ++
mcdstub/mcdstub.c | 35 +++++++++++++++++++++--------------
2 files changed, 23 insertions(+), 14 deletions(-)
@@ -78,6 +78,8 @@
/* for packets sent to qemu */
#define ARGUMENT_SEPARATOR ';'
+#define NEGATIVE_FLAG 0
+#define POSITIVE_FLAG 1
/* core states */
#define CORE_STATE_RUNNING "running"
@@ -435,7 +435,7 @@ int mcd_handle_packet(const char *line_buf)
};
go_cmd_desc.cmd = (char[2]) { TCP_CHAR_GO, '\0' };
strcpy(go_cmd_desc.schema,
- (char[2]) { ARG_SCHEMA_CORENUM, '\0' });
+ (char[3]) { ARG_SCHEMA_INT, ARG_SCHEMA_CORENUM, '\0' });
cmd_parser = &go_cmd_desc;
}
break;
@@ -446,7 +446,7 @@ int mcd_handle_packet(const char *line_buf)
};
step_cmd_desc.cmd = (char[2]) { TCP_CHAR_STEP, '\0' };
strcpy(step_cmd_desc.schema,
- (char[2]) { ARG_SCHEMA_CORENUM, '\0' });
+ (char[3]) { ARG_SCHEMA_INT, ARG_SCHEMA_CORENUM, '\0' });
cmd_parser = &step_cmd_desc;
}
break;
@@ -608,28 +608,35 @@ int mcd_handle_packet(const char *line_buf)
void handle_vm_start(GArray *params, void *user_ctx)
{
- /* TODO: add partial restart with arguments and so on */
- uint32_t cpu_id = get_param(params, 0)->cpu_id;
- CPUState *cpu = mcd_get_cpu(cpu_id);
- mcd_cpu_start(cpu);
+ 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)
{
- /* TODO: add partial restart with arguments and so on */
- uint32_t cpu_id = get_param(params, 0)->cpu_id;
-
- CPUState *cpu = mcd_get_cpu(cpu_id);
- int return_value = mcd_cpu_sstep(cpu);
- if (return_value != 0) {
- g_assert_not_reached();
+ 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 partial stop with arguments and so on */
+ /* TODO: add core dependant break option */
mcd_vm_stop();
}
--
2.34.1
From 7ea2961119797d28034d5d1114a9e78e35e2bc68 Mon Sep 17 00:00:00 2001
From: Nicolas Eder <nicolas.eder@lauterbach.com>
Date: Tue, 22 Aug 2023 11:59:42 +0200
Subject: [PATCH 25/29] Doxygen documentation added
Signed-off-by: Nicolas Eder <nicolas.eder@lauterbach.com>
---
include/exec/mcdstub.h | 7 -
include/mcdstub/syscalls.h | 2 +-
mcdstub/mcd_shared_defines.h | 1 +
mcdstub/mcdstub.c | 61 ++--
mcdstub/mcdstub.h | 579 ++++++++++++++++++++++++++++++++++-
mcdstub/mcdstub_common.h | 18 ++
target/arm/mcdstub.c | 6 -
target/arm/mcdstub.h | 105 +++++++
8 files changed, 709 insertions(+), 70 deletions(-)
@@ -3,13 +3,6 @@
#define DEFAULT_MCDSTUB_PORT "1235"
-/* breakpoint defines */
-#define MCD_BREAKPOINT_SW 0
-#define MCD_BREAKPOINT_HW 1
-#define MCD_WATCHPOINT_WRITE 2
-#define MCD_WATCHPOINT_READ 3
-#define MCD_WATCHPOINT_ACCESS 4
-
/**
* mcd_tcp_server_start: start the tcp server to connect via mcd
* @device: connection spec for mcd
@@ -3,4 +3,4 @@
typedef void (*gdb_syscall_complete_cb)(CPUState *cpu, uint64_t ret, int err);
-#endif /* _SYSCALLS_H_ */
+#endif /* _MCD_SYSCALLS_H_ */
@@ -38,6 +38,7 @@
/* 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"
@@ -218,12 +218,6 @@ int find_cpu_clusters(Object *child, void *opaque)
s->processes = g_renew(MCDProcess, s->processes, ++s->process_num);
process = &s->processes[s->process_num - 1];
-
- /*
- * GDB process IDs -1 and 0 are reserved. To avoid subtle errors at
- * runtime, we enforce here that the machine does not use a cluster ID
- * that would lead to PID 0.
- */
assert(cluster->cluster_id != UINT32_MAX);
process->pid = cluster->cluster_id + 1;
process->attached = false;
@@ -925,7 +919,7 @@ void mcd_vm_state_change(void *opaque, bool running, RunState state)
int mcd_put_packet(const char *buf)
{
- return mcd_put_packet_binary(buf, strlen(buf), false);
+ return mcd_put_packet_binary(buf, strlen(buf));
}
void mcd_put_strbuf(void)
@@ -933,7 +927,7 @@ void mcd_put_strbuf(void)
mcd_put_packet(mcdserver_state.str_buf->str);
}
-int mcd_put_packet_binary(const char *buf, int len, bool dump)
+int mcd_put_packet_binary(const char *buf, int len)
{
for (;;) {
g_byte_array_set_size(mcdserver_state.last_packet, 0);
@@ -999,12 +993,12 @@ MCDProcess *mcd_get_process(uint32_t pid)
return NULL;
}
-CPUState *mcd_get_cpu(uint32_t i_cpu_index)
+CPUState *mcd_get_cpu(uint32_t cpu_index)
{
CPUState *cpu = first_cpu;
while (cpu) {
- if (cpu->cpu_index == i_cpu_index) {
+ if (cpu->cpu_index == cpu_index) {
return cpu;
}
cpu = mcd_next_attached_cpu(cpu);
@@ -1344,15 +1338,13 @@ void handle_open_core(GArray *params, void *user_ctx)
void handle_query_reset_f(GArray *params, void *user_ctx)
{
- /* TODO: vull reset over the qemu monitor */
-
/* 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!");
+ g_string_printf(mcdserver_state.str_buf, "0%s", QUERY_END_INDEX);
} else {
- g_string_printf(mcdserver_state.str_buf, "1!");
+ 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);
@@ -1370,7 +1362,7 @@ void handle_query_reset_c(GArray *params, void *user_ctx)
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!");
+ g_string_printf(mcdserver_state.str_buf, "0%s", QUERY_END_INDEX);
} else {
g_string_printf(mcdserver_state.str_buf, "%u!", query_index + 1);
}
@@ -1487,9 +1479,9 @@ void handle_query_mem_spaces_f(GArray *params, void *user_ctx)
int nb_groups = memspaces->len;
if (nb_groups == 1) {
/* indicates this is the last packet */
- g_string_printf(mcdserver_state.str_buf, "0!");
+ g_string_printf(mcdserver_state.str_buf, "0%s", QUERY_END_INDEX);
} else {
- g_string_printf(mcdserver_state.str_buf, "1!");
+ g_string_printf(mcdserver_state.str_buf, "1%s", QUERY_END_INDEX);
}
/* 3. send data */
@@ -1522,7 +1514,7 @@ void handle_query_mem_spaces_c(GArray *params, void *user_ctx)
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!");
+ g_string_printf(mcdserver_state.str_buf, "0%s", QUERY_END_INDEX);
} else {
g_string_printf(mcdserver_state.str_buf, "%u!", query_index + 1);
}
@@ -1555,9 +1547,9 @@ void handle_query_reg_groups_f(GArray *params, void *user_ctx)
int nb_groups = reggroups->len;
if (nb_groups == 1) {
/* indicates this is the last packet */
- g_string_printf(mcdserver_state.str_buf, "0!");
+ g_string_printf(mcdserver_state.str_buf, "0%s", QUERY_END_INDEX);
} else {
- g_string_printf(mcdserver_state.str_buf, "1!");
+ 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);
@@ -1580,7 +1572,7 @@ void handle_query_reg_groups_c(GArray *params, void *user_ctx)
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!");
+ g_string_printf(mcdserver_state.str_buf, "0%s", QUERY_END_INDEX);
} else {
g_string_printf(mcdserver_state.str_buf, "%u!", query_index + 1);
}
@@ -1604,9 +1596,9 @@ void handle_query_regs_f(GArray *params, void *user_ctx)
int nb_regs = registers->len;
if (nb_regs == 1) {
/* indicates this is the last packet */
- g_string_printf(mcdserver_state.str_buf, "0!");
+ g_string_printf(mcdserver_state.str_buf, "0%s", QUERY_END_INDEX);
} else {
- g_string_printf(mcdserver_state.str_buf, "1!");
+ 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);
@@ -1637,7 +1629,7 @@ void handle_query_regs_c(GArray *params, void *user_ctx)
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!");
+ g_string_printf(mcdserver_state.str_buf, "0%s", QUERY_END_INDEX);
} else {
g_string_printf(mcdserver_state.str_buf, "%u!", query_index + 1);
}
@@ -1672,19 +1664,8 @@ void handle_query_state(GArray *params, void *user_ctx)
* get state info
*/
mcd_cpu_state_st state_info = mcdserver_state.cpu_state;
- mcd_core_event_et event = MCD_CORE_EVENT_NONE;
- if (state_info.memory_changed) {
- event = event | MCD_CORE_EVENT_MEMORY_CHANGE;
- state_info.memory_changed = false;
- }
- if (state_info.registers_changed) {
- event = event | MCD_CORE_EVENT_REGISTER_CHANGE;
- state_info.registers_changed = false;
- }
- if (state_info.target_was_stopped) {
- event = event | MCD_CORE_EVENT_STOPPED;
- state_info.target_was_stopped = false;
- }
+ /* 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.",
@@ -1863,7 +1844,7 @@ void handle_write_memory(GArray *params, void *user_ctx)
mcd_put_packet(TCP_EXECUTION_ERROR);
return;
}
- /* read memory */
+ /* write memory */
mcd_hextomem(mcdserver_state.mem_buf, mcdserver_state.str_buf->str, len);
if (mcd_write_memory(cpu, mem_address,
mcdserver_state.mem_buf->data, len) != 0) {
@@ -1879,7 +1860,7 @@ int mcd_breakpoint_insert(CPUState *cpu, int type, vaddr addr)
int bp_type = 0;
CPUClass *cc = CPU_GET_CLASS(cpu);
if (cc->gdb_stop_before_watchpoint) {
- //bp_type |= BP_STOP_BEFORE_ACCESS;
+ /* bp_type |= BP_STOP_BEFORE_ACCESS; */
}
int return_value = 0;
switch (type) {
@@ -1909,7 +1890,7 @@ int mcd_breakpoint_remove(CPUState *cpu, int type, vaddr addr)
int bp_type = 0;
CPUClass *cc = CPU_GET_CLASS(cpu);
if (cc->gdb_stop_before_watchpoint) {
- //bp_type |= BP_STOP_BEFORE_ACCESS;
+ /* bp_type |= BP_STOP_BEFORE_ACCESS; */
}
int return_value = 0;
switch (type) {
@@ -12,20 +12,6 @@
#define MCD_TRIG_OPT_DATA_IS_CONDITION 0x00000008
#define MCD_TRIG_ACTION_DBG_DEBUG 0x00000001
-typedef uint32_t mcd_core_event_et;
-/* TODO: replace mcd defines with custom layer */
-enum {
- MCD_CORE_EVENT_NONE = 0x00000000,
- MCD_CORE_EVENT_MEMORY_CHANGE = 0x00000001,
- MCD_CORE_EVENT_REGISTER_CHANGE = 0x00000002,
- MCD_CORE_EVENT_TRACE_CHANGE = 0x00000004,
- MCD_CORE_EVENT_TRIGGER_CHANGE = 0x00000008,
- MCD_CORE_EVENT_STOPPED = 0x00000010,
- MCD_CORE_EVENT_CHL_PENDING = 0x00000020,
- MCD_CORE_EVENT_CUSTOM_LO = 0x00010000,
- MCD_CORE_EVENT_CUSTOM_HI = 0x40000000,
-};
-
/* schema defines */
#define ARG_SCHEMA_QRYHANDLE 'q'
#define ARG_SCHEMA_STRING 's'
@@ -187,88 +173,649 @@ static inline int tohex(int v)
void mcd_sigterm_handler(int signal);
#endif
+/**
+ * \defgroup mcdstub Main mcdstub functions
+ * All architecture independent mcdstub functions.
+ */
+
+/**
+ * \addtogroup mcdstub
+ * @{
+ */
+
+/**
+ * \brief 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 \ref
+ * init_query_cmds_table.
+ */
void mcd_init_mcdserver_state(void);
+/**
+ * \brief 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.
+ * @param[out] mcd_query_cmds_table Lookup table with all query commands.
+ */
void init_query_cmds_table(MCDCmdParseEntry *mcd_query_cmds_table);
+/**
+ * \brief 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".
+ * @param[out] resets GArray with possible resets.
+ */
int init_resets(GArray *resets);
+/**
+ * \brief Initializes the trigger info.
+ *
+ * This function adds the types of trigger, their possible options and actions
+ * to the trigger struct.
+ * @param[out] trigger Struct with all trigger info.
+ */
int init_trigger(mcd_trigger_into_st *trigger);
+/**
+ * \brief Resets the mcdserver_state struct.
+ *
+ * This function deletes all processes connected to the mcdserver_state.
+ */
void reset_mcdserver_state(void);
+/**
+ * \brief Sorts all processes and calls \ref mcd_create_default_process.
+ *
+ * This function sorts all connected processes with the qsort function.
+ * Afterwards, it creates a new process with \ref mcd_create_default_process.
+ * @param[in] s A MCDState object.
+ */
void create_processes(MCDState *s);
+/**
+ * \brief Creates a default process for debugging.
+ *
+ * This function creates a new, not yet attached, process with an ID one above
+ * the previous maximum ID.
+ * @param[in] s A MCDState object.
+ */
void mcd_create_default_process(MCDState *s);
+/**
+ * \brief 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);
+/**
+ * \brief 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.
+ * @param[in] a Process a.
+ * @param[in] b Process b.
+ */
int pid_order(const void *a, const void *b);
+/**
+ * \brief Returns the maximum packet length of a TCP packet.
+ */
int mcd_chr_can_receive(void *opaque);
+/**
+ * \brief Handles receiving a TCP packet.
+ *
+ * This function gets called by QEMU when a TCP packet is received.
+ * It iterates over that packet an calls \ref mcd_read_byte for each char
+ * of the packet.
+ * @param[in] buf Content of the packet.
+ * @param[in] size Length of the packet.
+ */
void mcd_chr_receive(void *opaque, const uint8_t *buf, int size);
+/**
+ * \brief 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.
+ * @param[in] event Type of event.
+ */
void mcd_chr_event(void *opaque, QEMUChrEvent event);
+/**
+ * \brief Returns true if debugging the selected accelerator is supported.
+ */
bool mcd_supports_guest_debug(void);
+/**
+ * \brief 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
+ * \c RUN_STATE_DEBUG it collects additional data on what watchpoint was hit.
+ * This function also resets the singlestep behavior.
+ * @param[in] running True if he VM is running.
+ * @param[in] state The new (and active) VM run state.
+ */
void mcd_vm_state_change(void *opaque, bool running, RunState state);
+/**
+ * \brief Calls \ref mcd_put_packet_binary with buf and length of buf.
+ *
+ * @param[in] buf TCP packet data.
+ */
int mcd_put_packet(const char *buf);
-int mcd_put_packet_binary(const char *buf, int len, bool dump);
+/**
+ * \brief 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 \ref mcd_put_buffer function.
+ * @param[in] buf TCP packet data.
+ * @param[in] len TCP packet length.
+ */
+int mcd_put_packet_binary(const char *buf, int len);
+/**
+ * \brief Always returns true, currently needed for copatibility.
+ */
bool mcd_got_immediate_ack(void);
+/**
+ * \brief Sends the buf as TCP packet with qemu_chr_fe_write_all.
+ *
+ * @param[in] buf TCP packet data.
+ * @param[in] len TCP packet length.
+ */
void mcd_put_buffer(const uint8_t *buf, int len);
+/**
+ * \brief Returns the process of the provided CPU.
+ *
+ * @param[in] cpu The CPU state.
+ */
MCDProcess *mcd_get_cpu_process(CPUState *cpu);
+/**
+ * \brief Returns the process ID of the provided CPU.
+ *
+ * @param[in] cpu The CPU state.
+ */
uint32_t mcd_get_cpu_pid(CPUState *cpu);
+/**
+ * \brief Returns the process of the provided pid.
+ *
+ * @param[in] pid The process ID.
+ */
MCDProcess *mcd_get_process(uint32_t pid);
+/**
+ * \brief Returns the first CPU with an attached process.
+ */
CPUState *mcd_first_attached_cpu(void);
+/**
+ * \brief Returns the first CPU with an attached process starting after the
+ * provided cpu.
+ *
+ * @param[in] cpu The CPU to start from.
+ */
CPUState *mcd_next_attached_cpu(CPUState *cpu);
+/**
+ * \brief 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 \ref mcd_handle_packet gets
+ * called.
+ * @param[in] ch Character of the received TCP packet, which should be parsed.
+ */
void mcd_read_byte(uint8_t ch);
+/**
+ * \brief 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 \ref run_cmd_parser.
+ * @param[in] line_buf TCP packet data.
+ */
int mcd_handle_packet(const char *line_buf);
+/**
+ * \brief Calls \ref mcd_put_packet with the str_buf of the mcdserver_state.
+ */
void mcd_put_strbuf(void);
+/**
+ * \brief 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.
+ * @param[in] code An exitcode, which can be used in the future.
+ */
void mcd_exit(int code);
+/**
+ * \brief 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 \ref process_string_cmd. In case this function fails, an empty
+ * TCP packet is sent back the MCD Shared Library.
+ * @param[in] data TCP packet data.
+ * @param[in] cmd Handler function (can be an array of functions).
+ */
void run_cmd_parser(const char *data, const MCDCmdParseEntry *cmd);
+/**
+ * \brief Collects all parameters from the data and calls the correct handler.
+ *
+ * The parameters are extracted with the \ref 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.
+ * @param[in] data TCP packet data.
+ * @param[in] cmds Array of possible commands.
+ * @param[in] 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);
+/**
+ * \brief 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.
+ * @param[in] data TCP packet data.
+ * @param[in] schema List of expected parameters for the packet.
+ * @param[out] params GArray with all extracted parameters.
+ */
int cmd_parse_params(const char *data, const char *schema, GArray *params);
+/**
+ * \brief Handler for the VM start TCP packet.
+ *
+ * Evaluates whether all cores or just a perticular core should get started and
+ * calls \ref mcd_vm_start or \ref mcd_cpu_start respectively.
+ * @param[in] params GArray with all TCP packet parameters.
+ */
void handle_vm_start(GArray *params, void *user_ctx);
+/**
+ * \brief Handler for the VM step TCP packet.
+ *
+ * Calls \ref mcd_cpu_sstep for the CPU which sould be stepped. Stepping all
+ * CPUs is currently not supported.
+ * @param[in] params GArray with all TCP packet parameters.
+ */
void handle_vm_step(GArray *params, void *user_ctx);
+/**
+ * \brief Handler for the VM stop TCP packet.
+ *
+ * Always calls \ref mcd_vm_stop and stops all cores. Stopping individual cores
+ * is currently not supported
+ * @param[in] params GArray with all TCP packet parameters.
+ */
void handle_vm_stop(GArray *params, void *user_ctx);
+/**
+ * \brief Handler for all TCP query packets.
+ *
+ * Calls \ref process_string_cmd with all query functions in the
+ * mcd_query_cmds_table. \ref process_string_cmd then selects the correct one.
+ * This function just passes on the TCP packet data string from the parameters.
+ * @param[in] params GArray with all TCP packet parameters.
+ */
void handle_gen_query(GArray *params, void *user_ctx);
+/**
+ * \brief Returns the internal CPU index plus one.
+ *
+ * @param[in] cpu CPU of interest.
+ */
int mcd_get_cpu_index(CPUState *cpu);
-CPUState *mcd_get_cpu(uint32_t i_cpu_index);
+/**
+ * \brief Returns the CPU the index i_cpu_index.
+ *
+ * @param[in] cpu_index Index of the desired CPU.
+ */
+CPUState *mcd_get_cpu(uint32_t cpu_index);
+/**
+ * \brief 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.
+ * @param[in] params GArray with all TCP packet parameters.
+ */
void handle_query_cores(GArray *params, void *user_ctx);
+/**
+ * \brief Handler for the system query.
+ *
+ * Sends the system name, which is "qemu-system".
+ * @param[in] params GArray with all TCP packet parameters.
+ */
void handle_query_system(GArray *params, void *user_ctx);
+/**
+ * \brief Returns the first CPU in the provided process.
+ *
+ * @param[in] process The process to look in.
+ */
CPUState *get_first_cpu_in_process(MCDProcess *process);
+/**
+ * \brief Returns the CPU with an index equal to the thread_id.
+ *
+ * @param[in] thread_id ID of the desired CPU.
+ */
CPUState *find_cpu(uint32_t thread_id);
+/**
+ * \brief 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.
+ * @param[in] params GArray with all TCP packet parameters.
+ */
void handle_open_core(GArray *params, void *user_ctx);
+/**
+ * \brief Handler for the first reset query.
+ *
+ * This function sends the first reset name and ID.
+ * @param[in] params GArray with all TCP packet parameters.
+ */
void handle_query_reset_f(GArray *params, void *user_ctx);
+/**
+ * \brief 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.
+ * @param[in] params GArray with all TCP packet parameters.
+ */
void handle_query_reset_c(GArray *params, void *user_ctx);
+/**
+ * \brief Handler for closing the MCD server.
+ *
+ * This function detaches the debugger (process) and frees up memory.
+ * Then it start the QEMU VM with \ref mcd_vm_start.
+ * @param[in] params GArray with all TCP packet parameters.
+ */
void handle_close_server(GArray *params, void *user_ctx);
+/**
+ * \brief Handler for closing a core.
+ *
+ * Frees all memory allocated for core specific information. This includes
+ * memory spaces, register groups and registers.
+ * @param[in] params GArray with all TCP packet parameters.
+ */
void handle_close_core(GArray *params, void *user_ctx);
+/**
+ * \brief Handler for trigger query.
+ *
+ * Sends data on the different types of trigger and their options and actions.
+ * @param[in] params GArray with all TCP packet parameters.
+ */
void handle_query_trigger(GArray *params, void *user_ctx);
+/**
+ * \brief Starts all CPUs with the vm_start function.
+ */
void mcd_vm_start(void);
+/**
+ * \brief Starts the selected CPU with the cpu_resume function.
+ *
+ * @param[in] cpu The CPU about to be started.
+ */
void mcd_cpu_start(CPUState *cpu);
+/**
+ * \brief 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.
+ * @param[in] cpu The CPU about to be stepped.
+ */
int mcd_cpu_sstep(CPUState *cpu);
+/**
+ * \brief Brings all CPUs in debug state with the vm_stop function.
+ */
void mcd_vm_stop(void);
+/**
+ * \brief Handler for the first register group query.
+ *
+ * This function sends the first register group name and ID.
+ * @param[in] params GArray with all TCP packet parameters.
+ */
void handle_query_reg_groups_f(GArray *params, void *user_ctx);
+/**
+ * \brief 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.
+ * @param[in] params GArray with all TCP packet parameters.
+ */
void handle_query_reg_groups_c(GArray *params, void *user_ctx);
+/**
+ * \brief Handler for the first memory space query.
+ *
+ * This function sends the first memory space name, ID, type and accessing
+ * options.
+ * @param[in] params GArray with all TCP packet parameters.
+ */
void handle_query_mem_spaces_f(GArray *params, void *user_ctx);
+/**
+ * \brief 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.
+ * @param[in] params GArray with all TCP packet parameters.
+ */
void handle_query_mem_spaces_c(GArray *params, void *user_ctx);
+/**
+ * \brief Handler for the first register query.
+ *
+ * This function sends the first register with all its information.
+ * @param[in] params GArray with all TCP packet parameters.
+ */
void handle_query_regs_f(GArray *params, void *user_ctx);
+/**
+ * \brief 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.
+ * @param[in] params GArray with all TCP packet parameters.
+ */
void handle_query_regs_c(GArray *params, void *user_ctx);
+/**
+ * \brief 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 \ref init_resets and
+ * \reg init_trigger functions. It also send the \c TCP_HANDSHAKE_SUCCESS
+ * packet back to the library to confirm the mcdstub is ready for further
+ * communication.
+ * @param[in] params GArray with all TCP packet parameters.
+ */
void handle_open_server(GArray *params, void *user_ctx);
+/**
+ * \brief Handler for performing resets.
+ *
+ * This function is currently not in use.
+ * @param[in] params GArray with all TCP packet parameters.
+ */
void handle_reset(GArray *params, void *user_ctx);
+/**
+ * \brief 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.
+ * @param[in] params GArray with all TCP packet parameters.
+ */
void handle_query_state(GArray *params, void *user_ctx);
+/**
+ * \brief Handler for reading a register.
+ *
+ * This function calls \ref 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 \ref mcd_memtohex and then send.
+ * @param[in] params GArray with all TCP packet parameters.
+ */
void handle_read_register(GArray *params, void *user_ctx);
+/**
+ * \brief Handler for writing a register.
+ *
+ * This function converts the incoming hex string data into a byte array with
+ * \ref mcd_hextomem. Then it calls \ref mcd_write_register to write to the
+ * register.
+ * @param[in] params GArray with all TCP packet parameters.
+ */
void handle_write_register(GArray *params, void *user_ctx);
+/**
+ * \brief Handler for reading memory.
+ *
+ * First, this function checks whether reading a secure memory space is
+ * requested and changes the access mode with \ref arm_mcd_set_scr.
+ * Then it calls \ref 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 \ref mcd_memtohex and then send.
+ * @param[in] params GArray with all TCP packet parameters.
+ */
void handle_read_memory(GArray *params, void *user_ctx);
+/**
+ * \brief Handler for writing memory.
+ *
+ * First, this function checks whether reading a secure memory space is
+ * requested and changes the access mode with \ref arm_mcd_set_scr.
+ * Then it converts the incoming hex string data into a byte array with
+ * \ref mcd_hextomem. Then it calls \ref mcd_write_memory to write to the
+ * register.
+ * @param[in] params GArray with all TCP packet parameters.
+ */
void handle_write_memory(GArray *params, void *user_ctx);
+/**
+ * \brief 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 \ref arm_mcd_read_register.
+ * @param[in] cpu CPU to which the register belongs.
+ * @param[out] buf Byte array with register data.
+ * @param[in] reg General ID of the register.
+ */
int mcd_read_register(CPUState *cpu, GByteArray *buf, int reg);
+/**
+ * \brief 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 \ref arm_mcd_write_register.
+ * @param[in] cpu CPU to which the register belongs.
+ * @param[in] buf Byte array with register data.
+ * @param[in] reg General ID of the register.
+ */
int mcd_write_register(CPUState *cpu, GByteArray *buf, int reg);
+/**
+ * \brief Reads memory data and stores it into the buf.
+ *
+ * This function calls cpu_memory_rw_debug or if available
+ * memory_rw_debug in read mode and passes on all parameters.
+ * @param[in] cpu CPU to which the memory belongs.
+ * @param[in] addr Address to start reading.
+ * @param[out] buf Byte array with memory data.
+ * @param[in] len Number of bytes to be read.
+ */
int mcd_read_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len);
+/**
+ * \brief Writes data from the buf into the memory.
+ *
+ * This function calls cpu_memory_rw_debug or if available
+ * memory_rw_debug in write mode and passes on all parameters.
+ * @param[in] cpu CPU to which the memory belongs.
+ * @param[in] addr Address to start writing.
+ * @param[in] buf Byte array with memory data.
+ * @param[in] len Number of bytes to be written.
+ */
int mcd_write_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len);
+/**
+ * \brief Handler for inserting a break- or watchpoint.
+ *
+ * This function extracts the CPU, breakpoint type and address from the
+ * parameters and calls \ref mcd_breakpoint_insert to insert the breakpoint.
+ * @param[in] params GArray with all TCP packet parameters.
+ */
void handle_breakpoint_insert(GArray *params, void *user_ctx);
+/**
+ * \brief Handler for inserting a break- or watchpoint.
+ *
+ * This function extracts the CPU, breakpoint type and address from the
+ * parameters and calls \ref mcd_breakpoint_remove to insert the breakpoint.
+ * @param[in] params GArray with all TCP packet parameters.
+ */
void handle_breakpoint_remove(GArray *params, void *user_ctx);
+/**
+ * \brief 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.
+ * @param[in] cpu CPU to which the breakpoint should be added.
+ * @param[in] addr Address of the breakpoint.
+ * @param[in] type Breakpoint type.
+ */
int mcd_breakpoint_insert(CPUState *cpu, int type, vaddr addr);
+/**
+ * \brief 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.
+ * @param[in] cpu CPU from which the breakpoint should be removed.
+ * @param[in] addr Address of the breakpoint.
+ * @param[in] type Breakpoint type.
+ */
int mcd_breakpoint_remove(CPUState *cpu, int type, vaddr addr);
+/** @} */
+
/* sycall handling */
void mcd_syscall_reset(void);
void mcd_disable_syscalls(void);
/* helpers */
+
+/**
+ * \defgroup helperfunctions Helper mcdstub functions
+ * Supporting functions used throughout the mcdstub.
+ */
+
+/**
+ * \addtogroup helperfunctions
+ * @{
+ */
+
+/**
+ * \brief Compares a and b and returns zero if they are equal.
+ *
+ * @param[in] a Pointer to integer a.
+ * @param[in] b Pointer to integer b.
+ */
int int_cmp(gconstpointer a, gconstpointer b);
+/**
+ * \brief Converts a byte array into a hex string.
+ *
+ * @param[in] mem Pointer to byte array.
+ * @param[out] buf Pointer to hex string.
+ * @param[in] len Number of bytes.
+ */
void mcd_memtohex(GString *buf, const uint8_t *mem, int len);
+/**
+ * \brief Converts a hex string into a byte array.
+ *
+ * @param[out] mem Pointer to byte array.
+ * @param[in] buf Pointer to hex string.
+ * @param[in] len Number of bytes.
+ */
void mcd_hextomem(GByteArray *mem, const char *buf, int len);
+/**
+ * \brief Converts a string into a unsigned 64 bit integer.
+ *
+ * @param[in] in Pointer to input string.
+ */
uint64_t atouint64_t(const char *in);
+/**
+ * \brief Converts a string into a unsigned 32 bit integer.
+ *
+ * @param[in] in Pointer to input string.
+ */
uint32_t atouint32_t(const char *in);
+/** @} */
+
#endif /* MCDSTUB_INTERNALS_H */
@@ -40,7 +40,25 @@ typedef struct mcd_reg_group_st {
uint32_t id;
} mcd_reg_group_st;
+/**
+ * \addtogroup mcdstub
+ * @{
+ */
+
+/**
+ * \brief 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.
+ * @param[in] xml String with contents of the XML file.
+ * @param[out] registers GArray with stored registers.
+ * @param[in] reg_type Register type (depending on file).
+ * @param[in] size Number of characters in the xml string.
+ */
void parse_reg_xml(const char *xml, int size, GArray* registers,
uint8_t reg_type);
+/** @} */
+
#endif /* MCDSTUB_COMMON_H */
@@ -350,11 +350,6 @@ int arm_mcd_store_mem_spaces(CPUState *cpu, GArray *memspaces)
int nr_address_spaces = cpu->num_ases;
uint32_t mem_space_id = 0;
- /*
- * TODO: atm we can only access physical memory addresses,
- * but trace32 needs fake locical spaces to work with
- */
-
mem_space_id++;
mcd_mem_space_st non_secure = {
.name = "Non Secure",
@@ -413,7 +408,6 @@ int arm_mcd_store_mem_spaces(CPUState *cpu, GArray *memspaces)
};
g_array_append_vals(memspaces, (gconstpointer)&phys_secure, 1);
}
- /* TODO: get dynamically how the per (CP15) space is called */
mem_space_id++;
mcd_mem_space_st gpr = {
.name = "GPR Registers",
@@ -25,19 +25,124 @@ enum {
MCD_ARM_REG_TYPE_CPR,
};
+/**
+ * \defgroup armmcdstub ARM mcdstub functions
+ * All ARM specific functions of the mcdstub.
+ */
+
+/**
+ * \addtogroup armmcdstub
+ * @{
+ */
+
+/**
+ * \brief Returns the contents of the desired XML file.
+ *
+ * @param[in] xmlname Name of the desired XML file.
+ * @param[in] cs CPU state.
+ */
const char *arm_mcd_get_dynamic_xml(CPUState *cs, const char *xmlname);
+/**
+ * \brief Calls the correct read function which writes data into the mem_buf.
+ *
+ * Depending on the reg_type of the register one of the following functions
+ * will get called: arm_mcd_read_gpr_register, arm_mcd_read_vfp_register,
+ * arm_mcd_read_vfp_sys_register, arm_mcd_read_mve_register and
+ * arm_mcd_read_cpr_register. In those the data of the requested register will
+ * be stored as byte array into mem_buf. The function returns zero if no bytes
+ * were written
+ * @param[out] mem_buf Byte array for register data.
+ * @param[in] reg_type Type of register.
+ * @param[in] n The register ID within its type.
+ * @param[in] cs CPU state.
+ */
int arm_mcd_read_register(CPUState *cs, GByteArray *mem_buf, uint8_t reg_type,
uint32_t n);
+/**
+ * \brief Calls the correct write function which writes data from the mem_buf.
+ *
+ * Depending on the reg_type of the register one of the following functions
+ * will get called: arm_mcd_write_gpr_register, arm_mcd_write_vfp_register,
+ * arm_mcd_write_vfp_sys_register, arm_mcd_write_mve_register and
+ * arm_mcd_write_cpr_register. In those the register data from mem_buf will
+ * be written. The function returns zero if no bytes were written.
+ * @param[in] mem_buf Byte array for register data.
+ * @param[in] reg_type Type of register.
+ * @param[in] n The register ID within its type.
+ * @param[in] cs CPU state.
+ */
int arm_mcd_write_register(CPUState *cs, GByteArray *mem_buf, uint8_t reg_type,
uint32_t n);
+/**
+ * \brief 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.
+ * @param[in] n The register ID of the CP register.
+ * @param[in] cs CPU state.
+ */
uint16_t arm_mcd_get_opcode(CPUState *cs, uint32_t n);
+/**
+ * \brief Sets the scr_el3 register according to the secure parameter.
+ *
+ * If secure is true, the first bit of the scr_el3 register gets set to 0,
+ * if not it gets set to 1.
+ * @param[in] secure True when secure is requested.
+ * @param[in] cs CPU state.
+ */
int arm_mcd_set_scr(CPUState *cs, bool secure);
+/**
+ * \brief 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.
+ * @param[out] memspaces GArray of memory spaces.
+ * @param[in] cpu CPU state.
+ */
int arm_mcd_store_mem_spaces(CPUState *cpu, GArray *memspaces);
+/**
+ * \brief 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.
+ * @param[out] reggroups GArray of register groups.
+ * @param[out] registers GArray of registers.
+ * @param[in] cc The CPU class.
+ * @param[in,out] 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);
+/**
+ * \brief 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.
+ * @param[out] reggroups GArray of register groups.
+ * @param[out] registers GArray of registers.
+ * @param[in] cpu The CPU state.
+ * @param[in,out] 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);
+/**
+ * \brief Adds additional data to parsed registers.
+ *
+ * This function is called, after \ref arm_mcd_parse_core_xml_file and
+ * \ref arm_mcd_parse_core_xml_file. 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.
+ * @param[in] reggroups GArray of register groups.
+ * @param[in,out] registers GArray of registers.
+ * @param[in] cpu The CPU state.
+ */
int arm_mcd_get_additional_register_info(GArray *reggroups, GArray *registers,
CPUState *cpu);
+/** @} */
+
#endif /* ARM_MCDSTUB_H */
--
2.34.1
From 40cd4a9d23f24b6350ce14fd6377e05a15e9c66b Mon Sep 17 00:00:00 2001
From: Nicolas Eder <nicolas.eder@lauterbach.com>
Date: Mon, 11 Sep 2023 11:36:24 +0200
Subject: [PATCH 26/29] moved all mcd related header files into include/mcdstub
Signed-off-by: Nicolas Eder <nicolas.eder@lauterbach.com>
---
target/arm/mcdstub.h => include/mcdstub/arm_mcdstub.h | 2 +-
{mcdstub => include/mcdstub}/mcd_shared_defines.h | 0
{mcdstub => include/mcdstub}/mcdstub.h | 0
{mcdstub => include/mcdstub}/mcdstub_common.h | 0
mcdstub/mcd_syscalls.c | 2 +-
mcdstub/mcdstub.c | 6 +++---
target/arm/mcdstub.c | 3 ++-
7 files changed, 7 insertions(+), 6 deletions(-)
rename target/arm/mcdstub.h => include/mcdstub/arm_mcdstub.h (99%)
rename {mcdstub => include/mcdstub}/mcd_shared_defines.h (100%)
rename {mcdstub => include/mcdstub}/mcdstub.h (100%)
rename {mcdstub => include/mcdstub}/mcdstub_common.h (100%)
similarity index 99%
rename from target/arm/mcdstub.h
rename to include/mcdstub/arm_mcdstub.h
@@ -2,7 +2,7 @@
#define ARM_MCDSTUB_H
#include "hw/core/cpu.h"
-#include "mcdstub/mcdstub_common.h"
+#include "mcdstub_common.h"
/* just used for the register xml files */
#include "exec/gdbstub.h"
similarity index 100%
rename from mcdstub/mcd_shared_defines.h
rename to include/mcdstub/mcd_shared_defines.h
similarity index 100%
rename from mcdstub/mcdstub.h
rename to include/mcdstub/mcdstub.h
similarity index 100%
rename from mcdstub/mcdstub_common.h
rename to include/mcdstub/mcdstub_common.h
@@ -3,7 +3,7 @@
#include "semihosting/semihost.h"
#include "sysemu/runstate.h"
#include "mcdstub/syscalls.h"
-#include "mcdstub.h"
+#include "mcdstub/mcdstub.h"
typedef struct {
char syscall_buf[256];
@@ -25,11 +25,11 @@
#include "monitor/monitor.h"
/* mcdstub header files */
-#include "mcd_shared_defines.h"
-#include "mcdstub.h"
+#include "mcdstub/mcd_shared_defines.h"
+#include "mcdstub/mcdstub.h"
/* architecture specific stubs */
-#include "target/arm/mcdstub.h"
+#include "mcdstub/arm_mcdstub.h"
typedef struct {
CharBackend chr;
@@ -4,7 +4,8 @@
#include "sysemu/tcg.h"
#include "internals.h"
#include "cpregs.h"
-#include "mcdstub.h"
+
+#include "mcdstub/arm_mcdstub.h"
static inline int mcd_get_reg32(GByteArray *buf, uint32_t val)
{
--
2.34.1
From 5f5795d6aa758484e61ee4bdc2ae210c47e788f2 Mon Sep 17 00:00:00 2001
From: Nicolas Eder <nicolas.eder@lauterbach.com>
Date: Mon, 11 Sep 2023 11:42:29 +0200
Subject: [PATCH 27/29] MCD stub entry added to maintainers file
Signed-off-by: Nicolas Eder <nicolas.eder@lauterbach.com>
---
MAINTAINERS | 9 +++++++++
1 file changed, 9 insertions(+)
@@ -2832,6 +2832,15 @@ F: tests/tcg/multiarch/gdbstub/
F: scripts/feature_to_c.sh
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/exec/mcdstub.h
+F: include/mcdstub/*
+F: target/arm/mcdstub.c
+
Memory API
M: Paolo Bonzini <pbonzini@redhat.com>
M: Peter Xu <peterx@redhat.com>
--
2.34.1
From 834f013b92d7b6b2039b7bd5802fc1072d621963 Mon Sep 17 00:00:00 2001
From: Nicolas Eder <nicolas.eder@lauterbach.com>
Date: Mon, 11 Sep 2023 11:45:51 +0200
Subject: [PATCH 28/29] added description to out-commented gdb function
Signed-off-by: Nicolas Eder <nicolas.eder@lauterbach.com>
---
softmmu/cpus.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
@@ -306,7 +306,10 @@ void cpu_handle_guest_debug(CPUState *cpu)
cpu_single_step(cpu, 0);
}
} else {
- /*gdb_set_stop_cpu(cpu);*/
+ /*
+ * TODO: was gdb_set_stop_cpu(cpu), need to abstract options to
+ * a QOM class.
+ */
qemu_system_debug_request();
cpu->stopped = true;
}
--
2.34.1
From c32c1312e521a7155810e0a00298bdc8be37dd0a Mon Sep 17 00:00:00 2001
From: Nicolas Eder <nicolas.eder@lauterbach.com>
Date: Thu, 21 Sep 2023 15:44:34 +0200
Subject: [PATCH 29/29] introducing the DebugClass. It is used to abstract the
gdb/mcd set_stop_cpu function.
Signed-off-by: Nicolas Eder <nicolas.eder@lauterbach.com>
---
MAINTAINERS | 3 +
debug/debug-common.c | 42 ++++++++++++
debug/debug-gdb.c | 24 +++++++
debug/debug-mcd.c | 25 +++++++
gdbstub/meson.build | 4 +-
gdbstub/softmmu.c | 4 ++
gdbstub/user.c | 2 +
include/exec/gdbstub.h | 5 ++
include/hw/boards.h | 1 +
include/mcdstub/arm_mcdstub.h | 25 +++----
include/mcdstub/mcdstub.h | 122 ++++++++++++++++++----------------
include/qemu/debug.h | 19 ++++++
include/qemu/typedefs.h | 2 +
mcdstub/mcdstub.c | 51 +++++++++-----
mcdstub/meson.build | 4 +-
softmmu/cpus.c | 12 ++--
target/arm/mcdstub.c | 17 +----
17 files changed, 247 insertions(+), 115 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
@@ -2839,6 +2839,9 @@ S: Maintained
F: mcdstub/*
F: include/exec/mcdstub.h
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
new file mode 100644
@@ -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);
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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;
+}
@@ -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', 'softmmu.c'))
+gdb_user_ss.add(files('gdbstub.c', 'user.c', '../debug/debug-gdb.c'))
+gdb_system_ss.add(files('gdbstub.c', 'softmmu.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)
@@ -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;
}
@@ -326,8 +326,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;
}
@@ -51,4 +51,9 @@ bool gdb_has_xml(void);
/* in gdbstub-xml.c, generated by scripts/feature_to_c.sh */
extern const char *const xml_builtin[][2];
+/**
+ * gdb_init_debug_class() - initialize gdb-specific DebugClass
+ */
+void gdb_init_debug_class(void);
+
#endif
@@ -380,6 +380,7 @@ struct MachineState {
CpuTopology smp;
struct NVDIMMState *nvdimms_state;
struct NumaState *numa_state;
+ DebugState *debug_state;
};
#define DEFINE_MACHINE(namestr, machine_initfn) \
@@ -37,14 +37,14 @@ enum {
/**
* \brief Returns the contents of the desired XML file.
- *
+ *
* @param[in] xmlname Name of the desired XML file.
* @param[in] cs CPU state.
*/
const char *arm_mcd_get_dynamic_xml(CPUState *cs, const char *xmlname);
/**
* \brief Calls the correct read function which writes data into the mem_buf.
- *
+ *
* Depending on the reg_type of the register one of the following functions
* will get called: arm_mcd_read_gpr_register, arm_mcd_read_vfp_register,
* arm_mcd_read_vfp_sys_register, arm_mcd_read_mve_register and
@@ -60,7 +60,7 @@ int arm_mcd_read_register(CPUState *cs, GByteArray *mem_buf, uint8_t reg_type,
uint32_t n);
/**
* \brief Calls the correct write function which writes data from the mem_buf.
- *
+ *
* Depending on the reg_type of the register one of the following functions
* will get called: arm_mcd_write_gpr_register, arm_mcd_write_vfp_register,
* arm_mcd_write_vfp_sys_register, arm_mcd_write_mve_register and
@@ -75,25 +75,16 @@ int arm_mcd_write_register(CPUState *cs, GByteArray *mem_buf, uint8_t reg_type,
uint32_t n);
/**
* \brief 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.
* @param[in] n The register ID of the CP register.
* @param[in] cs CPU state.
*/
uint16_t arm_mcd_get_opcode(CPUState *cs, uint32_t n);
-/**
- * \brief Sets the scr_el3 register according to the secure parameter.
- *
- * If secure is true, the first bit of the scr_el3 register gets set to 0,
- * if not it gets set to 1.
- * @param[in] secure True when secure is requested.
- * @param[in] cs CPU state.
- */
-int arm_mcd_set_scr(CPUState *cs, bool secure);
/**
* \brief 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.
@@ -103,7 +94,7 @@ int arm_mcd_set_scr(CPUState *cs, bool secure);
int arm_mcd_store_mem_spaces(CPUState *cpu, GArray *memspaces);
/**
* \brief 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.
@@ -117,7 +108,7 @@ int arm_mcd_parse_core_xml_file(CPUClass *cc, GArray *reggroups,
GArray *registers, int *current_group_id);
/**
* \brief 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.
@@ -131,7 +122,7 @@ int arm_mcd_parse_general_xml_files(CPUState *cpu, GArray* reggroups,
GArray *registers, int *current_group_id);
/**
* \brief Adds additional data to parsed registers.
- *
+ *
* This function is called, after \ref arm_mcd_parse_core_xml_file and
* \ref arm_mcd_parse_core_xml_file. It adds additional data for all already
* parsed registers. The registers get a correct ID, group, memory space and
@@ -217,6 +217,10 @@ int init_resets(GArray *resets);
* @param[out] 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);
/**
* \brief Resets the mcdserver_state struct.
*
@@ -251,7 +255,7 @@ int find_cpu_clusters(Object *child, void *opaque);
*
* 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.
+ * returned.
* @param[in] a Process a.
* @param[in] b Process b.
*/
@@ -262,7 +266,7 @@ int pid_order(const void *a, const void *b);
int mcd_chr_can_receive(void *opaque);
/**
* \brief Handles receiving a TCP packet.
- *
+ *
* This function gets called by QEMU when a TCP packet is received.
* It iterates over that packet an calls \ref mcd_read_byte for each char
* of the packet.
@@ -272,7 +276,7 @@ int mcd_chr_can_receive(void *opaque);
void mcd_chr_receive(void *opaque, const uint8_t *buf, int size);
/**
* \brief 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.
@@ -285,7 +289,7 @@ void mcd_chr_event(void *opaque, QEMUChrEvent event);
bool mcd_supports_guest_debug(void);
/**
* \brief 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
* \c RUN_STATE_DEBUG it collects additional data on what watchpoint was hit.
@@ -296,13 +300,13 @@ bool mcd_supports_guest_debug(void);
void mcd_vm_state_change(void *opaque, bool running, RunState state);
/**
* \brief Calls \ref mcd_put_packet_binary with buf and length of buf.
- *
+ *
* @param[in] buf TCP packet data.
*/
int mcd_put_packet(const char *buf);
/**
* \brief 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 \ref mcd_put_buffer function.
@@ -316,26 +320,30 @@ int mcd_put_packet_binary(const char *buf, int len);
bool mcd_got_immediate_ack(void);
/**
* \brief Sends the buf as TCP packet with qemu_chr_fe_write_all.
- *
+ *
* @param[in] buf TCP packet data.
* @param[in] len TCP packet length.
*/
void mcd_put_buffer(const uint8_t *buf, int len);
/**
* \brief Returns the process of the provided CPU.
- *
+ *
* @param[in] cpu The CPU state.
*/
MCDProcess *mcd_get_cpu_process(CPUState *cpu);
+/**
+ * \brief Sets c_cpu to the just stopped CPU.
+ */
+void mcd_set_stop_cpu(CPUState *cpu);
/**
* \brief Returns the process ID of the provided CPU.
- *
+ *
* @param[in] cpu The CPU state.
*/
uint32_t mcd_get_cpu_pid(CPUState *cpu);
/**
* \brief Returns the process of the provided pid.
- *
+ *
* @param[in] pid The process ID.
*/
MCDProcess *mcd_get_process(uint32_t pid);
@@ -344,16 +352,16 @@ MCDProcess *mcd_get_process(uint32_t pid);
*/
CPUState *mcd_first_attached_cpu(void);
/**
- * \brief Returns the first CPU with an attached process starting after the
+ * \brief Returns the first CPU with an attached process starting after the
* provided cpu.
- *
+ *
* @param[in] cpu The CPU to start from.
*/
CPUState *mcd_next_attached_cpu(CPUState *cpu);
/**
* \brief 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
@@ -366,7 +374,7 @@ CPUState *mcd_next_attached_cpu(CPUState *cpu);
void mcd_read_byte(uint8_t ch);
/**
* \brief 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 \ref run_cmd_parser.
@@ -379,7 +387,7 @@ int mcd_handle_packet(const char *line_buf);
void mcd_put_strbuf(void);
/**
* \brief 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.
* @param[in] code An exitcode, which can be used in the future.
@@ -387,7 +395,7 @@ void mcd_put_strbuf(void);
void mcd_exit(int code);
/**
* \brief 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 \ref process_string_cmd. In case this function fails, an empty
* TCP packet is sent back the MCD Shared Library.
@@ -397,7 +405,7 @@ void mcd_exit(int code);
void run_cmd_parser(const char *data, const MCDCmdParseEntry *cmd);
/**
* \brief Collects all parameters from the data and calls the correct handler.
- *
+ *
* The parameters are extracted with the \ref 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.
@@ -409,7 +417,7 @@ int process_string_cmd(void *user_ctx, const char *data,
const MCDCmdParseEntry *cmds, int num_cmds);
/**
* \brief 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.
@@ -420,7 +428,7 @@ int process_string_cmd(void *user_ctx, const char *data,
int cmd_parse_params(const char *data, const char *schema, GArray *params);
/**
* \brief Handler for the VM start TCP packet.
- *
+ *
* Evaluates whether all cores or just a perticular core should get started and
* calls \ref mcd_vm_start or \ref mcd_cpu_start respectively.
* @param[in] params GArray with all TCP packet parameters.
@@ -428,7 +436,7 @@ int cmd_parse_params(const char *data, const char *schema, GArray *params);
void handle_vm_start(GArray *params, void *user_ctx);
/**
* \brief Handler for the VM step TCP packet.
- *
+ *
* Calls \ref mcd_cpu_sstep for the CPU which sould be stepped. Stepping all
* CPUs is currently not supported.
* @param[in] params GArray with all TCP packet parameters.
@@ -436,7 +444,7 @@ void handle_vm_start(GArray *params, void *user_ctx);
void handle_vm_step(GArray *params, void *user_ctx);
/**
* \brief Handler for the VM stop TCP packet.
- *
+ *
* Always calls \ref mcd_vm_stop and stops all cores. Stopping individual cores
* is currently not supported
* @param[in] params GArray with all TCP packet parameters.
@@ -444,7 +452,7 @@ void handle_vm_step(GArray *params, void *user_ctx);
void handle_vm_stop(GArray *params, void *user_ctx);
/**
* \brief Handler for all TCP query packets.
- *
+ *
* Calls \ref process_string_cmd with all query functions in the
* mcd_query_cmds_table. \ref process_string_cmd then selects the correct one.
* This function just passes on the TCP packet data string from the parameters.
@@ -453,19 +461,19 @@ void handle_vm_stop(GArray *params, void *user_ctx);
void handle_gen_query(GArray *params, void *user_ctx);
/**
* \brief Returns the internal CPU index plus one.
- *
+ *
* @param[in] cpu CPU of interest.
*/
int mcd_get_cpu_index(CPUState *cpu);
/**
* \brief Returns the CPU the index i_cpu_index.
- *
+ *
* @param[in] cpu_index Index of the desired CPU.
*/
CPUState *mcd_get_cpu(uint32_t cpu_index);
/**
* \brief 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.
* @param[in] params GArray with all TCP packet parameters.
@@ -473,26 +481,26 @@ CPUState *mcd_get_cpu(uint32_t cpu_index);
void handle_query_cores(GArray *params, void *user_ctx);
/**
* \brief Handler for the system query.
- *
+ *
* Sends the system name, which is "qemu-system".
* @param[in] params GArray with all TCP packet parameters.
*/
void handle_query_system(GArray *params, void *user_ctx);
/**
* \brief Returns the first CPU in the provided process.
- *
+ *
* @param[in] process The process to look in.
*/
CPUState *get_first_cpu_in_process(MCDProcess *process);
/**
* \brief Returns the CPU with an index equal to the thread_id.
- *
+ *
* @param[in] thread_id ID of the desired CPU.
*/
CPUState *find_cpu(uint32_t thread_id);
/**
* \brief 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,
@@ -503,14 +511,14 @@ CPUState *find_cpu(uint32_t thread_id);
void handle_open_core(GArray *params, void *user_ctx);
/**
* \brief Handler for the first reset query.
- *
+ *
* This function sends the first reset name and ID.
* @param[in] params GArray with all TCP packet parameters.
*/
void handle_query_reset_f(GArray *params, void *user_ctx);
/**
* \brief 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.
* @param[in] params GArray with all TCP packet parameters.
@@ -518,7 +526,7 @@ void handle_query_reset_f(GArray *params, void *user_ctx);
void handle_query_reset_c(GArray *params, void *user_ctx);
/**
* \brief Handler for closing the MCD server.
- *
+ *
* This function detaches the debugger (process) and frees up memory.
* Then it start the QEMU VM with \ref mcd_vm_start.
* @param[in] params GArray with all TCP packet parameters.
@@ -526,7 +534,7 @@ void handle_query_reset_c(GArray *params, void *user_ctx);
void handle_close_server(GArray *params, void *user_ctx);
/**
* \brief Handler for closing a core.
- *
+ *
* Frees all memory allocated for core specific information. This includes
* memory spaces, register groups and registers.
* @param[in] params GArray with all TCP packet parameters.
@@ -534,7 +542,7 @@ void handle_close_server(GArray *params, void *user_ctx);
void handle_close_core(GArray *params, void *user_ctx);
/**
* \brief Handler for trigger query.
- *
+ *
* Sends data on the different types of trigger and their options and actions.
* @param[in] params GArray with all TCP packet parameters.
*/
@@ -545,13 +553,13 @@ void handle_query_trigger(GArray *params, void *user_ctx);
void mcd_vm_start(void);
/**
* \brief Starts the selected CPU with the cpu_resume function.
- *
+ *
* @param[in] cpu The CPU about to be started.
*/
void mcd_cpu_start(CPUState *cpu);
/**
* \brief 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.
* @param[in] cpu The CPU about to be stepped.
@@ -563,14 +571,14 @@ int mcd_cpu_sstep(CPUState *cpu);
void mcd_vm_stop(void);
/**
* \brief Handler for the first register group query.
- *
+ *
* This function sends the first register group name and ID.
* @param[in] params GArray with all TCP packet parameters.
*/
void handle_query_reg_groups_f(GArray *params, void *user_ctx);
/**
* \brief 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.
* @param[in] params GArray with all TCP packet parameters.
@@ -578,7 +586,7 @@ void handle_query_reg_groups_f(GArray *params, void *user_ctx);
void handle_query_reg_groups_c(GArray *params, void *user_ctx);
/**
* \brief Handler for the first memory space query.
- *
+ *
* This function sends the first memory space name, ID, type and accessing
* options.
* @param[in] params GArray with all TCP packet parameters.
@@ -586,7 +594,7 @@ void handle_query_reg_groups_c(GArray *params, void *user_ctx);
void handle_query_mem_spaces_f(GArray *params, void *user_ctx);
/**
* \brief 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
@@ -596,14 +604,14 @@ void handle_query_mem_spaces_f(GArray *params, void *user_ctx);
void handle_query_mem_spaces_c(GArray *params, void *user_ctx);
/**
* \brief Handler for the first register query.
- *
+ *
* This function sends the first register with all its information.
* @param[in] params GArray with all TCP packet parameters.
*/
void handle_query_regs_f(GArray *params, void *user_ctx);
/**
* \brief 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.
@@ -612,7 +620,7 @@ void handle_query_regs_f(GArray *params, void *user_ctx);
void handle_query_regs_c(GArray *params, void *user_ctx);
/**
* \brief 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 \ref init_resets and
* \reg init_trigger functions. It also send the \c TCP_HANDSHAKE_SUCCESS
@@ -623,14 +631,14 @@ void handle_query_regs_c(GArray *params, void *user_ctx);
void handle_open_server(GArray *params, void *user_ctx);
/**
* \brief Handler for performing resets.
- *
+ *
* This function is currently not in use.
* @param[in] params GArray with all TCP packet parameters.
*/
void handle_reset(GArray *params, void *user_ctx);
/**
* \brief 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.
@@ -639,7 +647,7 @@ void handle_reset(GArray *params, void *user_ctx);
void handle_query_state(GArray *params, void *user_ctx);
/**
* \brief Handler for reading a register.
- *
+ *
* This function calls \ref 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 \ref mcd_memtohex and then send.
@@ -648,7 +656,7 @@ void handle_query_state(GArray *params, void *user_ctx);
void handle_read_register(GArray *params, void *user_ctx);
/**
* \brief Handler for writing a register.
- *
+ *
* This function converts the incoming hex string data into a byte array with
* \ref mcd_hextomem. Then it calls \ref mcd_write_register to write to the
* register.
@@ -657,7 +665,7 @@ void handle_read_register(GArray *params, void *user_ctx);
void handle_write_register(GArray *params, void *user_ctx);
/**
* \brief Handler for reading memory.
- *
+ *
* First, this function checks whether reading a secure memory space is
* requested and changes the access mode with \ref arm_mcd_set_scr.
* Then it calls \ref mcd_read_memory to read memory. The collected
@@ -668,7 +676,7 @@ void handle_write_register(GArray *params, void *user_ctx);
void handle_read_memory(GArray *params, void *user_ctx);
/**
* \brief Handler for writing memory.
- *
+ *
* First, this function checks whether reading a secure memory space is
* requested and changes the access mode with \ref arm_mcd_set_scr.
* Then it converts the incoming hex string data into a byte array with
@@ -679,7 +687,7 @@ void handle_read_memory(GArray *params, void *user_ctx);
void handle_write_memory(GArray *params, void *user_ctx);
/**
* \brief 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 \ref arm_mcd_read_register.
@@ -690,7 +698,7 @@ void handle_write_memory(GArray *params, void *user_ctx);
int mcd_read_register(CPUState *cpu, GByteArray *buf, int reg);
/**
* \brief 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 \ref arm_mcd_write_register.
@@ -701,7 +709,7 @@ int mcd_read_register(CPUState *cpu, GByteArray *buf, int reg);
int mcd_write_register(CPUState *cpu, GByteArray *buf, int reg);
/**
* \brief Reads memory data and stores it into the buf.
- *
+ *
* This function calls cpu_memory_rw_debug or if available
* memory_rw_debug in read mode and passes on all parameters.
* @param[in] cpu CPU to which the memory belongs.
@@ -712,7 +720,7 @@ int mcd_write_register(CPUState *cpu, GByteArray *buf, int reg);
int mcd_read_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len);
/**
* \brief Writes data from the buf into the memory.
- *
+ *
* This function calls cpu_memory_rw_debug or if available
* memory_rw_debug in write mode and passes on all parameters.
* @param[in] cpu CPU to which the memory belongs.
@@ -723,7 +731,7 @@ int mcd_read_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len);
int mcd_write_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len);
/**
* \brief Handler for inserting a break- or watchpoint.
- *
+ *
* This function extracts the CPU, breakpoint type and address from the
* parameters and calls \ref mcd_breakpoint_insert to insert the breakpoint.
* @param[in] params GArray with all TCP packet parameters.
@@ -731,7 +739,7 @@ int mcd_write_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len);
void handle_breakpoint_insert(GArray *params, void *user_ctx);
/**
* \brief Handler for inserting a break- or watchpoint.
- *
+ *
* This function extracts the CPU, breakpoint type and address from the
* parameters and calls \ref mcd_breakpoint_remove to insert the breakpoint.
* @param[in] params GArray with all TCP packet parameters.
@@ -739,7 +747,7 @@ void handle_breakpoint_insert(GArray *params, void *user_ctx);
void handle_breakpoint_remove(GArray *params, void *user_ctx);
/**
* \brief 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
@@ -751,7 +759,7 @@ void handle_breakpoint_remove(GArray *params, void *user_ctx);
int mcd_breakpoint_insert(CPUState *cpu, int type, vaddr addr);
/**
* \brief 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
new file mode 100644
@@ -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 */
@@ -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;
@@ -7,6 +7,7 @@
#include "qemu/cutils.h"
#include "qemu/module.h"
#include "qemu/error-report.h"
+#include "qemu/debug.h"
#include "exec/mcdstub.h"
#include "mcdstub/syscalls.h"
#include "hw/cpu/cluster.h"
@@ -67,6 +68,14 @@ void mcd_init_mcdserver_state(void)
.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)
@@ -1804,19 +1813,22 @@ int mcd_write_memory(CPUState *cpu, hwaddr addr, uint8_t *buf, int len)
void handle_read_memory(GArray *params, void *user_ctx)
{
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;
CPUState *cpu = mcd_get_cpu(cpu_id);
- /* check if the mem space is secure */
- 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);
- if (arm_mcd_set_scr(cpu, space.is_secure)) {
- mcd_put_packet(TCP_EXECUTION_ERROR);
- return;
- }
+ /*
+ * TODO: select to correct address space
+ * uint32_t mem_space_id = get_param(params, 1)->data_uint32_t;
+ * 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);
+ * if (arm_mcd_set_scr(cpu, space.is_secure)) {
+ * mcd_put_packet(TCP_EXECUTION_ERROR);
+ * return;
+ * }
+ */
/* read memory */
g_byte_array_set_size(mcdserver_state.mem_buf, len);
if (mcd_read_memory(cpu, mem_address, mcdserver_state.mem_buf->data,
@@ -1832,18 +1844,21 @@ void handle_read_memory(GArray *params, void *user_ctx)
void handle_write_memory(GArray *params, void *user_ctx)
{
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;
CPUState *cpu = mcd_get_cpu(cpu_id);
- /* check if the mem space is secure */
- 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);
- if (arm_mcd_set_scr(cpu, space.is_secure)) {
- mcd_put_packet(TCP_EXECUTION_ERROR);
- return;
- }
+ /*
+ * TODO: select to correct address space
+ * uint32_t mem_space_id = get_param(params, 1)->data_uint32_t;
+ * 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);
+ * if (arm_mcd_set_scr(cpu, space.is_secure)) {
+ * mcd_put_packet(TCP_EXECUTION_ERROR);
+ * return;
+ * }
+ */
/* write memory */
mcd_hextomem(mcdserver_state.mem_buf, mcdserver_state.str_buf->str, len);
if (mcd_write_memory(cpu, mem_address,
@@ -4,7 +4,7 @@
mcd_system_ss = ss.source_set()
# only system emulation is supported over mcd
-mcd_system_ss.add(files('mcdstub.c'))
+mcd_system_ss.add(files('mcdstub.c', '../debug/debug-mcd.c'))
mcd_system_ss = mcd_system_ss.apply(config_host, strict: false)
@@ -16,4 +16,4 @@ libmcd_softmmu = static_library('mcd_softmmu',
mcd_softmmu = declare_dependency(link_whole: libmcd_softmmu)
system_ss.add(mcd_softmmu)
-common_ss.add(files('mcd_syscalls.c'))
+common_ss.add(files('../debug/debug-common.c', 'mcd_syscalls.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,10 +307,13 @@ void cpu_handle_guest_debug(CPUState *cpu)
cpu_single_step(cpu, 0);
}
} else {
- /*
- * TODO: was gdb_set_stop_cpu(cpu), need to abstract options to
- * a QOM class.
- */
+ 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;
}
@@ -4,6 +4,7 @@
#include "sysemu/tcg.h"
#include "internals.h"
#include "cpregs.h"
+#include "qemu/debug.h"
#include "mcdstub/arm_mcdstub.h"
@@ -332,20 +333,6 @@ uint16_t arm_mcd_get_opcode(CPUState *cs, uint32_t n)
return 0;
}
-int arm_mcd_set_scr(CPUState *cs, bool secure)
-{
- /* switches between secure and non secure mode */
- ARMCPU *cpu = ARM_CPU(cs);
- CPUARMState *env = &cpu->env;
- /* set bit 0 to 1 if non secure, to 0 if secure*/
- if (secure) {
- env->cp15.scr_el3 &= 0xFFFFFFFE;
- } else {
- env->cp15.scr_el3 |= 1;
- }
- return 0;
-}
-
int arm_mcd_store_mem_spaces(CPUState *cpu, GArray *memspaces)
{
int nr_address_spaces = cpu->num_ases;
@@ -379,7 +366,7 @@ int arm_mcd_store_mem_spaces(CPUState *cpu, GArray *memspaces)
.is_secure = false,
};
g_array_append_vals(memspaces, (gconstpointer)&phys_non_secure, 1);
- if(nr_address_spaces > 1) {
+ if (nr_address_spaces > 1) {
mem_space_id++;
mcd_mem_space_st secure = {
.name = "Secure",