qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v2 03/15] gdbstub: add multiprocess support to '


From: Philippe Mathieu-Daudé
Subject: Re: [Qemu-devel] [PATCH v2 03/15] gdbstub: add multiprocess support to 'H' and 'T' packets
Date: Mon, 1 Oct 2018 19:07:48 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.0

On 01/10/2018 13:56, Luc Michel wrote:
> Add a couple of helper functions to cope with GDB threads and processes.
> 
> The gdb_get_process() function looks for a process given a pid.
> 
> The gdb_get_cpu() function returns the CPU corresponding to the (pid,
> tid) pair given as parameters.
> 
> The read_thread_id() function parses the thread-id sent by the peer.
> This function supports the multiprocess extension thread-id syntax.  The
> return value specifies if the parsing failed, or if a special case was
> encountered (all processes or all threads).
> 
> Use them in 'H' and 'T' packets handling to support the multiprocess
> extension.
> 
> Signed-off-by: Luc Michel <address@hidden>
> ---
>  gdbstub.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++-------
>  1 file changed, 131 insertions(+), 18 deletions(-)
> 
> diff --git a/gdbstub.c b/gdbstub.c
> index ac9d540fda..a21ce3ca18 100644
> --- a/gdbstub.c
> +++ b/gdbstub.c
> @@ -667,10 +667,74 @@ static uint32_t gdb_get_cpu_pid(const GDBState *s, 
> CPUState *cpu)
>      }
>  
>      return pid + 1;
>  }
>  
> +static GDBProcess *gdb_get_process(const GDBState *s, uint32_t pid)
> +{
> +    uint32_t process_idx;
> +
> +    if (!pid) {
> +        /* 0 means any process, we take the first one */
> +        pid = 1;
> +    }
> +
> +    /* GDB PIDs are in the range [1;n] */
> +    process_idx = pid - 1;
> +
> +    if (process_idx >= s->process_num) {
> +        return NULL;
> +    }
> +
> +    return &s->processes[process_idx];
> +}
> +
> +static GDBProcess *gdb_get_cpu_process(const GDBState *s, CPUState *cpu)
> +{
> +    return gdb_get_process(s, gdb_get_cpu_pid(s, cpu));
> +}
> +
> +static CPUState *find_cpu(uint32_t thread_id)
> +{
> +    CPUState *cpu;
> +
> +    CPU_FOREACH(cpu) {
> +        if (cpu_gdb_index(cpu) == thread_id) {
> +            return cpu;
> +        }
> +    }
> +
> +    return NULL;
> +}
> +
> +static CPUState *gdb_get_cpu(const GDBState *s, uint32_t pid, uint32_t tid)
> +{
> +    GDBProcess *process;
> +    CPUState *cpu = find_cpu(tid);
> +
> +    if (!tid) {
> +        /* 0 means any thread, we take the first one */
> +        tid = 1;
> +    }
> +
> +    if (cpu == NULL) {
> +        return NULL;
> +    }
> +
> +    process = gdb_get_cpu_process(s, cpu);
> +
> +    if (process->pid != pid) {
> +        return NULL;
> +    }
> +
> +    if (!process->attached) {
> +        return NULL;
> +    }
> +
> +    return cpu;
> +}
> +
>  static const char *get_feature_xml(const char *p, const char **newp,
>                                     CPUClass *cc)
>  {
>      size_t len;
>      int i;
> @@ -923,23 +987,10 @@ static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
>  
>      cpu_synchronize_state(cpu);
>      cpu_set_pc(cpu, pc);
>  }
>  
> -static CPUState *find_cpu(uint32_t thread_id)
> -{
> -    CPUState *cpu;
> -
> -    CPU_FOREACH(cpu) {
> -        if (cpu_gdb_index(cpu) == thread_id) {
> -            return cpu;
> -        }
> -    }
> -
> -    return NULL;
> -}
> -
>  static char *gdb_fmt_thread_id(const GDBState *s, CPUState *cpu,
>                             char *buf, size_t buf_size)
>  {
>      if (s->multiprocess) {
>          snprintf(buf, buf_size, "p%02x.%02x",
> @@ -949,10 +1000,64 @@ static char *gdb_fmt_thread_id(const GDBState *s, 
> CPUState *cpu,
>      }
>  
>      return buf;
>  }
>  
> +typedef enum GDBThreadIdKind {
> +    GDB_ONE_THREAD = 0,
> +    GDB_ALL_THREADS,     /* One process, all threads */
> +    GDB_ALL_PROCESSES,
> +    GDB_READ_THREAD_ERR
> +} GDBThreadIdKind;
> +
> +static GDBThreadIdKind read_thread_id(const char *buf, const char **end_buf,
> +                                      uint32_t *pid, uint32_t *tid)
> +{
> +    unsigned long p, t;
> +    int ret;
> +
> +    if (*buf == 'p') {
> +        buf++;
> +        ret = qemu_strtoul(buf, &buf, 16, &p);
> +
> +        if (ret) {
> +            return GDB_READ_THREAD_ERR;
> +        }
> +
> +        /* Skip '.' */
> +        buf++;
> +    } else {
> +        p = 1;
> +    }
> +
> +    ret = qemu_strtoul(buf, &buf, 16, &t);
> +
> +    if (ret) {
> +        return GDB_READ_THREAD_ERR;
> +    }
> +
> +    *end_buf = buf;
> +
> +    if (p == -1) {
> +        return GDB_ALL_PROCESSES;
> +    }
> +
> +    if (pid) {
> +        *pid = p;
> +    }
> +
> +    if (t == -1) {
> +        return GDB_ALL_THREADS;
> +    }
> +
> +    if (tid) {
> +        *tid = t;
> +    }
> +
> +    return GDB_ONE_THREAD;
> +}
> +
>  static int is_query_packet(const char *p, const char *query, char separator)
>  {
>      unsigned int query_len = strlen(query);
>  
>      return strncmp(p, query, query_len) == 0 &&
> @@ -1057,16 +1162,18 @@ static int gdb_handle_packet(GDBState *s, const char 
> *line_buf)
>  {
>      CPUState *cpu;
>      CPUClass *cc;
>      const char *p;
>      uint32_t thread;
> +    uint32_t pid, tid;
>      int ch, reg_size, type, res;
>      uint8_t mem_buf[MAX_PACKET_LENGTH];
>      char buf[sizeof(mem_buf) + 1 /* trailing NUL */];
>      char thread_id[16];
>      uint8_t *registers;
>      target_ulong addr, len;
> +    GDBThreadIdKind thread_kind;
>  
>      trace_gdbstub_io_command(line_buf);
>  
>      p = line_buf;
>      ch = *p++;
> @@ -1270,16 +1377,22 @@ static int gdb_handle_packet(GDBState *s, const char 
> *line_buf)
>          else
>              put_packet(s, "E22");
>          break;
>      case 'H':
>          type = *p++;
> -        thread = strtoull(p, (char **)&p, 16);
> -        if (thread == -1 || thread == 0) {
> +
> +        thread_kind = read_thread_id(p, &p, &pid, &tid);
> +        if (thread_kind == GDB_READ_THREAD_ERR) {
> +            put_packet(s, "E22");
> +            break;
> +        }
> +
> +        if (thread_kind != GDB_ONE_THREAD) {
>              put_packet(s, "OK");
>              break;
>          }
> -        cpu = find_cpu(thread);
> +        cpu = gdb_get_cpu(s, pid, tid);
>          if (cpu == NULL) {
>              put_packet(s, "E22");
>              break;
>          }
>          switch (type) {
> @@ -1295,12 +1408,12 @@ static int gdb_handle_packet(GDBState *s, const char 
> *line_buf)
>               put_packet(s, "E22");
>               break;
>          }
>          break;
>      case 'T':
> -        thread = strtoull(p, (char **)&p, 16);
> -        cpu = find_cpu(thread);
> +        read_thread_id(p, &p, &pid, &tid);

This part can now be safer too:

           thread_kind = read_thread_id(p, &p, &pid, &tid);
           if (thread_kind == GDB_READ_THREAD_ERR) {
               put_packet(s, "E22");
               break;
           }

With this change:
Reviewed-by: Philippe Mathieu-Daudé <address@hidden>

> +        cpu = gdb_get_cpu(s, pid, tid);
>  
>          if (cpu != NULL) {
>              put_packet(s, "OK");
>          } else {
>              put_packet(s, "E22");
> 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]