[PATCH 4/8] winedbg: Support qXfer:features:read request.

Rémi Bernon rbernon at codeweavers.com
Thu Apr 2 08:55:17 CDT 2020


Also introduces packet_reply_open_xfer and packet_reply_close_xfer,
supporting partial qXfer replies. It always allocates the whole reply
buffer for simplicity, but then trucates to the requested offset and
length.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---

This makes gdb frontend stop trying to figure libraries by itself, so
we temporarily lose debug symbol lookup. It will be fixed by the
qXfer:libraries:read request.

 programs/winedbg/gdbproxy.c | 199 +++++++++++++++++++++++++++++-------
 1 file changed, 162 insertions(+), 37 deletions(-)

diff --git a/programs/winedbg/gdbproxy.c b/programs/winedbg/gdbproxy.c
index 7c57caf9d1e8..5a273c4a3199 100644
--- a/programs/winedbg/gdbproxy.c
+++ b/programs/winedbg/gdbproxy.c
@@ -168,40 +168,6 @@ static unsigned char checksum(const char* ptr, int len)
     return cksum;
 }
 
-#ifdef __i386__
-static const char target_xml[] = "";
-#elif defined(__powerpc__)
-static const char target_xml[] = "";
-#elif defined(__x86_64__)
-static const char target_xml[] = "";
-#elif defined(__arm__)
-static const char target_xml[] =
-    "l <target><architecture>arm</architecture>\n"
-    "<feature name=\"org.gnu.gdb.arm.core\">\n"
-    "    <reg name=\"r0\" bitsize=\"32\" type=\"uint32\"/>\n"
-    "    <reg name=\"r1\" bitsize=\"32\" type=\"uint32\"/>\n"
-    "    <reg name=\"r2\" bitsize=\"32\" type=\"uint32\"/>\n"
-    "    <reg name=\"r3\" bitsize=\"32\" type=\"uint32\"/>\n"
-    "    <reg name=\"r4\" bitsize=\"32\" type=\"uint32\"/>\n"
-    "    <reg name=\"r5\" bitsize=\"32\" type=\"uint32\"/>\n"
-    "    <reg name=\"r6\" bitsize=\"32\" type=\"uint32\"/>\n"
-    "    <reg name=\"r7\" bitsize=\"32\" type=\"uint32\"/>\n"
-    "    <reg name=\"r8\" bitsize=\"32\" type=\"uint32\"/>\n"
-    "    <reg name=\"r9\" bitsize=\"32\" type=\"uint32\"/>\n"
-    "    <reg name=\"r10\" bitsize=\"32\" type=\"uint32\"/>\n"
-    "    <reg name=\"r11\" bitsize=\"32\" type=\"uint32\"/>\n"
-    "    <reg name=\"r12\" bitsize=\"32\" type=\"uint32\"/>\n"
-    "    <reg name=\"sp\" bitsize=\"32\" type=\"data_ptr\"/>\n"
-    "    <reg name=\"lr\" bitsize=\"32\"/>\n"
-    "    <reg name=\"pc\" bitsize=\"32\" type=\"code_ptr\"/>\n"
-    "    <reg name=\"cpsr\" bitsize=\"32\"/>\n"
-    "</feature></target>\n";
-#elif defined(__aarch64__)
-static const char target_xml[] = "";
-#else
-# error Define the registers map for your CPU
-#endif
-
 static inline void* cpu_register_ptr(struct gdb_context *gdbctx,
     dbg_ctx_t *ctx, unsigned idx)
 {
@@ -767,6 +733,35 @@ static void packet_reply_close(struct gdb_context* gdbctx)
     gdbctx->out_curr_packet = -1;
 }
 
+static void packet_reply_open_xfer(struct gdb_context* gdbctx)
+{
+    packet_reply_open(gdbctx);
+    packet_reply_add(gdbctx, "m");
+}
+
+static void packet_reply_close_xfer(struct gdb_context* gdbctx, int off, int len)
+{
+    int begin = gdbctx->out_curr_packet + 1;
+    int plen;
+
+    if (begin + off < gdbctx->out_len)
+    {
+        gdbctx->out_len -= off;
+        memmove(gdbctx->out_buf + begin, gdbctx->out_buf + begin + off, gdbctx->out_len);
+    }
+    else
+    {
+        gdbctx->out_buf[gdbctx->out_curr_packet] = 'l';
+        gdbctx->out_len = gdbctx->out_curr_packet + 1;
+    }
+
+    plen = gdbctx->out_len - begin;
+    if (len >= 0 && plen > len) gdbctx->out_len -= (plen - len);
+    else gdbctx->out_buf[gdbctx->out_curr_packet] = 'l';
+
+    packet_reply_close(gdbctx);
+}
+
 static enum packet_return packet_reply(struct gdb_context* gdbctx, const char* packet)
 {
     packet_reply_open(gdbctx);
@@ -1396,8 +1391,130 @@ static enum packet_return packet_query_remote_command(struct gdb_context* gdbctx
     return packet_reply_error(gdbctx, EINVAL);
 }
 
+static void packet_query_target_xml(struct gdb_context* gdbctx, struct backend_cpu* cpu)
+{
+    const char* feature_prefix = NULL;
+    const char* feature = NULL;
+    char buffer[256];
+    int i;
+ 
+    packet_reply_add(gdbctx, "<target>");
+    switch (cpu->machine)
+    {
+    case IMAGE_FILE_MACHINE_AMD64:
+        packet_reply_add(gdbctx, "<architecture>i386:x86-64</architecture>");
+        feature_prefix = "org.gnu.gdb.i386.";
+        break;
+    case IMAGE_FILE_MACHINE_I386:
+        packet_reply_add(gdbctx, "<architecture>i386</architecture>");
+        feature_prefix = "org.gnu.gdb.i386.";
+        break;
+    case IMAGE_FILE_MACHINE_POWERPC:
+        packet_reply_add(gdbctx, "<architecture>powerpc:common</architecture>");
+        feature_prefix = "org.gnu.gdb.power.";
+        break;
+    case IMAGE_FILE_MACHINE_ARMNT:
+        packet_reply_add(gdbctx, "<architecture>arm</architecture>");
+        feature_prefix = "org.gnu.gdb.arm.";
+        break;
+    case IMAGE_FILE_MACHINE_ARM64:
+        packet_reply_add(gdbctx, "<architecture>aarch64</architecture>");
+        feature_prefix = "org.gnu.gdb.aarch64.";
+        break;
+    }
+
+    for (i = 0; i < cpu->gdb_num_regs; ++i)
+    {
+        if (cpu->gdb_register_map[i].feature)
+        {
+            if (feature) packet_reply_add(gdbctx, "</feature>");
+            feature = cpu->gdb_register_map[i].feature;
+
+            packet_reply_add(gdbctx, "<feature name=\"");
+            if (feature_prefix) packet_reply_add(gdbctx, feature_prefix);
+            packet_reply_add(gdbctx, feature);
+            packet_reply_add(gdbctx, "\">");
+
+            if (strcmp(feature_prefix, "org.gnu.gdb.i386.") == 0 &&
+                strcmp(feature, "core") == 0)
+                packet_reply_add(gdbctx, "<flags id=\"i386_eflags\" size=\"4\">"
+                                         "<field name=\"CF\" start=\"0\" end=\"0\"/>"
+                                         "<field name=\"\" start=\"1\" end=\"1\"/>"
+                                         "<field name=\"PF\" start=\"2\" end=\"2\"/>"
+                                         "<field name=\"AF\" start=\"4\" end=\"4\"/>"
+                                         "<field name=\"ZF\" start=\"6\" end=\"6\"/>"
+                                         "<field name=\"SF\" start=\"7\" end=\"7\"/>"
+                                         "<field name=\"TF\" start=\"8\" end=\"8\"/>"
+                                         "<field name=\"IF\" start=\"9\" end=\"9\"/>"
+                                         "<field name=\"DF\" start=\"10\" end=\"10\"/>"
+                                         "<field name=\"OF\" start=\"11\" end=\"11\"/>"
+                                         "<field name=\"NT\" start=\"14\" end=\"14\"/>"
+                                         "<field name=\"RF\" start=\"16\" end=\"16\"/>"
+                                         "<field name=\"VM\" start=\"17\" end=\"17\"/>"
+                                         "<field name=\"AC\" start=\"18\" end=\"18\"/>"
+                                         "<field name=\"VIF\" start=\"19\" end=\"19\"/>"
+                                         "<field name=\"VIP\" start=\"20\" end=\"20\"/>"
+                                         "<field name=\"ID\" start=\"21\" end=\"21\"/>"
+                                         "</flags>");
+
+            if (strcmp(feature_prefix, "org.gnu.gdb.i386.") == 0 &&
+                strcmp(feature, "sse") == 0)
+                packet_reply_add(gdbctx, "<vector id=\"v4f\" type=\"ieee_single\" count=\"4\"/>"
+                                         "<vector id=\"v2d\" type=\"ieee_double\" count=\"2\"/>"
+                                         "<vector id=\"v16i8\" type=\"int8\" count=\"16\"/>"
+                                         "<vector id=\"v8i16\" type=\"int16\" count=\"8\"/>"
+                                         "<vector id=\"v4i32\" type=\"int32\" count=\"4\"/>"
+                                         "<vector id=\"v2i64\" type=\"int64\" count=\"2\"/>"
+                                         "<union id=\"vec128\">"
+                                         "<field name=\"v4_float\" type=\"v4f\"/>"
+                                         "<field name=\"v2_double\" type=\"v2d\"/>"
+                                         "<field name=\"v16_int8\" type=\"v16i8\"/>"
+                                         "<field name=\"v8_int16\" type=\"v8i16\"/>"
+                                         "<field name=\"v4_int32\" type=\"v4i32\"/>"
+                                         "<field name=\"v2_int64\" type=\"v2i64\"/>"
+                                         "<field name=\"uint128\" type=\"uint128\"/>"
+                                         "</union>"
+                                         "<flags id=\"i386_mxcsr\" size=\"4\">"
+                                         "<field name=\"IE\" start=\"0\" end=\"0\"/>"
+                                         "<field name=\"DE\" start=\"1\" end=\"1\"/>"
+                                         "<field name=\"ZE\" start=\"2\" end=\"2\"/>"
+                                         "<field name=\"OE\" start=\"3\" end=\"3\"/>"
+                                         "<field name=\"UE\" start=\"4\" end=\"4\"/>"
+                                         "<field name=\"PE\" start=\"5\" end=\"5\"/>"
+                                         "<field name=\"DAZ\" start=\"6\" end=\"6\"/>"
+                                         "<field name=\"IM\" start=\"7\" end=\"7\"/>"
+                                         "<field name=\"DM\" start=\"8\" end=\"8\"/>"
+                                         "<field name=\"ZM\" start=\"9\" end=\"9\"/>"
+                                         "<field name=\"OM\" start=\"10\" end=\"10\"/>"
+                                         "<field name=\"UM\" start=\"11\" end=\"11\"/>"
+                                         "<field name=\"PM\" start=\"12\" end=\"12\"/>"
+                                         "<field name=\"FZ\" start=\"15\" end=\"15\"/>"
+                                         "</flags>");
+        }
+
+        snprintf(buffer, ARRAY_SIZE(buffer), "<reg name=\"%s\" bitsize=\"%zu\"",
+                 cpu->gdb_register_map[i].name, 8 * cpu->gdb_register_map[i].gdb_length);
+        packet_reply_add(gdbctx, buffer);
+
+        if (cpu->gdb_register_map[i].type)
+        {
+            packet_reply_add(gdbctx, " type=\"");
+            packet_reply_add(gdbctx, cpu->gdb_register_map[i].type);
+            packet_reply_add(gdbctx, "\"");
+        }
+
+        packet_reply_add(gdbctx, "/>");
+    }
+
+    if (feature) packet_reply_add(gdbctx, "</feature>");
+    packet_reply_add(gdbctx, "</target>");
+}
+
 static enum packet_return packet_query(struct gdb_context* gdbctx)
 {
+    int off, len;
+    struct backend_cpu *cpu;
+
     switch (gdbctx->in_packet[0])
     {
     case 'f':
@@ -1485,7 +1602,7 @@ static enum packet_return packet_query(struct gdb_context* gdbctx)
         {
             packet_reply_open(gdbctx);
             packet_reply_add(gdbctx, "QStartNoAckMode+;");
-            if (*target_xml) packet_reply_add(gdbctx, "PacketSize=400;qXfer:features:read+");
+            packet_reply_add(gdbctx, "qXfer:features:read+;");
             packet_reply_close(gdbctx);
             return packet_done;
         }
@@ -1516,8 +1633,16 @@ static enum packet_return packet_query(struct gdb_context* gdbctx)
         }
         break;
     case 'X':
-        if (*target_xml && strncmp(gdbctx->in_packet, "Xfer:features:read:target.xml", 29) == 0)
-            return packet_reply(gdbctx, target_xml);
+        if (sscanf(gdbctx->in_packet, "Xfer:features:read:target.xml:%x,%x", &off, &len) == 2)
+        {
+            if (!gdbctx->process) return packet_error;
+            if (!(cpu = gdbctx->process->be_cpu)) return packet_error;
+
+            packet_reply_open_xfer(gdbctx);
+            packet_query_target_xml(gdbctx, cpu);
+            packet_reply_close_xfer(gdbctx, off, len);
+            return packet_done;
+        }
         break;
     }
     ERR("Unhandled query %s\n", debugstr_an(gdbctx->in_packet, gdbctx->in_packet_len));
-- 
2.26.0.rc2




More information about the wine-devel mailing list