Commit | Line | Data |
---|---|---|
97b58163 MD |
1 | /* |
2 | * lttng-filter-interpreter.c | |
3 | * | |
4 | * LTTng UST filter interpreter. | |
5 | * | |
6 | * Copyright (C) 2010-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | |
7 | * | |
8 | * This library is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU Lesser General Public | |
10 | * License as published by the Free Software Foundation; only | |
11 | * version 2.1 of the License. | |
12 | * | |
13 | * This library is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | * Lesser General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU Lesser General Public | |
19 | * License along with this library; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
21 | */ | |
22 | ||
23 | #include "lttng-filter.h" | |
24 | ||
25 | /* | |
26 | * -1: wildcard found. | |
27 | * -2: unknown escape char. | |
28 | * 0: normal char. | |
29 | */ | |
30 | ||
31 | static | |
32 | int parse_char(const char **p) | |
33 | { | |
34 | switch (**p) { | |
35 | case '\\': | |
36 | (*p)++; | |
37 | switch (**p) { | |
38 | case '\\': | |
39 | case '*': | |
40 | return 0; | |
41 | default: | |
42 | return -2; | |
43 | } | |
44 | case '*': | |
45 | return -1; | |
46 | default: | |
47 | return 0; | |
48 | } | |
49 | } | |
50 | ||
51 | static | |
52 | int reg_strcmp(struct reg reg[NR_REG], const char *cmp_type) | |
53 | { | |
54 | const char *p = reg[REG_R0].str, *q = reg[REG_R1].str; | |
55 | int ret; | |
56 | int diff; | |
57 | ||
58 | for (;;) { | |
59 | int escaped_r0 = 0; | |
60 | ||
61 | if (unlikely(p - reg[REG_R0].str > reg[REG_R0].seq_len || *p == '\0')) { | |
62 | if (q - reg[REG_R1].str > reg[REG_R1].seq_len || *q == '\0') | |
63 | diff = 0; | |
64 | else | |
65 | diff = -1; | |
66 | break; | |
67 | } | |
68 | if (unlikely(q - reg[REG_R1].str > reg[REG_R1].seq_len || *q == '\0')) { | |
69 | if (p - reg[REG_R0].str > reg[REG_R0].seq_len || *p == '\0') | |
70 | diff = 0; | |
71 | else | |
72 | diff = 1; | |
73 | break; | |
74 | } | |
75 | if (reg[REG_R0].literal) { | |
76 | ret = parse_char(&p); | |
77 | if (ret == -1) { | |
78 | return 0; | |
79 | } else if (ret == -2) { | |
80 | escaped_r0 = 1; | |
81 | } | |
82 | /* else compare both char */ | |
83 | } | |
84 | if (reg[REG_R1].literal) { | |
85 | ret = parse_char(&q); | |
86 | if (ret == -1) { | |
87 | return 0; | |
88 | } else if (ret == -2) { | |
89 | if (!escaped_r0) | |
90 | return -1; | |
91 | } else { | |
92 | if (escaped_r0) | |
93 | return 1; | |
94 | } | |
95 | } else { | |
96 | if (escaped_r0) | |
97 | return 1; | |
98 | } | |
99 | diff = *p - *q; | |
100 | if (diff != 0) | |
101 | break; | |
102 | p++; | |
103 | q++; | |
104 | } | |
105 | return diff; | |
106 | } | |
107 | ||
108 | int lttng_filter_false(void *filter_data, | |
109 | const char *filter_stack_data) | |
110 | { | |
111 | return 0; | |
112 | } | |
113 | ||
114 | #ifdef INTERPRETER_USE_SWITCH | |
115 | ||
116 | /* | |
117 | * Fallback for compilers that do not support taking address of labels. | |
118 | */ | |
119 | ||
120 | #define START_OP \ | |
121 | start_pc = &bytecode->data[0]; \ | |
122 | for (pc = next_pc = start_pc; pc - start_pc < bytecode->len; \ | |
123 | pc = next_pc) { \ | |
124 | dbg_printf("Executing op %s (%u)\n", \ | |
125 | print_op((unsigned int) *(filter_opcode_t *) pc), \ | |
126 | (unsigned int) *(filter_opcode_t *) pc); \ | |
127 | switch (*(filter_opcode_t *) pc) { | |
128 | ||
129 | #define OP(name) case name | |
130 | ||
131 | #define PO break | |
132 | ||
133 | #define END_OP } \ | |
134 | } | |
135 | ||
136 | #else | |
137 | ||
138 | /* | |
139 | * Dispatch-table based interpreter. | |
140 | */ | |
141 | ||
142 | #define START_OP \ | |
143 | start_pc = &bytecode->data[0]; \ | |
144 | pc = next_pc = start_pc; \ | |
145 | if (unlikely(pc - start_pc >= bytecode->len)) \ | |
146 | goto end; \ | |
147 | goto *dispatch[*(filter_opcode_t *) pc]; | |
148 | ||
149 | #define OP(name) \ | |
150 | LABEL_##name | |
151 | ||
152 | #define PO \ | |
153 | pc = next_pc; \ | |
154 | goto *dispatch[*(filter_opcode_t *) pc]; | |
155 | ||
156 | #define END_OP | |
157 | ||
158 | #endif | |
159 | ||
160 | int lttng_filter_interpret_bytecode(void *filter_data, | |
161 | const char *filter_stack_data) | |
162 | { | |
163 | struct bytecode_runtime *bytecode = filter_data; | |
164 | void *pc, *next_pc, *start_pc; | |
165 | int ret = -EINVAL; | |
166 | int retval = 0; | |
167 | struct reg reg[NR_REG]; | |
168 | #ifndef INTERPRETER_USE_SWITCH | |
169 | static void *dispatch[NR_FILTER_OPS] = { | |
170 | [ FILTER_OP_UNKNOWN ] = &&LABEL_FILTER_OP_UNKNOWN, | |
171 | ||
172 | [ FILTER_OP_RETURN ] = &&LABEL_FILTER_OP_RETURN, | |
173 | ||
174 | /* binary */ | |
175 | [ FILTER_OP_MUL ] = &&LABEL_FILTER_OP_MUL, | |
176 | [ FILTER_OP_DIV ] = &&LABEL_FILTER_OP_DIV, | |
177 | [ FILTER_OP_MOD ] = &&LABEL_FILTER_OP_MOD, | |
178 | [ FILTER_OP_PLUS ] = &&LABEL_FILTER_OP_PLUS, | |
179 | [ FILTER_OP_MINUS ] = &&LABEL_FILTER_OP_MINUS, | |
180 | [ FILTER_OP_RSHIFT ] = &&LABEL_FILTER_OP_RSHIFT, | |
181 | [ FILTER_OP_LSHIFT ] = &&LABEL_FILTER_OP_LSHIFT, | |
182 | [ FILTER_OP_BIN_AND ] = &&LABEL_FILTER_OP_BIN_AND, | |
183 | [ FILTER_OP_BIN_OR ] = &&LABEL_FILTER_OP_BIN_OR, | |
184 | [ FILTER_OP_BIN_XOR ] = &&LABEL_FILTER_OP_BIN_XOR, | |
185 | ||
186 | /* binary comparators */ | |
187 | [ FILTER_OP_EQ ] = &&LABEL_FILTER_OP_EQ, | |
188 | [ FILTER_OP_NE ] = &&LABEL_FILTER_OP_NE, | |
189 | [ FILTER_OP_GT ] = &&LABEL_FILTER_OP_GT, | |
190 | [ FILTER_OP_LT ] = &&LABEL_FILTER_OP_LT, | |
191 | [ FILTER_OP_GE ] = &&LABEL_FILTER_OP_GE, | |
192 | [ FILTER_OP_LE ] = &&LABEL_FILTER_OP_LE, | |
193 | ||
194 | /* string binary comparator */ | |
195 | [ FILTER_OP_EQ_STRING ] = &&LABEL_FILTER_OP_EQ_STRING, | |
196 | [ FILTER_OP_NE_STRING ] = &&LABEL_FILTER_OP_NE_STRING, | |
197 | [ FILTER_OP_GT_STRING ] = &&LABEL_FILTER_OP_GT_STRING, | |
198 | [ FILTER_OP_LT_STRING ] = &&LABEL_FILTER_OP_LT_STRING, | |
199 | [ FILTER_OP_GE_STRING ] = &&LABEL_FILTER_OP_GE_STRING, | |
200 | [ FILTER_OP_LE_STRING ] = &&LABEL_FILTER_OP_LE_STRING, | |
201 | ||
202 | /* s64 binary comparator */ | |
203 | [ FILTER_OP_EQ_S64 ] = &&LABEL_FILTER_OP_EQ_S64, | |
204 | [ FILTER_OP_NE_S64 ] = &&LABEL_FILTER_OP_NE_S64, | |
205 | [ FILTER_OP_GT_S64 ] = &&LABEL_FILTER_OP_GT_S64, | |
206 | [ FILTER_OP_LT_S64 ] = &&LABEL_FILTER_OP_LT_S64, | |
207 | [ FILTER_OP_GE_S64 ] = &&LABEL_FILTER_OP_GE_S64, | |
208 | [ FILTER_OP_LE_S64 ] = &&LABEL_FILTER_OP_LE_S64, | |
209 | ||
210 | /* double binary comparator */ | |
211 | [ FILTER_OP_EQ_DOUBLE ] = &&LABEL_FILTER_OP_EQ_DOUBLE, | |
212 | [ FILTER_OP_NE_DOUBLE ] = &&LABEL_FILTER_OP_NE_DOUBLE, | |
213 | [ FILTER_OP_GT_DOUBLE ] = &&LABEL_FILTER_OP_GT_DOUBLE, | |
214 | [ FILTER_OP_LT_DOUBLE ] = &&LABEL_FILTER_OP_LT_DOUBLE, | |
215 | [ FILTER_OP_GE_DOUBLE ] = &&LABEL_FILTER_OP_GE_DOUBLE, | |
216 | [ FILTER_OP_LE_DOUBLE ] = &&LABEL_FILTER_OP_LE_DOUBLE, | |
217 | ||
218 | /* unary */ | |
219 | [ FILTER_OP_UNARY_PLUS ] = &&LABEL_FILTER_OP_UNARY_PLUS, | |
220 | [ FILTER_OP_UNARY_MINUS ] = &&LABEL_FILTER_OP_UNARY_MINUS, | |
221 | [ FILTER_OP_UNARY_NOT ] = &&LABEL_FILTER_OP_UNARY_NOT, | |
222 | [ FILTER_OP_UNARY_PLUS_S64 ] = &&LABEL_FILTER_OP_UNARY_PLUS_S64, | |
223 | [ FILTER_OP_UNARY_MINUS_S64 ] = &&LABEL_FILTER_OP_UNARY_MINUS_S64, | |
224 | [ FILTER_OP_UNARY_NOT_S64 ] = &&LABEL_FILTER_OP_UNARY_NOT_S64, | |
225 | [ FILTER_OP_UNARY_PLUS_DOUBLE ] = &&LABEL_FILTER_OP_UNARY_PLUS_DOUBLE, | |
226 | [ FILTER_OP_UNARY_MINUS_DOUBLE ] = &&LABEL_FILTER_OP_UNARY_MINUS_DOUBLE, | |
227 | [ FILTER_OP_UNARY_NOT_DOUBLE ] = &&LABEL_FILTER_OP_UNARY_NOT_DOUBLE, | |
228 | ||
229 | /* logical */ | |
230 | [ FILTER_OP_AND ] = &&LABEL_FILTER_OP_AND, | |
231 | [ FILTER_OP_OR ] = &&LABEL_FILTER_OP_OR, | |
232 | ||
233 | /* load */ | |
234 | [ FILTER_OP_LOAD_FIELD_REF ] = &&LABEL_FILTER_OP_LOAD_FIELD_REF, | |
235 | [ FILTER_OP_LOAD_FIELD_REF_STRING ] = &&LABEL_FILTER_OP_LOAD_FIELD_REF_STRING, | |
236 | [ FILTER_OP_LOAD_FIELD_REF_SEQUENCE ] = &&LABEL_FILTER_OP_LOAD_FIELD_REF_SEQUENCE, | |
237 | [ FILTER_OP_LOAD_FIELD_REF_S64 ] = &&LABEL_FILTER_OP_LOAD_FIELD_REF_S64, | |
238 | [ FILTER_OP_LOAD_FIELD_REF_DOUBLE ] = &&LABEL_FILTER_OP_LOAD_FIELD_REF_DOUBLE, | |
239 | ||
240 | [ FILTER_OP_LOAD_STRING ] = &&LABEL_FILTER_OP_LOAD_STRING, | |
241 | [ FILTER_OP_LOAD_S64 ] = &&LABEL_FILTER_OP_LOAD_S64, | |
242 | [ FILTER_OP_LOAD_DOUBLE ] = &&LABEL_FILTER_OP_LOAD_DOUBLE, | |
243 | ||
244 | /* cast */ | |
245 | [ FILTER_OP_CAST_TO_S64 ] = &&LABEL_FILTER_OP_CAST_TO_S64, | |
246 | [ FILTER_OP_CAST_DOUBLE_TO_S64 ] = &&LABEL_FILTER_OP_CAST_DOUBLE_TO_S64, | |
247 | [ FILTER_OP_CAST_NOP ] = &&LABEL_FILTER_OP_CAST_NOP, | |
248 | }; | |
249 | #endif /* #ifndef INTERPRETER_USE_SWITCH */ | |
250 | ||
251 | START_OP | |
252 | ||
253 | OP(FILTER_OP_UNKNOWN): | |
254 | OP(FILTER_OP_LOAD_FIELD_REF): | |
255 | #ifdef INTERPRETER_USE_SWITCH | |
256 | default: | |
257 | #endif /* INTERPRETER_USE_SWITCH */ | |
258 | ERR("unknown bytecode op %u\n", | |
259 | (unsigned int) *(filter_opcode_t *) pc); | |
260 | ret = -EINVAL; | |
261 | goto end; | |
262 | ||
263 | OP(FILTER_OP_RETURN): | |
264 | retval = !!reg[0].v; | |
265 | ret = 0; | |
266 | goto end; | |
267 | ||
268 | /* binary */ | |
269 | OP(FILTER_OP_MUL): | |
270 | OP(FILTER_OP_DIV): | |
271 | OP(FILTER_OP_MOD): | |
272 | OP(FILTER_OP_PLUS): | |
273 | OP(FILTER_OP_MINUS): | |
274 | OP(FILTER_OP_RSHIFT): | |
275 | OP(FILTER_OP_LSHIFT): | |
276 | OP(FILTER_OP_BIN_AND): | |
277 | OP(FILTER_OP_BIN_OR): | |
278 | OP(FILTER_OP_BIN_XOR): | |
279 | ERR("unsupported bytecode op %u\n", | |
280 | (unsigned int) *(filter_opcode_t *) pc); | |
281 | ret = -EINVAL; | |
282 | goto end; | |
283 | ||
284 | OP(FILTER_OP_EQ): | |
285 | OP(FILTER_OP_NE): | |
286 | OP(FILTER_OP_GT): | |
287 | OP(FILTER_OP_LT): | |
288 | OP(FILTER_OP_GE): | |
289 | OP(FILTER_OP_LE): | |
290 | ERR("unsupported non-specialized bytecode op %u\n", | |
291 | (unsigned int) *(filter_opcode_t *) pc); | |
292 | ret = -EINVAL; | |
293 | goto end; | |
294 | ||
295 | OP(FILTER_OP_EQ_STRING): | |
296 | { | |
297 | reg[REG_R0].v = (reg_strcmp(reg, "==") == 0); | |
298 | reg[REG_R0].type = REG_S64; | |
299 | next_pc += sizeof(struct binary_op); | |
300 | PO; | |
301 | } | |
302 | OP(FILTER_OP_NE_STRING): | |
303 | { | |
304 | reg[REG_R0].v = (reg_strcmp(reg, "!=") != 0); | |
305 | reg[REG_R0].type = REG_S64; | |
306 | next_pc += sizeof(struct binary_op); | |
307 | PO; | |
308 | } | |
309 | OP(FILTER_OP_GT_STRING): | |
310 | { | |
311 | reg[REG_R0].v = (reg_strcmp(reg, ">") > 0); | |
312 | reg[REG_R0].type = REG_S64; | |
313 | next_pc += sizeof(struct binary_op); | |
314 | PO; | |
315 | } | |
316 | OP(FILTER_OP_LT_STRING): | |
317 | { | |
318 | reg[REG_R0].v = (reg_strcmp(reg, "<") < 0); | |
319 | reg[REG_R0].type = REG_S64; | |
320 | next_pc += sizeof(struct binary_op); | |
321 | PO; | |
322 | } | |
323 | OP(FILTER_OP_GE_STRING): | |
324 | { | |
325 | reg[REG_R0].v = (reg_strcmp(reg, ">=") >= 0); | |
326 | reg[REG_R0].type = REG_S64; | |
327 | next_pc += sizeof(struct binary_op); | |
328 | PO; | |
329 | } | |
330 | OP(FILTER_OP_LE_STRING): | |
331 | { | |
332 | reg[REG_R0].v = (reg_strcmp(reg, "<=") <= 0); | |
333 | reg[REG_R0].type = REG_S64; | |
334 | next_pc += sizeof(struct binary_op); | |
335 | PO; | |
336 | } | |
337 | ||
338 | OP(FILTER_OP_EQ_S64): | |
339 | { | |
340 | reg[REG_R0].v = (reg[REG_R0].v == reg[REG_R1].v); | |
341 | reg[REG_R0].type = REG_S64; | |
342 | next_pc += sizeof(struct binary_op); | |
343 | PO; | |
344 | } | |
345 | OP(FILTER_OP_NE_S64): | |
346 | { | |
347 | reg[REG_R0].v = (reg[REG_R0].v != reg[REG_R1].v); | |
348 | reg[REG_R0].type = REG_S64; | |
349 | next_pc += sizeof(struct binary_op); | |
350 | PO; | |
351 | } | |
352 | OP(FILTER_OP_GT_S64): | |
353 | { | |
354 | reg[REG_R0].v = (reg[REG_R0].v > reg[REG_R1].v); | |
355 | reg[REG_R0].type = REG_S64; | |
356 | next_pc += sizeof(struct binary_op); | |
357 | PO; | |
358 | } | |
359 | OP(FILTER_OP_LT_S64): | |
360 | { | |
361 | reg[REG_R0].v = (reg[REG_R0].v < reg[REG_R1].v); | |
362 | reg[REG_R0].type = REG_S64; | |
363 | next_pc += sizeof(struct binary_op); | |
364 | PO; | |
365 | } | |
366 | OP(FILTER_OP_GE_S64): | |
367 | { | |
368 | reg[REG_R0].v = (reg[REG_R0].v >= reg[REG_R1].v); | |
369 | reg[REG_R0].type = REG_S64; | |
370 | next_pc += sizeof(struct binary_op); | |
371 | PO; | |
372 | } | |
373 | OP(FILTER_OP_LE_S64): | |
374 | { | |
375 | reg[REG_R0].v = (reg[REG_R0].v <= reg[REG_R1].v); | |
376 | reg[REG_R0].type = REG_S64; | |
377 | next_pc += sizeof(struct binary_op); | |
378 | PO; | |
379 | } | |
380 | ||
381 | OP(FILTER_OP_EQ_DOUBLE): | |
382 | { | |
383 | if (unlikely(reg[REG_R0].type == REG_S64)) | |
384 | reg[REG_R0].d = (double) reg[REG_R0].v; | |
385 | else if (unlikely(reg[REG_R1].type == REG_S64)) | |
386 | reg[REG_R1].d = (double) reg[REG_R1].v; | |
387 | reg[REG_R0].v = (reg[REG_R0].d == reg[REG_R1].d); | |
388 | reg[REG_R0].type = REG_S64; | |
389 | next_pc += sizeof(struct binary_op); | |
390 | PO; | |
391 | } | |
392 | OP(FILTER_OP_NE_DOUBLE): | |
393 | { | |
394 | if (unlikely(reg[REG_R0].type == REG_S64)) | |
395 | reg[REG_R0].d = (double) reg[REG_R0].v; | |
396 | else if (unlikely(reg[REG_R1].type == REG_S64)) | |
397 | reg[REG_R1].d = (double) reg[REG_R1].v; | |
398 | reg[REG_R0].v = (reg[REG_R0].d != reg[REG_R1].d); | |
399 | reg[REG_R0].type = REG_S64; | |
400 | next_pc += sizeof(struct binary_op); | |
401 | PO; | |
402 | } | |
403 | OP(FILTER_OP_GT_DOUBLE): | |
404 | { | |
405 | if (unlikely(reg[REG_R0].type == REG_S64)) | |
406 | reg[REG_R0].d = (double) reg[REG_R0].v; | |
407 | else if (unlikely(reg[REG_R1].type == REG_S64)) | |
408 | reg[REG_R1].d = (double) reg[REG_R1].v; | |
409 | reg[REG_R0].v = (reg[REG_R0].d > reg[REG_R1].d); | |
410 | reg[REG_R0].type = REG_S64; | |
411 | next_pc += sizeof(struct binary_op); | |
412 | PO; | |
413 | } | |
414 | OP(FILTER_OP_LT_DOUBLE): | |
415 | { | |
416 | if (unlikely(reg[REG_R0].type == REG_S64)) | |
417 | reg[REG_R0].d = (double) reg[REG_R0].v; | |
418 | else if (unlikely(reg[REG_R1].type == REG_S64)) | |
419 | reg[REG_R1].d = (double) reg[REG_R1].v; | |
420 | reg[REG_R0].v = (reg[REG_R0].d < reg[REG_R1].d); | |
421 | reg[REG_R0].type = REG_S64; | |
422 | next_pc += sizeof(struct binary_op); | |
423 | PO; | |
424 | } | |
425 | OP(FILTER_OP_GE_DOUBLE): | |
426 | { | |
427 | if (unlikely(reg[REG_R0].type == REG_S64)) | |
428 | reg[REG_R0].d = (double) reg[REG_R0].v; | |
429 | else if (unlikely(reg[REG_R1].type == REG_S64)) | |
430 | reg[REG_R1].d = (double) reg[REG_R1].v; | |
431 | reg[REG_R0].v = (reg[REG_R0].d >= reg[REG_R1].d); | |
432 | reg[REG_R0].type = REG_S64; | |
433 | next_pc += sizeof(struct binary_op); | |
434 | PO; | |
435 | } | |
436 | OP(FILTER_OP_LE_DOUBLE): | |
437 | { | |
438 | if (unlikely(reg[REG_R0].type == REG_S64)) | |
439 | reg[REG_R0].d = (double) reg[REG_R0].v; | |
440 | else if (unlikely(reg[REG_R1].type == REG_S64)) | |
441 | reg[REG_R1].d = (double) reg[REG_R1].v; | |
442 | reg[REG_R0].v = (reg[REG_R0].d <= reg[REG_R1].d); | |
443 | reg[REG_R0].type = REG_S64; | |
444 | next_pc += sizeof(struct binary_op); | |
445 | PO; | |
446 | } | |
447 | ||
448 | /* unary */ | |
449 | OP(FILTER_OP_UNARY_PLUS): | |
450 | OP(FILTER_OP_UNARY_MINUS): | |
451 | OP(FILTER_OP_UNARY_NOT): | |
452 | ERR("unsupported non-specialized bytecode op %u\n", | |
453 | (unsigned int) *(filter_opcode_t *) pc); | |
454 | ret = -EINVAL; | |
455 | goto end; | |
456 | ||
457 | ||
458 | OP(FILTER_OP_UNARY_PLUS_S64): | |
459 | OP(FILTER_OP_UNARY_PLUS_DOUBLE): | |
460 | { | |
461 | next_pc += sizeof(struct unary_op); | |
462 | PO; | |
463 | } | |
464 | OP(FILTER_OP_UNARY_MINUS_S64): | |
465 | { | |
466 | struct unary_op *insn = (struct unary_op *) pc; | |
467 | ||
468 | reg[insn->reg].v = -reg[insn->reg].v; | |
469 | next_pc += sizeof(struct unary_op); | |
470 | PO; | |
471 | } | |
472 | OP(FILTER_OP_UNARY_MINUS_DOUBLE): | |
473 | { | |
474 | struct unary_op *insn = (struct unary_op *) pc; | |
475 | ||
476 | reg[insn->reg].d = -reg[insn->reg].d; | |
477 | next_pc += sizeof(struct unary_op); | |
478 | PO; | |
479 | } | |
480 | OP(FILTER_OP_UNARY_NOT_S64): | |
481 | { | |
482 | struct unary_op *insn = (struct unary_op *) pc; | |
483 | ||
484 | reg[insn->reg].v = !reg[insn->reg].v; | |
485 | next_pc += sizeof(struct unary_op); | |
486 | PO; | |
487 | } | |
488 | OP(FILTER_OP_UNARY_NOT_DOUBLE): | |
489 | { | |
490 | struct unary_op *insn = (struct unary_op *) pc; | |
491 | ||
492 | reg[insn->reg].d = !reg[insn->reg].d; | |
493 | next_pc += sizeof(struct unary_op); | |
494 | PO; | |
495 | } | |
496 | ||
497 | /* logical */ | |
498 | OP(FILTER_OP_AND): | |
499 | { | |
500 | struct logical_op *insn = (struct logical_op *) pc; | |
501 | ||
502 | /* If REG_R0 is 0, skip and evaluate to 0 */ | |
503 | if (unlikely(reg[REG_R0].v == 0)) { | |
504 | dbg_printf("Jumping to bytecode offset %u\n", | |
505 | (unsigned int) insn->skip_offset); | |
506 | next_pc = start_pc + insn->skip_offset; | |
507 | } else { | |
508 | next_pc += sizeof(struct logical_op); | |
509 | } | |
510 | PO; | |
511 | } | |
512 | OP(FILTER_OP_OR): | |
513 | { | |
514 | struct logical_op *insn = (struct logical_op *) pc; | |
515 | ||
516 | /* If REG_R0 is nonzero, skip and evaluate to 1 */ | |
517 | ||
518 | if (unlikely(reg[REG_R0].v != 0)) { | |
519 | reg[REG_R0].v = 1; | |
520 | dbg_printf("Jumping to bytecode offset %u\n", | |
521 | (unsigned int) insn->skip_offset); | |
522 | next_pc = start_pc + insn->skip_offset; | |
523 | } else { | |
524 | next_pc += sizeof(struct logical_op); | |
525 | } | |
526 | PO; | |
527 | } | |
528 | ||
529 | ||
530 | /* load */ | |
531 | OP(FILTER_OP_LOAD_FIELD_REF_STRING): | |
532 | { | |
533 | struct load_op *insn = (struct load_op *) pc; | |
534 | struct field_ref *ref = (struct field_ref *) insn->data; | |
535 | ||
536 | dbg_printf("load field ref offset %u type string\n", | |
537 | ref->offset); | |
538 | reg[insn->reg].str = | |
539 | *(const char * const *) &filter_stack_data[ref->offset]; | |
540 | if (unlikely(!reg[insn->reg].str)) { | |
541 | dbg_printf("Filter warning: loading a NULL string.\n"); | |
542 | ret = -EINVAL; | |
543 | goto end; | |
544 | } | |
545 | reg[insn->reg].type = REG_STRING; | |
546 | reg[insn->reg].seq_len = UINT_MAX; | |
547 | reg[insn->reg].literal = 0; | |
548 | dbg_printf("ref load string %s\n", reg[insn->reg].str); | |
549 | next_pc += sizeof(struct load_op) + sizeof(struct field_ref); | |
550 | PO; | |
551 | } | |
552 | ||
553 | OP(FILTER_OP_LOAD_FIELD_REF_SEQUENCE): | |
554 | { | |
555 | struct load_op *insn = (struct load_op *) pc; | |
556 | struct field_ref *ref = (struct field_ref *) insn->data; | |
557 | ||
558 | dbg_printf("load field ref offset %u type sequence\n", | |
559 | ref->offset); | |
560 | reg[insn->reg].seq_len = | |
561 | *(unsigned long *) &filter_stack_data[ref->offset]; | |
562 | reg[insn->reg].str = | |
563 | *(const char **) (&filter_stack_data[ref->offset | |
564 | + sizeof(unsigned long)]); | |
565 | if (unlikely(!reg[insn->reg].str)) { | |
566 | dbg_printf("Filter warning: loading a NULL sequence.\n"); | |
567 | ret = -EINVAL; | |
568 | goto end; | |
569 | } | |
570 | reg[insn->reg].type = REG_STRING; | |
571 | reg[insn->reg].literal = 0; | |
572 | next_pc += sizeof(struct load_op) + sizeof(struct field_ref); | |
573 | PO; | |
574 | } | |
575 | ||
576 | OP(FILTER_OP_LOAD_FIELD_REF_S64): | |
577 | { | |
578 | struct load_op *insn = (struct load_op *) pc; | |
579 | struct field_ref *ref = (struct field_ref *) insn->data; | |
580 | ||
581 | dbg_printf("load field ref offset %u type s64\n", | |
582 | ref->offset); | |
583 | memcpy(®[insn->reg].v, &filter_stack_data[ref->offset], | |
584 | sizeof(struct literal_numeric)); | |
585 | reg[insn->reg].type = REG_S64; | |
586 | dbg_printf("ref load s64 %" PRIi64 "\n", reg[insn->reg].v); | |
587 | next_pc += sizeof(struct load_op) + sizeof(struct field_ref); | |
588 | PO; | |
589 | } | |
590 | ||
591 | OP(FILTER_OP_LOAD_FIELD_REF_DOUBLE): | |
592 | { | |
593 | struct load_op *insn = (struct load_op *) pc; | |
594 | struct field_ref *ref = (struct field_ref *) insn->data; | |
595 | ||
596 | dbg_printf("load field ref offset %u type double\n", | |
597 | ref->offset); | |
598 | memcpy(®[insn->reg].d, &filter_stack_data[ref->offset], | |
599 | sizeof(struct literal_double)); | |
600 | reg[insn->reg].type = REG_DOUBLE; | |
601 | dbg_printf("ref load double %g\n", reg[insn->reg].d); | |
602 | next_pc += sizeof(struct load_op) + sizeof(struct field_ref); | |
603 | PO; | |
604 | } | |
605 | ||
606 | OP(FILTER_OP_LOAD_STRING): | |
607 | { | |
608 | struct load_op *insn = (struct load_op *) pc; | |
609 | ||
610 | dbg_printf("load string %s\n", insn->data); | |
611 | reg[insn->reg].str = insn->data; | |
612 | reg[insn->reg].type = REG_STRING; | |
613 | reg[insn->reg].seq_len = UINT_MAX; | |
614 | reg[insn->reg].literal = 1; | |
615 | next_pc += sizeof(struct load_op) + strlen(insn->data) + 1; | |
616 | PO; | |
617 | } | |
618 | ||
619 | OP(FILTER_OP_LOAD_S64): | |
620 | { | |
621 | struct load_op *insn = (struct load_op *) pc; | |
622 | ||
623 | memcpy(®[insn->reg].v, insn->data, | |
624 | sizeof(struct literal_numeric)); | |
625 | dbg_printf("load s64 %" PRIi64 "\n", reg[insn->reg].v); | |
626 | reg[insn->reg].type = REG_S64; | |
627 | next_pc += sizeof(struct load_op) | |
628 | + sizeof(struct literal_numeric); | |
629 | PO; | |
630 | } | |
631 | ||
632 | OP(FILTER_OP_LOAD_DOUBLE): | |
633 | { | |
634 | struct load_op *insn = (struct load_op *) pc; | |
635 | ||
636 | memcpy(®[insn->reg].d, insn->data, | |
637 | sizeof(struct literal_double)); | |
638 | dbg_printf("load s64 %g\n", reg[insn->reg].d); | |
639 | reg[insn->reg].type = REG_DOUBLE; | |
640 | next_pc += sizeof(struct load_op) | |
641 | + sizeof(struct literal_double); | |
642 | PO; | |
643 | } | |
644 | ||
645 | /* cast */ | |
646 | OP(FILTER_OP_CAST_TO_S64): | |
647 | ERR("unsupported non-specialized bytecode op %u\n", | |
648 | (unsigned int) *(filter_opcode_t *) pc); | |
649 | ret = -EINVAL; | |
650 | goto end; | |
651 | ||
652 | OP(FILTER_OP_CAST_DOUBLE_TO_S64): | |
653 | { | |
654 | struct cast_op *insn = (struct cast_op *) pc; | |
655 | ||
656 | reg[insn->reg].v = (int64_t) reg[insn->reg].d; | |
657 | reg[insn->reg].type = REG_S64; | |
658 | next_pc += sizeof(struct cast_op); | |
659 | PO; | |
660 | } | |
661 | ||
662 | OP(FILTER_OP_CAST_NOP): | |
663 | { | |
664 | next_pc += sizeof(struct cast_op); | |
665 | PO; | |
666 | } | |
667 | ||
668 | END_OP | |
669 | end: | |
670 | /* return 0 (discard) on error */ | |
671 | if (ret) | |
672 | return 0; | |
673 | return retval; | |
674 | } | |
675 | ||
676 | #undef START_OP | |
677 | #undef OP | |
678 | #undef PO | |
679 | #undef END_OP |