From 71013521d7b195022616284aabc5e072a60c52bf Mon Sep 17 00:00:00 2001
From: Antonio Borneo <borneo.antonio@gmail.com>
Date: Fri, 3 May 2024 23:04:46 +0200
Subject: [PATCH] server: gdb: respect command gdb_report_register_access_error

Commit 236c54c94a53 ("server/gdb_server.c: support unavailable
registers") correctly returns a string of 'x' when the register is
not available in the current target.

While implementing this, it incorrectly drops the pre-existing
feature of optionally ignoring errors while reading a register.
This feature has a real use case documented in the OpenOCD manual
in chapter 'Using GDB as a non-intrusive memory inspector', where
GDB attaches to a target without halting it. For targets that need
to be halted to read its registers, we need to hack the values of
the registers returned to GDB; either returning 'xxxx' or an error
causes GDB to drop the connection.

Re-add the check on 'gdb_report_register_access_error' to keep the
pre-existing behavior when a register error has to be ignored:
- return a string of '0';
- drop a debug message.

Change-Id: Ie65c92f259f92502e688914f334655b635874179
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Fixes: 236c54c94a53 ("server/gdb_server.c: support unavailable registers")
Reviewed-on: https://review.openocd.org/c/openocd/+/8228
Tested-by: jenkins
---
 src/server/gdb_server.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c
index 5052bf43b..7c2f41e41 100644
--- a/src/server/gdb_server.c
+++ b/src/server/gdb_server.c
@@ -1233,6 +1233,8 @@ static int gdb_get_reg_value_as_str(struct target *target, char *tstr, struct re
 			tstr[len] = '\0';
 			return ERROR_OK;
 	}
+	memset(tstr, '0', len);
+	tstr[len] = '\0';
 	return ERROR_FAIL;
 }
 
@@ -1277,7 +1279,9 @@ static int gdb_get_registers_packet(struct connection *connection,
 	for (i = 0; i < reg_list_size; i++) {
 		if (!reg_list[i] || reg_list[i]->exist == false || reg_list[i]->hidden)
 			continue;
-		if (gdb_get_reg_value_as_str(target, reg_packet_p, reg_list[i]) != ERROR_OK) {
+		retval = gdb_get_reg_value_as_str(target, reg_packet_p, reg_list[i]);
+		if (retval != ERROR_OK && gdb_report_register_access_error) {
+			LOG_DEBUG("Couldn't get register %s.", reg_list[i]->name);
 			free(reg_packet);
 			free(reg_list);
 			return gdb_error(connection, retval);
@@ -1395,7 +1399,9 @@ static int gdb_get_register_packet(struct connection *connection,
 
 	reg_packet = calloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2 + 1, 1); /* plus one for string termination null */
 
-	if (gdb_get_reg_value_as_str(target, reg_packet, reg_list[reg_num]) != ERROR_OK) {
+	retval = gdb_get_reg_value_as_str(target, reg_packet, reg_list[reg_num]);
+	if (retval != ERROR_OK && gdb_report_register_access_error) {
+		LOG_DEBUG("Couldn't get register %s.", reg_list[reg_num]->name);
 		free(reg_packet);
 		free(reg_list);
 		return gdb_error(connection, retval);