#include #include #include #include #include #include #include #include #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) unsigned long encode_dr7(int drnum, int enable, unsigned int type, unsigned int len) { unsigned long dr7; dr7 = ((len | type) & 0xf) << (DR_CONTROL_SHIFT + drnum * DR_CONTROL_SIZE); if (enable) dr7 |= (DR_GLOBAL_ENABLE << (drnum * DR_ENABLE_SIZE)); return dr7; } int write_dr(int pid, int dr, unsigned long val) { return ptrace(PTRACE_POKEUSER, pid, offsetof (struct user, u_debugreg[dr]), val); } void set_bp(pid_t pid, void *addr) { unsigned long dr7; assert(write_dr(pid, 0, (long)addr) == 0); dr7 = encode_dr7(0, 1, DR_RW_EXECUTE, DR_LEN_1); assert(write_dr(pid, 7, dr7) == 0); } # define noinline __attribute__((noinline)) static noinline void bp1(void) {} static noinline void bp2(void) {} static void child1() { int nr = 0; for (;;) { bp1(); printf("fail1 %d %d\n", getpid(), ++nr); } } static void child2() { int nr = 0; for (;;) { bp2(); printf("fail2 %d %d\n", getpid(), ++nr); } } # define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) int main(int argc, char *argv[]) { pid_t pid; int status, i; for (i = 0; ; i++ ) { pid = fork(); assert(pid != -1); if (pid == 0) { assert(ptrace(PTRACE_TRACEME, 0, 0, 0) == 0); kill(getpid(), SIGSTOP); if (i % 2) child1(); else child2(); return 1; } assert(waitpid(pid, NULL, 0) == pid); set_bp(pid, i % 2 ? bp1 : bp2); assert(ptrace(PTRACE_CONT, pid, NULL, NULL) == 0); assert(waitpid(pid, &status, 0) == pid); if (WIFEXITED(status)) return 1; assert(ptrace(PTRACE_KILL, pid, 0, 0) == 0); assert(waitpid(pid, &status, 0) == pid); } return 0; }