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