| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: t_ptrace_wait.c,v 1.3 2016/12/03 01:41:15 kamil Exp $ */ | | 1 | /* $NetBSD: t_ptrace_wait.c,v 1.4 2016/12/04 03:38:58 kamil Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2016 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2016 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
| @@ -17,52 +17,84 @@ | | | @@ -17,52 +17,84 @@ |
17 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 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 | | 18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
19 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 19 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
20 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 20 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 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 | | 23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 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 | | 25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
26 | * POSSIBILITY OF SUCH DAMAGE. | | 26 | * POSSIBILITY OF SUCH DAMAGE. |
27 | */ | | 27 | */ |
28 | | | 28 | |
29 | #include <sys/cdefs.h> | | 29 | #include <sys/cdefs.h> |
30 | __RCSID("$NetBSD: t_ptrace_wait.c,v 1.3 2016/12/03 01:41:15 kamil Exp $"); | | 30 | __RCSID("$NetBSD: t_ptrace_wait.c,v 1.4 2016/12/04 03:38:58 kamil Exp $"); |
31 | | | 31 | |
32 | #include <sys/param.h> | | 32 | #include <sys/param.h> |
33 | #include <sys/types.h> | | 33 | #include <sys/types.h> |
34 | #include <sys/ptrace.h> | | 34 | #include <sys/ptrace.h> |
35 | #include <sys/resource.h> | | 35 | #include <sys/resource.h> |
36 | #include <sys/stat.h> | | 36 | #include <sys/stat.h> |
37 | #include <sys/sysctl.h> | | 37 | #include <sys/sysctl.h> |
38 | #include <sys/wait.h> | | 38 | #include <sys/wait.h> |
39 | #include <machine/reg.h> | | 39 | #include <machine/reg.h> |
40 | #include <err.h> | | 40 | #include <err.h> |
41 | #include <errno.h> | | 41 | #include <errno.h> |
42 | #include <sched.h> | | 42 | #include <sched.h> |
43 | #include <signal.h> | | 43 | #include <signal.h> |
44 | #include <stdint.h> | | 44 | #include <stdint.h> |
45 | #include <stdio.h> | | 45 | #include <stdio.h> |
46 | #include <stdlib.h> | | 46 | #include <stdlib.h> |
47 | #include <strings.h> | | 47 | #include <strings.h> |
48 | #include <unistd.h> | | 48 | #include <unistd.h> |
49 | | | 49 | |
50 | #include <atf-c.h> | | 50 | #include <atf-c.h> |
51 | | | 51 | |
52 | #include "../../../h_macros.h" | | 52 | #include "../../../h_macros.h" |
53 | | | 53 | |
54 | #include "../../t_ptrace_wait.h" | | 54 | #include "../../t_ptrace_wait.h" |
55 | | | 55 | |
| | | 56 | |
| | | 57 | union u { |
| | | 58 | long raw; |
| | | 59 | struct { |
| | | 60 | long local_dr0_breakpoint : 1; /* 0 */ |
| | | 61 | long global_dr0_breakpoint : 1; /* 1 */ |
| | | 62 | long local_dr1_breakpoint : 1; /* 2 */ |
| | | 63 | long global_dr1_breakpoint : 1; /* 3 */ |
| | | 64 | long local_dr2_breakpoint : 1; /* 4 */ |
| | | 65 | long global_dr2_breakpoint : 1; /* 5 */ |
| | | 66 | long local_dr3_breakpoint : 1; /* 6 */ |
| | | 67 | long global_dr3_breakpoint : 1; /* 7 */ |
| | | 68 | long local_exact_breakpt : 1; /* 8 */ |
| | | 69 | long global_exact_breakpt : 1; /* 9 */ |
| | | 70 | long reserved_10 : 1; /* 10 */ |
| | | 71 | long rest_trans_memory : 1; /* 11 */ |
| | | 72 | long reserved_12 : 1; /* 12 */ |
| | | 73 | long general_detect_enable : 1; /* 13 */ |
| | | 74 | long reserved_14 : 1; /* 14 */ |
| | | 75 | long reserved_15 : 1; /* 15 */ |
| | | 76 | long condition_dr0 : 2; /* 16-17 */ |
| | | 77 | long len_dr0 : 2; /* 18-19 */ |
| | | 78 | long condition_dr1 : 2; /* 20-21 */ |
| | | 79 | long len_dr1 : 2; /* 22-23 */ |
| | | 80 | long condition_dr2 : 2; /* 24-25 */ |
| | | 81 | long len_dr2 : 2; /* 26-27 */ |
| | | 82 | long condition_dr3 : 2; /* 28-29 */ |
| | | 83 | long len_dr3 : 2; /* 30-31 */ |
| | | 84 | } bits; |
| | | 85 | }; |
| | | 86 | |
| | | 87 | |
56 | #if defined(HAVE_DBREGS) | | 88 | #if defined(HAVE_DBREGS) |
57 | ATF_TC(dbregs_print); | | 89 | ATF_TC(dbregs_print); |
58 | ATF_TC_HEAD(dbregs_print, tc) | | 90 | ATF_TC_HEAD(dbregs_print, tc) |
59 | { | | 91 | { |
60 | atf_tc_set_md_var(tc, "descr", | | 92 | atf_tc_set_md_var(tc, "descr", |
61 | "Verify plain PT_GETDBREGS with printing Debug Registers"); | | 93 | "Verify plain PT_GETDBREGS with printing Debug Registers"); |
62 | } | | 94 | } |
63 | | | 95 | |
64 | ATF_TC_BODY(dbregs_print, tc) | | 96 | ATF_TC_BODY(dbregs_print, tc) |
65 | { | | 97 | { |
66 | const int exitval = 5; | | 98 | const int exitval = 5; |
67 | const int sigval = SIGSTOP; | | 99 | const int sigval = SIGSTOP; |
68 | pid_t child, wpid; | | 100 | pid_t child, wpid; |
| @@ -79,27 +111,27 @@ ATF_TC_BODY(dbregs_print, tc) | | | @@ -79,27 +111,27 @@ ATF_TC_BODY(dbregs_print, tc) |
79 | FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); | | 111 | FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); |
80 | | | 112 | |
81 | printf("Before raising %s from child\n", strsignal(sigval)); | | 113 | printf("Before raising %s from child\n", strsignal(sigval)); |
82 | FORKEE_ASSERT(raise(sigval) == 0); | | 114 | FORKEE_ASSERT(raise(sigval) == 0); |
83 | | | 115 | |
84 | printf("Before exiting of the child process\n"); | | 116 | printf("Before exiting of the child process\n"); |
85 | _exit(exitval); | | 117 | _exit(exitval); |
86 | } | | 118 | } |
87 | printf("Parent process PID=%d, child's PID=%d\n", getpid(), child); | | 119 | printf("Parent process PID=%d, child's PID=%d\n", getpid(), child); |
88 | | | 120 | |
89 | printf("Before calling %s() for the child\n", TWAIT_FNAME); | | 121 | printf("Before calling %s() for the child\n", TWAIT_FNAME); |
90 | TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); | | 122 | TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); |
91 | | | 123 | |
92 | validate_status_stopped(status, sigval); | | 124 | validate_status_stopped(status, sigval); |
93 | | | 125 | |
94 | printf("Call GETDBREGS for the child process\n"); | | 126 | printf("Call GETDBREGS for the child process\n"); |
95 | ATF_REQUIRE(ptrace(PT_GETDBREGS, child, &r, 0) != -1); | | 127 | ATF_REQUIRE(ptrace(PT_GETDBREGS, child, &r, 0) != -1); |
96 | | | 128 | |
97 | printf("State of the debug registers:\n"); | | 129 | printf("State of the debug registers:\n"); |
98 | for (i = 0; i < __arraycount(r.dbregs); i++) | | 130 | for (i = 0; i < __arraycount(r.dbregs); i++) |
99 | printf("r[%zu]=%#lx\n", i, r.dbregs[i]); | | 131 | printf("r[%zu]=%#lx\n", i, r.dbregs[i]); |
100 | | | 132 | |
101 | printf("Before resuming the child process where it left off and " | | 133 | printf("Before resuming the child process where it left off and " |
102 | "without signal to be sent\n"); | | 134 | "without signal to be sent\n"); |
103 | ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1); | | 135 | ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1); |
104 | | | 136 | |
105 | printf("Before calling %s() for the child\n", TWAIT_FNAME); | | 137 | printf("Before calling %s() for the child\n", TWAIT_FNAME); |
| @@ -1182,37 +1214,486 @@ ATF_TC_BODY(dbregs_preserve_dr3_continue | | | @@ -1182,37 +1214,486 @@ ATF_TC_BODY(dbregs_preserve_dr3_continue |
1182 | "without signal to be sent\n"); | | 1214 | "without signal to be sent\n"); |
1183 | ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1); | | 1215 | ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1); |
1184 | | | 1216 | |
1185 | printf("Before calling %s() for the child\n", TWAIT_FNAME); | | 1217 | printf("Before calling %s() for the child\n", TWAIT_FNAME); |
1186 | TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); | | 1218 | TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); |
1187 | | | 1219 | |
1188 | validate_status_exited(status, exitval); | | 1220 | validate_status_exited(status, exitval); |
1189 | | | 1221 | |
1190 | printf("Before calling %s() for the child\n", TWAIT_FNAME); | | 1222 | printf("Before calling %s() for the child\n", TWAIT_FNAME); |
1191 | TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); | | 1223 | TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); |
1192 | } | | 1224 | } |
1193 | #endif | | 1225 | #endif |
1194 | | | 1226 | |
| | | 1227 | #if defined(HAVE_DBREGS) |
| | | 1228 | ATF_TC(dbregs_dr0_trap_variable); |
| | | 1229 | ATF_TC_HEAD(dbregs_dr0_trap_variable, tc) |
| | | 1230 | { |
| | | 1231 | atf_tc_set_md_var(tc, "descr", |
| | | 1232 | "Verify that setting trap with DR0 triggers SIGTRAP"); |
| | | 1233 | } |
| | | 1234 | |
| | | 1235 | ATF_TC_BODY(dbregs_dr0_trap_variable, tc) |
| | | 1236 | { |
| | | 1237 | const int exitval = 5; |
| | | 1238 | const int sigval = SIGSTOP; |
| | | 1239 | pid_t child, wpid; |
| | | 1240 | #if defined(TWAIT_HAVE_STATUS) |
| | | 1241 | int status; |
| | | 1242 | #endif |
| | | 1243 | struct dbreg r1; |
| | | 1244 | struct dbreg r2; |
| | | 1245 | /* Number of available CPU Debug Registers on AMD64 */ |
| | | 1246 | const size_t len = 16; |
| | | 1247 | size_t i; |
| | | 1248 | volatile int watchme; |
| | | 1249 | union u dr7; |
| | | 1250 | |
| | | 1251 | dr7.raw = 0; |
| | | 1252 | dr7.bits.global_dr0_breakpoint = 1; |
| | | 1253 | dr7.bits.condition_dr0 = 3; /* 0b11 -- break on data write&read */ |
| | | 1254 | dr7.bits.len_dr0 = 3; /* 0b11 -- 4 bytes */ |
| | | 1255 | |
| | | 1256 | printf("Assert that known number of Debug Registers (%zu) is valid\n", |
| | | 1257 | len); |
| | | 1258 | ATF_REQUIRE_EQ(__arraycount(r1.dbregs), len); |
| | | 1259 | ATF_REQUIRE_EQ(__arraycount(r2.dbregs), len); |
| | | 1260 | |
| | | 1261 | printf("Before forking process PID=%d\n", getpid()); |
| | | 1262 | child = atf_utils_fork(); |
| | | 1263 | if (child == 0) { |
| | | 1264 | printf("Before calling PT_TRACE_ME from child %d\n", getpid()); |
| | | 1265 | FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); |
| | | 1266 | |
| | | 1267 | printf("Before raising %s from child\n", strsignal(sigval)); |
| | | 1268 | FORKEE_ASSERT(raise(sigval) == 0); |
| | | 1269 | |
| | | 1270 | watchme = 1; |
| | | 1271 | |
| | | 1272 | printf("Before raising %s from child\n", strsignal(sigval)); |
| | | 1273 | FORKEE_ASSERT(raise(sigval) == 0); |
| | | 1274 | |
| | | 1275 | printf("Before exiting of the child process\n"); |
| | | 1276 | _exit(exitval); |
| | | 1277 | } |
| | | 1278 | printf("Parent process PID=%d, child's PID=%d\n", getpid(), child); |
| | | 1279 | |
| | | 1280 | printf("Before calling %s() for the child\n", TWAIT_FNAME); |
| | | 1281 | TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); |
| | | 1282 | |
| | | 1283 | validate_status_stopped(status, sigval); |
| | | 1284 | |
| | | 1285 | printf("Call GETDBREGS for the child process (r1)\n"); |
| | | 1286 | ATF_REQUIRE(ptrace(PT_GETDBREGS, child, &r1, 0) != -1); |
| | | 1287 | |
| | | 1288 | printf("State of the debug registers (r1):\n"); |
| | | 1289 | for (i = 0; i < __arraycount(r1.dbregs); i++) |
| | | 1290 | printf("r1[%zu]=%#lx\n", i, r1.dbregs[i]); |
| | | 1291 | |
| | | 1292 | r1.dbregs[0] = (long)(intptr_t)&watchme; |
| | | 1293 | printf("Set DR0 (r1.dbregs[0]) to new value %#lx\n", r1.dbregs[0]); |
| | | 1294 | |
| | | 1295 | r1.dbregs[7] = dr7.raw; |
| | | 1296 | printf("Set DR7 (r1.dbregs[7]) to new value %#lx\n", r1.dbregs[7]); |
| | | 1297 | |
| | | 1298 | printf("New state of the debug registers (r1):\n"); |
| | | 1299 | for (i = 0; i < __arraycount(r1.dbregs); i++) |
| | | 1300 | printf("r1[%zu]=%#lx\n", i, r1.dbregs[i]); |
| | | 1301 | |
| | | 1302 | printf("Call SETDBREGS for the child process (r1)\n"); |
| | | 1303 | ATF_REQUIRE(ptrace(PT_SETDBREGS, child, &r1, 0) != -1); |
| | | 1304 | |
| | | 1305 | printf("Call CONTINUE for the child process\n"); |
| | | 1306 | ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1); |
| | | 1307 | |
| | | 1308 | printf("Before calling %s() for the child\n", TWAIT_FNAME); |
| | | 1309 | TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); |
| | | 1310 | |
| | | 1311 | validate_status_stopped(status, SIGTRAP); |
| | | 1312 | |
| | | 1313 | printf("Before calling %s() for the child\n", TWAIT_FNAME); |
| | | 1314 | TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); |
| | | 1315 | |
| | | 1316 | validate_status_stopped(status, sigval); |
| | | 1317 | |
| | | 1318 | printf("Call GETDBREGS for the child process (r2)\n"); |
| | | 1319 | ATF_REQUIRE(ptrace(PT_GETDBREGS, child, &r2, 0) != -1); |
| | | 1320 | |
| | | 1321 | printf("Assert that (r1) and (r2) are the same\n"); |
| | | 1322 | ATF_REQUIRE(memcmp(&r1, &r2, len) == 0); |
| | | 1323 | |
| | | 1324 | printf("Before resuming the child process where it left off and " |
| | | 1325 | "without signal to be sent\n"); |
| | | 1326 | ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1); |
| | | 1327 | |
| | | 1328 | printf("Before calling %s() for the child\n", TWAIT_FNAME); |
| | | 1329 | TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); |
| | | 1330 | |
| | | 1331 | validate_status_exited(status, exitval); |
| | | 1332 | |
| | | 1333 | printf("Before calling %s() for the child\n", TWAIT_FNAME); |
| | | 1334 | TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); |
| | | 1335 | } |
| | | 1336 | #endif |
| | | 1337 | |
| | | 1338 | #if defined(HAVE_DBREGS) |
| | | 1339 | ATF_TC(dbregs_dr1_trap_variable); |
| | | 1340 | ATF_TC_HEAD(dbregs_dr1_trap_variable, tc) |
| | | 1341 | { |
| | | 1342 | atf_tc_set_md_var(tc, "descr", |
| | | 1343 | "Verify that setting trap with DR1 triggers SIGTRAP"); |
| | | 1344 | } |
| | | 1345 | |
| | | 1346 | ATF_TC_BODY(dbregs_dr1_trap_variable, tc) |
| | | 1347 | { |
| | | 1348 | const int exitval = 5; |
| | | 1349 | const int sigval = SIGSTOP; |
| | | 1350 | pid_t child, wpid; |
| | | 1351 | #if defined(TWAIT_HAVE_STATUS) |
| | | 1352 | int status; |
| | | 1353 | #endif |
| | | 1354 | struct dbreg r1; |
| | | 1355 | struct dbreg r2; |
| | | 1356 | /* Number of available CPU Debug Registers on AMD64 */ |
| | | 1357 | const size_t len = 16; |
| | | 1358 | size_t i; |
| | | 1359 | volatile int watchme; |
| | | 1360 | union u dr7; |
| | | 1361 | |
| | | 1362 | dr7.raw = 0; |
| | | 1363 | dr7.bits.global_dr1_breakpoint = 1; |
| | | 1364 | dr7.bits.condition_dr1 = 3; /* 0b11 -- break on data write&read */ |
| | | 1365 | dr7.bits.len_dr1 = 3; /* 0b11 -- 4 bytes */ |
| | | 1366 | |
| | | 1367 | printf("Assert that known number of Debug Registers (%zu) is valid\n", |
| | | 1368 | len); |
| | | 1369 | ATF_REQUIRE_EQ(__arraycount(r1.dbregs), len); |
| | | 1370 | ATF_REQUIRE_EQ(__arraycount(r2.dbregs), len); |
| | | 1371 | |
| | | 1372 | printf("Before forking process PID=%d\n", getpid()); |
| | | 1373 | child = atf_utils_fork(); |
| | | 1374 | if (child == 0) { |
| | | 1375 | printf("Before calling PT_TRACE_ME from child %d\n", getpid()); |
| | | 1376 | FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); |
| | | 1377 | |
| | | 1378 | printf("Before raising %s from child\n", strsignal(sigval)); |
| | | 1379 | FORKEE_ASSERT(raise(sigval) == 0); |
| | | 1380 | |
| | | 1381 | watchme = 1; |
| | | 1382 | |
| | | 1383 | printf("Before raising %s from child\n", strsignal(sigval)); |
| | | 1384 | FORKEE_ASSERT(raise(sigval) == 0); |
| | | 1385 | |
| | | 1386 | printf("Before exiting of the child process\n"); |
| | | 1387 | _exit(exitval); |
| | | 1388 | } |
| | | 1389 | printf("Parent process PID=%d, child's PID=%d\n", getpid(), child); |
| | | 1390 | |
| | | 1391 | printf("Before calling %s() for the child\n", TWAIT_FNAME); |
| | | 1392 | TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); |
| | | 1393 | |
| | | 1394 | validate_status_stopped(status, sigval); |
| | | 1395 | |
| | | 1396 | printf("Call GETDBREGS for the child process (r1)\n"); |
| | | 1397 | ATF_REQUIRE(ptrace(PT_GETDBREGS, child, &r1, 0) != -1); |
| | | 1398 | |
| | | 1399 | printf("State of the debug registers (r1):\n"); |
| | | 1400 | for (i = 0; i < __arraycount(r1.dbregs); i++) |
| | | 1401 | printf("r1[%zu]=%#lx\n", i, r1.dbregs[i]); |
| | | 1402 | |
| | | 1403 | r1.dbregs[1] = (long)(intptr_t)&watchme; |
| | | 1404 | printf("Set DR1 (r1.dbregs[1]) to new value %#lx\n", r1.dbregs[1]); |
| | | 1405 | |
| | | 1406 | r1.dbregs[7] = dr7.raw; |
| | | 1407 | printf("Set DR7 (r1.dbregs[7]) to new value %#lx\n", r1.dbregs[7]); |
| | | 1408 | |
| | | 1409 | printf("New state of the debug registers (r1):\n"); |
| | | 1410 | for (i = 0; i < __arraycount(r1.dbregs); i++) |
| | | 1411 | printf("r1[%zu]=%#lx\n", i, r1.dbregs[i]); |
| | | 1412 | |
| | | 1413 | printf("Call SETDBREGS for the child process (r1)\n"); |
| | | 1414 | ATF_REQUIRE(ptrace(PT_SETDBREGS, child, &r1, 0) != -1); |
| | | 1415 | |
| | | 1416 | printf("Call CONTINUE for the child process\n"); |
| | | 1417 | ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1); |
| | | 1418 | |
| | | 1419 | printf("Before calling %s() for the child\n", TWAIT_FNAME); |
| | | 1420 | TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); |
| | | 1421 | |
| | | 1422 | validate_status_stopped(status, SIGTRAP); |
| | | 1423 | |
| | | 1424 | printf("Before calling %s() for the child\n", TWAIT_FNAME); |
| | | 1425 | TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); |
| | | 1426 | |
| | | 1427 | validate_status_stopped(status, sigval); |
| | | 1428 | |
| | | 1429 | printf("Call GETDBREGS for the child process (r2)\n"); |
| | | 1430 | ATF_REQUIRE(ptrace(PT_GETDBREGS, child, &r2, 0) != -1); |
| | | 1431 | |
| | | 1432 | printf("Assert that (r1) and (r2) are the same\n"); |
| | | 1433 | ATF_REQUIRE(memcmp(&r1, &r2, len) == 0); |
| | | 1434 | |
| | | 1435 | printf("Before resuming the child process where it left off and " |
| | | 1436 | "without signal to be sent\n"); |
| | | 1437 | ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1); |
| | | 1438 | |
| | | 1439 | printf("Before calling %s() for the child\n", TWAIT_FNAME); |
| | | 1440 | TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); |
| | | 1441 | |
| | | 1442 | validate_status_exited(status, exitval); |
| | | 1443 | |
| | | 1444 | printf("Before calling %s() for the child\n", TWAIT_FNAME); |
| | | 1445 | TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); |
| | | 1446 | } |
| | | 1447 | #endif |
| | | 1448 | |
| | | 1449 | #if defined(HAVE_DBREGS) |
| | | 1450 | ATF_TC(dbregs_dr2_trap_variable); |
| | | 1451 | ATF_TC_HEAD(dbregs_dr2_trap_variable, tc) |
| | | 1452 | { |
| | | 1453 | atf_tc_set_md_var(tc, "descr", |
| | | 1454 | "Verify that setting trap with DR2 triggers SIGTRAP"); |
| | | 1455 | } |
| | | 1456 | |
| | | 1457 | ATF_TC_BODY(dbregs_dr2_trap_variable, tc) |
| | | 1458 | { |
| | | 1459 | const int exitval = 5; |
| | | 1460 | const int sigval = SIGSTOP; |
| | | 1461 | pid_t child, wpid; |
| | | 1462 | #if defined(TWAIT_HAVE_STATUS) |
| | | 1463 | int status; |
| | | 1464 | #endif |
| | | 1465 | struct dbreg r1; |
| | | 1466 | struct dbreg r2; |
| | | 1467 | /* Number of available CPU Debug Registers on AMD64 */ |
| | | 1468 | const size_t len = 16; |
| | | 1469 | size_t i; |
| | | 1470 | volatile int watchme; |
| | | 1471 | union u dr7; |
| | | 1472 | |
| | | 1473 | dr7.raw = 0; |
| | | 1474 | dr7.bits.global_dr2_breakpoint = 1; |
| | | 1475 | dr7.bits.condition_dr2 = 3; /* 0b11 -- break on data write&read */ |
| | | 1476 | dr7.bits.len_dr2 = 3; /* 0b11 -- 4 bytes */ |
| | | 1477 | |
| | | 1478 | printf("Assert that known number of Debug Registers (%zu) is valid\n", |
| | | 1479 | len); |
| | | 1480 | ATF_REQUIRE_EQ(__arraycount(r1.dbregs), len); |
| | | 1481 | ATF_REQUIRE_EQ(__arraycount(r2.dbregs), len); |
| | | 1482 | |
| | | 1483 | printf("Before forking process PID=%d\n", getpid()); |
| | | 1484 | child = atf_utils_fork(); |
| | | 1485 | if (child == 0) { |
| | | 1486 | printf("Before calling PT_TRACE_ME from child %d\n", getpid()); |
| | | 1487 | FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); |
| | | 1488 | |
| | | 1489 | printf("Before raising %s from child\n", strsignal(sigval)); |
| | | 1490 | FORKEE_ASSERT(raise(sigval) == 0); |
| | | 1491 | |
| | | 1492 | watchme = 1; |
| | | 1493 | |
| | | 1494 | printf("Before raising %s from child\n", strsignal(sigval)); |
| | | 1495 | FORKEE_ASSERT(raise(sigval) == 0); |
| | | 1496 | |
| | | 1497 | printf("Before exiting of the child process\n"); |
| | | 1498 | _exit(exitval); |
| | | 1499 | } |
| | | 1500 | printf("Parent process PID=%d, child's PID=%d\n", getpid(), child); |
| | | 1501 | |
| | | 1502 | printf("Before calling %s() for the child\n", TWAIT_FNAME); |
| | | 1503 | TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); |
| | | 1504 | |
| | | 1505 | validate_status_stopped(status, sigval); |
| | | 1506 | |
| | | 1507 | printf("Call GETDBREGS for the child process (r1)\n"); |
| | | 1508 | ATF_REQUIRE(ptrace(PT_GETDBREGS, child, &r1, 0) != -1); |
| | | 1509 | |
| | | 1510 | printf("State of the debug registers (r1):\n"); |
| | | 1511 | for (i = 0; i < __arraycount(r1.dbregs); i++) |
| | | 1512 | printf("r1[%zu]=%#lx\n", i, r1.dbregs[i]); |
| | | 1513 | |
| | | 1514 | r1.dbregs[2] = (long)(intptr_t)&watchme; |
| | | 1515 | printf("Set DR2 (r1.dbregs[2]) to new value %#lx\n", r1.dbregs[2]); |
| | | 1516 | |
| | | 1517 | r1.dbregs[7] = dr7.raw; |
| | | 1518 | printf("Set DR7 (r1.dbregs[7]) to new value %#lx\n", r1.dbregs[7]); |
| | | 1519 | |
| | | 1520 | printf("New state of the debug registers (r1):\n"); |
| | | 1521 | for (i = 0; i < __arraycount(r1.dbregs); i++) |
| | | 1522 | printf("r1[%zu]=%#lx\n", i, r1.dbregs[i]); |
| | | 1523 | |
| | | 1524 | printf("Call SETDBREGS for the child process (r1)\n"); |
| | | 1525 | ATF_REQUIRE(ptrace(PT_SETDBREGS, child, &r1, 0) != -1); |
| | | 1526 | |
| | | 1527 | printf("Call CONTINUE for the child process\n"); |
| | | 1528 | ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1); |
| | | 1529 | |
| | | 1530 | printf("Before calling %s() for the child\n", TWAIT_FNAME); |
| | | 1531 | TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); |
| | | 1532 | |
| | | 1533 | validate_status_stopped(status, SIGTRAP); |
| | | 1534 | |
| | | 1535 | printf("Before calling %s() for the child\n", TWAIT_FNAME); |
| | | 1536 | TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); |
| | | 1537 | |
| | | 1538 | validate_status_stopped(status, sigval); |
| | | 1539 | |
| | | 1540 | printf("Call GETDBREGS for the child process (r2)\n"); |
| | | 1541 | ATF_REQUIRE(ptrace(PT_GETDBREGS, child, &r2, 0) != -1); |
| | | 1542 | |
| | | 1543 | printf("Assert that (r1) and (r2) are the same\n"); |
| | | 1544 | ATF_REQUIRE(memcmp(&r1, &r2, len) == 0); |
| | | 1545 | |
| | | 1546 | printf("Before resuming the child process where it left off and " |
| | | 1547 | "without signal to be sent\n"); |
| | | 1548 | ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1); |
| | | 1549 | |
| | | 1550 | printf("Before calling %s() for the child\n", TWAIT_FNAME); |
| | | 1551 | TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); |
| | | 1552 | |
| | | 1553 | validate_status_exited(status, exitval); |
| | | 1554 | |
| | | 1555 | printf("Before calling %s() for the child\n", TWAIT_FNAME); |
| | | 1556 | TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); |
| | | 1557 | } |
| | | 1558 | #endif |
| | | 1559 | |
| | | 1560 | #if defined(HAVE_DBREGS) |
| | | 1561 | ATF_TC(dbregs_dr3_trap_variable); |
| | | 1562 | ATF_TC_HEAD(dbregs_dr3_trap_variable, tc) |
| | | 1563 | { |
| | | 1564 | atf_tc_set_md_var(tc, "descr", |
| | | 1565 | "Verify that setting trap with DR3 triggers SIGTRAP"); |
| | | 1566 | } |
| | | 1567 | |
| | | 1568 | ATF_TC_BODY(dbregs_dr3_trap_variable, tc) |
| | | 1569 | { |
| | | 1570 | const int exitval = 5; |
| | | 1571 | const int sigval = SIGSTOP; |
| | | 1572 | pid_t child, wpid; |
| | | 1573 | #if defined(TWAIT_HAVE_STATUS) |
| | | 1574 | int status; |
| | | 1575 | #endif |
| | | 1576 | struct dbreg r1; |
| | | 1577 | struct dbreg r2; |
| | | 1578 | /* Number of available CPU Debug Registers on AMD64 */ |
| | | 1579 | const size_t len = 16; |
| | | 1580 | size_t i; |
| | | 1581 | volatile int watchme; |
| | | 1582 | union u dr7; |
| | | 1583 | |
| | | 1584 | dr7.raw = 0; |
| | | 1585 | dr7.bits.global_dr3_breakpoint = 1; |
| | | 1586 | dr7.bits.condition_dr3 = 3; /* 0b11 -- break on data write&read */ |
| | | 1587 | dr7.bits.len_dr3 = 3; /* 0b11 -- 4 bytes */ |
| | | 1588 | |
| | | 1589 | printf("Assert that known number of Debug Registers (%zu) is valid\n", |
| | | 1590 | len); |
| | | 1591 | ATF_REQUIRE_EQ(__arraycount(r1.dbregs), len); |
| | | 1592 | ATF_REQUIRE_EQ(__arraycount(r2.dbregs), len); |
| | | 1593 | |
| | | 1594 | printf("Before forking process PID=%d\n", getpid()); |
| | | 1595 | child = atf_utils_fork(); |
| | | 1596 | if (child == 0) { |
| | | 1597 | printf("Before calling PT_TRACE_ME from child %d\n", getpid()); |
| | | 1598 | FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); |
| | | 1599 | |
| | | 1600 | printf("Before raising %s from child\n", strsignal(sigval)); |
| | | 1601 | FORKEE_ASSERT(raise(sigval) == 0); |
| | | 1602 | |
| | | 1603 | watchme = 1; |
| | | 1604 | |
| | | 1605 | printf("Before raising %s from child\n", strsignal(sigval)); |
| | | 1606 | FORKEE_ASSERT(raise(sigval) == 0); |
| | | 1607 | |
| | | 1608 | printf("Before exiting of the child process\n"); |
| | | 1609 | _exit(exitval); |
| | | 1610 | } |
| | | 1611 | printf("Parent process PID=%d, child's PID=%d\n", getpid(), child); |
| | | 1612 | |
| | | 1613 | printf("Before calling %s() for the child\n", TWAIT_FNAME); |
| | | 1614 | TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); |
| | | 1615 | |
| | | 1616 | validate_status_stopped(status, sigval); |
| | | 1617 | |
| | | 1618 | printf("Call GETDBREGS for the child process (r1)\n"); |
| | | 1619 | ATF_REQUIRE(ptrace(PT_GETDBREGS, child, &r1, 0) != -1); |
| | | 1620 | |
| | | 1621 | printf("State of the debug registers (r1):\n"); |
| | | 1622 | for (i = 0; i < __arraycount(r1.dbregs); i++) |
| | | 1623 | printf("r1[%zu]=%#lx\n", i, r1.dbregs[i]); |
| | | 1624 | |
| | | 1625 | r1.dbregs[3] = (long)(intptr_t)&watchme; |
| | | 1626 | printf("Set DR3 (r1.dbregs[3]) to new value %#lx\n", r1.dbregs[3]); |
| | | 1627 | |
| | | 1628 | r1.dbregs[7] = dr7.raw; |
| | | 1629 | printf("Set DR7 (r1.dbregs[7]) to new value %#lx\n", r1.dbregs[7]); |
| | | 1630 | |
| | | 1631 | printf("New state of the debug registers (r1):\n"); |
| | | 1632 | for (i = 0; i < __arraycount(r1.dbregs); i++) |
| | | 1633 | printf("r1[%zu]=%#lx\n", i, r1.dbregs[i]); |
| | | 1634 | |
| | | 1635 | printf("Call SETDBREGS for the child process (r1)\n"); |
| | | 1636 | ATF_REQUIRE(ptrace(PT_SETDBREGS, child, &r1, 0) != -1); |
| | | 1637 | |
| | | 1638 | printf("Call CONTINUE for the child process\n"); |
| | | 1639 | ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1); |
| | | 1640 | |
| | | 1641 | printf("Before calling %s() for the child\n", TWAIT_FNAME); |
| | | 1642 | TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); |
| | | 1643 | |
| | | 1644 | validate_status_stopped(status, SIGTRAP); |
| | | 1645 | |
| | | 1646 | printf("Before calling %s() for the child\n", TWAIT_FNAME); |
| | | 1647 | TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); |
| | | 1648 | |
| | | 1649 | validate_status_stopped(status, sigval); |
| | | 1650 | |
| | | 1651 | printf("Call GETDBREGS for the child process (r2)\n"); |
| | | 1652 | ATF_REQUIRE(ptrace(PT_GETDBREGS, child, &r2, 0) != -1); |
| | | 1653 | |
| | | 1654 | printf("Assert that (r1) and (r2) are the same\n"); |
| | | 1655 | ATF_REQUIRE(memcmp(&r1, &r2, len) == 0); |
| | | 1656 | |
| | | 1657 | printf("Before resuming the child process where it left off and " |
| | | 1658 | "without signal to be sent\n"); |
| | | 1659 | ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1); |
| | | 1660 | |
| | | 1661 | printf("Before calling %s() for the child\n", TWAIT_FNAME); |
| | | 1662 | TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); |
| | | 1663 | |
| | | 1664 | validate_status_exited(status, exitval); |
| | | 1665 | |
| | | 1666 | printf("Before calling %s() for the child\n", TWAIT_FNAME); |
| | | 1667 | TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); |
| | | 1668 | } |
| | | 1669 | #endif |
| | | 1670 | |
1195 | ATF_TP_ADD_TCS(tp) | | 1671 | ATF_TP_ADD_TCS(tp) |
1196 | { | | 1672 | { |
1197 | setvbuf(stdout, NULL, _IONBF, 0); | | 1673 | setvbuf(stdout, NULL, _IONBF, 0); |
1198 | setvbuf(stderr, NULL, _IONBF, 0); | | 1674 | setvbuf(stderr, NULL, _IONBF, 0); |
1199 | | | 1675 | |
1200 | ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_print); | | 1676 | ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_print); |
1201 | | | 1677 | |
1202 | ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_preserve_dr0); | | 1678 | ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_preserve_dr0); |
1203 | ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_preserve_dr1); | | 1679 | ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_preserve_dr1); |
1204 | ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_preserve_dr2); | | 1680 | ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_preserve_dr2); |
1205 | ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_preserve_dr3); | | 1681 | ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_preserve_dr3); |
1206 | | | 1682 | |
1207 | ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_preserve_dr0_yield); | | 1683 | ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_preserve_dr0_yield); |
1208 | ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_preserve_dr1_yield); | | 1684 | ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_preserve_dr1_yield); |
1209 | ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_preserve_dr2_yield); | | 1685 | ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_preserve_dr2_yield); |
1210 | ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_preserve_dr3_yield); | | 1686 | ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_preserve_dr3_yield); |
1211 | | | 1687 | |
1212 | ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_preserve_dr0_continued); | | 1688 | ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_preserve_dr0_continued); |
1213 | ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_preserve_dr1_continued); | | 1689 | ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_preserve_dr1_continued); |
1214 | ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_preserve_dr2_continued); | | 1690 | ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_preserve_dr2_continued); |
1215 | ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_preserve_dr3_continued); | | 1691 | ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_preserve_dr3_continued); |
1216 | | | 1692 | |
| | | 1693 | ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_dr0_trap_variable); |
| | | 1694 | ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_dr1_trap_variable); |
| | | 1695 | ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_dr2_trap_variable); |
| | | 1696 | ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_dr3_trap_variable); |
| | | 1697 | |
1217 | return atf_no_error(); | | 1698 | return atf_no_error(); |
1218 | } | | 1699 | } |