This doesn't compile anymore, let's get rid of it instead or pretending it can still be useful.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- programs/winedbg/gdbproxy.c | 38 ------------------------------------- 1 file changed, 38 deletions(-)
diff --git a/programs/winedbg/gdbproxy.c b/programs/winedbg/gdbproxy.c index 02522ea31955..059564d8663c 100644 --- a/programs/winedbg/gdbproxy.c +++ b/programs/winedbg/gdbproxy.c @@ -850,14 +850,6 @@ static enum packet_return packet_reply_status(struct gdb_context* gdbctx) } }
-#if 0 -static enum packet_return packet_extended(struct gdb_context* gdbctx) -{ - gdbctx->extended = 1; - return packet_ok; -} -#endif - static enum packet_return packet_last_signal(struct gdb_context* gdbctx) { assert(gdbctx->in_packet_len == 0); @@ -1150,10 +1142,6 @@ static enum packet_return packet_write_registers(struct gdb_context* gdbctx) static enum packet_return packet_kill(struct gdb_context* gdbctx) { detach_debuggee(gdbctx, TRUE); -#if 0 - if (!gdbctx->extended) - /* dunno whether GDB cares or not */ -#endif return packet_ok | packet_last_f; }
@@ -1674,29 +1662,6 @@ static enum packet_return packet_step(struct gdb_context* gdbctx) 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); - if (sig != gdbctx->last_sig) - return packet_error; - resume_debuggee(gdbctx, DBG_EXCEPTION_NOT_HANDLED); - wait_for_debuggee(gdbctx); - return packet_reply_status(gdbctx); -} -#endif - static enum packet_return packet_thread_alive(struct gdb_context* gdbctx) { char* end; @@ -1723,7 +1688,6 @@ struct packet_entry
static struct packet_entry packet_entries[] = { - /*{'!', packet_extended}, */ {'?', packet_last_signal}, {'c', packet_continue}, {'C', packet_continue_signal}, @@ -1738,9 +1702,7 @@ static struct packet_entry packet_entries[] = {'P', packet_write_register}, {'q', packet_query}, {'Q', packet_set}, - /* {'R', packet,restart}, only in extended mode ! */ {'s', packet_step}, - /*{'S', packet_step_signal}, hard(er) to implement */ {'T', packet_thread_alive}, {'v', packet_verbose}, };
This was using some conditional context read and dbg_curr_thread checks, we can just read the context of the selected thread and write it back as needed.
Also, packet_reply_register_hex_to was using gdbctx->context, which is not always the context we want to read.
We still need to keep changes in sync with gdbctx->context as it may be still be used for step / continue, but step / continue doesn't work well and we will rewrite it later.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
v2: Same as before, with better precondition checks.
programs/winedbg/gdbproxy.c | 145 ++++++++++++++++++++---------------- 1 file changed, 81 insertions(+), 64 deletions(-)
diff --git a/programs/winedbg/gdbproxy.c b/programs/winedbg/gdbproxy.c index 059564d8663c..0c9872d93197 100644 --- a/programs/winedbg/gdbproxy.c +++ b/programs/winedbg/gdbproxy.c @@ -786,16 +786,16 @@ static enum packet_return packet_reply_error(struct gdb_context* gdbctx, int err return packet_done; }
-static inline void packet_reply_register_hex_to(struct gdb_context* gdbctx, unsigned idx) +static inline void packet_reply_register_hex_to(struct gdb_context* gdbctx, dbg_ctx_t* ctx, unsigned idx) { const struct gdb_register *cpu_register_map = gdbctx->process->be_cpu->gdb_register_map;
if (cpu_register_map[idx].gdb_length == cpu_register_map[idx].ctx_length) - packet_reply_hex_to(gdbctx, cpu_register_ptr(gdbctx, &gdbctx->context, idx), + packet_reply_hex_to(gdbctx, cpu_register_ptr(gdbctx, ctx, idx), cpu_register_map[idx].gdb_length); else { - DWORD64 val = cpu_register(gdbctx, &gdbctx->context, idx); + DWORD64 val = cpu_register(gdbctx, ctx, idx); unsigned i;
for (i = 0; i < cpu_register_map[idx].gdb_length; i++) @@ -829,12 +829,9 @@ static enum packet_return packet_reply_status(struct gdb_context* gdbctx)
for (i = 0; i < gdbctx->process->be_cpu->gdb_num_regs; i++) { - /* FIXME: this call will also grow the buffer... - * unneeded, but not harmful - */ packet_reply_val(gdbctx, i, 1); packet_reply_add(gdbctx, ":"); - packet_reply_register_hex_to(gdbctx, i); + packet_reply_register_hex_to(gdbctx, &gdbctx->context, i); packet_reply_add(gdbctx, ";"); }
@@ -1090,20 +1087,24 @@ static enum packet_return packet_detach(struct gdb_context* gdbctx)
static enum packet_return packet_read_registers(struct gdb_context* gdbctx) { - int i; + struct dbg_thread *thread = gdbctx->other_thread ? gdbctx->other_thread : dbg_curr_thread; + struct backend_cpu *backend; dbg_ctx_t ctx; + size_t i;
assert(gdbctx->in_trap);
- if (dbg_curr_thread != gdbctx->other_thread && gdbctx->other_thread) - { - if (!fetch_context(gdbctx, gdbctx->other_thread->handle, &ctx)) - return packet_error; - } + if (!thread) return packet_error; + if (!thread->process) return packet_error; + if (!(backend = thread->process->be_cpu)) return packet_error; + + if (!backend->get_context(thread->handle, &ctx)) + return packet_error; + if (thread == dbg_curr_thread) ctx = gdbctx->context;
packet_reply_open(gdbctx); - for (i = 0; i < gdbctx->process->be_cpu->gdb_num_regs; i++) - packet_reply_register_hex_to(gdbctx, i); + for (i = 0; i < backend->gdb_num_regs; i++) + packet_reply_register_hex_to(gdbctx, &ctx, i);
packet_reply_close(gdbctx); return packet_done; @@ -1111,31 +1112,36 @@ static enum packet_return packet_read_registers(struct gdb_context* gdbctx)
static enum packet_return packet_write_registers(struct gdb_context* gdbctx) { - const size_t cpu_num_regs = gdbctx->process->be_cpu->gdb_num_regs; - unsigned i; + struct dbg_thread *thread = gdbctx->other_thread ? gdbctx->other_thread : dbg_curr_thread; + struct backend_cpu *backend; dbg_ctx_t ctx; - dbg_ctx_t *pctx = &gdbctx->context; - const char* ptr; + const char *ptr; + size_t i;
assert(gdbctx->in_trap); - if (dbg_curr_thread != gdbctx->other_thread && gdbctx->other_thread) - { - if (!fetch_context(gdbctx, gdbctx->other_thread->handle, pctx = &ctx)) - return packet_error; - } - if (gdbctx->in_packet_len < cpu_num_regs * 2) return packet_error; + + if (!thread) return packet_error; + if (!thread->process) return packet_error; + if (!(backend = thread->process->be_cpu)) return packet_error; + + if (!backend->get_context(thread->handle, &ctx)) + return packet_error; + if (thread == dbg_curr_thread) ctx = gdbctx->context; + + if (gdbctx->in_packet_len < backend->gdb_num_regs * 2) + return packet_error;
ptr = gdbctx->in_packet; - for (i = 0; i < cpu_num_regs; i++) - cpu_register_hex_from(gdbctx, pctx, i, &ptr); + for (i = 0; i < backend->gdb_num_regs; i++) + cpu_register_hex_from(gdbctx, &ctx, i, &ptr);
- if (pctx != &gdbctx->context && - !gdbctx->process->be_cpu->set_context(gdbctx->other_thread->handle, pctx)) + if (!backend->set_context(thread->handle, &ctx)) { - ERR("Failed to set context for tid %04x, error %u\n", - gdbctx->other_thread->tid, GetLastError()); + ERR("Failed to set context for tid %04x, error %u\n", thread->tid, GetLastError()); return packet_error; } + + if (thread == dbg_curr_thread) gdbctx->context = ctx; return packet_ok; }
@@ -1249,69 +1255,80 @@ static enum packet_return packet_write_memory(struct gdb_context* gdbctx)
static enum packet_return packet_read_register(struct gdb_context* gdbctx) { - unsigned reg; + struct dbg_thread *thread = gdbctx->other_thread ? gdbctx->other_thread : dbg_curr_thread; + struct backend_cpu *backend; dbg_ctx_t ctx; - dbg_ctx_t *pctx = &gdbctx->context; + size_t reg;
assert(gdbctx->in_trap); - reg = hex_to_int(gdbctx->in_packet, gdbctx->in_packet_len); - if (reg >= gdbctx->process->be_cpu->gdb_num_regs) - { - WARN("Unhandled register %u\n", reg); + + if (!thread) return packet_error; + if (!thread->process) return packet_error; + if (!(backend = thread->process->be_cpu)) return packet_error; + + if (!backend->get_context(thread->handle, &ctx)) return packet_error; - } - if (dbg_curr_thread != gdbctx->other_thread && gdbctx->other_thread) + if (thread == dbg_curr_thread) ctx = gdbctx->context; + + if (sscanf(gdbctx->in_packet, "%zx", ®) != 1) + return packet_error; + if (reg >= backend->gdb_num_regs) { - if (!fetch_context(gdbctx, gdbctx->other_thread->handle, pctx = &ctx)) - return packet_error; + WARN("Unhandled register %zu\n", reg); + return packet_error; }
- TRACE("%u => %s\n", reg, wine_dbgstr_longlong(cpu_register(gdbctx, pctx, reg))); + TRACE("%zu => %s\n", reg, wine_dbgstr_longlong(cpu_register(gdbctx, &ctx, reg)));
packet_reply_open(gdbctx); - packet_reply_register_hex_to(gdbctx, reg); + packet_reply_register_hex_to(gdbctx, &ctx, reg); packet_reply_close(gdbctx); return packet_done; }
static enum packet_return packet_write_register(struct gdb_context* gdbctx) { - unsigned reg; - char* ptr; + struct dbg_thread *thread = gdbctx->other_thread ? gdbctx->other_thread : dbg_curr_thread; + struct backend_cpu *backend; dbg_ctx_t ctx; - dbg_ctx_t *pctx = &gdbctx->context; + size_t reg; + char *ptr;
assert(gdbctx->in_trap);
- reg = strtoul(gdbctx->in_packet, &ptr, 16); - if (ptr == NULL || reg >= gdbctx->process->be_cpu->gdb_num_regs || *ptr++ != '=') + if (!thread) return packet_error; + if (!thread->process) return packet_error; + if (!(backend = thread->process->be_cpu)) return packet_error; + + if (!backend->get_context(thread->handle, &ctx)) + return packet_error; + if (thread == dbg_curr_thread) ctx = gdbctx->context; + + if (!(ptr = strchr(gdbctx->in_packet, '='))) + return packet_error; + *ptr++ = '\0'; + + if (sscanf(gdbctx->in_packet, "%zx", ®) != 1) + return packet_error; + if (reg >= backend->gdb_num_regs) { - WARN("Unhandled register %s\n", - debugstr_an(gdbctx->in_packet, gdbctx->in_packet_len)); /* FIXME: if just the reg is above cpu_num_regs, don't tell gdb * it wouldn't matter too much, and it fakes our support for all regs */ - return (ptr == NULL) ? packet_error : packet_ok; + WARN("Unhandled register %zu\n", reg); + return packet_ok; }
- TRACE("%u <= %s\n", reg, - debugstr_an(ptr, (int)(gdbctx->in_packet_len - (ptr - gdbctx->in_packet)))); - - if (dbg_curr_thread != gdbctx->other_thread && gdbctx->other_thread) - { - if (!fetch_context(gdbctx, gdbctx->other_thread->handle, pctx = &ctx)) - return packet_error; - } + TRACE("%zu <= %s\n", reg, debugstr_an(ptr, (int)(gdbctx->in_packet_len - (ptr - gdbctx->in_packet))));
- cpu_register_hex_from(gdbctx, pctx, reg, (const char**)&ptr); - if (pctx != &gdbctx->context && - !gdbctx->process->be_cpu->set_context(gdbctx->other_thread->handle, pctx)) + cpu_register_hex_from(gdbctx, &ctx, reg, (const char**)&ptr); + if (!backend->set_context(thread->handle, &ctx)) { - ERR("Failed to set context for tid %04x, error %u\n", - gdbctx->other_thread->tid, GetLastError()); + ERR("Failed to set context for tid %04x, error %u\n", thread->tid, GetLastError()); return packet_error; }
+ if (thread == dbg_curr_thread) gdbctx->context = ctx; return packet_ok; }
This is still some cleanup, and does not fix much wrt step / continue, but it introduces dbg_thread_set_single_step that is going to be useful for individual thread control and let us remove all remaining uses of gdbctx->context.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
v2: Same as before, with better precondition checks.
programs/winedbg/gdbproxy.c | 71 +++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 35 deletions(-)
diff --git a/programs/winedbg/gdbproxy.c b/programs/winedbg/gdbproxy.c index 0c9872d93197..f20c8d2ea9ae 100644 --- a/programs/winedbg/gdbproxy.c +++ b/programs/winedbg/gdbproxy.c @@ -89,7 +89,6 @@ struct gdb_context /* current Win32 trap env */ unsigned last_sig; BOOL in_trap; - dbg_ctx_t context; /* Win32 information */ struct dbg_process* process; /* Unix environment */ @@ -271,14 +270,23 @@ static inline void cpu_register_hex_from(struct gdb_context *gdbctx, * =============================================== * */
-static BOOL fetch_context(struct gdb_context *gdbctx, HANDLE h, dbg_ctx_t *ctx) +static void dbg_thread_set_single_step(struct dbg_thread *thread, BOOL enable) { - if (!gdbctx->process->be_cpu->get_context(h, ctx)) + struct backend_cpu *backend; + dbg_ctx_t ctx; + + if (!thread) return; + if (!thread->process) return; + if (!(backend = thread->process->be_cpu)) return; + + if (!backend->get_context(thread->handle, &ctx)) { - ERR("Failed to get context, error %u\n", GetLastError()); - return FALSE; + ERR("get_context failed for thread %04x:%04x\n", thread->process->pid, thread->tid); + return; } - return TRUE; + backend->single_step(&ctx, enable); + if (!backend->set_context(thread->handle, &ctx)) + ERR("set_context failed for thread %04x:%04x\n", thread->process->pid, thread->tid); }
static BOOL handle_exception(struct gdb_context* gdbctx, EXCEPTION_DEBUG_INFO* exc) @@ -438,10 +446,7 @@ static void handle_debug_event(struct gdb_context* gdbctx, DEBUG_EVENT* de) TRACE("%08x:%08x: exception code=0x%08x\n", de->dwProcessId, de->dwThreadId, de->u.Exception.ExceptionRecord.ExceptionCode);
- if (fetch_context(gdbctx, dbg_curr_thread->handle, &gdbctx->context)) - { - gdbctx->in_trap = handle_exception(gdbctx, &de->u.Exception); - } + gdbctx->in_trap = handle_exception(gdbctx, &de->u.Exception); break;
case CREATE_THREAD_DEBUG_EVENT: @@ -499,9 +504,6 @@ 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()); @@ -518,9 +520,6 @@ static void resume_debuggee_thread(struct gdb_context* gdbctx, DWORD cont, unsig { if(dbg_curr_thread->tid == threadid){ /* 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()); @@ -594,7 +593,7 @@ static void wait_for_debuggee(struct gdb_context* gdbctx) static void detach_debuggee(struct gdb_context* gdbctx, BOOL kill) { assert(gdbctx->process->be_cpu); - gdbctx->process->be_cpu->single_step(&gdbctx->context, FALSE); + if (dbg_curr_thread) dbg_thread_set_single_step(dbg_curr_thread, FALSE); resume_debuggee(gdbctx, DBG_CONTINUE); if (!kill) DebugActiveProcessStop(gdbctx->process->pid); @@ -814,10 +813,19 @@ static inline void packet_reply_register_hex_to(struct gdb_context* gdbctx, dbg_
static enum packet_return packet_reply_status(struct gdb_context* gdbctx) { - if (gdbctx->process != NULL) + struct dbg_process *process = gdbctx->process; + struct backend_cpu *backend; + dbg_ctx_t ctx; + size_t i; + + if (process != NULL) { unsigned char sig; - unsigned i; + + if (!(backend = process->be_cpu)) return packet_error; + + if (!backend->get_context(dbg_curr_thread->handle, &ctx)) + return packet_error;
packet_reply_open(gdbctx); packet_reply_add(gdbctx, "T"); @@ -827,11 +835,11 @@ static enum packet_return packet_reply_status(struct gdb_context* gdbctx) packet_reply_val(gdbctx, dbg_curr_thread->tid, 4); packet_reply_add(gdbctx, ";");
- for (i = 0; i < gdbctx->process->be_cpu->gdb_num_regs; i++) + for (i = 0; i < backend->gdb_num_regs; i++) { packet_reply_val(gdbctx, i, 1); packet_reply_add(gdbctx, ":"); - packet_reply_register_hex_to(gdbctx, &gdbctx->context, i); + packet_reply_register_hex_to(gdbctx, &ctx, i); packet_reply_add(gdbctx, ";"); }
@@ -978,13 +986,13 @@ static enum packet_return packet_verbose_cont(struct gdb_context* gdbctx) switch (gdbctx->in_packet[actionIndex[i] + 1]) { case 's': /* step */ - gdbctx->process->be_cpu->single_step(&gdbctx->context, TRUE); + if (dbg_curr_thread) dbg_thread_set_single_step(dbg_curr_thread, TRUE); /* fall through*/ case 'c': /* continue */ resume_debuggee_thread(gdbctx, DBG_CONTINUE, threadID); break; case 'S': /* step Sig, */ - gdbctx->process->be_cpu->single_step(&gdbctx->context, TRUE); + if (dbg_curr_thread) dbg_thread_set_single_step(dbg_curr_thread, TRUE); /* fall through */ case 'C': /* continue sig */ hex_from(&sig, gdbctx->in_packet + actionIndex[i] + 2, 1); @@ -1020,13 +1028,13 @@ static enum packet_return packet_verbose_cont(struct gdb_context* gdbctx) switch (gdbctx->in_packet[actionIndex[defaultAction] + 1]) { case 's': /* step */ - gdbctx->process->be_cpu->single_step(&gdbctx->context, TRUE); + if (dbg_curr_thread) dbg_thread_set_single_step(dbg_curr_thread, 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); + if (dbg_curr_thread) dbg_thread_set_single_step(dbg_curr_thread, TRUE); /* fall through */ case 'C': /* continue sig */ hex_from(&sig, gdbctx->in_packet + actionIndex[defaultAction] + 2, 1); @@ -1042,8 +1050,7 @@ static enum packet_return packet_verbose_cont(struct gdb_context* gdbctx) } /* if(defaultAction >=0) */
wait_for_debuggee(gdbctx); - if (gdbctx->process) - gdbctx->process->be_cpu->single_step(&gdbctx->context, FALSE); + if (gdbctx->process && dbg_curr_thread) dbg_thread_set_single_step(dbg_curr_thread, FALSE); return packet_reply_status(gdbctx); }
@@ -1100,7 +1107,6 @@ static enum packet_return packet_read_registers(struct gdb_context* gdbctx)
if (!backend->get_context(thread->handle, &ctx)) return packet_error; - if (thread == dbg_curr_thread) ctx = gdbctx->context;
packet_reply_open(gdbctx); for (i = 0; i < backend->gdb_num_regs; i++) @@ -1126,7 +1132,6 @@ static enum packet_return packet_write_registers(struct gdb_context* gdbctx)
if (!backend->get_context(thread->handle, &ctx)) return packet_error; - if (thread == dbg_curr_thread) ctx = gdbctx->context;
if (gdbctx->in_packet_len < backend->gdb_num_regs * 2) return packet_error; @@ -1141,7 +1146,6 @@ static enum packet_return packet_write_registers(struct gdb_context* gdbctx) return packet_error; }
- if (thread == dbg_curr_thread) gdbctx->context = ctx; return packet_ok; }
@@ -1268,7 +1272,6 @@ static enum packet_return packet_read_register(struct gdb_context* gdbctx)
if (!backend->get_context(thread->handle, &ctx)) return packet_error; - if (thread == dbg_curr_thread) ctx = gdbctx->context;
if (sscanf(gdbctx->in_packet, "%zx", ®) != 1) return packet_error; @@ -1302,7 +1305,6 @@ static enum packet_return packet_write_register(struct gdb_context* gdbctx)
if (!backend->get_context(thread->handle, &ctx)) return packet_error; - if (thread == dbg_curr_thread) ctx = gdbctx->context;
if (!(ptr = strchr(gdbctx->in_packet, '='))) return packet_error; @@ -1328,7 +1330,6 @@ static enum packet_return packet_write_register(struct gdb_context* gdbctx) return packet_error; }
- if (thread == dbg_curr_thread) gdbctx->context = ctx; return packet_ok; }
@@ -1672,10 +1673,10 @@ static enum packet_return packet_step(struct gdb_context* gdbctx) 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); + if (dbg_curr_thread) dbg_thread_set_single_step(dbg_curr_thread, TRUE); resume_debuggee(gdbctx, DBG_CONTINUE); wait_for_debuggee(gdbctx); - gdbctx->process->be_cpu->single_step(&gdbctx->context, FALSE); + if (dbg_curr_thread) dbg_thread_set_single_step(dbg_curr_thread, FALSE); return packet_reply_status(gdbctx); }
Looking up the thread makes us loose track of any/all (0/-1) tids, we need that for correct continue/step implementation.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- programs/winedbg/gdbproxy.c | 76 ++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 35 deletions(-)
diff --git a/programs/winedbg/gdbproxy.c b/programs/winedbg/gdbproxy.c index f20c8d2ea9ae..a2a6df91f336 100644 --- a/programs/winedbg/gdbproxy.c +++ b/programs/winedbg/gdbproxy.c @@ -84,8 +84,8 @@ struct gdb_context int out_len; int out_curr_packet; /* generic GDB thread information */ - struct dbg_thread* exec_thread; /* thread used in step & continue */ - struct dbg_thread* other_thread; /* thread to be used in any other operation */ + int exec_tid; /* tid used in step & continue */ + int other_tid; /* tid to be used in any other operation */ /* current Win32 trap env */ unsigned last_sig; BOOL in_trap; @@ -270,6 +270,23 @@ static inline void cpu_register_hex_from(struct gdb_context *gdbctx, * =============================================== * */
+static struct dbg_thread* dbg_thread_from_tid(struct gdb_context* gdbctx, int tid) +{ + struct dbg_process *process = gdbctx->process; + struct dbg_thread *thread; + + if (!process) return NULL; + + if (tid == 0) return dbg_curr_thread; + LIST_FOR_EACH_ENTRY(thread, &process->threads, struct dbg_thread, entry) + { + if (tid > 0 && thread->tid != tid) continue; + return thread; + } + + return dbg_curr_thread; +} + static void dbg_thread_set_single_step(struct dbg_thread *thread, BOOL enable) { struct backend_cpu *backend; @@ -384,6 +401,8 @@ static void handle_debug_event(struct gdb_context* gdbctx, DEBUG_EVENT* de) } u;
dbg_curr_thread = dbg_get_thread(gdbctx->process, de->dwThreadId); + gdbctx->exec_tid = de->dwThreadId; + gdbctx->other_tid = de->dwThreadId;
switch (de->dwDebugEventCode) { @@ -464,8 +483,6 @@ static void handle_debug_event(struct gdb_context* gdbctx, DEBUG_EVENT* de) de->dwProcessId, de->dwThreadId, de->u.ExitThread.dwExitCode);
assert(dbg_curr_thread); - if (dbg_curr_thread == gdbctx->exec_thread) gdbctx->exec_thread = NULL; - if (dbg_curr_thread == gdbctx->other_thread) gdbctx->other_thread = NULL; dbg_del_thread(dbg_curr_thread); break;
@@ -865,9 +882,9 @@ 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) + if (gdbctx->exec_tid > 0 && dbg_curr_thread->tid != gdbctx->exec_tid) FIXME("Can't continue thread %04x while on thread %04x\n", - gdbctx->exec_thread->tid, dbg_curr_thread->tid); + gdbctx->exec_tid, dbg_curr_thread->tid); resume_debuggee(gdbctx, DBG_CONTINUE); wait_for_debuggee(gdbctx); return packet_reply_status(gdbctx); @@ -962,9 +979,9 @@ static enum packet_return packet_verbose_cont(struct gdb_context* gdbctx) /* 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) + if (gdbctx->exec_tid > 0 && dbg_curr_thread->tid != gdbctx->exec_tid) FIXME("Can't continue thread %04x while on thread %04x\n", - gdbctx->exec_thread->tid, dbg_curr_thread->tid); + gdbctx->exec_tid, dbg_curr_thread->tid);
/* deal with the threaded stuff first */ for (i = 0; i < actions ; i++) @@ -1073,9 +1090,9 @@ static enum packet_return packet_continue_signal(struct gdb_context* gdbctx)
/* FIXME: add support for address in packet */ assert(gdbctx->in_packet_len == 2); - if (dbg_curr_thread != gdbctx->exec_thread && gdbctx->exec_thread) + if (gdbctx->exec_tid > 0 && dbg_curr_thread->tid != gdbctx->exec_tid) FIXME("Can't continue thread %04x while on thread %04x\n", - gdbctx->exec_thread->tid, dbg_curr_thread->tid); + gdbctx->exec_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); @@ -1094,7 +1111,7 @@ static enum packet_return packet_detach(struct gdb_context* gdbctx)
static enum packet_return packet_read_registers(struct gdb_context* gdbctx) { - struct dbg_thread *thread = gdbctx->other_thread ? gdbctx->other_thread : dbg_curr_thread; + struct dbg_thread *thread = dbg_thread_from_tid(gdbctx, gdbctx->other_tid); struct backend_cpu *backend; dbg_ctx_t ctx; size_t i; @@ -1118,7 +1135,7 @@ static enum packet_return packet_read_registers(struct gdb_context* gdbctx)
static enum packet_return packet_write_registers(struct gdb_context* gdbctx) { - struct dbg_thread *thread = gdbctx->other_thread ? gdbctx->other_thread : dbg_curr_thread; + struct dbg_thread *thread = dbg_thread_from_tid(gdbctx, gdbctx->other_tid); struct backend_cpu *backend; dbg_ctx_t ctx; const char *ptr; @@ -1157,28 +1174,16 @@ static enum packet_return packet_kill(struct gdb_context* gdbctx)
static enum packet_return packet_thread(struct gdb_context* gdbctx) { - char* end; - unsigned thread; - switch (gdbctx->in_packet[0]) { case 'c': + if (sscanf(gdbctx->in_packet, "c%x", &gdbctx->exec_tid) == 1) + return packet_ok; + return packet_error; case 'g': - if (gdbctx->in_packet[1] == '-') - thread = -strtol(gdbctx->in_packet + 2, &end, 16); - else - thread = strtol(gdbctx->in_packet + 1, &end, 16); - if (end == NULL || end > gdbctx->in_packet + gdbctx->in_packet_len) - { - ERR("Failed to parse %s\n", - debugstr_an(gdbctx->in_packet, gdbctx->in_packet_len)); - return packet_error; - } - if (gdbctx->in_packet[0] == 'c') - gdbctx->exec_thread = dbg_get_thread(gdbctx->process, thread); - else - gdbctx->other_thread = dbg_get_thread(gdbctx->process, thread); - return packet_ok; + if (sscanf(gdbctx->in_packet, "g%x", &gdbctx->other_tid) == 1) + return packet_ok; + return packet_error; default: FIXME("Unknown thread sub-command %c\n", gdbctx->in_packet[0]); return packet_error; @@ -1259,7 +1264,7 @@ static enum packet_return packet_write_memory(struct gdb_context* gdbctx)
static enum packet_return packet_read_register(struct gdb_context* gdbctx) { - struct dbg_thread *thread = gdbctx->other_thread ? gdbctx->other_thread : dbg_curr_thread; + struct dbg_thread *thread = dbg_thread_from_tid(gdbctx, gdbctx->other_tid); struct backend_cpu *backend; dbg_ctx_t ctx; size_t reg; @@ -1291,7 +1296,7 @@ static enum packet_return packet_read_register(struct gdb_context* gdbctx)
static enum packet_return packet_write_register(struct gdb_context* gdbctx) { - struct dbg_thread *thread = gdbctx->other_thread ? gdbctx->other_thread : dbg_curr_thread; + struct dbg_thread *thread = dbg_thread_from_tid(gdbctx, gdbctx->other_tid); struct backend_cpu *backend; dbg_ctx_t ctx; size_t reg; @@ -1670,9 +1675,9 @@ 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) + if (gdbctx->exec_tid > 0 && dbg_curr_thread->tid != gdbctx->exec_tid) FIXME("Can't single-step thread %04x while on thread %04x\n", - gdbctx->exec_thread->tid, dbg_curr_thread->tid); + gdbctx->exec_tid, dbg_curr_thread->tid); if (dbg_curr_thread) dbg_thread_set_single_step(dbg_curr_thread, TRUE); resume_debuggee(gdbctx, DBG_CONTINUE); wait_for_debuggee(gdbctx); @@ -1976,7 +1981,8 @@ static BOOL gdb_init_context(struct gdb_context* gdbctx, unsigned flags, unsigne gdbctx->out_len = 0; gdbctx->out_curr_packet = -1;
- gdbctx->exec_thread = gdbctx->other_thread = NULL; + gdbctx->exec_tid = -1; + gdbctx->other_tid = -1; gdbctx->last_sig = 0; gdbctx->in_trap = FALSE; gdbctx->process = NULL;
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- programs/winedbg/gdbproxy.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-)
diff --git a/programs/winedbg/gdbproxy.c b/programs/winedbg/gdbproxy.c index a2a6df91f336..078a140a611d 100644 --- a/programs/winedbg/gdbproxy.c +++ b/programs/winedbg/gdbproxy.c @@ -87,6 +87,7 @@ struct gdb_context int exec_tid; /* tid used in step & continue */ int other_tid; /* tid to be used in any other operation */ /* current Win32 trap env */ + DEBUG_EVENT de; unsigned last_sig; BOOL in_trap; /* Win32 information */ @@ -393,8 +394,10 @@ static BOOL handle_exception(struct gdb_context* gdbctx, EXCEPTION_DEBUG_INFO* e return ret; }
-static void handle_debug_event(struct gdb_context* gdbctx, DEBUG_EVENT* de) +static void handle_debug_event(struct gdb_context* gdbctx) { + DEBUG_EVENT *de = &gdbctx->de; + union { char bufferA[256]; WCHAR buffer[256]; @@ -575,12 +578,10 @@ static BOOL check_for_interrupt(struct gdb_context* gdbctx)
static void wait_for_debuggee(struct gdb_context* gdbctx) { - DEBUG_EVENT de; - gdbctx->in_trap = FALSE; for (;;) { - if (!WaitForDebugEvent(&de, 10)) + if (!WaitForDebugEvent(&gdbctx->de, 10)) { if (GetLastError() == ERROR_SEM_TIMEOUT) { @@ -589,7 +590,7 @@ static void wait_for_debuggee(struct gdb_context* gdbctx) ERR("Failed to break into debuggee\n"); break; } - WaitForDebugEvent(&de, INFINITE); + WaitForDebugEvent(&gdbctx->de, INFINITE); } else { continue; } @@ -597,13 +598,13 @@ static void wait_for_debuggee(struct gdb_context* gdbctx) break; } } - handle_debug_event(gdbctx, &de); + handle_debug_event(gdbctx); assert(!gdbctx->process || gdbctx->process->pid == 0 || - de.dwProcessId == gdbctx->process->pid); - assert(!dbg_curr_thread || de.dwThreadId == dbg_curr_thread->tid); + gdbctx->de.dwProcessId == gdbctx->process->pid); + assert(!dbg_curr_thread || gdbctx->de.dwThreadId == dbg_curr_thread->tid); if (gdbctx->in_trap) break; - ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_CONTINUE); + ContinueDebugEvent(gdbctx->de.dwProcessId, gdbctx->de.dwThreadId, DBG_CONTINUE); } }
@@ -1880,7 +1881,7 @@ static BOOL gdb_exec(const char* wine_path, unsigned port, unsigned flags) return TRUE; }
-static BOOL gdb_startup(struct gdb_context* gdbctx, DEBUG_EVENT* de, unsigned flags, unsigned port) +static BOOL gdb_startup(struct gdb_context* gdbctx, unsigned flags, unsigned port) { int sock; struct sockaddr_in s_addrs = {0}; @@ -1906,7 +1907,7 @@ static BOOL gdb_startup(struct gdb_context* gdbctx, DEBUG_EVENT* de, unsigned fl goto cleanup;
/* step 2: do the process internal creation */ - handle_debug_event(gdbctx, de); + handle_debug_event(gdbctx);
/* step3: get the wine loader name */ if (!dbg_get_debuggee_info(gdbctx->process->handle, &imh_mod)) @@ -1969,7 +1970,6 @@ cleanup:
static BOOL gdb_init_context(struct gdb_context* gdbctx, unsigned flags, unsigned port) { - DEBUG_EVENT de; int i;
gdbctx->sock = -1; @@ -1991,23 +1991,23 @@ static BOOL gdb_init_context(struct gdb_context* gdbctx, unsigned flags, unsigne gdbctx->wine_segs[i] = 0;
/* wait for first trap */ - while (WaitForDebugEvent(&de, INFINITE)) + while (WaitForDebugEvent(&gdbctx->de, INFINITE)) { - if (de.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT) + if (gdbctx->de.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT) { /* this should be the first event we get, * and the only one of this type */ - assert(gdbctx->process == NULL && de.dwProcessId == dbg_curr_pid); + assert(gdbctx->process == NULL && gdbctx->de.dwProcessId == dbg_curr_pid); /* gdbctx->dwProcessId = pid; */ - if (!gdb_startup(gdbctx, &de, flags, port)) return FALSE; + if (!gdb_startup(gdbctx, flags, port)) return FALSE; assert(!gdbctx->in_trap); } else { - handle_debug_event(gdbctx, &de); + handle_debug_event(gdbctx); if (gdbctx->in_trap) break; } - ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_CONTINUE); + ContinueDebugEvent(gdbctx->de.dwProcessId, gdbctx->de.dwThreadId, DBG_CONTINUE); } return TRUE; }
The vCont handler used some overcomplicated logic, we only need to iterate over the actions and apply them on the matching threads that didn't match yet.
Thanks to DBG_REPLY_LATER we can now continue/step any thread regardless of whether it is the one that raised the debug event. Just suspend all active threads after debug event is raised and resume them one by one, according to the gdb request. If the thread that raised the debug event should not be resumed, reply with DBG_REPLY_LATER.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- programs/winedbg/debugger.h | 1 + programs/winedbg/gdbproxy.c | 289 ++++++++++-------------------------- programs/winedbg/winedbg.c | 1 + 3 files changed, 80 insertions(+), 211 deletions(-)
diff --git a/programs/winedbg/debugger.h b/programs/winedbg/debugger.h index 40d93d669c82..ddac129bab53 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 078a140a611d..0e60bbb6457f 100644 --- a/programs/winedbg/gdbproxy.c +++ b/programs/winedbg/gdbproxy.c @@ -88,6 +88,7 @@ struct gdb_context int other_tid; /* tid to be used in any other operation */ /* current Win32 trap env */ DEBUG_EVENT de; + DWORD de_reply; unsigned last_sig; BOOL in_trap; /* Win32 information */ @@ -137,17 +138,6 @@ static inline unsigned char hex_to0(int x) return "0123456789abcdef"[x]; }
-static int hex_to_int(const char* src, size_t len) -{ - unsigned int returnval = 0; - while (len--) - { - returnval <<= 4; - returnval |= hex_from0(*src++); - } - return returnval; -} - static void hex_from(void* dst, const char* src, size_t len) { unsigned char *p = dst; @@ -397,6 +387,7 @@ static BOOL handle_exception(struct gdb_context* gdbctx, EXCEPTION_DEBUG_INFO* e static void handle_debug_event(struct gdb_context* gdbctx) { DEBUG_EVENT *de = &gdbctx->de; + struct dbg_thread *thread;
union { char bufferA[256]; @@ -406,6 +397,7 @@ static void handle_debug_event(struct gdb_context* gdbctx) dbg_curr_thread = dbg_get_thread(gdbctx->process, de->dwThreadId); gdbctx->exec_tid = de->dwThreadId; gdbctx->other_tid = de->dwThreadId; + gdbctx->de_reply = DBG_REPLY_LATER;
switch (de->dwDebugEventCode) { @@ -518,35 +510,34 @@ static void handle_debug_event(struct gdb_context* gdbctx) 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->in_trap || !gdbctx->process) return; + + LIST_FOR_EACH_ENTRY(thread, &gdbctx->process->threads, struct dbg_thread, entry) { - 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 (!thread->suspended) SuspendThread(thread->handle); + thread->suspended = TRUE; } - else - ERR("Cannot find last thread\n"); }
- -static void resume_debuggee_thread(struct gdb_context* gdbctx, DWORD cont, unsigned int threadid) +static void handle_step_or_continue(struct gdb_context* gdbctx, int tid, BOOL step, int sig) { + struct dbg_process *process = gdbctx->process; + struct dbg_thread *thread;
- if (dbg_curr_thread) + if (tid == 0) tid = dbg_curr_thread->tid; + LIST_FOR_EACH_ENTRY(thread, &process->threads, struct dbg_thread, entry) { - if(dbg_curr_thread->tid == threadid){ - /* Windows debug and GDB don't seem to work well here, windows only likes ContinueDebugEvent being used on the reporter of the event */ - 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 (tid != -1 && thread->tid != tid) continue; + if (!thread->suspended) continue; + thread->suspended = FALSE; + + if (process->pid == gdbctx->de.dwProcessId && thread->tid == gdbctx->de.dwThreadId) + gdbctx->de_reply = (sig == -1 ? DBG_CONTINUE : DBG_EXCEPTION_NOT_HANDLED); + + dbg_thread_set_single_step(thread, step); + ResumeThread(thread->handle); } - else - ERR("Cannot find last thread\n"); }
static BOOL check_for_interrupt(struct gdb_context* gdbctx) @@ -578,6 +569,9 @@ static BOOL check_for_interrupt(struct gdb_context* gdbctx)
static void wait_for_debuggee(struct gdb_context* gdbctx) { + if (gdbctx->de.dwDebugEventCode) + ContinueDebugEvent(gdbctx->de.dwProcessId, gdbctx->de.dwThreadId, gdbctx->de_reply); + gdbctx->in_trap = FALSE; for (;;) { @@ -610,9 +604,11 @@ static void wait_for_debuggee(struct gdb_context* gdbctx)
static void detach_debuggee(struct gdb_context* gdbctx, BOOL kill) { - assert(gdbctx->process->be_cpu); - if (dbg_curr_thread) dbg_thread_set_single_step(dbg_curr_thread, FALSE); - resume_debuggee(gdbctx, DBG_CONTINUE); + handle_step_or_continue(gdbctx, -1, FALSE, -1); + + if (gdbctx->de.dwDebugEventCode) + ContinueDebugEvent(gdbctx->de.dwProcessId, gdbctx->de.dwThreadId, DBG_CONTINUE); + if (!kill) DebugActiveProcessStop(gdbctx->process->pid); dbg_del_process(gdbctx->process); @@ -881,51 +877,25 @@ 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 (gdbctx->exec_tid > 0 && dbg_curr_thread->tid != gdbctx->exec_tid) - FIXME("Can't continue thread %04x while on thread %04x\n", - gdbctx->exec_tid, dbg_curr_thread->tid); - resume_debuggee(gdbctx, DBG_CONTINUE); + void *addr; + + if (sscanf(gdbctx->in_packet, "%p", &addr) == 1) + FIXME("Continue at address %p not supported\n", addr); + + handle_step_or_continue(gdbctx, gdbctx->exec_tid, FALSE, -1); + wait_for_debuggee(gdbctx); return packet_reply_status(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;
- /* 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"); @@ -934,141 +904,37 @@ 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++) + while (buf < end && (buf = memchr(buf + 1, ';', end - buf - 1))) { - if (gdbctx->in_packet[i] == ';') - { - threadIndex[actions] = 0; - actionIndex[actions++] = i; - } - else if (gdbctx->in_packet[i] == ':') - { - threadIndex[actions - 1] = i; - } - } + int tid = -1, sig = -1; + int action, n;
- /* now look up the default action */ - for (i = 0 ; i < actions; i++) - { - if (threadIndex[i] == 0) + switch ((action = buf[1])) { - if (defaultAction != -1) - { - fprintf(stderr,"Too many default actions specified\n"); + default: + return packet_error; + case 'c': + case 's': + buf += 2; + break; + case 'C': + case 'S': + if (sscanf(buf, ";%*c%2x", &sig) <= 0 || + sig != gdbctx->last_sig) return packet_error; - } - defaultAction = i; - } - } - - /* Now, I have this default action thing that needs to be applied to all non counted threads */ - - /* 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) - { - fprintf(stderr, "Wow, that's a lot of threads, change threadIDs in wine/programs/winedbg/gdbproxy.c to be higher\n"); + 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 (gdbctx->exec_tid > 0 && dbg_curr_thread->tid != gdbctx->exec_tid) - FIXME("Can't continue thread %04x while on thread %04x\n", - gdbctx->exec_tid, dbg_curr_thread->tid); - - /* deal with the threaded stuff first */ - for (i = 0; i < actions ; i++) - { - if (threadIndex[i] != 0) - { - int j, idLength = 0; - if (i < actions - 1) - { - idLength = (actionIndex[i+1] - threadIndex[i]) - 1; - } - else - { - idLength = (gdbctx->in_packet_len - threadIndex[i]) - 1; - }
- threadID = hex_to_int(gdbctx->in_packet + threadIndex[i] + 1 , idLength); - /* process the action */ - switch (gdbctx->in_packet[actionIndex[i] + 1]) - { - case 's': /* step */ - if (dbg_curr_thread) dbg_thread_set_single_step(dbg_curr_thread, TRUE); - /* fall through*/ - case 'c': /* continue */ - resume_debuggee_thread(gdbctx, DBG_CONTINUE, threadID); - break; - case 'S': /* step Sig, */ - if (dbg_curr_thread) dbg_thread_set_single_step(dbg_curr_thread, 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); - break; - } - for (j = 0 ; j < threadCount; j++) - { - if (threadIDs[j] == threadID) - { - threadIDs[j] = 0; - break; - } - } - } - } /* for i=0 ; i< actions */ + if (buf > end) + return packet_error; + if (buf < end && *buf == ':' && (n = sscanf(buf, ":%x", &tid)) <= 0) + return packet_error;
- /* 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 */ - if (dbg_curr_thread) dbg_thread_set_single_step(dbg_curr_thread, TRUE); - /* fall through */ - case 'c': /* continue */ - resume_debuggee_thread(gdbctx, DBG_CONTINUE, threadID); - break; - case 'S': - if (dbg_curr_thread) dbg_thread_set_single_step(dbg_curr_thread, 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) */ + handle_step_or_continue(gdbctx, tid, action == 's' || action == 'S', sig); + }
wait_for_debuggee(gdbctx); - if (gdbctx->process && dbg_curr_thread) dbg_thread_set_single_step(dbg_curr_thread, FALSE); return packet_reply_status(gdbctx); }
@@ -1087,19 +953,21 @@ 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, n; + + if ((n = sscanf(gdbctx->in_packet, "%x;%p", &sig, &addr)) == 2) + FIXME("Continue at address %p not supported\n", addr); + if (n < 1) return packet_error;
- /* FIXME: add support for address in packet */ - assert(gdbctx->in_packet_len == 2); - if (gdbctx->exec_tid > 0 && dbg_curr_thread->tid != gdbctx->exec_tid) - FIXME("Can't continue thread %04x while on thread %04x\n", - gdbctx->exec_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 (sig != gdbctx->last_sig) + { + ERR("Changing signals is not supported.\n"); return packet_error; - resume_debuggee(gdbctx, DBG_EXCEPTION_NOT_HANDLED); + } + + handle_step_or_continue(gdbctx, gdbctx->exec_tid, FALSE, sig); + wait_for_debuggee(gdbctx); return packet_reply_status(gdbctx); } @@ -1674,15 +1542,14 @@ 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 (gdbctx->exec_tid > 0 && dbg_curr_thread->tid != gdbctx->exec_tid) - FIXME("Can't single-step thread %04x while on thread %04x\n", - gdbctx->exec_tid, dbg_curr_thread->tid); - if (dbg_curr_thread) dbg_thread_set_single_step(dbg_curr_thread, TRUE); - resume_debuggee(gdbctx, DBG_CONTINUE); + void *addr; + + if (sscanf(gdbctx->in_packet, "%p", &addr) == 1) + FIXME("Continue at address %p not supported\n", addr); + + handle_step_or_continue(gdbctx, gdbctx->exec_tid, TRUE, -1); + wait_for_debuggee(gdbctx); - if (dbg_curr_thread) dbg_thread_set_single_step(dbg_curr_thread, FALSE); return packet_reply_status(gdbctx); }
diff --git a/programs/winedbg/winedbg.c b/programs/winedbg/winedbg.c index 5dee3b7e5ab4..19f30f04e5dd 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);
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- programs/winedbg/gdbproxy.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-)
diff --git a/programs/winedbg/gdbproxy.c b/programs/winedbg/gdbproxy.c index 0e60bbb6457f..7c57caf9d1e8 100644 --- a/programs/winedbg/gdbproxy.c +++ b/programs/winedbg/gdbproxy.c @@ -268,14 +268,14 @@ static struct dbg_thread* dbg_thread_from_tid(struct gdb_context* gdbctx, int ti
if (!process) return NULL;
- if (tid == 0) return dbg_curr_thread; + if (tid == 0) tid = gdbctx->de.dwThreadId; LIST_FOR_EACH_ENTRY(thread, &process->threads, struct dbg_thread, entry) { if (tid > 0 && thread->tid != tid) continue; return thread; }
- return dbg_curr_thread; + return NULL; }
static void dbg_thread_set_single_step(struct dbg_thread *thread, BOOL enable) @@ -357,7 +357,7 @@ static BOOL handle_exception(struct gdb_context* gdbctx, EXCEPTION_DEBUG_INFO* e SIZE_T read;
if (threadname->dwThreadID == -1) - thread = dbg_curr_thread; + thread = dbg_get_thread(gdbctx->process, gdbctx->de.dwThreadId); else thread = dbg_get_thread(gdbctx->process, threadname->dwThreadID); if (thread) @@ -394,7 +394,6 @@ static void handle_debug_event(struct gdb_context* gdbctx) WCHAR buffer[256]; } u;
- dbg_curr_thread = dbg_get_thread(gdbctx->process, de->dwThreadId); gdbctx->exec_tid = de->dwThreadId; gdbctx->other_tid = de->dwThreadId; gdbctx->de_reply = DBG_REPLY_LATER; @@ -426,14 +425,12 @@ static void handle_debug_event(struct gdb_context* gdbctx) fprintf(stderr, "%04x:%04x: create thread I @%p\n", de->dwProcessId, de->dwThreadId, de->u.CreateProcessInfo.lpStartAddress);
- assert(dbg_curr_thread == NULL); /* shouldn't be there */ dbg_add_thread(gdbctx->process, de->dwThreadId, de->u.CreateProcessInfo.hThread, de->u.CreateProcessInfo.lpThreadLocalBase); break;
case LOAD_DLL_DEBUG_EVENT: - assert(dbg_curr_thread); memory_get_string_indirect(gdbctx->process, de->u.LoadDll.lpImageName, de->u.LoadDll.fUnicode, @@ -456,7 +453,6 @@ static void handle_debug_event(struct gdb_context* gdbctx) break;
case EXCEPTION_DEBUG_EVENT: - assert(dbg_curr_thread); TRACE("%08x:%08x: exception code=0x%08x\n", de->dwProcessId, de->dwThreadId, de->u.Exception.ExceptionRecord.ExceptionCode);
@@ -476,9 +472,8 @@ static void handle_debug_event(struct gdb_context* gdbctx) case EXIT_THREAD_DEBUG_EVENT: fprintf(stderr, "%08x:%08x: exit thread (%u)\n", de->dwProcessId, de->dwThreadId, de->u.ExitThread.dwExitCode); - - assert(dbg_curr_thread); - dbg_del_thread(dbg_curr_thread); + if ((thread = dbg_get_thread(gdbctx->process, de->dwThreadId))) + dbg_del_thread(thread); break;
case EXIT_PROCESS_DEBUG_EVENT: @@ -493,7 +488,6 @@ static void handle_debug_event(struct gdb_context* gdbctx) break;
case OUTPUT_DEBUG_STRING_EVENT: - assert(dbg_curr_thread); memory_get_string(gdbctx->process, de->u.DebugString.lpDebugStringData, TRUE, de->u.DebugString.fUnicode, u.bufferA, sizeof(u.bufferA)); @@ -525,7 +519,7 @@ static void handle_step_or_continue(struct gdb_context* gdbctx, int tid, BOOL st struct dbg_process *process = gdbctx->process; struct dbg_thread *thread;
- if (tid == 0) tid = dbg_curr_thread->tid; + if (tid == 0) tid = gdbctx->de.dwThreadId; LIST_FOR_EACH_ENTRY(thread, &process->threads, struct dbg_thread, entry) { if (tid != -1 && thread->tid != tid) continue; @@ -596,7 +590,6 @@ static void wait_for_debuggee(struct gdb_context* gdbctx) assert(!gdbctx->process || gdbctx->process->pid == 0 || gdbctx->de.dwProcessId == gdbctx->process->pid); - assert(!dbg_curr_thread || gdbctx->de.dwThreadId == dbg_curr_thread->tid); if (gdbctx->in_trap) break; ContinueDebugEvent(gdbctx->de.dwProcessId, gdbctx->de.dwThreadId, DBG_CONTINUE); } @@ -828,6 +821,7 @@ static inline void packet_reply_register_hex_to(struct gdb_context* gdbctx, dbg_ static enum packet_return packet_reply_status(struct gdb_context* gdbctx) { struct dbg_process *process = gdbctx->process; + struct dbg_thread *thread; struct backend_cpu *backend; dbg_ctx_t ctx; size_t i; @@ -838,7 +832,8 @@ static enum packet_return packet_reply_status(struct gdb_context* gdbctx)
if (!(backend = process->be_cpu)) return packet_error;
- if (!backend->get_context(dbg_curr_thread->handle, &ctx)) + if (!(thread = dbg_get_thread(process, gdbctx->de.dwThreadId)) || + !backend->get_context(thread->handle, &ctx)) return packet_error;
packet_reply_open(gdbctx); @@ -846,7 +841,7 @@ static enum packet_return packet_reply_status(struct gdb_context* gdbctx) sig = gdbctx->last_sig; packet_reply_val(gdbctx, sig, 1); packet_reply_add(gdbctx, "thread:"); - packet_reply_val(gdbctx, dbg_curr_thread->tid, 4); + packet_reply_val(gdbctx, gdbctx->de.dwThreadId, 4); packet_reply_add(gdbctx, ";");
for (i = 0; i < backend->gdb_num_regs; i++)