From e76d385e49e11bdfd2cbbcfc78ebb60914905f26 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Thu, 14 Oct 2021 10:14:50 -0700 Subject: [PATCH] debug: gdbstub: add arch-specific funcs to read/write registers This adds architecture-specific functions to read/write registers. This allows architecture to have a sparse representation of the register file as not all registers are saved during context switches. This saves some runtime space, and provides some flexibility on what architectures can do. Remove from header the need to define ARCH_GDB_NUM_REGISTERS as it is no longer used in the common gdbstub code. Signed-off-by: Daniel Leung --- include/sys/arch_interface.h | 73 ++++++++++++++++++++++++++++++++---- subsys/debug/gdbstub.c | 21 +++-------- 2 files changed, 71 insertions(+), 23 deletions(-) diff --git a/include/sys/arch_interface.h b/include/sys/arch_interface.h index f570a72e0fd..ccaedaff701 100644 --- a/include/sys/arch_interface.h +++ b/include/sys/arch_interface.h @@ -819,14 +819,9 @@ static inline void arch_cohere_stacks(struct k_thread *old_thread, * @{ */ -/** - * @def ARCH_GDB_NUM_REGISTERS - * - * ARCH_GDB_NUM_REGISTERS is architecure specific and - * this symbol must be defined in architecure specific header - */ - #ifdef CONFIG_GDBSTUB +struct gdb_ctx; + /** * @brief Architecture layer debug start * @@ -848,6 +843,70 @@ void arch_gdb_continue(void); */ void arch_gdb_step(void); +/** + * @brief Read all registers, and outputs as hexadecimal string. + * + * This reads all CPU registers and outputs as hexadecimal string. + * The output string must be parsable by GDB. + * + * @param ctx GDB context + * @param buf Buffer to output hexadecimal string. + * @param buflen Length of buffer. + * + * @return Length of hexadecimal string written. + * Return 0 if error or not supported. + */ +size_t arch_gdb_reg_readall(struct gdb_ctx *ctx, uint8_t *buf, size_t buflen); + +/** + * @brief Take a hexadecimal string and update all registers. + * + * This takes in a hexadecimal string as presented from GDB, + * and updates all CPU registers with new values. + * + * @param ctx GDB context + * @param hex Input hexadecimal string. + * @param hexlen Length of hexadecimal string. + * + * @return Length of hexadecimal string parsed. + * Return 0 if error or not supported. + */ +size_t arch_gdb_reg_writeall(struct gdb_ctx *ctx, uint8_t *hex, size_t hexlen); + +/** + * @brief Read one register, and outputs as hexadecimal string. + * + * This reads one CPU register and outputs as hexadecimal string. + * The output string must be parsable by GDB. + * + * @param ctx GDB context + * @param buf Buffer to output hexadecimal string. + * @param buflen Length of buffer. + * @param regno Register number + * + * @return Length of hexadecimal string written. + * Return 0 if error or not supported. + */ +size_t arch_gdb_reg_readone(struct gdb_ctx *ctx, uint8_t *buf, size_t buflen, + uint32_t regno); + +/** + * @brief Take a hexadecimal string and update one register. + * + * This takes in a hexadecimal string as presented from GDB, + * and updates one CPU registers with new value. + * + * @param ctx GDB context + * @param hex Input hexadecimal string. + * @param hexlen Length of hexadecimal string. + * @param regno Register number + * + * @return Length of hexadecimal string parsed. + * Return 0 if error or not supported. + */ +size_t arch_gdb_reg_writeone(struct gdb_ctx *ctx, uint8_t *hex, size_t hexlen, + uint32_t regno); + #endif /** @} */ diff --git a/subsys/debug/gdbstub.c b/subsys/debug/gdbstub.c index 80ceda4de3e..6b4f7b03f66 100644 --- a/subsys/debug/gdbstub.c +++ b/subsys/debug/gdbstub.c @@ -344,8 +344,7 @@ int z_gdb_main_loop(struct gdb_ctx *ctx, bool start) * Format: g */ case 'g': - pkt_len = bin2hex((const uint8_t *)&(ctx->registers), - sizeof(ctx->registers), buf, sizeof(buf)); + pkt_len = arch_gdb_reg_readall(ctx, buf, sizeof(buf)); CHECK_FAILURE(pkt_len == 0); gdb_send_packet(buf, pkt_len); break; @@ -355,9 +354,7 @@ int z_gdb_main_loop(struct gdb_ctx *ctx, bool start) * Fromat: G XX... */ case 'G': - pkt_len = hex2bin(ptr, pkt_len - 1, - (uint8_t *)&(ctx->registers), - sizeof(ctx->registers)); + pkt_len = arch_gdb_reg_writeall(ctx, ptr, pkt_len - 1); CHECK_FAILURE(pkt_len == 0); gdb_send_packet("OK", 2); break; @@ -368,13 +365,9 @@ int z_gdb_main_loop(struct gdb_ctx *ctx, bool start) */ case 'p': CHECK_INT(addr); - CHECK_FAILURE(addr >= ARCH_GDB_NUM_REGISTERS); /* Read Register */ - pkt_len = bin2hex( - (const uint8_t *)&(ctx->registers[addr]), - sizeof(ctx->registers[addr]), - buf, sizeof(buf)); + pkt_len = arch_gdb_reg_readone(ctx, buf, sizeof(buf), addr); CHECK_FAILURE(pkt_len == 0); gdb_send_packet(buf, pkt_len); break; @@ -393,12 +386,8 @@ int z_gdb_main_loop(struct gdb_ctx *ctx, bool start) * return "E01" gdb will stop. So, we just * send "OK" and ignore it. */ - if (addr < ARCH_GDB_NUM_REGISTERS) { - pkt_len = hex2bin(ptr, strlen(ptr), - (uint8_t *)&(ctx->registers[addr]), - sizeof(ctx->registers[addr])); - CHECK_FAILURE(pkt_len == 0); - } + pkt_len = arch_gdb_reg_writeone(ctx, ptr, strlen(ptr), addr); + CHECK_FAILURE(pkt_len == 0); gdb_send_packet("OK", 2); break;