1f08c3bdfSopenharmony_ci/* 2f08c3bdfSopenharmony_ci * Spawn a child and set it up for ptrace()-ing 3f08c3bdfSopenharmony_ci * 4f08c3bdfSopenharmony_ci * Copyright (c) 2008 Analog Devices Inc. 5f08c3bdfSopenharmony_ci * 6f08c3bdfSopenharmony_ci * Licensed under the GPL-2 or later 7f08c3bdfSopenharmony_ci */ 8f08c3bdfSopenharmony_ci 9f08c3bdfSopenharmony_ci/* 10f08c3bdfSopenharmony_ci * To use: 11f08c3bdfSopenharmony_ci * - add this line after your normal includes: 12f08c3bdfSopenharmony_ci * #include "spawn_ptrace_child.c" 13f08c3bdfSopenharmony_ci * - add this line to the top of your main(): 14f08c3bdfSopenharmony_ci * make_a_baby(argc, argv); 15f08c3bdfSopenharmony_ci * - access the child pid via the "pid" variable 16f08c3bdfSopenharmony_ci */ 17f08c3bdfSopenharmony_ci 18f08c3bdfSopenharmony_ci#include <errno.h> /* errno */ 19f08c3bdfSopenharmony_ci#include <signal.h> /* signal() */ 20f08c3bdfSopenharmony_ci#include <stdbool.h> /* true */ 21f08c3bdfSopenharmony_ci#include <string.h> /* strcmp() */ 22f08c3bdfSopenharmony_ci#include <unistd.h> /* execlp() sleep() vfork() */ 23f08c3bdfSopenharmony_ci#include <sys/ptrace.h> /* ptrace() */ 24f08c3bdfSopenharmony_ci#include <sys/wait.h> 25f08c3bdfSopenharmony_ci 26f08c3bdfSopenharmony_ci#include "test.h" 27f08c3bdfSopenharmony_ci 28f08c3bdfSopenharmony_cistatic pid_t pid; 29f08c3bdfSopenharmony_ci 30f08c3bdfSopenharmony_ci#ifdef __sparc__ 31f08c3bdfSopenharmony_ci/* sparce swaps addr/data for get/set regs */ 32f08c3bdfSopenharmony_ci# define maybe_swap(request, addr, data) \ 33f08c3bdfSopenharmony_cido { \ 34f08c3bdfSopenharmony_ci if (request == PTRACE_GETREGS || request == PTRACE_SETREGS) { \ 35f08c3bdfSopenharmony_ci void *__s = addr; \ 36f08c3bdfSopenharmony_ci addr = data; \ 37f08c3bdfSopenharmony_ci data = __s; \ 38f08c3bdfSopenharmony_ci } \ 39f08c3bdfSopenharmony_ci} while (0) 40f08c3bdfSopenharmony_ci#else 41f08c3bdfSopenharmony_ci# define maybe_swap(...) 42f08c3bdfSopenharmony_ci#endif 43f08c3bdfSopenharmony_ci#define vptrace(request, pid, addr, data) \ 44f08c3bdfSopenharmony_ci({ \ 45f08c3bdfSopenharmony_ci errno = 0; \ 46f08c3bdfSopenharmony_ci long __ret; \ 47f08c3bdfSopenharmony_ci void *__addr = (void *)(addr); \ 48f08c3bdfSopenharmony_ci void *__data = (void *)(data); \ 49f08c3bdfSopenharmony_ci maybe_swap(request, __addr, __data); \ 50f08c3bdfSopenharmony_ci __ret = ptrace(request, pid, __addr, __data); \ 51f08c3bdfSopenharmony_ci if (__ret && errno) \ 52f08c3bdfSopenharmony_ci perror("ptrace(" #request ", " #pid ", " #addr ", " #data ")"); \ 53f08c3bdfSopenharmony_ci __ret; \ 54f08c3bdfSopenharmony_ci}) 55f08c3bdfSopenharmony_ci 56f08c3bdfSopenharmony_cistatic void make_a_baby(int argc, char *argv[]) 57f08c3bdfSopenharmony_ci{ 58f08c3bdfSopenharmony_ci if (argc > 1 && !strcmp(argv[1], "child")) { 59f08c3bdfSopenharmony_ci /* if we're the child, just sit around doing nothing */ 60f08c3bdfSopenharmony_ci int i = 60; 61f08c3bdfSopenharmony_ci while (i--) { 62f08c3bdfSopenharmony_ci close(-100); 63f08c3bdfSopenharmony_ci sleep(1); 64f08c3bdfSopenharmony_ci } 65f08c3bdfSopenharmony_ci exit(1); 66f08c3bdfSopenharmony_ci } 67f08c3bdfSopenharmony_ci 68f08c3bdfSopenharmony_ci signal(SIGCHLD, SIG_IGN); 69f08c3bdfSopenharmony_ci 70f08c3bdfSopenharmony_ci pid = vfork(); 71f08c3bdfSopenharmony_ci if (pid == -1) { 72f08c3bdfSopenharmony_ci tst_resm(TFAIL, "vfork() failed"); 73f08c3bdfSopenharmony_ci tst_exit(); 74f08c3bdfSopenharmony_ci } else if (pid) { 75f08c3bdfSopenharmony_ci int status; 76f08c3bdfSopenharmony_ci 77f08c3bdfSopenharmony_ci if (wait(&status) != pid) { 78f08c3bdfSopenharmony_ci tst_brkm(TBROK | TERRNO, NULL, "wait(%i) failed: %#x", pid, status); 79f08c3bdfSopenharmony_ci kill(pid, SIGKILL); 80f08c3bdfSopenharmony_ci exit(1); 81f08c3bdfSopenharmony_ci } 82f08c3bdfSopenharmony_ci if (!WIFSTOPPED(status)) { 83f08c3bdfSopenharmony_ci tst_brkm(TBROK, NULL, "child status not stopped: %#x", status); 84f08c3bdfSopenharmony_ci kill(pid, SIGKILL); 85f08c3bdfSopenharmony_ci exit(1); 86f08c3bdfSopenharmony_ci } 87f08c3bdfSopenharmony_ci 88f08c3bdfSopenharmony_ci return; 89f08c3bdfSopenharmony_ci } 90f08c3bdfSopenharmony_ci 91f08c3bdfSopenharmony_ci errno = 0; 92f08c3bdfSopenharmony_ci long ret = ptrace(PTRACE_TRACEME, 0, NULL, NULL); 93f08c3bdfSopenharmony_ci if (ret && errno) { 94f08c3bdfSopenharmony_ci tst_resm(TFAIL, "PTRACE_TRACEME failed"); 95f08c3bdfSopenharmony_ci tst_exit(); 96f08c3bdfSopenharmony_ci } 97f08c3bdfSopenharmony_ci 98f08c3bdfSopenharmony_ci execlp(argv[0], argv[0], "child", NULL); 99f08c3bdfSopenharmony_ci tst_resm(TFAIL, "execlp() failed"); 100f08c3bdfSopenharmony_ci tst_exit(); 101f08c3bdfSopenharmony_ci} 102f08c3bdfSopenharmony_ci 103f08c3bdfSopenharmony_ci#define SPT(x) [PTRACE_##x] = #x, 104f08c3bdfSopenharmony_cistatic char *strings[] = { 105f08c3bdfSopenharmony_ci SPT(TRACEME) 106f08c3bdfSopenharmony_ci SPT(PEEKTEXT) 107f08c3bdfSopenharmony_ci SPT(PEEKDATA) 108f08c3bdfSopenharmony_ci SPT(PEEKUSER) 109f08c3bdfSopenharmony_ci SPT(POKETEXT) 110f08c3bdfSopenharmony_ci SPT(POKEDATA) 111f08c3bdfSopenharmony_ci SPT(POKEUSER) 112f08c3bdfSopenharmony_ci#ifdef PTRACE_GETREGS 113f08c3bdfSopenharmony_ci SPT(GETREGS) 114f08c3bdfSopenharmony_ci#endif 115f08c3bdfSopenharmony_ci#ifdef PTRACE_SETREGS 116f08c3bdfSopenharmony_ci SPT(SETREGS) 117f08c3bdfSopenharmony_ci#endif 118f08c3bdfSopenharmony_ci#ifdef PTRACE_GETSIGINFO 119f08c3bdfSopenharmony_ci SPT(GETSIGINFO) 120f08c3bdfSopenharmony_ci#endif 121f08c3bdfSopenharmony_ci#ifdef PTRACE_SETSIGINFO 122f08c3bdfSopenharmony_ci SPT(SETSIGINFO) 123f08c3bdfSopenharmony_ci#endif 124f08c3bdfSopenharmony_ci#ifdef PTRACE_GETFGREGS 125f08c3bdfSopenharmony_ci SPT(GETFGREGS) 126f08c3bdfSopenharmony_ci#endif 127f08c3bdfSopenharmony_ci#ifdef PTRACE_SETFGREGS 128f08c3bdfSopenharmony_ci SPT(SETFGREGS) 129f08c3bdfSopenharmony_ci#endif 130f08c3bdfSopenharmony_ci SPT(KILL) 131f08c3bdfSopenharmony_ci SPT(SINGLESTEP) 132f08c3bdfSopenharmony_ci}; 133f08c3bdfSopenharmony_cistatic inline char *strptrace(int request) 134f08c3bdfSopenharmony_ci{ 135f08c3bdfSopenharmony_ci return strings[request]; 136f08c3bdfSopenharmony_ci} 137