]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/bpf/coreout.cc
bpf: add preserve_field_info builtin
[thirdparty/gcc.git] / gcc / config / bpf / coreout.cc
CommitLineData
8bdabb37 1/* BPF Compile Once - Run Everywhere (CO-RE) support.
7adcbafe 2 Copyright (C) 2021-2022 Free Software Foundation, Inc.
8bdabb37
DF
3
4 This file is part of GCC.
5
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)
9 any later version.
10
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.
15
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/>. */
19
20#define IN_TARGET_CODE 1
21
22#include "config.h"
23#include "system.h"
24#include "coretypes.h"
25#include "target.h"
26#include "memmodel.h"
27#include "tm_p.h"
28#include "output.h"
29#include "dwarf2asm.h"
30#include "ctfc.h"
31#include "btf.h"
32#include "rtl.h"
33
34#include "coreout.h"
35
36/* This file contains data structures and routines for construction and output
37 of BPF Compile Once - Run Everywhere (BPF CO-RE) information.
38
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:
42
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.
47
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
52 another architecture.
53
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.
57
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.
61
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
67 about the member.
68 - The offset of the appropriate instruction to patch in the BPF program.
69 - An integer specifying what kind of relocation to perform.
70
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
74 instruction.
75
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:
78
79 +------------+
80 | C compiler |
81 +-----+------+
82 | BPF + BTF + CO-RE relocations
83 v
84 +------------+
85 +--->| BPF loader |
86 | +-----+------+
87 | | BPF (adapted)
88 BTF | v
89 | +------------+
90 +----+ Kernel |
91 +------------+
92
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. */
96
97/* Internal representation of a BPF CO-RE relocation record. */
98
99typedef 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
102 string table. */
103 rtx_code_label * bpfcr_insn_label; /* RTX label attached to instruction
104 to patch. */
105 enum btf_core_reloc_kind bpfcr_kind; /* Kind of relocation to perform. */
106} bpf_core_reloc_t;
107
108typedef bpf_core_reloc_t * bpf_core_reloc_ref;
109
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. */
113
114typedef struct GTY (()) bpf_core_section {
115 /* Name of ELF section to which these CO-RE relocations apply. */
116 const char * name;
117
118 /* Offset of section name in .BTF string table. */
119 uint32_t name_offset;
120
121 /* Relocations in the section. */
122 vec <bpf_core_reloc_ref, va_gc> * GTY (()) relocs;
123} bpf_core_section_t;
124
125typedef bpf_core_section_t * bpf_core_section_ref;
126
127/* BTF.ext debug info section. */
128
129static GTY (()) section * btf_ext_info_section;
130
131static int btf_ext_label_num;
132
133#ifndef BTF_EXT_INFO_SECTION_NAME
134#define BTF_EXT_INFO_SECTION_NAME ".BTF.ext"
135#endif
136
137#define BTF_EXT_INFO_SECTION_FLAGS (SECTION_DEBUG)
138
139#define MAX_BTF_EXT_LABEL_BYTES 40
140
141static char btf_ext_info_section_label[MAX_BTF_EXT_LABEL_BYTES];
142
143#ifndef BTF_EXT_INFO_SECTION_LABEL
144#define BTF_EXT_INFO_SECTION_LABEL "Lbtfext"
145#endif
146
147static GTY (()) vec<bpf_core_section_ref, va_gc> *bpf_core_sections;
148
149
150/* Create a new BPF CO-RE relocation record, and add it to the appropriate
151 CO-RE section. */
152
153void
154bpf_core_reloc_add (const tree type, const char * section_name,
068baae1
DF
155 vec<unsigned int> *accessors, rtx_code_label *label,
156 enum btf_core_reloc_kind kind)
8bdabb37
DF
157{
158 char buf[40];
159 unsigned int i, n = 0;
160
161 /* A valid CO-RE access must have at least one accessor. */
162 if (accessors->length () < 1)
163 return;
164
165 for (i = 0; i < accessors->length () - 1; i++)
166 n += snprintf (buf + n, sizeof (buf) - n, "%u:", (*accessors)[i]);
167 snprintf (buf + n, sizeof (buf) - n, "%u", (*accessors)[i]);
168
169 bpf_core_reloc_ref bpfcr = ggc_cleared_alloc<bpf_core_reloc_t> ();
170 ctf_container_ref ctfc = ctf_get_tu_ctfc ();
171
7db42268 172 /* Buffer the access string in the auxiliary strtab. */
8bdabb37 173 ctf_add_string (ctfc, buf, &(bpfcr->bpfcr_astr_off), CTF_AUX_STRTAB);
8bdabb37
DF
174
175 bpfcr->bpfcr_type = get_btf_id (ctf_lookup_tree_type (ctfc, type));
176 bpfcr->bpfcr_insn_label = label;
068baae1 177 bpfcr->bpfcr_kind = kind;
8bdabb37
DF
178
179 /* Add the CO-RE reloc to the appropriate section. */
180 bpf_core_section_ref sec;
181 FOR_EACH_VEC_ELT (*bpf_core_sections, i, sec)
182 if (strcmp (sec->name, section_name) == 0)
183 {
184 vec_safe_push (sec->relocs, bpfcr);
185 return;
186 }
187
188 /* If the CO-RE section does not yet exist, create it. */
189 sec = ggc_cleared_alloc<bpf_core_section_t> ();
190
191 ctf_add_string (ctfc, section_name, &sec->name_offset, CTF_AUX_STRTAB);
8bdabb37
DF
192 if (strcmp (section_name, ""))
193 ctfc->ctfc_aux_strlen += strlen (section_name) + 1;
194
195 sec->name = section_name;
196 vec_alloc (sec->relocs, 1);
197 vec_safe_push (sec->relocs, bpfcr);
198
199 vec_safe_push (bpf_core_sections, sec);
200}
201
202/* Return the 0-based index of the field NODE in its containing struct or union
203 type. */
204
205int
206bpf_core_get_sou_member_index (ctf_container_ref ctfc, const tree node)
207{
208 if (TREE_CODE (node) == FIELD_DECL)
209 {
210 const tree container = DECL_CONTEXT (node);
8bdabb37
DF
211
212 /* Lookup the CTF type info for the containing type. */
213 dw_die_ref die = lookup_type_die (container);
214 if (die == NULL)
215 return -1;
216
217 ctf_dtdef_ref dtd = ctf_dtd_lookup (ctfc, die);
218 if (dtd == NULL)
219 return -1;
220
221 unsigned int kind = CTF_V2_INFO_KIND (dtd->dtd_data.ctti_info);
222 if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
223 return -1;
224
b504149d 225 tree field = TYPE_FIELDS (container);
8bdabb37
DF
226 int i = 0;
227 ctf_dmdef_t * dmd;
228 for (dmd = dtd->dtd_u.dtu_members;
229 dmd != NULL; dmd = (ctf_dmdef_t *) ctf_dmd_list_next (dmd))
230 {
b504149d
DF
231 bool field_has_btf = get_btf_id (dmd->dmd_type) <= BTF_MAX_TYPE;
232
233 if (field == node)
234 return field_has_btf ? i : -1;
235
236 if (field_has_btf)
237 i++;
238
239 field = DECL_CHAIN (field);
8bdabb37
DF
240 }
241 }
242 return -1;
243}
244
245/* Compute and output the header of a .BTF.ext debug info section. */
246
247static void
248output_btfext_header (void)
249{
250 switch_to_section (btf_ext_info_section);
251 ASM_OUTPUT_LABEL (asm_out_file, btf_ext_info_section_label);
252
253 dw2_asm_output_data (2, BTF_MAGIC, "btf_magic");
254 dw2_asm_output_data (1, BTF_VERSION, "btfext_version");
255 dw2_asm_output_data (1, 0, "btfext_flags");
256 dw2_asm_output_data (4, sizeof (struct btf_ext_header), "btfext_hdr_len");
257
258 uint32_t func_info_off = 0, func_info_len = 0;
259 uint32_t line_info_off = 0, line_info_len = 0;
260 uint32_t core_relo_off = 0, core_relo_len = 0;
261
262 /* Header core_relo_len is the sum total length in bytes of all CO-RE
43ec2652 263 relocation sections, plus the 4 byte record size. */
8bdabb37
DF
264 size_t i;
265 bpf_core_section_ref sec;
266 core_relo_len += vec_safe_length (bpf_core_sections)
267 * sizeof (struct btf_ext_section_header);
268
269 FOR_EACH_VEC_ELT (*bpf_core_sections, i, sec)
270 core_relo_len +=
271 vec_safe_length (sec->relocs) * sizeof (struct btf_ext_reloc);
272
43ec2652
DF
273 if (core_relo_len)
274 core_relo_len += sizeof (uint32_t);
275
8bdabb37
DF
276 dw2_asm_output_data (4, func_info_off, "func_info_offset");
277 dw2_asm_output_data (4, func_info_len, "func_info_len");
278
279 dw2_asm_output_data (4, line_info_off, "line_info_offset");
280 dw2_asm_output_data (4, line_info_len, "line_info_len");
281
282 dw2_asm_output_data (4, core_relo_off, "core_relo_offset");
283 dw2_asm_output_data (4, core_relo_len, "core_relo_len");
284}
285
286/* Output a single CO-RE relocation record. */
287
288static void
289output_asm_btfext_core_reloc (bpf_core_reloc_ref bpfcr)
290{
7db42268
DF
291 bpfcr->bpfcr_astr_off += ctfc_get_strtab_len (ctf_get_tu_ctfc (),
292 CTF_STRTAB);
293
8bdabb37
DF
294 dw2_assemble_integer (4, gen_rtx_LABEL_REF (Pmode, bpfcr->bpfcr_insn_label));
295 fprintf (asm_out_file, "\t%s bpfcr_insn\n", ASM_COMMENT_START);
296
297 dw2_asm_output_data (4, bpfcr->bpfcr_type, "bpfcr_type");
298 dw2_asm_output_data (4, bpfcr->bpfcr_astr_off, "bpfcr_astr_off");
299 dw2_asm_output_data (4, bpfcr->bpfcr_kind, "bpfcr_kind");
300}
301
302/* Output all CO-RE relocation records for a section. */
303
304static void
305output_btfext_core_relocs (bpf_core_section_ref sec)
306{
307 size_t i;
308 bpf_core_reloc_ref bpfcr;
309 FOR_EACH_VEC_ELT (*(sec->relocs), i, bpfcr)
310 output_asm_btfext_core_reloc (bpfcr);
311}
312
313/* Output all CO-RE relocation sections. */
314
315static void
316output_btfext_core_sections (void)
317{
318 size_t i;
319 bpf_core_section_ref sec;
43ec2652
DF
320
321 /* BTF Ext section info. */
322 dw2_asm_output_data (4, sizeof (struct btf_ext_reloc),
323 "btfext_core_info_rec_size");
324
8bdabb37
DF
325 FOR_EACH_VEC_ELT (*bpf_core_sections, i, sec)
326 {
8bdabb37
DF
327 /* Section name offset, refers to the offset of a string with the name of
328 the section to which these CORE relocations refer, e.g. '.text'.
329 The string is buffered in the BTF strings table. */
7db42268
DF
330
331 /* BTF specific strings are in CTF_AUX_STRTAB, which is concatenated
332 after CTF_STRTAB. Add the length of STRTAB to the final offset. */
333 sec->name_offset += ctfc_get_strtab_len (ctf_get_tu_ctfc (), CTF_STRTAB);
334
8bdabb37
DF
335 dw2_asm_output_data (4, sec->name_offset, "btfext_secinfo_sec_name_off");
336 dw2_asm_output_data (4, vec_safe_length (sec->relocs),
337 "btfext_secinfo_num_recs");
338
339 output_btfext_core_relocs (sec);
340 }
341}
342
343/* Initialize sections, labels, and data structures for BTF.ext output. */
344
345void
346btf_ext_init (void)
347{
348 btf_ext_info_section = get_section (BTF_EXT_INFO_SECTION_NAME,
349 BTF_EXT_INFO_SECTION_FLAGS, NULL);
350
351 ASM_GENERATE_INTERNAL_LABEL (btf_ext_info_section_label,
352 BTF_EXT_INFO_SECTION_LABEL,
353 btf_ext_label_num++);
354
355 vec_alloc (bpf_core_sections, 1);
356}
357
358/* Output the entire .BTF.ext section. */
359
360void
361btf_ext_output (void)
362{
363 output_btfext_header ();
364 output_btfext_core_sections ();
365
366 bpf_core_sections = NULL;
367}
368
369#include "gt-coreout.h"