xref: /third_party/elfutils/libcpu/bpf_disasm.c (revision da0c48c4)
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
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) 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
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	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