• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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) laid 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