1*387f9dfdSAndroid Build Coastguard Worker // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2*387f9dfdSAndroid Build Coastguard Worker
3*387f9dfdSAndroid Build Coastguard Worker /*
4*387f9dfdSAndroid Build Coastguard Worker * sigsnoop Trace standard and real-time signals.
5*387f9dfdSAndroid Build Coastguard Worker *
6*387f9dfdSAndroid Build Coastguard Worker * Copyright (c) 2021~2022 Hengqi Chen
7*387f9dfdSAndroid Build Coastguard Worker *
8*387f9dfdSAndroid Build Coastguard Worker * 08-Aug-2021 Hengqi Chen Created this.
9*387f9dfdSAndroid Build Coastguard Worker */
10*387f9dfdSAndroid Build Coastguard Worker #include <argp.h>
11*387f9dfdSAndroid Build Coastguard Worker #include <libgen.h>
12*387f9dfdSAndroid Build Coastguard Worker #include <signal.h>
13*387f9dfdSAndroid Build Coastguard Worker #include <time.h>
14*387f9dfdSAndroid Build Coastguard Worker
15*387f9dfdSAndroid Build Coastguard Worker #include <bpf/bpf.h>
16*387f9dfdSAndroid Build Coastguard Worker #include "sigsnoop.h"
17*387f9dfdSAndroid Build Coastguard Worker #include "sigsnoop.skel.h"
18*387f9dfdSAndroid Build Coastguard Worker
19*387f9dfdSAndroid Build Coastguard Worker #define PERF_BUFFER_PAGES 16
20*387f9dfdSAndroid Build Coastguard Worker #define PERF_POLL_TIMEOUT_MS 100
21*387f9dfdSAndroid Build Coastguard Worker #define warn(...) fprintf(stderr, __VA_ARGS__)
22*387f9dfdSAndroid Build Coastguard Worker #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
23*387f9dfdSAndroid Build Coastguard Worker
24*387f9dfdSAndroid Build Coastguard Worker static volatile sig_atomic_t exiting = 0;
25*387f9dfdSAndroid Build Coastguard Worker
26*387f9dfdSAndroid Build Coastguard Worker static pid_t target_pid = 0;
27*387f9dfdSAndroid Build Coastguard Worker static int target_signal = 0;
28*387f9dfdSAndroid Build Coastguard Worker static bool failed_only = false;
29*387f9dfdSAndroid Build Coastguard Worker static bool kill_only = false;
30*387f9dfdSAndroid Build Coastguard Worker static bool signal_name = false;
31*387f9dfdSAndroid Build Coastguard Worker static bool verbose = false;
32*387f9dfdSAndroid Build Coastguard Worker
33*387f9dfdSAndroid Build Coastguard Worker static const char *sig_name[] = {
34*387f9dfdSAndroid Build Coastguard Worker [0] = "N/A",
35*387f9dfdSAndroid Build Coastguard Worker [1] = "SIGHUP",
36*387f9dfdSAndroid Build Coastguard Worker [2] = "SIGINT",
37*387f9dfdSAndroid Build Coastguard Worker [3] = "SIGQUIT",
38*387f9dfdSAndroid Build Coastguard Worker [4] = "SIGILL",
39*387f9dfdSAndroid Build Coastguard Worker [5] = "SIGTRAP",
40*387f9dfdSAndroid Build Coastguard Worker [6] = "SIGABRT",
41*387f9dfdSAndroid Build Coastguard Worker [7] = "SIGBUS",
42*387f9dfdSAndroid Build Coastguard Worker [8] = "SIGFPE",
43*387f9dfdSAndroid Build Coastguard Worker [9] = "SIGKILL",
44*387f9dfdSAndroid Build Coastguard Worker [10] = "SIGUSR1",
45*387f9dfdSAndroid Build Coastguard Worker [11] = "SIGSEGV",
46*387f9dfdSAndroid Build Coastguard Worker [12] = "SIGUSR2",
47*387f9dfdSAndroid Build Coastguard Worker [13] = "SIGPIPE",
48*387f9dfdSAndroid Build Coastguard Worker [14] = "SIGALRM",
49*387f9dfdSAndroid Build Coastguard Worker [15] = "SIGTERM",
50*387f9dfdSAndroid Build Coastguard Worker [16] = "SIGSTKFLT",
51*387f9dfdSAndroid Build Coastguard Worker [17] = "SIGCHLD",
52*387f9dfdSAndroid Build Coastguard Worker [18] = "SIGCONT",
53*387f9dfdSAndroid Build Coastguard Worker [19] = "SIGSTOP",
54*387f9dfdSAndroid Build Coastguard Worker [20] = "SIGTSTP",
55*387f9dfdSAndroid Build Coastguard Worker [21] = "SIGTTIN",
56*387f9dfdSAndroid Build Coastguard Worker [22] = "SIGTTOU",
57*387f9dfdSAndroid Build Coastguard Worker [23] = "SIGURG",
58*387f9dfdSAndroid Build Coastguard Worker [24] = "SIGXCPU",
59*387f9dfdSAndroid Build Coastguard Worker [25] = "SIGXFSZ",
60*387f9dfdSAndroid Build Coastguard Worker [26] = "SIGVTALRM",
61*387f9dfdSAndroid Build Coastguard Worker [27] = "SIGPROF",
62*387f9dfdSAndroid Build Coastguard Worker [28] = "SIGWINCH",
63*387f9dfdSAndroid Build Coastguard Worker [29] = "SIGIO",
64*387f9dfdSAndroid Build Coastguard Worker [30] = "SIGPWR",
65*387f9dfdSAndroid Build Coastguard Worker [31] = "SIGSYS",
66*387f9dfdSAndroid Build Coastguard Worker };
67*387f9dfdSAndroid Build Coastguard Worker
68*387f9dfdSAndroid Build Coastguard Worker const char *argp_program_version = "sigsnoop 0.1";
69*387f9dfdSAndroid Build Coastguard Worker const char *argp_program_bug_address =
70*387f9dfdSAndroid Build Coastguard Worker "https://github.com/iovisor/bcc/tree/master/libbpf-tools";
71*387f9dfdSAndroid Build Coastguard Worker const char argp_program_doc[] =
72*387f9dfdSAndroid Build Coastguard Worker "Trace standard and real-time signals.\n"
73*387f9dfdSAndroid Build Coastguard Worker "\n"
74*387f9dfdSAndroid Build Coastguard Worker "USAGE: sigsnoop [-h] [-x] [-k] [-n] [-p PID] [-s SIGNAL]\n"
75*387f9dfdSAndroid Build Coastguard Worker "\n"
76*387f9dfdSAndroid Build Coastguard Worker "EXAMPLES:\n"
77*387f9dfdSAndroid Build Coastguard Worker " sigsnoop # trace signals system-wide\n"
78*387f9dfdSAndroid Build Coastguard Worker " sigsnoop -k # trace signals issued by kill syscall only\n"
79*387f9dfdSAndroid Build Coastguard Worker " sigsnoop -x # trace failed signals only\n"
80*387f9dfdSAndroid Build Coastguard Worker " sigsnoop -p 1216 # only trace PID 1216\n"
81*387f9dfdSAndroid Build Coastguard Worker " sigsnoop -s 9 # only trace signal 9\n";
82*387f9dfdSAndroid Build Coastguard Worker
83*387f9dfdSAndroid Build Coastguard Worker static const struct argp_option opts[] = {
84*387f9dfdSAndroid Build Coastguard Worker { "failed", 'x', NULL, 0, "Trace failed signals only." },
85*387f9dfdSAndroid Build Coastguard Worker { "kill", 'k', NULL, 0, "Trace signals issued by kill syscall only." },
86*387f9dfdSAndroid Build Coastguard Worker { "pid", 'p', "PID", 0, "Process ID to trace" },
87*387f9dfdSAndroid Build Coastguard Worker { "signal", 's', "SIGNAL", 0, "Signal to trace." },
88*387f9dfdSAndroid Build Coastguard Worker { "name", 'n', NULL, 0, "Output signal name instead of signal number." },
89*387f9dfdSAndroid Build Coastguard Worker { "verbose", 'v', NULL, 0, "Verbose debug output" },
90*387f9dfdSAndroid Build Coastguard Worker { NULL, 'h', NULL, OPTION_HIDDEN, "Show the full help" },
91*387f9dfdSAndroid Build Coastguard Worker {},
92*387f9dfdSAndroid Build Coastguard Worker };
93*387f9dfdSAndroid Build Coastguard Worker
parse_arg(int key,char * arg,struct argp_state * state)94*387f9dfdSAndroid Build Coastguard Worker static error_t parse_arg(int key, char *arg, struct argp_state *state)
95*387f9dfdSAndroid Build Coastguard Worker {
96*387f9dfdSAndroid Build Coastguard Worker long pid, sig;
97*387f9dfdSAndroid Build Coastguard Worker
98*387f9dfdSAndroid Build Coastguard Worker switch (key) {
99*387f9dfdSAndroid Build Coastguard Worker case 'p':
100*387f9dfdSAndroid Build Coastguard Worker errno = 0;
101*387f9dfdSAndroid Build Coastguard Worker pid = strtol(arg, NULL, 10);
102*387f9dfdSAndroid Build Coastguard Worker if (errno || pid <= 0) {
103*387f9dfdSAndroid Build Coastguard Worker warn("Invalid PID: %s\n", arg);
104*387f9dfdSAndroid Build Coastguard Worker argp_usage(state);
105*387f9dfdSAndroid Build Coastguard Worker }
106*387f9dfdSAndroid Build Coastguard Worker target_pid = pid;
107*387f9dfdSAndroid Build Coastguard Worker break;
108*387f9dfdSAndroid Build Coastguard Worker case 's':
109*387f9dfdSAndroid Build Coastguard Worker errno = 0;
110*387f9dfdSAndroid Build Coastguard Worker sig = strtol(arg, NULL, 10);
111*387f9dfdSAndroid Build Coastguard Worker if (errno || sig <= 0) {
112*387f9dfdSAndroid Build Coastguard Worker warn("Invalid SIGNAL: %s\n", arg);
113*387f9dfdSAndroid Build Coastguard Worker argp_usage(state);
114*387f9dfdSAndroid Build Coastguard Worker }
115*387f9dfdSAndroid Build Coastguard Worker target_signal = sig;
116*387f9dfdSAndroid Build Coastguard Worker break;
117*387f9dfdSAndroid Build Coastguard Worker case 'n':
118*387f9dfdSAndroid Build Coastguard Worker signal_name = true;
119*387f9dfdSAndroid Build Coastguard Worker break;
120*387f9dfdSAndroid Build Coastguard Worker case 'x':
121*387f9dfdSAndroid Build Coastguard Worker failed_only = true;
122*387f9dfdSAndroid Build Coastguard Worker break;
123*387f9dfdSAndroid Build Coastguard Worker case 'k':
124*387f9dfdSAndroid Build Coastguard Worker kill_only = true;
125*387f9dfdSAndroid Build Coastguard Worker break;
126*387f9dfdSAndroid Build Coastguard Worker case 'v':
127*387f9dfdSAndroid Build Coastguard Worker verbose = true;
128*387f9dfdSAndroid Build Coastguard Worker break;
129*387f9dfdSAndroid Build Coastguard Worker case 'h':
130*387f9dfdSAndroid Build Coastguard Worker argp_state_help(state, stderr, ARGP_HELP_STD_HELP);
131*387f9dfdSAndroid Build Coastguard Worker break;
132*387f9dfdSAndroid Build Coastguard Worker default:
133*387f9dfdSAndroid Build Coastguard Worker return ARGP_ERR_UNKNOWN;
134*387f9dfdSAndroid Build Coastguard Worker }
135*387f9dfdSAndroid Build Coastguard Worker return 0;
136*387f9dfdSAndroid Build Coastguard Worker }
137*387f9dfdSAndroid Build Coastguard Worker
libbpf_print_fn(enum libbpf_print_level level,const char * format,va_list args)138*387f9dfdSAndroid Build Coastguard Worker static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)
139*387f9dfdSAndroid Build Coastguard Worker {
140*387f9dfdSAndroid Build Coastguard Worker if (level == LIBBPF_DEBUG && !verbose)
141*387f9dfdSAndroid Build Coastguard Worker return 0;
142*387f9dfdSAndroid Build Coastguard Worker return vfprintf(stderr, format, args);
143*387f9dfdSAndroid Build Coastguard Worker }
144*387f9dfdSAndroid Build Coastguard Worker
alias_parse(char * prog)145*387f9dfdSAndroid Build Coastguard Worker static void alias_parse(char *prog)
146*387f9dfdSAndroid Build Coastguard Worker {
147*387f9dfdSAndroid Build Coastguard Worker char *name = basename(prog);
148*387f9dfdSAndroid Build Coastguard Worker
149*387f9dfdSAndroid Build Coastguard Worker if (!strcmp(name, "killsnoop")) {
150*387f9dfdSAndroid Build Coastguard Worker kill_only = true;
151*387f9dfdSAndroid Build Coastguard Worker }
152*387f9dfdSAndroid Build Coastguard Worker }
153*387f9dfdSAndroid Build Coastguard Worker
sig_int(int signo)154*387f9dfdSAndroid Build Coastguard Worker static void sig_int(int signo)
155*387f9dfdSAndroid Build Coastguard Worker {
156*387f9dfdSAndroid Build Coastguard Worker exiting = 1;
157*387f9dfdSAndroid Build Coastguard Worker }
158*387f9dfdSAndroid Build Coastguard Worker
handle_event(void * ctx,int cpu,void * data,__u32 data_sz)159*387f9dfdSAndroid Build Coastguard Worker static void handle_event(void *ctx, int cpu, void *data, __u32 data_sz)
160*387f9dfdSAndroid Build Coastguard Worker {
161*387f9dfdSAndroid Build Coastguard Worker struct event *e = data;
162*387f9dfdSAndroid Build Coastguard Worker struct tm *tm;
163*387f9dfdSAndroid Build Coastguard Worker char ts[32];
164*387f9dfdSAndroid Build Coastguard Worker time_t t;
165*387f9dfdSAndroid Build Coastguard Worker
166*387f9dfdSAndroid Build Coastguard Worker time(&t);
167*387f9dfdSAndroid Build Coastguard Worker tm = localtime(&t);
168*387f9dfdSAndroid Build Coastguard Worker strftime(ts, sizeof(ts), "%H:%M:%S", tm);
169*387f9dfdSAndroid Build Coastguard Worker if (signal_name && e->sig < ARRAY_SIZE(sig_name))
170*387f9dfdSAndroid Build Coastguard Worker printf("%-8s %-7d %-16s %-9s %-7d %-6d\n",
171*387f9dfdSAndroid Build Coastguard Worker ts, e->pid, e->comm, sig_name[e->sig], e->tpid, e->ret);
172*387f9dfdSAndroid Build Coastguard Worker else
173*387f9dfdSAndroid Build Coastguard Worker printf("%-8s %-7d %-16s %-9d %-7d %-6d\n",
174*387f9dfdSAndroid Build Coastguard Worker ts, e->pid, e->comm, e->sig, e->tpid, e->ret);
175*387f9dfdSAndroid Build Coastguard Worker }
176*387f9dfdSAndroid Build Coastguard Worker
handle_lost_events(void * ctx,int cpu,__u64 lost_cnt)177*387f9dfdSAndroid Build Coastguard Worker static void handle_lost_events(void *ctx, int cpu, __u64 lost_cnt)
178*387f9dfdSAndroid Build Coastguard Worker {
179*387f9dfdSAndroid Build Coastguard Worker warn("lost %llu events on CPU #%d\n", lost_cnt, cpu);
180*387f9dfdSAndroid Build Coastguard Worker }
181*387f9dfdSAndroid Build Coastguard Worker
main(int argc,char ** argv)182*387f9dfdSAndroid Build Coastguard Worker int main(int argc, char **argv)
183*387f9dfdSAndroid Build Coastguard Worker {
184*387f9dfdSAndroid Build Coastguard Worker static const struct argp argp = {
185*387f9dfdSAndroid Build Coastguard Worker .options = opts,
186*387f9dfdSAndroid Build Coastguard Worker .parser = parse_arg,
187*387f9dfdSAndroid Build Coastguard Worker .doc = argp_program_doc,
188*387f9dfdSAndroid Build Coastguard Worker };
189*387f9dfdSAndroid Build Coastguard Worker struct perf_buffer *pb = NULL;
190*387f9dfdSAndroid Build Coastguard Worker struct sigsnoop_bpf *obj;
191*387f9dfdSAndroid Build Coastguard Worker int err;
192*387f9dfdSAndroid Build Coastguard Worker
193*387f9dfdSAndroid Build Coastguard Worker alias_parse(argv[0]);
194*387f9dfdSAndroid Build Coastguard Worker err = argp_parse(&argp, argc, argv, 0, NULL, NULL);
195*387f9dfdSAndroid Build Coastguard Worker if (err)
196*387f9dfdSAndroid Build Coastguard Worker return err;
197*387f9dfdSAndroid Build Coastguard Worker
198*387f9dfdSAndroid Build Coastguard Worker libbpf_set_print(libbpf_print_fn);
199*387f9dfdSAndroid Build Coastguard Worker
200*387f9dfdSAndroid Build Coastguard Worker obj = sigsnoop_bpf__open();
201*387f9dfdSAndroid Build Coastguard Worker if (!obj) {
202*387f9dfdSAndroid Build Coastguard Worker warn("failed to open BPF object\n");
203*387f9dfdSAndroid Build Coastguard Worker return 1;
204*387f9dfdSAndroid Build Coastguard Worker }
205*387f9dfdSAndroid Build Coastguard Worker
206*387f9dfdSAndroid Build Coastguard Worker obj->rodata->filtered_pid = target_pid;
207*387f9dfdSAndroid Build Coastguard Worker obj->rodata->target_signal = target_signal;
208*387f9dfdSAndroid Build Coastguard Worker obj->rodata->failed_only = failed_only;
209*387f9dfdSAndroid Build Coastguard Worker
210*387f9dfdSAndroid Build Coastguard Worker if (kill_only) {
211*387f9dfdSAndroid Build Coastguard Worker bpf_program__set_autoload(obj->progs.sig_trace, false);
212*387f9dfdSAndroid Build Coastguard Worker } else {
213*387f9dfdSAndroid Build Coastguard Worker bpf_program__set_autoload(obj->progs.kill_entry, false);
214*387f9dfdSAndroid Build Coastguard Worker bpf_program__set_autoload(obj->progs.kill_exit, false);
215*387f9dfdSAndroid Build Coastguard Worker bpf_program__set_autoload(obj->progs.tkill_entry, false);
216*387f9dfdSAndroid Build Coastguard Worker bpf_program__set_autoload(obj->progs.tkill_exit, false);
217*387f9dfdSAndroid Build Coastguard Worker bpf_program__set_autoload(obj->progs.tgkill_entry, false);
218*387f9dfdSAndroid Build Coastguard Worker bpf_program__set_autoload(obj->progs.tgkill_exit, false);
219*387f9dfdSAndroid Build Coastguard Worker }
220*387f9dfdSAndroid Build Coastguard Worker
221*387f9dfdSAndroid Build Coastguard Worker err = sigsnoop_bpf__load(obj);
222*387f9dfdSAndroid Build Coastguard Worker if (err) {
223*387f9dfdSAndroid Build Coastguard Worker warn("failed to load BPF object: %d\n", err);
224*387f9dfdSAndroid Build Coastguard Worker goto cleanup;
225*387f9dfdSAndroid Build Coastguard Worker }
226*387f9dfdSAndroid Build Coastguard Worker
227*387f9dfdSAndroid Build Coastguard Worker err = sigsnoop_bpf__attach(obj);
228*387f9dfdSAndroid Build Coastguard Worker if (err) {
229*387f9dfdSAndroid Build Coastguard Worker warn("failed to attach BPF programs: %d\n", err);
230*387f9dfdSAndroid Build Coastguard Worker goto cleanup;
231*387f9dfdSAndroid Build Coastguard Worker }
232*387f9dfdSAndroid Build Coastguard Worker
233*387f9dfdSAndroid Build Coastguard Worker pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES,
234*387f9dfdSAndroid Build Coastguard Worker handle_event, handle_lost_events, NULL, NULL);
235*387f9dfdSAndroid Build Coastguard Worker if (!pb) {
236*387f9dfdSAndroid Build Coastguard Worker err = -errno;
237*387f9dfdSAndroid Build Coastguard Worker warn("failed to open perf buffer: %d\n", err);
238*387f9dfdSAndroid Build Coastguard Worker goto cleanup;
239*387f9dfdSAndroid Build Coastguard Worker }
240*387f9dfdSAndroid Build Coastguard Worker
241*387f9dfdSAndroid Build Coastguard Worker if (signal(SIGINT, sig_int) == SIG_ERR) {
242*387f9dfdSAndroid Build Coastguard Worker warn("can't set signal handler: %s\n", strerror(errno));
243*387f9dfdSAndroid Build Coastguard Worker goto cleanup;
244*387f9dfdSAndroid Build Coastguard Worker }
245*387f9dfdSAndroid Build Coastguard Worker
246*387f9dfdSAndroid Build Coastguard Worker printf("%-8s %-7s %-16s %-9s %-7s %-6s\n",
247*387f9dfdSAndroid Build Coastguard Worker "TIME", "PID", "COMM", "SIG", "TPID", "RESULT");
248*387f9dfdSAndroid Build Coastguard Worker
249*387f9dfdSAndroid Build Coastguard Worker while (!exiting) {
250*387f9dfdSAndroid Build Coastguard Worker err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS);
251*387f9dfdSAndroid Build Coastguard Worker if (err < 0 && err != -EINTR) {
252*387f9dfdSAndroid Build Coastguard Worker warn("error polling perf buffer: %s\n", strerror(-err));
253*387f9dfdSAndroid Build Coastguard Worker goto cleanup;
254*387f9dfdSAndroid Build Coastguard Worker }
255*387f9dfdSAndroid Build Coastguard Worker /* reset err to return 0 if exiting */
256*387f9dfdSAndroid Build Coastguard Worker err = 0;
257*387f9dfdSAndroid Build Coastguard Worker }
258*387f9dfdSAndroid Build Coastguard Worker
259*387f9dfdSAndroid Build Coastguard Worker cleanup:
260*387f9dfdSAndroid Build Coastguard Worker perf_buffer__free(pb);
261*387f9dfdSAndroid Build Coastguard Worker sigsnoop_bpf__destroy(obj);
262*387f9dfdSAndroid Build Coastguard Worker
263*387f9dfdSAndroid Build Coastguard Worker return err != 0;
264*387f9dfdSAndroid Build Coastguard Worker }
265