1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (c) 2020 Facebook */
3
4#include <linux/bpf.h>
5#include <stdint.h>
6#include <bpf/bpf_helpers.h>
7#include <bpf/bpf_core_read.h>
8
9char _license[] SEC("license") = "GPL";
10
11/* fields of exactly the same size */
12struct test_struct___samesize {
13 void *ptr;
14 unsigned long long val1;
15 unsigned int val2;
16 unsigned short val3;
17 unsigned char val4;
18} __attribute((preserve_access_index));
19
20/* unsigned fields that have to be downsized by libbpf */
21struct test_struct___downsize {
22 void *ptr;
23 unsigned long val1;
24 unsigned long val2;
25 unsigned long val3;
26 unsigned long val4;
27 /* total sz: 40 */
28} __attribute__((preserve_access_index));
29
30/* fields with signed integers of wrong size, should be rejected */
31struct test_struct___signed {
32 void *ptr;
33 long val1;
34 long val2;
35 long val3;
36 long val4;
37} __attribute((preserve_access_index));
38
39/* real layout and sizes according to test's (32-bit) BTF */
40struct test_struct___real {
41 unsigned int ptr; /* can't use `void *`, it is always 8 byte in BPF target */
42 unsigned int val2;
43 unsigned long long val1;
44 unsigned short val3;
45 unsigned char val4;
46 unsigned char _pad;
47 /* total sz: 20 */
48};
49
50struct test_struct___real input = {
51 .ptr = 0x01020304,
52 .val1 = 0x1020304050607080,
53 .val2 = 0x0a0b0c0d,
54 .val3 = 0xfeed,
55 .val4 = 0xb9,
56 ._pad = 0xff, /* make sure no accidental zeros are present */
57};
58
59unsigned long long ptr_samesized = 0;
60unsigned long long val1_samesized = 0;
61unsigned long long val2_samesized = 0;
62unsigned long long val3_samesized = 0;
63unsigned long long val4_samesized = 0;
64struct test_struct___real output_samesized = {};
65
66unsigned long long ptr_downsized = 0;
67unsigned long long val1_downsized = 0;
68unsigned long long val2_downsized = 0;
69unsigned long long val3_downsized = 0;
70unsigned long long val4_downsized = 0;
71struct test_struct___real output_downsized = {};
72
73unsigned long long ptr_probed = 0;
74unsigned long long val1_probed = 0;
75unsigned long long val2_probed = 0;
76unsigned long long val3_probed = 0;
77unsigned long long val4_probed = 0;
78
79unsigned long long ptr_signed = 0;
80unsigned long long val1_signed = 0;
81unsigned long long val2_signed = 0;
82unsigned long long val3_signed = 0;
83unsigned long long val4_signed = 0;
84struct test_struct___real output_signed = {};
85
86SEC("raw_tp/sys_exit")
87int handle_samesize(void *ctx)
88{
89 struct test_struct___samesize *in = (void *)&input;
90 struct test_struct___samesize *out = (void *)&output_samesized;
91
92 ptr_samesized = (unsigned long long)in->ptr;
93 val1_samesized = in->val1;
94 val2_samesized = in->val2;
95 val3_samesized = in->val3;
96 val4_samesized = in->val4;
97
98 out->ptr = in->ptr;
99 out->val1 = in->val1;
100 out->val2 = in->val2;
101 out->val3 = in->val3;
102 out->val4 = in->val4;
103
104 return 0;
105}
106
107SEC("raw_tp/sys_exit")
108int handle_downsize(void *ctx)
109{
110 struct test_struct___downsize *in = (void *)&input;
111 struct test_struct___downsize *out = (void *)&output_downsized;
112
113 ptr_downsized = (unsigned long long)in->ptr;
114 val1_downsized = in->val1;
115 val2_downsized = in->val2;
116 val3_downsized = in->val3;
117 val4_downsized = in->val4;
118
119 out->ptr = in->ptr;
120 out->val1 = in->val1;
121 out->val2 = in->val2;
122 out->val3 = in->val3;
123 out->val4 = in->val4;
124
125 return 0;
126}
127
128#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
129#define bpf_core_read_int bpf_core_read
130#else
131#define bpf_core_read_int(dst, sz, src) ({ \
132 /* Prevent "subtraction from stack pointer prohibited" */ \
133 volatile long __off = sizeof(*dst) - (sz); \
134 bpf_core_read((char *)(dst) + __off, sz, src); \
135})
136#endif
137
138SEC("raw_tp/sys_enter")
139int handle_probed(void *ctx)
140{
141 struct test_struct___downsize *in = (void *)&input;
142 __u64 tmp;
143
144 tmp = 0;
145 bpf_core_read_int(&tmp, bpf_core_field_size(in->ptr), &in->ptr);
146 ptr_probed = tmp;
147
148 tmp = 0;
149 bpf_core_read_int(&tmp, bpf_core_field_size(in->val1), &in->val1);
150 val1_probed = tmp;
151
152 tmp = 0;
153 bpf_core_read_int(&tmp, bpf_core_field_size(in->val2), &in->val2);
154 val2_probed = tmp;
155
156 tmp = 0;
157 bpf_core_read_int(&tmp, bpf_core_field_size(in->val3), &in->val3);
158 val3_probed = tmp;
159
160 tmp = 0;
161 bpf_core_read_int(&tmp, bpf_core_field_size(in->val4), &in->val4);
162 val4_probed = tmp;
163
164 return 0;
165}
166
167SEC("raw_tp/sys_enter")
168int handle_signed(void *ctx)
169{
170 struct test_struct___signed *in = (void *)&input;
171 struct test_struct___signed *out = (void *)&output_signed;
172
173 val2_signed = in->val2;
174 val3_signed = in->val3;
175 val4_signed = in->val4;
176
177 out->val2= in->val2;
178 out->val3= in->val3;
179 out->val4= in->val4;
180
181 return 0;
182}
183

source code of linux/tools/testing/selftests/bpf/progs/test_core_autosize.c