From d29c6ead9280a174fa07ec7d5cd07293c3f7832d Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Tue, 30 Mar 2010 21:37:01 +0200 Subject: [PATCH] winedbg: Store the CONTEXT in each stack frame to enable register access in the non topmost frames. --- programs/winedbg/debugger.h | 6 ++-- programs/winedbg/memory.c | 11 ++----- programs/winedbg/stack.c | 53 ++++++++++++++++++++++++++++----- programs/winedbg/tgt_active.c | 2 +- programs/winedbg/tgt_minidump.c | 2 +- 5 files changed, 54 insertions(+), 20 deletions(-) diff --git a/programs/winedbg/debugger.h b/programs/winedbg/debugger.h index 373600a8ef..9d9c1b27eb 100644 --- a/programs/winedbg/debugger.h +++ b/programs/winedbg/debugger.h @@ -192,6 +192,8 @@ struct dbg_thread DWORD_PTR linear_pc; DWORD_PTR linear_frame; DWORD_PTR linear_stack; + CONTEXT context; /* context we got out of stackwalk for this frame */ + BOOL is_ctx_valid; /* is the context above valid */ }* frames; int num_frames; int curr_frame; @@ -387,8 +389,8 @@ extern void stack_info(void); extern void stack_backtrace(DWORD threadID); extern BOOL stack_set_frame(int newframe); extern BOOL stack_get_current_frame(IMAGEHLP_STACK_FRAME* ihsf); -extern BOOL stack_get_register_current_frame(unsigned regno, DWORD_PTR** pval); -extern unsigned stack_fetch_frames(void); +extern BOOL stack_get_register_frame(const struct dbg_internal_var* div, DWORD_PTR** pval); +extern unsigned stack_fetch_frames(const CONTEXT* ctx); extern BOOL stack_get_current_symbol(SYMBOL_INFO* sym); /* symbol.c */ diff --git a/programs/winedbg/memory.c b/programs/winedbg/memory.c index 2b17dab42f..76a103a0c5 100644 --- a/programs/winedbg/memory.c +++ b/programs/winedbg/memory.c @@ -694,16 +694,11 @@ BOOL memory_get_register(DWORD regno, DWORD_PTR** value, char* buffer, int len) { if (div->val == regno) { - if (dbg_curr_thread->curr_frame != 0) + if (!stack_get_register_frame(div, value)) { - if (!stack_get_register_current_frame(regno, value)) - { - if (buffer) snprintf(buffer, len, "", div->name); - return FALSE; - } + if (buffer) snprintf(buffer, len, "", div->name); + return FALSE; } - else - *value = (DWORD_PTR*)((char*)&dbg_context + (DWORD_PTR)div->pval); if (buffer) lstrcpynA(buffer, div->name, len); return TRUE; diff --git a/programs/winedbg/stack.c b/programs/winedbg/stack.c index 40e6dae119..f5769a854f 100644 --- a/programs/winedbg/stack.c +++ b/programs/winedbg/stack.c @@ -119,6 +119,35 @@ BOOL stack_get_register_current_frame(unsigned regno, DWORD_PTR** pval) return TRUE; } +BOOL stack_get_register_frame(const struct dbg_internal_var* div, DWORD_PTR** pval) +{ + if (dbg_curr_thread->frames == NULL) return FALSE; + if (dbg_curr_thread->frames[dbg_curr_thread->curr_frame].is_ctx_valid) + *pval = (DWORD_PTR*)((char*)&dbg_curr_thread->frames[dbg_curr_thread->curr_frame].context + + (DWORD_PTR)div->pval); + else + { + enum be_cpu_addr kind; + + if (!be_cpu->get_register_info(div->val, &kind)) return FALSE; + + /* reuse some known registers directly out of stackwalk details */ + switch (kind) + { + case be_cpu_addr_pc: + *pval = &dbg_curr_thread->frames[dbg_curr_thread->curr_frame].linear_pc; + break; + case be_cpu_addr_stack: + *pval = &dbg_curr_thread->frames[dbg_curr_thread->curr_frame].linear_stack; + break; + case be_cpu_addr_frame: + *pval = &dbg_curr_thread->frames[dbg_curr_thread->curr_frame].linear_frame; + break; + } + } + return TRUE; +} + BOOL stack_set_frame(int newframe) { ADDRESS64 addr; @@ -163,14 +192,14 @@ static BOOL CALLBACK stack_read_mem(HANDLE hProc, DWORD64 addr, * * Do a backtrace on the current thread */ -unsigned stack_fetch_frames(void) +unsigned stack_fetch_frames(const CONTEXT* _ctx) { STACKFRAME64 sf; unsigned nf = 0; /* as native stackwalk can modify the context passed to it, simply copy * it to avoid any damage */ - CONTEXT ctx = dbg_context; + CONTEXT ctx = *_ctx, prevctx = ctx; HeapFree(GetProcessHeap(), 0, dbg_curr_thread->frames); dbg_curr_thread->frames = NULL; @@ -200,6 +229,15 @@ unsigned stack_fetch_frames(void) dbg_curr_thread->frames[nf].linear_frame = (DWORD_PTR)memory_to_linear_addr(&sf.AddrFrame); dbg_curr_thread->frames[nf].addr_stack = sf.AddrStack; dbg_curr_thread->frames[nf].linear_stack = (DWORD_PTR)memory_to_linear_addr(&sf.AddrStack); + dbg_curr_thread->frames[nf].context = prevctx; + /* FIXME: can this heuristic be improved: we declare first context always valid, and next ones + * if it has been modified by the call to StackWalk... + */ + dbg_curr_thread->frames[nf].is_ctx_valid = + (nf == 0 || + (dbg_curr_thread->frames[nf - 1].is_ctx_valid && + memcmp(&dbg_curr_thread->frames[nf - 1].context, &ctx, sizeof(ctx)))); + prevctx = ctx; nf++; /* we've probably gotten ourselves into an infinite loop so bail */ if (nf > 200) break; @@ -317,27 +355,26 @@ static void backtrace_tid(struct dbg_process* pcs, DWORD tid) dbg_printf("Unknown thread id (%04x) in process (%04x)\n", tid, pcs->pid); else { - CONTEXT saved_ctx = dbg_context; + CONTEXT context; dbg_curr_tid = dbg_curr_thread->tid; - memset(&dbg_context, 0, sizeof(dbg_context)); - dbg_context.ContextFlags = CONTEXT_FULL; + memset(&context, 0, sizeof(context)); + context.ContextFlags = CONTEXT_FULL; if (SuspendThread(dbg_curr_thread->handle) != -1) { - if (!GetThreadContext(dbg_curr_thread->handle, &dbg_context)) + if (!GetThreadContext(dbg_curr_thread->handle, &context)) { dbg_printf("Can't get context for thread %04x in current process\n", tid); } else { - stack_fetch_frames(); + stack_fetch_frames(&context); backtrace(); } ResumeThread(dbg_curr_thread->handle); } else dbg_printf("Can't suspend thread %04x in current process\n", tid); - dbg_context = saved_ctx; } dbg_curr_thread = thread; dbg_curr_tid = thread ? thread->tid : 0; diff --git a/programs/winedbg/tgt_active.c b/programs/winedbg/tgt_active.c index cbcc297c83..c61261593c 100644 --- a/programs/winedbg/tgt_active.c +++ b/programs/winedbg/tgt_active.c @@ -157,7 +157,7 @@ static unsigned dbg_exception_prolog(BOOL is_debug, BOOL first_chance, const EXC * Do a quiet backtrace so that we have an idea of what the situation * is WRT the source files. */ - stack_fetch_frames(); + stack_fetch_frames(&dbg_context); if (is_debug && !is_break && break_should_continue(&addr, rec->ExceptionCode)) return FALSE; diff --git a/programs/winedbg/tgt_minidump.c b/programs/winedbg/tgt_minidump.c index 7826b78b1e..a4a1af7430 100644 --- a/programs/winedbg/tgt_minidump.c +++ b/programs/winedbg/tgt_minidump.c @@ -376,7 +376,7 @@ static enum dbg_start minidump_do_reload(struct tgt_process_minidump_data* data) memcpy(&dbg_context, (char*)data->mapping + mes->ThreadContext.Rva, min(sizeof(dbg_context), mes->ThreadContext.DataSize)); memory_get_current_pc(&addr); - stack_fetch_frames(); + stack_fetch_frames(&dbg_context); be_cpu->print_context(dbg_curr_thread->handle, &dbg_context, 0); stack_info(); be_cpu->print_segment_info(dbg_curr_thread->handle, &dbg_context); -- 2.32.0.93.g670b81a890