1 /* BPF Compile Once - Run Everywhere (CO-RE) support.
2 Copyright (C) 2021 Free Software Foundation, Inc.
4 This file is part of GCC.
6 GCC is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
11 GCC is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3. If not see
18 <http://www.gnu.org/licenses/>. */
20 #define IN_TARGET_CODE 1
24 #include "coretypes.h"
29 #include "dwarf2asm.h"
36 /* This file contains data structures and routines for construction and output
37 of BPF Compile Once - Run Everywhere (BPF CO-RE) information.
39 eBPF programs written in C usually include Linux kernel headers, so that
40 they may interact with kernel data structures in a useful way. This
41 intrudces two major portability issues:
43 1. Kernel data structures regularly change, with fields added, moved or
44 deleted between versions. An eBPF program cannot in general be expected
45 to run on any systems which does not share an identical kernel version to
46 the system on which it was compiled.
48 2. Included kernel headers (and used data structures) may be internal, not
49 exposed in an userspace API, and therefore target-specific. An eBPF
50 program compiled on an x86_64 machine will include x86_64 kernel headers.
51 The resulting program may not run well (or at all) in machines of
54 BPF CO-RE is designed to solve the first issue by leveraging the BPF loader
55 to adjust references to kernel data structures made by the program as-needed
56 according to versions of structures actually present on the host kernel.
58 To achieve this, additional information is placed in a ".BTF.ext" section.
59 This information tells the loader which references will require adjusting,
60 and how to perform each necessary adjustment.
62 For any access to a data structure which may require load-time adjustment,
63 the following information is recorded (making up a CO-RE relocation record):
64 - The BTF type ID of the outermost structure which is accessed.
65 - An access string encoding the accessed member via a series of member and
66 array indexes. These indexes are used to look up detailed BTF information
68 - The offset of the appropriate instruction to patch in the BPF program.
69 - An integer specifying what kind of relocation to perform.
71 A CO-RE-capable BPF loader reads this information together with the BTF
72 information of the program, compares it against BTF information of the host
73 kernel, and determines the appropriate way to patch the specified
76 Once all CO-RE relocations are resolved, the program is loaded and verified
77 as usual. The process can be summarized with the following diagram:
82 | BPF + BTF + CO-RE relocations
93 Note that a single ELF object may contain multiple eBPF programs. As a
94 result, a single .BTF.ext section can contain CO-RE relocations for multiple
95 programs in distinct sections. */
97 /* Internal representation of a BPF CO-RE relocation record. */
99 typedef struct GTY (()) bpf_core_reloc
{
100 unsigned int bpfcr_type
; /* BTF type ID of container. */
101 unsigned int bpfcr_astr_off
; /* Offset of access string in .BTF
103 rtx_code_label
* bpfcr_insn_label
; /* RTX label attached to instruction
105 enum btf_core_reloc_kind bpfcr_kind
; /* Kind of relocation to perform. */
108 typedef bpf_core_reloc_t
* bpf_core_reloc_ref
;
110 /* Internal representation of a CO-RE relocation (sub)section of the
111 .BTF.ext information. One such section is generated for each ELF section
112 in the output object having relocations that a BPF loader must resolve. */
114 typedef struct GTY (()) bpf_core_section
{
115 /* Name of ELF section to which these CO-RE relocations apply. */
118 /* Offset of section name in .BTF string table. */
119 uint32_t name_offset
;
121 /* Relocations in the section. */
122 vec
<bpf_core_reloc_ref
, va_gc
> * GTY (()) relocs
;
123 } bpf_core_section_t
;
125 typedef bpf_core_section_t
* bpf_core_section_ref
;
127 /* BTF.ext debug info section. */
129 static GTY (()) section
* btf_ext_info_section
;
131 static int btf_ext_label_num
;
133 #ifndef BTF_EXT_INFO_SECTION_NAME
134 #define BTF_EXT_INFO_SECTION_NAME ".BTF.ext"
137 #define BTF_EXT_INFO_SECTION_FLAGS (SECTION_DEBUG)
139 #define MAX_BTF_EXT_LABEL_BYTES 40
141 static char btf_ext_info_section_label
[MAX_BTF_EXT_LABEL_BYTES
];
143 #ifndef BTF_EXT_INFO_SECTION_LABEL
144 #define BTF_EXT_INFO_SECTION_LABEL "Lbtfext"
147 static GTY (()) vec
<bpf_core_section_ref
, va_gc
> *bpf_core_sections
;
150 /* Create a new BPF CO-RE relocation record, and add it to the appropriate
154 bpf_core_reloc_add (const tree type
, const char * section_name
,
155 vec
<unsigned int> *accessors
, rtx_code_label
*label
)
158 unsigned int i
, n
= 0;
160 /* A valid CO-RE access must have at least one accessor. */
161 if (accessors
->length () < 1)
164 for (i
= 0; i
< accessors
->length () - 1; i
++)
165 n
+= snprintf (buf
+ n
, sizeof (buf
) - n
, "%u:", (*accessors
)[i
]);
166 snprintf (buf
+ n
, sizeof (buf
) - n
, "%u", (*accessors
)[i
]);
168 bpf_core_reloc_ref bpfcr
= ggc_cleared_alloc
<bpf_core_reloc_t
> ();
169 ctf_container_ref ctfc
= ctf_get_tu_ctfc ();
171 /* Buffer the access string in the auxiliary strtab. Since the two string
172 tables are concatenated, add the length of the first to the offset. */
173 size_t strtab_len
= ctfc_get_strtab_len (ctfc
, CTF_STRTAB
);
174 ctf_add_string (ctfc
, buf
, &(bpfcr
->bpfcr_astr_off
), CTF_AUX_STRTAB
);
175 bpfcr
->bpfcr_astr_off
+= strtab_len
;
177 bpfcr
->bpfcr_type
= get_btf_id (ctf_lookup_tree_type (ctfc
, type
));
178 bpfcr
->bpfcr_insn_label
= label
;
179 bpfcr
->bpfcr_kind
= BPF_RELO_FIELD_BYTE_OFFSET
;
181 /* Add the CO-RE reloc to the appropriate section. */
182 bpf_core_section_ref sec
;
183 FOR_EACH_VEC_ELT (*bpf_core_sections
, i
, sec
)
184 if (strcmp (sec
->name
, section_name
) == 0)
186 vec_safe_push (sec
->relocs
, bpfcr
);
190 /* If the CO-RE section does not yet exist, create it. */
191 sec
= ggc_cleared_alloc
<bpf_core_section_t
> ();
193 ctf_add_string (ctfc
, section_name
, &sec
->name_offset
, CTF_AUX_STRTAB
);
194 sec
->name_offset
+= strtab_len
;
195 if (strcmp (section_name
, ""))
196 ctfc
->ctfc_aux_strlen
+= strlen (section_name
) + 1;
198 sec
->name
= section_name
;
199 vec_alloc (sec
->relocs
, 1);
200 vec_safe_push (sec
->relocs
, bpfcr
);
202 vec_safe_push (bpf_core_sections
, sec
);
205 /* Return the 0-based index of the field NODE in its containing struct or union
209 bpf_core_get_sou_member_index (ctf_container_ref ctfc
, const tree node
)
211 if (TREE_CODE (node
) == FIELD_DECL
)
213 const tree container
= DECL_CONTEXT (node
);
214 const char * name
= IDENTIFIER_POINTER (DECL_NAME (node
));
216 /* Lookup the CTF type info for the containing type. */
217 dw_die_ref die
= lookup_type_die (container
);
221 ctf_dtdef_ref dtd
= ctf_dtd_lookup (ctfc
, die
);
225 unsigned int kind
= CTF_V2_INFO_KIND (dtd
->dtd_data
.ctti_info
);
226 if (kind
!= CTF_K_STRUCT
&& kind
!= CTF_K_UNION
)
231 for (dmd
= dtd
->dtd_u
.dtu_members
;
232 dmd
!= NULL
; dmd
= (ctf_dmdef_t
*) ctf_dmd_list_next (dmd
))
234 if (get_btf_id (dmd
->dmd_type
) > BTF_MAX_TYPE
)
236 if (strcmp (dmd
->dmd_name
, name
) == 0)
244 /* Compute and output the header of a .BTF.ext debug info section. */
247 output_btfext_header (void)
249 switch_to_section (btf_ext_info_section
);
250 ASM_OUTPUT_LABEL (asm_out_file
, btf_ext_info_section_label
);
252 dw2_asm_output_data (2, BTF_MAGIC
, "btf_magic");
253 dw2_asm_output_data (1, BTF_VERSION
, "btfext_version");
254 dw2_asm_output_data (1, 0, "btfext_flags");
255 dw2_asm_output_data (4, sizeof (struct btf_ext_header
), "btfext_hdr_len");
257 uint32_t func_info_off
= 0, func_info_len
= 0;
258 uint32_t line_info_off
= 0, line_info_len
= 0;
259 uint32_t core_relo_off
= 0, core_relo_len
= 0;
261 /* Header core_relo_len is the sum total length in bytes of all CO-RE
262 relocation sections. */
264 bpf_core_section_ref sec
;
265 core_relo_len
+= vec_safe_length (bpf_core_sections
)
266 * sizeof (struct btf_ext_section_header
);
268 FOR_EACH_VEC_ELT (*bpf_core_sections
, i
, sec
)
270 vec_safe_length (sec
->relocs
) * sizeof (struct btf_ext_reloc
);
272 dw2_asm_output_data (4, func_info_off
, "func_info_offset");
273 dw2_asm_output_data (4, func_info_len
, "func_info_len");
275 dw2_asm_output_data (4, line_info_off
, "line_info_offset");
276 dw2_asm_output_data (4, line_info_len
, "line_info_len");
278 dw2_asm_output_data (4, core_relo_off
, "core_relo_offset");
279 dw2_asm_output_data (4, core_relo_len
, "core_relo_len");
282 /* Output a single CO-RE relocation record. */
285 output_asm_btfext_core_reloc (bpf_core_reloc_ref bpfcr
)
287 dw2_assemble_integer (4, gen_rtx_LABEL_REF (Pmode
, bpfcr
->bpfcr_insn_label
));
288 fprintf (asm_out_file
, "\t%s bpfcr_insn\n", ASM_COMMENT_START
);
290 dw2_asm_output_data (4, bpfcr
->bpfcr_type
, "bpfcr_type");
291 dw2_asm_output_data (4, bpfcr
->bpfcr_astr_off
, "bpfcr_astr_off");
292 dw2_asm_output_data (4, bpfcr
->bpfcr_kind
, "bpfcr_kind");
295 /* Output all CO-RE relocation records for a section. */
298 output_btfext_core_relocs (bpf_core_section_ref sec
)
301 bpf_core_reloc_ref bpfcr
;
302 FOR_EACH_VEC_ELT (*(sec
->relocs
), i
, bpfcr
)
303 output_asm_btfext_core_reloc (bpfcr
);
306 /* Output all CO-RE relocation sections. */
309 output_btfext_core_sections (void)
312 bpf_core_section_ref sec
;
313 FOR_EACH_VEC_ELT (*bpf_core_sections
, i
, sec
)
315 /* BTF Ext section info. */
316 dw2_asm_output_data (4, sizeof (struct btf_ext_reloc
),
317 "btfext_secinfo_rec_size");
319 /* Section name offset, refers to the offset of a string with the name of
320 the section to which these CORE relocations refer, e.g. '.text'.
321 The string is buffered in the BTF strings table. */
322 dw2_asm_output_data (4, sec
->name_offset
, "btfext_secinfo_sec_name_off");
323 dw2_asm_output_data (4, vec_safe_length (sec
->relocs
),
324 "btfext_secinfo_num_recs");
326 output_btfext_core_relocs (sec
);
330 /* Initialize sections, labels, and data structures for BTF.ext output. */
335 btf_ext_info_section
= get_section (BTF_EXT_INFO_SECTION_NAME
,
336 BTF_EXT_INFO_SECTION_FLAGS
, NULL
);
338 ASM_GENERATE_INTERNAL_LABEL (btf_ext_info_section_label
,
339 BTF_EXT_INFO_SECTION_LABEL
,
340 btf_ext_label_num
++);
342 vec_alloc (bpf_core_sections
, 1);
345 /* Output the entire .BTF.ext section. */
348 btf_ext_output (void)
350 output_btfext_header ();
351 output_btfext_core_sections ();
353 bpf_core_sections
= NULL
;
356 #include "gt-coreout.h"