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