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