xref: /linux/tools/testing/selftests/bpf/prog_tests/tp_btf_ids.c (revision 081e5bf2a9d941da60cd70c97c5a704b29e47f7f)
1*74ae53cbSMykyta Yatsenko // SPDX-License-Identifier: GPL-2.0
2*74ae53cbSMykyta Yatsenko #include <test_progs.h>
3*74ae53cbSMykyta Yatsenko #include <bpf/btf.h>
4*74ae53cbSMykyta Yatsenko 
5*74ae53cbSMykyta Yatsenko #define TRACEFS		"/sys/kernel/tracing"
6*74ae53cbSMykyta Yatsenko #define DEBUGFS_TRACING	"/sys/kernel/debug/tracing"
7*74ae53cbSMykyta Yatsenko #define EVENT_SUBPATH	"events/bpf_testmod/bpf_testmod_test_read/btf_ids"
8*74ae53cbSMykyta Yatsenko 
9*74ae53cbSMykyta Yatsenko struct btf_ids_info {
10*74ae53cbSMykyta Yatsenko 	__u32 obj_id;
11*74ae53cbSMykyta Yatsenko 	__u32 raw_id;
12*74ae53cbSMykyta Yatsenko 	__u32 tp_id;
13*74ae53cbSMykyta Yatsenko };
14*74ae53cbSMykyta Yatsenko 
15*74ae53cbSMykyta Yatsenko static const char *btf_ids_path(char *buf, size_t sz)
16*74ae53cbSMykyta Yatsenko {
17*74ae53cbSMykyta Yatsenko 	if (access(TRACEFS "/trace", F_OK) == 0)
18*74ae53cbSMykyta Yatsenko 		snprintf(buf, sz, "%s/%s", TRACEFS, EVENT_SUBPATH);
19*74ae53cbSMykyta Yatsenko 	else
20*74ae53cbSMykyta Yatsenko 		snprintf(buf, sz, "%s/%s", DEBUGFS_TRACING, EVENT_SUBPATH);
21*74ae53cbSMykyta Yatsenko 	return buf;
22*74ae53cbSMykyta Yatsenko }
23*74ae53cbSMykyta Yatsenko 
24*74ae53cbSMykyta Yatsenko static int read_btf_ids(struct btf_ids_info *info)
25*74ae53cbSMykyta Yatsenko {
26*74ae53cbSMykyta Yatsenko 	char path[256], buf[256];
27*74ae53cbSMykyta Yatsenko 	int fd, n;
28*74ae53cbSMykyta Yatsenko 
29*74ae53cbSMykyta Yatsenko 	fd = open(btf_ids_path(path, sizeof(path)), O_RDONLY);
30*74ae53cbSMykyta Yatsenko 	if (fd < 0)
31*74ae53cbSMykyta Yatsenko 		return -errno;
32*74ae53cbSMykyta Yatsenko 
33*74ae53cbSMykyta Yatsenko 	n = read(fd, buf, sizeof(buf) - 1);
34*74ae53cbSMykyta Yatsenko 	close(fd);
35*74ae53cbSMykyta Yatsenko 	if (n <= 0)
36*74ae53cbSMykyta Yatsenko 		return -EIO;
37*74ae53cbSMykyta Yatsenko 	buf[n] = '\0';
38*74ae53cbSMykyta Yatsenko 
39*74ae53cbSMykyta Yatsenko 	if (sscanf(buf,
40*74ae53cbSMykyta Yatsenko 		   "btf_obj_id: %u\nraw_btf_id: %u\ntp_btf_id: %u\n",
41*74ae53cbSMykyta Yatsenko 		   &info->obj_id, &info->raw_id, &info->tp_id) != 3)
42*74ae53cbSMykyta Yatsenko 		return -EINVAL;
43*74ae53cbSMykyta Yatsenko 	return 0;
44*74ae53cbSMykyta Yatsenko }
45*74ae53cbSMykyta Yatsenko 
46*74ae53cbSMykyta Yatsenko static const char *param_name(struct btf *btf, const struct btf_param *p)
47*74ae53cbSMykyta Yatsenko {
48*74ae53cbSMykyta Yatsenko 	return btf__name_by_offset(btf, p->name_off);
49*74ae53cbSMykyta Yatsenko }
50*74ae53cbSMykyta Yatsenko 
51*74ae53cbSMykyta Yatsenko static const char *member_name(struct btf *btf, const struct btf_member *m)
52*74ae53cbSMykyta Yatsenko {
53*74ae53cbSMykyta Yatsenko 	return btf__name_by_offset(btf, m->name_off);
54*74ae53cbSMykyta Yatsenko }
55*74ae53cbSMykyta Yatsenko 
56*74ae53cbSMykyta Yatsenko void test_tp_btf_ids(void)
57*74ae53cbSMykyta Yatsenko {
58*74ae53cbSMykyta Yatsenko 	const struct btf_type *proto_t, *rec_t;
59*74ae53cbSMykyta Yatsenko 	const struct btf_param *params;
60*74ae53cbSMykyta Yatsenko 	const struct btf_member *members;
61*74ae53cbSMykyta Yatsenko 	struct btf_ids_info info;
62*74ae53cbSMykyta Yatsenko 	struct btf *vmlinux_btf, *btf;
63*74ae53cbSMykyta Yatsenko 	const char *name;
64*74ae53cbSMykyta Yatsenko 	int err;
65*74ae53cbSMykyta Yatsenko 
66*74ae53cbSMykyta Yatsenko 	if (!env.has_testmod) {
67*74ae53cbSMykyta Yatsenko 		test__skip();
68*74ae53cbSMykyta Yatsenko 		return;
69*74ae53cbSMykyta Yatsenko 	}
70*74ae53cbSMykyta Yatsenko 
71*74ae53cbSMykyta Yatsenko 	err = read_btf_ids(&info);
72*74ae53cbSMykyta Yatsenko 	if (!ASSERT_OK(err, "read btf_ids"))
73*74ae53cbSMykyta Yatsenko 		return;
74*74ae53cbSMykyta Yatsenko 
75*74ae53cbSMykyta Yatsenko 	ASSERT_GT(info.obj_id, 0, "obj_id non-zero");
76*74ae53cbSMykyta Yatsenko 	ASSERT_GT(info.raw_id, 0, "raw_id non-zero");
77*74ae53cbSMykyta Yatsenko 	ASSERT_GT(info.tp_id, 0, "tp_id non-zero");
78*74ae53cbSMykyta Yatsenko 
79*74ae53cbSMykyta Yatsenko 	vmlinux_btf = btf__load_vmlinux_btf();
80*74ae53cbSMykyta Yatsenko 	if (!ASSERT_OK_PTR(vmlinux_btf, "load vmlinux BTF"))
81*74ae53cbSMykyta Yatsenko 		return;
82*74ae53cbSMykyta Yatsenko 
83*74ae53cbSMykyta Yatsenko 	/* Module BTF is split BTF; load with vmlinux as base. */
84*74ae53cbSMykyta Yatsenko 	btf = btf__load_from_kernel_by_id_split(info.obj_id, vmlinux_btf);
85*74ae53cbSMykyta Yatsenko 	if (!ASSERT_OK_PTR(btf, "load module BTF")) {
86*74ae53cbSMykyta Yatsenko 		btf__free(vmlinux_btf);
87*74ae53cbSMykyta Yatsenko 		return;
88*74ae53cbSMykyta Yatsenko 	}
89*74ae53cbSMykyta Yatsenko 
90*74ae53cbSMykyta Yatsenko 	/*
91*74ae53cbSMykyta Yatsenko 	 * raw_btf_id should be the FUNC_PROTO of __bpf_trace_<call>:
92*74ae53cbSMykyta Yatsenko 	 *   void *__data, struct task_struct *task,
93*74ae53cbSMykyta Yatsenko 	 *   struct bpf_testmod_test_read_ctx *ctx
94*74ae53cbSMykyta Yatsenko 	 */
95*74ae53cbSMykyta Yatsenko 	proto_t = btf__type_by_id(btf, info.raw_id);
96*74ae53cbSMykyta Yatsenko 	if (!ASSERT_OK_PTR(proto_t, "raw type_by_id"))
97*74ae53cbSMykyta Yatsenko 		goto out;
98*74ae53cbSMykyta Yatsenko 	if (!ASSERT_TRUE(btf_is_func_proto(proto_t), "raw is FUNC_PROTO"))
99*74ae53cbSMykyta Yatsenko 		goto out;
100*74ae53cbSMykyta Yatsenko 	if (!ASSERT_EQ(btf_vlen(proto_t), 3, "func_proto arg count"))
101*74ae53cbSMykyta Yatsenko 		goto out;
102*74ae53cbSMykyta Yatsenko 
103*74ae53cbSMykyta Yatsenko 	params = btf_params(proto_t);
104*74ae53cbSMykyta Yatsenko 	ASSERT_STREQ(param_name(btf, &params[0]), "__data", "arg0 name");
105*74ae53cbSMykyta Yatsenko 	ASSERT_STREQ(param_name(btf, &params[1]), "task", "arg1 name");
106*74ae53cbSMykyta Yatsenko 	ASSERT_STREQ(param_name(btf, &params[2]), "ctx", "arg2 name");
107*74ae53cbSMykyta Yatsenko 
108*74ae53cbSMykyta Yatsenko 	/*
109*74ae53cbSMykyta Yatsenko 	 * tp_btf_id should be STRUCT trace_event_raw_<call> with the
110*74ae53cbSMykyta Yatsenko 	 * fields declared by TP_STRUCT__entry plus the common header.
111*74ae53cbSMykyta Yatsenko 	 */
112*74ae53cbSMykyta Yatsenko 	rec_t = btf__type_by_id(btf, info.tp_id);
113*74ae53cbSMykyta Yatsenko 	if (!ASSERT_OK_PTR(rec_t, "tp type_by_id"))
114*74ae53cbSMykyta Yatsenko 		goto out;
115*74ae53cbSMykyta Yatsenko 	if (!ASSERT_TRUE(btf_is_struct(rec_t), "tp is STRUCT"))
116*74ae53cbSMykyta Yatsenko 		goto out;
117*74ae53cbSMykyta Yatsenko 	name = btf__name_by_offset(btf, rec_t->name_off);
118*74ae53cbSMykyta Yatsenko 	ASSERT_STREQ(name, "trace_event_raw_bpf_testmod_test_read",
119*74ae53cbSMykyta Yatsenko 		     "tp struct name");
120*74ae53cbSMykyta Yatsenko 	if (!ASSERT_GE(btf_vlen(rec_t), 5, "tp struct field count"))
121*74ae53cbSMykyta Yatsenko 		goto out;
122*74ae53cbSMykyta Yatsenko 
123*74ae53cbSMykyta Yatsenko 	members = btf_members(rec_t);
124*74ae53cbSMykyta Yatsenko 	ASSERT_STREQ(member_name(btf, &members[0]), "ent", "field0 name");
125*74ae53cbSMykyta Yatsenko 	ASSERT_STREQ(member_name(btf, &members[1]), "pid", "field1 name");
126*74ae53cbSMykyta Yatsenko 	ASSERT_STREQ(member_name(btf, &members[2]), "comm", "field2 name");
127*74ae53cbSMykyta Yatsenko 	ASSERT_STREQ(member_name(btf, &members[3]), "off", "field3 name");
128*74ae53cbSMykyta Yatsenko 	ASSERT_STREQ(member_name(btf, &members[4]), "len", "field4 name");
129*74ae53cbSMykyta Yatsenko out:
130*74ae53cbSMykyta Yatsenko 	btf__free(btf);
131*74ae53cbSMykyta Yatsenko 	btf__free(vmlinux_btf);
132*74ae53cbSMykyta Yatsenko }
133