summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEli Zaretskii <eliz@gnu.org>2024-01-26 15:01:51 +0200
committerEli Zaretskii <eliz@gnu.org>2024-01-26 15:01:51 +0200
commitde020255a5cef4349d786fceb19481352c49557b (patch)
tree983b2f255dbdeeb4c3c302adcf7f92ea77c6b75b
parent723b0973512c0e6e9fb0f07678124347ccd44b54 (diff)
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.ac2
-rw-r--r--etc/DEBUG33
-rw-r--r--src/w32fns.c26
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
mingw32)
## Is it any better under MinGW64 to relocate emacs into higher addresses?
+ ## If the values of -image-base are modified, the corresponding
+ ## values of DEFAULT_IMAGE_BASE in w32fns.c should be kept in sync.
case "$canonical" in
x86_64-*-*) LD_SWITCH_SYSTEM_TEMACS="-Wl,-stack,0x00800000 -Wl,-heap,0x00100000 -Wl,-image-base,0x400000000 -Wl,-entry,__start -Wl,-Map,./temacs.map" ;;
*) LD_SWITCH_SYSTEM_TEMACS="-Wl,-stack,0x00800000 -Wl,-heap,0x00100000 -Wl,-image-base,0x01000000 -Wl,-entry,__start -Wl,-Map,./temacs.map" ;;
diff --git a/etc/DEBUG b/etc/DEBUG
index 1680aab4385..6c7f4040b8d 100644
--- a/etc/DEBUG
+++ b/etc/DEBUG
@@ -928,7 +928,10 @@ data that is modified only very rarely.)
It is also useful to look at the corrupted object or data structure in
a fresh Emacs session and compare its contents with a session that you
-are debugging.
+are debugging. This might be somewhat harder on modern systems which
+randomize addresses of running executables (the so-called Address
+Space Layout Randomization, or ASLR, feature). If you have this
+problem, see below under "How to disable ASLR".
** Debugging the TTY (non-windowed) version
@@ -1080,6 +1083,34 @@ suppresses some Valgrind false alarms during Emacs garbage collection:
Unfortunately Valgrind suppression files tend to be system-dependent,
so you will need to keep one around that matches your system.
+** How to disable ASLR
+
+Modern systems use the so-called Address Space Layout Randomization,
+(ASLR) feature, which randomizes the base address of running programs,
+making it harder for malicious software or hackers to find the address
+of some function or variable in a running program by looking at its
+executable file. This causes the address of the same symbol to be
+different across rerunning of the same program. Sometimes, it can be
+useful to disable ASLR, for example, if you want to compare objects in
+two different Emacs sessions.
+
+On GNU/Linux, you can disable ASLR temporarily with the following
+shell command:
+
+ echo 0 > /proc/sys/kernel/randomize_va_space
+
+or by running Emacs in an environment where ASLR is temporarily
+disabled:
+
+ setarch -R emacs [args...]
+
+To disable ASLR in Emacs on MS-Windows, you will have to rebuild Emacs
+while adding '-Wl,-disable-dynamicbase' to LD_SWITCH_SYSTEM_TEMACS
+variable defined in src/Makefile. Alternatively, use some tool to
+edit the PE header of the Emacs executable file and reset the
+DYNAMIC_BASE (0x40) flag in the DllCharacteristics flags recorded by
+the PE header.
+
** How to recover buffer contents from an Emacs core dump file
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)
return prev_exception_handler (exception_data);
return EXCEPTION_EXECUTE_HANDLER;
}
-#endif
+#endif /* !CYGWIN */
typedef USHORT (WINAPI * CaptureStackBackTrace_proc) (ULONG, ULONG, PVOID *,
PULONG);
#define BACKTRACE_LIMIT_MAX 62
+/* The below must be kept in sync with the value of the
+ -Wl,-image-base switch we use in LD_SWITCH_SYSTEM_TEMACS, see
+ configure.ac. */
+#if defined MINGW_W64 && EMACS_INT_MAX > LONG_MAX
+# define DEFAULT_IMAGE_BASE (ptrdiff_t)0x400000000
+#else /* 32-bit MinGW build */
+# define DEFAULT_IMAGE_BASE (ptrdiff_t)0x01000000
+#endif
static int
w32_backtrace (void **buffer, int limit)
@@ -11181,6 +11189,13 @@ emacs_abort (void)
{
void *stack[BACKTRACE_LIMIT_MAX + 1];
int i = w32_backtrace (stack, BACKTRACE_LIMIT_MAX + 1);
+#ifdef CYGWIN
+ ptrdiff_t addr_offset = 0;
+#else /* MinGW */
+ /* The offset below is zero unless ASLR is in effect. */
+ ptrdiff_t addr_offset
+ = DEFAULT_IMAGE_BASE - (ptrdiff_t)GetModuleHandle (NULL);
+#endif /* MinGW */
if (i)
{
@@ -11231,8 +11246,13 @@ emacs_abort (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, "%p\r\n", (char *)stack[j] - sizeof(void *));
+ by approximate size of 1 CALL instruction. We add
+ ADDR_OFFSET to account for ASLR which changes the
+ base address of the program's image in memory,
+ whereas 'addr2line' needs to see addresses relative
+ to the fixed base recorded in the PE header. */
+ sprintf (buf, "%p\r\n",
+ (char *)stack[j] - sizeof(void *) + addr_offset);
if (stderr_fd >= 0)
write (stderr_fd, buf, strlen (buf));
if (errfile_fd >= 0)