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