1 /*
2  * BPF asm code parser
3  *
4  * This program is free software; you can distribute it and/or modify
5  * it under the terms of the GNU General Public License as published
6  * by the Free Software Foundation; either version 2 of the License,
7  * or (at your option) any later version.
8  *
9  * Syntax kept close to:
10  *
11  * Steven McCanne and Van Jacobson. 1993. The BSD packet filter: a new
12  * architecture for user-level packet capture. In Proceedings of the
13  * USENIX Winter 1993 Conference Proceedings on USENIX Winter 1993
14  * Conference Proceedings (USENIX'93). USENIX Association, Berkeley,
15  * CA, USA, 2-2.
16  *
17  * Copyright 2013 Daniel Borkmann <borkmann@redhat.com>
18  * Licensed under the GNU General Public License, version 2.0 (GPLv2)
19  */
20 
21 %{
22 
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdint.h>
26 #include <stdlib.h>
27 #include <stdbool.h>
28 #include <unistd.h>
29 #include <errno.h>
30 #include <assert.h>
31 #include <linux/filter.h>
32 
33 #include "bpf_exp.yacc.h"
34 
35 enum jmp_type { JTL, JFL, JKL };
36 
37 extern FILE *yyin;
38 extern int yylex(void);
39 extern void yyerror(const char *str);
40 
41 extern void bpf_asm_compile(FILE *fp, bool cstyle);
42 static void bpf_set_curr_instr(uint16_t op, uint8_t jt, uint8_t jf, uint32_t k);
43 static void bpf_set_curr_label(char *label);
44 static void bpf_set_jmp_label(char *label, enum jmp_type type);
45 
46 %}
47 
48 %union {
49 	char *label;
50 	uint32_t number;
51 }
52 
53 %token OP_LDB OP_LDH OP_LD OP_LDX OP_ST OP_STX OP_JMP OP_JEQ OP_JGT OP_JGE
54 %token OP_JSET OP_ADD OP_SUB OP_MUL OP_DIV OP_AND OP_OR OP_XOR OP_LSH OP_RSH
55 %token OP_RET OP_TAX OP_TXA OP_LDXB OP_MOD OP_NEG OP_JNEQ OP_JLT OP_JLE OP_LDI
56 %token OP_LDXI
57 
58 %token K_PKT_LEN K_PROTO K_TYPE K_NLATTR K_NLATTR_NEST K_MARK K_QUEUE K_HATYPE
59 %token K_RXHASH K_CPU K_IFIDX K_VLAN_TCI K_VLAN_AVAIL K_VLAN_TPID K_POFF K_RAND
60 
61 %token ':' ',' '[' ']' '(' ')' 'x' 'a' '+' 'M' '*' '&' '#' '%'
62 
63 %token number label
64 
65 %type <label> label
66 %type <number> number
67 
68 %%
69 
70 prog
71 	: line
72 	| prog line
73 	;
74 
75 line
76 	: instr
77 	| labelled_instr
78 	;
79 
80 labelled_instr
81 	: labelled instr
82 	;
83 
84 instr
85 	: ldb
86 	| ldh
87 	| ld
88 	| ldi
89 	| ldx
90 	| ldxi
91 	| st
92 	| stx
93 	| jmp
94 	| jeq
95 	| jneq
96 	| jlt
97 	| jle
98 	| jgt
99 	| jge
100 	| jset
101 	| add
102 	| sub
103 	| mul
104 	| div
105 	| mod
106 	| neg
107 	| and
108 	| or
109 	| xor
110 	| lsh
111 	| rsh
112 	| ret
113 	| tax
114 	| txa
115 	;
116 
117 labelled
118 	: label ':' { bpf_set_curr_label($1); }
119 	;
120 
121 ldb
122 	: OP_LDB '[' 'x' '+' number ']' {
123 		bpf_set_curr_instr(BPF_LD | BPF_B | BPF_IND, 0, 0, $5); }
124 	| OP_LDB '[' '%' 'x' '+' number ']' {
125 		bpf_set_curr_instr(BPF_LD | BPF_B | BPF_IND, 0, 0, $6); }
126 	| OP_LDB '[' number ']' {
127 		bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, $3); }
128 	| OP_LDB K_PROTO {
129 		bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
130 				   SKF_AD_OFF + SKF_AD_PROTOCOL); }
131 	| OP_LDB K_TYPE {
132 		bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
133 				   SKF_AD_OFF + SKF_AD_PKTTYPE); }
134 	| OP_LDB K_IFIDX {
135 		bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
136 				   SKF_AD_OFF + SKF_AD_IFINDEX); }
137 	| OP_LDB K_NLATTR {
138 		bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
139 				   SKF_AD_OFF + SKF_AD_NLATTR); }
140 	| OP_LDB K_NLATTR_NEST {
141 		bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
142 				   SKF_AD_OFF + SKF_AD_NLATTR_NEST); }
143 	| OP_LDB K_MARK {
144 		bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
145 				   SKF_AD_OFF + SKF_AD_MARK); }
146 	| OP_LDB K_QUEUE {
147 		bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
148 				   SKF_AD_OFF + SKF_AD_QUEUE); }
149 	| OP_LDB K_HATYPE {
150 		bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
151 				   SKF_AD_OFF + SKF_AD_HATYPE); }
152 	| OP_LDB K_RXHASH {
153 		bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
154 				   SKF_AD_OFF + SKF_AD_RXHASH); }
155 	| OP_LDB K_CPU {
156 		bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
157 				   SKF_AD_OFF + SKF_AD_CPU); }
158 	| OP_LDB K_VLAN_TCI {
159 		bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
160 				   SKF_AD_OFF + SKF_AD_VLAN_TAG); }
161 	| OP_LDB K_VLAN_AVAIL {
162 		bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
163 				   SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT); }
164 	| OP_LDB K_POFF {
165 		bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
166 				   SKF_AD_OFF + SKF_AD_PAY_OFFSET); }
167 	| OP_LDB K_RAND {
168 		bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
169 				   SKF_AD_OFF + SKF_AD_RANDOM); }
170 	| OP_LDB K_VLAN_TPID {
171 		bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
172 				   SKF_AD_OFF + SKF_AD_VLAN_TPID); }
173 	;
174 
175 ldh
176 	: OP_LDH '[' 'x' '+' number ']' {
177 		bpf_set_curr_instr(BPF_LD | BPF_H | BPF_IND, 0, 0, $5); }
178 	| OP_LDH '[' '%' 'x' '+' number ']' {
179 		bpf_set_curr_instr(BPF_LD | BPF_H | BPF_IND, 0, 0, $6); }
180 	| OP_LDH '[' number ']' {
181 		bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, $3); }
182 	| OP_LDH K_PROTO {
183 		bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
184 				   SKF_AD_OFF + SKF_AD_PROTOCOL); }
185 	| OP_LDH K_TYPE {
186 		bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
187 				   SKF_AD_OFF + SKF_AD_PKTTYPE); }
188 	| OP_LDH K_IFIDX {
189 		bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
190 				   SKF_AD_OFF + SKF_AD_IFINDEX); }
191 	| OP_LDH K_NLATTR {
192 		bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
193 				   SKF_AD_OFF + SKF_AD_NLATTR); }
194 	| OP_LDH K_NLATTR_NEST {
195 		bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
196 				   SKF_AD_OFF + SKF_AD_NLATTR_NEST); }
197 	| OP_LDH K_MARK {
198 		bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
199 				   SKF_AD_OFF + SKF_AD_MARK); }
200 	| OP_LDH K_QUEUE {
201 		bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
202 				   SKF_AD_OFF + SKF_AD_QUEUE); }
203 	| OP_LDH K_HATYPE {
204 		bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
205 				   SKF_AD_OFF + SKF_AD_HATYPE); }
206 	| OP_LDH K_RXHASH {
207 		bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
208 				   SKF_AD_OFF + SKF_AD_RXHASH); }
209 	| OP_LDH K_CPU {
210 		bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
211 				   SKF_AD_OFF + SKF_AD_CPU); }
212 	| OP_LDH K_VLAN_TCI {
213 		bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
214 				   SKF_AD_OFF + SKF_AD_VLAN_TAG); }
215 	| OP_LDH K_VLAN_AVAIL {
216 		bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
217 				   SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT); }
218 	| OP_LDH K_POFF {
219 		bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
220 				   SKF_AD_OFF + SKF_AD_PAY_OFFSET); }
221 	| OP_LDH K_RAND {
222 		bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
223 				   SKF_AD_OFF + SKF_AD_RANDOM); }
224 	| OP_LDH K_VLAN_TPID {
225 		bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
226 				   SKF_AD_OFF + SKF_AD_VLAN_TPID); }
227 	;
228 
229 ldi
230 	: OP_LDI '#' number {
231 		bpf_set_curr_instr(BPF_LD | BPF_IMM, 0, 0, $3); }
232 	| OP_LDI number {
233 		bpf_set_curr_instr(BPF_LD | BPF_IMM, 0, 0, $2); }
234 	;
235 
236 ld
237 	: OP_LD '#' number {
238 		bpf_set_curr_instr(BPF_LD | BPF_IMM, 0, 0, $3); }
239 	| OP_LD K_PKT_LEN {
240 		bpf_set_curr_instr(BPF_LD | BPF_W | BPF_LEN, 0, 0, 0); }
241 	| OP_LD K_PROTO {
242 		bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
243 				   SKF_AD_OFF + SKF_AD_PROTOCOL); }
244 	| OP_LD K_TYPE {
245 		bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
246 				   SKF_AD_OFF + SKF_AD_PKTTYPE); }
247 	| OP_LD K_IFIDX {
248 		bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
249 				   SKF_AD_OFF + SKF_AD_IFINDEX); }
250 	| OP_LD K_NLATTR {
251 		bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
252 				   SKF_AD_OFF + SKF_AD_NLATTR); }
253 	| OP_LD K_NLATTR_NEST {
254 		bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
255 				   SKF_AD_OFF + SKF_AD_NLATTR_NEST); }
256 	| OP_LD K_MARK {
257 		bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
258 				   SKF_AD_OFF + SKF_AD_MARK); }
259 	| OP_LD K_QUEUE {
260 		bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
261 				   SKF_AD_OFF + SKF_AD_QUEUE); }
262 	| OP_LD K_HATYPE {
263 		bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
264 				   SKF_AD_OFF + SKF_AD_HATYPE); }
265 	| OP_LD K_RXHASH {
266 		bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
267 				   SKF_AD_OFF + SKF_AD_RXHASH); }
268 	| OP_LD K_CPU {
269 		bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
270 				   SKF_AD_OFF + SKF_AD_CPU); }
271 	| OP_LD K_VLAN_TCI {
272 		bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
273 				   SKF_AD_OFF + SKF_AD_VLAN_TAG); }
274 	| OP_LD K_VLAN_AVAIL {
275 		bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
276 				   SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT); }
277 	| OP_LD K_POFF {
278 		bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
279 				   SKF_AD_OFF + SKF_AD_PAY_OFFSET); }
280 	| OP_LD K_RAND {
281 		bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
282 				   SKF_AD_OFF + SKF_AD_RANDOM); }
283 	| OP_LD K_VLAN_TPID {
284 		bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
285 				   SKF_AD_OFF + SKF_AD_VLAN_TPID); }
286 	| OP_LD 'M' '[' number ']' {
287 		bpf_set_curr_instr(BPF_LD | BPF_MEM, 0, 0, $4); }
288 	| OP_LD '[' 'x' '+' number ']' {
289 		bpf_set_curr_instr(BPF_LD | BPF_W | BPF_IND, 0, 0, $5); }
290 	| OP_LD '[' '%' 'x' '+' number ']' {
291 		bpf_set_curr_instr(BPF_LD | BPF_W | BPF_IND, 0, 0, $6); }
292 	| OP_LD '[' number ']' {
293 		bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, $3); }
294 	;
295 
296 ldxi
297 	: OP_LDXI '#' number {
298 		bpf_set_curr_instr(BPF_LDX | BPF_IMM, 0, 0, $3); }
299 	| OP_LDXI number {
300 		bpf_set_curr_instr(BPF_LDX | BPF_IMM, 0, 0, $2); }
301 	;
302 
303 ldx
304 	: OP_LDX '#' number {
305 		bpf_set_curr_instr(BPF_LDX | BPF_IMM, 0, 0, $3); }
306 	| OP_LDX K_PKT_LEN {
307 		bpf_set_curr_instr(BPF_LDX | BPF_W | BPF_LEN, 0, 0, 0); }
308 	| OP_LDX 'M' '[' number ']' {
309 		bpf_set_curr_instr(BPF_LDX | BPF_MEM, 0, 0, $4); }
310 	| OP_LDXB number '*' '(' '[' number ']' '&' number ')' {
311 		if ($2 != 4 || $9 != 0xf) {
312 			fprintf(stderr, "ldxb offset not supported!\n");
313 			exit(0);
314 		} else {
315 			bpf_set_curr_instr(BPF_LDX | BPF_MSH | BPF_B, 0, 0, $6); } }
316 	| OP_LDX number '*' '(' '[' number ']' '&' number ')' {
317 		if ($2 != 4 || $9 != 0xf) {
318 			fprintf(stderr, "ldxb offset not supported!\n");
319 			exit(0);
320 		} else {
321 			bpf_set_curr_instr(BPF_LDX | BPF_MSH | BPF_B, 0, 0, $6); } }
322 	;
323 
324 st
325 	: OP_ST 'M' '[' number ']' {
326 		bpf_set_curr_instr(BPF_ST, 0, 0, $4); }
327 	;
328 
329 stx
330 	: OP_STX 'M' '[' number ']' {
331 		bpf_set_curr_instr(BPF_STX, 0, 0, $4); }
332 	;
333 
334 jmp
335 	: OP_JMP label {
336 		bpf_set_jmp_label($2, JKL);
337 		bpf_set_curr_instr(BPF_JMP | BPF_JA, 0, 0, 0); }
338 	;
339 
340 jeq
341 	: OP_JEQ '#' number ',' label ',' label {
342 		bpf_set_jmp_label($5, JTL);
343 		bpf_set_jmp_label($7, JFL);
344 		bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, $3); }
345 	| OP_JEQ 'x' ',' label ',' label {
346 		bpf_set_jmp_label($4, JTL);
347 		bpf_set_jmp_label($6, JFL);
348 		bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); }
349 	| OP_JEQ '%' 'x' ',' label ',' label {
350 		bpf_set_jmp_label($5, JTL);
351 		bpf_set_jmp_label($7, JFL);
352 		bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); }
353 	| OP_JEQ '#' number ',' label {
354 		bpf_set_jmp_label($5, JTL);
355 		bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, $3); }
356 	| OP_JEQ 'x' ',' label {
357 		bpf_set_jmp_label($4, JTL);
358 		bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); }
359 	| OP_JEQ '%' 'x' ',' label {
360 		bpf_set_jmp_label($5, JTL);
361 		bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); }
362 	;
363 
364 jneq
365 	: OP_JNEQ '#' number ',' label {
366 		bpf_set_jmp_label($5, JFL);
367 		bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, $3); }
368 	| OP_JNEQ 'x' ',' label {
369 		bpf_set_jmp_label($4, JFL);
370 		bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); }
371 	| OP_JNEQ '%' 'x' ',' label {
372 		bpf_set_jmp_label($5, JFL);
373 		bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); }
374 	;
375 
376 jlt
377 	: OP_JLT '#' number ',' label {
378 		bpf_set_jmp_label($5, JFL);
379 		bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_K, 0, 0, $3); }
380 	| OP_JLT 'x' ',' label {
381 		bpf_set_jmp_label($4, JFL);
382 		bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); }
383 	| OP_JLT '%' 'x' ',' label {
384 		bpf_set_jmp_label($5, JFL);
385 		bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); }
386 	;
387 
388 jle
389 	: OP_JLE '#' number ',' label {
390 		bpf_set_jmp_label($5, JFL);
391 		bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_K, 0, 0, $3); }
392 	| OP_JLE 'x' ',' label {
393 		bpf_set_jmp_label($4, JFL);
394 		bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); }
395 	| OP_JLE '%' 'x' ',' label {
396 		bpf_set_jmp_label($5, JFL);
397 		bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); }
398 	;
399 
400 jgt
401 	: OP_JGT '#' number ',' label ',' label {
402 		bpf_set_jmp_label($5, JTL);
403 		bpf_set_jmp_label($7, JFL);
404 		bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_K, 0, 0, $3); }
405 	| OP_JGT 'x' ',' label ',' label {
406 		bpf_set_jmp_label($4, JTL);
407 		bpf_set_jmp_label($6, JFL);
408 		bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); }
409 	| OP_JGT '%' 'x' ',' label ',' label {
410 		bpf_set_jmp_label($5, JTL);
411 		bpf_set_jmp_label($7, JFL);
412 		bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); }
413 	| OP_JGT '#' number ',' label {
414 		bpf_set_jmp_label($5, JTL);
415 		bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_K, 0, 0, $3); }
416 	| OP_JGT 'x' ',' label {
417 		bpf_set_jmp_label($4, JTL);
418 		bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); }
419 	| OP_JGT '%' 'x' ',' label {
420 		bpf_set_jmp_label($5, JTL);
421 		bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); }
422 	;
423 
424 jge
425 	: OP_JGE '#' number ',' label ',' label {
426 		bpf_set_jmp_label($5, JTL);
427 		bpf_set_jmp_label($7, JFL);
428 		bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_K, 0, 0, $3); }
429 	| OP_JGE 'x' ',' label ',' label {
430 		bpf_set_jmp_label($4, JTL);
431 		bpf_set_jmp_label($6, JFL);
432 		bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); }
433 	| OP_JGE '%' 'x' ',' label ',' label {
434 		bpf_set_jmp_label($5, JTL);
435 		bpf_set_jmp_label($7, JFL);
436 		bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); }
437 	| OP_JGE '#' number ',' label {
438 		bpf_set_jmp_label($5, JTL);
439 		bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_K, 0, 0, $3); }
440 	| OP_JGE 'x' ',' label {
441 		bpf_set_jmp_label($4, JTL);
442 		bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); }
443 	| OP_JGE '%' 'x' ',' label {
444 		bpf_set_jmp_label($5, JTL);
445 		bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); }
446 	;
447 
448 jset
449 	: OP_JSET '#' number ',' label ',' label {
450 		bpf_set_jmp_label($5, JTL);
451 		bpf_set_jmp_label($7, JFL);
452 		bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_K, 0, 0, $3); }
453 	| OP_JSET 'x' ',' label ',' label {
454 		bpf_set_jmp_label($4, JTL);
455 		bpf_set_jmp_label($6, JFL);
456 		bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); }
457 	| OP_JSET '%' 'x' ',' label ',' label {
458 		bpf_set_jmp_label($5, JTL);
459 		bpf_set_jmp_label($7, JFL);
460 		bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); }
461 	| OP_JSET '#' number ',' label {
462 		bpf_set_jmp_label($5, JTL);
463 		bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_K, 0, 0, $3); }
464 	| OP_JSET 'x' ',' label {
465 		bpf_set_jmp_label($4, JTL);
466 		bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); }
467 	| OP_JSET '%' 'x' ',' label {
468 		bpf_set_jmp_label($5, JTL);
469 		bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); }
470 	;
471 
472 add
473 	: OP_ADD '#' number {
474 		bpf_set_curr_instr(BPF_ALU | BPF_ADD | BPF_K, 0, 0, $3); }
475 	| OP_ADD 'x' {
476 		bpf_set_curr_instr(BPF_ALU | BPF_ADD | BPF_X, 0, 0, 0); }
477 	| OP_ADD '%' 'x' {
478 		bpf_set_curr_instr(BPF_ALU | BPF_ADD | BPF_X, 0, 0, 0); }
479 	;
480 
481 sub
482 	: OP_SUB '#' number {
483 		bpf_set_curr_instr(BPF_ALU | BPF_SUB | BPF_K, 0, 0, $3); }
484 	| OP_SUB 'x' {
485 		bpf_set_curr_instr(BPF_ALU | BPF_SUB | BPF_X, 0, 0, 0); }
486 	| OP_SUB '%' 'x' {
487 		bpf_set_curr_instr(BPF_ALU | BPF_SUB | BPF_X, 0, 0, 0); }
488 	;
489 
490 mul
491 	: OP_MUL '#' number {
492 		bpf_set_curr_instr(BPF_ALU | BPF_MUL | BPF_K, 0, 0, $3); }
493 	| OP_MUL 'x' {
494 		bpf_set_curr_instr(BPF_ALU | BPF_MUL | BPF_X, 0, 0, 0); }
495 	| OP_MUL '%' 'x' {
496 		bpf_set_curr_instr(BPF_ALU | BPF_MUL | BPF_X, 0, 0, 0); }
497 	;
498 
499 div
500 	: OP_DIV '#' number {
501 		bpf_set_curr_instr(BPF_ALU | BPF_DIV | BPF_K, 0, 0, $3); }
502 	| OP_DIV 'x' {
503 		bpf_set_curr_instr(BPF_ALU | BPF_DIV | BPF_X, 0, 0, 0); }
504 	| OP_DIV '%' 'x' {
505 		bpf_set_curr_instr(BPF_ALU | BPF_DIV | BPF_X, 0, 0, 0); }
506 	;
507 
508 mod
509 	: OP_MOD '#' number {
510 		bpf_set_curr_instr(BPF_ALU | BPF_MOD | BPF_K, 0, 0, $3); }
511 	| OP_MOD 'x' {
512 		bpf_set_curr_instr(BPF_ALU | BPF_MOD | BPF_X, 0, 0, 0); }
513 	| OP_MOD '%' 'x' {
514 		bpf_set_curr_instr(BPF_ALU | BPF_MOD | BPF_X, 0, 0, 0); }
515 	;
516 
517 neg
518 	: OP_NEG {
519 		bpf_set_curr_instr(BPF_ALU | BPF_NEG, 0, 0, 0); }
520 	;
521 
522 and
523 	: OP_AND '#' number {
524 		bpf_set_curr_instr(BPF_ALU | BPF_AND | BPF_K, 0, 0, $3); }
525 	| OP_AND 'x' {
526 		bpf_set_curr_instr(BPF_ALU | BPF_AND | BPF_X, 0, 0, 0); }
527 	| OP_AND '%' 'x' {
528 		bpf_set_curr_instr(BPF_ALU | BPF_AND | BPF_X, 0, 0, 0); }
529 	;
530 
531 or
532 	: OP_OR '#' number {
533 		bpf_set_curr_instr(BPF_ALU | BPF_OR | BPF_K, 0, 0, $3); }
534 	| OP_OR 'x' {
535 		bpf_set_curr_instr(BPF_ALU | BPF_OR | BPF_X, 0, 0, 0); }
536 	| OP_OR '%' 'x' {
537 		bpf_set_curr_instr(BPF_ALU | BPF_OR | BPF_X, 0, 0, 0); }
538 	;
539 
540 xor
541 	: OP_XOR '#' number {
542 		bpf_set_curr_instr(BPF_ALU | BPF_XOR | BPF_K, 0, 0, $3); }
543 	| OP_XOR 'x' {
544 		bpf_set_curr_instr(BPF_ALU | BPF_XOR | BPF_X, 0, 0, 0); }
545 	| OP_XOR '%' 'x' {
546 		bpf_set_curr_instr(BPF_ALU | BPF_XOR | BPF_X, 0, 0, 0); }
547 	;
548 
549 lsh
550 	: OP_LSH '#' number {
551 		bpf_set_curr_instr(BPF_ALU | BPF_LSH | BPF_K, 0, 0, $3); }
552 	| OP_LSH 'x' {
553 		bpf_set_curr_instr(BPF_ALU | BPF_LSH | BPF_X, 0, 0, 0); }
554 	| OP_LSH '%' 'x' {
555 		bpf_set_curr_instr(BPF_ALU | BPF_LSH | BPF_X, 0, 0, 0); }
556 	;
557 
558 rsh
559 	: OP_RSH '#' number {
560 		bpf_set_curr_instr(BPF_ALU | BPF_RSH | BPF_K, 0, 0, $3); }
561 	| OP_RSH 'x' {
562 		bpf_set_curr_instr(BPF_ALU | BPF_RSH | BPF_X, 0, 0, 0); }
563 	| OP_RSH '%' 'x' {
564 		bpf_set_curr_instr(BPF_ALU | BPF_RSH | BPF_X, 0, 0, 0); }
565 	;
566 
567 ret
568 	: OP_RET 'a' {
569 		bpf_set_curr_instr(BPF_RET | BPF_A, 0, 0, 0); }
570 	| OP_RET '%' 'a' {
571 		bpf_set_curr_instr(BPF_RET | BPF_A, 0, 0, 0); }
572 	| OP_RET 'x' {
573 		bpf_set_curr_instr(BPF_RET | BPF_X, 0, 0, 0); }
574 	| OP_RET '%' 'x' {
575 		bpf_set_curr_instr(BPF_RET | BPF_X, 0, 0, 0); }
576 	| OP_RET '#' number {
577 		bpf_set_curr_instr(BPF_RET | BPF_K, 0, 0, $3); }
578 	;
579 
580 tax
581 	: OP_TAX {
582 		bpf_set_curr_instr(BPF_MISC | BPF_TAX, 0, 0, 0); }
583 	;
584 
585 txa
586 	: OP_TXA {
587 		bpf_set_curr_instr(BPF_MISC | BPF_TXA, 0, 0, 0); }
588 	;
589 
590 %%
591 
592 static int curr_instr = 0;
593 static struct sock_filter out[BPF_MAXINSNS];
594 static char **labels, **labels_jt, **labels_jf, **labels_k;
595 
bpf_assert_max(void)596 static void bpf_assert_max(void)
597 {
598 	if (curr_instr >= BPF_MAXINSNS) {
599 		fprintf(stderr, "only max %u insns allowed!\n", BPF_MAXINSNS);
600 		exit(0);
601 	}
602 }
603 
bpf_set_curr_instr(uint16_t code,uint8_t jt,uint8_t jf,uint32_t k)604 static void bpf_set_curr_instr(uint16_t code, uint8_t jt, uint8_t jf,
605 			       uint32_t k)
606 {
607 	bpf_assert_max();
608 	out[curr_instr].code = code;
609 	out[curr_instr].jt = jt;
610 	out[curr_instr].jf = jf;
611 	out[curr_instr].k = k;
612 	curr_instr++;
613 }
614 
bpf_set_curr_label(char * label)615 static void bpf_set_curr_label(char *label)
616 {
617 	bpf_assert_max();
618 	labels[curr_instr] = label;
619 }
620 
bpf_set_jmp_label(char * label,enum jmp_type type)621 static void bpf_set_jmp_label(char *label, enum jmp_type type)
622 {
623 	bpf_assert_max();
624 	switch (type) {
625 	case JTL:
626 		labels_jt[curr_instr] = label;
627 		break;
628 	case JFL:
629 		labels_jf[curr_instr] = label;
630 		break;
631 	case JKL:
632 		labels_k[curr_instr] = label;
633 		break;
634 	}
635 }
636 
bpf_find_insns_offset(const char * label)637 static int bpf_find_insns_offset(const char *label)
638 {
639 	int i, max = curr_instr, ret = -ENOENT;
640 
641 	for (i = 0; i < max; i++) {
642 		if (labels[i] && !strcmp(label, labels[i])) {
643 			ret = i;
644 			break;
645 		}
646 	}
647 
648 	if (ret == -ENOENT) {
649 		fprintf(stderr, "no such label \'%s\'!\n", label);
650 		exit(0);
651 	}
652 
653 	return ret;
654 }
655 
bpf_stage_1_insert_insns(void)656 static void bpf_stage_1_insert_insns(void)
657 {
658 	yyparse();
659 }
660 
bpf_reduce_k_jumps(void)661 static void bpf_reduce_k_jumps(void)
662 {
663 	int i;
664 
665 	for (i = 0; i < curr_instr; i++) {
666 		if (labels_k[i]) {
667 			int off = bpf_find_insns_offset(labels_k[i]);
668 			out[i].k = (uint32_t) (off - i - 1);
669 		}
670 	}
671 }
672 
bpf_reduce_jt_jumps(void)673 static void bpf_reduce_jt_jumps(void)
674 {
675 	int i;
676 
677 	for (i = 0; i < curr_instr; i++) {
678 		if (labels_jt[i]) {
679 			int off = bpf_find_insns_offset(labels_jt[i]);
680 			out[i].jt = (uint8_t) (off - i -1);
681 		}
682 	}
683 }
684 
bpf_reduce_jf_jumps(void)685 static void bpf_reduce_jf_jumps(void)
686 {
687 	int i;
688 
689 	for (i = 0; i < curr_instr; i++) {
690 		if (labels_jf[i]) {
691 			int off = bpf_find_insns_offset(labels_jf[i]);
692 			out[i].jf = (uint8_t) (off - i - 1);
693 		}
694 	}
695 }
696 
bpf_stage_2_reduce_labels(void)697 static void bpf_stage_2_reduce_labels(void)
698 {
699 	bpf_reduce_k_jumps();
700 	bpf_reduce_jt_jumps();
701 	bpf_reduce_jf_jumps();
702 }
703 
bpf_pretty_print_c(void)704 static void bpf_pretty_print_c(void)
705 {
706 	int i;
707 
708 	for (i = 0; i < curr_instr; i++)
709 		printf("{ %#04x, %2u, %2u, %#010x },\n", out[i].code,
710 		       out[i].jt, out[i].jf, out[i].k);
711 }
712 
bpf_pretty_print(void)713 static void bpf_pretty_print(void)
714 {
715 	int i;
716 
717 	printf("%u,", curr_instr);
718 	for (i = 0; i < curr_instr; i++)
719 		printf("%u %u %u %u,", out[i].code,
720 		       out[i].jt, out[i].jf, out[i].k);
721 	printf("\n");
722 }
723 
bpf_init(void)724 static void bpf_init(void)
725 {
726 	memset(out, 0, sizeof(out));
727 
728 	labels = calloc(BPF_MAXINSNS, sizeof(*labels));
729 	assert(labels);
730 	labels_jt = calloc(BPF_MAXINSNS, sizeof(*labels_jt));
731 	assert(labels_jt);
732 	labels_jf = calloc(BPF_MAXINSNS, sizeof(*labels_jf));
733 	assert(labels_jf);
734 	labels_k = calloc(BPF_MAXINSNS, sizeof(*labels_k));
735 	assert(labels_k);
736 }
737 
bpf_destroy_labels(void)738 static void bpf_destroy_labels(void)
739 {
740 	int i;
741 
742 	for (i = 0; i < curr_instr; i++) {
743 		free(labels_jf[i]);
744 		free(labels_jt[i]);
745 		free(labels_k[i]);
746 		free(labels[i]);
747 	}
748 }
749 
bpf_destroy(void)750 static void bpf_destroy(void)
751 {
752 	bpf_destroy_labels();
753 	free(labels_jt);
754 	free(labels_jf);
755 	free(labels_k);
756 	free(labels);
757 }
758 
bpf_asm_compile(FILE * fp,bool cstyle)759 void bpf_asm_compile(FILE *fp, bool cstyle)
760 {
761 	yyin = fp;
762 
763 	bpf_init();
764 	bpf_stage_1_insert_insns();
765 	bpf_stage_2_reduce_labels();
766 	bpf_destroy();
767 
768 	if (cstyle)
769 		bpf_pretty_print_c();
770 	else
771 		bpf_pretty_print();
772 
773 	if (fp != stdin)
774 		fclose(yyin);
775 }
776 
yyerror(const char * str)777 void yyerror(const char *str)
778 {
779 	exit(1);
780 }
781