Coverage Report

Created: 2025-07-11 06:46

/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
}