strace: Allow "strace command" to trace a process from start to finish.

Tracing a specific pid is now done via "strace -p PID".
To ensure we don't miss any syscalls, we fork and have the child immediately
SIGSTOP itself. Then when the parent has set up the systrace() fd, we send
SIGCONT to the child which then execs the command. :^)
This commit is contained in:
Andreas Kling 2019-05-02 15:51:39 +02:00
parent 25ddcd1022
commit 2a65f0ee4f
Notes: sideshowbarker 2024-07-19 14:20:35 +09:00

View file

@ -1,22 +1,58 @@
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <AK/Assertions.h>
#include <AK/Types.h>
#include <Kernel/Syscall.h>
static int usage()
{
printf("usage: strace [-p PID] [command...]\n");
return 0;
}
int main(int argc, char** argv)
{
if (argc < 2)
return 1;
if (argc == 1)
return usage();
pid_t pid = -1;
bool pid_is_child = false;
if (!strcmp(argv[1], "-p")) {
if (argc != 3)
return usage();
pid = atoi(argv[2]);
} else {
pid_is_child = true;
pid = fork();
if (!pid) {
kill(getpid(), SIGSTOP);
int rc = execvp(argv[1], &argv[1]);
if (rc < 0) {
perror("execvp");
exit(1);
}
ASSERT_NOT_REACHED();
}
}
int pid = atoi(argv[1]);
int fd = systrace(pid);
if (fd < 0) {
perror("systrace");
return 1;
}
if (pid_is_child) {
int rc = kill(pid, SIGCONT);
if (rc < 0) {
perror("kill(pid, SIGCONT)");
return 1;
}
}
for (;;) {
dword call[5];
int nread = read(fd, &call, sizeof(call));
@ -27,7 +63,7 @@ int main(int argc, char** argv)
return 1;
}
ASSERT(nread == sizeof(call));
printf("%s(%#x, %#x, %#x) = %#x\n", Syscall::to_string((Syscall::Function)call[0]), call[1], call[2], call[3], call[4]);
fprintf(stderr, "%s(%#x, %#x, %#x) = %#x\n", Syscall::to_string((Syscall::Function)call[0]), call[1], call[2], call[3], call[4]);
}
int rc = close(fd);