/src/elfutils/libcpu/bpf_disasm.c
Line | Count | Source (jump to first uncovered line) |
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 "common.h" |
41 | | #include "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 | 0 | #define REG(N) "r%" #N "$d" |
56 | 0 | #define REGU(N) "(u32)" REG(N) |
57 | | #define REGS(N) "(s64)" REG(N) |
58 | | |
59 | 0 | #define IMMS(N) "%" #N "$d" |
60 | 0 | #define IMMX(N) "%" #N "$#x" |
61 | | |
62 | | #define OFF(N) "%" #N "$+d" |
63 | 0 | #define JMP(N) "%" #N "$#x" |
64 | | |
65 | 0 | #define A32(O, S) REG(1) " = " REGU(1) " " #O " " S |
66 | 0 | #define A64(O, S) REG(1) " " #O "= " S |
67 | 0 | #define J64(D, O, S) "if " D " " #O " " S " goto " JMP(3) |
68 | 0 | #define LOAD(T) REG(1) " = *(" #T " *)(" REG(2) OFF(3) ")" |
69 | 0 | #define STORE(T, S) "*(" #T " *)(" REG(1) OFF(3) ") = " S |
70 | 0 | #define XADD(T, S) "lock *(" #T " *)(" REG(1) OFF(3) ") += " S |
71 | 0 | #define LDSKB(T, S) "r0 = *(" #T " *)skb[" S "]" |
72 | | |
73 | | static void |
74 | | bswap_bpf_insn (struct bpf_insn *p) |
75 | 0 | { |
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 | 0 | int t = p->dst_reg; |
82 | 0 | p->dst_reg = p->src_reg; |
83 | 0 | p->src_reg = t; |
84 | | |
85 | | /* The other 2 and 4 byte fields are trivially converted. */ |
86 | 0 | CONVERT (p->off); |
87 | 0 | CONVERT (p->imm); |
88 | 0 | } |
89 | | |
90 | | int |
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 | 0 | { |
98 | 0 | const bool need_bswap = MY_ELFDATA != ebl->data; |
99 | 0 | const uint8_t *start = *startp; |
100 | 0 | char buf[128]; |
101 | 0 | int len, retval = 0; |
102 | |
|
103 | 0 | while (start + sizeof(struct bpf_insn) <= end) |
104 | 0 | { |
105 | 0 | struct bpf_insn i; |
106 | 0 | unsigned code, class, jmp; |
107 | 0 | const char *code_fmt; |
108 | |
|
109 | 0 | memcpy(&i, start, sizeof(struct bpf_insn)); |
110 | 0 | if (need_bswap) |
111 | 0 | bswap_bpf_insn (&i); |
112 | |
|
113 | 0 | start += sizeof(struct bpf_insn); |
114 | 0 | addr += sizeof(struct bpf_insn); |
115 | 0 | jmp = addr + i.off * sizeof(struct bpf_insn); |
116 | |
|
117 | 0 | code = i.code; |
118 | 0 | switch (code) |
119 | 0 | { |
120 | 0 | case BPF_LD | BPF_IMM | BPF_DW: |
121 | 0 | { |
122 | 0 | struct bpf_insn i2; |
123 | 0 | uint64_t imm64; |
124 | |
|
125 | 0 | if (start + sizeof(struct bpf_insn) > end) |
126 | 0 | { |
127 | 0 | start -= sizeof(struct bpf_insn); |
128 | 0 | *startp = start; |
129 | 0 | goto done; |
130 | 0 | } |
131 | 0 | memcpy(&i2, start, sizeof(struct bpf_insn)); |
132 | 0 | if (need_bswap) |
133 | 0 | bswap_bpf_insn (&i2); |
134 | 0 | start += sizeof(struct bpf_insn); |
135 | 0 | addr += sizeof(struct bpf_insn); |
136 | |
|
137 | 0 | imm64 = (uint32_t)i.imm | ((uint64_t)i2.imm << 32); |
138 | 0 | switch (i.src_reg) |
139 | 0 | { |
140 | 0 | case 0: |
141 | 0 | code_fmt = REG(1) " = %2$#" PRIx64; |
142 | 0 | break; |
143 | 0 | case BPF_PSEUDO_MAP_FD: |
144 | 0 | code_fmt = REG(1) " = map_fd(%2$#" PRIx64 ")"; |
145 | 0 | break; |
146 | 0 | default: |
147 | 0 | code_fmt = REG(1) " = ld_pseudo(%3$d, %2$#" PRIx64 ")"; |
148 | 0 | break; |
149 | 0 | } |
150 | 0 | len = snprintf(buf, sizeof(buf), code_fmt, |
151 | 0 | i.dst_reg, imm64, i.src_reg); |
152 | 0 | } |
153 | 0 | break; |
154 | | |
155 | 0 | case BPF_JMP | BPF_EXIT: |
156 | 0 | len = snprintf(buf, sizeof(buf), "exit"); |
157 | 0 | break; |
158 | 0 | case BPF_JMP | BPF_JA: |
159 | 0 | len = snprintf(buf, sizeof(buf), "goto " JMP(1), jmp); |
160 | 0 | break; |
161 | 0 | case BPF_JMP | BPF_CALL: |
162 | 0 | code_fmt = "call " IMMS(1); |
163 | 0 | goto do_imm; |
164 | | |
165 | 0 | case BPF_ALU | BPF_END | BPF_TO_LE: |
166 | | /* The imm field contains {16,32,64}. */ |
167 | 0 | code_fmt = REG(1) " = le" IMMS(2) "(" REG(1) ")"; |
168 | 0 | goto do_dst_imm; |
169 | 0 | case BPF_ALU | BPF_END | BPF_TO_BE: |
170 | 0 | code_fmt = REG(1) " = be" IMMS(2) "(" REG(1) ")"; |
171 | 0 | goto do_dst_imm; |
172 | | |
173 | 0 | case BPF_ALU | BPF_ADD | BPF_K: |
174 | 0 | code_fmt = A32(+, IMMS(2)); |
175 | 0 | goto do_dst_imm; |
176 | 0 | case BPF_ALU | BPF_SUB | BPF_K: |
177 | 0 | code_fmt = A32(-, IMMS(2)); |
178 | 0 | goto do_dst_imm; |
179 | 0 | case BPF_ALU | BPF_MUL | BPF_K: |
180 | 0 | code_fmt = A32(*, IMMS(2)); |
181 | 0 | goto do_dst_imm; |
182 | 0 | case BPF_ALU | BPF_DIV | BPF_K: |
183 | 0 | code_fmt = A32(/, IMMS(2)); |
184 | 0 | goto do_dst_imm; |
185 | 0 | case BPF_ALU | BPF_OR | BPF_K: |
186 | 0 | code_fmt = A32(|, IMMX(2)); |
187 | 0 | goto do_dst_imm; |
188 | 0 | case BPF_ALU | BPF_AND | BPF_K: |
189 | 0 | code_fmt = A32(&, IMMX(2)); |
190 | 0 | goto do_dst_imm; |
191 | 0 | case BPF_ALU | BPF_LSH | BPF_K: |
192 | 0 | code_fmt = A32(<<, IMMS(2)); |
193 | 0 | goto do_dst_imm; |
194 | 0 | case BPF_ALU | BPF_RSH | BPF_K: |
195 | 0 | code_fmt = A32(>>, IMMS(2)); |
196 | 0 | goto do_dst_imm; |
197 | 0 | case BPF_ALU | BPF_MOD | BPF_K: |
198 | 0 | code_fmt = A32(%%, IMMS(2)); |
199 | 0 | goto do_dst_imm; |
200 | 0 | case BPF_ALU | BPF_XOR | BPF_K: |
201 | 0 | code_fmt = A32(^, IMMX(2)); |
202 | 0 | goto do_dst_imm; |
203 | 0 | case BPF_ALU | BPF_MOV | BPF_K: |
204 | 0 | code_fmt = REG(1) " = " IMMX(2); |
205 | 0 | goto do_dst_imm; |
206 | 0 | case BPF_ALU | BPF_ARSH | BPF_K: |
207 | 0 | code_fmt = REG(1) " = (u32)((s32)" REG(1) " >> " IMMS(2) ")"; |
208 | 0 | goto do_dst_imm; |
209 | | |
210 | 0 | case BPF_ALU | BPF_ADD | BPF_X: |
211 | 0 | code_fmt = A32(+, REGU(2)); |
212 | 0 | goto do_dst_src; |
213 | 0 | case BPF_ALU | BPF_SUB | BPF_X: |
214 | 0 | code_fmt = A32(-, REGU(2)); |
215 | 0 | goto do_dst_src; |
216 | 0 | case BPF_ALU | BPF_MUL | BPF_X: |
217 | 0 | code_fmt = A32(*, REGU(2)); |
218 | 0 | goto do_dst_src; |
219 | 0 | case BPF_ALU | BPF_DIV | BPF_X: |
220 | 0 | code_fmt = A32(/, REGU(2)); |
221 | 0 | goto do_dst_src; |
222 | 0 | case BPF_ALU | BPF_OR | BPF_X: |
223 | 0 | code_fmt = A32(|, REGU(2)); |
224 | 0 | goto do_dst_src; |
225 | 0 | case BPF_ALU | BPF_AND | BPF_X: |
226 | 0 | code_fmt = A32(&, REGU(2)); |
227 | 0 | goto do_dst_src; |
228 | 0 | case BPF_ALU | BPF_LSH | BPF_X: |
229 | 0 | code_fmt = A32(<<, REGU(2)); |
230 | 0 | goto do_dst_src; |
231 | 0 | case BPF_ALU | BPF_RSH | BPF_X: |
232 | 0 | code_fmt = A32(>>, REGU(2)); |
233 | 0 | goto do_dst_src; |
234 | 0 | case BPF_ALU | BPF_MOD | BPF_X: |
235 | 0 | code_fmt = A32(%%, REGU(2)); |
236 | 0 | goto do_dst_src; |
237 | 0 | case BPF_ALU | BPF_XOR | BPF_X: |
238 | 0 | code_fmt = A32(^, REGU(2)); |
239 | 0 | goto do_dst_src; |
240 | 0 | case BPF_ALU | BPF_MOV | BPF_X: |
241 | 0 | code_fmt = REG(1) " = " REGU(2); |
242 | 0 | goto do_dst_src; |
243 | 0 | case BPF_ALU | BPF_ARSH | BPF_X: |
244 | 0 | code_fmt = REG(1) " = (u32)((s32)" REG(1) " >> " REG(2) ")"; |
245 | 0 | goto do_dst_src; |
246 | | |
247 | 0 | case BPF_ALU64 | BPF_ADD | BPF_K: |
248 | 0 | code_fmt = A64(+, IMMS(2)); |
249 | 0 | goto do_dst_imm; |
250 | 0 | case BPF_ALU64 | BPF_SUB | BPF_K: |
251 | 0 | code_fmt = A64(-, IMMS(2)); |
252 | 0 | goto do_dst_imm; |
253 | 0 | case BPF_ALU64 | BPF_MUL | BPF_K: |
254 | 0 | code_fmt = A64(*, IMMS(2)); |
255 | 0 | goto do_dst_imm; |
256 | 0 | case BPF_ALU64 | BPF_DIV | BPF_K: |
257 | 0 | code_fmt = A64(/, IMMS(2)); |
258 | 0 | goto do_dst_imm; |
259 | 0 | case BPF_ALU64 | BPF_OR | BPF_K: |
260 | 0 | code_fmt = A64(|, IMMS(2)); |
261 | 0 | goto do_dst_imm; |
262 | 0 | case BPF_ALU64 | BPF_AND | BPF_K: |
263 | 0 | code_fmt = A64(&, IMMS(2)); |
264 | 0 | goto do_dst_imm; |
265 | 0 | case BPF_ALU64 | BPF_LSH | BPF_K: |
266 | 0 | code_fmt = A64(<<, IMMS(2)); |
267 | 0 | goto do_dst_imm; |
268 | 0 | case BPF_ALU64 | BPF_RSH | BPF_K: |
269 | 0 | code_fmt = A64(>>, IMMS(2)); |
270 | 0 | goto do_dst_imm; |
271 | 0 | case BPF_ALU64 | BPF_MOD | BPF_K: |
272 | 0 | code_fmt = A64(%%, IMMS(2)); |
273 | 0 | goto do_dst_imm; |
274 | 0 | case BPF_ALU64 | BPF_XOR | BPF_K: |
275 | 0 | code_fmt = A64(^, IMMS(2)); |
276 | 0 | goto do_dst_imm; |
277 | 0 | case BPF_ALU64 | BPF_MOV | BPF_K: |
278 | 0 | code_fmt = REG(1) " = " IMMS(2); |
279 | 0 | goto do_dst_imm; |
280 | 0 | case BPF_ALU64 | BPF_ARSH | BPF_K: |
281 | 0 | code_fmt = REG(1) " = (s64)" REG(1) " >> " IMMS(2); |
282 | 0 | goto do_dst_imm; |
283 | | |
284 | 0 | case BPF_ALU64 | BPF_ADD | BPF_X: |
285 | 0 | code_fmt = A64(+, REG(2)); |
286 | 0 | goto do_dst_src; |
287 | 0 | case BPF_ALU64 | BPF_SUB | BPF_X: |
288 | 0 | code_fmt = A64(-, REG(2)); |
289 | 0 | goto do_dst_src; |
290 | 0 | case BPF_ALU64 | BPF_MUL | BPF_X: |
291 | 0 | code_fmt = A64(*, REG(2)); |
292 | 0 | goto do_dst_src; |
293 | 0 | case BPF_ALU64 | BPF_DIV | BPF_X: |
294 | 0 | code_fmt = A64(/, REG(2)); |
295 | 0 | goto do_dst_src; |
296 | 0 | case BPF_ALU64 | BPF_OR | BPF_X: |
297 | 0 | code_fmt = A64(|, REG(2)); |
298 | 0 | goto do_dst_src; |
299 | 0 | case BPF_ALU64 | BPF_AND | BPF_X: |
300 | 0 | code_fmt = A64(&, REG(2)); |
301 | 0 | goto do_dst_src; |
302 | 0 | case BPF_ALU64 | BPF_LSH | BPF_X: |
303 | 0 | code_fmt = A64(<<, REG(2)); |
304 | 0 | goto do_dst_src; |
305 | 0 | case BPF_ALU64 | BPF_RSH | BPF_X: |
306 | 0 | code_fmt = A64(>>, REG(2)); |
307 | 0 | goto do_dst_src; |
308 | 0 | case BPF_ALU64 | BPF_MOD | BPF_X: |
309 | 0 | code_fmt = A64(%%, REG(2)); |
310 | 0 | goto do_dst_src; |
311 | 0 | case BPF_ALU64 | BPF_XOR | BPF_X: |
312 | 0 | code_fmt = A64(^, REG(2)); |
313 | 0 | goto do_dst_src; |
314 | 0 | case BPF_ALU64 | BPF_MOV | BPF_X: |
315 | 0 | code_fmt = REG(1) " = " REG(2); |
316 | 0 | goto do_dst_src; |
317 | 0 | case BPF_ALU64 | BPF_ARSH | BPF_X: |
318 | 0 | code_fmt = REG(1) " = (s64)" REG(1) " >> " REG(2); |
319 | 0 | goto do_dst_src; |
320 | | |
321 | 0 | case BPF_ALU | BPF_NEG: |
322 | 0 | code_fmt = REG(1) " = (u32)-" REG(1); |
323 | 0 | goto do_dst_src; |
324 | 0 | case BPF_ALU64 | BPF_NEG: |
325 | 0 | code_fmt = REG(1) " = -" REG(1); |
326 | 0 | goto do_dst_src; |
327 | | |
328 | 0 | case BPF_JMP | BPF_JEQ | BPF_K: |
329 | 0 | code_fmt = J64(REG(1), ==, IMMS(2)); |
330 | 0 | goto do_dst_imm_jmp; |
331 | 0 | case BPF_JMP | BPF_JGT | BPF_K: |
332 | 0 | code_fmt = J64(REG(1), >, IMMS(2)); |
333 | 0 | goto do_dst_imm_jmp; |
334 | 0 | case BPF_JMP | BPF_JGE | BPF_K: |
335 | 0 | code_fmt = J64(REG(1), >=, IMMS(2)); |
336 | 0 | goto do_dst_imm_jmp; |
337 | 0 | case BPF_JMP | BPF_JSET | BPF_K: |
338 | 0 | code_fmt = J64(REG(1), &, IMMS(2)); |
339 | 0 | goto do_dst_imm_jmp; |
340 | 0 | case BPF_JMP | BPF_JNE | BPF_K: |
341 | 0 | code_fmt = J64(REG(1), !=, IMMS(2)); |
342 | 0 | goto do_dst_imm_jmp; |
343 | 0 | case BPF_JMP | BPF_JSGT | BPF_K: |
344 | 0 | code_fmt = J64(REGS(1), >, IMMS(2)); |
345 | 0 | goto do_dst_imm_jmp; |
346 | 0 | case BPF_JMP | BPF_JSGE | BPF_K: |
347 | 0 | code_fmt = J64(REGS(1), >=, IMMS(2)); |
348 | 0 | goto do_dst_imm_jmp; |
349 | 0 | case BPF_JMP | BPF_JLT | BPF_K: |
350 | 0 | code_fmt = J64(REG(1), <, IMMS(2)); |
351 | 0 | goto do_dst_imm_jmp; |
352 | 0 | case BPF_JMP | BPF_JLE | BPF_K: |
353 | 0 | code_fmt = J64(REG(1), <=, IMMS(2)); |
354 | 0 | goto do_dst_imm_jmp; |
355 | 0 | case BPF_JMP | BPF_JSLT | BPF_K: |
356 | 0 | code_fmt = J64(REGS(1), <, IMMS(2)); |
357 | 0 | goto do_dst_imm_jmp; |
358 | 0 | case BPF_JMP | BPF_JSLE | BPF_K: |
359 | 0 | code_fmt = J64(REGS(1), <=, IMMS(2)); |
360 | 0 | goto do_dst_imm_jmp; |
361 | | |
362 | 0 | case BPF_JMP | BPF_JEQ | BPF_X: |
363 | 0 | code_fmt = J64(REG(1), ==, REG(2)); |
364 | 0 | goto do_dst_src_jmp; |
365 | 0 | case BPF_JMP | BPF_JGT | BPF_X: |
366 | 0 | code_fmt = J64(REG(1), >, REG(2)); |
367 | 0 | goto do_dst_src_jmp; |
368 | 0 | case BPF_JMP | BPF_JGE | BPF_X: |
369 | 0 | code_fmt = J64(REG(1), >=, REG(2)); |
370 | 0 | goto do_dst_src_jmp; |
371 | 0 | case BPF_JMP | BPF_JSET | BPF_X: |
372 | 0 | code_fmt = J64(REG(1), &, REG(2)); |
373 | 0 | goto do_dst_src_jmp; |
374 | 0 | case BPF_JMP | BPF_JNE | BPF_X: |
375 | 0 | code_fmt = J64(REG(1), !=, REG(2)); |
376 | 0 | goto do_dst_src_jmp; |
377 | 0 | case BPF_JMP | BPF_JSGT | BPF_X: |
378 | 0 | code_fmt = J64(REGS(1), >, REGS(2)); |
379 | 0 | goto do_dst_src_jmp; |
380 | 0 | case BPF_JMP | BPF_JSGE | BPF_X: |
381 | 0 | code_fmt = J64(REGS(1), >=, REGS(2)); |
382 | 0 | goto do_dst_src_jmp; |
383 | 0 | case BPF_JMP | BPF_JLT | BPF_X: |
384 | 0 | code_fmt = J64(REG(1), <, REG(2)); |
385 | 0 | goto do_dst_src_jmp; |
386 | 0 | case BPF_JMP | BPF_JLE | BPF_X: |
387 | 0 | code_fmt = J64(REG(1), <=, REG(2)); |
388 | 0 | goto do_dst_src_jmp; |
389 | 0 | case BPF_JMP | BPF_JSLT | BPF_X: |
390 | 0 | code_fmt = J64(REGS(1), <, REGS(2)); |
391 | 0 | goto do_dst_src_jmp; |
392 | 0 | case BPF_JMP | BPF_JSLE | BPF_X: |
393 | 0 | code_fmt = J64(REGS(1), <=, REGS(2)); |
394 | 0 | goto do_dst_src_jmp; |
395 | | |
396 | 0 | case BPF_LDX | BPF_MEM | BPF_B: |
397 | 0 | code_fmt = LOAD(u8); |
398 | 0 | goto do_dst_src_off; |
399 | 0 | case BPF_LDX | BPF_MEM | BPF_H: |
400 | 0 | code_fmt = LOAD(u16); |
401 | 0 | goto do_dst_src_off; |
402 | 0 | case BPF_LDX | BPF_MEM | BPF_W: |
403 | 0 | code_fmt = LOAD(u32); |
404 | 0 | goto do_dst_src_off; |
405 | 0 | case BPF_LDX | BPF_MEM | BPF_DW: |
406 | 0 | code_fmt = LOAD(u64); |
407 | 0 | goto do_dst_src_off; |
408 | | |
409 | 0 | case BPF_STX | BPF_MEM | BPF_B: |
410 | 0 | code_fmt = STORE(u8, REG(2)); |
411 | 0 | goto do_dst_src_off; |
412 | 0 | case BPF_STX | BPF_MEM | BPF_H: |
413 | 0 | code_fmt = STORE(u16, REG(2)); |
414 | 0 | goto do_dst_src_off; |
415 | 0 | case BPF_STX | BPF_MEM | BPF_W: |
416 | 0 | code_fmt = STORE(u32, REG(2)); |
417 | 0 | goto do_dst_src_off; |
418 | 0 | case BPF_STX | BPF_MEM | BPF_DW: |
419 | 0 | code_fmt = STORE(u64, REG(2)); |
420 | 0 | goto do_dst_src_off; |
421 | | |
422 | 0 | case BPF_STX | BPF_XADD | BPF_W: |
423 | 0 | code_fmt = XADD(u32, REG(2)); |
424 | 0 | goto do_dst_src_off; |
425 | 0 | case BPF_STX | BPF_XADD | BPF_DW: |
426 | 0 | code_fmt = XADD(u64, REG(2)); |
427 | 0 | goto do_dst_src_off; |
428 | | |
429 | 0 | case BPF_ST | BPF_MEM | BPF_B: |
430 | 0 | code_fmt = STORE(u8, IMMS(2)); |
431 | 0 | goto do_dst_imm_off; |
432 | 0 | case BPF_ST | BPF_MEM | BPF_H: |
433 | 0 | code_fmt = STORE(u16, IMMS(2)); |
434 | 0 | goto do_dst_imm_off; |
435 | 0 | case BPF_ST | BPF_MEM | BPF_W: |
436 | 0 | code_fmt = STORE(u32, IMMS(2)); |
437 | 0 | goto do_dst_imm_off; |
438 | 0 | case BPF_ST | BPF_MEM | BPF_DW: |
439 | 0 | code_fmt = STORE(u64, IMMS(2)); |
440 | 0 | goto do_dst_imm_off; |
441 | | |
442 | 0 | case BPF_LD | BPF_ABS | BPF_B: |
443 | 0 | code_fmt = LDSKB(u8, IMMS(1)); |
444 | 0 | goto do_imm; |
445 | 0 | case BPF_LD | BPF_ABS | BPF_H: |
446 | 0 | code_fmt = LDSKB(u16, IMMS(1)); |
447 | 0 | goto do_imm; |
448 | 0 | case BPF_LD | BPF_ABS | BPF_W: |
449 | 0 | code_fmt = LDSKB(u32, IMMS(1)); |
450 | 0 | goto do_imm; |
451 | | |
452 | 0 | case BPF_LD | BPF_IND | BPF_B: |
453 | 0 | code_fmt = LDSKB(u8, REG(1) "+" IMMS(2)); |
454 | 0 | goto do_src_imm; |
455 | 0 | case BPF_LD | BPF_IND | BPF_H: |
456 | 0 | code_fmt = LDSKB(u16, REG(1) "+" IMMS(2)); |
457 | 0 | goto do_src_imm; |
458 | 0 | case BPF_LD | BPF_IND | BPF_W: |
459 | 0 | code_fmt = LDSKB(u32, REG(1) "+" IMMS(2)); |
460 | 0 | goto do_src_imm; |
461 | | |
462 | 0 | do_imm: |
463 | 0 | len = snprintf(buf, sizeof(buf), code_fmt, i.imm); |
464 | 0 | break; |
465 | 0 | do_dst_imm: |
466 | 0 | len = snprintf(buf, sizeof(buf), code_fmt, i.dst_reg, i.imm); |
467 | 0 | break; |
468 | 0 | do_src_imm: |
469 | 0 | len = snprintf(buf, sizeof(buf), code_fmt, i.src_reg, i.imm); |
470 | 0 | break; |
471 | 0 | do_dst_src: |
472 | 0 | len = snprintf(buf, sizeof(buf), code_fmt, i.dst_reg, i.src_reg); |
473 | 0 | break; |
474 | 0 | do_dst_imm_jmp: |
475 | 0 | len = snprintf(buf, sizeof(buf), code_fmt, i.dst_reg, i.imm, jmp); |
476 | 0 | break; |
477 | 0 | do_dst_src_jmp: |
478 | 0 | len = snprintf(buf, sizeof(buf), code_fmt, |
479 | 0 | i.dst_reg, i.src_reg, jmp); |
480 | 0 | break; |
481 | 0 | do_dst_imm_off: |
482 | 0 | len = snprintf(buf, sizeof(buf), code_fmt, i.dst_reg, i.imm, i.off); |
483 | 0 | break; |
484 | 0 | do_dst_src_off: |
485 | 0 | len = snprintf(buf, sizeof(buf), code_fmt, |
486 | 0 | i.dst_reg, i.src_reg, i.off); |
487 | 0 | break; |
488 | | |
489 | 0 | default: |
490 | 0 | class = BPF_CLASS(code); |
491 | 0 | len = snprintf(buf, sizeof(buf), "invalid class %s", |
492 | 0 | class_string[class]); |
493 | 0 | break; |
494 | 0 | } |
495 | | |
496 | 0 | *startp = start; |
497 | 0 | retval = outcb (buf, len, outcbarg); |
498 | 0 | if (retval != 0) |
499 | 0 | goto done; |
500 | 0 | } |
501 | | |
502 | 0 | done: |
503 | 0 | return retval; |
504 | 0 | } |