1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2020 Anton Protopopov
3 //
4 // Based on syscount(8) from BCC by Sasha Goldshtein
5 #include <vmlinux.h>
6 #include <bpf/bpf_helpers.h>
7 #include <bpf/bpf_tracing.h>
8 #include <bpf/bpf_core_read.h>
9 #include "syscount.h"
10 #include "maps.bpf.h"
11
12 const volatile bool count_by_process = false;
13 const volatile bool measure_latency = false;
14 const volatile bool filter_failed = false;
15 const volatile int filter_errno = false;
16 const volatile pid_t filter_pid = 0;
17
18 struct {
19 __uint(type, BPF_MAP_TYPE_HASH);
20 __uint(max_entries, MAX_ENTRIES);
21 __type(key, u32);
22 __type(value, u64);
23 __uint(map_flags, BPF_F_NO_PREALLOC);
24 } start SEC(".maps");
25
26 struct {
27 __uint(type, BPF_MAP_TYPE_HASH);
28 __uint(max_entries, MAX_ENTRIES);
29 __type(key, u32);
30 __type(value, struct data_t);
31 __uint(map_flags, BPF_F_NO_PREALLOC);
32 } data SEC(".maps");
33
34 static __always_inline
save_proc_name(struct data_t * val)35 void save_proc_name(struct data_t *val)
36 {
37 struct task_struct *current = (void *)bpf_get_current_task();
38
39 /* We should save the process name every time because it can be
40 * changed (e.g., by exec). This can be optimized later by managing
41 * this field with the help of tp/sched/sched_process_exec and
42 * raw_tp/task_rename. */
43 BPF_CORE_READ_STR_INTO(&val->comm, current, group_leader, comm);
44 }
45
46 SEC("tracepoint/raw_syscalls/sys_enter")
sys_enter(struct trace_event_raw_sys_enter * args)47 int sys_enter(struct trace_event_raw_sys_enter *args)
48 {
49 u64 id = bpf_get_current_pid_tgid();
50 pid_t pid = id >> 32;
51 u32 tid = id;
52 u64 ts;
53
54 if (filter_pid && pid != filter_pid)
55 return 0;
56
57 ts = bpf_ktime_get_ns();
58 bpf_map_update_elem(&start, &tid, &ts, 0);
59 return 0;
60 }
61
62 SEC("tracepoint/raw_syscalls/sys_exit")
sys_exit(struct trace_event_raw_sys_exit * args)63 int sys_exit(struct trace_event_raw_sys_exit *args)
64 {
65 u64 id = bpf_get_current_pid_tgid();
66 static const struct data_t zero;
67 pid_t pid = id >> 32;
68 struct data_t *val;
69 u64 *start_ts;
70 u32 tid = id;
71 u32 key;
72
73 /* this happens when there is an interrupt */
74 if (args->id == -1)
75 return 0;
76
77 if (filter_pid && pid != filter_pid)
78 return 0;
79 if (filter_failed && args->ret >= 0)
80 return 0;
81 if (filter_errno && args->ret != -filter_errno)
82 return 0;
83
84 if (measure_latency) {
85 start_ts = bpf_map_lookup_elem(&start, &tid);
86 if (!start_ts)
87 return 0;
88 }
89
90 key = (count_by_process) ? pid : args->id;
91 val = bpf_map_lookup_or_try_init(&data, &key, &zero);
92 if (val) {
93 __sync_fetch_and_add(&val->count, 1);
94 if (count_by_process)
95 save_proc_name(val);
96 if (measure_latency)
97 __sync_fetch_and_add(&val->total_ns, bpf_ktime_get_ns() - *start_ts);
98 }
99 return 0;
100 }
101
102 char LICENSE[] SEC("license") = "GPL";
103