162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
262306a36Sopenharmony_ci/* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com
362306a36Sopenharmony_ci * Copyright (c) 2016 Facebook
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/bpf.h>
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "disasm.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#define __BPF_FUNC_STR_FN(x) [BPF_FUNC_ ## x] = __stringify(bpf_ ## x)
1162306a36Sopenharmony_cistatic const char * const func_id_str[] = {
1262306a36Sopenharmony_ci	__BPF_FUNC_MAPPER(__BPF_FUNC_STR_FN)
1362306a36Sopenharmony_ci};
1462306a36Sopenharmony_ci#undef __BPF_FUNC_STR_FN
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistatic const char *__func_get_name(const struct bpf_insn_cbs *cbs,
1762306a36Sopenharmony_ci				   const struct bpf_insn *insn,
1862306a36Sopenharmony_ci				   char *buff, size_t len)
1962306a36Sopenharmony_ci{
2062306a36Sopenharmony_ci	BUILD_BUG_ON(ARRAY_SIZE(func_id_str) != __BPF_FUNC_MAX_ID);
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci	if (!insn->src_reg &&
2362306a36Sopenharmony_ci	    insn->imm >= 0 && insn->imm < __BPF_FUNC_MAX_ID &&
2462306a36Sopenharmony_ci	    func_id_str[insn->imm])
2562306a36Sopenharmony_ci		return func_id_str[insn->imm];
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	if (cbs && cbs->cb_call) {
2862306a36Sopenharmony_ci		const char *res;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci		res = cbs->cb_call(cbs->private_data, insn);
3162306a36Sopenharmony_ci		if (res)
3262306a36Sopenharmony_ci			return res;
3362306a36Sopenharmony_ci	}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	if (insn->src_reg == BPF_PSEUDO_CALL)
3662306a36Sopenharmony_ci		snprintf(buff, len, "%+d", insn->imm);
3762306a36Sopenharmony_ci	else if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL)
3862306a36Sopenharmony_ci		snprintf(buff, len, "kernel-function");
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	return buff;
4162306a36Sopenharmony_ci}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic const char *__func_imm_name(const struct bpf_insn_cbs *cbs,
4462306a36Sopenharmony_ci				   const struct bpf_insn *insn,
4562306a36Sopenharmony_ci				   u64 full_imm, char *buff, size_t len)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	if (cbs && cbs->cb_imm)
4862306a36Sopenharmony_ci		return cbs->cb_imm(cbs->private_data, insn, full_imm);
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	snprintf(buff, len, "0x%llx", (unsigned long long)full_imm);
5162306a36Sopenharmony_ci	return buff;
5262306a36Sopenharmony_ci}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ciconst char *func_id_name(int id)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	if (id >= 0 && id < __BPF_FUNC_MAX_ID && func_id_str[id])
5762306a36Sopenharmony_ci		return func_id_str[id];
5862306a36Sopenharmony_ci	else
5962306a36Sopenharmony_ci		return "unknown";
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ciconst char *const bpf_class_string[8] = {
6362306a36Sopenharmony_ci	[BPF_LD]    = "ld",
6462306a36Sopenharmony_ci	[BPF_LDX]   = "ldx",
6562306a36Sopenharmony_ci	[BPF_ST]    = "st",
6662306a36Sopenharmony_ci	[BPF_STX]   = "stx",
6762306a36Sopenharmony_ci	[BPF_ALU]   = "alu",
6862306a36Sopenharmony_ci	[BPF_JMP]   = "jmp",
6962306a36Sopenharmony_ci	[BPF_JMP32] = "jmp32",
7062306a36Sopenharmony_ci	[BPF_ALU64] = "alu64",
7162306a36Sopenharmony_ci};
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ciconst char *const bpf_alu_string[16] = {
7462306a36Sopenharmony_ci	[BPF_ADD >> 4]  = "+=",
7562306a36Sopenharmony_ci	[BPF_SUB >> 4]  = "-=",
7662306a36Sopenharmony_ci	[BPF_MUL >> 4]  = "*=",
7762306a36Sopenharmony_ci	[BPF_DIV >> 4]  = "/=",
7862306a36Sopenharmony_ci	[BPF_OR  >> 4]  = "|=",
7962306a36Sopenharmony_ci	[BPF_AND >> 4]  = "&=",
8062306a36Sopenharmony_ci	[BPF_LSH >> 4]  = "<<=",
8162306a36Sopenharmony_ci	[BPF_RSH >> 4]  = ">>=",
8262306a36Sopenharmony_ci	[BPF_NEG >> 4]  = "neg",
8362306a36Sopenharmony_ci	[BPF_MOD >> 4]  = "%=",
8462306a36Sopenharmony_ci	[BPF_XOR >> 4]  = "^=",
8562306a36Sopenharmony_ci	[BPF_MOV >> 4]  = "=",
8662306a36Sopenharmony_ci	[BPF_ARSH >> 4] = "s>>=",
8762306a36Sopenharmony_ci	[BPF_END >> 4]  = "endian",
8862306a36Sopenharmony_ci};
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic const char *const bpf_alu_sign_string[16] = {
9162306a36Sopenharmony_ci	[BPF_DIV >> 4]  = "s/=",
9262306a36Sopenharmony_ci	[BPF_MOD >> 4]  = "s%=",
9362306a36Sopenharmony_ci};
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic const char *const bpf_movsx_string[4] = {
9662306a36Sopenharmony_ci	[0] = "(s8)",
9762306a36Sopenharmony_ci	[1] = "(s16)",
9862306a36Sopenharmony_ci	[3] = "(s32)",
9962306a36Sopenharmony_ci};
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic const char *const bpf_atomic_alu_string[16] = {
10262306a36Sopenharmony_ci	[BPF_ADD >> 4]  = "add",
10362306a36Sopenharmony_ci	[BPF_AND >> 4]  = "and",
10462306a36Sopenharmony_ci	[BPF_OR >> 4]  = "or",
10562306a36Sopenharmony_ci	[BPF_XOR >> 4]  = "xor",
10662306a36Sopenharmony_ci};
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cistatic const char *const bpf_ldst_string[] = {
10962306a36Sopenharmony_ci	[BPF_W >> 3]  = "u32",
11062306a36Sopenharmony_ci	[BPF_H >> 3]  = "u16",
11162306a36Sopenharmony_ci	[BPF_B >> 3]  = "u8",
11262306a36Sopenharmony_ci	[BPF_DW >> 3] = "u64",
11362306a36Sopenharmony_ci};
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistatic const char *const bpf_ldsx_string[] = {
11662306a36Sopenharmony_ci	[BPF_W >> 3]  = "s32",
11762306a36Sopenharmony_ci	[BPF_H >> 3]  = "s16",
11862306a36Sopenharmony_ci	[BPF_B >> 3]  = "s8",
11962306a36Sopenharmony_ci};
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic const char *const bpf_jmp_string[16] = {
12262306a36Sopenharmony_ci	[BPF_JA >> 4]   = "jmp",
12362306a36Sopenharmony_ci	[BPF_JEQ >> 4]  = "==",
12462306a36Sopenharmony_ci	[BPF_JGT >> 4]  = ">",
12562306a36Sopenharmony_ci	[BPF_JLT >> 4]  = "<",
12662306a36Sopenharmony_ci	[BPF_JGE >> 4]  = ">=",
12762306a36Sopenharmony_ci	[BPF_JLE >> 4]  = "<=",
12862306a36Sopenharmony_ci	[BPF_JSET >> 4] = "&",
12962306a36Sopenharmony_ci	[BPF_JNE >> 4]  = "!=",
13062306a36Sopenharmony_ci	[BPF_JSGT >> 4] = "s>",
13162306a36Sopenharmony_ci	[BPF_JSLT >> 4] = "s<",
13262306a36Sopenharmony_ci	[BPF_JSGE >> 4] = "s>=",
13362306a36Sopenharmony_ci	[BPF_JSLE >> 4] = "s<=",
13462306a36Sopenharmony_ci	[BPF_CALL >> 4] = "call",
13562306a36Sopenharmony_ci	[BPF_EXIT >> 4] = "exit",
13662306a36Sopenharmony_ci};
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_cistatic void print_bpf_end_insn(bpf_insn_print_t verbose,
13962306a36Sopenharmony_ci			       void *private_data,
14062306a36Sopenharmony_ci			       const struct bpf_insn *insn)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	verbose(private_data, "(%02x) r%d = %s%d r%d\n",
14362306a36Sopenharmony_ci		insn->code, insn->dst_reg,
14462306a36Sopenharmony_ci		BPF_SRC(insn->code) == BPF_TO_BE ? "be" : "le",
14562306a36Sopenharmony_ci		insn->imm, insn->dst_reg);
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic void print_bpf_bswap_insn(bpf_insn_print_t verbose,
14962306a36Sopenharmony_ci			       void *private_data,
15062306a36Sopenharmony_ci			       const struct bpf_insn *insn)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	verbose(private_data, "(%02x) r%d = bswap%d r%d\n",
15362306a36Sopenharmony_ci		insn->code, insn->dst_reg,
15462306a36Sopenharmony_ci		insn->imm, insn->dst_reg);
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_cistatic bool is_sdiv_smod(const struct bpf_insn *insn)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	return (BPF_OP(insn->code)  == BPF_DIV || BPF_OP(insn->code) == BPF_MOD) &&
16062306a36Sopenharmony_ci	       insn->off == 1;
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistatic bool is_movsx(const struct bpf_insn *insn)
16462306a36Sopenharmony_ci{
16562306a36Sopenharmony_ci	return BPF_OP(insn->code) == BPF_MOV &&
16662306a36Sopenharmony_ci	       (insn->off == 8 || insn->off == 16 || insn->off == 32);
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_civoid print_bpf_insn(const struct bpf_insn_cbs *cbs,
17062306a36Sopenharmony_ci		    const struct bpf_insn *insn,
17162306a36Sopenharmony_ci		    bool allow_ptr_leaks)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	const bpf_insn_print_t verbose = cbs->cb_print;
17462306a36Sopenharmony_ci	u8 class = BPF_CLASS(insn->code);
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	if (class == BPF_ALU || class == BPF_ALU64) {
17762306a36Sopenharmony_ci		if (BPF_OP(insn->code) == BPF_END) {
17862306a36Sopenharmony_ci			if (class == BPF_ALU64)
17962306a36Sopenharmony_ci				print_bpf_bswap_insn(verbose, cbs->private_data, insn);
18062306a36Sopenharmony_ci			else
18162306a36Sopenharmony_ci				print_bpf_end_insn(verbose, cbs->private_data, insn);
18262306a36Sopenharmony_ci		} else if (BPF_OP(insn->code) == BPF_NEG) {
18362306a36Sopenharmony_ci			verbose(cbs->private_data, "(%02x) %c%d = -%c%d\n",
18462306a36Sopenharmony_ci				insn->code, class == BPF_ALU ? 'w' : 'r',
18562306a36Sopenharmony_ci				insn->dst_reg, class == BPF_ALU ? 'w' : 'r',
18662306a36Sopenharmony_ci				insn->dst_reg);
18762306a36Sopenharmony_ci		} else if (BPF_SRC(insn->code) == BPF_X) {
18862306a36Sopenharmony_ci			verbose(cbs->private_data, "(%02x) %c%d %s %s%c%d\n",
18962306a36Sopenharmony_ci				insn->code, class == BPF_ALU ? 'w' : 'r',
19062306a36Sopenharmony_ci				insn->dst_reg,
19162306a36Sopenharmony_ci				is_sdiv_smod(insn) ? bpf_alu_sign_string[BPF_OP(insn->code) >> 4]
19262306a36Sopenharmony_ci						   : bpf_alu_string[BPF_OP(insn->code) >> 4],
19362306a36Sopenharmony_ci				is_movsx(insn) ? bpf_movsx_string[(insn->off >> 3) - 1] : "",
19462306a36Sopenharmony_ci				class == BPF_ALU ? 'w' : 'r',
19562306a36Sopenharmony_ci				insn->src_reg);
19662306a36Sopenharmony_ci		} else {
19762306a36Sopenharmony_ci			verbose(cbs->private_data, "(%02x) %c%d %s %d\n",
19862306a36Sopenharmony_ci				insn->code, class == BPF_ALU ? 'w' : 'r',
19962306a36Sopenharmony_ci				insn->dst_reg,
20062306a36Sopenharmony_ci				is_sdiv_smod(insn) ? bpf_alu_sign_string[BPF_OP(insn->code) >> 4]
20162306a36Sopenharmony_ci						   : bpf_alu_string[BPF_OP(insn->code) >> 4],
20262306a36Sopenharmony_ci				insn->imm);
20362306a36Sopenharmony_ci		}
20462306a36Sopenharmony_ci	} else if (class == BPF_STX) {
20562306a36Sopenharmony_ci		if (BPF_MODE(insn->code) == BPF_MEM)
20662306a36Sopenharmony_ci			verbose(cbs->private_data, "(%02x) *(%s *)(r%d %+d) = r%d\n",
20762306a36Sopenharmony_ci				insn->code,
20862306a36Sopenharmony_ci				bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
20962306a36Sopenharmony_ci				insn->dst_reg,
21062306a36Sopenharmony_ci				insn->off, insn->src_reg);
21162306a36Sopenharmony_ci		else if (BPF_MODE(insn->code) == BPF_ATOMIC &&
21262306a36Sopenharmony_ci			 (insn->imm == BPF_ADD || insn->imm == BPF_AND ||
21362306a36Sopenharmony_ci			  insn->imm == BPF_OR || insn->imm == BPF_XOR)) {
21462306a36Sopenharmony_ci			verbose(cbs->private_data, "(%02x) lock *(%s *)(r%d %+d) %s r%d\n",
21562306a36Sopenharmony_ci				insn->code,
21662306a36Sopenharmony_ci				bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
21762306a36Sopenharmony_ci				insn->dst_reg, insn->off,
21862306a36Sopenharmony_ci				bpf_alu_string[BPF_OP(insn->imm) >> 4],
21962306a36Sopenharmony_ci				insn->src_reg);
22062306a36Sopenharmony_ci		} else if (BPF_MODE(insn->code) == BPF_ATOMIC &&
22162306a36Sopenharmony_ci			   (insn->imm == (BPF_ADD | BPF_FETCH) ||
22262306a36Sopenharmony_ci			    insn->imm == (BPF_AND | BPF_FETCH) ||
22362306a36Sopenharmony_ci			    insn->imm == (BPF_OR | BPF_FETCH) ||
22462306a36Sopenharmony_ci			    insn->imm == (BPF_XOR | BPF_FETCH))) {
22562306a36Sopenharmony_ci			verbose(cbs->private_data, "(%02x) r%d = atomic%s_fetch_%s((%s *)(r%d %+d), r%d)\n",
22662306a36Sopenharmony_ci				insn->code, insn->src_reg,
22762306a36Sopenharmony_ci				BPF_SIZE(insn->code) == BPF_DW ? "64" : "",
22862306a36Sopenharmony_ci				bpf_atomic_alu_string[BPF_OP(insn->imm) >> 4],
22962306a36Sopenharmony_ci				bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
23062306a36Sopenharmony_ci				insn->dst_reg, insn->off, insn->src_reg);
23162306a36Sopenharmony_ci		} else if (BPF_MODE(insn->code) == BPF_ATOMIC &&
23262306a36Sopenharmony_ci			   insn->imm == BPF_CMPXCHG) {
23362306a36Sopenharmony_ci			verbose(cbs->private_data, "(%02x) r0 = atomic%s_cmpxchg((%s *)(r%d %+d), r0, r%d)\n",
23462306a36Sopenharmony_ci				insn->code,
23562306a36Sopenharmony_ci				BPF_SIZE(insn->code) == BPF_DW ? "64" : "",
23662306a36Sopenharmony_ci				bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
23762306a36Sopenharmony_ci				insn->dst_reg, insn->off,
23862306a36Sopenharmony_ci				insn->src_reg);
23962306a36Sopenharmony_ci		} else if (BPF_MODE(insn->code) == BPF_ATOMIC &&
24062306a36Sopenharmony_ci			   insn->imm == BPF_XCHG) {
24162306a36Sopenharmony_ci			verbose(cbs->private_data, "(%02x) r%d = atomic%s_xchg((%s *)(r%d %+d), r%d)\n",
24262306a36Sopenharmony_ci				insn->code, insn->src_reg,
24362306a36Sopenharmony_ci				BPF_SIZE(insn->code) == BPF_DW ? "64" : "",
24462306a36Sopenharmony_ci				bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
24562306a36Sopenharmony_ci				insn->dst_reg, insn->off, insn->src_reg);
24662306a36Sopenharmony_ci		} else {
24762306a36Sopenharmony_ci			verbose(cbs->private_data, "BUG_%02x\n", insn->code);
24862306a36Sopenharmony_ci		}
24962306a36Sopenharmony_ci	} else if (class == BPF_ST) {
25062306a36Sopenharmony_ci		if (BPF_MODE(insn->code) == BPF_MEM) {
25162306a36Sopenharmony_ci			verbose(cbs->private_data, "(%02x) *(%s *)(r%d %+d) = %d\n",
25262306a36Sopenharmony_ci				insn->code,
25362306a36Sopenharmony_ci				bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
25462306a36Sopenharmony_ci				insn->dst_reg,
25562306a36Sopenharmony_ci				insn->off, insn->imm);
25662306a36Sopenharmony_ci		} else if (BPF_MODE(insn->code) == 0xc0 /* BPF_NOSPEC, no UAPI */) {
25762306a36Sopenharmony_ci			verbose(cbs->private_data, "(%02x) nospec\n", insn->code);
25862306a36Sopenharmony_ci		} else {
25962306a36Sopenharmony_ci			verbose(cbs->private_data, "BUG_st_%02x\n", insn->code);
26062306a36Sopenharmony_ci		}
26162306a36Sopenharmony_ci	} else if (class == BPF_LDX) {
26262306a36Sopenharmony_ci		if (BPF_MODE(insn->code) != BPF_MEM && BPF_MODE(insn->code) != BPF_MEMSX) {
26362306a36Sopenharmony_ci			verbose(cbs->private_data, "BUG_ldx_%02x\n", insn->code);
26462306a36Sopenharmony_ci			return;
26562306a36Sopenharmony_ci		}
26662306a36Sopenharmony_ci		verbose(cbs->private_data, "(%02x) r%d = *(%s *)(r%d %+d)\n",
26762306a36Sopenharmony_ci			insn->code, insn->dst_reg,
26862306a36Sopenharmony_ci			BPF_MODE(insn->code) == BPF_MEM ?
26962306a36Sopenharmony_ci				 bpf_ldst_string[BPF_SIZE(insn->code) >> 3] :
27062306a36Sopenharmony_ci				 bpf_ldsx_string[BPF_SIZE(insn->code) >> 3],
27162306a36Sopenharmony_ci			insn->src_reg, insn->off);
27262306a36Sopenharmony_ci	} else if (class == BPF_LD) {
27362306a36Sopenharmony_ci		if (BPF_MODE(insn->code) == BPF_ABS) {
27462306a36Sopenharmony_ci			verbose(cbs->private_data, "(%02x) r0 = *(%s *)skb[%d]\n",
27562306a36Sopenharmony_ci				insn->code,
27662306a36Sopenharmony_ci				bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
27762306a36Sopenharmony_ci				insn->imm);
27862306a36Sopenharmony_ci		} else if (BPF_MODE(insn->code) == BPF_IND) {
27962306a36Sopenharmony_ci			verbose(cbs->private_data, "(%02x) r0 = *(%s *)skb[r%d + %d]\n",
28062306a36Sopenharmony_ci				insn->code,
28162306a36Sopenharmony_ci				bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
28262306a36Sopenharmony_ci				insn->src_reg, insn->imm);
28362306a36Sopenharmony_ci		} else if (BPF_MODE(insn->code) == BPF_IMM &&
28462306a36Sopenharmony_ci			   BPF_SIZE(insn->code) == BPF_DW) {
28562306a36Sopenharmony_ci			/* At this point, we already made sure that the second
28662306a36Sopenharmony_ci			 * part of the ldimm64 insn is accessible.
28762306a36Sopenharmony_ci			 */
28862306a36Sopenharmony_ci			u64 imm = ((u64)(insn + 1)->imm << 32) | (u32)insn->imm;
28962306a36Sopenharmony_ci			bool is_ptr = insn->src_reg == BPF_PSEUDO_MAP_FD ||
29062306a36Sopenharmony_ci				      insn->src_reg == BPF_PSEUDO_MAP_VALUE;
29162306a36Sopenharmony_ci			char tmp[64];
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci			if (is_ptr && !allow_ptr_leaks)
29462306a36Sopenharmony_ci				imm = 0;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci			verbose(cbs->private_data, "(%02x) r%d = %s\n",
29762306a36Sopenharmony_ci				insn->code, insn->dst_reg,
29862306a36Sopenharmony_ci				__func_imm_name(cbs, insn, imm,
29962306a36Sopenharmony_ci						tmp, sizeof(tmp)));
30062306a36Sopenharmony_ci		} else {
30162306a36Sopenharmony_ci			verbose(cbs->private_data, "BUG_ld_%02x\n", insn->code);
30262306a36Sopenharmony_ci			return;
30362306a36Sopenharmony_ci		}
30462306a36Sopenharmony_ci	} else if (class == BPF_JMP32 || class == BPF_JMP) {
30562306a36Sopenharmony_ci		u8 opcode = BPF_OP(insn->code);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci		if (opcode == BPF_CALL) {
30862306a36Sopenharmony_ci			char tmp[64];
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci			if (insn->src_reg == BPF_PSEUDO_CALL) {
31162306a36Sopenharmony_ci				verbose(cbs->private_data, "(%02x) call pc%s\n",
31262306a36Sopenharmony_ci					insn->code,
31362306a36Sopenharmony_ci					__func_get_name(cbs, insn,
31462306a36Sopenharmony_ci							tmp, sizeof(tmp)));
31562306a36Sopenharmony_ci			} else {
31662306a36Sopenharmony_ci				strcpy(tmp, "unknown");
31762306a36Sopenharmony_ci				verbose(cbs->private_data, "(%02x) call %s#%d\n", insn->code,
31862306a36Sopenharmony_ci					__func_get_name(cbs, insn,
31962306a36Sopenharmony_ci							tmp, sizeof(tmp)),
32062306a36Sopenharmony_ci					insn->imm);
32162306a36Sopenharmony_ci			}
32262306a36Sopenharmony_ci		} else if (insn->code == (BPF_JMP | BPF_JA)) {
32362306a36Sopenharmony_ci			verbose(cbs->private_data, "(%02x) goto pc%+d\n",
32462306a36Sopenharmony_ci				insn->code, insn->off);
32562306a36Sopenharmony_ci		} else if (insn->code == (BPF_JMP32 | BPF_JA)) {
32662306a36Sopenharmony_ci			verbose(cbs->private_data, "(%02x) gotol pc%+d\n",
32762306a36Sopenharmony_ci				insn->code, insn->imm);
32862306a36Sopenharmony_ci		} else if (insn->code == (BPF_JMP | BPF_EXIT)) {
32962306a36Sopenharmony_ci			verbose(cbs->private_data, "(%02x) exit\n", insn->code);
33062306a36Sopenharmony_ci		} else if (BPF_SRC(insn->code) == BPF_X) {
33162306a36Sopenharmony_ci			verbose(cbs->private_data,
33262306a36Sopenharmony_ci				"(%02x) if %c%d %s %c%d goto pc%+d\n",
33362306a36Sopenharmony_ci				insn->code, class == BPF_JMP32 ? 'w' : 'r',
33462306a36Sopenharmony_ci				insn->dst_reg,
33562306a36Sopenharmony_ci				bpf_jmp_string[BPF_OP(insn->code) >> 4],
33662306a36Sopenharmony_ci				class == BPF_JMP32 ? 'w' : 'r',
33762306a36Sopenharmony_ci				insn->src_reg, insn->off);
33862306a36Sopenharmony_ci		} else {
33962306a36Sopenharmony_ci			verbose(cbs->private_data,
34062306a36Sopenharmony_ci				"(%02x) if %c%d %s 0x%x goto pc%+d\n",
34162306a36Sopenharmony_ci				insn->code, class == BPF_JMP32 ? 'w' : 'r',
34262306a36Sopenharmony_ci				insn->dst_reg,
34362306a36Sopenharmony_ci				bpf_jmp_string[BPF_OP(insn->code) >> 4],
34462306a36Sopenharmony_ci				insn->imm, insn->off);
34562306a36Sopenharmony_ci		}
34662306a36Sopenharmony_ci	} else {
34762306a36Sopenharmony_ci		verbose(cbs->private_data, "(%02x) %s\n",
34862306a36Sopenharmony_ci			insn->code, bpf_class_string[class]);
34962306a36Sopenharmony_ci	}
35062306a36Sopenharmony_ci}
351