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