1 /* Copyright (C) 2001-2021 Free Software Foundation, Inc.
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
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.
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
12    Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, see
16    <https://www.gnu.org/licenses/>.  */
17 
18 #include <errno.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <ucontext.h>
23 #include <unistd.h>
24 
25 static ucontext_t ctx[3];
26 
27 static int was_in_f1;
28 static int was_in_f2;
29 
30 static char st2[32768];
31 
32 static volatile int flag;
33 
34 static void
f1(int a00,int a01,int a02,int a03,int a04,int a05,int a06,int a07,int a08,int a09,int a10,int a11,int a12,int a13,int a14,int a15,int a16,int a17,int a18,int a19,int a20,int a21,int a22,int a23,int a24,int a25,int a26,int a27,int a28,int a29,int a30,int a31,int a32)35 f1 (int a00, int a01, int a02, int a03, int a04, int a05, int a06, int a07,
36     int a08, int a09, int a10, int a11, int a12, int a13, int a14, int a15,
37     int a16, int a17, int a18, int a19, int a20, int a21, int a22, int a23,
38     int a24, int a25, int a26, int a27, int a28, int a29, int a30, int a31,
39     int a32)
40 {
41   printf ("start f1(a00=%08x,a01=%08x,a02=%08x,a03=%08x,\n"
42 	  "         a04=%08x,a05=%08x,a06=%08x,a07=%08x,\n"
43 	  "         a08=%08x,a09=%08x,a10=%08x,a11=%08x,\n"
44 	  "         a12=%08x,a13=%08x,a14=%08x,a15=%08x,\n"
45 	  "         a16=%08x,a17=%08x,a18=%08x,a19=%08x,\n"
46 	  "         a20=%08x,a21=%08x,a22=%08x,a23=%08x,\n"
47 	  "         a24=%08x,a25=%08x,a26=%08x,a27=%08x,\n"
48 	  "         a28=%08x,a29=%08x,a30=%08x,a31=%08x,\n"
49 	  "         a32=%08x) [%d]\n",
50 	  a00, a01, a02, a03, a04, a05, a06, a07,
51 	  a08, a09, a10, a11, a12, a13, a14, a15,
52 	  a16, a17, a18, a19, a20, a21, a22, a23,
53 	  a24, a25, a26, a27, a28, a29, a30, a31,
54 	  a32, flag);
55 
56   if (a00 != (0x00000001 << flag) || a01 != (0x00000004 << flag)
57       || a02 != (0x00000012 << flag) || a03 != (0x00000048 << flag)
58       || a04 != (0x00000123 << flag) || a05 != (0x0000048d << flag)
59       || a06 != (0x00001234 << flag) || a07 != (0x000048d1 << flag)
60       || a08 != (0x00012345 << flag) || a09 != (0x00048d15 << flag)
61       || a10 != (0x00123456 << flag) || a11 != (0x0048d159 << flag)
62       || a12 != (0x01234567 << flag) || a13 != (0x048d159e << flag)
63       || a14 != (0x12345678 << flag) || a15 != (0x48d159e2 << flag)
64       || a16 != (0x23456789 << flag) || a17 != (0x8d159e26 << flag)
65       || a18 != (0x3456789a << flag) || a19 != (0xd159e26a << flag)
66       || a20 != (0x456789ab << flag) || a21 != (0x159e26af << flag)
67       || a22 != (0x56789abc << flag) || a23 != (0x59e26af3 << flag)
68       || a24 != (0x6789abcd << flag) || a25 != (0x9e26af37 << flag)
69       || a26 != (0x789abcde << flag) || a27 != (0xe26af37b << flag)
70       || a28 != (0x89abcdef << flag) || a29 != (0x26af37bc << flag)
71       || a30 != (0x9abcdef0 << flag) || a31 != (0x6af37bc3 << flag)
72       || a32 != (0xabcdef0f << flag))
73     {
74       puts ("arg mismatch");
75       exit (-1);
76     }
77 
78   if (flag && swapcontext (&ctx[1], &ctx[2]) != 0)
79     {
80       printf ("%s: swapcontext: %m\n", __FUNCTION__);
81       exit (1);
82     }
83   printf ("finish f1 [%d]\n", flag);
84   flag++;
85   was_in_f1++;
86 }
87 
88 static void
f2(void)89 f2 (void)
90 {
91   puts ("start f2");
92   if (swapcontext (&ctx[2], &ctx[1]) != 0)
93     {
94       printf ("%s: swapcontext: %m\n", __FUNCTION__);
95       exit (1);
96     }
97   puts ("finish f2");
98   was_in_f2 = 1;
99 }
100 
101 volatile int global;
102 
103 
104 static int back_in_main;
105 
106 
107 static void
check_called(void)108 check_called (void)
109 {
110   if (back_in_main == 0)
111     {
112       puts ("program did not reach main again");
113       _exit (1);
114     }
115 }
116 
117 
118 int
main(void)119 main (void)
120 {
121   atexit (check_called);
122 
123   char st1[32768];
124 
125   puts ("making contexts");
126   if (getcontext (&ctx[0]) != 0)
127     {
128       if (errno == ENOSYS)
129 	{
130 	  back_in_main = 1;
131 	  exit (0);
132 	}
133 
134       printf ("%s: getcontext: %m\n", __FUNCTION__);
135       exit (1);
136     }
137 
138   if (getcontext (&ctx[1]) != 0)
139     {
140       printf ("%s: getcontext: %m\n", __FUNCTION__);
141       exit (1);
142     }
143 
144   ctx[1].uc_stack.ss_sp = st1;
145   ctx[1].uc_stack.ss_size = sizeof st1;
146   ctx[1].uc_link = &ctx[0];
147   errno = 0;
148   makecontext (&ctx[1], (void (*) (void)) f1, 33,
149 	       0x00000001 << flag, 0x00000004 << flag,
150 	       0x00000012 << flag, 0x00000048 << flag,
151 	       0x00000123 << flag, 0x0000048d << flag,
152 	       0x00001234 << flag, 0x000048d1 << flag,
153 	       0x00012345 << flag, 0x00048d15 << flag,
154 	       0x00123456 << flag, 0x0048d159 << flag,
155 	       0x01234567 << flag, 0x048d159e << flag,
156 	       0x12345678 << flag, 0x48d159e2 << flag,
157 	       0x23456789 << flag, 0x8d159e26 << flag,
158 	       0x3456789a << flag, 0xd159e26a << flag,
159 	       0x456789ab << flag, 0x159e26af << flag,
160 	       0x56789abc << flag, 0x59e26af3 << flag,
161 	       0x6789abcd << flag, 0x9e26af37 << flag,
162 	       0x789abcde << flag, 0xe26af37b << flag,
163 	       0x89abcdef << flag, 0x26af37bc << flag,
164 	       0x9abcdef0 << flag, 0x6af37bc3 << flag,
165 	       0xabcdef0f << flag);
166 
167   /* Without this check, a stub makecontext can make us spin forever.  */
168   if (errno == ENOSYS)
169     {
170       puts ("makecontext not implemented");
171       back_in_main = 1;
172       return 0;
173     }
174 
175   /* Play some tricks with this context.  */
176   if (++global == 1)
177     if (setcontext (&ctx[1]) != 0)
178       {
179 	printf ("%s: setcontext: %m\n", __FUNCTION__);
180 	exit (1);
181       }
182   if (global != 2)
183     {
184       printf ("%s: 'global' not incremented twice\n", __FUNCTION__);
185       exit (1);
186     }
187 
188   if (getcontext (&ctx[2]) != 0)
189     {
190       printf ("%s: second getcontext: %m\n", __FUNCTION__);
191       exit (1);
192     }
193   ctx[2].uc_stack.ss_sp = st2;
194   ctx[2].uc_stack.ss_size = sizeof st2;
195   ctx[2].uc_link = &ctx[1];
196   makecontext (&ctx[2], f2, 0);
197 
198   puts ("swapping contexts");
199   if (swapcontext (&ctx[0], &ctx[2]) != 0)
200     {
201       printf ("%s: swapcontext: %m\n", __FUNCTION__);
202       exit (1);
203     }
204   puts ("back at main program");
205   back_in_main = 1;
206 
207   if (was_in_f1 < 2)
208     {
209       puts ("didn't reach f1 twice");
210       exit (1);
211     }
212   if (was_in_f2 == 0)
213     {
214       puts ("didn't reach f2");
215       exit (1);
216     }
217 
218   puts ("test succeeded");
219   return 0;
220 }
221