1 /* 2 * Copyright (C) 2011 Red Hat, Inc., Frederic Weisbecker <fweisbec@redhat.com> 3 * 4 * Licensed under the terms of the GNU GPL License version 2 5 * 6 * Selftests for breakpoints (and more generally the do_debug() path) in x86. 7 */ 8 9 10 #include <sys/ptrace.h> 11 #include <unistd.h> 12 #include <stddef.h> 13 #include <sys/user.h> 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <signal.h> 17 #include <sys/types.h> 18 #include <sys/wait.h> 19 #include <errno.h> 20 #include <string.h> 21 22 #include "../kselftest.h" 23 24 #define COUNT_ISN_BPS 4 25 #define COUNT_WPS 4 26 27 /* Breakpoint access modes */ 28 enum { 29 BP_X = 1, 30 BP_RW = 2, 31 BP_W = 4, 32 }; 33 34 static pid_t child_pid; 35 36 /* 37 * Ensures the child and parent are always "talking" about 38 * the same test sequence. (ie: that we haven't forgotten 39 * to call check_trapped() somewhere). 40 */ 41 static int nr_tests; 42 43 static void set_breakpoint_addr(void *addr, int n) 44 { 45 int ret; 46 47 ret = ptrace(PTRACE_POKEUSER, child_pid, 48 offsetof(struct user, u_debugreg[n]), addr); 49 if (ret) 50 ksft_exit_fail_msg("Can't set breakpoint addr: %s\n", 51 strerror(errno)); 52 } 53 54 static void toggle_breakpoint(int n, int type, int len, 55 int local, int global, int set) 56 { 57 int ret; 58 59 int xtype, xlen; 60 unsigned long vdr7, dr7; 61 62 switch (type) { 63 case BP_X: 64 xtype = 0; 65 break; 66 case BP_W: 67 xtype = 1; 68 break; 69 case BP_RW: 70 xtype = 3; 71 break; 72 } 73 74 switch (len) { 75 case 1: 76 xlen = 0; 77 break; 78 case 2: 79 xlen = 4; 80 break; 81 case 4: 82 xlen = 0xc; 83 break; 84 case 8: 85 xlen = 8; 86 break; 87 } 88 89 dr7 = ptrace(PTRACE_PEEKUSER, child_pid, 90 offsetof(struct user, u_debugreg[7]), 0); 91 92 vdr7 = (xlen | xtype) << 16; 93 vdr7 <<= 4 * n; 94 95 if (local) { 96 vdr7 |= 1 << (2 * n); 97 vdr7 |= 1 << 8; 98 } 99 if (global) { 100 vdr7 |= 2 << (2 * n); 101 vdr7 |= 1 << 9; 102 } 103 104 if (set) 105 dr7 |= vdr7; 106 else 107 dr7 &= ~vdr7; 108 109 ret = ptrace(PTRACE_POKEUSER, child_pid, 110 offsetof(struct user, u_debugreg[7]), dr7); 111 if (ret) { 112 ksft_print_msg("Can't set dr7: %s\n", strerror(errno)); 113 exit(-1); 114 } 115 } 116 117 /* Dummy variables to test read/write accesses */ 118 static unsigned long long dummy_var[4]; 119 120 /* Dummy functions to test execution accesses */ 121 static void dummy_func(void) { } 122 static void dummy_func1(void) { } 123 static void dummy_func2(void) { } 124 static void dummy_func3(void) { } 125 126 static void (*dummy_funcs[])(void) = { 127 dummy_func, 128 dummy_func1, 129 dummy_func2, 130 dummy_func3, 131 }; 132 133 static int trapped; 134 135 static void check_trapped(void) 136 { 137 /* 138 * If we haven't trapped, wake up the parent 139 * so that it notices the failure. 140 */ 141 if (!trapped) 142 kill(getpid(), SIGUSR1); 143 trapped = 0; 144 145 nr_tests++; 146 } 147 148 static void write_var(int len) 149 { 150 char *pcval; short *psval; int *pival; long long *plval; 151 int i; 152 153 for (i = 0; i < 4; i++) { 154 switch (len) { 155 case 1: 156 pcval = (char *)&dummy_var[i]; 157 *pcval = 0xff; 158 break; 159 case 2: 160 psval = (short *)&dummy_var[i]; 161 *psval = 0xffff; 162 break; 163 case 4: 164 pival = (int *)&dummy_var[i]; 165 *pival = 0xffffffff; 166 break; 167 case 8: 168 plval = (long long *)&dummy_var[i]; 169 *plval = 0xffffffffffffffffLL; 170 break; 171 } 172 check_trapped(); 173 } 174 } 175 176 static void read_var(int len) 177 { 178 char cval; short sval; int ival; long long lval; 179 int i; 180 181 for (i = 0; i < 4; i++) { 182 switch (len) { 183 case 1: 184 cval = *(char *)&dummy_var[i]; 185 break; 186 case 2: 187 sval = *(short *)&dummy_var[i]; 188 break; 189 case 4: 190 ival = *(int *)&dummy_var[i]; 191 break; 192 case 8: 193 lval = *(long long *)&dummy_var[i]; 194 break; 195 } 196 check_trapped(); 197 } 198 } 199 200 /* 201 * Do the r/w/x accesses to trigger the breakpoints. And run 202 * the usual traps. 203 */ 204 static void trigger_tests(void) 205 { 206 int len, local, global, i; 207 char val; 208 int ret; 209 210 ret = ptrace(PTRACE_TRACEME, 0, NULL, 0); 211 if (ret) { 212 ksft_print_msg("Can't be traced? %s\n", strerror(errno)); 213 return; 214 } 215 216 /* Wake up father so that it sets up the first test */ 217 kill(getpid(), SIGUSR1); 218 219 /* Test instruction breakpoints */ 220 for (local = 0; local < 2; local++) { 221 for (global = 0; global < 2; global++) { 222 if (!local && !global) 223 continue; 224 225 for (i = 0; i < COUNT_ISN_BPS; i++) { 226 dummy_funcs[i](); 227 check_trapped(); 228 } 229 } 230 } 231 232 /* Test write watchpoints */ 233 for (len = 1; len <= sizeof(long); len <<= 1) { 234 for (local = 0; local < 2; local++) { 235 for (global = 0; global < 2; global++) { 236 if (!local && !global) 237 continue; 238 write_var(len); 239 } 240 } 241 } 242 243 /* Test read/write watchpoints (on read accesses) */ 244 for (len = 1; len <= sizeof(long); len <<= 1) { 245 for (local = 0; local < 2; local++) { 246 for (global = 0; global < 2; global++) { 247 if (!local && !global) 248 continue; 249 read_var(len); 250 } 251 } 252 } 253 254 /* Icebp trap */ 255 asm(".byte 0xf1\n"); 256 check_trapped(); 257 258 /* Int 3 trap */ 259 asm("int $3\n"); 260 check_trapped(); 261 262 kill(getpid(), SIGUSR1); 263 } 264 265 static void check_success(const char *msg) 266 { 267 int child_nr_tests; 268 int status; 269 int ret; 270 271 /* Wait for the child to SIGTRAP */ 272 wait(&status); 273 274 ret = 0; 275 276 if (WSTOPSIG(status) == SIGTRAP) { 277 child_nr_tests = ptrace(PTRACE_PEEKDATA, child_pid, 278 &nr_tests, 0); 279 if (child_nr_tests == nr_tests) 280 ret = 1; 281 if (ptrace(PTRACE_POKEDATA, child_pid, &trapped, 1)) 282 ksft_exit_fail_msg("Can't poke: %s\n", strerror(errno)); 283 } 284 285 nr_tests++; 286 287 if (ret) 288 ksft_test_result_pass(msg); 289 else 290 ksft_test_result_fail(msg); 291 } 292 293 static void launch_instruction_breakpoints(char *buf, int local, int global) 294 { 295 int i; 296 297 for (i = 0; i < COUNT_ISN_BPS; i++) { 298 set_breakpoint_addr(dummy_funcs[i], i); 299 toggle_breakpoint(i, BP_X, 1, local, global, 1); 300 ptrace(PTRACE_CONT, child_pid, NULL, 0); 301 sprintf(buf, "Test breakpoint %d with local: %d global: %d\n", 302 i, local, global); 303 check_success(buf); 304 toggle_breakpoint(i, BP_X, 1, local, global, 0); 305 } 306 } 307 308 static void launch_watchpoints(char *buf, int mode, int len, 309 int local, int global) 310 { 311 const char *mode_str; 312 int i; 313 314 if (mode == BP_W) 315 mode_str = "write"; 316 else 317 mode_str = "read"; 318 319 for (i = 0; i < COUNT_WPS; i++) { 320 set_breakpoint_addr(&dummy_var[i], i); 321 toggle_breakpoint(i, mode, len, local, global, 1); 322 ptrace(PTRACE_CONT, child_pid, NULL, 0); 323 sprintf(buf, 324 "Test %s watchpoint %d with len: %d local: %d global: %d\n", 325 mode_str, i, len, local, global); 326 check_success(buf); 327 toggle_breakpoint(i, mode, len, local, global, 0); 328 } 329 } 330 331 /* Set the breakpoints and check the child successfully trigger them */ 332 static void launch_tests(void) 333 { 334 char buf[1024]; 335 unsigned int tests = 0; 336 int len, local, global, i; 337 338 tests += 3 * COUNT_ISN_BPS; 339 tests += sizeof(long) / 2 * 3 * COUNT_WPS; 340 tests += sizeof(long) / 2 * 3 * COUNT_WPS; 341 tests += 2; 342 ksft_set_plan(tests); 343 344 /* Instruction breakpoints */ 345 for (local = 0; local < 2; local++) { 346 for (global = 0; global < 2; global++) { 347 if (!local && !global) 348 continue; 349 launch_instruction_breakpoints(buf, local, global); 350 } 351 } 352 353 /* Write watchpoint */ 354 for (len = 1; len <= sizeof(long); len <<= 1) { 355 for (local = 0; local < 2; local++) { 356 for (global = 0; global < 2; global++) { 357 if (!local && !global) 358 continue; 359 launch_watchpoints(buf, BP_W, len, 360 local, global); 361 } 362 } 363 } 364 365 /* Read-Write watchpoint */ 366 for (len = 1; len <= sizeof(long); len <<= 1) { 367 for (local = 0; local < 2; local++) { 368 for (global = 0; global < 2; global++) { 369 if (!local && !global) 370 continue; 371 launch_watchpoints(buf, BP_RW, len, 372 local, global); 373 } 374 } 375 } 376 377 /* Icebp traps */ 378 ptrace(PTRACE_CONT, child_pid, NULL, 0); 379 check_success("Test icebp\n"); 380 381 /* Int 3 traps */ 382 ptrace(PTRACE_CONT, child_pid, NULL, 0); 383 check_success("Test int 3 trap\n"); 384 385 ptrace(PTRACE_CONT, child_pid, NULL, 0); 386 } 387 388 int main(int argc, char **argv) 389 { 390 pid_t pid; 391 int ret; 392 393 ksft_print_header(); 394 395 pid = fork(); 396 if (!pid) { 397 trigger_tests(); 398 exit(0); 399 } 400 401 child_pid = pid; 402 403 wait(NULL); 404 405 launch_tests(); 406 407 wait(NULL); 408 409 ksft_exit_pass(); 410 } 411