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))))
98 int (*func
)(char *args
);
101 struct pcap_filehdr
{
103 uint16_t version_major
;
104 uint16_t version_minor
;
111 struct pcap_timeval
{
117 struct pcap_timeval ts
;
125 uint32_t M
[BPF_MEMWORDS
];
131 static struct sock_filter bpf_image
[BPF_MAXINSNS
+ 1];
132 static unsigned int bpf_prog_len
;
134 static int bpf_breakpoints
[64];
135 static struct bpf_regs bpf_regs
[BPF_MAXINSNS
+ 1];
136 static struct bpf_regs bpf_curr
;
137 static unsigned int bpf_regs_len
;
139 static int pcap_fd
= -1;
140 static unsigned int pcap_packet
;
141 static size_t pcap_map_size
;
142 static char *pcap_ptr_va_start
, *pcap_ptr_va_curr
;
144 static const char * const op_table
[] = {
151 [BPF_LDX_B
] = "ldxb",
153 [BPF_JMP_JEQ
] = "jeq",
154 [BPF_JMP_JGT
] = "jgt",
155 [BPF_JMP_JGE
] = "jge",
156 [BPF_JMP_JSET
] = "jset",
157 [BPF_ALU_ADD
] = "add",
158 [BPF_ALU_SUB
] = "sub",
159 [BPF_ALU_MUL
] = "mul",
160 [BPF_ALU_DIV
] = "div",
161 [BPF_ALU_MOD
] = "mod",
162 [BPF_ALU_NEG
] = "neg",
163 [BPF_ALU_AND
] = "and",
165 [BPF_ALU_XOR
] = "xor",
166 [BPF_ALU_LSH
] = "lsh",
167 [BPF_ALU_RSH
] = "rsh",
168 [BPF_MISC_TAX
] = "tax",
169 [BPF_MISC_TXA
] = "txa",
173 static __check_format_printf(1, 2) int rl_printf(const char *fmt
, ...)
179 ret
= vfprintf(rl_outstream
, fmt
, vl
);
185 static int matches(const char *cmd
, const char *pattern
)
187 int len
= strlen(cmd
);
189 if (len
> strlen(pattern
))
192 return memcmp(pattern
, cmd
, len
);
195 static void hex_dump(const uint8_t *buf
, size_t len
)
199 rl_printf("%3u: ", 0);
200 for (i
= 0; i
< len
; i
++) {
202 rl_printf("\n%3u: ", i
);
203 rl_printf("%02x ", buf
[i
]);
208 static bool bpf_prog_loaded(void)
210 if (bpf_prog_len
== 0)
211 rl_printf("no bpf program loaded!\n");
213 return bpf_prog_len
> 0;
216 static void bpf_disasm(const struct sock_filter f
, unsigned int i
)
218 const char *op
, *fmt
;
223 case BPF_RET
| BPF_K
:
224 op
= op_table
[BPF_RET
];
227 case BPF_RET
| BPF_A
:
228 op
= op_table
[BPF_RET
];
231 case BPF_RET
| BPF_X
:
232 op
= op_table
[BPF_RET
];
236 op
= op_table
[BPF_MISC_TAX
];
240 op
= op_table
[BPF_MISC_TXA
];
244 op
= op_table
[BPF_ST
];
248 op
= op_table
[BPF_STX
];
251 case BPF_LD_W
| BPF_ABS
:
252 op
= op_table
[BPF_LD_W
];
255 case BPF_LD_H
| BPF_ABS
:
256 op
= op_table
[BPF_LD_H
];
259 case BPF_LD_B
| BPF_ABS
:
260 op
= op_table
[BPF_LD_B
];
263 case BPF_LD_W
| BPF_LEN
:
264 op
= op_table
[BPF_LD_W
];
267 case BPF_LD_W
| BPF_IND
:
268 op
= op_table
[BPF_LD_W
];
271 case BPF_LD_H
| BPF_IND
:
272 op
= op_table
[BPF_LD_H
];
275 case BPF_LD_B
| BPF_IND
:
276 op
= op_table
[BPF_LD_B
];
279 case BPF_LD
| BPF_IMM
:
280 op
= op_table
[BPF_LD_W
];
283 case BPF_LDX
| BPF_IMM
:
284 op
= op_table
[BPF_LDX
];
287 case BPF_LDX_B
| BPF_MSH
:
288 op
= op_table
[BPF_LDX_B
];
289 fmt
= "4*([%d]&0xf)";
291 case BPF_LD
| BPF_MEM
:
292 op
= op_table
[BPF_LD_W
];
295 case BPF_LDX
| BPF_MEM
:
296 op
= op_table
[BPF_LDX
];
300 op
= op_table
[BPF_JMP_JA
];
304 case BPF_JMP_JGT
| BPF_X
:
305 op
= op_table
[BPF_JMP_JGT
];
308 case BPF_JMP_JGT
| BPF_K
:
309 op
= op_table
[BPF_JMP_JGT
];
312 case BPF_JMP_JGE
| BPF_X
:
313 op
= op_table
[BPF_JMP_JGE
];
316 case BPF_JMP_JGE
| BPF_K
:
317 op
= op_table
[BPF_JMP_JGE
];
320 case BPF_JMP_JEQ
| BPF_X
:
321 op
= op_table
[BPF_JMP_JEQ
];
324 case BPF_JMP_JEQ
| BPF_K
:
325 op
= op_table
[BPF_JMP_JEQ
];
328 case BPF_JMP_JSET
| BPF_X
:
329 op
= op_table
[BPF_JMP_JSET
];
332 case BPF_JMP_JSET
| BPF_K
:
333 op
= op_table
[BPF_JMP_JSET
];
337 op
= op_table
[BPF_ALU_NEG
];
340 case BPF_ALU_LSH
| BPF_X
:
341 op
= op_table
[BPF_ALU_LSH
];
344 case BPF_ALU_LSH
| BPF_K
:
345 op
= op_table
[BPF_ALU_LSH
];
348 case BPF_ALU_RSH
| BPF_X
:
349 op
= op_table
[BPF_ALU_RSH
];
352 case BPF_ALU_RSH
| BPF_K
:
353 op
= op_table
[BPF_ALU_RSH
];
356 case BPF_ALU_ADD
| BPF_X
:
357 op
= op_table
[BPF_ALU_ADD
];
360 case BPF_ALU_ADD
| BPF_K
:
361 op
= op_table
[BPF_ALU_ADD
];
364 case BPF_ALU_SUB
| BPF_X
:
365 op
= op_table
[BPF_ALU_SUB
];
368 case BPF_ALU_SUB
| BPF_K
:
369 op
= op_table
[BPF_ALU_SUB
];
372 case BPF_ALU_MUL
| BPF_X
:
373 op
= op_table
[BPF_ALU_MUL
];
376 case BPF_ALU_MUL
| BPF_K
:
377 op
= op_table
[BPF_ALU_MUL
];
380 case BPF_ALU_DIV
| BPF_X
:
381 op
= op_table
[BPF_ALU_DIV
];
384 case BPF_ALU_DIV
| BPF_K
:
385 op
= op_table
[BPF_ALU_DIV
];
388 case BPF_ALU_MOD
| BPF_X
:
389 op
= op_table
[BPF_ALU_MOD
];
392 case BPF_ALU_MOD
| BPF_K
:
393 op
= op_table
[BPF_ALU_MOD
];
396 case BPF_ALU_AND
| BPF_X
:
397 op
= op_table
[BPF_ALU_AND
];
400 case BPF_ALU_AND
| BPF_K
:
401 op
= op_table
[BPF_ALU_AND
];
404 case BPF_ALU_OR
| BPF_X
:
405 op
= op_table
[BPF_ALU_OR
];
408 case BPF_ALU_OR
| BPF_K
:
409 op
= op_table
[BPF_ALU_OR
];
412 case BPF_ALU_XOR
| BPF_X
:
413 op
= op_table
[BPF_ALU_XOR
];
416 case BPF_ALU_XOR
| BPF_K
:
417 op
= op_table
[BPF_ALU_XOR
];
427 memset(buf
, 0, sizeof(buf
));
428 snprintf(buf
, sizeof(buf
), fmt
, val
);
429 buf
[sizeof(buf
) - 1] = 0;
431 if ((BPF_CLASS(f
.code
) == BPF_JMP
&& BPF_OP(f
.code
) != BPF_JA
))
432 rl_printf("l%d:\t%s %s, l%d, l%d\n", i
, op
, buf
,
433 i
+ 1 + f
.jt
, i
+ 1 + f
.jf
);
435 rl_printf("l%d:\t%s %s\n", i
, op
, buf
);
438 static void bpf_dump_curr(struct bpf_regs
*r
, struct sock_filter
*f
)
442 rl_printf("pc: [%u]\n", r
->Pc
);
443 rl_printf("code: [%u] jt[%u] jf[%u] k[%u]\n",
444 f
->code
, f
->jt
, f
->jf
, f
->k
);
446 bpf_disasm(*f
, r
->Pc
);
448 if (f
->jt
|| f
->jf
) {
450 bpf_disasm(*(f
+ f
->jt
+ 1), r
->Pc
+ f
->jt
+ 1);
452 bpf_disasm(*(f
+ f
->jf
+ 1), r
->Pc
+ f
->jf
+ 1);
455 rl_printf("A: [%#08x][%u]\n", r
->A
, r
->A
);
456 rl_printf("X: [%#08x][%u]\n", r
->X
, r
->X
);
458 rl_printf("ret: [%#08x][%u]!\n", r
->R
, r
->R
);
460 for (i
= 0; i
< BPF_MEMWORDS
; i
++) {
463 rl_printf("M[%d]: [%#08x][%u]\n", i
, r
->M
[i
], r
->M
[i
]);
467 rl_printf("M[0,%d]: [%#08x][%u]\n", BPF_MEMWORDS
- 1, 0, 0);
470 static void bpf_dump_pkt(uint8_t *pkt
, uint32_t pkt_caplen
, uint32_t pkt_len
)
472 if (pkt_caplen
!= pkt_len
)
473 rl_printf("cap: %u, len: %u\n", pkt_caplen
, pkt_len
);
475 rl_printf("len: %u\n", pkt_len
);
477 hex_dump(pkt
, pkt_caplen
);
480 static void bpf_disasm_all(const struct sock_filter
*f
, unsigned int len
)
484 for (i
= 0; i
< len
; i
++)
488 static void bpf_dump_all(const struct sock_filter
*f
, unsigned int len
)
492 rl_printf("/* { op, jt, jf, k }, */\n");
493 for (i
= 0; i
< len
; i
++)
494 rl_printf("{ %#04x, %2u, %2u, %#010x },\n",
495 f
[i
].code
, f
[i
].jt
, f
[i
].jf
, f
[i
].k
);
498 static bool bpf_runnable(struct sock_filter
*f
, unsigned int len
)
501 struct sock_fprog bpf
= {
506 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
508 rl_printf("cannot open socket!\n");
511 ret
= setsockopt(sock
, SOL_SOCKET
, SO_ATTACH_FILTER
, &bpf
, sizeof(bpf
));
514 rl_printf("program not allowed to run by kernel!\n");
517 for (i
= 0; i
< len
; i
++) {
518 if (BPF_CLASS(f
[i
].code
) == BPF_LD
&&
519 f
[i
].k
> SKF_AD_OFF
) {
520 rl_printf("extensions currently not supported!\n");
528 static void bpf_reset_breakpoints(void)
532 for (i
= 0; i
< array_size(bpf_breakpoints
); i
++)
533 bpf_breakpoints
[i
] = -1;
536 static void bpf_set_breakpoints(unsigned int where
)
541 for (i
= 0; i
< array_size(bpf_breakpoints
); i
++) {
542 if (bpf_breakpoints
[i
] == (int) where
) {
543 rl_printf("breakpoint already set!\n");
548 if (bpf_breakpoints
[i
] == -1 && set
== false) {
549 bpf_breakpoints
[i
] = where
;
555 rl_printf("too many breakpoints set, reset first!\n");
558 static void bpf_dump_breakpoints(void)
562 rl_printf("breakpoints: ");
564 for (i
= 0; i
< array_size(bpf_breakpoints
); i
++) {
565 if (bpf_breakpoints
[i
] < 0)
567 rl_printf("%d ", bpf_breakpoints
[i
]);
573 static void bpf_reset(void)
577 memset(bpf_regs
, 0, sizeof(bpf_regs
));
578 memset(&bpf_curr
, 0, sizeof(bpf_curr
));
581 static void bpf_safe_regs(void)
583 memcpy(&bpf_regs
[bpf_regs_len
++], &bpf_curr
, sizeof(bpf_curr
));
586 static bool bpf_restore_regs(int off
)
588 unsigned int index
= bpf_regs_len
- 1 + off
;
593 } else if (index
< bpf_regs_len
) {
594 memcpy(&bpf_curr
, &bpf_regs
[index
], sizeof(bpf_curr
));
595 bpf_regs_len
= index
;
598 rl_printf("reached bottom of register history stack!\n");
603 static uint32_t extract_u32(uint8_t *pkt
, uint32_t off
)
607 memcpy(&r
, &pkt
[off
], sizeof(r
));
612 static uint16_t extract_u16(uint8_t *pkt
, uint32_t off
)
616 memcpy(&r
, &pkt
[off
], sizeof(r
));
621 static uint8_t extract_u8(uint8_t *pkt
, uint32_t off
)
626 static void set_return(struct bpf_regs
*r
)
632 static void bpf_single_step(struct bpf_regs
*r
, struct sock_filter
*f
,
633 uint8_t *pkt
, uint32_t pkt_caplen
,
640 case BPF_RET
| BPF_K
:
644 case BPF_RET
| BPF_A
:
648 case BPF_RET
| BPF_X
:
664 case BPF_LD_W
| BPF_ABS
:
666 if (d
>= sizeof(uint32_t))
667 r
->A
= extract_u32(pkt
, K
);
671 case BPF_LD_H
| BPF_ABS
:
673 if (d
>= sizeof(uint16_t))
674 r
->A
= extract_u16(pkt
, K
);
678 case BPF_LD_B
| BPF_ABS
:
680 if (d
>= sizeof(uint8_t))
681 r
->A
= extract_u8(pkt
, K
);
685 case BPF_LD_W
| BPF_IND
:
686 d
= pkt_caplen
- (r
->X
+ K
);
687 if (d
>= sizeof(uint32_t))
688 r
->A
= extract_u32(pkt
, r
->X
+ K
);
690 case BPF_LD_H
| BPF_IND
:
691 d
= pkt_caplen
- (r
->X
+ K
);
692 if (d
>= sizeof(uint16_t))
693 r
->A
= extract_u16(pkt
, r
->X
+ K
);
697 case BPF_LD_B
| BPF_IND
:
698 d
= pkt_caplen
- (r
->X
+ K
);
699 if (d
>= sizeof(uint8_t))
700 r
->A
= extract_u8(pkt
, r
->X
+ K
);
704 case BPF_LDX_B
| BPF_MSH
:
706 if (d
>= sizeof(uint8_t)) {
707 r
->X
= extract_u8(pkt
, K
);
708 r
->X
= (r
->X
& 0xf) << 2;
712 case BPF_LD_W
| BPF_LEN
:
715 case BPF_LDX_W
| BPF_LEN
:
718 case BPF_LD
| BPF_IMM
:
721 case BPF_LDX
| BPF_IMM
:
724 case BPF_LD
| BPF_MEM
:
727 case BPF_LDX
| BPF_MEM
:
733 case BPF_JMP_JGT
| BPF_X
:
734 r
->Pc
+= r
->A
> r
->X
? f
->jt
: f
->jf
;
736 case BPF_JMP_JGT
| BPF_K
:
737 r
->Pc
+= r
->A
> K
? f
->jt
: f
->jf
;
739 case BPF_JMP_JGE
| BPF_X
:
740 r
->Pc
+= r
->A
>= r
->X
? f
->jt
: f
->jf
;
742 case BPF_JMP_JGE
| BPF_K
:
743 r
->Pc
+= r
->A
>= K
? f
->jt
: f
->jf
;
745 case BPF_JMP_JEQ
| BPF_X
:
746 r
->Pc
+= r
->A
== r
->X
? f
->jt
: f
->jf
;
748 case BPF_JMP_JEQ
| BPF_K
:
749 r
->Pc
+= r
->A
== K
? f
->jt
: f
->jf
;
751 case BPF_JMP_JSET
| BPF_X
:
752 r
->Pc
+= r
->A
& r
->X
? f
->jt
: f
->jf
;
754 case BPF_JMP_JSET
| BPF_K
:
755 r
->Pc
+= r
->A
& K
? f
->jt
: f
->jf
;
760 case BPF_ALU_LSH
| BPF_X
:
763 case BPF_ALU_LSH
| BPF_K
:
766 case BPF_ALU_RSH
| BPF_X
:
769 case BPF_ALU_RSH
| BPF_K
:
772 case BPF_ALU_ADD
| BPF_X
:
775 case BPF_ALU_ADD
| BPF_K
:
778 case BPF_ALU_SUB
| BPF_X
:
781 case BPF_ALU_SUB
| BPF_K
:
784 case BPF_ALU_MUL
| BPF_X
:
787 case BPF_ALU_MUL
| BPF_K
:
790 case BPF_ALU_DIV
| BPF_X
:
791 case BPF_ALU_MOD
| BPF_X
:
797 case BPF_ALU_DIV
| BPF_K
:
798 case BPF_ALU_MOD
| BPF_K
:
805 case BPF_ALU_DIV
| BPF_X
:
808 case BPF_ALU_DIV
| BPF_K
:
811 case BPF_ALU_MOD
| BPF_X
:
814 case BPF_ALU_MOD
| BPF_K
:
819 case BPF_ALU_AND
| BPF_X
:
822 case BPF_ALU_AND
| BPF_K
:
825 case BPF_ALU_OR
| BPF_X
:
828 case BPF_ALU_OR
| BPF_K
:
831 case BPF_ALU_XOR
| BPF_X
:
834 case BPF_ALU_XOR
| BPF_K
:
840 static bool bpf_pc_has_breakpoint(uint16_t pc
)
844 for (i
= 0; i
< array_size(bpf_breakpoints
); i
++) {
845 if (bpf_breakpoints
[i
] < 0)
847 if (bpf_breakpoints
[i
] == pc
)
854 static bool bpf_handle_breakpoint(struct bpf_regs
*r
, struct sock_filter
*f
,
855 uint8_t *pkt
, uint32_t pkt_caplen
,
858 rl_printf("-- register dump --\n");
859 bpf_dump_curr(r
, &f
[r
->Pc
]);
860 rl_printf("-- packet dump --\n");
861 bpf_dump_pkt(pkt
, pkt_caplen
, pkt_len
);
862 rl_printf("(breakpoint)\n");
866 static int bpf_run_all(struct sock_filter
*f
, uint16_t bpf_len
, uint8_t *pkt
,
867 uint32_t pkt_caplen
, uint32_t pkt_len
)
871 while (bpf_curr
.Rs
== false && stop
== false) {
874 if (bpf_pc_has_breakpoint(bpf_curr
.Pc
))
875 stop
= bpf_handle_breakpoint(&bpf_curr
, f
, pkt
,
876 pkt_caplen
, pkt_len
);
878 bpf_single_step(&bpf_curr
, &f
[bpf_curr
.Pc
], pkt
, pkt_caplen
,
883 return stop
? -1 : bpf_curr
.R
;
886 static int bpf_run_stepping(struct sock_filter
*f
, uint16_t bpf_len
,
887 uint8_t *pkt
, uint32_t pkt_caplen
,
888 uint32_t pkt_len
, int next
)
893 while (bpf_curr
.Rs
== false && stop
== false) {
897 stop
= bpf_handle_breakpoint(&bpf_curr
, f
, pkt
,
898 pkt_caplen
, pkt_len
);
900 bpf_single_step(&bpf_curr
, &f
[bpf_curr
.Pc
], pkt
, pkt_caplen
,
905 return stop
? -1 : bpf_curr
.R
;
908 static bool pcap_loaded(void)
911 rl_printf("no pcap file loaded!\n");
916 static struct pcap_pkthdr
*pcap_curr_pkt(void)
918 return (void *) pcap_ptr_va_curr
;
921 static bool pcap_next_pkt(void)
923 struct pcap_pkthdr
*hdr
= pcap_curr_pkt();
925 if (pcap_ptr_va_curr
+ sizeof(*hdr
) -
926 pcap_ptr_va_start
>= pcap_map_size
)
928 if (hdr
->caplen
== 0 || hdr
->len
== 0 || hdr
->caplen
> hdr
->len
)
930 if (pcap_ptr_va_curr
+ sizeof(*hdr
) + hdr
->caplen
-
931 pcap_ptr_va_start
>= pcap_map_size
)
934 pcap_ptr_va_curr
+= (sizeof(*hdr
) + hdr
->caplen
);
938 static void pcap_reset_pkt(void)
940 pcap_ptr_va_curr
= pcap_ptr_va_start
+ sizeof(struct pcap_filehdr
);
943 static int try_load_pcap(const char *file
)
945 struct pcap_filehdr
*hdr
;
949 pcap_fd
= open(file
, O_RDONLY
);
951 rl_printf("cannot open pcap [%s]!\n", strerror(errno
));
955 ret
= fstat(pcap_fd
, &sb
);
957 rl_printf("cannot fstat pcap file!\n");
961 if (!S_ISREG(sb
.st_mode
)) {
962 rl_printf("not a regular pcap file, duh!\n");
966 pcap_map_size
= sb
.st_size
;
967 if (pcap_map_size
<= sizeof(struct pcap_filehdr
)) {
968 rl_printf("pcap file too small!\n");
972 pcap_ptr_va_start
= mmap(NULL
, pcap_map_size
, PROT_READ
,
973 MAP_SHARED
| MAP_LOCKED
, pcap_fd
, 0);
974 if (pcap_ptr_va_start
== MAP_FAILED
) {
975 rl_printf("mmap of file failed!");
979 hdr
= (void *) pcap_ptr_va_start
;
980 if (hdr
->magic
!= TCPDUMP_MAGIC
) {
981 rl_printf("wrong pcap magic!\n");
991 static void try_close_pcap(void)
994 munmap(pcap_ptr_va_start
, pcap_map_size
);
997 pcap_ptr_va_start
= pcap_ptr_va_curr
= NULL
;
1004 static int cmd_load_bpf(char *bpf_string
)
1006 char sp
, *token
, separator
= ',';
1007 unsigned short bpf_len
, i
= 0;
1008 struct sock_filter tmp
;
1011 memset(bpf_image
, 0, sizeof(bpf_image
));
1013 if (sscanf(bpf_string
, "%hu%c", &bpf_len
, &sp
) != 2 ||
1014 sp
!= separator
|| bpf_len
> BPF_MAXINSNS
|| bpf_len
== 0) {
1015 rl_printf("syntax error in head length encoding!\n");
1020 while ((token
= strchr(token
, separator
)) && (++token
)[0]) {
1022 rl_printf("program exceeds encoded length!\n");
1026 if (sscanf(token
, "%hu %hhu %hhu %u,",
1027 &tmp
.code
, &tmp
.jt
, &tmp
.jf
, &tmp
.k
) != 4) {
1028 rl_printf("syntax error at instruction %d!\n", i
);
1032 bpf_image
[i
].code
= tmp
.code
;
1033 bpf_image
[i
].jt
= tmp
.jt
;
1034 bpf_image
[i
].jf
= tmp
.jf
;
1035 bpf_image
[i
].k
= tmp
.k
;
1041 rl_printf("syntax error exceeding encoded length!\n");
1044 bpf_prog_len
= bpf_len
;
1045 if (!bpf_runnable(bpf_image
, bpf_prog_len
))
1051 static int cmd_load_pcap(char *file
)
1053 char *file_trim
, *tmp
;
1055 file_trim
= strtok_r(file
, " ", &tmp
);
1056 if (file_trim
== NULL
)
1061 return try_load_pcap(file_trim
);
1064 static int cmd_load(char *arg
)
1066 char *subcmd
, *cont
= NULL
, *tmp
= strdup(arg
);
1069 subcmd
= strtok_r(tmp
, " ", &cont
);
1072 if (matches(subcmd
, "bpf") == 0) {
1074 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 bool have_next
= true;
1132 if (!pcap_loaded() || strlen(num
) == 0)
1135 which
= strtoul(num
, NULL
, 10);
1137 rl_printf("packet count starts with 1, clamping!\n");
1144 for (i
= 0; i
< which
&& (have_next
= pcap_next_pkt()); i
++)
1146 if (!have_next
|| pcap_curr_pkt() == NULL
) {
1147 rl_printf("no packet #%u available!\n", which
);
1155 static int cmd_breakpoint(char *subcmd
)
1157 if (!bpf_prog_loaded())
1159 if (strlen(subcmd
) == 0)
1160 bpf_dump_breakpoints();
1161 else if (matches(subcmd
, "reset") == 0)
1162 bpf_reset_breakpoints();
1164 unsigned int where
= strtoul(subcmd
, NULL
, 10);
1166 if (where
< bpf_prog_len
) {
1167 bpf_set_breakpoints(where
);
1168 rl_printf("breakpoint at: ");
1169 bpf_disasm(bpf_image
[where
], where
);
1176 static int cmd_run(char *num
)
1178 static uint32_t pass
, fail
;
1179 bool has_limit
= true;
1180 int pkts
= 0, i
= 0;
1182 if (!bpf_prog_loaded() || !pcap_loaded())
1185 pkts
= strtol(num
, NULL
, 10);
1186 if (pkts
== 0 || strlen(num
) == 0)
1190 struct pcap_pkthdr
*hdr
= pcap_curr_pkt();
1191 int ret
= bpf_run_all(bpf_image
, bpf_prog_len
,
1192 (uint8_t *) hdr
+ sizeof(*hdr
),
1193 hdr
->caplen
, hdr
->len
);
1201 } while (pcap_next_pkt() && (!has_limit
|| (has_limit
&& ++i
< pkts
)));
1203 rl_printf("bpf passes:%u fails:%u\n", pass
, fail
);
1212 static int cmd_disassemble(char *line_string
)
1214 bool single_line
= false;
1217 if (!bpf_prog_loaded())
1219 if (strlen(line_string
) > 0 &&
1220 (line
= strtoul(line_string
, NULL
, 10)) < bpf_prog_len
)
1223 bpf_disasm(bpf_image
[line
], line
);
1225 bpf_disasm_all(bpf_image
, bpf_prog_len
);
1230 static int cmd_dump(char *dontcare
)
1232 if (!bpf_prog_loaded())
1235 bpf_dump_all(bpf_image
, bpf_prog_len
);
1240 static int cmd_quit(char *dontcare
)
1245 static const struct shell_cmd cmds
[] = {
1246 { .name
= "load", .func
= cmd_load
},
1247 { .name
= "select", .func
= cmd_select
},
1248 { .name
= "step", .func
= cmd_step
},
1249 { .name
= "run", .func
= cmd_run
},
1250 { .name
= "breakpoint", .func
= cmd_breakpoint
},
1251 { .name
= "disassemble", .func
= cmd_disassemble
},
1252 { .name
= "dump", .func
= cmd_dump
},
1253 { .name
= "quit", .func
= cmd_quit
},
1256 static int execf(char *arg
)
1258 char *cmd
, *cont
, *tmp
= strdup(arg
);
1259 int i
, ret
= 0, len
;
1261 cmd
= strtok_r(tmp
, " ", &cont
);
1265 for (i
= 0; i
< array_size(cmds
); i
++) {
1266 if (len
!= strlen(cmds
[i
].name
))
1268 if (strncmp(cmds
[i
].name
, cmd
, len
) == 0) {
1269 ret
= cmds
[i
].func(cont
);
1278 static char *shell_comp_gen(const char *buf
, int state
)
1280 static int list_index
, len
;
1287 for (; list_index
< array_size(cmds
); ) {
1288 const char *name
= cmds
[list_index
].name
;
1291 if (strncmp(name
, buf
, len
) == 0)
1292 return strdup(name
);
1298 static char **shell_completion(const char *buf
, int start
, int end
)
1300 char **matches
= NULL
;
1303 matches
= rl_completion_matches(buf
, shell_comp_gen
);
1308 static void intr_shell(int sig
)
1311 rl_kill_line(-1, 0);
1314 rl_refresh_line(0, 0);
1315 rl_free_line_state();
1318 static void init_shell(FILE *fin
, FILE *fout
)
1322 snprintf(file
, sizeof(file
), "%s/.bpf_dbg_history", getenv("HOME"));
1326 rl_outstream
= fout
;
1328 rl_readline_name
= "bpf_dbg";
1329 rl_terminal_name
= getenv("TERM");
1331 rl_catch_signals
= 0;
1332 rl_catch_sigwinch
= 1;
1334 rl_attempted_completion_function
= shell_completion
;
1336 rl_bind_key('\t', rl_complete
);
1338 rl_bind_key_in_map('\t', rl_complete
, emacs_meta_keymap
);
1339 rl_bind_key_in_map('\033', rl_complete
, emacs_meta_keymap
);
1341 snprintf(file
, sizeof(file
), "%s/.bpf_dbg_init", getenv("HOME"));
1342 rl_read_init_file(file
);
1344 rl_prep_terminal(0);
1347 signal(SIGINT
, intr_shell
);
1350 static void exit_shell(FILE *fin
, FILE *fout
)
1354 snprintf(file
, sizeof(file
), "%s/.bpf_dbg_history", getenv("HOME"));
1355 write_history(file
);
1358 rl_deprep_terminal();
1368 static int run_shell_loop(FILE *fin
, FILE *fout
)
1372 init_shell(fin
, fout
);
1374 while ((buf
= readline("> ")) != NULL
) {
1375 int ret
= execf(buf
);
1378 if (ret
== CMD_OK
&& strlen(buf
) > 0)
1384 exit_shell(fin
, fout
);
1388 int main(int argc
, char **argv
)
1390 FILE *fin
= NULL
, *fout
= NULL
;
1393 fin
= fopen(argv
[1], "r");
1395 fout
= fopen(argv
[2], "w");
1397 return run_shell_loop(fin
? : stdin
, fout
? : stdout
);