aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Matz <matz@suse.de>2010-08-22 16:53:24 +0200
committerPetr Baudis <pasky@suse.cz>2010-11-16 02:50:19 +0100
commit31eb5a4c4986367538ccb154dfce0c84276ba151 (patch)
treed5fdda573b28dd3c55ddd3acd0a580262ba97b92
parent9fcff7a79b60cd9202fdacafdbd5fb369933c64b (diff)
downloadglibc-31eb5a4c4986367538ccb154dfce0c84276ba151.zip
glibc-31eb5a4c4986367538ccb154dfce0c84276ba151.tar.gz
glibc-31eb5a4c4986367538ccb154dfce0c84276ba151.tar.bz2
Add proper unwind information for x86_64 _fini
It is impossible to reliably unwind the stack above _fini() on x86_64 since no unwind information is provided for it and it modifies a stack register. This matters for gdb backtracing - if a process crashes within a destructor, it can frequently be essential to look at why the program began terminating in the first place.
-rw-r--r--ChangeLog5
-rw-r--r--sysdeps/x86_64/elf/initfini.c33
2 files changed, 37 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index 122a2b8..d253fde 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2010-05-17 Michael Matz <matz@suse.de>
+
+ [BZ #11610]
+ * sysdeps/x86_64/elf/initfini.c (_fini): Add unwind information.
+
2010-05-12 Petr Baudis <pasky@suse.cz>
[BZ #11589]
diff --git a/sysdeps/x86_64/elf/initfini.c b/sysdeps/x86_64/elf/initfini.c
index 30161d5..dd1a4ce 100644
--- a/sysdeps/x86_64/elf/initfini.c
+++ b/sysdeps/x86_64/elf/initfini.c
@@ -44,6 +44,25 @@
* crtn.s puts the corresponding function epilogues
in the .init and .fini sections. */
+/* The unwind annotation for _fini is peculiar for good reasons:
+ (a) We need a real function that isn't constructed separately
+ (i.e. one which has a .size directive) in order to attach unwind
+ info to it. Hence _fini is a wrapper around _real_fini, the
+ former being a normal function, the latter being the first
+ instruction of the traditional _fini.
+ (b) We must not fiddle with the stack pointer in _real_fini,
+ as we wouldn't be able to describe the effects in unwind info
+ (c) some versions of GCC have no correct unwind info for
+ __do_global_dtors_aux, meaning they can't properly restore %rbp
+ (unwinding through it is possible but later up when we next
+ need %rbp we can't access it anymore)
+ Therefore we save/restore it in _fini for uses later up the call chain.
+ But we don't make the CFA use that register (that would lead to
+ the above problem)
+ (d) We want an 16-aligned stack pointer at _real_fini. Because of (a)
+ we can't align it in _real_fini, hence we do it in the caller by
+ subtracting 8, making in 8mod16 which the call then make 0mod16
+ again. */
__asm__ ("\n\
#include \"defs.h\"\n\
\n\
@@ -88,16 +107,28 @@ _init:\n\
.globl _fini\n\
.type _fini,@function\n\
_fini:\n\
+ .cfi_startproc\n\
+ push %rbp\n\
+ .cfi_def_cfa_offset 16\n\
+ .cfi_offset 6,-16\n\
subq $8, %rsp\n\
+ .cfi_def_cfa_offset 24\n\
+ call _real_fini\n\
+ addq $8, %rsp\n\
+ .cfi_def_cfa_offset 16\n\
+ pop %rbp\n\
+ ret\n\
+ .cfi_endproc\n\
ALIGN\n\
END_FINI\n\
+.size _fini, .-_fini\n\
+_real_fini:\n\
\n\
/*@_fini_PROLOG_ENDS*/\n\
call i_am_not_a_leaf@PLT\n\
\n\
/*@_fini_EPILOG_BEGINS*/\n\
.section .fini\n\
- addq $8, %rsp\n\
ret\n\
END_FINI\n\
\n\