winedbg: Store the CONTEXT in each stack frame to enable register access in the non topmost frames.

This commit is contained in:
Eric Pouech 2010-03-30 21:37:01 +02:00 committed by Alexandre Julliard
parent 1991ff2a0c
commit d29c6ead92
5 changed files with 54 additions and 20 deletions

View File

@ -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 */

View File

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

View File

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

View File

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

View File

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