Commit | Line | Data |
---|---|---|
48c47564 PP |
1 | /* |
2 | * event-expr.c | |
3 | * | |
48c47564 PP |
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 | ||
1575be4a | 14 | #include <common/bytecode/bytecode.h> |
48c47564 PP |
15 | #include <common/error.h> |
16 | #include <common/macros.h> | |
0f7c2963 | 17 | #include <common/mi-lttng.h> |
48c47564 | 18 | #include <lttng/event-expr-internal.h> |
1575be4a JR |
19 | #include <lttng/event-expr.h> |
20 | #include <stdio.h> | |
48c47564 PP |
21 | |
22 | enum lttng_event_expr_type lttng_event_expr_get_type( | |
23 | const struct lttng_event_expr *expr) | |
24 | { | |
25 | enum lttng_event_expr_type type; | |
26 | ||
27 | if (!expr) { | |
28 | type = LTTNG_EVENT_EXPR_TYPE_INVALID; | |
29 | goto end; | |
30 | } | |
31 | ||
32 | type = expr->type; | |
33 | ||
34 | end: | |
35 | return type; | |
36 | } | |
37 | ||
38 | static | |
39 | struct lttng_event_expr *create_empty_expr(enum lttng_event_expr_type type, | |
40 | size_t size) | |
41 | { | |
42 | struct lttng_event_expr *expr; | |
43 | ||
44 | expr = zmalloc(size); | |
45 | if (!expr) { | |
46 | goto end; | |
47 | } | |
48 | ||
49 | expr->type = type; | |
50 | ||
51 | end: | |
52 | return expr; | |
53 | } | |
54 | ||
55 | static | |
56 | struct lttng_event_expr_field *create_field_event_expr( | |
57 | enum lttng_event_expr_type type, | |
58 | const char *name) | |
59 | { | |
60 | struct lttng_event_expr_field *expr = | |
61 | container_of( | |
62 | create_empty_expr(type, sizeof(*expr)), | |
63 | struct lttng_event_expr_field, parent); | |
64 | ||
65 | if (!expr) { | |
66 | goto error; | |
67 | } | |
68 | ||
69 | assert(name); | |
70 | expr->name = strdup(name); | |
71 | if (!expr->name) { | |
72 | goto error; | |
73 | } | |
74 | ||
75 | goto end; | |
76 | ||
77 | error: | |
5b5ad96e FD |
78 | if (expr) { |
79 | lttng_event_expr_destroy(&expr->parent); | |
80 | } | |
81 | expr = NULL; | |
48c47564 PP |
82 | |
83 | end: | |
84 | return expr; | |
85 | } | |
86 | ||
87 | struct lttng_event_expr *lttng_event_expr_event_payload_field_create( | |
88 | const char *field_name) | |
89 | { | |
90 | struct lttng_event_expr *expr = NULL; | |
91 | ||
92 | if (!field_name) { | |
93 | goto end; | |
94 | } | |
95 | ||
96 | expr = &create_field_event_expr( | |
97 | LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD, | |
98 | field_name)->parent; | |
99 | ||
100 | end: | |
101 | return expr; | |
102 | } | |
103 | ||
104 | struct lttng_event_expr *lttng_event_expr_channel_context_field_create( | |
105 | const char *field_name) | |
106 | { | |
107 | struct lttng_event_expr *expr = NULL; | |
108 | ||
109 | if (!field_name) { | |
110 | goto end; | |
111 | } | |
112 | ||
113 | expr = &create_field_event_expr( | |
114 | LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD, | |
115 | field_name)->parent; | |
116 | ||
117 | end: | |
118 | return expr; | |
119 | } | |
120 | ||
121 | struct lttng_event_expr *lttng_event_expr_app_specific_context_field_create( | |
122 | const char *provider_name, const char *type_name) | |
123 | { | |
124 | struct lttng_event_expr_app_specific_context_field *expr = NULL; | |
5b5ad96e | 125 | struct lttng_event_expr *ret_parent_expr; |
48c47564 PP |
126 | |
127 | if (!type_name || !provider_name) { | |
128 | goto error; | |
129 | } | |
130 | ||
131 | expr = container_of(create_empty_expr( | |
132 | LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD, | |
133 | sizeof(*expr)), | |
134 | struct lttng_event_expr_app_specific_context_field, | |
135 | parent); | |
136 | if (!expr) { | |
137 | goto error; | |
138 | } | |
139 | ||
140 | expr->provider_name = strdup(provider_name); | |
141 | if (!expr->provider_name) { | |
142 | goto error; | |
143 | } | |
144 | ||
145 | expr->type_name = strdup(type_name); | |
146 | if (!expr->type_name) { | |
147 | goto error; | |
148 | } | |
149 | ||
5b5ad96e | 150 | ret_parent_expr = &expr->parent; |
48c47564 PP |
151 | goto end; |
152 | ||
153 | error: | |
5b5ad96e FD |
154 | if (expr) { |
155 | lttng_event_expr_destroy(&expr->parent); | |
156 | } | |
157 | ret_parent_expr = NULL; | |
48c47564 PP |
158 | |
159 | end: | |
5b5ad96e | 160 | return ret_parent_expr; |
48c47564 PP |
161 | } |
162 | ||
163 | struct lttng_event_expr *lttng_event_expr_array_field_element_create( | |
164 | struct lttng_event_expr *array_field_expr, | |
165 | unsigned int index) | |
166 | { | |
167 | struct lttng_event_expr_array_field_element *expr = NULL; | |
5b5ad96e | 168 | struct lttng_event_expr *ret_parent_expr; |
48c47564 PP |
169 | |
170 | /* The parent array field expression must be an l-value */ | |
171 | if (!array_field_expr || | |
172 | !lttng_event_expr_is_lvalue(array_field_expr)) { | |
173 | goto error; | |
174 | } | |
175 | ||
176 | expr = container_of(create_empty_expr( | |
177 | LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT, | |
178 | sizeof(*expr)), | |
179 | struct lttng_event_expr_array_field_element, | |
180 | parent); | |
181 | if (!expr) { | |
182 | goto error; | |
183 | } | |
184 | ||
185 | expr->array_field_expr = array_field_expr; | |
186 | expr->index = index; | |
5b5ad96e | 187 | ret_parent_expr = &expr->parent; |
48c47564 PP |
188 | goto end; |
189 | ||
190 | error: | |
5b5ad96e | 191 | ret_parent_expr = NULL; |
48c47564 PP |
192 | |
193 | end: | |
5b5ad96e | 194 | return ret_parent_expr; |
48c47564 PP |
195 | } |
196 | ||
197 | const char *lttng_event_expr_event_payload_field_get_name( | |
198 | const struct lttng_event_expr *expr) | |
199 | { | |
200 | const char *ret = NULL; | |
201 | ||
202 | if (!expr || expr->type != LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD) { | |
203 | goto end; | |
204 | } | |
205 | ||
206 | ret = container_of(expr, | |
207 | const struct lttng_event_expr_field, parent)->name; | |
208 | ||
209 | end: | |
210 | return ret; | |
211 | } | |
212 | ||
213 | const char *lttng_event_expr_channel_context_field_get_name( | |
214 | const struct lttng_event_expr *expr) | |
215 | { | |
216 | const char *ret = NULL; | |
217 | ||
218 | if (!expr || expr->type != LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD) { | |
219 | goto end; | |
220 | } | |
221 | ||
222 | ret = container_of(expr, | |
223 | const struct lttng_event_expr_field, parent)->name; | |
224 | ||
225 | end: | |
226 | return ret; | |
227 | } | |
228 | ||
229 | const char *lttng_event_expr_app_specific_context_field_get_provider_name( | |
230 | const struct lttng_event_expr *expr) | |
231 | { | |
232 | const char *ret = NULL; | |
233 | ||
234 | if (!expr || expr->type != LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD) { | |
235 | goto end; | |
236 | } | |
237 | ||
238 | ret = container_of(expr, | |
239 | const struct lttng_event_expr_app_specific_context_field, | |
240 | parent)->provider_name; | |
241 | ||
242 | end: | |
243 | return ret; | |
244 | } | |
245 | ||
246 | const char *lttng_event_expr_app_specific_context_field_get_type_name( | |
247 | const struct lttng_event_expr *expr) | |
248 | { | |
249 | const char *ret = NULL; | |
250 | ||
251 | if (!expr || expr->type != LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD) { | |
252 | goto end; | |
253 | } | |
254 | ||
255 | ret = container_of(expr, | |
256 | const struct lttng_event_expr_app_specific_context_field, | |
257 | parent)->type_name; | |
258 | ||
259 | end: | |
260 | return ret; | |
261 | } | |
262 | ||
263 | const struct lttng_event_expr * | |
264 | lttng_event_expr_array_field_element_get_parent_expr( | |
265 | const struct lttng_event_expr *expr) | |
266 | { | |
267 | const struct lttng_event_expr *ret = NULL; | |
268 | ||
269 | if (!expr || expr->type != LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT) { | |
270 | goto end; | |
271 | } | |
272 | ||
273 | ret = container_of(expr, | |
274 | const struct lttng_event_expr_array_field_element, | |
275 | parent)->array_field_expr; | |
276 | ||
277 | end: | |
278 | return ret; | |
279 | } | |
280 | ||
281 | enum lttng_event_expr_status lttng_event_expr_array_field_element_get_index( | |
282 | const struct lttng_event_expr *expr, unsigned int *index) | |
283 | { | |
284 | enum lttng_event_expr_status ret = LTTNG_EVENT_EXPR_STATUS_OK; | |
285 | ||
286 | if (!expr || expr->type != LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT || | |
287 | !index) { | |
288 | ret = LTTNG_EVENT_EXPR_STATUS_INVALID; | |
289 | goto end; | |
290 | } | |
291 | ||
292 | *index = container_of(expr, | |
293 | const struct lttng_event_expr_array_field_element, | |
294 | parent)->index; | |
295 | ||
296 | end: | |
297 | return ret; | |
298 | } | |
299 | ||
300 | bool lttng_event_expr_is_equal(const struct lttng_event_expr *expr_a, | |
301 | const struct lttng_event_expr *expr_b) | |
302 | { | |
303 | bool is_equal = true; | |
304 | ||
305 | if (!expr_a && !expr_b) { | |
306 | /* Both `NULL`: equal */ | |
307 | goto end; | |
308 | } | |
309 | ||
310 | if (!expr_a || !expr_b) { | |
311 | /* Only one `NULL`: not equal */ | |
312 | goto not_equal; | |
313 | } | |
314 | ||
315 | if (expr_a->type != expr_b->type) { | |
316 | /* Different types: not equal */ | |
317 | goto not_equal; | |
318 | } | |
319 | ||
320 | switch (expr_a->type) { | |
321 | case LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD: | |
322 | case LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD: | |
323 | { | |
324 | const struct lttng_event_expr_field *field_expr_a = | |
325 | container_of(expr_a, | |
326 | const struct lttng_event_expr_field, | |
327 | parent); | |
328 | const struct lttng_event_expr_field *field_expr_b = | |
329 | container_of(expr_b, | |
330 | const struct lttng_event_expr_field, | |
331 | parent); | |
332 | ||
333 | if (strcmp(field_expr_a->name, field_expr_b->name) != 0) { | |
334 | goto not_equal; | |
335 | } | |
336 | ||
337 | break; | |
338 | } | |
339 | case LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD: | |
340 | { | |
341 | const struct lttng_event_expr_app_specific_context_field *field_expr_a = | |
342 | container_of(expr_a, | |
343 | const struct lttng_event_expr_app_specific_context_field, | |
344 | parent); | |
345 | const struct lttng_event_expr_app_specific_context_field *field_expr_b = | |
346 | container_of(expr_b, | |
347 | const struct lttng_event_expr_app_specific_context_field, | |
348 | parent); | |
349 | ||
350 | if (strcmp(field_expr_a->provider_name, | |
351 | field_expr_b->provider_name) != 0) { | |
352 | goto not_equal; | |
353 | } | |
354 | ||
355 | if (strcmp(field_expr_a->type_name, | |
356 | field_expr_b->type_name) != 0) { | |
357 | goto not_equal; | |
358 | } | |
359 | ||
360 | break; | |
361 | } | |
362 | case LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT: | |
363 | { | |
364 | const struct lttng_event_expr_array_field_element *elem_expr_a = | |
365 | container_of(expr_a, | |
366 | const struct lttng_event_expr_array_field_element, | |
367 | parent); | |
368 | const struct lttng_event_expr_array_field_element *elem_expr_b = | |
369 | container_of(expr_b, | |
370 | const struct lttng_event_expr_array_field_element, | |
371 | parent); | |
372 | ||
373 | if (!lttng_event_expr_is_equal(elem_expr_a->array_field_expr, | |
374 | elem_expr_b->array_field_expr)) { | |
375 | goto not_equal; | |
376 | } | |
377 | ||
378 | if (elem_expr_a->index != elem_expr_b->index) { | |
379 | goto not_equal; | |
380 | } | |
381 | ||
382 | break; | |
383 | } | |
384 | default: | |
385 | break; | |
386 | } | |
387 | ||
388 | goto end; | |
389 | ||
390 | not_equal: | |
391 | is_equal = false; | |
392 | ||
393 | end: | |
394 | return is_equal; | |
395 | } | |
396 | ||
397 | void lttng_event_expr_destroy(struct lttng_event_expr *expr) | |
398 | { | |
399 | if (!expr) { | |
400 | goto end; | |
401 | } | |
402 | ||
403 | switch (expr->type) { | |
404 | case LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD: | |
405 | case LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD: | |
406 | { | |
407 | struct lttng_event_expr_field *field_expr = | |
408 | container_of(expr, | |
409 | struct lttng_event_expr_field, parent); | |
410 | ||
411 | free(field_expr->name); | |
412 | break; | |
413 | } | |
414 | case LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD: | |
415 | { | |
416 | struct lttng_event_expr_app_specific_context_field *field_expr = | |
417 | container_of(expr, | |
418 | struct lttng_event_expr_app_specific_context_field, | |
419 | parent); | |
420 | ||
421 | free(field_expr->provider_name); | |
422 | free(field_expr->type_name); | |
423 | break; | |
424 | } | |
425 | case LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT: | |
426 | { | |
427 | struct lttng_event_expr_array_field_element *elem_expr = | |
428 | container_of(expr, | |
429 | struct lttng_event_expr_array_field_element, | |
430 | parent); | |
431 | ||
432 | lttng_event_expr_destroy(elem_expr->array_field_expr); | |
433 | break; | |
434 | } | |
435 | default: | |
436 | break; | |
437 | } | |
438 | ||
439 | free(expr); | |
440 | ||
441 | end: | |
442 | return; | |
443 | } | |
1575be4a JR |
444 | |
445 | static int event_expr_to_bytecode_recursive(const struct lttng_event_expr *expr, | |
446 | struct lttng_bytecode_alloc **bytecode, | |
447 | struct lttng_bytecode_alloc **bytecode_reloc) | |
448 | { | |
449 | int status; | |
450 | enum lttng_event_expr_status event_expr_status; | |
451 | ||
452 | switch (lttng_event_expr_get_type(expr)) { | |
453 | case LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD: | |
454 | { | |
455 | const char *name; | |
456 | ||
457 | status = bytecode_push_get_payload_root(bytecode); | |
458 | if (status) { | |
459 | ERR("Failed to get payload root from bytecode"); | |
460 | goto end; | |
461 | } | |
462 | ||
463 | name = lttng_event_expr_event_payload_field_get_name(expr); | |
464 | if (!name) { | |
465 | ERR("Failed to get payload field name from event expression"); | |
466 | status = -1; | |
467 | goto end; | |
468 | } | |
469 | ||
470 | status = bytecode_push_get_symbol( | |
471 | bytecode, bytecode_reloc, name); | |
472 | if (status) { | |
473 | ERR("Failed to push 'get symbol %s' in bytecode", name); | |
474 | goto end; | |
475 | } | |
476 | ||
477 | break; | |
478 | } | |
479 | case LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD: | |
480 | { | |
481 | const char *name; | |
482 | ||
483 | status = bytecode_push_get_context_root(bytecode); | |
484 | if (status) { | |
485 | ERR("Failed to get context root from bytecode"); | |
486 | goto end; | |
487 | } | |
488 | ||
489 | name = lttng_event_expr_channel_context_field_get_name(expr); | |
490 | if (!name) { | |
491 | ERR("Failed to get channel context field name from event expression"); | |
492 | status = -1; | |
493 | goto end; | |
494 | } | |
495 | ||
496 | status = bytecode_push_get_symbol( | |
497 | bytecode, bytecode_reloc, name); | |
498 | if (status) { | |
499 | ERR("Failed to push 'get symbol %s' in bytecode", name); | |
500 | goto end; | |
501 | } | |
502 | ||
503 | break; | |
504 | } | |
505 | case LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD: | |
506 | { | |
507 | int ret; | |
508 | char *name = NULL; | |
509 | const char *provider_name, *type_name; | |
510 | ||
511 | status = bytecode_push_get_app_context_root(bytecode); | |
512 | if (status) { | |
513 | ERR("Failed to get application context root from bytecode"); | |
514 | goto end; | |
515 | } | |
516 | ||
517 | provider_name = lttng_event_expr_app_specific_context_field_get_provider_name( | |
518 | expr); | |
519 | if (!provider_name) { | |
520 | ERR("Failed to get application context provider name from event expression"); | |
521 | status = -1; | |
522 | goto end; | |
523 | } | |
524 | ||
525 | type_name = lttng_event_expr_app_specific_context_field_get_type_name( | |
526 | expr); | |
527 | if (!type_name) { | |
528 | ERR("Failed to get application context type name from event expression"); | |
529 | status = -1; | |
530 | goto end; | |
531 | } | |
532 | ||
533 | /* | |
534 | * Reconstitute the app context field name from its two parts. | |
535 | */ | |
536 | ret = asprintf(&name, "%s:%s", provider_name, type_name); | |
537 | if (ret < 0) { | |
538 | PERROR("Failed to format application specific context: provider_name = '%s', type_name = '%s'", | |
539 | provider_name, type_name); | |
540 | status = -1; | |
541 | goto end; | |
542 | } | |
543 | ||
544 | status = bytecode_push_get_symbol( | |
545 | bytecode, bytecode_reloc, name); | |
546 | free(name); | |
547 | if (status) { | |
548 | ERR("Failed to push 'get symbol %s:%s' in bytecode", | |
549 | provider_name, type_name); | |
550 | goto end; | |
551 | } | |
552 | ||
553 | break; | |
554 | } | |
555 | case LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT: | |
556 | { | |
557 | unsigned int index; | |
558 | const struct lttng_event_expr *parent; | |
559 | ||
560 | parent = lttng_event_expr_array_field_element_get_parent_expr( | |
561 | expr); | |
562 | if (!parent) { | |
563 | ERR("Failed to get parent expression from array event expression"); | |
564 | status = -1; | |
565 | goto end; | |
566 | } | |
567 | ||
568 | status = event_expr_to_bytecode_recursive( | |
569 | parent, bytecode, bytecode_reloc); | |
570 | if (status) { | |
571 | goto end; | |
572 | } | |
573 | ||
574 | event_expr_status = | |
575 | lttng_event_expr_array_field_element_get_index( | |
576 | expr, &index); | |
577 | if (event_expr_status != LTTNG_EVENT_EXPR_STATUS_OK) { | |
578 | ERR("Failed to get array field element index from event expression"); | |
579 | status = -1; | |
580 | goto end; | |
581 | } | |
582 | ||
583 | status = bytecode_push_get_index_u64(bytecode, index); | |
584 | if (status) { | |
585 | ERR("Failed to push 'get index %u' in bytecode", index); | |
586 | goto end; | |
587 | } | |
588 | ||
589 | break; | |
590 | } | |
591 | default: | |
592 | abort(); | |
593 | } | |
594 | ||
595 | status = 0; | |
596 | end: | |
597 | return status; | |
598 | } | |
599 | ||
600 | LTTNG_HIDDEN | |
601 | int lttng_event_expr_to_bytecode(const struct lttng_event_expr *expr, | |
602 | struct lttng_bytecode **bytecode_out) | |
603 | { | |
604 | int status; | |
605 | struct return_op ret_insn; | |
606 | struct lttng_bytecode_alloc *bytecode = NULL; | |
607 | struct lttng_bytecode_alloc *bytecode_reloc = NULL; | |
608 | ||
609 | status = bytecode_init(&bytecode); | |
610 | if (status) { | |
611 | ERR("Failed to initialize bytecode"); | |
612 | goto end; | |
613 | } | |
614 | ||
615 | status = bytecode_init(&bytecode_reloc); | |
616 | if (status) { | |
617 | ERR("Failed to initialize relocation bytecode"); | |
618 | goto end; | |
619 | } | |
620 | ||
621 | status = event_expr_to_bytecode_recursive( | |
622 | expr, &bytecode, &bytecode_reloc); | |
623 | if (status) { | |
624 | /* Errors already logged. */ | |
625 | goto end; | |
626 | } | |
627 | ||
628 | ret_insn.op = BYTECODE_OP_RETURN; | |
629 | bytecode_push(&bytecode, &ret_insn, 1, sizeof(ret_insn)); | |
630 | ||
631 | /* Append symbol table to bytecode. */ | |
632 | bytecode->b.reloc_table_offset = bytecode_get_len(&bytecode->b); | |
633 | status = bytecode_push(&bytecode, bytecode_reloc->b.data, 1, | |
634 | bytecode_get_len(&bytecode_reloc->b)); | |
635 | if (status) { | |
636 | ERR("Failed to push symbol table to bytecode"); | |
637 | goto end; | |
638 | } | |
639 | ||
640 | /* Copy the `lttng_bytecode` out of the `lttng_bytecode_alloc`. */ | |
641 | *bytecode_out = lttng_bytecode_copy(&bytecode->b); | |
642 | if (!*bytecode_out) { | |
643 | status = -1; | |
644 | goto end; | |
645 | } | |
646 | ||
647 | end: | |
648 | if (bytecode) { | |
649 | free(bytecode); | |
650 | } | |
651 | ||
652 | if (bytecode_reloc) { | |
653 | free(bytecode_reloc); | |
654 | } | |
655 | ||
656 | return status; | |
657 | } | |
0f7c2963 JR |
658 | |
659 | static | |
660 | enum lttng_error_code lttng_event_expr_event_payload_field_mi_serialize( | |
661 | const struct lttng_event_expr *expression, | |
662 | struct mi_writer *writer) | |
663 | { | |
664 | int ret; | |
665 | enum lttng_error_code ret_code; | |
666 | const char *name = NULL; | |
667 | ||
668 | assert(expression); | |
669 | assert(writer); | |
670 | assert(expression->type == LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD); | |
671 | ||
672 | name = lttng_event_expr_event_payload_field_get_name(expression); | |
673 | assert(name); | |
674 | ||
675 | /* Open event expr payload field element. */ | |
676 | ret = mi_lttng_writer_open_element( | |
677 | writer, mi_lttng_element_event_expr_payload_field); | |
678 | if (ret) { | |
679 | goto mi_error; | |
680 | } | |
681 | ||
682 | /* Name. */ | |
683 | ret = mi_lttng_writer_write_element_string( | |
684 | writer, config_element_name, name); | |
685 | if (ret) { | |
686 | goto mi_error; | |
687 | } | |
688 | ||
689 | /* Close event expr payload field element. */ | |
690 | ret = mi_lttng_writer_close_element(writer); | |
691 | if (ret) { | |
692 | goto mi_error; | |
693 | } | |
694 | ||
695 | ret_code = LTTNG_OK; | |
696 | goto end; | |
697 | ||
698 | mi_error: | |
699 | ret_code = LTTNG_ERR_MI_IO_FAIL; | |
700 | end: | |
701 | return ret_code; | |
702 | } | |
703 | ||
704 | static | |
705 | enum lttng_error_code lttng_event_expr_channel_context_field_mi_serialize( | |
706 | const struct lttng_event_expr *expression, | |
707 | struct mi_writer *writer) | |
708 | { | |
709 | int ret; | |
710 | enum lttng_error_code ret_code; | |
711 | const char *name = NULL; | |
712 | ||
713 | assert(expression); | |
714 | assert(writer); | |
715 | assert(expression->type == LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD); | |
716 | ||
717 | name = lttng_event_expr_channel_context_field_get_name(expression); | |
718 | assert(name); | |
719 | ||
720 | /* Open event expr channel context field element. */ | |
721 | ret = mi_lttng_writer_open_element(writer, | |
722 | mi_lttng_element_event_expr_channel_context_field); | |
723 | if (ret) { | |
724 | goto mi_error; | |
725 | } | |
726 | ||
727 | /* Name. */ | |
728 | ret = mi_lttng_writer_write_element_string( | |
729 | writer, config_element_name, name); | |
730 | if (ret) { | |
731 | goto mi_error; | |
732 | } | |
733 | ||
734 | /* Close event expr channel context field element. */ | |
735 | ret = mi_lttng_writer_close_element(writer); | |
736 | if (ret) { | |
737 | goto mi_error; | |
738 | } | |
739 | ||
740 | ret_code = LTTNG_OK; | |
741 | goto end; | |
742 | ||
743 | mi_error: | |
744 | ret_code = LTTNG_ERR_MI_IO_FAIL; | |
745 | end: | |
746 | return ret_code; | |
747 | } | |
748 | ||
749 | static | |
750 | enum lttng_error_code lttng_event_expr_app_specific_context_field_mi_serialize( | |
751 | const struct lttng_event_expr *expression, | |
752 | struct mi_writer *writer) | |
753 | { | |
754 | int ret; | |
755 | enum lttng_error_code ret_code; | |
756 | const char *provider_name = NULL; | |
757 | const char *type_name = NULL; | |
758 | ||
759 | assert(expression); | |
760 | assert(writer); | |
761 | assert(expression->type == | |
762 | LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD); | |
763 | ||
764 | provider_name = lttng_event_expr_app_specific_context_field_get_provider_name( | |
765 | expression); | |
766 | assert(provider_name); | |
767 | ||
768 | type_name = lttng_event_expr_app_specific_context_field_get_type_name( | |
769 | expression); | |
770 | assert(provider_name); | |
771 | ||
772 | /* Open event expr app specific context field element. */ | |
773 | ret = mi_lttng_writer_open_element(writer, | |
774 | mi_lttng_element_event_expr_app_specific_context_field); | |
775 | if (ret) { | |
776 | goto mi_error; | |
777 | } | |
778 | ||
779 | /* Provider name. */ | |
780 | ret = mi_lttng_writer_write_element_string(writer, | |
781 | mi_lttng_element_event_expr_provider_name, | |
782 | provider_name); | |
783 | if (ret) { | |
784 | goto mi_error; | |
785 | } | |
786 | ||
787 | /* Type name. */ | |
788 | ret = mi_lttng_writer_write_element_string(writer, | |
789 | mi_lttng_element_event_expr_type_name, type_name); | |
790 | if (ret) { | |
791 | goto mi_error; | |
792 | } | |
793 | ||
794 | /* Close event expr app specific context field element. */ | |
795 | ret = mi_lttng_writer_close_element(writer); | |
796 | if (ret) { | |
797 | goto mi_error; | |
798 | } | |
799 | ||
800 | ret_code = LTTNG_OK; | |
801 | goto end; | |
802 | ||
803 | mi_error: | |
804 | ret_code = LTTNG_ERR_MI_IO_FAIL; | |
805 | end: | |
806 | return ret_code; | |
807 | } | |
808 | ||
809 | static | |
810 | enum lttng_error_code lttng_event_expr_array_field_element_mi_serialize( | |
811 | const struct lttng_event_expr *expression, | |
812 | struct mi_writer *writer) | |
813 | { | |
814 | int ret; | |
815 | enum lttng_error_code ret_code; | |
816 | enum lttng_event_expr_status status; | |
817 | const struct lttng_event_expr *parent_expr = NULL; | |
818 | unsigned int index; | |
819 | ||
820 | assert(expression); | |
821 | assert(writer); | |
822 | assert(expression->type == LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT); | |
823 | ||
824 | status = lttng_event_expr_array_field_element_get_index( | |
825 | expression, &index); | |
826 | assert(status == LTTNG_EVENT_EXPR_STATUS_OK); | |
827 | ||
828 | parent_expr = lttng_event_expr_array_field_element_get_parent_expr( | |
829 | expression); | |
830 | assert(parent_expr != NULL); | |
831 | ||
832 | /* Open event expr array field element. */ | |
833 | ret = mi_lttng_writer_open_element(writer, | |
834 | mi_lttng_element_event_expr_array_field_element); | |
835 | if (ret) { | |
836 | goto mi_error; | |
837 | } | |
838 | ||
839 | /* Index. */ | |
840 | ret = mi_lttng_writer_write_element_unsigned_int( | |
841 | writer, mi_lttng_element_event_expr_index, index); | |
842 | if (ret) { | |
843 | goto mi_error; | |
844 | } | |
845 | ||
846 | /* Parent expression. */ | |
847 | ret_code = lttng_event_expr_mi_serialize(parent_expr, writer); | |
848 | if (ret_code != LTTNG_OK) { | |
849 | goto end; | |
850 | } | |
851 | ||
852 | /* Close event expr array field element. */ | |
853 | ret = mi_lttng_writer_close_element(writer); | |
854 | if (ret) { | |
855 | goto mi_error; | |
856 | } | |
857 | ||
858 | ret_code = LTTNG_OK; | |
859 | goto end; | |
860 | ||
861 | mi_error: | |
862 | ret_code = LTTNG_ERR_MI_IO_FAIL; | |
863 | end: | |
864 | return ret_code; | |
865 | } | |
866 | ||
867 | LTTNG_HIDDEN | |
868 | enum lttng_error_code lttng_event_expr_mi_serialize( | |
869 | const struct lttng_event_expr *expression, | |
870 | struct mi_writer *writer) | |
871 | { | |
872 | int ret; | |
873 | enum lttng_error_code ret_code; | |
874 | ||
875 | assert(expression); | |
876 | assert(writer); | |
877 | ||
878 | ret = mi_lttng_writer_open_element(writer, mi_lttng_element_event_expr); | |
879 | if (ret) { | |
880 | goto mi_error; | |
881 | } | |
882 | ||
883 | switch (expression->type) { | |
884 | case LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD: | |
885 | ret_code = lttng_event_expr_event_payload_field_mi_serialize( | |
886 | expression, writer); | |
887 | break; | |
888 | case LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD: | |
889 | ret_code = lttng_event_expr_channel_context_field_mi_serialize( | |
890 | expression, writer); | |
891 | break; | |
892 | case LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD: | |
893 | ret_code = lttng_event_expr_app_specific_context_field_mi_serialize( | |
894 | expression, writer); | |
895 | break; | |
896 | case LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT: | |
897 | ret_code = lttng_event_expr_array_field_element_mi_serialize( | |
898 | expression, writer); | |
899 | break; | |
900 | default: | |
901 | abort(); | |
902 | } | |
903 | ||
904 | if (ret_code != LTTNG_OK) { | |
905 | goto end; | |
906 | } | |
907 | ||
908 | ret = mi_lttng_writer_close_element(writer); | |
909 | if (ret) { | |
910 | goto mi_error; | |
911 | } | |
912 | ||
913 | ret_code = LTTNG_OK; | |
914 | goto end; | |
915 | ||
916 | mi_error: | |
917 | ret_code = LTTNG_ERR_MI_IO_FAIL; | |
918 | ||
919 | end: | |
920 | return ret_code; | |
921 | } |