Eric Pouech : winedbg: Store the CONTEXT in each stack frame to enable register access in the non topmost frames .
Alexandre Julliard
julliard at winehq.org
Wed Mar 31 10:04:49 CDT 2010
Module: wine
Branch: master
Commit: d29c6ead9280a174fa07ec7d5cd07293c3f7832d
URL: http://source.winehq.org/git/wine.git/?a=commit;h=d29c6ead9280a174fa07ec7d5cd07293c3f7832d
Author: Eric Pouech <eric.pouech at orange.fr>
Date: Tue Mar 30 21:37:01 2010 +0200
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 373600a..9d9c1b2 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 2b17dab..76a103a 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, "<register %s not in topmost frame>", div->name);
- return FALSE;
- }
+ if (buffer) snprintf(buffer, len, "<register %s not accessible in this frame>", 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 40e6dae..f5769a8 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 cbcc297..c612615 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 7826b78..a4a1af7 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);
More information about the wine-cvs
mailing list