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