diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 11 | ||||
| -rw-r--r-- | src/w32fns.c | 169 |
2 files changed, 121 insertions, 59 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index db311bdcba5..a5c6668c551 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,14 @@ | |||
| 1 | 2013-12-02 Eli Zaretskii <eliz@gnu.org> | ||
| 2 | |||
| 3 | Improve reporting of fatal exception on MS-Windows. | ||
| 4 | * w32fns.c (my_exception_handler): New function. | ||
| 5 | (globals_of_w32fns): Set it up as the unhandled exception | ||
| 6 | handler. Initialize exception code and address to zeros. | ||
| 7 | (emacs_abort): If the exception code and address are available, | ||
| 8 | print them at the beginning of the backtrace. Fix the format of | ||
| 9 | printing addresses (was producing 0x0x12345678 on XP). | ||
| 10 | (Bug#15994) | ||
| 11 | |||
| 1 | 2013-12-02 Helmut Eller <eller.helmut@gmail.com> | 12 | 2013-12-02 Helmut Eller <eller.helmut@gmail.com> |
| 2 | 13 | ||
| 3 | * eval.c (Fbacktrace__locals): New function. | 14 | * eval.c (Fbacktrace__locals): New function. |
diff --git a/src/w32fns.c b/src/w32fns.c index f574a86b1e1..79011f9afc2 100644 --- a/src/w32fns.c +++ b/src/w32fns.c | |||
| @@ -7969,61 +7969,35 @@ only be necessary if the default setting causes problems. */); | |||
| 7969 | #endif | 7969 | #endif |
| 7970 | } | 7970 | } |
| 7971 | 7971 | ||
| 7972 | |||
| 7972 | 7973 | ||
| 7973 | /* | 7974 | /* Crashing and reporting backtrace. */ |
| 7974 | globals_of_w32fns is used to initialize those global variables that | ||
| 7975 | must always be initialized on startup even when the global variable | ||
| 7976 | initialized is non zero (see the function main in emacs.c). | ||
| 7977 | globals_of_w32fns is called from syms_of_w32fns when the global | ||
| 7978 | variable initialized is 0 and directly from main when initialized | ||
| 7979 | is non zero. | ||
| 7980 | */ | ||
| 7981 | void | ||
| 7982 | globals_of_w32fns (void) | ||
| 7983 | { | ||
| 7984 | HMODULE user32_lib = GetModuleHandle ("user32.dll"); | ||
| 7985 | /* | ||
| 7986 | TrackMouseEvent not available in all versions of Windows, so must load | ||
| 7987 | it dynamically. Do it once, here, instead of every time it is used. | ||
| 7988 | */ | ||
| 7989 | track_mouse_event_fn = (TrackMouseEvent_Proc) | ||
| 7990 | GetProcAddress (user32_lib, "TrackMouseEvent"); | ||
| 7991 | |||
| 7992 | monitor_from_point_fn = (MonitorFromPoint_Proc) | ||
| 7993 | GetProcAddress (user32_lib, "MonitorFromPoint"); | ||
| 7994 | get_monitor_info_fn = (GetMonitorInfo_Proc) | ||
| 7995 | GetProcAddress (user32_lib, "GetMonitorInfoA"); | ||
| 7996 | monitor_from_window_fn = (MonitorFromWindow_Proc) | ||
| 7997 | GetProcAddress (user32_lib, "MonitorFromWindow"); | ||
| 7998 | enum_display_monitors_fn = (EnumDisplayMonitors_Proc) | ||
| 7999 | GetProcAddress (user32_lib, "EnumDisplayMonitors"); | ||
| 8000 | |||
| 8001 | { | ||
| 8002 | HMODULE imm32_lib = GetModuleHandle ("imm32.dll"); | ||
| 8003 | get_composition_string_fn = (ImmGetCompositionString_Proc) | ||
| 8004 | GetProcAddress (imm32_lib, "ImmGetCompositionStringW"); | ||
| 8005 | get_ime_context_fn = (ImmGetContext_Proc) | ||
| 8006 | GetProcAddress (imm32_lib, "ImmGetContext"); | ||
| 8007 | release_ime_context_fn = (ImmReleaseContext_Proc) | ||
| 8008 | GetProcAddress (imm32_lib, "ImmReleaseContext"); | ||
| 8009 | set_ime_composition_window_fn = (ImmSetCompositionWindow_Proc) | ||
| 8010 | GetProcAddress (imm32_lib, "ImmSetCompositionWindow"); | ||
| 8011 | } | ||
| 8012 | DEFVAR_INT ("w32-ansi-code-page", | ||
| 8013 | w32_ansi_code_page, | ||
| 8014 | doc: /* The ANSI code page used by the system. */); | ||
| 8015 | w32_ansi_code_page = GetACP (); | ||
| 8016 | |||
| 8017 | if (os_subtype == OS_NT) | ||
| 8018 | w32_unicode_gui = 1; | ||
| 8019 | else | ||
| 8020 | w32_unicode_gui = 0; | ||
| 8021 | 7975 | ||
| 8022 | /* MessageBox does not work without this when linked to comctl32.dll 6.0. */ | 7976 | #ifndef CYGWIN |
| 8023 | InitCommonControls (); | 7977 | static LONG CALLBACK my_exception_handler (EXCEPTION_POINTERS *); |
| 7978 | static LPTOP_LEVEL_EXCEPTION_FILTER prev_exception_handler; | ||
| 7979 | #endif | ||
| 7980 | static DWORD except_code; | ||
| 7981 | static PVOID except_addr; | ||
| 8024 | 7982 | ||
| 8025 | syms_of_w32uniscribe (); | 7983 | #ifndef CYGWIN |
| 7984 | /* This handler records the exception code and the address where it | ||
| 7985 | was triggered so that this info could be included in the backtrace. | ||
| 7986 | Without that, the backtrace in some cases has no information | ||
| 7987 | whatsoever about the offending code, and looks as if the top-level | ||
| 7988 | exception handler in the MinGW startup code di the one that | ||
| 7989 | crashed. */ | ||
| 7990 | static LONG CALLBACK | ||
| 7991 | my_exception_handler (EXCEPTION_POINTERS * exception_data) | ||
| 7992 | { | ||
| 7993 | except_code = exception_data->ExceptionRecord->ExceptionCode; | ||
| 7994 | except_addr = exception_data->ExceptionRecord->ExceptionAddress; | ||
| 7995 | |||
| 7996 | if (prev_exception_handler) | ||
| 7997 | return prev_exception_handler (exception_data); | ||
| 7998 | return EXCEPTION_EXECUTE_HANDLER; | ||
| 8026 | } | 7999 | } |
| 8000 | #endif | ||
| 8027 | 8001 | ||
| 8028 | typedef USHORT (WINAPI * CaptureStackBackTrace_proc) (ULONG, ULONG, PVOID *, | 8002 | typedef USHORT (WINAPI * CaptureStackBackTrace_proc) (ULONG, ULONG, PVOID *, |
| 8029 | PULONG); | 8003 | PULONG); |
| @@ -8080,21 +8054,32 @@ emacs_abort (void) | |||
| 8080 | 8054 | ||
| 8081 | if (i) | 8055 | if (i) |
| 8082 | { | 8056 | { |
| 8057 | int errfile_fd = -1; | ||
| 8058 | int j; | ||
| 8059 | char buf[sizeof ("\r\nException at this address:\r\n\r\n") | ||
| 8060 | + 2 * INT_BUFSIZE_BOUND (void *)]; | ||
| 8083 | #ifdef CYGWIN | 8061 | #ifdef CYGWIN |
| 8084 | int stderr_fd = 2; | 8062 | int stderr_fd = 2; |
| 8085 | #else | 8063 | #else |
| 8086 | HANDLE errout = GetStdHandle (STD_ERROR_HANDLE); | 8064 | HANDLE errout = GetStdHandle (STD_ERROR_HANDLE); |
| 8087 | int stderr_fd = -1; | 8065 | int stderr_fd = -1; |
| 8088 | #endif | ||
| 8089 | int errfile_fd = -1; | ||
| 8090 | int j; | ||
| 8091 | 8066 | ||
| 8092 | #ifndef CYGWIN | ||
| 8093 | if (errout && errout != INVALID_HANDLE_VALUE) | 8067 | if (errout && errout != INVALID_HANDLE_VALUE) |
| 8094 | stderr_fd = _open_osfhandle ((intptr_t)errout, O_APPEND | O_BINARY); | 8068 | stderr_fd = _open_osfhandle ((intptr_t)errout, O_APPEND | O_BINARY); |
| 8095 | #endif | 8069 | #endif |
| 8070 | |||
| 8071 | /* We use %p, not 0x%p, as %p produces a leading "0x" on XP, | ||
| 8072 | but not on Windows 7. addr2line doesn't mind a missing | ||
| 8073 | "0x", but will be confused by an extra one. */ | ||
| 8074 | if (except_addr) | ||
| 8075 | sprintf (buf, "\r\nException 0x%lx at this address:\r\n%p\r\n", | ||
| 8076 | except_code, except_addr); | ||
| 8096 | if (stderr_fd >= 0) | 8077 | if (stderr_fd >= 0) |
| 8097 | write (stderr_fd, "\r\nBacktrace:\r\n", 14); | 8078 | { |
| 8079 | if (except_addr) | ||
| 8080 | write (stderr_fd, buf, strlen (buf)); | ||
| 8081 | write (stderr_fd, "\r\nBacktrace:\r\n", 14); | ||
| 8082 | } | ||
| 8098 | #ifdef CYGWIN | 8083 | #ifdef CYGWIN |
| 8099 | #define _open open | 8084 | #define _open open |
| 8100 | #endif | 8085 | #endif |
| @@ -8102,17 +8087,17 @@ emacs_abort (void) | |||
| 8102 | if (errfile_fd >= 0) | 8087 | if (errfile_fd >= 0) |
| 8103 | { | 8088 | { |
| 8104 | lseek (errfile_fd, 0L, SEEK_END); | 8089 | lseek (errfile_fd, 0L, SEEK_END); |
| 8090 | if (except_addr) | ||
| 8091 | write (errfile_fd, buf, strlen (buf)); | ||
| 8105 | write (errfile_fd, "\r\nBacktrace:\r\n", 14); | 8092 | write (errfile_fd, "\r\nBacktrace:\r\n", 14); |
| 8106 | } | 8093 | } |
| 8107 | 8094 | ||
| 8108 | for (j = 0; j < i; j++) | 8095 | for (j = 0; j < i; j++) |
| 8109 | { | 8096 | { |
| 8110 | char buf[INT_BUFSIZE_BOUND (void *)]; | ||
| 8111 | |||
| 8112 | /* stack[] gives the return addresses, whereas we want | 8097 | /* stack[] gives the return addresses, whereas we want |
| 8113 | the address of the call, so decrease each address | 8098 | the address of the call, so decrease each address |
| 8114 | by approximate size of 1 CALL instruction. */ | 8099 | by approximate size of 1 CALL instruction. */ |
| 8115 | sprintf (buf, "0x%p\r\n", (char *)stack[j] - sizeof(void *)); | 8100 | sprintf (buf, "%p\r\n", (char *)stack[j] - sizeof(void *)); |
| 8116 | if (stderr_fd >= 0) | 8101 | if (stderr_fd >= 0) |
| 8117 | write (stderr_fd, buf, strlen (buf)); | 8102 | write (stderr_fd, buf, strlen (buf)); |
| 8118 | if (errfile_fd >= 0) | 8103 | if (errfile_fd >= 0) |
| @@ -8134,6 +8119,72 @@ emacs_abort (void) | |||
| 8134 | } | 8119 | } |
| 8135 | } | 8120 | } |
| 8136 | 8121 | ||
| 8122 | |||
| 8123 | |||
| 8124 | /* Initialization. */ | ||
| 8125 | |||
| 8126 | /* | ||
| 8127 | globals_of_w32fns is used to initialize those global variables that | ||
| 8128 | must always be initialized on startup even when the global variable | ||
| 8129 | initialized is non zero (see the function main in emacs.c). | ||
| 8130 | globals_of_w32fns is called from syms_of_w32fns when the global | ||
| 8131 | variable initialized is 0 and directly from main when initialized | ||
| 8132 | is non zero. | ||
| 8133 | */ | ||
| 8134 | void | ||
| 8135 | globals_of_w32fns (void) | ||
| 8136 | { | ||
| 8137 | HMODULE user32_lib = GetModuleHandle ("user32.dll"); | ||
| 8138 | /* | ||
| 8139 | TrackMouseEvent not available in all versions of Windows, so must load | ||
| 8140 | it dynamically. Do it once, here, instead of every time it is used. | ||
| 8141 | */ | ||
| 8142 | track_mouse_event_fn = (TrackMouseEvent_Proc) | ||
| 8143 | GetProcAddress (user32_lib, "TrackMouseEvent"); | ||
| 8144 | |||
| 8145 | monitor_from_point_fn = (MonitorFromPoint_Proc) | ||
| 8146 | GetProcAddress (user32_lib, "MonitorFromPoint"); | ||
| 8147 | get_monitor_info_fn = (GetMonitorInfo_Proc) | ||
| 8148 | GetProcAddress (user32_lib, "GetMonitorInfoA"); | ||
| 8149 | monitor_from_window_fn = (MonitorFromWindow_Proc) | ||
| 8150 | GetProcAddress (user32_lib, "MonitorFromWindow"); | ||
| 8151 | enum_display_monitors_fn = (EnumDisplayMonitors_Proc) | ||
| 8152 | GetProcAddress (user32_lib, "EnumDisplayMonitors"); | ||
| 8153 | |||
| 8154 | { | ||
| 8155 | HMODULE imm32_lib = GetModuleHandle ("imm32.dll"); | ||
| 8156 | get_composition_string_fn = (ImmGetCompositionString_Proc) | ||
| 8157 | GetProcAddress (imm32_lib, "ImmGetCompositionStringW"); | ||
| 8158 | get_ime_context_fn = (ImmGetContext_Proc) | ||
| 8159 | GetProcAddress (imm32_lib, "ImmGetContext"); | ||
| 8160 | release_ime_context_fn = (ImmReleaseContext_Proc) | ||
| 8161 | GetProcAddress (imm32_lib, "ImmReleaseContext"); | ||
| 8162 | set_ime_composition_window_fn = (ImmSetCompositionWindow_Proc) | ||
| 8163 | GetProcAddress (imm32_lib, "ImmSetCompositionWindow"); | ||
| 8164 | } | ||
| 8165 | |||
| 8166 | except_code = 0; | ||
| 8167 | except_addr = 0; | ||
| 8168 | #ifndef CYGWIN | ||
| 8169 | prev_exception_handler = SetUnhandledExceptionFilter (my_exception_handler); | ||
| 8170 | #endif | ||
| 8171 | |||
| 8172 | DEFVAR_INT ("w32-ansi-code-page", | ||
| 8173 | w32_ansi_code_page, | ||
| 8174 | doc: /* The ANSI code page used by the system. */); | ||
| 8175 | w32_ansi_code_page = GetACP (); | ||
| 8176 | |||
| 8177 | if (os_subtype == OS_NT) | ||
| 8178 | w32_unicode_gui = 1; | ||
| 8179 | else | ||
| 8180 | w32_unicode_gui = 0; | ||
| 8181 | |||
| 8182 | /* MessageBox does not work without this when linked to comctl32.dll 6.0. */ | ||
| 8183 | InitCommonControls (); | ||
| 8184 | |||
| 8185 | syms_of_w32uniscribe (); | ||
| 8186 | } | ||
| 8187 | |||
| 8137 | #ifdef NTGUI_UNICODE | 8188 | #ifdef NTGUI_UNICODE |
| 8138 | 8189 | ||
| 8139 | Lisp_Object | 8190 | Lisp_Object |