18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Minimal BPF debugger
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Minimal BPF debugger that mimics the kernel's engine (w/o extensions)
68c2ecf20Sopenharmony_ci * and allows for single stepping through selected packets from a pcap
78c2ecf20Sopenharmony_ci * with a provided user filter in order to facilitate verification of a
88c2ecf20Sopenharmony_ci * BPF program. Besides others, this is useful to verify BPF programs
98c2ecf20Sopenharmony_ci * before attaching to a live system, and can be used in socket filters,
108c2ecf20Sopenharmony_ci * cls_bpf, xt_bpf, team driver and e.g. PTP code; in particular when a
118c2ecf20Sopenharmony_ci * single more complex BPF program is being used. Reasons for a more
128c2ecf20Sopenharmony_ci * complex BPF program are likely primarily to optimize execution time
138c2ecf20Sopenharmony_ci * for making a verdict when multiple simple BPF programs are combined
148c2ecf20Sopenharmony_ci * into one in order to prevent parsing same headers multiple times.
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * More on how to debug BPF opcodes see Documentation/networking/filter.rst
178c2ecf20Sopenharmony_ci * which is the main document on BPF. Mini howto for getting started:
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci *  1) `./bpf_dbg` to enter the shell (shell cmds denoted with '>'):
208c2ecf20Sopenharmony_ci *  2) > load bpf 6,40 0 0 12,21 0 3 20... (output from `bpf_asm` or
218c2ecf20Sopenharmony_ci *     `tcpdump -iem1 -ddd port 22 | tr '\n' ','` to load as filter)
228c2ecf20Sopenharmony_ci *  3) > load pcap foo.pcap
238c2ecf20Sopenharmony_ci *  4) > run <n>/disassemble/dump/quit (self-explanatory)
248c2ecf20Sopenharmony_ci *  5) > breakpoint 2 (sets bp at loaded BPF insns 2, do `run` then;
258c2ecf20Sopenharmony_ci *       multiple bps can be set, of course, a call to `breakpoint`
268c2ecf20Sopenharmony_ci *       w/o args shows currently loaded bps, `breakpoint reset` for
278c2ecf20Sopenharmony_ci *       resetting all breakpoints)
288c2ecf20Sopenharmony_ci *  6) > select 3 (`run` etc will start from the 3rd packet in the pcap)
298c2ecf20Sopenharmony_ci *  7) > step [-<n>, +<n>] (performs single stepping through the BPF)
308c2ecf20Sopenharmony_ci *
318c2ecf20Sopenharmony_ci * Copyright 2013 Daniel Borkmann <borkmann@redhat.com>
328c2ecf20Sopenharmony_ci */
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#include <stdio.h>
358c2ecf20Sopenharmony_ci#include <unistd.h>
368c2ecf20Sopenharmony_ci#include <stdlib.h>
378c2ecf20Sopenharmony_ci#include <ctype.h>
388c2ecf20Sopenharmony_ci#include <stdbool.h>
398c2ecf20Sopenharmony_ci#include <stdarg.h>
408c2ecf20Sopenharmony_ci#include <setjmp.h>
418c2ecf20Sopenharmony_ci#include <linux/filter.h>
428c2ecf20Sopenharmony_ci#include <linux/if_packet.h>
438c2ecf20Sopenharmony_ci#include <readline/readline.h>
448c2ecf20Sopenharmony_ci#include <readline/history.h>
458c2ecf20Sopenharmony_ci#include <sys/types.h>
468c2ecf20Sopenharmony_ci#include <sys/socket.h>
478c2ecf20Sopenharmony_ci#include <sys/stat.h>
488c2ecf20Sopenharmony_ci#include <sys/mman.h>
498c2ecf20Sopenharmony_ci#include <fcntl.h>
508c2ecf20Sopenharmony_ci#include <errno.h>
518c2ecf20Sopenharmony_ci#include <signal.h>
528c2ecf20Sopenharmony_ci#include <arpa/inet.h>
538c2ecf20Sopenharmony_ci#include <net/ethernet.h>
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci#define TCPDUMP_MAGIC	0xa1b2c3d4
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci#define BPF_LDX_B	(BPF_LDX | BPF_B)
588c2ecf20Sopenharmony_ci#define BPF_LDX_W	(BPF_LDX | BPF_W)
598c2ecf20Sopenharmony_ci#define BPF_JMP_JA	(BPF_JMP | BPF_JA)
608c2ecf20Sopenharmony_ci#define BPF_JMP_JEQ	(BPF_JMP | BPF_JEQ)
618c2ecf20Sopenharmony_ci#define BPF_JMP_JGT	(BPF_JMP | BPF_JGT)
628c2ecf20Sopenharmony_ci#define BPF_JMP_JGE	(BPF_JMP | BPF_JGE)
638c2ecf20Sopenharmony_ci#define BPF_JMP_JSET	(BPF_JMP | BPF_JSET)
648c2ecf20Sopenharmony_ci#define BPF_ALU_ADD	(BPF_ALU | BPF_ADD)
658c2ecf20Sopenharmony_ci#define BPF_ALU_SUB	(BPF_ALU | BPF_SUB)
668c2ecf20Sopenharmony_ci#define BPF_ALU_MUL	(BPF_ALU | BPF_MUL)
678c2ecf20Sopenharmony_ci#define BPF_ALU_DIV	(BPF_ALU | BPF_DIV)
688c2ecf20Sopenharmony_ci#define BPF_ALU_MOD	(BPF_ALU | BPF_MOD)
698c2ecf20Sopenharmony_ci#define BPF_ALU_NEG	(BPF_ALU | BPF_NEG)
708c2ecf20Sopenharmony_ci#define BPF_ALU_AND	(BPF_ALU | BPF_AND)
718c2ecf20Sopenharmony_ci#define BPF_ALU_OR	(BPF_ALU | BPF_OR)
728c2ecf20Sopenharmony_ci#define BPF_ALU_XOR	(BPF_ALU | BPF_XOR)
738c2ecf20Sopenharmony_ci#define BPF_ALU_LSH	(BPF_ALU | BPF_LSH)
748c2ecf20Sopenharmony_ci#define BPF_ALU_RSH	(BPF_ALU | BPF_RSH)
758c2ecf20Sopenharmony_ci#define BPF_MISC_TAX	(BPF_MISC | BPF_TAX)
768c2ecf20Sopenharmony_ci#define BPF_MISC_TXA	(BPF_MISC | BPF_TXA)
778c2ecf20Sopenharmony_ci#define BPF_LD_B	(BPF_LD | BPF_B)
788c2ecf20Sopenharmony_ci#define BPF_LD_H	(BPF_LD | BPF_H)
798c2ecf20Sopenharmony_ci#define BPF_LD_W	(BPF_LD | BPF_W)
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci#ifndef array_size
828c2ecf20Sopenharmony_ci# define array_size(x)	(sizeof(x) / sizeof((x)[0]))
838c2ecf20Sopenharmony_ci#endif
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci#ifndef __check_format_printf
868c2ecf20Sopenharmony_ci# define __check_format_printf(pos_fmtstr, pos_fmtargs) \
878c2ecf20Sopenharmony_ci	__attribute__ ((format (printf, (pos_fmtstr), (pos_fmtargs))))
888c2ecf20Sopenharmony_ci#endif
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cienum {
918c2ecf20Sopenharmony_ci	CMD_OK,
928c2ecf20Sopenharmony_ci	CMD_ERR,
938c2ecf20Sopenharmony_ci	CMD_EX,
948c2ecf20Sopenharmony_ci};
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistruct shell_cmd {
978c2ecf20Sopenharmony_ci	const char *name;
988c2ecf20Sopenharmony_ci	int (*func)(char *args);
998c2ecf20Sopenharmony_ci};
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistruct pcap_filehdr {
1028c2ecf20Sopenharmony_ci	uint32_t magic;
1038c2ecf20Sopenharmony_ci	uint16_t version_major;
1048c2ecf20Sopenharmony_ci	uint16_t version_minor;
1058c2ecf20Sopenharmony_ci	int32_t  thiszone;
1068c2ecf20Sopenharmony_ci	uint32_t sigfigs;
1078c2ecf20Sopenharmony_ci	uint32_t snaplen;
1088c2ecf20Sopenharmony_ci	uint32_t linktype;
1098c2ecf20Sopenharmony_ci};
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistruct pcap_timeval {
1128c2ecf20Sopenharmony_ci	int32_t tv_sec;
1138c2ecf20Sopenharmony_ci	int32_t tv_usec;
1148c2ecf20Sopenharmony_ci};
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistruct pcap_pkthdr {
1178c2ecf20Sopenharmony_ci	struct pcap_timeval ts;
1188c2ecf20Sopenharmony_ci	uint32_t caplen;
1198c2ecf20Sopenharmony_ci	uint32_t len;
1208c2ecf20Sopenharmony_ci};
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistruct bpf_regs {
1238c2ecf20Sopenharmony_ci	uint32_t A;
1248c2ecf20Sopenharmony_ci	uint32_t X;
1258c2ecf20Sopenharmony_ci	uint32_t M[BPF_MEMWORDS];
1268c2ecf20Sopenharmony_ci	uint32_t R;
1278c2ecf20Sopenharmony_ci	bool     Rs;
1288c2ecf20Sopenharmony_ci	uint16_t Pc;
1298c2ecf20Sopenharmony_ci};
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistatic struct sock_filter bpf_image[BPF_MAXINSNS + 1];
1328c2ecf20Sopenharmony_cistatic unsigned int bpf_prog_len;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistatic int bpf_breakpoints[64];
1358c2ecf20Sopenharmony_cistatic struct bpf_regs bpf_regs[BPF_MAXINSNS + 1];
1368c2ecf20Sopenharmony_cistatic struct bpf_regs bpf_curr;
1378c2ecf20Sopenharmony_cistatic unsigned int bpf_regs_len;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cistatic int pcap_fd = -1;
1408c2ecf20Sopenharmony_cistatic unsigned int pcap_packet;
1418c2ecf20Sopenharmony_cistatic size_t pcap_map_size;
1428c2ecf20Sopenharmony_cistatic char *pcap_ptr_va_start, *pcap_ptr_va_curr;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic const char * const op_table[] = {
1458c2ecf20Sopenharmony_ci	[BPF_ST]	= "st",
1468c2ecf20Sopenharmony_ci	[BPF_STX]	= "stx",
1478c2ecf20Sopenharmony_ci	[BPF_LD_B]	= "ldb",
1488c2ecf20Sopenharmony_ci	[BPF_LD_H]	= "ldh",
1498c2ecf20Sopenharmony_ci	[BPF_LD_W]	= "ld",
1508c2ecf20Sopenharmony_ci	[BPF_LDX]	= "ldx",
1518c2ecf20Sopenharmony_ci	[BPF_LDX_B]	= "ldxb",
1528c2ecf20Sopenharmony_ci	[BPF_JMP_JA]	= "ja",
1538c2ecf20Sopenharmony_ci	[BPF_JMP_JEQ]	= "jeq",
1548c2ecf20Sopenharmony_ci	[BPF_JMP_JGT]	= "jgt",
1558c2ecf20Sopenharmony_ci	[BPF_JMP_JGE]	= "jge",
1568c2ecf20Sopenharmony_ci	[BPF_JMP_JSET]	= "jset",
1578c2ecf20Sopenharmony_ci	[BPF_ALU_ADD]	= "add",
1588c2ecf20Sopenharmony_ci	[BPF_ALU_SUB]	= "sub",
1598c2ecf20Sopenharmony_ci	[BPF_ALU_MUL]	= "mul",
1608c2ecf20Sopenharmony_ci	[BPF_ALU_DIV]	= "div",
1618c2ecf20Sopenharmony_ci	[BPF_ALU_MOD]	= "mod",
1628c2ecf20Sopenharmony_ci	[BPF_ALU_NEG]	= "neg",
1638c2ecf20Sopenharmony_ci	[BPF_ALU_AND]	= "and",
1648c2ecf20Sopenharmony_ci	[BPF_ALU_OR]	= "or",
1658c2ecf20Sopenharmony_ci	[BPF_ALU_XOR]	= "xor",
1668c2ecf20Sopenharmony_ci	[BPF_ALU_LSH]	= "lsh",
1678c2ecf20Sopenharmony_ci	[BPF_ALU_RSH]	= "rsh",
1688c2ecf20Sopenharmony_ci	[BPF_MISC_TAX]	= "tax",
1698c2ecf20Sopenharmony_ci	[BPF_MISC_TXA]	= "txa",
1708c2ecf20Sopenharmony_ci	[BPF_RET]	= "ret",
1718c2ecf20Sopenharmony_ci};
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cistatic __check_format_printf(1, 2) int rl_printf(const char *fmt, ...)
1748c2ecf20Sopenharmony_ci{
1758c2ecf20Sopenharmony_ci	int ret;
1768c2ecf20Sopenharmony_ci	va_list vl;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	va_start(vl, fmt);
1798c2ecf20Sopenharmony_ci	ret = vfprintf(rl_outstream, fmt, vl);
1808c2ecf20Sopenharmony_ci	va_end(vl);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	return ret;
1838c2ecf20Sopenharmony_ci}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_cistatic int matches(const char *cmd, const char *pattern)
1868c2ecf20Sopenharmony_ci{
1878c2ecf20Sopenharmony_ci	int len = strlen(cmd);
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	if (len > strlen(pattern))
1908c2ecf20Sopenharmony_ci		return -1;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	return memcmp(pattern, cmd, len);
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistatic void hex_dump(const uint8_t *buf, size_t len)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci	int i;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	rl_printf("%3u: ", 0);
2008c2ecf20Sopenharmony_ci	for (i = 0; i < len; i++) {
2018c2ecf20Sopenharmony_ci		if (i && !(i % 16))
2028c2ecf20Sopenharmony_ci			rl_printf("\n%3u: ", i);
2038c2ecf20Sopenharmony_ci		rl_printf("%02x ", buf[i]);
2048c2ecf20Sopenharmony_ci	}
2058c2ecf20Sopenharmony_ci	rl_printf("\n");
2068c2ecf20Sopenharmony_ci}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_cistatic bool bpf_prog_loaded(void)
2098c2ecf20Sopenharmony_ci{
2108c2ecf20Sopenharmony_ci	if (bpf_prog_len == 0)
2118c2ecf20Sopenharmony_ci		rl_printf("no bpf program loaded!\n");
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	return bpf_prog_len > 0;
2148c2ecf20Sopenharmony_ci}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_cistatic void bpf_disasm(const struct sock_filter f, unsigned int i)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	const char *op, *fmt;
2198c2ecf20Sopenharmony_ci	int val = f.k;
2208c2ecf20Sopenharmony_ci	char buf[256];
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	switch (f.code) {
2238c2ecf20Sopenharmony_ci	case BPF_RET | BPF_K:
2248c2ecf20Sopenharmony_ci		op = op_table[BPF_RET];
2258c2ecf20Sopenharmony_ci		fmt = "#%#x";
2268c2ecf20Sopenharmony_ci		break;
2278c2ecf20Sopenharmony_ci	case BPF_RET | BPF_A:
2288c2ecf20Sopenharmony_ci		op = op_table[BPF_RET];
2298c2ecf20Sopenharmony_ci		fmt = "a";
2308c2ecf20Sopenharmony_ci		break;
2318c2ecf20Sopenharmony_ci	case BPF_RET | BPF_X:
2328c2ecf20Sopenharmony_ci		op = op_table[BPF_RET];
2338c2ecf20Sopenharmony_ci		fmt = "x";
2348c2ecf20Sopenharmony_ci		break;
2358c2ecf20Sopenharmony_ci	case BPF_MISC_TAX:
2368c2ecf20Sopenharmony_ci		op = op_table[BPF_MISC_TAX];
2378c2ecf20Sopenharmony_ci		fmt = "";
2388c2ecf20Sopenharmony_ci		break;
2398c2ecf20Sopenharmony_ci	case BPF_MISC_TXA:
2408c2ecf20Sopenharmony_ci		op = op_table[BPF_MISC_TXA];
2418c2ecf20Sopenharmony_ci		fmt = "";
2428c2ecf20Sopenharmony_ci		break;
2438c2ecf20Sopenharmony_ci	case BPF_ST:
2448c2ecf20Sopenharmony_ci		op = op_table[BPF_ST];
2458c2ecf20Sopenharmony_ci		fmt = "M[%d]";
2468c2ecf20Sopenharmony_ci		break;
2478c2ecf20Sopenharmony_ci	case BPF_STX:
2488c2ecf20Sopenharmony_ci		op = op_table[BPF_STX];
2498c2ecf20Sopenharmony_ci		fmt = "M[%d]";
2508c2ecf20Sopenharmony_ci		break;
2518c2ecf20Sopenharmony_ci	case BPF_LD_W | BPF_ABS:
2528c2ecf20Sopenharmony_ci		op = op_table[BPF_LD_W];
2538c2ecf20Sopenharmony_ci		fmt = "[%d]";
2548c2ecf20Sopenharmony_ci		break;
2558c2ecf20Sopenharmony_ci	case BPF_LD_H | BPF_ABS:
2568c2ecf20Sopenharmony_ci		op = op_table[BPF_LD_H];
2578c2ecf20Sopenharmony_ci		fmt = "[%d]";
2588c2ecf20Sopenharmony_ci		break;
2598c2ecf20Sopenharmony_ci	case BPF_LD_B | BPF_ABS:
2608c2ecf20Sopenharmony_ci		op = op_table[BPF_LD_B];
2618c2ecf20Sopenharmony_ci		fmt = "[%d]";
2628c2ecf20Sopenharmony_ci		break;
2638c2ecf20Sopenharmony_ci	case BPF_LD_W | BPF_LEN:
2648c2ecf20Sopenharmony_ci		op = op_table[BPF_LD_W];
2658c2ecf20Sopenharmony_ci		fmt = "#len";
2668c2ecf20Sopenharmony_ci		break;
2678c2ecf20Sopenharmony_ci	case BPF_LD_W | BPF_IND:
2688c2ecf20Sopenharmony_ci		op = op_table[BPF_LD_W];
2698c2ecf20Sopenharmony_ci		fmt = "[x+%d]";
2708c2ecf20Sopenharmony_ci		break;
2718c2ecf20Sopenharmony_ci	case BPF_LD_H | BPF_IND:
2728c2ecf20Sopenharmony_ci		op = op_table[BPF_LD_H];
2738c2ecf20Sopenharmony_ci		fmt = "[x+%d]";
2748c2ecf20Sopenharmony_ci		break;
2758c2ecf20Sopenharmony_ci	case BPF_LD_B | BPF_IND:
2768c2ecf20Sopenharmony_ci		op = op_table[BPF_LD_B];
2778c2ecf20Sopenharmony_ci		fmt = "[x+%d]";
2788c2ecf20Sopenharmony_ci		break;
2798c2ecf20Sopenharmony_ci	case BPF_LD | BPF_IMM:
2808c2ecf20Sopenharmony_ci		op = op_table[BPF_LD_W];
2818c2ecf20Sopenharmony_ci		fmt = "#%#x";
2828c2ecf20Sopenharmony_ci		break;
2838c2ecf20Sopenharmony_ci	case BPF_LDX | BPF_IMM:
2848c2ecf20Sopenharmony_ci		op = op_table[BPF_LDX];
2858c2ecf20Sopenharmony_ci		fmt = "#%#x";
2868c2ecf20Sopenharmony_ci		break;
2878c2ecf20Sopenharmony_ci	case BPF_LDX_B | BPF_MSH:
2888c2ecf20Sopenharmony_ci		op = op_table[BPF_LDX_B];
2898c2ecf20Sopenharmony_ci		fmt = "4*([%d]&0xf)";
2908c2ecf20Sopenharmony_ci		break;
2918c2ecf20Sopenharmony_ci	case BPF_LD | BPF_MEM:
2928c2ecf20Sopenharmony_ci		op = op_table[BPF_LD_W];
2938c2ecf20Sopenharmony_ci		fmt = "M[%d]";
2948c2ecf20Sopenharmony_ci		break;
2958c2ecf20Sopenharmony_ci	case BPF_LDX | BPF_MEM:
2968c2ecf20Sopenharmony_ci		op = op_table[BPF_LDX];
2978c2ecf20Sopenharmony_ci		fmt = "M[%d]";
2988c2ecf20Sopenharmony_ci		break;
2998c2ecf20Sopenharmony_ci	case BPF_JMP_JA:
3008c2ecf20Sopenharmony_ci		op = op_table[BPF_JMP_JA];
3018c2ecf20Sopenharmony_ci		fmt = "%d";
3028c2ecf20Sopenharmony_ci		val = i + 1 + f.k;
3038c2ecf20Sopenharmony_ci		break;
3048c2ecf20Sopenharmony_ci	case BPF_JMP_JGT | BPF_X:
3058c2ecf20Sopenharmony_ci		op = op_table[BPF_JMP_JGT];
3068c2ecf20Sopenharmony_ci		fmt = "x";
3078c2ecf20Sopenharmony_ci		break;
3088c2ecf20Sopenharmony_ci	case BPF_JMP_JGT | BPF_K:
3098c2ecf20Sopenharmony_ci		op = op_table[BPF_JMP_JGT];
3108c2ecf20Sopenharmony_ci		fmt = "#%#x";
3118c2ecf20Sopenharmony_ci		break;
3128c2ecf20Sopenharmony_ci	case BPF_JMP_JGE | BPF_X:
3138c2ecf20Sopenharmony_ci		op = op_table[BPF_JMP_JGE];
3148c2ecf20Sopenharmony_ci		fmt = "x";
3158c2ecf20Sopenharmony_ci		break;
3168c2ecf20Sopenharmony_ci	case BPF_JMP_JGE | BPF_K:
3178c2ecf20Sopenharmony_ci		op = op_table[BPF_JMP_JGE];
3188c2ecf20Sopenharmony_ci		fmt = "#%#x";
3198c2ecf20Sopenharmony_ci		break;
3208c2ecf20Sopenharmony_ci	case BPF_JMP_JEQ | BPF_X:
3218c2ecf20Sopenharmony_ci		op = op_table[BPF_JMP_JEQ];
3228c2ecf20Sopenharmony_ci		fmt = "x";
3238c2ecf20Sopenharmony_ci		break;
3248c2ecf20Sopenharmony_ci	case BPF_JMP_JEQ | BPF_K:
3258c2ecf20Sopenharmony_ci		op = op_table[BPF_JMP_JEQ];
3268c2ecf20Sopenharmony_ci		fmt = "#%#x";
3278c2ecf20Sopenharmony_ci		break;
3288c2ecf20Sopenharmony_ci	case BPF_JMP_JSET | BPF_X:
3298c2ecf20Sopenharmony_ci		op = op_table[BPF_JMP_JSET];
3308c2ecf20Sopenharmony_ci		fmt = "x";
3318c2ecf20Sopenharmony_ci		break;
3328c2ecf20Sopenharmony_ci	case BPF_JMP_JSET | BPF_K:
3338c2ecf20Sopenharmony_ci		op = op_table[BPF_JMP_JSET];
3348c2ecf20Sopenharmony_ci		fmt = "#%#x";
3358c2ecf20Sopenharmony_ci		break;
3368c2ecf20Sopenharmony_ci	case BPF_ALU_NEG:
3378c2ecf20Sopenharmony_ci		op = op_table[BPF_ALU_NEG];
3388c2ecf20Sopenharmony_ci		fmt = "";
3398c2ecf20Sopenharmony_ci		break;
3408c2ecf20Sopenharmony_ci	case BPF_ALU_LSH | BPF_X:
3418c2ecf20Sopenharmony_ci		op = op_table[BPF_ALU_LSH];
3428c2ecf20Sopenharmony_ci		fmt = "x";
3438c2ecf20Sopenharmony_ci		break;
3448c2ecf20Sopenharmony_ci	case BPF_ALU_LSH | BPF_K:
3458c2ecf20Sopenharmony_ci		op = op_table[BPF_ALU_LSH];
3468c2ecf20Sopenharmony_ci		fmt = "#%d";
3478c2ecf20Sopenharmony_ci		break;
3488c2ecf20Sopenharmony_ci	case BPF_ALU_RSH | BPF_X:
3498c2ecf20Sopenharmony_ci		op = op_table[BPF_ALU_RSH];
3508c2ecf20Sopenharmony_ci		fmt = "x";
3518c2ecf20Sopenharmony_ci		break;
3528c2ecf20Sopenharmony_ci	case BPF_ALU_RSH | BPF_K:
3538c2ecf20Sopenharmony_ci		op = op_table[BPF_ALU_RSH];
3548c2ecf20Sopenharmony_ci		fmt = "#%d";
3558c2ecf20Sopenharmony_ci		break;
3568c2ecf20Sopenharmony_ci	case BPF_ALU_ADD | BPF_X:
3578c2ecf20Sopenharmony_ci		op = op_table[BPF_ALU_ADD];
3588c2ecf20Sopenharmony_ci		fmt = "x";
3598c2ecf20Sopenharmony_ci		break;
3608c2ecf20Sopenharmony_ci	case BPF_ALU_ADD | BPF_K:
3618c2ecf20Sopenharmony_ci		op = op_table[BPF_ALU_ADD];
3628c2ecf20Sopenharmony_ci		fmt = "#%d";
3638c2ecf20Sopenharmony_ci		break;
3648c2ecf20Sopenharmony_ci	case BPF_ALU_SUB | BPF_X:
3658c2ecf20Sopenharmony_ci		op = op_table[BPF_ALU_SUB];
3668c2ecf20Sopenharmony_ci		fmt = "x";
3678c2ecf20Sopenharmony_ci		break;
3688c2ecf20Sopenharmony_ci	case BPF_ALU_SUB | BPF_K:
3698c2ecf20Sopenharmony_ci		op = op_table[BPF_ALU_SUB];
3708c2ecf20Sopenharmony_ci		fmt = "#%d";
3718c2ecf20Sopenharmony_ci		break;
3728c2ecf20Sopenharmony_ci	case BPF_ALU_MUL | BPF_X:
3738c2ecf20Sopenharmony_ci		op = op_table[BPF_ALU_MUL];
3748c2ecf20Sopenharmony_ci		fmt = "x";
3758c2ecf20Sopenharmony_ci		break;
3768c2ecf20Sopenharmony_ci	case BPF_ALU_MUL | BPF_K:
3778c2ecf20Sopenharmony_ci		op = op_table[BPF_ALU_MUL];
3788c2ecf20Sopenharmony_ci		fmt = "#%d";
3798c2ecf20Sopenharmony_ci		break;
3808c2ecf20Sopenharmony_ci	case BPF_ALU_DIV | BPF_X:
3818c2ecf20Sopenharmony_ci		op = op_table[BPF_ALU_DIV];
3828c2ecf20Sopenharmony_ci		fmt = "x";
3838c2ecf20Sopenharmony_ci		break;
3848c2ecf20Sopenharmony_ci	case BPF_ALU_DIV | BPF_K:
3858c2ecf20Sopenharmony_ci		op = op_table[BPF_ALU_DIV];
3868c2ecf20Sopenharmony_ci		fmt = "#%d";
3878c2ecf20Sopenharmony_ci		break;
3888c2ecf20Sopenharmony_ci	case BPF_ALU_MOD | BPF_X:
3898c2ecf20Sopenharmony_ci		op = op_table[BPF_ALU_MOD];
3908c2ecf20Sopenharmony_ci		fmt = "x";
3918c2ecf20Sopenharmony_ci		break;
3928c2ecf20Sopenharmony_ci	case BPF_ALU_MOD | BPF_K:
3938c2ecf20Sopenharmony_ci		op = op_table[BPF_ALU_MOD];
3948c2ecf20Sopenharmony_ci		fmt = "#%d";
3958c2ecf20Sopenharmony_ci		break;
3968c2ecf20Sopenharmony_ci	case BPF_ALU_AND | BPF_X:
3978c2ecf20Sopenharmony_ci		op = op_table[BPF_ALU_AND];
3988c2ecf20Sopenharmony_ci		fmt = "x";
3998c2ecf20Sopenharmony_ci		break;
4008c2ecf20Sopenharmony_ci	case BPF_ALU_AND | BPF_K:
4018c2ecf20Sopenharmony_ci		op = op_table[BPF_ALU_AND];
4028c2ecf20Sopenharmony_ci		fmt = "#%#x";
4038c2ecf20Sopenharmony_ci		break;
4048c2ecf20Sopenharmony_ci	case BPF_ALU_OR | BPF_X:
4058c2ecf20Sopenharmony_ci		op = op_table[BPF_ALU_OR];
4068c2ecf20Sopenharmony_ci		fmt = "x";
4078c2ecf20Sopenharmony_ci		break;
4088c2ecf20Sopenharmony_ci	case BPF_ALU_OR | BPF_K:
4098c2ecf20Sopenharmony_ci		op = op_table[BPF_ALU_OR];
4108c2ecf20Sopenharmony_ci		fmt = "#%#x";
4118c2ecf20Sopenharmony_ci		break;
4128c2ecf20Sopenharmony_ci	case BPF_ALU_XOR | BPF_X:
4138c2ecf20Sopenharmony_ci		op = op_table[BPF_ALU_XOR];
4148c2ecf20Sopenharmony_ci		fmt = "x";
4158c2ecf20Sopenharmony_ci		break;
4168c2ecf20Sopenharmony_ci	case BPF_ALU_XOR | BPF_K:
4178c2ecf20Sopenharmony_ci		op = op_table[BPF_ALU_XOR];
4188c2ecf20Sopenharmony_ci		fmt = "#%#x";
4198c2ecf20Sopenharmony_ci		break;
4208c2ecf20Sopenharmony_ci	default:
4218c2ecf20Sopenharmony_ci		op = "nosup";
4228c2ecf20Sopenharmony_ci		fmt = "%#x";
4238c2ecf20Sopenharmony_ci		val = f.code;
4248c2ecf20Sopenharmony_ci		break;
4258c2ecf20Sopenharmony_ci	}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	memset(buf, 0, sizeof(buf));
4288c2ecf20Sopenharmony_ci	snprintf(buf, sizeof(buf), fmt, val);
4298c2ecf20Sopenharmony_ci	buf[sizeof(buf) - 1] = 0;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	if ((BPF_CLASS(f.code) == BPF_JMP && BPF_OP(f.code) != BPF_JA))
4328c2ecf20Sopenharmony_ci		rl_printf("l%d:\t%s %s, l%d, l%d\n", i, op, buf,
4338c2ecf20Sopenharmony_ci			  i + 1 + f.jt, i + 1 + f.jf);
4348c2ecf20Sopenharmony_ci	else
4358c2ecf20Sopenharmony_ci		rl_printf("l%d:\t%s %s\n", i, op, buf);
4368c2ecf20Sopenharmony_ci}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_cistatic void bpf_dump_curr(struct bpf_regs *r, struct sock_filter *f)
4398c2ecf20Sopenharmony_ci{
4408c2ecf20Sopenharmony_ci	int i, m = 0;
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	rl_printf("pc:       [%u]\n", r->Pc);
4438c2ecf20Sopenharmony_ci	rl_printf("code:     [%u] jt[%u] jf[%u] k[%u]\n",
4448c2ecf20Sopenharmony_ci		  f->code, f->jt, f->jf, f->k);
4458c2ecf20Sopenharmony_ci	rl_printf("curr:     ");
4468c2ecf20Sopenharmony_ci	bpf_disasm(*f, r->Pc);
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	if (f->jt || f->jf) {
4498c2ecf20Sopenharmony_ci		rl_printf("jt:       ");
4508c2ecf20Sopenharmony_ci		bpf_disasm(*(f + f->jt + 1), r->Pc + f->jt + 1);
4518c2ecf20Sopenharmony_ci		rl_printf("jf:       ");
4528c2ecf20Sopenharmony_ci		bpf_disasm(*(f + f->jf + 1), r->Pc + f->jf + 1);
4538c2ecf20Sopenharmony_ci	}
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	rl_printf("A:        [%#08x][%u]\n", r->A, r->A);
4568c2ecf20Sopenharmony_ci	rl_printf("X:        [%#08x][%u]\n", r->X, r->X);
4578c2ecf20Sopenharmony_ci	if (r->Rs)
4588c2ecf20Sopenharmony_ci		rl_printf("ret:      [%#08x][%u]!\n", r->R, r->R);
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	for (i = 0; i < BPF_MEMWORDS; i++) {
4618c2ecf20Sopenharmony_ci		if (r->M[i]) {
4628c2ecf20Sopenharmony_ci			m++;
4638c2ecf20Sopenharmony_ci			rl_printf("M[%d]: [%#08x][%u]\n", i, r->M[i], r->M[i]);
4648c2ecf20Sopenharmony_ci		}
4658c2ecf20Sopenharmony_ci	}
4668c2ecf20Sopenharmony_ci	if (m == 0)
4678c2ecf20Sopenharmony_ci		rl_printf("M[0,%d]:  [%#08x][%u]\n", BPF_MEMWORDS - 1, 0, 0);
4688c2ecf20Sopenharmony_ci}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_cistatic void bpf_dump_pkt(uint8_t *pkt, uint32_t pkt_caplen, uint32_t pkt_len)
4718c2ecf20Sopenharmony_ci{
4728c2ecf20Sopenharmony_ci	if (pkt_caplen != pkt_len)
4738c2ecf20Sopenharmony_ci		rl_printf("cap: %u, len: %u\n", pkt_caplen, pkt_len);
4748c2ecf20Sopenharmony_ci	else
4758c2ecf20Sopenharmony_ci		rl_printf("len: %u\n", pkt_len);
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	hex_dump(pkt, pkt_caplen);
4788c2ecf20Sopenharmony_ci}
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_cistatic void bpf_disasm_all(const struct sock_filter *f, unsigned int len)
4818c2ecf20Sopenharmony_ci{
4828c2ecf20Sopenharmony_ci	unsigned int i;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	for (i = 0; i < len; i++)
4858c2ecf20Sopenharmony_ci		bpf_disasm(f[i], i);
4868c2ecf20Sopenharmony_ci}
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_cistatic void bpf_dump_all(const struct sock_filter *f, unsigned int len)
4898c2ecf20Sopenharmony_ci{
4908c2ecf20Sopenharmony_ci	unsigned int i;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	rl_printf("/* { op, jt, jf, k }, */\n");
4938c2ecf20Sopenharmony_ci	for (i = 0; i < len; i++)
4948c2ecf20Sopenharmony_ci		rl_printf("{ %#04x, %2u, %2u, %#010x },\n",
4958c2ecf20Sopenharmony_ci			  f[i].code, f[i].jt, f[i].jf, f[i].k);
4968c2ecf20Sopenharmony_ci}
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_cistatic bool bpf_runnable(struct sock_filter *f, unsigned int len)
4998c2ecf20Sopenharmony_ci{
5008c2ecf20Sopenharmony_ci	int sock, ret, i;
5018c2ecf20Sopenharmony_ci	struct sock_fprog bpf = {
5028c2ecf20Sopenharmony_ci		.filter = f,
5038c2ecf20Sopenharmony_ci		.len = len,
5048c2ecf20Sopenharmony_ci	};
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	sock = socket(AF_INET, SOCK_DGRAM, 0);
5078c2ecf20Sopenharmony_ci	if (sock < 0) {
5088c2ecf20Sopenharmony_ci		rl_printf("cannot open socket!\n");
5098c2ecf20Sopenharmony_ci		return false;
5108c2ecf20Sopenharmony_ci	}
5118c2ecf20Sopenharmony_ci	ret = setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf));
5128c2ecf20Sopenharmony_ci	close(sock);
5138c2ecf20Sopenharmony_ci	if (ret < 0) {
5148c2ecf20Sopenharmony_ci		rl_printf("program not allowed to run by kernel!\n");
5158c2ecf20Sopenharmony_ci		return false;
5168c2ecf20Sopenharmony_ci	}
5178c2ecf20Sopenharmony_ci	for (i = 0; i < len; i++) {
5188c2ecf20Sopenharmony_ci		if (BPF_CLASS(f[i].code) == BPF_LD &&
5198c2ecf20Sopenharmony_ci		    f[i].k > SKF_AD_OFF) {
5208c2ecf20Sopenharmony_ci			rl_printf("extensions currently not supported!\n");
5218c2ecf20Sopenharmony_ci			return false;
5228c2ecf20Sopenharmony_ci		}
5238c2ecf20Sopenharmony_ci	}
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	return true;
5268c2ecf20Sopenharmony_ci}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_cistatic void bpf_reset_breakpoints(void)
5298c2ecf20Sopenharmony_ci{
5308c2ecf20Sopenharmony_ci	int i;
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	for (i = 0; i < array_size(bpf_breakpoints); i++)
5338c2ecf20Sopenharmony_ci		bpf_breakpoints[i] = -1;
5348c2ecf20Sopenharmony_ci}
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_cistatic void bpf_set_breakpoints(unsigned int where)
5378c2ecf20Sopenharmony_ci{
5388c2ecf20Sopenharmony_ci	int i;
5398c2ecf20Sopenharmony_ci	bool set = false;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	for (i = 0; i < array_size(bpf_breakpoints); i++) {
5428c2ecf20Sopenharmony_ci		if (bpf_breakpoints[i] == (int) where) {
5438c2ecf20Sopenharmony_ci			rl_printf("breakpoint already set!\n");
5448c2ecf20Sopenharmony_ci			set = true;
5458c2ecf20Sopenharmony_ci			break;
5468c2ecf20Sopenharmony_ci		}
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci		if (bpf_breakpoints[i] == -1 && set == false) {
5498c2ecf20Sopenharmony_ci			bpf_breakpoints[i] = where;
5508c2ecf20Sopenharmony_ci			set = true;
5518c2ecf20Sopenharmony_ci		}
5528c2ecf20Sopenharmony_ci	}
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	if (!set)
5558c2ecf20Sopenharmony_ci		rl_printf("too many breakpoints set, reset first!\n");
5568c2ecf20Sopenharmony_ci}
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_cistatic void bpf_dump_breakpoints(void)
5598c2ecf20Sopenharmony_ci{
5608c2ecf20Sopenharmony_ci	int i;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	rl_printf("breakpoints: ");
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	for (i = 0; i < array_size(bpf_breakpoints); i++) {
5658c2ecf20Sopenharmony_ci		if (bpf_breakpoints[i] < 0)
5668c2ecf20Sopenharmony_ci			continue;
5678c2ecf20Sopenharmony_ci		rl_printf("%d ", bpf_breakpoints[i]);
5688c2ecf20Sopenharmony_ci	}
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	rl_printf("\n");
5718c2ecf20Sopenharmony_ci}
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_cistatic void bpf_reset(void)
5748c2ecf20Sopenharmony_ci{
5758c2ecf20Sopenharmony_ci	bpf_regs_len = 0;
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	memset(bpf_regs, 0, sizeof(bpf_regs));
5788c2ecf20Sopenharmony_ci	memset(&bpf_curr, 0, sizeof(bpf_curr));
5798c2ecf20Sopenharmony_ci}
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_cistatic void bpf_safe_regs(void)
5828c2ecf20Sopenharmony_ci{
5838c2ecf20Sopenharmony_ci	memcpy(&bpf_regs[bpf_regs_len++], &bpf_curr, sizeof(bpf_curr));
5848c2ecf20Sopenharmony_ci}
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_cistatic bool bpf_restore_regs(int off)
5878c2ecf20Sopenharmony_ci{
5888c2ecf20Sopenharmony_ci	unsigned int index = bpf_regs_len - 1 + off;
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	if (index == 0) {
5918c2ecf20Sopenharmony_ci		bpf_reset();
5928c2ecf20Sopenharmony_ci		return true;
5938c2ecf20Sopenharmony_ci	} else if (index < bpf_regs_len) {
5948c2ecf20Sopenharmony_ci		memcpy(&bpf_curr, &bpf_regs[index], sizeof(bpf_curr));
5958c2ecf20Sopenharmony_ci		bpf_regs_len = index;
5968c2ecf20Sopenharmony_ci		return true;
5978c2ecf20Sopenharmony_ci	} else {
5988c2ecf20Sopenharmony_ci		rl_printf("reached bottom of register history stack!\n");
5998c2ecf20Sopenharmony_ci		return false;
6008c2ecf20Sopenharmony_ci	}
6018c2ecf20Sopenharmony_ci}
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_cistatic uint32_t extract_u32(uint8_t *pkt, uint32_t off)
6048c2ecf20Sopenharmony_ci{
6058c2ecf20Sopenharmony_ci	uint32_t r;
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	memcpy(&r, &pkt[off], sizeof(r));
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	return ntohl(r);
6108c2ecf20Sopenharmony_ci}
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_cistatic uint16_t extract_u16(uint8_t *pkt, uint32_t off)
6138c2ecf20Sopenharmony_ci{
6148c2ecf20Sopenharmony_ci	uint16_t r;
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	memcpy(&r, &pkt[off], sizeof(r));
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	return ntohs(r);
6198c2ecf20Sopenharmony_ci}
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_cistatic uint8_t extract_u8(uint8_t *pkt, uint32_t off)
6228c2ecf20Sopenharmony_ci{
6238c2ecf20Sopenharmony_ci	return pkt[off];
6248c2ecf20Sopenharmony_ci}
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_cistatic void set_return(struct bpf_regs *r)
6278c2ecf20Sopenharmony_ci{
6288c2ecf20Sopenharmony_ci	r->R = 0;
6298c2ecf20Sopenharmony_ci	r->Rs = true;
6308c2ecf20Sopenharmony_ci}
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_cistatic void bpf_single_step(struct bpf_regs *r, struct sock_filter *f,
6338c2ecf20Sopenharmony_ci			    uint8_t *pkt, uint32_t pkt_caplen,
6348c2ecf20Sopenharmony_ci			    uint32_t pkt_len)
6358c2ecf20Sopenharmony_ci{
6368c2ecf20Sopenharmony_ci	uint32_t K = f->k;
6378c2ecf20Sopenharmony_ci	int d;
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	switch (f->code) {
6408c2ecf20Sopenharmony_ci	case BPF_RET | BPF_K:
6418c2ecf20Sopenharmony_ci		r->R = K;
6428c2ecf20Sopenharmony_ci		r->Rs = true;
6438c2ecf20Sopenharmony_ci		break;
6448c2ecf20Sopenharmony_ci	case BPF_RET | BPF_A:
6458c2ecf20Sopenharmony_ci		r->R = r->A;
6468c2ecf20Sopenharmony_ci		r->Rs = true;
6478c2ecf20Sopenharmony_ci		break;
6488c2ecf20Sopenharmony_ci	case BPF_RET | BPF_X:
6498c2ecf20Sopenharmony_ci		r->R = r->X;
6508c2ecf20Sopenharmony_ci		r->Rs = true;
6518c2ecf20Sopenharmony_ci		break;
6528c2ecf20Sopenharmony_ci	case BPF_MISC_TAX:
6538c2ecf20Sopenharmony_ci		r->X = r->A;
6548c2ecf20Sopenharmony_ci		break;
6558c2ecf20Sopenharmony_ci	case BPF_MISC_TXA:
6568c2ecf20Sopenharmony_ci		r->A = r->X;
6578c2ecf20Sopenharmony_ci		break;
6588c2ecf20Sopenharmony_ci	case BPF_ST:
6598c2ecf20Sopenharmony_ci		r->M[K] = r->A;
6608c2ecf20Sopenharmony_ci		break;
6618c2ecf20Sopenharmony_ci	case BPF_STX:
6628c2ecf20Sopenharmony_ci		r->M[K] = r->X;
6638c2ecf20Sopenharmony_ci		break;
6648c2ecf20Sopenharmony_ci	case BPF_LD_W | BPF_ABS:
6658c2ecf20Sopenharmony_ci		d = pkt_caplen - K;
6668c2ecf20Sopenharmony_ci		if (d >= sizeof(uint32_t))
6678c2ecf20Sopenharmony_ci			r->A = extract_u32(pkt, K);
6688c2ecf20Sopenharmony_ci		else
6698c2ecf20Sopenharmony_ci			set_return(r);
6708c2ecf20Sopenharmony_ci		break;
6718c2ecf20Sopenharmony_ci	case BPF_LD_H | BPF_ABS:
6728c2ecf20Sopenharmony_ci		d = pkt_caplen - K;
6738c2ecf20Sopenharmony_ci		if (d >= sizeof(uint16_t))
6748c2ecf20Sopenharmony_ci			r->A = extract_u16(pkt, K);
6758c2ecf20Sopenharmony_ci		else
6768c2ecf20Sopenharmony_ci			set_return(r);
6778c2ecf20Sopenharmony_ci		break;
6788c2ecf20Sopenharmony_ci	case BPF_LD_B | BPF_ABS:
6798c2ecf20Sopenharmony_ci		d = pkt_caplen - K;
6808c2ecf20Sopenharmony_ci		if (d >= sizeof(uint8_t))
6818c2ecf20Sopenharmony_ci			r->A = extract_u8(pkt, K);
6828c2ecf20Sopenharmony_ci		else
6838c2ecf20Sopenharmony_ci			set_return(r);
6848c2ecf20Sopenharmony_ci		break;
6858c2ecf20Sopenharmony_ci	case BPF_LD_W | BPF_IND:
6868c2ecf20Sopenharmony_ci		d = pkt_caplen - (r->X + K);
6878c2ecf20Sopenharmony_ci		if (d >= sizeof(uint32_t))
6888c2ecf20Sopenharmony_ci			r->A = extract_u32(pkt, r->X + K);
6898c2ecf20Sopenharmony_ci		break;
6908c2ecf20Sopenharmony_ci	case BPF_LD_H | BPF_IND:
6918c2ecf20Sopenharmony_ci		d = pkt_caplen - (r->X + K);
6928c2ecf20Sopenharmony_ci		if (d >= sizeof(uint16_t))
6938c2ecf20Sopenharmony_ci			r->A = extract_u16(pkt, r->X + K);
6948c2ecf20Sopenharmony_ci		else
6958c2ecf20Sopenharmony_ci			set_return(r);
6968c2ecf20Sopenharmony_ci		break;
6978c2ecf20Sopenharmony_ci	case BPF_LD_B | BPF_IND:
6988c2ecf20Sopenharmony_ci		d = pkt_caplen - (r->X + K);
6998c2ecf20Sopenharmony_ci		if (d >= sizeof(uint8_t))
7008c2ecf20Sopenharmony_ci			r->A = extract_u8(pkt, r->X + K);
7018c2ecf20Sopenharmony_ci		else
7028c2ecf20Sopenharmony_ci			set_return(r);
7038c2ecf20Sopenharmony_ci		break;
7048c2ecf20Sopenharmony_ci	case BPF_LDX_B | BPF_MSH:
7058c2ecf20Sopenharmony_ci		d = pkt_caplen - K;
7068c2ecf20Sopenharmony_ci		if (d >= sizeof(uint8_t)) {
7078c2ecf20Sopenharmony_ci			r->X = extract_u8(pkt, K);
7088c2ecf20Sopenharmony_ci			r->X = (r->X & 0xf) << 2;
7098c2ecf20Sopenharmony_ci		} else
7108c2ecf20Sopenharmony_ci			set_return(r);
7118c2ecf20Sopenharmony_ci		break;
7128c2ecf20Sopenharmony_ci	case BPF_LD_W | BPF_LEN:
7138c2ecf20Sopenharmony_ci		r->A = pkt_len;
7148c2ecf20Sopenharmony_ci		break;
7158c2ecf20Sopenharmony_ci	case BPF_LDX_W | BPF_LEN:
7168c2ecf20Sopenharmony_ci		r->A = pkt_len;
7178c2ecf20Sopenharmony_ci		break;
7188c2ecf20Sopenharmony_ci	case BPF_LD | BPF_IMM:
7198c2ecf20Sopenharmony_ci		r->A = K;
7208c2ecf20Sopenharmony_ci		break;
7218c2ecf20Sopenharmony_ci	case BPF_LDX | BPF_IMM:
7228c2ecf20Sopenharmony_ci		r->X = K;
7238c2ecf20Sopenharmony_ci		break;
7248c2ecf20Sopenharmony_ci	case BPF_LD | BPF_MEM:
7258c2ecf20Sopenharmony_ci		r->A = r->M[K];
7268c2ecf20Sopenharmony_ci		break;
7278c2ecf20Sopenharmony_ci	case BPF_LDX | BPF_MEM:
7288c2ecf20Sopenharmony_ci		r->X = r->M[K];
7298c2ecf20Sopenharmony_ci		break;
7308c2ecf20Sopenharmony_ci	case BPF_JMP_JA:
7318c2ecf20Sopenharmony_ci		r->Pc += K;
7328c2ecf20Sopenharmony_ci		break;
7338c2ecf20Sopenharmony_ci	case BPF_JMP_JGT | BPF_X:
7348c2ecf20Sopenharmony_ci		r->Pc += r->A > r->X ? f->jt : f->jf;
7358c2ecf20Sopenharmony_ci		break;
7368c2ecf20Sopenharmony_ci	case BPF_JMP_JGT | BPF_K:
7378c2ecf20Sopenharmony_ci		r->Pc += r->A > K ? f->jt : f->jf;
7388c2ecf20Sopenharmony_ci		break;
7398c2ecf20Sopenharmony_ci	case BPF_JMP_JGE | BPF_X:
7408c2ecf20Sopenharmony_ci		r->Pc += r->A >= r->X ? f->jt : f->jf;
7418c2ecf20Sopenharmony_ci		break;
7428c2ecf20Sopenharmony_ci	case BPF_JMP_JGE | BPF_K:
7438c2ecf20Sopenharmony_ci		r->Pc += r->A >= K ? f->jt : f->jf;
7448c2ecf20Sopenharmony_ci		break;
7458c2ecf20Sopenharmony_ci	case BPF_JMP_JEQ | BPF_X:
7468c2ecf20Sopenharmony_ci		r->Pc += r->A == r->X ? f->jt : f->jf;
7478c2ecf20Sopenharmony_ci		break;
7488c2ecf20Sopenharmony_ci	case BPF_JMP_JEQ | BPF_K:
7498c2ecf20Sopenharmony_ci		r->Pc += r->A == K ? f->jt : f->jf;
7508c2ecf20Sopenharmony_ci		break;
7518c2ecf20Sopenharmony_ci	case BPF_JMP_JSET | BPF_X:
7528c2ecf20Sopenharmony_ci		r->Pc += r->A & r->X ? f->jt : f->jf;
7538c2ecf20Sopenharmony_ci		break;
7548c2ecf20Sopenharmony_ci	case BPF_JMP_JSET | BPF_K:
7558c2ecf20Sopenharmony_ci		r->Pc += r->A & K ? f->jt : f->jf;
7568c2ecf20Sopenharmony_ci		break;
7578c2ecf20Sopenharmony_ci	case BPF_ALU_NEG:
7588c2ecf20Sopenharmony_ci		r->A = -r->A;
7598c2ecf20Sopenharmony_ci		break;
7608c2ecf20Sopenharmony_ci	case BPF_ALU_LSH | BPF_X:
7618c2ecf20Sopenharmony_ci		r->A <<= r->X;
7628c2ecf20Sopenharmony_ci		break;
7638c2ecf20Sopenharmony_ci	case BPF_ALU_LSH | BPF_K:
7648c2ecf20Sopenharmony_ci		r->A <<= K;
7658c2ecf20Sopenharmony_ci		break;
7668c2ecf20Sopenharmony_ci	case BPF_ALU_RSH | BPF_X:
7678c2ecf20Sopenharmony_ci		r->A >>= r->X;
7688c2ecf20Sopenharmony_ci		break;
7698c2ecf20Sopenharmony_ci	case BPF_ALU_RSH | BPF_K:
7708c2ecf20Sopenharmony_ci		r->A >>= K;
7718c2ecf20Sopenharmony_ci		break;
7728c2ecf20Sopenharmony_ci	case BPF_ALU_ADD | BPF_X:
7738c2ecf20Sopenharmony_ci		r->A += r->X;
7748c2ecf20Sopenharmony_ci		break;
7758c2ecf20Sopenharmony_ci	case BPF_ALU_ADD | BPF_K:
7768c2ecf20Sopenharmony_ci		r->A += K;
7778c2ecf20Sopenharmony_ci		break;
7788c2ecf20Sopenharmony_ci	case BPF_ALU_SUB | BPF_X:
7798c2ecf20Sopenharmony_ci		r->A -= r->X;
7808c2ecf20Sopenharmony_ci		break;
7818c2ecf20Sopenharmony_ci	case BPF_ALU_SUB | BPF_K:
7828c2ecf20Sopenharmony_ci		r->A -= K;
7838c2ecf20Sopenharmony_ci		break;
7848c2ecf20Sopenharmony_ci	case BPF_ALU_MUL | BPF_X:
7858c2ecf20Sopenharmony_ci		r->A *= r->X;
7868c2ecf20Sopenharmony_ci		break;
7878c2ecf20Sopenharmony_ci	case BPF_ALU_MUL | BPF_K:
7888c2ecf20Sopenharmony_ci		r->A *= K;
7898c2ecf20Sopenharmony_ci		break;
7908c2ecf20Sopenharmony_ci	case BPF_ALU_DIV | BPF_X:
7918c2ecf20Sopenharmony_ci	case BPF_ALU_MOD | BPF_X:
7928c2ecf20Sopenharmony_ci		if (r->X == 0) {
7938c2ecf20Sopenharmony_ci			set_return(r);
7948c2ecf20Sopenharmony_ci			break;
7958c2ecf20Sopenharmony_ci		}
7968c2ecf20Sopenharmony_ci		goto do_div;
7978c2ecf20Sopenharmony_ci	case BPF_ALU_DIV | BPF_K:
7988c2ecf20Sopenharmony_ci	case BPF_ALU_MOD | BPF_K:
7998c2ecf20Sopenharmony_ci		if (K == 0) {
8008c2ecf20Sopenharmony_ci			set_return(r);
8018c2ecf20Sopenharmony_ci			break;
8028c2ecf20Sopenharmony_ci		}
8038c2ecf20Sopenharmony_cido_div:
8048c2ecf20Sopenharmony_ci		switch (f->code) {
8058c2ecf20Sopenharmony_ci		case BPF_ALU_DIV | BPF_X:
8068c2ecf20Sopenharmony_ci			r->A /= r->X;
8078c2ecf20Sopenharmony_ci			break;
8088c2ecf20Sopenharmony_ci		case BPF_ALU_DIV | BPF_K:
8098c2ecf20Sopenharmony_ci			r->A /= K;
8108c2ecf20Sopenharmony_ci			break;
8118c2ecf20Sopenharmony_ci		case BPF_ALU_MOD | BPF_X:
8128c2ecf20Sopenharmony_ci			r->A %= r->X;
8138c2ecf20Sopenharmony_ci			break;
8148c2ecf20Sopenharmony_ci		case BPF_ALU_MOD | BPF_K:
8158c2ecf20Sopenharmony_ci			r->A %= K;
8168c2ecf20Sopenharmony_ci			break;
8178c2ecf20Sopenharmony_ci		}
8188c2ecf20Sopenharmony_ci		break;
8198c2ecf20Sopenharmony_ci	case BPF_ALU_AND | BPF_X:
8208c2ecf20Sopenharmony_ci		r->A &= r->X;
8218c2ecf20Sopenharmony_ci		break;
8228c2ecf20Sopenharmony_ci	case BPF_ALU_AND | BPF_K:
8238c2ecf20Sopenharmony_ci		r->A &= K;
8248c2ecf20Sopenharmony_ci		break;
8258c2ecf20Sopenharmony_ci	case BPF_ALU_OR | BPF_X:
8268c2ecf20Sopenharmony_ci		r->A |= r->X;
8278c2ecf20Sopenharmony_ci		break;
8288c2ecf20Sopenharmony_ci	case BPF_ALU_OR | BPF_K:
8298c2ecf20Sopenharmony_ci		r->A |= K;
8308c2ecf20Sopenharmony_ci		break;
8318c2ecf20Sopenharmony_ci	case BPF_ALU_XOR | BPF_X:
8328c2ecf20Sopenharmony_ci		r->A ^= r->X;
8338c2ecf20Sopenharmony_ci		break;
8348c2ecf20Sopenharmony_ci	case BPF_ALU_XOR | BPF_K:
8358c2ecf20Sopenharmony_ci		r->A ^= K;
8368c2ecf20Sopenharmony_ci		break;
8378c2ecf20Sopenharmony_ci	}
8388c2ecf20Sopenharmony_ci}
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_cistatic bool bpf_pc_has_breakpoint(uint16_t pc)
8418c2ecf20Sopenharmony_ci{
8428c2ecf20Sopenharmony_ci	int i;
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	for (i = 0; i < array_size(bpf_breakpoints); i++) {
8458c2ecf20Sopenharmony_ci		if (bpf_breakpoints[i] < 0)
8468c2ecf20Sopenharmony_ci			continue;
8478c2ecf20Sopenharmony_ci		if (bpf_breakpoints[i] == pc)
8488c2ecf20Sopenharmony_ci			return true;
8498c2ecf20Sopenharmony_ci	}
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	return false;
8528c2ecf20Sopenharmony_ci}
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_cistatic bool bpf_handle_breakpoint(struct bpf_regs *r, struct sock_filter *f,
8558c2ecf20Sopenharmony_ci				  uint8_t *pkt, uint32_t pkt_caplen,
8568c2ecf20Sopenharmony_ci				  uint32_t pkt_len)
8578c2ecf20Sopenharmony_ci{
8588c2ecf20Sopenharmony_ci	rl_printf("-- register dump --\n");
8598c2ecf20Sopenharmony_ci	bpf_dump_curr(r, &f[r->Pc]);
8608c2ecf20Sopenharmony_ci	rl_printf("-- packet dump --\n");
8618c2ecf20Sopenharmony_ci	bpf_dump_pkt(pkt, pkt_caplen, pkt_len);
8628c2ecf20Sopenharmony_ci	rl_printf("(breakpoint)\n");
8638c2ecf20Sopenharmony_ci	return true;
8648c2ecf20Sopenharmony_ci}
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_cistatic int bpf_run_all(struct sock_filter *f, uint16_t bpf_len, uint8_t *pkt,
8678c2ecf20Sopenharmony_ci		       uint32_t pkt_caplen, uint32_t pkt_len)
8688c2ecf20Sopenharmony_ci{
8698c2ecf20Sopenharmony_ci	bool stop = false;
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	while (bpf_curr.Rs == false && stop == false) {
8728c2ecf20Sopenharmony_ci		bpf_safe_regs();
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci		if (bpf_pc_has_breakpoint(bpf_curr.Pc))
8758c2ecf20Sopenharmony_ci			stop = bpf_handle_breakpoint(&bpf_curr, f, pkt,
8768c2ecf20Sopenharmony_ci						     pkt_caplen, pkt_len);
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci		bpf_single_step(&bpf_curr, &f[bpf_curr.Pc], pkt, pkt_caplen,
8798c2ecf20Sopenharmony_ci				pkt_len);
8808c2ecf20Sopenharmony_ci		bpf_curr.Pc++;
8818c2ecf20Sopenharmony_ci	}
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	return stop ? -1 : bpf_curr.R;
8848c2ecf20Sopenharmony_ci}
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_cistatic int bpf_run_stepping(struct sock_filter *f, uint16_t bpf_len,
8878c2ecf20Sopenharmony_ci			    uint8_t *pkt, uint32_t pkt_caplen,
8888c2ecf20Sopenharmony_ci			    uint32_t pkt_len, int next)
8898c2ecf20Sopenharmony_ci{
8908c2ecf20Sopenharmony_ci	bool stop = false;
8918c2ecf20Sopenharmony_ci	int i = 1;
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	while (bpf_curr.Rs == false && stop == false) {
8948c2ecf20Sopenharmony_ci		bpf_safe_regs();
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci		if (i++ == next)
8978c2ecf20Sopenharmony_ci			stop = bpf_handle_breakpoint(&bpf_curr, f, pkt,
8988c2ecf20Sopenharmony_ci						     pkt_caplen, pkt_len);
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci		bpf_single_step(&bpf_curr, &f[bpf_curr.Pc], pkt, pkt_caplen,
9018c2ecf20Sopenharmony_ci				pkt_len);
9028c2ecf20Sopenharmony_ci		bpf_curr.Pc++;
9038c2ecf20Sopenharmony_ci	}
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	return stop ? -1 : bpf_curr.R;
9068c2ecf20Sopenharmony_ci}
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_cistatic bool pcap_loaded(void)
9098c2ecf20Sopenharmony_ci{
9108c2ecf20Sopenharmony_ci	if (pcap_fd < 0)
9118c2ecf20Sopenharmony_ci		rl_printf("no pcap file loaded!\n");
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci	return pcap_fd >= 0;
9148c2ecf20Sopenharmony_ci}
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_cistatic struct pcap_pkthdr *pcap_curr_pkt(void)
9178c2ecf20Sopenharmony_ci{
9188c2ecf20Sopenharmony_ci	return (void *) pcap_ptr_va_curr;
9198c2ecf20Sopenharmony_ci}
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_cistatic bool pcap_next_pkt(void)
9228c2ecf20Sopenharmony_ci{
9238c2ecf20Sopenharmony_ci	struct pcap_pkthdr *hdr = pcap_curr_pkt();
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ci	if (pcap_ptr_va_curr + sizeof(*hdr) -
9268c2ecf20Sopenharmony_ci	    pcap_ptr_va_start >= pcap_map_size)
9278c2ecf20Sopenharmony_ci		return false;
9288c2ecf20Sopenharmony_ci	if (hdr->caplen == 0 || hdr->len == 0 || hdr->caplen > hdr->len)
9298c2ecf20Sopenharmony_ci		return false;
9308c2ecf20Sopenharmony_ci	if (pcap_ptr_va_curr + sizeof(*hdr) + hdr->caplen -
9318c2ecf20Sopenharmony_ci	    pcap_ptr_va_start >= pcap_map_size)
9328c2ecf20Sopenharmony_ci		return false;
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	pcap_ptr_va_curr += (sizeof(*hdr) + hdr->caplen);
9358c2ecf20Sopenharmony_ci	return true;
9368c2ecf20Sopenharmony_ci}
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_cistatic void pcap_reset_pkt(void)
9398c2ecf20Sopenharmony_ci{
9408c2ecf20Sopenharmony_ci	pcap_ptr_va_curr = pcap_ptr_va_start + sizeof(struct pcap_filehdr);
9418c2ecf20Sopenharmony_ci}
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_cistatic int try_load_pcap(const char *file)
9448c2ecf20Sopenharmony_ci{
9458c2ecf20Sopenharmony_ci	struct pcap_filehdr *hdr;
9468c2ecf20Sopenharmony_ci	struct stat sb;
9478c2ecf20Sopenharmony_ci	int ret;
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci	pcap_fd = open(file, O_RDONLY);
9508c2ecf20Sopenharmony_ci	if (pcap_fd < 0) {
9518c2ecf20Sopenharmony_ci		rl_printf("cannot open pcap [%s]!\n", strerror(errno));
9528c2ecf20Sopenharmony_ci		return CMD_ERR;
9538c2ecf20Sopenharmony_ci	}
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	ret = fstat(pcap_fd, &sb);
9568c2ecf20Sopenharmony_ci	if (ret < 0) {
9578c2ecf20Sopenharmony_ci		rl_printf("cannot fstat pcap file!\n");
9588c2ecf20Sopenharmony_ci		return CMD_ERR;
9598c2ecf20Sopenharmony_ci	}
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	if (!S_ISREG(sb.st_mode)) {
9628c2ecf20Sopenharmony_ci		rl_printf("not a regular pcap file, duh!\n");
9638c2ecf20Sopenharmony_ci		return CMD_ERR;
9648c2ecf20Sopenharmony_ci	}
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	pcap_map_size = sb.st_size;
9678c2ecf20Sopenharmony_ci	if (pcap_map_size <= sizeof(struct pcap_filehdr)) {
9688c2ecf20Sopenharmony_ci		rl_printf("pcap file too small!\n");
9698c2ecf20Sopenharmony_ci		return CMD_ERR;
9708c2ecf20Sopenharmony_ci	}
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci	pcap_ptr_va_start = mmap(NULL, pcap_map_size, PROT_READ,
9738c2ecf20Sopenharmony_ci				 MAP_SHARED | MAP_LOCKED, pcap_fd, 0);
9748c2ecf20Sopenharmony_ci	if (pcap_ptr_va_start == MAP_FAILED) {
9758c2ecf20Sopenharmony_ci		rl_printf("mmap of file failed!");
9768c2ecf20Sopenharmony_ci		return CMD_ERR;
9778c2ecf20Sopenharmony_ci	}
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci	hdr = (void *) pcap_ptr_va_start;
9808c2ecf20Sopenharmony_ci	if (hdr->magic != TCPDUMP_MAGIC) {
9818c2ecf20Sopenharmony_ci		rl_printf("wrong pcap magic!\n");
9828c2ecf20Sopenharmony_ci		return CMD_ERR;
9838c2ecf20Sopenharmony_ci	}
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	pcap_reset_pkt();
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci	return CMD_OK;
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci}
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_cistatic void try_close_pcap(void)
9928c2ecf20Sopenharmony_ci{
9938c2ecf20Sopenharmony_ci	if (pcap_fd >= 0) {
9948c2ecf20Sopenharmony_ci		munmap(pcap_ptr_va_start, pcap_map_size);
9958c2ecf20Sopenharmony_ci		close(pcap_fd);
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci		pcap_ptr_va_start = pcap_ptr_va_curr = NULL;
9988c2ecf20Sopenharmony_ci		pcap_map_size = 0;
9998c2ecf20Sopenharmony_ci		pcap_packet = 0;
10008c2ecf20Sopenharmony_ci		pcap_fd = -1;
10018c2ecf20Sopenharmony_ci	}
10028c2ecf20Sopenharmony_ci}
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_cistatic int cmd_load_bpf(char *bpf_string)
10058c2ecf20Sopenharmony_ci{
10068c2ecf20Sopenharmony_ci	char sp, *token, separator = ',';
10078c2ecf20Sopenharmony_ci	unsigned short bpf_len, i = 0;
10088c2ecf20Sopenharmony_ci	struct sock_filter tmp;
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci	bpf_prog_len = 0;
10118c2ecf20Sopenharmony_ci	memset(bpf_image, 0, sizeof(bpf_image));
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci	if (sscanf(bpf_string, "%hu%c", &bpf_len, &sp) != 2 ||
10148c2ecf20Sopenharmony_ci	    sp != separator || bpf_len > BPF_MAXINSNS || bpf_len == 0) {
10158c2ecf20Sopenharmony_ci		rl_printf("syntax error in head length encoding!\n");
10168c2ecf20Sopenharmony_ci		return CMD_ERR;
10178c2ecf20Sopenharmony_ci	}
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci	token = bpf_string;
10208c2ecf20Sopenharmony_ci	while ((token = strchr(token, separator)) && (++token)[0]) {
10218c2ecf20Sopenharmony_ci		if (i >= bpf_len) {
10228c2ecf20Sopenharmony_ci			rl_printf("program exceeds encoded length!\n");
10238c2ecf20Sopenharmony_ci			return CMD_ERR;
10248c2ecf20Sopenharmony_ci		}
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci		if (sscanf(token, "%hu %hhu %hhu %u,",
10278c2ecf20Sopenharmony_ci			   &tmp.code, &tmp.jt, &tmp.jf, &tmp.k) != 4) {
10288c2ecf20Sopenharmony_ci			rl_printf("syntax error at instruction %d!\n", i);
10298c2ecf20Sopenharmony_ci			return CMD_ERR;
10308c2ecf20Sopenharmony_ci		}
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci		bpf_image[i].code = tmp.code;
10338c2ecf20Sopenharmony_ci		bpf_image[i].jt = tmp.jt;
10348c2ecf20Sopenharmony_ci		bpf_image[i].jf = tmp.jf;
10358c2ecf20Sopenharmony_ci		bpf_image[i].k = tmp.k;
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci		i++;
10388c2ecf20Sopenharmony_ci	}
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci	if (i != bpf_len) {
10418c2ecf20Sopenharmony_ci		rl_printf("syntax error exceeding encoded length!\n");
10428c2ecf20Sopenharmony_ci		return CMD_ERR;
10438c2ecf20Sopenharmony_ci	} else
10448c2ecf20Sopenharmony_ci		bpf_prog_len = bpf_len;
10458c2ecf20Sopenharmony_ci	if (!bpf_runnable(bpf_image, bpf_prog_len))
10468c2ecf20Sopenharmony_ci		bpf_prog_len = 0;
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci	return CMD_OK;
10498c2ecf20Sopenharmony_ci}
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_cistatic int cmd_load_pcap(char *file)
10528c2ecf20Sopenharmony_ci{
10538c2ecf20Sopenharmony_ci	char *file_trim, *tmp;
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	file_trim = strtok_r(file, " ", &tmp);
10568c2ecf20Sopenharmony_ci	if (file_trim == NULL)
10578c2ecf20Sopenharmony_ci		return CMD_ERR;
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci	try_close_pcap();
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	return try_load_pcap(file_trim);
10628c2ecf20Sopenharmony_ci}
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_cistatic int cmd_load(char *arg)
10658c2ecf20Sopenharmony_ci{
10668c2ecf20Sopenharmony_ci	char *subcmd, *cont = NULL, *tmp = strdup(arg);
10678c2ecf20Sopenharmony_ci	int ret = CMD_OK;
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci	subcmd = strtok_r(tmp, " ", &cont);
10708c2ecf20Sopenharmony_ci	if (subcmd == NULL)
10718c2ecf20Sopenharmony_ci		goto out;
10728c2ecf20Sopenharmony_ci	if (matches(subcmd, "bpf") == 0) {
10738c2ecf20Sopenharmony_ci		bpf_reset();
10748c2ecf20Sopenharmony_ci		bpf_reset_breakpoints();
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci		if (!cont)
10778c2ecf20Sopenharmony_ci			ret = CMD_ERR;
10788c2ecf20Sopenharmony_ci		else
10798c2ecf20Sopenharmony_ci			ret = cmd_load_bpf(cont);
10808c2ecf20Sopenharmony_ci	} else if (matches(subcmd, "pcap") == 0) {
10818c2ecf20Sopenharmony_ci		ret = cmd_load_pcap(cont);
10828c2ecf20Sopenharmony_ci	} else {
10838c2ecf20Sopenharmony_ciout:
10848c2ecf20Sopenharmony_ci		rl_printf("bpf <code>:  load bpf code\n");
10858c2ecf20Sopenharmony_ci		rl_printf("pcap <file>: load pcap file\n");
10868c2ecf20Sopenharmony_ci		ret = CMD_ERR;
10878c2ecf20Sopenharmony_ci	}
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	free(tmp);
10908c2ecf20Sopenharmony_ci	return ret;
10918c2ecf20Sopenharmony_ci}
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_cistatic int cmd_step(char *num)
10948c2ecf20Sopenharmony_ci{
10958c2ecf20Sopenharmony_ci	struct pcap_pkthdr *hdr;
10968c2ecf20Sopenharmony_ci	int steps, ret;
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci	if (!bpf_prog_loaded() || !pcap_loaded())
10998c2ecf20Sopenharmony_ci		return CMD_ERR;
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci	steps = strtol(num, NULL, 10);
11028c2ecf20Sopenharmony_ci	if (steps == 0 || strlen(num) == 0)
11038c2ecf20Sopenharmony_ci		steps = 1;
11048c2ecf20Sopenharmony_ci	if (steps < 0) {
11058c2ecf20Sopenharmony_ci		if (!bpf_restore_regs(steps))
11068c2ecf20Sopenharmony_ci			return CMD_ERR;
11078c2ecf20Sopenharmony_ci		steps = 1;
11088c2ecf20Sopenharmony_ci	}
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_ci	hdr = pcap_curr_pkt();
11118c2ecf20Sopenharmony_ci	ret = bpf_run_stepping(bpf_image, bpf_prog_len,
11128c2ecf20Sopenharmony_ci			       (uint8_t *) hdr + sizeof(*hdr),
11138c2ecf20Sopenharmony_ci			       hdr->caplen, hdr->len, steps);
11148c2ecf20Sopenharmony_ci	if (ret >= 0 || bpf_curr.Rs) {
11158c2ecf20Sopenharmony_ci		bpf_reset();
11168c2ecf20Sopenharmony_ci		if (!pcap_next_pkt()) {
11178c2ecf20Sopenharmony_ci			rl_printf("(going back to first packet)\n");
11188c2ecf20Sopenharmony_ci			pcap_reset_pkt();
11198c2ecf20Sopenharmony_ci		} else {
11208c2ecf20Sopenharmony_ci			rl_printf("(next packet)\n");
11218c2ecf20Sopenharmony_ci		}
11228c2ecf20Sopenharmony_ci	}
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci	return CMD_OK;
11258c2ecf20Sopenharmony_ci}
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_cistatic int cmd_select(char *num)
11288c2ecf20Sopenharmony_ci{
11298c2ecf20Sopenharmony_ci	unsigned int which, i;
11308c2ecf20Sopenharmony_ci	bool have_next = true;
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci	if (!pcap_loaded() || strlen(num) == 0)
11338c2ecf20Sopenharmony_ci		return CMD_ERR;
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci	which = strtoul(num, NULL, 10);
11368c2ecf20Sopenharmony_ci	if (which == 0) {
11378c2ecf20Sopenharmony_ci		rl_printf("packet count starts with 1, clamping!\n");
11388c2ecf20Sopenharmony_ci		which = 1;
11398c2ecf20Sopenharmony_ci	}
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_ci	pcap_reset_pkt();
11428c2ecf20Sopenharmony_ci	bpf_reset();
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	for (i = 0; i < which && (have_next = pcap_next_pkt()); i++)
11458c2ecf20Sopenharmony_ci		/* noop */;
11468c2ecf20Sopenharmony_ci	if (!have_next || pcap_curr_pkt() == NULL) {
11478c2ecf20Sopenharmony_ci		rl_printf("no packet #%u available!\n", which);
11488c2ecf20Sopenharmony_ci		pcap_reset_pkt();
11498c2ecf20Sopenharmony_ci		return CMD_ERR;
11508c2ecf20Sopenharmony_ci	}
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	return CMD_OK;
11538c2ecf20Sopenharmony_ci}
11548c2ecf20Sopenharmony_ci
11558c2ecf20Sopenharmony_cistatic int cmd_breakpoint(char *subcmd)
11568c2ecf20Sopenharmony_ci{
11578c2ecf20Sopenharmony_ci	if (!bpf_prog_loaded())
11588c2ecf20Sopenharmony_ci		return CMD_ERR;
11598c2ecf20Sopenharmony_ci	if (strlen(subcmd) == 0)
11608c2ecf20Sopenharmony_ci		bpf_dump_breakpoints();
11618c2ecf20Sopenharmony_ci	else if (matches(subcmd, "reset") == 0)
11628c2ecf20Sopenharmony_ci		bpf_reset_breakpoints();
11638c2ecf20Sopenharmony_ci	else {
11648c2ecf20Sopenharmony_ci		unsigned int where = strtoul(subcmd, NULL, 10);
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci		if (where < bpf_prog_len) {
11678c2ecf20Sopenharmony_ci			bpf_set_breakpoints(where);
11688c2ecf20Sopenharmony_ci			rl_printf("breakpoint at: ");
11698c2ecf20Sopenharmony_ci			bpf_disasm(bpf_image[where], where);
11708c2ecf20Sopenharmony_ci		}
11718c2ecf20Sopenharmony_ci	}
11728c2ecf20Sopenharmony_ci
11738c2ecf20Sopenharmony_ci	return CMD_OK;
11748c2ecf20Sopenharmony_ci}
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_cistatic int cmd_run(char *num)
11778c2ecf20Sopenharmony_ci{
11788c2ecf20Sopenharmony_ci	static uint32_t pass, fail;
11798c2ecf20Sopenharmony_ci	bool has_limit = true;
11808c2ecf20Sopenharmony_ci	int pkts = 0, i = 0;
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	if (!bpf_prog_loaded() || !pcap_loaded())
11838c2ecf20Sopenharmony_ci		return CMD_ERR;
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci	pkts = strtol(num, NULL, 10);
11868c2ecf20Sopenharmony_ci	if (pkts == 0 || strlen(num) == 0)
11878c2ecf20Sopenharmony_ci		has_limit = false;
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ci	do {
11908c2ecf20Sopenharmony_ci		struct pcap_pkthdr *hdr = pcap_curr_pkt();
11918c2ecf20Sopenharmony_ci		int ret = bpf_run_all(bpf_image, bpf_prog_len,
11928c2ecf20Sopenharmony_ci				      (uint8_t *) hdr + sizeof(*hdr),
11938c2ecf20Sopenharmony_ci				      hdr->caplen, hdr->len);
11948c2ecf20Sopenharmony_ci		if (ret > 0)
11958c2ecf20Sopenharmony_ci			pass++;
11968c2ecf20Sopenharmony_ci		else if (ret == 0)
11978c2ecf20Sopenharmony_ci			fail++;
11988c2ecf20Sopenharmony_ci		else
11998c2ecf20Sopenharmony_ci			return CMD_OK;
12008c2ecf20Sopenharmony_ci		bpf_reset();
12018c2ecf20Sopenharmony_ci	} while (pcap_next_pkt() && (!has_limit || (has_limit && ++i < pkts)));
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci	rl_printf("bpf passes:%u fails:%u\n", pass, fail);
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci	pcap_reset_pkt();
12068c2ecf20Sopenharmony_ci	bpf_reset();
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci	pass = fail = 0;
12098c2ecf20Sopenharmony_ci	return CMD_OK;
12108c2ecf20Sopenharmony_ci}
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_cistatic int cmd_disassemble(char *line_string)
12138c2ecf20Sopenharmony_ci{
12148c2ecf20Sopenharmony_ci	bool single_line = false;
12158c2ecf20Sopenharmony_ci	unsigned long line;
12168c2ecf20Sopenharmony_ci
12178c2ecf20Sopenharmony_ci	if (!bpf_prog_loaded())
12188c2ecf20Sopenharmony_ci		return CMD_ERR;
12198c2ecf20Sopenharmony_ci	if (strlen(line_string) > 0 &&
12208c2ecf20Sopenharmony_ci	    (line = strtoul(line_string, NULL, 10)) < bpf_prog_len)
12218c2ecf20Sopenharmony_ci		single_line = true;
12228c2ecf20Sopenharmony_ci	if (single_line)
12238c2ecf20Sopenharmony_ci		bpf_disasm(bpf_image[line], line);
12248c2ecf20Sopenharmony_ci	else
12258c2ecf20Sopenharmony_ci		bpf_disasm_all(bpf_image, bpf_prog_len);
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci	return CMD_OK;
12288c2ecf20Sopenharmony_ci}
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_cistatic int cmd_dump(char *dontcare)
12318c2ecf20Sopenharmony_ci{
12328c2ecf20Sopenharmony_ci	if (!bpf_prog_loaded())
12338c2ecf20Sopenharmony_ci		return CMD_ERR;
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_ci	bpf_dump_all(bpf_image, bpf_prog_len);
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	return CMD_OK;
12388c2ecf20Sopenharmony_ci}
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_cistatic int cmd_quit(char *dontcare)
12418c2ecf20Sopenharmony_ci{
12428c2ecf20Sopenharmony_ci	return CMD_EX;
12438c2ecf20Sopenharmony_ci}
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_cistatic const struct shell_cmd cmds[] = {
12468c2ecf20Sopenharmony_ci	{ .name = "load", .func = cmd_load },
12478c2ecf20Sopenharmony_ci	{ .name = "select", .func = cmd_select },
12488c2ecf20Sopenharmony_ci	{ .name = "step", .func = cmd_step },
12498c2ecf20Sopenharmony_ci	{ .name = "run", .func = cmd_run },
12508c2ecf20Sopenharmony_ci	{ .name = "breakpoint", .func = cmd_breakpoint },
12518c2ecf20Sopenharmony_ci	{ .name = "disassemble", .func = cmd_disassemble },
12528c2ecf20Sopenharmony_ci	{ .name = "dump", .func = cmd_dump },
12538c2ecf20Sopenharmony_ci	{ .name = "quit", .func = cmd_quit },
12548c2ecf20Sopenharmony_ci};
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_cistatic int execf(char *arg)
12578c2ecf20Sopenharmony_ci{
12588c2ecf20Sopenharmony_ci	char *cmd, *cont, *tmp = strdup(arg);
12598c2ecf20Sopenharmony_ci	int i, ret = 0, len;
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	cmd = strtok_r(tmp, " ", &cont);
12628c2ecf20Sopenharmony_ci	if (cmd == NULL)
12638c2ecf20Sopenharmony_ci		goto out;
12648c2ecf20Sopenharmony_ci	len = strlen(cmd);
12658c2ecf20Sopenharmony_ci	for (i = 0; i < array_size(cmds); i++) {
12668c2ecf20Sopenharmony_ci		if (len != strlen(cmds[i].name))
12678c2ecf20Sopenharmony_ci			continue;
12688c2ecf20Sopenharmony_ci		if (strncmp(cmds[i].name, cmd, len) == 0) {
12698c2ecf20Sopenharmony_ci			ret = cmds[i].func(cont);
12708c2ecf20Sopenharmony_ci			break;
12718c2ecf20Sopenharmony_ci		}
12728c2ecf20Sopenharmony_ci	}
12738c2ecf20Sopenharmony_ciout:
12748c2ecf20Sopenharmony_ci	free(tmp);
12758c2ecf20Sopenharmony_ci	return ret;
12768c2ecf20Sopenharmony_ci}
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_cistatic char *shell_comp_gen(const char *buf, int state)
12798c2ecf20Sopenharmony_ci{
12808c2ecf20Sopenharmony_ci	static int list_index, len;
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_ci	if (!state) {
12838c2ecf20Sopenharmony_ci		list_index = 0;
12848c2ecf20Sopenharmony_ci		len = strlen(buf);
12858c2ecf20Sopenharmony_ci	}
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci	for (; list_index < array_size(cmds); ) {
12888c2ecf20Sopenharmony_ci		const char *name = cmds[list_index].name;
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci		list_index++;
12918c2ecf20Sopenharmony_ci		if (strncmp(name, buf, len) == 0)
12928c2ecf20Sopenharmony_ci			return strdup(name);
12938c2ecf20Sopenharmony_ci	}
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_ci	return NULL;
12968c2ecf20Sopenharmony_ci}
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_cistatic char **shell_completion(const char *buf, int start, int end)
12998c2ecf20Sopenharmony_ci{
13008c2ecf20Sopenharmony_ci	char **matches = NULL;
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci	if (start == 0)
13038c2ecf20Sopenharmony_ci		matches = rl_completion_matches(buf, shell_comp_gen);
13048c2ecf20Sopenharmony_ci
13058c2ecf20Sopenharmony_ci	return matches;
13068c2ecf20Sopenharmony_ci}
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_cistatic void intr_shell(int sig)
13098c2ecf20Sopenharmony_ci{
13108c2ecf20Sopenharmony_ci	if (rl_end)
13118c2ecf20Sopenharmony_ci		rl_kill_line(-1, 0);
13128c2ecf20Sopenharmony_ci
13138c2ecf20Sopenharmony_ci	rl_crlf();
13148c2ecf20Sopenharmony_ci	rl_refresh_line(0, 0);
13158c2ecf20Sopenharmony_ci	rl_free_line_state();
13168c2ecf20Sopenharmony_ci}
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_cistatic void init_shell(FILE *fin, FILE *fout)
13198c2ecf20Sopenharmony_ci{
13208c2ecf20Sopenharmony_ci	char file[128];
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci	snprintf(file, sizeof(file), "%s/.bpf_dbg_history", getenv("HOME"));
13238c2ecf20Sopenharmony_ci	read_history(file);
13248c2ecf20Sopenharmony_ci
13258c2ecf20Sopenharmony_ci	rl_instream = fin;
13268c2ecf20Sopenharmony_ci	rl_outstream = fout;
13278c2ecf20Sopenharmony_ci
13288c2ecf20Sopenharmony_ci	rl_readline_name = "bpf_dbg";
13298c2ecf20Sopenharmony_ci	rl_terminal_name = getenv("TERM");
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_ci	rl_catch_signals = 0;
13328c2ecf20Sopenharmony_ci	rl_catch_sigwinch = 1;
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci	rl_attempted_completion_function = shell_completion;
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_ci	rl_bind_key('\t', rl_complete);
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_ci	rl_bind_key_in_map('\t', rl_complete, emacs_meta_keymap);
13398c2ecf20Sopenharmony_ci	rl_bind_key_in_map('\033', rl_complete, emacs_meta_keymap);
13408c2ecf20Sopenharmony_ci
13418c2ecf20Sopenharmony_ci	snprintf(file, sizeof(file), "%s/.bpf_dbg_init", getenv("HOME"));
13428c2ecf20Sopenharmony_ci	rl_read_init_file(file);
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci	rl_prep_terminal(0);
13458c2ecf20Sopenharmony_ci	rl_set_signals();
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci	signal(SIGINT, intr_shell);
13488c2ecf20Sopenharmony_ci}
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_cistatic void exit_shell(FILE *fin, FILE *fout)
13518c2ecf20Sopenharmony_ci{
13528c2ecf20Sopenharmony_ci	char file[128];
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci	snprintf(file, sizeof(file), "%s/.bpf_dbg_history", getenv("HOME"));
13558c2ecf20Sopenharmony_ci	write_history(file);
13568c2ecf20Sopenharmony_ci
13578c2ecf20Sopenharmony_ci	clear_history();
13588c2ecf20Sopenharmony_ci	rl_deprep_terminal();
13598c2ecf20Sopenharmony_ci
13608c2ecf20Sopenharmony_ci	try_close_pcap();
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_ci	if (fin != stdin)
13638c2ecf20Sopenharmony_ci		fclose(fin);
13648c2ecf20Sopenharmony_ci	if (fout != stdout)
13658c2ecf20Sopenharmony_ci		fclose(fout);
13668c2ecf20Sopenharmony_ci}
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_cistatic int run_shell_loop(FILE *fin, FILE *fout)
13698c2ecf20Sopenharmony_ci{
13708c2ecf20Sopenharmony_ci	char *buf;
13718c2ecf20Sopenharmony_ci
13728c2ecf20Sopenharmony_ci	init_shell(fin, fout);
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci	while ((buf = readline("> ")) != NULL) {
13758c2ecf20Sopenharmony_ci		int ret = execf(buf);
13768c2ecf20Sopenharmony_ci		if (ret == CMD_EX)
13778c2ecf20Sopenharmony_ci			break;
13788c2ecf20Sopenharmony_ci		if (ret == CMD_OK && strlen(buf) > 0)
13798c2ecf20Sopenharmony_ci			add_history(buf);
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci		free(buf);
13828c2ecf20Sopenharmony_ci	}
13838c2ecf20Sopenharmony_ci
13848c2ecf20Sopenharmony_ci	exit_shell(fin, fout);
13858c2ecf20Sopenharmony_ci	return 0;
13868c2ecf20Sopenharmony_ci}
13878c2ecf20Sopenharmony_ci
13888c2ecf20Sopenharmony_ciint main(int argc, char **argv)
13898c2ecf20Sopenharmony_ci{
13908c2ecf20Sopenharmony_ci	FILE *fin = NULL, *fout = NULL;
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_ci	if (argc >= 2)
13938c2ecf20Sopenharmony_ci		fin = fopen(argv[1], "r");
13948c2ecf20Sopenharmony_ci	if (argc >= 3)
13958c2ecf20Sopenharmony_ci		fout = fopen(argv[2], "w");
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_ci	return run_shell_loop(fin ? : stdin, fout ? : stdout);
13988c2ecf20Sopenharmony_ci}
1399