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:
stack_walker();
FPTR ip() const { return m_stackframe.AddrPC.Offset; }
FPTR sp() const { return m_stackframe.AddrStack.Offset; }
FPTR frame() const { return m_stackframe.AddrFrame.Offset; }
bool reset();
void reset(CONTEXT &context, HANDLE thread);
bool unwind();
@ -138,6 +139,7 @@ private:
dynamic_bind<BOOL (WINAPI *)(HANDLE, LPCTSTR, BOOL)> m_sym_initialize;
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<VOID (WINAPI *)(PCONTEXT)> m_rtl_capture_context;
static bool s_initialized;
};
@ -392,11 +394,15 @@ int main(int argc, char *argv[])
// allocate symbols
symbol_manager local_symbols(argv[0]);
symbols = &local_symbols;
// set up exception handling
pass_thru_filter = SetUnhandledExceptionFilter(exception_filter);
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 (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
//============================================================
@ -755,14 +778,13 @@ static LONG WINAPI exception_filter(struct _EXCEPTION_POINTERS *info)
// walk the stack
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
return EXCEPTION_CONTINUE_SEARCH;
}
//**************************************************************************
// STACK WALKER
//**************************************************************************
@ -778,7 +800,8 @@ stack_walker::stack_walker()
m_stack_walk_64(TEXT("dbghelp.dll"), "StackWalk64"),
m_sym_initialize(TEXT("dbghelp.dll"), "SymInitialize"),
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
memset(&m_stackframe, 0, sizeof(m_stackframe));
@ -797,6 +820,34 @@ stack_walker::stack_walker()
// 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)
{
// 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
void winmain_watchdog_ping(void);
void winmain_dump_stack();

View File

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