[PATCH 13/15] winedbg: Rewrite and simplify vCont request handler.

Rémi Bernon rbernon at codeweavers.com
Mon Jan 27 06:07:16 CST 2020


There was some overcomplicated logic, we only need to iterate over the
actions and apply them on the matching threads that didn't match yet.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 programs/winedbg/debugger.h |   1 +
 programs/winedbg/gdbproxy.c | 180 ++++++++----------------------------
 programs/winedbg/winedbg.c  |   1 +
 3 files changed, 40 insertions(+), 142 deletions(-)

diff --git a/programs/winedbg/debugger.h b/programs/winedbg/debugger.h
index 40d93d669c8..ddac129bab5 100644
--- a/programs/winedbg/debugger.h
+++ b/programs/winedbg/debugger.h
@@ -207,6 +207,7 @@ struct dbg_thread
     }*                          frames;
     int                         num_frames;
     int                         curr_frame;
+    BOOL                        suspended;
 };
 
 struct dbg_delayed_bp
diff --git a/programs/winedbg/gdbproxy.c b/programs/winedbg/gdbproxy.c
index d0e0cfb3428..eb550bdfe41 100644
--- a/programs/winedbg/gdbproxy.c
+++ b/programs/winedbg/gdbproxy.c
@@ -638,12 +638,12 @@ static void resume_debuggee(struct gdb_context* gdbctx, DWORD cont)
 }
 
 
-static void resume_debuggee_thread(struct gdb_context* gdbctx, DWORD cont, unsigned int threadid)
+static void resume_debuggee_thread(struct gdb_context* gdbctx, DWORD cont, struct dbg_thread* thread)
 {
-
     if (dbg_curr_thread)
     {
-        if(dbg_curr_thread->tid  == threadid){
+        if (dbg_curr_thread->tid == thread->tid)
+        {
             /* Windows debug and GDB don't seem to work well here, windows only likes ContinueDebugEvent being used on the reporter of the event */
             if (!gdbctx->process->be_cpu->set_context(dbg_curr_thread->handle, &gdbctx->context))
                 ERR("Failed to set context for thread %04x, error %u\n",
@@ -1038,39 +1038,14 @@ static enum packet_return packet_continue(struct gdb_context* gdbctx)
 
 static enum packet_return packet_verbose_cont(struct gdb_context* gdbctx)
 {
-    int i;
-    int defaultAction = -1; /* magic non action */
-    unsigned char sig;
-    int actions =0;
-    int actionIndex[20]; /* allow for up to 20 actions */
-    int threadIndex[20];
-    int threadCount = 0;
-    unsigned int threadIDs[100]; /* TODO: Should make this dynamic */
-    unsigned int threadID = 0;
-    struct dbg_thread*  thd;
-
-    /* OK we have vCont followed by..
-    * ? for query
-    * c for packet_continue
-    * Csig for packet_continue_signal
-    * s for step
-    * Ssig  for step signal
-    * and then an optional thread ID at the end..
-    * *******************************************/
+    char *buf = gdbctx->in_packet, *end = gdbctx->in_packet + gdbctx->in_packet_len;
+    struct dbg_process *proc = gdbctx->process;
+    struct dbg_thread *thrd;
 
-    /* Query */
     if (gdbctx->in_packet[4] == '?')
     {
-        /*
-          Reply:
-          `vCont[;action]...'
-          The vCont packet is supported. Each action is a supported command in the vCont packet.
-          `'
-          The vCont packet is not supported.  (this didn't seem to be obeyed!)
-        */
         packet_reply_open(gdbctx);
         packet_reply_add(gdbctx, "vCont");
-        /* add all the supported actions to the reply (all of them for now) */
         packet_reply_add(gdbctx, ";c");
         packet_reply_add(gdbctx, ";C");
         packet_reply_add(gdbctx, ";s");
@@ -1079,138 +1054,59 @@ static enum packet_return packet_verbose_cont(struct gdb_context* gdbctx)
         return packet_done;
     }
 
-    /* go through the packet and identify where all the actions start at */
-    for (i = 4; i < gdbctx->in_packet_len - 1; i++)
-    {
-        if (gdbctx->in_packet[i] == ';')
-        {
-            threadIndex[actions] = 0;
-            actionIndex[actions++] = i;
-        }
-        else if (gdbctx->in_packet[i] == ':')
-        {
-            threadIndex[actions - 1] = i;
-        }
-    }
+    LIST_FOR_EACH_ENTRY(thrd, &proc->threads, struct dbg_thread, entry)
+        thrd->suspended = TRUE;
 
-    /* now look up the default action */
-    for (i = 0 ; i < actions; i++)
+    while (buf < end && (buf = memchr(buf + 1, ';', end - buf - 1)))
     {
-        if (threadIndex[i] == 0)
-        {
-            if (defaultAction != -1)
-            {
-                fprintf(stderr,"Too many default actions specified\n");
-                return packet_error;
-            }
-            defaultAction = i;
-        }
-    }
-
-    /* Now, I have this default action thing that needs to be applied to all non counted threads */
+        int tid = -1, sig = 0;
+        int action, n;
 
-    /* go through all the threads and stick their ids in the to be done list. */
-    LIST_FOR_EACH_ENTRY(thd, &gdbctx->process->threads, struct dbg_thread, entry)
-    {
-        threadIDs[threadCount++] = thd->tid;
-        /* check to see if we have more threads than I counted on, and tell the user what to do
-         * (they're running winedbg, so I'm sure they can fix the problem from the error message!) */
-        if (threadCount == 100)
+        switch ((action = buf[1]))
         {
-            fprintf(stderr, "Wow, that's a lot of threads, change threadIDs in wine/programs/winedbg/gdbproxy.c to be higher\n");
+        default:
+            return packet_error;
+        case 'c':
+        case 's':
+            buf += 2;
+            break;
+        case 'C':
+        case 'S':
+            if (snscanf(buf, end - buf, ";%*c%2x", &sig) <= 0 ||
+                sig != gdbctx->last_sig)
+                return packet_error;
+            buf += 4;
             break;
         }
-    }
 
-    /* Ok, now we have... actionIndex full of actions and we know what threads there are, so all
-     * that remains is to apply the actions to the threads and the default action to any threads
-     * left */
-    if (dbg_curr_thread != gdbctx->exec_thread && gdbctx->exec_thread)
-        FIXME("Can't continue thread %04x while on thread %04x\n",
-            gdbctx->exec_thread->tid, dbg_curr_thread->tid);
+        if (buf > end)
+            return packet_error;
+        if (buf < end && *buf == ':' && (n = snscanf(buf, end - buf, ":%x", &tid)) <= 0)
+            return packet_error;
 
-    /* deal with the threaded stuff first */
-    for (i = 0; i < actions ; i++)
-    {
-        if (threadIndex[i] != 0)
+        LIST_FOR_EACH_ENTRY(thrd, &proc->threads, struct dbg_thread, entry)
         {
-            int j, idLength = 0;
-            if (i < actions - 1)
-            {
-                idLength = (actionIndex[i+1] - threadIndex[i]) - 1;
-            }
-            else
-            {
-                idLength = (gdbctx->in_packet_len - threadIndex[i]) - 1;
-            }
+            if (tid != -1 && thrd->tid != tid) continue;
+            if (!thrd->suspended) continue;
+            thrd->suspended = FALSE;
 
-            threadID = hex_to_int(gdbctx->in_packet + threadIndex[i] + 1 , idLength);
-            /* process the action */
-            switch (gdbctx->in_packet[actionIndex[i] + 1])
+            switch (action)
             {
             case 's': /* step */
                 gdbctx->process->be_cpu->single_step(&gdbctx->context, TRUE);
-                /* fall through*/
+                /* fall through */
             case 'c': /* continue */
-                resume_debuggee_thread(gdbctx, DBG_CONTINUE, threadID);
+                resume_debuggee_thread(gdbctx, DBG_CONTINUE, thrd);
                 break;
-            case 'S': /* step Sig, */
+            case 'S':
                 gdbctx->process->be_cpu->single_step(&gdbctx->context, TRUE);
                 /* fall through */
             case 'C': /* continue sig */
-                hex_from(&sig, gdbctx->in_packet + actionIndex[i] + 2, 1);
-                /* cannot change signals on the fly */
-                TRACE("sigs: %u %u\n", sig, gdbctx->last_sig);
-                if (sig != gdbctx->last_sig)
-                    return packet_error;
-                resume_debuggee_thread(gdbctx, DBG_EXCEPTION_NOT_HANDLED, threadID);
+                resume_debuggee_thread(gdbctx, DBG_EXCEPTION_NOT_HANDLED, thrd);
                 break;
             }
-            for (j = 0 ; j < threadCount; j++)
-            {
-                if (threadIDs[j] == threadID)
-                {
-                    threadIDs[j] = 0;
-                    break;
-                }
-            }
-        }
-    } /* for i=0 ; i< actions */
-
-    /* now we have manage the default action */
-    if (defaultAction >= 0)
-    {
-        for (i = 0 ; i< threadCount; i++)
-        {
-            /* check to see if we've already done something to the thread*/
-            if (threadIDs[i] != 0)
-            {
-                /* if not apply the default action*/
-                threadID = threadIDs[i];
-                /* process the action (yes this is almost identical to the one above!) */
-                switch (gdbctx->in_packet[actionIndex[defaultAction] + 1])
-                {
-                case 's': /* step */
-                    gdbctx->process->be_cpu->single_step(&gdbctx->context, TRUE);
-                    /* fall through */
-                case 'c': /* continue */
-                    resume_debuggee_thread(gdbctx, DBG_CONTINUE, threadID);
-                    break;
-                case 'S':
-                     gdbctx->process->be_cpu->single_step(&gdbctx->context, TRUE);
-                     /* fall through */
-                case 'C': /* continue sig */
-                    hex_from(&sig, gdbctx->in_packet + actionIndex[defaultAction] + 2, 1);
-                    /* cannot change signals on the fly */
-                    TRACE("sigs: %u %u\n", sig, gdbctx->last_sig);
-                    if (sig != gdbctx->last_sig)
-                        return packet_error;
-                    resume_debuggee_thread(gdbctx, DBG_EXCEPTION_NOT_HANDLED, threadID);
-                    break;
-                }
-            }
         }
-    } /* if(defaultAction >=0) */
+    }
 
     wait_for_debuggee(gdbctx);
     if (gdbctx->process)
diff --git a/programs/winedbg/winedbg.c b/programs/winedbg/winedbg.c
index 5dee3b7e5ab..19f30f04e5d 100644
--- a/programs/winedbg/winedbg.c
+++ b/programs/winedbg/winedbg.c
@@ -500,6 +500,7 @@ struct dbg_thread* dbg_add_thread(struct dbg_process* p, DWORD tid,
     t->num_frames = 0;
     t->curr_frame = -1;
     t->addr_mode = AddrModeFlat;
+    t->suspended = FALSE;
 
     snprintf(t->name, sizeof(t->name), "%04x", tid);
 
-- 
2.25.0




More information about the wine-devel mailing list