]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
Add proper unwind information for x86_64 _fini
authorMichael Matz <matz@suse.de>
Sun, 22 Aug 2010 14:53:24 +0000 (16:53 +0200)
committerPetr Baudis <pasky@suse.cz>
Tue, 16 Nov 2010 01:50:19 +0000 (02:50 +0100)
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.

ChangeLog
sysdeps/x86_64/elf/initfini.c

index 122a2b874343b6cf1fd0f756903961100d09fcbf..d253fde600c6e77585fe943dc3ce2c9e34d4b906 100644 (file)
--- 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]
index 30161d52eddd6f49b1913d96523cb690d0a76285..dd1a4cedc97581da26f546247ae57b3811073fca 100644 (file)
    * 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\