diff --git a/.vscode/settings.json b/.vscode/settings.json index c6e1ed1..607786c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -59,6 +59,9 @@ "ctype.h": "c", "gdbstub.h": "c", "pthread.h": "c", - "enums.h": "c" + "enums.h": "c", + "ctime": "c", + "iomanip": "c", + "sstream": "c" } } \ No newline at end of file diff --git a/gdbstub/enums.c b/gdbstub/enums.c index 8283f34..aaede0a 100644 --- a/gdbstub/enums.c +++ b/gdbstub/enums.c @@ -3,6 +3,39 @@ #include +/** + * Helper function for error checking after strtol() and the like + */ +static int check_strtox_error(const char *nptr, char *ep, const char **endptr, bool check_zero, int libc_errno) { + assert(ep >= nptr); + + /* Windows has a bug in that it fails to parse 0 from "0x" in base 16 */ + if (check_zero && ep == nptr && libc_errno == 0) { + char *tmp; + + errno = 0; + if (strtol(nptr, &tmp, 10) == 0 && errno == 0 && (*tmp == 'x' || *tmp == 'X')) { + ep = tmp; + } + } + + if (endptr) { + *endptr = ep; + } + + /* Turn "no conversion" into an error */ + if (libc_errno == 0 && ep == nptr) { + return -EINVAL; + } + + /* Fail when we're expected to consume the string, but didn't */ + if (!endptr && *ep) { + return -EINVAL; + } + + return -libc_errno; +} + int qemu_strtoul(const char *nptr, const char **endptr, int base, unsigned long *result) { char *ep; @@ -21,7 +54,7 @@ int qemu_strtoul(const char *nptr, const char **endptr, int base, unsigned long if (errno == ERANGE) { *result = -1; } - return 0; + return check_strtox_error(nptr, ep, endptr, *result == 0, errno); } int qemu_strtou64(const char *nptr, const char **endptr, int base, uint64_t *result) { @@ -44,5 +77,5 @@ int qemu_strtou64(const char *nptr, const char **endptr, int base, uint64_t *res if (errno == ERANGE) { *result = -1; } - return 0; -} + return check_strtox_error(nptr, ep, endptr, *result == 0, errno); +} \ No newline at end of file diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index 4fe8906..e0d8f82 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -220,7 +220,10 @@ static void gdb_set_cpu_pc(vaddr pc) { cpu_set_pc(cpu, pc); } -void gdb_append_thread_id(CPUState *cpu, GString *buf) { g_string_append_printf(buf, "%02x", 1); } +void gdb_append_thread_id(CPUState *cpu, GString *buf) { + g_string_append_printf(buf, "p%02x.%02x", 1, 1); + // g_string_append_printf(buf, "%02x", 1); +} static GDBThreadIdKind read_thread_id(const char *buf, const char **end_buf, uint32_t *pid, uint32_t *tid) { unsigned long p, t; @@ -345,10 +348,10 @@ static int gdb_handle_vcont(const char *p) { break; case GDB_ALL_THREADS: - process = gdb_get_process(); - if (!process->attached) { - return -EINVAL; - } + // process = gdb_get_process(); + // if (!process->attached) { + // return -EINVAL; + // } cpu = get_cpu(); if (cpu) { if (newstates[cpu->cpu_index] == 1) { @@ -856,7 +859,6 @@ static void handle_v_commands(GArray *params, void *user_ctx) { if (!params->len) { return; } - if (!process_string_cmd(gdb_get_cmd_param(params, 0)->data, gdb_v_commands_table, ARRAY_SIZE(gdb_v_commands_table))) { gdb_put_packet(""); } @@ -915,6 +917,11 @@ static void handle_query_curr_tid(GArray *params, void *user_ctx) { gdb_put_strbuf(); } +static void handle_query_gdb_server_version(GArray *params, void *user_ctx) { + g_string_printf(gdb_state.str_buf, "name:system-riscv;version:1.9;"); + gdb_put_strbuf(); +} + static void handle_query_threads(GArray *params, void *user_ctx) { if (!gdb_state.query_cpu) { gdb_put_packet("l"); @@ -925,11 +932,6 @@ static void handle_query_threads(GArray *params, void *user_ctx) { gdb_state.query_cpu = 0; } -static void handle_query_gdb_server_version(GArray *params, void *user_ctx) { - g_string_printf(gdb_state.str_buf, "name:qemu-system-riscv;version:1.9;"); - gdb_put_strbuf(); -} - static void handle_query_first_threads(GArray *params, void *user_ctx) { gdb_state.query_cpu = get_cpu(); handle_query_threads(params, user_ctx); diff --git a/gdbstub/internals.h b/gdbstub/internals.h index 467d88f..5df107f 100644 --- a/gdbstub/internals.h +++ b/gdbstub/internals.h @@ -240,4 +240,6 @@ void cpu_register_gdb_commands(); int cpu_common_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); int cpu_common_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); +void gdb_vm_state_change(); + #endif /* GDBSTUB_INTERNALS_H */ diff --git a/gdbstub/system.c b/gdbstub/system.c index a1b49de..ceba904 100644 --- a/gdbstub/system.c +++ b/gdbstub/system.c @@ -10,7 +10,9 @@ * SPDX-License-Identifier: LGPL-2.0-or-later */ +#include #include +#include #include "commands.h" #include "cpu.h" @@ -312,40 +314,71 @@ bool runstate_is_running() { /////// local cpu operation /////// -void vm_stop() { get_cpu()->running = false; } -void vm_start() { get_cpu()->running = true; } +void vm_stop() { + std::cout << "CPU=>vm_stop" << std::endl; + get_cpu()->running = false; +} +void vm_start() { + std::cout << "CPU=>vm_start" << std::endl; + get_cpu()->running = true; +} void cpu_synchronize_state(CPUState *cpu) {} void gdb_exit(int i) {}; void gdb_qemu_exit(int i) {}; -void gdb_breakpoint_remove_all(CPUState *cs) {} -int gdb_breakpoint_insert(CPUState *cs, int type, vaddr addr, vaddr len) { return 0; } -int gdb_breakpoint_remove(CPUState *cs, int type, vaddr addr, vaddr len) { return 0; } +void gdb_breakpoint_remove_all(CPUState *cs) { std::cout << "CPU=>gdb_breakpoint_remove_all" << std::endl; } +int gdb_breakpoint_insert(CPUState *cs, int type, vaddr addr, vaddr len) { + std::cout << "CPU=>gdb_breakpoint_insert" << std::endl; + return 0; +} +int gdb_breakpoint_remove(CPUState *cs, int type, vaddr addr, vaddr len) { + std::cout << "CPU=>gdb_breakpoint_remove" << std::endl; + return 0; +} -static inline void cpu_physical_memory_write(hwaddr addr, const void *buf, hwaddr len) {} -static inline void cpu_physical_memory_read(hwaddr addr, const void *buf, hwaddr len) {} +static inline void cpu_physical_memory_write(hwaddr addr, const void *buf, hwaddr len) { + std::cout << "CPU=>memory_write addr:0x" << std::hex << addr << " len:0x" << len << std::endl; + std::cout << "CPU=>memory_write data:"; + for (int i = 0; i < len; i++) { + uint8_t d = *((uint8_t *)buf + i); + std::cout << std::hex << std::setfill('0') << std::setw(2) << static_cast(d); + } + std::cout << std::endl; +} +static inline void cpu_physical_memory_read(hwaddr addr, const void *buf, hwaddr len) { + std::cout << "CPU=>memory_read addr:0x" << std::hex << addr << " len:0x" << len << std::endl; +} bool runstate_needs_reset(void) { return false; } -bool vm_prepare_start(bool step_requested) { return true; } +bool vm_prepare_start(bool step_requested) { return false; } -void gdb_handle_file_io(GArray *params, void *user_ctx) {} +void gdb_handle_file_io(GArray *params, void *user_ctx) { std::cout << "CPU=>gdb_handle_file_io" << std::endl; } void gdb_disable_syscalls(void) {} -void cpu_single_step(CPUState *cpu, int enabled) {} +void cpu_single_step(CPUState *cpu, int enabled) { std::cout << "CPU=>cpu_single_step" << std::endl; } void cpu_resume(CPUState *cpu) { cpu->stop = false; cpu->stopped = false; + std::cout << "CPU=>cpu_resume" << std::endl; + + // g_autoptr(GString) buf = g_string_new(NULL); + // g_string_printf(buf, "T%02xthread:p01.01;", 05); + // gdb_put_packet(buf->str); } int cpu_common_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg) { uint64_t val = 0; g_byte_array_append(buf, (uint8_t *)&val, 8); + std::cout << "CPU=>read_register reg:0x" << reg << std::endl; return 8; } -int cpu_common_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg) { return 0; } +int cpu_common_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg) { + std::cout << "CPU=>write_register reg:0x" << reg << std::endl; + return 0; +} int gdb_target_memory_rw_debug(CPUState *cpu, hwaddr addr, uint8_t *buf, int len, bool is_write) { if (is_write) { @@ -357,7 +390,105 @@ int gdb_target_memory_rw_debug(CPUState *cpu, hwaddr addr, uint8_t *buf, int len } void gdb_continue(void) { + std::cout << "CPU=>gdb_continue" << std::endl; + if (!runstate_needs_reset()) { vm_start(); } -} \ No newline at end of file +} + +// static void gdb_vm_state_change() { +// CPUState *cpu = gdbserver_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 || gdbserver_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; +// } + +// if (!gdbserver_state.allow_stop_reply) { +// 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(); +// } +// if (tcg_enabled()) { +// 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_STOP; +// 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; +// } +// gdb_set_stop_cpu(cpu); +// g_string_printf(buf, "T%02xthread:%s;", ret, tid->str); + +// send_packet: +// gdb_put_packet(buf->str); +// gdbserver_state.allow_stop_reply = false; + +// /* disable single step if it was enabled */ +// cpu_single_step(cpu, 0); +// } \ No newline at end of file diff --git a/gdbstub/utils/conn.c b/gdbstub/utils/conn.c index 3770ea7..181f1bc 100644 --- a/gdbstub/utils/conn.c +++ b/gdbstub/utils/conn.c @@ -90,7 +90,7 @@ void conn_recv_packet(conn_t *conn) { packet_t *conn_pop_packet(conn_t *conn) { packet_t *pkt = pktbuf_pop_packet(&conn->pktbuf); - if (pkt) printf("packet = %s\n", pkt->data); + if (pkt) printf("receive = %s\n", pkt->data); return pkt; }