[PATCH 14/15] winedbg: Improve continue/step packets implementation.

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


Using DBG_REPLY_LATER we can now continue/step any thread regardless
of whether it is the one that raised the debug event.

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

diff --git a/programs/winedbg/debugger.h b/programs/winedbg/debugger.h
index ddac129bab5..97218008283 100644
--- a/programs/winedbg/debugger.h
+++ b/programs/winedbg/debugger.h
@@ -208,6 +208,7 @@ struct dbg_thread
     int                         num_frames;
     int                         curr_frame;
     BOOL                        suspended;
+    DWORD                       continue_mode;
 };
 
 struct dbg_delayed_bp
diff --git a/programs/winedbg/gdbproxy.c b/programs/winedbg/gdbproxy.c
index eb550bdfe41..e53ba2b965d 100644
--- a/programs/winedbg/gdbproxy.c
+++ b/programs/winedbg/gdbproxy.c
@@ -496,13 +496,18 @@ static BOOL handle_exception(struct gdb_context* gdbctx, EXCEPTION_DEBUG_INFO* e
 
 static	void	handle_debug_event(struct gdb_context* gdbctx, DEBUG_EVENT* de)
 {
+    struct dbg_process *proc = gdbctx->process;
+    struct dbg_thread *thrd;
+
     union {
         char                bufferA[256];
         WCHAR               buffer[256];
     } u;
 
+    gdbctx->exec_thread = NULL;
     gdbctx->other_thread = NULL;
     dbg_curr_thread = dbg_get_thread(gdbctx->process, de->dwThreadId);
+    if (dbg_curr_thread) dbg_curr_thread->continue_mode = DBG_REPLY_LATER;
 
     switch (de->dwDebugEventCode)
     {
@@ -510,6 +515,8 @@ static	void	handle_debug_event(struct gdb_context* gdbctx, DEBUG_EVENT* de)
         gdbctx->process = dbg_add_process(&be_process_gdbproxy_io, de->dwProcessId,
                                           de->u.CreateProcessInfo.hProcess);
         if (!gdbctx->process) break;
+        proc = gdbctx->process;
+
         memory_get_string_indirect(gdbctx->process,
                                    de->u.CreateProcessInfo.lpImageName,
                                    de->u.CreateProcessInfo.fUnicode,
@@ -620,41 +627,14 @@ static	void	handle_debug_event(struct gdb_context* gdbctx, DEBUG_EVENT* de)
         FIXME("%08x:%08x: unknown event (%u)\n",
             de->dwProcessId, de->dwThreadId, de->dwDebugEventCode);
     }
-}
 
-static void resume_debuggee(struct gdb_context* gdbctx, DWORD cont)
-{
-    if (dbg_curr_thread)
-    {
-        if (!gdbctx->process->be_cpu->set_context(dbg_curr_thread->handle, &gdbctx->context))
-            ERR("Failed to set context for thread %04x, error %u\n",
-                dbg_curr_thread->tid, GetLastError());
-        if (!ContinueDebugEvent(gdbctx->process->pid, dbg_curr_thread->tid, cont))
-            ERR("Failed to continue thread %04x, error %u\n",
-                dbg_curr_thread->tid, GetLastError());
-    }
-    else
-        ERR("Cannot find last thread\n");
-}
+    if (!gdbctx->in_trap || !gdbctx->process) return;
 
-
-static void resume_debuggee_thread(struct gdb_context* gdbctx, DWORD cont, struct dbg_thread* thread)
-{
-    if (dbg_curr_thread)
+    LIST_FOR_EACH_ENTRY(thrd, &proc->threads, struct dbg_thread, entry)
     {
-        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",
-                    dbg_curr_thread->tid, GetLastError());
-            if (!ContinueDebugEvent(gdbctx->process->pid, dbg_curr_thread->tid, cont))
-                ERR("Failed to continue thread %04x, error %u\n",
-                    dbg_curr_thread->tid, GetLastError());
-        }
+        if (!thrd->suspended) SuspendThread(thrd->handle);
+        thrd->suspended = TRUE;
     }
-    else
-        ERR("Cannot find last thread\n");
 }
 
 static BOOL	check_for_interrupt(struct gdb_context* gdbctx)
@@ -688,6 +668,9 @@ static void    wait_for_debuggee(struct gdb_context* gdbctx)
 {
     DEBUG_EVENT         de;
 
+    if (dbg_curr_thread)
+        ContinueDebugEvent(dbg_curr_thread->process->pid, dbg_curr_thread->tid, dbg_curr_thread->continue_mode);
+
     gdbctx->in_trap = FALSE;
     for (;;)
     {
@@ -718,11 +701,47 @@ static void    wait_for_debuggee(struct gdb_context* gdbctx)
     }
 }
 
+static void thread_set_single_step(struct dbg_thread *thrd, BOOL enable)
+{
+    struct dbg_process *proc = thrd->process;
+    struct backend_cpu *be = proc->be_cpu;
+    dbg_ctx_t ctx;
+
+    if (!be->get_context(thrd->handle, &ctx))
+    {
+        ERR("get_context failed for thread %04x:%04x\n", proc->pid, thrd->tid);
+        return;
+    }
+    be->single_step(&ctx, enable);
+    if (!be->set_context(thrd->handle, &ctx))
+        ERR("set_context failed for thread %04x:%04x\n", proc->pid, thrd->tid);
+}
+
+static void handle_step_or_continue(struct gdb_context* gdbctx, int tid, BOOL step, int sig)
+{
+    struct dbg_process *proc = gdbctx->process;
+    struct dbg_thread *thrd;
+
+    if (tid == 0) tid = dbg_curr_thread->tid;
+    LIST_FOR_EACH_ENTRY(thrd, &proc->threads, struct dbg_thread, entry)
+    {
+        if (tid != -1 && thrd->tid != tid) continue;
+        if (!thrd->suspended) continue;
+        thrd->suspended = FALSE;
+        thrd->continue_mode = (sig == -1 ? DBG_CONTINUE : DBG_EXCEPTION_NOT_HANDLED);
+
+        thread_set_single_step(thrd, step);
+        ResumeThread(thrd->handle);
+    }
+}
+
 static void detach_debuggee(struct gdb_context* gdbctx, BOOL kill)
 {
-    assert(gdbctx->process->be_cpu);
-    gdbctx->process->be_cpu->single_step(&gdbctx->context, FALSE);
-    resume_debuggee(gdbctx, DBG_CONTINUE);
+    handle_step_or_continue(gdbctx, -1, FALSE, -1);
+
+    if (dbg_curr_thread)
+        ContinueDebugEvent(dbg_curr_thread->process->pid, dbg_curr_thread->tid, dbg_curr_thread->continue_mode);
+
     if (!kill)
         DebugActiveProcessStop(gdbctx->process->pid);
     dbg_del_process(gdbctx->process);
@@ -1026,12 +1045,13 @@ static enum packet_return packet_last_signal(struct gdb_context* gdbctx)
 
 static enum packet_return packet_continue(struct gdb_context* gdbctx)
 {
-    /* FIXME: add support for address in packet */
-    assert(gdbctx->in_packet_len == 0);
-    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);
-    resume_debuggee(gdbctx, DBG_CONTINUE);
+    void *addr;
+
+    if (snscanf(gdbctx->in_packet, gdbctx->in_packet_len, "%p", &addr) == 1)
+        FIXME("Continue at address %p not supported\n", addr);
+
+    handle_step_or_continue(gdbctx, gdbctx->exec_thread ? gdbctx->exec_thread->tid : -1, FALSE, -1);
+
     wait_for_debuggee(gdbctx);
     return packet_reply_status(gdbctx);
 }
@@ -1039,8 +1059,6 @@ static enum packet_return packet_continue(struct gdb_context* gdbctx)
 static enum packet_return packet_verbose_cont(struct gdb_context* gdbctx)
 {
     char *buf = gdbctx->in_packet, *end = gdbctx->in_packet + gdbctx->in_packet_len;
-    struct dbg_process *proc = gdbctx->process;
-    struct dbg_thread *thrd;
 
     if (gdbctx->in_packet[4] == '?')
     {
@@ -1054,12 +1072,9 @@ static enum packet_return packet_verbose_cont(struct gdb_context* gdbctx)
         return packet_done;
     }
 
-    LIST_FOR_EACH_ENTRY(thrd, &proc->threads, struct dbg_thread, entry)
-        thrd->suspended = TRUE;
-
     while (buf < end && (buf = memchr(buf + 1, ';', end - buf - 1)))
     {
-        int tid = -1, sig = 0;
+        int tid = -1, sig = -1;
         int action, n;
 
         switch ((action = buf[1]))
@@ -1084,33 +1099,10 @@ static enum packet_return packet_verbose_cont(struct gdb_context* gdbctx)
         if (buf < end && *buf == ':' && (n = snscanf(buf, end - buf, ":%x", &tid)) <= 0)
             return packet_error;
 
-        LIST_FOR_EACH_ENTRY(thrd, &proc->threads, struct dbg_thread, entry)
-        {
-            if (tid != -1 && thrd->tid != tid) continue;
-            if (!thrd->suspended) continue;
-            thrd->suspended = FALSE;
-
-            switch (action)
-            {
-            case 's': /* step */
-                gdbctx->process->be_cpu->single_step(&gdbctx->context, TRUE);
-                /* fall through */
-            case 'c': /* continue */
-                resume_debuggee_thread(gdbctx, DBG_CONTINUE, thrd);
-                break;
-            case 'S':
-                gdbctx->process->be_cpu->single_step(&gdbctx->context, TRUE);
-                /* fall through */
-            case 'C': /* continue sig */
-                resume_debuggee_thread(gdbctx, DBG_EXCEPTION_NOT_HANDLED, thrd);
-                break;
-            }
-        }
+        handle_step_or_continue(gdbctx, tid, action == 's' || action == 'S', sig);
     }
 
     wait_for_debuggee(gdbctx);
-    if (gdbctx->process)
-        gdbctx->process->be_cpu->single_step(&gdbctx->context, FALSE);
     return packet_reply_status(gdbctx);
 }
 
@@ -1127,19 +1119,16 @@ static enum packet_return packet_verbose(struct gdb_context* gdbctx)
 
 static enum packet_return packet_continue_signal(struct gdb_context* gdbctx)
 {
-    unsigned char sig;
+    void *addr;
+    int sig;
 
-    /* FIXME: add support for address in packet */
-    assert(gdbctx->in_packet_len == 2);
-    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);
-    hex_from(&sig, gdbctx->in_packet, 1);
-    /* cannot change signals on the fly */
-    TRACE("sigs: %u %u\n", sig, gdbctx->last_sig);
+    if (snscanf(gdbctx->in_packet, gdbctx->in_packet_len, "%x;%p", &sig, &addr) == 2)
+        FIXME("Continue at address %p not supported\n", addr);
     if (sig != gdbctx->last_sig)
         return packet_error;
-    resume_debuggee(gdbctx, DBG_EXCEPTION_NOT_HANDLED);
+
+    handle_step_or_continue(gdbctx, gdbctx->exec_thread ? gdbctx->exec_thread->tid : -1, FALSE, sig);
+
     wait_for_debuggee(gdbctx);
     return packet_reply_status(gdbctx);
 }
@@ -1801,36 +1790,30 @@ static enum packet_return packet_set(struct gdb_context* gdbctx)
 
 static enum packet_return packet_step(struct gdb_context* gdbctx)
 {
-    /* FIXME: add support for address in packet */
-    assert(gdbctx->in_packet_len == 0);
-    if (dbg_curr_thread != gdbctx->exec_thread && gdbctx->exec_thread)
-        FIXME("Can't single-step thread %04x while on thread %04x\n",
-            gdbctx->exec_thread->tid, dbg_curr_thread->tid);
-    gdbctx->process->be_cpu->single_step(&gdbctx->context, TRUE);
-    resume_debuggee(gdbctx, DBG_CONTINUE);
+    void *addr;
+
+    if (snscanf(gdbctx->in_packet, gdbctx->in_packet_len, "%p", &addr) == 1)
+        FIXME("Continue at address %p not supported\n", addr);
+
+    handle_step_or_continue(gdbctx, gdbctx->exec_thread ? gdbctx->exec_thread->tid : -1, TRUE, -1);
+
     wait_for_debuggee(gdbctx);
-    gdbctx->process->be_cpu->single_step(&gdbctx->context, FALSE);
     return packet_reply_status(gdbctx);
 }
 
 #if 0
 static enum packet_return packet_step_signal(struct gdb_context* gdbctx)
 {
-    unsigned char sig;
-
-    /* FIXME: add support for address in packet */
-    assert(gdbctx->in_packet_len == 2);
-    if (dbg_curr_thread->tid != gdbctx->exec_thread && gdbctx->exec_thread)
-        if (gdbctx->trace & GDBPXY_TRC_COMMAND_ERROR)
-            fprintf(stderr, "NIY: step/sig on %u, while last thread is %u\n",
-                    gdbctx->exec_thread, DEBUG_CurrThread->tid);
-    hex_from(&sig, gdbctx->in_packet, 1);
-    /* cannot change signals on the fly */
-    if (gdbctx->trace & GDBPXY_TRC_COMMAND)
-        fprintf(stderr, "sigs: %u %u\n", sig, gdbctx->last_sig);
+    void *addr;
+    int sig;
+
+    if (snscanf(gdbctx->in_packet, gdbctx->in_packet_len, "%x;%p", &sig, &addr) == 2)
+        FIXME("Continue at address %p not supported\n", addr);
     if (sig != gdbctx->last_sig)
         return packet_error;
-    resume_debuggee(gdbctx, DBG_EXCEPTION_NOT_HANDLED);
+
+    handle_step_or_continue(gdbctx, gdbctx->exec_thread ? gdbctx->exec_thread->tid : -1, TRUE, sig);
+
     wait_for_debuggee(gdbctx);
     return packet_reply_status(gdbctx);
 }
-- 
2.25.0




More information about the wine-devel mailing list