xref: /netbsd-src/tests/lib/libc/sys/t_ptrace_i386_wait.h (revision f3cfa6f6ce31685c6c4a758bc430e69eb99f50a4)
1 /*	$NetBSD: t_ptrace_i386_wait.h,v 1.8 2019/05/10 16:24:35 mgorny Exp $	*/
2 
3 /*-
4  * Copyright (c) 2016, 2017, 2018, 2019 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #if defined(__i386__)
30 ATF_TC(i386_regs1);
31 ATF_TC_HEAD(i386_regs1, tc)
32 {
33 	atf_tc_set_md_var(tc, "descr",
34 	    "Call PT_GETREGS and iterate over General Purpose registers");
35 }
36 
37 ATF_TC_BODY(i386_regs1, tc)
38 {
39 	const int exitval = 5;
40 	const int sigval = SIGSTOP;
41 	pid_t child, wpid;
42 #if defined(TWAIT_HAVE_STATUS)
43 	int status;
44 #endif
45 	struct reg r;
46 
47 	DPRINTF("Before forking process PID=%d\n", getpid());
48 	SYSCALL_REQUIRE((child = fork()) != -1);
49 	if (child == 0) {
50 		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
51 		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
52 
53 		DPRINTF("Before raising %s from child\n", strsignal(sigval));
54 		FORKEE_ASSERT(raise(sigval) == 0);
55 
56 		DPRINTF("Before exiting of the child process\n");
57 		_exit(exitval);
58 	}
59 	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
60 
61 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
62 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
63 
64 	validate_status_stopped(status, sigval);
65 
66 	DPRINTF("Call GETREGS for the child process\n");
67 	SYSCALL_REQUIRE(ptrace(PT_GETREGS, child, &r, 0) != -1);
68 
69 	DPRINTF("EAX=%#" PRIxREGISTER "\n", r.r_eax);
70 	DPRINTF("EBX=%#" PRIxREGISTER "\n", r.r_ebx);
71 	DPRINTF("ECX=%#" PRIxREGISTER "\n", r.r_ecx);
72 	DPRINTF("EDX=%#" PRIxREGISTER "\n", r.r_edx);
73 
74 	DPRINTF("ESP=%#" PRIxREGISTER "\n", r.r_esp);
75 	DPRINTF("EBP=%#" PRIxREGISTER "\n", r.r_ebp);
76 
77 	DPRINTF("ESI=%#" PRIxREGISTER "\n", r.r_esi);
78 	DPRINTF("EDI=%#" PRIxREGISTER "\n", r.r_edi);
79 
80 	DPRINTF("EIP=%#" PRIxREGISTER "\n", r.r_eip);
81 
82 	DPRINTF("EFLAGS=%#" PRIxREGISTER "\n", r.r_eflags);
83 
84 	DPRINTF("CS=%#" PRIxREGISTER "\n", r.r_cs);
85 	DPRINTF("SS=%#" PRIxREGISTER "\n", r.r_ss);
86 	DPRINTF("DS=%#" PRIxREGISTER "\n", r.r_ds);
87 	DPRINTF("ES=%#" PRIxREGISTER "\n", r.r_es);
88 	DPRINTF("FS=%#" PRIxREGISTER "\n", r.r_fs);
89 	DPRINTF("GS=%#" PRIxREGISTER "\n", r.r_gs);
90 
91 	DPRINTF("Before resuming the child process where it left off and "
92 	    "without signal to be sent\n");
93 	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
94 
95 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
96 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
97 
98 	validate_status_exited(status, exitval);
99 
100 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
101 	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
102 }
103 
104 ATF_TC(i386_regs_gp_read);
105 ATF_TC_HEAD(i386_regs_gp_read, tc)
106 {
107 	atf_tc_set_md_var(tc, "descr",
108 		"Set general-purpose reg values from debugged program and read "
109 		"them via PT_GETREGS, comparing values against expected.");
110 }
111 
112 ATF_TC_BODY(i386_regs_gp_read, tc)
113 {
114 	const int exitval = 5;
115 	pid_t child, wpid;
116 #if defined(TWAIT_HAVE_STATUS)
117 	const int sigval = SIGTRAP;
118 	int status;
119 #endif
120 	struct reg gpr;
121 
122 	const uint32_t eax = 0x00010203;
123 	const uint32_t ebx = 0x10111213;
124 	const uint32_t ecx = 0x20212223;
125 	const uint32_t edx = 0x30313233;
126 	const uint32_t esi = 0x40414243;
127 	const uint32_t edi = 0x50515253;
128 
129 	DPRINTF("Before forking process PID=%d\n", getpid());
130 	SYSCALL_REQUIRE((child = fork()) != -1);
131 	if (child == 0) {
132 		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
133 		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
134 
135 		DPRINTF("Before running assembly from child\n");
136 
137 		__asm__ __volatile__(
138 			"int3\n\t"
139 			:
140 			: "a"(eax), "b"(ebx), "c"(ecx), "d"(edx), "S"(esi), "D"(edi)
141 			:
142 		);
143 
144 		DPRINTF("Before exiting of the child process\n");
145 		_exit(exitval);
146 	}
147 	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
148 
149 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
150 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
151 
152 	validate_status_stopped(status, sigval);
153 
154 	DPRINTF("Call GETREGS for the child process\n");
155 	SYSCALL_REQUIRE(ptrace(PT_GETREGS, child, &gpr, 0) != -1);
156 
157 	ATF_CHECK_EQ((uint32_t)gpr.r_eax, eax);
158 	ATF_CHECK_EQ((uint32_t)gpr.r_ebx, ebx);
159 	ATF_CHECK_EQ((uint32_t)gpr.r_ecx, ecx);
160 	ATF_CHECK_EQ((uint32_t)gpr.r_edx, edx);
161 	ATF_CHECK_EQ((uint32_t)gpr.r_esi, esi);
162 	ATF_CHECK_EQ((uint32_t)gpr.r_edi, edi);
163 
164 	DPRINTF("Before resuming the child process where it left off and "
165 	    "without signal to be sent\n");
166 	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
167 
168 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
169 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
170 
171 	validate_status_exited(status, exitval);
172 
173 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
174 	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
175 }
176 
177 ATF_TC(i386_regs_gp_write);
178 ATF_TC_HEAD(i386_regs_gp_write, tc)
179 {
180 	atf_tc_set_md_var(tc, "descr",
181 		"Set general-purpose reg values into a debugged program via "
182 		"PT_SETREGS and compare the result against expected.");
183 }
184 
185 ATF_TC_BODY(i386_regs_gp_write, tc)
186 {
187 	const int exitval = 5;
188 	pid_t child, wpid;
189 #if defined(TWAIT_HAVE_STATUS)
190 	const int sigval = SIGTRAP;
191 	int status;
192 #endif
193 	struct reg gpr;
194 
195 	const uint32_t eax = 0x00010203;
196 	const uint32_t ebx = 0x10111213;
197 	const uint32_t ecx = 0x20212223;
198 	const uint32_t edx = 0x30313233;
199 	const uint32_t esi = 0x40414243;
200 	const uint32_t edi = 0x50515253;
201 
202 	DPRINTF("Before forking process PID=%d\n", getpid());
203 	SYSCALL_REQUIRE((child = fork()) != -1);
204 	if (child == 0) {
205 		const uint64_t fill = 0x0F0F0F0F;
206 		uint32_t v_eax, v_ebx, v_ecx, v_edx, v_esi, v_edi;
207 
208 		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
209 		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
210 
211 		DPRINTF("Before running assembly from child\n");
212 
213 		__asm__ __volatile__(
214 			/* fill registers with clobber pattern */
215 			"movl    %6, %%eax\n\t"
216 			"movl    %6, %%ebx\n\t"
217 			"movl    %6, %%ecx\n\t"
218 			"movl    %6, %%edx\n\t"
219 			"movl    %6, %%esi\n\t"
220 			"movl    %6, %%edi\n\t"
221 			"\n\t"
222 			"int3\n\t"
223 			: "=a"(v_eax), "=b"(v_ebx), "=c"(v_ecx), "=d"(v_edx), "=S"(v_esi),
224 			"=D"(v_edi)
225 			: "g"(fill)
226 			:
227 		);
228 
229 		FORKEE_ASSERT_EQ(v_eax, eax);
230 		FORKEE_ASSERT_EQ(v_ebx, ebx);
231 		FORKEE_ASSERT_EQ(v_ecx, ecx);
232 		FORKEE_ASSERT_EQ(v_edx, edx);
233 		FORKEE_ASSERT_EQ(v_esi, esi);
234 		FORKEE_ASSERT_EQ(v_edi, edi);
235 
236 		DPRINTF("Before exiting of the child process\n");
237 		_exit(exitval);
238 	}
239 	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
240 
241 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
242 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
243 
244 	validate_status_stopped(status, sigval);
245 
246 	DPRINTF("Call GETREGS for the child process\n");
247 	SYSCALL_REQUIRE(ptrace(PT_GETREGS, child, &gpr, 0) != -1);
248 
249 	gpr.r_eax = eax;
250 	gpr.r_ebx = ebx;
251 	gpr.r_ecx = ecx;
252 	gpr.r_edx = edx;
253 	gpr.r_esi = esi;
254 	gpr.r_edi = edi;
255 
256 	DPRINTF("Call SETREGS for the child process\n");
257 	SYSCALL_REQUIRE(ptrace(PT_SETREGS, child, &gpr, 0) != -1);
258 
259 	DPRINTF("Before resuming the child process where it left off and "
260 	    "without signal to be sent\n");
261 	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
262 
263 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
264 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
265 
266 	validate_status_exited(status, exitval);
267 
268 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
269 	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
270 }
271 
272 ATF_TC(i386_regs_ebp_esp_read);
273 ATF_TC_HEAD(i386_regs_ebp_esp_read, tc)
274 {
275 	atf_tc_set_md_var(tc, "descr",
276 		"Set EBP & ESP reg values from debugged program and read "
277 		"them via PT_GETREGS, comparing values against expected.");
278 }
279 
280 ATF_TC_BODY(i386_regs_ebp_esp_read, tc)
281 {
282 	const int exitval = 5;
283 	pid_t child, wpid;
284 #if defined(TWAIT_HAVE_STATUS)
285 	const int sigval = SIGTRAP;
286 	int status;
287 #endif
288 	struct reg gpr;
289 
290 	const uint32_t esp = 0x60616263;
291 	const uint32_t ebp = 0x70717273;
292 
293 	DPRINTF("Before forking process PID=%d\n", getpid());
294 	SYSCALL_REQUIRE((child = fork()) != -1);
295 	if (child == 0) {
296 		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
297 		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
298 
299 		DPRINTF("Before running assembly from child\n");
300 
301 		__asm__ __volatile__(
302 			/* ebp & ebp are a bit tricky, we must not clobber them */
303 			"movl    %%esp, %%eax\n\t"
304 			"movl    %%ebp, %%ebx\n\t"
305 			"movl    %0, %%esp\n\t"
306 			"movl    %1, %%ebp\n\t"
307 			"\n\t"
308 			"int3\n\t"
309 			"\n\t"
310 			"movl    %%eax, %%esp\n\t"
311 			"movl    %%ebx, %%ebp\n\t"
312 			:
313 			: "ri"(esp), "ri"(ebp)
314 			: "%eax", "%ebx"
315 		);
316 
317 		DPRINTF("Before exiting of the child process\n");
318 		_exit(exitval);
319 	}
320 	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
321 
322 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
323 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
324 
325 	validate_status_stopped(status, sigval);
326 
327 	DPRINTF("Call GETREGS for the child process\n");
328 	SYSCALL_REQUIRE(ptrace(PT_GETREGS, child, &gpr, 0) != -1);
329 
330 	ATF_CHECK_EQ((uint32_t)gpr.r_esp, esp);
331 	ATF_CHECK_EQ((uint32_t)gpr.r_ebp, ebp);
332 
333 	DPRINTF("Before resuming the child process where it left off and "
334 	    "without signal to be sent\n");
335 	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
336 
337 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
338 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
339 
340 	validate_status_exited(status, exitval);
341 
342 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
343 	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
344 }
345 
346 ATF_TC(i386_regs_ebp_esp_write);
347 ATF_TC_HEAD(i386_regs_ebp_esp_write, tc)
348 {
349 	atf_tc_set_md_var(tc, "descr",
350 		"Set EBP & ESP reg values into a debugged program via "
351 		"PT_SETREGS and compare the result against expected.");
352 }
353 
354 ATF_TC_BODY(i386_regs_ebp_esp_write, tc)
355 {
356 	const int exitval = 5;
357 	pid_t child, wpid;
358 #if defined(TWAIT_HAVE_STATUS)
359 	const int sigval = SIGTRAP;
360 	int status;
361 #endif
362 	struct reg gpr;
363 
364 	const uint32_t esp = 0x60616263;
365 	const uint32_t ebp = 0x70717273;
366 
367 	DPRINTF("Before forking process PID=%d\n", getpid());
368 	SYSCALL_REQUIRE((child = fork()) != -1);
369 	if (child == 0) {
370 		const uint64_t fill = 0x0F0F0F0F;
371 		uint32_t v_esp, v_ebp;
372 
373 		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
374 		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
375 
376 		DPRINTF("Before running assembly from child\n");
377 
378 		__asm__ __volatile__(
379 			/* save original ebp & esp using our output registers */
380 			"movl    %%esp, %0\n\t"
381 			"movl    %%ebp, %1\n\t"
382 			/* fill them with clobber pattern */
383 			"movl    %2, %%esp\n\t"
384 			"movl    %2, %%ebp\n\t"
385 			"\n\t"
386 			"int3\n\t"
387 			"\n\t"
388 			/* restore ebp & esp, and save the result */
389 			"xchgl   %%esp, %0\n\t"
390 			"xchgl   %%ebp, %1\n\t"
391 			: "=r"(v_esp), "=r"(v_ebp)
392 			: "g"(fill)
393 			:
394 		);
395 
396 		FORKEE_ASSERT_EQ(v_esp, esp);
397 		FORKEE_ASSERT_EQ(v_ebp, ebp);
398 
399 		DPRINTF("Before exiting of the child process\n");
400 		_exit(exitval);
401 	}
402 	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
403 
404 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
405 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
406 
407 	validate_status_stopped(status, sigval);
408 
409 	DPRINTF("Call GETREGS for the child process\n");
410 	SYSCALL_REQUIRE(ptrace(PT_GETREGS, child, &gpr, 0) != -1);
411 
412 	gpr.r_esp = esp;
413 	gpr.r_ebp = ebp;
414 
415 	DPRINTF("Call SETREGS for the child process\n");
416 	SYSCALL_REQUIRE(ptrace(PT_SETREGS, child, &gpr, 0) != -1);
417 
418 	DPRINTF("Before resuming the child process where it left off and "
419 	    "without signal to be sent\n");
420 	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
421 
422 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
423 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
424 
425 	validate_status_exited(status, exitval);
426 
427 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
428 	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
429 }
430 
431 #define ATF_TP_ADD_TCS_PTRACE_WAIT_I386() \
432 	ATF_TP_ADD_TC_HAVE_GPREGS(tp, i386_regs1); \
433 	ATF_TP_ADD_TC_HAVE_GPREGS(tp, i386_regs_gp_read); \
434 	ATF_TP_ADD_TC_HAVE_GPREGS(tp, i386_regs_gp_write); \
435 	ATF_TP_ADD_TC_HAVE_GPREGS(tp, i386_regs_ebp_esp_read); \
436 	ATF_TP_ADD_TC_HAVE_GPREGS(tp, i386_regs_ebp_esp_write);
437 #else
438 #define ATF_TP_ADD_TCS_PTRACE_WAIT_I386()
439 #endif
440