Commit 3e07e047 authored by Eric Pouech's avatar Eric Pouech Committed by Alexandre Julliard

- now storing frames information in thread structure

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