1 /* Disassembler for BPF.
2 Copyright (C) 2016, 2018 Red Hat, Inc.
3 This file is part of elfutils.
4
5 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
7
8 * the GNU Lesser General Public License as published by the Free
9 Software Foundation; either version 3 of the License, or (at
10 your option) any later version
11
12 or
13
14 * the GNU General Public License as published by the Free
15 Software Foundation; either version 2 of the License, or (at
16 your option) any later version
17
18 or both in parallel, as here.
19
20 elfutils is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 General Public License for more details.
24
25 You should have received copies of the GNU General Public License and
26 the GNU Lesser General Public License along with this program. If
27 not, see <http://www.gnu.org/licenses/>. */
28
29 #ifdef HAVE_CONFIG_H
30 # include <config.h>
31 #endif
32
33 #include <assert.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include <gelf.h>
37 #include <inttypes.h>
38 #include "bpf.h"
39
40 #include "../libelf/common.h"
41 #include "../libebl/libeblP.h"
42
43 static const char class_string[8][8] = {
44 [BPF_LD] = "ld",
45 [BPF_LDX] = "ldx",
46 [BPF_ST] = "st",
47 [BPF_STX] = "stx",
48 [BPF_ALU] = "alu",
49 [BPF_JMP] = "jmp",
50 [BPF_RET] = "6", /* completely unused in ebpf */
51 [BPF_ALU64] = "alu64",
52 };
53
54
55 #define REG(N) "r%" #N "$d"
56 #define REGU(N) "(u32)" REG(N)
57 #define REGS(N) "(s64)" REG(N)
58
59 #define IMMS(N) "%" #N "$d"
60 #define IMMX(N) "%" #N "$#x"
61
62 #define OFF(N) "%" #N "$+d"
63 #define JMP(N) "%" #N "$#x"
64
65 #define A32(O, S) REG(1) " = " REGU(1) " " #O " " S
66 #define A64(O, S) REG(1) " " #O "= " S
67 #define J64(D, O, S) "if " D " " #O " " S " goto " JMP(3)
68 #define LOAD(T) REG(1) " = *(" #T " *)(" REG(2) OFF(3) ")"
69 #define STORE(T, S) "*(" #T " *)(" REG(1) OFF(3) ") = " S
70 #define XADD(T, S) "lock *(" #T " *)(" REG(1) OFF(3) ") += " S
71 #define LDSKB(T, S) "r0 = *(" #T " *)skb[" S "]"
72
73 static void
bswap_bpf_insn(struct bpf_insn * p)74 bswap_bpf_insn (struct bpf_insn *p)
75 {
76 /* Note that the dst_reg and src_reg fields are 4-bit bitfields.
77 That means these two nibbles are (typically) layed out in the
78 opposite order between big- and little-endian hosts. This is
79 not required by any standard, but does happen to be true for
80 at least ppc, s390, arm and mips as big-endian hosts. */
81 int t = p->dst_reg;
82 p->dst_reg = p->src_reg;
83 p->src_reg = t;
84
85 /* The other 2 and 4 byte fields are trivially converted. */
86 CONVERT (p->off);
87 CONVERT (p->imm);
88 }
89
90 int
bpf_disasm(Ebl * ebl,const uint8_t ** startp,const uint8_t * end,GElf_Addr addr,const char * fmt,DisasmOutputCB_t outcb,DisasmGetSymCB_t symcb,void * outcbarg,void * symcbarg)91 bpf_disasm (Ebl *ebl, const uint8_t **startp, const uint8_t *end,
92 GElf_Addr addr, const char *fmt __attribute__((unused)),
93 DisasmOutputCB_t outcb,
94 DisasmGetSymCB_t symcb __attribute__((unused)),
95 void *outcbarg,
96 void *symcbarg __attribute__((unused)))
97 {
98 const bool need_bswap = MY_ELFDATA != ebl->data;
99 const uint8_t *start = *startp;
100 char buf[128];
101 int len, retval = 0;
102
103 while (start + sizeof(struct bpf_insn) <= end)
104 {
105 struct bpf_insn i;
106 unsigned code, class, jmp;
107 const char *code_fmt;
108
109 memcpy(&i, start, sizeof(struct bpf_insn));
110 if (need_bswap)
111 bswap_bpf_insn (&i);
112
113 start += sizeof(struct bpf_insn);
114 addr += sizeof(struct bpf_insn);
115 jmp = addr + i.off * sizeof(struct bpf_insn);
116
117 code = i.code;
118 switch (code)
119 {
120 case BPF_LD | BPF_IMM | BPF_DW:
121 {
122 struct bpf_insn i2;
123 uint64_t imm64;
124
125 if (start + sizeof(struct bpf_insn) > end)
126 {
127 start -= sizeof(struct bpf_insn);
128 *startp = start;
129 goto done;
130 }
131 memcpy(&i2, start, sizeof(struct bpf_insn));
132 if (need_bswap)
133 bswap_bpf_insn (&i2);
134 start += sizeof(struct bpf_insn);
135 addr += sizeof(struct bpf_insn);
136
137 imm64 = (uint32_t)i.imm | ((uint64_t)i2.imm << 32);
138 switch (i.src_reg)
139 {
140 case 0:
141 code_fmt = REG(1) " = %2$#" PRIx64;
142 break;
143 case BPF_PSEUDO_MAP_FD:
144 code_fmt = REG(1) " = map_fd(%2$#" PRIx64 ")";
145 break;
146 default:
147 code_fmt = REG(1) " = ld_pseudo(%3$d, %2$#" PRIx64 ")";
148 break;
149 }
150 len = snprintf(buf, sizeof(buf), code_fmt,
151 i.dst_reg, imm64, i.src_reg);
152 }
153 break;
154
155 case BPF_JMP | BPF_EXIT:
156 len = snprintf(buf, sizeof(buf), "exit");
157 break;
158 case BPF_JMP | BPF_JA:
159 len = snprintf(buf, sizeof(buf), "goto " JMP(1), jmp);
160 break;
161 case BPF_JMP | BPF_CALL:
162 code_fmt = "call " IMMS(1);
163 goto do_imm;
164
165 case BPF_ALU | BPF_END | BPF_TO_LE:
166 /* The imm field contains {16,32,64}. */
167 code_fmt = REG(1) " = le" IMMS(2) "(" REG(1) ")";
168 goto do_dst_imm;
169 case BPF_ALU | BPF_END | BPF_TO_BE:
170 code_fmt = REG(1) " = be" IMMS(2) "(" REG(1) ")";
171 goto do_dst_imm;
172
173 case BPF_ALU | BPF_ADD | BPF_K:
174 code_fmt = A32(+, IMMS(2));
175 goto do_dst_imm;
176 case BPF_ALU | BPF_SUB | BPF_K:
177 code_fmt = A32(-, IMMS(2));
178 goto do_dst_imm;
179 case BPF_ALU | BPF_MUL | BPF_K:
180 code_fmt = A32(*, IMMS(2));
181 goto do_dst_imm;
182 case BPF_ALU | BPF_DIV | BPF_K:
183 code_fmt = A32(/, IMMS(2));
184 goto do_dst_imm;
185 case BPF_ALU | BPF_OR | BPF_K:
186 code_fmt = A32(|, IMMX(2));
187 goto do_dst_imm;
188 case BPF_ALU | BPF_AND | BPF_K:
189 code_fmt = A32(&, IMMX(2));
190 goto do_dst_imm;
191 case BPF_ALU | BPF_LSH | BPF_K:
192 code_fmt = A32(<<, IMMS(2));
193 goto do_dst_imm;
194 case BPF_ALU | BPF_RSH | BPF_K:
195 code_fmt = A32(>>, IMMS(2));
196 goto do_dst_imm;
197 case BPF_ALU | BPF_MOD | BPF_K:
198 code_fmt = A32(%%, IMMS(2));
199 goto do_dst_imm;
200 case BPF_ALU | BPF_XOR | BPF_K:
201 code_fmt = A32(^, IMMX(2));
202 goto do_dst_imm;
203 case BPF_ALU | BPF_MOV | BPF_K:
204 code_fmt = REG(1) " = " IMMX(2);
205 goto do_dst_imm;
206 case BPF_ALU | BPF_ARSH | BPF_K:
207 code_fmt = REG(1) " = (u32)((s32)" REG(1) " >> " IMMS(2) ")";
208 goto do_dst_imm;
209
210 case BPF_ALU | BPF_ADD | BPF_X:
211 code_fmt = A32(+, REGU(2));
212 goto do_dst_src;
213 case BPF_ALU | BPF_SUB | BPF_X:
214 code_fmt = A32(-, REGU(2));
215 goto do_dst_src;
216 case BPF_ALU | BPF_MUL | BPF_X:
217 code_fmt = A32(*, REGU(2));
218 goto do_dst_src;
219 case BPF_ALU | BPF_DIV | BPF_X:
220 code_fmt = A32(/, REGU(2));
221 goto do_dst_src;
222 case BPF_ALU | BPF_OR | BPF_X:
223 code_fmt = A32(|, REGU(2));
224 goto do_dst_src;
225 case BPF_ALU | BPF_AND | BPF_X:
226 code_fmt = A32(&, REGU(2));
227 goto do_dst_src;
228 case BPF_ALU | BPF_LSH | BPF_X:
229 code_fmt = A32(<<, REGU(2));
230 goto do_dst_src;
231 case BPF_ALU | BPF_RSH | BPF_X:
232 code_fmt = A32(>>, REGU(2));
233 goto do_dst_src;
234 case BPF_ALU | BPF_MOD | BPF_X:
235 code_fmt = A32(%%, REGU(2));
236 goto do_dst_src;
237 case BPF_ALU | BPF_XOR | BPF_X:
238 code_fmt = A32(^, REGU(2));
239 goto do_dst_src;
240 case BPF_ALU | BPF_MOV | BPF_X:
241 code_fmt = REG(1) " = " REGU(2);
242 goto do_dst_src;
243 case BPF_ALU | BPF_ARSH | BPF_X:
244 code_fmt = REG(1) " = (u32)((s32)" REG(1) " >> " REG(2) ")";
245 goto do_dst_src;
246
247 case BPF_ALU64 | BPF_ADD | BPF_K:
248 code_fmt = A64(+, IMMS(2));
249 goto do_dst_imm;
250 case BPF_ALU64 | BPF_SUB | BPF_K:
251 code_fmt = A64(-, IMMS(2));
252 goto do_dst_imm;
253 case BPF_ALU64 | BPF_MUL | BPF_K:
254 code_fmt = A64(*, IMMS(2));
255 goto do_dst_imm;
256 case BPF_ALU64 | BPF_DIV | BPF_K:
257 code_fmt = A64(/, IMMS(2));
258 goto do_dst_imm;
259 case BPF_ALU64 | BPF_OR | BPF_K:
260 code_fmt = A64(|, IMMS(2));
261 goto do_dst_imm;
262 case BPF_ALU64 | BPF_AND | BPF_K:
263 code_fmt = A64(&, IMMS(2));
264 goto do_dst_imm;
265 case BPF_ALU64 | BPF_LSH | BPF_K:
266 code_fmt = A64(<<, IMMS(2));
267 goto do_dst_imm;
268 case BPF_ALU64 | BPF_RSH | BPF_K:
269 code_fmt = A64(>>, IMMS(2));
270 goto do_dst_imm;
271 case BPF_ALU64 | BPF_MOD | BPF_K:
272 code_fmt = A64(%%, IMMS(2));
273 goto do_dst_imm;
274 case BPF_ALU64 | BPF_XOR | BPF_K:
275 code_fmt = A64(^, IMMS(2));
276 goto do_dst_imm;
277 case BPF_ALU64 | BPF_MOV | BPF_K:
278 code_fmt = REG(1) " = " IMMS(2);
279 goto do_dst_imm;
280 case BPF_ALU64 | BPF_ARSH | BPF_K:
281 code_fmt = REG(1) " = (s64)" REG(1) " >> " IMMS(2);
282 goto do_dst_imm;
283
284 case BPF_ALU64 | BPF_ADD | BPF_X:
285 code_fmt = A64(+, REG(2));
286 goto do_dst_src;
287 case BPF_ALU64 | BPF_SUB | BPF_X:
288 code_fmt = A64(-, REG(2));
289 goto do_dst_src;
290 case BPF_ALU64 | BPF_MUL | BPF_X:
291 code_fmt = A64(*, REG(2));
292 goto do_dst_src;
293 case BPF_ALU64 | BPF_DIV | BPF_X:
294 code_fmt = A64(/, REG(2));
295 goto do_dst_src;
296 case BPF_ALU64 | BPF_OR | BPF_X:
297 code_fmt = A64(|, REG(2));
298 goto do_dst_src;
299 case BPF_ALU64 | BPF_AND | BPF_X:
300 code_fmt = A64(&, REG(2));
301 goto do_dst_src;
302 case BPF_ALU64 | BPF_LSH | BPF_X:
303 code_fmt = A64(<<, REG(2));
304 goto do_dst_src;
305 case BPF_ALU64 | BPF_RSH | BPF_X:
306 code_fmt = A64(>>, REG(2));
307 goto do_dst_src;
308 case BPF_ALU64 | BPF_MOD | BPF_X:
309 code_fmt = A64(%%, REG(2));
310 goto do_dst_src;
311 case BPF_ALU64 | BPF_XOR | BPF_X:
312 code_fmt = A64(^, REG(2));
313 goto do_dst_src;
314 case BPF_ALU64 | BPF_MOV | BPF_X:
315 code_fmt = REG(1) " = " REG(2);
316 goto do_dst_src;
317 case BPF_ALU64 | BPF_ARSH | BPF_X:
318 code_fmt = REG(1) " = (s64)" REG(1) " >> " REG(2);
319 goto do_dst_src;
320
321 case BPF_ALU | BPF_NEG:
322 code_fmt = REG(1) " = (u32)-" REG(1);
323 goto do_dst_src;
324 case BPF_ALU64 | BPF_NEG:
325 code_fmt = REG(1) " = -" REG(1);
326 goto do_dst_src;
327
328 case BPF_JMP | BPF_JEQ | BPF_K:
329 code_fmt = J64(REG(1), ==, IMMS(2));
330 goto do_dst_imm_jmp;
331 case BPF_JMP | BPF_JGT | BPF_K:
332 code_fmt = J64(REG(1), >, IMMS(2));
333 goto do_dst_imm_jmp;
334 case BPF_JMP | BPF_JGE | BPF_K:
335 code_fmt = J64(REG(1), >=, IMMS(2));
336 goto do_dst_imm_jmp;
337 case BPF_JMP | BPF_JSET | BPF_K:
338 code_fmt = J64(REG(1), &, IMMS(2));
339 goto do_dst_imm_jmp;
340 case BPF_JMP | BPF_JNE | BPF_K:
341 code_fmt = J64(REG(1), !=, IMMS(2));
342 goto do_dst_imm_jmp;
343 case BPF_JMP | BPF_JSGT | BPF_K:
344 code_fmt = J64(REGS(1), >, IMMS(2));
345 goto do_dst_imm_jmp;
346 case BPF_JMP | BPF_JSGE | BPF_K:
347 code_fmt = J64(REGS(1), >=, IMMS(2));
348 goto do_dst_imm_jmp;
349 case BPF_JMP | BPF_JLT | BPF_K:
350 code_fmt = J64(REG(1), <, IMMS(2));
351 goto do_dst_imm_jmp;
352 case BPF_JMP | BPF_JLE | BPF_K:
353 code_fmt = J64(REG(1), <=, IMMS(2));
354 goto do_dst_imm_jmp;
355 case BPF_JMP | BPF_JSLT | BPF_K:
356 code_fmt = J64(REGS(1), <, IMMS(2));
357 goto do_dst_imm_jmp;
358 case BPF_JMP | BPF_JSLE | BPF_K:
359 code_fmt = J64(REGS(1), <=, IMMS(2));
360 goto do_dst_imm_jmp;
361
362 case BPF_JMP | BPF_JEQ | BPF_X:
363 code_fmt = J64(REG(1), ==, REG(2));
364 goto do_dst_src_jmp;
365 case BPF_JMP | BPF_JGT | BPF_X:
366 code_fmt = J64(REG(1), >, REG(2));
367 goto do_dst_src_jmp;
368 case BPF_JMP | BPF_JGE | BPF_X:
369 code_fmt = J64(REG(1), >=, REG(2));
370 goto do_dst_src_jmp;
371 case BPF_JMP | BPF_JSET | BPF_X:
372 code_fmt = J64(REG(1), &, REG(2));
373 goto do_dst_src_jmp;
374 case BPF_JMP | BPF_JNE | BPF_X:
375 code_fmt = J64(REG(1), !=, REG(2));
376 goto do_dst_src_jmp;
377 case BPF_JMP | BPF_JSGT | BPF_X:
378 code_fmt = J64(REGS(1), >, REGS(2));
379 goto do_dst_src_jmp;
380 case BPF_JMP | BPF_JSGE | BPF_X:
381 code_fmt = J64(REGS(1), >=, REGS(2));
382 goto do_dst_src_jmp;
383 case BPF_JMP | BPF_JLT | BPF_X:
384 code_fmt = J64(REG(1), <, REG(2));
385 goto do_dst_src_jmp;
386 case BPF_JMP | BPF_JLE | BPF_X:
387 code_fmt = J64(REG(1), <=, REG(2));
388 goto do_dst_src_jmp;
389 case BPF_JMP | BPF_JSLT | BPF_X:
390 code_fmt = J64(REGS(1), <, REGS(2));
391 goto do_dst_src_jmp;
392 case BPF_JMP | BPF_JSLE | BPF_X:
393 code_fmt = J64(REGS(1), <=, REGS(2));
394 goto do_dst_src_jmp;
395
396 case BPF_LDX | BPF_MEM | BPF_B:
397 code_fmt = LOAD(u8);
398 goto do_dst_src_off;
399 case BPF_LDX | BPF_MEM | BPF_H:
400 code_fmt = LOAD(u16);
401 goto do_dst_src_off;
402 case BPF_LDX | BPF_MEM | BPF_W:
403 code_fmt = LOAD(u32);
404 goto do_dst_src_off;
405 case BPF_LDX | BPF_MEM | BPF_DW:
406 code_fmt = LOAD(u64);
407 goto do_dst_src_off;
408
409 case BPF_STX | BPF_MEM | BPF_B:
410 code_fmt = STORE(u8, REG(2));
411 goto do_dst_src_off;
412 case BPF_STX | BPF_MEM | BPF_H:
413 code_fmt = STORE(u16, REG(2));
414 goto do_dst_src_off;
415 case BPF_STX | BPF_MEM | BPF_W:
416 code_fmt = STORE(u32, REG(2));
417 goto do_dst_src_off;
418 case BPF_STX | BPF_MEM | BPF_DW:
419 code_fmt = STORE(u64, REG(2));
420 goto do_dst_src_off;
421
422 case BPF_STX | BPF_XADD | BPF_W:
423 code_fmt = XADD(u32, REG(2));
424 goto do_dst_src_off;
425 case BPF_STX | BPF_XADD | BPF_DW:
426 code_fmt = XADD(u64, REG(2));
427 goto do_dst_src_off;
428
429 case BPF_ST | BPF_MEM | BPF_B:
430 code_fmt = STORE(u8, IMMS(2));
431 goto do_dst_imm_off;
432 case BPF_ST | BPF_MEM | BPF_H:
433 code_fmt = STORE(u16, IMMS(2));
434 goto do_dst_imm_off;
435 case BPF_ST | BPF_MEM | BPF_W:
436 code_fmt = STORE(u32, IMMS(2));
437 goto do_dst_imm_off;
438 case BPF_ST | BPF_MEM | BPF_DW:
439 code_fmt = STORE(u64, IMMS(2));
440 goto do_dst_imm_off;
441
442 case BPF_LD | BPF_ABS | BPF_B:
443 code_fmt = LDSKB(u8, IMMS(1));
444 goto do_imm;
445 case BPF_LD | BPF_ABS | BPF_H:
446 code_fmt = LDSKB(u16, IMMS(1));
447 goto do_imm;
448 case BPF_LD | BPF_ABS | BPF_W:
449 code_fmt = LDSKB(u32, IMMS(1));
450 goto do_imm;
451
452 case BPF_LD | BPF_IND | BPF_B:
453 code_fmt = LDSKB(u8, REG(1) "+" IMMS(2));
454 goto do_src_imm;
455 case BPF_LD | BPF_IND | BPF_H:
456 code_fmt = LDSKB(u16, REG(1) "+" IMMS(2));
457 goto do_src_imm;
458 case BPF_LD | BPF_IND | BPF_W:
459 code_fmt = LDSKB(u32, REG(1) "+" IMMS(2));
460 goto do_src_imm;
461
462 do_imm:
463 len = snprintf(buf, sizeof(buf), code_fmt, i.imm);
464 break;
465 do_dst_imm:
466 len = snprintf(buf, sizeof(buf), code_fmt, i.dst_reg, i.imm);
467 break;
468 do_src_imm:
469 len = snprintf(buf, sizeof(buf), code_fmt, i.src_reg, i.imm);
470 break;
471 do_dst_src:
472 len = snprintf(buf, sizeof(buf), code_fmt, i.dst_reg, i.src_reg);
473 break;
474 do_dst_imm_jmp:
475 len = snprintf(buf, sizeof(buf), code_fmt, i.dst_reg, i.imm, jmp);
476 break;
477 do_dst_src_jmp:
478 len = snprintf(buf, sizeof(buf), code_fmt,
479 i.dst_reg, i.src_reg, jmp);
480 break;
481 do_dst_imm_off:
482 len = snprintf(buf, sizeof(buf), code_fmt, i.dst_reg, i.imm, i.off);
483 break;
484 do_dst_src_off:
485 len = snprintf(buf, sizeof(buf), code_fmt,
486 i.dst_reg, i.src_reg, i.off);
487 break;
488
489 default:
490 class = BPF_CLASS(code);
491 len = snprintf(buf, sizeof(buf), "invalid class %s",
492 class_string[class]);
493 break;
494 }
495
496 *startp = start;
497 retval = outcb (buf, len, outcbarg);
498 if (retval != 0)
499 goto done;
500 }
501
502 done:
503 return retval;
504 }
505