0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <sys/ptrace.h>
0010 #include <unistd.h>
0011 #include <stddef.h>
0012 #include <sys/user.h>
0013 #include <stdio.h>
0014 #include <stdlib.h>
0015 #include <signal.h>
0016 #include <sys/types.h>
0017 #include <sys/wait.h>
0018 #include <errno.h>
0019 #include <string.h>
0020
0021 #include "../kselftest.h"
0022
0023 #define COUNT_ISN_BPS 4
0024 #define COUNT_WPS 4
0025
0026
0027 enum {
0028 BP_X = 1,
0029 BP_RW = 2,
0030 BP_W = 4,
0031 };
0032
0033 static pid_t child_pid;
0034
0035
0036
0037
0038
0039
0040 static int nr_tests;
0041
0042 static void set_breakpoint_addr(void *addr, int n)
0043 {
0044 int ret;
0045
0046 ret = ptrace(PTRACE_POKEUSER, child_pid,
0047 offsetof(struct user, u_debugreg[n]), addr);
0048 if (ret)
0049 ksft_exit_fail_msg("Can't set breakpoint addr: %s\n",
0050 strerror(errno));
0051 }
0052
0053 static void toggle_breakpoint(int n, int type, int len,
0054 int local, int global, int set)
0055 {
0056 int ret;
0057
0058 int xtype, xlen;
0059 unsigned long vdr7, dr7;
0060
0061 switch (type) {
0062 case BP_X:
0063 xtype = 0;
0064 break;
0065 case BP_W:
0066 xtype = 1;
0067 break;
0068 case BP_RW:
0069 xtype = 3;
0070 break;
0071 }
0072
0073 switch (len) {
0074 case 1:
0075 xlen = 0;
0076 break;
0077 case 2:
0078 xlen = 4;
0079 break;
0080 case 4:
0081 xlen = 0xc;
0082 break;
0083 case 8:
0084 xlen = 8;
0085 break;
0086 }
0087
0088 dr7 = ptrace(PTRACE_PEEKUSER, child_pid,
0089 offsetof(struct user, u_debugreg[7]), 0);
0090
0091 vdr7 = (xlen | xtype) << 16;
0092 vdr7 <<= 4 * n;
0093
0094 if (local) {
0095 vdr7 |= 1 << (2 * n);
0096 vdr7 |= 1 << 8;
0097 }
0098 if (global) {
0099 vdr7 |= 2 << (2 * n);
0100 vdr7 |= 1 << 9;
0101 }
0102
0103 if (set)
0104 dr7 |= vdr7;
0105 else
0106 dr7 &= ~vdr7;
0107
0108 ret = ptrace(PTRACE_POKEUSER, child_pid,
0109 offsetof(struct user, u_debugreg[7]), dr7);
0110 if (ret) {
0111 ksft_print_msg("Can't set dr7: %s\n", strerror(errno));
0112 exit(-1);
0113 }
0114 }
0115
0116
0117 static unsigned long long dummy_var[4];
0118
0119
0120 static void dummy_func(void) { }
0121 static void dummy_func1(void) { }
0122 static void dummy_func2(void) { }
0123 static void dummy_func3(void) { }
0124
0125 static void (*dummy_funcs[])(void) = {
0126 dummy_func,
0127 dummy_func1,
0128 dummy_func2,
0129 dummy_func3,
0130 };
0131
0132 static int trapped;
0133
0134 static void check_trapped(void)
0135 {
0136
0137
0138
0139
0140 if (!trapped)
0141 kill(getpid(), SIGUSR1);
0142 trapped = 0;
0143
0144 nr_tests++;
0145 }
0146
0147 static void write_var(int len)
0148 {
0149 char *pcval; short *psval; int *pival; long long *plval;
0150 int i;
0151
0152 for (i = 0; i < 4; i++) {
0153 switch (len) {
0154 case 1:
0155 pcval = (char *)&dummy_var[i];
0156 *pcval = 0xff;
0157 break;
0158 case 2:
0159 psval = (short *)&dummy_var[i];
0160 *psval = 0xffff;
0161 break;
0162 case 4:
0163 pival = (int *)&dummy_var[i];
0164 *pival = 0xffffffff;
0165 break;
0166 case 8:
0167 plval = (long long *)&dummy_var[i];
0168 *plval = 0xffffffffffffffffLL;
0169 break;
0170 }
0171 check_trapped();
0172 }
0173 }
0174
0175 static void read_var(int len)
0176 {
0177 char cval; short sval; int ival; long long lval;
0178 int i;
0179
0180 for (i = 0; i < 4; i++) {
0181 switch (len) {
0182 case 1:
0183 cval = *(char *)&dummy_var[i];
0184 break;
0185 case 2:
0186 sval = *(short *)&dummy_var[i];
0187 break;
0188 case 4:
0189 ival = *(int *)&dummy_var[i];
0190 break;
0191 case 8:
0192 lval = *(long long *)&dummy_var[i];
0193 break;
0194 }
0195 check_trapped();
0196 }
0197 }
0198
0199
0200
0201
0202
0203 static void trigger_tests(void)
0204 {
0205 int len, local, global, i;
0206 char val;
0207 int ret;
0208
0209 ret = ptrace(PTRACE_TRACEME, 0, NULL, 0);
0210 if (ret) {
0211 ksft_print_msg("Can't be traced? %s\n", strerror(errno));
0212 return;
0213 }
0214
0215
0216 kill(getpid(), SIGUSR1);
0217
0218
0219 for (local = 0; local < 2; local++) {
0220 for (global = 0; global < 2; global++) {
0221 if (!local && !global)
0222 continue;
0223
0224 for (i = 0; i < COUNT_ISN_BPS; i++) {
0225 dummy_funcs[i]();
0226 check_trapped();
0227 }
0228 }
0229 }
0230
0231
0232 for (len = 1; len <= sizeof(long); len <<= 1) {
0233 for (local = 0; local < 2; local++) {
0234 for (global = 0; global < 2; global++) {
0235 if (!local && !global)
0236 continue;
0237 write_var(len);
0238 }
0239 }
0240 }
0241
0242
0243 for (len = 1; len <= sizeof(long); len <<= 1) {
0244 for (local = 0; local < 2; local++) {
0245 for (global = 0; global < 2; global++) {
0246 if (!local && !global)
0247 continue;
0248 read_var(len);
0249 }
0250 }
0251 }
0252
0253
0254 asm(".byte 0xf1\n");
0255 check_trapped();
0256
0257
0258 asm("int $3\n");
0259 check_trapped();
0260
0261 kill(getpid(), SIGUSR1);
0262 }
0263
0264 static void check_success(const char *msg)
0265 {
0266 int child_nr_tests;
0267 int status;
0268 int ret;
0269
0270
0271 wait(&status);
0272
0273 ret = 0;
0274
0275 if (WSTOPSIG(status) == SIGTRAP) {
0276 child_nr_tests = ptrace(PTRACE_PEEKDATA, child_pid,
0277 &nr_tests, 0);
0278 if (child_nr_tests == nr_tests)
0279 ret = 1;
0280 if (ptrace(PTRACE_POKEDATA, child_pid, &trapped, 1))
0281 ksft_exit_fail_msg("Can't poke: %s\n", strerror(errno));
0282 }
0283
0284 nr_tests++;
0285
0286 if (ret)
0287 ksft_test_result_pass(msg);
0288 else
0289 ksft_test_result_fail(msg);
0290 }
0291
0292 static void launch_instruction_breakpoints(char *buf, int local, int global)
0293 {
0294 int i;
0295
0296 for (i = 0; i < COUNT_ISN_BPS; i++) {
0297 set_breakpoint_addr(dummy_funcs[i], i);
0298 toggle_breakpoint(i, BP_X, 1, local, global, 1);
0299 ptrace(PTRACE_CONT, child_pid, NULL, 0);
0300 sprintf(buf, "Test breakpoint %d with local: %d global: %d\n",
0301 i, local, global);
0302 check_success(buf);
0303 toggle_breakpoint(i, BP_X, 1, local, global, 0);
0304 }
0305 }
0306
0307 static void launch_watchpoints(char *buf, int mode, int len,
0308 int local, int global)
0309 {
0310 const char *mode_str;
0311 int i;
0312
0313 if (mode == BP_W)
0314 mode_str = "write";
0315 else
0316 mode_str = "read";
0317
0318 for (i = 0; i < COUNT_WPS; i++) {
0319 set_breakpoint_addr(&dummy_var[i], i);
0320 toggle_breakpoint(i, mode, len, local, global, 1);
0321 ptrace(PTRACE_CONT, child_pid, NULL, 0);
0322 sprintf(buf,
0323 "Test %s watchpoint %d with len: %d local: %d global: %d\n",
0324 mode_str, i, len, local, global);
0325 check_success(buf);
0326 toggle_breakpoint(i, mode, len, local, global, 0);
0327 }
0328 }
0329
0330
0331 static void launch_tests(void)
0332 {
0333 char buf[1024];
0334 unsigned int tests = 0;
0335 int len, local, global, i;
0336
0337 tests += 3 * COUNT_ISN_BPS;
0338 tests += sizeof(long) / 2 * 3 * COUNT_WPS;
0339 tests += sizeof(long) / 2 * 3 * COUNT_WPS;
0340 tests += 2;
0341 ksft_set_plan(tests);
0342
0343
0344 for (local = 0; local < 2; local++) {
0345 for (global = 0; global < 2; global++) {
0346 if (!local && !global)
0347 continue;
0348 launch_instruction_breakpoints(buf, local, global);
0349 }
0350 }
0351
0352
0353 for (len = 1; len <= sizeof(long); len <<= 1) {
0354 for (local = 0; local < 2; local++) {
0355 for (global = 0; global < 2; global++) {
0356 if (!local && !global)
0357 continue;
0358 launch_watchpoints(buf, BP_W, len,
0359 local, global);
0360 }
0361 }
0362 }
0363
0364
0365 for (len = 1; len <= sizeof(long); len <<= 1) {
0366 for (local = 0; local < 2; local++) {
0367 for (global = 0; global < 2; global++) {
0368 if (!local && !global)
0369 continue;
0370 launch_watchpoints(buf, BP_RW, len,
0371 local, global);
0372 }
0373 }
0374 }
0375
0376
0377 ptrace(PTRACE_CONT, child_pid, NULL, 0);
0378 check_success("Test icebp\n");
0379
0380
0381 ptrace(PTRACE_CONT, child_pid, NULL, 0);
0382 check_success("Test int 3 trap\n");
0383
0384 ptrace(PTRACE_CONT, child_pid, NULL, 0);
0385 }
0386
0387 int main(int argc, char **argv)
0388 {
0389 pid_t pid;
0390 int ret;
0391
0392 ksft_print_header();
0393
0394 pid = fork();
0395 if (!pid) {
0396 trigger_tests();
0397 exit(0);
0398 }
0399
0400 child_pid = pid;
0401
0402 wait(NULL);
0403
0404 launch_tests();
0405
0406 wait(NULL);
0407
0408 ksft_exit_pass();
0409 }