# Copyright 2023 syzkaller project authors. All rights reserved.
# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

include <uapi/linux/bpf.h>
include <uapi/linux/bpf_common.h>

define BPF_LINE_INFO_SIZE	sizeof(struct bpf_line_info)
define BPF_FUNC_INFO_SIZE	sizeof(struct bpf_func_info)
define BPF_CORE_RELO_SIZE	sizeof(struct bpf_core_relo)

type bpf_prog_t[TYPE, ATTACH_TYPE, BTF_ID, PROG_FD] {
	type			TYPE
	ninsn			bytesize8[insns, int32]
	insns			ptr64[in, bpf_instructions]
	license			ptr64[in, string[bpf_licenses]]
	loglev			int32
	logsize			len[log, int32]
	log			ptr64[out, array[int8], opt]
	kern_version		flags[bpf_kern_version, int32]
	flags			flags[bpf_prog_load_flags, int32]
	prog_name		array[const[0, int8], BPF_OBJ_NAME_LEN]
	prog_ifindex		ifindex[opt]
	expected_attach_type	ATTACH_TYPE
	btf_fd			fd_btf[opt]
	func_info_rec_size	const[BPF_FUNC_INFO_SIZE, int32]
	func_info		ptr64[in, bpf_func_info, opt]
	func_info_cnt		len[func_info, int32]
	line_info_rec_size	const[BPF_LINE_INFO_SIZE, int32]
	line_info		ptr64[in, bpf_line_info, opt]
	line_info_cnt		len[line_info, int32]
	attach_btf_id		BTF_ID
	attach_prog_fd		PROG_FD
	core_relo_cnt		len[core_relos, int32]
	fd_array		ptr64[in, array[fd_bpf_map], opt]
	core_relos		ptr64[in, array[bpf_core_relo], opt]
	core_relo_rec_size	const[BPF_CORE_RELO_SIZE, int32]
	log_true_size		int32
	prog_token_fd		fd_bpf_token	(if[value[flags] & BPF_F_TOKEN_FD != 0])
	pad			const[0, int32]	(if[value[flags] & BPF_F_TOKEN_FD == 0])
} [packed]

# These flags should match the mappings in bpf_prog_load_check_attach and attach_type_to_prog_type upstream.
cgroup_sock_attach_types = BPF_CGROUP_INET_SOCK_CREATE, BPF_CGROUP_INET_SOCK_RELEASE, BPF_CGROUP_INET4_POST_BIND, BPF_CGROUP_INET6_POST_BIND
cgroup_sock_addr_attach_types = BPF_CGROUP_INET4_BIND, BPF_CGROUP_INET6_BIND, BPF_CGROUP_INET4_CONNECT, BPF_CGROUP_INET6_CONNECT, BPF_CGROUP_UNIX_CONNECT, BPF_CGROUP_INET4_GETPEERNAME, BPF_CGROUP_INET6_GETPEERNAME, BPF_CGROUP_UNIX_GETPEERNAME, BPF_CGROUP_INET4_GETSOCKNAME, BPF_CGROUP_INET6_GETSOCKNAME, BPF_CGROUP_UNIX_GETSOCKNAME, BPF_CGROUP_UDP4_SENDMSG, BPF_CGROUP_UDP6_SENDMSG, BPF_CGROUP_UNIX_SENDMSG, BPF_CGROUP_UDP4_RECVMSG, BPF_CGROUP_UDP6_RECVMSG, BPF_CGROUP_UNIX_RECVMSG
cgroup_skb_attach_types = BPF_CGROUP_INET_INGRESS, BPF_CGROUP_INET_EGRESS
cgroup_sockopt_attach_types = BPF_CGROUP_SETSOCKOPT, BPF_CGROUP_GETSOCKOPT
sk_lookup_attach_types = BPF_SK_LOOKUP
sk_reuseport_attach_types = BPF_SK_REUSEPORT_SELECT, BPF_SK_REUSEPORT_SELECT_OR_MIGRATE
netfilter_attach_types = BPF_NETFILTER
sock_ops_attach_types = BPF_CGROUP_SOCK_OPS
cgroup_device_attach_types = BPF_CGROUP_DEVICE
sk_msg_attach_types = BPF_SK_MSG_VERDICT
sk_skb_attach_types = BPF_SK_SKB_STREAM_PARSER, BPF_SK_SKB_STREAM_VERDICT, BPF_SK_SKB_VERDICT
lirc_mode2_attach_types = BPF_LIRC_MODE2
flow_dissector_attach_types = BPF_FLOW_DISSECTOR
cgroup_sysctl_attach_types = BPF_CGROUP_SYSCTL
tracing_attach_types = BPF_TRACE_ITER, BPF_TRACE_RAW_TP, BPF_TRACE_FENTRY, BPF_TRACE_FEXIT, BPF_MODIFY_RETURN
lsm_attach_types = BPF_LSM_MAC, BPF_LSM_CGROUP
xdp_attach_types = BPF_XDP
sched_cls_attach_types = BPF_TCX_INGRESS, BPF_TCX_EGRESS, BPF_NETKIT_PRIMARY, BPF_NETKIT_PEER

bpf_prog_attach_types [
	cgroup_sock		flags[cgroup_sock_attach_types, int32]	(if[value[bpf_prog_t:type] == BPF_PROG_TYPE_CGROUP_SOCK])
	cgroup_sock_addr	flags[cgroup_sock_addr_attach_types, int32]	(if[value[bpf_prog_t:type] == BPF_PROG_TYPE_CGROUP_SOCK_ADDR])
	cgroup_skb		flags[cgroup_skb_attach_types, int32]	(if[value[bpf_prog_t:type] == BPF_PROG_TYPE_CGROUP_SKB])
	cgroup_sockopt		flags[cgroup_sockopt_attach_types, int32]	(if[value[bpf_prog_t:type] == BPF_PROG_TYPE_CGROUP_SOCKOPT])
	sk_lookup		flags[sk_lookup_attach_types, int32]	(if[value[bpf_prog_t:type] == BPF_PROG_TYPE_SK_LOOKUP])
	sk_reuseport		flags[sk_reuseport_attach_types, int32]	(if[value[bpf_prog_t:type] == BPF_PROG_TYPE_SK_REUSEPORT])
	netfilter		flags[netfilter_attach_types, int32]	(if[value[bpf_prog_t:type] == BPF_PROG_TYPE_NETFILTER])
	sock_ops		flags[sock_ops_attach_types, int32]	(if[value[bpf_prog_t:type] == BPF_PROG_TYPE_SOCK_OPS])
	cgroup_device		flags[cgroup_device_attach_types, int32]	(if[value[bpf_prog_t:type] == BPF_PROG_TYPE_CGROUP_DEVICE])
	sk_msg			flags[sk_msg_attach_types, int32]	(if[value[bpf_prog_t:type] == BPF_PROG_TYPE_SK_MSG])
	sk_skb			flags[sk_skb_attach_types, int32]	(if[value[bpf_prog_t:type] == BPF_PROG_TYPE_SK_SKB])
	lirc_mode2		flags[lirc_mode2_attach_types, int32]	(if[value[bpf_prog_t:type] == BPF_PROG_TYPE_LIRC_MODE2])
	flow_dissector		flags[flow_dissector_attach_types, int32]	(if[value[bpf_prog_t:type] == BPF_PROG_TYPE_FLOW_DISSECTOR])
	cgroup_sysctl		flags[cgroup_sysctl_attach_types, int32]	(if[value[bpf_prog_t:type] == BPF_PROG_TYPE_CGROUP_SYSCTL])
	tracing			flags[tracing_attach_types, int32]	(if[value[bpf_prog_t:type] == BPF_PROG_TYPE_TRACING])
	lsm			flags[lsm_attach_types, int32]	(if[value[bpf_prog_t:type] == BPF_PROG_TYPE_LSM])
	xdp			flags[xdp_attach_types, int32]	(if[value[bpf_prog_t:type] == BPF_PROG_TYPE_XDP])
	sched_cls		flags[sched_cls_attach_types, int32]	(if[value[bpf_prog_t:type] == BPF_PROG_TYPE_SCHED_CLS])
	fallback		flags[bpf_attach_types, int32]
]

type bpf_prog bpf_prog_t[flags[bpf_prog_type, int32], bpf_prog_attach_types, bpf_btf_id[opt], fd_bpf_prog[opt]]

bpf_licenses = "GPL", "syzkaller"
bpf_kern_version = 0x40f00, 0x41000, 0x41100

bpf_func_info {
# This is instruction index, so should not be too large.
	insn_off	int32[0:10]
	type_id		btf_type_id
}

bpf_line_info {
# This is instruction index, so should not be too large.
	insn_off	int32[0:5]
	file_name_off	btf_opt_name_off
	line_off	int32
	line_col	int32
}

bpf_core_relo {
# This is instruction index, so should not be too large.
	insn_off	int32[0:5]
	type_id		btf_type_id
	access_str_off	btf_opt_name_off
	kind		flags[bpf_core_relo_kind, int32]
}

bpf_instructions [
	raw	array[bpf_insn]
	framed	bpf_framed_program
	ringbuf	bpf_program_ringbuf
] [varlen]

bpf_framed_program {
	initr0	bpf_insn_init_r0
	body	array[bpf_insn]
	exit	bpf_insn_exit
} [packed]

bpf_program_ringbuf {
	initr0		bpf_insn_init_r0
	reserve		bpf_insn_ringbuf_reserve
	null_check	bpf_insn_null_check[BPF_REG_9]
	body		array[bpf_insn]
	free		bpf_insn_ringbuf_free
	exit		bpf_insn_exit
} [packed]

bpf_insn [
	generic		bpf_insn_generic
	ldst		bpf_insn_ldst
	alu		bpf_insn_alu
	jmp		bpf_insn_jmp
	call		bpf_insn_call_helper
	func		bpf_insn_call_func
	kfunc		bpf_insn_call_kfunc
	exit		bpf_insn_exit
	initr0		bpf_insn_init_r0
	map_fd		bpf_insn_map_fd
	map_idx		bpf_insn_map_idx
	map_val		bpf_insn_map_value
	map_idx_val	bpf_insn_map_idx_value
	btf_id		bpf_insn_btf_id
	cb_func		bpf_insn_cb_func
	printk		bpf_insn_trace_printk
	snprintf	bpf_insn_snprintf
	tail_call	bpf_insn_tail_call
	ringbuf_query	bpf_insn_ringbuf_query
	ringbuf_output	bpf_insn_ringbuf_output
] [varlen]

bpf_insn_generic {
	code	int8
	dst	int8:4
	src	int8:4
	off	int16
	imm	int32
}

type bpf_insn_ldst_t[CLASS, SZ, MODE, DST, SRC, OFF, IMM] {
	code_class	int8:3[CLASS]
	code_size	int8:2[SZ]
	code_mode	int8:3[MODE]
	dst		DST
	src		SRC
	off		OFF
	imm		IMM
}

type bpf_insn_ldst bpf_insn_ldst_t[bpf_ldst_insn, bpf_ldst_size, bpf_ldst_mode, flags[bpf_reg, int8:4], flags[bpf_reg, int8:4], flags[bpf_insn_offsets, int16], flags[bpf_insn_immediates, int32]]
type bpf_insn_st64_reg[SRC, DST, OFF] bpf_insn_ldst_t[BPF_STX, BPF_DW0, BPF_MEM0, const[DST, int8:4], const[SRC, int8:4], const[OFF, int16], const[0, int32]]

bpf_ldst_insn = BPF_LD, BPF_LDX, BPF_ST, BPF_STX
bpf_ldst_size = BPF_W0, BPF_H0, BPF_B0, BPF_DW0
bpf_ldst_mode = BPF_IMM0, BPF_ABS0, BPF_IND0, BPF_MEM0, BPF_XADD0, BPF_MEMSX0

define BPF_W0	BPF_W >> 3
define BPF_H0	BPF_H >> 3
define BPF_B0	BPF_B >> 3
define BPF_DW0	BPF_DW >> 3

define BPF_IMM0	BPF_IMM >> 5
define BPF_ABS0	BPF_ABS >> 5
define BPF_IND0	BPF_IND >> 5
define BPF_MEM0	BPF_MEM >> 5
define BPF_XADD0	BPF_XADD >> 5
define BPF_MEMSX0	BPF_MEMSX >> 5

type bpf_insn_alu_t[CLASS, SOURCE, OP, DST, SRC, OFF, IMM] {
	code_class	int8:3[CLASS]
	code_s		int8:1[SOURCE]
	code_op		int8:4[OP]
	dst		DST
	src		SRC
	off		OFF
	imm		IMM
}

type bpf_insn_alu bpf_insn_alu_t[bpf_alu_insn, bpf_alu_source, bpf_alu_op, flags[bpf_reg, int8:4], flags[bpf_reg, int8:4], flags[bpf_insn_offsets, int16], flags[bpf_insn_immediates, int32]]
type bpf_insn_mov_imm[DST, IMM] bpf_insn_alu_t[BPF_ALU64, BPF_K0, BPF_MOV0, const[DST, int8:4], const[0, int8:4], const[0, int16], const[IMM, int32]]
type bpf_insn_mov_imm_any[DST] bpf_insn_alu_t[BPF_ALU64, BPF_K0, BPF_MOV0, const[DST, int8:4], const[0, int8:4], const[0, int16], int32]
type bpf_insn_mov_imm_flag[DST, FLAG] bpf_insn_alu_t[BPF_ALU64, BPF_K0, BPF_MOV0, const[DST, int8:4], const[0, int8:4], const[0, int16], flags[FLAG, int32]]
type bpf_insn_mov_reg[SRC, DST] bpf_insn_alu_t[BPF_ALU64, BPF_X0, BPF_MOV0, const[DST, int8:4], const[SRC, int8:4], const[0, int16], const[0, int32]]
type bpf_insn_op_imm[DST, OP, IMM] bpf_insn_alu_t[BPF_ALU64, BPF_K0, OP, const[DST, int8:4], const[0, int8:4], const[0, int16], const[IMM, int32]]

bpf_alu_source = BPF_K0, BPF_X0
bpf_alu_insn = BPF_ALU, BPF_ALU64
bpf_alu_op = BPF_ADD0, BPF_SUB0, BPF_MUL0, BPF_DIV0, BPF_OR0, BPF_AND0, BPF_LSH0, BPF_RSH0, BPF_NEG0, BPF_MOD0, BPF_XOR0, BPF_MOV0, BPF_ARSH0, BPF_END0

define BPF_ADD0	BPF_ADD >> 4
define BPF_SUB0	BPF_SUB >> 4
define BPF_MUL0	BPF_MUL >> 4
define BPF_DIV0	BPF_DIV >> 4
define BPF_OR0	BPF_OR >> 4
define BPF_AND0	BPF_AND >> 4
define BPF_LSH0	BPF_LSH >> 4
define BPF_RSH0	BPF_RSH >> 4
define BPF_NEG0	BPF_NEG >> 4
define BPF_MOD0	BPF_MOD >> 4
define BPF_XOR0	BPF_XOR >> 4
define BPF_MOV0	BPF_MOV >> 4
define BPF_ARSH0	BPF_ARSH >> 4
define BPF_END0	BPF_END >> 4

define BPF_K0	BPF_K >> 3
define BPF_X0	BPF_X >> 3

bpf_insn_jmp {
	code_class	const[BPF_JMP, int8:3]
	code_s		int8:1
	code_op		flags[bpf_jmp_op, int8:4]
	dst		flags[bpf_reg, int8:4]
	src		flags[bpf_reg, int8:4]
	off		flags[bpf_insn_offsets, int16]
	imm		flags[bpf_insn_immediates, int32]
}

# Equivalent to: if reg != 0 goto +1;
type bpf_insn_not_null_jmp[REG] {
	code_class	const[BPF_JMP, int8:3]
	code_s		const[BPF_K0, int8:1]
	code_op		const[BPF_JNE0, int8:4]
	dst		const[REG, int8:4]
	src		const[0, int8:4]
	off		const[1, int16]
	imm		const[0, int32]
}

bpf_jmp_op = BPF_JA0, BPF_JEQ0, BPF_JGT0, BPF_JGE0, BPF_JSET0, BPF_JNE0, BPF_JSGT0, BPF_JSGE0, BPF_CALL0, BPF_EXIT0, BPF_JLT0, BPF_JLE0, BPF_JSLT0, BPF_JSLE0

define BPF_JA0	BPF_JA >> 4
define BPF_JEQ0	BPF_JEQ >> 4
define BPF_JGT0	BPF_JGT >> 4
define BPF_JGE0	BPF_JGE >> 4
define BPF_JSET0	BPF_JSET >> 4
define BPF_JNE0	BPF_JNE >> 4
define BPF_JSGT0	BPF_JSGT >> 4
define BPF_JSGE0	BPF_JSGE >> 4
define BPF_CALL0	BPF_CALL >> 4
define BPF_EXIT0	BPF_EXIT >> 4
define BPF_JLT0	BPF_JLT >> 4
define BPF_JLE0	BPF_JLE >> 4
define BPF_JSLT0	BPF_JSLT >> 4
define BPF_JSLE0	BPF_JSLE >> 4

type bpf_insn_call_helper_t[FUNC] {
	code	const[bpf_call_code, int8]
	regs	const[0, int8]
	off	const[0, int16]
	func	FUNC
}

type bpf_insn_call_helper bpf_insn_call_helper_t[int32[0:__BPF_FUNC_MAX_ID]]

bpf_insn_call_func {
	code	const[bpf_call_code, int8]
	dst	const[0, int8:4]
	src	const[BPF_PSEUDO_CALL, int8:4]
	off	const[0, int16]
# NEED: to limit the call offset to the program size, we'd need support for path expressions inside ranges of values.
	func	int32[-8:8]
}

bpf_insn_call_kfunc {
	code	const[bpf_call_code, int8]
	dst	const[0, int8:4]
	src	const[BPF_PSEUDO_KFUNC_CALL, int8:4]
	off	const[0, int16]
	kfunc	btf_type_id
}

define bpf_call_code	BPF_JMP | BPF_CALL

bpf_insn_exit {
	code	const[bpf_exit_code, int8]
	regs	const[0, int8]
	off	const[0, int16]
	imm	const[0, int32]
}

define bpf_exit_code	BPF_JMP | BPF_EXIT

bpf_insn_init_r0 {
	code	const[bpf_insn_load_imm_dw, int8]
	dst	const[BPF_REG_0, int8:4]
	src	const[0, int8:4]
	off	const[0, int16]
	imm	int32
	code2	const[0, int8]
	regs2	const[0, int8]
	off2	const[0, int16]
	imm2	int32
}

type bpf_insn_mov_imm64[DST, IMM1, IMM2] {
	code	const[bpf_insn_load_imm_dw, int8]
	dst	const[DST, int8:4]
	src	const[0, int8:4]
	off	const[0, int16]
	imm	const[IMM1, int32]
	code2	const[0, int8]
	regs2	const[0, int8]
	off2	const[0, int16]
	imm2	const[IMM2, int32]
}

type bpf_insn_map_fd_t[DST, MAP_FD] {
	code	const[bpf_insn_load_imm_dw, int8]
	dst	DST
	src	const[BPF_PSEUDO_MAP_FD, int8:4]
	off	const[0, int16]
	imm	MAP_FD
	code2	const[0, int8]
	regs2	const[0, int8]
	off2	const[0, int16]
	imm2	const[0, int32]
}

type bpf_insn_map_fd bpf_insn_map_fd_t[flags[bpf_reg, int8:4], fd_bpf_map]
type bpf_insn_tail_call_map_fd[DST] bpf_insn_map_fd_t[const[DST, int8:4], tail_call_map]
type bpf_insn_ringbuf_fd[DST] bpf_insn_map_fd_t[const[DST, int8:4], ringbuf_map_fd]

bpf_insn_map_idx {
	code	const[bpf_insn_load_imm_dw, int8]
	dst	flags[bpf_reg, int8:4]
	src	const[BPF_PSEUDO_MAP_IDX, int8:4]
	off	const[0, int16]
	imm	map_fd_id
	code2	const[0, int8]
	regs2	const[0, int8]
	off2	const[0, int16]
	imm2	const[0, int32]
}

type bpf_insn_map_value_t[DST, MAP_FD, VALUE_OFFSET] {
	code	const[bpf_insn_load_imm_dw, int8]
	dst	DST
	src	const[BPF_PSEUDO_MAP_VALUE, int8:4]
	off	const[0, int16]
	imm	MAP_FD
	code2	const[0, int8]
	regs2	const[0, int8]
	off2	const[0, int16]
	imm2	VALUE_OFFSET
}

type bpf_insn_map_value bpf_insn_map_value_t[flags[bpf_reg, int8:4], fd_bpf_map, int32]
type bpf_insn_const_str[DST] bpf_insn_map_value_t[const[DST, int8:4], bpf_frozen_const_str, const[0, int32]]

bpf_insn_map_idx_value {
	code	const[bpf_insn_load_imm_dw, int8]
	dst	flags[bpf_reg, int8:4]
	src	const[BPF_PSEUDO_MAP_IDX_VALUE, int8:4]
	off	const[0, int16]
	imm	map_fd_id
	code2	const[0, int8]
	regs2	const[0, int8]
	off2	const[0, int16]
	imm2	int32
}

bpf_insn_cb_func {
	code	const[bpf_insn_load_imm_dw, int8]
	dst	flags[bpf_reg, int8:4]
	src	const[BPF_PSEUDO_FUNC, int8:4]
	off	const[0, int16]
# NEED: to limit the call offset to the program size, we'd need support for path expressions inside ranges of values.
	imm	int32[-8:8]
	code2	const[0, int8]
	regs2	const[0, int8]
	off2	const[0, int16]
	imm2	const[0, int32]
}

bpf_insn_btf_id {
	code	const[bpf_insn_load_imm_dw, int8]
	dst	flags[bpf_reg, int8:4]
	src	const[BPF_PSEUDO_BTF_ID, int8:4]
	off	const[0, int16]
	imm	btf_type_id
	code2	const[0, int8]
	regs2	const[0, int8]
	off2	const[0, int16]
	imm2	const[0, int32]
}

define bpf_insn_load_imm_dw	BPF_LD | BPF_DW | BPF_IMM

# Slightly prune state space, these values frequently must be 0.
bpf_insn_offsets = 0, 1, 2, 4, 6, 8, 12, 16, 24, 32, 48, 64, 80, 128, 256, -1, -2, -4, -8, -12, -16, -32, -64
bpf_insn_immediates = 0, 1, 4, 8, 16, -1, -4, -16
bpf_reg = BPF_REG_0, BPF_REG_1, BPF_REG_2, BPF_REG_3, BPF_REG_4, BPF_REG_5, BPF_REG_6, BPF_REG_7, BPF_REG_8, BPF_REG_9, BPF_REG_10, __MAX_BPF_REG

# Equivalent to:
# if reg != 0 goto +1;
# exit;
# This is useful to check null pointers. We exit if the pointer is null and
# continue the normal flow otherwise.
type bpf_insn_null_check[REG] {
	cond_jump	bpf_insn_not_null_jmp[REG]
	exit		bpf_insn_exit
}

# Format specifiers for bpf_trace_printk, encoded as a zero-terminated string
# of 7 characters. For example, field 'p' corresponds to "%p     ".
type bpf_insn_mov_printk_str_hex[DST] [
	p	bpf_insn_mov_imm64[DST, 0x25702020, 0x20202000]
	d	bpf_insn_mov_imm64[DST, 0x25642020, 0x20202000]
	i	bpf_insn_mov_imm64[DST, 0x25692020, 0x20202000]
	u	bpf_insn_mov_imm64[DST, 0x25752020, 0x20202000]
	x	bpf_insn_mov_imm64[DST, 0x25782020, 0x20202000]
	ld	bpf_insn_mov_imm64[DST, 0x256c6420, 0x20202000]
	li	bpf_insn_mov_imm64[DST, 0x256c6920, 0x20202000]
	lu	bpf_insn_mov_imm64[DST, 0x256c7520, 0x20202000]
	lx	bpf_insn_mov_imm64[DST, 0x256c7820, 0x20202000]
	lld	bpf_insn_mov_imm64[DST, 0x256c6c64, 0x20202000]
	lli	bpf_insn_mov_imm64[DST, 0x256c6c69, 0x20202000]
	llu	bpf_insn_mov_imm64[DST, 0x256c6c75, 0x20202000]
	llx	bpf_insn_mov_imm64[DST, 0x256c6c78, 0x20202000]
	s	bpf_insn_mov_imm64[DST, 0x25732020, 0x20202000]
]

# (18) r1 = "%d     "
# (7b) *(u64 *)(r10 -8) = r1
# (bf) r1 = r10
# (07) r1 += -8
# (b7) r2 = 8
# (b7) r3 = X
# (85) call bpf_trace_printk#-108352
bpf_insn_trace_printk {
	insn1	bpf_insn_mov_printk_str_hex[BPF_REG_1]
	insn2	bpf_insn_st64_reg[BPF_REG_1, BPF_REG_10, -8]
	insn3	bpf_insn_mov_reg[BPF_REG_10, BPF_REG_1]
	insn4	bpf_insn_op_imm[BPF_REG_1, BPF_ADD0, -8]
	insn5	bpf_insn_mov_imm[BPF_REG_2, 8]
	insn6	bpf_insn_mov_imm_any[BPF_REG_3]
	insn7	bpf_insn_call_helper_t[const[BPF_FUNC_trace_printk, int32]]
}

# (b7) r8 = 0
# (7b) *(u64 *)(r10 -8) = r8
# (b7) r8 = X
# (7b) *(u64 *)(r10 -16) = r8
# (bf) r1 = r10
# (07) r1 += -8
# (bf) r4 = r10
# (07) r4 += -16
# (b7) r2 = 8
# (18) r3 = map[id:31][0]+0
# (b7) r5 = 8
# (85) call bpf_snprintf#168880
bpf_insn_snprintf {
	insn1	bpf_insn_mov_imm[BPF_REG_8, 0]
	insn2	bpf_insn_st64_reg[BPF_REG_8, BPF_REG_10, -8]
	insn3	bpf_insn_mov_imm_any[BPF_REG_8]
	insn4	bpf_insn_st64_reg[BPF_REG_8, BPF_REG_10, -16]
	insn5	bpf_insn_mov_reg[BPF_REG_10, BPF_REG_1]
	insn6	bpf_insn_op_imm[BPF_REG_1, BPF_ADD0, -8]
	insn7	bpf_insn_mov_reg[BPF_REG_10, BPF_REG_4]
	insn8	bpf_insn_op_imm[BPF_REG_4, BPF_ADD0, -16]
	insn9	bpf_insn_mov_imm[BPF_REG_2, 8]
	insn10	bpf_insn_const_str[BPF_REG_3]
	insn11	bpf_insn_mov_imm[BPF_REG_5, 8]
	insn12	bpf_insn_call_helper_t[const[BPF_FUNC_snprintf, int32]]
}

# (18) r2 = map[id:10]
# (b7) r3 = 2
# (85) call bpf_tail_call#12
# (b7) r0 = 0
bpf_insn_tail_call {
	insn1	bpf_insn_tail_call_map_fd[BPF_REG_2]
	insn2	bpf_insn_mov_imm[BPF_REG_3, 0]
	insn3	bpf_insn_call_helper_t[const[BPF_FUNC_tail_call, int32]]
	insn4	bpf_insn_mov_imm[BPF_REG_0, 0]
}

# (18) r1 = map[id:16]
# (b7) r2 = 8
# (b7) r3 = 0
# (85) call bpf_ringbuf_reserve#320112
# (bf) r9 = r0
bpf_insn_ringbuf_reserve {
	insn1	bpf_insn_ringbuf_fd[BPF_REG_1]
	insn2	bpf_insn_mov_imm[BPF_REG_2, 20]
	insn3	bpf_insn_mov_imm[BPF_REG_3, 0]
	insn4	bpf_insn_call_helper_t[const[BPF_FUNC_ringbuf_reserve, int32]]
	insn5	bpf_insn_mov_reg[BPF_REG_0, BPF_REG_9]
}

# (bf) r1 = r9
# (b7) r2 = BPF_RB_X
# (85) call bpf_ringbuf_{submit,discard}#322192
# (bf) r0 = 0
bpf_insn_ringbuf_free {
	insn1	bpf_insn_mov_reg[BPF_REG_9, BPF_REG_1]
	insn2	bpf_insn_mov_imm_flag[BPF_REG_2, bpf_ringbuf_wakeup_flags]
	insn3	bpf_insn_call_helper_t[flags[bpf_helpers_ringbuf_free, int32]]
	insn4	bpf_insn_mov_imm[BPF_REG_0, 0]
}

bpf_helpers_ringbuf_free = BPF_FUNC_ringbuf_submit, BPF_FUNC_ringbuf_discard

# (18) r1 = map[id:16]
# (b7) r2 = 0
# (85) call bpf_ringbuf_query#322192
bpf_insn_ringbuf_query {
	insn1	bpf_insn_ringbuf_fd[BPF_REG_1]
	insn2	bpf_insn_mov_imm[BPF_REG_2, 0]
	insn3	bpf_insn_call_helper_t[const[BPF_FUNC_ringbuf_query, int32]]
}

# (18) r1 = map[id:16]
# (b7) r8 = X
# (7b) *(u64 *)(r10 -8) = r8
# (bf) r2 = r10
# (07) r2 += -8
# (b7) r3 = 8
# (b7) r4 = BPF_RB_X
# (85) call bpf_ringbuf_output#322192
bpf_insn_ringbuf_output {
	insn1	bpf_insn_ringbuf_fd[BPF_REG_1]
	insn2	bpf_insn_mov_imm_any[BPF_REG_8]
	insn3	bpf_insn_st64_reg[BPF_REG_8, BPF_REG_10, -8]
	insn4	bpf_insn_mov_reg[BPF_REG_10, BPF_REG_2]
	insn5	bpf_insn_op_imm[BPF_REG_2, BPF_ADD0, -8]
	insn6	bpf_insn_mov_imm[BPF_REG_3, 8]
	insn7	bpf_insn_mov_imm_flag[BPF_REG_4, bpf_ringbuf_wakeup_flags]
	insn8	bpf_insn_call_helper_t[const[BPF_FUNC_ringbuf_output, int32]]
}

define MAX_BPF_REG	__MAX_BPF_REG

bpf_ringbuf_wakeup_flags = 0, BPF_RB_NO_WAKEUP, BPF_RB_FORCE_WAKEUP
