brintos

brintos / linux-shallow public Read only

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