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