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@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); }