4 * Minimal BPF debugger that mimics the kernel's engine (w/o extensions)
5 * and allows for single stepping through selected packets from a pcap
6 * with a provided user filter in order to facilitate verification of a
7 * BPF program. Besides others, this is useful to verify BPF programs
8 * before attaching to a live system, and can be used in socket filters,
9 * cls_bpf, xt_bpf, team driver and e.g. PTP code; in particular when a
10 * single more complex BPF program is being used. Reasons for a more
11 * complex BPF program are likely primarily to optimize execution time
12 * for making a verdict when multiple simple BPF programs are combined
13 * into one in order to prevent parsing same headers multiple times.
15 * More on how to debug BPF opcodes see Documentation/networking/filter.txt
16 * which is the main document on BPF. Mini howto for getting started:
18 * 1) `./bpf_dbg` to enter the shell (shell cmds denoted with '>'):
19 * 2) > load bpf 6,40 0 0 12,21 0 3 20... (output from `bpf_asm` or
20 * `tcpdump -iem1 -ddd port 22 | tr '\n' ','` to load as filter)
21 * 3) > load pcap foo.pcap
22 * 4) > run <n>/disassemble/dump/quit (self-explanatory)
23 * 5) > breakpoint 2 (sets bp at loaded BPF insns 2, do `run` then;
24 * multiple bps can be set, of course, a call to `breakpoint`
25 * w/o args shows currently loaded bps, `breakpoint reset` for
26 * resetting all breakpoints)
27 * 6) > select 3 (`run` etc will start from the 3rd packet in the pcap)
28 * 7) > step [-<n>, +<n>] (performs single stepping through the BPF)
30 * Copyright 2013 Daniel Borkmann <borkmann@redhat.com>
31 * Licensed under the GNU General Public License, version 2.0 (GPLv2)
41 #include <linux/filter.h>
42 #include <linux/if_packet.h>
43 #include <readline/readline.h>
44 #include <readline/history.h>
45 #include <sys/types.h>
46 #include <sys/socket.h>
52 #include <arpa/inet.h>
53 #include <net/ethernet.h>
55 #define TCPDUMP_MAGIC 0xa1b2c3d4
57 #define BPF_LDX_B (BPF_LDX | BPF_B)
58 #define BPF_LDX_W (BPF_LDX | BPF_W)
59 #define BPF_JMP_JA (BPF_JMP | BPF_JA)
60 #define BPF_JMP_JEQ (BPF_JMP | BPF_JEQ)
61 #define BPF_JMP_JGT (BPF_JMP | BPF_JGT)
62 #define BPF_JMP_JGE (BPF_JMP | BPF_JGE)
63 #define BPF_JMP_JSET (BPF_JMP | BPF_JSET)
64 #define BPF_ALU_ADD (BPF_ALU | BPF_ADD)
65 #define BPF_ALU_SUB (BPF_ALU | BPF_SUB)
66 #define BPF_ALU_MUL (BPF_ALU | BPF_MUL)
67 #define BPF_ALU_DIV (BPF_ALU | BPF_DIV)
68 #define BPF_ALU_MOD (BPF_ALU | BPF_MOD)
69 #define BPF_ALU_NEG (BPF_ALU | BPF_NEG)
70 #define BPF_ALU_AND (BPF_ALU | BPF_AND)
71 #define BPF_ALU_OR (BPF_ALU | BPF_OR)
72 #define BPF_ALU_XOR (BPF_ALU | BPF_XOR)
73 #define BPF_ALU_LSH (BPF_ALU | BPF_LSH)
74 #define BPF_ALU_RSH (BPF_ALU | BPF_RSH)
75 #define BPF_MISC_TAX (BPF_MISC | BPF_TAX)
76 #define BPF_MISC_TXA (BPF_MISC | BPF_TXA)
77 #define BPF_LD_B (BPF_LD | BPF_B)
78 #define BPF_LD_H (BPF_LD | BPF_H)
79 #define BPF_LD_W (BPF_LD | BPF_W)
82 # define array_size(x) (sizeof(x) / sizeof((x)[0]))
85 #ifndef __check_format_printf
86 # define __check_format_printf(pos_fmtstr, pos_fmtargs) \
87 __attribute__ ((format (printf, (pos_fmtstr), (pos_fmtargs))))
90 #define CMD(_name, _func) { .name = _name, .func = _func, }
91 #define OP(_op, _name) [_op] = _name
101 int (*func
)(char *args
);
104 struct pcap_filehdr
{
106 uint16_t version_major
;
107 uint16_t version_minor
;
114 struct pcap_timeval
{
120 struct pcap_timeval ts
;
128 uint32_t M
[BPF_MEMWORDS
];
134 static struct sock_filter bpf_image
[BPF_MAXINSNS
+ 1];
135 static unsigned int bpf_prog_len
= 0;
137 static int bpf_breakpoints
[64];
138 static struct bpf_regs bpf_regs
[BPF_MAXINSNS
+ 1];
139 static struct bpf_regs bpf_curr
;
140 static unsigned int bpf_regs_len
= 0;
142 static int pcap_fd
= -1;
143 static unsigned int pcap_packet
= 0;
144 static size_t pcap_map_size
= 0;
145 static char *pcap_ptr_va_start
, *pcap_ptr_va_curr
;
147 static const char * const op_table
[] = {
154 OP(BPF_LDX_B
, "ldxb"),
155 OP(BPF_JMP_JA
, "ja"),
156 OP(BPF_JMP_JEQ
, "jeq"),
157 OP(BPF_JMP_JGT
, "jgt"),
158 OP(BPF_JMP_JGE
, "jge"),
159 OP(BPF_JMP_JSET
, "jset"),
160 OP(BPF_ALU_ADD
, "add"),
161 OP(BPF_ALU_SUB
, "sub"),
162 OP(BPF_ALU_MUL
, "mul"),
163 OP(BPF_ALU_DIV
, "div"),
164 OP(BPF_ALU_MOD
, "mod"),
165 OP(BPF_ALU_NEG
, "neg"),
166 OP(BPF_ALU_AND
, "and"),
167 OP(BPF_ALU_OR
, "or"),
168 OP(BPF_ALU_XOR
, "xor"),
169 OP(BPF_ALU_LSH
, "lsh"),
170 OP(BPF_ALU_RSH
, "rsh"),
171 OP(BPF_MISC_TAX
, "tax"),
172 OP(BPF_MISC_TXA
, "txa"),
176 static __check_format_printf(1, 2) int rl_printf(const char *fmt
, ...)
182 ret
= vfprintf(rl_outstream
, fmt
, vl
);
188 static int matches(const char *cmd
, const char *pattern
)
190 int len
= strlen(cmd
);
192 if (len
> strlen(pattern
))
195 return memcmp(pattern
, cmd
, len
);
198 static void hex_dump(const uint8_t *buf
, size_t len
)
202 rl_printf("%3u: ", 0);
203 for (i
= 0; i
< len
; i
++) {
205 rl_printf("\n%3u: ", i
);
206 rl_printf("%02x ", buf
[i
]);
211 static bool bpf_prog_loaded(void)
213 if (bpf_prog_len
== 0)
214 rl_printf("no bpf program loaded!\n");
216 return bpf_prog_len
> 0;
219 static void bpf_disasm(const struct sock_filter f
, unsigned int i
)
221 const char *op
, *fmt
;
226 case BPF_RET
| BPF_K
:
227 op
= op_table
[BPF_RET
];
230 case BPF_RET
| BPF_A
:
231 op
= op_table
[BPF_RET
];
234 case BPF_RET
| BPF_X
:
235 op
= op_table
[BPF_RET
];
239 op
= op_table
[BPF_MISC_TAX
];
243 op
= op_table
[BPF_MISC_TXA
];
247 op
= op_table
[BPF_ST
];
251 op
= op_table
[BPF_STX
];
254 case BPF_LD_W
| BPF_ABS
:
255 op
= op_table
[BPF_LD_W
];
258 case BPF_LD_H
| BPF_ABS
:
259 op
= op_table
[BPF_LD_H
];
262 case BPF_LD_B
| BPF_ABS
:
263 op
= op_table
[BPF_LD_B
];
266 case BPF_LD_W
| BPF_LEN
:
267 op
= op_table
[BPF_LD_W
];
270 case BPF_LD_W
| BPF_IND
:
271 op
= op_table
[BPF_LD_W
];
274 case BPF_LD_H
| BPF_IND
:
275 op
= op_table
[BPF_LD_H
];
278 case BPF_LD_B
| BPF_IND
:
279 op
= op_table
[BPF_LD_B
];
282 case BPF_LD
| BPF_IMM
:
283 op
= op_table
[BPF_LD_W
];
286 case BPF_LDX
| BPF_IMM
:
287 op
= op_table
[BPF_LDX
];
290 case BPF_LDX_B
| BPF_MSH
:
291 op
= op_table
[BPF_LDX_B
];
292 fmt
= "4*([%d]&0xf)";
294 case BPF_LD
| BPF_MEM
:
295 op
= op_table
[BPF_LD_W
];
298 case BPF_LDX
| BPF_MEM
:
299 op
= op_table
[BPF_LDX
];
303 op
= op_table
[BPF_JMP_JA
];
307 case BPF_JMP_JGT
| BPF_X
:
308 op
= op_table
[BPF_JMP_JGT
];
311 case BPF_JMP_JGT
| BPF_K
:
312 op
= op_table
[BPF_JMP_JGT
];
315 case BPF_JMP_JGE
| BPF_X
:
316 op
= op_table
[BPF_JMP_JGE
];
319 case BPF_JMP_JGE
| BPF_K
:
320 op
= op_table
[BPF_JMP_JGE
];
323 case BPF_JMP_JEQ
| BPF_X
:
324 op
= op_table
[BPF_JMP_JEQ
];
327 case BPF_JMP_JEQ
| BPF_K
:
328 op
= op_table
[BPF_JMP_JEQ
];
331 case BPF_JMP_JSET
| BPF_X
:
332 op
= op_table
[BPF_JMP_JSET
];
335 case BPF_JMP_JSET
| BPF_K
:
336 op
= op_table
[BPF_JMP_JSET
];
340 op
= op_table
[BPF_ALU_NEG
];
343 case BPF_ALU_LSH
| BPF_X
:
344 op
= op_table
[BPF_ALU_LSH
];
347 case BPF_ALU_LSH
| BPF_K
:
348 op
= op_table
[BPF_ALU_LSH
];
351 case BPF_ALU_RSH
| BPF_X
:
352 op
= op_table
[BPF_ALU_RSH
];
355 case BPF_ALU_RSH
| BPF_K
:
356 op
= op_table
[BPF_ALU_RSH
];
359 case BPF_ALU_ADD
| BPF_X
:
360 op
= op_table
[BPF_ALU_ADD
];
363 case BPF_ALU_ADD
| BPF_K
:
364 op
= op_table
[BPF_ALU_ADD
];
367 case BPF_ALU_SUB
| BPF_X
:
368 op
= op_table
[BPF_ALU_SUB
];
371 case BPF_ALU_SUB
| BPF_K
:
372 op
= op_table
[BPF_ALU_SUB
];
375 case BPF_ALU_MUL
| BPF_X
:
376 op
= op_table
[BPF_ALU_MUL
];
379 case BPF_ALU_MUL
| BPF_K
:
380 op
= op_table
[BPF_ALU_MUL
];
383 case BPF_ALU_DIV
| BPF_X
:
384 op
= op_table
[BPF_ALU_DIV
];
387 case BPF_ALU_DIV
| BPF_K
:
388 op
= op_table
[BPF_ALU_DIV
];
391 case BPF_ALU_MOD
| BPF_X
:
392 op
= op_table
[BPF_ALU_MOD
];
395 case BPF_ALU_MOD
| BPF_K
:
396 op
= op_table
[BPF_ALU_MOD
];
399 case BPF_ALU_AND
| BPF_X
:
400 op
= op_table
[BPF_ALU_AND
];
403 case BPF_ALU_AND
| BPF_K
:
404 op
= op_table
[BPF_ALU_AND
];
407 case BPF_ALU_OR
| BPF_X
:
408 op
= op_table
[BPF_ALU_OR
];
411 case BPF_ALU_OR
| BPF_K
:
412 op
= op_table
[BPF_ALU_OR
];
415 case BPF_ALU_XOR
| BPF_X
:
416 op
= op_table
[BPF_ALU_XOR
];
419 case BPF_ALU_XOR
| BPF_K
:
420 op
= op_table
[BPF_ALU_XOR
];
430 memset(buf
, 0, sizeof(buf
));
431 snprintf(buf
, sizeof(buf
), fmt
, val
);
432 buf
[sizeof(buf
) - 1] = 0;
434 if ((BPF_CLASS(f
.code
) == BPF_JMP
&& BPF_OP(f
.code
) != BPF_JA
))
435 rl_printf("l%d:\t%s %s, l%d, l%d\n", i
, op
, buf
,
436 i
+ 1 + f
.jt
, i
+ 1 + f
.jf
);
438 rl_printf("l%d:\t%s %s\n", i
, op
, buf
);
441 static void bpf_dump_curr(struct bpf_regs
*r
, struct sock_filter
*f
)
445 rl_printf("pc: [%u]\n", r
->Pc
);
446 rl_printf("code: [%u] jt[%u] jf[%u] k[%u]\n",
447 f
->code
, f
->jt
, f
->jf
, f
->k
);
449 bpf_disasm(*f
, r
->Pc
);
451 if (f
->jt
|| f
->jf
) {
453 bpf_disasm(*(f
+ f
->jt
+ 1), r
->Pc
+ f
->jt
+ 1);
455 bpf_disasm(*(f
+ f
->jf
+ 1), r
->Pc
+ f
->jf
+ 1);
458 rl_printf("A: [%#08x][%u]\n", r
->A
, r
->A
);
459 rl_printf("X: [%#08x][%u]\n", r
->X
, r
->X
);
461 rl_printf("ret: [%#08x][%u]!\n", r
->R
, r
->R
);
463 for (i
= 0; i
< BPF_MEMWORDS
; i
++) {
466 rl_printf("M[%d]: [%#08x][%u]\n", i
, r
->M
[i
], r
->M
[i
]);
470 rl_printf("M[0,%d]: [%#08x][%u]\n", BPF_MEMWORDS
- 1, 0, 0);
473 static void bpf_dump_pkt(uint8_t *pkt
, uint32_t pkt_caplen
, uint32_t pkt_len
)
475 if (pkt_caplen
!= pkt_len
)
476 rl_printf("cap: %u, len: %u\n", pkt_caplen
, pkt_len
);
478 rl_printf("len: %u\n", pkt_len
);
480 hex_dump(pkt
, pkt_caplen
);
483 static void bpf_disasm_all(const struct sock_filter
*f
, unsigned int len
)
487 for (i
= 0; i
< len
; i
++)
491 static void bpf_dump_all(const struct sock_filter
*f
, unsigned int len
)
495 rl_printf("/* { op, jt, jf, k }, */\n");
496 for (i
= 0; i
< len
; i
++)
497 rl_printf("{ %#04x, %2u, %2u, %#010x },\n",
498 f
[i
].code
, f
[i
].jt
, f
[i
].jf
, f
[i
].k
);
501 static bool bpf_runnable(struct sock_filter
*f
, unsigned int len
)
504 struct sock_fprog bpf
= {
509 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
511 rl_printf("cannot open socket!\n");
514 ret
= setsockopt(sock
, SOL_SOCKET
, SO_ATTACH_FILTER
, &bpf
, sizeof(bpf
));
517 rl_printf("program not allowed to run by kernel!\n");
520 for (i
= 0; i
< len
; i
++) {
521 if (BPF_CLASS(f
[i
].code
) == BPF_LD
&&
522 f
[i
].k
> SKF_AD_OFF
) {
523 rl_printf("extensions currently not supported!\n");
531 static void bpf_reset_breakpoints(void)
535 for (i
= 0; i
< array_size(bpf_breakpoints
); i
++)
536 bpf_breakpoints
[i
] = -1;
539 static void bpf_set_breakpoints(unsigned int where
)
544 for (i
= 0; i
< array_size(bpf_breakpoints
); i
++) {
545 if (bpf_breakpoints
[i
] == (int) where
) {
546 rl_printf("breakpoint already set!\n");
551 if (bpf_breakpoints
[i
] == -1 && set
== false) {
552 bpf_breakpoints
[i
] = where
;
558 rl_printf("too many breakpoints set, reset first!\n");
561 static void bpf_dump_breakpoints(void)
565 rl_printf("breakpoints: ");
567 for (i
= 0; i
< array_size(bpf_breakpoints
); i
++) {
568 if (bpf_breakpoints
[i
] < 0)
570 rl_printf("%d ", bpf_breakpoints
[i
]);
576 static void bpf_reset(void)
580 memset(bpf_regs
, 0, sizeof(bpf_regs
));
581 memset(&bpf_curr
, 0, sizeof(bpf_curr
));
584 static void bpf_safe_regs(void)
586 memcpy(&bpf_regs
[bpf_regs_len
++], &bpf_curr
, sizeof(bpf_curr
));
589 static bool bpf_restore_regs(int off
)
591 unsigned int index
= bpf_regs_len
- 1 + off
;
596 } else if (index
< bpf_regs_len
) {
597 memcpy(&bpf_curr
, &bpf_regs
[index
], sizeof(bpf_curr
));
598 bpf_regs_len
= index
;
601 rl_printf("reached bottom of register history stack!\n");
606 static uint32_t extract_u32(uint8_t *pkt
, uint32_t off
)
610 memcpy(&r
, &pkt
[off
], sizeof(r
));
615 static uint16_t extract_u16(uint8_t *pkt
, uint32_t off
)
619 memcpy(&r
, &pkt
[off
], sizeof(r
));
624 static uint8_t extract_u8(uint8_t *pkt
, uint32_t off
)
629 static void set_return(struct bpf_regs
*r
)
635 static void bpf_single_step(struct bpf_regs
*r
, struct sock_filter
*f
,
636 uint8_t *pkt
, uint32_t pkt_caplen
,
643 case BPF_RET
| BPF_K
:
647 case BPF_RET
| BPF_A
:
651 case BPF_RET
| BPF_X
:
667 case BPF_LD_W
| BPF_ABS
:
669 if (d
>= sizeof(uint32_t))
670 r
->A
= extract_u32(pkt
, K
);
674 case BPF_LD_H
| BPF_ABS
:
676 if (d
>= sizeof(uint16_t))
677 r
->A
= extract_u16(pkt
, K
);
681 case BPF_LD_B
| BPF_ABS
:
683 if (d
>= sizeof(uint8_t))
684 r
->A
= extract_u8(pkt
, K
);
688 case BPF_LD_W
| BPF_IND
:
689 d
= pkt_caplen
- (r
->X
+ K
);
690 if (d
>= sizeof(uint32_t))
691 r
->A
= extract_u32(pkt
, r
->X
+ K
);
693 case BPF_LD_H
| BPF_IND
:
694 d
= pkt_caplen
- (r
->X
+ K
);
695 if (d
>= sizeof(uint16_t))
696 r
->A
= extract_u16(pkt
, r
->X
+ K
);
700 case BPF_LD_B
| BPF_IND
:
701 d
= pkt_caplen
- (r
->X
+ K
);
702 if (d
>= sizeof(uint8_t))
703 r
->A
= extract_u8(pkt
, r
->X
+ K
);
707 case BPF_LDX_B
| BPF_MSH
:
709 if (d
>= sizeof(uint8_t)) {
710 r
->X
= extract_u8(pkt
, K
);
711 r
->X
= (r
->X
& 0xf) << 2;
715 case BPF_LD_W
| BPF_LEN
:
718 case BPF_LDX_W
| BPF_LEN
:
721 case BPF_LD
| BPF_IMM
:
724 case BPF_LDX
| BPF_IMM
:
727 case BPF_LD
| BPF_MEM
:
730 case BPF_LDX
| BPF_MEM
:
736 case BPF_JMP_JGT
| BPF_X
:
737 r
->Pc
+= r
->A
> r
->X
? f
->jt
: f
->jf
;
739 case BPF_JMP_JGT
| BPF_K
:
740 r
->Pc
+= r
->A
> K
? f
->jt
: f
->jf
;
742 case BPF_JMP_JGE
| BPF_X
:
743 r
->Pc
+= r
->A
>= r
->X
? f
->jt
: f
->jf
;
745 case BPF_JMP_JGE
| BPF_K
:
746 r
->Pc
+= r
->A
>= K
? f
->jt
: f
->jf
;
748 case BPF_JMP_JEQ
| BPF_X
:
749 r
->Pc
+= r
->A
== r
->X
? f
->jt
: f
->jf
;
751 case BPF_JMP_JEQ
| BPF_K
:
752 r
->Pc
+= r
->A
== K
? f
->jt
: f
->jf
;
754 case BPF_JMP_JSET
| BPF_X
:
755 r
->Pc
+= r
->A
& r
->X
? f
->jt
: f
->jf
;
757 case BPF_JMP_JSET
| BPF_K
:
758 r
->Pc
+= r
->A
& K
? f
->jt
: f
->jf
;
763 case BPF_ALU_LSH
| BPF_X
:
766 case BPF_ALU_LSH
| BPF_K
:
769 case BPF_ALU_RSH
| BPF_X
:
772 case BPF_ALU_RSH
| BPF_K
:
775 case BPF_ALU_ADD
| BPF_X
:
778 case BPF_ALU_ADD
| BPF_K
:
781 case BPF_ALU_SUB
| BPF_X
:
784 case BPF_ALU_SUB
| BPF_K
:
787 case BPF_ALU_MUL
| BPF_X
:
790 case BPF_ALU_MUL
| BPF_K
:
793 case BPF_ALU_DIV
| BPF_X
:
794 case BPF_ALU_MOD
| BPF_X
:
800 case BPF_ALU_DIV
| BPF_K
:
801 case BPF_ALU_MOD
| BPF_K
:
808 case BPF_ALU_DIV
| BPF_X
:
811 case BPF_ALU_DIV
| BPF_K
:
814 case BPF_ALU_MOD
| BPF_X
:
817 case BPF_ALU_MOD
| BPF_K
:
822 case BPF_ALU_AND
| BPF_X
:
825 case BPF_ALU_AND
| BPF_K
:
828 case BPF_ALU_OR
| BPF_X
:
831 case BPF_ALU_OR
| BPF_K
:
834 case BPF_ALU_XOR
| BPF_X
:
837 case BPF_ALU_XOR
| BPF_K
:
843 static bool bpf_pc_has_breakpoint(uint16_t pc
)
847 for (i
= 0; i
< array_size(bpf_breakpoints
); i
++) {
848 if (bpf_breakpoints
[i
] < 0)
850 if (bpf_breakpoints
[i
] == pc
)
857 static bool bpf_handle_breakpoint(struct bpf_regs
*r
, struct sock_filter
*f
,
858 uint8_t *pkt
, uint32_t pkt_caplen
,
861 rl_printf("-- register dump --\n");
862 bpf_dump_curr(r
, &f
[r
->Pc
]);
863 rl_printf("-- packet dump --\n");
864 bpf_dump_pkt(pkt
, pkt_caplen
, pkt_len
);
865 rl_printf("(breakpoint)\n");
869 static int bpf_run_all(struct sock_filter
*f
, uint16_t bpf_len
, uint8_t *pkt
,
870 uint32_t pkt_caplen
, uint32_t pkt_len
)
874 while (bpf_curr
.Rs
== false && stop
== false) {
877 if (bpf_pc_has_breakpoint(bpf_curr
.Pc
))
878 stop
= bpf_handle_breakpoint(&bpf_curr
, f
, pkt
,
879 pkt_caplen
, pkt_len
);
881 bpf_single_step(&bpf_curr
, &f
[bpf_curr
.Pc
], pkt
, pkt_caplen
,
886 return stop
? -1 : bpf_curr
.R
;
889 static int bpf_run_stepping(struct sock_filter
*f
, uint16_t bpf_len
,
890 uint8_t *pkt
, uint32_t pkt_caplen
,
891 uint32_t pkt_len
, int next
)
896 while (bpf_curr
.Rs
== false && stop
== false) {
900 stop
= bpf_handle_breakpoint(&bpf_curr
, f
, pkt
,
901 pkt_caplen
, pkt_len
);
903 bpf_single_step(&bpf_curr
, &f
[bpf_curr
.Pc
], pkt
, pkt_caplen
,
908 return stop
? -1 : bpf_curr
.R
;
911 static bool pcap_loaded(void)
914 rl_printf("no pcap file loaded!\n");
919 static struct pcap_pkthdr
*pcap_curr_pkt(void)
921 return (void *) pcap_ptr_va_curr
;
924 static bool pcap_next_pkt(void)
926 struct pcap_pkthdr
*hdr
= pcap_curr_pkt();
928 if (pcap_ptr_va_curr
+ sizeof(*hdr
) -
929 pcap_ptr_va_start
>= pcap_map_size
)
931 if (hdr
->caplen
== 0 || hdr
->len
== 0 || hdr
->caplen
> hdr
->len
)
933 if (pcap_ptr_va_curr
+ sizeof(*hdr
) + hdr
->caplen
-
934 pcap_ptr_va_start
>= pcap_map_size
)
937 pcap_ptr_va_curr
+= (sizeof(*hdr
) + hdr
->caplen
);
941 static void pcap_reset_pkt(void)
943 pcap_ptr_va_curr
= pcap_ptr_va_start
+ sizeof(struct pcap_filehdr
);
946 static int try_load_pcap(const char *file
)
948 struct pcap_filehdr
*hdr
;
952 pcap_fd
= open(file
, O_RDONLY
);
954 rl_printf("cannot open pcap [%s]!\n", strerror(errno
));
958 ret
= fstat(pcap_fd
, &sb
);
960 rl_printf("cannot fstat pcap file!\n");
964 if (!S_ISREG(sb
.st_mode
)) {
965 rl_printf("not a regular pcap file, duh!\n");
969 pcap_map_size
= sb
.st_size
;
970 if (pcap_map_size
<= sizeof(struct pcap_filehdr
)) {
971 rl_printf("pcap file too small!\n");
975 pcap_ptr_va_start
= mmap(NULL
, pcap_map_size
, PROT_READ
,
976 MAP_SHARED
| MAP_LOCKED
, pcap_fd
, 0);
977 if (pcap_ptr_va_start
== MAP_FAILED
) {
978 rl_printf("mmap of file failed!");
982 hdr
= (void *) pcap_ptr_va_start
;
983 if (hdr
->magic
!= TCPDUMP_MAGIC
) {
984 rl_printf("wrong pcap magic!\n");
994 static void try_close_pcap(void)
997 munmap(pcap_ptr_va_start
, pcap_map_size
);
1000 pcap_ptr_va_start
= pcap_ptr_va_curr
= NULL
;
1007 static int cmd_load_bpf(char *bpf_string
)
1009 char sp
, *token
, separator
= ',';
1010 unsigned short bpf_len
, i
= 0;
1011 struct sock_filter tmp
;
1014 memset(bpf_image
, 0, sizeof(bpf_image
));
1016 if (sscanf(bpf_string
, "%hu%c", &bpf_len
, &sp
) != 2 ||
1017 sp
!= separator
|| bpf_len
> BPF_MAXINSNS
|| bpf_len
== 0) {
1018 rl_printf("syntax error in head length encoding!\n");
1023 while ((token
= strchr(token
, separator
)) && (++token
)[0]) {
1025 rl_printf("program exceeds encoded length!\n");
1029 if (sscanf(token
, "%hu %hhu %hhu %u,",
1030 &tmp
.code
, &tmp
.jt
, &tmp
.jf
, &tmp
.k
) != 4) {
1031 rl_printf("syntax error at instruction %d!\n", i
);
1035 bpf_image
[i
].code
= tmp
.code
;
1036 bpf_image
[i
].jt
= tmp
.jt
;
1037 bpf_image
[i
].jf
= tmp
.jf
;
1038 bpf_image
[i
].k
= tmp
.k
;
1044 rl_printf("syntax error exceeding encoded length!\n");
1047 bpf_prog_len
= bpf_len
;
1048 if (!bpf_runnable(bpf_image
, bpf_prog_len
))
1054 static int cmd_load_pcap(char *file
)
1056 char *file_trim
, *tmp
;
1058 file_trim
= strtok_r(file
, " ", &tmp
);
1059 if (file_trim
== NULL
)
1064 return try_load_pcap(file_trim
);
1067 static int cmd_load(char *arg
)
1069 char *subcmd
, *cont
, *tmp
= strdup(arg
);
1072 subcmd
= strtok_r(tmp
, " ", &cont
);
1075 if (matches(subcmd
, "bpf") == 0) {
1077 bpf_reset_breakpoints();
1079 ret
= cmd_load_bpf(cont
);
1080 } else if (matches(subcmd
, "pcap") == 0) {
1081 ret
= cmd_load_pcap(cont
);
1084 rl_printf("bpf <code>: load bpf code\n");
1085 rl_printf("pcap <file>: load pcap file\n");
1093 static int cmd_step(char *num
)
1095 struct pcap_pkthdr
*hdr
;
1098 if (!bpf_prog_loaded() || !pcap_loaded())
1101 steps
= strtol(num
, NULL
, 10);
1102 if (steps
== 0 || strlen(num
) == 0)
1105 if (!bpf_restore_regs(steps
))
1110 hdr
= pcap_curr_pkt();
1111 ret
= bpf_run_stepping(bpf_image
, bpf_prog_len
,
1112 (uint8_t *) hdr
+ sizeof(*hdr
),
1113 hdr
->caplen
, hdr
->len
, steps
);
1114 if (ret
>= 0 || bpf_curr
.Rs
) {
1116 if (!pcap_next_pkt()) {
1117 rl_printf("(going back to first packet)\n");
1120 rl_printf("(next packet)\n");
1127 static int cmd_select(char *num
)
1129 unsigned int which
, i
;
1130 struct pcap_pkthdr
*hdr
;
1131 bool have_next
= true;
1133 if (!pcap_loaded() || strlen(num
) == 0)
1136 which
= strtoul(num
, NULL
, 10);
1138 rl_printf("packet count starts with 1, clamping!\n");
1145 for (i
= 0; i
< which
&& (have_next
= pcap_next_pkt()); i
++)
1147 if (!have_next
|| (hdr
= pcap_curr_pkt()) == NULL
) {
1148 rl_printf("no packet #%u available!\n", which
);
1156 static int cmd_breakpoint(char *subcmd
)
1158 if (!bpf_prog_loaded())
1160 if (strlen(subcmd
) == 0)
1161 bpf_dump_breakpoints();
1162 else if (matches(subcmd
, "reset") == 0)
1163 bpf_reset_breakpoints();
1165 unsigned int where
= strtoul(subcmd
, NULL
, 10);
1167 if (where
< bpf_prog_len
) {
1168 bpf_set_breakpoints(where
);
1169 rl_printf("breakpoint at: ");
1170 bpf_disasm(bpf_image
[where
], where
);
1177 static int cmd_run(char *num
)
1179 static uint32_t pass
= 0, fail
= 0;
1180 struct pcap_pkthdr
*hdr
;
1181 bool has_limit
= true;
1182 int ret
, pkts
= 0, i
= 0;
1184 if (!bpf_prog_loaded() || !pcap_loaded())
1187 pkts
= strtol(num
, NULL
, 10);
1188 if (pkts
== 0 || strlen(num
) == 0)
1192 hdr
= pcap_curr_pkt();
1193 ret
= bpf_run_all(bpf_image
, bpf_prog_len
,
1194 (uint8_t *) hdr
+ sizeof(*hdr
),
1195 hdr
->caplen
, hdr
->len
);
1203 } while (pcap_next_pkt() && (!has_limit
|| (has_limit
&& ++i
< pkts
)));
1205 rl_printf("bpf passes:%u fails:%u\n", pass
, fail
);
1214 static int cmd_disassemble(char *line_string
)
1216 bool single_line
= false;
1219 if (!bpf_prog_loaded())
1221 if (strlen(line_string
) > 0 &&
1222 (line
= strtoul(line_string
, NULL
, 10)) < bpf_prog_len
)
1225 bpf_disasm(bpf_image
[line
], line
);
1227 bpf_disasm_all(bpf_image
, bpf_prog_len
);
1232 static int cmd_dump(char *dontcare
)
1234 if (!bpf_prog_loaded())
1237 bpf_dump_all(bpf_image
, bpf_prog_len
);
1242 static int cmd_quit(char *dontcare
)
1247 static const struct shell_cmd cmds
[] = {
1248 CMD("load", cmd_load
),
1249 CMD("select", cmd_select
),
1250 CMD("step", cmd_step
),
1251 CMD("run", cmd_run
),
1252 CMD("breakpoint", cmd_breakpoint
),
1253 CMD("disassemble", cmd_disassemble
),
1254 CMD("dump", cmd_dump
),
1255 CMD("quit", cmd_quit
),
1258 static int execf(char *arg
)
1260 char *cmd
, *cont
, *tmp
= strdup(arg
);
1261 int i
, ret
= 0, len
;
1263 cmd
= strtok_r(tmp
, " ", &cont
);
1267 for (i
= 0; i
< array_size(cmds
); i
++) {
1268 if (len
!= strlen(cmds
[i
].name
))
1270 if (strncmp(cmds
[i
].name
, cmd
, len
) == 0) {
1271 ret
= cmds
[i
].func(cont
);
1280 static char *shell_comp_gen(const char *buf
, int state
)
1282 static int list_index
, len
;
1290 for (; list_index
< array_size(cmds
); ) {
1291 name
= cmds
[list_index
].name
;
1294 if (strncmp(name
, buf
, len
) == 0)
1295 return strdup(name
);
1301 static char **shell_completion(const char *buf
, int start
, int end
)
1303 char **matches
= NULL
;
1306 matches
= rl_completion_matches(buf
, shell_comp_gen
);
1311 static void intr_shell(int sig
)
1314 rl_kill_line(-1, 0);
1317 rl_refresh_line(0, 0);
1318 rl_free_line_state();
1321 static void init_shell(FILE *fin
, FILE *fout
)
1325 memset(file
, 0, sizeof(file
));
1326 snprintf(file
, sizeof(file
) - 1,
1327 "%s/.bpf_dbg_history", getenv("HOME"));
1331 memset(file
, 0, sizeof(file
));
1332 snprintf(file
, sizeof(file
) - 1,
1333 "%s/.bpf_dbg_init", getenv("HOME"));
1336 rl_outstream
= fout
;
1338 rl_readline_name
= "bpf_dbg";
1339 rl_terminal_name
= getenv("TERM");
1341 rl_catch_signals
= 0;
1342 rl_catch_sigwinch
= 1;
1344 rl_attempted_completion_function
= shell_completion
;
1346 rl_bind_key('\t', rl_complete
);
1348 rl_bind_key_in_map('\t', rl_complete
, emacs_meta_keymap
);
1349 rl_bind_key_in_map('\033', rl_complete
, emacs_meta_keymap
);
1351 rl_read_init_file(file
);
1352 rl_prep_terminal(0);
1355 signal(SIGINT
, intr_shell
);
1358 static void exit_shell(void)
1362 memset(file
, 0, sizeof(file
));
1363 snprintf(file
, sizeof(file
) - 1,
1364 "%s/.bpf_dbg_history", getenv("HOME"));
1366 write_history(file
);
1368 rl_deprep_terminal();
1373 static int run_shell_loop(FILE *fin
, FILE *fout
)
1378 init_shell(fin
, fout
);
1380 while ((buf
= readline("> ")) != NULL
) {
1384 if (ret
== CMD_OK
&& strlen(buf
) > 0)
1394 int main(int argc
, char **argv
)
1396 FILE *fin
= NULL
, *fout
= NULL
;
1399 fin
= fopen(argv
[1], "r");
1401 fout
= fopen(argv
[2], "w");
1403 return run_shell_loop(fin
? : stdin
, fout
? : stdout
);