[Pdbg] [PATCH v2 35/39] gdbserver: better deal with threads initially stopped

Joel Stanley joel at jms.id.au
Tue May 3 17:40:18 AEST 2022


On Wed, 20 Apr 2022 at 06:51, Nicholas Piggin <npiggin at gmail.com> wrote:
>
> Better deal with threads that are quiesced when gdbserver starts.
> Record and clear SPATTN register to determine whether any had hit
> attn, and prevent subsequent stop from getting a false positive on
> SPATTN.
>
> Switch target thread to the first one that had hit an attn or been
> stopped when gdbserver starts up, if any.
>
> Don't resume initially-stopped threads unless a client attaches and
> directs them to.
>
> Signed-off-by: Nicholas Piggin <npiggin at gmail.com>

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

> ---
>  src/pdbgproxy.c | 90 +++++++++++++++++++++++++++++++++++++++++++------
>  1 file changed, 80 insertions(+), 10 deletions(-)
>
> diff --git a/src/pdbgproxy.c b/src/pdbgproxy.c
> index 642cbe61..6b9bdf90 100644
> --- a/src/pdbgproxy.c
> +++ b/src/pdbgproxy.c
> @@ -64,6 +64,7 @@ static enum client_state state = IDLE;
>  struct gdb_thread {
>         uint64_t pir;
>         bool attn_set;
> +       bool initial_stopped;
>         bool stop_attn;
>         bool stop_ctrlc;
>  };
> @@ -1058,11 +1059,15 @@ static int gdbserver_start(struct pdbg_target *adu, uint16_t port)
>
>  static int gdbserver(uint16_t port)
>  {
> -       struct pdbg_target *target, *adu, *first_target = NULL;
> +       struct pdbg_target *target, *adu;
> +       struct pdbg_target *first_target = NULL;
> +       struct pdbg_target *first_stopped_target = NULL;
> +       struct pdbg_target *first_attn_target = NULL;
>
>         for_each_path_target_class("thread", target) {
>                 struct thread *thread = target_to_thread(target);
>                 struct gdb_thread *gdb_thread;
> +               struct thread_state status;
>
>                 if (pdbg_target_status(target) != PDBG_TARGET_ENABLED)
>                         continue;
> @@ -1080,6 +1085,13 @@ static int gdbserver(uint16_t port)
>
>                 if (!first_target)
>                         first_target = target;
> +
> +               status = thread_status(target);
> +               if (status.quiesced) {
> +                       if (!first_stopped_target)
> +                               first_stopped_target = target;
> +                       gdb_thread->initial_stopped = true;
> +               }
>         }
>
>         if (!first_target) {
> @@ -1099,16 +1111,19 @@ static int gdbserver(uint16_t port)
>                 PR_WARNING("GDBSERVER works best when targeting all threads (-a)\n");
>         }
>
> -       thread_target = first_target;
> -
>         for_each_path_target_class("thread", target) {
> +               struct thread *thread = target_to_thread(target);
> +               struct gdb_thread *gdb_thread = thread->gdbserver_priv;
> +
>                 if (pdbg_target_status(target) != PDBG_TARGET_ENABLED)
>                         continue;
>
> -               if (thread_stop(target)) {
> -                       PR_ERROR("Could not stop thread %s\n",
> -                                pdbg_target_path(target));
> -                       return -1;
> +               if (!gdb_thread->initial_stopped) {
> +                       if (thread_stop(target)) {
> +                               PR_ERROR("Could not stop thread %s\n",
> +                                        pdbg_target_path(target));
> +                               return -1;
> +                       }
>                 }
>         }
>
> @@ -1129,9 +1144,46 @@ static int gdbserver(uint16_t port)
>                         PR_ERROR("PIR exceeds 16-bits.");
>                         goto out;
>                 }
> +
> +               if (thread_check_attn(target)) {
> +                       PR_INFO("thread pir=%"PRIx64" hit attn\n", gdb_thread->pir);
> +
> +                       if (!first_attn_target)
> +                               first_attn_target = target;
> +                       gdb_thread->stop_attn = true;
> +                       if (!gdb_thread->initial_stopped) {
> +                               PR_WARNING("thread pir=%"PRIx64" hit attn but was not stopped\n", gdb_thread->pir);
> +                               gdb_thread->initial_stopped = true;
> +                       }
> +               }
>         }
>
> -       start_all();
> +       /* Target attn as a priority, then any stopped, then first */
> +       if (first_attn_target)
> +               thread_target = first_target;
> +       else if (first_stopped_target)
> +               thread_target = first_stopped_target;
> +       else
> +               thread_target = first_target;
> +
> +       /*
> +        * Resume threads now, except those that were initially stopped,
> +        * leave them so the client can inspect them.
> +        */
> +       for_each_path_target_class("thread", target) {
> +               struct thread *thread = target_to_thread(target);
> +               struct gdb_thread *gdb_thread = thread->gdbserver_priv;
> +
> +               if (pdbg_target_status(target) != PDBG_TARGET_ENABLED)
> +                       continue;
> +
> +               if (!gdb_thread->initial_stopped) {
> +                       if (thread_start(target)) {
> +                               PR_ERROR("Could not start thread %s\n",
> +                                        pdbg_target_path(target));
> +                       }
> +               }
> +       }
>
>         /* Select ADU target */
>         pdbg_for_each_class_target("mem", adu) {
> @@ -1147,8 +1199,26 @@ static int gdbserver(uint16_t port)
>         gdbserver_start(adu, port);
>
>  out:
> -       if (all_stopped)
> -               __start_all();
> +       if (!all_stopped)
> +               stop_all();
> +
> +       /*
> +        * Only resume those which were not initially stopped
> +        */
> +       for_each_path_target_class("thread", target) {
> +               struct thread *thread = target_to_thread(target);
> +               struct gdb_thread *gdb_thread = thread->gdbserver_priv;
> +
> +               if (pdbg_target_status(target) != PDBG_TARGET_ENABLED)
> +                       continue;
> +
> +               if (!gdb_thread->initial_stopped) {
> +                       if (thread_start(target)) {
> +                               PR_ERROR("Could not start thread %s\n",
> +                                        pdbg_target_path(target));
> +                       }
> +               }
> +       }
>
>         return 0;
>  }
> --
> 2.35.1
>
> --
> Pdbg mailing list
> Pdbg at lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/pdbg


More information about the Pdbg mailing list