]>
Commit | Line | Data |
---|---|---|
688903eb | 1 | /* Copyright (C) 2001-2018 Free Software Foundation, Inc. |
aeba9785 UD |
2 | This file is part of the GNU C Library. |
3 | ||
4 | The GNU C Library is free software; you can redistribute it and/or | |
41bdb6e2 AJ |
5 | modify it under the terms of the GNU Lesser General Public |
6 | License as published by the Free Software Foundation; either | |
7 | version 2.1 of the License, or (at your option) any later version. | |
aeba9785 UD |
8 | |
9 | The GNU C Library is distributed in the hope that it will be useful, | |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
41bdb6e2 | 12 | Lesser General Public License for more details. |
aeba9785 | 13 | |
41bdb6e2 | 14 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 PE |
15 | License along with the GNU C Library; if not, see |
16 | <http://www.gnu.org/licenses/>. */ | |
aeba9785 UD |
17 | |
18 | #include <errno.h> | |
e04a4e9d | 19 | #include <signal.h> |
aeba9785 UD |
20 | #include <stdio.h> |
21 | #include <stdlib.h> | |
37076fcc | 22 | #include <string.h> |
aeba9785 | 23 | #include <ucontext.h> |
b5ec5fce | 24 | #include <unistd.h> |
aeba9785 UD |
25 | |
26 | static ucontext_t ctx[3]; | |
27 | ||
28 | static int was_in_f1; | |
29 | static int was_in_f2; | |
30 | ||
e710e49f | 31 | static char st2[32768]; |
1a51bde7 | 32 | |
aeba9785 | 33 | static void |
3295976a | 34 | f1 (int a0, int a1, int a2, int a3) |
aeba9785 | 35 | { |
3295976a | 36 | printf ("start f1(a0=%x,a1=%x,a2=%x,a3=%x)\n", a0, a1, a2, a3); |
aeba9785 UD |
37 | |
38 | if (a0 != 1 || a1 != 2 || a2 != 3 || a3 != -4) | |
39 | { | |
40 | puts ("arg mismatch"); | |
41 | exit (-1); | |
42 | } | |
43 | ||
44 | if (swapcontext (&ctx[1], &ctx[2]) != 0) | |
45 | { | |
46 | printf ("%s: swapcontext: %m\n", __FUNCTION__); | |
47 | exit (1); | |
48 | } | |
49 | puts ("finish f1"); | |
50 | was_in_f1 = 1; | |
51 | } | |
52 | ||
53 | static void | |
54 | f2 (void) | |
55 | { | |
1a51bde7 UD |
56 | char on_stack[1]; |
57 | ||
aeba9785 | 58 | puts ("start f2"); |
1a51bde7 UD |
59 | |
60 | printf ("&on_stack=%p\n", on_stack); | |
61 | if (on_stack < st2 || on_stack >= st2 + sizeof (st2)) | |
62 | { | |
63 | printf ("%s: memory stack is not where it belongs!", __FUNCTION__); | |
64 | exit (1); | |
65 | } | |
66 | ||
aeba9785 UD |
67 | if (swapcontext (&ctx[2], &ctx[1]) != 0) |
68 | { | |
69 | printf ("%s: swapcontext: %m\n", __FUNCTION__); | |
70 | exit (1); | |
71 | } | |
72 | puts ("finish f2"); | |
73 | was_in_f2 = 1; | |
74 | } | |
75 | ||
e710e49f | 76 | void |
a1d8c621 MF |
77 | test_stack (volatile int a, volatile int b, |
78 | volatile int c, volatile int d) | |
73f7c32c UD |
79 | { |
80 | volatile int e = 5; | |
81 | volatile int f = 6; | |
82 | ucontext_t uc; | |
83 | ||
84 | /* Test for cases where getcontext is clobbering the callers | |
85 | stack, including parameters. */ | |
a1d8c621 | 86 | getcontext (&uc); |
e710e49f | 87 | |
73f7c32c UD |
88 | if (a != 1) |
89 | { | |
90 | printf ("%s: getcontext clobbers parm a\n", __FUNCTION__); | |
91 | exit (1); | |
92 | } | |
e710e49f | 93 | |
73f7c32c UD |
94 | if (b != 2) |
95 | { | |
96 | printf ("%s: getcontext clobbers parm b\n", __FUNCTION__); | |
97 | exit (1); | |
98 | } | |
e710e49f | 99 | |
73f7c32c UD |
100 | if (c != 3) |
101 | { | |
102 | printf ("%s: getcontext clobbers parm c\n", __FUNCTION__); | |
103 | exit (1); | |
104 | } | |
e710e49f | 105 | |
73f7c32c UD |
106 | if (d != 4) |
107 | { | |
108 | printf ("%s: getcontext clobbers parm d\n", __FUNCTION__); | |
109 | exit (1); | |
110 | } | |
111 | ||
112 | if (e != 5) | |
113 | { | |
114 | printf ("%s: getcontext clobbers varible e\n", __FUNCTION__); | |
115 | exit (1); | |
116 | } | |
e710e49f | 117 | |
73f7c32c UD |
118 | if (f != 6) |
119 | { | |
120 | printf ("%s: getcontext clobbers variable f\n", __FUNCTION__); | |
121 | exit (1); | |
122 | } | |
123 | } | |
124 | ||
232fdf8c UD |
125 | volatile int global; |
126 | ||
d90d0256 UD |
127 | |
128 | static int back_in_main; | |
129 | ||
130 | ||
131 | static void | |
132 | check_called (void) | |
133 | { | |
134 | if (back_in_main == 0) | |
135 | { | |
92505456 | 136 | puts ("program did not reach main again"); |
d90d0256 UD |
137 | _exit (1); |
138 | } | |
139 | } | |
140 | ||
141 | ||
aeba9785 UD |
142 | int |
143 | main (void) | |
144 | { | |
d90d0256 UD |
145 | atexit (check_called); |
146 | ||
e710e49f | 147 | char st1[32768]; |
e04a4e9d WN |
148 | stack_t stack_before, stack_after; |
149 | ||
a1d8c621 | 150 | sigaltstack (NULL, &stack_before); |
aeba9785 UD |
151 | |
152 | puts ("making contexts"); | |
153 | if (getcontext (&ctx[1]) != 0) | |
154 | { | |
155 | if (errno == ENOSYS) | |
cefa2dd3 UD |
156 | { |
157 | back_in_main = 1; | |
158 | exit (0); | |
159 | } | |
aeba9785 UD |
160 | |
161 | printf ("%s: getcontext: %m\n", __FUNCTION__); | |
162 | exit (1); | |
163 | } | |
e710e49f | 164 | |
73f7c32c | 165 | test_stack (1, 2, 3, 4); |
232fdf8c UD |
166 | |
167 | /* Play some tricks with this context. */ | |
168 | if (++global == 1) | |
169 | if (setcontext (&ctx[1]) != 0) | |
170 | { | |
171 | printf ("%s: setcontext: %m\n", __FUNCTION__); | |
172 | exit (1); | |
173 | } | |
174 | if (global != 2) | |
175 | { | |
176 | printf ("%s: 'global' not incremented twice\n", __FUNCTION__); | |
177 | exit (1); | |
178 | } | |
179 | ||
aeba9785 UD |
180 | ctx[1].uc_stack.ss_sp = st1; |
181 | ctx[1].uc_stack.ss_size = sizeof st1; | |
182 | ctx[1].uc_link = &ctx[0]; | |
37076fcc RM |
183 | { |
184 | ucontext_t tempctx = ctx[1]; | |
185 | makecontext (&ctx[1], (void (*) (void)) f1, 4, 1, 2, 3, -4); | |
186 | ||
187 | /* Without this check, a stub makecontext can make us spin forever. */ | |
188 | if (memcmp (&tempctx, &ctx[1], sizeof ctx[1]) == 0) | |
189 | { | |
190 | puts ("makecontext was a no-op, presuming not implemented"); | |
191 | return 0; | |
192 | } | |
193 | } | |
aeba9785 UD |
194 | |
195 | if (getcontext (&ctx[2]) != 0) | |
196 | { | |
197 | printf ("%s: second getcontext: %m\n", __FUNCTION__); | |
198 | exit (1); | |
199 | } | |
200 | ctx[2].uc_stack.ss_sp = st2; | |
201 | ctx[2].uc_stack.ss_size = sizeof st2; | |
202 | ctx[2].uc_link = &ctx[1]; | |
203 | makecontext (&ctx[2], f2, 0); | |
204 | ||
205 | puts ("swapping contexts"); | |
206 | if (swapcontext (&ctx[0], &ctx[2]) != 0) | |
207 | { | |
208 | printf ("%s: swapcontext: %m\n", __FUNCTION__); | |
209 | exit (1); | |
210 | } | |
211 | puts ("back at main program"); | |
d90d0256 | 212 | back_in_main = 1; |
aeba9785 | 213 | |
a1d8c621 | 214 | sigaltstack (NULL, &stack_after); |
e04a4e9d | 215 | |
aeba9785 UD |
216 | if (was_in_f1 == 0) |
217 | { | |
218 | puts ("didn't reach f1"); | |
219 | exit (1); | |
220 | } | |
221 | if (was_in_f2 == 0) | |
222 | { | |
223 | puts ("didn't reach f2"); | |
224 | exit (1); | |
225 | } | |
226 | ||
e04a4e9d WN |
227 | /* Check sigaltstack state is not clobbered as in BZ #16629. */ |
228 | if (stack_before.ss_sp != stack_after.ss_sp) | |
229 | { | |
230 | printf ("stack ss_sp mismatch: %p %p\n", | |
231 | stack_before.ss_sp, stack_after.ss_sp); | |
232 | exit (1); | |
233 | } | |
234 | ||
235 | if (stack_before.ss_size != stack_after.ss_size) | |
236 | { | |
237 | printf ("stack ss_size mismatch: %zd %zd\n", | |
238 | stack_before.ss_size, stack_after.ss_size); | |
239 | exit (1); | |
240 | } | |
241 | ||
aeba9785 UD |
242 | puts ("test succeeded"); |
243 | return 0; | |
244 | } |