mirror of
https://github.com/reactos/wine.git
synced 2024-11-28 22:20:26 +00:00
winedbg: Store the CONTEXT in each stack frame to enable register access in the non topmost frames.
This commit is contained in:
parent
1991ff2a0c
commit
d29c6ead92
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user