[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