On Windows, osd_break_into_debugger() will now dump a stack crawl

if there's no debugger attached. This means that asserts should have
a full crawl now, for easier debugging.
This commit is contained in:
Aaron Giles 2010-09-10 17:34:52 +00:00
parent 8f8981db66
commit 3d1a55e19e
3 changed files with 68 additions and 5 deletions

View File

@ -118,11 +118,12 @@ class stack_walker
{ {
public: public:
stack_walker(); stack_walker();
FPTR ip() const { return m_stackframe.AddrPC.Offset; } FPTR ip() const { return m_stackframe.AddrPC.Offset; }
FPTR sp() const { return m_stackframe.AddrStack.Offset; } FPTR sp() const { return m_stackframe.AddrStack.Offset; }
FPTR frame() const { return m_stackframe.AddrFrame.Offset; } FPTR frame() const { return m_stackframe.AddrFrame.Offset; }
bool reset();
void reset(CONTEXT &context, HANDLE thread); void reset(CONTEXT &context, HANDLE thread);
bool unwind(); bool unwind();
@ -138,6 +139,7 @@ private:
dynamic_bind<BOOL (WINAPI *)(HANDLE, LPCTSTR, BOOL)> m_sym_initialize; dynamic_bind<BOOL (WINAPI *)(HANDLE, LPCTSTR, BOOL)> m_sym_initialize;
dynamic_bind<PVOID (WINAPI *)(HANDLE, DWORD64)> m_sym_function_table_access_64; dynamic_bind<PVOID (WINAPI *)(HANDLE, DWORD64)> m_sym_function_table_access_64;
dynamic_bind<DWORD64 (WINAPI *)(HANDLE, DWORD64)> m_sym_get_module_base_64; dynamic_bind<DWORD64 (WINAPI *)(HANDLE, DWORD64)> m_sym_get_module_base_64;
dynamic_bind<VOID (WINAPI *)(PCONTEXT)> m_rtl_capture_context;
static bool s_initialized; static bool s_initialized;
}; };
@ -392,11 +394,15 @@ int main(int argc, char *argv[])
// allocate symbols // allocate symbols
symbol_manager local_symbols(argv[0]); symbol_manager local_symbols(argv[0]);
symbols = &local_symbols; symbols = &local_symbols;
// set up exception handling // set up exception handling
pass_thru_filter = SetUnhandledExceptionFilter(exception_filter); pass_thru_filter = SetUnhandledExceptionFilter(exception_filter);
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
// enable stack crawls for asserts
extern void (*s_debugger_stack_crawler)();
s_debugger_stack_crawler = winmain_dump_stack;
// if we're a GUI app, out errors to message boxes // if we're a GUI app, out errors to message boxes
if (win_is_gui_application() || is_double_click_start(argc)) if (win_is_gui_application() || is_double_click_start(argc))
{ {
@ -582,6 +588,23 @@ static void osd_exit(running_machine &machine)
} }
//============================================================
// winmain_dump_stack
//============================================================
void winmain_dump_stack()
{
// set up the stack walker
stack_walker walker;
if (!walker.reset())
return;
// walk the stack
while (walker.unwind())
fprintf(stderr, " %p: %p%s\n", (void *)walker.frame(), (void *)walker.ip(), (symbols == NULL) ? "" : symbols->symbol_for_address(walker.ip()));
}
//============================================================ //============================================================
// check_for_double_click_start // check_for_double_click_start
//============================================================ //============================================================
@ -755,14 +778,13 @@ static LONG WINAPI exception_filter(struct _EXCEPTION_POINTERS *info)
// walk the stack // walk the stack
while (walker.unwind()) while (walker.unwind())
fprintf(stderr, " %p: %p%s\n", (void *)walker.frame(), (void *)walker.ip(), symbols->symbol_for_address(walker.ip())); fprintf(stderr, " %p: %p%s\n", (void *)walker.frame(), (void *)walker.ip(), (symbols == NULL) ? "" : symbols->symbol_for_address(walker.ip()));
// exit // exit
return EXCEPTION_CONTINUE_SEARCH; return EXCEPTION_CONTINUE_SEARCH;
} }
//************************************************************************** //**************************************************************************
// STACK WALKER // STACK WALKER
//************************************************************************** //**************************************************************************
@ -778,7 +800,8 @@ stack_walker::stack_walker()
m_stack_walk_64(TEXT("dbghelp.dll"), "StackWalk64"), m_stack_walk_64(TEXT("dbghelp.dll"), "StackWalk64"),
m_sym_initialize(TEXT("dbghelp.dll"), "SymInitialize"), m_sym_initialize(TEXT("dbghelp.dll"), "SymInitialize"),
m_sym_function_table_access_64(TEXT("dbghelp.dll"), "SymFunctionTableAccess64"), m_sym_function_table_access_64(TEXT("dbghelp.dll"), "SymFunctionTableAccess64"),
m_sym_get_module_base_64(TEXT("dbghelp.dll"), "SymGetModuleBase64") m_sym_get_module_base_64(TEXT("dbghelp.dll"), "SymGetModuleBase64"),
m_rtl_capture_context(TEXT("kernel32.dll"), "RtlCaptureContext")
{ {
// zap the structs // zap the structs
memset(&m_stackframe, 0, sizeof(m_stackframe)); memset(&m_stackframe, 0, sizeof(m_stackframe));
@ -797,6 +820,34 @@ stack_walker::stack_walker()
// reset - set up a new context // reset - set up a new context
//------------------------------------------------- //-------------------------------------------------
bool stack_walker::reset()
{
// set up the initial state
if (!m_rtl_capture_context)
return false;
(*m_rtl_capture_context)(&m_context);
m_thread = GetCurrentThread();
m_first = true;
// initialize the stackframe
memset(&m_stackframe, 0, sizeof(m_stackframe));
m_stackframe.AddrPC.Mode = AddrModeFlat;
m_stackframe.AddrFrame.Mode = AddrModeFlat;
m_stackframe.AddrStack.Mode = AddrModeFlat;
// pull architecture-specific fields from the context
#ifdef PTR64
m_stackframe.AddrPC.Offset = m_context.Rip;
m_stackframe.AddrFrame.Offset = m_context.Rsp;
m_stackframe.AddrStack.Offset = m_context.Rsp;
#else
m_stackframe.AddrPC.Offset = m_context.Eip;
m_stackframe.AddrFrame.Offset = m_context.Ebp;
m_stackframe.AddrStack.Offset = m_context.Esp;
#endif
return true;
}
void stack_walker::reset(CONTEXT &initial, HANDLE thread) void stack_walker::reset(CONTEXT &initial, HANDLE thread)
{ {
// set up the initial state // set up the initial state

View File

@ -149,3 +149,4 @@ void CLIB_DECL mame_printf_verbose(const char *text, ...) ATTR_PRINTF(1,2);
// use this to ping the watchdog // use this to ping the watchdog
void winmain_watchdog_ping(void); void winmain_watchdog_ping(void);
void winmain_dump_stack();

View File

@ -50,6 +50,7 @@
// MAMEOS headers // MAMEOS headers
#include "winutf8.h" #include "winutf8.h"
#include "strconv.h" #include "strconv.h"
#include "strconv.h"
//============================================================ //============================================================
@ -67,6 +68,14 @@
//============================================================
// GLOBAL VARIABLES
//============================================================
void (*s_debugger_stack_crawler)() = NULL;
//============================================================ //============================================================
// osd_malloc // osd_malloc
//============================================================ //============================================================
@ -167,4 +176,6 @@ void osd_break_into_debugger(const char *message)
win_output_debug_string_utf8(message); win_output_debug_string_utf8(message);
DebugBreak(); DebugBreak();
} }
else if (s_debugger_stack_crawler != NULL)
(*s_debugger_stack_crawler)();
} }