/** * cc -pthread -o /tmp/singlestep /public/singlestep.c */ #include #include #include #include #include #include #include #include #include #include void handler(int n) { asm("nop"); } int child(void) { assert(ptrace(PT_TRACE_ME, 0,0,0) == 0); signal(SIGALRM, handler); kill(getpid(), SIGALRM); return 0x23; } void * getip(int pid) { struct reg regs; ptrace(PT_GETREGS, pid, (void*)®s, 0); #if defined(__powerpc__) return (void*)regs.pc; #elif defined(__amd64__) return (void*)regs.r_rip; #else #error "I don't know how to get the program counter" #endif } int main(void) { int pid, status; pid = fork(); if (!pid) return child(); assert(wait(&status) == pid); assert(WIFSTOPPED(status) && WSTOPSIG(status) == SIGALRM); printf("Child pid: %d\n", pid); printf("Handler address: %p\n", &handler); printf("At initial SIGALRM point. IP = %p\n", getip(pid)); assert(ptrace(PT_STEP, pid, 0, SIGALRM) == 0); assert(wait(&status) == pid); assert(WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP); printf("At SIGTRAP. IP = %p\n", getip(pid)); assert(ptrace(PT_STEP, pid, 0, SIGALRM) == 0); assert(wait(&status) == pid); assert(WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP); printf("At second SIGTRAP. IP = %p\n", getip(pid)); assert(ptrace(PT_CONTINUE, pid, 0,0) == 0); assert(wait(&status) == pid); printf("Child exit status was %d (expected %d)\n", WEXITSTATUS(status), 0x23); //assert(WIFEXITED(status)); return 0; }