]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / sysdeps / unix / sysv / linux / arm / unwind-forcedunwind.c
CommitLineData
b168057a 1/* Copyright (C) 2003-2015 Free Software Foundation, Inc.
02a9f771
DJ
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
ab84e3ff
PE
16 License along with the GNU C Library. If not, see
17 <http://www.gnu.org/licenses/>. */
02a9f771
DJ
18
19#include <dlfcn.h>
20#include <stdio.h>
21#include <unwind.h>
22#include <pthreadP.h>
23
f281f9cf 24static void *libgcc_s_handle;
175cef41
JM
25static void (*libgcc_s_resume) (struct _Unwind_Exception *exc)
26 __attribute_used__;
02a9f771
DJ
27static _Unwind_Reason_Code (*libgcc_s_personality)
28 (_Unwind_State, struct _Unwind_Exception *, struct _Unwind_Context *);
29static _Unwind_Reason_Code (*libgcc_s_forcedunwind)
30 (struct _Unwind_Exception *, _Unwind_Stop_Fn, void *);
31static _Unwind_Word (*libgcc_s_getcfa) (struct _Unwind_Context *);
32
33void
8323b1ab 34__attribute_noinline__
02a9f771
DJ
35pthread_cancel_init (void)
36{
37 void *resume, *personality, *forcedunwind, *getcfa;
38 void *handle;
39
f281f9cf 40 if (__builtin_expect (libgcc_s_handle != NULL, 1))
8323b1ab
DJ
41 {
42 /* Force gcc to reload all values. */
43 asm volatile ("" ::: "memory");
44 return;
45 }
02a9f771
DJ
46
47 handle = __libc_dlopen ("libgcc_s.so.1");
48
49 if (handle == NULL
50 || (resume = __libc_dlsym (handle, "_Unwind_Resume")) == NULL
51 || (personality = __libc_dlsym (handle, "__gcc_personality_v0")) == NULL
52 || (forcedunwind = __libc_dlsym (handle, "_Unwind_ForcedUnwind"))
53 == NULL
54 || (getcfa = __libc_dlsym (handle, "_Unwind_GetCFA")) == NULL
55#ifdef ARCH_CANCEL_INIT
56 || ARCH_CANCEL_INIT (handle)
57#endif
58 )
59 __libc_fatal ("libgcc_s.so.1 must be installed for pthread_cancel to work\n");
60
61 libgcc_s_resume = resume;
62 libgcc_s_personality = personality;
63 libgcc_s_forcedunwind = forcedunwind;
f281f9cf 64 libgcc_s_getcfa = getcfa;
8323b1ab
DJ
65 /* Make sure libgcc_s_getcfa is written last. Otherwise,
66 pthread_cancel_init might return early even when the pointer the
67 caller is interested in is not initialized yet. */
68 atomic_write_barrier ();
f281f9cf
JM
69 libgcc_s_handle = handle;
70}
71
72void
73__libc_freeres_fn_section
74__unwind_freeres (void)
75{
76 void *handle = libgcc_s_handle;
77 if (handle != NULL)
78 {
79 libgcc_s_handle = NULL;
80 __libc_dlclose (handle);
81 }
02a9f771
DJ
82}
83
84/* It's vitally important that _Unwind_Resume not have a stack frame; the
85 ARM unwinder relies on register state at entrance. So we write this in
86 assembly. */
87
783a65c2
RH
88#define STR1(S) #S
89#define STR(S) STR1(S)
90
02a9f771
DJ
91asm (
92" .globl _Unwind_Resume\n"
93" .type _Unwind_Resume, %function\n"
94"_Unwind_Resume:\n"
01b32e73
TS
95" .cfi_sections .debug_frame\n"
96" " CFI_STARTPROC "\n"
55668624 97" push {r4, r5, r6, lr}\n"
01b32e73
TS
98" " CFI_ADJUST_CFA_OFFSET (16)" \n"
99" " CFI_REL_OFFSET (r4, 0) "\n"
100" " CFI_REL_OFFSET (r5, 4) "\n"
101" " CFI_REL_OFFSET (r6, 8) "\n"
102" " CFI_REL_OFFSET (lr, 12) "\n"
103" " CFI_REMEMBER_STATE "\n"
02a9f771
DJ
104" ldr r4, 1f\n"
105" ldr r5, 2f\n"
106"3: add r4, pc, r4\n"
107" ldr r3, [r4, r5]\n"
108" mov r6, r0\n"
109" cmp r3, #0\n"
110" beq 4f\n"
111"5: mov r0, r6\n"
55668624 112" pop {r4, r5, r6, lr}\n"
01b32e73
TS
113" " CFI_ADJUST_CFA_OFFSET (-16) "\n"
114" " CFI_RESTORE (r4) "\n"
115" " CFI_RESTORE (r5) "\n"
116" " CFI_RESTORE (r6) "\n"
117" " CFI_RESTORE (lr) "\n"
02a9f771 118" bx r3\n"
01b32e73 119" " CFI_RESTORE_STATE "\n"
02a9f771
DJ
120"4: bl pthread_cancel_init\n"
121" ldr r3, [r4, r5]\n"
122" b 5b\n"
01b32e73 123" " CFI_ENDPROC "\n"
5631abde 124" .align 2\n"
783a65c2 125"1: .word _GLOBAL_OFFSET_TABLE_ - 3b - " STR (PC_OFS) "\n"
02a9f771
DJ
126"2: .word libgcc_s_resume(GOTOFF)\n"
127" .size _Unwind_Resume, .-_Unwind_Resume\n"
128);
129
130_Unwind_Reason_Code
131__gcc_personality_v0 (_Unwind_State state,
132 struct _Unwind_Exception *ue_header,
133 struct _Unwind_Context *context)
134{
135 if (__builtin_expect (libgcc_s_personality == NULL, 0))
136 pthread_cancel_init ();
8323b1ab 137
02a9f771
DJ
138 return libgcc_s_personality (state, ue_header, context);
139}
140
141_Unwind_Reason_Code
142_Unwind_ForcedUnwind (struct _Unwind_Exception *exc, _Unwind_Stop_Fn stop,
143 void *stop_argument)
144{
145 if (__builtin_expect (libgcc_s_forcedunwind == NULL, 0))
146 pthread_cancel_init ();
8323b1ab 147
02a9f771
DJ
148 return libgcc_s_forcedunwind (exc, stop, stop_argument);
149}
150
151_Unwind_Word
152_Unwind_GetCFA (struct _Unwind_Context *context)
153{
154 if (__builtin_expect (libgcc_s_getcfa == NULL, 0))
155 pthread_cancel_init ();
8323b1ab 156
02a9f771
DJ
157 return libgcc_s_getcfa (context);
158}