Skip to content

Commit 4cedc0d

Browse files
anakryikoAlexei Starovoitov
authored andcommitted
libbpf: add .BTF.ext offset relocation section loading
Add support for BPF CO-RE offset relocations. Add section/record iteration macros for .BTF.ext. These macro are useful for iterating over each .BTF.ext record, either for dumping out contents or later for BPF CO-RE relocation handling. To enable other parts of libbpf to work with .BTF.ext contents, moved a bunch of type definitions into libbpf_internal.h. Signed-off-by: Andrii Nakryiko <[email protected]> Acked-by: Song Liu <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent b03bc68 commit 4cedc0d

File tree

3 files changed

+136
-42
lines changed

3 files changed

+136
-42
lines changed

tools/lib/bpf/btf.c

Lines changed: 27 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -35,47 +35,6 @@ struct btf {
3535
int fd;
3636
};
3737

38-
struct btf_ext_info {
39-
/*
40-
* info points to the individual info section (e.g. func_info and
41-
* line_info) from the .BTF.ext. It does not include the __u32 rec_size.
42-
*/
43-
void *info;
44-
__u32 rec_size;
45-
__u32 len;
46-
};
47-
48-
struct btf_ext {
49-
union {
50-
struct btf_ext_header *hdr;
51-
void *data;
52-
};
53-
struct btf_ext_info func_info;
54-
struct btf_ext_info line_info;
55-
__u32 data_size;
56-
};
57-
58-
struct btf_ext_info_sec {
59-
__u32 sec_name_off;
60-
__u32 num_info;
61-
/* Followed by num_info * record_size number of bytes */
62-
__u8 data[0];
63-
};
64-
65-
/* The minimum bpf_func_info checked by the loader */
66-
struct bpf_func_info_min {
67-
__u32 insn_off;
68-
__u32 type_id;
69-
};
70-
71-
/* The minimum bpf_line_info checked by the loader */
72-
struct bpf_line_info_min {
73-
__u32 insn_off;
74-
__u32 file_name_off;
75-
__u32 line_off;
76-
__u32 line_col;
77-
};
78-
7938
static inline __u64 ptr_to_u64(const void *ptr)
8039
{
8140
return (__u64) (unsigned long) ptr;
@@ -822,6 +781,9 @@ static int btf_ext_setup_info(struct btf_ext *btf_ext,
822781
/* The start of the info sec (including the __u32 record_size). */
823782
void *info;
824783

784+
if (ext_sec->len == 0)
785+
return 0;
786+
825787
if (ext_sec->off & 0x03) {
826788
pr_debug(".BTF.ext %s section is not aligned to 4 bytes\n",
827789
ext_sec->desc);
@@ -925,11 +887,24 @@ static int btf_ext_setup_line_info(struct btf_ext *btf_ext)
925887
return btf_ext_setup_info(btf_ext, &param);
926888
}
927889

890+
static int btf_ext_setup_offset_reloc(struct btf_ext *btf_ext)
891+
{
892+
struct btf_ext_sec_setup_param param = {
893+
.off = btf_ext->hdr->offset_reloc_off,
894+
.len = btf_ext->hdr->offset_reloc_len,
895+
.min_rec_size = sizeof(struct bpf_offset_reloc),
896+
.ext_info = &btf_ext->offset_reloc_info,
897+
.desc = "offset_reloc",
898+
};
899+
900+
return btf_ext_setup_info(btf_ext, &param);
901+
}
902+
928903
static int btf_ext_parse_hdr(__u8 *data, __u32 data_size)
929904
{
930905
const struct btf_ext_header *hdr = (struct btf_ext_header *)data;
931906

932-
if (data_size < offsetof(struct btf_ext_header, func_info_off) ||
907+
if (data_size < offsetofend(struct btf_ext_header, hdr_len) ||
933908
data_size < hdr->hdr_len) {
934909
pr_debug("BTF.ext header not found");
935910
return -EINVAL;
@@ -987,6 +962,9 @@ struct btf_ext *btf_ext__new(__u8 *data, __u32 size)
987962
}
988963
memcpy(btf_ext->data, data, size);
989964

965+
if (btf_ext->hdr->hdr_len <
966+
offsetofend(struct btf_ext_header, line_info_len))
967+
goto done;
990968
err = btf_ext_setup_func_info(btf_ext);
991969
if (err)
992970
goto done;
@@ -995,6 +973,13 @@ struct btf_ext *btf_ext__new(__u8 *data, __u32 size)
995973
if (err)
996974
goto done;
997975

976+
if (btf_ext->hdr->hdr_len <
977+
offsetofend(struct btf_ext_header, offset_reloc_len))
978+
goto done;
979+
err = btf_ext_setup_offset_reloc(btf_ext);
980+
if (err)
981+
goto done;
982+
998983
done:
999984
if (err) {
1000985
btf_ext__free(btf_ext);

tools/lib/bpf/btf.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ struct btf_ext_header {
5858
__u32 func_info_len;
5959
__u32 line_info_off;
6060
__u32 line_info_len;
61+
62+
/* optional part of .BTF.ext header */
63+
__u32 offset_reloc_off;
64+
__u32 offset_reloc_len;
6165
};
6266

6367
LIBBPF_API void btf__free(struct btf *btf);

tools/lib/bpf/libbpf_internal.h

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@
2929
#ifndef max
3030
# define max(x, y) ((x) < (y) ? (y) : (x))
3131
#endif
32+
#ifndef offsetofend
33+
# define offsetofend(TYPE, FIELD) \
34+
(offsetof(TYPE, FIELD) + sizeof(((TYPE *)0)->FIELD))
35+
#endif
3236

3337
extern void libbpf_print(enum libbpf_print_level level,
3438
const char *format, ...)
@@ -46,4 +50,105 @@ do { \
4650
int libbpf__load_raw_btf(const char *raw_types, size_t types_len,
4751
const char *str_sec, size_t str_len);
4852

53+
struct btf_ext_info {
54+
/*
55+
* info points to the individual info section (e.g. func_info and
56+
* line_info) from the .BTF.ext. It does not include the __u32 rec_size.
57+
*/
58+
void *info;
59+
__u32 rec_size;
60+
__u32 len;
61+
};
62+
63+
#define for_each_btf_ext_sec(seg, sec) \
64+
for (sec = (seg)->info; \
65+
(void *)sec < (seg)->info + (seg)->len; \
66+
sec = (void *)sec + sizeof(struct btf_ext_info_sec) + \
67+
(seg)->rec_size * sec->num_info)
68+
69+
#define for_each_btf_ext_rec(seg, sec, i, rec) \
70+
for (i = 0, rec = (void *)&(sec)->data; \
71+
i < (sec)->num_info; \
72+
i++, rec = (void *)rec + (seg)->rec_size)
73+
74+
struct btf_ext {
75+
union {
76+
struct btf_ext_header *hdr;
77+
void *data;
78+
};
79+
struct btf_ext_info func_info;
80+
struct btf_ext_info line_info;
81+
struct btf_ext_info offset_reloc_info;
82+
__u32 data_size;
83+
};
84+
85+
struct btf_ext_info_sec {
86+
__u32 sec_name_off;
87+
__u32 num_info;
88+
/* Followed by num_info * record_size number of bytes */
89+
__u8 data[0];
90+
};
91+
92+
/* The minimum bpf_func_info checked by the loader */
93+
struct bpf_func_info_min {
94+
__u32 insn_off;
95+
__u32 type_id;
96+
};
97+
98+
/* The minimum bpf_line_info checked by the loader */
99+
struct bpf_line_info_min {
100+
__u32 insn_off;
101+
__u32 file_name_off;
102+
__u32 line_off;
103+
__u32 line_col;
104+
};
105+
106+
/* The minimum bpf_offset_reloc checked by the loader
107+
*
108+
* Offset relocation captures the following data:
109+
* - insn_off - instruction offset (in bytes) within a BPF program that needs
110+
* its insn->imm field to be relocated with actual offset;
111+
* - type_id - BTF type ID of the "root" (containing) entity of a relocatable
112+
* offset;
113+
* - access_str_off - offset into corresponding .BTF string section. String
114+
* itself encodes an accessed field using a sequence of field and array
115+
* indicies, separated by colon (:). It's conceptually very close to LLVM's
116+
* getelementptr ([0]) instruction's arguments for identifying offset to
117+
* a field.
118+
*
119+
* Example to provide a better feel.
120+
*
121+
* struct sample {
122+
* int a;
123+
* struct {
124+
* int b[10];
125+
* };
126+
* };
127+
*
128+
* struct sample *s = ...;
129+
* int x = &s->a; // encoded as "0:0" (a is field #0)
130+
* int y = &s->b[5]; // encoded as "0:1:0:5" (anon struct is field #1,
131+
* // b is field #0 inside anon struct, accessing elem #5)
132+
* int z = &s[10]->b; // encoded as "10:1" (ptr is used as an array)
133+
*
134+
* type_id for all relocs in this example will capture BTF type id of
135+
* `struct sample`.
136+
*
137+
* Such relocation is emitted when using __builtin_preserve_access_index()
138+
* Clang built-in, passing expression that captures field address, e.g.:
139+
*
140+
* bpf_probe_read(&dst, sizeof(dst),
141+
* __builtin_preserve_access_index(&src->a.b.c));
142+
*
143+
* In this case Clang will emit offset relocation recording necessary data to
144+
* be able to find offset of embedded `a.b.c` field within `src` struct.
145+
*
146+
* [0] https://llvm.org/docs/LangRef.html#getelementptr-instruction
147+
*/
148+
struct bpf_offset_reloc {
149+
__u32 insn_off;
150+
__u32 type_id;
151+
__u32 access_str_off;
152+
};
153+
49154
#endif /* __LIBBPF_LIBBPF_INTERNAL_H */

0 commit comments

Comments
 (0)