1 /****************************************************************************
3 * GNAT COMPILER COMPONENTS *
7 * Asm Implementation File *
9 * Copyright (C) 2015-2018, Free Software Foundation, Inc. *
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. *
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. *
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 *
27 * GNAT was originally developed by the GNAT team at New York University. *
28 * Extensive contributions were provided by Ada Core Technologies Inc. *
30 ****************************************************************************/
32 /****************************************************
33 * ARM64/IOS version of the __gnat_sigtramp service *
34 ****************************************************/
36 #include <sys/ucontext.h>
39 /* See sigtramp.h for a general explanation of functionality. */
41 /* ----------------------
42 -- General comments --
43 ----------------------
45 Unfortunately the libunwind library used on this platform comes with severe
46 limitations that make the implementation convoluted:
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.
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.
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.
61 Therefore we need 2 distinct call-saved registers in the trampoline and
62 we resort to manual encoding of CFI byte sequences. */
64 /* -----------------------------------------
65 -- Protypes for our internal asm stubs --
66 -----------------------------------------
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
72 /* sigtramp stub providing unwind info for common registers. */
74 extern void __gnat_sigtramp_common
75 (int signo
, void *siginfo
, void *sigcontext
,
76 __sigtramphandler_t
* handler
);
78 void __gnat_sigtramp (int signo
, void *si
, void *ucontext
,
79 __sigtramphandler_t
* handler
)
80 __attribute__((optimize(2)));
82 void __gnat_sigtramp (int signo
, void *si
, void *ucontext
,
83 __sigtramphandler_t
* handler
)
85 mcontext_t mcontext
= ((ucontext_t
*) ucontext
)->uc_mcontext
;
87 __gnat_sigtramp_common (signo
, si
, mcontext
, handler
);
90 /* asm string construction helpers. */
92 #define STR(TEXT) #TEXT
93 /* stringify expanded TEXT, surrounding it with double quotes. */
96 /* stringify E, which will resolve as text but may contain macros
97 still to be expanded. */
99 /* asm (TEXT) outputs <tab>TEXT. These facilitate the output of
100 multiline contents: */
101 #define TAB(S) "\t" S
105 #define TCR(S) TAB(CR(S))
107 /* Offset in uc_mcontext of the __ss structure containing the registers. */
108 #define UC_MCONTEXT_SS 16
113 #define DW_CFA_def_cfa 0x0c
114 #define DW_CFA_expression 0x10
116 #define DW_OP_breg(n) 0x70+(n)
118 #define REG_REGNO_GR(n) n
119 #define REG_REGNO_PC 30
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)
127 #define REG_OFFSET_LONG256_PC REG_OFFSET_LONG256_GR(32)
129 #define CFI_DEF_CFA \
130 TCR(".cfi_def_cfa " S(CFA_REG) ", 0")
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)
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"
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"
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"
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))
183 /* Trampoline body block
184 --------------------- */
186 #define SIGTRAMP_BODY \
187 TCR("stp fp, lr, [sp, #-32]!") \
188 TCR("stp x" S(CFA_REG) ", x" S(BASE_REG) ", [sp, #16]") \
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") \
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") \
201 /* -----------------------------
202 -- Symbol definition block --
203 ----------------------------- */
205 #define SIGTRAMP_START(SYM) \
206 CR("# " S(SYM) " signal trampoline") \
208 TCR(".cfi_startproc") \
209 TCR(".cfi_signal_frame")
211 /* ------------------------------
212 -- Symbol termination block --
213 ------------------------------ */
215 #define SIGTRAMP_END(SYM) \
218 /*----------------------------
219 -- And now, the real code --
220 ---------------------------- */
225 /* sigtramp stub for common registers. */
227 #define TRAMP_COMMON ___gnat_sigtramp_common
229 asm (SIGTRAMP_START(TRAMP_COMMON
));
231 asm (CFI_COMMON_REGS
);
233 asm (SIGTRAMP_END(TRAMP_COMMON
));