[PATCH v6 5/6] winedbg: Cache GDB qXfer command result for chunked fetching.

Jinoh Kang jinoh.kang.kr at gmail.com
Mon Nov 22 09:00:03 CST 2021


GDB does not retrieve the result of a qXfer command at once; instead, it
issues a series of requests to obtain the result one "chunk" at a time,
and concatenates those chunks internally.  Each request contains offset
and length variables that specify which portion of the result shall be
retrieved.

Today, Winedbg handles this by generating the entire result data each
time a request is received and slicing out the requested range for the
response.  This is not only inefficient due to repeated computation,
but also prone to race condition since the result may change between
successive chunk requests due to the dynamic nature of some commands
such as "libraries" and "threads."

Fix this by cacheing the result into a buffer at the first request, and
use the buffer to serve successive chunk requests.  The cache is
invalidated when the remote requests a different object, or the debugger
reaches the end of the result cache buffer.

Signed-off-by: Jinoh Kang <jinoh.kang.kr at gmail.com>
---

Notes:
    v3 -> v4:
    - Refactor the code a bit
    - Revert to scanf() when parsing Xfer packet lines
    - Fix pointer variable declaration style
    
    v3 -> v4: Synchronize to prior modified patches.
    
    v4 -> v5:
    - Synchronize to prior modified patches.
    - Fix pointer variable declaration style.

 programs/winedbg/gdbproxy.c | 43 +++++++++++++++++++++++++++----------
 1 file changed, 32 insertions(+), 11 deletions(-)

diff --git a/programs/winedbg/gdbproxy.c b/programs/winedbg/gdbproxy.c
index c9c7656f2a0..bdbfbe029f8 100644
--- a/programs/winedbg/gdbproxy.c
+++ b/programs/winedbg/gdbproxy.c
@@ -927,15 +927,16 @@ static inline void packet_reply_register_hex_to(struct gdb_context* gdbctx, dbg_
 }
 
 static void packet_reply_xfer(struct gdb_context* gdbctx, const void *data, size_t datalen,
-                              unsigned int off, unsigned int len)
+                              unsigned int off, unsigned int len, BOOL* more_p)
 {
-    BOOL nonempty;
+    BOOL nonempty, more;
     size_t trunc_len;
 
     packet_reply_open(gdbctx);
 
     nonempty = (size_t)off < datalen;
-    if (nonempty && (size_t)off + len < datalen)
+    more = nonempty && (size_t)off + len < datalen;
+    if (more)
         packet_reply_add(gdbctx, "m");
     else
         packet_reply_add(gdbctx, "l");
@@ -947,6 +948,8 @@ static void packet_reply_xfer(struct gdb_context* gdbctx, const void *data, size
     }
 
     packet_reply_close(gdbctx);
+
+    *more_p = more;
 }
 
 /* =============================================== *
@@ -2067,6 +2070,7 @@ static enum packet_return packet_query(struct gdb_context* gdbctx)
         {
             enum packet_return result;
             int i;
+            BOOL more;
 
             for (i = 0; i < ARRAY_SIZE(qxfer_handlers); i++)
             {
@@ -2082,24 +2086,41 @@ static enum packet_return packet_query(struct gdb_context* gdbctx)
 
             TRACE("qXfer %s read %s %u,%u\n", debugstr_a(object_name), debugstr_a(annex), off, len);
 
-            gdbctx->qxfer_object_idx = i;
-            strcpy(gdbctx->qxfer_object_annex, annex);
+            if (off > 0 &&
+                gdbctx->qxfer_buffer.len > 0 &&
+                gdbctx->qxfer_object_idx == i &&
+                strcmp(gdbctx->qxfer_object_annex, annex) == 0)
+            {
+                result = packet_send_buffer;
+                TRACE("qXfer read result = %d (cached)\n", result);
+            }
+            else
+            {
+                reply_buffer_empty(&gdbctx->qxfer_buffer);
 
-            result = (*qxfer_handlers[i].handler)(gdbctx);
-            TRACE("qXfer read result = %d\n", result);
+                gdbctx->qxfer_object_idx = i;
+                strcpy(gdbctx->qxfer_object_annex, annex);
 
+                result = (*qxfer_handlers[i].handler)(gdbctx);
+                TRACE("qXfer read result = %d\n", result);
+            }
+
+            more = FALSE;
             if ((result & ~packet_last_f) == packet_send_buffer)
             {
                 packet_reply_xfer(gdbctx,
                                   gdbctx->qxfer_buffer.base,
                                   gdbctx->qxfer_buffer.len,
-                                  off, len);
+                                  off, len, &more);
                 result = (result & packet_last_f) | packet_done;
             }
 
-            gdbctx->qxfer_object_idx = -1;
-            gdbctx->qxfer_object_annex[0] = '\0';
-            reply_buffer_empty(&gdbctx->qxfer_buffer);
+            if (!more)
+            {
+                gdbctx->qxfer_object_idx = -1;
+                gdbctx->qxfer_object_annex[0] = '\0';
+                reply_buffer_empty(&gdbctx->qxfer_buffer);
+            }
 
             return result;
         }
-- 
2.31.1




More information about the wine-devel mailing list