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 const char *func_id_name(int id
)
26 BUILD_BUG_ON(ARRAY_SIZE(func_id_str
) != __BPF_FUNC_MAX_ID
);
28 if (id
>= 0 && id
< __BPF_FUNC_MAX_ID
&& func_id_str
[id
])
29 return func_id_str
[id
];
34 const char *const bpf_class_string
[8] = {
42 [BPF_ALU64
] = "alu64",
45 const char *const bpf_alu_string
[16] = {
46 [BPF_ADD
>> 4] = "+=",
47 [BPF_SUB
>> 4] = "-=",
48 [BPF_MUL
>> 4] = "*=",
49 [BPF_DIV
>> 4] = "/=",
51 [BPF_AND
>> 4] = "&=",
52 [BPF_LSH
>> 4] = "<<=",
53 [BPF_RSH
>> 4] = ">>=",
54 [BPF_NEG
>> 4] = "neg",
55 [BPF_MOD
>> 4] = "%=",
56 [BPF_XOR
>> 4] = "^=",
58 [BPF_ARSH
>> 4] = "s>>=",
59 [BPF_END
>> 4] = "endian",
62 static const char *const bpf_ldst_string
[] = {
66 [BPF_DW
>> 3] = "u64",
69 static const char *const bpf_jmp_string
[16] = {
70 [BPF_JA
>> 4] = "jmp",
71 [BPF_JEQ
>> 4] = "==",
74 [BPF_JGE
>> 4] = ">=",
75 [BPF_JLE
>> 4] = "<=",
76 [BPF_JSET
>> 4] = "&",
77 [BPF_JNE
>> 4] = "!=",
78 [BPF_JSGT
>> 4] = "s>",
79 [BPF_JSLT
>> 4] = "s<",
80 [BPF_JSGE
>> 4] = "s>=",
81 [BPF_JSLE
>> 4] = "s<=",
82 [BPF_CALL
>> 4] = "call",
83 [BPF_EXIT
>> 4] = "exit",
86 static void print_bpf_end_insn(bpf_insn_print_cb verbose
,
87 struct bpf_verifier_env
*env
,
88 const struct bpf_insn
*insn
)
90 verbose(env
, "(%02x) r%d = %s%d r%d\n", insn
->code
, insn
->dst_reg
,
91 BPF_SRC(insn
->code
) == BPF_TO_BE
? "be" : "le",
92 insn
->imm
, insn
->dst_reg
);
95 void print_bpf_insn(bpf_insn_print_cb verbose
, struct bpf_verifier_env
*env
,
96 const struct bpf_insn
*insn
, bool allow_ptr_leaks
)
98 u8
class = BPF_CLASS(insn
->code
);
100 if (class == BPF_ALU
|| class == BPF_ALU64
) {
101 if (BPF_OP(insn
->code
) == BPF_END
) {
102 if (class == BPF_ALU64
)
103 verbose(env
, "BUG_alu64_%02x\n", insn
->code
);
105 print_bpf_end_insn(verbose
, env
, insn
);
106 } else if (BPF_OP(insn
->code
) == BPF_NEG
) {
107 verbose(env
, "(%02x) r%d = %s-r%d\n",
108 insn
->code
, insn
->dst_reg
,
109 class == BPF_ALU
? "(u32) " : "",
111 } else if (BPF_SRC(insn
->code
) == BPF_X
) {
112 verbose(env
, "(%02x) %sr%d %s %sr%d\n",
113 insn
->code
, class == BPF_ALU
? "(u32) " : "",
115 bpf_alu_string
[BPF_OP(insn
->code
) >> 4],
116 class == BPF_ALU
? "(u32) " : "",
119 verbose(env
, "(%02x) %sr%d %s %s%d\n",
120 insn
->code
, class == BPF_ALU
? "(u32) " : "",
122 bpf_alu_string
[BPF_OP(insn
->code
) >> 4],
123 class == BPF_ALU
? "(u32) " : "",
126 } else if (class == BPF_STX
) {
127 if (BPF_MODE(insn
->code
) == BPF_MEM
)
128 verbose(env
, "(%02x) *(%s *)(r%d %+d) = r%d\n",
130 bpf_ldst_string
[BPF_SIZE(insn
->code
) >> 3],
132 insn
->off
, insn
->src_reg
);
133 else if (BPF_MODE(insn
->code
) == BPF_XADD
)
134 verbose(env
, "(%02x) lock *(%s *)(r%d %+d) += r%d\n",
136 bpf_ldst_string
[BPF_SIZE(insn
->code
) >> 3],
137 insn
->dst_reg
, insn
->off
,
140 verbose(env
, "BUG_%02x\n", insn
->code
);
141 } else if (class == BPF_ST
) {
142 if (BPF_MODE(insn
->code
) != BPF_MEM
) {
143 verbose(env
, "BUG_st_%02x\n", insn
->code
);
146 verbose(env
, "(%02x) *(%s *)(r%d %+d) = %d\n",
148 bpf_ldst_string
[BPF_SIZE(insn
->code
) >> 3],
150 insn
->off
, insn
->imm
);
151 } else if (class == BPF_LDX
) {
152 if (BPF_MODE(insn
->code
) != BPF_MEM
) {
153 verbose(env
, "BUG_ldx_%02x\n", insn
->code
);
156 verbose(env
, "(%02x) r%d = *(%s *)(r%d %+d)\n",
157 insn
->code
, insn
->dst_reg
,
158 bpf_ldst_string
[BPF_SIZE(insn
->code
) >> 3],
159 insn
->src_reg
, insn
->off
);
160 } else if (class == BPF_LD
) {
161 if (BPF_MODE(insn
->code
) == BPF_ABS
) {
162 verbose(env
, "(%02x) r0 = *(%s *)skb[%d]\n",
164 bpf_ldst_string
[BPF_SIZE(insn
->code
) >> 3],
166 } else if (BPF_MODE(insn
->code
) == BPF_IND
) {
167 verbose(env
, "(%02x) r0 = *(%s *)skb[r%d + %d]\n",
169 bpf_ldst_string
[BPF_SIZE(insn
->code
) >> 3],
170 insn
->src_reg
, insn
->imm
);
171 } else if (BPF_MODE(insn
->code
) == BPF_IMM
&&
172 BPF_SIZE(insn
->code
) == BPF_DW
) {
173 /* At this point, we already made sure that the second
174 * part of the ldimm64 insn is accessible.
176 u64 imm
= ((u64
)(insn
+ 1)->imm
<< 32) | (u32
)insn
->imm
;
177 bool map_ptr
= insn
->src_reg
== BPF_PSEUDO_MAP_FD
;
179 if (map_ptr
&& !allow_ptr_leaks
)
182 verbose(env
, "(%02x) r%d = 0x%llx\n", insn
->code
,
183 insn
->dst_reg
, (unsigned long long)imm
);
185 verbose(env
, "BUG_ld_%02x\n", insn
->code
);
188 } else if (class == BPF_JMP
) {
189 u8 opcode
= BPF_OP(insn
->code
);
191 if (opcode
== BPF_CALL
) {
192 verbose(env
, "(%02x) call %s#%d\n", insn
->code
,
193 func_id_name(insn
->imm
), insn
->imm
);
194 } else if (insn
->code
== (BPF_JMP
| BPF_JA
)) {
195 verbose(env
, "(%02x) goto pc%+d\n",
196 insn
->code
, insn
->off
);
197 } else if (insn
->code
== (BPF_JMP
| BPF_EXIT
)) {
198 verbose(env
, "(%02x) exit\n", insn
->code
);
199 } else if (BPF_SRC(insn
->code
) == BPF_X
) {
200 verbose(env
, "(%02x) if r%d %s r%d goto pc%+d\n",
201 insn
->code
, insn
->dst_reg
,
202 bpf_jmp_string
[BPF_OP(insn
->code
) >> 4],
203 insn
->src_reg
, insn
->off
);
205 verbose(env
, "(%02x) if r%d %s 0x%x goto pc%+d\n",
206 insn
->code
, insn
->dst_reg
,
207 bpf_jmp_string
[BPF_OP(insn
->code
) >> 4],
208 insn
->imm
, insn
->off
);
211 verbose(env
, "(%02x) %s\n",
212 insn
->code
, bpf_class_string
[class]);