qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Jan Kiszka <jan.kiszka@web.de>
To: Nathan Froyd <froydnj@codesourcery.com>
Cc: qemu-devel@nongnu.org
Subject: [Qemu-devel] Re: [PATCH] fix gdbstub support for multiple threads in usermode
Date: Tue, 12 May 2009 22:53:22 +0200	[thread overview]
Message-ID: <4A09E1C2.9020302@web.de> (raw)
In-Reply-To: <1242156943-27850-1-git-send-email-froydnj@codesourcery.com>

[-- Attachment #1: Type: text/plain, Size: 6414 bytes --]

Nathan Froyd wrote:
> When debugging multi-threaded programs, QEMU's gdb stub would report the
> correct number of threads (the qfThreadInfo and qsThreadInfo packets).
> However, the stub was unable to actually switch between threads (the T
> packet), since it would report every thread except the first as being
> dead.  Furthermore, the stub relied upon cpu_index as a reliable means
> of assigning IDs to the threads.  This was a bad idea; if you have this
> sequence of events:
> 
> initial thread created
> new thread #1
> new thread #2
> thread #1 exits
> new thread #3
> 
> thread #3 will have the same cpu_index as thread #1, which would confuse
> GDB.
> 
> We fix this by adding a stable gdbstub_index field for each CPU; the
> index is incremented for every CPU (thread) created.  We ignore
> wraparound issues for now.  Once we have this field, the stub needs to
> use this field instead of cpu_index for communicating with GDB.
> 
> Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
> ---
>  cpu-defs.h |    1 +
>  exec.c     |    5 +++++
>  gdbstub.c  |   32 +++++++++++++++++++++++---------
>  3 files changed, 29 insertions(+), 9 deletions(-)
> 
> diff --git a/cpu-defs.h b/cpu-defs.h
> index 0a82197..c923708 100644
> --- a/cpu-defs.h
> +++ b/cpu-defs.h
> @@ -207,6 +207,7 @@ typedef struct CPUWatchpoint {
>                                                                          \
>      CPUState *next_cpu; /* next CPU sharing TB cache */                 \
>      int cpu_index; /* CPU index (informative) */                        \
> +    int gdbstub_index; /* index for gdbstub T and H packets */          \
>      int numa_node; /* NUMA node this cpu is belonging to  */            \
>      int running; /* Nonzero if cpu is currently running(usermode).  */  \
>      /* user data */                                                     \
> diff --git a/exec.c b/exec.c
> index c5c9280..63e3411 100644
> --- a/exec.c
> +++ b/exec.c
> @@ -538,6 +538,8 @@ static int cpu_common_load(QEMUFile *f, void *opaque, int version_id)
>  }
>  #endif
>  
> +static int next_gdbstub_index;
> +
>  void cpu_exec_init(CPUState *env)
>  {
>      CPUState **penv;
> @@ -554,6 +556,7 @@ void cpu_exec_init(CPUState *env)
>          cpu_index++;
>      }
>      env->cpu_index = cpu_index;
> +    env->gdbstub_index = ++next_gdbstub_index;

While this is simple and sufficient for most cases, making
next_gdbstub_index robust against collisions due to overflow is not much
more complicated - so why not do this right from the beginning?

>      env->numa_node = 0;
>      TAILQ_INIT(&env->breakpoints);
>      TAILQ_INIT(&env->watchpoints);
> @@ -1711,6 +1714,8 @@ CPUState *cpu_copy(CPUState *env)
>                                wp->flags, NULL);
>      }
>  #endif
> +    /* Need to assign a new thread ID for the gdbstub */
> +    new_env->gdbstub_index = ++next_gdbstub_index;
>  
>      return new_env;
>  }
> diff --git a/gdbstub.c b/gdbstub.c
> index 3c34741..61b065b 100644
> --- a/gdbstub.c
> +++ b/gdbstub.c
> @@ -1718,9 +1718,11 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
>              put_packet(s, "OK");
>              break;
>          }
> -        for (env = first_cpu; env != NULL; env = env->next_cpu)
> -            if (env->cpu_index + 1 == thread)
> +        for (env = first_cpu; env != NULL; env = env->next_cpu) {
> +            if (env->gdbstub_index == thread) {
>                  break;
> +            }
> +        }
>          if (env == NULL) {
>              put_packet(s, "E22");
>              break;
> @@ -1741,14 +1743,25 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
>          break;
>      case 'T':
>          thread = strtoull(p, (char **)&p, 16);
> -#ifndef CONFIG_USER_ONLY
> -        if (thread > 0 && thread < smp_cpus + 1)
> +#if defined(CONFIG_USER_ONLY)
> +        {
> +            for (env = first_cpu; env != NULL; env = env->next_cpu) {
> +                if (env->gdbstub_index == thread) {
> +                    break;
> +                }
> +            }
> +
> +            if (env != NULL)
> +                put_packet(s, "OK");
> +            else
> +                put_packet(s, "E22");
> +        }
>  #else
> -        if (thread == 1)
> -#endif
> +        if (thread > 0 && thread < smp_cpus + 1)
>               put_packet(s, "OK");
>          else
>              put_packet(s, "E22");
> +#endif

I don't think we need these #ifdefs here. You assign continuously
increasing IDs also to system-mode CPUs, so we can handle them
identically (we have to anyway once cpu hotplugging hits upstream).

>          break;
>      case 'q':
>      case 'Q':
> @@ -1786,7 +1799,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
>          } else if (strcmp(p,"sThreadInfo") == 0) {
>          report_cpuinfo:
>              if (s->query_cpu) {
> -                snprintf(buf, sizeof(buf), "m%x", s->query_cpu->cpu_index+1);
> +                snprintf(buf, sizeof(buf), "m%x", s->query_cpu->gdbstub_index);
>                  put_packet(s, buf);
>                  s->query_cpu = s->query_cpu->next_cpu;
>              } else
> @@ -1794,8 +1807,8 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
>              break;
>          } else if (strncmp(p,"ThreadExtraInfo,", 16) == 0) {
>              thread = strtoull(p+16, (char **)&p, 16);
> -            for (env = first_cpu; env != NULL; env = env->next_cpu)
> -                if (env->cpu_index + 1 == thread) {
> +            for (env = first_cpu; env != NULL; env = env->next_cpu) {
> +                if (env->gdbstub_index == thread) {
>                      cpu_synchronize_state(env, 0);
>                      len = snprintf((char *)mem_buf, sizeof(mem_buf),
>                                     "CPU#%d [%s]", env->cpu_index,
> @@ -1804,6 +1817,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
>                      put_packet(s, buf);
>                      break;
>                  }
> +            }
>              break;
>          }
>  #ifdef CONFIG_USER_ONLY

Hmm, I bet you now have some use for my good-old vCont patch (=>continue
single-stepping on different CPU / in different thread). Will repost soon.

Jan


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 257 bytes --]

  reply	other threads:[~2009-05-12 20:54 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-05-12 19:35 [Qemu-devel] [PATCH] fix gdbstub support for multiple threads in usermode Nathan Froyd
2009-05-12 20:53 ` Jan Kiszka [this message]
2009-05-13  5:08   ` [Qemu-devel] " vibisreenivasan
2009-05-13 14:13   ` vibisreenivasan
2009-05-19 14:59     ` Nathan Froyd
2009-05-21  8:19       ` vibi sreenivasan
2009-05-19 15:06   ` Nathan Froyd
2009-05-19 16:53     ` Jan Kiszka
2009-05-19 18:01       ` Nathan Froyd
2009-05-20  6:39         ` Jan Kiszka
2009-05-20 15:27           ` Jamie Lokier

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4A09E1C2.9020302@web.de \
    --to=jan.kiszka@web.de \
    --cc=froydnj@codesourcery.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).