111
|
1 /****************************************************************************
|
|
2 * *
|
|
3 * GNAT COMPILER COMPONENTS *
|
|
4 * *
|
|
5 * S I G T R A M P *
|
|
6 * *
|
|
7 * Asm Implementation File *
|
|
8 * *
|
|
9 * Copyright (C) 2015, Free Software Foundation, Inc. *
|
|
10 * *
|
|
11 * GNAT is free software; you can redistribute it and/or modify it under *
|
|
12 * terms of the GNU General Public License as published by the Free Soft- *
|
|
13 * ware Foundation; either version 3, or (at your option) any later ver- *
|
|
14 * sion. GNAT is distributed in the hope that it will be useful, but WITH- *
|
|
15 * OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
|
|
16 * or FITNESS FOR A PARTICULAR PURPOSE. *
|
|
17 * *
|
|
18 * As a special exception under Section 7 of GPL version 3, you are granted *
|
|
19 * additional permissions described in the GCC Runtime Library Exception, *
|
|
20 * version 3.1, as published by the Free Software Foundation. *
|
|
21 * *
|
|
22 * In particular, you can freely distribute your programs built with the *
|
|
23 * GNAT Pro compiler, including any required library run-time units, using *
|
|
24 * any licensing terms of your choosing. See the AdaCore Software License *
|
|
25 * for full details. *
|
|
26 * *
|
|
27 * GNAT was originally developed by the GNAT team at New York University. *
|
|
28 * Extensive contributions were provided by Ada Core Technologies Inc. *
|
|
29 * *
|
|
30 ****************************************************************************/
|
|
31
|
|
32 /****************************************************
|
|
33 * ARM64/IOS version of the __gnat_sigtramp service *
|
|
34 ****************************************************/
|
|
35
|
|
36 #include <sys/ucontext.h>
|
|
37
|
|
38 #include "sigtramp.h"
|
|
39 /* See sigtramp.h for a general explanation of functionality. */
|
|
40
|
|
41 /* ----------------------
|
|
42 -- General comments --
|
|
43 ----------------------
|
|
44
|
|
45 Unfortunately the libunwind library used on this platform comes with severe
|
|
46 limitations that make the implementation convoluted:
|
|
47
|
|
48 1. At each step, the stack pointer register SP is restored with the CFA.
|
|
49 This makes it impossible to set the CFA to an arbitrary value, for
|
|
50 example to the address of the context saved on the stack, which means
|
|
51 that the simple CFI directives cannot be used for the registers.
|
|
52
|
|
53 2. For the ARM64 architecture (and only it), DWARF expressions are not
|
|
54 supported to compute the CFA. Only DW_CFA_def_cfa is supported, which
|
|
55 means that the CFA (modulo offset) must be loaded into a register.
|
|
56
|
|
57 3. The return column cannot be changed (30 for the ARM64 architecture).
|
|
58 Since column 30 is that of the LR register, this makes it impossible
|
|
59 to restore both the LR register and the PC.
|
|
60
|
|
61 Therefore we need 2 distinct call-saved registers in the trampoline and
|
|
62 we resort to manual encoding of CFI byte sequences. */
|
|
63
|
|
64 /* -----------------------------------------
|
|
65 -- Protypes for our internal asm stubs --
|
|
66 -----------------------------------------
|
|
67
|
|
68 Even though our symbols will remain local, the prototype claims "extern"
|
|
69 and not "static" to prevent compiler complaints about a symbol used but
|
|
70 never defined. */
|
|
71
|
|
72 /* sigtramp stub providing unwind info for common registers. */
|
|
73
|
|
74 extern void __gnat_sigtramp_common
|
|
75 (int signo, void *siginfo, void *sigcontext,
|
|
76 __sigtramphandler_t * handler);
|
|
77
|
|
78 void __gnat_sigtramp (int signo, void *si, void *ucontext,
|
|
79 __sigtramphandler_t * handler)
|
|
80 __attribute__((optimize(2)));
|
|
81
|
|
82 void __gnat_sigtramp (int signo, void *si, void *ucontext,
|
|
83 __sigtramphandler_t * handler)
|
|
84 {
|
|
85 mcontext_t mcontext = ((ucontext_t *) ucontext)->uc_mcontext;
|
|
86
|
|
87 __gnat_sigtramp_common (signo, si, mcontext, handler);
|
|
88 }
|
|
89
|
|
90 /* asm string construction helpers. */
|
|
91
|
|
92 #define STR(TEXT) #TEXT
|
|
93 /* stringify expanded TEXT, surrounding it with double quotes. */
|
|
94
|
|
95 #define S(E) STR(E)
|
|
96 /* stringify E, which will resolve as text but may contain macros
|
|
97 still to be expanded. */
|
|
98
|
|
99 /* asm (TEXT) outputs <tab>TEXT. These facilitate the output of
|
|
100 multiline contents: */
|
|
101 #define TAB(S) "\t" S
|
|
102 #define CR(S) S "\n"
|
|
103
|
|
104 #undef TCR
|
|
105 #define TCR(S) TAB(CR(S))
|
|
106
|
|
107 /* Offset in uc_mcontext of the __ss structure containing the registers. */
|
|
108 #define UC_MCONTEXT_SS 16
|
|
109
|
|
110 #define CFA_REG 19
|
|
111 #define BASE_REG 20
|
|
112
|
|
113 #define DW_CFA_def_cfa 0x0c
|
|
114 #define DW_CFA_expression 0x10
|
|
115
|
|
116 #define DW_OP_breg(n) 0x70+(n)
|
|
117
|
|
118 #define REG_REGNO_GR(n) n
|
|
119 #define REG_REGNO_PC 30
|
|
120
|
|
121 /* The first byte of the SLEB128 value of the offset. */
|
|
122 #define REG_OFFSET_GR(n) (UC_MCONTEXT_SS + n * 8)
|
|
123 #define REG_OFFSET_LONG_GR(n) (UC_MCONTEXT_SS + n * 8 + 128)
|
|
124 #define REG_OFFSET_LONG128_GR(n) (UC_MCONTEXT_SS + (n - 16) * 8 + 128)
|
|
125 #define REG_OFFSET_LONG256_GR(n) (UC_MCONTEXT_SS + (n - 32) * 8 + 128)
|
|
126
|
|
127 #define REG_OFFSET_LONG256_PC REG_OFFSET_LONG256_GR(32)
|
|
128
|
|
129 #define CFI_DEF_CFA \
|
|
130 TCR(".cfi_def_cfa " S(CFA_REG) ", 0")
|
|
131
|
|
132 /* We need 4 variants depending on the offset: 0+, 64+, 128+, 256+. */
|
|
133 #define COMMON_CFI(REG) \
|
|
134 ".cfi_escape " S(DW_CFA_expression) "," S(REG_REGNO_##REG) ",2," \
|
|
135 S(DW_OP_breg(BASE_REG)) "," S(REG_OFFSET_##REG)
|
|
136
|
|
137 #define COMMON_LONG_CFI(REG) \
|
|
138 ".cfi_escape " S(DW_CFA_expression) "," S(REG_REGNO_##REG) ",3," \
|
|
139 S(DW_OP_breg(BASE_REG)) "," S(REG_OFFSET_LONG_##REG) ",0"
|
|
140
|
|
141 #define COMMON_LONG128_CFI(REG) \
|
|
142 ".cfi_escape " S(DW_CFA_expression) "," S(REG_REGNO_##REG) ",3," \
|
|
143 S(DW_OP_breg(BASE_REG)) "," S(REG_OFFSET_LONG128_##REG) ",1"
|
|
144
|
|
145 #define COMMON_LONG256_CFI(REG) \
|
|
146 ".cfi_escape " S(DW_CFA_expression) "," S(REG_REGNO_##REG) ",3," \
|
|
147 S(DW_OP_breg(BASE_REG)) "," S(REG_OFFSET_LONG256_##REG) ",2"
|
|
148
|
|
149 #define CFI_COMMON_REGS \
|
|
150 CR("# CFI for common registers\n") \
|
|
151 TCR(COMMON_CFI(GR(0))) \
|
|
152 TCR(COMMON_CFI(GR(1))) \
|
|
153 TCR(COMMON_CFI(GR(2))) \
|
|
154 TCR(COMMON_CFI(GR(3))) \
|
|
155 TCR(COMMON_CFI(GR(4))) \
|
|
156 TCR(COMMON_CFI(GR(5))) \
|
|
157 TCR(COMMON_LONG_CFI(GR(6))) \
|
|
158 TCR(COMMON_LONG_CFI(GR(7))) \
|
|
159 TCR(COMMON_LONG_CFI(GR(8))) \
|
|
160 TCR(COMMON_LONG_CFI(GR(9))) \
|
|
161 TCR(COMMON_LONG_CFI(GR(10))) \
|
|
162 TCR(COMMON_LONG_CFI(GR(11))) \
|
|
163 TCR(COMMON_LONG_CFI(GR(12))) \
|
|
164 TCR(COMMON_LONG_CFI(GR(13))) \
|
|
165 TCR(COMMON_LONG128_CFI(GR(14))) \
|
|
166 TCR(COMMON_LONG128_CFI(GR(15))) \
|
|
167 TCR(COMMON_LONG128_CFI(GR(16))) \
|
|
168 TCR(COMMON_LONG128_CFI(GR(17))) \
|
|
169 TCR(COMMON_LONG128_CFI(GR(18))) \
|
|
170 TCR(COMMON_LONG128_CFI(GR(19))) \
|
|
171 TCR(COMMON_LONG128_CFI(GR(20))) \
|
|
172 TCR(COMMON_LONG128_CFI(GR(21))) \
|
|
173 TCR(COMMON_LONG128_CFI(GR(22))) \
|
|
174 TCR(COMMON_LONG128_CFI(GR(23))) \
|
|
175 TCR(COMMON_LONG128_CFI(GR(24))) \
|
|
176 TCR(COMMON_LONG128_CFI(GR(25))) \
|
|
177 TCR(COMMON_LONG128_CFI(GR(26))) \
|
|
178 TCR(COMMON_LONG128_CFI(GR(27))) \
|
|
179 TCR(COMMON_LONG128_CFI(GR(28))) \
|
|
180 TCR(COMMON_LONG128_CFI(GR(29))) \
|
|
181 TCR(COMMON_LONG256_CFI(PC))
|
|
182
|
|
183 /* Trampoline body block
|
|
184 --------------------- */
|
|
185
|
|
186 #define SIGTRAMP_BODY \
|
|
187 TCR("stp fp, lr, [sp, #-32]!") \
|
|
188 TCR("stp x" S(CFA_REG) ", x" S(BASE_REG) ", [sp, #16]") \
|
|
189 TCR("mov fp, sp") \
|
|
190 TCR("# Load the saved value of the stack pointer as CFA") \
|
|
191 TCR("ldr x" S(CFA_REG) ", [x2, #" S(REG_OFFSET_GR(31)) "]") \
|
|
192 TCR("# Use x" S(BASE_REG) " as base register for the CFI") \
|
|
193 TCR("mov x" S(BASE_REG) ", x2") \
|
|
194 TCR("# Call the handler") \
|
|
195 TCR("blr x3") \
|
|
196 TCR("# Release our frame and return (should never get here!).") \
|
|
197 TCR("ldp x" S(CFA_REG) ", x" S(BASE_REG)" , [sp, #16]") \
|
|
198 TCR("ldp fp, lr, [sp], 32") \
|
|
199 TCR("ret")
|
|
200
|
|
201 /* -----------------------------
|
|
202 -- Symbol definition block --
|
|
203 ----------------------------- */
|
|
204
|
|
205 #define SIGTRAMP_START(SYM) \
|
|
206 CR("# " S(SYM) " signal trampoline") \
|
|
207 CR(S(SYM) ":") \
|
|
208 TCR(".cfi_startproc") \
|
|
209 TCR(".cfi_signal_frame")
|
|
210
|
|
211 /* ------------------------------
|
|
212 -- Symbol termination block --
|
|
213 ------------------------------ */
|
|
214
|
|
215 #define SIGTRAMP_END(SYM) \
|
|
216 TCR(".cfi_endproc")
|
|
217
|
|
218 /*----------------------------
|
|
219 -- And now, the real code --
|
|
220 ---------------------------- */
|
|
221
|
|
222 asm(".text\n"
|
|
223 TCR(".align 2"));
|
|
224
|
|
225 /* sigtramp stub for common registers. */
|
|
226
|
|
227 #define TRAMP_COMMON ___gnat_sigtramp_common
|
|
228
|
|
229 asm (SIGTRAMP_START(TRAMP_COMMON));
|
|
230 asm (CFI_DEF_CFA);
|
|
231 asm (CFI_COMMON_REGS);
|
|
232 asm (SIGTRAMP_BODY);
|
|
233 asm (SIGTRAMP_END(TRAMP_COMMON));
|