diff options
| author | Eli Zaretskii | 2024-01-26 15:01:51 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2024-01-26 15:01:51 +0200 |
| commit | de020255a5cef4349d786fceb19481352c49557b (patch) | |
| tree | 983b2f255dbdeeb4c3c302adcf7f92ea77c6b75b | |
| parent | 723b0973512c0e6e9fb0f07678124347ccd44b54 (diff) | |
| download | emacs-de020255a5cef4349d786fceb19481352c49557b.tar.gz emacs-de020255a5cef4349d786fceb19481352c49557b.zip | |
Fix crash backtraces on MS-Windows, broken by ASLR
* src/w32fns.c (DEFAULT_IMAGE_BASE): Define for 64-bit and 32-bit
MinGW builds.
(emacs_abort): Correct the callstack addresses for potential
relocation of the image base due to ASLR. This makes 'addr2line'
be able to interpret emacs_backtrace.txt when ASLR is in effect,
which it is on every modern version of MS-Windows. (Bug#63365)
* configure.ac (LD_SWITCH_SYSTEM_TEMACS) [mingw32]: Add comment
about keeping the image-base values in sync with w32fns.c.
* etc/DEBUG (How to disable ASLR): New section.
| -rw-r--r-- | configure.ac | 2 | ||||
| -rw-r--r-- | etc/DEBUG | 33 | ||||
| -rw-r--r-- | src/w32fns.c | 26 |
3 files changed, 57 insertions, 4 deletions
diff --git a/configure.ac b/configure.ac index 55f742ba8ef..fa8b04ec685 100644 --- a/configure.ac +++ b/configure.ac | |||
| @@ -7463,6 +7463,8 @@ case "$opsys" in | |||
| 7463 | 7463 | ||
| 7464 | mingw32) | 7464 | mingw32) |
| 7465 | ## Is it any better under MinGW64 to relocate emacs into higher addresses? | 7465 | ## Is it any better under MinGW64 to relocate emacs into higher addresses? |
| 7466 | ## If the values of -image-base are modified, the corresponding | ||
| 7467 | ## values of DEFAULT_IMAGE_BASE in w32fns.c should be kept in sync. | ||
| 7466 | case "$canonical" in | 7468 | case "$canonical" in |
| 7467 | x86_64-*-*) LD_SWITCH_SYSTEM_TEMACS="-Wl,-stack,0x00800000 -Wl,-heap,0x00100000 -Wl,-image-base,0x400000000 -Wl,-entry,__start -Wl,-Map,./temacs.map" ;; | 7469 | x86_64-*-*) LD_SWITCH_SYSTEM_TEMACS="-Wl,-stack,0x00800000 -Wl,-heap,0x00100000 -Wl,-image-base,0x400000000 -Wl,-entry,__start -Wl,-Map,./temacs.map" ;; |
| 7468 | *) LD_SWITCH_SYSTEM_TEMACS="-Wl,-stack,0x00800000 -Wl,-heap,0x00100000 -Wl,-image-base,0x01000000 -Wl,-entry,__start -Wl,-Map,./temacs.map" ;; | 7470 | *) LD_SWITCH_SYSTEM_TEMACS="-Wl,-stack,0x00800000 -Wl,-heap,0x00100000 -Wl,-image-base,0x01000000 -Wl,-entry,__start -Wl,-Map,./temacs.map" ;; |
| @@ -928,7 +928,10 @@ data that is modified only very rarely.) | |||
| 928 | 928 | ||
| 929 | It is also useful to look at the corrupted object or data structure in | 929 | It is also useful to look at the corrupted object or data structure in |
| 930 | a fresh Emacs session and compare its contents with a session that you | 930 | a fresh Emacs session and compare its contents with a session that you |
| 931 | are debugging. | 931 | are debugging. This might be somewhat harder on modern systems which |
| 932 | randomize addresses of running executables (the so-called Address | ||
| 933 | Space Layout Randomization, or ASLR, feature). If you have this | ||
| 934 | problem, see below under "How to disable ASLR". | ||
| 932 | 935 | ||
| 933 | ** Debugging the TTY (non-windowed) version | 936 | ** Debugging the TTY (non-windowed) version |
| 934 | 937 | ||
| @@ -1080,6 +1083,34 @@ suppresses some Valgrind false alarms during Emacs garbage collection: | |||
| 1080 | Unfortunately Valgrind suppression files tend to be system-dependent, | 1083 | Unfortunately Valgrind suppression files tend to be system-dependent, |
| 1081 | so you will need to keep one around that matches your system. | 1084 | so you will need to keep one around that matches your system. |
| 1082 | 1085 | ||
| 1086 | ** How to disable ASLR | ||
| 1087 | |||
| 1088 | Modern systems use the so-called Address Space Layout Randomization, | ||
| 1089 | (ASLR) feature, which randomizes the base address of running programs, | ||
| 1090 | making it harder for malicious software or hackers to find the address | ||
| 1091 | of some function or variable in a running program by looking at its | ||
| 1092 | executable file. This causes the address of the same symbol to be | ||
| 1093 | different across rerunning of the same program. Sometimes, it can be | ||
| 1094 | useful to disable ASLR, for example, if you want to compare objects in | ||
| 1095 | two different Emacs sessions. | ||
| 1096 | |||
| 1097 | On GNU/Linux, you can disable ASLR temporarily with the following | ||
| 1098 | shell command: | ||
| 1099 | |||
| 1100 | echo 0 > /proc/sys/kernel/randomize_va_space | ||
| 1101 | |||
| 1102 | or by running Emacs in an environment where ASLR is temporarily | ||
| 1103 | disabled: | ||
| 1104 | |||
| 1105 | setarch -R emacs [args...] | ||
| 1106 | |||
| 1107 | To disable ASLR in Emacs on MS-Windows, you will have to rebuild Emacs | ||
| 1108 | while adding '-Wl,-disable-dynamicbase' to LD_SWITCH_SYSTEM_TEMACS | ||
| 1109 | variable defined in src/Makefile. Alternatively, use some tool to | ||
| 1110 | edit the PE header of the Emacs executable file and reset the | ||
| 1111 | DYNAMIC_BASE (0x40) flag in the DllCharacteristics flags recorded by | ||
| 1112 | the PE header. | ||
| 1113 | |||
| 1083 | ** How to recover buffer contents from an Emacs core dump file | 1114 | ** How to recover buffer contents from an Emacs core dump file |
| 1084 | 1115 | ||
| 1085 | The file etc/emacs-buffer.gdb defines a set of GDB commands for | 1116 | The file etc/emacs-buffer.gdb defines a set of GDB commands for |
diff --git a/src/w32fns.c b/src/w32fns.c index f8de45da7c9..f44460e52c0 100644 --- a/src/w32fns.c +++ b/src/w32fns.c | |||
| @@ -11121,12 +11121,20 @@ my_exception_handler (EXCEPTION_POINTERS * exception_data) | |||
| 11121 | return prev_exception_handler (exception_data); | 11121 | return prev_exception_handler (exception_data); |
| 11122 | return EXCEPTION_EXECUTE_HANDLER; | 11122 | return EXCEPTION_EXECUTE_HANDLER; |
| 11123 | } | 11123 | } |
| 11124 | #endif | 11124 | #endif /* !CYGWIN */ |
| 11125 | 11125 | ||
| 11126 | typedef USHORT (WINAPI * CaptureStackBackTrace_proc) (ULONG, ULONG, PVOID *, | 11126 | typedef USHORT (WINAPI * CaptureStackBackTrace_proc) (ULONG, ULONG, PVOID *, |
| 11127 | PULONG); | 11127 | PULONG); |
| 11128 | 11128 | ||
| 11129 | #define BACKTRACE_LIMIT_MAX 62 | 11129 | #define BACKTRACE_LIMIT_MAX 62 |
| 11130 | /* The below must be kept in sync with the value of the | ||
| 11131 | -Wl,-image-base switch we use in LD_SWITCH_SYSTEM_TEMACS, see | ||
| 11132 | configure.ac. */ | ||
| 11133 | #if defined MINGW_W64 && EMACS_INT_MAX > LONG_MAX | ||
| 11134 | # define DEFAULT_IMAGE_BASE (ptrdiff_t)0x400000000 | ||
| 11135 | #else /* 32-bit MinGW build */ | ||
| 11136 | # define DEFAULT_IMAGE_BASE (ptrdiff_t)0x01000000 | ||
| 11137 | #endif | ||
| 11130 | 11138 | ||
| 11131 | static int | 11139 | static int |
| 11132 | w32_backtrace (void **buffer, int limit) | 11140 | w32_backtrace (void **buffer, int limit) |
| @@ -11181,6 +11189,13 @@ emacs_abort (void) | |||
| 11181 | { | 11189 | { |
| 11182 | void *stack[BACKTRACE_LIMIT_MAX + 1]; | 11190 | void *stack[BACKTRACE_LIMIT_MAX + 1]; |
| 11183 | int i = w32_backtrace (stack, BACKTRACE_LIMIT_MAX + 1); | 11191 | int i = w32_backtrace (stack, BACKTRACE_LIMIT_MAX + 1); |
| 11192 | #ifdef CYGWIN | ||
| 11193 | ptrdiff_t addr_offset = 0; | ||
| 11194 | #else /* MinGW */ | ||
| 11195 | /* The offset below is zero unless ASLR is in effect. */ | ||
| 11196 | ptrdiff_t addr_offset | ||
| 11197 | = DEFAULT_IMAGE_BASE - (ptrdiff_t)GetModuleHandle (NULL); | ||
| 11198 | #endif /* MinGW */ | ||
| 11184 | 11199 | ||
| 11185 | if (i) | 11200 | if (i) |
| 11186 | { | 11201 | { |
| @@ -11231,8 +11246,13 @@ emacs_abort (void) | |||
| 11231 | { | 11246 | { |
| 11232 | /* stack[] gives the return addresses, whereas we want | 11247 | /* stack[] gives the return addresses, whereas we want |
| 11233 | the address of the call, so decrease each address | 11248 | the address of the call, so decrease each address |
| 11234 | by approximate size of 1 CALL instruction. */ | 11249 | by approximate size of 1 CALL instruction. We add |
| 11235 | sprintf (buf, "%p\r\n", (char *)stack[j] - sizeof(void *)); | 11250 | ADDR_OFFSET to account for ASLR which changes the |
| 11251 | base address of the program's image in memory, | ||
| 11252 | whereas 'addr2line' needs to see addresses relative | ||
| 11253 | to the fixed base recorded in the PE header. */ | ||
| 11254 | sprintf (buf, "%p\r\n", | ||
| 11255 | (char *)stack[j] - sizeof(void *) + addr_offset); | ||
| 11236 | if (stderr_fd >= 0) | 11256 | if (stderr_fd >= 0) |
| 11237 | write (stderr_fd, buf, strlen (buf)); | 11257 | write (stderr_fd, buf, strlen (buf)); |
| 11238 | if (errfile_fd >= 0) | 11258 | if (errfile_fd >= 0) |