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