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 28static pid_t pid; 29 30#ifdef __sparc__ 31/* sparce swaps addr/data for get/set regs */ 32# define maybe_swap(request, addr, data) \ 33do { \ 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 56static 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, 104static 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}; 133static inline char *strptrace(enum __ptrace_request request) 134{ 135 return strings[request]; 136} 137