Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0-only
2 : /*
3 : * Copyright (c) 2023 Meta Platforms, Inc. and affiliates.
4 : */
5 :
6 : #include "core/btf.h"
7 :
8 : #include <linux/btf.h>
9 :
10 : #include <bpf/btf.h>
11 : #include <errno.h>
12 : #include <limits.h>
13 : #include <stddef.h>
14 : #include <stdlib.h>
15 :
16 : #include "core/helper.h"
17 : #include "core/logger.h"
18 :
19 : static struct btf *_bf_btf = NULL;
20 :
21 3 : int bf_btf_setup(void)
22 : {
23 3 : _bf_btf = btf__load_vmlinux_btf();
24 3 : if (!_bf_btf)
25 1 : return bf_err_r(errno, "failed to load vmlinux BTF");
26 :
27 : return 0;
28 : }
29 :
30 2 : void bf_btf_teardown(void)
31 : {
32 2 : btf__free(_bf_btf);
33 2 : _bf_btf = NULL;
34 2 : }
35 :
36 0 : int bf_btf_get_id(const char *name)
37 : {
38 : int id;
39 :
40 0 : bf_assert(name);
41 :
42 0 : id = btf__find_by_name(_bf_btf, name);
43 0 : if (id < 0)
44 0 : return bf_err_r(errno, "failed to find BTF type for \"%s\"", name);
45 :
46 : return id;
47 : }
48 :
49 0 : const char *bf_btf_get_name(int id)
50 : {
51 : const struct btf_type *type;
52 :
53 0 : type = btf__type_by_id(_bf_btf, id);
54 0 : if (!type) {
55 0 : bf_warn("can't find BTF type ID %d", id);
56 0 : return NULL;
57 : }
58 :
59 0 : return btf__name_by_offset(_bf_btf, type->name_off);
60 : }
61 :
62 0 : int bf_btf_kernel_has_token(void)
63 : {
64 : int bpf_attr_id;
65 : const struct btf_type *bpf_attr_type;
66 : const struct btf_member *bpf_attr_members;
67 :
68 0 : bpf_attr_id = btf__find_by_name_kind(_bf_btf, "bpf_attr", BTF_KIND_UNION);
69 0 : if (bpf_attr_id < 0) {
70 0 : return bf_err_r(bpf_attr_id,
71 : "can't find structure 'bpf_attr' in kernel BTF");
72 : }
73 :
74 0 : bpf_attr_type = btf__type_by_id(_bf_btf, bpf_attr_id);
75 0 : if (!bpf_attr_type)
76 0 : return bf_err_r(-EINVAL, "failed to request 'bpf_attr' BTF type");
77 :
78 : bpf_attr_members = btf_members(bpf_attr_type);
79 : // Iterate through union members
80 0 : for (unsigned short i = 0; i < btf_vlen(bpf_attr_type); i++) {
81 : const struct btf_type *member_type =
82 0 : btf__type_by_id(_bf_btf, bpf_attr_members[i].type);
83 : const struct btf_member *m_members = btf_members(member_type);
84 :
85 : // We are looking for an anonymous structure
86 0 : if (!btf_is_struct(member_type) || bpf_attr_members[i].name_off != 0)
87 0 : continue;
88 :
89 0 : for (int j = 0; j < btf_vlen(member_type); j++) {
90 : const char *member_name =
91 0 : btf__name_by_offset(_bf_btf, m_members[j].name_off);
92 :
93 0 : if (member_name && bf_streq(member_name, "prog_token_fd"))
94 : return 0;
95 : }
96 : }
97 :
98 : return -ENOENT;
99 : }
100 :
101 6 : int bf_btf_get_field_off(const char *struct_name, const char *field_name)
102 : {
103 : int offset = -1;
104 : int struct_id;
105 : struct btf_member *member;
106 : const struct btf_type *type;
107 :
108 6 : struct_id = btf__find_by_name_kind(_bf_btf, struct_name, BTF_KIND_STRUCT);
109 6 : if (struct_id < 0) {
110 2 : return bf_err_r(struct_id, "can't find structure '%s' in kernel BTF",
111 : struct_name);
112 : }
113 :
114 4 : type = btf__type_by_id(_bf_btf, struct_id);
115 4 : if (!type)
116 0 : return bf_err_r(errno, "can't get btf_type for '%s'", struct_name);
117 :
118 4 : member = (struct btf_member *)(type + 1);
119 22 : for (size_t i = 0; i < BTF_INFO_VLEN(type->info); ++i, ++member) {
120 21 : const char *cur_name = btf__name_by_offset(_bf_btf, member->name_off);
121 21 : if (!cur_name || !bf_streq(cur_name, field_name))
122 : continue;
123 :
124 3 : if (BTF_INFO_KFLAG(type->info)) {
125 2 : offset = BTF_MEMBER_BIT_OFFSET(member->offset);
126 : } else {
127 1 : if (member->offset > INT_MAX) {
128 0 : return bf_err_r(-E2BIG, "BTF member offset is too big: %u",
129 : member->offset);
130 : }
131 : offset = (int)member->offset;
132 : }
133 :
134 : break;
135 : }
136 :
137 4 : if (offset < 0 || offset % 8)
138 1 : return -ENOENT;
139 :
140 3 : return offset / 8;
141 : }
|