root/tools/bpf/bpftool/perf.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. has_perf_query_support
  2. print_perf_json
  3. print_perf_plain
  4. show_proc
  5. do_show
  6. do_help
  7. do_perf

   1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
   2 // Copyright (C) 2018 Facebook
   3 // Author: Yonghong Song <yhs@fb.com>
   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 <ftw.h>
  15 
  16 #include <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(const char *fpath, const struct stat *sb,
 151                      int tflag, struct FTW *ftwbuf)
 152 {
 153         __u64 probe_offset, probe_addr;
 154         __u32 len, prog_id, fd_type;
 155         int err, pid = 0, fd = 0;
 156         const char *pch;
 157         char buf[4096];
 158 
 159         /* prefix always /proc */
 160         pch = fpath + 5;
 161         if (*pch == '\0')
 162                 return 0;
 163 
 164         /* pid should be all numbers */
 165         pch++;
 166         while (isdigit(*pch)) {
 167                 pid = pid * 10 + *pch - '0';
 168                 pch++;
 169         }
 170         if (*pch == '\0')
 171                 return 0;
 172         if (*pch != '/')
 173                 return FTW_SKIP_SUBTREE;
 174 
 175         /* check /proc/<pid>/fd directory */
 176         pch++;
 177         if (strncmp(pch, "fd", 2))
 178                 return FTW_SKIP_SUBTREE;
 179         pch += 2;
 180         if (*pch == '\0')
 181                 return 0;
 182         if (*pch != '/')
 183                 return FTW_SKIP_SUBTREE;
 184 
 185         /* check /proc/<pid>/fd/<fd_num> */
 186         pch++;
 187         while (isdigit(*pch)) {
 188                 fd = fd * 10 + *pch - '0';
 189                 pch++;
 190         }
 191         if (*pch != '\0')
 192                 return FTW_SKIP_SUBTREE;
 193 
 194         /* query (pid, fd) for potential perf events */
 195         len = sizeof(buf);
 196         err = bpf_task_fd_query(pid, fd, 0, buf, &len, &prog_id, &fd_type,
 197                                 &probe_offset, &probe_addr);
 198         if (err < 0)
 199                 return 0;
 200 
 201         if (json_output)
 202                 print_perf_json(pid, fd, prog_id, fd_type, buf, probe_offset,
 203                                 probe_addr);
 204         else
 205                 print_perf_plain(pid, fd, prog_id, fd_type, buf, probe_offset,
 206                                  probe_addr);
 207 
 208         return 0;
 209 }
 210 
 211 static int do_show(int argc, char **argv)
 212 {
 213         int flags = FTW_ACTIONRETVAL | FTW_PHYS;
 214         int err = 0, nopenfd = 16;
 215 
 216         if (!has_perf_query_support())
 217                 return -1;
 218 
 219         if (json_output)
 220                 jsonw_start_array(json_wtr);
 221         if (nftw("/proc", show_proc, nopenfd, flags) == -1) {
 222                 p_err("%s", strerror(errno));
 223                 err = -1;
 224         }
 225         if (json_output)
 226                 jsonw_end_array(json_wtr);
 227 
 228         return err;
 229 }
 230 
 231 static int do_help(int argc, char **argv)
 232 {
 233         fprintf(stderr,
 234                 "Usage: %s %s { show | list | help }\n"
 235                 "",
 236                 bin_name, argv[-2]);
 237 
 238         return 0;
 239 }
 240 
 241 static const struct cmd cmds[] = {
 242         { "show",       do_show },
 243         { "list",       do_show },
 244         { "help",       do_help },
 245         { 0 }
 246 };
 247 
 248 int do_perf(int argc, char **argv)
 249 {
 250         return cmd_select(cmds, argc, argv, do_help);
 251 }

/* [<][>][^][v][top][bottom][index][help] */