diff options
-rw-r--r-- | nptl/ChangeLog | 1 | ||||
-rw-r--r-- | nptl/descr.h | 24 | ||||
-rw-r--r-- | nptl/sysdeps/pthread/pthread.h | 2 | ||||
-rw-r--r-- | nptl/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h | 108 | ||||
-rw-r--r-- | nptl/unwind.c | 30 |
5 files changed, 132 insertions, 33 deletions
diff --git a/nptl/ChangeLog b/nptl/ChangeLog index bbda8c591e..d40118b42d 100644 --- a/nptl/ChangeLog +++ b/nptl/ChangeLog @@ -30,6 +30,7 @@ handler interfaces. * sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Add quite a bit of complication to generate unwind information for syscall wrappers. + * sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h: Likewise. * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Define __cleanup_fct_attribute. diff --git a/nptl/descr.h b/nptl/descr.h index 28b7afa1a1..efb25c7479 100644 --- a/nptl/descr.h +++ b/nptl/descr.h @@ -63,18 +63,19 @@ information. */ struct pthread_unwind_buf { + struct + { + __jmp_buf jmp_buf; + int mask_was_saved; + } cancel_jmp_buf[1]; + union { /* This is the placeholder of the public version. */ - void *pad[16]; + void *pad[4]; struct { -#ifdef HAVE_FORCED_UNWIND - /* First the machine-specific unwind info. */ - struct _Unwind_Exception exc; -#endif - /* Pointer to the previous cleanup buffer. */ __pthread_unwind_buf_t *prev; @@ -87,12 +88,6 @@ struct pthread_unwind_buf int canceltype; } data; } priv; - - struct - { - __jmp_buf jmp_buf; - int mask_was_saved; - } cancel_jmp_buf[1]; }; @@ -226,6 +221,11 @@ struct pthread /* Next descriptor with a pending event. */ struct pthread *nextevent; +#ifdef HAVE_FORCED_UNWIND + /* Machine-specific unwind info. */ + struct _Unwind_Exception exc; +#endif + /* If nonzero pointer to area allocated for the stack and its size. */ void *stackblock; diff --git a/nptl/sysdeps/pthread/pthread.h b/nptl/sysdeps/pthread/pthread.h index 5373b80dcf..1c59e1ea2e 100644 --- a/nptl/sysdeps/pthread/pthread.h +++ b/nptl/sysdeps/pthread/pthread.h @@ -385,12 +385,12 @@ extern void pthread_testcancel (void) __THROW; typedef struct { - void *__pad[16]; struct { __jmp_buf __cancel_jmp_buf; int __mask_was_saved; } __cancel_jmp_buf[1]; + void *__pad[4]; } __pthread_unwind_buf_t __attribute__ ((__aligned__)); /* No special attributes by default. */ diff --git a/nptl/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h b/nptl/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h index fde001d4a6..7e7bc49073 100644 --- a/nptl/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h +++ b/nptl/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h @@ -29,6 +29,7 @@ # define PSEUDO(name, syscall_name, args) \ .text; \ ENTRY (name) \ + L(name##START): \ SINGLE_THREAD_P; \ jne L(pseudo_cancel); \ DO_CALL (syscall_name, args); \ @@ -54,7 +55,100 @@ RESTSTK_##args \ cmpq $-4095, %rax; \ jae SYSCALL_ERROR_LABEL; \ - L(pseudo_end): + L(pseudo_end): \ + \ + /* Create unwinding information for the syscall wrapper. */ \ + .section .eh_frame,"a",@progbits; \ + L(STARTFRAME): \ + /* Length of the CIE. */ \ + .long L(ENDCIE)-L(STARTCIE); \ + L(STARTCIE): \ + /* CIE ID. */ \ + .long 0; \ + /* Version number. */ \ + .byte 1; \ + /* NUL-terminated augmentation string. Note "z" means there is an \ + augmentation value later on. */ \ + .string "zR"; \ + /* Code alignment factor. */ \ + .uleb128 1; \ + /* Data alignment factor. */ \ + .sleb128 -8; \ + /* Return address register column. */ \ + .byte 16; \ + /* Augmentation value length. */ \ + .uleb128 1; \ + /* Encoding: DW_EH_PE_pcrel + DW_EH_PE_sdata4. */ \ + .byte 0x1b; \ + /* Start of the table initialization. */ \ + .byte 0xc; \ + .uleb128 7; \ + .uleb128 8; \ + .byte 0x90; \ + .uleb128 1; \ + .align 8; \ + L(ENDCIE): \ + /* Length of the FDE. */ \ + .long L(ENDFDE)-L(STARTFDE); \ + L(STARTFDE): \ + /* CIE pointer. */ \ + .long L(STARTFDE)-L(STARTFRAME); \ + /* PC-relative start address of the code. */ \ + .long L(name##START)-.; \ + /* Length of the code. */ \ + .long L(name##END)-L(name##START); \ + /* No augmentation data. */ \ + .uleb128 0; \ + /* The rest of the code depends on the number of parameters the syscall \ + takes. */ \ + EH_FRAME_##args(name); \ + .align 4; \ + L(ENDFDE): \ + .previous + +# define EH_FRAME_0(name) \ + .byte 4; \ + .long L(SAVESTK)-L(name##START); \ + .byte 14; \ + .uleb128 32; \ + .byte 4; \ + .long L(RESTSTK)-L(SAVESTK); \ + .byte 14; \ + .uleb128 8; \ + .align 8 + +# define EH_FRAME_1(name) EH_FRAME_0 (name) +# define EH_FRAME_2(name) EH_FRAME_1 (name) + +# define EH_FRAME_3(name) \ + .byte 4; \ + .long L(SAVESTK)-L(name##START); \ + .byte 14; \ + .uleb128 48; \ + .byte 4; \ + .long L(RESTSTK)-L(SAVESTK); \ + .byte 14; \ + .uleb128 8; \ + .align 8 + +# define EH_FRAME_4(name) EH_FRAME_3 (name) + +# define EH_FRAME_5(name) \ + .byte 4; \ + .long L(SAVESTK)-L(name##START); \ + .byte 14; \ + .uleb128 64; \ + .byte 4; \ + .long L(RESTSTK)-L(SAVESTK); \ + .byte 14; \ + .uleb128 8; \ + .align 8 + +# define EH_FRAME_6(name) EH_FRAME_5 (name) + + +# undef ASM_SIZE_DIRECTIVE +# define ASM_SIZE_DIRECTIVE(name) L(name##END): .size name,.-name; # define PUSHARGS_0 /* Nothing. */ # define PUSHARGS_1 PUSHARGS_0 movq %rdi, 8(%rsp); @@ -73,20 +167,20 @@ # define POPARGS_6 POPARGS_5 movq 48(%rsp), %r9; /* We always have to align the stack before calling a function. */ -# define SAVESTK_0 subq $24, %rsp; +# define SAVESTK_0 subq $24, %rsp; L(SAVESTK): # define SAVESTK_1 SAVESTK_0 # define SAVESTK_2 SAVESTK_1 -# define SAVESTK_3 subq $40, %rsp; +# define SAVESTK_3 subq $40, %rsp; L(SAVESTK): # define SAVESTK_4 SAVESTK_3 -# define SAVESTK_5 subq $56, %rsp; +# define SAVESTK_5 subq $56, %rsp; L(SAVESTK): # define SAVESTK_6 SAVESTK_5 -# define RESTSTK_0 addq $24,%rsp; +# define RESTSTK_0 addq $24,%rsp; L(RESTSTK): # define RESTSTK_1 RESTSTK_0 # define RESTSTK_2 RESTSTK_1 -# define RESTSTK_3 addq $40, %rsp; +# define RESTSTK_3 addq $40, %rsp; L(RESTSTK): # define RESTSTK_4 RESTSTK_3 -# define RESTSTK_5 addq $56, %rsp; +# define RESTSTK_5 addq $56, %rsp; L(RESTSTK): # define RESTSTK_6 RESTSTK_5 # ifdef IS_IN_libpthread diff --git a/nptl/unwind.c b/nptl/unwind.c index 46c896d5b3..7529174d5a 100644 --- a/nptl/unwind.c +++ b/nptl/unwind.c @@ -69,28 +69,32 @@ __pthread_unwind (__pthread_unwind_buf_t *buf) struct _pthread_cleanup_buffer *oldp = ibuf->priv.data.cleanup; struct _pthread_cleanup_buffer *curp = THREAD_GETMEM (self, cleanup); - while (curp != oldp) + if (curp != oldp) { - /* Pointer to the next element. */ - struct _pthread_cleanup_buffer *nextp = curp->__prev; + do + { + /* Pointer to the next element. */ + struct _pthread_cleanup_buffer *nextp = curp->__prev; - /* Call the handler. */ - curp->__routine (curp->__arg); + /* Call the handler. */ + curp->__routine (curp->__arg); - /* To the next. */ - curp = nextp; - } + /* To the next. */ + curp = nextp; + } + while (curp != oldp); - /* Mark the current element as handled. */ - THREAD_SETMEM (self, cleanup, curp); + /* Mark the current element as handled. */ + THREAD_SETMEM (self, cleanup, curp); + } #ifdef HAVE_FORCED_UNWIND /* This is not a catchable exception, so don't provide any details about the exception type. We do need to initialize the field though. */ - ibuf->priv.data.exc.exception_class = 0; - ibuf->priv.data.exc.exception_cleanup = unwind_cleanup; + THREAD_SETMEM (self, exc.exception_class, 0); + THREAD_SETMEM (self, exc.exception_cleanup, unwind_cleanup); - _Unwind_ForcedUnwind (&ibuf->priv.data.exc, unwind_stop, ibuf); + _Unwind_ForcedUnwind (&self->exc, unwind_stop, ibuf); #else /* We simply jump to the registered setjmp buffer. */ __libc_longjmp ((struct __jmp_buf_tag *) ibuf->cancel_jmp_buf, 1); |