]>
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 | ||
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 */ | |
0316fb52 | 30 | #include "bpf-helpers.h" |
b26e2ae7 JM |
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 | |
81e6e8ae | 208 | bpf_def_model_init (void) |
b26e2ae7 JM |
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 | }; |