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
35enum jmp_type { JTL, JFL, JKL };
36
37extern FILE *yyin;
38extern int yylineno;
39extern int yylex(void);
40extern void yyerror(const char *str);
41
42extern void bpf_asm_compile(FILE *fp, bool cstyle);
43static void bpf_set_curr_instr(uint16_t op, uint8_t jt, uint8_t jf, uint32_t k);
44static void bpf_set_curr_label(char *label);
45static void bpf_set_jmp_label(char *label, enum jmp_type type);
46
47%}
48
49%union {
50	char *label;
51	uint32_t number;
52}
53
54%token OP_LDB OP_LDH OP_LD OP_LDX OP_ST OP_STX OP_JMP OP_JEQ OP_JGT OP_JGE
55%token OP_JSET OP_ADD OP_SUB OP_MUL OP_DIV OP_AND OP_OR OP_XOR OP_LSH OP_RSH
56%token OP_RET OP_TAX OP_TXA OP_LDXB OP_MOD OP_NEG OP_JNEQ OP_JLT OP_JLE OP_LDI
57%token OP_LDXI
58
59%token K_PKT_LEN
60
61%token ':' ',' '[' ']' '(' ')' 'x' 'a' '+' 'M' '*' '&' '#' '%'
62
63%token extension number label
64
65%type <label> label
66%type <number> extension
67%type <number> number
68
69%%
70
71prog
72	: line
73	| prog line
74	;
75
76line
77	: instr
78	| labelled_instr
79	;
80
81labelled_instr
82	: labelled instr
83	;
84
85instr
86	: ldb
87	| ldh
88	| ld
89	| ldi
90	| ldx
91	| ldxi
92	| st
93	| stx
94	| jmp
95	| jeq
96	| jneq
97	| jlt
98	| jle
99	| jgt
100	| jge
101	| jset
102	| add
103	| sub
104	| mul
105	| div
106	| mod
107	| neg
108	| and
109	| or
110	| xor
111	| lsh
112	| rsh
113	| ret
114	| tax
115	| txa
116	;
117
118labelled
119	: label ':' { bpf_set_curr_label($1); }
120	;
121
122ldb
123	: OP_LDB '[' 'x' '+' number ']' {
124		bpf_set_curr_instr(BPF_LD | BPF_B | BPF_IND, 0, 0, $5); }
125	| OP_LDB '[' '%' 'x' '+' number ']' {
126		bpf_set_curr_instr(BPF_LD | BPF_B | BPF_IND, 0, 0, $6); }
127	| OP_LDB '[' number ']' {
128		bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, $3); }
129	| OP_LDB extension {
130		bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
131				   SKF_AD_OFF + $2); }
132	;
133
134ldh
135	: OP_LDH '[' 'x' '+' number ']' {
136		bpf_set_curr_instr(BPF_LD | BPF_H | BPF_IND, 0, 0, $5); }
137	| OP_LDH '[' '%' 'x' '+' number ']' {
138		bpf_set_curr_instr(BPF_LD | BPF_H | BPF_IND, 0, 0, $6); }
139	| OP_LDH '[' number ']' {
140		bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, $3); }
141	| OP_LDH extension {
142		bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
143				   SKF_AD_OFF + $2); }
144	;
145
146ldi
147	: OP_LDI '#' number {
148		bpf_set_curr_instr(BPF_LD | BPF_IMM, 0, 0, $3); }
149	| OP_LDI number {
150		bpf_set_curr_instr(BPF_LD | BPF_IMM, 0, 0, $2); }
151	;
152
153ld
154	: OP_LD '#' number {
155		bpf_set_curr_instr(BPF_LD | BPF_IMM, 0, 0, $3); }
156	| OP_LD K_PKT_LEN {
157		bpf_set_curr_instr(BPF_LD | BPF_W | BPF_LEN, 0, 0, 0); }
158	| OP_LD extension {
159		bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
160				   SKF_AD_OFF + $2); }
161	| OP_LD 'M' '[' number ']' {
162		bpf_set_curr_instr(BPF_LD | BPF_MEM, 0, 0, $4); }
163	| OP_LD '[' 'x' '+' number ']' {
164		bpf_set_curr_instr(BPF_LD | BPF_W | BPF_IND, 0, 0, $5); }
165	| OP_LD '[' '%' 'x' '+' number ']' {
166		bpf_set_curr_instr(BPF_LD | BPF_W | BPF_IND, 0, 0, $6); }
167	| OP_LD '[' number ']' {
168		bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, $3); }
169	;
170
171ldxi
172	: OP_LDXI '#' number {
173		bpf_set_curr_instr(BPF_LDX | BPF_IMM, 0, 0, $3); }
174	| OP_LDXI number {
175		bpf_set_curr_instr(BPF_LDX | BPF_IMM, 0, 0, $2); }
176	;
177
178ldx
179	: OP_LDX '#' number {
180		bpf_set_curr_instr(BPF_LDX | BPF_IMM, 0, 0, $3); }
181	| OP_LDX K_PKT_LEN {
182		bpf_set_curr_instr(BPF_LDX | BPF_W | BPF_LEN, 0, 0, 0); }
183	| OP_LDX 'M' '[' number ']' {
184		bpf_set_curr_instr(BPF_LDX | BPF_MEM, 0, 0, $4); }
185	| OP_LDXB number '*' '(' '[' number ']' '&' number ')' {
186		if ($2 != 4 || $9 != 0xf) {
187			fprintf(stderr, "ldxb offset not supported!\n");
188			exit(1);
189		} else {
190			bpf_set_curr_instr(BPF_LDX | BPF_MSH | BPF_B, 0, 0, $6); } }
191	| OP_LDX number '*' '(' '[' number ']' '&' number ')' {
192		if ($2 != 4 || $9 != 0xf) {
193			fprintf(stderr, "ldxb offset not supported!\n");
194			exit(1);
195		} else {
196			bpf_set_curr_instr(BPF_LDX | BPF_MSH | BPF_B, 0, 0, $6); } }
197	;
198
199st
200	: OP_ST 'M' '[' number ']' {
201		bpf_set_curr_instr(BPF_ST, 0, 0, $4); }
202	;
203
204stx
205	: OP_STX 'M' '[' number ']' {
206		bpf_set_curr_instr(BPF_STX, 0, 0, $4); }
207	;
208
209jmp
210	: OP_JMP label {
211		bpf_set_jmp_label($2, JKL);
212		bpf_set_curr_instr(BPF_JMP | BPF_JA, 0, 0, 0); }
213	;
214
215jeq
216	: OP_JEQ '#' number ',' label ',' label {
217		bpf_set_jmp_label($5, JTL);
218		bpf_set_jmp_label($7, JFL);
219		bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, $3); }
220	| OP_JEQ 'x' ',' label ',' label {
221		bpf_set_jmp_label($4, JTL);
222		bpf_set_jmp_label($6, JFL);
223		bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); }
224	| OP_JEQ '%' 'x' ',' label ',' label {
225		bpf_set_jmp_label($5, JTL);
226		bpf_set_jmp_label($7, JFL);
227		bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); }
228	| OP_JEQ '#' number ',' label {
229		bpf_set_jmp_label($5, JTL);
230		bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, $3); }
231	| OP_JEQ 'x' ',' label {
232		bpf_set_jmp_label($4, JTL);
233		bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); }
234	| OP_JEQ '%' 'x' ',' label {
235		bpf_set_jmp_label($5, JTL);
236		bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); }
237	;
238
239jneq
240	: OP_JNEQ '#' number ',' label {
241		bpf_set_jmp_label($5, JFL);
242		bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, $3); }
243	| OP_JNEQ 'x' ',' label {
244		bpf_set_jmp_label($4, JFL);
245		bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); }
246	| OP_JNEQ '%' 'x' ',' label {
247		bpf_set_jmp_label($5, JFL);
248		bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); }
249	;
250
251jlt
252	: OP_JLT '#' number ',' label {
253		bpf_set_jmp_label($5, JFL);
254		bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_K, 0, 0, $3); }
255	| OP_JLT 'x' ',' label {
256		bpf_set_jmp_label($4, JFL);
257		bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); }
258	| OP_JLT '%' 'x' ',' label {
259		bpf_set_jmp_label($5, JFL);
260		bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); }
261	;
262
263jle
264	: OP_JLE '#' number ',' label {
265		bpf_set_jmp_label($5, JFL);
266		bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_K, 0, 0, $3); }
267	| OP_JLE 'x' ',' label {
268		bpf_set_jmp_label($4, JFL);
269		bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); }
270	| OP_JLE '%' 'x' ',' label {
271		bpf_set_jmp_label($5, JFL);
272		bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); }
273	;
274
275jgt
276	: OP_JGT '#' number ',' label ',' label {
277		bpf_set_jmp_label($5, JTL);
278		bpf_set_jmp_label($7, JFL);
279		bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_K, 0, 0, $3); }
280	| OP_JGT 'x' ',' label ',' label {
281		bpf_set_jmp_label($4, JTL);
282		bpf_set_jmp_label($6, JFL);
283		bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); }
284	| OP_JGT '%' 'x' ',' label ',' label {
285		bpf_set_jmp_label($5, JTL);
286		bpf_set_jmp_label($7, JFL);
287		bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); }
288	| OP_JGT '#' number ',' label {
289		bpf_set_jmp_label($5, JTL);
290		bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_K, 0, 0, $3); }
291	| OP_JGT 'x' ',' label {
292		bpf_set_jmp_label($4, JTL);
293		bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); }
294	| OP_JGT '%' 'x' ',' label {
295		bpf_set_jmp_label($5, JTL);
296		bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); }
297	;
298
299jge
300	: OP_JGE '#' number ',' label ',' label {
301		bpf_set_jmp_label($5, JTL);
302		bpf_set_jmp_label($7, JFL);
303		bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_K, 0, 0, $3); }
304	| OP_JGE 'x' ',' label ',' label {
305		bpf_set_jmp_label($4, JTL);
306		bpf_set_jmp_label($6, JFL);
307		bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); }
308	| OP_JGE '%' 'x' ',' label ',' label {
309		bpf_set_jmp_label($5, JTL);
310		bpf_set_jmp_label($7, JFL);
311		bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); }
312	| OP_JGE '#' number ',' label {
313		bpf_set_jmp_label($5, JTL);
314		bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_K, 0, 0, $3); }
315	| OP_JGE 'x' ',' label {
316		bpf_set_jmp_label($4, JTL);
317		bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); }
318	| OP_JGE '%' 'x' ',' label {
319		bpf_set_jmp_label($5, JTL);
320		bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); }
321	;
322
323jset
324	: OP_JSET '#' number ',' label ',' label {
325		bpf_set_jmp_label($5, JTL);
326		bpf_set_jmp_label($7, JFL);
327		bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_K, 0, 0, $3); }
328	| OP_JSET 'x' ',' label ',' label {
329		bpf_set_jmp_label($4, JTL);
330		bpf_set_jmp_label($6, JFL);
331		bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); }
332	| OP_JSET '%' 'x' ',' label ',' label {
333		bpf_set_jmp_label($5, JTL);
334		bpf_set_jmp_label($7, JFL);
335		bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); }
336	| OP_JSET '#' number ',' label {
337		bpf_set_jmp_label($5, JTL);
338		bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_K, 0, 0, $3); }
339	| OP_JSET 'x' ',' label {
340		bpf_set_jmp_label($4, JTL);
341		bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); }
342	| OP_JSET '%' 'x' ',' label {
343		bpf_set_jmp_label($5, JTL);
344		bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); }
345	;
346
347add
348	: OP_ADD '#' number {
349		bpf_set_curr_instr(BPF_ALU | BPF_ADD | BPF_K, 0, 0, $3); }
350	| OP_ADD 'x' {
351		bpf_set_curr_instr(BPF_ALU | BPF_ADD | BPF_X, 0, 0, 0); }
352	| OP_ADD '%' 'x' {
353		bpf_set_curr_instr(BPF_ALU | BPF_ADD | BPF_X, 0, 0, 0); }
354	;
355
356sub
357	: OP_SUB '#' number {
358		bpf_set_curr_instr(BPF_ALU | BPF_SUB | BPF_K, 0, 0, $3); }
359	| OP_SUB 'x' {
360		bpf_set_curr_instr(BPF_ALU | BPF_SUB | BPF_X, 0, 0, 0); }
361	| OP_SUB '%' 'x' {
362		bpf_set_curr_instr(BPF_ALU | BPF_SUB | BPF_X, 0, 0, 0); }
363	;
364
365mul
366	: OP_MUL '#' number {
367		bpf_set_curr_instr(BPF_ALU | BPF_MUL | BPF_K, 0, 0, $3); }
368	| OP_MUL 'x' {
369		bpf_set_curr_instr(BPF_ALU | BPF_MUL | BPF_X, 0, 0, 0); }
370	| OP_MUL '%' 'x' {
371		bpf_set_curr_instr(BPF_ALU | BPF_MUL | BPF_X, 0, 0, 0); }
372	;
373
374div
375	: OP_DIV '#' number {
376		bpf_set_curr_instr(BPF_ALU | BPF_DIV | BPF_K, 0, 0, $3); }
377	| OP_DIV 'x' {
378		bpf_set_curr_instr(BPF_ALU | BPF_DIV | BPF_X, 0, 0, 0); }
379	| OP_DIV '%' 'x' {
380		bpf_set_curr_instr(BPF_ALU | BPF_DIV | BPF_X, 0, 0, 0); }
381	;
382
383mod
384	: OP_MOD '#' number {
385		bpf_set_curr_instr(BPF_ALU | BPF_MOD | BPF_K, 0, 0, $3); }
386	| OP_MOD 'x' {
387		bpf_set_curr_instr(BPF_ALU | BPF_MOD | BPF_X, 0, 0, 0); }
388	| OP_MOD '%' 'x' {
389		bpf_set_curr_instr(BPF_ALU | BPF_MOD | BPF_X, 0, 0, 0); }
390	;
391
392neg
393	: OP_NEG {
394		bpf_set_curr_instr(BPF_ALU | BPF_NEG, 0, 0, 0); }
395	;
396
397and
398	: OP_AND '#' number {
399		bpf_set_curr_instr(BPF_ALU | BPF_AND | BPF_K, 0, 0, $3); }
400	| OP_AND 'x' {
401		bpf_set_curr_instr(BPF_ALU | BPF_AND | BPF_X, 0, 0, 0); }
402	| OP_AND '%' 'x' {
403		bpf_set_curr_instr(BPF_ALU | BPF_AND | BPF_X, 0, 0, 0); }
404	;
405
406or
407	: OP_OR '#' number {
408		bpf_set_curr_instr(BPF_ALU | BPF_OR | BPF_K, 0, 0, $3); }
409	| OP_OR 'x' {
410		bpf_set_curr_instr(BPF_ALU | BPF_OR | BPF_X, 0, 0, 0); }
411	| OP_OR '%' 'x' {
412		bpf_set_curr_instr(BPF_ALU | BPF_OR | BPF_X, 0, 0, 0); }
413	;
414
415xor
416	: OP_XOR '#' number {
417		bpf_set_curr_instr(BPF_ALU | BPF_XOR | BPF_K, 0, 0, $3); }
418	| OP_XOR 'x' {
419		bpf_set_curr_instr(BPF_ALU | BPF_XOR | BPF_X, 0, 0, 0); }
420	| OP_XOR '%' 'x' {
421		bpf_set_curr_instr(BPF_ALU | BPF_XOR | BPF_X, 0, 0, 0); }
422	;
423
424lsh
425	: OP_LSH '#' number {
426		bpf_set_curr_instr(BPF_ALU | BPF_LSH | BPF_K, 0, 0, $3); }
427	| OP_LSH 'x' {
428		bpf_set_curr_instr(BPF_ALU | BPF_LSH | BPF_X, 0, 0, 0); }
429	| OP_LSH '%' 'x' {
430		bpf_set_curr_instr(BPF_ALU | BPF_LSH | BPF_X, 0, 0, 0); }
431	;
432
433rsh
434	: OP_RSH '#' number {
435		bpf_set_curr_instr(BPF_ALU | BPF_RSH | BPF_K, 0, 0, $3); }
436	| OP_RSH 'x' {
437		bpf_set_curr_instr(BPF_ALU | BPF_RSH | BPF_X, 0, 0, 0); }
438	| OP_RSH '%' 'x' {
439		bpf_set_curr_instr(BPF_ALU | BPF_RSH | BPF_X, 0, 0, 0); }
440	;
441
442ret
443	: OP_RET 'a' {
444		bpf_set_curr_instr(BPF_RET | BPF_A, 0, 0, 0); }
445	| OP_RET '%' 'a' {
446		bpf_set_curr_instr(BPF_RET | BPF_A, 0, 0, 0); }
447	| OP_RET 'x' {
448		bpf_set_curr_instr(BPF_RET | BPF_X, 0, 0, 0); }
449	| OP_RET '%' 'x' {
450		bpf_set_curr_instr(BPF_RET | BPF_X, 0, 0, 0); }
451	| OP_RET '#' number {
452		bpf_set_curr_instr(BPF_RET | BPF_K, 0, 0, $3); }
453	;
454
455tax
456	: OP_TAX {
457		bpf_set_curr_instr(BPF_MISC | BPF_TAX, 0, 0, 0); }
458	;
459
460txa
461	: OP_TXA {
462		bpf_set_curr_instr(BPF_MISC | BPF_TXA, 0, 0, 0); }
463	;
464
465%%
466
467static int curr_instr = 0;
468static struct sock_filter out[BPF_MAXINSNS];
469static char **labels, **labels_jt, **labels_jf, **labels_k;
470
471static void bpf_assert_max(void)
472{
473	if (curr_instr >= BPF_MAXINSNS) {
474		fprintf(stderr, "only max %u insns allowed!\n", BPF_MAXINSNS);
475		exit(1);
476	}
477}
478
479static void bpf_set_curr_instr(uint16_t code, uint8_t jt, uint8_t jf,
480			       uint32_t k)
481{
482	bpf_assert_max();
483	out[curr_instr].code = code;
484	out[curr_instr].jt = jt;
485	out[curr_instr].jf = jf;
486	out[curr_instr].k = k;
487	curr_instr++;
488}
489
490static void bpf_set_curr_label(char *label)
491{
492	bpf_assert_max();
493	labels[curr_instr] = label;
494}
495
496static void bpf_set_jmp_label(char *label, enum jmp_type type)
497{
498	bpf_assert_max();
499	switch (type) {
500	case JTL:
501		labels_jt[curr_instr] = label;
502		break;
503	case JFL:
504		labels_jf[curr_instr] = label;
505		break;
506	case JKL:
507		labels_k[curr_instr] = label;
508		break;
509	}
510}
511
512static int bpf_find_insns_offset(const char *label)
513{
514	int i, max = curr_instr, ret = -ENOENT;
515
516	for (i = 0; i < max; i++) {
517		if (labels[i] && !strcmp(label, labels[i])) {
518			ret = i;
519			break;
520		}
521	}
522
523	if (ret == -ENOENT) {
524		fprintf(stderr, "no such label \'%s\'!\n", label);
525		exit(1);
526	}
527
528	return ret;
529}
530
531static void bpf_stage_1_insert_insns(void)
532{
533	yyparse();
534}
535
536static void bpf_reduce_k_jumps(void)
537{
538	int i;
539
540	for (i = 0; i < curr_instr; i++) {
541		if (labels_k[i]) {
542			int off = bpf_find_insns_offset(labels_k[i]);
543			out[i].k = (uint32_t) (off - i - 1);
544		}
545	}
546}
547
548static uint8_t bpf_encode_jt_jf_offset(int off, int i)
549{
550	int delta = off - i - 1;
551
552	if (delta < 0 || delta > 255) {
553		fprintf(stderr, "error: insn #%d jumps to insn #%d, "
554				"which is out of range\n", i, off);
555		exit(1);
556	}
557	return (uint8_t) delta;
558}
559
560static void bpf_reduce_jt_jumps(void)
561{
562	int i;
563
564	for (i = 0; i < curr_instr; i++) {
565		if (labels_jt[i]) {
566			int off = bpf_find_insns_offset(labels_jt[i]);
567			out[i].jt = bpf_encode_jt_jf_offset(off, i);
568		}
569	}
570}
571
572static void bpf_reduce_jf_jumps(void)
573{
574	int i;
575
576	for (i = 0; i < curr_instr; i++) {
577		if (labels_jf[i]) {
578			int off = bpf_find_insns_offset(labels_jf[i]);
579			out[i].jf = bpf_encode_jt_jf_offset(off, i);
580		}
581	}
582}
583
584static void bpf_stage_2_reduce_labels(void)
585{
586	bpf_reduce_k_jumps();
587	bpf_reduce_jt_jumps();
588	bpf_reduce_jf_jumps();
589}
590
591static void bpf_pretty_print_c(void)
592{
593	int i;
594
595	for (i = 0; i < curr_instr; i++)
596		printf("{ %#04x, %2u, %2u, %#010x },\n", out[i].code,
597		       out[i].jt, out[i].jf, out[i].k);
598}
599
600static void bpf_pretty_print(void)
601{
602	int i;
603
604	printf("%u,", curr_instr);
605	for (i = 0; i < curr_instr; i++)
606		printf("%u %u %u %u,", out[i].code,
607		       out[i].jt, out[i].jf, out[i].k);
608	printf("\n");
609}
610
611static void bpf_init(void)
612{
613	memset(out, 0, sizeof(out));
614
615	labels = calloc(BPF_MAXINSNS, sizeof(*labels));
616	assert(labels);
617	labels_jt = calloc(BPF_MAXINSNS, sizeof(*labels_jt));
618	assert(labels_jt);
619	labels_jf = calloc(BPF_MAXINSNS, sizeof(*labels_jf));
620	assert(labels_jf);
621	labels_k = calloc(BPF_MAXINSNS, sizeof(*labels_k));
622	assert(labels_k);
623}
624
625static void bpf_destroy_labels(void)
626{
627	int i;
628
629	for (i = 0; i < curr_instr; i++) {
630		free(labels_jf[i]);
631		free(labels_jt[i]);
632		free(labels_k[i]);
633		free(labels[i]);
634	}
635}
636
637static void bpf_destroy(void)
638{
639	bpf_destroy_labels();
640	free(labels_jt);
641	free(labels_jf);
642	free(labels_k);
643	free(labels);
644}
645
646void bpf_asm_compile(FILE *fp, bool cstyle)
647{
648	yyin = fp;
649
650	bpf_init();
651	bpf_stage_1_insert_insns();
652	bpf_stage_2_reduce_labels();
653	bpf_destroy();
654
655	if (cstyle)
656		bpf_pretty_print_c();
657	else
658		bpf_pretty_print();
659
660	if (fp != stdin)
661		fclose(yyin);
662}
663
664void yyerror(const char *str)
665{
666	fprintf(stderr, "error: %s at line %d\n", str, yylineno);
667	exit(1);
668}
669