Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <AK/Assertions.h>
28#include <AK/Types.h>
29#include <Kernel/Syscall.h>
30#include <signal.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <unistd.h>
35
36static int usage()
37{
38 printf("usage: strace [-p PID] [command...]\n");
39 return 0;
40}
41
42int main(int argc, char** argv)
43{
44 if (argc == 1)
45 return usage();
46
47 pid_t pid = -1;
48 bool pid_is_child = false;
49
50 if (!strcmp(argv[1], "-p")) {
51 if (argc != 3)
52 return usage();
53 pid = atoi(argv[2]);
54 } else {
55 pid_is_child = true;
56 pid = fork();
57 if (!pid) {
58 kill(getpid(), SIGSTOP);
59 int rc = execvp(argv[1], &argv[1]);
60 if (rc < 0) {
61 perror("execvp");
62 exit(1);
63 }
64 ASSERT_NOT_REACHED();
65 }
66 }
67
68 int fd = systrace(pid);
69 if (fd < 0) {
70 perror("systrace");
71 return 1;
72 }
73
74 if (pid_is_child) {
75 int rc = kill(pid, SIGCONT);
76 if (rc < 0) {
77 perror("kill(pid, SIGCONT)");
78 return 1;
79 }
80 }
81
82 for (;;) {
83 u32 call[5];
84 int nread = read(fd, &call, sizeof(call));
85 if (nread == 0)
86 break;
87 if (nread < 0) {
88 perror("read");
89 return 1;
90 }
91 ASSERT(nread == sizeof(call));
92 fprintf(stderr, "%s(%#x, %#x, %#x) = %#x\n", Syscall::to_string((Syscall::Function)call[0]), call[1], call[2], call[3], call[4]);
93 }
94
95 int rc = close(fd);
96 if (rc < 0) {
97 perror("close");
98 return 1;
99 }
100
101 return 0;
102}