1 /* 2 * Spawn a child and set it up for ptrace()-ing 3 * 4 * Copyright (c) 2008 Analog Devices Inc. 5 * 6 * Licensed under the GPL-2 or later 7 */ 8 9 /* 10 * To use: 11 * - add this line after your normal includes: 12 * #include "spawn_ptrace_child.c" 13 * - add this line to the top of your main(): 14 * make_a_baby(argc, argv); 15 * - access the child pid via the "pid" variable 16 */ 17 18 #include <errno.h> /* errno */ 19 #include <signal.h> /* signal() */ 20 #include <stdbool.h> /* true */ 21 #include <string.h> /* strcmp() */ 22 #include <unistd.h> /* execlp() sleep() vfork() */ 23 #include <sys/ptrace.h> /* ptrace() */ 24 #include <sys/wait.h> 25 26 #include "test.h" 27 28 static pid_t pid; 29 30 #ifdef __sparc__ 31 /* sparce swaps addr/data for get/set regs */ 32 # define maybe_swap(request, addr, data) \ 33 do { \ 34 if (request == PTRACE_GETREGS || request == PTRACE_SETREGS) { \ 35 void *__s = addr; \ 36 addr = data; \ 37 data = __s; \ 38 } \ 39 } while (0) 40 #else 41 # define maybe_swap(...) 42 #endif 43 #define vptrace(request, pid, addr, data) \ 44 ({ \ 45 errno = 0; \ 46 long __ret; \ 47 void *__addr = (void *)(addr); \ 48 void *__data = (void *)(data); \ 49 maybe_swap(request, __addr, __data); \ 50 __ret = ptrace(request, pid, __addr, __data); \ 51 if (__ret && errno) \ 52 perror("ptrace(" #request ", " #pid ", " #addr ", " #data ")"); \ 53 __ret; \ 54 }) 55 56 static void make_a_baby(int argc, char *argv[]) 57 { 58 if (argc > 1 && !strcmp(argv[1], "child")) { 59 /* if we're the child, just sit around doing nothing */ 60 int i = 60; 61 while (i--) { 62 close(-100); 63 sleep(1); 64 } 65 exit(1); 66 } 67 68 signal(SIGCHLD, SIG_IGN); 69 70 pid = vfork(); 71 if (pid == -1) { 72 tst_resm(TFAIL, "vfork() failed"); 73 tst_exit(); 74 } else if (pid) { 75 int status; 76 77 if (wait(&status) != pid) { 78 tst_brkm(TBROK | TERRNO, NULL, "wait(%i) failed: %#x", pid, status); 79 kill(pid, SIGKILL); 80 exit(1); 81 } 82 if (!WIFSTOPPED(status)) { 83 tst_brkm(TBROK, NULL, "child status not stopped: %#x", status); 84 kill(pid, SIGKILL); 85 exit(1); 86 } 87 88 return; 89 } 90 91 errno = 0; 92 long ret = ptrace(PTRACE_TRACEME, 0, NULL, NULL); 93 if (ret && errno) { 94 tst_resm(TFAIL, "PTRACE_TRACEME failed"); 95 tst_exit(); 96 } 97 98 execlp(argv[0], argv[0], "child", NULL); 99 tst_resm(TFAIL, "execlp() failed"); 100 tst_exit(); 101 } 102 103 #define SPT(x) [PTRACE_##x] = #x, 104 static char *strings[] = { 105 SPT(TRACEME) 106 SPT(PEEKTEXT) 107 SPT(PEEKDATA) 108 SPT(PEEKUSER) 109 SPT(POKETEXT) 110 SPT(POKEDATA) 111 SPT(POKEUSER) 112 #ifdef PTRACE_GETREGS 113 SPT(GETREGS) 114 #endif 115 #ifdef PTRACE_SETREGS 116 SPT(SETREGS) 117 #endif 118 #ifdef PTRACE_GETSIGINFO 119 SPT(GETSIGINFO) 120 #endif 121 #ifdef PTRACE_SETSIGINFO 122 SPT(SETSIGINFO) 123 #endif 124 #ifdef PTRACE_GETFGREGS 125 SPT(GETFGREGS) 126 #endif 127 #ifdef PTRACE_SETFGREGS 128 SPT(SETFGREGS) 129 #endif 130 SPT(KILL) 131 SPT(SINGLESTEP) 132 }; 133 static inline char *strptrace(enum __ptrace_request request) 134 { 135 return strings[request]; 136 } 137