Home | History | Annotate | Download | only in ptrace
      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