Commit | Line | Data |
---|---|---|
d28fcdec PP |
1 | /* |
2 | * event-field-value.c | |
3 | * | |
4 | * Linux Trace Toolkit Control Library | |
5 | * | |
6 | * Copyright (C) 2020 Philippe Proulx <pproulx@efficios.com> | |
7 | * | |
8 | * SPDX-License-Identifier: LGPL-2.1-only | |
9 | * | |
10 | */ | |
11 | ||
12 | #define _LGPL_SOURCE | |
d28fcdec PP |
13 | #include <stddef.h> |
14 | #include <stdbool.h> | |
15 | ||
16 | #include <common/error.h> | |
17 | #include <common/macros.h> | |
18 | #include <lttng/event-field-value-internal.h> | |
19 | ||
20 | static | |
21 | struct lttng_event_field_value *create_empty_field_val( | |
22 | enum lttng_event_field_value_type type, size_t size) | |
23 | { | |
24 | struct lttng_event_field_value *field_val; | |
25 | ||
26 | field_val = zmalloc(size); | |
27 | if (!field_val) { | |
28 | goto end; | |
29 | } | |
30 | ||
31 | field_val->type = type; | |
32 | ||
33 | end: | |
34 | return field_val; | |
35 | } | |
36 | ||
37 | LTTNG_HIDDEN | |
38 | struct lttng_event_field_value *lttng_event_field_value_uint_create( | |
39 | uint64_t val) | |
40 | { | |
41 | struct lttng_event_field_value_uint *field_val; | |
42 | ||
43 | field_val = container_of(create_empty_field_val( | |
44 | LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT, | |
45 | sizeof(*field_val)), | |
46 | struct lttng_event_field_value_uint, parent); | |
47 | if (!field_val) { | |
48 | goto error; | |
49 | } | |
50 | ||
51 | field_val->val = val; | |
52 | goto end; | |
53 | ||
54 | error: | |
55 | lttng_event_field_value_destroy(&field_val->parent); | |
56 | ||
57 | end: | |
58 | return &field_val->parent; | |
59 | } | |
60 | ||
61 | LTTNG_HIDDEN | |
62 | struct lttng_event_field_value *lttng_event_field_value_int_create( | |
63 | int64_t val) | |
64 | { | |
65 | struct lttng_event_field_value_int *field_val; | |
66 | ||
67 | field_val = container_of(create_empty_field_val( | |
68 | LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT, | |
69 | sizeof(*field_val)), | |
70 | struct lttng_event_field_value_int, parent); | |
71 | if (!field_val) { | |
72 | goto error; | |
73 | } | |
74 | ||
75 | field_val->val = val; | |
76 | goto end; | |
77 | ||
78 | error: | |
79 | lttng_event_field_value_destroy(&field_val->parent); | |
80 | ||
81 | end: | |
82 | return &field_val->parent; | |
83 | } | |
84 | ||
85 | static | |
86 | struct lttng_event_field_value_enum *create_enum_field_val( | |
87 | enum lttng_event_field_value_type type, size_t size) | |
88 | { | |
89 | struct lttng_event_field_value_enum *field_val; | |
90 | ||
91 | field_val = container_of(create_empty_field_val(type, size), | |
92 | struct lttng_event_field_value_enum, parent); | |
93 | if (!field_val) { | |
94 | goto error; | |
95 | } | |
96 | ||
97 | lttng_dynamic_pointer_array_init(&field_val->labels, free); | |
98 | goto end; | |
99 | ||
100 | error: | |
101 | lttng_event_field_value_destroy(&field_val->parent); | |
102 | ||
103 | end: | |
104 | return field_val; | |
105 | } | |
106 | ||
107 | LTTNG_HIDDEN | |
108 | struct lttng_event_field_value *lttng_event_field_value_enum_uint_create( | |
109 | uint64_t val) | |
110 | { | |
111 | struct lttng_event_field_value_enum_uint *field_val; | |
112 | ||
113 | field_val = container_of(create_enum_field_val( | |
114 | LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM, | |
115 | sizeof(*field_val)), | |
116 | struct lttng_event_field_value_enum_uint, parent); | |
117 | if (!field_val) { | |
118 | goto error; | |
119 | } | |
120 | ||
121 | field_val->val = val; | |
122 | goto end; | |
123 | ||
124 | error: | |
125 | lttng_event_field_value_destroy(&field_val->parent.parent); | |
126 | ||
127 | end: | |
128 | return &field_val->parent.parent; | |
129 | } | |
130 | ||
131 | LTTNG_HIDDEN | |
132 | struct lttng_event_field_value *lttng_event_field_value_enum_int_create( | |
133 | int64_t val) | |
134 | { | |
135 | struct lttng_event_field_value_enum_int *field_val; | |
136 | ||
137 | field_val = container_of(create_enum_field_val( | |
138 | LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM, | |
139 | sizeof(*field_val)), | |
140 | struct lttng_event_field_value_enum_int, parent); | |
141 | if (!field_val) { | |
142 | goto error; | |
143 | } | |
144 | ||
145 | field_val->val = val; | |
146 | goto end; | |
147 | ||
148 | error: | |
149 | lttng_event_field_value_destroy(&field_val->parent.parent); | |
150 | ||
151 | end: | |
152 | return &field_val->parent.parent; | |
153 | } | |
154 | ||
155 | LTTNG_HIDDEN | |
156 | struct lttng_event_field_value *lttng_event_field_value_real_create(double val) | |
157 | { | |
158 | struct lttng_event_field_value_real *field_val = container_of( | |
159 | create_empty_field_val( | |
160 | LTTNG_EVENT_FIELD_VALUE_TYPE_REAL, | |
161 | sizeof(*field_val)), | |
162 | struct lttng_event_field_value_real, parent); | |
163 | ||
164 | if (!field_val) { | |
165 | goto error; | |
166 | } | |
167 | ||
168 | field_val->val = val; | |
169 | goto end; | |
170 | ||
171 | error: | |
172 | lttng_event_field_value_destroy(&field_val->parent); | |
173 | ||
174 | end: | |
175 | return &field_val->parent; | |
176 | } | |
177 | ||
178 | LTTNG_HIDDEN | |
179 | struct lttng_event_field_value *lttng_event_field_value_string_create_with_size( | |
180 | const char *val, size_t size) | |
181 | { | |
182 | struct lttng_event_field_value_string *field_val = container_of( | |
183 | create_empty_field_val( | |
184 | LTTNG_EVENT_FIELD_VALUE_TYPE_STRING, | |
185 | sizeof(*field_val)), | |
186 | struct lttng_event_field_value_string, parent); | |
187 | ||
188 | if (!field_val) { | |
189 | goto error; | |
190 | } | |
191 | ||
a0377dfe | 192 | LTTNG_ASSERT(val); |
d28fcdec PP |
193 | field_val->val = strndup(val, size); |
194 | if (!field_val->val) { | |
195 | goto error; | |
196 | } | |
197 | ||
198 | goto end; | |
199 | ||
200 | error: | |
201 | lttng_event_field_value_destroy(&field_val->parent); | |
202 | ||
203 | end: | |
204 | return &field_val->parent; | |
205 | } | |
206 | ||
207 | LTTNG_HIDDEN | |
208 | struct lttng_event_field_value *lttng_event_field_value_string_create( | |
209 | const char *val) | |
210 | { | |
a0377dfe | 211 | LTTNG_ASSERT(val); |
d28fcdec PP |
212 | return lttng_event_field_value_string_create_with_size(val, |
213 | strlen(val)); | |
214 | } | |
215 | ||
216 | static | |
217 | void destroy_field_val(void *field_val) | |
218 | { | |
219 | lttng_event_field_value_destroy(field_val); | |
220 | } | |
221 | ||
222 | LTTNG_HIDDEN | |
223 | struct lttng_event_field_value *lttng_event_field_value_array_create(void) | |
224 | { | |
225 | struct lttng_event_field_value_array *field_val = container_of( | |
226 | create_empty_field_val( | |
227 | LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY, | |
228 | sizeof(*field_val)), | |
229 | struct lttng_event_field_value_array, parent); | |
230 | ||
231 | if (!field_val) { | |
232 | goto error; | |
233 | } | |
234 | ||
235 | lttng_dynamic_pointer_array_init(&field_val->elems, destroy_field_val); | |
236 | goto end; | |
237 | ||
238 | error: | |
239 | lttng_event_field_value_destroy(&field_val->parent); | |
240 | ||
241 | end: | |
242 | return &field_val->parent; | |
243 | } | |
244 | ||
245 | LTTNG_HIDDEN | |
246 | void lttng_event_field_value_destroy(struct lttng_event_field_value *field_val) | |
247 | { | |
248 | if (!field_val) { | |
249 | goto end; | |
250 | } | |
251 | ||
252 | switch (field_val->type) { | |
253 | case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM: | |
254 | case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM: | |
255 | { | |
256 | struct lttng_event_field_value_enum *enum_field_val = | |
257 | container_of(field_val, | |
258 | struct lttng_event_field_value_enum, parent); | |
259 | ||
260 | lttng_dynamic_pointer_array_reset(&enum_field_val->labels); | |
261 | break; | |
262 | } | |
263 | case LTTNG_EVENT_FIELD_VALUE_TYPE_STRING: | |
264 | { | |
265 | struct lttng_event_field_value_string *str_field_val = | |
266 | container_of(field_val, | |
267 | struct lttng_event_field_value_string, parent); | |
268 | ||
269 | free(str_field_val->val); | |
270 | break; | |
271 | } | |
272 | case LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY: | |
273 | { | |
274 | struct lttng_event_field_value_array *array_field_expr = | |
275 | container_of(field_val, | |
276 | struct lttng_event_field_value_array, | |
277 | parent); | |
278 | ||
279 | lttng_dynamic_pointer_array_reset(&array_field_expr->elems); | |
280 | break; | |
281 | } | |
282 | default: | |
283 | break; | |
284 | } | |
285 | ||
286 | free(field_val); | |
287 | ||
288 | end: | |
289 | return; | |
290 | } | |
291 | ||
292 | LTTNG_HIDDEN | |
293 | int lttng_event_field_value_enum_append_label_with_size( | |
294 | struct lttng_event_field_value *field_val, | |
295 | const char *label, size_t size) | |
296 | { | |
297 | int ret; | |
298 | char *new_label; | |
299 | ||
a0377dfe FD |
300 | LTTNG_ASSERT(field_val); |
301 | LTTNG_ASSERT(label); | |
d28fcdec PP |
302 | new_label = strndup(label, size); |
303 | if (!new_label) { | |
304 | ret = -1; | |
305 | goto end; | |
306 | } | |
307 | ||
308 | ret = lttng_dynamic_pointer_array_add_pointer( | |
309 | &container_of(field_val, | |
310 | struct lttng_event_field_value_enum, parent)->labels, | |
311 | new_label); | |
312 | if (ret == 0) { | |
313 | new_label = NULL; | |
314 | } | |
315 | ||
316 | end: | |
317 | free(new_label); | |
318 | return ret; | |
319 | } | |
320 | ||
321 | LTTNG_HIDDEN | |
322 | int lttng_event_field_value_enum_append_label( | |
323 | struct lttng_event_field_value *field_val, | |
324 | const char *label) | |
325 | { | |
a0377dfe | 326 | LTTNG_ASSERT(label); |
d28fcdec PP |
327 | return lttng_event_field_value_enum_append_label_with_size(field_val, |
328 | label, strlen(label)); | |
329 | } | |
330 | ||
331 | LTTNG_HIDDEN | |
332 | int lttng_event_field_value_array_append( | |
333 | struct lttng_event_field_value *array_field_val, | |
334 | struct lttng_event_field_value *field_val) | |
335 | { | |
a0377dfe FD |
336 | LTTNG_ASSERT(array_field_val); |
337 | LTTNG_ASSERT(field_val); | |
d28fcdec PP |
338 | return lttng_dynamic_pointer_array_add_pointer( |
339 | &container_of(array_field_val, | |
340 | struct lttng_event_field_value_array, parent)->elems, | |
341 | field_val); | |
342 | } | |
343 | ||
344 | LTTNG_HIDDEN | |
345 | int lttng_event_field_value_array_append_unavailable( | |
346 | struct lttng_event_field_value *array_field_val) | |
347 | { | |
a0377dfe | 348 | LTTNG_ASSERT(array_field_val); |
d28fcdec PP |
349 | return lttng_dynamic_pointer_array_add_pointer( |
350 | &container_of(array_field_val, | |
351 | struct lttng_event_field_value_array, parent)->elems, | |
352 | NULL); | |
353 | } | |
354 | ||
355 | enum lttng_event_field_value_type lttng_event_field_value_get_type( | |
356 | const struct lttng_event_field_value *field_val) | |
357 | { | |
358 | enum lttng_event_field_value_type type; | |
359 | ||
360 | if (!field_val) { | |
361 | type = LTTNG_EVENT_FIELD_VALUE_TYPE_INVALID; | |
362 | goto end; | |
363 | } | |
364 | ||
365 | type = field_val->type; | |
366 | ||
367 | end: | |
368 | return type; | |
369 | } | |
370 | ||
371 | enum lttng_event_field_value_status | |
372 | lttng_event_field_value_unsigned_int_get_value( | |
373 | const struct lttng_event_field_value *field_val, uint64_t *val) | |
374 | { | |
375 | enum lttng_event_field_value_status status; | |
376 | ||
377 | if (!field_val || !val) { | |
378 | status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID; | |
379 | goto end; | |
380 | } | |
381 | ||
382 | switch (field_val->type) { | |
383 | case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT: | |
384 | *val = container_of(field_val, | |
385 | const struct lttng_event_field_value_uint, | |
386 | parent)->val; | |
387 | break; | |
388 | case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM: | |
9918e00a SM |
389 | { |
390 | const struct lttng_event_field_value_enum *field_val_enum = container_of( | |
391 | field_val, | |
392 | const struct lttng_event_field_value_enum, | |
393 | parent); | |
394 | const struct lttng_event_field_value_enum_uint | |
395 | *field_val_enum_uint = container_of( | |
396 | field_val_enum, | |
397 | const struct lttng_event_field_value_enum_uint, | |
398 | parent); | |
399 | *val = field_val_enum_uint->val; | |
d28fcdec | 400 | break; |
9918e00a | 401 | } |
d28fcdec PP |
402 | default: |
403 | status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID; | |
404 | goto end; | |
405 | } | |
406 | ||
407 | status = LTTNG_EVENT_FIELD_VALUE_STATUS_OK; | |
408 | ||
409 | end: | |
410 | return status; | |
411 | } | |
412 | ||
413 | enum lttng_event_field_value_status | |
414 | lttng_event_field_value_signed_int_get_value( | |
415 | const struct lttng_event_field_value *field_val, int64_t *val) | |
416 | { | |
417 | enum lttng_event_field_value_status status; | |
418 | ||
419 | if (!field_val || !val) { | |
420 | status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID; | |
421 | goto end; | |
422 | } | |
423 | ||
424 | switch (field_val->type) { | |
425 | case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT: | |
426 | *val = container_of(field_val, | |
427 | const struct lttng_event_field_value_int, | |
428 | parent)->val; | |
429 | break; | |
430 | case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM: | |
9918e00a SM |
431 | { |
432 | const struct lttng_event_field_value_enum *field_val_enum = container_of( | |
433 | field_val, | |
434 | const struct lttng_event_field_value_enum, | |
435 | parent); | |
436 | const struct lttng_event_field_value_enum_int | |
437 | *field_val_enum_uint = container_of( | |
438 | field_val_enum, | |
439 | const struct lttng_event_field_value_enum_int, | |
440 | parent); | |
441 | *val = field_val_enum_uint->val; | |
d28fcdec | 442 | break; |
9918e00a | 443 | } |
d28fcdec PP |
444 | default: |
445 | status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID; | |
446 | goto end; | |
447 | } | |
448 | ||
449 | status = LTTNG_EVENT_FIELD_VALUE_STATUS_OK; | |
450 | ||
451 | end: | |
452 | return status; | |
453 | } | |
454 | ||
455 | enum lttng_event_field_value_status | |
456 | lttng_event_field_value_real_get_value( | |
457 | const struct lttng_event_field_value *field_val, double *val) | |
458 | { | |
459 | enum lttng_event_field_value_status status; | |
460 | ||
461 | if (!field_val || field_val->type != LTTNG_EVENT_FIELD_VALUE_TYPE_REAL || | |
462 | !val) { | |
463 | status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID; | |
464 | goto end; | |
465 | } | |
466 | ||
467 | *val = container_of(field_val, | |
468 | const struct lttng_event_field_value_real, parent)->val; | |
469 | status = LTTNG_EVENT_FIELD_VALUE_STATUS_OK; | |
470 | ||
471 | end: | |
472 | return status; | |
473 | } | |
474 | ||
475 | static | |
476 | bool is_enum_field_val(const struct lttng_event_field_value *field_val) | |
477 | { | |
478 | return field_val->type == LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM || | |
479 | field_val->type == LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM; | |
480 | } | |
481 | ||
482 | enum lttng_event_field_value_status | |
483 | lttng_event_field_value_enum_get_label_count( | |
484 | const struct lttng_event_field_value *field_val, | |
485 | unsigned int *count) | |
486 | { | |
487 | enum lttng_event_field_value_status status; | |
488 | ||
489 | if (!field_val || !is_enum_field_val(field_val) || !count) { | |
490 | status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID; | |
491 | goto end; | |
492 | } | |
493 | ||
494 | *count = (unsigned int) lttng_dynamic_pointer_array_get_count( | |
495 | &container_of(field_val, | |
496 | const struct lttng_event_field_value_enum, | |
497 | parent)->labels); | |
498 | status = LTTNG_EVENT_FIELD_VALUE_STATUS_OK; | |
499 | ||
500 | end: | |
501 | return status; | |
502 | } | |
503 | ||
504 | const char *lttng_event_field_value_enum_get_label_at_index( | |
505 | const struct lttng_event_field_value *field_val, | |
506 | unsigned int index) | |
507 | { | |
508 | const char *ret; | |
509 | const struct lttng_event_field_value_enum *enum_field_val; | |
510 | ||
511 | if (!field_val || !is_enum_field_val(field_val)) { | |
512 | ret = NULL; | |
513 | goto end; | |
514 | } | |
515 | ||
516 | enum_field_val = container_of(field_val, | |
517 | const struct lttng_event_field_value_enum, parent); | |
518 | ||
519 | if (index >= lttng_dynamic_pointer_array_get_count(&enum_field_val->labels)) { | |
520 | ret = NULL; | |
521 | goto end; | |
522 | } | |
523 | ||
524 | ret = lttng_dynamic_pointer_array_get_pointer(&enum_field_val->labels, | |
525 | index); | |
526 | ||
527 | end: | |
528 | return ret; | |
529 | } | |
530 | ||
7c920b63 PP |
531 | enum lttng_event_field_value_status lttng_event_field_value_string_get_value( |
532 | const struct lttng_event_field_value *field_val, | |
533 | const char **value) | |
d28fcdec | 534 | { |
7c920b63 | 535 | enum lttng_event_field_value_status status; |
d28fcdec PP |
536 | |
537 | if (!field_val || field_val->type != LTTNG_EVENT_FIELD_VALUE_TYPE_STRING) { | |
7c920b63 | 538 | status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID; |
d28fcdec PP |
539 | goto end; |
540 | } | |
541 | ||
7c920b63 | 542 | *value = container_of(field_val, |
d28fcdec | 543 | const struct lttng_event_field_value_string, parent)->val; |
7c920b63 | 544 | status = LTTNG_EVENT_FIELD_VALUE_STATUS_OK; |
d28fcdec PP |
545 | |
546 | end: | |
7c920b63 | 547 | return status; |
d28fcdec PP |
548 | } |
549 | ||
550 | enum lttng_event_field_value_status lttng_event_field_value_array_get_length( | |
551 | const struct lttng_event_field_value *field_val, | |
552 | unsigned int *length) | |
553 | { | |
554 | enum lttng_event_field_value_status status; | |
555 | ||
556 | if (!field_val || field_val->type != LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY || | |
557 | !length) { | |
558 | status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID; | |
559 | goto end; | |
560 | } | |
561 | ||
562 | *length = (unsigned int) lttng_dynamic_pointer_array_get_count( | |
563 | &container_of(field_val, | |
564 | const struct lttng_event_field_value_array, | |
565 | parent)->elems); | |
566 | status = LTTNG_EVENT_FIELD_VALUE_STATUS_OK; | |
567 | ||
568 | end: | |
569 | return status; | |
570 | } | |
571 | ||
572 | enum lttng_event_field_value_status | |
573 | lttng_event_field_value_array_get_element_at_index( | |
574 | const struct lttng_event_field_value *field_val, | |
575 | unsigned int index, | |
576 | const struct lttng_event_field_value **elem_field_val) | |
577 | { | |
578 | enum lttng_event_field_value_status status; | |
579 | const struct lttng_event_field_value_array *array_field_val; | |
580 | ||
581 | if (!field_val || field_val->type != LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY || | |
582 | !elem_field_val) { | |
583 | status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID; | |
584 | goto end; | |
585 | } | |
586 | ||
587 | array_field_val = container_of(field_val, | |
588 | const struct lttng_event_field_value_array, parent); | |
589 | ||
590 | if (index >= lttng_dynamic_pointer_array_get_count(&array_field_val->elems)) { | |
591 | status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID; | |
592 | goto end; | |
593 | } | |
594 | ||
595 | *elem_field_val = lttng_dynamic_pointer_array_get_pointer( | |
596 | &array_field_val->elems, index); | |
597 | if (*elem_field_val) { | |
598 | status = LTTNG_EVENT_FIELD_VALUE_STATUS_OK; | |
599 | } else { | |
600 | status = LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE; | |
601 | } | |
602 | ||
603 | end: | |
604 | return status; | |
605 | } |