0001
0002
0003
0004
0005 #define _GNU_SOURCE
0006 #include <ctype.h>
0007 #include <errno.h>
0008 #include <fcntl.h>
0009 #include <stdlib.h>
0010 #include <string.h>
0011 #include <sys/stat.h>
0012 #include <sys/types.h>
0013 #include <unistd.h>
0014 #include <dirent.h>
0015
0016 #include <bpf/bpf.h>
0017
0018 #include "main.h"
0019
0020
0021 static int perf_query_supported;
0022 static bool has_perf_query_support(void)
0023 {
0024 __u64 probe_offset, probe_addr;
0025 __u32 len, prog_id, fd_type;
0026 char buf[256];
0027 int fd;
0028
0029 if (perf_query_supported)
0030 goto out;
0031
0032 fd = open("/", O_RDONLY);
0033 if (fd < 0) {
0034 p_err("perf_query_support: cannot open directory \"/\" (%s)",
0035 strerror(errno));
0036 goto out;
0037 }
0038
0039
0040
0041
0042 errno = 0;
0043 len = sizeof(buf);
0044 bpf_task_fd_query(getpid(), fd, 0, buf, &len, &prog_id,
0045 &fd_type, &probe_offset, &probe_addr);
0046
0047 if (errno == 524 ) {
0048 perf_query_supported = 1;
0049 goto close_fd;
0050 }
0051
0052 perf_query_supported = 2;
0053 p_err("perf_query_support: %s", strerror(errno));
0054 fprintf(stderr,
0055 "HINT: non root or kernel doesn't support TASK_FD_QUERY\n");
0056
0057 close_fd:
0058 close(fd);
0059 out:
0060 return perf_query_supported == 1;
0061 }
0062
0063 static void print_perf_json(int pid, int fd, __u32 prog_id, __u32 fd_type,
0064 char *buf, __u64 probe_offset, __u64 probe_addr)
0065 {
0066 jsonw_start_object(json_wtr);
0067 jsonw_int_field(json_wtr, "pid", pid);
0068 jsonw_int_field(json_wtr, "fd", fd);
0069 jsonw_uint_field(json_wtr, "prog_id", prog_id);
0070 switch (fd_type) {
0071 case BPF_FD_TYPE_RAW_TRACEPOINT:
0072 jsonw_string_field(json_wtr, "fd_type", "raw_tracepoint");
0073 jsonw_string_field(json_wtr, "tracepoint", buf);
0074 break;
0075 case BPF_FD_TYPE_TRACEPOINT:
0076 jsonw_string_field(json_wtr, "fd_type", "tracepoint");
0077 jsonw_string_field(json_wtr, "tracepoint", buf);
0078 break;
0079 case BPF_FD_TYPE_KPROBE:
0080 jsonw_string_field(json_wtr, "fd_type", "kprobe");
0081 if (buf[0] != '\0') {
0082 jsonw_string_field(json_wtr, "func", buf);
0083 jsonw_lluint_field(json_wtr, "offset", probe_offset);
0084 } else {
0085 jsonw_lluint_field(json_wtr, "addr", probe_addr);
0086 }
0087 break;
0088 case BPF_FD_TYPE_KRETPROBE:
0089 jsonw_string_field(json_wtr, "fd_type", "kretprobe");
0090 if (buf[0] != '\0') {
0091 jsonw_string_field(json_wtr, "func", buf);
0092 jsonw_lluint_field(json_wtr, "offset", probe_offset);
0093 } else {
0094 jsonw_lluint_field(json_wtr, "addr", probe_addr);
0095 }
0096 break;
0097 case BPF_FD_TYPE_UPROBE:
0098 jsonw_string_field(json_wtr, "fd_type", "uprobe");
0099 jsonw_string_field(json_wtr, "filename", buf);
0100 jsonw_lluint_field(json_wtr, "offset", probe_offset);
0101 break;
0102 case BPF_FD_TYPE_URETPROBE:
0103 jsonw_string_field(json_wtr, "fd_type", "uretprobe");
0104 jsonw_string_field(json_wtr, "filename", buf);
0105 jsonw_lluint_field(json_wtr, "offset", probe_offset);
0106 break;
0107 default:
0108 break;
0109 }
0110 jsonw_end_object(json_wtr);
0111 }
0112
0113 static void print_perf_plain(int pid, int fd, __u32 prog_id, __u32 fd_type,
0114 char *buf, __u64 probe_offset, __u64 probe_addr)
0115 {
0116 printf("pid %d fd %d: prog_id %u ", pid, fd, prog_id);
0117 switch (fd_type) {
0118 case BPF_FD_TYPE_RAW_TRACEPOINT:
0119 printf("raw_tracepoint %s\n", buf);
0120 break;
0121 case BPF_FD_TYPE_TRACEPOINT:
0122 printf("tracepoint %s\n", buf);
0123 break;
0124 case BPF_FD_TYPE_KPROBE:
0125 if (buf[0] != '\0')
0126 printf("kprobe func %s offset %llu\n", buf,
0127 probe_offset);
0128 else
0129 printf("kprobe addr %llu\n", probe_addr);
0130 break;
0131 case BPF_FD_TYPE_KRETPROBE:
0132 if (buf[0] != '\0')
0133 printf("kretprobe func %s offset %llu\n", buf,
0134 probe_offset);
0135 else
0136 printf("kretprobe addr %llu\n", probe_addr);
0137 break;
0138 case BPF_FD_TYPE_UPROBE:
0139 printf("uprobe filename %s offset %llu\n", buf, probe_offset);
0140 break;
0141 case BPF_FD_TYPE_URETPROBE:
0142 printf("uretprobe filename %s offset %llu\n", buf,
0143 probe_offset);
0144 break;
0145 default:
0146 break;
0147 }
0148 }
0149
0150 static int show_proc(void)
0151 {
0152 struct dirent *proc_de, *pid_fd_de;
0153 __u64 probe_offset, probe_addr;
0154 __u32 len, prog_id, fd_type;
0155 DIR *proc, *pid_fd;
0156 int err, pid, fd;
0157 const char *pch;
0158 char buf[4096];
0159
0160 proc = opendir("/proc");
0161 if (!proc)
0162 return -1;
0163
0164 while ((proc_de = readdir(proc))) {
0165 pid = 0;
0166 pch = proc_de->d_name;
0167
0168
0169 while (isdigit(*pch)) {
0170 pid = pid * 10 + *pch - '0';
0171 pch++;
0172 }
0173 if (*pch != '\0')
0174 continue;
0175
0176 err = snprintf(buf, sizeof(buf), "/proc/%s/fd", proc_de->d_name);
0177 if (err < 0 || err >= (int)sizeof(buf))
0178 continue;
0179
0180 pid_fd = opendir(buf);
0181 if (!pid_fd)
0182 continue;
0183
0184 while ((pid_fd_de = readdir(pid_fd))) {
0185 fd = 0;
0186 pch = pid_fd_de->d_name;
0187
0188
0189 while (isdigit(*pch)) {
0190 fd = fd * 10 + *pch - '0';
0191 pch++;
0192 }
0193 if (*pch != '\0')
0194 continue;
0195
0196
0197 len = sizeof(buf);
0198 err = bpf_task_fd_query(pid, fd, 0, buf, &len,
0199 &prog_id, &fd_type,
0200 &probe_offset, &probe_addr);
0201 if (err < 0)
0202 continue;
0203
0204 if (json_output)
0205 print_perf_json(pid, fd, prog_id, fd_type, buf,
0206 probe_offset, probe_addr);
0207 else
0208 print_perf_plain(pid, fd, prog_id, fd_type, buf,
0209 probe_offset, probe_addr);
0210 }
0211 closedir(pid_fd);
0212 }
0213 closedir(proc);
0214 return 0;
0215 }
0216
0217 static int do_show(int argc, char **argv)
0218 {
0219 int err;
0220
0221 if (!has_perf_query_support())
0222 return -1;
0223
0224 if (json_output)
0225 jsonw_start_array(json_wtr);
0226 err = show_proc();
0227 if (json_output)
0228 jsonw_end_array(json_wtr);
0229
0230 return err;
0231 }
0232
0233 static int do_help(int argc, char **argv)
0234 {
0235 fprintf(stderr,
0236 "Usage: %1$s %2$s { show | list }\n"
0237 " %1$s %2$s help }\n"
0238 "\n"
0239 " " HELP_SPEC_OPTIONS " }\n"
0240 "",
0241 bin_name, argv[-2]);
0242
0243 return 0;
0244 }
0245
0246 static const struct cmd cmds[] = {
0247 { "show", do_show },
0248 { "list", do_show },
0249 { "help", do_help },
0250 { 0 }
0251 };
0252
0253 int do_perf(int argc, char **argv)
0254 {
0255 return cmd_select(cmds, argc, argv, do_help);
0256 }