]> Git Repo - linux.git/blob - tools/bpf/bpftool/perf.c
HID: hid-sensor-custom: Fix big on-stack allocation in hid_sensor_custom_get_known()
[linux.git] / tools / bpf / bpftool / perf.c
1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2 // Copyright (C) 2018 Facebook
3 // Author: Yonghong Song <[email protected]>
4
5 #define _GNU_SOURCE
6 #include <ctype.h>
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <sys/stat.h>
12 #include <sys/types.h>
13 #include <unistd.h>
14 #include <dirent.h>
15
16 #include <bpf/bpf.h>
17
18 #include "main.h"
19
20 /* 0: undecided, 1: supported, 2: not supported */
21 static int perf_query_supported;
22 static bool has_perf_query_support(void)
23 {
24         __u64 probe_offset, probe_addr;
25         __u32 len, prog_id, fd_type;
26         char buf[256];
27         int fd;
28
29         if (perf_query_supported)
30                 goto out;
31
32         fd = open("/", O_RDONLY);
33         if (fd < 0) {
34                 p_err("perf_query_support: cannot open directory \"/\" (%s)",
35                       strerror(errno));
36                 goto out;
37         }
38
39         /* the following query will fail as no bpf attachment,
40          * the expected errno is ENOTSUPP
41          */
42         errno = 0;
43         len = sizeof(buf);
44         bpf_task_fd_query(getpid(), fd, 0, buf, &len, &prog_id,
45                           &fd_type, &probe_offset, &probe_addr);
46
47         if (errno == 524 /* ENOTSUPP */) {
48                 perf_query_supported = 1;
49                 goto close_fd;
50         }
51
52         perf_query_supported = 2;
53         p_err("perf_query_support: %s", strerror(errno));
54         fprintf(stderr,
55                 "HINT: non root or kernel doesn't support TASK_FD_QUERY\n");
56
57 close_fd:
58         close(fd);
59 out:
60         return perf_query_supported == 1;
61 }
62
63 static void print_perf_json(int pid, int fd, __u32 prog_id, __u32 fd_type,
64                             char *buf, __u64 probe_offset, __u64 probe_addr)
65 {
66         jsonw_start_object(json_wtr);
67         jsonw_int_field(json_wtr, "pid", pid);
68         jsonw_int_field(json_wtr, "fd", fd);
69         jsonw_uint_field(json_wtr, "prog_id", prog_id);
70         switch (fd_type) {
71         case BPF_FD_TYPE_RAW_TRACEPOINT:
72                 jsonw_string_field(json_wtr, "fd_type", "raw_tracepoint");
73                 jsonw_string_field(json_wtr, "tracepoint", buf);
74                 break;
75         case BPF_FD_TYPE_TRACEPOINT:
76                 jsonw_string_field(json_wtr, "fd_type", "tracepoint");
77                 jsonw_string_field(json_wtr, "tracepoint", buf);
78                 break;
79         case BPF_FD_TYPE_KPROBE:
80                 jsonw_string_field(json_wtr, "fd_type", "kprobe");
81                 if (buf[0] != '\0') {
82                         jsonw_string_field(json_wtr, "func", buf);
83                         jsonw_lluint_field(json_wtr, "offset", probe_offset);
84                 } else {
85                         jsonw_lluint_field(json_wtr, "addr", probe_addr);
86                 }
87                 break;
88         case BPF_FD_TYPE_KRETPROBE:
89                 jsonw_string_field(json_wtr, "fd_type", "kretprobe");
90                 if (buf[0] != '\0') {
91                         jsonw_string_field(json_wtr, "func", buf);
92                         jsonw_lluint_field(json_wtr, "offset", probe_offset);
93                 } else {
94                         jsonw_lluint_field(json_wtr, "addr", probe_addr);
95                 }
96                 break;
97         case BPF_FD_TYPE_UPROBE:
98                 jsonw_string_field(json_wtr, "fd_type", "uprobe");
99                 jsonw_string_field(json_wtr, "filename", buf);
100                 jsonw_lluint_field(json_wtr, "offset", probe_offset);
101                 break;
102         case BPF_FD_TYPE_URETPROBE:
103                 jsonw_string_field(json_wtr, "fd_type", "uretprobe");
104                 jsonw_string_field(json_wtr, "filename", buf);
105                 jsonw_lluint_field(json_wtr, "offset", probe_offset);
106                 break;
107         default:
108                 break;
109         }
110         jsonw_end_object(json_wtr);
111 }
112
113 static void print_perf_plain(int pid, int fd, __u32 prog_id, __u32 fd_type,
114                              char *buf, __u64 probe_offset, __u64 probe_addr)
115 {
116         printf("pid %d  fd %d: prog_id %u  ", pid, fd, prog_id);
117         switch (fd_type) {
118         case BPF_FD_TYPE_RAW_TRACEPOINT:
119                 printf("raw_tracepoint  %s\n", buf);
120                 break;
121         case BPF_FD_TYPE_TRACEPOINT:
122                 printf("tracepoint  %s\n", buf);
123                 break;
124         case BPF_FD_TYPE_KPROBE:
125                 if (buf[0] != '\0')
126                         printf("kprobe  func %s  offset %llu\n", buf,
127                                probe_offset);
128                 else
129                         printf("kprobe  addr %llu\n", probe_addr);
130                 break;
131         case BPF_FD_TYPE_KRETPROBE:
132                 if (buf[0] != '\0')
133                         printf("kretprobe  func %s  offset %llu\n", buf,
134                                probe_offset);
135                 else
136                         printf("kretprobe  addr %llu\n", probe_addr);
137                 break;
138         case BPF_FD_TYPE_UPROBE:
139                 printf("uprobe  filename %s  offset %llu\n", buf, probe_offset);
140                 break;
141         case BPF_FD_TYPE_URETPROBE:
142                 printf("uretprobe  filename %s  offset %llu\n", buf,
143                        probe_offset);
144                 break;
145         default:
146                 break;
147         }
148 }
149
150 static int show_proc(void)
151 {
152         struct dirent *proc_de, *pid_fd_de;
153         __u64 probe_offset, probe_addr;
154         __u32 len, prog_id, fd_type;
155         DIR *proc, *pid_fd;
156         int err, pid, fd;
157         const char *pch;
158         char buf[4096];
159
160         proc = opendir("/proc");
161         if (!proc)
162                 return -1;
163
164         while ((proc_de = readdir(proc))) {
165                 pid = 0;
166                 pch = proc_de->d_name;
167
168                 /* pid should be all numbers */
169                 while (isdigit(*pch)) {
170                         pid = pid * 10 + *pch - '0';
171                         pch++;
172                 }
173                 if (*pch != '\0')
174                         continue;
175
176                 err = snprintf(buf, sizeof(buf), "/proc/%s/fd", proc_de->d_name);
177                 if (err < 0 || err >= (int)sizeof(buf))
178                         continue;
179
180                 pid_fd = opendir(buf);
181                 if (!pid_fd)
182                         continue;
183
184                 while ((pid_fd_de = readdir(pid_fd))) {
185                         fd = 0;
186                         pch = pid_fd_de->d_name;
187
188                         /* fd should be all numbers */
189                         while (isdigit(*pch)) {
190                                 fd = fd * 10 + *pch - '0';
191                                 pch++;
192                         }
193                         if (*pch != '\0')
194                                 continue;
195
196                         /* query (pid, fd) for potential perf events */
197                         len = sizeof(buf);
198                         err = bpf_task_fd_query(pid, fd, 0, buf, &len,
199                                                 &prog_id, &fd_type,
200                                                 &probe_offset, &probe_addr);
201                         if (err < 0)
202                                 continue;
203
204                         if (json_output)
205                                 print_perf_json(pid, fd, prog_id, fd_type, buf,
206                                                 probe_offset, probe_addr);
207                         else
208                                 print_perf_plain(pid, fd, prog_id, fd_type, buf,
209                                                  probe_offset, probe_addr);
210                 }
211                 closedir(pid_fd);
212         }
213         closedir(proc);
214         return 0;
215 }
216
217 static int do_show(int argc, char **argv)
218 {
219         int err;
220
221         if (!has_perf_query_support())
222                 return -1;
223
224         if (json_output)
225                 jsonw_start_array(json_wtr);
226         err = show_proc();
227         if (json_output)
228                 jsonw_end_array(json_wtr);
229
230         return err;
231 }
232
233 static int do_help(int argc, char **argv)
234 {
235         fprintf(stderr,
236                 "Usage: %1$s %2$s { show | list }\n"
237                 "       %1$s %2$s help }\n"
238                 "\n"
239                 "       " HELP_SPEC_OPTIONS " }\n"
240                 "",
241                 bin_name, argv[-2]);
242
243         return 0;
244 }
245
246 static const struct cmd cmds[] = {
247         { "show",       do_show },
248         { "list",       do_show },
249         { "help",       do_help },
250         { 0 }
251 };
252
253 int do_perf(int argc, char **argv)
254 {
255         return cmd_select(cmds, argc, argv, do_help);
256 }
This page took 0.04991 seconds and 4 git commands to generate.