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