SoW-2020-0002: Trace Hit Counters: trigger error reporting integration
[lttng-tools.git] / src / common / filter / filter-visitor-generate-bytecode.c
... / ...
CommitLineData
1/*
2 * filter-visitor-generate-bytecode.c
3 *
4 * LTTng filter bytecode generation
5 *
6 * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
7 *
8 * SPDX-License-Identifier: LGPL-2.1-only
9 *
10 */
11
12#include <stdlib.h>
13#include <string.h>
14#include <errno.h>
15
16#include "common/align.h"
17#include "common/bytecode/bytecode.h"
18#include "common/compat/string.h"
19#include "common/macros.h"
20#include "filter-ast.h"
21#include "filter-ir.h"
22
23#ifndef max_t
24#define max_t(type, a, b) ((type) ((a) > (b) ? (a) : (b)))
25#endif
26
27static
28int recursive_visit_gen_bytecode(struct filter_parser_ctx *ctx,
29 struct ir_op *node);
30
31static
32int bytecode_patch(struct lttng_bytecode_alloc **fb,
33 const void *data,
34 uint16_t offset,
35 uint32_t len)
36{
37 if (offset >= (*fb)->b.len) {
38 return -EINVAL;
39 }
40 memcpy(&(*fb)->b.data[offset], data, len);
41 return 0;
42}
43
44static
45int visit_node_root(struct filter_parser_ctx *ctx, struct ir_op *node)
46{
47 int ret;
48 struct return_op insn;
49
50 /* Visit child */
51 ret = recursive_visit_gen_bytecode(ctx, node->u.root.child);
52 if (ret)
53 return ret;
54
55 /* Generate end of bytecode instruction */
56 insn.op = BYTECODE_OP_RETURN;
57 return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn));
58}
59
60static
61int append_str(char **s, const char *append)
62{
63 char *old = *s;
64 char *new;
65 size_t oldlen = (old == NULL) ? 0 : strlen(old);
66 size_t appendlen = strlen(append);
67
68 new = calloc(oldlen + appendlen + 1, 1);
69 if (!new) {
70 return -ENOMEM;
71 }
72 if (oldlen) {
73 strcpy(new, old);
74 }
75 strcat(new, append);
76 *s = new;
77 free(old);
78 return 0;
79}
80
81/*
82 * 1: match
83 * 0: no match
84 * < 0: error
85 */
86static
87int load_expression_legacy_match(const struct ir_load_expression *exp,
88 enum bytecode_op *op_type,
89 char **symbol)
90{
91 const struct ir_load_expression_op *op;
92 bool need_dot = false;
93
94 op = exp->child;
95 switch (op->type) {
96 case IR_LOAD_EXPRESSION_GET_CONTEXT_ROOT:
97 *op_type = BYTECODE_OP_GET_CONTEXT_REF;
98 if (append_str(symbol, "$ctx.")) {
99 return -ENOMEM;
100 }
101 need_dot = false;
102 break;
103 case IR_LOAD_EXPRESSION_GET_APP_CONTEXT_ROOT:
104 *op_type = BYTECODE_OP_GET_CONTEXT_REF;
105 if (append_str(symbol, "$app.")) {
106 return -ENOMEM;
107 }
108 need_dot = false;
109 break;
110 case IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT:
111 *op_type = BYTECODE_OP_LOAD_FIELD_REF;
112 need_dot = false;
113 break;
114
115 case IR_LOAD_EXPRESSION_GET_SYMBOL:
116 case IR_LOAD_EXPRESSION_GET_INDEX:
117 case IR_LOAD_EXPRESSION_LOAD_FIELD:
118 default:
119 return 0; /* no match */
120 }
121
122 for (;;) {
123 op = op->next;
124 if (!op) {
125 return 0; /* no match */
126 }
127 switch (op->type) {
128 case IR_LOAD_EXPRESSION_LOAD_FIELD:
129 goto end;
130 case IR_LOAD_EXPRESSION_GET_SYMBOL:
131 if (need_dot && append_str(symbol, ".")) {
132 return -ENOMEM;
133 }
134 if (append_str(symbol, op->u.symbol)) {
135 return -ENOMEM;
136 }
137 break;
138 default:
139 return 0; /* no match */
140 }
141 need_dot = true;
142 }
143end:
144 return 1; /* Legacy match */
145}
146
147/*
148 * 1: legacy match
149 * 0: no legacy match
150 * < 0: error
151 */
152static
153int visit_node_load_expression_legacy(struct filter_parser_ctx *ctx,
154 const struct ir_load_expression *exp,
155 const struct ir_load_expression_op *op)
156{
157 struct load_op *insn = NULL;
158 uint32_t insn_len = sizeof(struct load_op)
159 + sizeof(struct field_ref);
160 struct field_ref ref_offset;
161 uint32_t reloc_offset_u32;
162 uint16_t reloc_offset;
163 enum bytecode_op op_type;
164 char *symbol = NULL;
165 int ret;
166
167 ret = load_expression_legacy_match(exp, &op_type, &symbol);
168 if (ret <= 0) {
169 goto end;
170 }
171 insn = calloc(insn_len, 1);
172 if (!insn) {
173 ret = -ENOMEM;
174 goto end;
175 }
176 insn->op = op_type;
177 ref_offset.offset = (uint16_t) -1U;
178 memcpy(insn->data, &ref_offset, sizeof(ref_offset));
179 /* reloc_offset points to struct load_op */
180 reloc_offset_u32 = bytecode_get_len(&ctx->bytecode->b);
181 if (reloc_offset_u32 > LTTNG_FILTER_MAX_LEN - 1) {
182 ret = -EINVAL;
183 goto end;
184 }
185 reloc_offset = (uint16_t) reloc_offset_u32;
186 ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
187 if (ret) {
188 goto end;
189 }
190 /* append reloc */
191 ret = bytecode_push(&ctx->bytecode_reloc, &reloc_offset,
192 1, sizeof(reloc_offset));
193 if (ret) {
194 goto end;
195 }
196 ret = bytecode_push(&ctx->bytecode_reloc, symbol,
197 1, strlen(symbol) + 1);
198 if (ret) {
199 goto end;
200 }
201 ret = 1; /* legacy */
202end:
203 free(insn);
204 free(symbol);
205 return ret;
206}
207
208static
209int visit_node_load_expression(struct filter_parser_ctx *ctx,
210 const struct ir_op *node)
211{
212 struct ir_load_expression *exp;
213 struct ir_load_expression_op *op;
214 int ret;
215
216 exp = node->u.load.u.expression;
217 if (!exp) {
218 return -EINVAL;
219 }
220 op = exp->child;
221 if (!op) {
222 return -EINVAL;
223 }
224
225 /*
226 * TODO: if we remove legacy load for application contexts, we
227 * need to update session bytecode parser as well.
228 */
229 ret = visit_node_load_expression_legacy(ctx, exp, op);
230 if (ret < 0) {
231 return ret;
232 }
233 if (ret > 0) {
234 return 0; /* legacy */
235 }
236
237 for (; op != NULL; op = op->next) {
238 switch (op->type) {
239 case IR_LOAD_EXPRESSION_GET_CONTEXT_ROOT:
240 {
241 int ret = bytecode_push_get_context_root(&ctx->bytecode);
242 if (ret) {
243 return ret;
244 }
245
246 break;
247 }
248 case IR_LOAD_EXPRESSION_GET_APP_CONTEXT_ROOT:
249 {
250 int ret = bytecode_push_get_app_context_root(&ctx->bytecode);
251 if (ret) {
252 return ret;
253 }
254
255 break;
256 }
257 case IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT:
258 {
259 int ret = bytecode_push_get_payload_root(&ctx->bytecode);
260 if (ret) {
261 return ret;
262 }
263
264 break;
265 }
266 case IR_LOAD_EXPRESSION_GET_SYMBOL:
267 {
268 int ret = bytecode_push_get_symbol(
269 &ctx->bytecode,
270 &ctx->bytecode_reloc,
271 op->u.symbol);
272 if (ret) {
273 return ret;
274 }
275 break;
276 }
277 case IR_LOAD_EXPRESSION_GET_INDEX:
278 {
279 int ret = bytecode_push_get_index_u64(&ctx->bytecode, op->u.index);
280 if (ret) {
281 return ret;
282 }
283 break;
284 }
285 case IR_LOAD_EXPRESSION_LOAD_FIELD:
286 {
287 struct load_op *insn;
288 uint32_t insn_len = sizeof(struct load_op);
289 int ret;
290
291 insn = calloc(insn_len, 1);
292 if (!insn)
293 return -ENOMEM;
294 insn->op = BYTECODE_OP_LOAD_FIELD;
295 ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
296 free(insn);
297 if (ret) {
298 return ret;
299 }
300 break;
301 }
302 }
303 }
304 return 0;
305}
306
307static
308int visit_node_load(struct filter_parser_ctx *ctx, struct ir_op *node)
309{
310 int ret;
311
312 switch (node->data_type) {
313 case IR_DATA_UNKNOWN:
314 default:
315 fprintf(stderr, "[error] Unknown data type in %s\n",
316 __func__);
317 return -EINVAL;
318
319 case IR_DATA_STRING:
320 {
321 struct load_op *insn;
322 uint32_t insn_len = sizeof(struct load_op)
323 + strlen(node->u.load.u.string.value) + 1;
324
325 insn = calloc(insn_len, 1);
326 if (!insn)
327 return -ENOMEM;
328
329 switch (node->u.load.u.string.type) {
330 case IR_LOAD_STRING_TYPE_GLOB_STAR:
331 /*
332 * We explicitly tell the interpreter here that
333 * this load is a full star globbing pattern so
334 * that the appropriate matching function can be
335 * called. Also, see comment below.
336 */
337 insn->op = BYTECODE_OP_LOAD_STAR_GLOB_STRING;
338 break;
339 default:
340 /*
341 * This is the "legacy" string, which includes
342 * star globbing patterns with a star only at
343 * the end. Both "plain" and "star at the end"
344 * literal strings are handled at the same place
345 * by the tracer's filter bytecode interpreter,
346 * whereas full star globbing patterns (stars
347 * can be anywhere in the string) is a special
348 * case.
349 */
350 insn->op = BYTECODE_OP_LOAD_STRING;
351 break;
352 }
353
354 strcpy(insn->data, node->u.load.u.string.value);
355 ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
356 free(insn);
357 return ret;
358 }
359 case IR_DATA_NUMERIC:
360 {
361 struct load_op *insn;
362 uint32_t insn_len = sizeof(struct load_op)
363 + sizeof(struct literal_numeric);
364
365 insn = calloc(insn_len, 1);
366 if (!insn)
367 return -ENOMEM;
368 insn->op = BYTECODE_OP_LOAD_S64;
369 memcpy(insn->data, &node->u.load.u.num, sizeof(int64_t));
370 ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
371 free(insn);
372 return ret;
373 }
374 case IR_DATA_FLOAT:
375 {
376 struct load_op *insn;
377 uint32_t insn_len = sizeof(struct load_op)
378 + sizeof(struct literal_double);
379
380 insn = calloc(insn_len, 1);
381 if (!insn)
382 return -ENOMEM;
383 insn->op = BYTECODE_OP_LOAD_DOUBLE;
384 memcpy(insn->data, &node->u.load.u.flt, sizeof(double));
385 ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
386 free(insn);
387 return ret;
388 }
389 case IR_DATA_EXPRESSION:
390 return visit_node_load_expression(ctx, node);
391 }
392}
393
394static
395int visit_node_unary(struct filter_parser_ctx *ctx, struct ir_op *node)
396{
397 int ret;
398 struct unary_op insn;
399
400 /* Visit child */
401 ret = recursive_visit_gen_bytecode(ctx, node->u.unary.child);
402 if (ret)
403 return ret;
404
405 /* Generate end of bytecode instruction */
406 switch (node->u.unary.type) {
407 case AST_UNARY_UNKNOWN:
408 default:
409 fprintf(stderr, "[error] Unknown unary node type in %s\n",
410 __func__);
411 return -EINVAL;
412 case AST_UNARY_PLUS:
413 /* Nothing to do. */
414 return 0;
415 case AST_UNARY_MINUS:
416 insn.op = BYTECODE_OP_UNARY_MINUS;
417 return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn));
418 case AST_UNARY_NOT:
419 insn.op = BYTECODE_OP_UNARY_NOT;
420 return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn));
421 case AST_UNARY_BIT_NOT:
422 insn.op = BYTECODE_OP_UNARY_BIT_NOT;
423 return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn));
424 }
425}
426
427/*
428 * Binary comparator nesting is disallowed. This allows fitting into
429 * only 2 registers.
430 */
431static
432int visit_node_binary(struct filter_parser_ctx *ctx, struct ir_op *node)
433{
434 int ret;
435 struct binary_op insn;
436
437 /* Visit child */
438 ret = recursive_visit_gen_bytecode(ctx, node->u.binary.left);
439 if (ret)
440 return ret;
441 ret = recursive_visit_gen_bytecode(ctx, node->u.binary.right);
442 if (ret)
443 return ret;
444
445 switch (node->u.binary.type) {
446 case AST_OP_UNKNOWN:
447 default:
448 fprintf(stderr, "[error] Unknown unary node type in %s\n",
449 __func__);
450 return -EINVAL;
451
452 case AST_OP_AND:
453 case AST_OP_OR:
454 fprintf(stderr, "[error] Unexpected logical node type in %s\n",
455 __func__);
456 return -EINVAL;
457
458 case AST_OP_MUL:
459 insn.op = BYTECODE_OP_MUL;
460 break;
461 case AST_OP_DIV:
462 insn.op = BYTECODE_OP_DIV;
463 break;
464 case AST_OP_MOD:
465 insn.op = BYTECODE_OP_MOD;
466 break;
467 case AST_OP_PLUS:
468 insn.op = BYTECODE_OP_PLUS;
469 break;
470 case AST_OP_MINUS:
471 insn.op = BYTECODE_OP_MINUS;
472 break;
473 case AST_OP_BIT_RSHIFT:
474 insn.op = BYTECODE_OP_BIT_RSHIFT;
475 break;
476 case AST_OP_BIT_LSHIFT:
477 insn.op = BYTECODE_OP_BIT_LSHIFT;
478 break;
479 case AST_OP_BIT_AND:
480 insn.op = BYTECODE_OP_BIT_AND;
481 break;
482 case AST_OP_BIT_OR:
483 insn.op = BYTECODE_OP_BIT_OR;
484 break;
485 case AST_OP_BIT_XOR:
486 insn.op = BYTECODE_OP_BIT_XOR;
487 break;
488
489 case AST_OP_EQ:
490 insn.op = BYTECODE_OP_EQ;
491 break;
492 case AST_OP_NE:
493 insn.op = BYTECODE_OP_NE;
494 break;
495 case AST_OP_GT:
496 insn.op = BYTECODE_OP_GT;
497 break;
498 case AST_OP_LT:
499 insn.op = BYTECODE_OP_LT;
500 break;
501 case AST_OP_GE:
502 insn.op = BYTECODE_OP_GE;
503 break;
504 case AST_OP_LE:
505 insn.op = BYTECODE_OP_LE;
506 break;
507 }
508 return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn));
509}
510
511/*
512 * A logical op always return a s64 (1 or 0).
513 */
514static
515int visit_node_logical(struct filter_parser_ctx *ctx, struct ir_op *node)
516{
517 int ret;
518 struct logical_op insn;
519 uint16_t skip_offset_loc;
520 uint16_t target_loc;
521
522 /* Visit left child */
523 ret = recursive_visit_gen_bytecode(ctx, node->u.binary.left);
524 if (ret)
525 return ret;
526 /* Cast to s64 if float or field ref */
527 if ((node->u.binary.left->data_type == IR_DATA_FIELD_REF
528 || node->u.binary.left->data_type == IR_DATA_GET_CONTEXT_REF
529 || node->u.binary.left->data_type == IR_DATA_EXPRESSION)
530 || node->u.binary.left->data_type == IR_DATA_FLOAT) {
531 struct cast_op cast_insn;
532
533 if (node->u.binary.left->data_type == IR_DATA_FIELD_REF
534 || node->u.binary.left->data_type == IR_DATA_GET_CONTEXT_REF
535 || node->u.binary.left->data_type == IR_DATA_EXPRESSION) {
536 cast_insn.op = BYTECODE_OP_CAST_TO_S64;
537 } else {
538 cast_insn.op = BYTECODE_OP_CAST_DOUBLE_TO_S64;
539 }
540 ret = bytecode_push(&ctx->bytecode, &cast_insn,
541 1, sizeof(cast_insn));
542 if (ret)
543 return ret;
544 }
545 switch (node->u.logical.type) {
546 default:
547 fprintf(stderr, "[error] Unknown node type in %s\n",
548 __func__);
549 return -EINVAL;
550
551 case AST_OP_AND:
552 insn.op = BYTECODE_OP_AND;
553 break;
554 case AST_OP_OR:
555 insn.op = BYTECODE_OP_OR;
556 break;
557 }
558 insn.skip_offset = (uint16_t) -1UL; /* Temporary */
559 ret = bytecode_push_logical(&ctx->bytecode, &insn, 1, sizeof(insn),
560 &skip_offset_loc);
561 if (ret)
562 return ret;
563 /* Visit right child */
564 ret = recursive_visit_gen_bytecode(ctx, node->u.binary.right);
565 if (ret)
566 return ret;
567 /* Cast to s64 if float or field ref */
568 if ((node->u.binary.right->data_type == IR_DATA_FIELD_REF
569 || node->u.binary.right->data_type == IR_DATA_GET_CONTEXT_REF
570 || node->u.binary.right->data_type == IR_DATA_EXPRESSION)
571 || node->u.binary.right->data_type == IR_DATA_FLOAT) {
572 struct cast_op cast_insn;
573
574 if (node->u.binary.right->data_type == IR_DATA_FIELD_REF
575 || node->u.binary.right->data_type == IR_DATA_GET_CONTEXT_REF
576 || node->u.binary.right->data_type == IR_DATA_EXPRESSION) {
577 cast_insn.op = BYTECODE_OP_CAST_TO_S64;
578 } else {
579 cast_insn.op = BYTECODE_OP_CAST_DOUBLE_TO_S64;
580 }
581 ret = bytecode_push(&ctx->bytecode, &cast_insn,
582 1, sizeof(cast_insn));
583 if (ret)
584 return ret;
585 }
586 /* We now know where the logical op can skip. */
587 target_loc = (uint16_t) bytecode_get_len(&ctx->bytecode->b);
588 ret = bytecode_patch(&ctx->bytecode,
589 &target_loc, /* Offset to jump to */
590 skip_offset_loc, /* Where to patch */
591 sizeof(uint16_t));
592 return ret;
593}
594
595/*
596 * Postorder traversal of the tree. We need the children result before
597 * we can evaluate the parent.
598 */
599static
600int recursive_visit_gen_bytecode(struct filter_parser_ctx *ctx,
601 struct ir_op *node)
602{
603 switch (node->op) {
604 case IR_OP_UNKNOWN:
605 default:
606 fprintf(stderr, "[error] Unknown node type in %s\n",
607 __func__);
608 return -EINVAL;
609
610 case IR_OP_ROOT:
611 return visit_node_root(ctx, node);
612 case IR_OP_LOAD:
613 return visit_node_load(ctx, node);
614 case IR_OP_UNARY:
615 return visit_node_unary(ctx, node);
616 case IR_OP_BINARY:
617 return visit_node_binary(ctx, node);
618 case IR_OP_LOGICAL:
619 return visit_node_logical(ctx, node);
620 }
621}
622
623LTTNG_HIDDEN
624void filter_bytecode_free(struct filter_parser_ctx *ctx)
625{
626 if (!ctx) {
627 return;
628 }
629
630 if (ctx->bytecode) {
631 free(ctx->bytecode);
632 ctx->bytecode = NULL;
633 }
634
635 if (ctx->bytecode_reloc) {
636 free(ctx->bytecode_reloc);
637 ctx->bytecode_reloc = NULL;
638 }
639}
640
641LTTNG_HIDDEN
642int filter_visitor_bytecode_generate(struct filter_parser_ctx *ctx)
643{
644 int ret;
645
646 ret = bytecode_init(&ctx->bytecode);
647 if (ret)
648 return ret;
649 ret = bytecode_init(&ctx->bytecode_reloc);
650 if (ret)
651 goto error;
652 ret = recursive_visit_gen_bytecode(ctx, ctx->ir_root);
653 if (ret)
654 goto error;
655
656 /* Finally, append symbol table to bytecode */
657 ctx->bytecode->b.reloc_table_offset = bytecode_get_len(&ctx->bytecode->b);
658 return bytecode_push(&ctx->bytecode, ctx->bytecode_reloc->b.data,
659 1, bytecode_get_len(&ctx->bytecode_reloc->b));
660
661error:
662 filter_bytecode_free(ctx);
663 return ret;
664}
This page took 0.025276 seconds and 5 git commands to generate.