diff mbox series

[v2,30/38] gdbserver: multi-thread polling and stop-reason

Message ID 20220329154931.493851-31-npiggin@gmail.com
State New
Headers show
Series gdbserver multi-threaded debugging and POWER9/10 support | expand

Commit Message

Nicholas Piggin March 29, 2022, 3:49 p.m. UTC
Rework poll() and the stop reason code to support multi-threaded
debugging.

- Make poll() iterate over all target threads to check whether any
  are stopped.

- If any are found stopped, stop the rest. Poll SPATTN for all
  target threads.

This provides the basis for "all-stop" threaded debugging mode,
which is what seems to work best for bare metal debugging.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
 src/pdbgproxy.c | 75 +++++++++++++++++++++++++++++--------------------
 1 file changed, 44 insertions(+), 31 deletions(-)
diff mbox series

Patch

diff --git a/src/pdbgproxy.c b/src/pdbgproxy.c
index d34a64e..db80b6a 100644
--- a/src/pdbgproxy.c
+++ b/src/pdbgproxy.c
@@ -683,60 +683,73 @@  static void stop_all(void)
 			PR_ERROR("Could not quiesce thread\n");
 			/* How to fix? */
 		}
+
+		if (thread_check_attn(target)) {
+			struct thread *thread = target_to_thread(target);
+			struct gdb_thread *gdb_thread = thread->gdbserver_priv;
+			uint64_t nia;
+
+			PR_INFO("thread pir=%llx hit attn\n", gdb_thread->pir);
+
+			if (!(status.active))
+				PR_ERROR("Error thread inactive after trap\n");
+			/* Restore NIA to before break */
+			if (thread_getnia(target, &nia))
+				PR_ERROR("Error during getnia\n");
+			if (thread_putnia(target, nia - 4))
+				PR_ERROR("Error during putnia\n");
+		}
 	}
 }
 
 static void interrupt(uint64_t *stack, void *priv)
 {
-	struct thread_state status;
-
 	PR_INFO("Interrupt from gdb client\n");
+	if (state != IDLE) {
+		stop_all();
 
-	stop_all();
-
-	status = thread_status(thread_target);
-	if (!(status.quiesced)) {
-		PR_ERROR("Could not quiesce thread\n");
-		return;
+		state = IDLE;
+		poll_interval = VCONT_POLL_DELAY;
 	}
-	state = IDLE;
-	poll_interval = VCONT_POLL_DELAY;
+
 	send_response(fd, TRAP);
 }
 
-static void poll(void)
+static bool poll_threads(void)
 {
-	struct thread_state status;
+	struct pdbg_target *target;
+
+	for_each_path_target_class("thread", target) {
+		struct thread_state status;
+
+		if (pdbg_target_status(target) != PDBG_TARGET_ENABLED)
+			continue;
 
+		target->probe(target);
+		status = thread_status(target);
+		if (status.quiesced)
+			return true;
+	}
+	return false;
+}
+
+static void poll(void)
+{
 	if (state != SIGNAL_WAIT)
 		return;
 
-	thread_target->probe(thread_target);
-	status = thread_status(thread_target);
-
-	if (!(status.quiesced))
+	if (!poll_threads())
 		return;
 
+	/* Something hit a breakpoint */
+
+	stop_all();
+
 	set_attn(false);
 
 	state = IDLE;
 	poll_interval = VCONT_POLL_DELAY;
 
-	if (thread_check_attn(thread_target)) {
-		uint64_t nia;
-
-		if (!(status.active)) {
-			PR_ERROR("Thread inactive after trap\n");
-			send_response(fd, ERROR(EPERM));
-			return;
-		}
-
-		/* Restore NIA */
-		if (thread_getnia(thread_target, &nia))
-			PR_ERROR("Error during getnia\n");
-		if (thread_putnia(thread_target, nia - 4))
-			PR_ERROR("Error during putnia\n");
-	}
 	send_response(fd, TRAP);
 }