blob: 1db45ef662b78705196109016048c259f20a49ea [file] [log] [blame] [edit]
/* Copyright (c) 2016 Google Inc., All Rights Reserved.
* Ron Minnich <rminnich@google.com>
* See LICENSE for details. */
#include <stdlib.h>
#include <stdio.h>
#include <parlib/parlib.h>
#include <unistd.h>
#include <signal.h>
#include <iplib/iplib.h>
#include <iplib/icmp.h>
#include <ctype.h>
#include <pthread.h>
#include <parlib/spinlock.h>
#include <parlib/timing.h>
#include <parlib/tsc-compat.h>
#include <parlib/printf-ext.h>
#include <benchutil/alarm.h>
#include <ndblib/ndb.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
void usage(void)
{
fprintf(stderr, "usage: strace command [args...]\n");
exit(1);
}
void main(int argc, char **argv, char **envp)
{
int fd;
int pid;
int amt;
static char p[2 * MAX_PATH_LEN];
static char buf[16384];
struct syscall sysc;
if (argc < 2)
usage();
pid = create_child_with_stdfds(argv[1], argc - 1, argv + 1, envp);
if (pid < 0) {
perror("proc_create");
exit(-1);
}
/* We need to wait on the child asynchronously. If we hold a ref (as the
* parent), the child won't proc_free and that won't hangup/wake us from a
* read. */
syscall_async(&sysc, SYS_waitpid, pid, NULL, 0, 0, 0, 0);
snprintf(p, sizeof(p), "/proc/%d/ctl", pid);
fd = open(p, O_WRITE);
if (fd < 0) {
fprintf(stderr, "open %s: %r\n", p);
exit(1);
}
snprintf(p, sizeof(p), "straceall");
if (write(fd, p, strlen(p)) < strlen(p)) {
fprintf(stderr, "write to ctl %s %d: %r\n", p, fd);
exit(1);
}
close(fd);
snprintf(p, sizeof(p), "/proc/%d/strace", pid);
fd = open(p, O_READ);
if (fd < 0) {
fprintf(stderr, "open %s: %r\n", p);
exit(1);
}
/* now that we've set up the tracing, we can run the process. isn't it
* great that the process doesn't immediately start when you make it? */
sys_proc_run(pid);
while ((amt = read(fd, buf, sizeof(buf))) > 0) {
if (write(fileno(stderr), buf, amt) < amt) {
fprintf(stderr, "Write to stdout: %r\n");
exit(1);
}
}
fprintf(stderr, "strace of PID %d: %r\n", pid);
}