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 | |
0305960f | 52 | int stack_strcmp(struct estack *stack, const char *cmp_type) |
97b58163 | 53 | { |
0305960f | 54 | const char *p = estack_bx(stack)->u.s.str, *q = estack_ax(stack)->u.s.str; |
97b58163 MD |
55 | int ret; |
56 | int diff; | |
57 | ||
58 | for (;;) { | |
59 | int escaped_r0 = 0; | |
60 | ||
0305960f MD |
61 | if (unlikely(p - estack_bx(stack)->u.s.str > estack_bx(stack)->u.s.seq_len || *p == '\0')) { |
62 | if (q - estack_ax(stack)->u.s.str > estack_ax(stack)->u.s.seq_len || *q == '\0') | |
97b58163 MD |
63 | diff = 0; |
64 | else | |
65 | diff = -1; | |
66 | break; | |
67 | } | |
0305960f MD |
68 | if (unlikely(q - estack_ax(stack)->u.s.str > estack_ax(stack)->u.s.seq_len || *q == '\0')) { |
69 | if (p - estack_bx(stack)->u.s.str > estack_bx(stack)->u.s.seq_len || *p == '\0') | |
97b58163 MD |
70 | diff = 0; |
71 | else | |
72 | diff = 1; | |
73 | break; | |
74 | } | |
0305960f | 75 | if (estack_bx(stack)->u.s.literal) { |
97b58163 MD |
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 | } | |
0305960f | 84 | if (estack_ax(stack)->u.s.literal) { |
97b58163 MD |
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; | |
0305960f MD |
167 | struct estack _stack; |
168 | struct estack *stack = &_stack; | |
97b58163 MD |
169 | #ifndef INTERPRETER_USE_SWITCH |
170 | static void *dispatch[NR_FILTER_OPS] = { | |
171 | [ FILTER_OP_UNKNOWN ] = &&LABEL_FILTER_OP_UNKNOWN, | |
172 | ||
173 | [ FILTER_OP_RETURN ] = &&LABEL_FILTER_OP_RETURN, | |
174 | ||
175 | /* binary */ | |
176 | [ FILTER_OP_MUL ] = &&LABEL_FILTER_OP_MUL, | |
177 | [ FILTER_OP_DIV ] = &&LABEL_FILTER_OP_DIV, | |
178 | [ FILTER_OP_MOD ] = &&LABEL_FILTER_OP_MOD, | |
179 | [ FILTER_OP_PLUS ] = &&LABEL_FILTER_OP_PLUS, | |
180 | [ FILTER_OP_MINUS ] = &&LABEL_FILTER_OP_MINUS, | |
181 | [ FILTER_OP_RSHIFT ] = &&LABEL_FILTER_OP_RSHIFT, | |
182 | [ FILTER_OP_LSHIFT ] = &&LABEL_FILTER_OP_LSHIFT, | |
183 | [ FILTER_OP_BIN_AND ] = &&LABEL_FILTER_OP_BIN_AND, | |
184 | [ FILTER_OP_BIN_OR ] = &&LABEL_FILTER_OP_BIN_OR, | |
185 | [ FILTER_OP_BIN_XOR ] = &&LABEL_FILTER_OP_BIN_XOR, | |
186 | ||
187 | /* binary comparators */ | |
188 | [ FILTER_OP_EQ ] = &&LABEL_FILTER_OP_EQ, | |
189 | [ FILTER_OP_NE ] = &&LABEL_FILTER_OP_NE, | |
190 | [ FILTER_OP_GT ] = &&LABEL_FILTER_OP_GT, | |
191 | [ FILTER_OP_LT ] = &&LABEL_FILTER_OP_LT, | |
192 | [ FILTER_OP_GE ] = &&LABEL_FILTER_OP_GE, | |
193 | [ FILTER_OP_LE ] = &&LABEL_FILTER_OP_LE, | |
194 | ||
195 | /* string binary comparator */ | |
196 | [ FILTER_OP_EQ_STRING ] = &&LABEL_FILTER_OP_EQ_STRING, | |
197 | [ FILTER_OP_NE_STRING ] = &&LABEL_FILTER_OP_NE_STRING, | |
198 | [ FILTER_OP_GT_STRING ] = &&LABEL_FILTER_OP_GT_STRING, | |
199 | [ FILTER_OP_LT_STRING ] = &&LABEL_FILTER_OP_LT_STRING, | |
200 | [ FILTER_OP_GE_STRING ] = &&LABEL_FILTER_OP_GE_STRING, | |
201 | [ FILTER_OP_LE_STRING ] = &&LABEL_FILTER_OP_LE_STRING, | |
202 | ||
203 | /* s64 binary comparator */ | |
204 | [ FILTER_OP_EQ_S64 ] = &&LABEL_FILTER_OP_EQ_S64, | |
205 | [ FILTER_OP_NE_S64 ] = &&LABEL_FILTER_OP_NE_S64, | |
206 | [ FILTER_OP_GT_S64 ] = &&LABEL_FILTER_OP_GT_S64, | |
207 | [ FILTER_OP_LT_S64 ] = &&LABEL_FILTER_OP_LT_S64, | |
208 | [ FILTER_OP_GE_S64 ] = &&LABEL_FILTER_OP_GE_S64, | |
209 | [ FILTER_OP_LE_S64 ] = &&LABEL_FILTER_OP_LE_S64, | |
210 | ||
211 | /* double binary comparator */ | |
212 | [ FILTER_OP_EQ_DOUBLE ] = &&LABEL_FILTER_OP_EQ_DOUBLE, | |
213 | [ FILTER_OP_NE_DOUBLE ] = &&LABEL_FILTER_OP_NE_DOUBLE, | |
214 | [ FILTER_OP_GT_DOUBLE ] = &&LABEL_FILTER_OP_GT_DOUBLE, | |
215 | [ FILTER_OP_LT_DOUBLE ] = &&LABEL_FILTER_OP_LT_DOUBLE, | |
216 | [ FILTER_OP_GE_DOUBLE ] = &&LABEL_FILTER_OP_GE_DOUBLE, | |
217 | [ FILTER_OP_LE_DOUBLE ] = &&LABEL_FILTER_OP_LE_DOUBLE, | |
218 | ||
219 | /* unary */ | |
220 | [ FILTER_OP_UNARY_PLUS ] = &&LABEL_FILTER_OP_UNARY_PLUS, | |
221 | [ FILTER_OP_UNARY_MINUS ] = &&LABEL_FILTER_OP_UNARY_MINUS, | |
222 | [ FILTER_OP_UNARY_NOT ] = &&LABEL_FILTER_OP_UNARY_NOT, | |
223 | [ FILTER_OP_UNARY_PLUS_S64 ] = &&LABEL_FILTER_OP_UNARY_PLUS_S64, | |
224 | [ FILTER_OP_UNARY_MINUS_S64 ] = &&LABEL_FILTER_OP_UNARY_MINUS_S64, | |
225 | [ FILTER_OP_UNARY_NOT_S64 ] = &&LABEL_FILTER_OP_UNARY_NOT_S64, | |
226 | [ FILTER_OP_UNARY_PLUS_DOUBLE ] = &&LABEL_FILTER_OP_UNARY_PLUS_DOUBLE, | |
227 | [ FILTER_OP_UNARY_MINUS_DOUBLE ] = &&LABEL_FILTER_OP_UNARY_MINUS_DOUBLE, | |
228 | [ FILTER_OP_UNARY_NOT_DOUBLE ] = &&LABEL_FILTER_OP_UNARY_NOT_DOUBLE, | |
229 | ||
230 | /* logical */ | |
231 | [ FILTER_OP_AND ] = &&LABEL_FILTER_OP_AND, | |
232 | [ FILTER_OP_OR ] = &&LABEL_FILTER_OP_OR, | |
233 | ||
234 | /* load */ | |
235 | [ FILTER_OP_LOAD_FIELD_REF ] = &&LABEL_FILTER_OP_LOAD_FIELD_REF, | |
236 | [ FILTER_OP_LOAD_FIELD_REF_STRING ] = &&LABEL_FILTER_OP_LOAD_FIELD_REF_STRING, | |
237 | [ FILTER_OP_LOAD_FIELD_REF_SEQUENCE ] = &&LABEL_FILTER_OP_LOAD_FIELD_REF_SEQUENCE, | |
238 | [ FILTER_OP_LOAD_FIELD_REF_S64 ] = &&LABEL_FILTER_OP_LOAD_FIELD_REF_S64, | |
239 | [ FILTER_OP_LOAD_FIELD_REF_DOUBLE ] = &&LABEL_FILTER_OP_LOAD_FIELD_REF_DOUBLE, | |
240 | ||
241 | [ FILTER_OP_LOAD_STRING ] = &&LABEL_FILTER_OP_LOAD_STRING, | |
242 | [ FILTER_OP_LOAD_S64 ] = &&LABEL_FILTER_OP_LOAD_S64, | |
243 | [ FILTER_OP_LOAD_DOUBLE ] = &&LABEL_FILTER_OP_LOAD_DOUBLE, | |
244 | ||
245 | /* cast */ | |
246 | [ FILTER_OP_CAST_TO_S64 ] = &&LABEL_FILTER_OP_CAST_TO_S64, | |
247 | [ FILTER_OP_CAST_DOUBLE_TO_S64 ] = &&LABEL_FILTER_OP_CAST_DOUBLE_TO_S64, | |
248 | [ FILTER_OP_CAST_NOP ] = &&LABEL_FILTER_OP_CAST_NOP, | |
249 | }; | |
250 | #endif /* #ifndef INTERPRETER_USE_SWITCH */ | |
251 | ||
0305960f MD |
252 | estack_init(stack); |
253 | ||
97b58163 MD |
254 | START_OP |
255 | ||
256 | OP(FILTER_OP_UNKNOWN): | |
257 | OP(FILTER_OP_LOAD_FIELD_REF): | |
258 | #ifdef INTERPRETER_USE_SWITCH | |
259 | default: | |
260 | #endif /* INTERPRETER_USE_SWITCH */ | |
261 | ERR("unknown bytecode op %u\n", | |
262 | (unsigned int) *(filter_opcode_t *) pc); | |
263 | ret = -EINVAL; | |
264 | goto end; | |
265 | ||
266 | OP(FILTER_OP_RETURN): | |
0305960f | 267 | retval = !!estack_ax(stack)->u.v; |
97b58163 MD |
268 | ret = 0; |
269 | goto end; | |
270 | ||
271 | /* binary */ | |
272 | OP(FILTER_OP_MUL): | |
273 | OP(FILTER_OP_DIV): | |
274 | OP(FILTER_OP_MOD): | |
275 | OP(FILTER_OP_PLUS): | |
276 | OP(FILTER_OP_MINUS): | |
277 | OP(FILTER_OP_RSHIFT): | |
278 | OP(FILTER_OP_LSHIFT): | |
279 | OP(FILTER_OP_BIN_AND): | |
280 | OP(FILTER_OP_BIN_OR): | |
281 | OP(FILTER_OP_BIN_XOR): | |
282 | ERR("unsupported bytecode op %u\n", | |
283 | (unsigned int) *(filter_opcode_t *) pc); | |
284 | ret = -EINVAL; | |
285 | goto end; | |
286 | ||
287 | OP(FILTER_OP_EQ): | |
288 | OP(FILTER_OP_NE): | |
289 | OP(FILTER_OP_GT): | |
290 | OP(FILTER_OP_LT): | |
291 | OP(FILTER_OP_GE): | |
292 | OP(FILTER_OP_LE): | |
293 | ERR("unsupported non-specialized bytecode op %u\n", | |
294 | (unsigned int) *(filter_opcode_t *) pc); | |
295 | ret = -EINVAL; | |
296 | goto end; | |
297 | ||
298 | OP(FILTER_OP_EQ_STRING): | |
299 | { | |
0305960f MD |
300 | int res; |
301 | ||
302 | res = (stack_strcmp(stack, "==") == 0); | |
303 | estack_pop(stack); | |
304 | estack_ax(stack)->u.v = res; | |
305 | estack_ax(stack)->type = REG_S64; | |
97b58163 MD |
306 | next_pc += sizeof(struct binary_op); |
307 | PO; | |
308 | } | |
309 | OP(FILTER_OP_NE_STRING): | |
310 | { | |
0305960f MD |
311 | int res; |
312 | ||
313 | res = (stack_strcmp(stack, "!=") != 0); | |
314 | estack_pop(stack); | |
315 | estack_ax(stack)->u.v = res; | |
316 | estack_ax(stack)->type = REG_S64; | |
97b58163 MD |
317 | next_pc += sizeof(struct binary_op); |
318 | PO; | |
319 | } | |
320 | OP(FILTER_OP_GT_STRING): | |
321 | { | |
0305960f MD |
322 | int res; |
323 | ||
324 | res = (stack_strcmp(stack, ">") > 0); | |
325 | estack_pop(stack); | |
326 | estack_ax(stack)->u.v = res; | |
327 | estack_ax(stack)->type = REG_S64; | |
97b58163 MD |
328 | next_pc += sizeof(struct binary_op); |
329 | PO; | |
330 | } | |
331 | OP(FILTER_OP_LT_STRING): | |
332 | { | |
0305960f MD |
333 | int res; |
334 | ||
335 | res = (stack_strcmp(stack, "<") < 0); | |
336 | estack_pop(stack); | |
337 | estack_ax(stack)->u.v = res; | |
338 | estack_ax(stack)->type = REG_S64; | |
97b58163 MD |
339 | next_pc += sizeof(struct binary_op); |
340 | PO; | |
341 | } | |
342 | OP(FILTER_OP_GE_STRING): | |
343 | { | |
0305960f MD |
344 | int res; |
345 | ||
346 | res = (stack_strcmp(stack, ">=") >= 0); | |
347 | estack_pop(stack); | |
348 | estack_ax(stack)->u.v = res; | |
349 | estack_ax(stack)->type = REG_S64; | |
97b58163 MD |
350 | next_pc += sizeof(struct binary_op); |
351 | PO; | |
352 | } | |
353 | OP(FILTER_OP_LE_STRING): | |
354 | { | |
0305960f MD |
355 | int res; |
356 | ||
357 | res = (stack_strcmp(stack, "<=") <= 0); | |
358 | estack_pop(stack); | |
359 | estack_ax(stack)->u.v = res; | |
360 | estack_ax(stack)->type = REG_S64; | |
97b58163 MD |
361 | next_pc += sizeof(struct binary_op); |
362 | PO; | |
363 | } | |
364 | ||
365 | OP(FILTER_OP_EQ_S64): | |
366 | { | |
0305960f MD |
367 | int res; |
368 | ||
369 | res = (estack_bx(stack)->u.v == estack_ax(stack)->u.v); | |
370 | estack_pop(stack); | |
371 | estack_ax(stack)->u.v = res; | |
372 | estack_ax(stack)->type = REG_S64; | |
97b58163 MD |
373 | next_pc += sizeof(struct binary_op); |
374 | PO; | |
375 | } | |
376 | OP(FILTER_OP_NE_S64): | |
377 | { | |
0305960f MD |
378 | int res; |
379 | ||
380 | res = (estack_bx(stack)->u.v != estack_ax(stack)->u.v); | |
381 | estack_pop(stack); | |
382 | estack_ax(stack)->u.v = res; | |
383 | estack_ax(stack)->type = REG_S64; | |
97b58163 MD |
384 | next_pc += sizeof(struct binary_op); |
385 | PO; | |
386 | } | |
387 | OP(FILTER_OP_GT_S64): | |
388 | { | |
0305960f MD |
389 | int res; |
390 | ||
391 | res = (estack_bx(stack)->u.v > estack_ax(stack)->u.v); | |
392 | estack_pop(stack); | |
393 | estack_ax(stack)->u.v = res; | |
394 | estack_ax(stack)->type = REG_S64; | |
97b58163 MD |
395 | next_pc += sizeof(struct binary_op); |
396 | PO; | |
397 | } | |
398 | OP(FILTER_OP_LT_S64): | |
399 | { | |
0305960f MD |
400 | int res; |
401 | ||
402 | res = (estack_bx(stack)->u.v < estack_ax(stack)->u.v); | |
403 | estack_pop(stack); | |
404 | estack_ax(stack)->u.v = res; | |
405 | estack_ax(stack)->type = REG_S64; | |
97b58163 MD |
406 | next_pc += sizeof(struct binary_op); |
407 | PO; | |
408 | } | |
409 | OP(FILTER_OP_GE_S64): | |
410 | { | |
0305960f MD |
411 | int res; |
412 | ||
413 | res = (estack_bx(stack)->u.v >= estack_ax(stack)->u.v); | |
414 | estack_pop(stack); | |
415 | estack_ax(stack)->u.v = res; | |
416 | estack_ax(stack)->type = REG_S64; | |
97b58163 MD |
417 | next_pc += sizeof(struct binary_op); |
418 | PO; | |
419 | } | |
420 | OP(FILTER_OP_LE_S64): | |
421 | { | |
0305960f MD |
422 | int res; |
423 | ||
424 | res = (estack_bx(stack)->u.v <= estack_ax(stack)->u.v); | |
425 | estack_pop(stack); | |
426 | estack_ax(stack)->u.v = res; | |
427 | estack_ax(stack)->type = REG_S64; | |
97b58163 MD |
428 | next_pc += sizeof(struct binary_op); |
429 | PO; | |
430 | } | |
431 | ||
432 | OP(FILTER_OP_EQ_DOUBLE): | |
433 | { | |
0305960f MD |
434 | int res; |
435 | ||
436 | if (unlikely(estack_ax(stack)->type == REG_S64)) | |
437 | estack_ax(stack)->u.d = (double) estack_ax(stack)->u.v; | |
438 | else if (unlikely(estack_bx(stack)->type == REG_S64)) | |
439 | estack_bx(stack)->u.d = (double) estack_bx(stack)->u.v; | |
440 | res = (estack_bx(stack)->u.v == estack_ax(stack)->u.v); | |
441 | estack_pop(stack); | |
442 | estack_ax(stack)->u.v = res; | |
443 | estack_ax(stack)->type = REG_S64; | |
97b58163 MD |
444 | next_pc += sizeof(struct binary_op); |
445 | PO; | |
446 | } | |
447 | OP(FILTER_OP_NE_DOUBLE): | |
448 | { | |
0305960f MD |
449 | int res; |
450 | ||
451 | if (unlikely(estack_ax(stack)->type == REG_S64)) | |
452 | estack_ax(stack)->u.d = (double) estack_ax(stack)->u.v; | |
453 | else if (unlikely(estack_bx(stack)->type == REG_S64)) | |
454 | estack_bx(stack)->u.d = (double) estack_bx(stack)->u.v; | |
455 | res = (estack_bx(stack)->u.v != estack_ax(stack)->u.v); | |
456 | estack_pop(stack); | |
457 | estack_ax(stack)->u.v = res; | |
458 | estack_ax(stack)->type = REG_S64; | |
97b58163 MD |
459 | next_pc += sizeof(struct binary_op); |
460 | PO; | |
461 | } | |
462 | OP(FILTER_OP_GT_DOUBLE): | |
463 | { | |
0305960f MD |
464 | int res; |
465 | ||
466 | if (unlikely(estack_ax(stack)->type == REG_S64)) | |
467 | estack_ax(stack)->u.d = (double) estack_ax(stack)->u.v; | |
468 | else if (unlikely(estack_bx(stack)->type == REG_S64)) | |
469 | estack_bx(stack)->u.d = (double) estack_bx(stack)->u.v; | |
470 | res = (estack_bx(stack)->u.v > estack_ax(stack)->u.v); | |
471 | estack_pop(stack); | |
472 | estack_ax(stack)->u.v = res; | |
473 | estack_ax(stack)->type = REG_S64; | |
97b58163 MD |
474 | next_pc += sizeof(struct binary_op); |
475 | PO; | |
476 | } | |
477 | OP(FILTER_OP_LT_DOUBLE): | |
478 | { | |
0305960f MD |
479 | int res; |
480 | ||
481 | if (unlikely(estack_ax(stack)->type == REG_S64)) | |
482 | estack_ax(stack)->u.d = (double) estack_ax(stack)->u.v; | |
483 | else if (unlikely(estack_bx(stack)->type == REG_S64)) | |
484 | estack_bx(stack)->u.d = (double) estack_bx(stack)->u.v; | |
485 | res = (estack_bx(stack)->u.v < estack_ax(stack)->u.v); | |
486 | estack_pop(stack); | |
487 | estack_ax(stack)->u.v = res; | |
488 | estack_ax(stack)->type = REG_S64; | |
97b58163 MD |
489 | next_pc += sizeof(struct binary_op); |
490 | PO; | |
491 | } | |
492 | OP(FILTER_OP_GE_DOUBLE): | |
493 | { | |
0305960f MD |
494 | int res; |
495 | ||
496 | if (unlikely(estack_ax(stack)->type == REG_S64)) | |
497 | estack_ax(stack)->u.d = (double) estack_ax(stack)->u.v; | |
498 | else if (unlikely(estack_bx(stack)->type == REG_S64)) | |
499 | estack_bx(stack)->u.d = (double) estack_bx(stack)->u.v; | |
500 | res = (estack_bx(stack)->u.v >= estack_ax(stack)->u.v); | |
501 | estack_pop(stack); | |
502 | estack_ax(stack)->u.v = res; | |
503 | estack_ax(stack)->type = REG_S64; | |
97b58163 MD |
504 | next_pc += sizeof(struct binary_op); |
505 | PO; | |
506 | } | |
507 | OP(FILTER_OP_LE_DOUBLE): | |
508 | { | |
0305960f MD |
509 | int res; |
510 | ||
511 | if (unlikely(estack_ax(stack)->type == REG_S64)) | |
512 | estack_ax(stack)->u.d = (double) estack_ax(stack)->u.v; | |
513 | else if (unlikely(estack_bx(stack)->type == REG_S64)) | |
514 | estack_bx(stack)->u.d = (double) estack_bx(stack)->u.v; | |
515 | res = (estack_bx(stack)->u.v <= estack_ax(stack)->u.v); | |
516 | estack_pop(stack); | |
517 | estack_ax(stack)->u.v = res; | |
518 | estack_ax(stack)->type = REG_S64; | |
97b58163 MD |
519 | next_pc += sizeof(struct binary_op); |
520 | PO; | |
521 | } | |
522 | ||
523 | /* unary */ | |
524 | OP(FILTER_OP_UNARY_PLUS): | |
525 | OP(FILTER_OP_UNARY_MINUS): | |
526 | OP(FILTER_OP_UNARY_NOT): | |
527 | ERR("unsupported non-specialized bytecode op %u\n", | |
528 | (unsigned int) *(filter_opcode_t *) pc); | |
529 | ret = -EINVAL; | |
530 | goto end; | |
531 | ||
532 | ||
533 | OP(FILTER_OP_UNARY_PLUS_S64): | |
534 | OP(FILTER_OP_UNARY_PLUS_DOUBLE): | |
535 | { | |
536 | next_pc += sizeof(struct unary_op); | |
537 | PO; | |
538 | } | |
539 | OP(FILTER_OP_UNARY_MINUS_S64): | |
540 | { | |
0305960f | 541 | estack_ax(stack)->u.v = -estack_ax(stack)->u.v; |
97b58163 MD |
542 | next_pc += sizeof(struct unary_op); |
543 | PO; | |
544 | } | |
545 | OP(FILTER_OP_UNARY_MINUS_DOUBLE): | |
546 | { | |
0305960f | 547 | estack_ax(stack)->u.d = -estack_ax(stack)->u.d; |
97b58163 MD |
548 | next_pc += sizeof(struct unary_op); |
549 | PO; | |
550 | } | |
551 | OP(FILTER_OP_UNARY_NOT_S64): | |
552 | { | |
0305960f | 553 | estack_ax(stack)->u.v = !estack_ax(stack)->u.v; |
97b58163 MD |
554 | next_pc += sizeof(struct unary_op); |
555 | PO; | |
556 | } | |
557 | OP(FILTER_OP_UNARY_NOT_DOUBLE): | |
558 | { | |
0305960f | 559 | estack_ax(stack)->u.d = !estack_ax(stack)->u.d; |
97b58163 MD |
560 | next_pc += sizeof(struct unary_op); |
561 | PO; | |
562 | } | |
563 | ||
564 | /* logical */ | |
565 | OP(FILTER_OP_AND): | |
566 | { | |
567 | struct logical_op *insn = (struct logical_op *) pc; | |
568 | ||
0305960f MD |
569 | /* If AX is 0, skip and evaluate to 0 */ |
570 | if (unlikely(estack_ax(stack)->u.v == 0)) { | |
97b58163 MD |
571 | dbg_printf("Jumping to bytecode offset %u\n", |
572 | (unsigned int) insn->skip_offset); | |
573 | next_pc = start_pc + insn->skip_offset; | |
574 | } else { | |
71c1ceeb MD |
575 | /* Pop 1 when jump not taken */ |
576 | estack_pop(stack); | |
97b58163 MD |
577 | next_pc += sizeof(struct logical_op); |
578 | } | |
579 | PO; | |
580 | } | |
581 | OP(FILTER_OP_OR): | |
582 | { | |
583 | struct logical_op *insn = (struct logical_op *) pc; | |
584 | ||
0305960f | 585 | /* If AX is nonzero, skip and evaluate to 1 */ |
97b58163 | 586 | |
0305960f MD |
587 | if (unlikely(estack_ax(stack)->u.v != 0)) { |
588 | estack_ax(stack)->u.v = 1; | |
97b58163 MD |
589 | dbg_printf("Jumping to bytecode offset %u\n", |
590 | (unsigned int) insn->skip_offset); | |
591 | next_pc = start_pc + insn->skip_offset; | |
592 | } else { | |
71c1ceeb MD |
593 | /* Pop 1 when jump not taken */ |
594 | estack_pop(stack); | |
97b58163 MD |
595 | next_pc += sizeof(struct logical_op); |
596 | } | |
597 | PO; | |
598 | } | |
599 | ||
600 | ||
601 | /* load */ | |
602 | OP(FILTER_OP_LOAD_FIELD_REF_STRING): | |
603 | { | |
604 | struct load_op *insn = (struct load_op *) pc; | |
605 | struct field_ref *ref = (struct field_ref *) insn->data; | |
606 | ||
607 | dbg_printf("load field ref offset %u type string\n", | |
608 | ref->offset); | |
0305960f MD |
609 | estack_push(stack); |
610 | estack_ax(stack)->u.s.str = | |
97b58163 | 611 | *(const char * const *) &filter_stack_data[ref->offset]; |
0305960f | 612 | if (unlikely(!estack_ax(stack)->u.s.str)) { |
97b58163 MD |
613 | dbg_printf("Filter warning: loading a NULL string.\n"); |
614 | ret = -EINVAL; | |
615 | goto end; | |
616 | } | |
0305960f MD |
617 | estack_ax(stack)->type = REG_STRING; |
618 | estack_ax(stack)->u.s.seq_len = UINT_MAX; | |
619 | estack_ax(stack)->u.s.literal = 0; | |
620 | dbg_printf("ref load string %s\n", estack_ax(stack)->u.s.str); | |
97b58163 MD |
621 | next_pc += sizeof(struct load_op) + sizeof(struct field_ref); |
622 | PO; | |
623 | } | |
624 | ||
625 | OP(FILTER_OP_LOAD_FIELD_REF_SEQUENCE): | |
626 | { | |
627 | struct load_op *insn = (struct load_op *) pc; | |
628 | struct field_ref *ref = (struct field_ref *) insn->data; | |
629 | ||
630 | dbg_printf("load field ref offset %u type sequence\n", | |
631 | ref->offset); | |
0305960f MD |
632 | estack_push(stack); |
633 | estack_ax(stack)->u.s.seq_len = | |
97b58163 | 634 | *(unsigned long *) &filter_stack_data[ref->offset]; |
0305960f | 635 | estack_ax(stack)->u.s.str = |
97b58163 MD |
636 | *(const char **) (&filter_stack_data[ref->offset |
637 | + sizeof(unsigned long)]); | |
0305960f | 638 | if (unlikely(!estack_ax(stack)->u.s.str)) { |
97b58163 MD |
639 | dbg_printf("Filter warning: loading a NULL sequence.\n"); |
640 | ret = -EINVAL; | |
641 | goto end; | |
642 | } | |
0305960f MD |
643 | estack_ax(stack)->type = REG_STRING; |
644 | estack_ax(stack)->u.s.literal = 0; | |
97b58163 MD |
645 | next_pc += sizeof(struct load_op) + sizeof(struct field_ref); |
646 | PO; | |
647 | } | |
648 | ||
649 | OP(FILTER_OP_LOAD_FIELD_REF_S64): | |
650 | { | |
651 | struct load_op *insn = (struct load_op *) pc; | |
652 | struct field_ref *ref = (struct field_ref *) insn->data; | |
653 | ||
654 | dbg_printf("load field ref offset %u type s64\n", | |
655 | ref->offset); | |
0305960f MD |
656 | estack_push(stack); |
657 | memcpy(&estack_ax(stack)->u.v, &filter_stack_data[ref->offset], | |
97b58163 | 658 | sizeof(struct literal_numeric)); |
0305960f MD |
659 | estack_ax(stack)->type = REG_S64; |
660 | dbg_printf("ref load s64 %" PRIi64 "\n", estack_ax(stack)->u.v); | |
97b58163 MD |
661 | next_pc += sizeof(struct load_op) + sizeof(struct field_ref); |
662 | PO; | |
663 | } | |
664 | ||
665 | OP(FILTER_OP_LOAD_FIELD_REF_DOUBLE): | |
666 | { | |
667 | struct load_op *insn = (struct load_op *) pc; | |
668 | struct field_ref *ref = (struct field_ref *) insn->data; | |
669 | ||
670 | dbg_printf("load field ref offset %u type double\n", | |
671 | ref->offset); | |
0305960f MD |
672 | estack_push(stack); |
673 | memcpy(&estack_ax(stack)->u.d, &filter_stack_data[ref->offset], | |
97b58163 | 674 | sizeof(struct literal_double)); |
0305960f MD |
675 | estack_ax(stack)->type = REG_DOUBLE; |
676 | dbg_printf("ref load double %g\n", estack_ax(stack)->u.d); | |
97b58163 MD |
677 | next_pc += sizeof(struct load_op) + sizeof(struct field_ref); |
678 | PO; | |
679 | } | |
680 | ||
681 | OP(FILTER_OP_LOAD_STRING): | |
682 | { | |
683 | struct load_op *insn = (struct load_op *) pc; | |
684 | ||
685 | dbg_printf("load string %s\n", insn->data); | |
0305960f MD |
686 | estack_push(stack); |
687 | estack_ax(stack)->type = REG_STRING; | |
688 | estack_ax(stack)->u.s.str = insn->data; | |
689 | estack_ax(stack)->u.s.seq_len = UINT_MAX; | |
690 | estack_ax(stack)->u.s.literal = 1; | |
97b58163 MD |
691 | next_pc += sizeof(struct load_op) + strlen(insn->data) + 1; |
692 | PO; | |
693 | } | |
694 | ||
695 | OP(FILTER_OP_LOAD_S64): | |
696 | { | |
697 | struct load_op *insn = (struct load_op *) pc; | |
698 | ||
0305960f MD |
699 | estack_push(stack); |
700 | memcpy(&estack_ax(stack)->u.v, insn->data, | |
97b58163 | 701 | sizeof(struct literal_numeric)); |
0305960f MD |
702 | dbg_printf("load s64 %" PRIi64 "\n", estack_ax(stack)->u.v); |
703 | estack_ax(stack)->type = REG_S64; | |
97b58163 MD |
704 | next_pc += sizeof(struct load_op) |
705 | + sizeof(struct literal_numeric); | |
706 | PO; | |
707 | } | |
708 | ||
709 | OP(FILTER_OP_LOAD_DOUBLE): | |
710 | { | |
711 | struct load_op *insn = (struct load_op *) pc; | |
712 | ||
0305960f MD |
713 | estack_push(stack); |
714 | memcpy(&estack_ax(stack)->u.d, insn->data, | |
97b58163 | 715 | sizeof(struct literal_double)); |
0305960f MD |
716 | dbg_printf("load s64 %g\n", estack_ax(stack)->u.d); |
717 | estack_ax(stack)->type = REG_DOUBLE; | |
97b58163 MD |
718 | next_pc += sizeof(struct load_op) |
719 | + sizeof(struct literal_double); | |
720 | PO; | |
721 | } | |
722 | ||
723 | /* cast */ | |
724 | OP(FILTER_OP_CAST_TO_S64): | |
725 | ERR("unsupported non-specialized bytecode op %u\n", | |
726 | (unsigned int) *(filter_opcode_t *) pc); | |
727 | ret = -EINVAL; | |
728 | goto end; | |
729 | ||
730 | OP(FILTER_OP_CAST_DOUBLE_TO_S64): | |
731 | { | |
0305960f MD |
732 | estack_ax(stack)->u.v = (int64_t) estack_ax(stack)->u.d; |
733 | estack_ax(stack)->type = REG_S64; | |
97b58163 MD |
734 | next_pc += sizeof(struct cast_op); |
735 | PO; | |
736 | } | |
737 | ||
738 | OP(FILTER_OP_CAST_NOP): | |
739 | { | |
740 | next_pc += sizeof(struct cast_op); | |
741 | PO; | |
742 | } | |
743 | ||
744 | END_OP | |
745 | end: | |
746 | /* return 0 (discard) on error */ | |
747 | if (ret) | |
748 | return 0; | |
749 | return retval; | |
750 | } | |
751 | ||
752 | #undef START_OP | |
753 | #undef OP | |
754 | #undef PO | |
755 | #undef END_OP |