Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
0002 // Copyright (C) 2018 Facebook
0003 // Author: Yonghong Song <yhs@fb.com>
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 /* 0: undecided, 1: supported, 2: not supported */
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     /* the following query will fail as no bpf attachment,
0040      * the expected errno is ENOTSUPP
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 /* ENOTSUPP */) {
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         /* pid should be all numbers */
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             /* fd should be all numbers */
0189             while (isdigit(*pch)) {
0190                 fd = fd * 10 + *pch - '0';
0191                 pch++;
0192             }
0193             if (*pch != '\0')
0194                 continue;
0195 
0196             /* query (pid, fd) for potential perf events */
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 }