#include #include #include #include #include #include #include #include #ifndef STAP_SCRIPT_FILENAME #error "STAP_SCRIPT_FILENAME is required" #endif #define STRINGIFY1(lit) #lit #define STRINGIFY(lit) STRINGIFY1 (lit) #define _(x) gettext (x) static int opt_d, opt_f, opt_q, opt_p; /* Script filename. */ static char *opt_Z = STRINGIFY (STAP_SCRIPT_FILENAME); static void * xmalloc (size_t size) { void *retval = malloc (size); if (retval == NULL) error (EXIT_FAILURE, errno, _("memory allocation of %zu bytes"), size); return retval; } static void usage (int status) { printf ("\ usage: staptrace [-dfq] [-o file] [-p pid] [command [arg ...]]\n\ [-Z ]\n\ \n\ Default -Z is: %s\n\ ", opt_Z); exit (status); } static void dump_args (char **args) { char **argp; for (argp = args; *argp; argp++) { if (argp > args) fputc (' ', stderr); fputs (*argp, stderr); } fputc ('\n', stderr); } int main (int argc, char **argv) { char **args, **argp; args = xmalloc (sizeof (*args) * argc * 2 + 32); argp = args; *argp++ = "stap"; for (;;) { int i; i = getopt (argc, argv, "+dfqo:p:hZ:"); if (i == EOF) break; switch (i) { case 'd': opt_d = 1; break; case 'f': if (opt_f) error (EXIT_FAILURE, 0, _("-ff is unsupported")); *argp++ = "-G"; *argp++ = "opt_f=1"; opt_f = 1; break; case 'q': *argp++ = "-G"; *argp++ = "opt_q=1"; opt_q = 1; break; case 'o': *argp++ = "-o"; *argp++ = optarg; break; case 'p': *argp++ = "-x"; *argp++ = optarg; opt_p = 1; break; case 'Z': opt_Z = optarg; break; case 'h': usage (EXIT_SUCCESS); default: usage (EXIT_FAILURE); } } if ((optind == argc) == !opt_p) usage (EXIT_FAILURE); if (optind < argc) { pid_t child; int i; static char kill_s[64]; static char opt_s[64]; child = fork (); switch (child) { case -1: error (EXIT_FAILURE, errno, _("Error calling fork")); case 0: i = raise (SIGSTOP); if (i != 0) error (EXIT_FAILURE, errno, _("Error calling raise (SIGSTOP)")); execvp (argv[optind], &argv[optind]); error (EXIT_FAILURE, errno, "Error executing child command"); default: break; } /* FIXME: Call `kill -CONT' from the systamtap script. How? */ i = sprintf (kill_s, "kill -CONT %lu; " "while [ -e /proc/%lu/root ]; do sleep 0.1; done", (unsigned long) child, (unsigned long) child); if (i <= 0) error (EXIT_FAILURE, errno, _("Error calling sprintf")); *argp++ = "-c"; *argp++ = kill_s; i = sprintf (opt_s, "opt_child=%lu", (unsigned long) child); if (i <= 0) error (EXIT_FAILURE, errno, _("Error calling sprintf")); *argp++ = "-G"; *argp++ = opt_s; } *argp++ = opt_Z; *argp = NULL; if (opt_d) dump_args (args); execvp ("stap", args); if (!opt_d) dump_args (args); error (EXIT_FAILURE, errno, "Error executing stap"); }