1 // SPDX-License-Identifier: GPL-2.0
2 #include <test_progs.h>
3 
serial_test_tp_attach_query(void)4 void serial_test_tp_attach_query(void)
5 {
6 	const int num_progs = 3;
7 	int i, j, bytes, efd, err, prog_fd[num_progs], pmu_fd[num_progs];
8 	__u32 duration = 0, info_len, saved_prog_ids[num_progs];
9 	const char *file = "./test_tracepoint.bpf.o";
10 	struct perf_event_query_bpf *query;
11 	struct perf_event_attr attr = {};
12 	struct bpf_object *obj[num_progs];
13 	struct bpf_prog_info prog_info;
14 	char buf[256];
15 
16 	for (i = 0; i < num_progs; i++)
17 		obj[i] = NULL;
18 
19 	snprintf(buf, sizeof(buf),
20 		 "/sys/kernel/debug/tracing/events/sched/sched_switch/id");
21 	efd = open(buf, O_RDONLY, 0);
22 	if (CHECK(efd < 0, "open", "err %d errno %d\n", efd, errno))
23 		return;
24 	bytes = read(efd, buf, sizeof(buf));
25 	close(efd);
26 	if (CHECK(bytes <= 0 || bytes >= sizeof(buf),
27 		  "read", "bytes %d errno %d\n", bytes, errno))
28 		return;
29 
30 	attr.config = strtol(buf, NULL, 0);
31 	attr.type = PERF_TYPE_TRACEPOINT;
32 	attr.sample_type = PERF_SAMPLE_RAW | PERF_SAMPLE_CALLCHAIN;
33 	attr.sample_period = 1;
34 	attr.wakeup_events = 1;
35 
36 	query = malloc(sizeof(*query) + sizeof(__u32) * num_progs);
37 	for (i = 0; i < num_progs; i++) {
38 		err = bpf_prog_test_load(file, BPF_PROG_TYPE_TRACEPOINT, &obj[i],
39 				    &prog_fd[i]);
40 		if (CHECK(err, "prog_load", "err %d errno %d\n", err, errno))
41 			goto cleanup1;
42 
43 		bzero(&prog_info, sizeof(prog_info));
44 		prog_info.jited_prog_len = 0;
45 		prog_info.xlated_prog_len = 0;
46 		prog_info.nr_map_ids = 0;
47 		info_len = sizeof(prog_info);
48 		err = bpf_prog_get_info_by_fd(prog_fd[i], &prog_info,
49 					      &info_len);
50 		if (CHECK(err, "bpf_prog_get_info_by_fd", "err %d errno %d\n",
51 			  err, errno))
52 			goto cleanup1;
53 		saved_prog_ids[i] = prog_info.id;
54 
55 		pmu_fd[i] = syscall(__NR_perf_event_open, &attr, -1 /* pid */,
56 				    0 /* cpu 0 */, -1 /* group id */,
57 				    0 /* flags */);
58 		if (CHECK(pmu_fd[i] < 0, "perf_event_open", "err %d errno %d\n",
59 			  pmu_fd[i], errno))
60 			goto cleanup2;
61 		err = ioctl(pmu_fd[i], PERF_EVENT_IOC_ENABLE, 0);
62 		if (CHECK(err, "perf_event_ioc_enable", "err %d errno %d\n",
63 			  err, errno))
64 			goto cleanup3;
65 
66 		if (i == 0) {
67 			/* check NULL prog array query */
68 			query->ids_len = num_progs;
69 			err = ioctl(pmu_fd[i], PERF_EVENT_IOC_QUERY_BPF, query);
70 			if (CHECK(err || query->prog_cnt != 0,
71 				  "perf_event_ioc_query_bpf",
72 				  "err %d errno %d query->prog_cnt %u\n",
73 				  err, errno, query->prog_cnt))
74 				goto cleanup3;
75 		}
76 
77 		err = ioctl(pmu_fd[i], PERF_EVENT_IOC_SET_BPF, prog_fd[i]);
78 		if (CHECK(err, "perf_event_ioc_set_bpf", "err %d errno %d\n",
79 			  err, errno))
80 			goto cleanup3;
81 
82 		if (i == 1) {
83 			/* try to get # of programs only */
84 			query->ids_len = 0;
85 			err = ioctl(pmu_fd[i], PERF_EVENT_IOC_QUERY_BPF, query);
86 			if (CHECK(err || query->prog_cnt != 2,
87 				  "perf_event_ioc_query_bpf",
88 				  "err %d errno %d query->prog_cnt %u\n",
89 				  err, errno, query->prog_cnt))
90 				goto cleanup3;
91 
92 			/* try a few negative tests */
93 			/* invalid query pointer */
94 			err = ioctl(pmu_fd[i], PERF_EVENT_IOC_QUERY_BPF,
95 				    (struct perf_event_query_bpf *)0x1);
96 			if (CHECK(!err || errno != EFAULT,
97 				  "perf_event_ioc_query_bpf",
98 				  "err %d errno %d\n", err, errno))
99 				goto cleanup3;
100 
101 			/* no enough space */
102 			query->ids_len = 1;
103 			err = ioctl(pmu_fd[i], PERF_EVENT_IOC_QUERY_BPF, query);
104 			if (CHECK(!err || errno != ENOSPC || query->prog_cnt != 2,
105 				  "perf_event_ioc_query_bpf",
106 				  "err %d errno %d query->prog_cnt %u\n",
107 				  err, errno, query->prog_cnt))
108 				goto cleanup3;
109 		}
110 
111 		query->ids_len = num_progs;
112 		err = ioctl(pmu_fd[i], PERF_EVENT_IOC_QUERY_BPF, query);
113 		if (CHECK(err || query->prog_cnt != (i + 1),
114 			  "perf_event_ioc_query_bpf",
115 			  "err %d errno %d query->prog_cnt %u\n",
116 			  err, errno, query->prog_cnt))
117 			goto cleanup3;
118 		for (j = 0; j < i + 1; j++)
119 			if (CHECK(saved_prog_ids[j] != query->ids[j],
120 				  "perf_event_ioc_query_bpf",
121 				  "#%d saved_prog_id %x query prog_id %x\n",
122 				  j, saved_prog_ids[j], query->ids[j]))
123 				goto cleanup3;
124 	}
125 
126 	i = num_progs - 1;
127 	for (; i >= 0; i--) {
128  cleanup3:
129 		ioctl(pmu_fd[i], PERF_EVENT_IOC_DISABLE);
130  cleanup2:
131 		close(pmu_fd[i]);
132  cleanup1:
133 		bpf_object__close(obj[i]);
134 	}
135 	free(query);
136 }
137