lib: merge common CTF IR part with the remaining implementation
[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/assert-pre-internal.h>
33 #include <babeltrace/ctf-ir/trace-internal.h>
34 #include <babeltrace/ctf-ir/clock-class-internal.h>
35 #include <babeltrace/ctf-ir/stream-internal.h>
36 #include <babeltrace/ctf-ir/stream-class-internal.h>
37 #include <babeltrace/ctf-ir/event-internal.h>
38 #include <babeltrace/ctf-ir/event-class.h>
39 #include <babeltrace/ctf-ir/event-class-internal.h>
40 #include <babeltrace/ctf-writer/functor-internal.h>
41 #include <babeltrace/ctf-writer/clock-internal.h>
42 #include <babeltrace/ctf-ir/field-wrapper-internal.h>
43 #include <babeltrace/ctf-ir/field-types-internal.h>
44 #include <babeltrace/ctf-ir/attributes-internal.h>
45 #include <babeltrace/ctf-ir/validation-internal.h>
46 #include <babeltrace/ctf-ir/visitor-internal.h>
47 #include <babeltrace/ctf-ir/utils.h>
48 #include <babeltrace/ctf-ir/utils-internal.h>
49 #include <babeltrace/compiler-internal.h>
50 #include <babeltrace/values.h>
51 #include <babeltrace/values-internal.h>
52 #include <babeltrace/ref.h>
53 #include <babeltrace/types.h>
54 #include <babeltrace/endian-internal.h>
55 #include <babeltrace/assert-internal.h>
56 #include <inttypes.h>
57 #include <stdint.h>
58 #include <string.h>
59 #include <stdlib.h>
60
61 #define DEFAULT_IDENTIFIER_SIZE 128
62 #define DEFAULT_METADATA_STRING_SIZE 4096
63
64 struct listener_wrapper {
65 bt_listener_cb listener;
66 void *data;
67 };
68
69 struct bt_trace_is_static_listener_elem {
70 bt_trace_is_static_listener func;
71 bt_trace_listener_removed removed;
72 void *data;
73 };
74
75 static inline
76 void bt_trace_finalize(struct bt_trace *trace)
77 {
78 BT_LOGD("Finalizing trace object: addr=%p, name=\"%s\"",
79 trace, bt_trace_get_name(trace));
80
81 if (trace->environment) {
82 BT_LOGD_STR("Destroying environment attributes.");
83 bt_attributes_destroy(trace->environment);
84 }
85
86 if (trace->name) {
87 g_string_free(trace->name, TRUE);
88 }
89
90 if (trace->clock_classes) {
91 BT_LOGD_STR("Putting clock classes.");
92 g_ptr_array_free(trace->clock_classes, TRUE);
93 }
94
95 if (trace->streams) {
96 BT_LOGD_STR("Destroying streams.");
97 g_ptr_array_free(trace->streams, TRUE);
98 }
99
100 if (trace->stream_classes) {
101 BT_LOGD_STR("Destroying stream classes.");
102 g_ptr_array_free(trace->stream_classes, TRUE);
103 }
104
105 BT_LOGD_STR("Putting packet header field type.");
106 bt_put(trace->packet_header_field_type);
107 }
108
109 static
110 void bt_trace_destroy(struct bt_object *obj)
111 {
112 struct bt_trace *trace = (void *) obj;
113
114 BT_LOGD("Destroying trace object: addr=%p, name=\"%s\"",
115 trace, bt_trace_get_name(trace));
116
117 /*
118 * Call remove listeners first so that everything else still
119 * exists in the trace.
120 */
121 if (trace->is_static_listeners) {
122 size_t i;
123
124 for (i = 0; i < trace->is_static_listeners->len; i++) {
125 struct bt_trace_is_static_listener_elem elem =
126 g_array_index(trace->is_static_listeners,
127 struct bt_trace_is_static_listener_elem, i);
128
129 if (elem.removed) {
130 elem.removed(trace, elem.data);
131 }
132 }
133
134 g_array_free(trace->is_static_listeners, TRUE);
135 }
136
137 if (trace->listeners) {
138 g_ptr_array_free(trace->listeners, TRUE);
139 }
140
141 bt_object_pool_finalize(&trace->packet_header_field_pool);
142 bt_trace_finalize(trace);
143 g_free(trace);
144 }
145
146 static inline
147 int bt_trace_initialize(struct bt_trace *trace,
148 bt_object_release_func release_func)
149 {
150 int ret = 0;
151
152 BT_LOGD_STR("Initializing trace object.");
153 trace->native_byte_order = BT_BYTE_ORDER_UNSPECIFIED;
154 bt_object_init_shared_with_parent(&trace->base, release_func);
155 trace->clock_classes = g_ptr_array_new_with_free_func(
156 (GDestroyNotify) bt_put);
157 if (!trace->clock_classes) {
158 BT_LOGE_STR("Failed to allocate one GPtrArray.");
159 goto error;
160 }
161
162 trace->streams = g_ptr_array_new_with_free_func(
163 (GDestroyNotify) bt_object_try_spec_release);
164 if (!trace->streams) {
165 BT_LOGE_STR("Failed to allocate one GPtrArray.");
166 goto error;
167 }
168
169 trace->stream_classes = g_ptr_array_new_with_free_func(
170 (GDestroyNotify) bt_object_try_spec_release);
171 if (!trace->stream_classes) {
172 BT_LOGE_STR("Failed to allocate one GPtrArray.");
173 goto error;
174 }
175
176 /* Create the environment array object */
177 trace->environment = bt_attributes_create();
178 if (!trace->environment) {
179 BT_LOGE_STR("Cannot create empty attributes object.");
180 goto error;
181 }
182
183 BT_LOGD("Initialized trace object: addr=%p", trace);
184 goto end;
185
186 error:
187 ret = -1;
188
189 end:
190 return ret;
191 }
192
193 static
194 void free_packet_header_field(struct bt_field_wrapper *field_wrapper,
195 struct bt_trace *trace)
196 {
197 bt_field_wrapper_destroy(field_wrapper);
198 }
199
200 struct bt_trace *bt_trace_create(void)
201 {
202 struct bt_trace *trace = NULL;
203 int ret;
204
205 BT_LOGD_STR("Creating trace object.");
206 trace = g_new0(struct bt_trace, 1);
207 if (!trace) {
208 BT_LOGE_STR("Failed to allocate one trace.");
209 goto error;
210 }
211
212 ret = bt_trace_initialize(trace, bt_trace_destroy);
213 if (ret) {
214 /* bt_trace_initialize() logs errors */
215 goto error;
216 }
217
218 trace->listeners = g_ptr_array_new_with_free_func(
219 (GDestroyNotify) g_free);
220 if (!trace->listeners) {
221 BT_LOGE_STR("Failed to allocate one GPtrArray.");
222 goto error;
223 }
224
225 trace->is_static_listeners = g_array_new(FALSE, TRUE,
226 sizeof(struct bt_trace_is_static_listener_elem));
227 if (!trace->is_static_listeners) {
228 BT_LOGE_STR("Failed to allocate one GArray.");
229 goto error;
230 }
231
232 ret = bt_object_pool_initialize(&trace->packet_header_field_pool,
233 (bt_object_pool_new_object_func) bt_field_wrapper_new,
234 (bt_object_pool_destroy_object_func) free_packet_header_field,
235 trace);
236 if (ret) {
237 BT_LOGE("Failed to initialize packet header field pool: ret=%d",
238 ret);
239 goto error;
240 }
241
242 BT_LOGD("Created trace object: addr=%p", trace);
243 return trace;
244
245 error:
246 BT_PUT(trace);
247 return trace;
248 }
249
250 const char *bt_trace_get_name(struct bt_trace *trace)
251 {
252 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
253 return trace->name ? trace->name->str : NULL;
254 }
255
256 int bt_trace_set_name(struct bt_trace *trace, const char *name)
257 {
258 int ret = 0;
259
260 if (!trace) {
261 BT_LOGW_STR("Invalid parameter: trace is NULL.");
262 ret = -1;
263 goto end;
264 }
265
266 if (!name) {
267 BT_LOGW_STR("Invalid parameter: name is NULL.");
268 ret = -1;
269 goto end;
270 }
271
272 if (trace->frozen) {
273 BT_LOGW("Invalid parameter: trace is frozen: "
274 "addr=%p, name=\"%s\"",
275 trace, bt_trace_get_name(trace));
276 ret = -1;
277 goto end;
278 }
279
280 trace->name = trace->name ? g_string_assign(trace->name, name) :
281 g_string_new(name);
282 if (!trace->name) {
283 BT_LOGE_STR("Failed to allocate one GString.");
284 ret = -1;
285 goto end;
286 }
287
288 BT_LOGV("Set trace's name: addr=%p, name=\"%s\"", trace, name);
289
290 end:
291 return ret;
292 }
293
294 const unsigned char *bt_trace_get_uuid(struct bt_trace *trace)
295 {
296 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
297 return trace->uuid_set ? trace->uuid : NULL;
298 }
299
300 int bt_trace_set_uuid(struct bt_trace *trace,
301 const unsigned char *uuid)
302 {
303 int ret = 0;
304
305 if (!trace) {
306 BT_LOGW_STR("Invalid parameter: trace is NULL.");
307 ret = -1;
308 goto end;
309 }
310
311 if (!uuid) {
312 BT_LOGW_STR("Invalid parameter: UUID is NULL.");
313 ret = -1;
314 goto end;
315 }
316
317 if (trace->frozen) {
318 BT_LOGW("Invalid parameter: trace is frozen: "
319 "addr=%p, name=\"%s\"",
320 trace, bt_trace_get_name(trace));
321 ret = -1;
322 goto end;
323 }
324
325 memcpy(trace->uuid, uuid, BABELTRACE_UUID_LEN);
326 trace->uuid_set = BT_TRUE;
327 BT_LOGV("Set trace's UUID: addr=%p, name=\"%s\", "
328 "uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"",
329 trace, bt_trace_get_name(trace),
330 (unsigned int) uuid[0],
331 (unsigned int) uuid[1],
332 (unsigned int) uuid[2],
333 (unsigned int) uuid[3],
334 (unsigned int) uuid[4],
335 (unsigned int) uuid[5],
336 (unsigned int) uuid[6],
337 (unsigned int) uuid[7],
338 (unsigned int) uuid[8],
339 (unsigned int) uuid[9],
340 (unsigned int) uuid[10],
341 (unsigned int) uuid[11],
342 (unsigned int) uuid[12],
343 (unsigned int) uuid[13],
344 (unsigned int) uuid[14],
345 (unsigned int) uuid[15]);
346
347 end:
348 return ret;
349 }
350
351 int bt_trace_set_environment_field(struct bt_trace *trace,
352 const char *name, struct bt_value *value)
353 {
354 int ret = 0;
355
356 if (!trace) {
357 BT_LOGW_STR("Invalid parameter: trace is NULL.");
358 ret = -1;
359 goto end;
360 }
361
362 if (!name) {
363 BT_LOGW_STR("Invalid parameter: name is NULL.");
364 ret = -1;
365 goto end;
366 }
367
368 if (!value) {
369 BT_LOGW_STR("Invalid parameter: value is NULL.");
370 ret = -1;
371 goto end;
372 }
373
374 if (trace->is_static) {
375 BT_LOGW("Invalid parameter: trace is static: "
376 "addr=%p, name=\"%s\"",
377 trace, bt_trace_get_name(trace));
378 ret = -1;
379 goto end;
380 }
381
382 if (!bt_identifier_is_valid(name)) {
383 BT_LOGW("Invalid parameter: environment field's name is not a valid CTF identifier: "
384 "trace-addr=%p, trace-name=\"%s\", "
385 "env-name=\"%s\"",
386 trace, bt_trace_get_name(trace), name);
387 ret = -1;
388 goto end;
389 }
390
391 if (!bt_value_is_integer(value) && !bt_value_is_string(value)) {
392 BT_LOGW("Invalid parameter: environment field's value is not an integer or string value: "
393 "trace-addr=%p, trace-name=\"%s\", "
394 "env-name=\"%s\", env-value-type=%s",
395 trace, bt_trace_get_name(trace), name,
396 bt_value_type_string(bt_value_get_type(value)));
397 ret = -1;
398 goto end;
399 }
400
401 if (trace->frozen) {
402 /*
403 * New environment fields may be added to a frozen trace,
404 * but existing fields may not be changed.
405 *
406 * The object passed is frozen like all other attributes.
407 */
408 struct bt_value *attribute =
409 bt_attributes_borrow_field_value_by_name(
410 trace->environment, name);
411
412 if (attribute) {
413 BT_LOGW("Invalid parameter: trace is frozen and environment field already exists with this name: "
414 "trace-addr=%p, trace-name=\"%s\", "
415 "env-name=\"%s\"",
416 trace, bt_trace_get_name(trace), name);
417 ret = -1;
418 goto end;
419 }
420
421 bt_value_freeze(value);
422 }
423
424 ret = bt_attributes_set_field_value(trace->environment, name,
425 value);
426 if (ret) {
427 BT_LOGE("Cannot set environment field's value: "
428 "trace-addr=%p, trace-name=\"%s\", "
429 "env-name=\"%s\"",
430 trace, bt_trace_get_name(trace), name);
431 } else {
432 BT_LOGV("Set environment field's value: "
433 "trace-addr=%p, trace-name=\"%s\", "
434 "env-name=\"%s\", value-addr=%p",
435 trace, bt_trace_get_name(trace), name, value);
436 }
437
438 end:
439 return ret;
440 }
441
442 int bt_trace_set_environment_field_string(struct bt_trace *trace,
443 const char *name, const char *value)
444 {
445 int ret = 0;
446 struct bt_value *env_value_string_obj = NULL;
447
448 if (!value) {
449 BT_LOGW_STR("Invalid parameter: value is NULL.");
450 ret = -1;
451 goto end;
452 }
453
454 env_value_string_obj = bt_value_string_create_init(value);
455 if (!env_value_string_obj) {
456 BT_LOGE_STR("Cannot create string value object.");
457 ret = -1;
458 goto end;
459 }
460
461 /* bt_trace_set_environment_field() logs errors */
462 ret = bt_trace_set_environment_field(trace, name,
463 env_value_string_obj);
464
465 end:
466 bt_put(env_value_string_obj);
467 return ret;
468 }
469
470 int bt_trace_set_environment_field_integer(
471 struct bt_trace *trace, const char *name, int64_t value)
472 {
473 int ret = 0;
474 struct bt_value *env_value_integer_obj = NULL;
475
476 env_value_integer_obj = bt_value_integer_create_init(value);
477 if (!env_value_integer_obj) {
478 BT_LOGE_STR("Cannot create integer value object.");
479 ret = -1;
480 goto end;
481 }
482
483 /* bt_trace_set_environment_field() logs errors */
484 ret = bt_trace_set_environment_field(trace, name,
485 env_value_integer_obj);
486
487 end:
488 bt_put(env_value_integer_obj);
489 return ret;
490 }
491
492 int64_t bt_trace_get_environment_field_count(struct bt_trace *trace)
493 {
494 int64_t ret;
495
496 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
497 ret = bt_attributes_get_count(trace->environment);
498 BT_ASSERT(ret >= 0);
499 return ret;
500 }
501
502 const char *
503 bt_trace_get_environment_field_name_by_index(struct bt_trace *trace,
504 uint64_t index)
505 {
506 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
507 return bt_attributes_get_field_name(trace->environment, index);
508 }
509
510 struct bt_value *bt_trace_borrow_environment_field_value_by_index(
511 struct bt_trace *trace, uint64_t index)
512 {
513 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
514 return bt_attributes_borrow_field_value(trace->environment, index);
515 }
516
517 struct bt_value *bt_trace_borrow_environment_field_value_by_name(
518 struct bt_trace *trace, const char *name)
519 {
520 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
521 BT_ASSERT_PRE_NON_NULL(name, "Name");
522 return bt_attributes_borrow_field_value_by_name(trace->environment,
523 name);
524 }
525
526 int bt_trace_add_clock_class(struct bt_trace *trace,
527 struct bt_clock_class *clock_class)
528 {
529 int ret = 0;
530
531 if (!trace) {
532 BT_LOGW_STR("Invalid parameter: trace is NULL.");
533 ret = -1;
534 goto end;
535 }
536
537 if (trace->is_static) {
538 BT_LOGW("Invalid parameter: trace is static: "
539 "addr=%p, name=\"%s\"",
540 trace, bt_trace_get_name(trace));
541 ret = -1;
542 goto end;
543 }
544
545 if (!bt_clock_class_is_valid(clock_class)) {
546 BT_LOGW("Invalid parameter: clock class is invalid: "
547 "trace-addr=%p, trace-name=\"%s\", "
548 "clock-class-addr=%p, clock-class-name=\"%s\"",
549 trace, bt_trace_get_name(trace),
550 clock_class, bt_clock_class_get_name(clock_class));
551 ret = -1;
552 goto end;
553 }
554
555 /* Check for duplicate clock classes */
556 if (bt_trace_has_clock_class(trace, clock_class)) {
557 BT_LOGW("Invalid parameter: clock class already exists in trace: "
558 "trace-addr=%p, trace-name=\"%s\", "
559 "clock-class-addr=%p, clock-class-name=\"%s\"",
560 trace, bt_trace_get_name(trace),
561 clock_class, bt_clock_class_get_name(clock_class));
562 ret = -1;
563 goto end;
564 }
565
566 bt_get(clock_class);
567 g_ptr_array_add(trace->clock_classes, clock_class);
568
569 if (trace->frozen) {
570 BT_LOGV_STR("Freezing added clock class because trace is frozen.");
571 bt_clock_class_freeze(clock_class);
572 }
573
574 BT_LOGV("Added clock class to trace: "
575 "trace-addr=%p, trace-name=\"%s\", "
576 "clock-class-addr=%p, clock-class-name=\"%s\"",
577 trace, bt_trace_get_name(trace),
578 clock_class, bt_clock_class_get_name(clock_class));
579
580 end:
581 return ret;
582 }
583
584 int64_t bt_trace_get_clock_class_count(struct bt_trace *trace)
585 {
586 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
587 return trace->clock_classes->len;
588 }
589
590 struct bt_clock_class *bt_trace_borrow_clock_class_by_index(
591 struct bt_trace *trace, uint64_t index)
592 {
593 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
594 BT_ASSERT_PRE(index < trace->clock_classes->len,
595 "Index is out of bounds: index=%" PRIu64 ", "
596 "count=%u",
597 index, trace->clock_classes->len);
598 return g_ptr_array_index(trace->clock_classes, index);
599 }
600
601 static
602 bool packet_header_field_type_is_valid(struct bt_trace *trace,
603 struct bt_field_type *packet_header_type)
604 {
605 int ret;
606 bool is_valid = true;
607 struct bt_field_type *field_type = NULL;
608
609 if (!packet_header_type) {
610 /*
611 * No packet header field type: trace must have only
612 * one stream. At this point the stream class being
613 * added is not part of the trace yet, so we validate
614 * that the trace contains no stream classes yet.
615 */
616 if (trace->stream_classes->len >= 1) {
617 BT_LOGW_STR("Invalid packet header field type: "
618 "packet header field type does not exist but there's more than one stream class in the trace.");
619 goto invalid;
620 }
621
622 /* No packet header field type: valid at this point */
623 goto end;
624 }
625
626 /* Packet header field type, if it exists, must be a structure */
627 if (packet_header_type->id != BT_FIELD_TYPE_ID_STRUCT) {
628 BT_LOGW("Invalid packet header field type: must be a structure field type if it exists: "
629 "ft-addr=%p, ft-id=%s",
630 packet_header_type,
631 bt_common_field_type_id_string(packet_header_type->id));
632 goto invalid;
633 }
634
635 /*
636 * If there's a `magic` field, it must be a 32-bit unsigned
637 * integer field type. Also it must be the first field of the
638 * packet header field type.
639 */
640 field_type = bt_field_type_structure_borrow_field_type_by_name(
641 packet_header_type, "magic");
642 if (field_type) {
643 const char *field_name;
644
645 if (field_type->id != BT_FIELD_TYPE_ID_INTEGER) {
646 BT_LOGW("Invalid packet header field type: `magic` field must be an integer field type: "
647 "magic-ft-addr=%p, magic-ft-id=%s",
648 field_type,
649 bt_common_field_type_id_string(field_type->id));
650 goto invalid;
651 }
652
653 if (bt_field_type_integer_is_signed(field_type)) {
654 BT_LOGW("Invalid packet header field type: `magic` field must be an unsigned integer field type: "
655 "magic-ft-addr=%p", field_type);
656 goto invalid;
657 }
658
659 if (bt_field_type_integer_get_size(field_type) != 32) {
660 BT_LOGW("Invalid packet header field type: `magic` field must be a 32-bit unsigned integer field type: "
661 "magic-ft-addr=%p, magic-ft-size=%u",
662 field_type,
663 bt_field_type_integer_get_size(field_type));
664 goto invalid;
665 }
666
667 ret = bt_field_type_structure_borrow_field_by_index(
668 packet_header_type, &field_name, NULL, 0);
669 BT_ASSERT(ret == 0);
670
671 if (strcmp(field_name, "magic") != 0) {
672 BT_LOGW("Invalid packet header field type: `magic` field must be the first field: "
673 "magic-ft-addr=%p, first-field-name=\"%s\"",
674 field_type, field_name);
675 goto invalid;
676 }
677 }
678
679 /*
680 * If there's a `uuid` field, it must be an array field type of
681 * length 16 with an 8-bit unsigned integer element field type.
682 */
683 field_type = bt_field_type_structure_borrow_field_type_by_name(
684 packet_header_type, "uuid");
685 if (field_type) {
686 struct bt_field_type *elem_ft;
687
688 if (field_type->id != BT_FIELD_TYPE_ID_ARRAY) {
689 BT_LOGW("Invalid packet header field type: `uuid` field must be an array field type: "
690 "uuid-ft-addr=%p, uuid-ft-id=%s",
691 field_type,
692 bt_common_field_type_id_string(field_type->id));
693 goto invalid;
694 }
695
696 if (bt_field_type_array_get_length(field_type) != 16) {
697 BT_LOGW("Invalid packet header field type: `uuid` array field type's length must be 16: "
698 "uuid-ft-addr=%p, uuid-ft-length=%" PRId64,
699 field_type,
700 bt_field_type_array_get_length(field_type));
701 goto invalid;
702 }
703
704 elem_ft = bt_field_type_array_borrow_element_field_type(field_type);
705 BT_ASSERT(elem_ft);
706
707 if (elem_ft->id != BT_FIELD_TYPE_ID_INTEGER) {
708 BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an integer field type: "
709 "elem-ft-addr=%p, elem-ft-id=%s",
710 elem_ft,
711 bt_common_field_type_id_string(elem_ft->id));
712 goto invalid;
713 }
714
715 if (bt_field_type_integer_is_signed(elem_ft)) {
716 BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an unsigned integer field type: "
717 "elem-ft-addr=%p", elem_ft);
718 goto invalid;
719 }
720
721 if (bt_field_type_integer_get_size(elem_ft) != 8) {
722 BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an 8-bit unsigned integer field type: "
723 "elem-ft-addr=%p, elem-ft-size=%u",
724 elem_ft,
725 bt_field_type_integer_get_size(elem_ft));
726 goto invalid;
727 }
728 }
729
730 /*
731 * The `stream_id` field must exist if there's more than one
732 * stream classes in the trace.
733 */
734 field_type = bt_field_type_structure_borrow_field_type_by_name(
735 packet_header_type, "stream_id");
736
737 if (!field_type && trace->stream_classes->len >= 1) {
738 BT_LOGW_STR("Invalid packet header field type: "
739 "`stream_id` field does not exist but there's more than one stream class in the trace.");
740 goto invalid;
741 }
742
743 /*
744 * If there's a `stream_id` field, it must be an unsigned
745 * integer field type.
746 */
747 if (field_type) {
748 if (field_type->id != BT_FIELD_TYPE_ID_INTEGER) {
749 BT_LOGW("Invalid packet header field type: `stream_id` field must be an integer field type: "
750 "stream-id-ft-addr=%p, stream-id-ft-id=%s",
751 field_type,
752 bt_common_field_type_id_string(field_type->id));
753 goto invalid;
754 }
755
756 if (bt_field_type_integer_is_signed(field_type)) {
757 BT_LOGW("Invalid packet header field type: `stream_id` field must be an unsigned integer field type: "
758 "stream-id-ft-addr=%p", field_type);
759 goto invalid;
760 }
761 }
762
763 /*
764 * If there's a `packet_seq_num` field, it must be an unsigned
765 * integer field type.
766 */
767 field_type = bt_field_type_structure_borrow_field_type_by_name(
768 packet_header_type, "packet_seq_num");
769 if (field_type) {
770 if (field_type->id != BT_FIELD_TYPE_ID_INTEGER) {
771 BT_LOGW("Invalid packet header field type: `packet_seq_num` field must be an integer field type: "
772 "stream-id-ft-addr=%p, packet-seq-num-ft-id=%s",
773 field_type,
774 bt_common_field_type_id_string(field_type->id));
775 goto invalid;
776 }
777
778 if (bt_field_type_integer_is_signed(field_type)) {
779 BT_LOGW("Invalid packet header field type: `packet_seq_num` field must be an unsigned integer field type: "
780 "packet-seq-num-ft-addr=%p", field_type);
781 goto invalid;
782 }
783 }
784
785 goto end;
786
787 invalid:
788 is_valid = false;
789
790 end:
791 return is_valid;
792 }
793
794 static
795 bool packet_context_field_type_is_valid(struct bt_trace *trace,
796 struct bt_stream_class *stream_class,
797 struct bt_field_type *packet_context_type,
798 bool check_ts_begin_end_mapped)
799 {
800 bool is_valid = true;
801 struct bt_field_type *field_type = NULL;
802
803 if (!packet_context_type) {
804 /* No packet context field type: valid at this point */
805 goto end;
806 }
807
808 /* Packet context field type, if it exists, must be a structure */
809 if (packet_context_type->id != BT_FIELD_TYPE_ID_STRUCT) {
810 BT_LOGW("Invalid packet context field type: must be a structure field type if it exists: "
811 "ft-addr=%p, ft-id=%s",
812 packet_context_type,
813 bt_common_field_type_id_string(packet_context_type->id));
814 goto invalid;
815 }
816
817 /*
818 * If there's a `packet_size` field, it must be an unsigned
819 * integer field type.
820 */
821 field_type = bt_field_type_structure_borrow_field_type_by_name(
822 packet_context_type, "packet_size");
823 if (field_type) {
824 if (field_type->id != BT_FIELD_TYPE_ID_INTEGER) {
825 BT_LOGW("Invalid packet context field type: `packet_size` field must be an integer field type: "
826 "packet-size-ft-addr=%p, packet-size-ft-id=%s",
827 field_type,
828 bt_common_field_type_id_string(field_type->id));
829 goto invalid;
830 }
831
832 if (bt_field_type_integer_is_signed(field_type)) {
833 BT_LOGW("Invalid packet context field type: `packet_size` field must be an unsigned integer field type: "
834 "packet-size-ft-addr=%p", field_type);
835 goto invalid;
836 }
837 }
838
839 /*
840 * If there's a `content_size` field, it must be an unsigned
841 * integer field type.
842 */
843 field_type = bt_field_type_structure_borrow_field_type_by_name(
844 packet_context_type, "content_size");
845 if (field_type) {
846 if (field_type->id != BT_FIELD_TYPE_ID_INTEGER) {
847 BT_LOGW("Invalid packet context field type: `content_size` field must be an integer field type: "
848 "content-size-ft-addr=%p, content-size-ft-id=%s",
849 field_type,
850 bt_common_field_type_id_string(field_type->id));
851 goto invalid;
852 }
853
854 if (bt_field_type_integer_is_signed(field_type)) {
855 BT_LOGW("Invalid packet context field type: `content_size` field must be an unsigned integer field type: "
856 "content-size-ft-addr=%p", field_type);
857 goto invalid;
858 }
859 }
860
861 /*
862 * If there's a `events_discarded` field, it must be an unsigned
863 * integer field type.
864 */
865 field_type = bt_field_type_structure_borrow_field_type_by_name(
866 packet_context_type, "events_discarded");
867 if (field_type) {
868 if (field_type->id != BT_FIELD_TYPE_ID_INTEGER) {
869 BT_LOGW("Invalid packet context field type: `events_discarded` field must be an integer field type: "
870 "events-discarded-ft-addr=%p, events-discarded-ft-id=%s",
871 field_type,
872 bt_common_field_type_id_string(field_type->id));
873 goto invalid;
874 }
875
876 if (bt_field_type_integer_is_signed(field_type)) {
877 BT_LOGW("Invalid packet context field type: `events_discarded` field must be an unsigned integer field type: "
878 "events-discarded-ft-addr=%p", field_type);
879 goto invalid;
880 }
881 }
882
883 /*
884 * If there's a `timestamp_begin` field, it must be an unsigned
885 * integer field type. Also, if the trace is not a CTF writer's
886 * trace, then we cannot automatically set the mapped clock
887 * class of this field, so it must have a mapped clock class.
888 */
889 field_type = bt_field_type_structure_borrow_field_type_by_name(
890 packet_context_type, "timestamp_begin");
891 if (field_type) {
892 if (field_type->id != BT_FIELD_TYPE_ID_INTEGER) {
893 BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be an integer field type: "
894 "timestamp-begin-ft-addr=%p, timestamp-begin-ft-id=%s",
895 field_type,
896 bt_common_field_type_id_string(field_type->id));
897 goto invalid;
898 }
899
900 if (bt_field_type_integer_is_signed(field_type)) {
901 BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be an unsigned integer field type: "
902 "timestamp-begin-ft-addr=%p", field_type);
903 goto invalid;
904 }
905
906 if (check_ts_begin_end_mapped) {
907 struct bt_clock_class *clock_class =
908 bt_field_type_integer_borrow_mapped_clock_class(
909 field_type);
910
911 if (!clock_class) {
912 BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be mapped to a clock class: "
913 "timestamp-begin-ft-addr=%p", field_type);
914 goto invalid;
915 }
916 }
917 }
918
919 /*
920 * If there's a `timestamp_end` field, it must be an unsigned
921 * integer field type. Also, if the trace is not a CTF writer's
922 * trace, then we cannot automatically set the mapped clock
923 * class of this field, so it must have a mapped clock class.
924 */
925 field_type = bt_field_type_structure_borrow_field_type_by_name(
926 packet_context_type, "timestamp_end");
927 if (field_type) {
928 if (field_type->id != BT_FIELD_TYPE_ID_INTEGER) {
929 BT_LOGW("Invalid packet context field type: `timestamp_end` field must be an integer field type: "
930 "timestamp-end-ft-addr=%p, timestamp-end-ft-id=%s",
931 field_type,
932 bt_common_field_type_id_string(field_type->id));
933 goto invalid;
934 }
935
936 if (bt_field_type_integer_is_signed(field_type)) {
937 BT_LOGW("Invalid packet context field type: `timestamp_end` field must be an unsigned integer field type: "
938 "timestamp-end-ft-addr=%p", field_type);
939 goto invalid;
940 }
941
942 if (check_ts_begin_end_mapped) {
943 struct bt_clock_class *clock_class =
944 bt_field_type_integer_borrow_mapped_clock_class(
945 field_type);
946
947 if (!clock_class) {
948 BT_LOGW("Invalid packet context field type: `timestamp_end` field must be mapped to a clock class: "
949 "timestamp-end-ft-addr=%p", field_type);
950 goto invalid;
951 }
952 }
953 }
954
955 goto end;
956
957 invalid:
958 is_valid = false;
959
960 end:
961 return is_valid;
962 }
963
964 static
965 bool event_header_field_type_is_valid(struct bt_trace *trace,
966 struct bt_stream_class *stream_class,
967 struct bt_field_type *event_header_type)
968 {
969 bool is_valid = true;
970 struct bt_field_type *field_type = NULL;
971
972 /*
973 * We do not validate that the `timestamp` field exists here
974 * because CTF does not require this exact name to be mapped to
975 * a clock class.
976 */
977
978 if (!event_header_type) {
979 /*
980 * No event header field type: stream class must have
981 * only one event class.
982 */
983 if (bt_stream_class_get_event_class_count(stream_class) > 1) {
984 BT_LOGW_STR("Invalid event header field type: "
985 "event header field type does not exist but there's more than one event class in the stream class.");
986 goto invalid;
987 }
988
989 /* No event header field type: valid at this point */
990 goto end;
991 }
992
993 /* Event header field type, if it exists, must be a structure */
994 if (event_header_type->id != BT_FIELD_TYPE_ID_STRUCT) {
995 BT_LOGW("Invalid event header field type: must be a structure field type if it exists: "
996 "ft-addr=%p, ft-id=%s",
997 event_header_type,
998 bt_common_field_type_id_string(event_header_type->id));
999 goto invalid;
1000 }
1001
1002 /*
1003 * If there's an `id` field, it must be an unsigned integer
1004 * field type or an enumeration field type with an unsigned
1005 * integer container field type.
1006 */
1007 field_type = bt_field_type_structure_borrow_field_type_by_name(
1008 event_header_type, "id");
1009 if (field_type) {
1010 struct bt_field_type *int_ft;
1011
1012 if (field_type->id == BT_FIELD_TYPE_ID_INTEGER) {
1013 int_ft = field_type;
1014 } else if (field_type->id == BT_FIELD_TYPE_ID_ENUM) {
1015 int_ft = bt_field_type_enumeration_borrow_container_field_type(
1016 field_type);
1017 } else {
1018 BT_LOGW("Invalid event header field type: `id` field must be an integer or enumeration field type: "
1019 "id-ft-addr=%p, id-ft-id=%s",
1020 field_type,
1021 bt_common_field_type_id_string(field_type->id));
1022 goto invalid;
1023 }
1024
1025 BT_ASSERT(int_ft);
1026 if (bt_field_type_integer_is_signed(int_ft)) {
1027 BT_LOGW("Invalid event header field type: `id` field must be an unsigned integer or enumeration field type: "
1028 "id-ft-addr=%p", int_ft);
1029 goto invalid;
1030 }
1031 }
1032
1033 goto end;
1034
1035 invalid:
1036 is_valid = false;
1037
1038 end:
1039 return is_valid;
1040 }
1041
1042 static
1043 int check_packet_header_type_has_no_clock_class(struct bt_trace *trace)
1044 {
1045 int ret = 0;
1046
1047 if (trace->packet_header_field_type) {
1048 struct bt_clock_class *clock_class = NULL;
1049
1050 ret = bt_field_type_validate_single_clock_class(
1051 trace->packet_header_field_type,
1052 &clock_class);
1053 bt_put(clock_class);
1054 if (ret || clock_class) {
1055 BT_LOGW("Trace's packet header field type cannot "
1056 "contain a field type which is mapped to "
1057 "a clock class: "
1058 "trace-addr=%p, trace-name=\"%s\", "
1059 "clock-class-name=\"%s\"",
1060 trace, bt_trace_get_name(trace),
1061 clock_class ?
1062 bt_clock_class_get_name(clock_class) :
1063 NULL);
1064 ret = -1;
1065 }
1066 }
1067
1068 return ret;
1069 }
1070
1071 int bt_trace_add_stream_class(struct bt_trace *trace,
1072 struct bt_stream_class *stream_class)
1073 {
1074 int ret;
1075 int64_t i;
1076 int64_t stream_id;
1077 struct bt_validation_output trace_sc_validation_output = { 0 };
1078 struct bt_validation_output *ec_validation_outputs = NULL;
1079 const enum bt_validation_flag trace_sc_validation_flags =
1080 BT_VALIDATION_FLAG_TRACE |
1081 BT_VALIDATION_FLAG_STREAM;
1082 const enum bt_validation_flag ec_validation_flags =
1083 BT_VALIDATION_FLAG_EVENT;
1084 struct bt_field_type *packet_header_type = NULL;
1085 struct bt_field_type *packet_context_type = NULL;
1086 struct bt_field_type *event_header_type = NULL;
1087 struct bt_field_type *stream_event_ctx_type = NULL;
1088 int64_t event_class_count;
1089 struct bt_trace *current_parent_trace = NULL;
1090 struct bt_clock_class *expected_clock_class = NULL;
1091
1092 if (!trace) {
1093 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1094 ret = -1;
1095 goto end;
1096 }
1097
1098 if (trace->is_static) {
1099 BT_LOGW_STR("Invalid parameter: trace is static.");
1100 ret = -1;
1101 goto end;
1102 }
1103
1104 if (!stream_class) {
1105 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
1106 ret = -1;
1107 goto end;
1108 }
1109
1110 BT_LOGD("Adding stream class to trace: "
1111 "trace-addr=%p, trace-name=\"%s\", "
1112 "stream-class-addr=%p, stream-class-name=\"%s\", "
1113 "stream-class-id=%" PRId64,
1114 trace, bt_trace_get_name(trace),
1115 stream_class, bt_stream_class_get_name(stream_class),
1116 bt_stream_class_get_id(stream_class));
1117
1118 current_parent_trace = bt_stream_class_borrow_trace(stream_class);
1119 if (current_parent_trace) {
1120 /* Stream class is already associated to a trace, abort. */
1121 BT_LOGW("Invalid parameter: stream class is already part of a trace: "
1122 "stream-class-trace-addr=%p, "
1123 "stream-class-trace-name=\"%s\"",
1124 current_parent_trace,
1125 bt_trace_get_name(current_parent_trace));
1126 ret = -1;
1127 goto end;
1128 }
1129
1130 event_class_count =
1131 bt_stream_class_get_event_class_count(stream_class);
1132 BT_ASSERT(event_class_count >= 0);
1133
1134 if (!stream_class->frozen) {
1135 /*
1136 * Stream class is not frozen yet. Validate that the
1137 * stream class contains at most a single clock class
1138 * because the previous
1139 * bt_stream_class_add_event_class() calls did
1140 * not make this validation since the stream class's
1141 * direct field types (packet context, event header,
1142 * event context) could change afterwards. This stream
1143 * class is about to be frozen and those field types
1144 * won't be changed if this function succeeds.
1145 *
1146 * At this point we're also sure that the stream class's
1147 * clock, if any, has the same class as the stream
1148 * class's expected clock class, if any. This is why, if
1149 * bt_stream_class_validate_single_clock_class()
1150 * succeeds below, the call to
1151 * bt_stream_class_map_clock_class() at the end of this
1152 * function is safe because it maps to the same, single
1153 * clock class.
1154 */
1155 ret = bt_stream_class_validate_single_clock_class(
1156 stream_class, &expected_clock_class);
1157 if (ret) {
1158 BT_LOGW("Invalid parameter: stream class or one of its "
1159 "event classes contains a field type which is "
1160 "not recursively mapped to the expected "
1161 "clock class: "
1162 "stream-class-addr=%p, "
1163 "stream-class-id=%" PRId64 ", "
1164 "stream-class-name=\"%s\", "
1165 "expected-clock-class-addr=%p, "
1166 "expected-clock-class-name=\"%s\"",
1167 stream_class, bt_stream_class_get_id(stream_class),
1168 bt_stream_class_get_name(stream_class),
1169 expected_clock_class,
1170 expected_clock_class ?
1171 bt_clock_class_get_name(expected_clock_class) :
1172 NULL);
1173 goto end;
1174 }
1175 }
1176
1177 ret = check_packet_header_type_has_no_clock_class(trace);
1178 if (ret) {
1179 /* check_packet_header_type_has_no_clock_class() logs errors */
1180 goto end;
1181 }
1182
1183 /*
1184 * We're about to freeze both the trace and the stream class.
1185 * Also, each event class contained in this stream class are
1186 * already frozen.
1187 *
1188 * This trace, this stream class, and all its event classes
1189 * should be valid at this point.
1190 *
1191 * Validate trace and stream class first, then each event
1192 * class of this stream class can be validated individually.
1193 */
1194 packet_header_type =
1195 bt_trace_borrow_packet_header_field_type(trace);
1196 packet_context_type =
1197 bt_stream_class_borrow_packet_context_field_type(stream_class);
1198 event_header_type =
1199 bt_stream_class_borrow_event_header_field_type(stream_class);
1200 stream_event_ctx_type =
1201 bt_stream_class_borrow_event_context_field_type(stream_class);
1202
1203 BT_LOGD("Validating trace and stream class field types.");
1204 ret = bt_validate_class_types(trace->environment,
1205 packet_header_type, packet_context_type, event_header_type,
1206 stream_event_ctx_type, NULL, NULL, trace->valid,
1207 stream_class->valid, 1, &trace_sc_validation_output,
1208 trace_sc_validation_flags, bt_field_type_copy);
1209
1210 if (ret) {
1211 /*
1212 * This means something went wrong during the validation
1213 * process, not that the objects are invalid.
1214 */
1215 BT_LOGE("Failed to validate trace and stream class field types: "
1216 "ret=%d", ret);
1217 goto end;
1218 }
1219
1220 if ((trace_sc_validation_output.valid_flags &
1221 trace_sc_validation_flags) !=
1222 trace_sc_validation_flags) {
1223 /* Invalid trace/stream class */
1224 BT_LOGW("Invalid trace or stream class field types: "
1225 "valid-flags=0x%x",
1226 trace_sc_validation_output.valid_flags);
1227 ret = -1;
1228 goto end;
1229 }
1230
1231 if (event_class_count > 0) {
1232 ec_validation_outputs = g_new0(struct bt_validation_output,
1233 event_class_count);
1234 if (!ec_validation_outputs) {
1235 BT_LOGE_STR("Failed to allocate one validation output structure.");
1236 ret = -1;
1237 goto end;
1238 }
1239 }
1240
1241 /* Validate each event class individually */
1242 for (i = 0; i < event_class_count; i++) {
1243 struct bt_event_class *event_class =
1244 bt_stream_class_borrow_event_class_by_index(
1245 stream_class, i);
1246 struct bt_field_type *event_context_type = NULL;
1247 struct bt_field_type *event_payload_type = NULL;
1248
1249 event_context_type =
1250 bt_event_class_borrow_context_field_type(
1251 event_class);
1252 event_payload_type =
1253 bt_event_class_borrow_payload_field_type(
1254 event_class);
1255
1256 /*
1257 * It is important to use the field types returned by
1258 * the previous trace and stream class validation here
1259 * because copies could have been made.
1260 */
1261 BT_LOGD("Validating event class's field types: "
1262 "addr=%p, name=\"%s\", id=%" PRId64,
1263 event_class, bt_event_class_get_name(event_class),
1264 bt_event_class_get_id(event_class));
1265 ret = bt_validate_class_types(trace->environment,
1266 trace_sc_validation_output.packet_header_type,
1267 trace_sc_validation_output.packet_context_type,
1268 trace_sc_validation_output.event_header_type,
1269 trace_sc_validation_output.stream_event_ctx_type,
1270 event_context_type, event_payload_type,
1271 1, 1, event_class->valid, &ec_validation_outputs[i],
1272 ec_validation_flags, bt_field_type_copy);
1273
1274 if (ret) {
1275 BT_LOGE("Failed to validate event class field types: "
1276 "ret=%d", ret);
1277 goto end;
1278 }
1279
1280 if ((ec_validation_outputs[i].valid_flags &
1281 ec_validation_flags) != ec_validation_flags) {
1282 /* Invalid event class */
1283 BT_LOGW("Invalid event class field types: "
1284 "valid-flags=0x%x",
1285 ec_validation_outputs[i].valid_flags);
1286 ret = -1;
1287 goto end;
1288 }
1289 }
1290
1291 stream_id = bt_stream_class_get_id(stream_class);
1292 if (stream_id < 0) {
1293 stream_id = trace->next_stream_id++;
1294 if (stream_id < 0) {
1295 BT_LOGE_STR("No more stream class IDs available.");
1296 ret = -1;
1297 goto end;
1298 }
1299
1300 /* Try to assign a new stream id */
1301 for (i = 0; i < trace->stream_classes->len; i++) {
1302 if (stream_id == bt_stream_class_get_id(
1303 trace->stream_classes->pdata[i])) {
1304 /* Duplicate stream id found */
1305 BT_LOGW("Duplicate stream class ID: "
1306 "id=%" PRId64, (int64_t) stream_id);
1307 ret = -1;
1308 goto end;
1309 }
1310 }
1311
1312 if (bt_stream_class_set_id_no_check(stream_class,
1313 stream_id)) {
1314 /* TODO Should retry with a different stream id */
1315 BT_LOGE("Cannot set stream class's ID: "
1316 "id=%" PRId64, (int64_t) stream_id);
1317 ret = -1;
1318 goto end;
1319 }
1320 }
1321
1322 /*
1323 * At this point all the field types in the validation output
1324 * are valid. Validate the semantics of some scopes according to
1325 * the CTF specification.
1326 */
1327 if (!packet_header_field_type_is_valid(trace,
1328 trace_sc_validation_output.packet_header_type)) {
1329 BT_LOGW_STR("Invalid trace's packet header field type.");
1330 ret = -1;
1331 goto end;
1332 }
1333
1334 if (!packet_context_field_type_is_valid(trace,
1335 stream_class,
1336 trace_sc_validation_output.packet_context_type, true)) {
1337 BT_LOGW_STR("Invalid stream class's packet context field type.");
1338 ret = -1;
1339 goto end;
1340 }
1341
1342 if (!event_header_field_type_is_valid(trace,
1343 stream_class,
1344 trace_sc_validation_output.event_header_type)) {
1345 BT_LOGW_STR("Invalid steam class's event header field type.");
1346 ret = -1;
1347 goto end;
1348 }
1349
1350 bt_object_set_parent(&stream_class->base, &trace->base);
1351 g_ptr_array_add(trace->stream_classes, stream_class);
1352
1353 /*
1354 * At this point we know that the function will be successful.
1355 * Therefore we can replace the trace and stream class field
1356 * types with what's in their validation output structure and
1357 * mark them as valid. We can also replace the field types of
1358 * all the event classes of the stream class and mark them as
1359 * valid.
1360 */
1361 bt_validation_replace_types(trace, stream_class, NULL,
1362 &trace_sc_validation_output, trace_sc_validation_flags);
1363 trace->valid = 1;
1364 stream_class->valid = 1;
1365
1366 /*
1367 * Put what was not moved in bt_validation_replace_types().
1368 */
1369 bt_validation_output_put_types(&trace_sc_validation_output);
1370
1371 for (i = 0; i < event_class_count; i++) {
1372 struct bt_event_class *event_class =
1373 bt_stream_class_borrow_event_class_by_index(
1374 stream_class, i);
1375
1376 bt_validation_replace_types(NULL, NULL, event_class,
1377 &ec_validation_outputs[i], ec_validation_flags);
1378 event_class->valid = 1;
1379
1380 /*
1381 * Put what was not moved in
1382 * bt_validation_replace_types().
1383 */
1384 bt_validation_output_put_types(&ec_validation_outputs[i]);
1385 }
1386
1387 /*
1388 * Freeze the trace and the stream class.
1389 */
1390 bt_stream_class_freeze(stream_class);
1391 bt_trace_freeze(trace);
1392
1393 /*
1394 * It is safe to set the stream class's unique clock class
1395 * now because the stream class is frozen.
1396 */
1397 if (expected_clock_class) {
1398 BT_MOVE(stream_class->clock_class, expected_clock_class);
1399 }
1400
1401 /* Notify listeners of the trace's schema modification. */
1402 bt_stream_class_visit(stream_class,
1403 bt_trace_object_modification, trace);
1404 BT_LOGD("Added stream class to trace: "
1405 "trace-addr=%p, trace-name=\"%s\", "
1406 "stream-class-addr=%p, stream-class-name=\"%s\", "
1407 "stream-class-id=%" PRId64,
1408 trace, bt_trace_get_name(trace),
1409 stream_class, bt_stream_class_get_name(stream_class),
1410 bt_stream_class_get_id(stream_class));
1411
1412 end:
1413 if (ret) {
1414 bt_object_set_parent(&stream_class->base, NULL);
1415
1416 if (ec_validation_outputs) {
1417 for (i = 0; i < event_class_count; i++) {
1418 bt_validation_output_put_types(
1419 &ec_validation_outputs[i]);
1420 }
1421 }
1422 }
1423
1424 g_free(ec_validation_outputs);
1425 bt_validation_output_put_types(&trace_sc_validation_output);
1426 bt_put(expected_clock_class);
1427 return ret;
1428 }
1429
1430 int64_t bt_trace_get_stream_count(struct bt_trace *trace)
1431 {
1432 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
1433 return (int64_t) trace->streams->len;
1434 }
1435
1436 struct bt_stream *bt_trace_borrow_stream_by_index(
1437 struct bt_trace *trace, uint64_t index)
1438 {
1439 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
1440 BT_ASSERT_PRE(index < trace->streams->len,
1441 "Index is out of bounds: index=%" PRIu64 ", "
1442 "count=%u",
1443 index, trace->streams->len);
1444 return g_ptr_array_index(trace->streams, index);
1445 }
1446
1447 int64_t bt_trace_get_stream_class_count(struct bt_trace *trace)
1448 {
1449 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
1450 return (int64_t) trace->stream_classes->len;
1451 }
1452
1453 struct bt_stream_class *bt_trace_borrow_stream_class_by_index(
1454 struct bt_trace *trace, uint64_t index)
1455 {
1456 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
1457 BT_ASSERT_PRE(index < trace->stream_classes->len,
1458 "Index is out of bounds: index=%" PRIu64 ", "
1459 "count=%u",
1460 index, trace->stream_classes->len);
1461 return g_ptr_array_index(trace->stream_classes, index);
1462 }
1463
1464 struct bt_stream_class *bt_trace_borrow_stream_class_by_id(
1465 struct bt_trace *trace, uint64_t id_param)
1466 {
1467 int i;
1468 struct bt_stream_class *stream_class = NULL;
1469 int64_t id = (int64_t) id_param;
1470
1471 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
1472 BT_ASSERT_PRE(id >= 0,
1473 "Invalid stream class ID: %" PRIu64, id_param);
1474
1475 for (i = 0; i < trace->stream_classes->len; i++) {
1476 struct bt_stream_class *stream_class_candidate;
1477
1478 stream_class_candidate =
1479 g_ptr_array_index(trace->stream_classes, i);
1480
1481 if (bt_stream_class_get_id(stream_class_candidate) ==
1482 (int64_t) id) {
1483 stream_class = stream_class_candidate;
1484 goto end;
1485 }
1486 }
1487
1488 end:
1489 return stream_class;
1490 }
1491
1492 struct bt_clock_class *bt_trace_borrow_clock_class_by_name(
1493 struct bt_trace *trace, const char *name)
1494 {
1495 size_t i;
1496 struct bt_clock_class *clock_class = NULL;
1497
1498 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
1499 BT_ASSERT_PRE_NON_NULL(name, "Name");
1500
1501 for (i = 0; i < trace->clock_classes->len; i++) {
1502 struct bt_clock_class *cur_clk =
1503 g_ptr_array_index(trace->clock_classes, i);
1504 const char *cur_clk_name = bt_clock_class_get_name(cur_clk);
1505
1506 if (!cur_clk_name) {
1507 goto end;
1508 }
1509
1510 if (!strcmp(cur_clk_name, name)) {
1511 clock_class = cur_clk;
1512 goto end;
1513 }
1514 }
1515
1516 end:
1517 return clock_class;
1518 }
1519
1520 BT_HIDDEN
1521 bt_bool bt_trace_has_clock_class(struct bt_trace *trace,
1522 struct bt_clock_class *clock_class)
1523 {
1524 struct search_query query = { .value = clock_class, .found = 0 };
1525
1526 BT_ASSERT(trace);
1527 BT_ASSERT(clock_class);
1528
1529 g_ptr_array_foreach(trace->clock_classes, value_exists, &query);
1530 return query.found;
1531 }
1532
1533 enum bt_byte_order bt_trace_get_native_byte_order(
1534 struct bt_trace *trace)
1535 {
1536 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
1537 return trace->native_byte_order;
1538 }
1539
1540 int bt_trace_set_native_byte_order(struct bt_trace *trace,
1541 enum bt_byte_order byte_order)
1542 {
1543 int ret = 0;
1544
1545 if (!trace) {
1546 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1547 ret = -1;
1548 goto end;
1549 }
1550
1551 if (trace->frozen) {
1552 BT_LOGW("Invalid parameter: trace is frozen: "
1553 "addr=%p, name=\"%s\"",
1554 trace, bt_trace_get_name(trace));
1555 ret = -1;
1556 goto end;
1557 }
1558
1559 if (byte_order != BT_BYTE_ORDER_LITTLE_ENDIAN &&
1560 byte_order != BT_BYTE_ORDER_BIG_ENDIAN &&
1561 byte_order != BT_BYTE_ORDER_NETWORK) {
1562 BT_LOGW("Invalid parameter: invalid byte order: "
1563 "addr=%p, name=\"%s\", bo=%s",
1564 trace, bt_trace_get_name(trace),
1565 bt_common_byte_order_string(byte_order));
1566 ret = -1;
1567 goto end;
1568 }
1569
1570 trace->native_byte_order = byte_order;
1571 BT_LOGV("Set trace's native byte order: "
1572 "addr=%p, name=\"%s\", bo=%s",
1573 trace, bt_trace_get_name(trace),
1574 bt_common_byte_order_string(byte_order));
1575
1576 end:
1577 return ret;
1578 }
1579
1580 struct bt_field_type *bt_trace_borrow_packet_header_field_type(
1581 struct bt_trace *trace)
1582 {
1583 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
1584 return trace->packet_header_field_type;
1585 }
1586
1587 int bt_trace_set_packet_header_field_type(struct bt_trace *trace,
1588 struct bt_field_type *packet_header_type)
1589 {
1590 int ret = 0;
1591
1592 if (!trace) {
1593 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1594 ret = -1;
1595 goto end;
1596 }
1597
1598 if (trace->frozen) {
1599 BT_LOGW("Invalid parameter: trace is frozen: "
1600 "addr=%p, name=\"%s\"",
1601 trace, bt_trace_get_name(trace));
1602 ret = -1;
1603 goto end;
1604 }
1605
1606 /* packet_header_type must be a structure. */
1607 if (packet_header_type &&
1608 packet_header_type->id != BT_FIELD_TYPE_ID_STRUCT) {
1609 BT_LOGW("Invalid parameter: packet header field type must be a structure field type if it exists: "
1610 "addr=%p, name=\"%s\", ft-addr=%p, ft-id=%s",
1611 trace, bt_trace_get_name(trace),
1612 packet_header_type,
1613 bt_common_field_type_id_string(packet_header_type->id));
1614 ret = -1;
1615 goto end;
1616 }
1617
1618 bt_put(trace->packet_header_field_type);
1619 trace->packet_header_field_type = bt_get(packet_header_type);
1620 BT_LOGV("Set trace's packet header field type: "
1621 "addr=%p, name=\"%s\", packet-context-ft-addr=%p",
1622 trace, bt_trace_get_name(trace), packet_header_type);
1623 end:
1624 return ret;
1625 }
1626
1627 static
1628 int64_t get_stream_class_count(void *element)
1629 {
1630 return bt_trace_get_stream_class_count(
1631 (struct bt_trace *) element);
1632 }
1633
1634 static
1635 void *get_stream_class(void *element, int i)
1636 {
1637 return bt_trace_get_stream_class_by_index(
1638 (struct bt_trace *) element, i);
1639 }
1640
1641 static
1642 int visit_stream_class(void *object, bt_visitor visitor,void *data)
1643 {
1644 return bt_stream_class_visit(object, visitor, data);
1645 }
1646
1647 int bt_trace_visit(struct bt_trace *trace,
1648 bt_visitor visitor, void *data)
1649 {
1650 int ret;
1651 struct bt_visitor_object obj = {
1652 .object = trace,
1653 .type = BT_VISITOR_OBJECT_TYPE_TRACE
1654 };
1655
1656 if (!trace) {
1657 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1658 ret = -1;
1659 goto end;
1660 }
1661
1662 if (!visitor) {
1663 BT_LOGW_STR("Invalid parameter: visitor is NULL.");
1664 ret = -1;
1665 goto end;
1666 }
1667
1668 BT_LOGV("Visiting trace: addr=%p, name=\"%s\"",
1669 trace, bt_trace_get_name(trace));
1670 ret = visitor_helper(&obj, get_stream_class_count,
1671 get_stream_class, visit_stream_class, visitor, data);
1672 end:
1673 return ret;
1674 }
1675
1676 static
1677 int invoke_listener(struct bt_visitor_object *object, void *data)
1678 {
1679 struct listener_wrapper *listener_wrapper = data;
1680
1681 listener_wrapper->listener(object, listener_wrapper->data);
1682 return 0;
1683 }
1684
1685 // TODO: add logging to this function once we use it internally.
1686 int bt_trace_add_listener(struct bt_trace *trace,
1687 bt_listener_cb listener, void *listener_data)
1688 {
1689 int ret = 0;
1690 struct listener_wrapper *listener_wrapper =
1691 g_new0(struct listener_wrapper, 1);
1692
1693 if (!trace || !listener || !listener_wrapper) {
1694 ret = -1;
1695 goto error;
1696 }
1697
1698 listener_wrapper->listener = listener;
1699 listener_wrapper->data = listener_data;
1700
1701 /* Visit the current schema. */
1702 ret = bt_trace_visit(trace, invoke_listener, listener_wrapper);
1703 if (ret) {
1704 goto error;
1705 }
1706
1707 /*
1708 * Add listener to the array of callbacks which will be invoked on
1709 * schema changes.
1710 */
1711 g_ptr_array_add(trace->listeners, listener_wrapper);
1712 return ret;
1713 error:
1714 g_free(listener_wrapper);
1715 return ret;
1716 }
1717
1718 BT_HIDDEN
1719 int bt_trace_object_modification(struct bt_visitor_object *object,
1720 void *trace_ptr)
1721 {
1722 size_t i;
1723 struct bt_trace *trace = trace_ptr;
1724
1725 BT_ASSERT(trace);
1726 BT_ASSERT(object);
1727
1728 if (trace->listeners->len == 0) {
1729 goto end;
1730 }
1731
1732 for (i = 0; i < trace->listeners->len; i++) {
1733 struct listener_wrapper *listener =
1734 g_ptr_array_index(trace->listeners, i);
1735
1736 listener->listener(object, listener->data);
1737 }
1738 end:
1739 return 0;
1740 }
1741
1742 bt_bool bt_trace_is_static(struct bt_trace *trace)
1743 {
1744 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
1745 return trace->is_static;
1746 }
1747
1748 int bt_trace_set_is_static(struct bt_trace *trace)
1749 {
1750 int ret = 0;
1751 size_t i;
1752
1753 if (!trace) {
1754 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1755 ret = -1;
1756 goto end;
1757 }
1758
1759 ret = check_packet_header_type_has_no_clock_class(trace);
1760 if (ret) {
1761 /* check_packet_header_type_has_no_clock_class() logs errors */
1762 goto end;
1763 }
1764
1765 trace->is_static = BT_TRUE;
1766 bt_trace_freeze(trace);
1767 BT_LOGV("Set trace static: addr=%p, name=\"%s\"",
1768 trace, bt_trace_get_name(trace));
1769
1770 /* Call all the "trace is static" listeners */
1771 for (i = 0; i < trace->is_static_listeners->len; i++) {
1772 struct bt_trace_is_static_listener_elem elem =
1773 g_array_index(trace->is_static_listeners,
1774 struct bt_trace_is_static_listener_elem, i);
1775
1776 if (elem.func) {
1777 elem.func(trace, elem.data);
1778 }
1779 }
1780
1781 end:
1782 return ret;
1783 }
1784
1785 int bt_trace_add_is_static_listener(struct bt_trace *trace,
1786 bt_trace_is_static_listener listener,
1787 bt_trace_listener_removed listener_removed, void *data)
1788 {
1789 int i;
1790 struct bt_trace_is_static_listener_elem new_elem = {
1791 .func = listener,
1792 .removed = listener_removed,
1793 .data = data,
1794 };
1795
1796 if (!trace) {
1797 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1798 i = -1;
1799 goto end;
1800 }
1801
1802 if (!listener) {
1803 BT_LOGW_STR("Invalid parameter: listener is NULL.");
1804 i = -1;
1805 goto end;
1806 }
1807
1808 if (trace->is_static) {
1809 BT_LOGW("Invalid parameter: trace is already static: "
1810 "addr=%p, name=\"%s\"",
1811 trace, bt_trace_get_name(trace));
1812 i = -1;
1813 goto end;
1814 }
1815
1816 if (trace->in_remove_listener) {
1817 BT_LOGW("Cannot call this function during the execution of a remove listener: "
1818 "addr=%p, name=\"%s\"",
1819 trace, bt_trace_get_name(trace));
1820 i = -1;
1821 goto end;
1822 }
1823
1824 /* Find the next available spot */
1825 for (i = 0; i < trace->is_static_listeners->len; i++) {
1826 struct bt_trace_is_static_listener_elem elem =
1827 g_array_index(trace->is_static_listeners,
1828 struct bt_trace_is_static_listener_elem, i);
1829
1830 if (!elem.func) {
1831 break;
1832 }
1833 }
1834
1835 if (i == trace->is_static_listeners->len) {
1836 g_array_append_val(trace->is_static_listeners, new_elem);
1837 } else {
1838 g_array_insert_val(trace->is_static_listeners, i, new_elem);
1839 }
1840
1841 BT_LOGV("Added \"trace is static\" listener: "
1842 "trace-addr=%p, trace-name=\"%s\", func-addr=%p, "
1843 "data-addr=%p, listener-id=%d",
1844 trace, bt_trace_get_name(trace), listener, data, i);
1845
1846 end:
1847 return i;
1848 }
1849
1850 int bt_trace_remove_is_static_listener(
1851 struct bt_trace *trace, int listener_id)
1852 {
1853 int ret = 0;
1854 struct bt_trace_is_static_listener_elem *elem;
1855
1856 if (!trace) {
1857 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1858 ret = -1;
1859 goto end;
1860 }
1861
1862 if (trace->in_remove_listener) {
1863 BT_LOGW("Cannot call this function during the execution of a remove listener: "
1864 "addr=%p, name=\"%s\", listener-id=%d",
1865 trace, bt_trace_get_name(trace),
1866 listener_id);
1867 ret = -1;
1868 goto end;
1869 }
1870
1871 if (listener_id < 0) {
1872 BT_LOGW("Invalid listener ID: must be zero or positive: "
1873 "listener-id=%d", listener_id);
1874 ret = -1;
1875 goto end;
1876 }
1877
1878 if (listener_id >= trace->is_static_listeners->len) {
1879 BT_LOGW("Invalid parameter: no listener with this listener ID: "
1880 "addr=%p, name=\"%s\", listener-id=%d",
1881 trace, bt_trace_get_name(trace),
1882 listener_id);
1883 ret = -1;
1884 goto end;
1885 }
1886
1887 elem = &g_array_index(trace->is_static_listeners,
1888 struct bt_trace_is_static_listener_elem,
1889 listener_id);
1890 if (!elem->func) {
1891 BT_LOGW("Invalid parameter: no listener with this listener ID: "
1892 "addr=%p, name=\"%s\", listener-id=%d",
1893 trace, bt_trace_get_name(trace),
1894 listener_id);
1895 ret = -1;
1896 goto end;
1897 }
1898
1899 if (elem->removed) {
1900 /* Call remove listener */
1901 BT_LOGV("Calling remove listener: "
1902 "trace-addr=%p, trace-name=\"%s\", "
1903 "listener-id=%d", trace, bt_trace_get_name(trace),
1904 listener_id);
1905 trace->in_remove_listener = BT_TRUE;
1906 elem->removed(trace, elem->data);
1907 trace->in_remove_listener = BT_FALSE;
1908 }
1909
1910 elem->func = NULL;
1911 elem->removed = NULL;
1912 elem->data = NULL;
1913 BT_LOGV("Removed \"trace is static\" listener: "
1914 "trace-addr=%p, trace-name=\"%s\", "
1915 "listener-id=%d", trace, bt_trace_get_name(trace),
1916 listener_id);
1917
1918 end:
1919 return ret;
1920 }
1921
1922 struct bt_packet_header_field *bt_trace_create_packet_header_field(
1923 struct bt_trace *trace)
1924 {
1925 struct bt_field_wrapper *field_wrapper;
1926
1927 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
1928 BT_ASSERT_PRE(trace->packet_header_field_type,
1929 "Trace has no packet header field type: %!+t",
1930 trace);
1931 field_wrapper = bt_field_wrapper_create(
1932 &trace->packet_header_field_pool,
1933 (void *) trace->packet_header_field_type);
1934 if (!field_wrapper) {
1935 BT_LIB_LOGE("Cannot allocate one packet header field from trace: "
1936 "%![trace-]+t", trace);
1937 goto error;
1938 }
1939
1940 BT_ASSERT(field_wrapper->field);
1941 bt_trace_freeze(trace);
1942 goto end;
1943
1944 error:
1945 if (field_wrapper) {
1946 bt_field_wrapper_destroy(field_wrapper);
1947 field_wrapper = NULL;
1948 }
1949
1950 end:
1951 return (void *) field_wrapper;
1952 }
This page took 0.142315 seconds and 4 git commands to generate.