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 6 : int bf_btf_get_field_off(const char *struct_name, const char *field_name)
63 : {
64 : int offset = -1;
65 : int struct_id;
66 : struct btf_member *member;
67 : const struct btf_type *type;
68 :
69 6 : struct_id = btf__find_by_name_kind(_bf_btf, struct_name, BTF_KIND_STRUCT);
70 6 : if (struct_id < 0) {
71 2 : return bf_err_r(struct_id, "can't find structure '%s' in kernel BTF",
72 : struct_name);
73 : }
74 :
75 4 : type = btf__type_by_id(_bf_btf, struct_id);
76 4 : if (!type)
77 0 : return bf_err_r(errno, "can't get btf_type for '%s'", struct_name);
78 :
79 4 : member = (struct btf_member *)(type + 1);
80 22 : for (size_t i = 0; i < BTF_INFO_VLEN(type->info); ++i, ++member) {
81 21 : const char *cur_name = btf__name_by_offset(_bf_btf, member->name_off);
82 21 : if (!cur_name || !bf_streq(cur_name, field_name))
83 : continue;
84 :
85 3 : if (BTF_INFO_KFLAG(type->info)) {
86 2 : offset = BTF_MEMBER_BIT_OFFSET(member->offset);
87 : } else {
88 1 : if (member->offset > INT_MAX) {
89 0 : return bf_err_r(-E2BIG, "BTF member offset is too big: %u",
90 : member->offset);
91 : }
92 : offset = (int)member->offset;
93 : }
94 :
95 : break;
96 : }
97 :
98 4 : if (offset < 0 || offset % 8)
99 1 : return -ENOENT;
100 :
101 3 : return offset / 8;
102 : }
|