rtos: server/gdb_server: fix missing thread ID in stop reply

Cherry-picked from [1].

To replicate the issue that this fixes:

1. Connect to a multi-hart RISC-V target configured as an SMP group.
2. Start a GDB instance against the running OpenOCD.
3. Observe that GDB might display "warning: multi-threaded target
   stopped without sending a thread-id, using first non-exited thread."
4. Set a breakpoint in code that any non-hart-0 hart is expected to
   reach (but hart 0 is not expected to reach).
5. Allow a non-hart-0 hart to reach the breakpoint.
6. Remove the breakpoint.
7. Do a few sequential `stepi` commands in GDB.
8. Observe that GDB displays "Switching to Thread 1" even though the
   thread that was just single stepped was not Thread 1 in GDB. Also
   observe that the register values in GDB correspond to the thread that
   was single-stepped, not Thread 1. Basically GDB erroneously starts to
   consider thread 1 to be current, when in fact the thread that was
   single-stepped is still current.

The changes in this pull request are intended to avoid the erroneous
"Switching to Thread 1" described in (8) above.

What was happening was that, in a couple areas of code, non-hart-0 harts
weren't seen as belonging to an RTOS module, and this had the effect of
(1) bypassing `hwthread_update_threads()` being called after a halt; (2)
omitting a thread ID in a stop reply over GDB remote protocol connection
(requiring GDB to take an arbitrary guess of current thread id, a guess
that is wrong unless the current thread happens to be hart 0).

Link: https://github.com/riscv-collab/riscv-openocd/pull/675 [1]
Change-Id: I9872062dfa0e3f1ca531d282d52a1b04c527546a
Signed-off-by: Greg Savin <greg.savin@sifive.com>
Reviewed-on: https://review.openocd.org/c/openocd/+/9183
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
This commit is contained in:
Greg Savin
2022-02-07 09:28:31 -08:00
committed by Tomas Vanek
parent 7b6496db7e
commit 1ea763d23c
3 changed files with 30 additions and 7 deletions

View File

@@ -11,6 +11,7 @@
#include "rtos.h"
#include "target/target.h"
#include "target/smp.h"
#include "helper/log.h"
#include "helper/binarybuffer.h"
#include "helper/types.h"
@@ -715,10 +716,24 @@ int rtos_generic_stack_read(struct target *target,
return ERROR_OK;
}
struct rtos *rtos_from_target(struct target *target)
{
if (target->rtos && target->rtos->type)
return target->rtos;
struct target_list *pos;
foreach_smp_target(pos, target->smp_targets)
if (pos->target->rtos && pos->target->rtos->type)
return pos->target->rtos;
return NULL;
}
int rtos_update_threads(struct target *target)
{
if ((target->rtos) && (target->rtos->type))
target->rtos->type->update_threads(target->rtos);
struct rtos *rtos = rtos_from_target(target);
if (rtos)
rtos->type->update_threads(rtos);
return ERROR_OK;
}

View File

@@ -154,6 +154,11 @@ int rtos_write_buffer(struct target *target, target_addr_t address,
bool rtos_needs_fake_step(struct target *target, int64_t thread_id);
struct target *rtos_swbp_target(struct target *target, target_addr_t address,
uint32_t length, enum breakpoint_type type);
/**
* Get the RTOS from the target itself, or from one of the targets in
* the same SMP node, or NULL when no RTOS is set.
*/
struct rtos *rtos_from_target(struct target *target);
// Keep in alphabetic order this list of rtos
extern const struct rtos_type chibios_rtos;

View File

@@ -813,9 +813,12 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio
sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "W00");
} else {
struct target *ct;
if (target->rtos) {
target->rtos->current_threadid = target->rtos->current_thread;
target->rtos->gdb_target_for_threadid(connection, target->rtos->current_threadid, &ct);
struct rtos *rtos;
rtos = rtos_from_target(target);
if (rtos) {
rtos->current_threadid = rtos->current_thread;
rtos->gdb_target_for_threadid(connection, rtos->current_threadid, &ct);
} else {
ct = target;
}
@@ -853,9 +856,9 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio
}
current_thread[0] = '\0';
if (target->rtos)
if (rtos)
snprintf(current_thread, sizeof(current_thread), "thread:%" PRIx64 ";",
target->rtos->current_thread);
rtos->current_thread);
sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "T%2.2x%s%s",
signal_var, stop_reason, current_thread);