xref: /openbmc/linux/tools/lib/bpf/relo_core.h (revision 3c8c1539)
1 /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2 /* Copyright (c) 2019 Facebook */
3 
4 #ifndef __RELO_CORE_H
5 #define __RELO_CORE_H
6 
7 /* bpf_core_relo_kind encodes which aspect of captured field/type/enum value
8  * has to be adjusted by relocations.
9  */
10 enum bpf_core_relo_kind {
11 	BPF_FIELD_BYTE_OFFSET = 0,	/* field byte offset */
12 	BPF_FIELD_BYTE_SIZE = 1,	/* field size in bytes */
13 	BPF_FIELD_EXISTS = 2,		/* field existence in target kernel */
14 	BPF_FIELD_SIGNED = 3,		/* field signedness (0 - unsigned, 1 - signed) */
15 	BPF_FIELD_LSHIFT_U64 = 4,	/* bitfield-specific left bitshift */
16 	BPF_FIELD_RSHIFT_U64 = 5,	/* bitfield-specific right bitshift */
17 	BPF_TYPE_ID_LOCAL = 6,		/* type ID in local BPF object */
18 	BPF_TYPE_ID_TARGET = 7,		/* type ID in target kernel */
19 	BPF_TYPE_EXISTS = 8,		/* type existence in target kernel */
20 	BPF_TYPE_SIZE = 9,		/* type size in bytes */
21 	BPF_ENUMVAL_EXISTS = 10,	/* enum value existence in target kernel */
22 	BPF_ENUMVAL_VALUE = 11,		/* enum value integer value */
23 };
24 
25 /* The minimum bpf_core_relo checked by the loader
26  *
27  * CO-RE relocation captures the following data:
28  * - insn_off - instruction offset (in bytes) within a BPF program that needs
29  *   its insn->imm field to be relocated with actual field info;
30  * - type_id - BTF type ID of the "root" (containing) entity of a relocatable
31  *   type or field;
32  * - access_str_off - offset into corresponding .BTF string section. String
33  *   interpretation depends on specific relocation kind:
34  *     - for field-based relocations, string encodes an accessed field using
35  *     a sequence of field and array indices, separated by colon (:). It's
36  *     conceptually very close to LLVM's getelementptr ([0]) instruction's
37  *     arguments for identifying offset to a field.
38  *     - for type-based relocations, strings is expected to be just "0";
39  *     - for enum value-based relocations, string contains an index of enum
40  *     value within its enum type;
41  *
42  * Example to provide a better feel.
43  *
44  *   struct sample {
45  *       int a;
46  *       struct {
47  *           int b[10];
48  *       };
49  *   };
50  *
51  *   struct sample *s = ...;
52  *   int x = &s->a;     // encoded as "0:0" (a is field #0)
53  *   int y = &s->b[5];  // encoded as "0:1:0:5" (anon struct is field #1,
54  *                      // b is field #0 inside anon struct, accessing elem #5)
55  *   int z = &s[10]->b; // encoded as "10:1" (ptr is used as an array)
56  *
57  * type_id for all relocs in this example  will capture BTF type id of
58  * `struct sample`.
59  *
60  * Such relocation is emitted when using __builtin_preserve_access_index()
61  * Clang built-in, passing expression that captures field address, e.g.:
62  *
63  * bpf_probe_read(&dst, sizeof(dst),
64  *		  __builtin_preserve_access_index(&src->a.b.c));
65  *
66  * In this case Clang will emit field relocation recording necessary data to
67  * be able to find offset of embedded `a.b.c` field within `src` struct.
68  *
69  *   [0] https://llvm.org/docs/LangRef.html#getelementptr-instruction
70  */
71 struct bpf_core_relo {
72 	__u32   insn_off;
73 	__u32   type_id;
74 	__u32   access_str_off;
75 	enum bpf_core_relo_kind kind;
76 };
77 
78 struct bpf_core_cand {
79 	const struct btf *btf;
80 	const struct btf_type *t;
81 	const char *name;
82 	__u32 id;
83 };
84 
85 /* dynamically sized list of type IDs and its associated struct btf */
86 struct bpf_core_cand_list {
87 	struct bpf_core_cand *cands;
88 	int len;
89 };
90 
91 int bpf_core_apply_relo_insn(const char *prog_name,
92 			     struct bpf_insn *insn, int insn_idx,
93 			     const struct bpf_core_relo *relo, int relo_idx,
94 			     const struct btf *local_btf,
95 			     struct bpf_core_cand_list *cands);
96 int bpf_core_types_are_compat(const struct btf *local_btf, __u32 local_id,
97 			      const struct btf *targ_btf, __u32 targ_id);
98 
99 size_t bpf_core_essential_name_len(const char *name);
100 #endif
101