blob: ae538e900729923a9a3adc4f43b9a2205750dc38 [file] [log] [blame]
/*
* Spawn a child and set it up for ptrace()-ing
*
* Copyright (c) 2008 Analog Devices Inc.
*
* Licensed under the GPL-2 or later
*/
/*
* To use:
* - add this line after your normal includes:
* #include "spawn_ptrace_child.c"
* - add this line to the top of your main():
* make_a_baby(argc, argv);
* - access the child pid via the "pid" variable
*/
#include <errno.h> /* errno */
#include <signal.h> /* signal() */
#include <stdbool.h> /* true */
#include <string.h> /* strcmp() */
#include <unistd.h> /* execlp() sleep() vfork() */
#include <sys/ptrace.h> /* ptrace() */
#include <sys/wait.h>
#include "test.h"
static pid_t pid;
#ifdef __sparc__
/* sparce swaps addr/data for get/set regs */
# define maybe_swap(request, addr, data) \
do { \
if (request == PTRACE_GETREGS || request == PTRACE_SETREGS) { \
void *__s = addr; \
addr = data; \
data = __s; \
} \
} while (0)
#else
# define maybe_swap(...)
#endif
#define vptrace(request, pid, addr, data) \
({ \
errno = 0; \
long __ret; \
void *__addr = (void *)(addr); \
void *__data = (void *)(data); \
maybe_swap(request, __addr, __data); \
__ret = ptrace(request, pid, __addr, __data); \
if (__ret && errno) \
perror("ptrace(" #request ", " #pid ", " #addr ", " #data ")"); \
__ret; \
})
static void make_a_baby(int argc, char *argv[])
{
if (argc > 1 && !strcmp(argv[1], "child")) {
/* if we're the child, just sit around doing nothing */
int i = 60;
while (i--) {
close(-100);
sleep(1);
}
exit(1);
}
signal(SIGCHLD, SIG_IGN);
pid = vfork();
if (pid == -1) {
tst_resm(TFAIL, "vfork() failed");
tst_exit();
} else if (pid) {
int status;
if (wait(&status) != pid) {
tst_brkm(TBROK | TERRNO, NULL, "wait(%i) failed: %#x", pid, status);
kill(pid, SIGKILL);
exit(1);
}
if (!WIFSTOPPED(status)) {
tst_brkm(TBROK, NULL, "child status not stopped: %#x", status);
kill(pid, SIGKILL);
exit(1);
}
return;
}
errno = 0;
long ret = ptrace(PTRACE_TRACEME, 0, NULL, NULL);
if (ret && errno) {
tst_resm(TFAIL, "PTRACE_TRACEME failed");
tst_exit();
}
execlp(argv[0], argv[0], "child", NULL);
tst_resm(TFAIL, "execlp() failed");
tst_exit();
}
#define SPT(x) [PTRACE_##x] = #x,
static char *strings[] = {
SPT(TRACEME)
SPT(PEEKTEXT)
SPT(PEEKDATA)
SPT(PEEKUSER)
SPT(POKETEXT)
SPT(POKEDATA)
SPT(POKEUSER)
#ifdef PTRACE_GETREGS
SPT(GETREGS)
#endif
#ifdef PTRACE_SETREGS
SPT(SETREGS)
#endif
#ifdef PTRACE_GETSIGINFO
SPT(GETSIGINFO)
#endif
#ifdef PTRACE_SETSIGINFO
SPT(SETSIGINFO)
#endif
#ifdef PTRACE_GETFGREGS
SPT(GETFGREGS)
#endif
#ifdef PTRACE_SETFGREGS
SPT(SETFGREGS)
#endif
SPT(KILL)
SPT(SINGLESTEP)
};
static inline char *strptrace(enum __ptrace_request request)
{
return strings[request];
}