149ca6153SDaniel Borkmann // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2f4ac7e0bSJakub Kicinski /* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com
3f4ac7e0bSJakub Kicinski * Copyright (c) 2016 Facebook
4f4ac7e0bSJakub Kicinski */
5f4ac7e0bSJakub Kicinski
6f4ac7e0bSJakub Kicinski #include <linux/bpf.h>
7f4ac7e0bSJakub Kicinski
8f4ac7e0bSJakub Kicinski #include "disasm.h"
9f4ac7e0bSJakub Kicinski
10f4ac7e0bSJakub Kicinski #define __BPF_FUNC_STR_FN(x) [BPF_FUNC_ ## x] = __stringify(bpf_ ## x)
11f4ac7e0bSJakub Kicinski static const char * const func_id_str[] = {
12f4ac7e0bSJakub Kicinski __BPF_FUNC_MAPPER(__BPF_FUNC_STR_FN)
13f4ac7e0bSJakub Kicinski };
14f4ac7e0bSJakub Kicinski #undef __BPF_FUNC_STR_FN
15f4ac7e0bSJakub Kicinski
__func_get_name(const struct bpf_insn_cbs * cbs,const struct bpf_insn * insn,char * buff,size_t len)167105e828SDaniel Borkmann static const char *__func_get_name(const struct bpf_insn_cbs *cbs,
177105e828SDaniel Borkmann const struct bpf_insn *insn,
187105e828SDaniel Borkmann char *buff, size_t len)
19f4ac7e0bSJakub Kicinski {
20f4ac7e0bSJakub Kicinski BUILD_BUG_ON(ARRAY_SIZE(func_id_str) != __BPF_FUNC_MAX_ID);
21f4ac7e0bSJakub Kicinski
22e6ac2450SMartin KaFai Lau if (!insn->src_reg &&
237105e828SDaniel Borkmann insn->imm >= 0 && insn->imm < __BPF_FUNC_MAX_ID &&
247105e828SDaniel Borkmann func_id_str[insn->imm])
257105e828SDaniel Borkmann return func_id_str[insn->imm];
267105e828SDaniel Borkmann
27e6ac2450SMartin KaFai Lau if (cbs && cbs->cb_call) {
28e6ac2450SMartin KaFai Lau const char *res;
29e6ac2450SMartin KaFai Lau
30e6ac2450SMartin KaFai Lau res = cbs->cb_call(cbs->private_data, insn);
31e6ac2450SMartin KaFai Lau if (res)
32e6ac2450SMartin KaFai Lau return res;
33e6ac2450SMartin KaFai Lau }
347105e828SDaniel Borkmann
357105e828SDaniel Borkmann if (insn->src_reg == BPF_PSEUDO_CALL)
367105e828SDaniel Borkmann snprintf(buff, len, "%+d", insn->imm);
37e6ac2450SMartin KaFai Lau else if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL)
38e6ac2450SMartin KaFai Lau snprintf(buff, len, "kernel-function");
397105e828SDaniel Borkmann
407105e828SDaniel Borkmann return buff;
417105e828SDaniel Borkmann }
427105e828SDaniel Borkmann
__func_imm_name(const struct bpf_insn_cbs * cbs,const struct bpf_insn * insn,u64 full_imm,char * buff,size_t len)437105e828SDaniel Borkmann static const char *__func_imm_name(const struct bpf_insn_cbs *cbs,
447105e828SDaniel Borkmann const struct bpf_insn *insn,
457105e828SDaniel Borkmann u64 full_imm, char *buff, size_t len)
467105e828SDaniel Borkmann {
477105e828SDaniel Borkmann if (cbs && cbs->cb_imm)
487105e828SDaniel Borkmann return cbs->cb_imm(cbs->private_data, insn, full_imm);
497105e828SDaniel Borkmann
507105e828SDaniel Borkmann snprintf(buff, len, "0x%llx", (unsigned long long)full_imm);
517105e828SDaniel Borkmann return buff;
527105e828SDaniel Borkmann }
537105e828SDaniel Borkmann
func_id_name(int id)547105e828SDaniel Borkmann const char *func_id_name(int id)
557105e828SDaniel Borkmann {
56f4ac7e0bSJakub Kicinski if (id >= 0 && id < __BPF_FUNC_MAX_ID && func_id_str[id])
57f4ac7e0bSJakub Kicinski return func_id_str[id];
58f4ac7e0bSJakub Kicinski else
59f4ac7e0bSJakub Kicinski return "unknown";
60f4ac7e0bSJakub Kicinski }
61f4ac7e0bSJakub Kicinski
62f4ac7e0bSJakub Kicinski const char *const bpf_class_string[8] = {
63f4ac7e0bSJakub Kicinski [BPF_LD] = "ld",
64f4ac7e0bSJakub Kicinski [BPF_LDX] = "ldx",
65f4ac7e0bSJakub Kicinski [BPF_ST] = "st",
66f4ac7e0bSJakub Kicinski [BPF_STX] = "stx",
67f4ac7e0bSJakub Kicinski [BPF_ALU] = "alu",
68f4ac7e0bSJakub Kicinski [BPF_JMP] = "jmp",
6956cbd82eSJiong Wang [BPF_JMP32] = "jmp32",
70f4ac7e0bSJakub Kicinski [BPF_ALU64] = "alu64",
71f4ac7e0bSJakub Kicinski };
72f4ac7e0bSJakub Kicinski
73f4ac7e0bSJakub Kicinski const char *const bpf_alu_string[16] = {
74f4ac7e0bSJakub Kicinski [BPF_ADD >> 4] = "+=",
75f4ac7e0bSJakub Kicinski [BPF_SUB >> 4] = "-=",
76f4ac7e0bSJakub Kicinski [BPF_MUL >> 4] = "*=",
77f4ac7e0bSJakub Kicinski [BPF_DIV >> 4] = "/=",
78f4ac7e0bSJakub Kicinski [BPF_OR >> 4] = "|=",
79f4ac7e0bSJakub Kicinski [BPF_AND >> 4] = "&=",
80f4ac7e0bSJakub Kicinski [BPF_LSH >> 4] = "<<=",
81f4ac7e0bSJakub Kicinski [BPF_RSH >> 4] = ">>=",
82f4ac7e0bSJakub Kicinski [BPF_NEG >> 4] = "neg",
83f4ac7e0bSJakub Kicinski [BPF_MOD >> 4] = "%=",
84f4ac7e0bSJakub Kicinski [BPF_XOR >> 4] = "^=",
85f4ac7e0bSJakub Kicinski [BPF_MOV >> 4] = "=",
86f4ac7e0bSJakub Kicinski [BPF_ARSH >> 4] = "s>>=",
87f4ac7e0bSJakub Kicinski [BPF_END >> 4] = "endian",
88f4ac7e0bSJakub Kicinski };
89f4ac7e0bSJakub Kicinski
901e8e2efbSYang Yingliang static const char *const bpf_alu_sign_string[16] = {
91f835bb62SYonghong Song [BPF_DIV >> 4] = "s/=",
92f835bb62SYonghong Song [BPF_MOD >> 4] = "s%=",
93f835bb62SYonghong Song };
94f835bb62SYonghong Song
951e8e2efbSYang Yingliang static const char *const bpf_movsx_string[4] = {
96f835bb62SYonghong Song [0] = "(s8)",
97f835bb62SYonghong Song [1] = "(s16)",
98f835bb62SYonghong Song [3] = "(s32)",
99f835bb62SYonghong Song };
100f835bb62SYonghong Song
101981f94c3SBrendan Jackman static const char *const bpf_atomic_alu_string[16] = {
102981f94c3SBrendan Jackman [BPF_ADD >> 4] = "add",
103981f94c3SBrendan Jackman [BPF_AND >> 4] = "and",
104981f94c3SBrendan Jackman [BPF_OR >> 4] = "or",
105d6fe1cf8SXu Kuohai [BPF_XOR >> 4] = "xor",
106981f94c3SBrendan Jackman };
107981f94c3SBrendan Jackman
108f4ac7e0bSJakub Kicinski static const char *const bpf_ldst_string[] = {
109f4ac7e0bSJakub Kicinski [BPF_W >> 3] = "u32",
110f4ac7e0bSJakub Kicinski [BPF_H >> 3] = "u16",
111f4ac7e0bSJakub Kicinski [BPF_B >> 3] = "u8",
112f4ac7e0bSJakub Kicinski [BPF_DW >> 3] = "u64",
113f4ac7e0bSJakub Kicinski };
114f4ac7e0bSJakub Kicinski
115f835bb62SYonghong Song static const char *const bpf_ldsx_string[] = {
116f835bb62SYonghong Song [BPF_W >> 3] = "s32",
117f835bb62SYonghong Song [BPF_H >> 3] = "s16",
118f835bb62SYonghong Song [BPF_B >> 3] = "s8",
119f835bb62SYonghong Song };
120f835bb62SYonghong Song
121f4ac7e0bSJakub Kicinski static const char *const bpf_jmp_string[16] = {
122f4ac7e0bSJakub Kicinski [BPF_JA >> 4] = "jmp",
123f4ac7e0bSJakub Kicinski [BPF_JEQ >> 4] = "==",
124f4ac7e0bSJakub Kicinski [BPF_JGT >> 4] = ">",
125f4ac7e0bSJakub Kicinski [BPF_JLT >> 4] = "<",
126f4ac7e0bSJakub Kicinski [BPF_JGE >> 4] = ">=",
127f4ac7e0bSJakub Kicinski [BPF_JLE >> 4] = "<=",
128f4ac7e0bSJakub Kicinski [BPF_JSET >> 4] = "&",
129f4ac7e0bSJakub Kicinski [BPF_JNE >> 4] = "!=",
130f4ac7e0bSJakub Kicinski [BPF_JSGT >> 4] = "s>",
131f4ac7e0bSJakub Kicinski [BPF_JSLT >> 4] = "s<",
132f4ac7e0bSJakub Kicinski [BPF_JSGE >> 4] = "s>=",
133f4ac7e0bSJakub Kicinski [BPF_JSLE >> 4] = "s<=",
134f4ac7e0bSJakub Kicinski [BPF_CALL >> 4] = "call",
135f4ac7e0bSJakub Kicinski [BPF_EXIT >> 4] = "exit",
136f4ac7e0bSJakub Kicinski };
137f4ac7e0bSJakub Kicinski
print_bpf_end_insn(bpf_insn_print_t verbose,void * private_data,const struct bpf_insn * insn)1387105e828SDaniel Borkmann static void print_bpf_end_insn(bpf_insn_print_t verbose,
139abe08840SJiri Olsa void *private_data,
140f4ac7e0bSJakub Kicinski const struct bpf_insn *insn)
141f4ac7e0bSJakub Kicinski {
142abe08840SJiri Olsa verbose(private_data, "(%02x) r%d = %s%d r%d\n",
143abe08840SJiri Olsa insn->code, insn->dst_reg,
144f4ac7e0bSJakub Kicinski BPF_SRC(insn->code) == BPF_TO_BE ? "be" : "le",
145f4ac7e0bSJakub Kicinski insn->imm, insn->dst_reg);
146f4ac7e0bSJakub Kicinski }
147f4ac7e0bSJakub Kicinski
print_bpf_bswap_insn(bpf_insn_print_t verbose,void * private_data,const struct bpf_insn * insn)148f835bb62SYonghong Song static void print_bpf_bswap_insn(bpf_insn_print_t verbose,
149f835bb62SYonghong Song void *private_data,
150f835bb62SYonghong Song const struct bpf_insn *insn)
151f835bb62SYonghong Song {
152f835bb62SYonghong Song verbose(private_data, "(%02x) r%d = bswap%d r%d\n",
153f835bb62SYonghong Song insn->code, insn->dst_reg,
154f835bb62SYonghong Song insn->imm, insn->dst_reg);
155f835bb62SYonghong Song }
156f835bb62SYonghong Song
is_sdiv_smod(const struct bpf_insn * insn)157f835bb62SYonghong Song static bool is_sdiv_smod(const struct bpf_insn *insn)
158f835bb62SYonghong Song {
159f835bb62SYonghong Song return (BPF_OP(insn->code) == BPF_DIV || BPF_OP(insn->code) == BPF_MOD) &&
160f835bb62SYonghong Song insn->off == 1;
161f835bb62SYonghong Song }
162f835bb62SYonghong Song
is_movsx(const struct bpf_insn * insn)163f835bb62SYonghong Song static bool is_movsx(const struct bpf_insn *insn)
164f835bb62SYonghong Song {
165e99688ebSYonghong Song return BPF_OP(insn->code) == BPF_MOV &&
166e99688ebSYonghong Song (insn->off == 8 || insn->off == 16 || insn->off == 32);
167f835bb62SYonghong Song }
168f835bb62SYonghong Song
is_addr_space_cast(const struct bpf_insn * insn)169667a86adSAlexei Starovoitov static bool is_addr_space_cast(const struct bpf_insn *insn)
170667a86adSAlexei Starovoitov {
171667a86adSAlexei Starovoitov return insn->code == (BPF_ALU64 | BPF_MOV | BPF_X) &&
172667a86adSAlexei Starovoitov insn->off == BPF_ADDR_SPACE_CAST;
173667a86adSAlexei Starovoitov }
174667a86adSAlexei Starovoitov
1757bdbf744SAndrii Nakryiko /* Special (internal-only) form of mov, used to resolve per-CPU addrs:
1767bdbf744SAndrii Nakryiko * dst_reg = src_reg + <percpu_base_off>
1777bdbf744SAndrii Nakryiko * BPF_ADDR_PERCPU is used as a special insn->off value.
1787bdbf744SAndrii Nakryiko */
1797bdbf744SAndrii Nakryiko #define BPF_ADDR_PERCPU (-1)
1807bdbf744SAndrii Nakryiko
is_mov_percpu_addr(const struct bpf_insn * insn)1817bdbf744SAndrii Nakryiko static inline bool is_mov_percpu_addr(const struct bpf_insn *insn)
1827bdbf744SAndrii Nakryiko {
1837bdbf744SAndrii Nakryiko return insn->code == (BPF_ALU64 | BPF_MOV | BPF_X) && insn->off == BPF_ADDR_PERCPU;
1847bdbf744SAndrii Nakryiko }
1857bdbf744SAndrii Nakryiko
print_bpf_insn(const struct bpf_insn_cbs * cbs,const struct bpf_insn * insn,bool allow_ptr_leaks)1867105e828SDaniel Borkmann void print_bpf_insn(const struct bpf_insn_cbs *cbs,
1877105e828SDaniel Borkmann const struct bpf_insn *insn,
1887105e828SDaniel Borkmann bool allow_ptr_leaks)
189f4ac7e0bSJakub Kicinski {
1907105e828SDaniel Borkmann const bpf_insn_print_t verbose = cbs->cb_print;
191f4ac7e0bSJakub Kicinski u8 class = BPF_CLASS(insn->code);
192f4ac7e0bSJakub Kicinski
193f4ac7e0bSJakub Kicinski if (class == BPF_ALU || class == BPF_ALU64) {
194f4ac7e0bSJakub Kicinski if (BPF_OP(insn->code) == BPF_END) {
195f4ac7e0bSJakub Kicinski if (class == BPF_ALU64)
196f835bb62SYonghong Song print_bpf_bswap_insn(verbose, cbs->private_data, insn);
197f4ac7e0bSJakub Kicinski else
198abe08840SJiri Olsa print_bpf_end_insn(verbose, cbs->private_data, insn);
199f4ac7e0bSJakub Kicinski } else if (BPF_OP(insn->code) == BPF_NEG) {
20056cbd82eSJiong Wang verbose(cbs->private_data, "(%02x) %c%d = -%c%d\n",
20156cbd82eSJiong Wang insn->code, class == BPF_ALU ? 'w' : 'r',
20256cbd82eSJiong Wang insn->dst_reg, class == BPF_ALU ? 'w' : 'r',
203f4ac7e0bSJakub Kicinski insn->dst_reg);
204667a86adSAlexei Starovoitov } else if (is_addr_space_cast(insn)) {
205*3775be34SJiayuan Chen verbose(cbs->private_data, "(%02x) r%d = addr_space_cast(r%d, %u, %u)\n",
206667a86adSAlexei Starovoitov insn->code, insn->dst_reg,
207667a86adSAlexei Starovoitov insn->src_reg, ((u32)insn->imm) >> 16, (u16)insn->imm);
2087bdbf744SAndrii Nakryiko } else if (is_mov_percpu_addr(insn)) {
2097bdbf744SAndrii Nakryiko verbose(cbs->private_data, "(%02x) r%d = &(void __percpu *)(r%d)\n",
2107bdbf744SAndrii Nakryiko insn->code, insn->dst_reg, insn->src_reg);
211f4ac7e0bSJakub Kicinski } else if (BPF_SRC(insn->code) == BPF_X) {
212f835bb62SYonghong Song verbose(cbs->private_data, "(%02x) %c%d %s %s%c%d\n",
21356cbd82eSJiong Wang insn->code, class == BPF_ALU ? 'w' : 'r',
214f4ac7e0bSJakub Kicinski insn->dst_reg,
215f835bb62SYonghong Song is_sdiv_smod(insn) ? bpf_alu_sign_string[BPF_OP(insn->code) >> 4]
216f835bb62SYonghong Song : bpf_alu_string[BPF_OP(insn->code) >> 4],
217f835bb62SYonghong Song is_movsx(insn) ? bpf_movsx_string[(insn->off >> 3) - 1] : "",
21856cbd82eSJiong Wang class == BPF_ALU ? 'w' : 'r',
219f4ac7e0bSJakub Kicinski insn->src_reg);
220f4ac7e0bSJakub Kicinski } else {
22156cbd82eSJiong Wang verbose(cbs->private_data, "(%02x) %c%d %s %d\n",
22256cbd82eSJiong Wang insn->code, class == BPF_ALU ? 'w' : 'r',
223f4ac7e0bSJakub Kicinski insn->dst_reg,
224f835bb62SYonghong Song is_sdiv_smod(insn) ? bpf_alu_sign_string[BPF_OP(insn->code) >> 4]
225f835bb62SYonghong Song : bpf_alu_string[BPF_OP(insn->code) >> 4],
226f4ac7e0bSJakub Kicinski insn->imm);
227f4ac7e0bSJakub Kicinski }
228f4ac7e0bSJakub Kicinski } else if (class == BPF_STX) {
229f4ac7e0bSJakub Kicinski if (BPF_MODE(insn->code) == BPF_MEM)
230abe08840SJiri Olsa verbose(cbs->private_data, "(%02x) *(%s *)(r%d %+d) = r%d\n",
231f4ac7e0bSJakub Kicinski insn->code,
232f4ac7e0bSJakub Kicinski bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
233f4ac7e0bSJakub Kicinski insn->dst_reg,
234f4ac7e0bSJakub Kicinski insn->off, insn->src_reg);
23591c960b0SBrendan Jackman else if (BPF_MODE(insn->code) == BPF_ATOMIC &&
23660e578e8SMenglong Dong (insn->imm == BPF_ADD || insn->imm == BPF_AND ||
237981f94c3SBrendan Jackman insn->imm == BPF_OR || insn->imm == BPF_XOR)) {
238981f94c3SBrendan Jackman verbose(cbs->private_data, "(%02x) lock *(%s *)(r%d %+d) %s r%d\n",
239f4ac7e0bSJakub Kicinski insn->code,
240f4ac7e0bSJakub Kicinski bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
241f4ac7e0bSJakub Kicinski insn->dst_reg, insn->off,
242981f94c3SBrendan Jackman bpf_alu_string[BPF_OP(insn->imm) >> 4],
243f4ac7e0bSJakub Kicinski insn->src_reg);
2445ca419f2SBrendan Jackman } else if (BPF_MODE(insn->code) == BPF_ATOMIC &&
245981f94c3SBrendan Jackman (insn->imm == (BPF_ADD | BPF_FETCH) ||
246981f94c3SBrendan Jackman insn->imm == (BPF_AND | BPF_FETCH) ||
247981f94c3SBrendan Jackman insn->imm == (BPF_OR | BPF_FETCH) ||
248981f94c3SBrendan Jackman insn->imm == (BPF_XOR | BPF_FETCH))) {
249981f94c3SBrendan Jackman verbose(cbs->private_data, "(%02x) r%d = atomic%s_fetch_%s((%s *)(r%d %+d), r%d)\n",
2505ca419f2SBrendan Jackman insn->code, insn->src_reg,
2515ca419f2SBrendan Jackman BPF_SIZE(insn->code) == BPF_DW ? "64" : "",
252981f94c3SBrendan Jackman bpf_atomic_alu_string[BPF_OP(insn->imm) >> 4],
2535ca419f2SBrendan Jackman bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
2545ca419f2SBrendan Jackman insn->dst_reg, insn->off, insn->src_reg);
2555ffa2550SBrendan Jackman } else if (BPF_MODE(insn->code) == BPF_ATOMIC &&
2565ffa2550SBrendan Jackman insn->imm == BPF_CMPXCHG) {
2575ffa2550SBrendan Jackman verbose(cbs->private_data, "(%02x) r0 = atomic%s_cmpxchg((%s *)(r%d %+d), r0, r%d)\n",
2585ffa2550SBrendan Jackman insn->code,
2595ffa2550SBrendan Jackman BPF_SIZE(insn->code) == BPF_DW ? "64" : "",
2605ffa2550SBrendan Jackman bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
2615ffa2550SBrendan Jackman insn->dst_reg, insn->off,
2625ffa2550SBrendan Jackman insn->src_reg);
2635ffa2550SBrendan Jackman } else if (BPF_MODE(insn->code) == BPF_ATOMIC &&
2645ffa2550SBrendan Jackman insn->imm == BPF_XCHG) {
2655ffa2550SBrendan Jackman verbose(cbs->private_data, "(%02x) r%d = atomic%s_xchg((%s *)(r%d %+d), r%d)\n",
2665ffa2550SBrendan Jackman insn->code, insn->src_reg,
2675ffa2550SBrendan Jackman BPF_SIZE(insn->code) == BPF_DW ? "64" : "",
2685ffa2550SBrendan Jackman bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
2695ffa2550SBrendan Jackman insn->dst_reg, insn->off, insn->src_reg);
27088044230SPeilin Ye } else if (BPF_MODE(insn->code) == BPF_ATOMIC &&
27188044230SPeilin Ye insn->imm == BPF_LOAD_ACQ) {
27288044230SPeilin Ye verbose(cbs->private_data, "(%02x) r%d = load_acquire((%s *)(r%d %+d))\n",
27388044230SPeilin Ye insn->code, insn->dst_reg,
27488044230SPeilin Ye bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
27588044230SPeilin Ye insn->src_reg, insn->off);
27688044230SPeilin Ye } else if (BPF_MODE(insn->code) == BPF_ATOMIC &&
27788044230SPeilin Ye insn->imm == BPF_STORE_REL) {
27888044230SPeilin Ye verbose(cbs->private_data, "(%02x) store_release((%s *)(r%d %+d), r%d)\n",
27988044230SPeilin Ye insn->code,
28088044230SPeilin Ye bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
28188044230SPeilin Ye insn->dst_reg, insn->off, insn->src_reg);
28291c960b0SBrendan Jackman } else {
283abe08840SJiri Olsa verbose(cbs->private_data, "BUG_%02x\n", insn->code);
28491c960b0SBrendan Jackman }
285f4ac7e0bSJakub Kicinski } else if (class == BPF_ST) {
286f5e81d11SDaniel Borkmann if (BPF_MODE(insn->code) == BPF_MEM) {
287abe08840SJiri Olsa verbose(cbs->private_data, "(%02x) *(%s *)(r%d %+d) = %d\n",
288f4ac7e0bSJakub Kicinski insn->code,
289f4ac7e0bSJakub Kicinski bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
290f4ac7e0bSJakub Kicinski insn->dst_reg,
291f4ac7e0bSJakub Kicinski insn->off, insn->imm);
292f5e81d11SDaniel Borkmann } else if (BPF_MODE(insn->code) == 0xc0 /* BPF_NOSPEC, no UAPI */) {
293f5e81d11SDaniel Borkmann verbose(cbs->private_data, "(%02x) nospec\n", insn->code);
294f5e81d11SDaniel Borkmann } else {
295f5e81d11SDaniel Borkmann verbose(cbs->private_data, "BUG_st_%02x\n", insn->code);
296f5e81d11SDaniel Borkmann }
297f4ac7e0bSJakub Kicinski } else if (class == BPF_LDX) {
298f835bb62SYonghong Song if (BPF_MODE(insn->code) != BPF_MEM && BPF_MODE(insn->code) != BPF_MEMSX) {
299abe08840SJiri Olsa verbose(cbs->private_data, "BUG_ldx_%02x\n", insn->code);
300f4ac7e0bSJakub Kicinski return;
301f4ac7e0bSJakub Kicinski }
302abe08840SJiri Olsa verbose(cbs->private_data, "(%02x) r%d = *(%s *)(r%d %+d)\n",
303f4ac7e0bSJakub Kicinski insn->code, insn->dst_reg,
304f835bb62SYonghong Song BPF_MODE(insn->code) == BPF_MEM ?
305f835bb62SYonghong Song bpf_ldst_string[BPF_SIZE(insn->code) >> 3] :
306f835bb62SYonghong Song bpf_ldsx_string[BPF_SIZE(insn->code) >> 3],
307f4ac7e0bSJakub Kicinski insn->src_reg, insn->off);
308f4ac7e0bSJakub Kicinski } else if (class == BPF_LD) {
309f4ac7e0bSJakub Kicinski if (BPF_MODE(insn->code) == BPF_ABS) {
310abe08840SJiri Olsa verbose(cbs->private_data, "(%02x) r0 = *(%s *)skb[%d]\n",
311f4ac7e0bSJakub Kicinski insn->code,
312f4ac7e0bSJakub Kicinski bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
313f4ac7e0bSJakub Kicinski insn->imm);
314f4ac7e0bSJakub Kicinski } else if (BPF_MODE(insn->code) == BPF_IND) {
315abe08840SJiri Olsa verbose(cbs->private_data, "(%02x) r0 = *(%s *)skb[r%d + %d]\n",
316f4ac7e0bSJakub Kicinski insn->code,
317f4ac7e0bSJakub Kicinski bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
318f4ac7e0bSJakub Kicinski insn->src_reg, insn->imm);
319f4ac7e0bSJakub Kicinski } else if (BPF_MODE(insn->code) == BPF_IMM &&
320f4ac7e0bSJakub Kicinski BPF_SIZE(insn->code) == BPF_DW) {
321f4ac7e0bSJakub Kicinski /* At this point, we already made sure that the second
322f4ac7e0bSJakub Kicinski * part of the ldimm64 insn is accessible.
323f4ac7e0bSJakub Kicinski */
324f4ac7e0bSJakub Kicinski u64 imm = ((u64)(insn + 1)->imm << 32) | (u32)insn->imm;
325d8eca5bbSDaniel Borkmann bool is_ptr = insn->src_reg == BPF_PSEUDO_MAP_FD ||
326d8eca5bbSDaniel Borkmann insn->src_reg == BPF_PSEUDO_MAP_VALUE;
3277105e828SDaniel Borkmann char tmp[64];
328f4ac7e0bSJakub Kicinski
329d8eca5bbSDaniel Borkmann if (is_ptr && !allow_ptr_leaks)
330f4ac7e0bSJakub Kicinski imm = 0;
331f4ac7e0bSJakub Kicinski
332abe08840SJiri Olsa verbose(cbs->private_data, "(%02x) r%d = %s\n",
3337105e828SDaniel Borkmann insn->code, insn->dst_reg,
3347105e828SDaniel Borkmann __func_imm_name(cbs, insn, imm,
3357105e828SDaniel Borkmann tmp, sizeof(tmp)));
336f4ac7e0bSJakub Kicinski } else {
337abe08840SJiri Olsa verbose(cbs->private_data, "BUG_ld_%02x\n", insn->code);
338f4ac7e0bSJakub Kicinski return;
339f4ac7e0bSJakub Kicinski }
34056cbd82eSJiong Wang } else if (class == BPF_JMP32 || class == BPF_JMP) {
341f4ac7e0bSJakub Kicinski u8 opcode = BPF_OP(insn->code);
342f4ac7e0bSJakub Kicinski
343f4ac7e0bSJakub Kicinski if (opcode == BPF_CALL) {
3447105e828SDaniel Borkmann char tmp[64];
3457105e828SDaniel Borkmann
3467105e828SDaniel Borkmann if (insn->src_reg == BPF_PSEUDO_CALL) {
347abe08840SJiri Olsa verbose(cbs->private_data, "(%02x) call pc%s\n",
3487105e828SDaniel Borkmann insn->code,
3497105e828SDaniel Borkmann __func_get_name(cbs, insn,
3507105e828SDaniel Borkmann tmp, sizeof(tmp)));
3517105e828SDaniel Borkmann } else {
3527105e828SDaniel Borkmann strcpy(tmp, "unknown");
353abe08840SJiri Olsa verbose(cbs->private_data, "(%02x) call %s#%d\n", insn->code,
3547105e828SDaniel Borkmann __func_get_name(cbs, insn,
3557105e828SDaniel Borkmann tmp, sizeof(tmp)),
3567105e828SDaniel Borkmann insn->imm);
3577105e828SDaniel Borkmann }
358f4ac7e0bSJakub Kicinski } else if (insn->code == (BPF_JMP | BPF_JA)) {
359abe08840SJiri Olsa verbose(cbs->private_data, "(%02x) goto pc%+d\n",
360f4ac7e0bSJakub Kicinski insn->code, insn->off);
361011832b9SAlexei Starovoitov } else if (insn->code == (BPF_JMP | BPF_JCOND) &&
362011832b9SAlexei Starovoitov insn->src_reg == BPF_MAY_GOTO) {
363011832b9SAlexei Starovoitov verbose(cbs->private_data, "(%02x) may_goto pc%+d\n",
364011832b9SAlexei Starovoitov insn->code, insn->off);
365f835bb62SYonghong Song } else if (insn->code == (BPF_JMP32 | BPF_JA)) {
366f835bb62SYonghong Song verbose(cbs->private_data, "(%02x) gotol pc%+d\n",
367f835bb62SYonghong Song insn->code, insn->imm);
368f4ac7e0bSJakub Kicinski } else if (insn->code == (BPF_JMP | BPF_EXIT)) {
369abe08840SJiri Olsa verbose(cbs->private_data, "(%02x) exit\n", insn->code);
370f4ac7e0bSJakub Kicinski } else if (BPF_SRC(insn->code) == BPF_X) {
37156cbd82eSJiong Wang verbose(cbs->private_data,
37256cbd82eSJiong Wang "(%02x) if %c%d %s %c%d goto pc%+d\n",
37356cbd82eSJiong Wang insn->code, class == BPF_JMP32 ? 'w' : 'r',
37456cbd82eSJiong Wang insn->dst_reg,
375f4ac7e0bSJakub Kicinski bpf_jmp_string[BPF_OP(insn->code) >> 4],
37656cbd82eSJiong Wang class == BPF_JMP32 ? 'w' : 'r',
377f4ac7e0bSJakub Kicinski insn->src_reg, insn->off);
378f4ac7e0bSJakub Kicinski } else {
37956cbd82eSJiong Wang verbose(cbs->private_data,
38056cbd82eSJiong Wang "(%02x) if %c%d %s 0x%x goto pc%+d\n",
38156cbd82eSJiong Wang insn->code, class == BPF_JMP32 ? 'w' : 'r',
38256cbd82eSJiong Wang insn->dst_reg,
383f4ac7e0bSJakub Kicinski bpf_jmp_string[BPF_OP(insn->code) >> 4],
384*3775be34SJiayuan Chen (u32)insn->imm, insn->off);
385f4ac7e0bSJakub Kicinski }
386f4ac7e0bSJakub Kicinski } else {
387abe08840SJiri Olsa verbose(cbs->private_data, "(%02x) %s\n",
388f4ac7e0bSJakub Kicinski insn->code, bpf_class_string[class]);
389f4ac7e0bSJakub Kicinski }
390f4ac7e0bSJakub Kicinski }
391