ir: add BT_CTF_BYTE_ORDER_NONE and make it the default trace's native BO
[babeltrace.git] / lib / ctf-ir / trace.c
1 /*
2 * trace.c
3 *
4 * Babeltrace CTF IR - Trace
5 *
6 * Copyright 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
7 *
8 * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 */
28
29 #define BT_LOG_TAG "TRACE"
30 #include <babeltrace/lib-logging-internal.h>
31
32 #include <babeltrace/ctf-ir/trace-internal.h>
33 #include <babeltrace/ctf-ir/clock-class-internal.h>
34 #include <babeltrace/ctf-ir/stream-internal.h>
35 #include <babeltrace/ctf-ir/stream-class-internal.h>
36 #include <babeltrace/ctf-ir/event-internal.h>
37 #include <babeltrace/ctf-ir/event-class.h>
38 #include <babeltrace/ctf-ir/event-class-internal.h>
39 #include <babeltrace/ctf-writer/functor-internal.h>
40 #include <babeltrace/ctf-writer/clock-internal.h>
41 #include <babeltrace/ctf-ir/field-types-internal.h>
42 #include <babeltrace/ctf-ir/attributes-internal.h>
43 #include <babeltrace/ctf-ir/validation-internal.h>
44 #include <babeltrace/ctf-ir/visitor-internal.h>
45 #include <babeltrace/ctf-ir/utils.h>
46 #include <babeltrace/compiler-internal.h>
47 #include <babeltrace/values.h>
48 #include <babeltrace/values-internal.h>
49 #include <babeltrace/ref.h>
50 #include <babeltrace/types.h>
51 #include <babeltrace/endian-internal.h>
52 #include <inttypes.h>
53 #include <stdint.h>
54 #include <string.h>
55 #include <stdlib.h>
56
57 #define DEFAULT_IDENTIFIER_SIZE 128
58 #define DEFAULT_METADATA_STRING_SIZE 4096
59
60 struct listener_wrapper {
61 bt_ctf_listener_cb listener;
62 void *data;
63 };
64
65 struct bt_ctf_trace_is_static_listener_elem {
66 bt_ctf_trace_is_static_listener func;
67 void *data;
68 };
69
70 static
71 void bt_ctf_trace_destroy(struct bt_object *obj);
72 static
73 void bt_ctf_trace_freeze(struct bt_ctf_trace *trace);
74
75 static
76 const unsigned int field_type_aliases_alignments[] = {
77 [FIELD_TYPE_ALIAS_UINT5_T] = 1,
78 [FIELD_TYPE_ALIAS_UINT8_T ... FIELD_TYPE_ALIAS_UINT16_T] = 8,
79 [FIELD_TYPE_ALIAS_UINT27_T] = 1,
80 [FIELD_TYPE_ALIAS_UINT32_T ... FIELD_TYPE_ALIAS_UINT64_T] = 8,
81 };
82
83 static
84 const unsigned int field_type_aliases_sizes[] = {
85 [FIELD_TYPE_ALIAS_UINT5_T] = 5,
86 [FIELD_TYPE_ALIAS_UINT8_T] = 8,
87 [FIELD_TYPE_ALIAS_UINT16_T] = 16,
88 [FIELD_TYPE_ALIAS_UINT27_T] = 27,
89 [FIELD_TYPE_ALIAS_UINT32_T] = 32,
90 [FIELD_TYPE_ALIAS_UINT64_T] = 64,
91 };
92
93 struct bt_ctf_trace *bt_ctf_trace_create(void)
94 {
95 struct bt_ctf_trace *trace = NULL;
96 struct bt_ctf_field_type *packet_header_type = NULL;
97
98 trace = g_new0(struct bt_ctf_trace, 1);
99 if (!trace) {
100 BT_LOGE_STR("Failed to allocate one trace.");
101 goto error;
102 }
103
104 BT_LOGD_STR("Creating trace object.");
105 trace->native_byte_order = BT_CTF_BYTE_ORDER_NONE;
106 bt_object_init(trace, bt_ctf_trace_destroy);
107 trace->clocks = g_ptr_array_new_with_free_func(
108 (GDestroyNotify) bt_put);
109 if (!trace->clocks) {
110 BT_LOGE_STR("Failed to allocate one GPtrArray.");
111 goto error;
112 }
113
114 trace->streams = g_ptr_array_new_with_free_func(
115 (GDestroyNotify) bt_object_release);
116 if (!trace->streams) {
117 BT_LOGE_STR("Failed to allocate one GPtrArray.");
118 goto error;
119 }
120
121 trace->stream_classes = g_ptr_array_new_with_free_func(
122 (GDestroyNotify) bt_object_release);
123 if (!trace->stream_classes) {
124 BT_LOGE_STR("Failed to allocate one GPtrArray.");
125 goto error;
126 }
127
128 packet_header_type = bt_ctf_field_type_structure_create();
129 if (!packet_header_type) {
130 goto error;
131 }
132
133 BT_MOVE(trace->packet_header_type, packet_header_type);
134
135 /* Create the environment array object */
136 trace->environment = bt_ctf_attributes_create();
137 if (!trace->environment) {
138 BT_LOGE_STR("Cannot create empty attributes object.");
139 goto error;
140 }
141
142 trace->listeners = g_ptr_array_new_with_free_func(
143 (GDestroyNotify) g_free);
144 if (!trace->listeners) {
145 BT_LOGE_STR("Failed to allocate one GPtrArray.");
146 goto error;
147 }
148
149 trace->is_static_listeners = g_array_new(FALSE, TRUE,
150 sizeof(struct bt_ctf_trace_is_static_listener_elem));
151 if (!trace->is_static_listeners) {
152 BT_LOGE_STR("Failed to allocate one GArray.");
153 goto error;
154 }
155
156 BT_LOGD("Created trace object: addr=%p", trace);
157 return trace;
158
159 error:
160 BT_PUT(trace);
161 bt_put(packet_header_type);
162 return trace;
163 }
164
165 const char *bt_ctf_trace_get_name(struct bt_ctf_trace *trace)
166 {
167 const char *name = NULL;
168
169 if (!trace) {
170 BT_LOGW_STR("Invalid parameter: trace is NULL.");
171 goto end;
172 }
173
174 if (!trace->name) {
175 goto end;
176 }
177
178 name = trace->name->str;
179 end:
180 return name;
181 }
182
183 int bt_ctf_trace_set_name(struct bt_ctf_trace *trace, const char *name)
184 {
185 int ret = 0;
186
187 if (!trace) {
188 BT_LOGW_STR("Invalid parameter: trace is NULL.");
189 ret = -1;
190 goto end;
191 }
192
193 if (!name) {
194 BT_LOGW_STR("Invalid parameter: name is NULL.");
195 ret = -1;
196 goto end;
197 }
198
199 if (trace->frozen) {
200 BT_LOGW("Invalid parameter: trace is frozen: "
201 "addr=%p, name=\"%s\"",
202 trace, bt_ctf_trace_get_name(trace));
203 ret = -1;
204 goto end;
205 }
206
207 trace->name = trace->name ? g_string_assign(trace->name, name) :
208 g_string_new(name);
209 if (!trace->name) {
210 BT_LOGE_STR("Failed to allocate one GString.");
211 ret = -1;
212 goto end;
213 }
214
215 BT_LOGV("Set trace's name: addr=%p, name=\"%s\"", trace, name);
216
217 end:
218 return ret;
219 }
220
221 const unsigned char *bt_ctf_trace_get_uuid(struct bt_ctf_trace *trace)
222 {
223 return trace && trace->uuid_set ? trace->uuid : NULL;
224 }
225
226 int bt_ctf_trace_set_uuid(struct bt_ctf_trace *trace, const unsigned char *uuid)
227 {
228 int ret = 0;
229
230 if (!trace) {
231 BT_LOGW_STR("Invalid parameter: trace is NULL.");
232 ret = -1;
233 goto end;
234 }
235
236 if (!uuid) {
237 BT_LOGW_STR("Invalid parameter: UUID is NULL.");
238 ret = -1;
239 goto end;
240 }
241
242 if (trace->frozen) {
243 BT_LOGW("Invalid parameter: trace is frozen: "
244 "addr=%p, name=\"%s\"",
245 trace, bt_ctf_trace_get_name(trace));
246 ret = -1;
247 goto end;
248 }
249
250 memcpy(trace->uuid, uuid, sizeof(uuid_t));
251 trace->uuid_set = BT_TRUE;
252 BT_LOGV("Set trace's UUID: addr=%p, name=\"%s\", "
253 "uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"",
254 trace, bt_ctf_trace_get_name(trace),
255 (unsigned int) uuid[0],
256 (unsigned int) uuid[1],
257 (unsigned int) uuid[2],
258 (unsigned int) uuid[3],
259 (unsigned int) uuid[4],
260 (unsigned int) uuid[5],
261 (unsigned int) uuid[6],
262 (unsigned int) uuid[7],
263 (unsigned int) uuid[8],
264 (unsigned int) uuid[9],
265 (unsigned int) uuid[10],
266 (unsigned int) uuid[11],
267 (unsigned int) uuid[12],
268 (unsigned int) uuid[13],
269 (unsigned int) uuid[14],
270 (unsigned int) uuid[15]);
271
272 end:
273 return ret;
274 }
275
276 void bt_ctf_trace_destroy(struct bt_object *obj)
277 {
278 struct bt_ctf_trace *trace;
279
280 trace = container_of(obj, struct bt_ctf_trace, base);
281
282 BT_LOGD("Destroying trace object: addr=%p, name=\"%s\"",
283 trace, bt_ctf_trace_get_name(trace));
284
285 if (trace->environment) {
286 BT_LOGD_STR("Destroying environment attributes.");
287 bt_ctf_attributes_destroy(trace->environment);
288 }
289
290 if (trace->name) {
291 g_string_free(trace->name, TRUE);
292 }
293
294 if (trace->clocks) {
295 BT_LOGD_STR("Putting clock classes.");
296 g_ptr_array_free(trace->clocks, TRUE);
297 }
298
299 if (trace->streams) {
300 BT_LOGD_STR("Destroying streams.");
301 g_ptr_array_free(trace->streams, TRUE);
302 }
303
304 if (trace->stream_classes) {
305 BT_LOGD_STR("Destroying stream classes.");
306 g_ptr_array_free(trace->stream_classes, TRUE);
307 }
308
309 if (trace->listeners) {
310 g_ptr_array_free(trace->listeners, TRUE);
311 }
312
313 if (trace->is_static_listeners) {
314 g_array_free(trace->is_static_listeners, TRUE);
315 }
316
317 BT_LOGD_STR("Putting packet header field type.");
318 bt_put(trace->packet_header_type);
319 g_free(trace);
320 }
321
322 int bt_ctf_trace_set_environment_field(struct bt_ctf_trace *trace,
323 const char *name, struct bt_value *value)
324 {
325 int ret = 0;
326
327 if (!trace) {
328 BT_LOGW_STR("Invalid parameter: trace is NULL.");
329 ret = -1;
330 goto end;
331 }
332
333 if (!name) {
334 BT_LOGW_STR("Invalid parameter: name is NULL.");
335 ret = -1;
336 goto end;
337 }
338
339 if (!value) {
340 BT_LOGW_STR("Invalid parameter: value is NULL.");
341 ret = -1;
342 goto end;
343 }
344
345 if (bt_ctf_validate_identifier(name)) {
346 BT_LOGW("Invalid parameter: environment field's name is not a valid CTF identifier: "
347 "trace-addr=%p, trace-name=\"%s\", "
348 "env-name=\"%s\"",
349 trace, bt_ctf_trace_get_name(trace), name);
350 ret = -1;
351 goto end;
352 }
353
354 if (!bt_value_is_integer(value) && !bt_value_is_string(value)) {
355 BT_LOGW("Invalid parameter: environment field's value is not an integer or string value: "
356 "trace-addr=%p, trace-name=\"%s\", "
357 "env-name=\"%s\", env-value-type=%s",
358 trace, bt_ctf_trace_get_name(trace), name,
359 bt_value_type_string(bt_value_get_type(value)));
360 ret = -1;
361 goto end;
362 }
363
364 if (trace->is_static) {
365 BT_LOGW("Invalid parameter: trace is static: "
366 "addr=%p, name=\"%s\"",
367 trace, bt_ctf_trace_get_name(trace));
368 ret = -1;
369 goto end;
370 }
371
372 if (trace->frozen) {
373 /*
374 * New environment fields may be added to a frozen trace,
375 * but existing fields may not be changed.
376 *
377 * The object passed is frozen like all other attributes.
378 */
379 struct bt_value *attribute =
380 bt_ctf_attributes_get_field_value_by_name(
381 trace->environment, name);
382
383 if (attribute) {
384 BT_LOGW("Invalid parameter: trace is frozen and environment field already exists with this name: "
385 "trace-addr=%p, trace-name=\"%s\", "
386 "env-name=\"%s\"",
387 trace, bt_ctf_trace_get_name(trace), name);
388 BT_PUT(attribute);
389 ret = -1;
390 goto end;
391 }
392
393 bt_value_freeze(value);
394 }
395
396 ret = bt_ctf_attributes_set_field_value(trace->environment, name,
397 value);
398 if (ret) {
399 BT_LOGE("Cannot set environment field's value: "
400 "trace-addr=%p, trace-name=\"%s\", "
401 "env-name=\"%s\"",
402 trace, bt_ctf_trace_get_name(trace), name);
403 } else {
404 BT_LOGV("Set environment field's value: "
405 "trace-addr=%p, trace-name=\"%s\", "
406 "env-name=\"%s\", value-addr=%p",
407 trace, bt_ctf_trace_get_name(trace), name, value);
408 }
409
410 end:
411 return ret;
412 }
413
414 int bt_ctf_trace_set_environment_field_string(struct bt_ctf_trace *trace,
415 const char *name, const char *value)
416 {
417 int ret = 0;
418 struct bt_value *env_value_string_obj = NULL;
419
420 if (!value) {
421 BT_LOGW_STR("Invalid parameter: value is NULL.");
422 ret = -1;
423 goto end;
424 }
425
426 env_value_string_obj = bt_value_string_create_init(value);
427 if (!env_value_string_obj) {
428 BT_LOGE_STR("Cannot create string value object.");
429 ret = -1;
430 goto end;
431 }
432
433 /* bt_ctf_trace_set_environment_field() logs errors */
434 ret = bt_ctf_trace_set_environment_field(trace, name,
435 env_value_string_obj);
436
437 end:
438 bt_put(env_value_string_obj);
439 return ret;
440 }
441
442 int bt_ctf_trace_set_environment_field_integer(struct bt_ctf_trace *trace,
443 const char *name, int64_t value)
444 {
445 int ret = 0;
446 struct bt_value *env_value_integer_obj = NULL;
447
448 env_value_integer_obj = bt_value_integer_create_init(value);
449 if (!env_value_integer_obj) {
450 BT_LOGE_STR("Cannot create integer value object.");
451 ret = -1;
452 goto end;
453 }
454
455 /* bt_ctf_trace_set_environment_field() logs errors */
456 ret = bt_ctf_trace_set_environment_field(trace, name,
457 env_value_integer_obj);
458
459 end:
460 bt_put(env_value_integer_obj);
461 return ret;
462 }
463
464 int64_t bt_ctf_trace_get_environment_field_count(struct bt_ctf_trace *trace)
465 {
466 int64_t ret = 0;
467
468 if (!trace) {
469 BT_LOGW_STR("Invalid parameter: trace is NULL.");
470 ret = (int64_t) -1;
471 goto end;
472 }
473
474 ret = bt_ctf_attributes_get_count(trace->environment);
475 assert(ret >= 0);
476
477 end:
478 return ret;
479 }
480
481 const char *
482 bt_ctf_trace_get_environment_field_name_by_index(struct bt_ctf_trace *trace,
483 uint64_t index)
484 {
485 const char *ret = NULL;
486
487 if (!trace) {
488 BT_LOGW_STR("Invalid parameter: trace is NULL.");
489 goto end;
490 }
491
492 ret = bt_ctf_attributes_get_field_name(trace->environment, index);
493
494 end:
495 return ret;
496 }
497
498 struct bt_value *bt_ctf_trace_get_environment_field_value_by_index(
499 struct bt_ctf_trace *trace, uint64_t index)
500 {
501 struct bt_value *ret = NULL;
502
503 if (!trace) {
504 BT_LOGW_STR("Invalid parameter: trace is NULL.");
505 goto end;
506 }
507
508 ret = bt_ctf_attributes_get_field_value(trace->environment, index);
509
510 end:
511 return ret;
512 }
513
514 struct bt_value *bt_ctf_trace_get_environment_field_value_by_name(
515 struct bt_ctf_trace *trace, const char *name)
516 {
517 struct bt_value *ret = NULL;
518
519 if (!trace) {
520 BT_LOGW_STR("Invalid parameter: trace is NULL.");
521 goto end;
522 }
523
524 if (!name) {
525 BT_LOGW_STR("Invalid parameter: name is NULL.");
526 goto end;
527 }
528
529 ret = bt_ctf_attributes_get_field_value_by_name(trace->environment,
530 name);
531
532 end:
533 return ret;
534 }
535
536 int bt_ctf_trace_add_clock_class(struct bt_ctf_trace *trace,
537 struct bt_ctf_clock_class *clock_class)
538 {
539 int ret = 0;
540
541 if (!trace) {
542 BT_LOGW_STR("Invalid parameter: trace is NULL.");
543 ret = -1;
544 goto end;
545 }
546
547 if (trace->is_static) {
548 BT_LOGW("Invalid parameter: trace is static: "
549 "addr=%p, name=\"%s\"",
550 trace, bt_ctf_trace_get_name(trace));
551 ret = -1;
552 goto end;
553 }
554
555 if (!bt_ctf_clock_class_is_valid(clock_class)) {
556 BT_LOGW("Invalid parameter: clock class is invalid: "
557 "trace-addr=%p, trace-name=\"%s\", "
558 "clock-class-addr=%p, clock-class-name=\"%s\"",
559 trace, bt_ctf_trace_get_name(trace),
560 clock_class, bt_ctf_clock_class_get_name(clock_class));
561 ret = -1;
562 goto end;
563 }
564
565 /* Check for duplicate clock classes */
566 if (bt_ctf_trace_has_clock_class(trace, clock_class)) {
567 BT_LOGW("Invalid parameter: clock class already exists in trace: "
568 "trace-addr=%p, trace-name=\"%s\", "
569 "clock-class-addr=%p, clock-class-name=\"%s\"",
570 trace, bt_ctf_trace_get_name(trace),
571 clock_class, bt_ctf_clock_class_get_name(clock_class));
572 ret = -1;
573 goto end;
574 }
575
576 bt_get(clock_class);
577 g_ptr_array_add(trace->clocks, clock_class);
578
579 if (trace->frozen) {
580 BT_LOGV_STR("Freezing added clock class because trace is frozen.");
581 bt_ctf_clock_class_freeze(clock_class);
582 }
583
584 BT_LOGV("Added clock class to trace: "
585 "trace-addr=%p, trace-name=\"%s\", "
586 "clock-class-addr=%p, clock-class-name=\"%s\"",
587 trace, bt_ctf_trace_get_name(trace),
588 clock_class, bt_ctf_clock_class_get_name(clock_class));
589
590 end:
591 return ret;
592 }
593
594 int64_t bt_ctf_trace_get_clock_class_count(struct bt_ctf_trace *trace)
595 {
596 int64_t ret = (int64_t) -1;
597
598 if (!trace) {
599 BT_LOGW_STR("Invalid parameter: trace is NULL.");
600 goto end;
601 }
602
603 ret = trace->clocks->len;
604 end:
605 return ret;
606 }
607
608 struct bt_ctf_clock_class *bt_ctf_trace_get_clock_class_by_index(
609 struct bt_ctf_trace *trace, uint64_t index)
610 {
611 struct bt_ctf_clock_class *clock_class = NULL;
612
613 if (!trace) {
614 BT_LOGW_STR("Invalid parameter: trace is NULL.");
615 goto end;
616 }
617
618 if (index >= trace->clocks->len) {
619 BT_LOGW("Invalid parameter: index is out of bounds: "
620 "addr=%p, name=\"%s\", "
621 "index=%" PRIu64 ", count=%u",
622 trace, bt_ctf_trace_get_name(trace),
623 index, trace->clocks->len);
624 goto end;
625 }
626
627 clock_class = g_ptr_array_index(trace->clocks, index);
628 bt_get(clock_class);
629 end:
630 return clock_class;
631 }
632
633 static
634 bool packet_header_field_type_is_valid(struct bt_ctf_trace *trace,
635 struct bt_ctf_field_type *packet_header_type)
636 {
637 int ret;
638 bool is_valid = true;
639 struct bt_ctf_field_type *field_type = NULL;
640
641 if (!packet_header_type) {
642 /*
643 * No packet header field type: trace must have only
644 * one stream. At this point the stream class being
645 * added is not part of the trace yet, so we validate
646 * that the trace contains no stream classes yet.
647 */
648 if (trace->stream_classes->len >= 1) {
649 BT_LOGW_STR("Invalid packet header field type: "
650 "packet header field type does not exist but there's more than one stream class in the trace.");
651 goto invalid;
652 }
653
654 /* No packet header field type: valid at this point */
655 goto end;
656 }
657
658 /* Packet header field type, if it exists, must be a structure */
659 if (!bt_ctf_field_type_is_structure(packet_header_type)) {
660 BT_LOGW("Invalid packet header field type: must be a structure field type if it exists: "
661 "ft-addr=%p, ft-id=%s",
662 packet_header_type,
663 bt_ctf_field_type_id_string(packet_header_type->id));
664 goto invalid;
665 }
666
667 /*
668 * If there's a `magic` field, it must be a 32-bit unsigned
669 * integer field type. Also it must be the first field of the
670 * packet header field type.
671 */
672 field_type = bt_ctf_field_type_structure_get_field_type_by_name(
673 packet_header_type, "magic");
674 if (field_type) {
675 const char *field_name;
676
677 if (!bt_ctf_field_type_is_integer(field_type)) {
678 BT_LOGW("Invalid packet header field type: `magic` field must be an integer field type: "
679 "magic-ft-addr=%p, magic-ft-id=%s",
680 field_type,
681 bt_ctf_field_type_id_string(field_type->id));
682 goto invalid;
683 }
684
685 if (bt_ctf_field_type_integer_is_signed(field_type)) {
686 BT_LOGW("Invalid packet header field type: `magic` field must be an unsigned integer field type: "
687 "magic-ft-addr=%p", field_type);
688 goto invalid;
689 }
690
691 if (bt_ctf_field_type_integer_get_size(field_type) != 32) {
692 BT_LOGW("Invalid packet header field type: `magic` field must be a 32-bit unsigned integer field type: "
693 "magic-ft-addr=%p, magic-ft-size=%u",
694 field_type,
695 bt_ctf_field_type_integer_get_size(field_type));
696 goto invalid;
697 }
698
699 ret = bt_ctf_field_type_structure_get_field_by_index(
700 packet_header_type, &field_name, NULL, 0);
701 assert(ret == 0);
702
703 if (strcmp(field_name, "magic") != 0) {
704 BT_LOGW("Invalid packet header field type: `magic` field must be the first field: "
705 "magic-ft-addr=%p, first-field-name=\"%s\"",
706 field_type, field_name);
707 goto invalid;
708 }
709
710 BT_PUT(field_type);
711 }
712
713 /*
714 * If there's a `uuid` field, it must be an array field type of
715 * length 16 with an 8-bit unsigned integer element field type.
716 */
717 field_type = bt_ctf_field_type_structure_get_field_type_by_name(
718 packet_header_type, "uuid");
719 if (field_type) {
720 struct bt_ctf_field_type *elem_ft;
721
722 if (!bt_ctf_field_type_is_array(field_type)) {
723 BT_LOGW("Invalid packet header field type: `uuid` field must be an array field type: "
724 "uuid-ft-addr=%p, uuid-ft-id=%s",
725 field_type,
726 bt_ctf_field_type_id_string(field_type->id));
727 goto invalid;
728 }
729
730 if (bt_ctf_field_type_array_get_length(field_type) != 16) {
731 BT_LOGW("Invalid packet header field type: `uuid` array field type's length must be 16: "
732 "uuid-ft-addr=%p, uuid-ft-length=%" PRId64,
733 field_type,
734 bt_ctf_field_type_array_get_length(field_type));
735 goto invalid;
736 }
737
738 elem_ft = bt_ctf_field_type_array_get_element_type(field_type);
739 assert(elem_ft);
740
741 if (!bt_ctf_field_type_is_integer(elem_ft)) {
742 BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an integer field type: "
743 "elem-ft-addr=%p, elem-ft-id=%s",
744 elem_ft,
745 bt_ctf_field_type_id_string(elem_ft->id));
746 bt_put(elem_ft);
747 goto invalid;
748 }
749
750 if (bt_ctf_field_type_integer_is_signed(elem_ft)) {
751 BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an unsigned integer field type: "
752 "elem-ft-addr=%p", elem_ft);
753 bt_put(elem_ft);
754 goto invalid;
755 }
756
757 if (bt_ctf_field_type_integer_get_size(elem_ft) != 8) {
758 BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an 8-bit unsigned integer field type: "
759 "elem-ft-addr=%p, elem-ft-size=%u",
760 elem_ft,
761 bt_ctf_field_type_integer_get_size(elem_ft));
762 bt_put(elem_ft);
763 goto invalid;
764 }
765
766 bt_put(elem_ft);
767 BT_PUT(field_type);
768 }
769
770 /*
771 * The `stream_id` field must exist if there's more than one
772 * stream classes in the trace.
773 */
774 field_type = bt_ctf_field_type_structure_get_field_type_by_name(
775 packet_header_type, "stream_id");
776
777 if (!field_type && trace->stream_classes->len >= 1) {
778 BT_LOGW_STR("Invalid packet header field type: "
779 "`stream_id` field does not exist but there's more than one stream class in the trace.");
780 goto invalid;
781 }
782
783 /*
784 * If there's a `stream_id` field, it must be an unsigned
785 * integer field type.
786 */
787 if (field_type) {
788 if (!bt_ctf_field_type_is_integer(field_type)) {
789 BT_LOGW("Invalid packet header field type: `stream_id` field must be an integer field type: "
790 "stream-id-ft-addr=%p, stream-id-ft-id=%s",
791 field_type,
792 bt_ctf_field_type_id_string(field_type->id));
793 goto invalid;
794 }
795
796 if (bt_ctf_field_type_integer_is_signed(field_type)) {
797 BT_LOGW("Invalid packet header field type: `stream_id` field must be an unsigned integer field type: "
798 "stream-id-ft-addr=%p", field_type);
799 goto invalid;
800 }
801
802 BT_PUT(field_type);
803 }
804
805 goto end;
806
807 invalid:
808 is_valid = false;
809
810 end:
811 bt_put(field_type);
812 return is_valid;
813 }
814
815 static
816 bool packet_context_field_type_is_valid(struct bt_ctf_trace *trace,
817 struct bt_ctf_stream_class *stream_class,
818 struct bt_ctf_field_type *packet_context_type)
819 {
820 bool is_valid = true;
821 struct bt_ctf_field_type *field_type = NULL;
822
823 if (!packet_context_type) {
824 /* No packet context field type: valid at this point */
825 goto end;
826 }
827
828 /* Packet context field type, if it exists, must be a structure */
829 if (!bt_ctf_field_type_is_structure(packet_context_type)) {
830 BT_LOGW("Invalid packet context field type: must be a structure field type if it exists: "
831 "ft-addr=%p, ft-id=%s",
832 packet_context_type,
833 bt_ctf_field_type_id_string(packet_context_type->id));
834 goto invalid;
835 }
836
837 /*
838 * If there's a `packet_size` field, it must be an unsigned
839 * integer field type.
840 */
841 field_type = bt_ctf_field_type_structure_get_field_type_by_name(
842 packet_context_type, "packet_size");
843 if (field_type) {
844 if (!bt_ctf_field_type_is_integer(field_type)) {
845 BT_LOGW("Invalid packet context field type: `packet_size` field must be an integer field type: "
846 "packet-size-ft-addr=%p, packet-size-ft-id=%s",
847 field_type,
848 bt_ctf_field_type_id_string(field_type->id));
849 goto invalid;
850 }
851
852 if (bt_ctf_field_type_integer_is_signed(field_type)) {
853 BT_LOGW("Invalid packet context field type: `packet_size` field must be an unsigned integer field type: "
854 "packet-size-ft-addr=%p", field_type);
855 goto invalid;
856 }
857
858 BT_PUT(field_type);
859 }
860
861 /*
862 * If there's a `content_size` field, it must be an unsigned
863 * integer field type.
864 */
865 field_type = bt_ctf_field_type_structure_get_field_type_by_name(
866 packet_context_type, "content_size");
867 if (field_type) {
868 if (!bt_ctf_field_type_is_integer(field_type)) {
869 BT_LOGW("Invalid packet context field type: `content_size` field must be an integer field type: "
870 "content-size-ft-addr=%p, content-size-ft-id=%s",
871 field_type,
872 bt_ctf_field_type_id_string(field_type->id));
873 goto invalid;
874 }
875
876 if (bt_ctf_field_type_integer_is_signed(field_type)) {
877 BT_LOGW("Invalid packet context field type: `content_size` field must be an unsigned integer field type: "
878 "content-size-ft-addr=%p", field_type);
879 goto invalid;
880 }
881
882 BT_PUT(field_type);
883 }
884
885 /*
886 * If there's a `events_discarded` field, it must be an unsigned
887 * integer field type.
888 */
889 field_type = bt_ctf_field_type_structure_get_field_type_by_name(
890 packet_context_type, "events_discarded");
891 if (field_type) {
892 if (!bt_ctf_field_type_is_integer(field_type)) {
893 BT_LOGW("Invalid packet context field type: `events_discarded` field must be an integer field type: "
894 "events-discarded-ft-addr=%p, events-discarded-ft-id=%s",
895 field_type,
896 bt_ctf_field_type_id_string(field_type->id));
897 goto invalid;
898 }
899
900 if (bt_ctf_field_type_integer_is_signed(field_type)) {
901 BT_LOGW("Invalid packet context field type: `events_discarded` field must be an unsigned integer field type: "
902 "events-discarded-ft-addr=%p", field_type);
903 goto invalid;
904 }
905
906 BT_PUT(field_type);
907 }
908
909 /*
910 * If there's a `timestamp_begin` field, it must be an unsigned
911 * integer field type. Also, if the trace is not a CTF writer's
912 * trace, then we cannot automatically set the mapped clock
913 * class of this field, so it must have a mapped clock class.
914 */
915 field_type = bt_ctf_field_type_structure_get_field_type_by_name(
916 packet_context_type, "timestamp_begin");
917 if (field_type) {
918 if (!bt_ctf_field_type_is_integer(field_type)) {
919 BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be an integer field type: "
920 "timestamp-begin-ft-addr=%p, timestamp-begin-ft-id=%s",
921 field_type,
922 bt_ctf_field_type_id_string(field_type->id));
923 goto invalid;
924 }
925
926 if (bt_ctf_field_type_integer_is_signed(field_type)) {
927 BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be an unsigned integer field type: "
928 "timestamp-begin-ft-addr=%p", field_type);
929 goto invalid;
930 }
931
932 if (!trace->is_created_by_writer) {
933 struct bt_ctf_clock_class *clock_class =
934 bt_ctf_field_type_integer_get_mapped_clock_class(
935 field_type);
936
937 bt_put(clock_class);
938 if (!clock_class) {
939 BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be mapped to a clock class: "
940 "timestamp-begin-ft-addr=%p", field_type);
941 goto invalid;
942 }
943 }
944
945 BT_PUT(field_type);
946 }
947
948 /*
949 * If there's a `timestamp_end` field, it must be an unsigned
950 * integer field type. Also, if the trace is not a CTF writer's
951 * trace, then we cannot automatically set the mapped clock
952 * class of this field, so it must have a mapped clock class.
953 */
954 field_type = bt_ctf_field_type_structure_get_field_type_by_name(
955 packet_context_type, "timestamp_end");
956 if (field_type) {
957 if (!bt_ctf_field_type_is_integer(field_type)) {
958 BT_LOGW("Invalid packet context field type: `timestamp_end` field must be an integer field type: "
959 "timestamp-end-ft-addr=%p, timestamp-end-ft-id=%s",
960 field_type,
961 bt_ctf_field_type_id_string(field_type->id));
962 goto invalid;
963 }
964
965 if (bt_ctf_field_type_integer_is_signed(field_type)) {
966 BT_LOGW("Invalid packet context field type: `timestamp_end` field must be an unsigned integer field type: "
967 "timestamp-end-ft-addr=%p", field_type);
968 goto invalid;
969 }
970
971 if (!trace->is_created_by_writer) {
972 struct bt_ctf_clock_class *clock_class =
973 bt_ctf_field_type_integer_get_mapped_clock_class(
974 field_type);
975
976 bt_put(clock_class);
977 if (!clock_class) {
978 BT_LOGW("Invalid packet context field type: `timestamp_end` field must be mapped to a clock class: "
979 "timestamp-end-ft-addr=%p", field_type);
980 goto invalid;
981 }
982 }
983
984 BT_PUT(field_type);
985 }
986
987 goto end;
988
989 invalid:
990 is_valid = false;
991
992 end:
993 bt_put(field_type);
994 return is_valid;
995 }
996
997 static
998 bool event_header_field_type_is_valid(struct bt_ctf_trace *trace,
999 struct bt_ctf_stream_class *stream_class,
1000 struct bt_ctf_field_type *event_header_type)
1001 {
1002 bool is_valid = true;
1003 struct bt_ctf_field_type *field_type = NULL;
1004
1005 /*
1006 * We do not validate that the `timestamp` field exists here
1007 * because CTF does not require this exact name to be mapped to
1008 * a clock class.
1009 */
1010
1011 if (!event_header_type) {
1012 /*
1013 * No event header field type: stream class must have
1014 * only one event class.
1015 */
1016 if (bt_ctf_stream_class_get_event_class_count(stream_class) > 1) {
1017 BT_LOGW_STR("Invalid event header field type: "
1018 "event header field type does not exist but there's more than one event class in the stream class.");
1019 goto invalid;
1020 }
1021
1022 /* No event header field type: valid at this point */
1023 goto end;
1024 }
1025
1026 /* Event header field type, if it exists, must be a structure */
1027 if (!bt_ctf_field_type_is_structure(event_header_type)) {
1028 BT_LOGW("Invalid event header field type: must be a structure field type if it exists: "
1029 "ft-addr=%p, ft-id=%s",
1030 event_header_type,
1031 bt_ctf_field_type_id_string(event_header_type->id));
1032 goto invalid;
1033 }
1034
1035 /*
1036 * If there's an `id` field, it must be an unsigned integer
1037 * field type or an enumeration field type with an unsigned
1038 * integer container field type.
1039 */
1040 field_type = bt_ctf_field_type_structure_get_field_type_by_name(
1041 event_header_type, "id");
1042 if (field_type) {
1043 struct bt_ctf_field_type *int_ft;
1044
1045 if (bt_ctf_field_type_is_integer(field_type)) {
1046 int_ft = bt_get(field_type);
1047 } else if (bt_ctf_field_type_is_enumeration(field_type)) {
1048 int_ft = bt_ctf_field_type_enumeration_get_container_type(
1049 field_type);
1050 } else {
1051 BT_LOGW("Invalid event header field type: `id` field must be an integer or enumeration field type: "
1052 "id-ft-addr=%p, id-ft-id=%s",
1053 field_type,
1054 bt_ctf_field_type_id_string(field_type->id));
1055 goto invalid;
1056 }
1057
1058 assert(int_ft);
1059 if (bt_ctf_field_type_integer_is_signed(int_ft)) {
1060 BT_LOGW("Invalid event header field type: `id` field must be an unsigned integer or enumeration field type: "
1061 "id-ft-addr=%p", int_ft);
1062 goto invalid;
1063 }
1064
1065 bt_put(int_ft);
1066 BT_PUT(field_type);
1067 }
1068
1069 goto end;
1070
1071 invalid:
1072 is_valid = false;
1073
1074 end:
1075 bt_put(field_type);
1076 return is_valid;
1077 }
1078
1079 int bt_ctf_trace_add_stream_class(struct bt_ctf_trace *trace,
1080 struct bt_ctf_stream_class *stream_class)
1081 {
1082 int ret;
1083 int64_t i;
1084 int64_t stream_id;
1085 struct bt_ctf_validation_output trace_sc_validation_output = { 0 };
1086 struct bt_ctf_validation_output *ec_validation_outputs = NULL;
1087 const enum bt_ctf_validation_flag trace_sc_validation_flags =
1088 BT_CTF_VALIDATION_FLAG_TRACE |
1089 BT_CTF_VALIDATION_FLAG_STREAM;
1090 const enum bt_ctf_validation_flag ec_validation_flags =
1091 BT_CTF_VALIDATION_FLAG_EVENT;
1092 struct bt_ctf_field_type *packet_header_type = NULL;
1093 struct bt_ctf_field_type *packet_context_type = NULL;
1094 struct bt_ctf_field_type *event_header_type = NULL;
1095 struct bt_ctf_field_type *stream_event_ctx_type = NULL;
1096 int64_t event_class_count;
1097 struct bt_ctf_trace *current_parent_trace = NULL;
1098
1099 if (!trace) {
1100 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1101 ret = -1;
1102 goto end;
1103 }
1104
1105 if (!stream_class) {
1106 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
1107 ret = -1;
1108 goto end;
1109 }
1110
1111 if (trace->is_static) {
1112 BT_LOGW_STR("Invalid parameter: trace is static.");
1113 ret = -1;
1114 goto end;
1115 }
1116
1117 BT_LOGD("Adding stream class to trace: "
1118 "trace-addr=%p, trace-name=\"%s\", "
1119 "stream-class-addr=%p, stream-class-name=\"%s\", "
1120 "stream-class-id=%" PRId64,
1121 trace, bt_ctf_trace_get_name(trace),
1122 stream_class, bt_ctf_stream_class_get_name(stream_class),
1123 bt_ctf_stream_class_get_id(stream_class));
1124
1125 current_parent_trace = bt_ctf_stream_class_get_trace(stream_class);
1126 if (current_parent_trace) {
1127 /* Stream class is already associated to a trace, abort. */
1128 BT_LOGW("Invalid parameter: stream class is already part of a trace: "
1129 "stream-class-trace-addr=%p, "
1130 "stream-class-trace-name=\"%s\"",
1131 current_parent_trace,
1132 bt_ctf_trace_get_name(current_parent_trace));
1133 ret = -1;
1134 goto end;
1135 }
1136
1137 event_class_count =
1138 bt_ctf_stream_class_get_event_class_count(stream_class);
1139 assert(event_class_count >= 0);
1140
1141 if (stream_class->clock) {
1142 struct bt_ctf_clock_class *stream_clock_class =
1143 stream_class->clock->clock_class;
1144
1145 if (trace->is_created_by_writer) {
1146 /*
1147 * Make sure this clock was also added to the
1148 * trace (potentially through its CTF writer
1149 * owner).
1150 */
1151 size_t i;
1152
1153 for (i = 0; i < trace->clocks->len; i++) {
1154 if (trace->clocks->pdata[i] ==
1155 stream_clock_class) {
1156 /* Found! */
1157 break;
1158 }
1159 }
1160
1161 if (i == trace->clocks->len) {
1162 /* Not found */
1163 BT_LOGW("Stream class's clock's class is not part of the trace: "
1164 "clock-class-addr=%p, clock-class-name=\"%s\"",
1165 stream_clock_class,
1166 bt_ctf_clock_class_get_name(stream_clock_class));
1167 ret = -1;
1168 goto end;
1169 }
1170 } else {
1171 /*
1172 * This trace was NOT created by a CTF writer,
1173 * thus do not allow the stream class to add to
1174 * have a clock at all. Those are two
1175 * independent APIs (non-writer and writer
1176 * APIs), and isolating them simplifies things.
1177 */
1178 BT_LOGW("Cannot add stream class with a clock to a trace which was not created by a CTF writer object: "
1179 "clock-class-addr=%p, clock-class-name=\"%s\"",
1180 stream_clock_class,
1181 bt_ctf_clock_class_get_name(stream_clock_class));
1182 ret = -1;
1183 goto end;
1184 }
1185 }
1186
1187 /*
1188 * We're about to freeze both the trace and the stream class.
1189 * Also, each event class contained in this stream class are
1190 * already frozen.
1191 *
1192 * This trace, this stream class, and all its event classes
1193 * should be valid at this point.
1194 *
1195 * Validate trace and stream class first, then each event
1196 * class of this stream class can be validated individually.
1197 */
1198 packet_header_type =
1199 bt_ctf_trace_get_packet_header_type(trace);
1200 packet_context_type =
1201 bt_ctf_stream_class_get_packet_context_type(stream_class);
1202 event_header_type =
1203 bt_ctf_stream_class_get_event_header_type(stream_class);
1204 stream_event_ctx_type =
1205 bt_ctf_stream_class_get_event_context_type(stream_class);
1206
1207 BT_LOGD("Validating trace and stream class field types.");
1208 ret = bt_ctf_validate_class_types(trace->environment,
1209 packet_header_type, packet_context_type, event_header_type,
1210 stream_event_ctx_type, NULL, NULL, trace->valid,
1211 stream_class->valid, 1, &trace_sc_validation_output,
1212 trace_sc_validation_flags);
1213 BT_PUT(packet_header_type);
1214 BT_PUT(packet_context_type);
1215 BT_PUT(event_header_type);
1216 BT_PUT(stream_event_ctx_type);
1217
1218 if (ret) {
1219 /*
1220 * This means something went wrong during the validation
1221 * process, not that the objects are invalid.
1222 */
1223 BT_LOGE("Failed to validate trace and stream class field types: "
1224 "ret=%d", ret);
1225 goto end;
1226 }
1227
1228 if ((trace_sc_validation_output.valid_flags &
1229 trace_sc_validation_flags) !=
1230 trace_sc_validation_flags) {
1231 /* Invalid trace/stream class */
1232 BT_LOGW("Invalid trace or stream class field types: "
1233 "valid-flags=0x%x",
1234 trace_sc_validation_output.valid_flags);
1235 ret = -1;
1236 goto end;
1237 }
1238
1239 if (event_class_count > 0) {
1240 ec_validation_outputs = g_new0(struct bt_ctf_validation_output,
1241 event_class_count);
1242 if (!ec_validation_outputs) {
1243 BT_LOGE_STR("Failed to allocate one validation output structure.");
1244 ret = -1;
1245 goto end;
1246 }
1247 }
1248
1249 /* Validate each event class individually */
1250 for (i = 0; i < event_class_count; i++) {
1251 struct bt_ctf_event_class *event_class =
1252 bt_ctf_stream_class_get_event_class_by_index(
1253 stream_class, i);
1254 struct bt_ctf_field_type *event_context_type = NULL;
1255 struct bt_ctf_field_type *event_payload_type = NULL;
1256
1257 event_context_type =
1258 bt_ctf_event_class_get_context_type(event_class);
1259 event_payload_type =
1260 bt_ctf_event_class_get_payload_type(event_class);
1261
1262 /*
1263 * It is important to use the field types returned by
1264 * the previous trace and stream class validation here
1265 * because copies could have been made.
1266 */
1267 BT_LOGD("Validating event class's field types: "
1268 "addr=%p, name=\"%s\", id=%" PRId64,
1269 event_class, bt_ctf_event_class_get_name(event_class),
1270 bt_ctf_event_class_get_id(event_class));
1271 ret = bt_ctf_validate_class_types(trace->environment,
1272 trace_sc_validation_output.packet_header_type,
1273 trace_sc_validation_output.packet_context_type,
1274 trace_sc_validation_output.event_header_type,
1275 trace_sc_validation_output.stream_event_ctx_type,
1276 event_context_type, event_payload_type,
1277 1, 1, event_class->valid, &ec_validation_outputs[i],
1278 ec_validation_flags);
1279 BT_PUT(event_context_type);
1280 BT_PUT(event_payload_type);
1281 BT_PUT(event_class);
1282
1283 if (ret) {
1284 BT_LOGE("Failed to validate event class field types: "
1285 "ret=%d", ret);
1286 goto end;
1287 }
1288
1289 if ((ec_validation_outputs[i].valid_flags &
1290 ec_validation_flags) != ec_validation_flags) {
1291 /* Invalid event class */
1292 BT_LOGW("Invalid event class field types: "
1293 "valid-flags=0x%x",
1294 ec_validation_outputs[i].valid_flags);
1295 ret = -1;
1296 goto end;
1297 }
1298 }
1299
1300 stream_id = bt_ctf_stream_class_get_id(stream_class);
1301 if (stream_id < 0) {
1302 stream_id = trace->next_stream_id++;
1303 if (stream_id < 0) {
1304 BT_LOGE_STR("No more stream class IDs available.");
1305 ret = -1;
1306 goto end;
1307 }
1308
1309 /* Try to assign a new stream id */
1310 for (i = 0; i < trace->stream_classes->len; i++) {
1311 if (stream_id == bt_ctf_stream_class_get_id(
1312 trace->stream_classes->pdata[i])) {
1313 /* Duplicate stream id found */
1314 BT_LOGW("Duplicate stream class ID: "
1315 "id=%" PRId64, (int64_t) stream_id);
1316 ret = -1;
1317 goto end;
1318 }
1319 }
1320
1321 if (bt_ctf_stream_class_set_id_no_check(stream_class,
1322 stream_id)) {
1323 /* TODO Should retry with a different stream id */
1324 BT_LOGE("Cannot set stream class's ID: "
1325 "id=%" PRId64, (int64_t) stream_id);
1326 ret = -1;
1327 goto end;
1328 }
1329 }
1330
1331 /*
1332 * At this point all the field types in the validation output
1333 * are valid. Validate the semantics of some scopes according to
1334 * the CTF specification.
1335 */
1336 if (!packet_header_field_type_is_valid(trace,
1337 trace_sc_validation_output.packet_header_type)) {
1338 BT_LOGW_STR("Invalid trace's packet header field type.");
1339 ret = -1;
1340 goto end;
1341 }
1342
1343 if (!packet_context_field_type_is_valid(trace,
1344 stream_class,
1345 trace_sc_validation_output.packet_context_type)) {
1346 BT_LOGW_STR("Invalid stream class's packet context field type.");
1347 ret = -1;
1348 goto end;
1349 }
1350
1351 if (!event_header_field_type_is_valid(trace,
1352 stream_class,
1353 trace_sc_validation_output.event_header_type)) {
1354 BT_LOGW_STR("Invalid steam class's event header field type.");
1355 ret = -1;
1356 goto end;
1357 }
1358
1359 /*
1360 * Now is the time to automatically map specific field types of
1361 * the stream class's packet context and event header field
1362 * types to the stream class's clock's class if they are not
1363 * mapped to a clock class yet. We do it here because we know
1364 * that after this point, everything is frozen so it won't be
1365 * possible for the user to modify the stream class's clock, or
1366 * to map those field types to other clock classes.
1367 */
1368 if (trace->is_created_by_writer) {
1369 if (bt_ctf_stream_class_map_clock_class(stream_class,
1370 trace_sc_validation_output.packet_context_type,
1371 trace_sc_validation_output.event_header_type)) {
1372 BT_LOGW_STR("Cannot automatically map selected stream class's field types to stream class's clock's class.");
1373 ret = -1;
1374 goto end;
1375 }
1376 }
1377
1378 bt_object_set_parent(stream_class, trace);
1379 g_ptr_array_add(trace->stream_classes, stream_class);
1380
1381 /*
1382 * At this point we know that the function will be successful.
1383 * Therefore we can replace the trace and stream class field
1384 * types with what's in their validation output structure and
1385 * mark them as valid. We can also replace the field types of
1386 * all the event classes of the stream class and mark them as
1387 * valid.
1388 */
1389 bt_ctf_validation_replace_types(trace, stream_class, NULL,
1390 &trace_sc_validation_output, trace_sc_validation_flags);
1391 trace->valid = 1;
1392 stream_class->valid = 1;
1393
1394 /*
1395 * Put what was not moved in bt_ctf_validation_replace_types().
1396 */
1397 bt_ctf_validation_output_put_types(&trace_sc_validation_output);
1398
1399 for (i = 0; i < event_class_count; i++) {
1400 struct bt_ctf_event_class *event_class =
1401 bt_ctf_stream_class_get_event_class_by_index(
1402 stream_class, i);
1403
1404 bt_ctf_validation_replace_types(NULL, NULL, event_class,
1405 &ec_validation_outputs[i], ec_validation_flags);
1406 event_class->valid = 1;
1407 BT_PUT(event_class);
1408
1409 /*
1410 * Put what was not moved in
1411 * bt_ctf_validation_replace_types().
1412 */
1413 bt_ctf_validation_output_put_types(&ec_validation_outputs[i]);
1414 }
1415
1416 /*
1417 * Freeze the trace and the stream class.
1418 */
1419 bt_ctf_stream_class_freeze(stream_class);
1420 bt_ctf_trace_freeze(trace);
1421
1422 /* Notifiy listeners of the trace's schema modification. */
1423 bt_ctf_stream_class_visit(stream_class,
1424 bt_ctf_trace_object_modification, trace);
1425 BT_LOGD("Added stream class to trace: "
1426 "trace-addr=%p, trace-name=\"%s\", "
1427 "stream-class-addr=%p, stream-class-name=\"%s\", "
1428 "stream-class-id=%" PRId64,
1429 trace, bt_ctf_trace_get_name(trace),
1430 stream_class, bt_ctf_stream_class_get_name(stream_class),
1431 bt_ctf_stream_class_get_id(stream_class));
1432
1433 end:
1434 if (ret) {
1435 bt_object_set_parent(stream_class, NULL);
1436
1437 if (ec_validation_outputs) {
1438 for (i = 0; i < event_class_count; i++) {
1439 bt_ctf_validation_output_put_types(
1440 &ec_validation_outputs[i]);
1441 }
1442 }
1443 }
1444
1445 g_free(ec_validation_outputs);
1446 bt_ctf_validation_output_put_types(&trace_sc_validation_output);
1447 bt_put(current_parent_trace);
1448 assert(!packet_header_type);
1449 assert(!packet_context_type);
1450 assert(!event_header_type);
1451 assert(!stream_event_ctx_type);
1452 return ret;
1453 }
1454
1455 int64_t bt_ctf_trace_get_stream_count(struct bt_ctf_trace *trace)
1456 {
1457 int64_t ret;
1458
1459 if (!trace) {
1460 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1461 ret = (int64_t) -1;
1462 goto end;
1463 }
1464
1465 ret = (int64_t) trace->streams->len;
1466
1467 end:
1468 return ret;
1469 }
1470
1471 struct bt_ctf_stream *bt_ctf_trace_get_stream_by_index(
1472 struct bt_ctf_trace *trace,
1473 uint64_t index)
1474 {
1475 struct bt_ctf_stream *stream = NULL;
1476
1477 if (!trace) {
1478 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1479 goto end;
1480 }
1481
1482 if (index >= trace->streams->len) {
1483 BT_LOGW("Invalid parameter: index is out of bounds: "
1484 "addr=%p, name=\"%s\", "
1485 "index=%" PRIu64 ", count=%u",
1486 trace, bt_ctf_trace_get_name(trace),
1487 index, trace->streams->len);
1488 goto end;
1489 }
1490
1491 stream = bt_get(g_ptr_array_index(trace->streams, index));
1492
1493 end:
1494 return stream;
1495 }
1496
1497 int64_t bt_ctf_trace_get_stream_class_count(struct bt_ctf_trace *trace)
1498 {
1499 int64_t ret;
1500
1501 if (!trace) {
1502 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1503 ret = (int64_t) -1;
1504 goto end;
1505 }
1506
1507 ret = (int64_t) trace->stream_classes->len;
1508 end:
1509 return ret;
1510 }
1511
1512 struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class_by_index(
1513 struct bt_ctf_trace *trace, uint64_t index)
1514 {
1515 struct bt_ctf_stream_class *stream_class = NULL;
1516
1517 if (!trace) {
1518 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1519 goto end;
1520 }
1521
1522 if (index >= trace->stream_classes->len) {
1523 BT_LOGW("Invalid parameter: index is out of bounds: "
1524 "addr=%p, name=\"%s\", "
1525 "index=%" PRIu64 ", count=%u",
1526 trace, bt_ctf_trace_get_name(trace),
1527 index, trace->stream_classes->len);
1528 goto end;
1529 }
1530
1531 stream_class = g_ptr_array_index(trace->stream_classes, index);
1532 bt_get(stream_class);
1533 end:
1534 return stream_class;
1535 }
1536
1537 struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class_by_id(
1538 struct bt_ctf_trace *trace, uint64_t id_param)
1539 {
1540 int i;
1541 struct bt_ctf_stream_class *stream_class = NULL;
1542 int64_t id = (int64_t) id_param;
1543
1544 if (!trace) {
1545 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1546 goto end;
1547 }
1548
1549 if (id < 0) {
1550 BT_LOGW("Invalid parameter: invalid stream class's ID: "
1551 "trace-addr=%p, trace-name=\"%s\", id=%" PRIu64,
1552 trace, bt_ctf_trace_get_name(trace), id_param);
1553 goto end;
1554 }
1555
1556 for (i = 0; i < trace->stream_classes->len; i++) {
1557 struct bt_ctf_stream_class *stream_class_candidate;
1558
1559 stream_class_candidate =
1560 g_ptr_array_index(trace->stream_classes, i);
1561
1562 if (bt_ctf_stream_class_get_id(stream_class_candidate) ==
1563 (int64_t) id) {
1564 stream_class = stream_class_candidate;
1565 bt_get(stream_class);
1566 goto end;
1567 }
1568 }
1569
1570 end:
1571 return stream_class;
1572 }
1573
1574 struct bt_ctf_clock_class *bt_ctf_trace_get_clock_class_by_name(
1575 struct bt_ctf_trace *trace, const char *name)
1576 {
1577 size_t i;
1578 struct bt_ctf_clock_class *clock_class = NULL;
1579
1580 if (!trace) {
1581 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1582 goto end;
1583 }
1584
1585 if (!name) {
1586 BT_LOGW_STR("Invalid parameter: name is NULL.");
1587 goto end;
1588 }
1589
1590 for (i = 0; i < trace->clocks->len; i++) {
1591 struct bt_ctf_clock_class *cur_clk =
1592 g_ptr_array_index(trace->clocks, i);
1593 const char *cur_clk_name = bt_ctf_clock_class_get_name(cur_clk);
1594
1595 if (!cur_clk_name) {
1596 goto end;
1597 }
1598
1599 if (!strcmp(cur_clk_name, name)) {
1600 clock_class = cur_clk;
1601 bt_get(clock_class);
1602 goto end;
1603 }
1604 }
1605
1606 end:
1607 return clock_class;
1608 }
1609
1610 BT_HIDDEN
1611 bt_bool bt_ctf_trace_has_clock_class(struct bt_ctf_trace *trace,
1612 struct bt_ctf_clock_class *clock_class)
1613 {
1614 struct search_query query = { .value = clock_class, .found = 0 };
1615
1616 assert(trace);
1617 assert(clock_class);
1618
1619 g_ptr_array_foreach(trace->clocks, value_exists, &query);
1620 return query.found;
1621 }
1622
1623 BT_HIDDEN
1624 const char *get_byte_order_string(enum bt_ctf_byte_order byte_order)
1625 {
1626 const char *string;
1627
1628 switch (byte_order) {
1629 case BT_CTF_BYTE_ORDER_LITTLE_ENDIAN:
1630 string = "le";
1631 break;
1632 case BT_CTF_BYTE_ORDER_BIG_ENDIAN:
1633 string = "be";
1634 break;
1635 case BT_CTF_BYTE_ORDER_NATIVE:
1636 string = "native";
1637 break;
1638 default:
1639 abort();
1640 }
1641
1642 return string;
1643 }
1644
1645 static
1646 int append_trace_metadata(struct bt_ctf_trace *trace,
1647 struct metadata_context *context)
1648 {
1649 unsigned char *uuid = trace->uuid;
1650 int ret = 0;
1651
1652 if (trace->native_byte_order == BT_CTF_BYTE_ORDER_NATIVE ||
1653 trace->native_byte_order == BT_CTF_BYTE_ORDER_NONE) {
1654 BT_LOGW("Invalid parameter: trace's byte order cannot be BT_CTF_BYTE_ORDER_NATIVE or BT_CTF_BYTE_ORDER_NONE at this point; "
1655 "set it with bt_ctf_trace_set_native_byte_order(): "
1656 "addr=%p, name=\"%s\"",
1657 trace, bt_ctf_trace_get_name(trace));
1658 ret = -1;
1659 goto end;
1660 }
1661
1662 g_string_append(context->string, "trace {\n");
1663 g_string_append(context->string, "\tmajor = 1;\n");
1664 g_string_append(context->string, "\tminor = 8;\n");
1665 assert(trace->native_byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ||
1666 trace->native_byte_order == BT_CTF_BYTE_ORDER_BIG_ENDIAN ||
1667 trace->native_byte_order == BT_CTF_BYTE_ORDER_NETWORK);
1668
1669 if (trace->uuid_set) {
1670 g_string_append_printf(context->string,
1671 "\tuuid = \"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\";\n",
1672 uuid[0], uuid[1], uuid[2], uuid[3],
1673 uuid[4], uuid[5], uuid[6], uuid[7],
1674 uuid[8], uuid[9], uuid[10], uuid[11],
1675 uuid[12], uuid[13], uuid[14], uuid[15]);
1676 }
1677
1678 g_string_append_printf(context->string, "\tbyte_order = %s;\n",
1679 get_byte_order_string(trace->native_byte_order));
1680
1681 if (trace->packet_header_type) {
1682 g_string_append(context->string, "\tpacket.header := ");
1683 context->current_indentation_level++;
1684 g_string_assign(context->field_name, "");
1685 BT_LOGD_STR("Serializing trace's packet header field type's metadata.");
1686 ret = bt_ctf_field_type_serialize(trace->packet_header_type,
1687 context);
1688 if (ret) {
1689 goto end;
1690 }
1691 context->current_indentation_level--;
1692 }
1693
1694 g_string_append(context->string, ";\n};\n\n");
1695 end:
1696 return ret;
1697 }
1698
1699 static
1700 void append_env_metadata(struct bt_ctf_trace *trace,
1701 struct metadata_context *context)
1702 {
1703 int64_t i;
1704 int64_t env_size;
1705
1706 env_size = bt_ctf_attributes_get_count(trace->environment);
1707 if (env_size <= 0) {
1708 return;
1709 }
1710
1711 g_string_append(context->string, "env {\n");
1712
1713 for (i = 0; i < env_size; i++) {
1714 struct bt_value *env_field_value_obj = NULL;
1715 const char *entry_name;
1716
1717 entry_name = bt_ctf_attributes_get_field_name(
1718 trace->environment, i);
1719 env_field_value_obj = bt_ctf_attributes_get_field_value(
1720 trace->environment, i);
1721
1722 assert(entry_name);
1723 assert(env_field_value_obj);
1724
1725 switch (bt_value_get_type(env_field_value_obj)) {
1726 case BT_VALUE_TYPE_INTEGER:
1727 {
1728 int ret;
1729 int64_t int_value;
1730
1731 ret = bt_value_integer_get(env_field_value_obj,
1732 &int_value);
1733 assert(ret == 0);
1734 g_string_append_printf(context->string,
1735 "\t%s = %" PRId64 ";\n", entry_name,
1736 int_value);
1737 break;
1738 }
1739 case BT_VALUE_TYPE_STRING:
1740 {
1741 int ret;
1742 const char *str_value;
1743 char *escaped_str = NULL;
1744
1745 ret = bt_value_string_get(env_field_value_obj,
1746 &str_value);
1747 assert(ret == 0);
1748 escaped_str = g_strescape(str_value, NULL);
1749 if (!escaped_str) {
1750 BT_LOGE("Cannot escape string: string=\"%s\"",
1751 str_value);
1752 goto loop_next;
1753 }
1754
1755 g_string_append_printf(context->string,
1756 "\t%s = \"%s\";\n", entry_name, escaped_str);
1757 free(escaped_str);
1758 break;
1759 }
1760 default:
1761 goto loop_next;
1762 }
1763
1764 loop_next:
1765 BT_PUT(env_field_value_obj);
1766 }
1767
1768 g_string_append(context->string, "};\n\n");
1769 }
1770
1771 char *bt_ctf_trace_get_metadata_string(struct bt_ctf_trace *trace)
1772 {
1773 char *metadata = NULL;
1774 struct metadata_context *context = NULL;
1775 int err = 0;
1776 size_t i;
1777
1778 if (!trace) {
1779 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1780 goto end;
1781 }
1782
1783 context = g_new0(struct metadata_context, 1);
1784 if (!context) {
1785 BT_LOGE_STR("Failed to allocate one metadata context.");
1786 goto end;
1787 }
1788
1789 context->field_name = g_string_sized_new(DEFAULT_IDENTIFIER_SIZE);
1790 context->string = g_string_sized_new(DEFAULT_METADATA_STRING_SIZE);
1791 g_string_append(context->string, "/* CTF 1.8 */\n\n");
1792 if (append_trace_metadata(trace, context)) {
1793 /* append_trace_metadata() logs errors */
1794 goto error;
1795 }
1796 append_env_metadata(trace, context);
1797 g_ptr_array_foreach(trace->clocks,
1798 (GFunc)bt_ctf_clock_class_serialize, context);
1799
1800 for (i = 0; i < trace->stream_classes->len; i++) {
1801 /* bt_ctf_stream_class_serialize() logs details */
1802 err = bt_ctf_stream_class_serialize(
1803 trace->stream_classes->pdata[i], context);
1804 if (err) {
1805 /* bt_ctf_stream_class_serialize() logs errors */
1806 goto error;
1807 }
1808 }
1809
1810 metadata = context->string->str;
1811
1812 error:
1813 g_string_free(context->string, err ? TRUE : FALSE);
1814 g_string_free(context->field_name, TRUE);
1815 g_free(context);
1816
1817 end:
1818 return metadata;
1819 }
1820
1821 enum bt_ctf_byte_order bt_ctf_trace_get_native_byte_order(
1822 struct bt_ctf_trace *trace)
1823 {
1824 enum bt_ctf_byte_order ret = BT_CTF_BYTE_ORDER_UNKNOWN;
1825
1826 if (!trace) {
1827 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1828 goto end;
1829 }
1830
1831 ret = trace->native_byte_order;
1832
1833 end:
1834 return ret;
1835 }
1836
1837 int bt_ctf_trace_set_native_byte_order(struct bt_ctf_trace *trace,
1838 enum bt_ctf_byte_order byte_order)
1839 {
1840 int ret = 0;
1841
1842 if (!trace) {
1843 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1844 ret = -1;
1845 goto end;
1846 }
1847
1848 if (trace->frozen) {
1849 BT_LOGW("Invalid parameter: trace is frozen: "
1850 "addr=%p, name=\"%s\"",
1851 trace, bt_ctf_trace_get_name(trace));
1852 ret = -1;
1853 goto end;
1854 }
1855
1856 if (trace->is_created_by_writer &&
1857 byte_order == BT_CTF_BYTE_ORDER_NONE) {
1858 BT_LOGW("Invalid parameter: BT_CTF_BYTE_ORDER_NONE byte order is not allowed for a CTF writer trace: "
1859 "addr=%p, name=\"%s\"",
1860 trace, bt_ctf_trace_get_name(trace));
1861 ret = -1;
1862 goto end;
1863 }
1864
1865 if (byte_order != BT_CTF_BYTE_ORDER_LITTLE_ENDIAN &&
1866 byte_order != BT_CTF_BYTE_ORDER_BIG_ENDIAN &&
1867 byte_order != BT_CTF_BYTE_ORDER_NETWORK) {
1868 BT_LOGW("Invalid parameter: invalid byte order: "
1869 "addr=%p, name=\"%s\", bo=%s",
1870 trace, bt_ctf_trace_get_name(trace),
1871 bt_ctf_byte_order_string(byte_order));
1872 ret = -1;
1873 goto end;
1874 }
1875
1876 trace->native_byte_order = byte_order;
1877 BT_LOGV("Set trace's native byte order: "
1878 "addr=%p, name=\"%s\", bo=%s",
1879 trace, bt_ctf_trace_get_name(trace),
1880 bt_ctf_byte_order_string(byte_order));
1881
1882 end:
1883 return ret;
1884 }
1885
1886 struct bt_ctf_field_type *bt_ctf_trace_get_packet_header_type(
1887 struct bt_ctf_trace *trace)
1888 {
1889 struct bt_ctf_field_type *field_type = NULL;
1890
1891 if (!trace) {
1892 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1893 goto end;
1894 }
1895
1896 bt_get(trace->packet_header_type);
1897 field_type = trace->packet_header_type;
1898 end:
1899 return field_type;
1900 }
1901
1902 int bt_ctf_trace_set_packet_header_type(struct bt_ctf_trace *trace,
1903 struct bt_ctf_field_type *packet_header_type)
1904 {
1905 int ret = 0;
1906
1907 if (!trace) {
1908 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1909 ret = -1;
1910 goto end;
1911 }
1912
1913 if (trace->frozen) {
1914 BT_LOGW("Invalid parameter: trace is frozen: "
1915 "addr=%p, name=\"%s\"",
1916 trace, bt_ctf_trace_get_name(trace));
1917 ret = -1;
1918 goto end;
1919 }
1920
1921 /* packet_header_type must be a structure. */
1922 if (packet_header_type &&
1923 !bt_ctf_field_type_is_structure(packet_header_type)) {
1924 BT_LOGW("Invalid parameter: packet header field type must be a structure field type if it exists: "
1925 "addr=%p, name=\"%s\", ft-addr=%p, ft-id=%s",
1926 trace, bt_ctf_trace_get_name(trace),
1927 packet_header_type,
1928 bt_ctf_field_type_id_string(packet_header_type->id));
1929 ret = -1;
1930 goto end;
1931 }
1932
1933 bt_put(trace->packet_header_type);
1934 trace->packet_header_type = bt_get(packet_header_type);
1935 BT_LOGV("Set trace's packet header field type: "
1936 "addr=%p, name=\"%s\", packet-context-ft-addr=%p",
1937 trace, bt_ctf_trace_get_name(trace), packet_header_type);
1938 end:
1939 return ret;
1940 }
1941
1942 static
1943 int64_t get_stream_class_count(void *element)
1944 {
1945 return bt_ctf_trace_get_stream_class_count(
1946 (struct bt_ctf_trace *) element);
1947 }
1948
1949 static
1950 void *get_stream_class(void *element, int i)
1951 {
1952 return bt_ctf_trace_get_stream_class_by_index(
1953 (struct bt_ctf_trace *) element, i);
1954 }
1955
1956 static
1957 int visit_stream_class(void *object, bt_ctf_visitor visitor,void *data)
1958 {
1959 return bt_ctf_stream_class_visit(object, visitor, data);
1960 }
1961
1962 int bt_ctf_trace_visit(struct bt_ctf_trace *trace,
1963 bt_ctf_visitor visitor, void *data)
1964 {
1965 int ret;
1966 struct bt_ctf_object obj =
1967 { .object = trace, .type = BT_CTF_OBJECT_TYPE_TRACE };
1968
1969 if (!trace) {
1970 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1971 ret = -1;
1972 goto end;
1973 }
1974
1975 if (!visitor) {
1976 BT_LOGW_STR("Invalid parameter: visitor is NULL.");
1977 ret = -1;
1978 goto end;
1979 }
1980
1981 BT_LOGV("Visiting trace: addr=%p, name=\"%s\"",
1982 trace, bt_ctf_trace_get_name(trace));
1983 ret = visitor_helper(&obj, get_stream_class_count,
1984 get_stream_class, visit_stream_class, visitor, data);
1985 end:
1986 return ret;
1987 }
1988
1989 static
1990 int invoke_listener(struct bt_ctf_object *object, void *data)
1991 {
1992 struct listener_wrapper *listener_wrapper = data;
1993
1994 listener_wrapper->listener(object, listener_wrapper->data);
1995 return 0;
1996 }
1997
1998 // TODO: add logging to this function once we use it internally.
1999 int bt_ctf_trace_add_listener(struct bt_ctf_trace *trace,
2000 bt_ctf_listener_cb listener, void *listener_data)
2001 {
2002 int ret = 0;
2003 struct listener_wrapper *listener_wrapper =
2004 g_new0(struct listener_wrapper, 1);
2005
2006 if (!trace || !listener || !listener_wrapper) {
2007 ret = -1;
2008 goto error;
2009 }
2010
2011 listener_wrapper->listener = listener;
2012 listener_wrapper->data = listener_data;
2013
2014 /* Visit the current schema. */
2015 ret = bt_ctf_trace_visit(trace, invoke_listener, listener_wrapper);
2016 if (ret) {
2017 goto error;
2018 }
2019
2020 /*
2021 * Add listener to the array of callbacks which will be invoked on
2022 * schema changes.
2023 */
2024 g_ptr_array_add(trace->listeners, listener_wrapper);
2025 return ret;
2026 error:
2027 g_free(listener_wrapper);
2028 return ret;
2029 }
2030
2031 BT_HIDDEN
2032 int bt_ctf_trace_object_modification(struct bt_ctf_object *object,
2033 void *trace_ptr)
2034 {
2035 size_t i;
2036 struct bt_ctf_trace *trace = trace_ptr;
2037
2038 assert(trace);
2039 assert(object);
2040
2041 if (trace->listeners->len == 0) {
2042 goto end;
2043 }
2044
2045 for (i = 0; i < trace->listeners->len; i++) {
2046 struct listener_wrapper *listener =
2047 g_ptr_array_index(trace->listeners, i);
2048
2049 listener->listener(object, listener->data);
2050 }
2051 end:
2052 return 0;
2053 }
2054
2055 BT_HIDDEN
2056 struct bt_ctf_field_type *get_field_type(enum field_type_alias alias)
2057 {
2058 int ret;
2059 unsigned int alignment, size;
2060 struct bt_ctf_field_type *field_type = NULL;
2061
2062 if (alias >= NR_FIELD_TYPE_ALIAS) {
2063 goto end;
2064 }
2065
2066 alignment = field_type_aliases_alignments[alias];
2067 size = field_type_aliases_sizes[alias];
2068 field_type = bt_ctf_field_type_integer_create(size);
2069 ret = bt_ctf_field_type_set_alignment(field_type, alignment);
2070 if (ret) {
2071 BT_PUT(field_type);
2072 }
2073 end:
2074 return field_type;
2075 }
2076
2077 static
2078 void bt_ctf_trace_freeze(struct bt_ctf_trace *trace)
2079 {
2080 int i;
2081
2082 if (trace->frozen) {
2083 return;
2084 }
2085
2086 BT_LOGD("Freezing trace: addr=%p, name=\"%s\"",
2087 trace, bt_ctf_trace_get_name(trace));
2088 BT_LOGD_STR("Freezing packet header field type.");
2089 bt_ctf_field_type_freeze(trace->packet_header_type);
2090 BT_LOGD_STR("Freezing environment attributes.");
2091 bt_ctf_attributes_freeze(trace->environment);
2092
2093 if (trace->clocks->len > 0) {
2094 BT_LOGD_STR("Freezing clock classes.");
2095 }
2096
2097 for (i = 0; i < trace->clocks->len; i++) {
2098 struct bt_ctf_clock_class *clock_class =
2099 g_ptr_array_index(trace->clocks, i);
2100
2101 bt_ctf_clock_class_freeze(clock_class);
2102 }
2103
2104 trace->frozen = 1;
2105 }
2106
2107 bt_bool bt_ctf_trace_is_static(struct bt_ctf_trace *trace)
2108 {
2109 bt_bool is_static = BT_FALSE;
2110
2111 if (!trace) {
2112 BT_LOGW_STR("Invalid parameter: trace is NULL.");
2113 goto end;
2114 }
2115
2116 is_static = trace->is_static;
2117
2118 end:
2119 return is_static;
2120 }
2121
2122 int bt_ctf_trace_set_is_static(struct bt_ctf_trace *trace)
2123 {
2124 int ret = 0;
2125 size_t i;
2126
2127 if (!trace) {
2128 BT_LOGW_STR("Invalid parameter: trace is NULL.");
2129 ret = -1;
2130 goto end;
2131 }
2132
2133 trace->is_static = BT_TRUE;
2134 bt_ctf_trace_freeze(trace);
2135 BT_LOGV("Set trace static: addr=%p, name=\"%s\"",
2136 trace, bt_ctf_trace_get_name(trace));
2137
2138 /* Call all the "trace is static" listeners */
2139 for (i = 0; i < trace->is_static_listeners->len; i++) {
2140 struct bt_ctf_trace_is_static_listener_elem elem =
2141 g_array_index(trace->is_static_listeners,
2142 struct bt_ctf_trace_is_static_listener_elem, i);
2143
2144 if (elem.func) {
2145 elem.func(trace, elem.data);
2146 }
2147 }
2148
2149 end:
2150 return ret;
2151 }
2152
2153 int bt_ctf_trace_add_is_static_listener(struct bt_ctf_trace *trace,
2154 bt_ctf_trace_is_static_listener listener, void *data)
2155 {
2156 int i;
2157 struct bt_ctf_trace_is_static_listener_elem new_elem = {
2158 .func = listener,
2159 .data = data,
2160 };
2161
2162 if (!trace) {
2163 BT_LOGW_STR("Invalid parameter: trace is NULL.");
2164 i = -1;
2165 goto end;
2166 }
2167
2168 if (!listener) {
2169 BT_LOGW_STR("Invalid parameter: listener is NULL.");
2170 i = -1;
2171 goto end;
2172 }
2173
2174 if (trace->is_static) {
2175 BT_LOGW("Invalid parameter: trace is already static: "
2176 "addr=%p, name=\"%s\"",
2177 trace, bt_ctf_trace_get_name(trace));
2178 i = -1;
2179 goto end;
2180 }
2181
2182 /* Find the next available spot */
2183 for (i = 0; i < trace->is_static_listeners->len; i++) {
2184 struct bt_ctf_trace_is_static_listener_elem elem =
2185 g_array_index(trace->is_static_listeners,
2186 struct bt_ctf_trace_is_static_listener_elem, i);
2187
2188 if (!elem.func) {
2189 break;
2190 }
2191 }
2192
2193 if (i == trace->is_static_listeners->len) {
2194 g_array_append_val(trace->is_static_listeners, new_elem);
2195 } else {
2196 g_array_insert_val(trace->is_static_listeners, i, new_elem);
2197 }
2198
2199 BT_LOGV("Added \"trace is static\" listener: "
2200 "trace-addr=%p, trace-name=\"%s\", func-addr=%p, "
2201 "data-addr=%p, listener-id=%d",
2202 trace, bt_ctf_trace_get_name(trace), listener, data, i);
2203
2204 end:
2205 return i;
2206 }
2207
2208 int bt_ctf_trace_remove_is_static_listener(
2209 struct bt_ctf_trace *trace, int listener_id)
2210 {
2211 int ret = 0;
2212 struct bt_ctf_trace_is_static_listener_elem *elem;
2213
2214 if (!trace) {
2215 BT_LOGW_STR("Invalid parameter: trace is NULL.");
2216 ret = -1;
2217 goto end;
2218 }
2219
2220 if (listener_id < 0) {
2221 BT_LOGW("Invalid listener ID: must be zero or positive: "
2222 "listener-id=%d", listener_id);
2223 ret = -1;
2224 goto end;
2225 }
2226
2227 if (listener_id >= trace->is_static_listeners->len) {
2228 BT_LOGW("Invalid parameter: no listener with this listener ID: "
2229 "addr=%p, name=\"%s\", listener-id=%d",
2230 trace, bt_ctf_trace_get_name(trace),
2231 listener_id);
2232 ret = -1;
2233 goto end;
2234 }
2235
2236 elem = &g_array_index(trace->is_static_listeners,
2237 struct bt_ctf_trace_is_static_listener_elem,
2238 listener_id);
2239 if (!elem->func) {
2240 BT_LOGW("Invalid parameter: no listener with this listener ID: "
2241 "addr=%p, name=\"%s\", listener-id=%d",
2242 trace, bt_ctf_trace_get_name(trace),
2243 listener_id);
2244 ret = -1;
2245 goto end;
2246 }
2247
2248 elem->func = NULL;
2249 elem->data = NULL;
2250 BT_LOGV("Removed \"trace is static\" listener: "
2251 "trace-addr=%p, trace-name=\"%s\", "
2252 "listener-id=%d", trace, bt_ctf_trace_get_name(trace),
2253 listener_id);
2254
2255 end:
2256 return ret;
2257 }
This page took 0.116874 seconds and 5 git commands to generate.