cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

perf.c (5935B)


      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 <dirent.h>
     15
     16#include <bpf/bpf.h>
     17
     18#include "main.h"
     19
     20/* 0: undecided, 1: supported, 2: not supported */
     21static int perf_query_supported;
     22static 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
     57close_fd:
     58	close(fd);
     59out:
     60	return perf_query_supported == 1;
     61}
     62
     63static 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
    113static 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
    150static int show_proc(void)
    151{
    152	struct dirent *proc_de, *pid_fd_de;
    153	__u64 probe_offset, probe_addr;
    154	__u32 len, prog_id, fd_type;
    155	DIR *proc, *pid_fd;
    156	int err, pid, fd;
    157	const char *pch;
    158	char buf[4096];
    159
    160	proc = opendir("/proc");
    161	if (!proc)
    162		return -1;
    163
    164	while ((proc_de = readdir(proc))) {
    165		pid = 0;
    166		pch = proc_de->d_name;
    167
    168		/* pid should be all numbers */
    169		while (isdigit(*pch)) {
    170			pid = pid * 10 + *pch - '0';
    171			pch++;
    172		}
    173		if (*pch != '\0')
    174			continue;
    175
    176		err = snprintf(buf, sizeof(buf), "/proc/%s/fd", proc_de->d_name);
    177		if (err < 0 || err >= (int)sizeof(buf))
    178			continue;
    179
    180		pid_fd = opendir(buf);
    181		if (!pid_fd)
    182			continue;
    183
    184		while ((pid_fd_de = readdir(pid_fd))) {
    185			fd = 0;
    186			pch = pid_fd_de->d_name;
    187
    188			/* fd should be all numbers */
    189			while (isdigit(*pch)) {
    190				fd = fd * 10 + *pch - '0';
    191				pch++;
    192			}
    193			if (*pch != '\0')
    194				continue;
    195
    196			/* query (pid, fd) for potential perf events */
    197			len = sizeof(buf);
    198			err = bpf_task_fd_query(pid, fd, 0, buf, &len,
    199						&prog_id, &fd_type,
    200						&probe_offset, &probe_addr);
    201			if (err < 0)
    202				continue;
    203
    204			if (json_output)
    205				print_perf_json(pid, fd, prog_id, fd_type, buf,
    206						probe_offset, probe_addr);
    207			else
    208				print_perf_plain(pid, fd, prog_id, fd_type, buf,
    209						 probe_offset, probe_addr);
    210		}
    211		closedir(pid_fd);
    212	}
    213	closedir(proc);
    214	return 0;
    215}
    216
    217static int do_show(int argc, char **argv)
    218{
    219	int err;
    220
    221	if (!has_perf_query_support())
    222		return -1;
    223
    224	if (json_output)
    225		jsonw_start_array(json_wtr);
    226	err = show_proc();
    227	if (json_output)
    228		jsonw_end_array(json_wtr);
    229
    230	return err;
    231}
    232
    233static int do_help(int argc, char **argv)
    234{
    235	fprintf(stderr,
    236		"Usage: %1$s %2$s { show | list }\n"
    237		"       %1$s %2$s help }\n"
    238		"\n"
    239		"       " HELP_SPEC_OPTIONS " }\n"
    240		"",
    241		bin_name, argv[-2]);
    242
    243	return 0;
    244}
    245
    246static const struct cmd cmds[] = {
    247	{ "show",	do_show },
    248	{ "list",	do_show },
    249	{ "help",	do_help },
    250	{ 0 }
    251};
    252
    253int do_perf(int argc, char **argv)
    254{
    255	return cmd_select(cmds, argc, argv, do_help);
    256}