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