1 /* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com
2 * Copyright (c) 2016 Facebook
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of version 2 of the GNU General Public
6 * License as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
14 #include <linux/bpf.h>
18 #define __BPF_FUNC_STR_FN(x) [BPF_FUNC_ ## x] = __stringify(bpf_ ## x)
19 static const char * const func_id_str
[] = {
20 __BPF_FUNC_MAPPER(__BPF_FUNC_STR_FN
)
22 #undef __BPF_FUNC_STR_FN
24 static const char *__func_get_name(const struct bpf_insn_cbs
*cbs
,
25 const struct bpf_insn
*insn
,
26 char *buff
, size_t len
)
28 BUILD_BUG_ON(ARRAY_SIZE(func_id_str
) != __BPF_FUNC_MAX_ID
);
30 if (insn
->src_reg
!= BPF_PSEUDO_CALL
&&
31 insn
->imm
>= 0 && insn
->imm
< __BPF_FUNC_MAX_ID
&&
32 func_id_str
[insn
->imm
])
33 return func_id_str
[insn
->imm
];
35 if (cbs
&& cbs
->cb_call
)
36 return cbs
->cb_call(cbs
->private_data
, insn
);
38 if (insn
->src_reg
== BPF_PSEUDO_CALL
)
39 snprintf(buff
, len
, "%+d", insn
->imm
);
44 static const char *__func_imm_name(const struct bpf_insn_cbs
*cbs
,
45 const struct bpf_insn
*insn
,
46 u64 full_imm
, char *buff
, size_t len
)
48 if (cbs
&& cbs
->cb_imm
)
49 return cbs
->cb_imm(cbs
->private_data
, insn
, full_imm
);
51 snprintf(buff
, len
, "0x%llx", (unsigned long long)full_imm
);
55 const char *func_id_name(int id
)
57 if (id
>= 0 && id
< __BPF_FUNC_MAX_ID
&& func_id_str
[id
])
58 return func_id_str
[id
];
63 const char *const bpf_class_string
[8] = {
71 [BPF_ALU64
] = "alu64",
74 const char *const bpf_alu_string
[16] = {
75 [BPF_ADD
>> 4] = "+=",
76 [BPF_SUB
>> 4] = "-=",
77 [BPF_MUL
>> 4] = "*=",
78 [BPF_DIV
>> 4] = "/=",
80 [BPF_AND
>> 4] = "&=",
81 [BPF_LSH
>> 4] = "<<=",
82 [BPF_RSH
>> 4] = ">>=",
83 [BPF_NEG
>> 4] = "neg",
84 [BPF_MOD
>> 4] = "%=",
85 [BPF_XOR
>> 4] = "^=",
87 [BPF_ARSH
>> 4] = "s>>=",
88 [BPF_END
>> 4] = "endian",
91 static const char *const bpf_ldst_string
[] = {
95 [BPF_DW
>> 3] = "u64",
98 static const char *const bpf_jmp_string
[16] = {
99 [BPF_JA
>> 4] = "jmp",
100 [BPF_JEQ
>> 4] = "==",
101 [BPF_JGT
>> 4] = ">",
102 [BPF_JLT
>> 4] = "<",
103 [BPF_JGE
>> 4] = ">=",
104 [BPF_JLE
>> 4] = "<=",
105 [BPF_JSET
>> 4] = "&",
106 [BPF_JNE
>> 4] = "!=",
107 [BPF_JSGT
>> 4] = "s>",
108 [BPF_JSLT
>> 4] = "s<",
109 [BPF_JSGE
>> 4] = "s>=",
110 [BPF_JSLE
>> 4] = "s<=",
111 [BPF_CALL
>> 4] = "call",
112 [BPF_EXIT
>> 4] = "exit",
115 static void print_bpf_end_insn(bpf_insn_print_t verbose
,
116 struct bpf_verifier_env
*env
,
117 const struct bpf_insn
*insn
)
119 verbose(env
, "(%02x) r%d = %s%d r%d\n", insn
->code
, insn
->dst_reg
,
120 BPF_SRC(insn
->code
) == BPF_TO_BE
? "be" : "le",
121 insn
->imm
, insn
->dst_reg
);
124 void print_bpf_insn(const struct bpf_insn_cbs
*cbs
,
125 struct bpf_verifier_env
*env
,
126 const struct bpf_insn
*insn
,
127 bool allow_ptr_leaks
)
129 const bpf_insn_print_t verbose
= cbs
->cb_print
;
130 u8
class = BPF_CLASS(insn
->code
);
132 if (class == BPF_ALU
|| class == BPF_ALU64
) {
133 if (BPF_OP(insn
->code
) == BPF_END
) {
134 if (class == BPF_ALU64
)
135 verbose(env
, "BUG_alu64_%02x\n", insn
->code
);
137 print_bpf_end_insn(verbose
, env
, insn
);
138 } else if (BPF_OP(insn
->code
) == BPF_NEG
) {
139 verbose(env
, "(%02x) r%d = %s-r%d\n",
140 insn
->code
, insn
->dst_reg
,
141 class == BPF_ALU
? "(u32) " : "",
143 } else if (BPF_SRC(insn
->code
) == BPF_X
) {
144 verbose(env
, "(%02x) %sr%d %s %sr%d\n",
145 insn
->code
, class == BPF_ALU
? "(u32) " : "",
147 bpf_alu_string
[BPF_OP(insn
->code
) >> 4],
148 class == BPF_ALU
? "(u32) " : "",
151 verbose(env
, "(%02x) %sr%d %s %s%d\n",
152 insn
->code
, class == BPF_ALU
? "(u32) " : "",
154 bpf_alu_string
[BPF_OP(insn
->code
) >> 4],
155 class == BPF_ALU
? "(u32) " : "",
158 } else if (class == BPF_STX
) {
159 if (BPF_MODE(insn
->code
) == BPF_MEM
)
160 verbose(env
, "(%02x) *(%s *)(r%d %+d) = r%d\n",
162 bpf_ldst_string
[BPF_SIZE(insn
->code
) >> 3],
164 insn
->off
, insn
->src_reg
);
165 else if (BPF_MODE(insn
->code
) == BPF_XADD
)
166 verbose(env
, "(%02x) lock *(%s *)(r%d %+d) += r%d\n",
168 bpf_ldst_string
[BPF_SIZE(insn
->code
) >> 3],
169 insn
->dst_reg
, insn
->off
,
172 verbose(env
, "BUG_%02x\n", insn
->code
);
173 } else if (class == BPF_ST
) {
174 if (BPF_MODE(insn
->code
) != BPF_MEM
) {
175 verbose(env
, "BUG_st_%02x\n", insn
->code
);
178 verbose(env
, "(%02x) *(%s *)(r%d %+d) = %d\n",
180 bpf_ldst_string
[BPF_SIZE(insn
->code
) >> 3],
182 insn
->off
, insn
->imm
);
183 } else if (class == BPF_LDX
) {
184 if (BPF_MODE(insn
->code
) != BPF_MEM
) {
185 verbose(env
, "BUG_ldx_%02x\n", insn
->code
);
188 verbose(env
, "(%02x) r%d = *(%s *)(r%d %+d)\n",
189 insn
->code
, insn
->dst_reg
,
190 bpf_ldst_string
[BPF_SIZE(insn
->code
) >> 3],
191 insn
->src_reg
, insn
->off
);
192 } else if (class == BPF_LD
) {
193 if (BPF_MODE(insn
->code
) == BPF_ABS
) {
194 verbose(env
, "(%02x) r0 = *(%s *)skb[%d]\n",
196 bpf_ldst_string
[BPF_SIZE(insn
->code
) >> 3],
198 } else if (BPF_MODE(insn
->code
) == BPF_IND
) {
199 verbose(env
, "(%02x) r0 = *(%s *)skb[r%d + %d]\n",
201 bpf_ldst_string
[BPF_SIZE(insn
->code
) >> 3],
202 insn
->src_reg
, insn
->imm
);
203 } else if (BPF_MODE(insn
->code
) == BPF_IMM
&&
204 BPF_SIZE(insn
->code
) == BPF_DW
) {
205 /* At this point, we already made sure that the second
206 * part of the ldimm64 insn is accessible.
208 u64 imm
= ((u64
)(insn
+ 1)->imm
<< 32) | (u32
)insn
->imm
;
209 bool map_ptr
= insn
->src_reg
== BPF_PSEUDO_MAP_FD
;
212 if (map_ptr
&& !allow_ptr_leaks
)
215 verbose(env
, "(%02x) r%d = %s\n",
216 insn
->code
, insn
->dst_reg
,
217 __func_imm_name(cbs
, insn
, imm
,
220 verbose(env
, "BUG_ld_%02x\n", insn
->code
);
223 } else if (class == BPF_JMP
) {
224 u8 opcode
= BPF_OP(insn
->code
);
226 if (opcode
== BPF_CALL
) {
229 if (insn
->src_reg
== BPF_PSEUDO_CALL
) {
230 verbose(env
, "(%02x) call pc%s\n",
232 __func_get_name(cbs
, insn
,
235 strcpy(tmp
, "unknown");
236 verbose(env
, "(%02x) call %s#%d\n", insn
->code
,
237 __func_get_name(cbs
, insn
,
241 } else if (insn
->code
== (BPF_JMP
| BPF_JA
)) {
242 verbose(env
, "(%02x) goto pc%+d\n",
243 insn
->code
, insn
->off
);
244 } else if (insn
->code
== (BPF_JMP
| BPF_EXIT
)) {
245 verbose(env
, "(%02x) exit\n", insn
->code
);
246 } else if (BPF_SRC(insn
->code
) == BPF_X
) {
247 verbose(env
, "(%02x) if r%d %s r%d goto pc%+d\n",
248 insn
->code
, insn
->dst_reg
,
249 bpf_jmp_string
[BPF_OP(insn
->code
) >> 4],
250 insn
->src_reg
, insn
->off
);
252 verbose(env
, "(%02x) if r%d %s 0x%x goto pc%+d\n",
253 insn
->code
, insn
->dst_reg
,
254 bpf_jmp_string
[BPF_OP(insn
->code
) >> 4],
255 insn
->imm
, insn
->off
);
258 verbose(env
, "(%02x) %s\n",
259 insn
->code
, bpf_class_string
[class]);