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 <daniel.leung@intel.com>
diff --git a/include/sys/arch_interface.h b/include/sys/arch_interface.h
index f570a72..ccaedaf 100644
--- a/include/sys/arch_interface.h
+++ b/include/sys/arch_interface.h
@@ -819,14 +819,9 @@
* @{
*/
-/**
- * @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_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 80ceda4..6b4f7b0 100644
--- a/subsys/debug/gdbstub.c
+++ b/subsys/debug/gdbstub.c
@@ -344,8 +344,7 @@
* 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 @@
* 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 @@
*/
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 @@
* 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;