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