On 15/5/24 19:31, Gustavo Romero wrote:
Currently, it's not possible to have stubs specific to a given target,
even though there are GDB features which are target-specific, like, for
instance, memory tagging.

This commit introduces set_query_supported_arch,
set_gdb_gen_query_table_arch, and set_gdb_gen_set_table_arch functions
as interfaces to extend the qSupported string, the query handler table,
and set handler table per target, so allowing target-specific stub
implementation.

Besides that, it moves GdbCmdParseEntry struct, its related types, and
gdb_put_packet to include/exec/gdbstub.h so they are also available in
the target-specific stubs.

Signed-off-by: Gustavo Romero <gustavo.rom...@linaro.org>
---
  gdbstub/gdbstub.c      | 108 +++++++++++++++++++++++------------------
  gdbstub/internals.h    |  22 ---------
  gdbstub/syscalls.c     |   1 +
  include/exec/gdbstub.h |  86 +++++++++++++++++++++++++++++++-
  4 files changed, 147 insertions(+), 70 deletions(-)


@@ -1645,6 +1608,13 @@ static void handle_query_thread_extra(GArray *params, 
void *user_ctx)
      gdb_put_strbuf();
  }
+/* Arch-specific qSupported */
+char *query_supported_arch = NULL;

Please declare query_supported_arch as static.

+void set_query_supported_arch(char *query_supported)
+{
+    query_supported_arch = query_supported;
+}
+
  static void handle_query_supported(GArray *params, void *user_ctx)
  {
      CPUClass *cc;
@@ -1684,6 +1654,11 @@ static void handle_query_supported(GArray *params, void 
*user_ctx)
      }
g_string_append(gdbserver_state.str_buf, ";vContSupported+;multiprocess+");
+
+    if (query_supported_arch) {
+        g_string_append(gdbserver_state.str_buf, query_supported_arch);
+    }
+
      gdb_put_strbuf();
  }

Reviewed-by: Philippe Mathieu-Daudé <phi...@linaro.org>

Although I'd rather split in 3 as:

1/ Expose API

-- >8 --
diff --git a/gdbstub/internals.h b/gdbstub/internals.h
index 32f9f63297..34121dc61a 100644
--- a/gdbstub/internals.h
+++ b/gdbstub/internals.h
@@ -109 +108,0 @@ void gdb_put_strbuf(void);
-int gdb_put_packet(const char *buf);
@@ -169,21 +167,0 @@ void gdb_init_gdbserver_state(void);
-typedef enum GDBThreadIdKind {
-    GDB_ONE_THREAD = 0,
-    GDB_ALL_THREADS,     /* One process, all threads */
-    GDB_ALL_PROCESSES,
-    GDB_READ_THREAD_ERR
-} GDBThreadIdKind;
-
-typedef union GdbCmdVariant {
-    const char *data;
-    uint8_t opcode;
-    unsigned long val_ul;
-    unsigned long long val_ull;
-    struct {
-        GDBThreadIdKind kind;
-        uint32_t pid;
-        uint32_t tid;
-    } thread_id;
-} GdbCmdVariant;
-
-#define get_param(p, i)    (&g_array_index(p, GdbCmdVariant, i))
-
diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index eb14b91139..7bf189d7f3 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -147 +147,85 @@ extern const GDBFeature gdb_static_features[];
-#endif
+typedef void (*GdbCmdHandler)(GArray *params, void *user_ctx);
+
+typedef enum GDBThreadIdKind {
+    GDB_ONE_THREAD = 0,
+    GDB_ALL_THREADS,     /* One process, all threads */
+    GDB_ALL_PROCESSES,
+    GDB_READ_THREAD_ERR
+} GDBThreadIdKind;
+
+typedef union GdbCmdVariant {
+    const char *data;
+    uint8_t opcode;
+    unsigned long val_ul;
+    unsigned long long val_ull;
+    struct {
+        GDBThreadIdKind kind;
+        uint32_t pid;
+        uint32_t tid;
+    } thread_id;
+} GdbCmdVariant;
+
+#define get_param(p, i)    (&g_array_index(p, GdbCmdVariant, i))
+
+/*
+ * cmd_startswith -> cmd is compared using startswith
+ *
+ * allow_stop_reply -> true iff the gdbstub can respond to this command with a
+ *   "stop reply" packet. The list of commands that accept such response is
+ *   defined at the GDB Remote Serial Protocol documentation. see:
+ * https://sourceware.org/gdb/onlinedocs/gdb/Stop-Reply-Packets.html#Stop-Reply-Packets.
+ *
+ * schema definitions:
+ * Each schema parameter entry consists of 2 chars,
+ * the first char represents the parameter type handling
+ * the second char represents the delimiter for the next parameter
+ *
+ * Currently supported schema types:
+ * 'l' -> unsigned long (stored in .val_ul)
+ * 'L' -> unsigned long long (stored in .val_ull)
+ * 's' -> string (stored in .data)
+ * 'o' -> single char (stored in .opcode)
+ * 't' -> thread id (stored in .thread_id)
+ * '?' -> skip according to delimiter
+ *
+ * Currently supported delimiters:
+ * '?' -> Stop at any delimiter (",;:=\0")
+ * '0' -> Stop at "\0"
+ * '.' -> Skip 1 char unless reached "\0"
+ * Any other value is treated as the delimiter value itself
+ */
+typedef struct GdbCmdParseEntry {
+    GdbCmdHandler handler;
+    const char *cmd;
+    bool cmd_startswith;
+    const char *schema;
+    bool allow_stop_reply;
+} GdbCmdParseEntry;
+
+#define get_cmd_parsers(p) (&g_array_index(p, GdbCmdParseEntry, 0))
+
+/**
+ * set_gdb_gen_query_table_arch() - set a table to handle arch-specific query
+ * packets
+ */
+void set_gdb_gen_query_table_arch(GdbCmdParseEntry *table, int size);
+
+/**
+ * set_gdb_gen_set_table_arch() - set a table to handle arch-specific set
+ * packets
+ */
+void set_gdb_gen_set_table_arch(GdbCmdParseEntry *, int size);
+
+/**
+ * set_query_supported_arch() - set arch-specific features in qSupported
+ * features
+ */
+void set_query_supported_arch(char *);
+
+/**
+ * gdb_put_packet() - put string into gdb server's buffer so it is sent
+ * to the client
+ */
+int gdb_put_packet(const char *buf);
+
+#endif /* GDBSTUB_H */
diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
index b3574997ea..fc72f03c8a 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -923,37 +922,0 @@ static int cmd_parse_params(const char *data, const char *schema,
-typedef void (*GdbCmdHandler)(GArray *params, void *user_ctx);
-
-/*
- * cmd_startswith -> cmd is compared using startswith
- *
- * allow_stop_reply -> true iff the gdbstub can respond to this command with a
- *   "stop reply" packet. The list of commands that accept such response is
- *   defined at the GDB Remote Serial Protocol documentation. see:
- * https://sourceware.org/gdb/onlinedocs/gdb/Stop-Reply-Packets.html#Stop-Reply-Packets.
- *
- * schema definitions:
- * Each schema parameter entry consists of 2 chars,
- * the first char represents the parameter type handling
- * the second char represents the delimiter for the next parameter
- *
- * Currently supported schema types:
- * 'l' -> unsigned long (stored in .val_ul)
- * 'L' -> unsigned long long (stored in .val_ull)
- * 's' -> string (stored in .data)
- * 'o' -> single char (stored in .opcode)
- * 't' -> thread id (stored in .thread_id)
- * '?' -> skip according to delimiter
- *
- * Currently supported delimiters:
- * '?' -> Stop at any delimiter (",;:=\0")
- * '0' -> Stop at "\0"
- * '.' -> Skip 1 char unless reached "\0"
- * Any other value is treated as the delimiter value itself
- */
-typedef struct GdbCmdParseEntry {
-    GdbCmdHandler handler;
-    const char *cmd;
-    bool cmd_startswith;
-    const char *schema;
-    bool allow_stop_reply;
-} GdbCmdParseEntry;
-
diff --git a/gdbstub/syscalls.c b/gdbstub/syscalls.c
index 02e3a8f74c..ee9a16495e 100644
--- a/gdbstub/syscalls.c
+++ b/gdbstub/syscalls.c
@@ -20,0 +21 @@
+#include "exec/gdbstub.h"
---

2/ Refactor query/set handlers in preparation of target specific

-- >8 --
diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
index fc72f03c8a..1bb35167d4 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -1855,3 +1855,3 @@ static void handle_gen_query(GArray *params, void *user_ctx)
-    if (!process_string_cmd(get_param(params, 0)->data,
-                            gdb_gen_query_set_common_table,
-                            ARRAY_SIZE(gdb_gen_query_set_common_table))) {
+    if (process_string_cmd(get_param(params, 0)->data,
+                           gdb_gen_query_set_common_table,
+ ARRAY_SIZE(gdb_gen_query_set_common_table)) == 0) { @@ -1863,2 +1863,2 @@ static void handle_gen_query(GArray *params, void *user_ctx)
-                           ARRAY_SIZE(gdb_gen_query_table))) {
-        gdb_put_packet("");
+                           ARRAY_SIZE(gdb_gen_query_table)) == 0) {
+        return;
@@ -1865,0 +1866,3 @@ static void handle_gen_query(GArray *params, void *user_ctx)
+
+    /* Can't handle query, return Empty response. */
+    gdb_put_packet("");
@@ -1874,3 +1877,3 @@ static void handle_gen_set(GArray *params, void *user_ctx)
-    if (!process_string_cmd(get_param(params, 0)->data,
-                            gdb_gen_query_set_common_table,
-                            ARRAY_SIZE(gdb_gen_query_set_common_table))) {
+    if (process_string_cmd(get_param(params, 0)->data,
+                           gdb_gen_query_set_common_table,
+ ARRAY_SIZE(gdb_gen_query_set_common_table)) == 0) { @@ -1882,2 +1885,2 @@ static void handle_gen_set(GArray *params, void *user_ctx)
-                           ARRAY_SIZE(gdb_gen_set_table))) {
-        gdb_put_packet("");
+                           ARRAY_SIZE(gdb_gen_set_table)) == 0) {
+        return;
@@ -1884,0 +1888,3 @@ static void handle_gen_set(GArray *params, void *user_ctx)
+
+    /* Can't handle set, return Empty response. */
+    gdb_put_packet("");
---

3/ Introduce target specific handlers

-- >8 --
diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
index 1bb35167d4..a6b2200fc3 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -1610,0 +1611,7 @@ static void handle_query_thread_extra(GArray *params, void *user_ctx)
+/* Arch-specific qSupported */
+static char *query_supported_arch = NULL;
+void set_query_supported_arch(char *query_supported)
+{
+    query_supported_arch = query_supported;
+}
+
@@ -1649,0 +1657,5 @@ static void handle_query_supported(GArray *params, void *user_ctx)
+
+    if (query_supported_arch) {
+        g_string_append(gdbserver_state.str_buf, query_supported_arch);
+    }
+
@@ -1730,0 +1743,10 @@ static const GdbCmdParseEntry gdb_gen_query_set_common_table[] = {
+
+/* Arch-specific query table */
+static GdbCmdParseEntry *gdb_gen_query_table_arch = NULL ;
+static int gdb_gen_query_table_arch_size = 0;
+void set_gdb_gen_query_table_arch(GdbCmdParseEntry  *table, int size)
+{
+    gdb_gen_query_table_arch = table;
+    gdb_gen_query_table_arch_size = size;
+}
+
@@ -1822,0 +1845,9 @@ static const GdbCmdParseEntry gdb_gen_query_table[] = {
+/* Arch-specific set table */
+static GdbCmdParseEntry *gdb_gen_set_table_arch = NULL;
+static int gdb_gen_set_table_arch_size = 0;
+void set_gdb_gen_set_table_arch(GdbCmdParseEntry *table, int size)
+{
+    gdb_gen_set_table_arch = table;
+    gdb_gen_set_table_arch_size = size;
+}
+
@@ -1866,0 +1898,7 @@ static void handle_gen_query(GArray *params, void *user_ctx)
+    if (gdb_gen_query_table_arch &&
+        process_string_cmd(get_param(params, 0)->data,
+                           gdb_gen_query_table_arch,
+                           gdb_gen_query_table_arch_size) == 0) {
+        return;
+    }
+
@@ -1888,0 +1927,7 @@ static void handle_gen_set(GArray *params, void *user_ctx)
+    if (gdb_gen_set_table_arch &&
+        process_string_cmd(get_param(params, 0)->data,
+                           gdb_gen_set_table_arch,
+                           gdb_gen_set_table_arch_size) == 0) {
+        return;
+    }
+
---

Regards,

Phil.

Reply via email to