• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
make_a_baby(int argc,char * argv[])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 };
strptrace(int request)133 static inline char *strptrace(int request)
134 {
135 	return strings[request];
136 }
137