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_VLANT K_VLANP 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_VLANT { 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_VLANP { 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 ; 171 172 ldh 173 : OP_LDH '[' 'x' '+' number ']' { 174 bpf_set_curr_instr(BPF_LD | BPF_H | BPF_IND, 0, 0, $5); } 175 | OP_LDH '[' '%' 'x' '+' number ']' { 176 bpf_set_curr_instr(BPF_LD | BPF_H | BPF_IND, 0, 0, $6); } 177 | OP_LDH '[' number ']' { 178 bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, $3); } 179 | OP_LDH K_PROTO { 180 bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, 181 SKF_AD_OFF + SKF_AD_PROTOCOL); } 182 | OP_LDH K_TYPE { 183 bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, 184 SKF_AD_OFF + SKF_AD_PKTTYPE); } 185 | OP_LDH K_IFIDX { 186 bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, 187 SKF_AD_OFF + SKF_AD_IFINDEX); } 188 | OP_LDH K_NLATTR { 189 bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, 190 SKF_AD_OFF + SKF_AD_NLATTR); } 191 | OP_LDH K_NLATTR_NEST { 192 bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, 193 SKF_AD_OFF + SKF_AD_NLATTR_NEST); } 194 | OP_LDH K_MARK { 195 bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, 196 SKF_AD_OFF + SKF_AD_MARK); } 197 | OP_LDH K_QUEUE { 198 bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, 199 SKF_AD_OFF + SKF_AD_QUEUE); } 200 | OP_LDH K_HATYPE { 201 bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, 202 SKF_AD_OFF + SKF_AD_HATYPE); } 203 | OP_LDH K_RXHASH { 204 bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, 205 SKF_AD_OFF + SKF_AD_RXHASH); } 206 | OP_LDH K_CPU { 207 bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, 208 SKF_AD_OFF + SKF_AD_CPU); } 209 | OP_LDH K_VLANT { 210 bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, 211 SKF_AD_OFF + SKF_AD_VLAN_TAG); } 212 | OP_LDH K_VLANP { 213 bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, 214 SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT); } 215 | OP_LDH K_POFF { 216 bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, 217 SKF_AD_OFF + SKF_AD_PAY_OFFSET); } 218 | OP_LDH K_RAND { 219 bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, 220 SKF_AD_OFF + SKF_AD_RANDOM); } 221 ; 222 223 ldi 224 : OP_LDI '#' number { 225 bpf_set_curr_instr(BPF_LD | BPF_IMM, 0, 0, $3); } 226 | OP_LDI number { 227 bpf_set_curr_instr(BPF_LD | BPF_IMM, 0, 0, $2); } 228 ; 229 230 ld 231 : OP_LD '#' number { 232 bpf_set_curr_instr(BPF_LD | BPF_IMM, 0, 0, $3); } 233 | OP_LD K_PKT_LEN { 234 bpf_set_curr_instr(BPF_LD | BPF_W | BPF_LEN, 0, 0, 0); } 235 | OP_LD K_PROTO { 236 bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, 237 SKF_AD_OFF + SKF_AD_PROTOCOL); } 238 | OP_LD K_TYPE { 239 bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, 240 SKF_AD_OFF + SKF_AD_PKTTYPE); } 241 | OP_LD K_IFIDX { 242 bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, 243 SKF_AD_OFF + SKF_AD_IFINDEX); } 244 | OP_LD K_NLATTR { 245 bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, 246 SKF_AD_OFF + SKF_AD_NLATTR); } 247 | OP_LD K_NLATTR_NEST { 248 bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, 249 SKF_AD_OFF + SKF_AD_NLATTR_NEST); } 250 | OP_LD K_MARK { 251 bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, 252 SKF_AD_OFF + SKF_AD_MARK); } 253 | OP_LD K_QUEUE { 254 bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, 255 SKF_AD_OFF + SKF_AD_QUEUE); } 256 | OP_LD K_HATYPE { 257 bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, 258 SKF_AD_OFF + SKF_AD_HATYPE); } 259 | OP_LD K_RXHASH { 260 bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, 261 SKF_AD_OFF + SKF_AD_RXHASH); } 262 | OP_LD K_CPU { 263 bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, 264 SKF_AD_OFF + SKF_AD_CPU); } 265 | OP_LD K_VLANT { 266 bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, 267 SKF_AD_OFF + SKF_AD_VLAN_TAG); } 268 | OP_LD K_VLANP { 269 bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, 270 SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT); } 271 | OP_LD K_POFF { 272 bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, 273 SKF_AD_OFF + SKF_AD_PAY_OFFSET); } 274 | OP_LD K_RAND { 275 bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, 276 SKF_AD_OFF + SKF_AD_RANDOM); } 277 | OP_LD 'M' '[' number ']' { 278 bpf_set_curr_instr(BPF_LD | BPF_MEM, 0, 0, $4); } 279 | OP_LD '[' 'x' '+' number ']' { 280 bpf_set_curr_instr(BPF_LD | BPF_W | BPF_IND, 0, 0, $5); } 281 | OP_LD '[' '%' 'x' '+' number ']' { 282 bpf_set_curr_instr(BPF_LD | BPF_W | BPF_IND, 0, 0, $6); } 283 | OP_LD '[' number ']' { 284 bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, $3); } 285 ; 286 287 ldxi 288 : OP_LDXI '#' number { 289 bpf_set_curr_instr(BPF_LDX | BPF_IMM, 0, 0, $3); } 290 | OP_LDXI number { 291 bpf_set_curr_instr(BPF_LDX | BPF_IMM, 0, 0, $2); } 292 ; 293 294 ldx 295 : OP_LDX '#' number { 296 bpf_set_curr_instr(BPF_LDX | BPF_IMM, 0, 0, $3); } 297 | OP_LDX K_PKT_LEN { 298 bpf_set_curr_instr(BPF_LDX | BPF_W | BPF_LEN, 0, 0, 0); } 299 | OP_LDX 'M' '[' number ']' { 300 bpf_set_curr_instr(BPF_LDX | BPF_MEM, 0, 0, $4); } 301 | OP_LDXB number '*' '(' '[' number ']' '&' number ')' { 302 if ($2 != 4 || $9 != 0xf) { 303 fprintf(stderr, "ldxb offset not supported!\n"); 304 exit(0); 305 } else { 306 bpf_set_curr_instr(BPF_LDX | BPF_MSH | BPF_B, 0, 0, $6); } } 307 | OP_LDX number '*' '(' '[' number ']' '&' number ')' { 308 if ($2 != 4 || $9 != 0xf) { 309 fprintf(stderr, "ldxb offset not supported!\n"); 310 exit(0); 311 } else { 312 bpf_set_curr_instr(BPF_LDX | BPF_MSH | BPF_B, 0, 0, $6); } } 313 ; 314 315 st 316 : OP_ST 'M' '[' number ']' { 317 bpf_set_curr_instr(BPF_ST, 0, 0, $4); } 318 ; 319 320 stx 321 : OP_STX 'M' '[' number ']' { 322 bpf_set_curr_instr(BPF_STX, 0, 0, $4); } 323 ; 324 325 jmp 326 : OP_JMP label { 327 bpf_set_jmp_label($2, JKL); 328 bpf_set_curr_instr(BPF_JMP | BPF_JA, 0, 0, 0); } 329 ; 330 331 jeq 332 : OP_JEQ '#' number ',' label ',' label { 333 bpf_set_jmp_label($5, JTL); 334 bpf_set_jmp_label($7, JFL); 335 bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, $3); } 336 | OP_JEQ 'x' ',' label ',' label { 337 bpf_set_jmp_label($4, JTL); 338 bpf_set_jmp_label($6, JFL); 339 bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); } 340 | OP_JEQ '%' 'x' ',' label ',' label { 341 bpf_set_jmp_label($5, JTL); 342 bpf_set_jmp_label($7, JFL); 343 bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); } 344 | OP_JEQ '#' number ',' label { 345 bpf_set_jmp_label($5, JTL); 346 bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, $3); } 347 | OP_JEQ 'x' ',' label { 348 bpf_set_jmp_label($4, JTL); 349 bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); } 350 | OP_JEQ '%' 'x' ',' label { 351 bpf_set_jmp_label($5, JTL); 352 bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); } 353 ; 354 355 jneq 356 : OP_JNEQ '#' number ',' label { 357 bpf_set_jmp_label($5, JFL); 358 bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, $3); } 359 | OP_JNEQ 'x' ',' label { 360 bpf_set_jmp_label($4, JFL); 361 bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); } 362 | OP_JNEQ '%' 'x' ',' label { 363 bpf_set_jmp_label($5, JFL); 364 bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); } 365 ; 366 367 jlt 368 : OP_JLT '#' number ',' label { 369 bpf_set_jmp_label($5, JFL); 370 bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_K, 0, 0, $3); } 371 | OP_JLT 'x' ',' label { 372 bpf_set_jmp_label($4, JFL); 373 bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); } 374 | OP_JLT '%' 'x' ',' label { 375 bpf_set_jmp_label($5, JFL); 376 bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); } 377 ; 378 379 jle 380 : OP_JLE '#' number ',' label { 381 bpf_set_jmp_label($5, JFL); 382 bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_K, 0, 0, $3); } 383 | OP_JLE 'x' ',' label { 384 bpf_set_jmp_label($4, JFL); 385 bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); } 386 | OP_JLE '%' 'x' ',' label { 387 bpf_set_jmp_label($5, JFL); 388 bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); } 389 ; 390 391 jgt 392 : OP_JGT '#' number ',' label ',' label { 393 bpf_set_jmp_label($5, JTL); 394 bpf_set_jmp_label($7, JFL); 395 bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_K, 0, 0, $3); } 396 | OP_JGT 'x' ',' label ',' label { 397 bpf_set_jmp_label($4, JTL); 398 bpf_set_jmp_label($6, JFL); 399 bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); } 400 | OP_JGT '%' 'x' ',' label ',' label { 401 bpf_set_jmp_label($5, JTL); 402 bpf_set_jmp_label($7, JFL); 403 bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); } 404 | OP_JGT '#' number ',' label { 405 bpf_set_jmp_label($5, JTL); 406 bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_K, 0, 0, $3); } 407 | OP_JGT 'x' ',' label { 408 bpf_set_jmp_label($4, JTL); 409 bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); } 410 | OP_JGT '%' 'x' ',' label { 411 bpf_set_jmp_label($5, JTL); 412 bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); } 413 ; 414 415 jge 416 : OP_JGE '#' number ',' label ',' label { 417 bpf_set_jmp_label($5, JTL); 418 bpf_set_jmp_label($7, JFL); 419 bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_K, 0, 0, $3); } 420 | OP_JGE 'x' ',' label ',' label { 421 bpf_set_jmp_label($4, JTL); 422 bpf_set_jmp_label($6, JFL); 423 bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); } 424 | OP_JGE '%' 'x' ',' label ',' label { 425 bpf_set_jmp_label($5, JTL); 426 bpf_set_jmp_label($7, JFL); 427 bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); } 428 | OP_JGE '#' number ',' label { 429 bpf_set_jmp_label($5, JTL); 430 bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_K, 0, 0, $3); } 431 | OP_JGE 'x' ',' label { 432 bpf_set_jmp_label($4, JTL); 433 bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); } 434 | OP_JGE '%' 'x' ',' label { 435 bpf_set_jmp_label($5, JTL); 436 bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); } 437 ; 438 439 jset 440 : OP_JSET '#' number ',' label ',' label { 441 bpf_set_jmp_label($5, JTL); 442 bpf_set_jmp_label($7, JFL); 443 bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_K, 0, 0, $3); } 444 | OP_JSET 'x' ',' label ',' label { 445 bpf_set_jmp_label($4, JTL); 446 bpf_set_jmp_label($6, JFL); 447 bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); } 448 | OP_JSET '%' 'x' ',' label ',' label { 449 bpf_set_jmp_label($5, JTL); 450 bpf_set_jmp_label($7, JFL); 451 bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); } 452 | OP_JSET '#' number ',' label { 453 bpf_set_jmp_label($5, JTL); 454 bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_K, 0, 0, $3); } 455 | OP_JSET 'x' ',' label { 456 bpf_set_jmp_label($4, JTL); 457 bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); } 458 | OP_JSET '%' 'x' ',' label { 459 bpf_set_jmp_label($5, JTL); 460 bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); } 461 ; 462 463 add 464 : OP_ADD '#' number { 465 bpf_set_curr_instr(BPF_ALU | BPF_ADD | BPF_K, 0, 0, $3); } 466 | OP_ADD 'x' { 467 bpf_set_curr_instr(BPF_ALU | BPF_ADD | BPF_X, 0, 0, 0); } 468 | OP_ADD '%' 'x' { 469 bpf_set_curr_instr(BPF_ALU | BPF_ADD | BPF_X, 0, 0, 0); } 470 ; 471 472 sub 473 : OP_SUB '#' number { 474 bpf_set_curr_instr(BPF_ALU | BPF_SUB | BPF_K, 0, 0, $3); } 475 | OP_SUB 'x' { 476 bpf_set_curr_instr(BPF_ALU | BPF_SUB | BPF_X, 0, 0, 0); } 477 | OP_SUB '%' 'x' { 478 bpf_set_curr_instr(BPF_ALU | BPF_SUB | BPF_X, 0, 0, 0); } 479 ; 480 481 mul 482 : OP_MUL '#' number { 483 bpf_set_curr_instr(BPF_ALU | BPF_MUL | BPF_K, 0, 0, $3); } 484 | OP_MUL 'x' { 485 bpf_set_curr_instr(BPF_ALU | BPF_MUL | BPF_X, 0, 0, 0); } 486 | OP_MUL '%' 'x' { 487 bpf_set_curr_instr(BPF_ALU | BPF_MUL | BPF_X, 0, 0, 0); } 488 ; 489 490 div 491 : OP_DIV '#' number { 492 bpf_set_curr_instr(BPF_ALU | BPF_DIV | BPF_K, 0, 0, $3); } 493 | OP_DIV 'x' { 494 bpf_set_curr_instr(BPF_ALU | BPF_DIV | BPF_X, 0, 0, 0); } 495 | OP_DIV '%' 'x' { 496 bpf_set_curr_instr(BPF_ALU | BPF_DIV | BPF_X, 0, 0, 0); } 497 ; 498 499 mod 500 : OP_MOD '#' number { 501 bpf_set_curr_instr(BPF_ALU | BPF_MOD | BPF_K, 0, 0, $3); } 502 | OP_MOD 'x' { 503 bpf_set_curr_instr(BPF_ALU | BPF_MOD | BPF_X, 0, 0, 0); } 504 | OP_MOD '%' 'x' { 505 bpf_set_curr_instr(BPF_ALU | BPF_MOD | BPF_X, 0, 0, 0); } 506 ; 507 508 neg 509 : OP_NEG { 510 bpf_set_curr_instr(BPF_ALU | BPF_NEG, 0, 0, 0); } 511 ; 512 513 and 514 : OP_AND '#' number { 515 bpf_set_curr_instr(BPF_ALU | BPF_AND | BPF_K, 0, 0, $3); } 516 | OP_AND 'x' { 517 bpf_set_curr_instr(BPF_ALU | BPF_AND | BPF_X, 0, 0, 0); } 518 | OP_AND '%' 'x' { 519 bpf_set_curr_instr(BPF_ALU | BPF_AND | BPF_X, 0, 0, 0); } 520 ; 521 522 or 523 : OP_OR '#' number { 524 bpf_set_curr_instr(BPF_ALU | BPF_OR | BPF_K, 0, 0, $3); } 525 | OP_OR 'x' { 526 bpf_set_curr_instr(BPF_ALU | BPF_OR | BPF_X, 0, 0, 0); } 527 | OP_OR '%' 'x' { 528 bpf_set_curr_instr(BPF_ALU | BPF_OR | BPF_X, 0, 0, 0); } 529 ; 530 531 xor 532 : OP_XOR '#' number { 533 bpf_set_curr_instr(BPF_ALU | BPF_XOR | BPF_K, 0, 0, $3); } 534 | OP_XOR 'x' { 535 bpf_set_curr_instr(BPF_ALU | BPF_XOR | BPF_X, 0, 0, 0); } 536 | OP_XOR '%' 'x' { 537 bpf_set_curr_instr(BPF_ALU | BPF_XOR | BPF_X, 0, 0, 0); } 538 ; 539 540 lsh 541 : OP_LSH '#' number { 542 bpf_set_curr_instr(BPF_ALU | BPF_LSH | BPF_K, 0, 0, $3); } 543 | OP_LSH 'x' { 544 bpf_set_curr_instr(BPF_ALU | BPF_LSH | BPF_X, 0, 0, 0); } 545 | OP_LSH '%' 'x' { 546 bpf_set_curr_instr(BPF_ALU | BPF_LSH | BPF_X, 0, 0, 0); } 547 ; 548 549 rsh 550 : OP_RSH '#' number { 551 bpf_set_curr_instr(BPF_ALU | BPF_RSH | BPF_K, 0, 0, $3); } 552 | OP_RSH 'x' { 553 bpf_set_curr_instr(BPF_ALU | BPF_RSH | BPF_X, 0, 0, 0); } 554 | OP_RSH '%' 'x' { 555 bpf_set_curr_instr(BPF_ALU | BPF_RSH | BPF_X, 0, 0, 0); } 556 ; 557 558 ret 559 : OP_RET 'a' { 560 bpf_set_curr_instr(BPF_RET | BPF_A, 0, 0, 0); } 561 | OP_RET '%' 'a' { 562 bpf_set_curr_instr(BPF_RET | BPF_A, 0, 0, 0); } 563 | OP_RET 'x' { 564 bpf_set_curr_instr(BPF_RET | BPF_X, 0, 0, 0); } 565 | OP_RET '%' 'x' { 566 bpf_set_curr_instr(BPF_RET | BPF_X, 0, 0, 0); } 567 | OP_RET '#' number { 568 bpf_set_curr_instr(BPF_RET | BPF_K, 0, 0, $3); } 569 ; 570 571 tax 572 : OP_TAX { 573 bpf_set_curr_instr(BPF_MISC | BPF_TAX, 0, 0, 0); } 574 ; 575 576 txa 577 : OP_TXA { 578 bpf_set_curr_instr(BPF_MISC | BPF_TXA, 0, 0, 0); } 579 ; 580 581 %% 582 583 static int curr_instr = 0; 584 static struct sock_filter out[BPF_MAXINSNS]; 585 static char **labels, **labels_jt, **labels_jf, **labels_k; 586 587 static void bpf_assert_max(void) 588 { 589 if (curr_instr >= BPF_MAXINSNS) { 590 fprintf(stderr, "only max %u insns allowed!\n", BPF_MAXINSNS); 591 exit(0); 592 } 593 } 594 595 static void bpf_set_curr_instr(uint16_t code, uint8_t jt, uint8_t jf, 596 uint32_t k) 597 { 598 bpf_assert_max(); 599 out[curr_instr].code = code; 600 out[curr_instr].jt = jt; 601 out[curr_instr].jf = jf; 602 out[curr_instr].k = k; 603 curr_instr++; 604 } 605 606 static void bpf_set_curr_label(char *label) 607 { 608 bpf_assert_max(); 609 labels[curr_instr] = label; 610 } 611 612 static void bpf_set_jmp_label(char *label, enum jmp_type type) 613 { 614 bpf_assert_max(); 615 switch (type) { 616 case JTL: 617 labels_jt[curr_instr] = label; 618 break; 619 case JFL: 620 labels_jf[curr_instr] = label; 621 break; 622 case JKL: 623 labels_k[curr_instr] = label; 624 break; 625 } 626 } 627 628 static int bpf_find_insns_offset(const char *label) 629 { 630 int i, max = curr_instr, ret = -ENOENT; 631 632 for (i = 0; i < max; i++) { 633 if (labels[i] && !strcmp(label, labels[i])) { 634 ret = i; 635 break; 636 } 637 } 638 639 if (ret == -ENOENT) { 640 fprintf(stderr, "no such label \'%s\'!\n", label); 641 exit(0); 642 } 643 644 return ret; 645 } 646 647 static void bpf_stage_1_insert_insns(void) 648 { 649 yyparse(); 650 } 651 652 static void bpf_reduce_k_jumps(void) 653 { 654 int i; 655 656 for (i = 0; i < curr_instr; i++) { 657 if (labels_k[i]) { 658 int off = bpf_find_insns_offset(labels_k[i]); 659 out[i].k = (uint32_t) (off - i - 1); 660 } 661 } 662 } 663 664 static void bpf_reduce_jt_jumps(void) 665 { 666 int i; 667 668 for (i = 0; i < curr_instr; i++) { 669 if (labels_jt[i]) { 670 int off = bpf_find_insns_offset(labels_jt[i]); 671 out[i].jt = (uint8_t) (off - i -1); 672 } 673 } 674 } 675 676 static void bpf_reduce_jf_jumps(void) 677 { 678 int i; 679 680 for (i = 0; i < curr_instr; i++) { 681 if (labels_jf[i]) { 682 int off = bpf_find_insns_offset(labels_jf[i]); 683 out[i].jf = (uint8_t) (off - i - 1); 684 } 685 } 686 } 687 688 static void bpf_stage_2_reduce_labels(void) 689 { 690 bpf_reduce_k_jumps(); 691 bpf_reduce_jt_jumps(); 692 bpf_reduce_jf_jumps(); 693 } 694 695 static void bpf_pretty_print_c(void) 696 { 697 int i; 698 699 for (i = 0; i < curr_instr; i++) 700 printf("{ %#04x, %2u, %2u, %#010x },\n", out[i].code, 701 out[i].jt, out[i].jf, out[i].k); 702 } 703 704 static void bpf_pretty_print(void) 705 { 706 int i; 707 708 printf("%u,", curr_instr); 709 for (i = 0; i < curr_instr; i++) 710 printf("%u %u %u %u,", out[i].code, 711 out[i].jt, out[i].jf, out[i].k); 712 printf("\n"); 713 } 714 715 static void bpf_init(void) 716 { 717 memset(out, 0, sizeof(out)); 718 719 labels = calloc(BPF_MAXINSNS, sizeof(*labels)); 720 assert(labels); 721 labels_jt = calloc(BPF_MAXINSNS, sizeof(*labels_jt)); 722 assert(labels_jt); 723 labels_jf = calloc(BPF_MAXINSNS, sizeof(*labels_jf)); 724 assert(labels_jf); 725 labels_k = calloc(BPF_MAXINSNS, sizeof(*labels_k)); 726 assert(labels_k); 727 } 728 729 static void bpf_destroy_labels(void) 730 { 731 int i; 732 733 for (i = 0; i < curr_instr; i++) { 734 free(labels_jf[i]); 735 free(labels_jt[i]); 736 free(labels_k[i]); 737 free(labels[i]); 738 } 739 } 740 741 static void bpf_destroy(void) 742 { 743 bpf_destroy_labels(); 744 free(labels_jt); 745 free(labels_jf); 746 free(labels_k); 747 free(labels); 748 } 749 750 void bpf_asm_compile(FILE *fp, bool cstyle) 751 { 752 yyin = fp; 753 754 bpf_init(); 755 bpf_stage_1_insert_insns(); 756 bpf_stage_2_reduce_labels(); 757 bpf_destroy(); 758 759 if (cstyle) 760 bpf_pretty_print_c(); 761 else 762 bpf_pretty_print(); 763 764 if (fp != stdin) 765 fclose(yyin); 766 } 767 768 void yyerror(const char *str) 769 { 770 exit(1); 771 }
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.