aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii2012-11-02 16:00:45 +0200
committerEli Zaretskii2012-11-02 16:00:45 +0200
commit1005b4b98a43c4aea2ac8f01a5743b6b38bdd964 (patch)
tree15933dd02566ab8cad6fd4e299612b41bbe188e0 /src
parentb9e9df47f2886bb4b6b67aea8eeb0b015258a063 (diff)
downloademacs-1005b4b98a43c4aea2ac8f01a5743b6b38bdd964.tar.gz
emacs-1005b4b98a43c4aea2ac8f01a5743b6b38bdd964.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog9
-rw-r--r--src/w32fns.c79
2 files changed, 85 insertions, 3 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 25cb1e76fa5..5739b5d9125 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,12 @@
12012-11-02 Eli Zaretskii <eliz@gnu.org>
2
3 Implement backtrace output for fatal errors on MS-Windows.
4 * w32fns.c (CaptureStackBackTrace_proc): New typedef.
5 (BACKTRACE_LIMIT_MAX): New macro.
6 (w32_backtrace): New function.
7 (emacs_abort): Use w32_backtrace when the user chooses not to
8 attach a debugger. Update the text of the abort dialog.
9
12012-11-02 Dmitry Antipov <dmantipov@yandex.ru> 102012-11-02 Dmitry Antipov <dmantipov@yandex.ru>
2 11
3 Window-related stuff cleanup here and there. 12 Window-related stuff cleanup here and there.
diff --git a/src/w32fns.c b/src/w32fns.c
index aa120d59ce5..7459c4a31db 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -26,6 +26,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
26#include <limits.h> 26#include <limits.h>
27#include <errno.h> 27#include <errno.h>
28#include <math.h> 28#include <math.h>
29#include <fcntl.h>
29 30
30#include "lisp.h" 31#include "lisp.h"
31#include "w32term.h" 32#include "w32term.h"
@@ -7697,6 +7698,30 @@ globals_of_w32fns (void)
7697 syms_of_w32uniscribe (); 7698 syms_of_w32uniscribe ();
7698} 7699}
7699 7700
7701typedef USHORT (WINAPI * CaptureStackBackTrace_proc) (ULONG, ULONG, PVOID *,
7702 PULONG);
7703
7704#define BACKTRACE_LIMIT_MAX 62
7705
7706int
7707w32_backtrace (void **buffer, int limit)
7708{
7709 static CaptureStackBackTrace_proc s_pfn_CaptureStackBackTrace = NULL;
7710 HMODULE hm_kernel32 = NULL;
7711
7712 if (!s_pfn_CaptureStackBackTrace)
7713 {
7714 hm_kernel32 = LoadLibrary ("Kernel32.dll");
7715 s_pfn_CaptureStackBackTrace =
7716 (CaptureStackBackTrace_proc) GetProcAddress (hm_kernel32,
7717 "RtlCaptureStackBackTrace");
7718 }
7719 if (s_pfn_CaptureStackBackTrace)
7720 return s_pfn_CaptureStackBackTrace (0, min (BACKTRACE_LIMIT_MAX, limit),
7721 buffer, NULL);
7722 return 0;
7723}
7724
7700void 7725void
7701emacs_abort (void) 7726emacs_abort (void)
7702{ 7727{
@@ -7704,7 +7729,10 @@ emacs_abort (void)
7704 button = MessageBox (NULL, 7729 button = MessageBox (NULL,
7705 "A fatal error has occurred!\n\n" 7730 "A fatal error has occurred!\n\n"
7706 "Would you like to attach a debugger?\n\n" 7731 "Would you like to attach a debugger?\n\n"
7707 "Select YES to debug, NO to abort Emacs" 7732 "Select:\n"
7733 "YES -- to debug Emacs, or\n"
7734 "NO -- to abort Emacs and produce a backtrace\n"
7735 " (emacs_backtrace.txt in current directory)."
7708#if __GNUC__ 7736#if __GNUC__
7709 "\n\n(type \"gdb -p <emacs-PID>\" and\n" 7737 "\n\n(type \"gdb -p <emacs-PID>\" and\n"
7710 "\"continue\" inside GDB before clicking YES.)" 7738 "\"continue\" inside GDB before clicking YES.)"
@@ -7719,7 +7747,52 @@ emacs_abort (void)
7719 exit (2); /* tell the compiler we will never return */ 7747 exit (2); /* tell the compiler we will never return */
7720 case IDNO: 7748 case IDNO:
7721 default: 7749 default:
7722 abort (); 7750 {
7723 break; 7751 void *stack[BACKTRACE_LIMIT_MAX + 1];
7752 int i = w32_backtrace (stack, BACKTRACE_LIMIT_MAX + 1);
7753
7754 if (i)
7755 {
7756 HANDLE errout = GetStdHandle (STD_ERROR_HANDLE);
7757 int stderr_fd = -1, errfile_fd = -1;
7758 int j;
7759
7760 if (errout && errout != INVALID_HANDLE_VALUE)
7761 stderr_fd = _open_osfhandle ((intptr_t)errout, O_APPEND | O_BINARY);
7762 if (stderr_fd >= 0)
7763 write (stderr_fd, "\r\nBacktrace:\r\n", 14);
7764 errfile_fd = _open ("emacs_backtrace.txt", O_RDWR | O_CREAT | O_BINARY, S_IREAD | S_IWRITE);
7765 if (errfile_fd >= 0)
7766 {
7767 lseek (errfile_fd, 0L, SEEK_END);
7768 write (errfile_fd, "\r\nBacktrace:\r\n", 14);
7769 }
7770
7771 for (j = 0; j < i; j++)
7772 {
7773 char buf[INT_BUFSIZE_BOUND (void *)];
7774
7775 /* stack[] gives the return addresses, whereas we want
7776 the address of the call, so decrease each address
7777 by approximate size of 1 CALL instruction. */
7778 sprintf (buf, "0x%p\r\n", stack[j] - sizeof(void *));
7779 if (stderr_fd >= 0)
7780 write (stderr_fd, buf, strlen (buf));
7781 if (errfile_fd >= 0)
7782 write (errfile_fd, buf, strlen (buf));
7783 }
7784 if (i == BACKTRACE_LIMIT_MAX)
7785 {
7786 if (stderr_fd >= 0)
7787 write (stderr_fd, "...\r\n", 5);
7788 if (errfile_fd >= 0)
7789 write (errfile_fd, "...\r\n", 5);
7790 }
7791 if (errfile_fd >= 0)
7792 close (errfile_fd);
7793 }
7794 abort ();
7795 break;
7796 }
7724 } 7797 }
7725} 7798}