- now storing frames information in thread structure
- frames are cached after each thread stops execution - reimplemented backtrace on top of this
This commit is contained in:
parent
ba2cb7c97b
commit
3e07e04764
|
@ -120,13 +120,13 @@ command:
|
|||
| tNEXTI tNUM { dbg_wait_next_exception(DBG_CONTINUE, $2, dbg_exec_step_over_insn); }
|
||||
| tFINISH { dbg_wait_next_exception(DBG_CONTINUE, 0, dbg_exec_finish); }
|
||||
| tABORT { abort(); }
|
||||
| tBACKTRACE { stack_backtrace(dbg_curr_tid, TRUE); }
|
||||
| tBACKTRACE tNUM { stack_backtrace($2, TRUE); }
|
||||
| tBACKTRACE tALL { stack_backtrace(-1, TRUE); }
|
||||
| tUP { stack_set_frame(dbg_curr_frame + 1); }
|
||||
| tUP tNUM { stack_set_frame(dbg_curr_frame + $2); }
|
||||
| tDOWN { stack_set_frame(dbg_curr_frame - 1); }
|
||||
| tDOWN tNUM { stack_set_frame(dbg_curr_frame - $2); }
|
||||
| tBACKTRACE { stack_backtrace(dbg_curr_tid); }
|
||||
| tBACKTRACE tNUM { stack_backtrace($2); }
|
||||
| tBACKTRACE tALL { stack_backtrace(-1); }
|
||||
| tUP { stack_set_frame(dbg_curr_thread->curr_frame + 1); }
|
||||
| tUP tNUM { stack_set_frame(dbg_curr_thread->curr_frame + $2); }
|
||||
| tDOWN { stack_set_frame(dbg_curr_thread->curr_frame - 1); }
|
||||
| tDOWN tNUM { stack_set_frame(dbg_curr_thread->curr_frame - $2); }
|
||||
| tFRAME tNUM { stack_set_frame($2); }
|
||||
| tSHOW tDIR { source_show_path(); }
|
||||
| tDIR pathname { source_add_path($2); }
|
||||
|
@ -276,7 +276,7 @@ maintenance_command:
|
|||
|
||||
noprocess_state:
|
||||
tNOPROCESS {} /* <CR> shall not barf anything */
|
||||
| tNOPROCESS tBACKTRACE tALL { stack_backtrace(-1, TRUE); } /* can backtrace all threads with no attached process */
|
||||
| tNOPROCESS tBACKTRACE tALL { stack_backtrace(-1); } /* can backtrace all threads with no attached process */
|
||||
| tNOPROCESS tSTRING { dbg_printf("No process loaded, cannot execute '%s'\n", $2); }
|
||||
;
|
||||
|
||||
|
|
|
@ -168,6 +168,13 @@ struct dbg_thread
|
|||
struct dbg_thread* prev;
|
||||
BOOL in_exception; /* TRUE if thread stopped with an exception */
|
||||
EXCEPTION_RECORD excpt_record; /* only valid when in_exception is TRUE */
|
||||
struct
|
||||
{
|
||||
ADDRESS addr_pc;
|
||||
ADDRESS addr_frame;
|
||||
}* frames;
|
||||
int num_frames;
|
||||
int curr_frame;
|
||||
};
|
||||
|
||||
struct dbg_delayed_bp
|
||||
|
@ -214,7 +221,6 @@ extern struct dbg_thread* dbg_curr_thread;
|
|||
extern DWORD dbg_curr_tid;
|
||||
extern CONTEXT dbg_context;
|
||||
extern BOOL dbg_interactiveP;
|
||||
extern int dbg_curr_frame;
|
||||
|
||||
struct dbg_internal_var
|
||||
{
|
||||
|
@ -339,9 +345,11 @@ extern void source_nuke_path(void);
|
|||
|
||||
/* stack.c */
|
||||
extern void stack_info(void);
|
||||
extern void stack_backtrace(DWORD threadID, BOOL noisy);
|
||||
extern int stack_set_frame(int newframe);
|
||||
extern void stack_backtrace(DWORD threadID);
|
||||
extern BOOL stack_set_frame(int newframe);
|
||||
extern BOOL stack_get_frame(SYMBOL_INFO* sym, IMAGEHLP_STACK_FRAME* ihsf);
|
||||
extern BOOL stack_get_current_frame(IMAGEHLP_STACK_FRAME* ihsf);
|
||||
extern unsigned stack_fetch_frames(void);
|
||||
|
||||
/* symbol.c */
|
||||
extern enum sym_get_lval symbol_get_lvalue(const char* name, const int lineno, struct dbg_lvalue* addr, BOOL bp_disp);
|
||||
|
|
|
@ -33,9 +33,6 @@
|
|||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
|
||||
|
||||
static int nframe;
|
||||
static IMAGEHLP_STACK_FRAME* frames = NULL;
|
||||
|
||||
/***********************************************************************
|
||||
* stack_info
|
||||
*
|
||||
|
@ -67,16 +64,41 @@ void stack_info(void)
|
|||
}
|
||||
}
|
||||
|
||||
int stack_set_frame(int newframe)
|
||||
static BOOL stack_set_frame_internal(int newframe)
|
||||
{
|
||||
if (newframe >= dbg_curr_thread->num_frames)
|
||||
newframe = dbg_curr_thread->num_frames - 1;
|
||||
if (newframe < 0)
|
||||
newframe = 0;
|
||||
|
||||
if (dbg_curr_thread->curr_frame != newframe)
|
||||
{
|
||||
IMAGEHLP_STACK_FRAME ihsf;
|
||||
|
||||
dbg_curr_thread->curr_frame = newframe;
|
||||
stack_get_current_frame(&ihsf);
|
||||
SymSetContext(dbg_curr_process->handle, &ihsf, NULL);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL stack_get_current_frame(IMAGEHLP_STACK_FRAME* ihsf)
|
||||
{
|
||||
/*
|
||||
* If we don't have a valid backtrace, then just return.
|
||||
*/
|
||||
if (dbg_curr_thread->frames == NULL) return FALSE;
|
||||
ihsf->InstructionOffset = (unsigned long)memory_to_linear_addr(&dbg_curr_thread->frames[dbg_curr_thread->curr_frame].addr_pc);
|
||||
ihsf->FrameOffset = (unsigned long)memory_to_linear_addr(&dbg_curr_thread->frames[dbg_curr_thread->curr_frame].addr_frame);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL stack_set_frame(int newframe)
|
||||
{
|
||||
ADDRESS addr;
|
||||
|
||||
dbg_curr_frame = newframe;
|
||||
if (dbg_curr_frame >= nframe) dbg_curr_frame = nframe - 1;
|
||||
if (dbg_curr_frame < 0) dbg_curr_frame = 0;
|
||||
|
||||
if (!stack_set_frame_internal(newframe)) return FALSE;
|
||||
addr.Mode = AddrModeFlat;
|
||||
addr.Offset = frames[dbg_curr_frame].InstructionOffset;
|
||||
addr.Offset = (unsigned long)memory_to_linear_addr(&dbg_curr_thread->frames[dbg_curr_thread->curr_frame].addr_pc);
|
||||
source_list_from_addr(&addr, 0);
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -87,30 +109,36 @@ BOOL stack_get_frame(SYMBOL_INFO* symbol, IMAGEHLP_STACK_FRAME* ihsf)
|
|||
/*
|
||||
* If we don't have a valid backtrace, then just return.
|
||||
*/
|
||||
if (frames == NULL) return FALSE;
|
||||
if (dbg_curr_thread->frames == NULL) return FALSE;
|
||||
|
||||
/*
|
||||
* If we don't know what the current function is, then we also have
|
||||
* nothing to report here.
|
||||
*/
|
||||
if (!SymFromAddr(dbg_curr_process->handle, frames[dbg_curr_frame].InstructionOffset,
|
||||
if (!SymFromAddr(dbg_curr_process->handle,
|
||||
(unsigned long)memory_to_linear_addr(&dbg_curr_thread->frames[dbg_curr_thread->curr_frame].addr_pc),
|
||||
&disp, symbol))
|
||||
return FALSE;
|
||||
if (ihsf) *ihsf = frames[dbg_curr_frame];
|
||||
if (ihsf && !stack_get_current_frame(ihsf)) return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* backtrace
|
||||
* stack_fetch_frames
|
||||
*
|
||||
* Do a backtrace on the the current thread
|
||||
*/
|
||||
static unsigned backtrace(BOOL with_frames, BOOL noisy)
|
||||
unsigned stack_fetch_frames(void)
|
||||
{
|
||||
STACKFRAME sf;
|
||||
unsigned nf = 0;
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, dbg_curr_thread->frames);
|
||||
dbg_curr_thread->frames = NULL;
|
||||
dbg_curr_thread->num_frames = 0;
|
||||
dbg_curr_thread->curr_frame = 0;
|
||||
|
||||
memset(&sf, 0, sizeof(sf));
|
||||
memory_get_current_frame(&sf.AddrFrame);
|
||||
memory_get_current_pc(&sf.AddrPC);
|
||||
|
@ -122,33 +150,41 @@ static unsigned backtrace(BOOL with_frames, BOOL noisy)
|
|||
sf.AddrFrame.Mode = AddrModeFlat;
|
||||
}
|
||||
|
||||
if (noisy) dbg_printf("Backtrace:\n");
|
||||
while (StackWalk(IMAGE_FILE_MACHINE_I386, dbg_curr_process->handle,
|
||||
dbg_curr_thread->handle, &sf, &dbg_context, NULL,
|
||||
SymFunctionTableAccess, SymGetModuleBase, NULL))
|
||||
{
|
||||
if (with_frames)
|
||||
{
|
||||
frames = dbg_heap_realloc(frames,
|
||||
(nf + 1) * sizeof(IMAGEHLP_STACK_FRAME));
|
||||
dbg_curr_thread->frames = dbg_heap_realloc(dbg_curr_thread->frames,
|
||||
(nf + 1) * sizeof(dbg_curr_thread->frames[0]));
|
||||
|
||||
frames[nf].InstructionOffset = (unsigned long)memory_to_linear_addr(&sf.AddrPC);
|
||||
frames[nf].FrameOffset = (unsigned long)memory_to_linear_addr(&sf.AddrFrame);
|
||||
}
|
||||
if (noisy)
|
||||
{
|
||||
dbg_printf("%s%d ",
|
||||
(with_frames && nf == dbg_curr_frame ? "=>" : " "),
|
||||
nf + 1);
|
||||
print_addr_and_args(&sf.AddrPC, &sf.AddrFrame);
|
||||
dbg_printf(" (");
|
||||
print_bare_address(&sf.AddrFrame);
|
||||
dbg_printf(")\n");
|
||||
}
|
||||
dbg_curr_thread->frames[nf].addr_pc = sf.AddrPC;
|
||||
dbg_curr_thread->frames[nf].addr_frame = sf.AddrFrame;
|
||||
nf++;
|
||||
/* we've probably gotten ourselves into an infinite loop so bail */
|
||||
if (nf > 200)
|
||||
break;
|
||||
if (nf > 200) break;
|
||||
}
|
||||
return dbg_curr_thread->num_frames = nf;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* backtrace
|
||||
*
|
||||
* Do a backtrace on the the current thread
|
||||
*/
|
||||
static unsigned backtrace(void)
|
||||
{
|
||||
unsigned nf = 0;
|
||||
|
||||
dbg_printf("Backtrace:\n");
|
||||
for (nf = 0; nf < dbg_curr_thread->num_frames; nf++)
|
||||
{
|
||||
dbg_printf("%s%d ",
|
||||
(nf == dbg_curr_thread->curr_frame ? "=>" : " "), nf + 1);
|
||||
print_addr_and_args(&dbg_curr_thread->frames[nf].addr_pc,
|
||||
&dbg_curr_thread->frames[nf].addr_frame);
|
||||
dbg_printf(" (");
|
||||
print_bare_address(&dbg_curr_thread->frames[nf].addr_pc);
|
||||
dbg_printf(")\n");
|
||||
}
|
||||
return nf;
|
||||
}
|
||||
|
@ -159,7 +195,7 @@ static unsigned backtrace(BOOL with_frames, BOOL noisy)
|
|||
* Do a backtrace on a thread from its process and its identifier
|
||||
* (preserves current thread and context information)
|
||||
*/
|
||||
static void backtrace_tid(struct dbg_process* pcs, DWORD tid, BOOL noisy)
|
||||
static void backtrace_tid(struct dbg_process* pcs, DWORD tid)
|
||||
{
|
||||
struct dbg_thread* thread = dbg_curr_thread;
|
||||
|
||||
|
@ -179,7 +215,7 @@ static void backtrace_tid(struct dbg_process* pcs, DWORD tid, BOOL noisy)
|
|||
dbg_printf("Can't get context for thread 0x%lx in current process\n",
|
||||
tid);
|
||||
}
|
||||
else backtrace(FALSE, noisy);
|
||||
else backtrace();
|
||||
ResumeThread(dbg_curr_thread->handle);
|
||||
}
|
||||
else dbg_printf("Can't suspend thread 0x%lx in current process\n", tid);
|
||||
|
@ -228,7 +264,7 @@ static void backtrace_all(void)
|
|||
|
||||
dbg_printf("\nBacktracing for thread 0x%lx in process 0x%lx (%s):\n",
|
||||
entry.th32ThreadID, dbg_curr_pid, dbg_curr_process->imageName);
|
||||
backtrace_tid(dbg_curr_process, entry.th32ThreadID, TRUE);
|
||||
backtrace_tid(dbg_curr_process, entry.th32ThreadID);
|
||||
}
|
||||
while (Thread32Next(snapshot, &entry));
|
||||
|
||||
|
@ -238,7 +274,7 @@ static void backtrace_all(void)
|
|||
CloseHandle(snapshot);
|
||||
}
|
||||
|
||||
void stack_backtrace(DWORD tid, BOOL noisy)
|
||||
void stack_backtrace(DWORD tid)
|
||||
{
|
||||
/* backtrace every thread in every process except the debugger itself,
|
||||
* invoking via "bt all"
|
||||
|
@ -253,12 +289,10 @@ void stack_backtrace(DWORD tid, BOOL noisy)
|
|||
|
||||
if (tid == dbg_curr_tid)
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, frames);
|
||||
frames = NULL;
|
||||
nframe = backtrace(TRUE, noisy);
|
||||
backtrace();
|
||||
}
|
||||
else
|
||||
{
|
||||
backtrace_tid(dbg_curr_process, tid, noisy);
|
||||
backtrace_tid(dbg_curr_process, tid);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ static BOOL CALLBACK sgv_cb(SYMBOL_INFO* sym, ULONG size, void* ctx)
|
|||
{
|
||||
const struct dbg_internal_var* div;
|
||||
|
||||
if (dbg_curr_frame != 0)
|
||||
if (dbg_curr_thread->curr_frame != 0)
|
||||
{
|
||||
dbg_printf(" %s (register): << cannot display, not in correct frame\n",
|
||||
sym->Name);
|
||||
|
@ -570,7 +570,7 @@ static BOOL CALLBACK info_locals_cb(SYMBOL_INFO* sym, ULONG size, void* ctx)
|
|||
{
|
||||
const struct dbg_internal_var* div;
|
||||
|
||||
if (dbg_curr_frame != 0)
|
||||
if (dbg_curr_thread->curr_frame != 0)
|
||||
{
|
||||
dbg_printf(" %s (register): << cannot display, not in correct frame\n",
|
||||
sym->Name);
|
||||
|
|
|
@ -94,7 +94,6 @@ struct dbg_thread* dbg_curr_thread = NULL;
|
|||
DWORD dbg_curr_tid;
|
||||
DWORD dbg_curr_pid;
|
||||
CONTEXT dbg_context;
|
||||
int dbg_curr_frame = 0;
|
||||
BOOL dbg_interactiveP = FALSE;
|
||||
static char* dbg_last_cmd_line = NULL;
|
||||
|
||||
|
@ -396,6 +395,9 @@ struct dbg_thread* dbg_add_thread(struct dbg_process* p, DWORD tid,
|
|||
t->step_over_bp.enabled = FALSE;
|
||||
t->step_over_bp.refcount = 0;
|
||||
t->in_exception = FALSE;
|
||||
t->frames = NULL;
|
||||
t->num_frames = 0;
|
||||
t->curr_frame = -1;
|
||||
|
||||
snprintf(t->name, sizeof(t->name), "0x%08lx", tid);
|
||||
|
||||
|
@ -428,6 +430,7 @@ static void dbg_init_current_thread(void* start)
|
|||
|
||||
void dbg_del_thread(struct dbg_thread* t)
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, t->frames);
|
||||
if (t->prev) t->prev->next = t->next;
|
||||
if (t->next) t->next->prev = t->prev;
|
||||
if (t == t->process->threads) t->process->threads = t->next;
|
||||
|
@ -538,7 +541,7 @@ static unsigned dbg_exception_prolog(BOOL is_debug, const EXCEPTION_RECORD* rec)
|
|||
* Do a quiet backtrace so that we have an idea of what the situation
|
||||
* is WRT the source files.
|
||||
*/
|
||||
stack_backtrace(dbg_curr_tid, FALSE);
|
||||
stack_fetch_frames();
|
||||
if (is_debug &&
|
||||
break_should_continue(&addr, rec->ExceptionCode, &dbg_curr_thread->exec_count, &is_break))
|
||||
return FALSE;
|
||||
|
@ -566,7 +569,7 @@ static unsigned dbg_exception_prolog(BOOL is_debug, const EXCEPTION_RECORD* rec)
|
|||
be_cpu->print_context(dbg_curr_thread->handle, &dbg_context);
|
||||
stack_info();
|
||||
be_cpu->print_segment_info(dbg_curr_thread->handle, &dbg_context);
|
||||
stack_backtrace(dbg_curr_tid, TRUE);
|
||||
stack_backtrace(dbg_curr_tid);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -603,7 +606,7 @@ static unsigned dbg_exception_prolog(BOOL is_debug, const EXCEPTION_RECORD* rec)
|
|||
{
|
||||
ADDRESS tmp = addr;
|
||||
/* Show where we crashed */
|
||||
dbg_curr_frame = 0;
|
||||
stack_set_frame(0);
|
||||
memory_disasm_one_insn(&tmp);
|
||||
}
|
||||
source_list_from_addr(&addr, 0);
|
||||
|
|
Loading…
Reference in New Issue