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)