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