blob: 054aba2bb05ca8ade920f769480b6ee991422a82 [file] [log] [blame]
Brian Silverman86497922018-02-10 19:28:39 -05001/* Disassembler for BPF.
2 Copyright (C) 2016 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
43static 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
73static void
74bswap_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
90int
91bpf_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
350 case BPF_JMP | BPF_JEQ | BPF_X:
351 code_fmt = J64(REG(1), ==, REG(2));
352 goto do_dst_src_jmp;
353 case BPF_JMP | BPF_JGT | BPF_X:
354 code_fmt = J64(REG(1), >, REG(2));
355 goto do_dst_src_jmp;
356 case BPF_JMP | BPF_JGE | BPF_X:
357 code_fmt = J64(REG(1), >=, REG(2));
358 goto do_dst_src_jmp;
359 case BPF_JMP | BPF_JSET | BPF_X:
360 code_fmt = J64(REG(1), &, REG(2));
361 goto do_dst_src_jmp;
362 case BPF_JMP | BPF_JNE | BPF_X:
363 code_fmt = J64(REG(1), !=, REG(2));
364 goto do_dst_src_jmp;
365 case BPF_JMP | BPF_JSGT | BPF_X:
366 code_fmt = J64(REGS(1), >, REGS(2));
367 goto do_dst_src_jmp;
368 case BPF_JMP | BPF_JSGE | BPF_X:
369 code_fmt = J64(REGS(1), >=, REGS(2));
370 goto do_dst_src_jmp;
371
372 case BPF_LDX | BPF_MEM | BPF_B:
373 code_fmt = LOAD(u8);
374 goto do_dst_src_off;
375 case BPF_LDX | BPF_MEM | BPF_H:
376 code_fmt = LOAD(u16);
377 goto do_dst_src_off;
378 case BPF_LDX | BPF_MEM | BPF_W:
379 code_fmt = LOAD(u32);
380 goto do_dst_src_off;
381 case BPF_LDX | BPF_MEM | BPF_DW:
382 code_fmt = LOAD(u64);
383 goto do_dst_src_off;
384
385 case BPF_STX | BPF_MEM | BPF_B:
386 code_fmt = STORE(u8, REG(2));
387 goto do_dst_src_off;
388 case BPF_STX | BPF_MEM | BPF_H:
389 code_fmt = STORE(u16, REG(2));
390 goto do_dst_src_off;
391 case BPF_STX | BPF_MEM | BPF_W:
392 code_fmt = STORE(u32, REG(2));
393 goto do_dst_src_off;
394 case BPF_STX | BPF_MEM | BPF_DW:
395 code_fmt = STORE(u64, REG(2));
396 goto do_dst_src_off;
397
398 case BPF_STX | BPF_XADD | BPF_W:
399 code_fmt = XADD(u32, REG(2));
400 goto do_dst_src_off;
401 case BPF_STX | BPF_XADD | BPF_DW:
402 code_fmt = XADD(u64, REG(2));
403 goto do_dst_src_off;
404
405 case BPF_ST | BPF_MEM | BPF_B:
406 code_fmt = STORE(u8, IMMS(2));
407 goto do_dst_imm_off;
408 case BPF_ST | BPF_MEM | BPF_H:
409 code_fmt = STORE(u16, IMMS(2));
410 goto do_dst_imm_off;
411 case BPF_ST | BPF_MEM | BPF_W:
412 code_fmt = STORE(u32, IMMS(2));
413 goto do_dst_imm_off;
414 case BPF_ST | BPF_MEM | BPF_DW:
415 code_fmt = STORE(u64, IMMS(2));
416 goto do_dst_imm_off;
417
418 case BPF_LD | BPF_ABS | BPF_B:
419 code_fmt = LDSKB(u8, IMMS(1));
420 goto do_imm;
421 case BPF_LD | BPF_ABS | BPF_H:
422 code_fmt = LDSKB(u16, IMMS(1));
423 goto do_imm;
424 case BPF_LD | BPF_ABS | BPF_W:
425 code_fmt = LDSKB(u32, IMMS(1));
426 goto do_imm;
427
428 case BPF_LD | BPF_IND | BPF_B:
429 code_fmt = LDSKB(u8, REG(1) "+" IMMS(2));
430 goto do_src_imm;
431 case BPF_LD | BPF_IND | BPF_H:
432 code_fmt = LDSKB(u16, REG(1) "+" IMMS(2));
433 goto do_src_imm;
434 case BPF_LD | BPF_IND | BPF_W:
435 code_fmt = LDSKB(u32, REG(1) "+" IMMS(2));
436 goto do_src_imm;
437
438 do_imm:
439 len = snprintf(buf, sizeof(buf), code_fmt, i.imm);
440 break;
441 do_dst_imm:
442 len = snprintf(buf, sizeof(buf), code_fmt, i.dst_reg, i.imm);
443 break;
444 do_src_imm:
445 len = snprintf(buf, sizeof(buf), code_fmt, i.src_reg, i.imm);
446 break;
447 do_dst_src:
448 len = snprintf(buf, sizeof(buf), code_fmt, i.dst_reg, i.src_reg);
449 break;
450 do_dst_imm_jmp:
451 len = snprintf(buf, sizeof(buf), code_fmt, i.dst_reg, i.imm, jmp);
452 break;
453 do_dst_src_jmp:
454 len = snprintf(buf, sizeof(buf), code_fmt,
455 i.dst_reg, i.src_reg, jmp);
456 break;
457 do_dst_imm_off:
458 len = snprintf(buf, sizeof(buf), code_fmt, i.dst_reg, i.imm, i.off);
459 break;
460 do_dst_src_off:
461 len = snprintf(buf, sizeof(buf), code_fmt,
462 i.dst_reg, i.src_reg, i.off);
463 break;
464
465 default:
466 class = BPF_CLASS(code);
467 len = snprintf(buf, sizeof(buf), "invalid class %s",
468 class_string[class]);
469 break;
470 }
471
472 *startp = start;
473 retval = outcb (buf, len, outcbarg);
474 if (retval != 0)
475 goto done;
476 }
477
478 done:
479 return retval;
480}