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