]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/bpf/bpf.c
bpf: several small fixes in the simulator
[thirdparty/binutils-gdb.git] / sim / bpf / bpf.c
1 /* eBPF simulator support code
2 Copyright (C) 2020 Free Software Foundation, Inc.
3
4 This file is part of GDB, the GNU debugger.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
18
19 #define WANT_CPU_BPFBF
20 #define WANT_CPU bpfbf
21
22 #include "sim-main.h"
23 #include "sim-fpu.h"
24 #include "cgen-mem.h"
25 #include "cgen-ops.h"
26 #include "cpuall.h"
27 #include "decode.h"
28
29 #include "defs-le.h" /* For SCACHE */
30 #include "bpf-helpers.h"
31
32 /* It is not possible to include both defs-le.h and defs-be.h due to
33 duplicated definitions, so we need a bunch of forward declarations
34 here. */
35 extern void bpfbf_ebpfle_init_idesc_table (SIM_CPU *);
36 extern void bpfbf_ebpfbe_init_idesc_table (SIM_CPU *);
37
38 uint64_t skb_data_offset;
39
40 IDESC *bpf_idesc_le;
41 IDESC *bpf_idesc_be;
42
43
44 int
45 bpfbf_fetch_register (SIM_CPU *current_cpu,
46 int rn,
47 unsigned char *buf,
48 int len)
49 {
50 if (rn == 11)
51 SETTDI (buf, CPU_PC_GET (current_cpu));
52 else if (0 <= rn && rn < 10)
53 SETTDI (buf, GET_H_GPR (rn));
54 else
55 return 0;
56
57 return len;
58 }
59
60 int
61 bpfbf_store_register (SIM_CPU *current_cpu,
62 int rn,
63 unsigned char *buf,
64 int len)
65 {
66 if (rn == 11)
67 CPU_PC_SET (current_cpu, GETTDI (buf));
68 else if (0 <= rn && rn < 10)
69 SET_H_GPR (rn, GETTDI (buf));
70 else
71 return 0;
72
73 return len;
74 }
75
76 void
77 bpfbf_model_insn_before (SIM_CPU *current_cpu, int first_p)
78 {
79 /* XXX */
80 }
81
82 void
83 bpfbf_model_insn_after (SIM_CPU *current_cpu, int first_p)
84 {
85 /* XXX */
86 }
87
88 \f
89 /***** Instruction helpers. *****/
90
91 /* The semantic routines for most instructions are expressed in RTL in
92 the cpu/bpf.cpu file, and automatically translated to C in the
93 sem-*.c files in this directory.
94
95 However, some of the semantic routines make use of helper C
96 functions. This happens when the semantics of the instructions
97 can't be expressed in RTL alone in a satisfactory way, or not at
98 all.
99
100 The following functions implement these C helpers. */
101
102 DI
103 bpfbf_endle (SIM_CPU *current_cpu, DI value, UINT bitsize)
104 {
105 switch (bitsize)
106 {
107 case 16: return endian_h2le_2(endian_t2h_2(value));
108 case 32: return endian_h2le_4(endian_t2h_4(value));
109 case 64: return endian_h2le_8(endian_t2h_8(value));
110 default: assert(0);
111 }
112 return value;
113 }
114
115 DI
116 bpfbf_endbe (SIM_CPU *current_cpu, DI value, UINT bitsize)
117 {
118 switch (bitsize)
119 {
120 case 16: return endian_h2be_2(endian_t2h_2(value));
121 case 32: return endian_h2be_4(endian_t2h_4(value));
122 case 64: return endian_h2be_8(endian_t2h_8(value));
123 default: assert(0);
124 }
125 return value;
126 }
127
128 DI
129 bpfbf_skb_data_offset (SIM_CPU *current_cpu)
130 {
131 /* Simply return the user-configured value.
132 This will be 0 if it has not been set. */
133 return skb_data_offset;
134 }
135
136
137 VOID
138 bpfbf_call (SIM_CPU *current_cpu, INT disp32, UINT src)
139 {
140 /* eBPF supports two kind of CALL instructions: the so called pseudo
141 calls ("bpf to bpf") and external calls ("bpf to helper").
142
143 Both kind of calls use the same instruction (CALL). However,
144 external calls are constructed by passing a constant argument to
145 the instruction, that identifies the helper, whereas pseudo calls
146 result from expressions involving symbols.
147
148 We distinguish calls from pseudo-calls with the later having a 1
149 stored in the SRC field of the instruction. */
150
151 if (src == 1)
152 {
153 /* This is a pseudo-call. */
154
155 /* XXX allocate a new stack frame and transfer control. For
156 that we need to analyze the target function, like the kernel
157 verifier does. We better populate a cache
158 (function_start_address -> frame_size) so we avoid
159 calculating this more than once. */
160 /* XXX note that disp32 is PC-relative in number of 64-bit
161 words, _minus one_. */
162 }
163 else
164 {
165 /* This is a call to a helper.
166
167 DISP32 contains the helper number. Dispatch to the
168 corresponding helper emulator in bpf-helpers.c. */
169
170 switch (disp32) {
171 /* case TRACE_PRINTK: */
172 case 7:
173 bpf_trace_printk (current_cpu);
174 break;
175 default:;
176 }
177 }
178 }
179
180 VOID
181 bpfbf_exit (SIM_CPU *current_cpu)
182 {
183 SIM_DESC sd = CPU_STATE (current_cpu);
184
185 /* r0 holds "return code" */
186 DI r0 = GET_H_GPR (0);
187
188 printf ("exit %ld (0x%lx)\n", r0, r0);
189
190 sim_engine_halt (sd, current_cpu, NULL, CPU_PC_GET (current_cpu),
191 sim_exited, 0 /* sigrc */);
192 }
193
194 VOID
195 bpfbf_breakpoint (SIM_CPU *current_cpu)
196 {
197 SIM_DESC sd = CPU_STATE (current_cpu);
198
199 sim_engine_halt (sd, current_cpu, NULL, CPU_PC_GET (current_cpu),
200 sim_stopped, SIM_SIGTRAP);
201 }
202
203 /* We use the definitions below instead of the cgen-generated model.c,
204 because the later is not really able to work with cpus featuring
205 several ISAs. This should be fixed in CGEN. */
206
207 static void
208 bpf_def_model_init ()
209 {
210 /* Do nothing. */
211 }
212
213 static void
214 bpfbf_prepare_run (SIM_CPU *cpu)
215 {
216 /* Nothing. */
217 }
218
219 void
220 bpf_engine_run_full (SIM_CPU *cpu)
221 {
222 if (current_target_byte_order == BFD_ENDIAN_LITTLE)
223 {
224 if (!bpf_idesc_le)
225 {
226 bpfbf_ebpfle_init_idesc_table (cpu);
227 bpf_idesc_le = CPU_IDESC (cpu);
228 }
229 else
230 CPU_IDESC (cpu) = bpf_idesc_le;
231
232 bpfbf_ebpfle_engine_run_full (cpu);
233 }
234 else
235 {
236 if (!bpf_idesc_be)
237 {
238 bpfbf_ebpfbe_init_idesc_table (cpu);
239 bpf_idesc_be = CPU_IDESC (cpu);
240 }
241 else
242 CPU_IDESC (cpu) = bpf_idesc_be;
243
244 bpfbf_ebpfbe_engine_run_full (cpu);
245 }
246 }
247
248 #if WITH_FAST
249
250 void
251 bpf_engine_run_fast (SIM_CPU *cpu)
252 {
253 if (current_target_byte_order == BFD_ENDIAN_LITTLE)
254 {
255 if (!bpf_idesc_le)
256 {
257 bpfbf_ebpfle_init_idesc_table (cpu);
258 bpf_idesc_le = CPU_IDESC (cpu);
259 }
260 else
261 CPU_IDESC (cpu) = bpf_idesc_le;
262
263 bpfbf_ebpfle_engine_run_fast (cpu);
264 }
265 else
266 {
267 if (!bpf_idesc_be)
268 {
269 bpfbf_ebpfbe_init_idesc_table (cpu);
270 bpf_idesc_be = CPU_IDESC (cpu);
271 }
272 else
273 CPU_IDESC (cpu) = bpf_idesc_be;
274
275 bpfbf_ebpfbe_engine_run_fast (cpu);
276 }
277 }
278
279 #endif /* WITH_FAST */
280
281 static const CGEN_INSN *
282 bpfbf_get_idata (SIM_CPU *cpu, int inum)
283 {
284 return CPU_IDESC (cpu) [inum].idata;
285 }
286
287 static void
288 bpf_init_cpu (SIM_CPU *cpu)
289 {
290 CPU_REG_FETCH (cpu) = bpfbf_fetch_register;
291 CPU_REG_STORE (cpu) = bpfbf_store_register;
292 CPU_PC_FETCH (cpu) = bpfbf_h_pc_get;
293 CPU_PC_STORE (cpu) = bpfbf_h_pc_set;
294 CPU_GET_IDATA (cpu) = bpfbf_get_idata;
295 /* Only used by profiling. 0 disables it. */
296 CPU_MAX_INSNS (cpu) = 0;
297 CPU_INSN_NAME (cpu) = cgen_insn_name;
298 CPU_FULL_ENGINE_FN (cpu) = bpf_engine_run_full;
299 #if WITH_FAST
300 CPU_FAST_ENGINE_FN (cpu) = bpf_engine_run_fast;
301 #else
302 CPU_FAST_ENGINE_FN (cpu) = bpf_engine_run_full;
303 #endif
304 }
305
306 static const SIM_MODEL bpf_models[] =
307 {
308 { "bpf-def", & bpf_mach, MODEL_BPF_DEF, NULL, bpf_def_model_init },
309 { 0 }
310 };
311
312 static const SIM_MACH_IMP_PROPERTIES bpfbf_imp_properties =
313 {
314 sizeof (SIM_CPU),
315 #if WITH_SCACHE
316 sizeof (SCACHE)
317 #else
318 0
319 #endif
320 };
321
322 const SIM_MACH bpf_mach =
323 {
324 "bpf", "bpf", MACH_BPF,
325 32, 32, & bpf_models[0], & bpfbf_imp_properties,
326 bpf_init_cpu,
327 bpfbf_prepare_run
328 };