123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
- // Copyright (C) 2018 Facebook
- // Author: Yonghong Song <[email protected]>
- #define _GNU_SOURCE
- #include <ctype.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include <dirent.h>
- #include <bpf/bpf.h>
- #include "main.h"
- /* 0: undecided, 1: supported, 2: not supported */
- static int perf_query_supported;
- static bool has_perf_query_support(void)
- {
- __u64 probe_offset, probe_addr;
- __u32 len, prog_id, fd_type;
- char buf[256];
- int fd;
- if (perf_query_supported)
- goto out;
- fd = open("/", O_RDONLY);
- if (fd < 0) {
- p_err("perf_query_support: cannot open directory \"/\" (%s)",
- strerror(errno));
- goto out;
- }
- /* the following query will fail as no bpf attachment,
- * the expected errno is ENOTSUPP
- */
- errno = 0;
- len = sizeof(buf);
- bpf_task_fd_query(getpid(), fd, 0, buf, &len, &prog_id,
- &fd_type, &probe_offset, &probe_addr);
- if (errno == 524 /* ENOTSUPP */) {
- perf_query_supported = 1;
- goto close_fd;
- }
- perf_query_supported = 2;
- p_err("perf_query_support: %s", strerror(errno));
- fprintf(stderr,
- "HINT: non root or kernel doesn't support TASK_FD_QUERY\n");
- close_fd:
- close(fd);
- out:
- return perf_query_supported == 1;
- }
- static void print_perf_json(int pid, int fd, __u32 prog_id, __u32 fd_type,
- char *buf, __u64 probe_offset, __u64 probe_addr)
- {
- jsonw_start_object(json_wtr);
- jsonw_int_field(json_wtr, "pid", pid);
- jsonw_int_field(json_wtr, "fd", fd);
- jsonw_uint_field(json_wtr, "prog_id", prog_id);
- switch (fd_type) {
- case BPF_FD_TYPE_RAW_TRACEPOINT:
- jsonw_string_field(json_wtr, "fd_type", "raw_tracepoint");
- jsonw_string_field(json_wtr, "tracepoint", buf);
- break;
- case BPF_FD_TYPE_TRACEPOINT:
- jsonw_string_field(json_wtr, "fd_type", "tracepoint");
- jsonw_string_field(json_wtr, "tracepoint", buf);
- break;
- case BPF_FD_TYPE_KPROBE:
- jsonw_string_field(json_wtr, "fd_type", "kprobe");
- if (buf[0] != '\0') {
- jsonw_string_field(json_wtr, "func", buf);
- jsonw_lluint_field(json_wtr, "offset", probe_offset);
- } else {
- jsonw_lluint_field(json_wtr, "addr", probe_addr);
- }
- break;
- case BPF_FD_TYPE_KRETPROBE:
- jsonw_string_field(json_wtr, "fd_type", "kretprobe");
- if (buf[0] != '\0') {
- jsonw_string_field(json_wtr, "func", buf);
- jsonw_lluint_field(json_wtr, "offset", probe_offset);
- } else {
- jsonw_lluint_field(json_wtr, "addr", probe_addr);
- }
- break;
- case BPF_FD_TYPE_UPROBE:
- jsonw_string_field(json_wtr, "fd_type", "uprobe");
- jsonw_string_field(json_wtr, "filename", buf);
- jsonw_lluint_field(json_wtr, "offset", probe_offset);
- break;
- case BPF_FD_TYPE_URETPROBE:
- jsonw_string_field(json_wtr, "fd_type", "uretprobe");
- jsonw_string_field(json_wtr, "filename", buf);
- jsonw_lluint_field(json_wtr, "offset", probe_offset);
- break;
- default:
- break;
- }
- jsonw_end_object(json_wtr);
- }
- static void print_perf_plain(int pid, int fd, __u32 prog_id, __u32 fd_type,
- char *buf, __u64 probe_offset, __u64 probe_addr)
- {
- printf("pid %d fd %d: prog_id %u ", pid, fd, prog_id);
- switch (fd_type) {
- case BPF_FD_TYPE_RAW_TRACEPOINT:
- printf("raw_tracepoint %s\n", buf);
- break;
- case BPF_FD_TYPE_TRACEPOINT:
- printf("tracepoint %s\n", buf);
- break;
- case BPF_FD_TYPE_KPROBE:
- if (buf[0] != '\0')
- printf("kprobe func %s offset %llu\n", buf,
- probe_offset);
- else
- printf("kprobe addr %llu\n", probe_addr);
- break;
- case BPF_FD_TYPE_KRETPROBE:
- if (buf[0] != '\0')
- printf("kretprobe func %s offset %llu\n", buf,
- probe_offset);
- else
- printf("kretprobe addr %llu\n", probe_addr);
- break;
- case BPF_FD_TYPE_UPROBE:
- printf("uprobe filename %s offset %llu\n", buf, probe_offset);
- break;
- case BPF_FD_TYPE_URETPROBE:
- printf("uretprobe filename %s offset %llu\n", buf,
- probe_offset);
- break;
- default:
- break;
- }
- }
- static int show_proc(void)
- {
- struct dirent *proc_de, *pid_fd_de;
- __u64 probe_offset, probe_addr;
- __u32 len, prog_id, fd_type;
- DIR *proc, *pid_fd;
- int err, pid, fd;
- const char *pch;
- char buf[4096];
- proc = opendir("/proc");
- if (!proc)
- return -1;
- while ((proc_de = readdir(proc))) {
- pid = 0;
- pch = proc_de->d_name;
- /* pid should be all numbers */
- while (isdigit(*pch)) {
- pid = pid * 10 + *pch - '0';
- pch++;
- }
- if (*pch != '\0')
- continue;
- err = snprintf(buf, sizeof(buf), "/proc/%s/fd", proc_de->d_name);
- if (err < 0 || err >= (int)sizeof(buf))
- continue;
- pid_fd = opendir(buf);
- if (!pid_fd)
- continue;
- while ((pid_fd_de = readdir(pid_fd))) {
- fd = 0;
- pch = pid_fd_de->d_name;
- /* fd should be all numbers */
- while (isdigit(*pch)) {
- fd = fd * 10 + *pch - '0';
- pch++;
- }
- if (*pch != '\0')
- continue;
- /* query (pid, fd) for potential perf events */
- len = sizeof(buf);
- err = bpf_task_fd_query(pid, fd, 0, buf, &len,
- &prog_id, &fd_type,
- &probe_offset, &probe_addr);
- if (err < 0)
- continue;
- if (json_output)
- print_perf_json(pid, fd, prog_id, fd_type, buf,
- probe_offset, probe_addr);
- else
- print_perf_plain(pid, fd, prog_id, fd_type, buf,
- probe_offset, probe_addr);
- }
- closedir(pid_fd);
- }
- closedir(proc);
- return 0;
- }
- static int do_show(int argc, char **argv)
- {
- int err;
- if (!has_perf_query_support())
- return -1;
- if (json_output)
- jsonw_start_array(json_wtr);
- err = show_proc();
- if (json_output)
- jsonw_end_array(json_wtr);
- return err;
- }
- static int do_help(int argc, char **argv)
- {
- fprintf(stderr,
- "Usage: %1$s %2$s { show | list }\n"
- " %1$s %2$s help }\n"
- "\n"
- " " HELP_SPEC_OPTIONS " }\n"
- "",
- bin_name, argv[-2]);
- return 0;
- }
- static const struct cmd cmds[] = {
- { "show", do_show },
- { "list", do_show },
- { "help", do_help },
- { 0 }
- };
- int do_perf(int argc, char **argv)
- {
- return cmd_select(cmds, argc, argv, do_help);
- }
|