Implement backtrace output for fatal errors on MS-Windows.

src/w32fns.c (CaptureStackBackTrace_proc): New typedef.
 (BACKTRACE_LIMIT_MAX): New macro.
 (w32_backtrace): New function.
 (emacs_abort): Use w32_backtrace when the user chooses not to
 attach a debugger.  Update the text of the abort dialog.
This commit is contained in:
Eli Zaretskii 2012-11-02 16:00:45 +02:00
parent b9e9df47f2
commit 1005b4b98a
2 changed files with 85 additions and 3 deletions

View file

@ -1,3 +1,12 @@
2012-11-02 Eli Zaretskii <eliz@gnu.org>
Implement backtrace output for fatal errors on MS-Windows.
* w32fns.c (CaptureStackBackTrace_proc): New typedef.
(BACKTRACE_LIMIT_MAX): New macro.
(w32_backtrace): New function.
(emacs_abort): Use w32_backtrace when the user chooses not to
attach a debugger. Update the text of the abort dialog.
2012-11-02 Dmitry Antipov <dmantipov@yandex.ru>
Window-related stuff cleanup here and there.

View file

@ -26,6 +26,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include <limits.h>
#include <errno.h>
#include <math.h>
#include <fcntl.h>
#include "lisp.h"
#include "w32term.h"
@ -7697,6 +7698,30 @@ globals_of_w32fns (void)
syms_of_w32uniscribe ();
}
typedef USHORT (WINAPI * CaptureStackBackTrace_proc) (ULONG, ULONG, PVOID *,
PULONG);
#define BACKTRACE_LIMIT_MAX 62
int
w32_backtrace (void **buffer, int limit)
{
static CaptureStackBackTrace_proc s_pfn_CaptureStackBackTrace = NULL;
HMODULE hm_kernel32 = NULL;
if (!s_pfn_CaptureStackBackTrace)
{
hm_kernel32 = LoadLibrary ("Kernel32.dll");
s_pfn_CaptureStackBackTrace =
(CaptureStackBackTrace_proc) GetProcAddress (hm_kernel32,
"RtlCaptureStackBackTrace");
}
if (s_pfn_CaptureStackBackTrace)
return s_pfn_CaptureStackBackTrace (0, min (BACKTRACE_LIMIT_MAX, limit),
buffer, NULL);
return 0;
}
void
emacs_abort (void)
{
@ -7704,7 +7729,10 @@ emacs_abort (void)
button = MessageBox (NULL,
"A fatal error has occurred!\n\n"
"Would you like to attach a debugger?\n\n"
"Select YES to debug, NO to abort Emacs"
"Select:\n"
"YES -- to debug Emacs, or\n"
"NO -- to abort Emacs and produce a backtrace\n"
" (emacs_backtrace.txt in current directory)."
#if __GNUC__
"\n\n(type \"gdb -p <emacs-PID>\" and\n"
"\"continue\" inside GDB before clicking YES.)"
@ -7719,7 +7747,52 @@ emacs_abort (void)
exit (2); /* tell the compiler we will never return */
case IDNO:
default:
abort ();
break;
{
void *stack[BACKTRACE_LIMIT_MAX + 1];
int i = w32_backtrace (stack, BACKTRACE_LIMIT_MAX + 1);
if (i)
{
HANDLE errout = GetStdHandle (STD_ERROR_HANDLE);
int stderr_fd = -1, errfile_fd = -1;
int j;
if (errout && errout != INVALID_HANDLE_VALUE)
stderr_fd = _open_osfhandle ((intptr_t)errout, O_APPEND | O_BINARY);
if (stderr_fd >= 0)
write (stderr_fd, "\r\nBacktrace:\r\n", 14);
errfile_fd = _open ("emacs_backtrace.txt", O_RDWR | O_CREAT | O_BINARY, S_IREAD | S_IWRITE);
if (errfile_fd >= 0)
{
lseek (errfile_fd, 0L, SEEK_END);
write (errfile_fd, "\r\nBacktrace:\r\n", 14);
}
for (j = 0; j < i; j++)
{
char buf[INT_BUFSIZE_BOUND (void *)];
/* stack[] gives the return addresses, whereas we want
the address of the call, so decrease each address
by approximate size of 1 CALL instruction. */
sprintf (buf, "0x%p\r\n", stack[j] - sizeof(void *));
if (stderr_fd >= 0)
write (stderr_fd, buf, strlen (buf));
if (errfile_fd >= 0)
write (errfile_fd, buf, strlen (buf));
}
if (i == BACKTRACE_LIMIT_MAX)
{
if (stderr_fd >= 0)
write (stderr_fd, "...\r\n", 5);
if (errfile_fd >= 0)
write (errfile_fd, "...\r\n", 5);
}
if (errfile_fd >= 0)
close (errfile_fd);
}
abort ();
break;
}
}
}