bpf_exp.y 16 KB

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