brintos

brintos / linux-shallow public Read only

0
0
Text · 11.3 KiB · 1e61f21 Raw
424 lines · c
1// SPDX-License-Identifier: GPL-2.02 3#include <stdio.h>4#include <stdlib.h>5#include <signal.h>6#include <unistd.h>7#include <stdbool.h>8#include <string.h>9#include <stdint.h>10#include <fcntl.h>11#include <linux/bpf.h>12#include <sys/ioctl.h>13#include <sys/types.h>14#include <sys/stat.h>15#include <linux/perf_event.h>16 17#include <bpf/bpf.h>18#include <bpf/libbpf.h>19#include "bpf_util.h"20#include "perf-sys.h"21#include "trace_helpers.h"22 23static struct bpf_program *progs[2];24static struct bpf_link *links[2];25 26#define CHECK_PERROR_RET(condition) ({			\27	int __ret = !!(condition);			\28	if (__ret) {					\29		printf("FAIL: %s:\n", __func__);	\30		perror("    ");			\31		return -1;				\32	}						\33})34 35#define CHECK_AND_RET(condition) ({			\36	int __ret = !!(condition);			\37	if (__ret)					\38		return -1;				\39})40 41static __u64 ptr_to_u64(void *ptr)42{43	return (__u64) (unsigned long) ptr;44}45 46#define PMU_TYPE_FILE "/sys/bus/event_source/devices/%s/type"47static int bpf_find_probe_type(const char *event_type)48{49	char buf[256];50	int fd, ret;51 52	ret = snprintf(buf, sizeof(buf), PMU_TYPE_FILE, event_type);53	CHECK_PERROR_RET(ret < 0 || ret >= sizeof(buf));54 55	fd = open(buf, O_RDONLY);56	CHECK_PERROR_RET(fd < 0);57 58	ret = read(fd, buf, sizeof(buf));59	close(fd);60	CHECK_PERROR_RET(ret < 0 || ret >= sizeof(buf));61 62	errno = 0;63	ret = (int)strtol(buf, NULL, 10);64	CHECK_PERROR_RET(errno);65	return ret;66}67 68#define PMU_RETPROBE_FILE "/sys/bus/event_source/devices/%s/format/retprobe"69static int bpf_get_retprobe_bit(const char *event_type)70{71	char buf[256];72	int fd, ret;73 74	ret = snprintf(buf, sizeof(buf), PMU_RETPROBE_FILE, event_type);75	CHECK_PERROR_RET(ret < 0 || ret >= sizeof(buf));76 77	fd = open(buf, O_RDONLY);78	CHECK_PERROR_RET(fd < 0);79 80	ret = read(fd, buf, sizeof(buf));81	close(fd);82	CHECK_PERROR_RET(ret < 0 || ret >= sizeof(buf));83	CHECK_PERROR_RET(strlen(buf) < strlen("config:"));84 85	errno = 0;86	ret = (int)strtol(buf + strlen("config:"), NULL, 10);87	CHECK_PERROR_RET(errno);88	return ret;89}90 91static int test_debug_fs_kprobe(int link_idx, const char *fn_name,92				__u32 expected_fd_type)93{94	__u64 probe_offset, probe_addr;95	__u32 len, prog_id, fd_type;96	int err, event_fd;97	char buf[256];98 99	len = sizeof(buf);100	event_fd = bpf_link__fd(links[link_idx]);101	err = bpf_task_fd_query(getpid(), event_fd, 0, buf, &len,102				&prog_id, &fd_type, &probe_offset,103				&probe_addr);104	if (err < 0) {105		printf("FAIL: %s, for event_fd idx %d, fn_name %s\n",106		       __func__, link_idx, fn_name);107		perror("    :");108		return -1;109	}110	if (strcmp(buf, fn_name) != 0 ||111	    fd_type != expected_fd_type ||112	    probe_offset != 0x0 || probe_addr != 0x0) {113		printf("FAIL: bpf_trace_event_query(event_fd[%d]):\n",114		       link_idx);115		printf("buf: %s, fd_type: %u, probe_offset: 0x%llx,"116		       " probe_addr: 0x%llx\n",117		       buf, fd_type, probe_offset, probe_addr);118		return -1;119	}120	return 0;121}122 123static int test_nondebug_fs_kuprobe_common(const char *event_type,124	const char *name, __u64 offset, __u64 addr, bool is_return,125	char *buf, __u32 *buf_len, __u32 *prog_id, __u32 *fd_type,126	__u64 *probe_offset, __u64 *probe_addr)127{128	int is_return_bit = bpf_get_retprobe_bit(event_type);129	int type = bpf_find_probe_type(event_type);130	struct perf_event_attr attr = {};131	struct bpf_link *link;132	int fd, err = -1;133 134	if (type < 0 || is_return_bit < 0) {135		printf("FAIL: %s incorrect type (%d) or is_return_bit (%d)\n",136			__func__, type, is_return_bit);137		return err;138	}139 140	attr.sample_period = 1;141	attr.wakeup_events = 1;142	if (is_return)143		attr.config |= 1 << is_return_bit;144 145	if (name) {146		attr.config1 = ptr_to_u64((void *)name);147		attr.config2 = offset;148	} else {149		attr.config1 = 0;150		attr.config2 = addr;151	}152	attr.size = sizeof(attr);153	attr.type = type;154 155	fd = sys_perf_event_open(&attr, -1, 0, -1, 0);156	link = bpf_program__attach_perf_event(progs[0], fd);157	if (libbpf_get_error(link)) {158		printf("ERROR: bpf_program__attach_perf_event failed\n");159		link = NULL;160		close(fd);161		goto cleanup;162	}163 164	CHECK_PERROR_RET(bpf_task_fd_query(getpid(), fd, 0, buf, buf_len,165			 prog_id, fd_type, probe_offset, probe_addr) < 0);166	err = 0;167 168cleanup:169	bpf_link__destroy(link);170	return err;171}172 173static int test_nondebug_fs_probe(const char *event_type, const char *name,174				  __u64 offset, __u64 addr, bool is_return,175				  __u32 expected_fd_type,176				  __u32 expected_ret_fd_type,177				  char *buf, __u32 buf_len)178{179	__u64 probe_offset, probe_addr;180	__u32 prog_id, fd_type;181	int err;182 183	err = test_nondebug_fs_kuprobe_common(event_type, name,184					      offset, addr, is_return,185					      buf, &buf_len, &prog_id,186					      &fd_type, &probe_offset,187					      &probe_addr);188	if (err < 0) {189		printf("FAIL: %s, "190		       "for name %s, offset 0x%llx, addr 0x%llx, is_return %d\n",191		       __func__, name ? name : "", offset, addr, is_return);192		perror("    :");193		return -1;194	}195	if ((is_return && fd_type != expected_ret_fd_type) ||196	    (!is_return && fd_type != expected_fd_type)) {197		printf("FAIL: %s, incorrect fd_type %u\n",198		       __func__, fd_type);199		return -1;200	}201	if (name) {202		if (strcmp(name, buf) != 0) {203			printf("FAIL: %s, incorrect buf %s\n", __func__, buf);204			return -1;205		}206		if (probe_offset != offset) {207			printf("FAIL: %s, incorrect probe_offset 0x%llx\n",208			       __func__, probe_offset);209			return -1;210		}211	} else {212		if (buf_len != 0) {213			printf("FAIL: %s, incorrect buf %p\n",214			       __func__, buf);215			return -1;216		}217 218		if (probe_addr != addr) {219			printf("FAIL: %s, incorrect probe_addr 0x%llx\n",220			       __func__, probe_addr);221			return -1;222		}223	}224	return 0;225}226 227static int test_debug_fs_uprobe(char *binary_path, long offset, bool is_return)228{229	char buf[256], event_alias[sizeof("test_1234567890")];230	const char *event_type = "uprobe";231	struct perf_event_attr attr = {};232	__u64 probe_offset, probe_addr;233	__u32 len, prog_id, fd_type;234	int err = -1, res, kfd, efd;235	struct bpf_link *link;236	ssize_t bytes;237 238	snprintf(buf, sizeof(buf), "/sys/kernel/tracing/%s_events",239		 event_type);240	kfd = open(buf, O_WRONLY | O_TRUNC, 0);241	CHECK_PERROR_RET(kfd < 0);242 243	res = snprintf(event_alias, sizeof(event_alias), "test_%d", getpid());244	CHECK_PERROR_RET(res < 0 || res >= sizeof(event_alias));245 246	res = snprintf(buf, sizeof(buf), "%c:%ss/%s %s:0x%lx",247		       is_return ? 'r' : 'p', event_type, event_alias,248		       binary_path, offset);249	CHECK_PERROR_RET(res < 0 || res >= sizeof(buf));250	CHECK_PERROR_RET(write(kfd, buf, strlen(buf)) < 0);251 252	close(kfd);253	kfd = -1;254 255	snprintf(buf, sizeof(buf), "/sys/kernel/tracing/events/%ss/%s/id",256		 event_type, event_alias);257	efd = open(buf, O_RDONLY, 0);258	CHECK_PERROR_RET(efd < 0);259 260	bytes = read(efd, buf, sizeof(buf));261	CHECK_PERROR_RET(bytes <= 0 || bytes >= sizeof(buf));262	close(efd);263	buf[bytes] = '\0';264 265	attr.config = strtol(buf, NULL, 0);266	attr.type = PERF_TYPE_TRACEPOINT;267	attr.sample_period = 1;268	attr.wakeup_events = 1;269 270	kfd = sys_perf_event_open(&attr, -1, 0, -1, PERF_FLAG_FD_CLOEXEC);271	link = bpf_program__attach_perf_event(progs[0], kfd);272	if (libbpf_get_error(link)) {273		printf("ERROR: bpf_program__attach_perf_event failed\n");274		link = NULL;275		close(kfd);276		goto cleanup;277	}278 279	len = sizeof(buf);280	err = bpf_task_fd_query(getpid(), kfd, 0, buf, &len,281				&prog_id, &fd_type, &probe_offset,282				&probe_addr);283	if (err < 0) {284		printf("FAIL: %s, binary_path %s\n", __func__, binary_path);285		perror("    :");286		return -1;287	}288	if ((is_return && fd_type != BPF_FD_TYPE_URETPROBE) ||289	    (!is_return && fd_type != BPF_FD_TYPE_UPROBE)) {290		printf("FAIL: %s, incorrect fd_type %u\n", __func__,291		       fd_type);292		return -1;293	}294	if (strcmp(binary_path, buf) != 0) {295		printf("FAIL: %s, incorrect buf %s\n", __func__, buf);296		return -1;297	}298	if (probe_offset != offset) {299		printf("FAIL: %s, incorrect probe_offset 0x%llx\n", __func__,300		       probe_offset);301		return -1;302	}303	err = 0;304 305cleanup:306	bpf_link__destroy(link);307	return err;308}309 310int main(int argc, char **argv)311{312	extern char __executable_start;313	char filename[256], buf[256];314	__u64 uprobe_file_offset;315	struct bpf_program *prog;316	struct bpf_object *obj;317	int i = 0, err = -1;318 319	if (load_kallsyms()) {320		printf("failed to process /proc/kallsyms\n");321		return err;322	}323 324	snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);325	obj = bpf_object__open_file(filename, NULL);326	if (libbpf_get_error(obj)) {327		fprintf(stderr, "ERROR: opening BPF object file failed\n");328		return err;329	}330 331	/* load BPF program */332	if (bpf_object__load(obj)) {333		fprintf(stderr, "ERROR: loading BPF object file failed\n");334		goto cleanup;335	}336 337	bpf_object__for_each_program(prog, obj) {338		progs[i] = prog;339		links[i] = bpf_program__attach(progs[i]);340		if (libbpf_get_error(links[i])) {341			fprintf(stderr, "ERROR: bpf_program__attach failed\n");342			links[i] = NULL;343			goto cleanup;344		}345		i++;346	}347 348	/* test two functions in the corresponding *_kern.c file */349	CHECK_AND_RET(test_debug_fs_kprobe(0, "blk_mq_start_request",350					   BPF_FD_TYPE_KPROBE));351	CHECK_AND_RET(test_debug_fs_kprobe(1, "__blk_account_io_done",352					   BPF_FD_TYPE_KRETPROBE));353 354	/* test nondebug fs kprobe */355	CHECK_AND_RET(test_nondebug_fs_probe("kprobe", "bpf_check", 0x0, 0x0,356					     false, BPF_FD_TYPE_KPROBE,357					     BPF_FD_TYPE_KRETPROBE,358					     buf, sizeof(buf)));359#ifdef __x86_64__360	/* set a kprobe on "bpf_check + 0x5", which is x64 specific */361	CHECK_AND_RET(test_nondebug_fs_probe("kprobe", "bpf_check", 0x5, 0x0,362					     false, BPF_FD_TYPE_KPROBE,363					     BPF_FD_TYPE_KRETPROBE,364					     buf, sizeof(buf)));365#endif366	CHECK_AND_RET(test_nondebug_fs_probe("kprobe", "bpf_check", 0x0, 0x0,367					     true, BPF_FD_TYPE_KPROBE,368					     BPF_FD_TYPE_KRETPROBE,369					     buf, sizeof(buf)));370	CHECK_AND_RET(test_nondebug_fs_probe("kprobe", NULL, 0x0,371					     ksym_get_addr("bpf_check"), false,372					     BPF_FD_TYPE_KPROBE,373					     BPF_FD_TYPE_KRETPROBE,374					     buf, sizeof(buf)));375	CHECK_AND_RET(test_nondebug_fs_probe("kprobe", NULL, 0x0,376					     ksym_get_addr("bpf_check"), false,377					     BPF_FD_TYPE_KPROBE,378					     BPF_FD_TYPE_KRETPROBE,379					     NULL, 0));380	CHECK_AND_RET(test_nondebug_fs_probe("kprobe", NULL, 0x0,381					     ksym_get_addr("bpf_check"), true,382					     BPF_FD_TYPE_KPROBE,383					     BPF_FD_TYPE_KRETPROBE,384					     buf, sizeof(buf)));385	CHECK_AND_RET(test_nondebug_fs_probe("kprobe", NULL, 0x0,386					     ksym_get_addr("bpf_check"), true,387					     BPF_FD_TYPE_KPROBE,388					     BPF_FD_TYPE_KRETPROBE,389					     0, 0));390 391	/* test nondebug fs uprobe */392	/* the calculation of uprobe file offset is based on gcc 7.3.1 on x64393	 * and the default linker script, which defines __executable_start as394	 * the start of the .text section. The calculation could be different395	 * on different systems with different compilers. The right way is396	 * to parse the ELF file. We took a shortcut here.397	 */398	uprobe_file_offset = (unsigned long)main - (unsigned long)&__executable_start;399	CHECK_AND_RET(test_nondebug_fs_probe("uprobe", (char *)argv[0],400					     uprobe_file_offset, 0x0, false,401					     BPF_FD_TYPE_UPROBE,402					     BPF_FD_TYPE_URETPROBE,403					     buf, sizeof(buf)));404	CHECK_AND_RET(test_nondebug_fs_probe("uprobe", (char *)argv[0],405					     uprobe_file_offset, 0x0, true,406					     BPF_FD_TYPE_UPROBE,407					     BPF_FD_TYPE_URETPROBE,408					     buf, sizeof(buf)));409 410	/* test debug fs uprobe */411	CHECK_AND_RET(test_debug_fs_uprobe((char *)argv[0], uprobe_file_offset,412					   false));413	CHECK_AND_RET(test_debug_fs_uprobe((char *)argv[0], uprobe_file_offset,414					   true));415	err = 0;416 417cleanup:418	for (i--; i >= 0; i--)419		bpf_link__destroy(links[i]);420 421	bpf_object__close(obj);422	return err;423}424