#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include static void ptrace_child(void) { if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) { fprintf(stderr, "%s: PTRACE_TRACEME failed: %m\n", __func__); raise(SIGKILL); } raise(SIGSTOP); getpid(); exit(0); } static int start_ptraced_child(void) { int pid, ret, status; pid = fork(); if (pid == 0) ptrace_child(); else if (pid < 0) fprintf(stderr, "%s: fork() failed: %m\n", __func__); ret = waitpid(pid, &status, WUNTRACED); if (ret < 0) fprintf(stderr, "%s: wait() failed: %m\n", __func__); if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) fprintf(stderr, "%s: expected SIGSTOP, got status:%#x\n", __func__, status); return pid; } static void stop_ptraced_child(int pid) { if (ptrace(PTRACE_CONT, pid, 0, 0) < 0) { fprintf(stderr, "%s: PTRACE_CONT failed: %m\n", __func__); return; } waitpid(pid, NULL, 0); } int main(void) { int pid, n, status, step_count = 0; pid = start_ptraced_child(); if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)) fprintf(stderr, "%s: PTRACE_OLDSETOPTIONS failed: %m\n", __func__); while (1) { if (ptrace(PTRACE_SYSEMU_SINGLESTEP, pid, 0, 0) < 0) exit(1); n = waitpid(pid, &status, WUNTRACED); if (n < 0) fprintf(stderr, "%s: wait() failed: %m\n", __func__); if (WIFSTOPPED(status) && (WSTOPSIG(status) == (SIGTRAP|0x80))) { if (!step_count) { fprintf(stderr, "SYSEMU_SINGLESTEP doesn't singlestep"); exit(1); } /* syscall */ break; } else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP)) { /* single step */ step_count++; } else { fprintf(stderr, "expected SIGTRAP or (SIGTRAP | 0x80), got status = %d\n", status); exit(1); } step_count++; } stop_ptraced_child(pid); return 0; }