qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH  v2 00/14] gdbstub refactor and SVE support
@ 2019-11-30  8:45 Alex Bennée
  2019-11-30  8:45 ` [PATCH v2 01/14] gdbstub: make GDBState static and have common init function Alex Bennée
                   ` (14 more replies)
  0 siblings, 15 replies; 38+ messages in thread
From: Alex Bennée @ 2019-11-30  8:45 UTC (permalink / raw)
  To: qemu-devel
  Cc: damien.hedde, luis.machado, Alex Bennée, richard.henderson,
	alan.hayward

Hi,

So this is the first fully working version of the SVE gdbstub
implementation. As before the first set of patches are mostly
re-factoring of the gdbstub register interface. I include a new patch
to default the SVE size to a more reasonable number for linux-user to
mirror what the Linux kernel actually does. Finally the XML that QEMU
generates is closer to that of GDB in terms of the nesting of the
union and keeping all registers intact. If you enable the maximum VQ
you still end up with pages of text if you examine the vector
registers.

Finally I've added a bit more test harness for running gdbstub tests
and included a basic smoke test for SVE itself. It's still not plumbed
into the main test harness yet though as there are complications
caused by the available version of gdb. However I hope I can hide
these in the run-test.py script later and just skip tests that we know
won't work.

Alex Bennée (14):
  gdbstub: make GDBState static and have common init function
  gdbstub: stop passing GDBState * around and use global
  gdbstub: move str_buf to GDBState and use GString
  gdbstub: move mem_buf to GDBState and use GByteArray
  gdbstub: add helper for 128 bit registers
  target/arm: use gdb_get_reg helpers
  target/m68k: use gdb_get_reg helpers
  gdbstub: extend GByteArray to read register helpers
  target/arm: prepare for multiple dynamic XMLs
  target/arm: explicitly encode regnum in our XML
  target/arm: default SVE length to 64 bytes for linux-user
  target/arm: generate xml description of our SVE registers
  tests/guest-debug: add a simple test runner
  tests/tcg: add a gdbstub testcase for SVE registers

 include/exec/gdbstub.h                |  49 +-
 include/hw/core/cpu.h                 |   2 +-
 target/alpha/cpu.h                    |   2 +-
 target/arm/cpu.h                      |  34 +-
 target/cris/cpu.h                     |   4 +-
 target/hppa/cpu.h                     |   2 +-
 target/i386/cpu.h                     |   2 +-
 target/lm32/cpu.h                     |   2 +-
 target/m68k/cpu.h                     |   2 +-
 target/microblaze/cpu.h               |   2 +-
 target/mips/internal.h                |   2 +-
 target/openrisc/cpu.h                 |   2 +-
 target/ppc/cpu.h                      |   4 +-
 target/riscv/cpu.h                    |   2 +-
 target/s390x/internal.h               |   2 +-
 target/sh4/cpu.h                      |   2 +-
 target/sparc/cpu.h                    |   2 +-
 target/xtensa/cpu.h                   |   2 +-
 gdbstub.c                             | 892 +++++++++++++-------------
 hw/core/cpu.c                         |   2 +-
 target/alpha/gdbstub.c                |   2 +-
 target/arm/cpu64.c                    |   3 +
 target/arm/gdbstub.c                  | 169 ++++-
 target/arm/gdbstub64.c                |   2 +-
 target/arm/helper.c                   | 151 ++++-
 target/cris/gdbstub.c                 |   4 +-
 target/hppa/gdbstub.c                 |   2 +-
 target/i386/gdbstub.c                 |   2 +-
 target/lm32/gdbstub.c                 |   2 +-
 target/m68k/gdbstub.c                 |   2 +-
 target/m68k/helper.c                  |  33 +-
 target/microblaze/gdbstub.c           |   2 +-
 target/mips/gdbstub.c                 |   2 +-
 target/nios2/cpu.c                    |   2 +-
 target/openrisc/gdbstub.c             |   2 +-
 target/ppc/gdbstub.c                  |  48 +-
 target/ppc/translate_init.inc.c       |  54 +-
 target/riscv/gdbstub.c                |  18 +-
 target/s390x/gdbstub.c                |  30 +-
 target/sh4/gdbstub.c                  |   2 +-
 target/sparc/gdbstub.c                |   2 +-
 target/xtensa/gdbstub.c               |   2 +-
 tests/.gitignore                      |   1 +
 tests/guest-debug/run-test.py         |  57 ++
 tests/tcg/aarch64/gdbstub/test-sve.py |  75 +++
 45 files changed, 1038 insertions(+), 644 deletions(-)
 create mode 100755 tests/guest-debug/run-test.py
 create mode 100644 tests/tcg/aarch64/gdbstub/test-sve.py

-- 
2.20.1



^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v2 01/14] gdbstub: make GDBState static and have common init function
  2019-11-30  8:45 [PATCH v2 00/14] gdbstub refactor and SVE support Alex Bennée
@ 2019-11-30  8:45 ` Alex Bennée
  2019-12-02  2:14   ` Richard Henderson
  2019-12-02 14:35   ` Damien Hedde
  2019-11-30  8:45 ` [PATCH v2 02/14] gdbstub: stop passing GDBState * around and use global Alex Bennée
                   ` (13 subsequent siblings)
  14 siblings, 2 replies; 38+ messages in thread
From: Alex Bennée @ 2019-11-30  8:45 UTC (permalink / raw)
  To: qemu-devel
  Cc: damien.hedde, luis.machado, Philippe Mathieu-Daudé,
	richard.henderson, alan.hayward, Alex Bennée

Instead of allocating make this entirely static. We shall reduce the
size of the structure in later commits and dynamically allocate parts
of it. We introduce an init and reset helper function to keep all the
manipulation in one place.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Cc: Damien Hedde <damien.hedde@greensocs.com>
Cc: Richard Henderson <richard.henderson@linaro.org>

---
v2
  - made entirely static, dropped dh/rth r-b tags due to changes
---
 gdbstub.c | 168 ++++++++++++++++++++++++++----------------------------
 1 file changed, 81 insertions(+), 87 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 4cf8af365e2..36b1d7a9408 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -342,6 +342,7 @@ enum RSState {
     RS_CHKSUM2,
 };
 typedef struct GDBState {
+    bool init;       /* have we been initialised? */
     CPUState *c_cpu; /* current CPU for step/continue ops */
     CPUState *g_cpu; /* current CPU for other ops */
     CPUState *query_cpu; /* for q{f|s}ThreadInfo */
@@ -372,7 +373,23 @@ typedef struct GDBState {
  */
 static int sstep_flags = SSTEP_ENABLE|SSTEP_NOIRQ|SSTEP_NOTIMER;
 
-static GDBState *gdbserver_state;
+static GDBState gdbserver_state;
+
+static void init_gdbserver_state(void)
+{
+    g_assert(!gdbserver_state.init);
+    memset(&gdbserver_state, 0, sizeof(GDBState));
+    gdbserver_state.init = true;
+}
+
+#ifndef CONFIG_USER_ONLY
+static void reset_gdbserver_state(void)
+{
+    g_free(gdbserver_state.processes);
+    gdbserver_state.processes = NULL;
+    gdbserver_state.process_num = 0;
+}
+#endif
 
 bool gdb_has_xml;
 
@@ -425,8 +442,8 @@ int use_gdb_syscalls(void)
     /* -semihosting-config target=auto */
     /* On the first call check if gdb is connected and remember. */
     if (gdb_syscall_mode == GDB_SYS_UNKNOWN) {
-        gdb_syscall_mode = (gdbserver_state ? GDB_SYS_ENABLED
-                                            : GDB_SYS_DISABLED);
+        gdb_syscall_mode = gdbserver_state.init ?
+            GDB_SYS_ENABLED : GDB_SYS_DISABLED;
     }
     return gdb_syscall_mode == GDB_SYS_ENABLED;
 }
@@ -984,7 +1001,7 @@ static int gdb_breakpoint_insert(int type, target_ulong addr, target_ulong len)
     int err = 0;
 
     if (kvm_enabled()) {
-        return kvm_insert_breakpoint(gdbserver_state->c_cpu, addr, len, type);
+        return kvm_insert_breakpoint(gdbserver_state.c_cpu, addr, len, type);
     }
 
     switch (type) {
@@ -1021,7 +1038,7 @@ static int gdb_breakpoint_remove(int type, target_ulong addr, target_ulong len)
     int err = 0;
 
     if (kvm_enabled()) {
-        return kvm_remove_breakpoint(gdbserver_state->c_cpu, addr, len, type);
+        return kvm_remove_breakpoint(gdbserver_state.c_cpu, addr, len, type);
     }
 
     switch (type) {
@@ -1074,7 +1091,7 @@ static void gdb_breakpoint_remove_all(void)
     CPUState *cpu;
 
     if (kvm_enabled()) {
-        kvm_remove_all_breakpoints(gdbserver_state->c_cpu);
+        kvm_remove_all_breakpoints(gdbserver_state.c_cpu);
         return;
     }
 
@@ -2601,7 +2618,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
 
 void gdb_set_stop_cpu(CPUState *cpu)
 {
-    GDBProcess *p = gdb_get_cpu_process(gdbserver_state, cpu);
+    GDBProcess *p = gdb_get_cpu_process(&gdbserver_state, cpu);
 
     if (!p->attached) {
         /*
@@ -2611,14 +2628,14 @@ void gdb_set_stop_cpu(CPUState *cpu)
         return;
     }
 
-    gdbserver_state->c_cpu = cpu;
-    gdbserver_state->g_cpu = cpu;
+    gdbserver_state.c_cpu = cpu;
+    gdbserver_state.g_cpu = cpu;
 }
 
 #ifndef CONFIG_USER_ONLY
 static void gdb_vm_state_change(void *opaque, int running, RunState state)
 {
-    GDBState *s = gdbserver_state;
+    GDBState *s = &gdbserver_state;
     CPUState *cpu = s->c_cpu;
     char buf[256];
     char thread_id[16];
@@ -2722,17 +2739,16 @@ void gdb_do_syscallv(gdb_syscall_complete_cb cb, const char *fmt, va_list va)
     char *p_end;
     target_ulong addr;
     uint64_t i64;
-    GDBState *s;
 
-    s = gdbserver_state;
-    if (!s)
+    if (!gdbserver_state.init)
         return;
-    s->current_syscall_cb = cb;
+
+    gdbserver_state.current_syscall_cb = cb;
 #ifndef CONFIG_USER_ONLY
     vm_stop(RUN_STATE_DEBUG);
 #endif
-    p = s->syscall_buf;
-    p_end = &s->syscall_buf[sizeof(s->syscall_buf)];
+    p = &gdbserver_state.syscall_buf[0];
+    p_end = &gdbserver_state.syscall_buf[sizeof(gdbserver_state.syscall_buf)];
     *(p++) = 'F';
     while (*fmt) {
         if (*fmt == '%') {
@@ -2765,14 +2781,14 @@ void gdb_do_syscallv(gdb_syscall_complete_cb cb, const char *fmt, va_list va)
     }
     *p = 0;
 #ifdef CONFIG_USER_ONLY
-    put_packet(s, s->syscall_buf);
+    put_packet(&gdbserver_state, gdbserver_state.syscall_buf);
     /* Return control to gdb for it to process the syscall request.
      * Since the protocol requires that gdb hands control back to us
      * using a "here are the results" F packet, we don't need to check
      * gdb_handlesig's return value (which is the signal to deliver if
      * execution was resumed via a continue packet).
      */
-    gdb_handlesig(s->c_cpu, 0);
+    gdb_handlesig(gdbserver_state.c_cpu, 0);
 #else
     /* In this case wait to send the syscall packet until notification that
        the CPU has stopped.  This must be done because if the packet is sent
@@ -2780,7 +2796,7 @@ void gdb_do_syscallv(gdb_syscall_complete_cb cb, const char *fmt, va_list va)
        is still in the running state, which can cause packets to be dropped
        and state transition 'T' packets to be sent while the syscall is still
        being processed.  */
-    qemu_cpu_kick(s->c_cpu);
+    qemu_cpu_kick(gdbserver_state.c_cpu);
 #endif
 }
 
@@ -2941,15 +2957,13 @@ static void gdb_read_byte(GDBState *s, uint8_t ch)
 /* Tell the remote gdb that the process has exited.  */
 void gdb_exit(CPUArchState *env, int code)
 {
-  GDBState *s;
   char buf[4];
 
-  s = gdbserver_state;
-  if (!s) {
+  if (!gdbserver_state.init) {
       return;
   }
 #ifdef CONFIG_USER_ONLY
-  if (gdbserver_fd < 0 || s->fd < 0) {
+  if (gdbserver_fd < 0 || gdbserver_state.fd < 0) {
       return;
   }
 #endif
@@ -2957,10 +2971,10 @@ void gdb_exit(CPUArchState *env, int code)
   trace_gdbstub_op_exiting((uint8_t)code);
 
   snprintf(buf, sizeof(buf), "W%02x", (uint8_t)code);
-  put_packet(s, buf);
+  put_packet(&gdbserver_state, buf);
 
 #ifndef CONFIG_USER_ONLY
-  qemu_chr_fe_deinit(&s->chr, true);
+  qemu_chr_fe_deinit(&gdbserver_state.chr, true);
 #endif
 }
 
@@ -2993,12 +3007,10 @@ static void create_default_process(GDBState *s)
 int
 gdb_handlesig(CPUState *cpu, int sig)
 {
-    GDBState *s;
     char buf[256];
     int n;
 
-    s = gdbserver_state;
-    if (gdbserver_fd < 0 || s->fd < 0) {
+    if (gdbserver_fd < 0 || gdbserver_state.fd < 0) {
         return sig;
     }
 
@@ -3008,58 +3020,55 @@ gdb_handlesig(CPUState *cpu, int sig)
 
     if (sig != 0) {
         snprintf(buf, sizeof(buf), "S%02x", target_signal_to_gdb(sig));
-        put_packet(s, buf);
+        put_packet(&gdbserver_state, buf);
     }
     /* put_packet() might have detected that the peer terminated the
        connection.  */
-    if (s->fd < 0) {
+    if (gdbserver_state.fd < 0) {
         return sig;
     }
 
     sig = 0;
-    s->state = RS_IDLE;
-    s->running_state = 0;
-    while (s->running_state == 0) {
-        n = read(s->fd, buf, 256);
+    gdbserver_state.state = RS_IDLE;
+    gdbserver_state.running_state = 0;
+    while (gdbserver_state.running_state == 0) {
+        n = read(gdbserver_state.fd, buf, 256);
         if (n > 0) {
             int i;
 
             for (i = 0; i < n; i++) {
-                gdb_read_byte(s, buf[i]);
+                gdb_read_byte(&gdbserver_state, buf[i]);
             }
         } else {
             /* XXX: Connection closed.  Should probably wait for another
                connection before continuing.  */
             if (n == 0) {
-                close(s->fd);
+                close(gdbserver_state.fd);
             }
-            s->fd = -1;
+            gdbserver_state.fd = -1;
             return sig;
         }
     }
-    sig = s->signal;
-    s->signal = 0;
+    sig = gdbserver_state.signal;
+    gdbserver_state.signal = 0;
     return sig;
 }
 
 /* Tell the remote gdb that the process has exited due to SIG.  */
 void gdb_signalled(CPUArchState *env, int sig)
 {
-    GDBState *s;
     char buf[4];
 
-    s = gdbserver_state;
-    if (gdbserver_fd < 0 || s->fd < 0) {
+    if (gdbserver_fd < 0 || gdbserver_state.fd < 0) {
         return;
     }
 
     snprintf(buf, sizeof(buf), "X%02x", target_signal_to_gdb(sig));
-    put_packet(s, buf);
+    put_packet(&gdbserver_state, buf);
 }
 
 static bool gdb_accept(void)
 {
-    GDBState *s;
     struct sockaddr_in sockaddr;
     socklen_t len;
     int fd;
@@ -3083,15 +3092,13 @@ static bool gdb_accept(void)
         return false;
     }
 
-    s = g_malloc0(sizeof(GDBState));
-    create_default_process(s);
-    s->processes[0].attached = true;
-    s->c_cpu = gdb_first_attached_cpu(s);
-    s->g_cpu = s->c_cpu;
-    s->fd = fd;
+    init_gdbserver_state();
+    create_default_process(&gdbserver_state);
+    gdbserver_state.processes[0].attached = true;
+    gdbserver_state.c_cpu = gdb_first_attached_cpu(&gdbserver_state);
+    gdbserver_state.g_cpu = gdbserver_state.c_cpu;
+    gdbserver_state.fd = fd;
     gdb_has_xml = false;
-
-    gdbserver_state = s;
     return true;
 }
 
@@ -3144,13 +3151,11 @@ int gdbserver_start(int port)
 /* Disable gdb stub for child processes.  */
 void gdbserver_fork(CPUState *cpu)
 {
-    GDBState *s = gdbserver_state;
-
-    if (gdbserver_fd < 0 || s->fd < 0) {
+    if (gdbserver_fd < 0 || gdbserver_state.fd < 0) {
         return;
     }
-    close(s->fd);
-    s->fd = -1;
+    close(gdbserver_state.fd);
+    gdbserver_state.fd = -1;
     cpu_breakpoint_remove_all(cpu, BP_GDB);
     cpu_watchpoint_remove_all(cpu, BP_GDB);
 }
@@ -3167,7 +3172,7 @@ static void gdb_chr_receive(void *opaque, const uint8_t *buf, int size)
     int i;
 
     for (i = 0; i < size; i++) {
-        gdb_read_byte(gdbserver_state, buf[i]);
+        gdb_read_byte(&gdbserver_state, buf[i]);
     }
 }
 
@@ -3210,13 +3215,13 @@ static int gdb_monitor_write(Chardev *chr, const uint8_t *buf, int len)
     const char *p = (const char *)buf;
     int max_sz;
 
-    max_sz = (sizeof(gdbserver_state->last_packet) - 2) / 2;
+    max_sz = (sizeof(gdbserver_state.last_packet) - 2) / 2;
     for (;;) {
         if (len <= max_sz) {
-            gdb_monitor_output(gdbserver_state, p, len);
+            gdb_monitor_output(&gdbserver_state, p, len);
             break;
         }
-        gdb_monitor_output(gdbserver_state, p, max_sz);
+        gdb_monitor_output(&gdbserver_state, p, max_sz);
         p += max_sz;
         len -= max_sz;
     }
@@ -3308,18 +3313,10 @@ static void create_processes(GDBState *s)
     create_default_process(s);
 }
 
-static void cleanup_processes(GDBState *s)
-{
-    g_free(s->processes);
-    s->process_num = 0;
-    s->processes = NULL;
-}
-
 int gdbserver_start(const char *device)
 {
     trace_gdbstub_op_start(device);
 
-    GDBState *s;
     char gdbstub_device_name[128];
     Chardev *chr = NULL;
     Chardev *mon_chr;
@@ -3357,10 +3354,8 @@ int gdbserver_start(const char *device)
             return -1;
     }
 
-    s = gdbserver_state;
-    if (!s) {
-        s = g_malloc0(sizeof(GDBState));
-        gdbserver_state = s;
+    if (!gdbserver_state.init) {
+        init_gdbserver_state();
 
         qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL);
 
@@ -3369,31 +3364,30 @@ int gdbserver_start(const char *device)
                                    NULL, NULL, &error_abort);
         monitor_init_hmp(mon_chr, false);
     } else {
-        qemu_chr_fe_deinit(&s->chr, true);
-        mon_chr = s->mon_chr;
-        cleanup_processes(s);
-        memset(s, 0, sizeof(GDBState));
-        s->mon_chr = mon_chr;
+        qemu_chr_fe_deinit(&gdbserver_state.chr, true);
+        mon_chr = gdbserver_state.mon_chr;
+        reset_gdbserver_state();
     }
 
-    create_processes(s);
+    create_processes(&gdbserver_state);
 
     if (chr) {
-        qemu_chr_fe_init(&s->chr, chr, &error_abort);
-        qemu_chr_fe_set_handlers(&s->chr, gdb_chr_can_receive, gdb_chr_receive,
-                                 gdb_chr_event, NULL, s, NULL, true);
+        qemu_chr_fe_init(&gdbserver_state.chr, chr, &error_abort);
+        qemu_chr_fe_set_handlers(&gdbserver_state.chr, gdb_chr_can_receive,
+                                 gdb_chr_receive, gdb_chr_event,
+                                 NULL, &gdbserver_state, NULL, true);
     }
-    s->state = chr ? RS_IDLE : RS_INACTIVE;
-    s->mon_chr = mon_chr;
-    s->current_syscall_cb = NULL;
+    gdbserver_state.state = chr ? RS_IDLE : RS_INACTIVE;
+    gdbserver_state.mon_chr = mon_chr;
+    gdbserver_state.current_syscall_cb = NULL;
 
     return 0;
 }
 
 void gdbserver_cleanup(void)
 {
-    if (gdbserver_state) {
-        put_packet(gdbserver_state, "W00");
+    if (gdbserver_state.init) {
+        put_packet(&gdbserver_state, "W00");
     }
 }
 
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v2 02/14] gdbstub: stop passing GDBState * around and use global
  2019-11-30  8:45 [PATCH v2 00/14] gdbstub refactor and SVE support Alex Bennée
  2019-11-30  8:45 ` [PATCH v2 01/14] gdbstub: make GDBState static and have common init function Alex Bennée
@ 2019-11-30  8:45 ` Alex Bennée
  2019-12-02  2:16   ` Richard Henderson
  2019-12-02 15:25   ` Damien Hedde
  2019-11-30  8:45 ` [PATCH v2 03/14] gdbstub: move str_buf to GDBState and use GString Alex Bennée
                   ` (12 subsequent siblings)
  14 siblings, 2 replies; 38+ messages in thread
From: Alex Bennée @ 2019-11-30  8:45 UTC (permalink / raw)
  To: qemu-devel
  Cc: damien.hedde, luis.machado, Philippe Mathieu-Daudé,
	richard.henderson, alan.hayward, Alex Bennée

We only have one GDBState which should be allocated at the time we
process any commands. This will make further clean-up a bit easier.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 gdbstub.c | 539 +++++++++++++++++++++++++++---------------------------
 1 file changed, 267 insertions(+), 272 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 36b1d7a9408..23f513f709e 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -397,21 +397,21 @@ bool gdb_has_xml;
 /* XXX: This is not thread safe.  Do we care?  */
 static int gdbserver_fd = -1;
 
-static int get_char(GDBState *s)
+static int get_char(void)
 {
     uint8_t ch;
     int ret;
 
     for(;;) {
-        ret = qemu_recv(s->fd, &ch, 1, 0);
+        ret = qemu_recv(gdbserver_state.fd, &ch, 1, 0);
         if (ret < 0) {
             if (errno == ECONNRESET)
-                s->fd = -1;
+                gdbserver_state.fd = -1;
             if (errno != EINTR)
                 return -1;
         } else if (ret == 0) {
-            close(s->fd);
-            s->fd = -1;
+            close(gdbserver_state.fd);
+            gdbserver_state.fd = -1;
             return -1;
         } else {
             break;
@@ -449,11 +449,11 @@ int use_gdb_syscalls(void)
 }
 
 /* Resume execution.  */
-static inline void gdb_continue(GDBState *s)
+static inline void gdb_continue(void)
 {
 
 #ifdef CONFIG_USER_ONLY
-    s->running_state = 1;
+    gdbserver_state.running_state = 1;
     trace_gdbstub_op_continue();
 #else
     if (!runstate_needs_reset()) {
@@ -467,7 +467,7 @@ static inline void gdb_continue(GDBState *s)
  * Resume execution, per CPU actions. For user-mode emulation it's
  * equivalent to gdb_continue.
  */
-static int gdb_continue_partial(GDBState *s, char *newstates)
+static int gdb_continue_partial(char *newstates)
 {
     CPUState *cpu;
     int res = 0;
@@ -482,7 +482,7 @@ static int gdb_continue_partial(GDBState *s, char *newstates)
             cpu_single_step(cpu, sstep_flags);
         }
     }
-    s->running_state = 1;
+    gdbserver_state.running_state = 1;
 #else
     int flag = 0;
 
@@ -520,13 +520,13 @@ static int gdb_continue_partial(GDBState *s, char *newstates)
     return res;
 }
 
-static void put_buffer(GDBState *s, const uint8_t *buf, int len)
+static void put_buffer(const uint8_t *buf, int len)
 {
 #ifdef CONFIG_USER_ONLY
     int ret;
 
     while (len > 0) {
-        ret = send(s->fd, buf, len, 0);
+        ret = send(gdbserver_state.fd, buf, len, 0);
         if (ret < 0) {
             if (errno != EINTR)
                 return;
@@ -538,7 +538,7 @@ static void put_buffer(GDBState *s, const uint8_t *buf, int len)
 #else
     /* XXX this blocks entire thread. Rewrite to use
      * qemu_chr_fe_write and background I/O callbacks */
-    qemu_chr_fe_write_all(&s->chr, buf, len);
+    qemu_chr_fe_write_all(&gdbserver_state.chr, buf, len);
 #endif
 }
 
@@ -620,17 +620,18 @@ static void hexdump(const char *buf, int len,
 }
 
 /* return -1 if error, 0 if OK */
-static int put_packet_binary(GDBState *s, const char *buf, int len, bool dump)
+static int put_packet_binary(const char *buf, int len, bool dump)
 {
     int csum, i;
     uint8_t *p;
+    uint8_t *ps = &gdbserver_state.last_packet[0];
 
     if (dump && trace_event_get_state_backends(TRACE_GDBSTUB_IO_BINARYREPLY)) {
         hexdump(buf, len, trace_gdbstub_io_binaryreply);
     }
 
     for(;;) {
-        p = s->last_packet;
+        p = ps;
         *(p++) = '$';
         memcpy(p, buf, len);
         p += len;
@@ -642,11 +643,11 @@ static int put_packet_binary(GDBState *s, const char *buf, int len, bool dump)
         *(p++) = tohex((csum >> 4) & 0xf);
         *(p++) = tohex((csum) & 0xf);
 
-        s->last_packet_len = p - s->last_packet;
-        put_buffer(s, (uint8_t *)s->last_packet, s->last_packet_len);
+        gdbserver_state.last_packet_len = p - ps;
+        put_buffer(ps, gdbserver_state.last_packet_len);
 
 #ifdef CONFIG_USER_ONLY
-        i = get_char(s);
+        i = get_char();
         if (i < 0)
             return -1;
         if (i == '+')
@@ -659,11 +660,11 @@ static int put_packet_binary(GDBState *s, const char *buf, int len, bool dump)
 }
 
 /* return -1 if error, 0 if OK */
-static int put_packet(GDBState *s, const char *buf)
+static int put_packet(const char *buf)
 {
     trace_gdbstub_io_reply(buf);
 
-    return put_packet_binary(s, buf, strlen(buf), false);
+    return put_packet_binary(buf, strlen(buf), false);
 }
 
 /* Encode data using the encoding for 'x' packets.  */
@@ -687,37 +688,38 @@ static int memtox(char *buf, const char *mem, int len)
     return p - buf;
 }
 
-static uint32_t gdb_get_cpu_pid(const GDBState *s, CPUState *cpu)
+static uint32_t gdb_get_cpu_pid(CPUState *cpu)
 {
     /* TODO: In user mode, we should use the task state PID */
     if (cpu->cluster_index == UNASSIGNED_CLUSTER_INDEX) {
         /* Return the default process' PID */
-        return s->processes[s->process_num - 1].pid;
+        int index = gdbserver_state.process_num - 1;
+        return gdbserver_state.processes[index].pid;
     }
     return cpu->cluster_index + 1;
 }
 
-static GDBProcess *gdb_get_process(const GDBState *s, uint32_t pid)
+static GDBProcess *gdb_get_process(uint32_t pid)
 {
     int i;
 
     if (!pid) {
         /* 0 means any process, we take the first one */
-        return &s->processes[0];
+        return &gdbserver_state.processes[0];
     }
 
-    for (i = 0; i < s->process_num; i++) {
-        if (s->processes[i].pid == pid) {
-            return &s->processes[i];
+    for (i = 0; i < gdbserver_state.process_num; i++) {
+        if (gdbserver_state.processes[i].pid == pid) {
+            return &gdbserver_state.processes[i];
         }
     }
 
     return NULL;
 }
 
-static GDBProcess *gdb_get_cpu_process(const GDBState *s, CPUState *cpu)
+static GDBProcess *gdb_get_cpu_process(CPUState *cpu)
 {
-    return gdb_get_process(s, gdb_get_cpu_pid(s, cpu));
+    return gdb_get_process(gdb_get_cpu_pid(cpu));
 }
 
 static CPUState *find_cpu(uint32_t thread_id)
@@ -733,13 +735,12 @@ static CPUState *find_cpu(uint32_t thread_id)
     return NULL;
 }
 
-static CPUState *get_first_cpu_in_process(const GDBState *s,
-                                          GDBProcess *process)
+static CPUState *get_first_cpu_in_process(GDBProcess *process)
 {
     CPUState *cpu;
 
     CPU_FOREACH(cpu) {
-        if (gdb_get_cpu_pid(s, cpu) == process->pid) {
+        if (gdb_get_cpu_pid(cpu) == process->pid) {
             return cpu;
         }
     }
@@ -747,13 +748,13 @@ static CPUState *get_first_cpu_in_process(const GDBState *s,
     return NULL;
 }
 
-static CPUState *gdb_next_cpu_in_process(const GDBState *s, CPUState *cpu)
+static CPUState *gdb_next_cpu_in_process(CPUState *cpu)
 {
-    uint32_t pid = gdb_get_cpu_pid(s, cpu);
+    uint32_t pid = gdb_get_cpu_pid(cpu);
     cpu = CPU_NEXT(cpu);
 
     while (cpu) {
-        if (gdb_get_cpu_pid(s, cpu) == pid) {
+        if (gdb_get_cpu_pid(cpu) == pid) {
             break;
         }
 
@@ -764,12 +765,12 @@ static CPUState *gdb_next_cpu_in_process(const GDBState *s, CPUState *cpu)
 }
 
 /* Return the cpu following @cpu, while ignoring unattached processes. */
-static CPUState *gdb_next_attached_cpu(const GDBState *s, CPUState *cpu)
+static CPUState *gdb_next_attached_cpu(CPUState *cpu)
 {
     cpu = CPU_NEXT(cpu);
 
     while (cpu) {
-        if (gdb_get_cpu_process(s, cpu)->attached) {
+        if (gdb_get_cpu_process(cpu)->attached) {
             break;
         }
 
@@ -780,29 +781,29 @@ static CPUState *gdb_next_attached_cpu(const GDBState *s, CPUState *cpu)
 }
 
 /* Return the first attached cpu */
-static CPUState *gdb_first_attached_cpu(const GDBState *s)
+static CPUState *gdb_first_attached_cpu(void)
 {
     CPUState *cpu = first_cpu;
-    GDBProcess *process = gdb_get_cpu_process(s, cpu);
+    GDBProcess *process = gdb_get_cpu_process(cpu);
 
     if (!process->attached) {
-        return gdb_next_attached_cpu(s, cpu);
+        return gdb_next_attached_cpu(cpu);
     }
 
     return cpu;
 }
 
-static CPUState *gdb_get_cpu(const GDBState *s, uint32_t pid, uint32_t tid)
+static CPUState *gdb_get_cpu(uint32_t pid, uint32_t tid)
 {
     GDBProcess *process;
     CPUState *cpu;
 
     if (!pid && !tid) {
         /* 0 means any process/thread, we take the first attached one */
-        return gdb_first_attached_cpu(s);
+        return gdb_first_attached_cpu();
     } else if (pid && !tid) {
         /* any thread in a specific process */
-        process = gdb_get_process(s, pid);
+        process = gdb_get_process(pid);
 
         if (process == NULL) {
             return NULL;
@@ -812,7 +813,7 @@ static CPUState *gdb_get_cpu(const GDBState *s, uint32_t pid, uint32_t tid)
             return NULL;
         }
 
-        return get_first_cpu_in_process(s, process);
+        return get_first_cpu_in_process(process);
     } else {
         /* a specific thread */
         cpu = find_cpu(tid);
@@ -821,7 +822,7 @@ static CPUState *gdb_get_cpu(const GDBState *s, uint32_t pid, uint32_t tid)
             return NULL;
         }
 
-        process = gdb_get_cpu_process(s, cpu);
+        process = gdb_get_cpu_process(cpu);
 
         if (pid && process->pid != pid) {
             return NULL;
@@ -835,13 +836,13 @@ static CPUState *gdb_get_cpu(const GDBState *s, uint32_t pid, uint32_t tid)
     }
 }
 
-static const char *get_feature_xml(const GDBState *s, const char *p,
-                                   const char **newp, GDBProcess *process)
+static const char *get_feature_xml(const char *p, const char **newp,
+                                   GDBProcess *process)
 {
     size_t len;
     int i;
     const char *name;
-    CPUState *cpu = get_first_cpu_in_process(s, process);
+    CPUState *cpu = get_first_cpu_in_process(process);
     CPUClass *cc = CPU_GET_CLASS(cpu);
 
     len = 0;
@@ -1076,13 +1077,13 @@ static inline void gdb_cpu_breakpoint_remove_all(CPUState *cpu)
 #endif
 }
 
-static void gdb_process_breakpoint_remove_all(const GDBState *s, GDBProcess *p)
+static void gdb_process_breakpoint_remove_all(GDBProcess *p)
 {
-    CPUState *cpu = get_first_cpu_in_process(s, p);
+    CPUState *cpu = get_first_cpu_in_process(p);
 
     while (cpu) {
         gdb_cpu_breakpoint_remove_all(cpu);
-        cpu = gdb_next_cpu_in_process(s, cpu);
+        cpu = gdb_next_cpu_in_process(cpu);
     }
 }
 
@@ -1100,20 +1101,19 @@ static void gdb_breakpoint_remove_all(void)
     }
 }
 
-static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
+static void gdb_set_cpu_pc(target_ulong pc)
 {
-    CPUState *cpu = s->c_cpu;
+    CPUState *cpu = gdbserver_state.c_cpu;
 
     cpu_synchronize_state(cpu);
     cpu_set_pc(cpu, pc);
 }
 
-static char *gdb_fmt_thread_id(const GDBState *s, CPUState *cpu,
-                           char *buf, size_t buf_size)
+static char *gdb_fmt_thread_id(CPUState *cpu, char *buf, size_t buf_size)
 {
-    if (s->multiprocess) {
+    if (gdbserver_state.multiprocess) {
         snprintf(buf, buf_size, "p%02x.%02x",
-                 gdb_get_cpu_pid(s, cpu), cpu_gdb_index(cpu));
+                 gdb_get_cpu_pid(cpu), cpu_gdb_index(cpu));
     } else {
         snprintf(buf, buf_size, "%02x", cpu_gdb_index(cpu));
     }
@@ -1180,7 +1180,7 @@ static GDBThreadIdKind read_thread_id(const char *buf, const char **end_buf,
  * returns -ENOTSUP if a command is unsupported, -EINVAL or -ERANGE if there is
  *         a format error, 0 on success.
  */
-static int gdb_handle_vcont(GDBState *s, const char *p)
+static int gdb_handle_vcont(const char *p)
 {
     int res, signal = 0;
     char cur_action;
@@ -1255,36 +1255,36 @@ static int gdb_handle_vcont(GDBState *s, const char *p)
             goto out;
 
         case GDB_ALL_PROCESSES:
-            cpu = gdb_first_attached_cpu(s);
+            cpu = gdb_first_attached_cpu();
             while (cpu) {
                 if (newstates[cpu->cpu_index] == 1) {
                     newstates[cpu->cpu_index] = cur_action;
                 }
 
-                cpu = gdb_next_attached_cpu(s, cpu);
+                cpu = gdb_next_attached_cpu(cpu);
             }
             break;
 
         case GDB_ALL_THREADS:
-            process = gdb_get_process(s, pid);
+            process = gdb_get_process(pid);
 
             if (!process->attached) {
                 res = -EINVAL;
                 goto out;
             }
 
-            cpu = get_first_cpu_in_process(s, process);
+            cpu = get_first_cpu_in_process(process);
             while (cpu) {
                 if (newstates[cpu->cpu_index] == 1) {
                     newstates[cpu->cpu_index] = cur_action;
                 }
 
-                cpu = gdb_next_cpu_in_process(s, cpu);
+                cpu = gdb_next_cpu_in_process(cpu);
             }
             break;
 
         case GDB_ONE_THREAD:
-            cpu = gdb_get_cpu(s, pid, tid);
+            cpu = gdb_get_cpu(pid, tid);
 
             /* invalid CPU/thread specified */
             if (!cpu) {
@@ -1299,8 +1299,8 @@ static int gdb_handle_vcont(GDBState *s, const char *p)
             break;
         }
     }
-    s->signal = signal;
-    gdb_continue_partial(s, newstates);
+    gdbserver_state.signal = signal;
+    gdb_continue_partial(newstates);
 
 out:
     g_free(newstates);
@@ -1409,7 +1409,6 @@ static int cmd_parse_params(const char *data, const char *schema,
 }
 
 typedef struct GdbCmdContext {
-    GDBState *s;
     GdbCmdVariant *params;
     int num_params;
     uint8_t mem_buf[MAX_PACKET_LENGTH];
@@ -1453,7 +1452,7 @@ static inline int startswith(const char *string, const char *pattern)
   return !strncmp(string, pattern, strlen(pattern));
 }
 
-static int process_string_cmd(GDBState *s, void *user_ctx, const char *data,
+static int process_string_cmd(void *user_ctx, const char *data,
                               const GdbCmdParseEntry *cmds, int num_cmds)
 {
     int i, schema_len, max_num_params = 0;
@@ -1490,7 +1489,6 @@ static int process_string_cmd(GDBState *s, void *user_ctx, const char *data,
             return -1;
         }
 
-        gdb_ctx.s = s;
         cmd->handler(&gdb_ctx, user_ctx);
         return 0;
     }
@@ -1507,44 +1505,43 @@ static void run_cmd_parser(GDBState *s, const char *data,
 
     /* In case there was an error during the command parsing we must
     * send a NULL packet to indicate the command is not supported */
-    if (process_string_cmd(s, NULL, data, cmd, 1)) {
-        put_packet(s, "");
+    if (process_string_cmd(NULL, data, cmd, 1)) {
+        put_packet("");
     }
 }
 
 static void handle_detach(GdbCmdContext *gdb_ctx, void *user_ctx)
 {
     GDBProcess *process;
-    GDBState *s = gdb_ctx->s;
     uint32_t pid = 1;
 
-    if (s->multiprocess) {
+    if (gdbserver_state.multiprocess) {
         if (!gdb_ctx->num_params) {
-            put_packet(s, "E22");
+            put_packet("E22");
             return;
         }
 
         pid = gdb_ctx->params[0].val_ul;
     }
 
-    process = gdb_get_process(s, pid);
-    gdb_process_breakpoint_remove_all(s, process);
+    process = gdb_get_process(pid);
+    gdb_process_breakpoint_remove_all(process);
     process->attached = false;
 
-    if (pid == gdb_get_cpu_pid(s, s->c_cpu)) {
-        s->c_cpu = gdb_first_attached_cpu(s);
+    if (pid == gdb_get_cpu_pid(gdbserver_state.c_cpu)) {
+        gdbserver_state.c_cpu = gdb_first_attached_cpu();
     }
 
-    if (pid == gdb_get_cpu_pid(s, s->g_cpu)) {
-        s->g_cpu = gdb_first_attached_cpu(s);
+    if (pid == gdb_get_cpu_pid(gdbserver_state.g_cpu)) {
+        gdbserver_state.g_cpu = gdb_first_attached_cpu();
     }
 
-    if (!s->c_cpu) {
+    if (!gdbserver_state.c_cpu) {
         /* No more process attached */
         gdb_syscall_mode = GDB_SYS_DISABLED;
-        gdb_continue(s);
+        gdb_continue();
     }
-    put_packet(s, "OK");
+    put_packet("OK");
 }
 
 static void handle_thread_alive(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -1552,33 +1549,33 @@ static void handle_thread_alive(GdbCmdContext *gdb_ctx, void *user_ctx)
     CPUState *cpu;
 
     if (!gdb_ctx->num_params) {
-        put_packet(gdb_ctx->s, "E22");
+        put_packet("E22");
         return;
     }
 
     if (gdb_ctx->params[0].thread_id.kind == GDB_READ_THREAD_ERR) {
-        put_packet(gdb_ctx->s, "E22");
+        put_packet("E22");
         return;
     }
 
-    cpu = gdb_get_cpu(gdb_ctx->s, gdb_ctx->params[0].thread_id.pid,
+    cpu = gdb_get_cpu(gdb_ctx->params[0].thread_id.pid,
                       gdb_ctx->params[0].thread_id.tid);
     if (!cpu) {
-        put_packet(gdb_ctx->s, "E22");
+        put_packet("E22");
         return;
     }
 
-    put_packet(gdb_ctx->s, "OK");
+    put_packet("OK");
 }
 
 static void handle_continue(GdbCmdContext *gdb_ctx, void *user_ctx)
 {
     if (gdb_ctx->num_params) {
-        gdb_set_cpu_pc(gdb_ctx->s, gdb_ctx->params[0].val_ull);
+        gdb_set_cpu_pc(gdb_ctx->params[0].val_ull);
     }
 
-    gdb_ctx->s->signal = 0;
-    gdb_continue(gdb_ctx->s);
+    gdbserver_state.signal = 0;
+    gdb_continue();
 }
 
 static void handle_cont_with_sig(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -1593,11 +1590,11 @@ static void handle_cont_with_sig(GdbCmdContext *gdb_ctx, void *user_ctx)
         signal = gdb_ctx->params[0].val_ul;
     }
 
-    gdb_ctx->s->signal = gdb_signal_to_target(signal);
-    if (gdb_ctx->s->signal == -1) {
-        gdb_ctx->s->signal = 0;
+    gdbserver_state.signal = gdb_signal_to_target(signal);
+    if (gdbserver_state.signal == -1) {
+        gdbserver_state.signal = 0;
     }
-    gdb_continue(gdb_ctx->s);
+    gdb_continue();
 }
 
 static void handle_set_thread(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -1605,24 +1602,24 @@ static void handle_set_thread(GdbCmdContext *gdb_ctx, void *user_ctx)
     CPUState *cpu;
 
     if (gdb_ctx->num_params != 2) {
-        put_packet(gdb_ctx->s, "E22");
+        put_packet("E22");
         return;
     }
 
     if (gdb_ctx->params[1].thread_id.kind == GDB_READ_THREAD_ERR) {
-        put_packet(gdb_ctx->s, "E22");
+        put_packet("E22");
         return;
     }
 
     if (gdb_ctx->params[1].thread_id.kind != GDB_ONE_THREAD) {
-        put_packet(gdb_ctx->s, "OK");
+        put_packet("OK");
         return;
     }
 
-    cpu = gdb_get_cpu(gdb_ctx->s, gdb_ctx->params[1].thread_id.pid,
+    cpu = gdb_get_cpu(gdb_ctx->params[1].thread_id.pid,
                       gdb_ctx->params[1].thread_id.tid);
     if (!cpu) {
-        put_packet(gdb_ctx->s, "E22");
+        put_packet("E22");
         return;
     }
 
@@ -1632,15 +1629,15 @@ static void handle_set_thread(GdbCmdContext *gdb_ctx, void *user_ctx)
      */
     switch (gdb_ctx->params[0].opcode) {
     case 'c':
-        gdb_ctx->s->c_cpu = cpu;
-        put_packet(gdb_ctx->s, "OK");
+        gdbserver_state.c_cpu = cpu;
+        put_packet("OK");
         break;
     case 'g':
-        gdb_ctx->s->g_cpu = cpu;
-        put_packet(gdb_ctx->s, "OK");
+        gdbserver_state.g_cpu = cpu;
+        put_packet("OK");
         break;
     default:
-        put_packet(gdb_ctx->s, "E22");
+        put_packet("E22");
         break;
     }
 }
@@ -1650,7 +1647,7 @@ static void handle_insert_bp(GdbCmdContext *gdb_ctx, void *user_ctx)
     int res;
 
     if (gdb_ctx->num_params != 3) {
-        put_packet(gdb_ctx->s, "E22");
+        put_packet("E22");
         return;
     }
 
@@ -1658,14 +1655,14 @@ static void handle_insert_bp(GdbCmdContext *gdb_ctx, void *user_ctx)
                                 gdb_ctx->params[1].val_ull,
                                 gdb_ctx->params[2].val_ull);
     if (res >= 0) {
-        put_packet(gdb_ctx->s, "OK");
+        put_packet("OK");
         return;
     } else if (res == -ENOSYS) {
-        put_packet(gdb_ctx->s, "");
+        put_packet("");
         return;
     }
 
-    put_packet(gdb_ctx->s, "E22");
+    put_packet("E22");
 }
 
 static void handle_remove_bp(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -1673,7 +1670,7 @@ static void handle_remove_bp(GdbCmdContext *gdb_ctx, void *user_ctx)
     int res;
 
     if (gdb_ctx->num_params != 3) {
-        put_packet(gdb_ctx->s, "E22");
+        put_packet("E22");
         return;
     }
 
@@ -1681,14 +1678,14 @@ static void handle_remove_bp(GdbCmdContext *gdb_ctx, void *user_ctx)
                                 gdb_ctx->params[1].val_ull,
                                 gdb_ctx->params[2].val_ull);
     if (res >= 0) {
-        put_packet(gdb_ctx->s, "OK");
+        put_packet("OK");
         return;
     } else if (res == -ENOSYS) {
-        put_packet(gdb_ctx->s, "");
+        put_packet("");
         return;
     }
 
-    put_packet(gdb_ctx->s, "E22");
+    put_packet("E22");
 }
 
 /*
@@ -1707,20 +1704,20 @@ static void handle_set_reg(GdbCmdContext *gdb_ctx, void *user_ctx)
     int reg_size;
 
     if (!gdb_has_xml) {
-        put_packet(gdb_ctx->s, "");
+        put_packet("");
         return;
     }
 
     if (gdb_ctx->num_params != 2) {
-        put_packet(gdb_ctx->s, "E22");
+        put_packet("E22");
         return;
     }
 
     reg_size = strlen(gdb_ctx->params[1].data) / 2;
     hextomem(gdb_ctx->mem_buf, gdb_ctx->params[1].data, reg_size);
-    gdb_write_register(gdb_ctx->s->g_cpu, gdb_ctx->mem_buf,
+    gdb_write_register(gdbserver_state.g_cpu, gdb_ctx->mem_buf,
                        gdb_ctx->params[0].val_ull);
-    put_packet(gdb_ctx->s, "OK");
+    put_packet("OK");
 }
 
 static void handle_get_reg(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -1728,73 +1725,73 @@ static void handle_get_reg(GdbCmdContext *gdb_ctx, void *user_ctx)
     int reg_size;
 
     if (!gdb_has_xml) {
-        put_packet(gdb_ctx->s, "");
+        put_packet("");
         return;
     }
 
     if (!gdb_ctx->num_params) {
-        put_packet(gdb_ctx->s, "E14");
+        put_packet("E14");
         return;
     }
 
-    reg_size = gdb_read_register(gdb_ctx->s->g_cpu, gdb_ctx->mem_buf,
+    reg_size = gdb_read_register(gdbserver_state.g_cpu, gdb_ctx->mem_buf,
                                  gdb_ctx->params[0].val_ull);
     if (!reg_size) {
-        put_packet(gdb_ctx->s, "E14");
+        put_packet("E14");
         return;
     }
 
     memtohex(gdb_ctx->str_buf, gdb_ctx->mem_buf, reg_size);
-    put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+    put_packet(gdb_ctx->str_buf);
 }
 
 static void handle_write_mem(GdbCmdContext *gdb_ctx, void *user_ctx)
 {
     if (gdb_ctx->num_params != 3) {
-        put_packet(gdb_ctx->s, "E22");
+        put_packet("E22");
         return;
     }
 
     /* hextomem() reads 2*len bytes */
     if (gdb_ctx->params[1].val_ull > strlen(gdb_ctx->params[2].data) / 2) {
-        put_packet(gdb_ctx->s, "E22");
+        put_packet("E22");
         return;
     }
 
     hextomem(gdb_ctx->mem_buf, gdb_ctx->params[2].data,
              gdb_ctx->params[1].val_ull);
-    if (target_memory_rw_debug(gdb_ctx->s->g_cpu, gdb_ctx->params[0].val_ull,
+    if (target_memory_rw_debug(gdbserver_state.g_cpu, gdb_ctx->params[0].val_ull,
                                gdb_ctx->mem_buf,
                                gdb_ctx->params[1].val_ull, true)) {
-        put_packet(gdb_ctx->s, "E14");
+        put_packet("E14");
         return;
     }
 
-    put_packet(gdb_ctx->s, "OK");
+    put_packet("OK");
 }
 
 static void handle_read_mem(GdbCmdContext *gdb_ctx, void *user_ctx)
 {
     if (gdb_ctx->num_params != 2) {
-        put_packet(gdb_ctx->s, "E22");
+        put_packet("E22");
         return;
     }
 
     /* memtohex() doubles the required space */
     if (gdb_ctx->params[1].val_ull > MAX_PACKET_LENGTH / 2) {
-        put_packet(gdb_ctx->s, "E22");
+        put_packet("E22");
         return;
     }
 
-    if (target_memory_rw_debug(gdb_ctx->s->g_cpu, gdb_ctx->params[0].val_ull,
+    if (target_memory_rw_debug(gdbserver_state.g_cpu, gdb_ctx->params[0].val_ull,
                                gdb_ctx->mem_buf,
                                gdb_ctx->params[1].val_ull, false)) {
-        put_packet(gdb_ctx->s, "E14");
+        put_packet("E14");
         return;
     }
 
     memtohex(gdb_ctx->str_buf, gdb_ctx->mem_buf, gdb_ctx->params[1].val_ull);
-    put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+    put_packet(gdb_ctx->str_buf);
 }
 
 static void handle_write_all_regs(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -1807,37 +1804,37 @@ static void handle_write_all_regs(GdbCmdContext *gdb_ctx, void *user_ctx)
         return;
     }
 
-    cpu_synchronize_state(gdb_ctx->s->g_cpu);
+    cpu_synchronize_state(gdbserver_state.g_cpu);
     registers = gdb_ctx->mem_buf;
     len = strlen(gdb_ctx->params[0].data) / 2;
     hextomem(registers, gdb_ctx->params[0].data, len);
-    for (addr = 0; addr < gdb_ctx->s->g_cpu->gdb_num_g_regs && len > 0;
+    for (addr = 0; addr < gdbserver_state.g_cpu->gdb_num_g_regs && len > 0;
          addr++) {
-        reg_size = gdb_write_register(gdb_ctx->s->g_cpu, registers, addr);
+        reg_size = gdb_write_register(gdbserver_state.g_cpu, registers, addr);
         len -= reg_size;
         registers += reg_size;
     }
-    put_packet(gdb_ctx->s, "OK");
+    put_packet("OK");
 }
 
 static void handle_read_all_regs(GdbCmdContext *gdb_ctx, void *user_ctx)
 {
     target_ulong addr, len;
 
-    cpu_synchronize_state(gdb_ctx->s->g_cpu);
+    cpu_synchronize_state(gdbserver_state.g_cpu);
     len = 0;
-    for (addr = 0; addr < gdb_ctx->s->g_cpu->gdb_num_g_regs; addr++) {
-        len += gdb_read_register(gdb_ctx->s->g_cpu, gdb_ctx->mem_buf + len,
+    for (addr = 0; addr < gdbserver_state.g_cpu->gdb_num_g_regs; addr++) {
+        len += gdb_read_register(gdbserver_state.g_cpu, gdb_ctx->mem_buf + len,
                                  addr);
     }
 
     memtohex(gdb_ctx->str_buf, gdb_ctx->mem_buf, len);
-    put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+    put_packet(gdb_ctx->str_buf);
 }
 
 static void handle_file_io(GdbCmdContext *gdb_ctx, void *user_ctx)
 {
-    if (gdb_ctx->num_params >= 1 && gdb_ctx->s->current_syscall_cb) {
+    if (gdb_ctx->num_params >= 1 && gdbserver_state.current_syscall_cb) {
         target_ulong ret, err;
 
         ret = (target_ulong)gdb_ctx->params[0].val_ull;
@@ -1846,31 +1843,31 @@ static void handle_file_io(GdbCmdContext *gdb_ctx, void *user_ctx)
         } else {
             err = 0;
         }
-        gdb_ctx->s->current_syscall_cb(gdb_ctx->s->c_cpu, ret, err);
-        gdb_ctx->s->current_syscall_cb = NULL;
+        gdbserver_state.current_syscall_cb(gdbserver_state.c_cpu, ret, err);
+        gdbserver_state.current_syscall_cb = NULL;
     }
 
     if (gdb_ctx->num_params >= 3 && gdb_ctx->params[2].opcode == (uint8_t)'C') {
-        put_packet(gdb_ctx->s, "T02");
+        put_packet("T02");
         return;
     }
 
-    gdb_continue(gdb_ctx->s);
+    gdb_continue();
 }
 
 static void handle_step(GdbCmdContext *gdb_ctx, void *user_ctx)
 {
     if (gdb_ctx->num_params) {
-        gdb_set_cpu_pc(gdb_ctx->s, (target_ulong)gdb_ctx->params[0].val_ull);
+        gdb_set_cpu_pc((target_ulong)gdb_ctx->params[0].val_ull);
     }
 
-    cpu_single_step(gdb_ctx->s->c_cpu, sstep_flags);
-    gdb_continue(gdb_ctx->s);
+    cpu_single_step(gdbserver_state.c_cpu, sstep_flags);
+    gdb_continue();
 }
 
 static void handle_v_cont_query(GdbCmdContext *gdb_ctx, void *user_ctx)
 {
-    put_packet(gdb_ctx->s, "vCont;c;C;s;S");
+    put_packet("vCont;c;C;s;S");
 }
 
 static void handle_v_cont(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -1881,11 +1878,11 @@ static void handle_v_cont(GdbCmdContext *gdb_ctx, void *user_ctx)
         return;
     }
 
-    res = gdb_handle_vcont(gdb_ctx->s, gdb_ctx->params[0].data);
+    res = gdb_handle_vcont(gdb_ctx->params[0].data);
     if ((res == -EINVAL) || (res == -ERANGE)) {
-        put_packet(gdb_ctx->s, "E22");
+        put_packet("E22");
     } else if (res) {
-        put_packet(gdb_ctx->s, "");
+        put_packet("");
     }
 }
 
@@ -1900,31 +1897,31 @@ static void handle_v_attach(GdbCmdContext *gdb_ctx, void *user_ctx)
         goto cleanup;
     }
 
-    process = gdb_get_process(gdb_ctx->s, gdb_ctx->params[0].val_ul);
+    process = gdb_get_process(gdb_ctx->params[0].val_ul);
     if (!process) {
         goto cleanup;
     }
 
-    cpu = get_first_cpu_in_process(gdb_ctx->s, process);
+    cpu = get_first_cpu_in_process(process);
     if (!cpu) {
         goto cleanup;
     }
 
     process->attached = true;
-    gdb_ctx->s->g_cpu = cpu;
-    gdb_ctx->s->c_cpu = cpu;
+    gdbserver_state.g_cpu = cpu;
+    gdbserver_state.c_cpu = cpu;
 
-    gdb_fmt_thread_id(gdb_ctx->s, cpu, thread_id, sizeof(thread_id));
+    gdb_fmt_thread_id(cpu, thread_id, sizeof(thread_id));
     snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "T%02xthread:%s;",
              GDB_SIGNAL_TRAP, thread_id);
 cleanup:
-    put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+    put_packet(gdb_ctx->str_buf);
 }
 
 static void handle_v_kill(GdbCmdContext *gdb_ctx, void *user_ctx)
 {
     /* Kill the target */
-    put_packet(gdb_ctx->s, "OK");
+    put_packet("OK");
     error_report("QEMU: Terminated via GDBstub");
     exit(0);
 }
@@ -1961,10 +1958,10 @@ static void handle_v_commands(GdbCmdContext *gdb_ctx, void *user_ctx)
         return;
     }
 
-    if (process_string_cmd(gdb_ctx->s, NULL, gdb_ctx->params[0].data,
+    if (process_string_cmd(NULL, gdb_ctx->params[0].data,
                            gdb_v_commands_table,
                            ARRAY_SIZE(gdb_v_commands_table))) {
-        put_packet(gdb_ctx->s, "");
+        put_packet("");
     }
 }
 
@@ -1973,7 +1970,7 @@ static void handle_query_qemu_sstepbits(GdbCmdContext *gdb_ctx, void *user_ctx)
     snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf),
              "ENABLE=%x,NOIRQ=%x,NOTIMER=%x", SSTEP_ENABLE,
              SSTEP_NOIRQ, SSTEP_NOTIMER);
-    put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+    put_packet(gdb_ctx->str_buf);
 }
 
 static void handle_set_qemu_sstep(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -1983,13 +1980,13 @@ static void handle_set_qemu_sstep(GdbCmdContext *gdb_ctx, void *user_ctx)
     }
 
     sstep_flags = gdb_ctx->params[0].val_ul;
-    put_packet(gdb_ctx->s, "OK");
+    put_packet("OK");
 }
 
 static void handle_query_qemu_sstep(GdbCmdContext *gdb_ctx, void *user_ctx)
 {
     snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "0x%x", sstep_flags);
-    put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+    put_packet(gdb_ctx->str_buf);
 }
 
 static void handle_query_curr_tid(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -2003,33 +2000,32 @@ static void handle_query_curr_tid(GdbCmdContext *gdb_ctx, void *user_ctx)
      * the first thread of the current process (gdb returns the
      * first thread).
      */
-    process = gdb_get_cpu_process(gdb_ctx->s, gdb_ctx->s->g_cpu);
-    cpu = get_first_cpu_in_process(gdb_ctx->s, process);
-    gdb_fmt_thread_id(gdb_ctx->s, cpu, thread_id, sizeof(thread_id));
+    process = gdb_get_cpu_process(gdbserver_state.g_cpu);
+    cpu = get_first_cpu_in_process(process);
+    gdb_fmt_thread_id(cpu, thread_id, sizeof(thread_id));
     snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "QC%s", thread_id);
-    put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+    put_packet(gdb_ctx->str_buf);
 }
 
 static void handle_query_threads(GdbCmdContext *gdb_ctx, void *user_ctx)
 {
     char thread_id[16];
 
-    if (!gdb_ctx->s->query_cpu) {
-        put_packet(gdb_ctx->s, "l");
+    if (!gdbserver_state.query_cpu) {
+        put_packet("l");
         return;
     }
 
-    gdb_fmt_thread_id(gdb_ctx->s, gdb_ctx->s->query_cpu, thread_id,
+    gdb_fmt_thread_id(gdbserver_state.query_cpu, thread_id,
                       sizeof(thread_id));
     snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "m%s", thread_id);
-    put_packet(gdb_ctx->s, gdb_ctx->str_buf);
-    gdb_ctx->s->query_cpu =
-        gdb_next_attached_cpu(gdb_ctx->s, gdb_ctx->s->query_cpu);
+    put_packet(gdb_ctx->str_buf);
+    gdbserver_state.query_cpu = gdb_next_attached_cpu(gdbserver_state.query_cpu);
 }
 
 static void handle_query_first_threads(GdbCmdContext *gdb_ctx, void *user_ctx)
 {
-    gdb_ctx->s->query_cpu = gdb_first_attached_cpu(gdb_ctx->s);
+    gdbserver_state.query_cpu = gdb_first_attached_cpu();
     handle_query_threads(gdb_ctx, user_ctx);
 }
 
@@ -2040,11 +2036,11 @@ static void handle_query_thread_extra(GdbCmdContext *gdb_ctx, void *user_ctx)
 
     if (!gdb_ctx->num_params ||
         gdb_ctx->params[0].thread_id.kind == GDB_READ_THREAD_ERR) {
-        put_packet(gdb_ctx->s, "E22");
+        put_packet("E22");
         return;
     }
 
-    cpu = gdb_get_cpu(gdb_ctx->s, gdb_ctx->params[0].thread_id.pid,
+    cpu = gdb_get_cpu(gdb_ctx->params[0].thread_id.pid,
                       gdb_ctx->params[0].thread_id.tid);
     if (!cpu) {
         return;
@@ -2052,7 +2048,7 @@ static void handle_query_thread_extra(GdbCmdContext *gdb_ctx, void *user_ctx)
 
     cpu_synchronize_state(cpu);
 
-    if (gdb_ctx->s->multiprocess && (gdb_ctx->s->process_num > 1)) {
+    if (gdbserver_state.multiprocess && (gdbserver_state.process_num > 1)) {
         /* Print the CPU model and name in multiprocess mode */
         ObjectClass *oc = object_get_class(OBJECT(cpu));
         const char *cpu_model = object_class_get_name(oc);
@@ -2069,7 +2065,7 @@ static void handle_query_thread_extra(GdbCmdContext *gdb_ctx, void *user_ctx)
     }
     trace_gdbstub_op_extra_info((char *)gdb_ctx->mem_buf);
     memtohex(gdb_ctx->str_buf, gdb_ctx->mem_buf, len);
-    put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+    put_packet(gdb_ctx->str_buf);
 }
 
 #ifdef CONFIG_USER_ONLY
@@ -2077,14 +2073,14 @@ static void handle_query_offsets(GdbCmdContext *gdb_ctx, void *user_ctx)
 {
     TaskState *ts;
 
-    ts = gdb_ctx->s->c_cpu->opaque;
+    ts = gdbserver_state.c_cpu->opaque;
     snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf),
              "Text=" TARGET_ABI_FMT_lx ";Data=" TARGET_ABI_FMT_lx
              ";Bss=" TARGET_ABI_FMT_lx,
              ts->info->code_offset,
              ts->info->data_offset,
              ts->info->data_offset);
-    put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+    put_packet(gdb_ctx->str_buf);
 }
 #else
 static void handle_query_rcmd(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -2092,21 +2088,21 @@ static void handle_query_rcmd(GdbCmdContext *gdb_ctx, void *user_ctx)
     int len;
 
     if (!gdb_ctx->num_params) {
-        put_packet(gdb_ctx->s, "E22");
+        put_packet("E22");
         return;
     }
 
     len = strlen(gdb_ctx->params[0].data);
     if (len % 2) {
-        put_packet(gdb_ctx->s, "E01");
+        put_packet("E01");
         return;
     }
 
     len = len / 2;
     hextomem(gdb_ctx->mem_buf, gdb_ctx->params[0].data, len);
     gdb_ctx->mem_buf[len++] = 0;
-    qemu_chr_be_write(gdb_ctx->s->mon_chr, gdb_ctx->mem_buf, len);
-    put_packet(gdb_ctx->s, "OK");
+    qemu_chr_be_write(gdbserver_state.mon_chr, gdb_ctx->mem_buf, len);
+    put_packet("OK");
 
 }
 #endif
@@ -2125,11 +2121,11 @@ static void handle_query_supported(GdbCmdContext *gdb_ctx, void *user_ctx)
 
     if (gdb_ctx->num_params &&
         strstr(gdb_ctx->params[0].data, "multiprocess+")) {
-        gdb_ctx->s->multiprocess = true;
+        gdbserver_state.multiprocess = true;
     }
 
     pstrcat(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), ";multiprocess+");
-    put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+    put_packet(gdb_ctx->str_buf);
 }
 
 static void handle_query_xfer_features(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -2141,22 +2137,22 @@ static void handle_query_xfer_features(GdbCmdContext *gdb_ctx, void *user_ctx)
     const char *p;
 
     if (gdb_ctx->num_params < 3) {
-        put_packet(gdb_ctx->s, "E22");
+        put_packet("E22");
         return;
     }
 
-    process = gdb_get_cpu_process(gdb_ctx->s, gdb_ctx->s->g_cpu);
-    cc = CPU_GET_CLASS(gdb_ctx->s->g_cpu);
+    process = gdb_get_cpu_process(gdbserver_state.g_cpu);
+    cc = CPU_GET_CLASS(gdbserver_state.g_cpu);
     if (!cc->gdb_core_xml_file) {
-        put_packet(gdb_ctx->s, "");
+        put_packet("");
         return;
     }
 
     gdb_has_xml = true;
     p = gdb_ctx->params[0].data;
-    xml = get_feature_xml(gdb_ctx->s, p, &p, process);
+    xml = get_feature_xml(p, &p, process);
     if (!xml) {
-        put_packet(gdb_ctx->s, "E00");
+        put_packet("E00");
         return;
     }
 
@@ -2164,7 +2160,7 @@ static void handle_query_xfer_features(GdbCmdContext *gdb_ctx, void *user_ctx)
     len = gdb_ctx->params[2].val_ul;
     total_len = strlen(xml);
     if (addr > total_len) {
-        put_packet(gdb_ctx->s, "E00");
+        put_packet("E00");
         return;
     }
 
@@ -2180,12 +2176,12 @@ static void handle_query_xfer_features(GdbCmdContext *gdb_ctx, void *user_ctx)
         len = memtox(gdb_ctx->str_buf + 1, xml + addr, total_len - addr);
     }
 
-    put_packet_binary(gdb_ctx->s, gdb_ctx->str_buf, len + 1, true);
+    put_packet_binary(gdb_ctx->str_buf, len + 1, true);
 }
 
 static void handle_query_attached(GdbCmdContext *gdb_ctx, void *user_ctx)
 {
-    put_packet(gdb_ctx->s, GDB_ATTACHED);
+    put_packet(GDB_ATTACHED);
 }
 
 static void handle_query_qemu_supported(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -2194,7 +2190,7 @@ static void handle_query_qemu_supported(GdbCmdContext *gdb_ctx, void *user_ctx)
 #ifndef CONFIG_USER_ONLY
     pstrcat(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), ";PhyMemMode");
 #endif
-    put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+    put_packet(gdb_ctx->str_buf);
 }
 
 #ifndef CONFIG_USER_ONLY
@@ -2202,13 +2198,13 @@ static void handle_query_qemu_phy_mem_mode(GdbCmdContext *gdb_ctx,
                                            void *user_ctx)
 {
     snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "%d", phy_memory_mode);
-    put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+    put_packet(gdb_ctx->str_buf);
 }
 
 static void handle_set_qemu_phy_mem_mode(GdbCmdContext *gdb_ctx, void *user_ctx)
 {
     if (!gdb_ctx->num_params) {
-        put_packet(gdb_ctx->s, "E22");
+        put_packet("E22");
         return;
     }
 
@@ -2217,7 +2213,7 @@ static void handle_set_qemu_phy_mem_mode(GdbCmdContext *gdb_ctx, void *user_ctx)
     } else {
         phy_memory_mode = 1;
     }
-    put_packet(gdb_ctx->s, "OK");
+    put_packet("OK");
 }
 #endif
 
@@ -2333,16 +2329,16 @@ static void handle_gen_query(GdbCmdContext *gdb_ctx, void *user_ctx)
         return;
     }
 
-    if (!process_string_cmd(gdb_ctx->s, NULL, gdb_ctx->params[0].data,
+    if (!process_string_cmd(NULL, gdb_ctx->params[0].data,
                             gdb_gen_query_set_common_table,
                             ARRAY_SIZE(gdb_gen_query_set_common_table))) {
         return;
     }
 
-    if (process_string_cmd(gdb_ctx->s, NULL, gdb_ctx->params[0].data,
+    if (process_string_cmd(NULL, gdb_ctx->params[0].data,
                            gdb_gen_query_table,
                            ARRAY_SIZE(gdb_gen_query_table))) {
-        put_packet(gdb_ctx->s, "");
+        put_packet("");
     }
 }
 
@@ -2352,16 +2348,16 @@ static void handle_gen_set(GdbCmdContext *gdb_ctx, void *user_ctx)
         return;
     }
 
-    if (!process_string_cmd(gdb_ctx->s, NULL, gdb_ctx->params[0].data,
+    if (!process_string_cmd(NULL, gdb_ctx->params[0].data,
                             gdb_gen_query_set_common_table,
                             ARRAY_SIZE(gdb_gen_query_set_common_table))) {
         return;
     }
 
-    if (process_string_cmd(gdb_ctx->s, NULL, gdb_ctx->params[0].data,
+    if (process_string_cmd(NULL, gdb_ctx->params[0].data,
                            gdb_gen_set_table,
                            ARRAY_SIZE(gdb_gen_set_table))) {
-        put_packet(gdb_ctx->s, "");
+        put_packet("");
     }
 }
 
@@ -2369,11 +2365,11 @@ static void handle_target_halt(GdbCmdContext *gdb_ctx, void *user_ctx)
 {
     char thread_id[16];
 
-    gdb_fmt_thread_id(gdb_ctx->s, gdb_ctx->s->c_cpu, thread_id,
+    gdb_fmt_thread_id(gdbserver_state.c_cpu, thread_id,
                       sizeof(thread_id));
     snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "T%02xthread:%s;",
              GDB_SIGNAL_TRAP, thread_id);
-    put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+    put_packet(gdb_ctx->str_buf);
     /*
      * Remove all the breakpoints when this query is issued,
      * because gdb is doing an initial connect and the state
@@ -2390,7 +2386,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
 
     switch (line_buf[0]) {
     case '!':
-        put_packet(s, "OK");
+        put_packet("OK");
         break;
     case '?':
         {
@@ -2605,7 +2601,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
         break;
     default:
         /* put empty packet */
-        put_packet(s, "");
+        put_packet("");
         break;
     }
 
@@ -2618,7 +2614,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
 
 void gdb_set_stop_cpu(CPUState *cpu)
 {
-    GDBProcess *p = gdb_get_cpu_process(&gdbserver_state, cpu);
+    GDBProcess *p = gdb_get_cpu_process(cpu);
 
     if (!p->attached) {
         /*
@@ -2635,19 +2631,18 @@ void gdb_set_stop_cpu(CPUState *cpu)
 #ifndef CONFIG_USER_ONLY
 static void gdb_vm_state_change(void *opaque, int running, RunState state)
 {
-    GDBState *s = &gdbserver_state;
-    CPUState *cpu = s->c_cpu;
+    CPUState *cpu = gdbserver_state.c_cpu;
     char buf[256];
     char thread_id[16];
     const char *type;
     int ret;
 
-    if (running || s->state == RS_INACTIVE) {
+    if (running || gdbserver_state.state == RS_INACTIVE) {
         return;
     }
     /* Is there a GDB syscall waiting to be sent?  */
-    if (s->current_syscall_cb) {
-        put_packet(s, s->syscall_buf);
+    if (gdbserver_state.current_syscall_cb) {
+        put_packet(gdbserver_state.syscall_buf);
         return;
     }
 
@@ -2656,7 +2651,7 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
         return;
     }
 
-    gdb_fmt_thread_id(s, cpu, thread_id, sizeof(thread_id));
+    gdb_fmt_thread_id(cpu, thread_id, sizeof(thread_id));
 
     switch (state) {
     case RUN_STATE_DEBUG:
@@ -2721,7 +2716,7 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
     snprintf(buf, sizeof(buf), "T%02xthread:%s;", ret, thread_id);
 
 send_packet:
-    put_packet(s, buf);
+    put_packet(buf);
 
     /* disable single step if it was enabled */
     cpu_single_step(cpu, 0);
@@ -2781,7 +2776,7 @@ void gdb_do_syscallv(gdb_syscall_complete_cb cb, const char *fmt, va_list va)
     }
     *p = 0;
 #ifdef CONFIG_USER_ONLY
-    put_packet(&gdbserver_state, gdbserver_state.syscall_buf);
+    put_packet(gdbserver_state.syscall_buf);
     /* Return control to gdb for it to process the syscall request.
      * Since the protocol requires that gdb hands control back to us
      * using a "here are the results" F packet, we don't need to check
@@ -2814,12 +2809,12 @@ static void gdb_read_byte(GDBState *s, uint8_t ch)
     uint8_t reply;
 
 #ifndef CONFIG_USER_ONLY
-    if (s->last_packet_len) {
+    if (gdbserver_state.last_packet_len) {
         /* Waiting for a response to the last packet.  If we see the start
            of a new command then abandon the previous response.  */
         if (ch == '-') {
             trace_gdbstub_err_got_nack();
-            put_buffer(s, (uint8_t *)s->last_packet, s->last_packet_len);
+            put_buffer((uint8_t *)gdbserver_state.last_packet, gdbserver_state.last_packet_len);
         } else if (ch == '+') {
             trace_gdbstub_io_got_ack();
         } else {
@@ -2827,7 +2822,7 @@ static void gdb_read_byte(GDBState *s, uint8_t ch)
         }
 
         if (ch == '+' || ch == '$')
-            s->last_packet_len = 0;
+            gdbserver_state.last_packet_len = 0;
         if (ch != '$')
             return;
     }
@@ -2838,13 +2833,13 @@ static void gdb_read_byte(GDBState *s, uint8_t ch)
     } else
 #endif
     {
-        switch(s->state) {
+        switch(gdbserver_state.state) {
         case RS_IDLE:
             if (ch == '$') {
                 /* start of command packet */
-                s->line_buf_index = 0;
-                s->line_sum = 0;
-                s->state = RS_GETLINE;
+                gdbserver_state.line_buf_index = 0;
+                gdbserver_state.line_sum = 0;
+                gdbserver_state.state = RS_GETLINE;
             } else {
                 trace_gdbstub_err_garbage(ch);
             }
@@ -2852,37 +2847,37 @@ static void gdb_read_byte(GDBState *s, uint8_t ch)
         case RS_GETLINE:
             if (ch == '}') {
                 /* start escape sequence */
-                s->state = RS_GETLINE_ESC;
-                s->line_sum += ch;
+                gdbserver_state.state = RS_GETLINE_ESC;
+                gdbserver_state.line_sum += ch;
             } else if (ch == '*') {
                 /* start run length encoding sequence */
-                s->state = RS_GETLINE_RLE;
-                s->line_sum += ch;
+                gdbserver_state.state = RS_GETLINE_RLE;
+                gdbserver_state.line_sum += ch;
             } else if (ch == '#') {
                 /* end of command, start of checksum*/
-                s->state = RS_CHKSUM1;
-            } else if (s->line_buf_index >= sizeof(s->line_buf) - 1) {
+                gdbserver_state.state = RS_CHKSUM1;
+            } else if (gdbserver_state.line_buf_index >= sizeof(gdbserver_state.line_buf) - 1) {
                 trace_gdbstub_err_overrun();
-                s->state = RS_IDLE;
+                gdbserver_state.state = RS_IDLE;
             } else {
                 /* unescaped command character */
-                s->line_buf[s->line_buf_index++] = ch;
-                s->line_sum += ch;
+                gdbserver_state.line_buf[gdbserver_state.line_buf_index++] = ch;
+                gdbserver_state.line_sum += ch;
             }
             break;
         case RS_GETLINE_ESC:
             if (ch == '#') {
                 /* unexpected end of command in escape sequence */
-                s->state = RS_CHKSUM1;
-            } else if (s->line_buf_index >= sizeof(s->line_buf) - 1) {
+                gdbserver_state.state = RS_CHKSUM1;
+            } else if (gdbserver_state.line_buf_index >= sizeof(gdbserver_state.line_buf) - 1) {
                 /* command buffer overrun */
                 trace_gdbstub_err_overrun();
-                s->state = RS_IDLE;
+                gdbserver_state.state = RS_IDLE;
             } else {
                 /* parse escaped character and leave escape state */
-                s->line_buf[s->line_buf_index++] = ch ^ 0x20;
-                s->line_sum += ch;
-                s->state = RS_GETLINE;
+                gdbserver_state.line_buf[gdbserver_state.line_buf_index++] = ch ^ 0x20;
+                gdbserver_state.line_sum += ch;
+                gdbserver_state.state = RS_GETLINE;
             }
             break;
         case RS_GETLINE_RLE:
@@ -2893,25 +2888,25 @@ static void gdb_read_byte(GDBState *s, uint8_t ch)
             if (ch < ' ' || ch == '#' || ch == '$' || ch > 126) {
                 /* invalid RLE count encoding */
                 trace_gdbstub_err_invalid_repeat(ch);
-                s->state = RS_GETLINE;
+                gdbserver_state.state = RS_GETLINE;
             } else {
                 /* decode repeat length */
                 int repeat = ch - ' ' + 3;
-                if (s->line_buf_index + repeat >= sizeof(s->line_buf) - 1) {
+                if (gdbserver_state.line_buf_index + repeat >= sizeof(gdbserver_state.line_buf) - 1) {
                     /* that many repeats would overrun the command buffer */
                     trace_gdbstub_err_overrun();
-                    s->state = RS_IDLE;
-                } else if (s->line_buf_index < 1) {
+                    gdbserver_state.state = RS_IDLE;
+                } else if (gdbserver_state.line_buf_index < 1) {
                     /* got a repeat but we have nothing to repeat */
                     trace_gdbstub_err_invalid_rle();
-                    s->state = RS_GETLINE;
+                    gdbserver_state.state = RS_GETLINE;
                 } else {
                     /* repeat the last character */
-                    memset(s->line_buf + s->line_buf_index,
-                           s->line_buf[s->line_buf_index - 1], repeat);
-                    s->line_buf_index += repeat;
-                    s->line_sum += ch;
-                    s->state = RS_GETLINE;
+                    memset(gdbserver_state.line_buf + gdbserver_state.line_buf_index,
+                           gdbserver_state.line_buf[gdbserver_state.line_buf_index - 1], repeat);
+                    gdbserver_state.line_buf_index += repeat;
+                    gdbserver_state.line_sum += ch;
+                    gdbserver_state.state = RS_GETLINE;
                 }
             }
             break;
@@ -2919,33 +2914,33 @@ static void gdb_read_byte(GDBState *s, uint8_t ch)
             /* get high hex digit of checksum */
             if (!isxdigit(ch)) {
                 trace_gdbstub_err_checksum_invalid(ch);
-                s->state = RS_GETLINE;
+                gdbserver_state.state = RS_GETLINE;
                 break;
             }
-            s->line_buf[s->line_buf_index] = '\0';
-            s->line_csum = fromhex(ch) << 4;
-            s->state = RS_CHKSUM2;
+            gdbserver_state.line_buf[gdbserver_state.line_buf_index] = '\0';
+            gdbserver_state.line_csum = fromhex(ch) << 4;
+            gdbserver_state.state = RS_CHKSUM2;
             break;
         case RS_CHKSUM2:
             /* get low hex digit of checksum */
             if (!isxdigit(ch)) {
                 trace_gdbstub_err_checksum_invalid(ch);
-                s->state = RS_GETLINE;
+                gdbserver_state.state = RS_GETLINE;
                 break;
             }
-            s->line_csum |= fromhex(ch);
+            gdbserver_state.line_csum |= fromhex(ch);
 
-            if (s->line_csum != (s->line_sum & 0xff)) {
-                trace_gdbstub_err_checksum_incorrect(s->line_sum, s->line_csum);
+            if (gdbserver_state.line_csum != (gdbserver_state.line_sum & 0xff)) {
+                trace_gdbstub_err_checksum_incorrect(gdbserver_state.line_sum, gdbserver_state.line_csum);
                 /* send NAK reply */
                 reply = '-';
-                put_buffer(s, &reply, 1);
-                s->state = RS_IDLE;
+                put_buffer(&reply, 1);
+                gdbserver_state.state = RS_IDLE;
             } else {
                 /* send ACK reply */
                 reply = '+';
-                put_buffer(s, &reply, 1);
-                s->state = gdb_handle_packet(s, s->line_buf);
+                put_buffer(&reply, 1);
+                gdbserver_state.state = gdb_handle_packet(s, gdbserver_state.line_buf);
             }
             break;
         default:
@@ -2971,7 +2966,7 @@ void gdb_exit(CPUArchState *env, int code)
   trace_gdbstub_op_exiting((uint8_t)code);
 
   snprintf(buf, sizeof(buf), "W%02x", (uint8_t)code);
-  put_packet(&gdbserver_state, buf);
+  put_packet(buf);
 
 #ifndef CONFIG_USER_ONLY
   qemu_chr_fe_deinit(&gdbserver_state.chr, true);
@@ -2988,7 +2983,7 @@ static void create_default_process(GDBState *s)
     GDBProcess *process;
     int max_pid = 0;
 
-    if (s->process_num) {
+    if (gdbserver_state.process_num) {
         max_pid = s->processes[s->process_num - 1].pid;
     }
 
@@ -3020,7 +3015,7 @@ gdb_handlesig(CPUState *cpu, int sig)
 
     if (sig != 0) {
         snprintf(buf, sizeof(buf), "S%02x", target_signal_to_gdb(sig));
-        put_packet(&gdbserver_state, buf);
+        put_packet(buf);
     }
     /* put_packet() might have detected that the peer terminated the
        connection.  */
@@ -3064,7 +3059,7 @@ void gdb_signalled(CPUArchState *env, int sig)
     }
 
     snprintf(buf, sizeof(buf), "X%02x", target_signal_to_gdb(sig));
-    put_packet(&gdbserver_state, buf);
+    put_packet(buf);
 }
 
 static bool gdb_accept(void)
@@ -3095,7 +3090,7 @@ static bool gdb_accept(void)
     init_gdbserver_state();
     create_default_process(&gdbserver_state);
     gdbserver_state.processes[0].attached = true;
-    gdbserver_state.c_cpu = gdb_first_attached_cpu(&gdbserver_state);
+    gdbserver_state.c_cpu = gdb_first_attached_cpu();
     gdbserver_state.g_cpu = gdbserver_state.c_cpu;
     gdbserver_state.fd = fd;
     gdb_has_xml = false;
@@ -3188,7 +3183,7 @@ static void gdb_chr_event(void *opaque, int event)
             s->processes[i].attached = !i;
         }
 
-        s->c_cpu = gdb_first_attached_cpu(s);
+        s->c_cpu = gdb_first_attached_cpu();
         s->g_cpu = s->c_cpu;
 
         vm_stop(RUN_STATE_PAUSED);
@@ -3207,7 +3202,7 @@ static void gdb_monitor_output(GDBState *s, const char *msg, int len)
     if (len > (MAX_PACKET_LENGTH/2) - 1)
         len = (MAX_PACKET_LENGTH/2) - 1;
     memtohex(buf + 1, (uint8_t *)msg, len);
-    put_packet(s, buf);
+    put_packet(buf);
 }
 
 static int gdb_monitor_write(Chardev *chr, const uint8_t *buf, int len)
@@ -3305,9 +3300,9 @@ static void create_processes(GDBState *s)
 {
     object_child_foreach(object_get_root(), find_cpu_clusters, s);
 
-    if (s->processes) {
+    if (gdbserver_state.processes) {
         /* Sort by PID */
-        qsort(s->processes, s->process_num, sizeof(s->processes[0]), pid_order);
+        qsort(gdbserver_state.processes, gdbserver_state.process_num, sizeof(gdbserver_state.processes[0]), pid_order);
     }
 
     create_default_process(s);
@@ -3387,7 +3382,7 @@ int gdbserver_start(const char *device)
 void gdbserver_cleanup(void)
 {
     if (gdbserver_state.init) {
-        put_packet(&gdbserver_state, "W00");
+        put_packet("W00");
     }
 }
 
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH  v2 03/14] gdbstub: move str_buf to GDBState and use GString
  2019-11-30  8:45 [PATCH v2 00/14] gdbstub refactor and SVE support Alex Bennée
  2019-11-30  8:45 ` [PATCH v2 01/14] gdbstub: make GDBState static and have common init function Alex Bennée
  2019-11-30  8:45 ` [PATCH v2 02/14] gdbstub: stop passing GDBState * around and use global Alex Bennée
@ 2019-11-30  8:45 ` Alex Bennée
  2019-12-02 15:26   ` Damien Hedde
  2019-12-03 12:49   ` Damien Hedde
  2019-11-30  8:45 ` [PATCH v2 04/14] gdbstub: move mem_buf to GDBState and use GByteArray Alex Bennée
                   ` (11 subsequent siblings)
  14 siblings, 2 replies; 38+ messages in thread
From: Alex Bennée @ 2019-11-30  8:45 UTC (permalink / raw)
  To: qemu-devel
  Cc: damien.hedde, luis.machado, Philippe Mathieu-Daudé,
	richard.henderson, alan.hayward, Alex Bennée

Rather than having a static buffer replace str_buf with a GString
which we know can grow on demand. Convert the internal functions to
take a GString instead of a char * and length.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

---
v2
  - fix conflict from status gdbserver_state
  - add put_strbuf helper
---
 gdbstub.c | 195 +++++++++++++++++++++++++-----------------------------
 1 file changed, 90 insertions(+), 105 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 23f513f709e..dc8a6f2c7e2 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -366,6 +366,7 @@ typedef struct GDBState {
     int process_num;
     char syscall_buf[256];
     gdb_syscall_complete_cb current_syscall_cb;
+    GString *str_buf;
 } GDBState;
 
 /* By default use no IRQs and no timers while single stepping so as to
@@ -380,6 +381,7 @@ static void init_gdbserver_state(void)
     g_assert(!gdbserver_state.init);
     memset(&gdbserver_state, 0, sizeof(GDBState));
     gdbserver_state.init = true;
+    gdbserver_state.str_buf = g_string_new(NULL);
 }
 
 #ifndef CONFIG_USER_ONLY
@@ -563,17 +565,15 @@ static inline int tohex(int v)
 }
 
 /* writes 2*len+1 bytes in buf */
-static void memtohex(char *buf, const uint8_t *mem, int len)
+static void memtohex(GString *buf, const uint8_t *mem, int len)
 {
     int i, c;
-    char *q;
-    q = buf;
     for(i = 0; i < len; i++) {
         c = mem[i];
-        *q++ = tohex(c >> 4);
-        *q++ = tohex(c & 0xf);
+        g_string_append_c(buf, tohex(c >> 4));
+        g_string_append_c(buf, tohex(c & 0xf));
     }
-    *q = '\0';
+    g_string_append_c(buf, '\0');
 }
 
 static void hextomem(uint8_t *mem, const char *buf, int len)
@@ -667,25 +667,28 @@ static int put_packet(const char *buf)
     return put_packet_binary(buf, strlen(buf), false);
 }
 
+static void put_strbuf(void)
+{
+    put_packet(gdbserver_state.str_buf->str);
+}
+
 /* Encode data using the encoding for 'x' packets.  */
-static int memtox(char *buf, const char *mem, int len)
+static void memtox(GString *buf, const char *mem, int len)
 {
-    char *p = buf;
     char c;
 
     while (len--) {
         c = *(mem++);
         switch (c) {
         case '#': case '$': case '*': case '}':
-            *(p++) = '}';
-            *(p++) = c ^ 0x20;
+            g_string_append_c(buf, '}');
+            g_string_append_c(buf, c ^ 0x20);
             break;
         default:
-            *(p++) = c;
+            g_string_append_c(buf, c);
             break;
         }
     }
-    return p - buf;
 }
 
 static uint32_t gdb_get_cpu_pid(CPUState *cpu)
@@ -1109,16 +1112,14 @@ static void gdb_set_cpu_pc(target_ulong pc)
     cpu_set_pc(cpu, pc);
 }
 
-static char *gdb_fmt_thread_id(CPUState *cpu, char *buf, size_t buf_size)
+static void gdb_append_thread_id(CPUState *cpu, GString *buf)
 {
     if (gdbserver_state.multiprocess) {
-        snprintf(buf, buf_size, "p%02x.%02x",
-                 gdb_get_cpu_pid(cpu), cpu_gdb_index(cpu));
+        g_string_append_printf(buf, "p%02x.%02x",
+                               gdb_get_cpu_pid(cpu), cpu_gdb_index(cpu));
     } else {
-        snprintf(buf, buf_size, "%02x", cpu_gdb_index(cpu));
+        g_string_append_printf(buf, "%02x", cpu_gdb_index(cpu));
     }
-
-    return buf;
 }
 
 typedef enum GDBThreadIdKind {
@@ -1412,7 +1413,6 @@ typedef struct GdbCmdContext {
     GdbCmdVariant *params;
     int num_params;
     uint8_t mem_buf[MAX_PACKET_LENGTH];
-    char str_buf[MAX_PACKET_LENGTH + 1];
 } GdbCmdContext;
 
 typedef void (*GdbCmdHandler)(GdbCmdContext *gdb_ctx, void *user_ctx);
@@ -1503,6 +1503,8 @@ static void run_cmd_parser(GDBState *s, const char *data,
         return;
     }
 
+    g_string_set_size(gdbserver_state.str_buf, 0);
+
     /* In case there was an error during the command parsing we must
     * send a NULL packet to indicate the command is not supported */
     if (process_string_cmd(NULL, data, cmd, 1)) {
@@ -1741,8 +1743,8 @@ static void handle_get_reg(GdbCmdContext *gdb_ctx, void *user_ctx)
         return;
     }
 
-    memtohex(gdb_ctx->str_buf, gdb_ctx->mem_buf, reg_size);
-    put_packet(gdb_ctx->str_buf);
+    memtohex(gdbserver_state.str_buf, gdb_ctx->mem_buf, reg_size);
+    put_strbuf();
 }
 
 static void handle_write_mem(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -1790,8 +1792,8 @@ static void handle_read_mem(GdbCmdContext *gdb_ctx, void *user_ctx)
         return;
     }
 
-    memtohex(gdb_ctx->str_buf, gdb_ctx->mem_buf, gdb_ctx->params[1].val_ull);
-    put_packet(gdb_ctx->str_buf);
+    memtohex(gdbserver_state.str_buf, gdb_ctx->mem_buf, gdb_ctx->params[1].val_ull);
+    put_strbuf();
 }
 
 static void handle_write_all_regs(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -1828,8 +1830,8 @@ static void handle_read_all_regs(GdbCmdContext *gdb_ctx, void *user_ctx)
                                  addr);
     }
 
-    memtohex(gdb_ctx->str_buf, gdb_ctx->mem_buf, len);
-    put_packet(gdb_ctx->str_buf);
+    memtohex(gdbserver_state.str_buf, gdb_ctx->mem_buf, len);
+    put_strbuf();
 }
 
 static void handle_file_io(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -1890,9 +1892,8 @@ static void handle_v_attach(GdbCmdContext *gdb_ctx, void *user_ctx)
 {
     GDBProcess *process;
     CPUState *cpu;
-    char thread_id[16];
 
-    pstrcpy(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "E22");
+    g_string_assign(gdbserver_state.str_buf, "E22");
     if (!gdb_ctx->num_params) {
         goto cleanup;
     }
@@ -1911,11 +1912,11 @@ static void handle_v_attach(GdbCmdContext *gdb_ctx, void *user_ctx)
     gdbserver_state.g_cpu = cpu;
     gdbserver_state.c_cpu = cpu;
 
-    gdb_fmt_thread_id(cpu, thread_id, sizeof(thread_id));
-    snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "T%02xthread:%s;",
-             GDB_SIGNAL_TRAP, thread_id);
+    g_string_printf(gdbserver_state.str_buf, "T%02xthread:", GDB_SIGNAL_TRAP);
+    gdb_append_thread_id(cpu, gdbserver_state.str_buf);
+    g_string_append_c(gdbserver_state.str_buf, ';');
 cleanup:
-    put_packet(gdb_ctx->str_buf);
+    put_strbuf();
 }
 
 static void handle_v_kill(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -1967,10 +1968,9 @@ static void handle_v_commands(GdbCmdContext *gdb_ctx, void *user_ctx)
 
 static void handle_query_qemu_sstepbits(GdbCmdContext *gdb_ctx, void *user_ctx)
 {
-    snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf),
-             "ENABLE=%x,NOIRQ=%x,NOTIMER=%x", SSTEP_ENABLE,
-             SSTEP_NOIRQ, SSTEP_NOTIMER);
-    put_packet(gdb_ctx->str_buf);
+    g_string_printf(gdbserver_state.str_buf, "ENABLE=%x,NOIRQ=%x,NOTIMER=%x",
+                    SSTEP_ENABLE, SSTEP_NOIRQ, SSTEP_NOTIMER);
+    put_strbuf();
 }
 
 static void handle_set_qemu_sstep(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -1985,15 +1985,14 @@ static void handle_set_qemu_sstep(GdbCmdContext *gdb_ctx, void *user_ctx)
 
 static void handle_query_qemu_sstep(GdbCmdContext *gdb_ctx, void *user_ctx)
 {
-    snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "0x%x", sstep_flags);
-    put_packet(gdb_ctx->str_buf);
+    g_string_printf(gdbserver_state.str_buf, "0x%x", sstep_flags);
+    put_strbuf();;
 }
 
 static void handle_query_curr_tid(GdbCmdContext *gdb_ctx, void *user_ctx)
 {
     CPUState *cpu;
     GDBProcess *process;
-    char thread_id[16];
 
     /*
      * "Current thread" remains vague in the spec, so always return
@@ -2002,24 +2001,21 @@ static void handle_query_curr_tid(GdbCmdContext *gdb_ctx, void *user_ctx)
      */
     process = gdb_get_cpu_process(gdbserver_state.g_cpu);
     cpu = get_first_cpu_in_process(process);
-    gdb_fmt_thread_id(cpu, thread_id, sizeof(thread_id));
-    snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "QC%s", thread_id);
-    put_packet(gdb_ctx->str_buf);
+    g_string_assign(gdbserver_state.str_buf, "QC");
+    gdb_append_thread_id(cpu, gdbserver_state.str_buf);
+    put_strbuf();;
 }
 
 static void handle_query_threads(GdbCmdContext *gdb_ctx, void *user_ctx)
 {
-    char thread_id[16];
-
     if (!gdbserver_state.query_cpu) {
         put_packet("l");
         return;
     }
 
-    gdb_fmt_thread_id(gdbserver_state.query_cpu, thread_id,
-                      sizeof(thread_id));
-    snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "m%s", thread_id);
-    put_packet(gdb_ctx->str_buf);
+    g_string_assign(gdbserver_state.str_buf, "m");
+    gdb_append_thread_id(gdbserver_state.query_cpu, gdbserver_state.str_buf);
+    put_strbuf();;
     gdbserver_state.query_cpu = gdb_next_attached_cpu(gdbserver_state.query_cpu);
 }
 
@@ -2031,8 +2027,8 @@ static void handle_query_first_threads(GdbCmdContext *gdb_ctx, void *user_ctx)
 
 static void handle_query_thread_extra(GdbCmdContext *gdb_ctx, void *user_ctx)
 {
+    g_autoptr(GString) rs = g_string_new(NULL);
     CPUState *cpu;
-    int len;
 
     if (!gdb_ctx->num_params ||
         gdb_ctx->params[0].thread_id.kind == GDB_READ_THREAD_ERR) {
@@ -2052,20 +2048,17 @@ static void handle_query_thread_extra(GdbCmdContext *gdb_ctx, void *user_ctx)
         /* Print the CPU model and name in multiprocess mode */
         ObjectClass *oc = object_get_class(OBJECT(cpu));
         const char *cpu_model = object_class_get_name(oc);
-        char *cpu_name = object_get_canonical_path_component(OBJECT(cpu));
-        len = snprintf((char *)gdb_ctx->mem_buf, sizeof(gdb_ctx->str_buf) / 2,
-                       "%s %s [%s]", cpu_model, cpu_name,
-                       cpu->halted ? "halted " : "running");
-        g_free(cpu_name);
+        g_autofree char *cpu_name;
+        cpu_name  = object_get_canonical_path_component(OBJECT(cpu));
+        g_string_printf(rs, "%s %s [%s]", cpu_model, cpu_name,
+                        cpu->halted ? "halted " : "running");
     } else {
-        /* memtohex() doubles the required space */
-        len = snprintf((char *)gdb_ctx->mem_buf, sizeof(gdb_ctx->str_buf) / 2,
-                        "CPU#%d [%s]", cpu->cpu_index,
+        g_string_printf(rs, "CPU#%d [%s]", cpu->cpu_index,
                         cpu->halted ? "halted " : "running");
     }
-    trace_gdbstub_op_extra_info((char *)gdb_ctx->mem_buf);
-    memtohex(gdb_ctx->str_buf, gdb_ctx->mem_buf, len);
-    put_packet(gdb_ctx->str_buf);
+    trace_gdbstub_op_extra_info(rs->str);
+    memtohex(gdbserver_state.str_buf, (uint8_t *)rs->str, rs->len);
+    put_strbuf();;
 }
 
 #ifdef CONFIG_USER_ONLY
@@ -2074,13 +2067,14 @@ static void handle_query_offsets(GdbCmdContext *gdb_ctx, void *user_ctx)
     TaskState *ts;
 
     ts = gdbserver_state.c_cpu->opaque;
-    snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf),
-             "Text=" TARGET_ABI_FMT_lx ";Data=" TARGET_ABI_FMT_lx
-             ";Bss=" TARGET_ABI_FMT_lx,
-             ts->info->code_offset,
-             ts->info->data_offset,
-             ts->info->data_offset);
-    put_packet(gdb_ctx->str_buf);
+    g_string_printf(gdbserver_state.str_buf,
+                    "Text=" TARGET_ABI_FMT_lx
+                    ";Data=" TARGET_ABI_FMT_lx
+                    ";Bss=" TARGET_ABI_FMT_lx,
+                    ts->info->code_offset,
+                    ts->info->data_offset,
+                    ts->info->data_offset);
+    put_strbuf();
 }
 #else
 static void handle_query_rcmd(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -2111,12 +2105,10 @@ static void handle_query_supported(GdbCmdContext *gdb_ctx, void *user_ctx)
 {
     CPUClass *cc;
 
-    snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "PacketSize=%x",
-             MAX_PACKET_LENGTH);
+    g_string_printf(gdbserver_state.str_buf, "PacketSize=%x", MAX_PACKET_LENGTH);
     cc = CPU_GET_CLASS(first_cpu);
     if (cc->gdb_core_xml_file) {
-        pstrcat(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf),
-                ";qXfer:features:read+");
+        g_string_append(gdbserver_state.str_buf, ";qXfer:features:read+");
     }
 
     if (gdb_ctx->num_params &&
@@ -2124,8 +2116,8 @@ static void handle_query_supported(GdbCmdContext *gdb_ctx, void *user_ctx)
         gdbserver_state.multiprocess = true;
     }
 
-    pstrcat(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), ";multiprocess+");
-    put_packet(gdb_ctx->str_buf);
+    g_string_append(gdbserver_state.str_buf, ";multiprocess+");
+    put_strbuf();
 }
 
 static void handle_query_xfer_features(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -2169,14 +2161,15 @@ static void handle_query_xfer_features(GdbCmdContext *gdb_ctx, void *user_ctx)
     }
 
     if (len < total_len - addr) {
-        gdb_ctx->str_buf[0] = 'm';
-        len = memtox(gdb_ctx->str_buf + 1, xml + addr, len);
+        g_string_assign(gdbserver_state.str_buf, "m");
+        memtox(gdbserver_state.str_buf, xml + addr, len);
     } else {
-        gdb_ctx->str_buf[0] = 'l';
-        len = memtox(gdb_ctx->str_buf + 1, xml + addr, total_len - addr);
+        g_string_assign(gdbserver_state.str_buf, "l");
+        memtox(gdbserver_state.str_buf, xml + addr, total_len - addr);
     }
 
-    put_packet_binary(gdb_ctx->str_buf, len + 1, true);
+    put_packet_binary(gdbserver_state.str_buf->str,
+                      gdbserver_state.str_buf->len, true);
 }
 
 static void handle_query_attached(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -2186,19 +2179,19 @@ static void handle_query_attached(GdbCmdContext *gdb_ctx, void *user_ctx)
 
 static void handle_query_qemu_supported(GdbCmdContext *gdb_ctx, void *user_ctx)
 {
-    snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "sstepbits;sstep");
+    g_string_printf(gdbserver_state.str_buf, "sstepbits;sstep");
 #ifndef CONFIG_USER_ONLY
-    pstrcat(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), ";PhyMemMode");
+    g_string_append(gdbserver_state.str_buf, ";PhyMemMode");
 #endif
-    put_packet(gdb_ctx->str_buf);
+    put_strbuf();
 }
 
 #ifndef CONFIG_USER_ONLY
 static void handle_query_qemu_phy_mem_mode(GdbCmdContext *gdb_ctx,
                                            void *user_ctx)
 {
-    snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "%d", phy_memory_mode);
-    put_packet(gdb_ctx->str_buf);
+    g_string_printf(gdbserver_state.str_buf, "%d", phy_memory_mode);
+    put_strbuf();
 }
 
 static void handle_set_qemu_phy_mem_mode(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -2363,13 +2356,10 @@ static void handle_gen_set(GdbCmdContext *gdb_ctx, void *user_ctx)
 
 static void handle_target_halt(GdbCmdContext *gdb_ctx, void *user_ctx)
 {
-    char thread_id[16];
-
-    gdb_fmt_thread_id(gdbserver_state.c_cpu, thread_id,
-                      sizeof(thread_id));
-    snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "T%02xthread:%s;",
-             GDB_SIGNAL_TRAP, thread_id);
-    put_packet(gdb_ctx->str_buf);
+    g_string_printf(gdbserver_state.str_buf, "T%02xthread:", GDB_SIGNAL_TRAP);
+    gdb_append_thread_id(gdbserver_state.c_cpu, gdbserver_state.str_buf);
+    g_string_append_c(gdbserver_state.str_buf, ';');
+    put_strbuf();
     /*
      * Remove all the breakpoints when this query is issued,
      * because gdb is doing an initial connect and the state
@@ -2632,8 +2622,8 @@ void gdb_set_stop_cpu(CPUState *cpu)
 static void gdb_vm_state_change(void *opaque, int running, RunState state)
 {
     CPUState *cpu = gdbserver_state.c_cpu;
-    char buf[256];
-    char thread_id[16];
+    g_autoptr(GString) buf = g_string_new(NULL);
+    g_autoptr(GString) tid = g_string_new(NULL);
     const char *type;
     int ret;
 
@@ -2651,7 +2641,7 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
         return;
     }
 
-    gdb_fmt_thread_id(cpu, thread_id, sizeof(thread_id));
+    gdb_append_thread_id(cpu, tid);
 
     switch (state) {
     case RUN_STATE_DEBUG:
@@ -2669,10 +2659,9 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
             }
             trace_gdbstub_hit_watchpoint(type, cpu_gdb_index(cpu),
                     (target_ulong)cpu->watchpoint_hit->vaddr);
-            snprintf(buf, sizeof(buf),
-                     "T%02xthread:%s;%swatch:" TARGET_FMT_lx ";",
-                     GDB_SIGNAL_TRAP, thread_id, type,
-                     (target_ulong)cpu->watchpoint_hit->vaddr);
+            g_string_printf(buf, "T%02xthread:%s;%swatch:" TARGET_FMT_lx ";",
+                            GDB_SIGNAL_TRAP, tid->str, type,
+                            (target_ulong)cpu->watchpoint_hit->vaddr);
             cpu->watchpoint_hit = NULL;
             goto send_packet;
         } else {
@@ -2713,10 +2702,10 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
         break;
     }
     gdb_set_stop_cpu(cpu);
-    snprintf(buf, sizeof(buf), "T%02xthread:%s;", ret, thread_id);
+    g_string_printf(buf, "T%02xthread:%s;", ret, tid->str);
 
 send_packet:
-    put_packet(buf);
+    put_packet(buf->str);
 
     /* disable single step if it was enabled */
     cpu_single_step(cpu, 0);
@@ -3196,13 +3185,9 @@ static void gdb_chr_event(void *opaque, int event)
 
 static void gdb_monitor_output(GDBState *s, const char *msg, int len)
 {
-    char buf[MAX_PACKET_LENGTH];
-
-    buf[0] = 'O';
-    if (len > (MAX_PACKET_LENGTH/2) - 1)
-        len = (MAX_PACKET_LENGTH/2) - 1;
-    memtohex(buf + 1, (uint8_t *)msg, len);
-    put_packet(buf);
+    g_autoptr(GString) buf = g_string_new("O");
+    memtohex(buf, (uint8_t *)msg, len);
+    put_packet(buf->str);
 }
 
 static int gdb_monitor_write(Chardev *chr, const uint8_t *buf, int len)
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v2 04/14] gdbstub: move mem_buf to GDBState and use GByteArray
  2019-11-30  8:45 [PATCH v2 00/14] gdbstub refactor and SVE support Alex Bennée
                   ` (2 preceding siblings ...)
  2019-11-30  8:45 ` [PATCH v2 03/14] gdbstub: move str_buf to GDBState and use GString Alex Bennée
@ 2019-11-30  8:45 ` Alex Bennée
  2019-12-03 11:11   ` Damien Hedde
  2019-11-30  8:45 ` [PATCH v2 05/14] gdbstub: add helper for 128 bit registers Alex Bennée
                   ` (10 subsequent siblings)
  14 siblings, 1 reply; 38+ messages in thread
From: Alex Bennée @ 2019-11-30  8:45 UTC (permalink / raw)
  To: qemu-devel
  Cc: damien.hedde, luis.machado, Philippe Mathieu-Daudé,
	richard.henderson, alan.hayward, Alex Bennée

This is in preparation for further re-factoring of the register API
with the rest of the code. Theoretically the read register function
could overwrite the MAX_PACKET_LENGTH buffer although currently all
registers are well within the size range.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
---
 gdbstub.c | 62 ++++++++++++++++++++++++++++++++++---------------------
 1 file changed, 38 insertions(+), 24 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index dc8a6f2c7e2..265157282f2 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -367,6 +367,7 @@ typedef struct GDBState {
     char syscall_buf[256];
     gdb_syscall_complete_cb current_syscall_cb;
     GString *str_buf;
+    GByteArray *mem_buf;
 } GDBState;
 
 /* By default use no IRQs and no timers while single stepping so as to
@@ -382,6 +383,7 @@ static void init_gdbserver_state(void)
     memset(&gdbserver_state, 0, sizeof(GDBState));
     gdbserver_state.init = true;
     gdbserver_state.str_buf = g_string_new(NULL);
+    gdbserver_state.mem_buf = g_byte_array_sized_new(MAX_PACKET_LENGTH);
 }
 
 #ifndef CONFIG_USER_ONLY
@@ -576,12 +578,13 @@ static void memtohex(GString *buf, const uint8_t *mem, int len)
     g_string_append_c(buf, '\0');
 }
 
-static void hextomem(uint8_t *mem, const char *buf, int len)
+static void hextomem(GByteArray *mem, const char *buf, int len)
 {
     int i;
 
     for(i = 0; i < len; i++) {
-        mem[i] = (fromhex(buf[0]) << 4) | fromhex(buf[1]);
+        guint8 byte = fromhex(buf[0]) << 4 | fromhex(buf[1]);
+        g_byte_array_append(mem, &byte, 1);
         buf += 2;
     }
 }
@@ -1412,7 +1415,6 @@ static int cmd_parse_params(const char *data, const char *schema,
 typedef struct GdbCmdContext {
     GdbCmdVariant *params;
     int num_params;
-    uint8_t mem_buf[MAX_PACKET_LENGTH];
 } GdbCmdContext;
 
 typedef void (*GdbCmdHandler)(GdbCmdContext *gdb_ctx, void *user_ctx);
@@ -1504,6 +1506,7 @@ static void run_cmd_parser(GDBState *s, const char *data,
     }
 
     g_string_set_size(gdbserver_state.str_buf, 0);
+    g_byte_array_set_size(gdbserver_state.mem_buf, 0);
 
     /* In case there was an error during the command parsing we must
     * send a NULL packet to indicate the command is not supported */
@@ -1716,8 +1719,8 @@ static void handle_set_reg(GdbCmdContext *gdb_ctx, void *user_ctx)
     }
 
     reg_size = strlen(gdb_ctx->params[1].data) / 2;
-    hextomem(gdb_ctx->mem_buf, gdb_ctx->params[1].data, reg_size);
-    gdb_write_register(gdbserver_state.g_cpu, gdb_ctx->mem_buf,
+    hextomem(gdbserver_state.mem_buf, gdb_ctx->params[1].data, reg_size);
+    gdb_write_register(gdbserver_state.g_cpu, gdbserver_state.mem_buf->data,
                        gdb_ctx->params[0].val_ull);
     put_packet("OK");
 }
@@ -1736,14 +1739,17 @@ static void handle_get_reg(GdbCmdContext *gdb_ctx, void *user_ctx)
         return;
     }
 
-    reg_size = gdb_read_register(gdbserver_state.g_cpu, gdb_ctx->mem_buf,
+    reg_size = gdb_read_register(gdbserver_state.g_cpu,
+                                 gdbserver_state.mem_buf->data,
                                  gdb_ctx->params[0].val_ull);
     if (!reg_size) {
         put_packet("E14");
         return;
+    } else {
+        g_byte_array_set_size(gdbserver_state.mem_buf, reg_size);
     }
 
-    memtohex(gdbserver_state.str_buf, gdb_ctx->mem_buf, reg_size);
+    memtohex(gdbserver_state.str_buf, gdbserver_state.mem_buf->data, reg_size);
     put_strbuf();
 }
 
@@ -1760,11 +1766,11 @@ static void handle_write_mem(GdbCmdContext *gdb_ctx, void *user_ctx)
         return;
     }
 
-    hextomem(gdb_ctx->mem_buf, gdb_ctx->params[2].data,
+    hextomem(gdbserver_state.mem_buf, gdb_ctx->params[2].data,
              gdb_ctx->params[1].val_ull);
     if (target_memory_rw_debug(gdbserver_state.g_cpu, gdb_ctx->params[0].val_ull,
-                               gdb_ctx->mem_buf,
-                               gdb_ctx->params[1].val_ull, true)) {
+                               gdbserver_state.mem_buf->data,
+                               gdbserver_state.mem_buf->len, true)) {
         put_packet("E14");
         return;
     }
@@ -1785,14 +1791,17 @@ static void handle_read_mem(GdbCmdContext *gdb_ctx, void *user_ctx)
         return;
     }
 
+    g_byte_array_set_size(gdbserver_state.mem_buf, gdb_ctx->params[1].val_ull);
+
     if (target_memory_rw_debug(gdbserver_state.g_cpu, gdb_ctx->params[0].val_ull,
-                               gdb_ctx->mem_buf,
-                               gdb_ctx->params[1].val_ull, false)) {
+                               gdbserver_state.mem_buf->data,
+                               gdbserver_state.mem_buf->len, false)) {
         put_packet("E14");
         return;
     }
 
-    memtohex(gdbserver_state.str_buf, gdb_ctx->mem_buf, gdb_ctx->params[1].val_ull);
+    memtohex(gdbserver_state.str_buf, gdbserver_state.mem_buf->data,
+             gdbserver_state.mem_buf->len);
     put_strbuf();
 }
 
@@ -1807,9 +1816,9 @@ static void handle_write_all_regs(GdbCmdContext *gdb_ctx, void *user_ctx)
     }
 
     cpu_synchronize_state(gdbserver_state.g_cpu);
-    registers = gdb_ctx->mem_buf;
     len = strlen(gdb_ctx->params[0].data) / 2;
-    hextomem(registers, gdb_ctx->params[0].data, len);
+    hextomem(gdbserver_state.mem_buf, gdb_ctx->params[0].data, len);
+    registers = gdbserver_state.mem_buf->data;
     for (addr = 0; addr < gdbserver_state.g_cpu->gdb_num_g_regs && len > 0;
          addr++) {
         reg_size = gdb_write_register(gdbserver_state.g_cpu, registers, addr);
@@ -1826,11 +1835,14 @@ static void handle_read_all_regs(GdbCmdContext *gdb_ctx, void *user_ctx)
     cpu_synchronize_state(gdbserver_state.g_cpu);
     len = 0;
     for (addr = 0; addr < gdbserver_state.g_cpu->gdb_num_g_regs; addr++) {
-        len += gdb_read_register(gdbserver_state.g_cpu, gdb_ctx->mem_buf + len,
+        len += gdb_read_register(gdbserver_state.g_cpu,
+                                 gdbserver_state.mem_buf->data + len,
                                  addr);
     }
+    /* FIXME: This is after the fact sizing */
+    g_byte_array_set_size(gdbserver_state.mem_buf, len);
 
-    memtohex(gdbserver_state.str_buf, gdb_ctx->mem_buf, len);
+    memtohex(gdbserver_state.str_buf, gdbserver_state.mem_buf->data, len);
     put_strbuf();
 }
 
@@ -2003,7 +2015,7 @@ static void handle_query_curr_tid(GdbCmdContext *gdb_ctx, void *user_ctx)
     cpu = get_first_cpu_in_process(process);
     g_string_assign(gdbserver_state.str_buf, "QC");
     gdb_append_thread_id(cpu, gdbserver_state.str_buf);
-    put_strbuf();;
+    put_strbuf();
 }
 
 static void handle_query_threads(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -2015,7 +2027,7 @@ static void handle_query_threads(GdbCmdContext *gdb_ctx, void *user_ctx)
 
     g_string_assign(gdbserver_state.str_buf, "m");
     gdb_append_thread_id(gdbserver_state.query_cpu, gdbserver_state.str_buf);
-    put_strbuf();;
+    put_strbuf();
     gdbserver_state.query_cpu = gdb_next_attached_cpu(gdbserver_state.query_cpu);
 }
 
@@ -2058,7 +2070,7 @@ static void handle_query_thread_extra(GdbCmdContext *gdb_ctx, void *user_ctx)
     }
     trace_gdbstub_op_extra_info(rs->str);
     memtohex(gdbserver_state.str_buf, (uint8_t *)rs->str, rs->len);
-    put_strbuf();;
+    put_strbuf();
 }
 
 #ifdef CONFIG_USER_ONLY
@@ -2079,6 +2091,7 @@ static void handle_query_offsets(GdbCmdContext *gdb_ctx, void *user_ctx)
 #else
 static void handle_query_rcmd(GdbCmdContext *gdb_ctx, void *user_ctx)
 {
+    const guint8 zero = 0;
     int len;
 
     if (!gdb_ctx->num_params) {
@@ -2093,11 +2106,12 @@ static void handle_query_rcmd(GdbCmdContext *gdb_ctx, void *user_ctx)
     }
 
     len = len / 2;
-    hextomem(gdb_ctx->mem_buf, gdb_ctx->params[0].data, len);
-    gdb_ctx->mem_buf[len++] = 0;
-    qemu_chr_be_write(gdbserver_state.mon_chr, gdb_ctx->mem_buf, len);
+    g_byte_array_set_size(gdbserver_state.mem_buf, len);
+    hextomem(gdbserver_state.mem_buf, gdb_ctx->params[0].data, len);
+    g_byte_array_append(gdbserver_state.mem_buf, &zero, 1);
+    qemu_chr_be_write(gdbserver_state.mon_chr, gdbserver_state.mem_buf->data,
+                      gdbserver_state.mem_buf->len);
     put_packet("OK");
-
 }
 #endif
 
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH  v2 05/14] gdbstub: add helper for 128 bit registers
  2019-11-30  8:45 [PATCH v2 00/14] gdbstub refactor and SVE support Alex Bennée
                   ` (3 preceding siblings ...)
  2019-11-30  8:45 ` [PATCH v2 04/14] gdbstub: move mem_buf to GDBState and use GByteArray Alex Bennée
@ 2019-11-30  8:45 ` Alex Bennée
  2019-12-01 20:02   ` Philippe Mathieu-Daudé
  2019-12-02  2:19   ` Richard Henderson
  2019-11-30  8:45 ` [PATCH v2 06/14] target/arm: use gdb_get_reg helpers Alex Bennée
                   ` (9 subsequent siblings)
  14 siblings, 2 replies; 38+ messages in thread
From: Alex Bennée @ 2019-11-30  8:45 UTC (permalink / raw)
  To: qemu-devel
  Cc: damien.hedde, luis.machado, Alex Bennée, richard.henderson,
	alan.hayward

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
v2
  - take care of endianess of the whole 128 bit word
---
 include/exec/gdbstub.h | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index 08363969c14..59e366ba3af 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -102,6 +102,19 @@ static inline int gdb_get_reg64(uint8_t *mem_buf, uint64_t val)
     return 8;
 }
 
+static inline int gdb_get_reg128(uint8_t *mem_buf, uint64_t val_hi,
+                                 uint64_t val_lo)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+    stq_p(mem_buf, val_hi);
+    stq_p(mem_buf + 8, val_lo);
+#else
+    stq_p(mem_buf, val_lo);
+    stq_p(mem_buf + 8, val_hi);
+#endif
+    return 16;
+}
+
 #if TARGET_LONG_BITS == 64
 #define gdb_get_regl(buf, val) gdb_get_reg64(buf, val)
 #define ldtul_p(addr) ldq_p(addr)
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH  v2 06/14] target/arm: use gdb_get_reg helpers
  2019-11-30  8:45 [PATCH v2 00/14] gdbstub refactor and SVE support Alex Bennée
                   ` (4 preceding siblings ...)
  2019-11-30  8:45 ` [PATCH v2 05/14] gdbstub: add helper for 128 bit registers Alex Bennée
@ 2019-11-30  8:45 ` Alex Bennée
  2019-12-01 20:05   ` Philippe Mathieu-Daudé
  2019-12-02  2:20   ` Richard Henderson
  2019-11-30  8:45 ` [PATCH v2 07/14] target/m68k: " Alex Bennée
                   ` (8 subsequent siblings)
  14 siblings, 2 replies; 38+ messages in thread
From: Alex Bennée @ 2019-11-30  8:45 UTC (permalink / raw)
  To: qemu-devel
  Cc: damien.hedde, Peter Maydell, luis.machado, richard.henderson,
	open list:ARM TCG CPUs, alan.hayward, Alex Bennée

This is cleaner than poking memory directly and will make later
clean-ups easier.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
v2
  - make sure we pass hi/lo correctly as quads are stored in LE order
---
 target/arm/helper.c | 18 +++++++-----------
 1 file changed, 7 insertions(+), 11 deletions(-)

diff --git a/target/arm/helper.c b/target/arm/helper.c
index 0bf8f53d4b8..0ac950d6c71 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -105,21 +105,17 @@ static int aarch64_fpu_gdb_get_reg(CPUARMState *env, uint8_t *buf, int reg)
 {
     switch (reg) {
     case 0 ... 31:
-        /* 128 bit FP register */
-        {
-            uint64_t *q = aa64_vfp_qreg(env, reg);
-            stq_le_p(buf, q[0]);
-            stq_le_p(buf + 8, q[1]);
-            return 16;
-        }
+    {
+        /* 128 bit FP register - quads are in LE order */
+        uint64_t *q = aa64_vfp_qreg(env, reg);
+        return gdb_get_reg128(buf, q[1], q[0]);
+    }
     case 32:
         /* FPSR */
-        stl_p(buf, vfp_get_fpsr(env));
-        return 4;
+        return gdb_get_reg32(buf, vfp_get_fpsr(env));
     case 33:
         /* FPCR */
-        stl_p(buf, vfp_get_fpcr(env));
-        return 4;
+        return gdb_get_reg32(buf,vfp_get_fpcr(env));
     default:
         return 0;
     }
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH  v2 07/14] target/m68k: use gdb_get_reg helpers
  2019-11-30  8:45 [PATCH v2 00/14] gdbstub refactor and SVE support Alex Bennée
                   ` (5 preceding siblings ...)
  2019-11-30  8:45 ` [PATCH v2 06/14] target/arm: use gdb_get_reg helpers Alex Bennée
@ 2019-11-30  8:45 ` Alex Bennée
  2019-11-30 10:58   ` Laurent Vivier
  2019-11-30  8:45 ` [PATCH v2 08/14] gdbstub: extend GByteArray to read register helpers Alex Bennée
                   ` (7 subsequent siblings)
  14 siblings, 1 reply; 38+ messages in thread
From: Alex Bennée @ 2019-11-30  8:45 UTC (permalink / raw)
  To: qemu-devel
  Cc: damien.hedde, luis.machado, richard.henderson, Laurent Vivier,
	alan.hayward, Alex Bennée

This is cleaner than poking memory directly and will make later
clean-ups easier.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/m68k/helper.c | 29 +++++++++++------------------
 1 file changed, 11 insertions(+), 18 deletions(-)

diff --git a/target/m68k/helper.c b/target/m68k/helper.c
index ae766a6cb0b..70b0c0b5076 100644
--- a/target/m68k/helper.c
+++ b/target/m68k/helper.c
@@ -72,19 +72,15 @@ static int cf_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
 {
     if (n < 8) {
         float_status s;
-        stfq_p(mem_buf, floatx80_to_float64(env->fregs[n].d, &s));
-        return 8;
+        return gdb_get_reg64(buf, floatx80_to_float64(env->fregs[n].d, &s));
     }
     switch (n) {
     case 8: /* fpcontrol */
-        stl_be_p(mem_buf, env->fpcr);
-        return 4;
+        return gdb_get_reg32(buf, env->fpcr);
     case 9: /* fpstatus */
-        stl_be_p(mem_buf, env->fpsr);
-        return 4;
+        return gdb_get_reg32(buf, env->fpsr);
     case 10: /* fpiar, not implemented */
-        memset(mem_buf, 0, 4);
-        return 4;
+        return gdb_get_reg32(buf, 0);
     }
     return 0;
 }
@@ -112,21 +108,18 @@ static int cf_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
 static int m68k_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
 {
     if (n < 8) {
-        stw_be_p(mem_buf, env->fregs[n].l.upper);
-        memset(mem_buf + 2, 0, 2);
-        stq_be_p(mem_buf + 4, env->fregs[n].l.lower);
-        return 12;
+        int len = gdb_get_reg16(buf, env->fregs[n].l.upper);
+        len += gdb_get_reg16(buf, 0);
+        len += gdb_get_reg64(buf, env->fregs[n].l.lower);
+        return len;
     }
     switch (n) {
     case 8: /* fpcontrol */
-        stl_be_p(mem_buf, env->fpcr);
-        return 4;
+        return gdb_get_reg32(buf, env->fpcr);
     case 9: /* fpstatus */
-        stl_be_p(mem_buf, env->fpsr);
-        return 4;
+        return gdb_get_reg32(buf, env->fpsr);
     case 10: /* fpiar, not implemented */
-        memset(mem_buf, 0, 4);
-        return 4;
+        return gdb_get_reg32(buf, 0);
     }
     return 0;
 }
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v2 08/14] gdbstub: extend GByteArray to read register helpers
  2019-11-30  8:45 [PATCH v2 00/14] gdbstub refactor and SVE support Alex Bennée
                   ` (6 preceding siblings ...)
  2019-11-30  8:45 ` [PATCH v2 07/14] target/m68k: " Alex Bennée
@ 2019-11-30  8:45 ` Alex Bennée
  2019-12-02  2:24   ` Richard Henderson
  2019-11-30  8:45 ` [PATCH v2 09/14] target/arm: prepare for multiple dynamic XMLs Alex Bennée
                   ` (6 subsequent siblings)
  14 siblings, 1 reply; 38+ messages in thread
From: Alex Bennée @ 2019-11-30  8:45 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, Cornelia Huck, luis.machado, Sagar Karandikar,
	David Hildenbrand, Mark Cave-Ayland, Max Filippov,
	Alistair Francis, Edgar E. Iglesias, Marek Vasut, alan.hayward,
	open list:PowerPC TCG CPUs, Aleksandar Rikalo, Richard Henderson,
	Philippe Mathieu-Daudé,
	Artyom Tarasenko, Eduardo Habkost, richard.henderson,
	open list:S390 TCG CPUs, open list:ARM TCG CPUs, Stafford Horne,
	Alex Bennée, David Gibson, damien.hedde,
	open list:RISC-V TCG CPUs, Bastian Koppelmann, Chris Wulff,
	Laurent Vivier, Michael Walle, Palmer Dabbelt,
	Aleksandar Markovic, Paolo Bonzini, Aurelien Jarno

Instead of passing a pointer to memory now just extend the GByteArray
to all the read register helpers. They can then safely append their
data through the normal way. We don't bother with this abstraction for
write registers as we have already ensured the buffer being copied
from is the correct size.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 include/exec/gdbstub.h          | 46 +++++++++++++++++-----------
 include/hw/core/cpu.h           |  2 +-
 target/alpha/cpu.h              |  2 +-
 target/arm/cpu.h                |  4 +--
 target/cris/cpu.h               |  4 +--
 target/hppa/cpu.h               |  2 +-
 target/i386/cpu.h               |  2 +-
 target/lm32/cpu.h               |  2 +-
 target/m68k/cpu.h               |  2 +-
 target/microblaze/cpu.h         |  2 +-
 target/mips/internal.h          |  2 +-
 target/openrisc/cpu.h           |  2 +-
 target/ppc/cpu.h                |  4 +--
 target/riscv/cpu.h              |  2 +-
 target/s390x/internal.h         |  2 +-
 target/sh4/cpu.h                |  2 +-
 target/sparc/cpu.h              |  2 +-
 target/xtensa/cpu.h             |  2 +-
 gdbstub.c                       | 20 ++++++------
 hw/core/cpu.c                   |  2 +-
 target/alpha/gdbstub.c          |  2 +-
 target/arm/gdbstub.c            |  2 +-
 target/arm/gdbstub64.c          |  2 +-
 target/arm/helper.c             | 19 +++++-------
 target/cris/gdbstub.c           |  4 +--
 target/hppa/gdbstub.c           |  2 +-
 target/i386/gdbstub.c           |  2 +-
 target/lm32/gdbstub.c           |  2 +-
 target/m68k/gdbstub.c           |  2 +-
 target/m68k/helper.c            |  4 +--
 target/microblaze/gdbstub.c     |  2 +-
 target/mips/gdbstub.c           |  2 +-
 target/nios2/cpu.c              |  2 +-
 target/openrisc/gdbstub.c       |  2 +-
 target/ppc/gdbstub.c            | 48 +++++++++++++++--------------
 target/ppc/translate_init.inc.c | 54 ++++++++++++++++++---------------
 target/riscv/gdbstub.c          | 18 +++++------
 target/s390x/gdbstub.c          | 30 +++++++++---------
 target/sh4/gdbstub.c            |  2 +-
 target/sparc/gdbstub.c          |  2 +-
 target/xtensa/gdbstub.c         |  2 +-
 41 files changed, 165 insertions(+), 148 deletions(-)

diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index 59e366ba3af..ef79e32708c 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -68,49 +68,59 @@ void gdb_signalled(CPUArchState *, int);
 void gdbserver_fork(CPUState *);
 #endif
 /* Get or set a register.  Returns the size of the register.  */
-typedef int (*gdb_reg_cb)(CPUArchState *env, uint8_t *buf, int reg);
+typedef int (*gdb_get_reg_cb)(CPUArchState *env, GByteArray *buf, int reg);
+typedef int (*gdb_set_reg_cb)(CPUArchState *env, uint8_t *buf, int reg);
 void gdb_register_coprocessor(CPUState *cpu,
-                              gdb_reg_cb get_reg, gdb_reg_cb set_reg,
+                              gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg,
                               int num_regs, const char *xml, int g_pos);
 
-/* The GDB remote protocol transfers values in target byte order.  This means
- * we can use the raw memory access routines to access the value buffer.
- * Conveniently, these also handle the case where the buffer is mis-aligned.
+/*
+ * The GDB remote protocol transfers values in target byte order. As
+ * the gdbstub may be batching up several register values we always
+ * append to the array.
  */
 
-static inline int gdb_get_reg8(uint8_t *mem_buf, uint8_t val)
+static inline int gdb_get_reg8(GByteArray *buf, uint8_t val)
 {
-    stb_p(mem_buf, val);
+    g_byte_array_append(buf, &val, 1);
     return 1;
 }
 
-static inline int gdb_get_reg16(uint8_t *mem_buf, uint16_t val)
+static inline int gdb_get_reg16(GByteArray *buf, uint16_t val)
 {
-    stw_p(mem_buf, val);
+    uint16_t to_word = tswap16(val);
+    g_byte_array_append(buf, (uint8_t *) &to_word, 2);
     return 2;
 }
 
-static inline int gdb_get_reg32(uint8_t *mem_buf, uint32_t val)
+static inline int gdb_get_reg32(GByteArray *buf, uint32_t val)
 {
-    stl_p(mem_buf, val);
+    uint32_t to_long = tswap32(val);
+    g_byte_array_append(buf, (uint8_t *) &to_long, 4);
     return 4;
 }
 
-static inline int gdb_get_reg64(uint8_t *mem_buf, uint64_t val)
+static inline int gdb_get_reg64(GByteArray *buf, uint64_t val)
 {
-    stq_p(mem_buf, val);
+    uint64_t to_quad = tswap64(val);
+    g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
     return 8;
 }
 
-static inline int gdb_get_reg128(uint8_t *mem_buf, uint64_t val_hi,
+static inline int gdb_get_reg128(GByteArray *buf, uint64_t val_hi,
                                  uint64_t val_lo)
 {
+    uint64_t to_quad;
 #ifdef TARGET_WORDS_BIGENDIAN
-    stq_p(mem_buf, val_hi);
-    stq_p(mem_buf + 8, val_lo);
+    to_quad = tswap64(val_hi);
+    g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
+    to_quad = tswap64(val_lo);
+    g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
 #else
-    stq_p(mem_buf, val_lo);
-    stq_p(mem_buf + 8, val_hi);
+    to_quad = tswap64(val_lo);
+    g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
+    to_quad = tswap64(val_hi);
+    g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
 #endif
     return 16;
 }
diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index 77c6f052990..e85ec519add 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -195,7 +195,7 @@ typedef struct CPUClass {
     hwaddr (*get_phys_page_attrs_debug)(CPUState *cpu, vaddr addr,
                                         MemTxAttrs *attrs);
     int (*asidx_from_attrs)(CPUState *cpu, MemTxAttrs attrs);
-    int (*gdb_read_register)(CPUState *cpu, uint8_t *buf, int reg);
+    int (*gdb_read_register)(CPUState *cpu, GByteArray *buf, int reg);
     int (*gdb_write_register)(CPUState *cpu, uint8_t *buf, int reg);
     bool (*debug_check_watchpoint)(CPUState *cpu, CPUWatchpoint *wp);
     void (*debug_excp_handler)(CPUState *cpu);
diff --git a/target/alpha/cpu.h b/target/alpha/cpu.h
index a530249a5bf..faa09768424 100644
--- a/target/alpha/cpu.h
+++ b/target/alpha/cpu.h
@@ -282,7 +282,7 @@ void alpha_cpu_do_interrupt(CPUState *cpu);
 bool alpha_cpu_exec_interrupt(CPUState *cpu, int int_req);
 void alpha_cpu_dump_state(CPUState *cs, FILE *f, int flags);
 hwaddr alpha_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-int alpha_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int alpha_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
 int alpha_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 void alpha_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
                                    MMUAccessType access_type,
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 83a809d4bac..cf16f915c82 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -949,7 +949,7 @@ bool arm_cpu_exec_interrupt(CPUState *cpu, int int_req);
 hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr,
                                          MemTxAttrs *attrs);
 
-int arm_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int arm_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
 int arm_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 
 /* Dynamically generates for gdb stub an XML description of the sysregs from
@@ -969,7 +969,7 @@ int arm_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
                              int cpuid, void *opaque);
 
 #ifdef TARGET_AARCH64
-int aarch64_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int aarch64_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
 int aarch64_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 void aarch64_sve_narrow_vq(CPUARMState *env, unsigned vq);
 void aarch64_sve_change_el(CPUARMState *env, int old_el,
diff --git a/target/cris/cpu.h b/target/cris/cpu.h
index aba0a664744..333ee5b171a 100644
--- a/target/cris/cpu.h
+++ b/target/cris/cpu.h
@@ -194,8 +194,8 @@ void cris_cpu_dump_state(CPUState *cs, FILE *f, int flags);
 
 hwaddr cris_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
 
-int crisv10_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
-int cris_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int crisv10_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
+int cris_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
 int cris_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 
 /* you can call this signal handler from your SIGBUS and SIGSEGV
diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h
index 6713d04f111..801a4fb1bae 100644
--- a/target/hppa/cpu.h
+++ b/target/hppa/cpu.h
@@ -321,7 +321,7 @@ void cpu_hppa_change_prot_id(CPUHPPAState *env);
 
 int cpu_hppa_signal_handler(int host_signum, void *pinfo, void *puc);
 hwaddr hppa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr);
-int hppa_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int hppa_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
 int hppa_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 void hppa_cpu_do_interrupt(CPUState *cpu);
 bool hppa_cpu_exec_interrupt(CPUState *cpu, int int_req);
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index cde2a16b941..11720130e66 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -1757,7 +1757,7 @@ void x86_cpu_dump_state(CPUState *cs, FILE *f, int flags);
 hwaddr x86_cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr,
                                          MemTxAttrs *attrs);
 
-int x86_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int x86_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
 int x86_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 
 void x86_cpu_exec_enter(CPUState *cpu);
diff --git a/target/lm32/cpu.h b/target/lm32/cpu.h
index 064c6b1267e..01d408eb55d 100644
--- a/target/lm32/cpu.h
+++ b/target/lm32/cpu.h
@@ -202,7 +202,7 @@ void lm32_cpu_do_interrupt(CPUState *cpu);
 bool lm32_cpu_exec_interrupt(CPUState *cs, int int_req);
 void lm32_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
 hwaddr lm32_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-int lm32_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int lm32_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
 int lm32_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 
 typedef enum {
diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h
index 20de3c379aa..cdb08c269f6 100644
--- a/target/m68k/cpu.h
+++ b/target/m68k/cpu.h
@@ -168,7 +168,7 @@ void m68k_cpu_do_interrupt(CPUState *cpu);
 bool m68k_cpu_exec_interrupt(CPUState *cpu, int int_req);
 void m68k_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
 hwaddr m68k_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-int m68k_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int m68k_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
 int m68k_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 
 void m68k_tcg_init(void);
diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h
index 95773089aa3..987e4629b0a 100644
--- a/target/microblaze/cpu.h
+++ b/target/microblaze/cpu.h
@@ -313,7 +313,7 @@ void mb_cpu_do_interrupt(CPUState *cs);
 bool mb_cpu_exec_interrupt(CPUState *cs, int int_req);
 void mb_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
 hwaddr mb_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-int mb_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int mb_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
 int mb_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 
 void mb_tcg_init(void);
diff --git a/target/mips/internal.h b/target/mips/internal.h
index 3f435b5e631..c5ae86360f5 100644
--- a/target/mips/internal.h
+++ b/target/mips/internal.h
@@ -82,7 +82,7 @@ void mips_cpu_do_interrupt(CPUState *cpu);
 bool mips_cpu_exec_interrupt(CPUState *cpu, int int_req);
 void mips_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
 hwaddr mips_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-int mips_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int mips_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
 int mips_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 void mips_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
                                   MMUAccessType access_type,
diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h
index 0ad02eab794..d9484b802f3 100644
--- a/target/openrisc/cpu.h
+++ b/target/openrisc/cpu.h
@@ -320,7 +320,7 @@ void openrisc_cpu_do_interrupt(CPUState *cpu);
 bool openrisc_cpu_exec_interrupt(CPUState *cpu, int int_req);
 void openrisc_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
 hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-int openrisc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int openrisc_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
 int openrisc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 void openrisc_translate_init(void);
 bool openrisc_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index e3e82327b72..ed3f55ea4b4 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1258,8 +1258,8 @@ bool ppc_cpu_exec_interrupt(CPUState *cpu, int int_req);
 void ppc_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
 void ppc_cpu_dump_statistics(CPUState *cpu, int flags);
 hwaddr ppc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-int ppc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
-int ppc_cpu_gdb_read_register_apple(CPUState *cpu, uint8_t *buf, int reg);
+int ppc_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
+int ppc_cpu_gdb_read_register_apple(CPUState *cpu, GByteArray *buf, int reg);
 int ppc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 int ppc_cpu_gdb_write_register_apple(CPUState *cpu, uint8_t *buf, int reg);
 #ifndef CONFIG_USER_ONLY
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index e59343e13c0..fe0b8861021 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -243,7 +243,7 @@ extern const char * const riscv_excp_names[];
 extern const char * const riscv_intr_names[];
 
 void riscv_cpu_do_interrupt(CPUState *cpu);
-int riscv_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int riscv_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
 int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request);
 bool riscv_cpu_fp_enabled(CPURISCVState *env);
diff --git a/target/s390x/internal.h b/target/s390x/internal.h
index d37816104dd..8c95c734dbe 100644
--- a/target/s390x/internal.h
+++ b/target/s390x/internal.h
@@ -292,7 +292,7 @@ uint16_t float128_dcmask(CPUS390XState *env, float128 f1);
 
 
 /* gdbstub.c */
-int s390_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int s390_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
 int s390_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 void s390_cpu_gdb_init(CPUState *cs);
 
diff --git a/target/sh4/cpu.h b/target/sh4/cpu.h
index ecaa7a18a94..d7a1bffd600 100644
--- a/target/sh4/cpu.h
+++ b/target/sh4/cpu.h
@@ -208,7 +208,7 @@ void superh_cpu_do_interrupt(CPUState *cpu);
 bool superh_cpu_exec_interrupt(CPUState *cpu, int int_req);
 void superh_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
 hwaddr superh_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-int superh_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int superh_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
 int superh_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 void superh_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
                                     MMUAccessType access_type,
diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h
index ae97c7d9f79..b9369398f24 100644
--- a/target/sparc/cpu.h
+++ b/target/sparc/cpu.h
@@ -571,7 +571,7 @@ extern const VMStateDescription vmstate_sparc_cpu;
 void sparc_cpu_do_interrupt(CPUState *cpu);
 void sparc_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
 hwaddr sparc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-int sparc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int sparc_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
 int sparc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 void QEMU_NORETURN sparc_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
                                                  MMUAccessType access_type,
diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h
index b363ffcf106..b20be1f5814 100644
--- a/target/xtensa/cpu.h
+++ b/target/xtensa/cpu.h
@@ -569,7 +569,7 @@ void xtensa_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
 hwaddr xtensa_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
 void xtensa_count_regs(const XtensaConfig *config,
                        unsigned *n_regs, unsigned *n_core_regs);
-int xtensa_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int xtensa_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
 int xtensa_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 void xtensa_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
                                     MMUAccessType access_type,
diff --git a/gdbstub.c b/gdbstub.c
index 265157282f2..7b695bdebe6 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -319,8 +319,8 @@ static int gdb_signal_to_target (int sig)
 typedef struct GDBRegisterState {
     int base_reg;
     int num_regs;
-    gdb_reg_cb get_reg;
-    gdb_reg_cb set_reg;
+    gdb_get_reg_cb get_reg;
+    gdb_set_reg_cb set_reg;
     const char *xml;
     struct GDBRegisterState *next;
 } GDBRegisterState;
@@ -905,19 +905,19 @@ static const char *get_feature_xml(const char *p, const char **newp,
     return name ? xml_builtin[i][1] : NULL;
 }
 
-static int gdb_read_register(CPUState *cpu, uint8_t *mem_buf, int reg)
+static int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg)
 {
     CPUClass *cc = CPU_GET_CLASS(cpu);
     CPUArchState *env = cpu->env_ptr;
     GDBRegisterState *r;
 
     if (reg < cc->gdb_num_core_regs) {
-        return cc->gdb_read_register(cpu, mem_buf, reg);
+        return cc->gdb_read_register(cpu, buf, reg);
     }
 
     for (r = cpu->gdb_regs; r; r = r->next) {
         if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) {
-            return r->get_reg(env, mem_buf, reg - r->base_reg);
+            return r->get_reg(env, buf, reg - r->base_reg);
         }
     }
     return 0;
@@ -948,7 +948,7 @@ static int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg)
  */
 
 void gdb_register_coprocessor(CPUState *cpu,
-                              gdb_reg_cb get_reg, gdb_reg_cb set_reg,
+                              gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg,
                               int num_regs, const char *xml, int g_pos)
 {
     GDBRegisterState *s;
@@ -1740,7 +1740,7 @@ static void handle_get_reg(GdbCmdContext *gdb_ctx, void *user_ctx)
     }
 
     reg_size = gdb_read_register(gdbserver_state.g_cpu,
-                                 gdbserver_state.mem_buf->data,
+                                 gdbserver_state.mem_buf,
                                  gdb_ctx->params[0].val_ull);
     if (!reg_size) {
         put_packet("E14");
@@ -1833,14 +1833,14 @@ static void handle_read_all_regs(GdbCmdContext *gdb_ctx, void *user_ctx)
     target_ulong addr, len;
 
     cpu_synchronize_state(gdbserver_state.g_cpu);
+    g_byte_array_set_size(gdbserver_state.mem_buf, 0);
     len = 0;
     for (addr = 0; addr < gdbserver_state.g_cpu->gdb_num_g_regs; addr++) {
         len += gdb_read_register(gdbserver_state.g_cpu,
-                                 gdbserver_state.mem_buf->data + len,
+                                 gdbserver_state.mem_buf,
                                  addr);
     }
-    /* FIXME: This is after the fact sizing */
-    g_byte_array_set_size(gdbserver_state.mem_buf, len);
+    g_assert(len == gdbserver_state.mem_buf->len);
 
     memtohex(gdbserver_state.str_buf, gdbserver_state.mem_buf->data, len);
     put_strbuf();
diff --git a/hw/core/cpu.c b/hw/core/cpu.c
index db1a03c6bbb..9cd1a2a54fb 100644
--- a/hw/core/cpu.c
+++ b/hw/core/cpu.c
@@ -177,7 +177,7 @@ static int cpu_common_write_elf64_note(WriteCoreDumpFunction f,
 }
 
 
-static int cpu_common_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg)
+static int cpu_common_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg)
 {
     return 0;
 }
diff --git a/target/alpha/gdbstub.c b/target/alpha/gdbstub.c
index 7f9cc092a9c..0cd76ddaa9e 100644
--- a/target/alpha/gdbstub.c
+++ b/target/alpha/gdbstub.c
@@ -21,7 +21,7 @@
 #include "cpu.h"
 #include "exec/gdbstub.h"
 
-int alpha_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int alpha_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
 {
     AlphaCPU *cpu = ALPHA_CPU(cs);
     CPUAlphaState *env = &cpu->env;
diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c
index 1239abd9842..4557775d245 100644
--- a/target/arm/gdbstub.c
+++ b/target/arm/gdbstub.c
@@ -32,7 +32,7 @@ typedef struct RegisterSysregXmlParam {
    We hack round this by giving the FPA regs zero size when talking to a
    newer gdb.  */
 
-int arm_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int arm_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
 {
     ARMCPU *cpu = ARM_CPU(cs);
     CPUARMState *env = &cpu->env;
diff --git a/target/arm/gdbstub64.c b/target/arm/gdbstub64.c
index 665ebb3ef64..35d0b80c2de 100644
--- a/target/arm/gdbstub64.c
+++ b/target/arm/gdbstub64.c
@@ -20,7 +20,7 @@
 #include "cpu.h"
 #include "exec/gdbstub.h"
 
-int aarch64_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int aarch64_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
 {
     ARMCPU *cpu = ARM_CPU(cs);
     CPUARMState *env = &cpu->env;
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 0ac950d6c71..6476245e789 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -47,30 +47,27 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
 
 static void switch_mode(CPUARMState *env, int mode);
 
-static int vfp_gdb_get_reg(CPUARMState *env, uint8_t *buf, int reg)
+static int vfp_gdb_get_reg(CPUARMState *env, GByteArray *buf, int reg)
 {
     int nregs;
 
     /* VFP data registers are always little-endian.  */
     nregs = arm_feature(env, ARM_FEATURE_VFP3) ? 32 : 16;
     if (reg < nregs) {
-        stq_le_p(buf, *aa32_vfp_dreg(env, reg));
-        return 8;
+        return gdb_get_reg64(buf, *aa32_vfp_dreg(env, reg));
     }
     if (arm_feature(env, ARM_FEATURE_NEON)) {
         /* Aliases for Q regs.  */
         nregs += 16;
         if (reg < nregs) {
             uint64_t *q = aa32_vfp_qreg(env, reg - 32);
-            stq_le_p(buf, q[0]);
-            stq_le_p(buf + 8, q[1]);
-            return 16;
+            return gdb_get_reg128(buf, q[0], q[1]);
         }
     }
     switch (reg - nregs) {
-    case 0: stl_p(buf, env->vfp.xregs[ARM_VFP_FPSID]); return 4;
-    case 1: stl_p(buf, vfp_get_fpscr(env)); return 4;
-    case 2: stl_p(buf, env->vfp.xregs[ARM_VFP_FPEXC]); return 4;
+    case 0: return gdb_get_reg32(buf, env->vfp.xregs[ARM_VFP_FPSID]); break;
+    case 1: return gdb_get_reg32(buf, vfp_get_fpscr(env)); break;
+    case 2: return gdb_get_reg32(buf, env->vfp.xregs[ARM_VFP_FPEXC]); break;
     }
     return 0;
 }
@@ -101,7 +98,7 @@ static int vfp_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg)
     return 0;
 }
 
-static int aarch64_fpu_gdb_get_reg(CPUARMState *env, uint8_t *buf, int reg)
+static int aarch64_fpu_gdb_get_reg(CPUARMState *env, GByteArray *buf, int reg)
 {
     switch (reg) {
     case 0 ... 31:
@@ -204,7 +201,7 @@ static void write_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri,
     }
 }
 
-static int arm_gdb_get_sysreg(CPUARMState *env, uint8_t *buf, int reg)
+static int arm_gdb_get_sysreg(CPUARMState *env, GByteArray *buf, int reg)
 {
     ARMCPU *cpu = env_archcpu(env);
     const ARMCPRegInfo *ri;
diff --git a/target/cris/gdbstub.c b/target/cris/gdbstub.c
index a3d76d2e8c2..b01b2aa0811 100644
--- a/target/cris/gdbstub.c
+++ b/target/cris/gdbstub.c
@@ -21,7 +21,7 @@
 #include "cpu.h"
 #include "exec/gdbstub.h"
 
-int crisv10_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int crisv10_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
 {
     CRISCPU *cpu = CRIS_CPU(cs);
     CPUCRISState *env = &cpu->env;
@@ -53,7 +53,7 @@ int crisv10_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
     return 0;
 }
 
-int cris_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int cris_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
 {
     CRISCPU *cpu = CRIS_CPU(cs);
     CPUCRISState *env = &cpu->env;
diff --git a/target/hppa/gdbstub.c b/target/hppa/gdbstub.c
index 341888a9da0..a6428a2893f 100644
--- a/target/hppa/gdbstub.c
+++ b/target/hppa/gdbstub.c
@@ -21,7 +21,7 @@
 #include "cpu.h"
 #include "exec/gdbstub.h"
 
-int hppa_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int hppa_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
 {
     HPPACPU *cpu = HPPA_CPU(cs);
     CPUHPPAState *env = &cpu->env;
diff --git a/target/i386/gdbstub.c b/target/i386/gdbstub.c
index aef25b70f10..38324498f33 100644
--- a/target/i386/gdbstub.c
+++ b/target/i386/gdbstub.c
@@ -79,7 +79,7 @@ static const int gpr_map32[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
 #endif
 
 
-int x86_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int x86_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
 {
     X86CPU *cpu = X86_CPU(cs);
     CPUX86State *env = &cpu->env;
diff --git a/target/lm32/gdbstub.c b/target/lm32/gdbstub.c
index 82ede436e12..b6fe12e1d61 100644
--- a/target/lm32/gdbstub.c
+++ b/target/lm32/gdbstub.c
@@ -22,7 +22,7 @@
 #include "exec/gdbstub.h"
 #include "hw/lm32/lm32_pic.h"
 
-int lm32_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int lm32_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
 {
     LM32CPU *cpu = LM32_CPU(cs);
     CPULM32State *env = &cpu->env;
diff --git a/target/m68k/gdbstub.c b/target/m68k/gdbstub.c
index fdc96f57fff..eb2d030e148 100644
--- a/target/m68k/gdbstub.c
+++ b/target/m68k/gdbstub.c
@@ -21,7 +21,7 @@
 #include "cpu.h"
 #include "exec/gdbstub.h"
 
-int m68k_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int m68k_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
 {
     M68kCPU *cpu = M68K_CPU(cs);
     CPUM68KState *env = &cpu->env;
diff --git a/target/m68k/helper.c b/target/m68k/helper.c
index 70b0c0b5076..a11863a8545 100644
--- a/target/m68k/helper.c
+++ b/target/m68k/helper.c
@@ -68,7 +68,7 @@ void m68k_cpu_list(void)
     g_slist_free(list);
 }
 
-static int cf_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
+static int cf_fpu_gdb_get_reg(CPUM68KState *env, GByteArray *buf, int n)
 {
     if (n < 8) {
         float_status s;
@@ -105,7 +105,7 @@ static int cf_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
     return 0;
 }
 
-static int m68k_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
+static int m68k_fpu_gdb_get_reg(CPUM68KState *env, GByteArray *buf, int n)
 {
     if (n < 8) {
         int len = gdb_get_reg16(buf, env->fregs[n].l.upper);
diff --git a/target/microblaze/gdbstub.c b/target/microblaze/gdbstub.c
index 30677b6d1f4..f41ebf1f33b 100644
--- a/target/microblaze/gdbstub.c
+++ b/target/microblaze/gdbstub.c
@@ -21,7 +21,7 @@
 #include "cpu.h"
 #include "exec/gdbstub.h"
 
-int mb_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int mb_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
 {
     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
     CPUMBState *env = &cpu->env;
diff --git a/target/mips/gdbstub.c b/target/mips/gdbstub.c
index bbb25449391..98f56e660d2 100644
--- a/target/mips/gdbstub.c
+++ b/target/mips/gdbstub.c
@@ -22,7 +22,7 @@
 #include "internal.h"
 #include "exec/gdbstub.h"
 
-int mips_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int mips_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
 {
     MIPSCPU *cpu = MIPS_CPU(cs);
     CPUMIPSState *env = &cpu->env;
diff --git a/target/nios2/cpu.c b/target/nios2/cpu.c
index ca9c7a6df5d..17d868421ed 100644
--- a/target/nios2/cpu.c
+++ b/target/nios2/cpu.c
@@ -124,7 +124,7 @@ static void nios2_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)
 #endif
 }
 
-static int nios2_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+static int nios2_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
 {
     Nios2CPU *cpu = NIOS2_CPU(cs);
     CPUClass *cc = CPU_GET_CLASS(cs);
diff --git a/target/openrisc/gdbstub.c b/target/openrisc/gdbstub.c
index 0fcdb79668c..095bf76c12c 100644
--- a/target/openrisc/gdbstub.c
+++ b/target/openrisc/gdbstub.c
@@ -21,7 +21,7 @@
 #include "cpu.h"
 #include "exec/gdbstub.h"
 
-int openrisc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int openrisc_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
 {
     OpenRISCCPU *cpu = OPENRISC_CPU(cs);
     CPUOpenRISCState *env = &cpu->env;
diff --git a/target/ppc/gdbstub.c b/target/ppc/gdbstub.c
index 823759c92e7..6f08021cc22 100644
--- a/target/ppc/gdbstub.c
+++ b/target/ppc/gdbstub.c
@@ -114,10 +114,11 @@ void ppc_maybe_bswap_register(CPUPPCState *env, uint8_t *mem_buf, int len)
  * the FP regs zero size when talking to a newer gdb.
  */
 
-int ppc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int ppc_cpu_gdb_read_register(CPUState *cs, GByteArray *buf, int n)
 {
     PowerPCCPU *cpu = POWERPC_CPU(cs);
     CPUPPCState *env = &cpu->env;
+    uint8_t *mem_buf;
     int r = ppc_gdb_register_len(n);
 
     if (!r) {
@@ -126,17 +127,17 @@ int ppc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
 
     if (n < 32) {
         /* gprs */
-        gdb_get_regl(mem_buf, env->gpr[n]);
+        gdb_get_regl(buf, env->gpr[n]);
     } else if (n < 64) {
         /* fprs */
-        stfq_p(mem_buf, *cpu_fpr_ptr(env, n - 32));
+        gdb_get_reg64(buf, *cpu_fpr_ptr(env, n - 32));
     } else {
         switch (n) {
         case 64:
-            gdb_get_regl(mem_buf, env->nip);
+            gdb_get_regl(buf, env->nip);
             break;
         case 65:
-            gdb_get_regl(mem_buf, env->msr);
+            gdb_get_regl(buf, env->msr);
             break;
         case 66:
             {
@@ -145,31 +146,33 @@ int ppc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
                 for (i = 0; i < 8; i++) {
                     cr |= env->crf[i] << (32 - ((i + 1) * 4));
                 }
-                gdb_get_reg32(mem_buf, cr);
+                gdb_get_reg32(buf, cr);
                 break;
             }
         case 67:
-            gdb_get_regl(mem_buf, env->lr);
+            gdb_get_regl(buf, env->lr);
             break;
         case 68:
-            gdb_get_regl(mem_buf, env->ctr);
+            gdb_get_regl(buf, env->ctr);
             break;
         case 69:
-            gdb_get_reg32(mem_buf, env->xer);
+            gdb_get_reg32(buf, env->xer);
             break;
         case 70:
-            gdb_get_reg32(mem_buf, env->fpscr);
+            gdb_get_reg32(buf, env->fpscr);
             break;
         }
     }
+    mem_buf = buf->data - r;
     ppc_maybe_bswap_register(env, mem_buf, r);
     return r;
 }
 
-int ppc_cpu_gdb_read_register_apple(CPUState *cs, uint8_t *mem_buf, int n)
+int ppc_cpu_gdb_read_register_apple(CPUState *cs, GByteArray *buf, int n)
 {
     PowerPCCPU *cpu = POWERPC_CPU(cs);
     CPUPPCState *env = &cpu->env;
+    uint8_t *mem_buf;
     int r = ppc_gdb_register_len_apple(n);
 
     if (!r) {
@@ -178,21 +181,21 @@ int ppc_cpu_gdb_read_register_apple(CPUState *cs, uint8_t *mem_buf, int n)
 
     if (n < 32) {
         /* gprs */
-        gdb_get_reg64(mem_buf, env->gpr[n]);
+        gdb_get_reg64(buf, env->gpr[n]);
     } else if (n < 64) {
         /* fprs */
-        stfq_p(mem_buf, *cpu_fpr_ptr(env, n - 32));
+        gdb_get_reg64(buf, *cpu_fpr_ptr(env, n - 32));
     } else if (n < 96) {
         /* Altivec */
-        stq_p(mem_buf, n - 64);
-        stq_p(mem_buf + 8, 0);
+        gdb_get_reg64(buf, n - 64);
+        gdb_get_reg64(buf, 0);
     } else {
         switch (n) {
         case 64 + 32:
-            gdb_get_reg64(mem_buf, env->nip);
+            gdb_get_reg64(buf, env->nip);
             break;
         case 65 + 32:
-            gdb_get_reg64(mem_buf, env->msr);
+            gdb_get_reg64(buf, env->msr);
             break;
         case 66 + 32:
             {
@@ -201,23 +204,24 @@ int ppc_cpu_gdb_read_register_apple(CPUState *cs, uint8_t *mem_buf, int n)
                 for (i = 0; i < 8; i++) {
                     cr |= env->crf[i] << (32 - ((i + 1) * 4));
                 }
-                gdb_get_reg32(mem_buf, cr);
+                gdb_get_reg32(buf, cr);
                 break;
             }
         case 67 + 32:
-            gdb_get_reg64(mem_buf, env->lr);
+            gdb_get_reg64(buf, env->lr);
             break;
         case 68 + 32:
-            gdb_get_reg64(mem_buf, env->ctr);
+            gdb_get_reg64(buf, env->ctr);
             break;
         case 69 + 32:
-            gdb_get_reg32(mem_buf, env->xer);
+            gdb_get_reg32(buf, env->xer);
             break;
         case 70 + 32:
-            gdb_get_reg64(mem_buf, env->fpscr);
+            gdb_get_reg64(buf, env->fpscr);
             break;
         }
     }
+    mem_buf = buf->data - r;
     ppc_maybe_bswap_register(env, mem_buf, r);
     return r;
 }
diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c
index ba726dec4d0..154f876e44c 100644
--- a/target/ppc/translate_init.inc.c
+++ b/target/ppc/translate_init.inc.c
@@ -9587,7 +9587,7 @@ static int gdb_find_spr_idx(CPUPPCState *env, int n)
     return -1;
 }
 
-static int gdb_get_spr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
+static int gdb_get_spr_reg(CPUPPCState *env, GByteArray *buf, int n)
 {
     int reg;
     int len;
@@ -9598,8 +9598,8 @@ static int gdb_get_spr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
     }
 
     len = TARGET_LONG_SIZE;
-    stn_p(mem_buf, len, env->spr[reg]);
-    ppc_maybe_bswap_register(env, mem_buf, len);
+    gdb_get_regl(buf, env->spr[reg]);
+    ppc_maybe_bswap_register(env, buf->data - len, len);
     return len;
 }
 
@@ -9621,15 +9621,18 @@ static int gdb_set_spr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
 }
 #endif
 
-static int gdb_get_float_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
+static int gdb_get_float_reg(CPUPPCState *env, GByteArray *buf, int n)
 {
+    uint8_t *mem_buf;
     if (n < 32) {
-        stfq_p(mem_buf, *cpu_fpr_ptr(env, n));
+        gdb_get_reg64(buf, *cpu_fpr_ptr(env, n));
+        mem_buf = buf->data - 8;
         ppc_maybe_bswap_register(env, mem_buf, 8);
         return 8;
     }
     if (n == 32) {
-        stl_p(mem_buf, env->fpscr);
+        gdb_get_reg32(buf, env->fpscr);
+        mem_buf = buf->data - 4;
         ppc_maybe_bswap_register(env, mem_buf, 4);
         return 4;
     }
@@ -9651,28 +9654,31 @@ static int gdb_set_float_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
     return 0;
 }
 
-static int gdb_get_avr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
+static int gdb_get_avr_reg(CPUPPCState *env, GByteArray *buf, int n)
 {
+    uint8_t *mem_buf;
+
     if (n < 32) {
         ppc_avr_t *avr = cpu_avr_ptr(env, n);
         if (!avr_need_swap(env)) {
-            stq_p(mem_buf, avr->u64[0]);
-            stq_p(mem_buf + 8, avr->u64[1]);
+            gdb_get_reg128(buf, avr->u64[0] , avr->u64[1]);
         } else {
-            stq_p(mem_buf, avr->u64[1]);
-            stq_p(mem_buf + 8, avr->u64[0]);
+            gdb_get_reg128(buf, avr->u64[1] , avr->u64[0]);
         }
+        mem_buf = buf->data - 16;
         ppc_maybe_bswap_register(env, mem_buf, 8);
         ppc_maybe_bswap_register(env, mem_buf + 8, 8);
         return 16;
     }
     if (n == 32) {
-        stl_p(mem_buf, helper_mfvscr(env));
+        gdb_get_reg32(buf, helper_mfvscr(env));
+        mem_buf = buf->data - 4;
         ppc_maybe_bswap_register(env, mem_buf, 4);
         return 4;
     }
     if (n == 33) {
-        stl_p(mem_buf, (uint32_t)env->spr[SPR_VRSAVE]);
+        gdb_get_reg32(buf, (uint32_t)env->spr[SPR_VRSAVE]);
+        mem_buf = buf->data - 4;
         ppc_maybe_bswap_register(env, mem_buf, 4);
         return 4;
     }
@@ -9707,25 +9713,25 @@ static int gdb_set_avr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
     return 0;
 }
 
-static int gdb_get_spe_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
+static int gdb_get_spe_reg(CPUPPCState *env, GByteArray *buf, int n)
 {
     if (n < 32) {
 #if defined(TARGET_PPC64)
-        stl_p(mem_buf, env->gpr[n] >> 32);
-        ppc_maybe_bswap_register(env, mem_buf, 4);
+        gdb_get_reg32(buf, env->gpr[n] >> 32);
+        ppc_maybe_bswap_register(env, buf->data - 4, 4);
 #else
-        stl_p(mem_buf, env->gprh[n]);
+        gdb_get_reg32(buf, env->gprh[n]);
 #endif
         return 4;
     }
     if (n == 32) {
-        stq_p(mem_buf, env->spe_acc);
-        ppc_maybe_bswap_register(env, mem_buf, 8);
+        gdb_get_reg64(buf, env->spe_acc);
+        ppc_maybe_bswap_register(env, buf->data - 8, 8);
         return 8;
     }
     if (n == 33) {
-        stl_p(mem_buf, env->spe_fscr);
-        ppc_maybe_bswap_register(env, mem_buf, 4);
+        gdb_get_reg32(buf, env->spe_fscr);
+        ppc_maybe_bswap_register(env, buf->data - 4, 4);
         return 4;
     }
     return 0;
@@ -9760,11 +9766,11 @@ static int gdb_set_spe_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
     return 0;
 }
 
-static int gdb_get_vsx_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
+static int gdb_get_vsx_reg(CPUPPCState *env, GByteArray *buf, int n)
 {
     if (n < 32) {
-        stq_p(mem_buf, *cpu_vsrl_ptr(env, n));
-        ppc_maybe_bswap_register(env, mem_buf, 8);
+        gdb_get_reg64(buf, *cpu_vsrl_ptr(env, n));
+        ppc_maybe_bswap_register(env, buf->data - 8, 8);
         return 8;
     }
     return 0;
diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c
index 1a7947e0198..05442215a4b 100644
--- a/target/riscv/gdbstub.c
+++ b/target/riscv/gdbstub.c
@@ -269,7 +269,7 @@ static int csr_register_map[] = {
     CSR_MHCOUNTEREN,
 };
 
-int riscv_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int riscv_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
 {
     RISCVCPU *cpu = RISCV_CPU(cs);
     CPURISCVState *env = &cpu->env;
@@ -300,10 +300,10 @@ int riscv_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
     return 0;
 }
 
-static int riscv_gdb_get_fpu(CPURISCVState *env, uint8_t *mem_buf, int n)
+static int riscv_gdb_get_fpu(CPURISCVState *env, GByteArray *buf, int n)
 {
     if (n < 32) {
-        return gdb_get_reg64(mem_buf, env->fpr[n]);
+        return gdb_get_reg64(buf, env->fpr[n]);
     /* there is hole between ft11 and fflags in fpu.xml */
     } else if (n < 36 && n > 32) {
         target_ulong val = 0;
@@ -316,7 +316,7 @@ static int riscv_gdb_get_fpu(CPURISCVState *env, uint8_t *mem_buf, int n)
         result = riscv_csrrw_debug(env, n - 33 + csr_register_map[8], &val,
                                    0, 0);
         if (result == 0) {
-            return gdb_get_regl(mem_buf, val);
+            return gdb_get_regl(buf, val);
         }
     }
     return 0;
@@ -345,7 +345,7 @@ static int riscv_gdb_set_fpu(CPURISCVState *env, uint8_t *mem_buf, int n)
     return 0;
 }
 
-static int riscv_gdb_get_csr(CPURISCVState *env, uint8_t *mem_buf, int n)
+static int riscv_gdb_get_csr(CPURISCVState *env, GByteArray *buf, int n)
 {
     if (n < ARRAY_SIZE(csr_register_map)) {
         target_ulong val = 0;
@@ -353,7 +353,7 @@ static int riscv_gdb_get_csr(CPURISCVState *env, uint8_t *mem_buf, int n)
 
         result = riscv_csrrw_debug(env, csr_register_map[n], &val, 0, 0);
         if (result == 0) {
-            return gdb_get_regl(mem_buf, val);
+            return gdb_get_regl(buf, val);
         }
     }
     return 0;
@@ -373,13 +373,13 @@ static int riscv_gdb_set_csr(CPURISCVState *env, uint8_t *mem_buf, int n)
     return 0;
 }
 
-static int riscv_gdb_get_virtual(CPURISCVState *cs, uint8_t *mem_buf, int n)
+static int riscv_gdb_get_virtual(CPURISCVState *cs, GByteArray *buf, int n)
 {
     if (n == 0) {
 #ifdef CONFIG_USER_ONLY
-        return gdb_get_regl(mem_buf, 0);
+        return gdb_get_regl(buf, 0);
 #else
-        return gdb_get_regl(mem_buf, cs->priv);
+        return gdb_get_regl(buf, cs->priv);
 #endif
     }
     return 0;
diff --git a/target/s390x/gdbstub.c b/target/s390x/gdbstub.c
index e24a49f4a91..d6fce5ff1e1 100644
--- a/target/s390x/gdbstub.c
+++ b/target/s390x/gdbstub.c
@@ -27,7 +27,7 @@
 #include "sysemu/hw_accel.h"
 #include "sysemu/tcg.h"
 
-int s390_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int s390_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
 {
     S390CPU *cpu = S390_CPU(cs);
     CPUS390XState *env = &cpu->env;
@@ -82,11 +82,11 @@ int s390_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
 /* total number of registers in s390-acr.xml */
 #define S390_NUM_AC_REGS 16
 
-static int cpu_read_ac_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
+static int cpu_read_ac_reg(CPUS390XState *env, GByteArray *buf, int n)
 {
     switch (n) {
     case S390_A0_REGNUM ... S390_A15_REGNUM:
-        return gdb_get_reg32(mem_buf, env->aregs[n]);
+        return gdb_get_reg32(buf, env->aregs[n]);
     default:
         return 0;
     }
@@ -111,13 +111,13 @@ static int cpu_write_ac_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
 /* total number of registers in s390-fpr.xml */
 #define S390_NUM_FP_REGS 17
 
-static int cpu_read_fp_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
+static int cpu_read_fp_reg(CPUS390XState *env, GByteArray *buf, int n)
 {
     switch (n) {
     case S390_FPC_REGNUM:
-        return gdb_get_reg32(mem_buf, env->fpc);
+        return gdb_get_reg32(buf, env->fpc);
     case S390_F0_REGNUM ... S390_F15_REGNUM:
-        return gdb_get_reg64(mem_buf, *get_freg(env, n - S390_F0_REGNUM));
+        return gdb_get_reg64(buf, *get_freg(env, n - S390_F0_REGNUM));
     default:
         return 0;
     }
@@ -145,17 +145,17 @@ static int cpu_write_fp_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
 /* total number of registers in s390-vx.xml */
 #define S390_NUM_VREGS 32
 
-static int cpu_read_vreg(CPUS390XState *env, uint8_t *mem_buf, int n)
+static int cpu_read_vreg(CPUS390XState *env, GByteArray *buf, int n)
 {
     int ret;
 
     switch (n) {
     case S390_V0L_REGNUM ... S390_V15L_REGNUM:
-        ret = gdb_get_reg64(mem_buf, env->vregs[n][1]);
+        ret = gdb_get_reg64(buf, env->vregs[n][1]);
         break;
     case S390_V16_REGNUM ... S390_V31_REGNUM:
-        ret = gdb_get_reg64(mem_buf, env->vregs[n][0]);
-        ret += gdb_get_reg64(mem_buf + 8, env->vregs[n][1]);
+        ret = gdb_get_reg64(buf, env->vregs[n][0]);
+        ret += gdb_get_reg64(buf, env->vregs[n][1]);
         break;
     default:
         ret = 0;
@@ -186,11 +186,11 @@ static int cpu_write_vreg(CPUS390XState *env, uint8_t *mem_buf, int n)
 #define S390_NUM_C_REGS 16
 
 #ifndef CONFIG_USER_ONLY
-static int cpu_read_c_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
+static int cpu_read_c_reg(CPUS390XState *env, GByteArray *buf, int n)
 {
     switch (n) {
     case S390_C0_REGNUM ... S390_C15_REGNUM:
-        return gdb_get_regl(mem_buf, env->cregs[n]);
+        return gdb_get_regl(buf, env->cregs[n]);
     default:
         return 0;
     }
@@ -223,7 +223,7 @@ static int cpu_write_c_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
 /* total number of registers in s390-virt.xml */
 #define S390_NUM_VIRT_REGS 8
 
-static int cpu_read_virt_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
+static int cpu_read_virt_reg(CPUS390XState *env, GByteArray *mem_buf, int n)
 {
     switch (n) {
     case S390_VIRT_CKC_REGNUM:
@@ -296,9 +296,9 @@ static int cpu_write_virt_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
 /* total number of registers in s390-gs.xml */
 #define S390_NUM_GS_REGS 4
 
-static int cpu_read_gs_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
+static int cpu_read_gs_reg(CPUS390XState *env, GByteArray *buf, int n)
 {
-    return gdb_get_regl(mem_buf, env->gscb[n]);
+    return gdb_get_regl(buf, env->gscb[n]);
 }
 
 static int cpu_write_gs_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
diff --git a/target/sh4/gdbstub.c b/target/sh4/gdbstub.c
index 44c1679e9db..49fc4a0cc69 100644
--- a/target/sh4/gdbstub.c
+++ b/target/sh4/gdbstub.c
@@ -24,7 +24,7 @@
 /* Hint: Use "set architecture sh4" in GDB to see fpu registers */
 /* FIXME: We should use XML for this.  */
 
-int superh_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int superh_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
 {
     SuperHCPU *cpu = SUPERH_CPU(cs);
     CPUSH4State *env = &cpu->env;
diff --git a/target/sparc/gdbstub.c b/target/sparc/gdbstub.c
index 8be742b5a3d..78dc8dcc980 100644
--- a/target/sparc/gdbstub.c
+++ b/target/sparc/gdbstub.c
@@ -27,7 +27,7 @@
 #define gdb_get_rega(buf, val) gdb_get_regl(buf, val)
 #endif
 
-int sparc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int sparc_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
 {
     SPARCCPU *cpu = SPARC_CPU(cs);
     CPUSPARCState *env = &cpu->env;
diff --git a/target/xtensa/gdbstub.c b/target/xtensa/gdbstub.c
index 54727881f38..0ee3feabe54 100644
--- a/target/xtensa/gdbstub.c
+++ b/target/xtensa/gdbstub.c
@@ -63,7 +63,7 @@ void xtensa_count_regs(const XtensaConfig *config,
     }
 }
 
-int xtensa_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int xtensa_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
 {
     XtensaCPU *cpu = XTENSA_CPU(cs);
     CPUXtensaState *env = &cpu->env;
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH  v2 09/14] target/arm: prepare for multiple dynamic XMLs
  2019-11-30  8:45 [PATCH v2 00/14] gdbstub refactor and SVE support Alex Bennée
                   ` (7 preceding siblings ...)
  2019-11-30  8:45 ` [PATCH v2 08/14] gdbstub: extend GByteArray to read register helpers Alex Bennée
@ 2019-11-30  8:45 ` Alex Bennée
  2019-12-02 18:26   ` Richard Henderson
  2019-11-30  8:45 ` [PATCH v2 10/14] target/arm: explicitly encode regnum in our XML Alex Bennée
                   ` (5 subsequent siblings)
  14 siblings, 1 reply; 38+ messages in thread
From: Alex Bennée @ 2019-11-30  8:45 UTC (permalink / raw)
  To: qemu-devel
  Cc: damien.hedde, Peter Maydell, luis.machado, richard.henderson,
	open list:ARM TCG CPUs, alan.hayward, Alex Bennée

We will want to generate similar dynamic XML for gdbstub support of
SVE registers (the upstream doesn't use XML). To that end lightly
rename a few things to make the distinction.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/cpu.h     | 20 +++++++++++++-------
 target/arm/gdbstub.c | 30 +++++++++++++++---------------
 target/arm/helper.c  |  4 ++--
 3 files changed, 30 insertions(+), 24 deletions(-)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index cf16f915c82..a31c7a36d6b 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -128,14 +128,20 @@ enum {
 /**
  * DynamicGDBXMLInfo:
  * @desc: Contains the XML descriptions.
- * @num_cpregs: Number of the Coprocessor registers seen by GDB.
- * @cpregs_keys: Array that contains the corresponding Key of
- * a given cpreg with the same order of the cpreg in the XML description.
+ * @num: Number of the registers in this XML seen by GDB.
+ * @data: A union with data specific to the set of registers
+ *    @cpregs_keys: Array that contains the corresponding Key of
+ *                  a given cpreg with the same order of the cpreg
+ *                  in the XML description.
  */
 typedef struct DynamicGDBXMLInfo {
     char *desc;
-    int num_cpregs;
-    uint32_t *cpregs_keys;
+    int num;
+    union {
+        struct {
+            uint32_t *keys;
+        } cpregs;
+    } data;
 } DynamicGDBXMLInfo;
 
 /* CPU state for each instance of a generic timer (in cp15 c14) */
@@ -748,7 +754,7 @@ struct ARMCPU {
     uint64_t *cpreg_vmstate_values;
     int32_t cpreg_vmstate_array_len;
 
-    DynamicGDBXMLInfo dyn_xml;
+    DynamicGDBXMLInfo dyn_sysreg_xml;
 
     /* Timers used by the generic (architected) timer */
     QEMUTimer *gt_timer[NUM_GTIMERS];
@@ -955,7 +961,7 @@ int arm_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 /* Dynamically generates for gdb stub an XML description of the sysregs from
  * the cp_regs hashtable. Returns the registered sysregs number.
  */
-int arm_gen_dynamic_xml(CPUState *cpu);
+int arm_gen_dynamic_sysreg_xml(CPUState *cpu);
 
 /* Returns the dynamically generated XML for the gdb stub.
  * Returns a pointer to the XML contents for the specified XML file or NULL
diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c
index 4557775d245..1f68ab98c3b 100644
--- a/target/arm/gdbstub.c
+++ b/target/arm/gdbstub.c
@@ -106,15 +106,15 @@ int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
     return 0;
 }
 
-static void arm_gen_one_xml_reg_tag(GString *s, DynamicGDBXMLInfo *dyn_xml,
-                                    ARMCPRegInfo *ri, uint32_t ri_key,
-                                    int bitsize)
+static void arm_gen_one_xml_sysreg_tag(GString *s, DynamicGDBXMLInfo *dyn_xml,
+                                       ARMCPRegInfo *ri, uint32_t ri_key,
+                                       int bitsize)
 {
     g_string_append_printf(s, "<reg name=\"%s\"", ri->name);
     g_string_append_printf(s, " bitsize=\"%d\"", bitsize);
     g_string_append_printf(s, " group=\"cp_regs\"/>");
-    dyn_xml->num_cpregs++;
-    dyn_xml->cpregs_keys[dyn_xml->num_cpregs - 1] = ri_key;
+    dyn_xml->data.cpregs.keys[dyn_xml->num] = ri_key;
+    dyn_xml->num++;
 }
 
 static void arm_register_sysreg_for_xml(gpointer key, gpointer value,
@@ -126,12 +126,12 @@ static void arm_register_sysreg_for_xml(gpointer key, gpointer value,
     GString *s = param->s;
     ARMCPU *cpu = ARM_CPU(param->cs);
     CPUARMState *env = &cpu->env;
-    DynamicGDBXMLInfo *dyn_xml = &cpu->dyn_xml;
+    DynamicGDBXMLInfo *dyn_xml = &cpu->dyn_sysreg_xml;
 
     if (!(ri->type & (ARM_CP_NO_RAW | ARM_CP_NO_GDB))) {
         if (arm_feature(env, ARM_FEATURE_AARCH64)) {
             if (ri->state == ARM_CP_STATE_AA64) {
-                arm_gen_one_xml_reg_tag(s , dyn_xml, ri, ri_key, 64);
+                arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 64);
             }
         } else {
             if (ri->state == ARM_CP_STATE_AA32) {
@@ -140,30 +140,30 @@ static void arm_register_sysreg_for_xml(gpointer key, gpointer value,
                     return;
                 }
                 if (ri->type & ARM_CP_64BIT) {
-                    arm_gen_one_xml_reg_tag(s , dyn_xml, ri, ri_key, 64);
+                    arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 64);
                 } else {
-                    arm_gen_one_xml_reg_tag(s , dyn_xml, ri, ri_key, 32);
+                    arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 32);
                 }
             }
         }
     }
 }
 
-int arm_gen_dynamic_xml(CPUState *cs)
+int arm_gen_dynamic_sysreg_xml(CPUState *cs)
 {
     ARMCPU *cpu = ARM_CPU(cs);
     GString *s = g_string_new(NULL);
     RegisterSysregXmlParam param = {cs, s};
 
-    cpu->dyn_xml.num_cpregs = 0;
-    cpu->dyn_xml.cpregs_keys = g_new(uint32_t, g_hash_table_size(cpu->cp_regs));
+    cpu->dyn_sysreg_xml.num = 0;
+    cpu->dyn_sysreg_xml.data.cpregs.keys = g_new(uint32_t, g_hash_table_size(cpu->cp_regs));
     g_string_printf(s, "<?xml version=\"1.0\"?>");
     g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">");
     g_string_append_printf(s, "<feature name=\"org.qemu.gdb.arm.sys.regs\">");
     g_hash_table_foreach(cpu->cp_regs, arm_register_sysreg_for_xml, &param);
     g_string_append_printf(s, "</feature>");
-    cpu->dyn_xml.desc = g_string_free(s, false);
-    return cpu->dyn_xml.num_cpregs;
+    cpu->dyn_sysreg_xml.desc = g_string_free(s, false);
+    return cpu->dyn_sysreg_xml.num;
 }
 
 const char *arm_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname)
@@ -171,7 +171,7 @@ const char *arm_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname)
     ARMCPU *cpu = ARM_CPU(cs);
 
     if (strcmp(xmlname, "system-registers.xml") == 0) {
-        return cpu->dyn_xml.desc;
+        return cpu->dyn_sysreg_xml.desc;
     }
     return NULL;
 }
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 6476245e789..4bf133e2f42 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -207,7 +207,7 @@ static int arm_gdb_get_sysreg(CPUARMState *env, GByteArray *buf, int reg)
     const ARMCPRegInfo *ri;
     uint32_t key;
 
-    key = cpu->dyn_xml.cpregs_keys[reg];
+    key = cpu->dyn_sysreg_xml.data.cpregs.keys[reg];
     ri = get_arm_cp_reginfo(cpu->cp_regs, key);
     if (ri) {
         if (cpreg_field_is_64bit(ri)) {
@@ -6995,7 +6995,7 @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
                                  19, "arm-vfp.xml", 0);
     }
     gdb_register_coprocessor(cs, arm_gdb_get_sysreg, arm_gdb_set_sysreg,
-                             arm_gen_dynamic_xml(cs),
+                             arm_gen_dynamic_sysreg_xml(cs),
                              "system-registers.xml", 0);
 }
 
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH  v2 10/14] target/arm: explicitly encode regnum in our XML
  2019-11-30  8:45 [PATCH v2 00/14] gdbstub refactor and SVE support Alex Bennée
                   ` (8 preceding siblings ...)
  2019-11-30  8:45 ` [PATCH v2 09/14] target/arm: prepare for multiple dynamic XMLs Alex Bennée
@ 2019-11-30  8:45 ` Alex Bennée
  2019-11-30  8:45 ` [PATCH v2 11/14] target/arm: default SVE length to 64 bytes for linux-user Alex Bennée
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 38+ messages in thread
From: Alex Bennée @ 2019-11-30  8:45 UTC (permalink / raw)
  To: qemu-devel
  Cc: damien.hedde, Peter Maydell, luis.machado, richard.henderson,
	open list:ARM TCG CPUs, alan.hayward, Alex Bennée

This is described as optional but I'm not convinced of the numbering
when multiple target fragments are sent.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

---
v2
  - post inc param->n in place so we don't get out count wrong
---
 target/arm/cpu.h     |  2 +-
 target/arm/gdbstub.c | 17 +++++++++++------
 target/arm/helper.c  |  2 +-
 3 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index a31c7a36d6b..cc7258d5f1d 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -961,7 +961,7 @@ int arm_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 /* Dynamically generates for gdb stub an XML description of the sysregs from
  * the cp_regs hashtable. Returns the registered sysregs number.
  */
-int arm_gen_dynamic_sysreg_xml(CPUState *cpu);
+int arm_gen_dynamic_sysreg_xml(CPUState *cpu, int base_reg);
 
 /* Returns the dynamically generated XML for the gdb stub.
  * Returns a pointer to the XML contents for the specified XML file or NULL
diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c
index 1f68ab98c3b..69c35462a63 100644
--- a/target/arm/gdbstub.c
+++ b/target/arm/gdbstub.c
@@ -24,6 +24,7 @@
 typedef struct RegisterSysregXmlParam {
     CPUState *cs;
     GString *s;
+    int n;
 } RegisterSysregXmlParam;
 
 /* Old gdb always expect FPA registers.  Newer (xml-aware) gdb only expect
@@ -108,10 +109,11 @@ int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
 
 static void arm_gen_one_xml_sysreg_tag(GString *s, DynamicGDBXMLInfo *dyn_xml,
                                        ARMCPRegInfo *ri, uint32_t ri_key,
-                                       int bitsize)
+                                       int bitsize, int regnum)
 {
     g_string_append_printf(s, "<reg name=\"%s\"", ri->name);
     g_string_append_printf(s, " bitsize=\"%d\"", bitsize);
+    g_string_append_printf(s, " regnum=\"%d\"", regnum);
     g_string_append_printf(s, " group=\"cp_regs\"/>");
     dyn_xml->data.cpregs.keys[dyn_xml->num] = ri_key;
     dyn_xml->num++;
@@ -131,7 +133,8 @@ static void arm_register_sysreg_for_xml(gpointer key, gpointer value,
     if (!(ri->type & (ARM_CP_NO_RAW | ARM_CP_NO_GDB))) {
         if (arm_feature(env, ARM_FEATURE_AARCH64)) {
             if (ri->state == ARM_CP_STATE_AA64) {
-                arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 64);
+                arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 64,
+                                           param->n++);
             }
         } else {
             if (ri->state == ARM_CP_STATE_AA32) {
@@ -140,20 +143,22 @@ static void arm_register_sysreg_for_xml(gpointer key, gpointer value,
                     return;
                 }
                 if (ri->type & ARM_CP_64BIT) {
-                    arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 64);
+                    arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 64,
+                                               param->n++);
                 } else {
-                    arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 32);
+                    arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 32,
+                                               param->n++);
                 }
             }
         }
     }
 }
 
-int arm_gen_dynamic_sysreg_xml(CPUState *cs)
+int arm_gen_dynamic_sysreg_xml(CPUState *cs, int base_reg)
 {
     ARMCPU *cpu = ARM_CPU(cs);
     GString *s = g_string_new(NULL);
-    RegisterSysregXmlParam param = {cs, s};
+    RegisterSysregXmlParam param = {cs, s, base_reg};
 
     cpu->dyn_sysreg_xml.num = 0;
     cpu->dyn_sysreg_xml.data.cpregs.keys = g_new(uint32_t, g_hash_table_size(cpu->cp_regs));
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 4bf133e2f42..d00e4fcca86 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -6995,7 +6995,7 @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
                                  19, "arm-vfp.xml", 0);
     }
     gdb_register_coprocessor(cs, arm_gdb_get_sysreg, arm_gdb_set_sysreg,
-                             arm_gen_dynamic_sysreg_xml(cs),
+                             arm_gen_dynamic_sysreg_xml(cs, cs->gdb_num_regs),
                              "system-registers.xml", 0);
 }
 
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v2 11/14] target/arm: default SVE length to 64 bytes for linux-user
  2019-11-30  8:45 [PATCH v2 00/14] gdbstub refactor and SVE support Alex Bennée
                   ` (9 preceding siblings ...)
  2019-11-30  8:45 ` [PATCH v2 10/14] target/arm: explicitly encode regnum in our XML Alex Bennée
@ 2019-11-30  8:45 ` Alex Bennée
  2019-12-02  2:41   ` Richard Henderson
  2019-11-30  8:46 ` [PATCH v2 12/14] target/arm: generate xml description of our SVE registers Alex Bennée
                   ` (3 subsequent siblings)
  14 siblings, 1 reply; 38+ messages in thread
From: Alex Bennée @ 2019-11-30  8:45 UTC (permalink / raw)
  To: qemu-devel
  Cc: damien.hedde, Peter Maydell, luis.machado, richard.henderson,
	open list:ARM TCG CPUs, alan.hayward, Alex Bennée

The Linux kernel chooses the default of 64 bytes for SVE registers on
the basis that it is the largest size that won't grow the signal
frame. When debugging larger sizes are also unwieldy in gdb as each
zreg will take over a page of terminal to display.

The user can of course always specify a larger size with the
sve-max-vq property on the command line:

  -cpu max,sve-max-vq=16

This should not make any difference to SVE enabled software as the SVE
is of course vector length agnostic.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/cpu64.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index a39d6fcea34..bc5d6c4b974 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -703,6 +703,9 @@ static void aarch64_max_initfn(Object *obj)
          */
         cpu->ctr = 0x80038003; /* 32 byte I and D cacheline size, VIPT icache */
         cpu->dcz_blocksize = 7; /*  512 bytes */
+
+        /* Default sve-max-vq to a reasonable numer */
+        cpu->sve_max_vq = 4;
 #endif
     }
 
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v2 12/14] target/arm: generate xml description of our SVE registers
  2019-11-30  8:45 [PATCH v2 00/14] gdbstub refactor and SVE support Alex Bennée
                   ` (10 preceding siblings ...)
  2019-11-30  8:45 ` [PATCH v2 11/14] target/arm: default SVE length to 64 bytes for linux-user Alex Bennée
@ 2019-11-30  8:46 ` Alex Bennée
  2019-12-02 18:44   ` Richard Henderson
  2019-11-30  8:46 ` [PATCH v2 13/14] tests/guest-debug: add a simple test runner Alex Bennée
                   ` (2 subsequent siblings)
  14 siblings, 1 reply; 38+ messages in thread
From: Alex Bennée @ 2019-11-30  8:46 UTC (permalink / raw)
  To: qemu-devel
  Cc: damien.hedde, Peter Maydell, luis.machado, richard.henderson,
	open list:ARM TCG CPUs, alan.hayward, Alex Bennée

We also expose a the helpers to read/write the the registers.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
v2
  - instead of zNpM expose zN at sve_max_vq width
  - wrap union in union q(us), d(usf), s(usf), h(usf), b(us)
---
 target/arm/cpu.h     |  10 +++-
 target/arm/gdbstub.c | 130 +++++++++++++++++++++++++++++++++++++++++++
 target/arm/helper.c  | 110 +++++++++++++++++++++++++++++++++++-
 3 files changed, 245 insertions(+), 5 deletions(-)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index cc7258d5f1d..bd4d5b4445b 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -141,6 +141,9 @@ typedef struct DynamicGDBXMLInfo {
         struct {
             uint32_t *keys;
         } cpregs;
+        struct {
+            int fpsr_pos;
+        } sve;
     } data;
 } DynamicGDBXMLInfo;
 
@@ -755,6 +758,7 @@ struct ARMCPU {
     int32_t cpreg_vmstate_array_len;
 
     DynamicGDBXMLInfo dyn_sysreg_xml;
+    DynamicGDBXMLInfo dyn_svereg_xml;
 
     /* Timers used by the generic (architected) timer */
     QEMUTimer *gt_timer[NUM_GTIMERS];
@@ -958,10 +962,12 @@ hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr,
 int arm_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
 int arm_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 
-/* Dynamically generates for gdb stub an XML description of the sysregs from
- * the cp_regs hashtable. Returns the registered sysregs number.
+/*
+ * Helpers to dynamically generates XML descriptions of the sysregs
+ * and SVE registers. Returns the number of registers in each set.
  */
 int arm_gen_dynamic_sysreg_xml(CPUState *cpu, int base_reg);
+int arm_gen_dynamic_svereg_xml(CPUState *cpu, int base_reg);
 
 /* Returns the dynamically generated XML for the gdb stub.
  * Returns a pointer to the XML contents for the specified XML file or NULL
diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c
index 69c35462a63..6567f746c47 100644
--- a/target/arm/gdbstub.c
+++ b/target/arm/gdbstub.c
@@ -171,12 +171,142 @@ int arm_gen_dynamic_sysreg_xml(CPUState *cs, int base_reg)
     return cpu->dyn_sysreg_xml.num;
 }
 
+struct TypeSize {
+    const char *gdb_type;
+    int  size;
+    const char sz, suffix;
+};
+
+static struct TypeSize vec_lanes[] = {
+    /* quads */
+    { "uint128", 128, 'q', 'u' },
+    { "int128", 128, 'q', 's' },
+    /* 64 bit */
+    { "uint64", 64, 'd', 'u' },
+    { "int64", 64, 'd', 's' },
+    { "ieee_double", 64, 'd', 'f' },
+    /* 32 bit */
+    { "uint32", 32, 's', 'u' },
+    { "int32", 32, 's', 's' },
+    { "ieee_single", 32, 's', 'f' },
+    /* 16 bit */
+    { "uint16", 16, 'h', 'u' },
+    { "int16", 16, 'h', 's' },
+    { "ieee_half", 16, 'h', 'f' },
+    /* bytes */
+    { "uint8", 8, 'b', 'u' },
+    { "int8", 8, 'b', 's' },
+};
+
+
+int arm_gen_dynamic_svereg_xml(CPUState *cs, int base_reg)
+{
+    ARMCPU *cpu = ARM_CPU(cs);
+    GString *s = g_string_new(NULL);
+    DynamicGDBXMLInfo *info = &cpu->dyn_svereg_xml;
+    g_autoptr(GString) ts = g_string_new("");
+    g_autoptr(GString) us = g_string_new("");
+    int i, bits, reg_width = (cpu->sve_max_vq * 128);
+    info->num = 0;
+    g_string_printf(s, "<?xml version=\"1.0\"?>");
+    g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">");
+    g_string_append_printf(s, "<feature name=\"org.qemu.gdb.aarch64.sve\">");
+
+    /* First define types and totals in a whole VL */
+    for (i = 0; i < ARRAY_SIZE(vec_lanes); i++) {
+        int count = reg_width / vec_lanes[i].size;
+        g_string_printf(ts, "vq%d%c%c", count,
+                        vec_lanes[i].sz, vec_lanes[i].suffix);
+        g_string_append_printf(s,
+                               "<vector id=\"%s\" type=\"%s\" count=\"%d\"/>",
+                               ts->str, vec_lanes[i].gdb_type, count);
+    }
+    /*
+     * Now define a union for each size group containing unsigned and
+     * signed and potentially float versions of each size from 128 to
+     * 8 bits.
+     */
+    for (bits = 128; bits >= 8; bits = bits/2) {
+        int count = reg_width / bits;
+        g_string_append_printf(s, "<union id=\"vq%dn\">", count);
+        for (i = 0; i < ARRAY_SIZE(vec_lanes); i++) {
+            if (vec_lanes[i].size == bits) {
+                g_string_append_printf(s, "<field name=\"%c\" type=\"vq%d%c%c\"/>",
+                                       vec_lanes[i].suffix,
+                                       count,
+                                       vec_lanes[i].sz, vec_lanes[i].suffix);
+            }
+        }
+        g_string_append(s, "</union>");
+    }
+    /* And now the final union of unions */
+    g_string_append(s, "<union id=\"vq\">");
+    for (bits = 128; bits >= 8; bits = bits/2) {
+        int count = reg_width / bits;
+        for (i = 0; i < ARRAY_SIZE(vec_lanes); i++) {
+            if (vec_lanes[i].size == bits) {
+                g_string_append_printf(s, "<field name=\"%c\" type=\"vq%dn\"/>",
+                                       vec_lanes[i].sz, count);
+                break;
+            }
+        }
+    }
+    g_string_append(s, "</union>");
+
+    /* Then define each register in parts for each vq */
+    for (i = 0; i < 32; i++) {
+        g_string_append_printf(s,
+                               "<reg name=\"z%d\" bitsize=\"%d\""
+                               " regnum=\"%d\" group=\"vector\""
+                               " type=\"vq\"/>",
+                               i, reg_width, base_reg++);
+        info->num++;
+    }
+    /* fpscr & status registers */
+    info->data.sve.fpsr_pos = info->num;
+    g_string_append_printf(s, "<reg name=\"fpsr\" bitsize=\"32\""
+                           " regnum=\"%d\" group=\"float\""
+                           " type=\"int\"/>", base_reg++);
+    g_string_append_printf(s, "<reg name=\"fpcr\" bitsize=\"32\""
+                           " regnum=\"%d\" group=\"float\""
+                           " type=\"int\"/>", base_reg++);
+    info->num += 2;
+    /*
+     * Predicate registers aren't so big they are worth splitting up
+     * but we do need to define a type to hold the array of quad
+     * references.
+     */
+    g_string_append_printf(s,
+                           "<vector id=\"vqp\" type=\"uint16\" count=\"%d\"/>",
+                           cpu->sve_max_vq);
+    for (i = 0; i < 16; i++) {
+        g_string_append_printf(s,
+                               "<reg name=\"p%d\" bitsize=\"%d\""
+                               " regnum=\"%d\" group=\"vector\""
+                               " type=\"vqp\"/>",
+                               i, cpu->sve_max_vq * 16, base_reg++);
+        info->num++;
+    }
+    g_string_append_printf(s,
+                           "<reg name=\"ffr\" bitsize=\"%d\""
+                           " regnum=\"%d\" group=\"vector\""
+                           " type=\"vqp\"/>",
+                           cpu->sve_max_vq * 16, base_reg++);
+    info->num++;
+    g_string_append_printf(s, "</feature>");
+    cpu->dyn_svereg_xml.desc = g_string_free(s, false);
+    return cpu->dyn_svereg_xml.num;
+}
+
+
 const char *arm_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname)
 {
     ARMCPU *cpu = ARM_CPU(cs);
 
     if (strcmp(xmlname, "system-registers.xml") == 0) {
         return cpu->dyn_sysreg_xml.desc;
+    } else if (strcmp(xmlname, "sve-registers.xml") == 0) {
+        return cpu->dyn_svereg_xml.desc;
     }
     return NULL;
 }
diff --git a/target/arm/helper.c b/target/arm/helper.c
index d00e4fcca86..f78dd3b5fe3 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -201,6 +201,15 @@ static void write_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri,
     }
 }
 
+/**
+ * arm_get/set_gdb_*: get/set a gdb register
+ * @env: the CPU state
+ * @buf: a buffer to copy to/from
+ * @reg: register number (offset from start of group)
+ *
+ * We return the number of bytes copied
+ */
+
 static int arm_gdb_get_sysreg(CPUARMState *env, GByteArray *buf, int reg)
 {
     ARMCPU *cpu = env_archcpu(env);
@@ -224,6 +233,87 @@ static int arm_gdb_set_sysreg(CPUARMState *env, uint8_t *buf, int reg)
     return 0;
 }
 
+#ifdef TARGET_AARCH64
+static int arm_gdb_get_svereg(CPUARMState *env, GByteArray *buf, int reg)
+{
+    ARMCPU *cpu = env_archcpu(env);
+    DynamicGDBXMLInfo *info = &cpu->dyn_svereg_xml;
+
+    /* The first 32 registers are the zregs */
+    if (reg < 32) {
+        int vq, len = 0;
+        for (vq = 0; vq < cpu->sve_max_vq; vq++) {
+            len += gdb_get_reg128(buf,
+                                  env->vfp.zregs[reg].d[vq * 2 + 1],
+                                  env->vfp.zregs[reg].d[vq * 2]);
+        }
+        return len;
+    }
+    switch (reg - info->data.sve.fpsr_pos) {
+    case 0:
+        return gdb_get_reg32(buf, vfp_get_fpsr(env));
+    case 1:
+        return gdb_get_reg32(buf, vfp_get_fpcr(env));
+    case 2 ... 19:
+    {
+        int preg = reg - info->data.sve.fpsr_pos - 2;
+        int vq, len = 0;
+        for (vq = 0; vq < cpu->sve_max_vq; vq = vq + 4) {
+            len += gdb_get_reg64(buf, env->vfp.pregs[preg].p[vq / 4]);
+        }
+        return len;
+    }
+    default:
+        /* gdbstub asked for something out our range */
+        break;
+    }
+
+    return 0;
+}
+
+static int arm_gdb_set_svereg(CPUARMState *env, uint8_t *buf, int reg)
+{
+    ARMCPU *cpu = env_archcpu(env);
+    DynamicGDBXMLInfo *info = &cpu->dyn_svereg_xml;
+
+    /* The first 32 registers are the zregs */
+    if (reg < 32) {
+        int vq, len = 0;
+        uint64_t *p = (uint64_t *) buf;
+        for (vq = 0; vq < cpu->sve_max_vq; vq++) {
+            env->vfp.zregs[reg].d[vq * 2 + 1] = *p++;
+            env->vfp.zregs[reg].d[vq * 2] = *p++;
+            len += 16;
+        }
+        return len;
+    }
+    switch (reg - info->data.sve.fpsr_pos) {
+    case 0:
+        vfp_set_fpsr(env, *(uint32_t *)buf);
+        return 4;
+    case 1:
+        vfp_set_fpcr(env, *(uint32_t *)buf);
+        return 4;
+    case 2 ... 19:
+    {
+        int preg = reg - info->data.sve.fpsr_pos - 2;
+        int vq, len = 0;
+        uint64_t *p = (uint64_t *) buf;
+        for (vq = 0; vq < cpu->sve_max_vq; vq = vq + 4) {
+            env->vfp.pregs[preg].p[vq / 4] = *p++;
+            len += 8;
+        }
+        return len;
+    }
+    default:
+        /* gdbstub asked for something out our range */
+        break;
+    }
+
+    return 0;
+}
+#endif /* TARGET_AARCH64 */
+
 static bool raw_accessors_invalid(const ARMCPRegInfo *ri)
 {
    /* Return true if the regdef would cause an assertion if you called
@@ -6981,9 +7071,22 @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
     CPUARMState *env = &cpu->env;
 
     if (arm_feature(env, ARM_FEATURE_AARCH64)) {
-        gdb_register_coprocessor(cs, aarch64_fpu_gdb_get_reg,
-                                 aarch64_fpu_gdb_set_reg,
-                                 34, "aarch64-fpu.xml", 0);
+        /*
+         * The lower part of each SVE register aliases to the FPU
+         * registers so we don't need to include both.
+         */
+#ifdef TARGET_AARCH64
+        if (isar_feature_aa64_sve(&cpu->isar)) {
+            gdb_register_coprocessor(cs, arm_gdb_get_svereg, arm_gdb_set_svereg,
+                                     arm_gen_dynamic_svereg_xml(cs, cs->gdb_num_regs),
+                                     "sve-registers.xml", 0);
+        } else
+#endif
+        {
+            gdb_register_coprocessor(cs, aarch64_fpu_gdb_get_reg,
+                                     aarch64_fpu_gdb_set_reg,
+                                     34, "aarch64-fpu.xml", 0);
+        }
     } else if (arm_feature(env, ARM_FEATURE_NEON)) {
         gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg,
                                  51, "arm-neon.xml", 0);
@@ -6997,6 +7100,7 @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
     gdb_register_coprocessor(cs, arm_gdb_get_sysreg, arm_gdb_set_sysreg,
                              arm_gen_dynamic_sysreg_xml(cs, cs->gdb_num_regs),
                              "system-registers.xml", 0);
+
 }
 
 /* Sort alphabetically by type name, except for "any". */
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH  v2 13/14] tests/guest-debug: add a simple test runner
  2019-11-30  8:45 [PATCH v2 00/14] gdbstub refactor and SVE support Alex Bennée
                   ` (11 preceding siblings ...)
  2019-11-30  8:46 ` [PATCH v2 12/14] target/arm: generate xml description of our SVE registers Alex Bennée
@ 2019-11-30  8:46 ` Alex Bennée
  2019-12-02 18:50   ` Richard Henderson
  2019-11-30  8:46 ` [PATCH v2 14/14] tests/tcg: add a gdbstub testcase for SVE registers Alex Bennée
  2019-11-30  9:33 ` [PATCH v2 00/14] gdbstub refactor and SVE support no-reply
  14 siblings, 1 reply; 38+ messages in thread
From: Alex Bennée @ 2019-11-30  8:46 UTC (permalink / raw)
  To: qemu-devel
  Cc: damien.hedde, luis.machado, Alex Bennée, richard.henderson,
	alan.hayward

The test runners job is to start QEMU with guest debug enabled and
then spawn a gdb process running a test script that exercises the
functionality it wants to test.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tests/guest-debug/run-test.py | 57 +++++++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)
 create mode 100755 tests/guest-debug/run-test.py

diff --git a/tests/guest-debug/run-test.py b/tests/guest-debug/run-test.py
new file mode 100755
index 00000000000..8c49ee2f225
--- /dev/null
+++ b/tests/guest-debug/run-test.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python3
+#
+# Run a gdbstub test case
+#
+# Copyright (c) 2019 Linaro
+#
+# Author: Alex Bennée <alex.bennee@linaro.org>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or later.
+# See the COPYING file in the top-level directory.
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import argparse
+import subprocess
+import shutil
+import shlex
+
+def get_args():
+    parser = argparse.ArgumentParser(description="A gdbstub test runner")
+    parser.add_argument("--qemu", help="Qemu binary for test",
+                        required=True)
+    parser.add_argument("--qargs", help="Qemu arguments for test")
+    parser.add_argument("--binary", help="Binary to debug",
+                        required=True)
+    parser.add_argument("--test", help="GDB test script",
+                        required=True)
+    parser.add_argument("--gdb", help="The gdb binary to use", default=None)
+
+    return parser.parse_args()
+
+if __name__ == '__main__':
+    args = get_args()
+
+    # Search for a gdb we can use
+    if not args.gdb:
+        args.gdb = shutil.which("gdb-multiarch")
+    if not args.gdb:
+        args.gdb = shutil.which("gdb")
+    if not args.gdb:
+        print("We need gdb to run the test")
+        exit(-1)
+
+    # Launch QEMU with binary
+    if "system" in args.qemu:
+        cmd = "%s %s %s -s -S" % (args.qemu, args.qargs, args.binary)
+    else:
+        cmd = "%s %s -g 1234 %s" % (args.qemu, args.qargs, args.binary)
+
+    inferior = subprocess.Popen(shlex.split(cmd))
+
+    # Now launch gdb with our test and collect the result
+    gdb_cmd = "%s %s -ex 'target remote localhost:1234' -x %s" % (args.gdb, args.binary, args.test)
+
+    result = subprocess.call(gdb_cmd, shell=True);
+
+    exit(result)
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH v2 14/14] tests/tcg: add a gdbstub testcase for SVE registers
  2019-11-30  8:45 [PATCH v2 00/14] gdbstub refactor and SVE support Alex Bennée
                   ` (12 preceding siblings ...)
  2019-11-30  8:46 ` [PATCH v2 13/14] tests/guest-debug: add a simple test runner Alex Bennée
@ 2019-11-30  8:46 ` Alex Bennée
  2019-11-30  9:33 ` [PATCH v2 00/14] gdbstub refactor and SVE support no-reply
  14 siblings, 0 replies; 38+ messages in thread
From: Alex Bennée @ 2019-11-30  8:46 UTC (permalink / raw)
  To: qemu-devel
  Cc: damien.hedde, Peter Maydell, luis.machado, richard.henderson,
	open list:ARM TCG CPUs, alan.hayward, Alex Bennée

We don't plumb this in yet as there are complications involved with
binutils and cross-architectiure debugging but it is one step closer.

Example:

  ./tests/guest-debug/run-test.py \
    --qemu ./aarch64-linux-user/qemu-aarch64 \
    --qargs "-cpu max" \
    --bin ./tests/tcg/aarch64-linux-user/hello \
    --test ~/lsrc/qemu.git/tests/tcg/aarch64/gdbstub/test-sve.py \
    --gdb /home/alex/src/tools/binutils-gdb.git/install/bin/gdb

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tests/.gitignore                      |  1 +
 tests/tcg/aarch64/gdbstub/test-sve.py | 75 +++++++++++++++++++++++++++
 2 files changed, 76 insertions(+)
 create mode 100644 tests/tcg/aarch64/gdbstub/test-sve.py

diff --git a/tests/.gitignore b/tests/.gitignore
index f9c01708812..8cc428b58bb 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -10,6 +10,7 @@ qht-bench
 rcutorture
 test-*
 !test-*.c
+!test-*.py
 !docker/test-*
 test-qapi-commands.[ch]
 include/test-qapi-commands-sub-module.[ch]
diff --git a/tests/tcg/aarch64/gdbstub/test-sve.py b/tests/tcg/aarch64/gdbstub/test-sve.py
new file mode 100644
index 00000000000..11bc96fc06d
--- /dev/null
+++ b/tests/tcg/aarch64/gdbstub/test-sve.py
@@ -0,0 +1,75 @@
+from __future__ import print_function
+#
+# Test the SVE registers are visable and changeable via gdbstub
+#
+# This is launched via tests/guest-debug/run-test.py
+#
+
+import gdb
+
+MAGIC = 0xDEADBEEF
+
+failcount = 0
+
+def report(cond, msg):
+    "Report success/fail of test"
+    if cond:
+        print ("PASS: %s" % (msg))
+    else:
+        print ("FAIL: %s" % (msg))
+        global failcount
+        failcount += 1
+
+def run_test():
+    "Run through the tests one by one"
+
+    gdb.execute("info registers")
+    report(True, "info registers")
+
+    gdb.execute("info registers vector")
+    report(True, "info registers vector")
+
+    # Now all the zregs
+    frame = gdb.selected_frame()
+    for i in range(0, 32):
+        rname = "z%d" % (i)
+        zreg = frame.read_register(rname)
+        report(True, "Reading %s" % rname)
+        for j in range(0, 4):
+            cmd = "set $%s.q.u[%d] = 0x%x" % (rname, j, MAGIC)
+            gdb.execute(cmd)
+            report(True, "%s" % cmd)
+        for j in range(0, 4):
+            reg = "$%s.q.u[%d]" % (rname, j)
+            v = gdb.parse_and_eval(reg)
+            report(str(v.type) == "uint128_t", "size of %s" % (reg))
+        for j in range(0, 8):
+            cmd = "set $%s.d.u[%d] = 0x%x" % (rname, j, MAGIC)
+            gdb.execute(cmd)
+            report(True, "%s" % cmd)
+        for j in range(0, 8):
+            reg = "$%s.d.u[%d]" % (rname, j)
+            v = gdb.parse_and_eval(reg)
+            report(str(v.type) == "uint64_t", "size of %s" % (reg))
+            report(int(v) == MAGIC, "%s is 0x%x" % (reg, MAGIC))
+
+#
+# This runs as the script it sourced (via -x, via run-test.py)
+#
+
+try:
+    # These are not very useful in scripts
+    gdb.execute("set pagination off")
+    gdb.execute("set confirm off")
+
+    # Run the actual tests
+    run_test()
+except:
+    print ("GDB Exception: %s" % (sys.exc_info()[0]))
+    failcount += 1
+
+print("All tests complete: %d failures" % failcount)
+
+# Finally kill the inferior and exit gdb with a count of failures
+gdb.execute("kill")
+exit(failcount)
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* Re: [PATCH  v2 00/14] gdbstub refactor and SVE support
  2019-11-30  8:45 [PATCH v2 00/14] gdbstub refactor and SVE support Alex Bennée
                   ` (13 preceding siblings ...)
  2019-11-30  8:46 ` [PATCH v2 14/14] tests/tcg: add a gdbstub testcase for SVE registers Alex Bennée
@ 2019-11-30  9:33 ` no-reply
  14 siblings, 0 replies; 38+ messages in thread
From: no-reply @ 2019-11-30  9:33 UTC (permalink / raw)
  To: alex.bennee
  Cc: damien.hedde, luis.machado, richard.henderson, qemu-devel,
	alan.hayward, alex.bennee

Patchew URL: https://patchew.org/QEMU/20191130084602.10818-1-alex.bennee@linaro.org/



Hi,

This series seems to have some coding style problems. See output below for
more information:

Subject: [PATCH  v2 00/14] gdbstub refactor and SVE support
Type: series
Message-id: 20191130084602.10818-1-alex.bennee@linaro.org

=== TEST SCRIPT BEGIN ===
#!/bin/bash
git rev-parse base > /dev/null || exit 0
git config --local diff.renamelimit 0
git config --local diff.renames True
git config --local diff.algorithm histogram
./scripts/checkpatch.pl --mailback base..
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
Switched to a new branch 'test'
b3409ec tests/tcg: add a gdbstub testcase for SVE registers
d39b296 tests/guest-debug: add a simple test runner
0a36c06 target/arm: generate xml description of our SVE registers
0536f07 target/arm: default SVE length to 64 bytes for linux-user
24fc7f5 target/arm: explicitly encode regnum in our XML
41a25c6 target/arm: prepare for multiple dynamic XMLs
7c1e4cd gdbstub: extend GByteArray to read register helpers
0918a59 target/m68k: use gdb_get_reg helpers
fd549cb target/arm: use gdb_get_reg helpers
588590d gdbstub: add helper for 128 bit registers
7368743 gdbstub: move mem_buf to GDBState and use GByteArray
9fd02d7 gdbstub: move str_buf to GDBState and use GString
27a63ee gdbstub: stop passing GDBState * around and use global
8bf5457 gdbstub: make GDBState static and have common init function

=== OUTPUT BEGIN ===
1/14 Checking commit 8bf54575f2b0 (gdbstub: make GDBState static and have common init function)
ERROR: braces {} are necessary for all arms of this statement
#128: FILE: gdbstub.c:2743:
+    if (!gdbserver_state.init)
[...]

ERROR: suspect code indent for conditional statements (2, 6)
#178: FILE: gdbstub.c:2962:
+  if (!gdbserver_state.init) {
       return;

ERROR: suspect code indent for conditional statements (2, 6)
#183: FILE: gdbstub.c:2966:
+  if (gdbserver_fd < 0 || gdbserver_state.fd < 0) {
       return;

total: 3 errors, 0 warnings, 384 lines checked

Patch 1/14 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

2/14 Checking commit 27a63ee5f12d (gdbstub: stop passing GDBState * around and use global)
WARNING: line over 80 characters
#742: FILE: gdbstub.c:1763:
+    if (target_memory_rw_debug(gdbserver_state.g_cpu, gdb_ctx->params[0].val_ull,

WARNING: line over 80 characters
#770: FILE: gdbstub.c:1786:
+    if (target_memory_rw_debug(gdbserver_state.g_cpu, gdb_ctx->params[0].val_ull,

WARNING: line over 80 characters
#997: FILE: gdbstub.c:2023:
+    gdbserver_state.query_cpu = gdb_next_attached_cpu(gdbserver_state.query_cpu);

ERROR: line over 90 characters
#1326: FILE: gdbstub.c:2817:
+            put_buffer((uint8_t *)gdbserver_state.last_packet, gdbserver_state.last_packet_len);

ERROR: space required before the open parenthesis '('
#1344: FILE: gdbstub.c:2836:
+        switch(gdbserver_state.state) {

ERROR: line over 90 characters
#1376: FILE: gdbstub.c:2859:
+            } else if (gdbserver_state.line_buf_index >= sizeof(gdbserver_state.line_buf) - 1) {

ERROR: line over 90 characters
#1394: FILE: gdbstub.c:2872:
+            } else if (gdbserver_state.line_buf_index >= sizeof(gdbserver_state.line_buf) - 1) {

WARNING: line over 80 characters
#1404: FILE: gdbstub.c:2878:
+                gdbserver_state.line_buf[gdbserver_state.line_buf_index++] = ch ^ 0x20;

ERROR: line over 90 characters
#1420: FILE: gdbstub.c:2895:
+                if (gdbserver_state.line_buf_index + repeat >= sizeof(gdbserver_state.line_buf) - 1) {

WARNING: line over 80 characters
#1438: FILE: gdbstub.c:2905:
+                    memset(gdbserver_state.line_buf + gdbserver_state.line_buf_index,

ERROR: line over 90 characters
#1439: FILE: gdbstub.c:2906:
+                           gdbserver_state.line_buf[gdbserver_state.line_buf_index - 1], repeat);

WARNING: line over 80 characters
#1474: FILE: gdbstub.c:2933:
+            if (gdbserver_state.line_csum != (gdbserver_state.line_sum & 0xff)) {

ERROR: line over 90 characters
#1475: FILE: gdbstub.c:2934:
+                trace_gdbstub_err_checksum_incorrect(gdbserver_state.line_sum, gdbserver_state.line_csum);

WARNING: line over 80 characters
#1488: FILE: gdbstub.c:2943:
+                gdbserver_state.state = gdb_handle_packet(s, gdbserver_state.line_buf);

ERROR: line over 90 characters
#1563: FILE: gdbstub.c:3305:
+        qsort(gdbserver_state.processes, gdbserver_state.process_num, sizeof(gdbserver_state.processes[0]), pid_order);

total: 8 errors, 7 warnings, 1478 lines checked

Patch 2/14 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

3/14 Checking commit 9fd02d7eba1e (gdbstub: move str_buf to GDBState and use GString)
WARNING: line over 80 characters
#149: FILE: gdbstub.c:1795:
+    memtohex(gdbserver_state.str_buf, gdb_ctx->mem_buf, gdb_ctx->params[1].val_ull);

WARNING: line over 80 characters
#322: FILE: gdbstub.c:2108:
+    g_string_printf(gdbserver_state.str_buf, "PacketSize=%x", MAX_PACKET_LENGTH);

total: 0 errors, 2 warnings, 422 lines checked

Patch 3/14 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
4/14 Checking commit 7368743b4a92 (gdbstub: move mem_buf to GDBState and use GByteArray)
5/14 Checking commit 588590d6a4ea (gdbstub: add helper for 128 bit registers)
6/14 Checking commit fd549cb833af (target/arm: use gdb_get_reg helpers)
ERROR: space required after that ',' (ctx:VxV)
#43: FILE: target/arm/helper.c:118:
+        return gdb_get_reg32(buf,vfp_get_fpcr(env));
                                 ^

total: 1 errors, 0 warnings, 28 lines checked

Patch 6/14 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

7/14 Checking commit 0918a59e7cc0 (target/m68k: use gdb_get_reg helpers)
8/14 Checking commit 7c1e4cda755c (gdbstub: extend GByteArray to read register helpers)
9/14 Checking commit 41a25c63b5c7 (target/arm: prepare for multiple dynamic XMLs)
ERROR: line over 90 characters
#127: FILE: target/arm/gdbstub.c:159:
+    cpu->dyn_sysreg_xml.data.cpregs.keys = g_new(uint32_t, g_hash_table_size(cpu->cp_regs));

total: 1 errors, 0 warnings, 136 lines checked

Patch 9/14 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

10/14 Checking commit 24fc7f5cae91 (target/arm: explicitly encode regnum in our XML)
11/14 Checking commit 0536f077e43f (target/arm: default SVE length to 64 bytes for linux-user)
12/14 Checking commit 0a36c0686afb (target/arm: generate xml description of our SVE registers)
ERROR: spaces required around that '/' (ctx:VxV)
#113: FILE: target/arm/gdbstub.c:229:
+    for (bits = 128; bits >= 8; bits = bits/2) {
                                            ^

WARNING: line over 80 characters
#118: FILE: target/arm/gdbstub.c:234:
+                g_string_append_printf(s, "<field name=\"%c\" type=\"vq%d%c%c\"/>",

ERROR: spaces required around that '/' (ctx:VxV)
#128: FILE: target/arm/gdbstub.c:244:
+    for (bits = 128; bits >= 8; bits = bits/2) {
                                            ^

WARNING: line over 80 characters
#319: FILE: target/arm/helper.c:7081:
+                                     arm_gen_dynamic_svereg_xml(cs, cs->gdb_num_regs),

total: 2 errors, 2 warnings, 306 lines checked

Patch 12/14 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

13/14 Checking commit d39b29603288 (tests/guest-debug: add a simple test runner)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#15: 
new file mode 100755

ERROR: line over 90 characters
#72: FILE: tests/guest-debug/run-test.py:53:
+    gdb_cmd = "%s %s -ex 'target remote localhost:1234' -x %s" % (args.gdb, args.binary, args.test)

total: 1 errors, 1 warnings, 57 lines checked

Patch 13/14 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

14/14 Checking commit b3409ec3f919 (tests/tcg: add a gdbstub testcase for SVE registers)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#35: 
new file mode 100644

total: 0 errors, 1 warnings, 82 lines checked

Patch 14/14 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
=== OUTPUT END ===

Test command exited with code: 1


The full log is available at
http://patchew.org/logs/20191130084602.10818-1-alex.bennee@linaro.org/testing.checkpatch/?type=message.
---
Email generated automatically by Patchew [https://patchew.org/].
Please send your feedback to patchew-devel@redhat.com

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v2 07/14] target/m68k: use gdb_get_reg helpers
  2019-11-30  8:45 ` [PATCH v2 07/14] target/m68k: " Alex Bennée
@ 2019-11-30 10:58   ` Laurent Vivier
  0 siblings, 0 replies; 38+ messages in thread
From: Laurent Vivier @ 2019-11-30 10:58 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: damien.hedde, richard.henderson, luis.machado, alan.hayward

Le 30/11/2019 à 09:45, Alex Bennée a écrit :
> This is cleaner than poking memory directly and will make later
> clean-ups easier.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  target/m68k/helper.c | 29 +++++++++++------------------
>  1 file changed, 11 insertions(+), 18 deletions(-)
> 
> diff --git a/target/m68k/helper.c b/target/m68k/helper.c
> index ae766a6cb0b..70b0c0b5076 100644
> --- a/target/m68k/helper.c
> +++ b/target/m68k/helper.c
> @@ -72,19 +72,15 @@ static int cf_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
>  {
>      if (n < 8) {
>          float_status s;
> -        stfq_p(mem_buf, floatx80_to_float64(env->fregs[n].d, &s));
> -        return 8;
> +        return gdb_get_reg64(buf, floatx80_to_float64(env->fregs[n].d, &s));

Where is coming from "buf"? We were using "mem_buf".

>      }
>      switch (n) {
>      case 8: /* fpcontrol */
> -        stl_be_p(mem_buf, env->fpcr);
> -        return 4;
> +        return gdb_get_reg32(buf, env->fpcr);
>      case 9: /* fpstatus */
> -        stl_be_p(mem_buf, env->fpsr);
> -        return 4;
> +        return gdb_get_reg32(buf, env->fpsr);
>      case 10: /* fpiar, not implemented */
> -        memset(mem_buf, 0, 4);
> -        return 4;
> +        return gdb_get_reg32(buf, 0);
>      }
>      return 0;
>  }
> @@ -112,21 +108,18 @@ static int cf_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
>  static int m68k_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
>  {
>      if (n < 8) {
> -        stw_be_p(mem_buf, env->fregs[n].l.upper);
> -        memset(mem_buf + 2, 0, 2);
> -        stq_be_p(mem_buf + 4, env->fregs[n].l.lower);
> -        return 12;
> +        int len = gdb_get_reg16(buf, env->fregs[n].l.upper);
> +        len += gdb_get_reg16(buf, 0);

len += gdb_get_reg16(buf + len, ...

> +        len += gdb_get_reg64(buf, env->fregs[n].l.lower);

len += gdb_get_reg64(buf + len, ...

> +        return len;
>      }
>      switch (n) {
>      case 8: /* fpcontrol */
> -        stl_be_p(mem_buf, env->fpcr);
> -        return 4;
> +        return gdb_get_reg32(buf, env->fpcr);
>      case 9: /* fpstatus */
> -        stl_be_p(mem_buf, env->fpsr);
> -        return 4;
> +        return gdb_get_reg32(buf, env->fpsr);
>      case 10: /* fpiar, not implemented */
> -        memset(mem_buf, 0, 4);
> -        return 4;
> +        return gdb_get_reg32(buf, 0);
>      }
>      return 0;
>  }
> 

Thanks,
Laurent


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v2 05/14] gdbstub: add helper for 128 bit registers
  2019-11-30  8:45 ` [PATCH v2 05/14] gdbstub: add helper for 128 bit registers Alex Bennée
@ 2019-12-01 20:02   ` Philippe Mathieu-Daudé
  2019-12-02  2:19   ` Richard Henderson
  1 sibling, 0 replies; 38+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-12-01 20:02 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: damien.hedde, richard.henderson, luis.machado, alan.hayward

On 11/30/19 9:45 AM, Alex Bennée wrote:
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> 
> ---
> v2
>    - take care of endianess of the whole 128 bit word
> ---
>   include/exec/gdbstub.h | 13 +++++++++++++
>   1 file changed, 13 insertions(+)
> 
> diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
> index 08363969c14..59e366ba3af 100644
> --- a/include/exec/gdbstub.h
> +++ b/include/exec/gdbstub.h
> @@ -102,6 +102,19 @@ static inline int gdb_get_reg64(uint8_t *mem_buf, uint64_t val)
>       return 8;
>   }
>   
> +static inline int gdb_get_reg128(uint8_t *mem_buf, uint64_t val_hi,
> +                                 uint64_t val_lo)
> +{
> +#ifdef TARGET_WORDS_BIGENDIAN
> +    stq_p(mem_buf, val_hi);
> +    stq_p(mem_buf + 8, val_lo);
> +#else
> +    stq_p(mem_buf, val_lo);
> +    stq_p(mem_buf + 8, val_hi);
> +#endif
> +    return 16;
> +}
> +
>   #if TARGET_LONG_BITS == 64
>   #define gdb_get_regl(buf, val) gdb_get_reg64(buf, val)
>   #define ldtul_p(addr) ldq_p(addr)
> 

Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>



^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v2 06/14] target/arm: use gdb_get_reg helpers
  2019-11-30  8:45 ` [PATCH v2 06/14] target/arm: use gdb_get_reg helpers Alex Bennée
@ 2019-12-01 20:05   ` Philippe Mathieu-Daudé
  2019-12-02 10:05     ` Alan Hayward
  2019-12-02  2:20   ` Richard Henderson
  1 sibling, 1 reply; 38+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-12-01 20:05 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: damien.hedde, Peter Maydell, luis.machado, richard.henderson,
	open list:ARM TCG CPUs, alan.hayward

On 11/30/19 9:45 AM, Alex Bennée wrote:
> This is cleaner than poking memory directly and will make later
> clean-ups easier.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> 
> ---
> v2
>    - make sure we pass hi/lo correctly as quads are stored in LE order
> ---
>   target/arm/helper.c | 18 +++++++-----------
>   1 file changed, 7 insertions(+), 11 deletions(-)
> 
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index 0bf8f53d4b8..0ac950d6c71 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -105,21 +105,17 @@ static int aarch64_fpu_gdb_get_reg(CPUARMState *env, uint8_t *buf, int reg)
>   {
>       switch (reg) {
>       case 0 ... 31:
> -        /* 128 bit FP register */
> -        {
> -            uint64_t *q = aa64_vfp_qreg(env, reg);
> -            stq_le_p(buf, q[0]);
> -            stq_le_p(buf + 8, q[1]);
> -            return 16;
> -        }
> +    {
> +        /* 128 bit FP register - quads are in LE order */

Oh, this was always wrong on BE :(

Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>

> +        uint64_t *q = aa64_vfp_qreg(env, reg);
> +        return gdb_get_reg128(buf, q[1], q[0]);
> +    }
>       case 32:
>           /* FPSR */
> -        stl_p(buf, vfp_get_fpsr(env));
> -        return 4;
> +        return gdb_get_reg32(buf, vfp_get_fpsr(env));
>       case 33:
>           /* FPCR */
> -        stl_p(buf, vfp_get_fpcr(env));
> -        return 4;
> +        return gdb_get_reg32(buf,vfp_get_fpcr(env));
>       default:
>           return 0;
>       }
> 



^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v2 01/14] gdbstub: make GDBState static and have common init function
  2019-11-30  8:45 ` [PATCH v2 01/14] gdbstub: make GDBState static and have common init function Alex Bennée
@ 2019-12-02  2:14   ` Richard Henderson
  2019-12-02 14:35   ` Damien Hedde
  1 sibling, 0 replies; 38+ messages in thread
From: Richard Henderson @ 2019-12-02  2:14 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: damien.hedde, Philippe Mathieu-Daudé, luis.machado, alan.hayward

On 11/30/19 8:45 AM, Alex Bennée wrote:
> -static GDBState *gdbserver_state;
> +static GDBState gdbserver_state;
> +
> +static void init_gdbserver_state(void)
> +{
> +    g_assert(!gdbserver_state.init);
> +    memset(&gdbserver_state, 0, sizeof(GDBState));
> +    gdbserver_state.init = true;
> +}

At no point does init transition from true to false, afaict.  Therefore the
memset is unnecessary, as the effect is had from the default
zero-initialization of the static variable.

Otherwise,
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v2 02/14] gdbstub: stop passing GDBState * around and use global
  2019-11-30  8:45 ` [PATCH v2 02/14] gdbstub: stop passing GDBState * around and use global Alex Bennée
@ 2019-12-02  2:16   ` Richard Henderson
  2019-12-02 15:25   ` Damien Hedde
  1 sibling, 0 replies; 38+ messages in thread
From: Richard Henderson @ 2019-12-02  2:16 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: damien.hedde, Philippe Mathieu-Daudé, luis.machado, alan.hayward

On 11/30/19 8:45 AM, Alex Bennée wrote:
> We only have one GDBState which should be allocated at the time we
> process any commands. This will make further clean-up a bit easier.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>  gdbstub.c | 539 +++++++++++++++++++++++++++---------------------------
>  1 file changed, 267 insertions(+), 272 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v2 05/14] gdbstub: add helper for 128 bit registers
  2019-11-30  8:45 ` [PATCH v2 05/14] gdbstub: add helper for 128 bit registers Alex Bennée
  2019-12-01 20:02   ` Philippe Mathieu-Daudé
@ 2019-12-02  2:19   ` Richard Henderson
  1 sibling, 0 replies; 38+ messages in thread
From: Richard Henderson @ 2019-12-02  2:19 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel; +Cc: damien.hedde, luis.machado, alan.hayward

On 11/30/19 8:45 AM, Alex Bennée wrote:
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> 
> ---
> v2
>   - take care of endianess of the whole 128 bit word
> ---
>  include/exec/gdbstub.h | 13 +++++++++++++
>  1 file changed, 13 insertions(+)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v2 06/14] target/arm: use gdb_get_reg helpers
  2019-11-30  8:45 ` [PATCH v2 06/14] target/arm: use gdb_get_reg helpers Alex Bennée
  2019-12-01 20:05   ` Philippe Mathieu-Daudé
@ 2019-12-02  2:20   ` Richard Henderson
  1 sibling, 0 replies; 38+ messages in thread
From: Richard Henderson @ 2019-12-02  2:20 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: damien.hedde, Peter Maydell, open list:ARM TCG CPUs,
	luis.machado, alan.hayward

On 11/30/19 8:45 AM, Alex Bennée wrote:
> This is cleaner than poking memory directly and will make later
> clean-ups easier.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> 
> ---
> v2
>   - make sure we pass hi/lo correctly as quads are stored in LE order
> ---
>  target/arm/helper.c | 18 +++++++-----------
>  1 file changed, 7 insertions(+), 11 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v2 08/14] gdbstub: extend GByteArray to read register helpers
  2019-11-30  8:45 ` [PATCH v2 08/14] gdbstub: extend GByteArray to read register helpers Alex Bennée
@ 2019-12-02  2:24   ` Richard Henderson
  0 siblings, 0 replies; 38+ messages in thread
From: Richard Henderson @ 2019-12-02  2:24 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: Peter Maydell, Cornelia Huck, luis.machado, Sagar Karandikar,
	David Hildenbrand, Mark Cave-Ayland, Max Filippov,
	Alistair Francis, Edgar E. Iglesias, Marek Vasut, alan.hayward,
	open list:PowerPC TCG CPUs, Aleksandar Rikalo, Richard Henderson,
	Philippe Mathieu-Daudé,
	Artyom Tarasenko, Eduardo Habkost, open list:S390 TCG CPUs,
	open list:ARM TCG CPUs, Stafford Horne, David Gibson,
	damien.hedde, open list:RISC-V TCG CPUs, Bastian Koppelmann,
	Chris Wulff, Laurent Vivier, Michael Walle, Palmer Dabbelt,
	Aleksandar Markovic, Paolo Bonzini, Aurelien Jarno

On 11/30/19 8:45 AM, Alex Bennée wrote:
> -static int cpu_read_virt_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
> +static int cpu_read_virt_reg(CPUS390XState *env, GByteArray *mem_buf, int n)
>  {
>      switch (n) {
>      case S390_VIRT_CKC_REGNUM:
> @@ -296,9 +296,9 @@ static int cpu_write_virt_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
>  /* total number of registers in s390-gs.xml */
>  #define S390_NUM_GS_REGS 4
>  
> -static int cpu_read_gs_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
> +static int cpu_read_gs_reg(CPUS390XState *env, GByteArray *buf, int n)

Sometimes you're changing the name from mem_buf and sometimes not.  Perhaps
better not to change it anywhere, or change it everywhere first, without
changing the type.


r~


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v2 11/14] target/arm: default SVE length to 64 bytes for linux-user
  2019-11-30  8:45 ` [PATCH v2 11/14] target/arm: default SVE length to 64 bytes for linux-user Alex Bennée
@ 2019-12-02  2:41   ` Richard Henderson
  2019-12-05 17:31     ` Alex Bennée
  0 siblings, 1 reply; 38+ messages in thread
From: Richard Henderson @ 2019-12-02  2:41 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: damien.hedde, Peter Maydell, open list:ARM TCG CPUs,
	luis.machado, alan.hayward

On 11/30/19 8:45 AM, Alex Bennée wrote:
> The Linux kernel chooses the default of 64 bytes for SVE registers on
> the basis that it is the largest size that won't grow the signal
> frame. When debugging larger sizes are also unwieldy in gdb as each
> zreg will take over a page of terminal to display.
> 
> The user can of course always specify a larger size with the
> sve-max-vq property on the command line:
> 
>   -cpu max,sve-max-vq=16
> 
> This should not make any difference to SVE enabled software as the SVE
> is of course vector length agnostic.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>  target/arm/cpu64.c | 3 +++
>  1 file changed, 3 insertions(+)

6 is the largest size that doesn't grow the signal frame.
I imagine 4 was chosen because that's the only real hw atm.

> +        /* Default sve-max-vq to a reasonable numer */
> +        cpu->sve_max_vq = 4;

I also agree that we should match the kernel, but this is not the right way.
Changing max vq is not the same as changing the default vq.

You should change the value of env->vfp.zcr_el[1] in arm_cpu_reset(), and the
user can increase the length with prctl(2) as they would be able to on real
hardware that would have support for longer vector lengths.

Also, I don't think you should mix this up with gdb stuff.


r~


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v2 06/14] target/arm: use gdb_get_reg helpers
  2019-12-01 20:05   ` Philippe Mathieu-Daudé
@ 2019-12-02 10:05     ` Alan Hayward
  2019-12-05 17:58       ` Alex Bennée
  0 siblings, 1 reply; 38+ messages in thread
From: Alan Hayward @ 2019-12-02 10:05 UTC (permalink / raw)
  To: Alex Bennée
  Cc: damien.hedde, Peter Maydell, Luis Machado, richard.henderson,
	qemu-devel, open list:ARM TCG CPUs, nd,
	Philippe Mathieu-Daudé



> On 1 Dec 2019, at 20:05, Philippe Mathieu-Daudé <philmd@redhat.com> wrote:
> 
> On 11/30/19 9:45 AM, Alex Bennée wrote:
>> This is cleaner than poking memory directly and will make later
>> clean-ups easier.
>> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>> ---
>> v2
>>   - make sure we pass hi/lo correctly as quads are stored in LE order
>> ---
>>  target/arm/helper.c | 18 +++++++-----------
>>  1 file changed, 7 insertions(+), 11 deletions(-)
>> diff --git a/target/arm/helper.c b/target/arm/helper.c
>> index 0bf8f53d4b8..0ac950d6c71 100644
>> --- a/target/arm/helper.c
>> +++ b/target/arm/helper.c
>> @@ -105,21 +105,17 @@ static int aarch64_fpu_gdb_get_reg(CPUARMState *env, uint8_t *buf, int reg)
>>  {
>>      switch (reg) {
>>      case 0 ... 31:
>> -        /* 128 bit FP register */
>> -        {
>> -            uint64_t *q = aa64_vfp_qreg(env, reg);
>> -            stq_le_p(buf, q[0]);
>> -            stq_le_p(buf + 8, q[1]);
>> -            return 16;
>> -        }
>> +    {
>> +        /* 128 bit FP register - quads are in LE order */
> 
> Oh, this was always wrong on BE :(

Am I right in thinking this patch correctly matches the SVE BE changes from June?

Specifically, this patch:
http://lists.infradead.org/pipermail/linux-arm-kernel/2019-June/657826.html


Alan.

> 
> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> 
>> +        uint64_t *q = aa64_vfp_qreg(env, reg);
>> +        return gdb_get_reg128(buf, q[1], q[0]);
>> +    }
>>      case 32:
>>          /* FPSR */
>> -        stl_p(buf, vfp_get_fpsr(env));
>> -        return 4;
>> +        return gdb_get_reg32(buf, vfp_get_fpsr(env));
>>      case 33:
>>          /* FPCR */
>> -        stl_p(buf, vfp_get_fpcr(env));
>> -        return 4;
>> +        return gdb_get_reg32(buf,vfp_get_fpcr(env));
>>      default:
>>          return 0;
>>      }


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v2 01/14] gdbstub: make GDBState static and have common init function
  2019-11-30  8:45 ` [PATCH v2 01/14] gdbstub: make GDBState static and have common init function Alex Bennée
  2019-12-02  2:14   ` Richard Henderson
@ 2019-12-02 14:35   ` Damien Hedde
  1 sibling, 0 replies; 38+ messages in thread
From: Damien Hedde @ 2019-12-02 14:35 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: luis.machado, Philippe Mathieu-Daudé,
	richard.henderson, alan.hayward



On 11/30/19 9:45 AM, Alex Bennée wrote:
> Instead of allocating make this entirely static. We shall reduce the
> size of the structure in later commits and dynamically allocate parts
> of it. We introduce an init and reset helper function to keep all the
> manipulation in one place.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> Cc: Damien Hedde <damien.hedde@greensocs.com>
> Cc: Richard Henderson <richard.henderson@linaro.org>
> 
> ---
> v2
>   - made entirely static, dropped dh/rth r-b tags due to changes

Modulo Richard's remark about unnecessary memset,
Reviewed-by: Damien Hedde <damien.hedde@greensocs.com>



^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v2 02/14] gdbstub: stop passing GDBState * around and use global
  2019-11-30  8:45 ` [PATCH v2 02/14] gdbstub: stop passing GDBState * around and use global Alex Bennée
  2019-12-02  2:16   ` Richard Henderson
@ 2019-12-02 15:25   ` Damien Hedde
  1 sibling, 0 replies; 38+ messages in thread
From: Damien Hedde @ 2019-12-02 15:25 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: luis.machado, Philippe Mathieu-Daudé,
	richard.henderson, alan.hayward



On 11/30/19 9:45 AM, Alex Bennée wrote:
> We only have one GDBState which should be allocated at the time we
> process any commands. This will make further clean-up a bit easier.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>  gdbstub.c | 539 +++++++++++++++++++++++++++---------------------------
>  1 file changed, 267 insertions(+), 272 deletions(-)
> 

> @@ -2919,33 +2914,33 @@ static void gdb_read_byte(GDBState *s, uint8_t ch)> [...]
>              } else {
>                  /* send ACK reply */
>                  reply = '+';
> -                put_buffer(s, &reply, 1);
> -                s->state = gdb_handle_packet(s, s->line_buf);
> +                put_buffer(&reply, 1);
> +                gdbserver_state.state = gdb_handle_packet(s, gdbserver_state.line_buf);

Is there a reason to keep the GDBState* first parameter in
gdb_handle_packet() ?

There is a few remaining functions still taking GDBState* parameter
+ gdb_handle_packet
+ run_cmd_parser
+ gdb_monitor_output
+ create_default_processes
+ create_processes
+ gdb_read_byte

We should probably clean them too, but otherwise it looks good.

--
Damien


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v2 03/14] gdbstub: move str_buf to GDBState and use GString
  2019-11-30  8:45 ` [PATCH v2 03/14] gdbstub: move str_buf to GDBState and use GString Alex Bennée
@ 2019-12-02 15:26   ` Damien Hedde
  2019-12-03 12:49   ` Damien Hedde
  1 sibling, 0 replies; 38+ messages in thread
From: Damien Hedde @ 2019-12-02 15:26 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: luis.machado, Philippe Mathieu-Daudé,
	richard.henderson, alan.hayward



On 11/30/19 9:45 AM, Alex Bennée wrote:
> Rather than having a static buffer replace str_buf with a GString
> which we know can grow on demand. Convert the internal functions to
> take a GString instead of a char * and length.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
> 
> ---
> v2
>   - fix conflict from status gdbserver_state
>   - add put_strbuf helper
> ---
>  gdbstub.c | 195 +++++++++++++++++++++++++-----------------------------
>  1 file changed, 90 insertions(+), 105 deletions(-)
> 

Reviewed-by: Damien Hedde <damien.hedde@greensocs.com>

--
Damien


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v2 09/14] target/arm: prepare for multiple dynamic XMLs
  2019-11-30  8:45 ` [PATCH v2 09/14] target/arm: prepare for multiple dynamic XMLs Alex Bennée
@ 2019-12-02 18:26   ` Richard Henderson
  0 siblings, 0 replies; 38+ messages in thread
From: Richard Henderson @ 2019-12-02 18:26 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: damien.hedde, Peter Maydell, open list:ARM TCG CPUs,
	luis.machado, alan.hayward

On 11/30/19 8:45 AM, Alex Bennée wrote:
> We will want to generate similar dynamic XML for gdbstub support of
> SVE registers (the upstream doesn't use XML). To that end lightly
> rename a few things to make the distinction.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>  target/arm/cpu.h     | 20 +++++++++++++-------
>  target/arm/gdbstub.c | 30 +++++++++++++++---------------
>  target/arm/helper.c  |  4 ++--
>  3 files changed, 30 insertions(+), 24 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~



^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v2 12/14] target/arm: generate xml description of our SVE registers
  2019-11-30  8:46 ` [PATCH v2 12/14] target/arm: generate xml description of our SVE registers Alex Bennée
@ 2019-12-02 18:44   ` Richard Henderson
  0 siblings, 0 replies; 38+ messages in thread
From: Richard Henderson @ 2019-12-02 18:44 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: damien.hedde, Peter Maydell, open list:ARM TCG CPUs,
	luis.machado, alan.hayward

On 11/30/19 8:46 AM, Alex Bennée wrote:
> +struct TypeSize {
> +    const char *gdb_type;
> +    int  size;
> +    const char sz, suffix;
> +};
> +
> +static struct TypeSize vec_lanes[] = {

static const.

> +    for (bits = 128; bits >= 8; bits = bits/2) {

Mind the spacing in the binary /, or bits /= 2.

> +#ifdef TARGET_AARCH64
> +static int arm_gdb_get_svereg(CPUARMState *env, GByteArray *buf, int reg)
> +{
> +    ARMCPU *cpu = env_archcpu(env);
> +    DynamicGDBXMLInfo *info = &cpu->dyn_svereg_xml;
> +
> +    /* The first 32 registers are the zregs */
> +    if (reg < 32) {
> +        int vq, len = 0;
> +        for (vq = 0; vq < cpu->sve_max_vq; vq++) {
> +            len += gdb_get_reg128(buf,
> +                                  env->vfp.zregs[reg].d[vq * 2 + 1],
> +                                  env->vfp.zregs[reg].d[vq * 2]);
> +        }
> +        return len;

This is tricky.  The "standard" ordering of sve vectors is a stream of bytes,
in little-endian ordering.  This is how the hardware handles things, even in
big-endian mode.

I'm not sure how gdb is set up to handle this.  Probably it
doesn't matter for now, since almost no one uses BE, and can
fixed later if needs be.

> +    case 2 ... 19:
> +    {
> +        int preg = reg - info->data.sve.fpsr_pos - 2;
> +        int vq, len = 0;
> +        for (vq = 0; vq < cpu->sve_max_vq; vq = vq + 4) {
> +            len += gdb_get_reg64(buf, env->vfp.pregs[preg].p[vq / 4]);
> +        }
> +        return len;
> +    }

The byte ordering of the predicate registers is similar.

This output does not appear to work for vq % 4 != 0.  The vqp type is defined
as a vector of uint16, so you'd need to output in units of reg16, extracted
from the uint64_t as

  extract64(env->vfp.pregs[preg].p[vq / 4], vq % 4 * 16, 16);


r~


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v2 13/14] tests/guest-debug: add a simple test runner
  2019-11-30  8:46 ` [PATCH v2 13/14] tests/guest-debug: add a simple test runner Alex Bennée
@ 2019-12-02 18:50   ` Richard Henderson
  0 siblings, 0 replies; 38+ messages in thread
From: Richard Henderson @ 2019-12-02 18:50 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel; +Cc: damien.hedde, luis.machado, alan.hayward

On 11/30/19 8:46 AM, Alex Bennée wrote:
> The test runners job is to start QEMU with guest debug enabled and
> then spawn a gdb process running a test script that exercises the
> functionality it wants to test.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>  tests/guest-debug/run-test.py | 57 +++++++++++++++++++++++++++++++++++
>  1 file changed, 57 insertions(+)
>  create mode 100755 tests/guest-debug/run-test.py

Looks plausible.

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v2 04/14] gdbstub: move mem_buf to GDBState and use GByteArray
  2019-11-30  8:45 ` [PATCH v2 04/14] gdbstub: move mem_buf to GDBState and use GByteArray Alex Bennée
@ 2019-12-03 11:11   ` Damien Hedde
  0 siblings, 0 replies; 38+ messages in thread
From: Damien Hedde @ 2019-12-03 11:11 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: luis.machado, Philippe Mathieu-Daudé,
	richard.henderson, alan.hayward



On 11/30/19 9:45 AM, Alex Bennée wrote:
> This is in preparation for further re-factoring of the register API
> with the rest of the code. Theoretically the read register function
> could overwrite the MAX_PACKET_LENGTH buffer although currently all
> registers are well within the size range.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  gdbstub.c | 62 ++++++++++++++++++++++++++++++++++---------------------
>  1 file changed, 38 insertions(+), 24 deletions(-)
> 
> @@ -2003,7 +2015,7 @@ static void handle_query_curr_tid(GdbCmdContext *gdb_ctx, void *user_ctx)
>      cpu = get_first_cpu_in_process(process);
>      g_string_assign(gdbserver_state.str_buf, "QC");
>      gdb_append_thread_id(cpu, gdbserver_state.str_buf);
> -    put_strbuf();;
> +    put_strbuf();
Hi Alex,

The double ';' (and the two other occurrences below) is added by your
previous patch.

>  }
>  
>  static void handle_query_threads(GdbCmdContext *gdb_ctx, void *user_ctx)
> @@ -2015,7 +2027,7 @@ static void handle_query_threads(GdbCmdContext *gdb_ctx, void *user_ctx)
>  
>      g_string_assign(gdbserver_state.str_buf, "m");
>      gdb_append_thread_id(gdbserver_state.query_cpu, gdbserver_state.str_buf);
> -    put_strbuf();;
> +    put_strbuf();
>      gdbserver_state.query_cpu = gdb_next_attached_cpu(gdbserver_state.query_cpu);
>  }
>  
> @@ -2058,7 +2070,7 @@ static void handle_query_thread_extra(GdbCmdContext *gdb_ctx, void *user_ctx)
>      }
>      trace_gdbstub_op_extra_info(rs->str);
>      memtohex(gdbserver_state.str_buf, (uint8_t *)rs->str, rs->len);
> -    put_strbuf();;
> +    put_strbuf();
>  }
>   

With the ";;" fix
Reviewed/Tested-by: Damien Hedde <damien.hedde@greensocs>

--
Damien


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v2 03/14] gdbstub: move str_buf to GDBState and use GString
  2019-11-30  8:45 ` [PATCH v2 03/14] gdbstub: move str_buf to GDBState and use GString Alex Bennée
  2019-12-02 15:26   ` Damien Hedde
@ 2019-12-03 12:49   ` Damien Hedde
  1 sibling, 0 replies; 38+ messages in thread
From: Damien Hedde @ 2019-12-03 12:49 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: luis.machado, Philippe Mathieu-Daudé,
	richard.henderson, alan.hayward


On 11/30/19 9:45 AM, Alex Bennée wrote:
> Rather than having a static buffer replace str_buf with a GString
> which we know can grow on demand. Convert the internal functions to
> take a GString instead of a char * and length.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
> 
> ---
> v2
>   - fix conflict from status gdbserver_state
>   - add put_strbuf helper
> ---
>  gdbstub.c | 195 +++++++++++++++++++++++++-----------------------------
>  1 file changed, 90 insertions(+), 105 deletions(-)
> 
> @@ -667,25 +667,28 @@ static int put_packet(const char *buf)

Hi,

I did some tests with my target having lot of registers and was
wondering if we should add an assert there (or even better in
put_packet_binary()). Something like:
       /* FIXME: until bigger packets are supported */
       g_assert(strlen(buf) <= MAX_PACKET_LENGTH);

There is a memcpy() in put_packet_binary() that overflows
in that case. With this patch, read_all_registers() can for example
generate binary packet up to 2*MAX_PACKET_LENGTH.

>      return put_packet_binary(buf, strlen(buf), false);
>  }

Apart from this case which don't happen with in-tree targets, it works
fine. So,
Tested-by: Damien Hedde <damien.hedde@greensocs.com>

I'll work on the missing bits for bigger packet support I soon as I have
some spare time.

Regards,
--
Damien


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v2 11/14] target/arm: default SVE length to 64 bytes for linux-user
  2019-12-02  2:41   ` Richard Henderson
@ 2019-12-05 17:31     ` Alex Bennée
  2019-12-05 19:36       ` Richard Henderson
  0 siblings, 1 reply; 38+ messages in thread
From: Alex Bennée @ 2019-12-05 17:31 UTC (permalink / raw)
  To: Richard Henderson
  Cc: damien.hedde, Peter Maydell, luis.machado, qemu-devel,
	open list:ARM TCG CPUs, alan.hayward


Richard Henderson <richard.henderson@linaro.org> writes:

> On 11/30/19 8:45 AM, Alex Bennée wrote:
>> The Linux kernel chooses the default of 64 bytes for SVE registers on
>> the basis that it is the largest size that won't grow the signal
>> frame. When debugging larger sizes are also unwieldy in gdb as each
>> zreg will take over a page of terminal to display.
>> 
>> The user can of course always specify a larger size with the
>> sve-max-vq property on the command line:
>> 
>>   -cpu max,sve-max-vq=16
>> 
>> This should not make any difference to SVE enabled software as the SVE
>> is of course vector length agnostic.
>> 
>> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>> ---
>>  target/arm/cpu64.c | 3 +++
>>  1 file changed, 3 insertions(+)
>
> 6 is the largest size that doesn't grow the signal frame.
> I imagine 4 was chosen because that's the only real hw atm.
>
>> +        /* Default sve-max-vq to a reasonable numer */
>> +        cpu->sve_max_vq = 4;
>
> I also agree that we should match the kernel, but this is not the right way.
> Changing max vq is not the same as changing the default vq.
>
> You should change the value of env->vfp.zcr_el[1] in arm_cpu_reset(), and the
> user can increase the length with prctl(2) as they would be able to on real
> hardware that would have support for longer vector lengths.

No the intention is to default to a lower max VQ because...

> Also, I don't think you should mix this up with gdb stuff.

it is what we use for sizing the registers for the gdbstub. The other
option would be to use the effective zcr_el1 value at the time of the
gdbstub connecting but then things will go horribly wrong if the user
execute a prctl and widens their size.

>
>
> r~


-- 
Alex Bennée


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v2 06/14] target/arm: use gdb_get_reg helpers
  2019-12-02 10:05     ` Alan Hayward
@ 2019-12-05 17:58       ` Alex Bennée
  0 siblings, 0 replies; 38+ messages in thread
From: Alex Bennée @ 2019-12-05 17:58 UTC (permalink / raw)
  To: Alan Hayward
  Cc: damien.hedde, Peter Maydell, Luis Machado, richard.henderson,
	qemu-devel, open list:ARM TCG CPUs, nd,
	Philippe Mathieu-Daudé


Alan Hayward <Alan.Hayward@arm.com> writes:

>> On 1 Dec 2019, at 20:05, Philippe Mathieu-Daudé <philmd@redhat.com> wrote:
>> 
>> On 11/30/19 9:45 AM, Alex Bennée wrote:
>>> This is cleaner than poking memory directly and will make later
>>> clean-ups easier.
>>> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>>> ---
>>> v2
>>>   - make sure we pass hi/lo correctly as quads are stored in LE order
>>> ---
>>>  target/arm/helper.c | 18 +++++++-----------
>>>  1 file changed, 7 insertions(+), 11 deletions(-)
>>> diff --git a/target/arm/helper.c b/target/arm/helper.c
>>> index 0bf8f53d4b8..0ac950d6c71 100644
>>> --- a/target/arm/helper.c
>>> +++ b/target/arm/helper.c
>>> @@ -105,21 +105,17 @@ static int aarch64_fpu_gdb_get_reg(CPUARMState *env, uint8_t *buf, int reg)
>>>  {
>>>      switch (reg) {
>>>      case 0 ... 31:
>>> -        /* 128 bit FP register */
>>> -        {
>>> -            uint64_t *q = aa64_vfp_qreg(env, reg);
>>> -            stq_le_p(buf, q[0]);
>>> -            stq_le_p(buf + 8, q[1]);
>>> -            return 16;
>>> -        }
>>> +    {
>>> +        /* 128 bit FP register - quads are in LE order */
>> 
>> Oh, this was always wrong on BE :(
>
> Am I right in thinking this patch correctly matches the SVE BE changes from June?
>
> Specifically, this patch:
> http://lists.infradead.org/pipermail/linux-arm-kernel/2019-June/657826.html

Not quite. This is just taking into account the way we store the data
internally in cpu.h. The gdb_get_reg128 helper will then ensure stuff is
in target endian format which is what gdbstub defines.

There aren't any actual kernel to userspace transfers going on here.

>
>
> Alan.
>
>> 
>> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
>> 
>>> +        uint64_t *q = aa64_vfp_qreg(env, reg);
>>> +        return gdb_get_reg128(buf, q[1], q[0]);
>>> +    }
>>>      case 32:
>>>          /* FPSR */
>>> -        stl_p(buf, vfp_get_fpsr(env));
>>> -        return 4;
>>> +        return gdb_get_reg32(buf, vfp_get_fpsr(env));
>>>      case 33:
>>>          /* FPCR */
>>> -        stl_p(buf, vfp_get_fpcr(env));
>>> -        return 4;
>>> +        return gdb_get_reg32(buf,vfp_get_fpcr(env));
>>>      default:
>>>          return 0;
>>>      }


-- 
Alex Bennée


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v2 11/14] target/arm: default SVE length to 64 bytes for linux-user
  2019-12-05 17:31     ` Alex Bennée
@ 2019-12-05 19:36       ` Richard Henderson
  2019-12-06 14:52         ` Alex Bennée
  0 siblings, 1 reply; 38+ messages in thread
From: Richard Henderson @ 2019-12-05 19:36 UTC (permalink / raw)
  To: Alex Bennée
  Cc: damien.hedde, Peter Maydell, luis.machado, qemu-devel,
	open list:ARM TCG CPUs, alan.hayward

On 12/5/19 9:31 AM, Alex Bennée wrote:
> 
> Richard Henderson <richard.henderson@linaro.org> writes:
> 
>> On 11/30/19 8:45 AM, Alex Bennée wrote:
>>> The Linux kernel chooses the default of 64 bytes for SVE registers on
>>> the basis that it is the largest size that won't grow the signal
>>> frame. When debugging larger sizes are also unwieldy in gdb as each
>>> zreg will take over a page of terminal to display.
>>>
>>> The user can of course always specify a larger size with the
>>> sve-max-vq property on the command line:
>>>
>>>   -cpu max,sve-max-vq=16
>>>
>>> This should not make any difference to SVE enabled software as the SVE
>>> is of course vector length agnostic.
>>>
>>> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>>> ---
>>>  target/arm/cpu64.c | 3 +++
>>>  1 file changed, 3 insertions(+)
>>
>> 6 is the largest size that doesn't grow the signal frame.
>> I imagine 4 was chosen because that's the only real hw atm.
>>
>>> +        /* Default sve-max-vq to a reasonable numer */
>>> +        cpu->sve_max_vq = 4;
>>
>> I also agree that we should match the kernel, but this is not the right way.
>> Changing max vq is not the same as changing the default vq.
>>
>> You should change the value of env->vfp.zcr_el[1] in arm_cpu_reset(), and the
>> user can increase the length with prctl(2) as they would be able to on real
>> hardware that would have support for longer vector lengths.
> 
> No the intention is to default to a lower max VQ because...
> 
>> Also, I don't think you should mix this up with gdb stuff.
> 
> it is what we use for sizing the registers for the gdbstub. The other
> option would be to use the effective zcr_el1 value at the time of the
> gdbstub connecting but then things will go horribly wrong if the user
> execute a prctl and widens their size.

Why would you care about the size of the registers as passed by default?  You
shouldn't need or want to change that default to make gdbstub work.

The gdbstub should be passing along the vq value (via the "vg" pseudo-register,
iirc), and gdb should be working out what to display based on that.

If that isn't happening, and you are only changing the default so that gdb
quits displaying massive registers when they aren't in use, then you're doing
something wrong with gdb and gdbstub.


r~


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v2 11/14] target/arm: default SVE length to 64 bytes for linux-user
  2019-12-05 19:36       ` Richard Henderson
@ 2019-12-06 14:52         ` Alex Bennée
  0 siblings, 0 replies; 38+ messages in thread
From: Alex Bennée @ 2019-12-06 14:52 UTC (permalink / raw)
  To: Richard Henderson
  Cc: damien.hedde, Peter Maydell, luis.machado, qemu-devel,
	open list:ARM TCG CPUs, alan.hayward


Richard Henderson <richard.henderson@linaro.org> writes:

> On 12/5/19 9:31 AM, Alex Bennée wrote:
>> 
>> Richard Henderson <richard.henderson@linaro.org> writes:
>> 
>>> On 11/30/19 8:45 AM, Alex Bennée wrote:
>>>> The Linux kernel chooses the default of 64 bytes for SVE registers on
>>>> the basis that it is the largest size that won't grow the signal
>>>> frame. When debugging larger sizes are also unwieldy in gdb as each
>>>> zreg will take over a page of terminal to display.
>>>>
>>>> The user can of course always specify a larger size with the
>>>> sve-max-vq property on the command line:
>>>>
>>>>   -cpu max,sve-max-vq=16
>>>>
>>>> This should not make any difference to SVE enabled software as the SVE
>>>> is of course vector length agnostic.
>>>>
>>>> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>>>> ---
>>>>  target/arm/cpu64.c | 3 +++
>>>>  1 file changed, 3 insertions(+)
>>>
>>> 6 is the largest size that doesn't grow the signal frame.
>>> I imagine 4 was chosen because that's the only real hw atm.
>>>
>>>> +        /* Default sve-max-vq to a reasonable numer */
>>>> +        cpu->sve_max_vq = 4;
>>>
>>> I also agree that we should match the kernel, but this is not the right way.
>>> Changing max vq is not the same as changing the default vq.
>>>
>>> You should change the value of env->vfp.zcr_el[1] in arm_cpu_reset(), and the
>>> user can increase the length with prctl(2) as they would be able to on real
>>> hardware that would have support for longer vector lengths.
>> 
>> No the intention is to default to a lower max VQ because...
>> 
>>> Also, I don't think you should mix this up with gdb stuff.
>> 
>> it is what we use for sizing the registers for the gdbstub. The other
>> option would be to use the effective zcr_el1 value at the time of the
>> gdbstub connecting but then things will go horribly wrong if the user
>> execute a prctl and widens their size.
>
> Why would you care about the size of the registers as passed by default?  You
> shouldn't need or want to change that default to make gdbstub work.
>
> The gdbstub should be passing along the vq value (via the "vg" pseudo-register,
> iirc), and gdb should be working out what to display based on that.
>
> If that isn't happening, and you are only changing the default so that gdb
> quits displaying massive registers when they aren't in use, then you're doing
> something wrong with gdb and gdbstub.

Currently the upstream gdbserver sends the XML based on the VL at start-up. It
doesn't handle changes in the vector size.

-- 
Alex Bennée


^ permalink raw reply	[flat|nested] 38+ messages in thread

end of thread, other threads:[~2019-12-06 16:14 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-30  8:45 [PATCH v2 00/14] gdbstub refactor and SVE support Alex Bennée
2019-11-30  8:45 ` [PATCH v2 01/14] gdbstub: make GDBState static and have common init function Alex Bennée
2019-12-02  2:14   ` Richard Henderson
2019-12-02 14:35   ` Damien Hedde
2019-11-30  8:45 ` [PATCH v2 02/14] gdbstub: stop passing GDBState * around and use global Alex Bennée
2019-12-02  2:16   ` Richard Henderson
2019-12-02 15:25   ` Damien Hedde
2019-11-30  8:45 ` [PATCH v2 03/14] gdbstub: move str_buf to GDBState and use GString Alex Bennée
2019-12-02 15:26   ` Damien Hedde
2019-12-03 12:49   ` Damien Hedde
2019-11-30  8:45 ` [PATCH v2 04/14] gdbstub: move mem_buf to GDBState and use GByteArray Alex Bennée
2019-12-03 11:11   ` Damien Hedde
2019-11-30  8:45 ` [PATCH v2 05/14] gdbstub: add helper for 128 bit registers Alex Bennée
2019-12-01 20:02   ` Philippe Mathieu-Daudé
2019-12-02  2:19   ` Richard Henderson
2019-11-30  8:45 ` [PATCH v2 06/14] target/arm: use gdb_get_reg helpers Alex Bennée
2019-12-01 20:05   ` Philippe Mathieu-Daudé
2019-12-02 10:05     ` Alan Hayward
2019-12-05 17:58       ` Alex Bennée
2019-12-02  2:20   ` Richard Henderson
2019-11-30  8:45 ` [PATCH v2 07/14] target/m68k: " Alex Bennée
2019-11-30 10:58   ` Laurent Vivier
2019-11-30  8:45 ` [PATCH v2 08/14] gdbstub: extend GByteArray to read register helpers Alex Bennée
2019-12-02  2:24   ` Richard Henderson
2019-11-30  8:45 ` [PATCH v2 09/14] target/arm: prepare for multiple dynamic XMLs Alex Bennée
2019-12-02 18:26   ` Richard Henderson
2019-11-30  8:45 ` [PATCH v2 10/14] target/arm: explicitly encode regnum in our XML Alex Bennée
2019-11-30  8:45 ` [PATCH v2 11/14] target/arm: default SVE length to 64 bytes for linux-user Alex Bennée
2019-12-02  2:41   ` Richard Henderson
2019-12-05 17:31     ` Alex Bennée
2019-12-05 19:36       ` Richard Henderson
2019-12-06 14:52         ` Alex Bennée
2019-11-30  8:46 ` [PATCH v2 12/14] target/arm: generate xml description of our SVE registers Alex Bennée
2019-12-02 18:44   ` Richard Henderson
2019-11-30  8:46 ` [PATCH v2 13/14] tests/guest-debug: add a simple test runner Alex Bennée
2019-12-02 18:50   ` Richard Henderson
2019-11-30  8:46 ` [PATCH v2 14/14] tests/tcg: add a gdbstub testcase for SVE registers Alex Bennée
2019-11-30  9:33 ` [PATCH v2 00/14] gdbstub refactor and SVE support no-reply

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).