OSDN Git Service

whitespace fixes
[uclinux-h8/uClibc.git] / libpthread / nptl / sysdeps / unix / sysv / linux / arm / unwind-forcedunwind.c
1 /* Copyright (C) 2003, 2005 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Jakub Jelinek <jakub@redhat.com>.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public License as
7    published by the Free Software Foundation; either version 2.1 of the
8    License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.  */
19
20 #include <dlfcn.h>
21 #include <string.h>
22 #include <unwind.h>
23 #include <unistd.h>
24 #include <pthreadP.h>
25
26 #define __libc_dlopen(x)        dlopen(x, (RTLD_LOCAL | RTLD_LAZY))
27 #define __libc_dlsym            dlsym
28
29 static void (*libgcc_s_resume) (struct _Unwind_Exception *exc);
30 static _Unwind_Reason_Code (*libgcc_s_personality)
31   (_Unwind_State, struct _Unwind_Exception *, struct _Unwind_Context *);
32 static _Unwind_Reason_Code (*libgcc_s_forcedunwind)
33   (struct _Unwind_Exception *, _Unwind_Stop_Fn, void *);
34 static _Unwind_Word (*libgcc_s_getcfa) (struct _Unwind_Context *);
35
36 void
37 pthread_cancel_init (void)
38 {
39   void *resume, *personality, *forcedunwind, *getcfa;
40   void *handle;
41
42   if (__builtin_expect (libgcc_s_getcfa != NULL, 1))
43     return;
44
45   handle = __libc_dlopen ("libgcc_s.so.1");
46
47   if (handle == NULL
48       || (resume = __libc_dlsym (handle, "_Unwind_Resume")) == NULL
49       || (personality = __libc_dlsym (handle, "__gcc_personality_v0")) == NULL
50       || (forcedunwind = __libc_dlsym (handle, "_Unwind_ForcedUnwind"))
51          == NULL
52       || (getcfa = __libc_dlsym (handle, "_Unwind_GetCFA")) == NULL
53 #ifdef ARCH_CANCEL_INIT
54       || ARCH_CANCEL_INIT (handle)
55 #endif
56       )
57     {
58 # define STR_N_LEN(str) str, strlen (str)
59       INTERNAL_SYSCALL_DECL (err);
60       INTERNAL_SYSCALL (write, err, 3, STDERR_FILENO,
61                         STR_N_LEN ("libgcc_s.so.1 must be installed for pthread_cancel to work\n"));
62       abort ();
63     }
64
65   libgcc_s_resume = resume;
66   libgcc_s_personality = personality;
67   libgcc_s_forcedunwind = forcedunwind;
68   libgcc_s_getcfa = getcfa;
69 }
70
71 /* It's vitally important that _Unwind_Resume not have a stack frame; the
72    ARM unwinder relies on register state at entrance.  So we write this in
73    assembly.  */
74
75 asm (
76 #ifdef __thumb__
77 "       .code 32"
78 #endif
79 "       .globl  _Unwind_Resume\n"
80 "       .type   _Unwind_Resume, %function\n"
81 "_Unwind_Resume:\n"
82 "       stmfd   sp!, {r4, r5, r6, lr}\n"
83 "       ldr     r4, 1f\n"
84 "       ldr     r5, 2f\n"
85 "3:     add     r4, pc, r4\n"
86 "       ldr     r3, [r4, r5]\n"
87 "       mov     r6, r0\n"
88 "       cmp     r3, #0\n"
89 "       beq     4f\n"
90 "5:     mov     r0, r6\n"
91 "       ldmfd   sp!, {r4, r5, r6, lr}\n"
92 "       bx      r3\n"
93 "4:     bl      pthread_cancel_init\n"
94 "       ldr     r3, [r4, r5]\n"
95 "       b       5b\n"
96 "1:     .word   _GLOBAL_OFFSET_TABLE_ - 3b - 8\n"
97 "2:     .word   libgcc_s_resume(GOTOFF)\n"
98 "       .size   _Unwind_Resume, .-_Unwind_Resume\n"
99 #ifdef __thumb__
100 "       .code 16"
101 #endif
102 );
103
104 _Unwind_Reason_Code
105 __gcc_personality_v0 (_Unwind_State state,
106                       struct _Unwind_Exception *ue_header,
107                       struct _Unwind_Context *context)
108 {
109   if (__builtin_expect (libgcc_s_personality == NULL, 0))
110     pthread_cancel_init ();
111   return libgcc_s_personality (state, ue_header, context);
112 }
113
114 _Unwind_Reason_Code
115 _Unwind_ForcedUnwind (struct _Unwind_Exception *exc, _Unwind_Stop_Fn stop,
116                       void *stop_argument)
117 {
118   if (__builtin_expect (libgcc_s_forcedunwind == NULL, 0))
119     pthread_cancel_init ();
120   return libgcc_s_forcedunwind (exc, stop, stop_argument);
121 }
122
123 _Unwind_Word
124 _Unwind_GetCFA (struct _Unwind_Context *context)
125 {
126   if (__builtin_expect (libgcc_s_getcfa == NULL, 0))
127     pthread_cancel_init ();
128   return libgcc_s_getcfa (context);
129 }