dbghelp: When doing a stack backtrace on i386 with dwarf or pdb unwinders, get the PC from the right frame.
This commit is contained in:
parent
9156501084
commit
16e8816505
|
@ -87,6 +87,51 @@ static unsigned i386_get_addr(HANDLE hThread, const CONTEXT* ctx,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
#ifdef __i386__
|
||||
/* fetch_next_frame32()
|
||||
*
|
||||
* modify (at least) context.{eip, esp, ebp} using unwind information
|
||||
* either out of debug info (dwarf, pdb), or simple stack unwind
|
||||
*/
|
||||
static BOOL fetch_next_frame32(struct cpu_stack_walk* csw,
|
||||
CONTEXT* context, DWORD_PTR curr_pc)
|
||||
{
|
||||
DWORD_PTR xframe;
|
||||
struct pdb_cmd_pair cpair[4];
|
||||
DWORD val32;
|
||||
|
||||
if (dwarf2_virtual_unwind(csw, curr_pc, context, &xframe))
|
||||
{
|
||||
context->Esp = xframe;
|
||||
return TRUE;
|
||||
}
|
||||
cpair[0].name = "$ebp"; cpair[0].pvalue = &context->Ebp;
|
||||
cpair[1].name = "$esp"; cpair[1].pvalue = &context->Esp;
|
||||
cpair[2].name = "$eip"; cpair[2].pvalue = &context->Eip;
|
||||
cpair[3].name = NULL; cpair[3].pvalue = NULL;
|
||||
|
||||
if (!pdb_virtual_unwind(csw, curr_pc, context, cpair))
|
||||
{
|
||||
/* do a simple unwind using ebp
|
||||
* we assume a "regular" prologue in the function has been used
|
||||
*/
|
||||
context->Esp = context->Ebp + 2 * sizeof(DWORD);
|
||||
if (!sw_read_mem(csw, context->Ebp + sizeof(DWORD), &val32, sizeof(DWORD)))
|
||||
{
|
||||
WARN("Cannot read new frame offset %p\n",
|
||||
(void*)(DWORD_PTR)(context->Ebp + (int)sizeof(DWORD)));
|
||||
return FALSE;
|
||||
}
|
||||
context->Eip = val32;
|
||||
/* "pop up" previous EBP value */
|
||||
if (!sw_read_mem(csw, context->Ebp, &val32, sizeof(DWORD)))
|
||||
return FALSE;
|
||||
context->Ebp = val32;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
enum st_mode {stm_start, stm_32bit, stm_16bit, stm_done};
|
||||
|
||||
/* indexes in Reserved array */
|
||||
|
@ -197,7 +242,6 @@ static BOOL i386_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, CO
|
|||
goto done_err;
|
||||
}
|
||||
curr_switch = (DWORD_PTR)frame16.frame32;
|
||||
|
||||
if (!sw_read_mem(csw, curr_switch, &ch, sizeof(ch)))
|
||||
curr_switch = 0xFFFFFFFF;
|
||||
}
|
||||
|
@ -212,32 +256,6 @@ static BOOL i386_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, CO
|
|||
* we will get it in the next frame
|
||||
*/
|
||||
memset(&frame->AddrBStore, 0, sizeof(frame->AddrBStore));
|
||||
#ifdef __i386__
|
||||
if (curr_mode == stm_32bit)
|
||||
{
|
||||
DWORD_PTR xframe;
|
||||
struct pdb_cmd_pair cpair[4];
|
||||
CONTEXT newctx = *context;
|
||||
|
||||
if (dwarf2_virtual_unwind(csw, frame->AddrPC.Offset - deltapc, &newctx, &xframe))
|
||||
{
|
||||
frame->AddrReturn.Mode = AddrModeFlat;
|
||||
frame->AddrReturn.Offset = newctx.Eip;
|
||||
goto done_pep;
|
||||
}
|
||||
cpair[0].name = "$ebp"; cpair[0].pvalue = &newctx.Ebp;
|
||||
cpair[1].name = "$esp"; cpair[1].pvalue = &newctx.Esp;
|
||||
cpair[2].name = "$eip"; cpair[2].pvalue = &newctx.Eip;
|
||||
cpair[3].name = NULL; cpair[3].pvalue = NULL;
|
||||
|
||||
if (pdb_virtual_unwind(csw, frame->AddrPC.Offset - deltapc, &newctx, cpair))
|
||||
{
|
||||
frame->AddrReturn.Mode = AddrModeFlat;
|
||||
frame->AddrReturn.Offset = newctx.Eip;
|
||||
goto done_pep;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -352,9 +370,9 @@ static BOOL i386_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, CO
|
|||
}
|
||||
else
|
||||
{
|
||||
frame->AddrPC = frame->AddrReturn;
|
||||
if (curr_mode == stm_16bit)
|
||||
{
|
||||
frame->AddrPC = frame->AddrReturn;
|
||||
frame->AddrStack.Offset = frame->AddrFrame.Offset + 2 * sizeof(WORD);
|
||||
/* "pop up" previous BP value */
|
||||
if (!sw_read_mem(csw, sw_xlat_addr(csw, &frame->AddrFrame),
|
||||
|
@ -365,36 +383,17 @@ static BOOL i386_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, CO
|
|||
else
|
||||
{
|
||||
#ifdef __i386__
|
||||
DWORD_PTR xframe;
|
||||
struct pdb_cmd_pair cpair[4];
|
||||
if (!fetch_next_frame32(csw, context, sw_xlat_addr(csw, &frame->AddrPC) - deltapc))
|
||||
goto done_err;
|
||||
|
||||
if (dwarf2_virtual_unwind(csw, frame->AddrPC.Offset - deltapc, context, &xframe))
|
||||
{
|
||||
frame->AddrStack.Mode = frame->AddrFrame.Mode = frame->AddrReturn.Mode = AddrModeFlat;
|
||||
frame->AddrStack.Offset = context->Esp = xframe;
|
||||
frame->AddrFrame.Offset = context->Ebp;
|
||||
frame->AddrReturn.Offset = context->Eip;
|
||||
goto done_pep;
|
||||
}
|
||||
cpair[0].name = "$ebp"; cpair[0].pvalue = &context->Ebp;
|
||||
cpair[1].name = "$esp"; cpair[1].pvalue = &context->Esp;
|
||||
cpair[2].name = "$eip"; cpair[2].pvalue = &context->Eip;
|
||||
cpair[3].name = NULL; cpair[3].pvalue = NULL;
|
||||
|
||||
if (pdb_virtual_unwind(csw, frame->AddrPC.Offset - deltapc, context, cpair))
|
||||
{
|
||||
frame->AddrStack.Mode = frame->AddrFrame.Mode = frame->AddrReturn.Mode = AddrModeFlat;
|
||||
frame->AddrStack.Mode = frame->AddrFrame.Mode = frame->AddrPC.Mode = AddrModeFlat;
|
||||
frame->AddrStack.Offset = context->Esp;
|
||||
frame->AddrFrame.Offset = context->Ebp;
|
||||
frame->AddrReturn.Offset = context->Eip;
|
||||
goto done_pep;
|
||||
}
|
||||
if (frame->AddrReturn.Offset != context->Eip)
|
||||
FIXME("new PC=%s different from Eip=%x\n",
|
||||
wine_dbgstr_longlong(frame->AddrReturn.Offset), context->Eip);
|
||||
frame->AddrPC.Offset = context->Eip;
|
||||
#endif
|
||||
frame->AddrStack.Offset = frame->AddrFrame.Offset + 2 * sizeof(DWORD);
|
||||
/* "pop up" previous EBP value */
|
||||
if (!sw_read_mem(csw, frame->AddrFrame.Offset, &val32, sizeof(DWORD)))
|
||||
goto done_err;
|
||||
frame->AddrFrame.Offset = val32;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -441,23 +440,6 @@ static BOOL i386_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, CO
|
|||
sw_read_mem(csw, p + (2 + i) * sizeof(WORD), &val16, sizeof(val16));
|
||||
frame->Params[i] = val16;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int i;
|
||||
if (!sw_read_mem(csw, frame->AddrFrame.Offset + sizeof(DWORD), &val32, sizeof(DWORD)))
|
||||
{
|
||||
WARN("Cannot read new frame offset %p\n",
|
||||
(void*)(DWORD_PTR)(frame->AddrFrame.Offset + (int)sizeof(DWORD)));
|
||||
goto done_err;
|
||||
}
|
||||
frame->AddrReturn.Offset = val32;
|
||||
for (i = 0; i < sizeof(frame->Params) / sizeof(frame->Params[0]); i++)
|
||||
{
|
||||
sw_read_mem(csw, frame->AddrFrame.Offset + (2 + i) * sizeof(DWORD), &val32, sizeof(val32));
|
||||
frame->Params[i] = val32;
|
||||
}
|
||||
}
|
||||
#ifdef __i386__
|
||||
if (context)
|
||||
{
|
||||
|
@ -473,8 +455,25 @@ static BOOL i386_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, CO
|
|||
SET(AddrReturn, SegCs, Eip);
|
||||
#undef SET
|
||||
}
|
||||
done_pep:
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int i;
|
||||
#ifdef __i386__
|
||||
CONTEXT newctx = *context;
|
||||
|
||||
if (!fetch_next_frame32(csw, &newctx, frame->AddrPC.Offset - deltapc))
|
||||
goto done_err;
|
||||
frame->AddrReturn.Mode = AddrModeFlat;
|
||||
frame->AddrReturn.Offset = newctx.Eip;
|
||||
#endif
|
||||
for (i = 0; i < sizeof(frame->Params) / sizeof(frame->Params[0]); i++)
|
||||
{
|
||||
sw_read_mem(csw, frame->AddrFrame.Offset + (2 + i) * sizeof(DWORD), &val32, sizeof(val32));
|
||||
frame->Params[i] = val32;
|
||||
}
|
||||
}
|
||||
|
||||
frame->Far = TRUE;
|
||||
frame->Virtual = TRUE;
|
||||
|
|
|
@ -214,7 +214,7 @@ unsigned stack_fetch_frames(const CONTEXT* _ctx)
|
|||
/* as native stackwalk can modify the context passed to it, simply copy
|
||||
* it to avoid any damage
|
||||
*/
|
||||
CONTEXT ctx = *_ctx, prevctx = ctx;
|
||||
CONTEXT ctx = *_ctx;
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, dbg_curr_thread->frames);
|
||||
dbg_curr_thread->frames = NULL;
|
||||
|
@ -244,7 +244,7 @@ unsigned stack_fetch_frames(const CONTEXT* _ctx)
|
|||
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;
|
||||
dbg_curr_thread->frames[nf].context = ctx;
|
||||
/* 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...
|
||||
*/
|
||||
|
@ -252,7 +252,6 @@ unsigned stack_fetch_frames(const CONTEXT* _ctx)
|
|||
(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;
|
||||
|
|
Loading…
Reference in New Issue