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) 2017-2019, 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  * QNX version of the __gnat_sigtramp service *
34  **********************************************/
35 
36 #include <ucontext.h>
37 
38 #include "sigtramp.h"
39 /* See sigtramp.h for a general explanation of functionality.  */
40 
41 extern void __gnat_sigtramp_common
42   (int signo, void *siginfo, void *sigcontext,
43    __sigtramphandler_t * handler);
44 
45 void __gnat_sigtramp (int signo, void *si, void *sc,
46                       __sigtramphandler_t * handler)
47      __attribute__((optimize(2)));
48 
__gnat_sigtramp(int signo,void * si,void * ucontext,__sigtramphandler_t * handler)49 void __gnat_sigtramp (int signo, void *si, void *ucontext,
50                       __sigtramphandler_t * handler)
51 {
52   struct sigcontext *mcontext = &((ucontext_t *) ucontext)->uc_mcontext;
53 
54   __gnat_sigtramp_common (signo, si, mcontext, handler);
55 }
56 
57 /* asm string construction helpers.  */
58 
59 #define STR(TEXT) #TEXT
60 /* stringify expanded TEXT, surrounding it with double quotes.  */
61 
62 #define S(E) STR(E)
63 /* stringify E, which will resolve as text but may contain macros
64    still to be expanded.  */
65 
66 /* asm (TEXT) outputs <tab>TEXT. These facilitate the output of
67    multiline contents:  */
68 #define TAB(S) "\t" S
69 #define CR(S)  S "\n"
70 
71 #undef TCR
72 #define TCR(S) TAB(CR(S))
73 
74 /* Trampoline body block
75    ---------------------  */
76 
77 #define COMMON_CFI(REG) \
78   ".cfi_offset " S(REGNO_##REG) "," S(REG_OFFSET_##REG)
79 
80 #ifdef __x86_64__
81 /*****************************************
82  *               x86-64                  *
83  *****************************************/
84 
85 // CFI register numbers
86 #define REGNO_RAX 0
87 #define REGNO_RDX 1
88 #define REGNO_RCX 2
89 #define REGNO_RBX 3
90 #define REGNO_RSI 4
91 #define REGNO_RDI 5
92 #define REGNO_RBP 6
93 #define REGNO_RSP 7
94 #define REGNO_R8 8
95 #define REGNO_R9 9
96 #define REGNO_R10 10
97 #define REGNO_R11 11
98 #define REGNO_R12 12
99 #define REGNO_R13 13
100 #define REGNO_R14 14
101 #define REGNO_R15 15 /* Used as CFA */
102 #define REGNO_RPC 16 /* aka %rip */
103 
104 //  Registers offset from the regset structure
105 #define REG_OFFSET_RDI 0x00
106 #define REG_OFFSET_RSI 0x08
107 #define REG_OFFSET_RDX 0x10
108 #define REG_OFFSET_R10 0x18
109 #define REG_OFFSET_R8  0x20
110 #define REG_OFFSET_R9  0x28
111 #define REG_OFFSET_RAX 0x30
112 #define REG_OFFSET_RBX 0x38
113 #define REG_OFFSET_RBP 0x40
114 #define REG_OFFSET_RCX 0x48
115 #define REG_OFFSET_R11 0x50
116 #define REG_OFFSET_R12 0x58
117 #define REG_OFFSET_R13 0x60
118 #define REG_OFFSET_R14 0x68
119 #define REG_OFFSET_R15 0x70
120 #define REG_OFFSET_RPC 0x78 /* RIP */
121 #define REG_OFFSET_RSP 0x90
122 
123 #define CFI_COMMON_REGS \
124 CR("# CFI for common registers\n") \
125 TCR(COMMON_CFI(RSP)) \
126 TCR(COMMON_CFI(R15)) \
127 TCR(COMMON_CFI(R14)) \
128 TCR(COMMON_CFI(R13)) \
129 TCR(COMMON_CFI(R12)) \
130 TCR(COMMON_CFI(R11)) \
131 TCR(COMMON_CFI(RCX)) \
132 TCR(COMMON_CFI(RBP)) \
133 TCR(COMMON_CFI(RBX)) \
134 TCR(COMMON_CFI(RAX)) \
135 TCR(COMMON_CFI(R9)) \
136 TCR(COMMON_CFI(R8)) \
137 TCR(COMMON_CFI(R10)) \
138 TCR(COMMON_CFI(RSI)) \
139 TCR(COMMON_CFI(RDI)) \
140 TCR(COMMON_CFI(RDX)) \
141 TCR(COMMON_CFI(RPC)) \
142 TCR(".cfi_return_column " S(REGNO_RPC))
143 
144 #define SIGTRAMP_BODY     \
145 TCR(".cfi_def_cfa 15, 0") \
146 CFI_COMMON_REGS \
147 CR("") \
148 TCR("# Allocate frame and save the non-volatile") \
149 TCR("# registers we're going to modify") \
150 TCR("subq	$8, %rsp") \
151 TCR("# Setup CFA_REG = context, which we'll retrieve as our CFA value") \
152 TCR("movq	%rdx, %r15") \
153 TCR("# Call the real handler. The signo, siginfo and sigcontext") \
154 TCR("# arguments are the same as those we received") \
155 TCR("call	*%rcx") \
156 TCR("# This part should never be executed") \
157 TCR("addq	$8, %rsp") \
158 TCR("ret")
159 #endif
160 
161 #ifdef __aarch64__
162 /*****************************************
163  *               Aarch64                 *
164  *****************************************/
165 
166 /* CFA reg: any callee saved register will do */
167 #define CFA_REG  19
168 
169 /* General purpose registers */
170 #define REG_OFFSET_GR(n)     (n * 8)
171 #define REGNO_GR(n)   n
172 
173 /* ELR value offset withing the mcontext registers list */
174 #define REG_OFFSET_ELR           (32 * 8)
175 /* The register used to hold the PC value to restore. We need a scratch
176    register.  */
177 #define REGNO_PC      9
178 
179 #define CFI_DEF_CFA \
180   TCR(".cfi_def_cfa " S(CFA_REG) ", 0")
181 
182 /* This restores the callee-saved registers, the FP, the LR, and the SP.
183    A scratch register is used as return column to indicate the new value
184    for PC */
185 #define CFI_COMMON_REGS \
186   CR("# CFI for common registers\n") \
187   TCR(COMMON_CFI(GR(18))) \
188   TCR(COMMON_CFI(GR(19))) \
189   TCR(COMMON_CFI(GR(20))) \
190   TCR(COMMON_CFI(GR(21))) \
191   TCR(COMMON_CFI(GR(22))) \
192   TCR(COMMON_CFI(GR(23))) \
193   TCR(COMMON_CFI(GR(24))) \
194   TCR(COMMON_CFI(GR(25))) \
195   TCR(COMMON_CFI(GR(26))) \
196   TCR(COMMON_CFI(GR(27))) \
197   TCR(COMMON_CFI(GR(28))) \
198   TCR(COMMON_CFI(GR(29))) \
199   TCR(COMMON_CFI(GR(30))) \
200   TCR(COMMON_CFI(GR(31))) \
201   TCR(".cfi_offset " S(REGNO_PC) "," S(REG_OFFSET_ELR)) \
202   TCR(".cfi_return_column " S(REGNO_PC))
203 
204 #define SIGTRAMP_BODY \
205   CFI_DEF_CFA \
206   CFI_COMMON_REGS \
207   TCR("# Allocate the frame (16bytes aligned) and push FP and LR") \
208   TCR("stp x29, x30, [sp, #-32]!") \
209   TCR("add x29, sp, 0") \
210   TCR("# Push register used to hold the CFA on stack") \
211   TCR("str x" S(CFA_REG) ", [sp, 16]")  \
212   TCR("# Set the CFA: x2 value") \
213   TCR("mov x" S(CFA_REG) ", x2") \
214   TCR("# Call the handler") \
215   TCR("blr x3") \
216   TCR("# Release our frame and return (should never get here!).") \
217   TCR("ldr x" S(CFA_REG) ", [sp, 16]") \
218   TCR("ldp x29, x30, [sp], 32") \
219   TCR("ret")
220 
221 #endif /* AARCH64 */
222 
223 /* Symbol definition block
224    -----------------------  */
225 
226 #if defined (__x86_64__) || defined (__aarch64__)
227 #define FUNC_ALIGN TCR(".p2align 4,,15")
228 #else
229 #define FUNC_ALIGN
230 #endif
231 
232 #define SIGTRAMP_START(SYM)       \
233 CR("# " S(SYM) " cfi trampoline") \
234 TCR(".type " S(SYM) ", @function") \
235 CR("") \
236 FUNC_ALIGN \
237 CR(S(SYM) ":") \
238 TCR(".cfi_startproc") \
239 TCR(".cfi_signal_frame")
240 
241 /* Symbol termination block
242    ------------------------  */
243 
244 #define SIGTRAMP_END(SYM) \
245 CR(".cfi_endproc") \
246 TCR(".size " S(SYM) ", .-" S(SYM))
247 
248 /*----------------------------
249   -- And now, the real code --
250   ---------------------------- */
251 
252 /* Text section start.  The compiler isn't aware of that switch.  */
253 
254 asm (".text\n"
255      TCR(".align 2"));
256 
257 /* sigtramp stub for common registers.  */
258 
259 #define TRAMP_COMMON __gnat_sigtramp_common
260 
261 asm (SIGTRAMP_START(TRAMP_COMMON));
262 asm (SIGTRAMP_BODY);
263 asm (SIGTRAMP_END(TRAMP_COMMON));
264