/src/ptracetest1.c
C | 69 lines | 49 code | 16 blank | 4 comment | 11 complexity | 92405821e3bcd45a9b9b77ca56ad7dba MD5 | raw file
1 2#include <assert.h> 3#include <sys/ptrace.h> 4#include <linux/ptrace.h> 5#include <sys/types.h> 6#include <sys/wait.h> 7#include <unistd.h> 8#include <linux/user.h> 9#include <sys/syscall.h> 10#include <syscall.h> 11#include <sys/reg.h> 12#include <stdio.h> 13#include <stdlib.h> 14 15#ifdef __x86_64__ 16#define SYSCALL_OFF (ORIG_RAX * 8) 17#else 18#define SYSCALL_OFF (ORIG_EAX * 4) 19#endif 20 21void checked (char const * const s, int const r) { if (r == -1) { perror(s); abort(); } } 22 23int main() 24{ 25 pid_t const child = fork(); 26 27 checked("fork", child); 28 29 if(child == 0) 30 { 31 checked("ptrace", ptrace(PTRACE_TRACEME, 0, NULL, NULL)); 32 checked("execl", execl("/usr/bin/whoami", "whoami", NULL)); 33 } 34 35 int status; 36 checked("wait", wait(&status)); 37 assert(WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP); 38 // No way to know whether this SIGTRAP was caused by entry/exit, because we couldn't set PTRACE_O_TRACESYSGOOD until now (see ptracetest2.c). 39 40 printf("opaque trap passed\n"); 41 42 checked("ptrace", ptrace(PTRACE_SETOPTIONS, child, NULL, PTRACE_O_TRACESYSGOOD)); 43 44 for(;;) 45 { 46 checked("ptrace", ptrace(PTRACE_SYSCALL, child, NULL, NULL)); 47 48 checked("wait", wait(&status)); 49 50 if (WIFEXITED(status)) break; 51 52 if (WSTOPSIG(status) == (SIGTRAP | 0x80)) 53 { 54 printf("syscall trap %ld\n", ptrace(PTRACE_PEEKUSER, child, SYSCALL_OFF, NULL)); 55 } 56 else 57 { 58 assert(WSTOPSIG(status) == SIGTRAP); 59 printf("non-syscall trap\n"); 60 } 61 } 62 63 return 0; 64} 65 66// On Eelis' machines, no syscall traps for execve are shown. On CoffeeBuzz' dual core machine, one syscall trap for execve is shown. 67// Conclusion: Using execve as "first SIGTRAP" foundation, one cannot know whether the first observed syscall trap is an entry or exit. 68 69// This testcase assumes that on syscall exit traps, ORIG_EAX/ORIG_RAX still holds the syscall number.