diff mbox series

[v2,31/39] gdbserver: multi-thread polling and stop-reason

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

Commit Message

Nicholas Piggin April 20, 2022, 6:50 a.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(-)

Comments

Joel Stanley May 3, 2022, 7:33 a.m. UTC | #1
On Wed, 20 Apr 2022 at 06:51, Nicholas Piggin <npiggin@gmail.com> wrote:
>
> 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>

Reviewed-by: Joel Stanley <joel@jms.id.au>

> ---
>  src/pdbgproxy.c | 75 +++++++++++++++++++++++++++++--------------------
>  1 file changed, 44 insertions(+), 31 deletions(-)
>
> diff --git a/src/pdbgproxy.c b/src/pdbgproxy.c
> index c5870091..735615c6 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=%"PRIx64" 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);
>  }
>
> --
> 2.35.1
>
> --
> Pdbg mailing list
> Pdbg@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/pdbg
diff mbox series

Patch

diff --git a/src/pdbgproxy.c b/src/pdbgproxy.c
index c5870091..735615c6 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=%"PRIx64" 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);
 }