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