Move event-expr-to-bytecode to event-expr
[lttng-tools.git] / src / common / event-expr / event-expr.c
1 /*
2 * event-expr.c
3 *
4 * Copyright (C) 2020 Philippe Proulx <pproulx@efficios.com>
5 *
6 * SPDX-License-Identifier: LGPL-2.1-only
7 *
8 */
9
10 #define _LGPL_SOURCE
11 #include <assert.h>
12 #include <stddef.h>
13
14 #include <common/bytecode/bytecode.h>
15 #include <common/error.h>
16 #include <common/macros.h>
17 #include <lttng/event-expr-internal.h>
18 #include <lttng/event-expr.h>
19 #include <stdio.h>
20
21 enum lttng_event_expr_type lttng_event_expr_get_type(
22 const struct lttng_event_expr *expr)
23 {
24 enum lttng_event_expr_type type;
25
26 if (!expr) {
27 type = LTTNG_EVENT_EXPR_TYPE_INVALID;
28 goto end;
29 }
30
31 type = expr->type;
32
33 end:
34 return type;
35 }
36
37 static
38 struct lttng_event_expr *create_empty_expr(enum lttng_event_expr_type type,
39 size_t size)
40 {
41 struct lttng_event_expr *expr;
42
43 expr = zmalloc(size);
44 if (!expr) {
45 goto end;
46 }
47
48 expr->type = type;
49
50 end:
51 return expr;
52 }
53
54 static
55 struct lttng_event_expr_field *create_field_event_expr(
56 enum lttng_event_expr_type type,
57 const char *name)
58 {
59 struct lttng_event_expr_field *expr =
60 container_of(
61 create_empty_expr(type, sizeof(*expr)),
62 struct lttng_event_expr_field, parent);
63
64 if (!expr) {
65 goto error;
66 }
67
68 assert(name);
69 expr->name = strdup(name);
70 if (!expr->name) {
71 goto error;
72 }
73
74 goto end;
75
76 error:
77 if (expr) {
78 lttng_event_expr_destroy(&expr->parent);
79 }
80 expr = NULL;
81
82 end:
83 return expr;
84 }
85
86 struct lttng_event_expr *lttng_event_expr_event_payload_field_create(
87 const char *field_name)
88 {
89 struct lttng_event_expr *expr = NULL;
90
91 if (!field_name) {
92 goto end;
93 }
94
95 expr = &create_field_event_expr(
96 LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD,
97 field_name)->parent;
98
99 end:
100 return expr;
101 }
102
103 struct lttng_event_expr *lttng_event_expr_channel_context_field_create(
104 const char *field_name)
105 {
106 struct lttng_event_expr *expr = NULL;
107
108 if (!field_name) {
109 goto end;
110 }
111
112 expr = &create_field_event_expr(
113 LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD,
114 field_name)->parent;
115
116 end:
117 return expr;
118 }
119
120 struct lttng_event_expr *lttng_event_expr_app_specific_context_field_create(
121 const char *provider_name, const char *type_name)
122 {
123 struct lttng_event_expr_app_specific_context_field *expr = NULL;
124 struct lttng_event_expr *ret_parent_expr;
125
126 if (!type_name || !provider_name) {
127 goto error;
128 }
129
130 expr = container_of(create_empty_expr(
131 LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD,
132 sizeof(*expr)),
133 struct lttng_event_expr_app_specific_context_field,
134 parent);
135 if (!expr) {
136 goto error;
137 }
138
139 expr->provider_name = strdup(provider_name);
140 if (!expr->provider_name) {
141 goto error;
142 }
143
144 expr->type_name = strdup(type_name);
145 if (!expr->type_name) {
146 goto error;
147 }
148
149 ret_parent_expr = &expr->parent;
150 goto end;
151
152 error:
153 if (expr) {
154 lttng_event_expr_destroy(&expr->parent);
155 }
156 ret_parent_expr = NULL;
157
158 end:
159 return ret_parent_expr;
160 }
161
162 struct lttng_event_expr *lttng_event_expr_array_field_element_create(
163 struct lttng_event_expr *array_field_expr,
164 unsigned int index)
165 {
166 struct lttng_event_expr_array_field_element *expr = NULL;
167 struct lttng_event_expr *ret_parent_expr;
168
169 /* The parent array field expression must be an l-value */
170 if (!array_field_expr ||
171 !lttng_event_expr_is_lvalue(array_field_expr)) {
172 goto error;
173 }
174
175 expr = container_of(create_empty_expr(
176 LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT,
177 sizeof(*expr)),
178 struct lttng_event_expr_array_field_element,
179 parent);
180 if (!expr) {
181 goto error;
182 }
183
184 expr->array_field_expr = array_field_expr;
185 expr->index = index;
186 ret_parent_expr = &expr->parent;
187 goto end;
188
189 error:
190 if (expr) {
191 lttng_event_expr_destroy(&expr->parent);
192 }
193 ret_parent_expr = NULL;
194
195 end:
196 return ret_parent_expr;
197 }
198
199 const char *lttng_event_expr_event_payload_field_get_name(
200 const struct lttng_event_expr *expr)
201 {
202 const char *ret = NULL;
203
204 if (!expr || expr->type != LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD) {
205 goto end;
206 }
207
208 ret = container_of(expr,
209 const struct lttng_event_expr_field, parent)->name;
210
211 end:
212 return ret;
213 }
214
215 const char *lttng_event_expr_channel_context_field_get_name(
216 const struct lttng_event_expr *expr)
217 {
218 const char *ret = NULL;
219
220 if (!expr || expr->type != LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD) {
221 goto end;
222 }
223
224 ret = container_of(expr,
225 const struct lttng_event_expr_field, parent)->name;
226
227 end:
228 return ret;
229 }
230
231 const char *lttng_event_expr_app_specific_context_field_get_provider_name(
232 const struct lttng_event_expr *expr)
233 {
234 const char *ret = NULL;
235
236 if (!expr || expr->type != LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD) {
237 goto end;
238 }
239
240 ret = container_of(expr,
241 const struct lttng_event_expr_app_specific_context_field,
242 parent)->provider_name;
243
244 end:
245 return ret;
246 }
247
248 const char *lttng_event_expr_app_specific_context_field_get_type_name(
249 const struct lttng_event_expr *expr)
250 {
251 const char *ret = NULL;
252
253 if (!expr || expr->type != LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD) {
254 goto end;
255 }
256
257 ret = container_of(expr,
258 const struct lttng_event_expr_app_specific_context_field,
259 parent)->type_name;
260
261 end:
262 return ret;
263 }
264
265 const struct lttng_event_expr *
266 lttng_event_expr_array_field_element_get_parent_expr(
267 const struct lttng_event_expr *expr)
268 {
269 const struct lttng_event_expr *ret = NULL;
270
271 if (!expr || expr->type != LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT) {
272 goto end;
273 }
274
275 ret = container_of(expr,
276 const struct lttng_event_expr_array_field_element,
277 parent)->array_field_expr;
278
279 end:
280 return ret;
281 }
282
283 enum lttng_event_expr_status lttng_event_expr_array_field_element_get_index(
284 const struct lttng_event_expr *expr, unsigned int *index)
285 {
286 enum lttng_event_expr_status ret = LTTNG_EVENT_EXPR_STATUS_OK;
287
288 if (!expr || expr->type != LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT ||
289 !index) {
290 ret = LTTNG_EVENT_EXPR_STATUS_INVALID;
291 goto end;
292 }
293
294 *index = container_of(expr,
295 const struct lttng_event_expr_array_field_element,
296 parent)->index;
297
298 end:
299 return ret;
300 }
301
302 bool lttng_event_expr_is_equal(const struct lttng_event_expr *expr_a,
303 const struct lttng_event_expr *expr_b)
304 {
305 bool is_equal = true;
306
307 if (!expr_a && !expr_b) {
308 /* Both `NULL`: equal */
309 goto end;
310 }
311
312 if (!expr_a || !expr_b) {
313 /* Only one `NULL`: not equal */
314 goto not_equal;
315 }
316
317 if (expr_a->type != expr_b->type) {
318 /* Different types: not equal */
319 goto not_equal;
320 }
321
322 switch (expr_a->type) {
323 case LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD:
324 case LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD:
325 {
326 const struct lttng_event_expr_field *field_expr_a =
327 container_of(expr_a,
328 const struct lttng_event_expr_field,
329 parent);
330 const struct lttng_event_expr_field *field_expr_b =
331 container_of(expr_b,
332 const struct lttng_event_expr_field,
333 parent);
334
335 if (strcmp(field_expr_a->name, field_expr_b->name) != 0) {
336 goto not_equal;
337 }
338
339 break;
340 }
341 case LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD:
342 {
343 const struct lttng_event_expr_app_specific_context_field *field_expr_a =
344 container_of(expr_a,
345 const struct lttng_event_expr_app_specific_context_field,
346 parent);
347 const struct lttng_event_expr_app_specific_context_field *field_expr_b =
348 container_of(expr_b,
349 const struct lttng_event_expr_app_specific_context_field,
350 parent);
351
352 if (strcmp(field_expr_a->provider_name,
353 field_expr_b->provider_name) != 0) {
354 goto not_equal;
355 }
356
357 if (strcmp(field_expr_a->type_name,
358 field_expr_b->type_name) != 0) {
359 goto not_equal;
360 }
361
362 break;
363 }
364 case LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT:
365 {
366 const struct lttng_event_expr_array_field_element *elem_expr_a =
367 container_of(expr_a,
368 const struct lttng_event_expr_array_field_element,
369 parent);
370 const struct lttng_event_expr_array_field_element *elem_expr_b =
371 container_of(expr_b,
372 const struct lttng_event_expr_array_field_element,
373 parent);
374
375 if (!lttng_event_expr_is_equal(elem_expr_a->array_field_expr,
376 elem_expr_b->array_field_expr)) {
377 goto not_equal;
378 }
379
380 if (elem_expr_a->index != elem_expr_b->index) {
381 goto not_equal;
382 }
383
384 break;
385 }
386 default:
387 break;
388 }
389
390 goto end;
391
392 not_equal:
393 is_equal = false;
394
395 end:
396 return is_equal;
397 }
398
399 void lttng_event_expr_destroy(struct lttng_event_expr *expr)
400 {
401 if (!expr) {
402 goto end;
403 }
404
405 switch (expr->type) {
406 case LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD:
407 case LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD:
408 {
409 struct lttng_event_expr_field *field_expr =
410 container_of(expr,
411 struct lttng_event_expr_field, parent);
412
413 free(field_expr->name);
414 break;
415 }
416 case LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD:
417 {
418 struct lttng_event_expr_app_specific_context_field *field_expr =
419 container_of(expr,
420 struct lttng_event_expr_app_specific_context_field,
421 parent);
422
423 free(field_expr->provider_name);
424 free(field_expr->type_name);
425 break;
426 }
427 case LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT:
428 {
429 struct lttng_event_expr_array_field_element *elem_expr =
430 container_of(expr,
431 struct lttng_event_expr_array_field_element,
432 parent);
433
434 lttng_event_expr_destroy(elem_expr->array_field_expr);
435 break;
436 }
437 default:
438 break;
439 }
440
441 free(expr);
442
443 end:
444 return;
445 }
446
447 static int event_expr_to_bytecode_recursive(const struct lttng_event_expr *expr,
448 struct lttng_bytecode_alloc **bytecode,
449 struct lttng_bytecode_alloc **bytecode_reloc)
450 {
451 int status;
452 enum lttng_event_expr_status event_expr_status;
453
454 switch (lttng_event_expr_get_type(expr)) {
455 case LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD:
456 {
457 const char *name;
458
459 status = bytecode_push_get_payload_root(bytecode);
460 if (status) {
461 ERR("Failed to get payload root from bytecode");
462 goto end;
463 }
464
465 name = lttng_event_expr_event_payload_field_get_name(expr);
466 if (!name) {
467 ERR("Failed to get payload field name from event expression");
468 status = -1;
469 goto end;
470 }
471
472 status = bytecode_push_get_symbol(
473 bytecode, bytecode_reloc, name);
474 if (status) {
475 ERR("Failed to push 'get symbol %s' in bytecode", name);
476 goto end;
477 }
478
479 break;
480 }
481 case LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD:
482 {
483 const char *name;
484
485 status = bytecode_push_get_context_root(bytecode);
486 if (status) {
487 ERR("Failed to get context root from bytecode");
488 goto end;
489 }
490
491 name = lttng_event_expr_channel_context_field_get_name(expr);
492 if (!name) {
493 ERR("Failed to get channel context field name from event expression");
494 status = -1;
495 goto end;
496 }
497
498 status = bytecode_push_get_symbol(
499 bytecode, bytecode_reloc, name);
500 if (status) {
501 ERR("Failed to push 'get symbol %s' in bytecode", name);
502 goto end;
503 }
504
505 break;
506 }
507 case LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD:
508 {
509 int ret;
510 char *name = NULL;
511 const char *provider_name, *type_name;
512
513 status = bytecode_push_get_app_context_root(bytecode);
514 if (status) {
515 ERR("Failed to get application context root from bytecode");
516 goto end;
517 }
518
519 provider_name = lttng_event_expr_app_specific_context_field_get_provider_name(
520 expr);
521 if (!provider_name) {
522 ERR("Failed to get application context provider name from event expression");
523 status = -1;
524 goto end;
525 }
526
527 type_name = lttng_event_expr_app_specific_context_field_get_type_name(
528 expr);
529 if (!type_name) {
530 ERR("Failed to get application context type name from event expression");
531 status = -1;
532 goto end;
533 }
534
535 /*
536 * Reconstitute the app context field name from its two parts.
537 */
538 ret = asprintf(&name, "%s:%s", provider_name, type_name);
539 if (ret < 0) {
540 PERROR("Failed to format application specific context: provider_name = '%s', type_name = '%s'",
541 provider_name, type_name);
542 status = -1;
543 goto end;
544 }
545
546 status = bytecode_push_get_symbol(
547 bytecode, bytecode_reloc, name);
548 free(name);
549 if (status) {
550 ERR("Failed to push 'get symbol %s:%s' in bytecode",
551 provider_name, type_name);
552 goto end;
553 }
554
555 break;
556 }
557 case LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT:
558 {
559 unsigned int index;
560 const struct lttng_event_expr *parent;
561
562 parent = lttng_event_expr_array_field_element_get_parent_expr(
563 expr);
564 if (!parent) {
565 ERR("Failed to get parent expression from array event expression");
566 status = -1;
567 goto end;
568 }
569
570 status = event_expr_to_bytecode_recursive(
571 parent, bytecode, bytecode_reloc);
572 if (status) {
573 goto end;
574 }
575
576 event_expr_status =
577 lttng_event_expr_array_field_element_get_index(
578 expr, &index);
579 if (event_expr_status != LTTNG_EVENT_EXPR_STATUS_OK) {
580 ERR("Failed to get array field element index from event expression");
581 status = -1;
582 goto end;
583 }
584
585 status = bytecode_push_get_index_u64(bytecode, index);
586 if (status) {
587 ERR("Failed to push 'get index %u' in bytecode", index);
588 goto end;
589 }
590
591 break;
592 }
593 default:
594 abort();
595 }
596
597 status = 0;
598 end:
599 return status;
600 }
601
602 LTTNG_HIDDEN
603 int lttng_event_expr_to_bytecode(const struct lttng_event_expr *expr,
604 struct lttng_bytecode **bytecode_out)
605 {
606 int status;
607 struct return_op ret_insn;
608 struct lttng_bytecode_alloc *bytecode = NULL;
609 struct lttng_bytecode_alloc *bytecode_reloc = NULL;
610
611 status = bytecode_init(&bytecode);
612 if (status) {
613 ERR("Failed to initialize bytecode");
614 goto end;
615 }
616
617 status = bytecode_init(&bytecode_reloc);
618 if (status) {
619 ERR("Failed to initialize relocation bytecode");
620 goto end;
621 }
622
623 status = event_expr_to_bytecode_recursive(
624 expr, &bytecode, &bytecode_reloc);
625 if (status) {
626 /* Errors already logged. */
627 goto end;
628 }
629
630 ret_insn.op = BYTECODE_OP_RETURN;
631 bytecode_push(&bytecode, &ret_insn, 1, sizeof(ret_insn));
632
633 /* Append symbol table to bytecode. */
634 bytecode->b.reloc_table_offset = bytecode_get_len(&bytecode->b);
635 status = bytecode_push(&bytecode, bytecode_reloc->b.data, 1,
636 bytecode_get_len(&bytecode_reloc->b));
637 if (status) {
638 ERR("Failed to push symbol table to bytecode");
639 goto end;
640 }
641
642 /* Copy the `lttng_bytecode` out of the `lttng_bytecode_alloc`. */
643 *bytecode_out = lttng_bytecode_copy(&bytecode->b);
644 if (!*bytecode_out) {
645 status = -1;
646 goto end;
647 }
648
649 end:
650 if (bytecode) {
651 free(bytecode);
652 }
653
654 if (bytecode_reloc) {
655 free(bytecode_reloc);
656 }
657
658 return status;
659 }
This page took 0.045208 seconds and 4 git commands to generate.