diff options
author | Khem Raj <raj.khem@gmail.com> | 2010-06-23 16:30:54 -0700 |
---|---|---|
committer | Khem Raj <raj.khem@gmail.com> | 2010-06-23 16:30:54 -0700 |
commit | 6cbeaa5dd11a1b506a8a97b4dfb4e632240f9953 (patch) | |
tree | 2c8e5e67a572e27a6a2a03b9e9cd3ec1c779102f /libpthread/nptl/sysdeps/unix/sysv/linux | |
parent | 84fa9cf6cb8d8b59a0d2fc889fd78ce6a9309420 (diff) |
arm/nptl: Sync unwinding with glibc.
Signed-off-by: Khem Raj <raj.khem@gmail.com>
Diffstat (limited to 'libpthread/nptl/sysdeps/unix/sysv/linux')
-rw-r--r-- | libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c | 108 | ||||
-rw-r--r-- | libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-resume.c | 102 |
2 files changed, 116 insertions, 94 deletions
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c index d095d3083..011746d0e 100644 --- a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2003, 2009 Free Software Foundation, Inc. +/* Copyright (C) 2003, 2005, 2007, 2009, 2010 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Jakub Jelinek <jakub@redhat.com>. @@ -21,20 +21,14 @@ #include <stdio.h> #include <unwind.h> #include <pthreadP.h> -#define __libc_dlopen(x) dlopen(x, (RTLD_LOCAL | RTLD_LAZY)) -#define __libc_dlsym dlsym -#define __libc_dlclose dlclose static void *libgcc_s_handle; static void (*libgcc_s_resume) (struct _Unwind_Exception *exc); static _Unwind_Reason_Code (*libgcc_s_personality) - (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *, - struct _Unwind_Context *); + (_Unwind_State, struct _Unwind_Exception *, struct _Unwind_Context *); static _Unwind_Reason_Code (*libgcc_s_forcedunwind) (struct _Unwind_Exception *, _Unwind_Stop_Fn, void *); static _Unwind_Word (*libgcc_s_getcfa) (struct _Unwind_Context *); -static void (*libgcc_s_sjlj_register) (struct SjLj_Function_Context *); -static void (*libgcc_s_sjlj_unregister) (struct SjLj_Function_Context *); void __attribute_noinline__ @@ -42,7 +36,6 @@ pthread_cancel_init (void) { void *resume, *personality, *forcedunwind, *getcfa; void *handle; - void *sjlj_register, *sjlj_unregister; if (__builtin_expect (libgcc_s_handle != NULL, 1)) { @@ -54,21 +47,20 @@ pthread_cancel_init (void) handle = __libc_dlopen ("libgcc_s.so.1"); if (handle == NULL - || (sjlj_register = __libc_dlsym (handle, "_Unwind_SjLj_Register")) == NULL - || (sjlj_unregister = __libc_dlsym (handle, "_Unwind_SjLj_Unregister")) == NULL - || (resume = __libc_dlsym (handle, "_Unwind_SjLj_Resume")) == NULL - || (personality = __libc_dlsym (handle, "__gcc_personality_sj0")) == NULL - || (forcedunwind = __libc_dlsym (handle, "_Unwind_SjLj_ForcedUnwind")) + || (resume = __libc_dlsym (handle, "_Unwind_Resume")) == NULL + || (personality = __libc_dlsym (handle, "__gcc_personality_v0")) == NULL + || (forcedunwind = __libc_dlsym (handle, "_Unwind_ForcedUnwind")) == NULL || (getcfa = __libc_dlsym (handle, "_Unwind_GetCFA")) == NULL +#ifdef ARCH_CANCEL_INIT + || ARCH_CANCEL_INIT (handle) +#endif ) - fprintf(stderr, "libgcc_s.so.1 must be installed for pthread_cancel to work\n"); + __libc_fatal ("libgcc_s.so.1 must be installed for pthread_cancel to work\n"); libgcc_s_resume = resume; libgcc_s_personality = personality; libgcc_s_forcedunwind = forcedunwind; - libgcc_s_sjlj_register = sjlj_register; - libgcc_s_sjlj_unregister = sjlj_unregister; libgcc_s_getcfa = getcfa; /* Make sure libgcc_s_getcfa is written last. Otherwise, pthread_cancel_init might return early even when the pointer the @@ -89,26 +81,62 @@ __unwind_freeres (void) } } -void -_Unwind_Resume (struct _Unwind_Exception *exc) -{ - if (__builtin_expect (libgcc_s_resume == NULL, 0)) - pthread_cancel_init (); - - libgcc_s_resume (exc); -} +/* It's vitally important that _Unwind_Resume not have a stack frame; the + ARM unwinder relies on register state at entrance. So we write this in + assembly. */ + +asm ( +" .globl _Unwind_Resume\n" +" .type _Unwind_Resume, %function\n" +"_Unwind_Resume:\n" +" .cfi_sections .debug_frame\n" +" " CFI_STARTPROC "\n" +" stmfd sp!, {r4, r5, r6, lr}\n" +" " CFI_ADJUST_CFA_OFFSET (16)" \n" +" " CFI_REL_OFFSET (r4, 0) "\n" +" " CFI_REL_OFFSET (r5, 4) "\n" +" " CFI_REL_OFFSET (r6, 8) "\n" +" " CFI_REL_OFFSET (lr, 12) "\n" +" " CFI_REMEMBER_STATE "\n" +" ldr r4, 1f\n" +" ldr r5, 2f\n" +"3: add r4, pc, r4\n" +" ldr r3, [r4, r5]\n" +" mov r6, r0\n" +" cmp r3, #0\n" +" beq 4f\n" +"5: mov r0, r6\n" +" ldmfd sp!, {r4, r5, r6, lr}\n" +" " CFI_ADJUST_CFA_OFFSET (-16) "\n" +" " CFI_RESTORE (r4) "\n" +" " CFI_RESTORE (r5) "\n" +" " CFI_RESTORE (r6) "\n" +" " CFI_RESTORE (lr) "\n" +" bx r3\n" +" " CFI_RESTORE_STATE "\n" +"4: bl pthread_cancel_init\n" +" ldr r3, [r4, r5]\n" +" b 5b\n" +" " CFI_ENDPROC "\n" +" .align 2\n" +#ifdef __thumb2__ +"1: .word _GLOBAL_OFFSET_TABLE_ - 3b - 4\n" +#else +"1: .word _GLOBAL_OFFSET_TABLE_ - 3b - 8\n" +#endif +"2: .word libgcc_s_resume(GOTOFF)\n" +" .size _Unwind_Resume, .-_Unwind_Resume\n" +); _Unwind_Reason_Code -__gcc_personality_v0 (int version, _Unwind_Action actions, - _Unwind_Exception_Class exception_class, - struct _Unwind_Exception *ue_header, - struct _Unwind_Context *context) +__gcc_personality_v0 (_Unwind_State state, + struct _Unwind_Exception *ue_header, + struct _Unwind_Context *context) { if (__builtin_expect (libgcc_s_personality == NULL, 0)) pthread_cancel_init (); - return libgcc_s_personality (version, actions, exception_class, - ue_header, context); + return libgcc_s_personality (state, ue_header, context); } _Unwind_Reason_Code @@ -129,21 +157,3 @@ _Unwind_GetCFA (struct _Unwind_Context *context) return libgcc_s_getcfa (context); } - -void -_Unwind_SjLj_Register (struct SjLj_Function_Context *fc) -{ - if (__builtin_expect (libgcc_s_sjlj_register == NULL, 0)) - pthread_cancel_init (); - - libgcc_s_sjlj_register (fc); -} - -void -_Unwind_SjLj_Unregister (struct SjLj_Function_Context *fc) -{ - if (__builtin_expect (libgcc_s_sjlj_unregister == NULL, 0)) - pthread_cancel_init (); - - libgcc_s_sjlj_unregister (fc); -} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-resume.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-resume.c index bf0348ac2..cdab10e30 100644 --- a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-resume.c +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-resume.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2003 Free Software Foundation, Inc. +/* Copyright (C) 2003, 2005, 2010 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Jakub Jelinek <jakub@redhat.com>. @@ -20,71 +20,83 @@ #include <dlfcn.h> #include <stdio.h> #include <unwind.h> -#define __libc_dlopen(x) dlopen(x, (RTLD_LOCAL | RTLD_LAZY)) -#define __libc_dlsym dlsym -#define __libc_dlclose dlclose static void (*libgcc_s_resume) (struct _Unwind_Exception *exc); static _Unwind_Reason_Code (*libgcc_s_personality) - (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *, - struct _Unwind_Context *); -static void (*libgcc_s_sjlj_register) (struct SjLj_Function_Context *); -static void (*libgcc_s_sjlj_unregister) (struct SjLj_Function_Context *); + (_Unwind_State, struct _Unwind_Exception *, struct _Unwind_Context *); + +static void init (void) __attribute_used__; static void init (void) { void *resume, *personality; void *handle; - void *sjlj_register, *sjlj_unregister; handle = __libc_dlopen ("libgcc_s.so.1"); if (handle == NULL - || (sjlj_register = __libc_dlsym (handle, "_Unwind_SjLj_Register")) == NULL - || (sjlj_unregister = __libc_dlsym (handle, "_Unwind_SjLj_Unregister")) == NULL - || (resume = __libc_dlsym (handle, "_Unwind_SjLj_Resume")) == NULL - || (personality = __libc_dlsym (handle, "__gcc_personality_sj0")) == NULL) - fprintf(stderr, "libgcc_s.so.1 must be installed for pthread_cancel to work\n"); + || (resume = __libc_dlsym (handle, "_Unwind_Resume")) == NULL + || (personality = __libc_dlsym (handle, "__gcc_personality_v0")) == NULL) + __libc_fatal ("libgcc_s.so.1 must be installed for pthread_cancel to work\n"); libgcc_s_resume = resume; libgcc_s_personality = personality; - libgcc_s_sjlj_register = sjlj_register; - libgcc_s_sjlj_unregister = sjlj_unregister; } -void -_Unwind_Resume (struct _Unwind_Exception *exc) -{ - if (__builtin_expect (libgcc_s_resume == NULL, 0)) - init (); - libgcc_s_resume (exc); -} +/* It's vitally important that _Unwind_Resume not have a stack frame; the + ARM unwinder relies on register state at entrance. So we write this in + assembly. */ + +asm ( +" .globl _Unwind_Resume\n" +" .type _Unwind_Resume, %function\n" +"_Unwind_Resume:\n" +" .cfi_sections .debug_frame\n" +" " CFI_STARTPROC "\n" +" stmfd sp!, {r4, r5, r6, lr}\n" +" " CFI_ADJUST_CFA_OFFSET (16)" \n" +" " CFI_REL_OFFSET (r4, 0) "\n" +" " CFI_REL_OFFSET (r5, 4) "\n" +" " CFI_REL_OFFSET (r6, 8) "\n" +" " CFI_REL_OFFSET (lr, 12) "\n" +" " CFI_REMEMBER_STATE "\n" +" ldr r4, 1f\n" +" ldr r5, 2f\n" +"3: add r4, pc, r4\n" +" ldr r3, [r4, r5]\n" +" mov r6, r0\n" +" cmp r3, #0\n" +" beq 4f\n" +"5: mov r0, r6\n" +" ldmfd sp!, {r4, r5, r6, lr}\n" +" " CFI_ADJUST_CFA_OFFSET (-16) "\n" +" " CFI_RESTORE (r4) "\n" +" " CFI_RESTORE (r5) "\n" +" " CFI_RESTORE (r6) "\n" +" " CFI_RESTORE (lr) "\n" +" bx r3\n" +" " CFI_RESTORE_STATE "\n" +"4: bl init\n" +" ldr r3, [r4, r5]\n" +" b 5b\n" +" " CFI_ENDPROC "\n" +" .align 2\n" +#ifdef __thumb2__ +"1: .word _GLOBAL_OFFSET_TABLE_ - 3b - 4\n" +#else +"1: .word _GLOBAL_OFFSET_TABLE_ - 3b - 8\n" +#endif +"2: .word libgcc_s_resume(GOTOFF)\n" +" .size _Unwind_Resume, .-_Unwind_Resume\n" +); _Unwind_Reason_Code -__gcc_personality_v0 (int version, _Unwind_Action actions, - _Unwind_Exception_Class exception_class, - struct _Unwind_Exception *ue_header, - struct _Unwind_Context *context) +__gcc_personality_v0 (_Unwind_State state, + struct _Unwind_Exception *ue_header, + struct _Unwind_Context *context) { if (__builtin_expect (libgcc_s_personality == NULL, 0)) init (); - return libgcc_s_personality (version, actions, exception_class, - ue_header, context); -} - -void -_Unwind_SjLj_Register (struct SjLj_Function_Context *fc) -{ - if (__builtin_expect (libgcc_s_sjlj_register == NULL, 0)) - init (); - libgcc_s_sjlj_register (fc); -} - -void -_Unwind_SjLj_Unregister (struct SjLj_Function_Context *fc) -{ - if (__builtin_expect (libgcc_s_sjlj_unregister == NULL, 0)) - init (); - libgcc_s_sjlj_unregister (fc); + return libgcc_s_personality (state, ue_header, context); } |