58d6b3a262bffed99561ca6403ee966186fb8e8b
[babeltrace.git] / src / ctf-writer / trace.c
1 /*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
5 * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
6 */
7
8 #define BT_LOG_TAG "CTF-WRITER/TRACE"
9 #include "logging.h"
10
11 #include <inttypes.h>
12 #include <stdbool.h>
13 #include <stdint.h>
14 #include <stdlib.h>
15 #include <string.h>
16
17 #include <babeltrace2-ctf-writer/event.h>
18 #include <babeltrace2-ctf-writer/object.h>
19 #include <babeltrace2-ctf-writer/utils.h>
20 #include <babeltrace2/types.h>
21
22 #include "common/assert.h"
23 #include "compat/compiler.h"
24 #include "compat/endian.h"
25
26 #include "attributes.h"
27 #include "clock-class.h"
28 #include "clock.h"
29 #include "event-class.h"
30 #include "event.h"
31 #include "field-types.h"
32 #include "field-wrapper.h"
33 #include "functor.h"
34 #include "stream-class.h"
35 #include "stream.h"
36 #include "trace.h"
37 #include "utils.h"
38 #include "validation.h"
39 #include "values.h"
40 #include "visitor.h"
41 #include "writer.h"
42
43 #define DEFAULT_IDENTIFIER_SIZE 128
44 #define DEFAULT_METADATA_STRING_SIZE 4096
45
46 BT_HIDDEN
47 int bt_ctf_trace_common_initialize(struct bt_ctf_trace_common *trace,
48 bt_ctf_object_release_func release_func)
49 {
50 int ret = 0;
51
52 BT_LOGD_STR("Initializing common trace object.");
53 trace->native_byte_order = BT_CTF_BYTE_ORDER_UNSPECIFIED;
54 bt_ctf_object_init_shared_with_parent(&trace->base, release_func);
55 trace->clock_classes = g_ptr_array_new_with_free_func(
56 (GDestroyNotify) bt_ctf_object_put_ref);
57 if (!trace->clock_classes) {
58 BT_LOGE_STR("Failed to allocate one GPtrArray.");
59 goto error;
60 }
61
62 trace->streams = g_ptr_array_new_with_free_func(
63 (GDestroyNotify) bt_ctf_object_try_spec_release);
64 if (!trace->streams) {
65 BT_LOGE_STR("Failed to allocate one GPtrArray.");
66 goto error;
67 }
68
69 trace->stream_classes = g_ptr_array_new_with_free_func(
70 (GDestroyNotify) bt_ctf_object_try_spec_release);
71 if (!trace->stream_classes) {
72 BT_LOGE_STR("Failed to allocate one GPtrArray.");
73 goto error;
74 }
75
76 /* Create the environment array object */
77 trace->environment = bt_ctf_attributes_create();
78 if (!trace->environment) {
79 BT_LOGE_STR("Cannot create empty attributes object.");
80 goto error;
81 }
82
83 BT_LOGD("Initialized common trace object: addr=%p", trace);
84 goto end;
85
86 error:
87 ret = -1;
88
89 end:
90 return ret;
91 }
92
93 BT_HIDDEN
94 void bt_ctf_trace_common_finalize(struct bt_ctf_trace_common *trace)
95 {
96 BT_LOGD("Finalizing common trace object: addr=%p, name=\"%s\"",
97 trace, bt_ctf_trace_common_get_name(trace));
98
99 if (trace->environment) {
100 BT_LOGD_STR("Destroying environment attributes.");
101 bt_ctf_attributes_destroy(trace->environment);
102 }
103
104 if (trace->name) {
105 g_string_free(trace->name, TRUE);
106 }
107
108 if (trace->clock_classes) {
109 BT_LOGD_STR("Putting clock classes.");
110 g_ptr_array_free(trace->clock_classes, TRUE);
111 }
112
113 if (trace->streams) {
114 BT_LOGD_STR("Destroying streams.");
115 g_ptr_array_free(trace->streams, TRUE);
116 }
117
118 if (trace->stream_classes) {
119 BT_LOGD_STR("Destroying stream classes.");
120 g_ptr_array_free(trace->stream_classes, TRUE);
121 }
122
123 BT_LOGD_STR("Putting packet header field type.");
124 bt_ctf_object_put_ref(trace->packet_header_field_type);
125 }
126
127 BT_HIDDEN
128 int bt_ctf_trace_common_set_name(struct bt_ctf_trace_common *trace, const char *name)
129 {
130 int ret = 0;
131
132 if (!trace) {
133 BT_LOGW_STR("Invalid parameter: trace is NULL.");
134 ret = -1;
135 goto end;
136 }
137
138 if (!name) {
139 BT_LOGW_STR("Invalid parameter: name is NULL.");
140 ret = -1;
141 goto end;
142 }
143
144 if (trace->frozen) {
145 BT_LOGW("Invalid parameter: trace is frozen: "
146 "addr=%p, name=\"%s\"",
147 trace, bt_ctf_trace_common_get_name(trace));
148 ret = -1;
149 goto end;
150 }
151
152 trace->name = trace->name ? g_string_assign(trace->name, name) :
153 g_string_new(name);
154 if (!trace->name) {
155 BT_LOGE_STR("Failed to allocate one GString.");
156 ret = -1;
157 goto end;
158 }
159
160 BT_LOGT("Set trace's name: addr=%p, name=\"%s\"", trace, name);
161
162 end:
163 return ret;
164 }
165
166 BT_HIDDEN
167 int bt_ctf_trace_common_set_uuid(struct bt_ctf_trace_common *trace,
168 const uint8_t *uuid)
169 {
170 int ret = 0;
171
172 if (!trace) {
173 BT_LOGW_STR("Invalid parameter: trace is NULL.");
174 ret = -1;
175 goto end;
176 }
177
178 if (!uuid) {
179 BT_LOGW_STR("Invalid parameter: UUID is NULL.");
180 ret = -1;
181 goto end;
182 }
183
184 if (trace->frozen) {
185 BT_LOGW("Invalid parameter: trace is frozen: "
186 "addr=%p, name=\"%s\"",
187 trace, bt_ctf_trace_common_get_name(trace));
188 ret = -1;
189 goto end;
190 }
191
192 bt_uuid_copy(trace->uuid, uuid);
193 trace->uuid_set = BT_CTF_TRUE;
194 BT_LOGT("Set trace's UUID: addr=%p, name=\"%s\", "
195 "uuid=\"" BT_UUID_FMT "\"",
196 trace, bt_ctf_trace_common_get_name(trace),
197 BT_UUID_FMT_VALUES(uuid));
198
199 end:
200 return ret;
201 }
202
203 BT_HIDDEN
204 int bt_ctf_trace_common_set_environment_field(struct bt_ctf_trace_common *trace,
205 const char *name, struct bt_ctf_private_value *value)
206 {
207 int ret = 0;
208
209 if (!trace) {
210 BT_LOGW_STR("Invalid parameter: trace is NULL.");
211 ret = -1;
212 goto end;
213 }
214
215 if (!name) {
216 BT_LOGW_STR("Invalid parameter: name is NULL.");
217 ret = -1;
218 goto end;
219 }
220
221 if (!value) {
222 BT_LOGW_STR("Invalid parameter: value is NULL.");
223 ret = -1;
224 goto end;
225 }
226
227 if (!bt_ctf_identifier_is_valid(name)) {
228 BT_LOGW("Invalid parameter: environment field's name is not a valid CTF identifier: "
229 "trace-addr=%p, trace-name=\"%s\", "
230 "env-name=\"%s\"",
231 trace, bt_ctf_trace_common_get_name(trace), name);
232 ret = -1;
233 goto end;
234 }
235
236 if (!bt_ctf_value_is_integer(bt_ctf_private_value_as_value(value)) &&
237 !bt_ctf_value_is_string(bt_ctf_private_value_as_value(value))) {
238 BT_LOGW("Invalid parameter: environment field's value is not an integer or string value: "
239 "trace-addr=%p, trace-name=\"%s\", "
240 "env-name=\"%s\", env-value-type=%s",
241 trace, bt_ctf_trace_common_get_name(trace), name,
242 bt_ctf_value_type_string(
243 bt_ctf_value_get_type(
244 bt_ctf_private_value_as_value(value))));
245 ret = -1;
246 goto end;
247 }
248
249 if (trace->frozen) {
250 /*
251 * New environment fields may be added to a frozen trace,
252 * but existing fields may not be changed.
253 *
254 * The object passed is frozen like all other attributes.
255 */
256 struct bt_ctf_private_value *attribute =
257 bt_ctf_attributes_borrow_field_value_by_name(
258 trace->environment, name);
259
260 if (attribute) {
261 BT_LOGW("Invalid parameter: trace is frozen and environment field already exists with this name: "
262 "trace-addr=%p, trace-name=\"%s\", "
263 "env-name=\"%s\"",
264 trace, bt_ctf_trace_common_get_name(trace), name);
265 ret = -1;
266 goto end;
267 }
268
269 bt_ctf_value_freeze(bt_ctf_private_value_as_value(value));
270 }
271
272 ret = bt_ctf_attributes_set_field_value(trace->environment, name,
273 value);
274 if (ret) {
275 BT_LOGE("Cannot set environment field's value: "
276 "trace-addr=%p, trace-name=\"%s\", "
277 "env-name=\"%s\"",
278 trace, bt_ctf_trace_common_get_name(trace), name);
279 } else {
280 BT_LOGT("Set environment field's value: "
281 "trace-addr=%p, trace-name=\"%s\", "
282 "env-name=\"%s\", value-addr=%p",
283 trace, bt_ctf_trace_common_get_name(trace), name, value);
284 }
285
286 end:
287 return ret;
288 }
289
290 BT_HIDDEN
291 int bt_ctf_trace_common_set_environment_field_string(struct bt_ctf_trace_common *trace,
292 const char *name, const char *value)
293 {
294 int ret = 0;
295 struct bt_ctf_private_value *env_value_string_obj = NULL;
296
297 if (!value) {
298 BT_LOGW_STR("Invalid parameter: value is NULL.");
299 ret = -1;
300 goto end;
301 }
302
303 env_value_string_obj = bt_ctf_private_value_string_create_init(value);
304 if (!env_value_string_obj) {
305 BT_LOGE_STR("Cannot create string value object.");
306 ret = -1;
307 goto end;
308 }
309
310 /* bt_ctf_trace_common_set_environment_field() logs errors */
311 ret = bt_ctf_trace_common_set_environment_field(trace, name,
312 env_value_string_obj);
313
314 end:
315 bt_ctf_object_put_ref(env_value_string_obj);
316 return ret;
317 }
318
319 BT_HIDDEN
320 int bt_ctf_trace_common_set_environment_field_integer(
321 struct bt_ctf_trace_common *trace, const char *name, int64_t value)
322 {
323 int ret = 0;
324 struct bt_ctf_private_value *env_value_integer_obj = NULL;
325
326 env_value_integer_obj = bt_ctf_private_value_integer_create_init(value);
327 if (!env_value_integer_obj) {
328 BT_LOGE_STR("Cannot create integer value object.");
329 ret = -1;
330 goto end;
331 }
332
333 /* bt_ctf_trace_common_set_environment_field() logs errors */
334 ret = bt_ctf_trace_common_set_environment_field(trace, name,
335 env_value_integer_obj);
336
337 end:
338 bt_ctf_object_put_ref(env_value_integer_obj);
339 return ret;
340 }
341
342 BT_HIDDEN
343 int bt_ctf_trace_common_add_clock_class(struct bt_ctf_trace_common *trace,
344 struct bt_ctf_clock_class *clock_class)
345 {
346 int ret = 0;
347
348 if (!trace) {
349 BT_LOGW_STR("Invalid parameter: trace is NULL.");
350 ret = -1;
351 goto end;
352 }
353
354 if (!bt_ctf_clock_class_is_valid(clock_class)) {
355 BT_LOGW("Invalid parameter: clock class is invalid: "
356 "trace-addr=%p, trace-name=\"%s\", "
357 "clock-class-addr=%p, clock-class-name=\"%s\"",
358 trace, bt_ctf_trace_common_get_name(trace),
359 clock_class, bt_ctf_clock_class_get_name(clock_class));
360 ret = -1;
361 goto end;
362 }
363
364 /* Check for duplicate clock classes */
365 if (bt_ctf_trace_common_has_clock_class(trace, clock_class)) {
366 BT_LOGW("Invalid parameter: clock class already exists in trace: "
367 "trace-addr=%p, trace-name=\"%s\", "
368 "clock-class-addr=%p, clock-class-name=\"%s\"",
369 trace, bt_ctf_trace_common_get_name(trace),
370 clock_class, bt_ctf_clock_class_get_name(clock_class));
371 ret = -1;
372 goto end;
373 }
374
375 bt_ctf_object_get_ref(clock_class);
376 g_ptr_array_add(trace->clock_classes, clock_class);
377
378 if (trace->frozen) {
379 BT_LOGT_STR("Freezing added clock class because trace is frozen.");
380 bt_ctf_clock_class_freeze(clock_class);
381 }
382
383 BT_LOGT("Added clock class to trace: "
384 "trace-addr=%p, trace-name=\"%s\", "
385 "clock-class-addr=%p, clock-class-name=\"%s\"",
386 trace, bt_ctf_trace_common_get_name(trace),
387 clock_class, bt_ctf_clock_class_get_name(clock_class));
388
389 end:
390 return ret;
391 }
392
393 static
394 bool packet_header_field_type_is_valid(struct bt_ctf_trace_common *trace,
395 struct bt_ctf_field_type_common *packet_header_type)
396 {
397 int ret;
398 bool is_valid = true;
399 struct bt_ctf_field_type_common *field_type = NULL;
400
401 if (!packet_header_type) {
402 /*
403 * No packet header field type: trace must have only
404 * one stream. At this point the stream class being
405 * added is not part of the trace yet, so we validate
406 * that the trace contains no stream classes yet.
407 */
408 if (trace->stream_classes->len >= 1) {
409 BT_LOGW_STR("Invalid packet header field type: "
410 "packet header field type does not exist but there's more than one stream class in the trace.");
411 goto invalid;
412 }
413
414 /* No packet header field type: valid at this point */
415 goto end;
416 }
417
418 /* Packet header field type, if it exists, must be a structure */
419 if (packet_header_type->id != BT_CTF_FIELD_TYPE_ID_STRUCT) {
420 BT_LOGW("Invalid packet header field type: must be a structure field type if it exists: "
421 "ft-addr=%p, ft-id=%s",
422 packet_header_type,
423 bt_ctf_field_type_id_string(packet_header_type->id));
424 goto invalid;
425 }
426
427 /*
428 * If there's a `magic` field, it must be a 32-bit unsigned
429 * integer field type. Also it must be the first field of the
430 * packet header field type.
431 */
432 field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name(
433 packet_header_type, "magic");
434 if (field_type) {
435 const char *field_name;
436
437 if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
438 BT_LOGW("Invalid packet header field type: `magic` field must be an integer field type: "
439 "magic-ft-addr=%p, magic-ft-id=%s",
440 field_type,
441 bt_ctf_field_type_id_string(field_type->id));
442 goto invalid;
443 }
444
445 if (bt_ctf_field_type_common_integer_is_signed(field_type)) {
446 BT_LOGW("Invalid packet header field type: `magic` field must be an unsigned integer field type: "
447 "magic-ft-addr=%p", field_type);
448 goto invalid;
449 }
450
451 if (bt_ctf_field_type_common_integer_get_size(field_type) != 32) {
452 BT_LOGW("Invalid packet header field type: `magic` field must be a 32-bit unsigned integer field type: "
453 "magic-ft-addr=%p, magic-ft-size=%u",
454 field_type,
455 bt_ctf_field_type_common_integer_get_size(field_type));
456 goto invalid;
457 }
458
459 ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
460 packet_header_type, &field_name, NULL, 0);
461 BT_ASSERT_DBG(ret == 0);
462
463 if (strcmp(field_name, "magic") != 0) {
464 BT_LOGW("Invalid packet header field type: `magic` field must be the first field: "
465 "magic-ft-addr=%p, first-field-name=\"%s\"",
466 field_type, field_name);
467 goto invalid;
468 }
469 }
470
471 /*
472 * If there's a `uuid` field, it must be an array field type of
473 * length 16 with an 8-bit unsigned integer element field type.
474 */
475 field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name(
476 packet_header_type, "uuid");
477 if (field_type) {
478 struct bt_ctf_field_type_common *elem_ft;
479
480 if (field_type->id != BT_CTF_FIELD_TYPE_ID_ARRAY) {
481 BT_LOGW("Invalid packet header field type: `uuid` field must be an array field type: "
482 "uuid-ft-addr=%p, uuid-ft-id=%s",
483 field_type,
484 bt_ctf_field_type_id_string(field_type->id));
485 goto invalid;
486 }
487
488 if (bt_ctf_field_type_common_array_get_length(field_type) != 16) {
489 BT_LOGW("Invalid packet header field type: `uuid` array field type's length must be 16: "
490 "uuid-ft-addr=%p, uuid-ft-length=%" PRId64,
491 field_type,
492 bt_ctf_field_type_common_array_get_length(field_type));
493 goto invalid;
494 }
495
496 elem_ft = bt_ctf_field_type_common_array_borrow_element_field_type(field_type);
497 BT_ASSERT_DBG(elem_ft);
498
499 if (elem_ft->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
500 BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an integer field type: "
501 "elem-ft-addr=%p, elem-ft-id=%s",
502 elem_ft,
503 bt_ctf_field_type_id_string(elem_ft->id));
504 goto invalid;
505 }
506
507 if (bt_ctf_field_type_common_integer_is_signed(elem_ft)) {
508 BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an unsigned integer field type: "
509 "elem-ft-addr=%p", elem_ft);
510 goto invalid;
511 }
512
513 if (bt_ctf_field_type_common_integer_get_size(elem_ft) != 8) {
514 BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an 8-bit unsigned integer field type: "
515 "elem-ft-addr=%p, elem-ft-size=%u",
516 elem_ft,
517 bt_ctf_field_type_common_integer_get_size(elem_ft));
518 goto invalid;
519 }
520 }
521
522 /*
523 * The `stream_id` field must exist if there's more than one
524 * stream classes in the trace.
525 */
526 field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name(
527 packet_header_type, "stream_id");
528
529 if (!field_type && trace->stream_classes->len >= 1) {
530 BT_LOGW_STR("Invalid packet header field type: "
531 "`stream_id` field does not exist but there's more than one stream class in the trace.");
532 goto invalid;
533 }
534
535 /*
536 * If there's a `stream_id` field, it must be an unsigned
537 * integer field type.
538 */
539 if (field_type) {
540 if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
541 BT_LOGW("Invalid packet header field type: `stream_id` field must be an integer field type: "
542 "stream-id-ft-addr=%p, stream-id-ft-id=%s",
543 field_type,
544 bt_ctf_field_type_id_string(field_type->id));
545 goto invalid;
546 }
547
548 if (bt_ctf_field_type_common_integer_is_signed(field_type)) {
549 BT_LOGW("Invalid packet header field type: `stream_id` field must be an unsigned integer field type: "
550 "stream-id-ft-addr=%p", field_type);
551 goto invalid;
552 }
553 }
554
555 /*
556 * If there's a `packet_seq_num` field, it must be an unsigned
557 * integer field type.
558 */
559 field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name(
560 packet_header_type, "packet_seq_num");
561 if (field_type) {
562 if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
563 BT_LOGW("Invalid packet header field type: `packet_seq_num` field must be an integer field type: "
564 "stream-id-ft-addr=%p, packet-seq-num-ft-id=%s",
565 field_type,
566 bt_ctf_field_type_id_string(field_type->id));
567 goto invalid;
568 }
569
570 if (bt_ctf_field_type_common_integer_is_signed(field_type)) {
571 BT_LOGW("Invalid packet header field type: `packet_seq_num` field must be an unsigned integer field type: "
572 "packet-seq-num-ft-addr=%p", field_type);
573 goto invalid;
574 }
575 }
576
577 goto end;
578
579 invalid:
580 is_valid = false;
581
582 end:
583 return is_valid;
584 }
585
586 static
587 bool packet_context_field_type_is_valid(struct bt_ctf_trace_common *trace,
588 struct bt_ctf_stream_class_common *stream_class,
589 struct bt_ctf_field_type_common *packet_context_type,
590 bool check_ts_begin_end_mapped)
591 {
592 bool is_valid = true;
593 struct bt_ctf_field_type_common *field_type = NULL;
594
595 if (!packet_context_type) {
596 /* No packet context field type: valid at this point */
597 goto end;
598 }
599
600 /* Packet context field type, if it exists, must be a structure */
601 if (packet_context_type->id != BT_CTF_FIELD_TYPE_ID_STRUCT) {
602 BT_LOGW("Invalid packet context field type: must be a structure field type if it exists: "
603 "ft-addr=%p, ft-id=%s",
604 packet_context_type,
605 bt_ctf_field_type_id_string(packet_context_type->id));
606 goto invalid;
607 }
608
609 /*
610 * If there's a `packet_size` field, it must be an unsigned
611 * integer field type.
612 */
613 field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name(
614 packet_context_type, "packet_size");
615 if (field_type) {
616 if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
617 BT_LOGW("Invalid packet context field type: `packet_size` field must be an integer field type: "
618 "packet-size-ft-addr=%p, packet-size-ft-id=%s",
619 field_type,
620 bt_ctf_field_type_id_string(field_type->id));
621 goto invalid;
622 }
623
624 if (bt_ctf_field_type_common_integer_is_signed(field_type)) {
625 BT_LOGW("Invalid packet context field type: `packet_size` field must be an unsigned integer field type: "
626 "packet-size-ft-addr=%p", field_type);
627 goto invalid;
628 }
629 }
630
631 /*
632 * If there's a `content_size` field, it must be an unsigned
633 * integer field type.
634 */
635 field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name(
636 packet_context_type, "content_size");
637 if (field_type) {
638 if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
639 BT_LOGW("Invalid packet context field type: `content_size` field must be an integer field type: "
640 "content-size-ft-addr=%p, content-size-ft-id=%s",
641 field_type,
642 bt_ctf_field_type_id_string(field_type->id));
643 goto invalid;
644 }
645
646 if (bt_ctf_field_type_common_integer_is_signed(field_type)) {
647 BT_LOGW("Invalid packet context field type: `content_size` field must be an unsigned integer field type: "
648 "content-size-ft-addr=%p", field_type);
649 goto invalid;
650 }
651 }
652
653 /*
654 * If there's a `events_discarded` field, it must be an unsigned
655 * integer field type.
656 */
657 field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name(
658 packet_context_type, "events_discarded");
659 if (field_type) {
660 if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
661 BT_LOGW("Invalid packet context field type: `events_discarded` field must be an integer field type: "
662 "events-discarded-ft-addr=%p, events-discarded-ft-id=%s",
663 field_type,
664 bt_ctf_field_type_id_string(field_type->id));
665 goto invalid;
666 }
667
668 if (bt_ctf_field_type_common_integer_is_signed(field_type)) {
669 BT_LOGW("Invalid packet context field type: `events_discarded` field must be an unsigned integer field type: "
670 "events-discarded-ft-addr=%p", field_type);
671 goto invalid;
672 }
673 }
674
675 /*
676 * If there's a `timestamp_begin` field, it must be an unsigned
677 * integer field type. Also, if the trace is not a CTF writer's
678 * trace, then we cannot automatically set the mapped clock
679 * class of this field, so it must have a mapped clock class.
680 */
681 field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name(
682 packet_context_type, "timestamp_begin");
683 if (field_type) {
684 if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
685 BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be an integer field type: "
686 "timestamp-begin-ft-addr=%p, timestamp-begin-ft-id=%s",
687 field_type,
688 bt_ctf_field_type_id_string(field_type->id));
689 goto invalid;
690 }
691
692 if (bt_ctf_field_type_common_integer_is_signed(field_type)) {
693 BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be an unsigned integer field type: "
694 "timestamp-begin-ft-addr=%p", field_type);
695 goto invalid;
696 }
697
698 if (check_ts_begin_end_mapped) {
699 struct bt_ctf_clock_class *clock_class =
700 bt_ctf_field_type_common_integer_borrow_mapped_clock_class(
701 field_type);
702
703 if (!clock_class) {
704 BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be mapped to a clock class: "
705 "timestamp-begin-ft-addr=%p", field_type);
706 goto invalid;
707 }
708 }
709 }
710
711 /*
712 * If there's a `timestamp_end` field, it must be an unsigned
713 * integer field type. Also, if the trace is not a CTF writer's
714 * trace, then we cannot automatically set the mapped clock
715 * class of this field, so it must have a mapped clock class.
716 */
717 field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name(
718 packet_context_type, "timestamp_end");
719 if (field_type) {
720 if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
721 BT_LOGW("Invalid packet context field type: `timestamp_end` field must be an integer field type: "
722 "timestamp-end-ft-addr=%p, timestamp-end-ft-id=%s",
723 field_type,
724 bt_ctf_field_type_id_string(field_type->id));
725 goto invalid;
726 }
727
728 if (bt_ctf_field_type_common_integer_is_signed(field_type)) {
729 BT_LOGW("Invalid packet context field type: `timestamp_end` field must be an unsigned integer field type: "
730 "timestamp-end-ft-addr=%p", field_type);
731 goto invalid;
732 }
733
734 if (check_ts_begin_end_mapped) {
735 struct bt_ctf_clock_class *clock_class =
736 bt_ctf_field_type_common_integer_borrow_mapped_clock_class(
737 field_type);
738
739 if (!clock_class) {
740 BT_LOGW("Invalid packet context field type: `timestamp_end` field must be mapped to a clock class: "
741 "timestamp-end-ft-addr=%p", field_type);
742 goto invalid;
743 }
744 }
745 }
746
747 goto end;
748
749 invalid:
750 is_valid = false;
751
752 end:
753 return is_valid;
754 }
755
756 static
757 bool event_header_field_type_is_valid(struct bt_ctf_trace_common *trace,
758 struct bt_ctf_stream_class_common *stream_class,
759 struct bt_ctf_field_type_common *event_header_type)
760 {
761 bool is_valid = true;
762 struct bt_ctf_field_type_common *field_type = NULL;
763
764 /*
765 * We do not validate that the `timestamp` field exists here
766 * because CTF does not require this exact name to be mapped to
767 * a clock class.
768 */
769
770 if (!event_header_type) {
771 /*
772 * No event header field type: stream class must have
773 * only one event class.
774 */
775 if (bt_ctf_stream_class_common_get_event_class_count(stream_class) > 1) {
776 BT_LOGW_STR("Invalid event header field type: "
777 "event header field type does not exist but there's more than one event class in the stream class.");
778 goto invalid;
779 }
780
781 /* No event header field type: valid at this point */
782 goto end;
783 }
784
785 /* Event header field type, if it exists, must be a structure */
786 if (event_header_type->id != BT_CTF_FIELD_TYPE_ID_STRUCT) {
787 BT_LOGW("Invalid event header field type: must be a structure field type if it exists: "
788 "ft-addr=%p, ft-id=%s",
789 event_header_type,
790 bt_ctf_field_type_id_string(event_header_type->id));
791 goto invalid;
792 }
793
794 /*
795 * If there's an `id` field, it must be an unsigned integer
796 * field type or an enumeration field type with an unsigned
797 * integer container field type.
798 */
799 field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name(
800 event_header_type, "id");
801 if (field_type) {
802 struct bt_ctf_field_type_common *int_ft;
803
804 if (field_type->id == BT_CTF_FIELD_TYPE_ID_INTEGER) {
805 int_ft = field_type;
806 } else if (field_type->id == BT_CTF_FIELD_TYPE_ID_ENUM) {
807 int_ft = bt_ctf_field_type_common_enumeration_borrow_container_field_type(
808 field_type);
809 } else {
810 BT_LOGW("Invalid event header field type: `id` field must be an integer or enumeration field type: "
811 "id-ft-addr=%p, id-ft-id=%s",
812 field_type,
813 bt_ctf_field_type_id_string(field_type->id));
814 goto invalid;
815 }
816
817 BT_ASSERT_DBG(int_ft);
818 if (bt_ctf_field_type_common_integer_is_signed(int_ft)) {
819 BT_LOGW("Invalid event header field type: `id` field must be an unsigned integer or enumeration field type: "
820 "id-ft-addr=%p", int_ft);
821 goto invalid;
822 }
823 }
824
825 goto end;
826
827 invalid:
828 is_valid = false;
829
830 end:
831 return is_valid;
832 }
833
834 static
835 int check_packet_header_type_has_no_clock_class(struct bt_ctf_trace_common *trace)
836 {
837 int ret = 0;
838
839 if (trace->packet_header_field_type) {
840 struct bt_ctf_clock_class *clock_class = NULL;
841
842 ret = bt_ctf_field_type_common_validate_single_clock_class(
843 trace->packet_header_field_type,
844 &clock_class);
845 bt_ctf_object_put_ref(clock_class);
846 if (ret || clock_class) {
847 BT_LOGW("Trace's packet header field type cannot "
848 "contain a field type which is mapped to "
849 "a clock class: "
850 "trace-addr=%p, trace-name=\"%s\", "
851 "clock-class-name=\"%s\"",
852 trace, bt_ctf_trace_common_get_name(trace),
853 clock_class ?
854 bt_ctf_clock_class_get_name(clock_class) :
855 NULL);
856 ret = -1;
857 }
858 }
859
860 return ret;
861 }
862
863 BT_HIDDEN
864 int bt_ctf_trace_common_add_stream_class(struct bt_ctf_trace_common *trace,
865 struct bt_ctf_stream_class_common *stream_class,
866 bt_ctf_validation_flag_copy_field_type_func copy_field_type_func,
867 struct bt_ctf_clock_class *init_expected_clock_class,
868 int (*map_clock_classes_func)(struct bt_ctf_stream_class_common *stream_class,
869 struct bt_ctf_field_type_common *packet_context_field_type,
870 struct bt_ctf_field_type_common *event_header_field_type),
871 bool check_ts_begin_end_mapped)
872 {
873 int ret;
874 int64_t i;
875 int64_t stream_id;
876 struct bt_ctf_validation_output trace_sc_validation_output = { 0 };
877 struct bt_ctf_validation_output *ec_validation_outputs = NULL;
878 const enum bt_ctf_validation_flag trace_sc_validation_flags =
879 BT_CTF_VALIDATION_FLAG_TRACE |
880 BT_CTF_VALIDATION_FLAG_STREAM;
881 const enum bt_ctf_validation_flag ec_validation_flags =
882 BT_CTF_VALIDATION_FLAG_EVENT;
883 struct bt_ctf_field_type_common *packet_header_type = NULL;
884 struct bt_ctf_field_type_common *packet_context_type = NULL;
885 struct bt_ctf_field_type_common *event_header_type = NULL;
886 struct bt_ctf_field_type_common *stream_event_ctx_type = NULL;
887 int64_t event_class_count = 0;
888 struct bt_ctf_trace_common *current_parent_trace = NULL;
889 struct bt_ctf_clock_class *expected_clock_class =
890 bt_ctf_object_get_ref(init_expected_clock_class);
891
892 BT_ASSERT_DBG(copy_field_type_func);
893
894 if (!trace) {
895 BT_LOGW_STR("Invalid parameter: trace is NULL.");
896 ret = -1;
897 goto end;
898 }
899
900 if (!stream_class) {
901 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
902 ret = -1;
903 goto end;
904 }
905
906 BT_LOGD("Adding stream class to trace: "
907 "trace-addr=%p, trace-name=\"%s\", "
908 "stream-class-addr=%p, stream-class-name=\"%s\", "
909 "stream-class-id=%" PRId64,
910 trace, bt_ctf_trace_common_get_name(trace),
911 stream_class, bt_ctf_stream_class_common_get_name(stream_class),
912 bt_ctf_stream_class_common_get_id(stream_class));
913
914 current_parent_trace = bt_ctf_stream_class_common_borrow_trace(stream_class);
915 if (current_parent_trace) {
916 /* Stream class is already associated to a trace, abort. */
917 BT_LOGW("Invalid parameter: stream class is already part of a trace: "
918 "stream-class-trace-addr=%p, "
919 "stream-class-trace-name=\"%s\"",
920 current_parent_trace,
921 bt_ctf_trace_common_get_name(current_parent_trace));
922 ret = -1;
923 goto end;
924 }
925
926 event_class_count =
927 bt_ctf_stream_class_common_get_event_class_count(stream_class);
928 BT_ASSERT_DBG(event_class_count >= 0);
929
930 if (!stream_class->frozen) {
931 /*
932 * Stream class is not frozen yet. Validate that the
933 * stream class contains at most a single clock class
934 * because the previous
935 * bt_ctf_stream_class_common_add_event_class() calls did
936 * not make this validation since the stream class's
937 * direct field types (packet context, event header,
938 * event context) could change afterwards. This stream
939 * class is about to be frozen and those field types
940 * won't be changed if this function succeeds.
941 *
942 * At this point we're also sure that the stream class's
943 * clock, if any, has the same class as the stream
944 * class's expected clock class, if any. This is why, if
945 * bt_ctf_stream_class_common_validate_single_clock_class()
946 * succeeds below, the call to
947 * bt_ctf_stream_class_map_clock_class() at the end of this
948 * function is safe because it maps to the same, single
949 * clock class.
950 */
951 ret = bt_ctf_stream_class_common_validate_single_clock_class(
952 stream_class, &expected_clock_class);
953 if (ret) {
954 BT_LOGW("Invalid parameter: stream class or one of its "
955 "event classes contains a field type which is "
956 "not recursively mapped to the expected "
957 "clock class: "
958 "stream-class-addr=%p, "
959 "stream-class-id=%" PRId64 ", "
960 "stream-class-name=\"%s\", "
961 "expected-clock-class-addr=%p, "
962 "expected-clock-class-name=\"%s\"",
963 stream_class, bt_ctf_stream_class_common_get_id(stream_class),
964 bt_ctf_stream_class_common_get_name(stream_class),
965 expected_clock_class,
966 expected_clock_class ?
967 bt_ctf_clock_class_get_name(expected_clock_class) :
968 NULL);
969 goto end;
970 }
971 }
972
973 ret = check_packet_header_type_has_no_clock_class(trace);
974 if (ret) {
975 /* check_packet_header_type_has_no_clock_class() logs errors */
976 goto end;
977 }
978
979 /*
980 * We're about to freeze both the trace and the stream class.
981 * Also, each event class contained in this stream class are
982 * already frozen.
983 *
984 * This trace, this stream class, and all its event classes
985 * should be valid at this point.
986 *
987 * Validate trace and stream class first, then each event
988 * class of this stream class can be validated individually.
989 */
990 packet_header_type =
991 bt_ctf_trace_common_borrow_packet_header_field_type(trace);
992 packet_context_type =
993 bt_ctf_stream_class_common_borrow_packet_context_field_type(stream_class);
994 event_header_type =
995 bt_ctf_stream_class_common_borrow_event_header_field_type(stream_class);
996 stream_event_ctx_type =
997 bt_ctf_stream_class_common_borrow_event_context_field_type(stream_class);
998
999 BT_LOGD("Validating trace and stream class field types.");
1000 ret = bt_ctf_validate_class_types(trace->environment,
1001 packet_header_type, packet_context_type, event_header_type,
1002 stream_event_ctx_type, NULL, NULL, trace->valid,
1003 stream_class->valid, 1, &trace_sc_validation_output,
1004 trace_sc_validation_flags, copy_field_type_func);
1005
1006 if (ret) {
1007 /*
1008 * This means something went wrong during the validation
1009 * process, not that the objects are invalid.
1010 */
1011 BT_LOGE("Failed to validate trace and stream class field types: "
1012 "ret=%d", ret);
1013 goto end;
1014 }
1015
1016 if ((trace_sc_validation_output.valid_flags &
1017 trace_sc_validation_flags) !=
1018 trace_sc_validation_flags) {
1019 /* Invalid trace/stream class */
1020 BT_LOGW("Invalid trace or stream class field types: "
1021 "valid-flags=0x%x",
1022 trace_sc_validation_output.valid_flags);
1023 ret = -1;
1024 goto end;
1025 }
1026
1027 if (event_class_count > 0) {
1028 ec_validation_outputs = g_new0(struct bt_ctf_validation_output,
1029 event_class_count);
1030 if (!ec_validation_outputs) {
1031 BT_LOGE_STR("Failed to allocate one validation output structure.");
1032 ret = -1;
1033 goto end;
1034 }
1035 }
1036
1037 /* Validate each event class individually */
1038 for (i = 0; i < event_class_count; i++) {
1039 struct bt_ctf_event_class_common *event_class =
1040 bt_ctf_stream_class_common_borrow_event_class_by_index(
1041 stream_class, i);
1042 struct bt_ctf_field_type_common *event_context_type = NULL;
1043 struct bt_ctf_field_type_common *event_payload_type = NULL;
1044
1045 event_context_type =
1046 bt_ctf_event_class_common_borrow_context_field_type(
1047 event_class);
1048 event_payload_type =
1049 bt_ctf_event_class_common_borrow_payload_field_type(
1050 event_class);
1051
1052 /*
1053 * It is important to use the field types returned by
1054 * the previous trace and stream class validation here
1055 * because copies could have been made.
1056 */
1057 BT_LOGD("Validating event class's field types: "
1058 "addr=%p, name=\"%s\", id=%" PRId64,
1059 event_class, bt_ctf_event_class_common_get_name(event_class),
1060 bt_ctf_event_class_common_get_id(event_class));
1061 ret = bt_ctf_validate_class_types(trace->environment,
1062 trace_sc_validation_output.packet_header_type,
1063 trace_sc_validation_output.packet_context_type,
1064 trace_sc_validation_output.event_header_type,
1065 trace_sc_validation_output.stream_event_ctx_type,
1066 event_context_type, event_payload_type,
1067 1, 1, event_class->valid, &ec_validation_outputs[i],
1068 ec_validation_flags, copy_field_type_func);
1069
1070 if (ret) {
1071 BT_LOGE("Failed to validate event class field types: "
1072 "ret=%d", ret);
1073 goto end;
1074 }
1075
1076 if ((ec_validation_outputs[i].valid_flags &
1077 ec_validation_flags) != ec_validation_flags) {
1078 /* Invalid event class */
1079 BT_LOGW("Invalid event class field types: "
1080 "valid-flags=0x%x",
1081 ec_validation_outputs[i].valid_flags);
1082 ret = -1;
1083 goto end;
1084 }
1085 }
1086
1087 stream_id = bt_ctf_stream_class_common_get_id(stream_class);
1088 if (stream_id < 0) {
1089 stream_id = trace->next_stream_id++;
1090 if (stream_id < 0) {
1091 BT_LOGE_STR("No more stream class IDs available.");
1092 ret = -1;
1093 goto end;
1094 }
1095
1096 /* Try to assign a new stream id */
1097 for (i = 0; i < trace->stream_classes->len; i++) {
1098 if (stream_id == bt_ctf_stream_class_common_get_id(
1099 trace->stream_classes->pdata[i])) {
1100 /* Duplicate stream id found */
1101 BT_LOGW("Duplicate stream class ID: "
1102 "id=%" PRId64, (int64_t) stream_id);
1103 ret = -1;
1104 goto end;
1105 }
1106 }
1107
1108 if (bt_ctf_stream_class_common_set_id_no_check(stream_class,
1109 stream_id)) {
1110 /* TODO Should retry with a different stream id */
1111 BT_LOGE("Cannot set stream class's ID: "
1112 "id=%" PRId64, (int64_t) stream_id);
1113 ret = -1;
1114 goto end;
1115 }
1116 }
1117
1118 /*
1119 * At this point all the field types in the validation output
1120 * are valid. Validate the semantics of some scopes according to
1121 * the CTF specification.
1122 */
1123 if (!packet_header_field_type_is_valid(trace,
1124 trace_sc_validation_output.packet_header_type)) {
1125 BT_LOGW_STR("Invalid trace's packet header field type.");
1126 ret = -1;
1127 goto end;
1128 }
1129
1130 if (!packet_context_field_type_is_valid(trace,
1131 stream_class,
1132 trace_sc_validation_output.packet_context_type,
1133 check_ts_begin_end_mapped)) {
1134 BT_LOGW_STR("Invalid stream class's packet context field type.");
1135 ret = -1;
1136 goto end;
1137 }
1138
1139 if (!event_header_field_type_is_valid(trace,
1140 stream_class,
1141 trace_sc_validation_output.event_header_type)) {
1142 BT_LOGW_STR("Invalid steam class's event header field type.");
1143 ret = -1;
1144 goto end;
1145 }
1146
1147 /*
1148 * Now is the time to automatically map specific field types of
1149 * the stream class's packet context and event header field
1150 * types to the stream class's clock's class if they are not
1151 * mapped to a clock class yet. We do it here because we know
1152 * that after this point, everything is frozen so it won't be
1153 * possible for the user to modify the stream class's clock, or
1154 * to map those field types to other clock classes.
1155 */
1156 if (map_clock_classes_func) {
1157 if (map_clock_classes_func(stream_class,
1158 trace_sc_validation_output.packet_context_type,
1159 trace_sc_validation_output.event_header_type)) {
1160 /* map_clock_classes_func() logs errors */
1161 ret = -1;
1162 goto end;
1163 }
1164 }
1165
1166 bt_ctf_object_set_parent(&stream_class->base, &trace->base);
1167 g_ptr_array_add(trace->stream_classes, stream_class);
1168
1169 /*
1170 * At this point we know that the function will be successful.
1171 * Therefore we can replace the trace and stream class field
1172 * types with what's in their validation output structure and
1173 * mark them as valid. We can also replace the field types of
1174 * all the event classes of the stream class and mark them as
1175 * valid.
1176 */
1177 bt_ctf_validation_replace_types(trace, stream_class, NULL,
1178 &trace_sc_validation_output, trace_sc_validation_flags);
1179 trace->valid = 1;
1180 stream_class->valid = 1;
1181
1182 /*
1183 * Put what was not moved in bt_ctf_validation_replace_types().
1184 */
1185 bt_ctf_validation_output_put_types(&trace_sc_validation_output);
1186
1187 for (i = 0; i < event_class_count; i++) {
1188 struct bt_ctf_event_class_common *event_class =
1189 bt_ctf_stream_class_common_borrow_event_class_by_index(
1190 stream_class, i);
1191
1192 bt_ctf_validation_replace_types(NULL, NULL, event_class,
1193 &ec_validation_outputs[i], ec_validation_flags);
1194 event_class->valid = 1;
1195
1196 /*
1197 * Put what was not moved in
1198 * bt_ctf_validation_replace_types().
1199 */
1200 bt_ctf_validation_output_put_types(&ec_validation_outputs[i]);
1201 }
1202
1203 /*
1204 * Freeze the trace and the stream class.
1205 */
1206 bt_ctf_stream_class_common_freeze(stream_class);
1207 bt_ctf_trace_common_freeze(trace);
1208
1209 /*
1210 * It is safe to set the stream class's unique clock class
1211 * now because the stream class is frozen.
1212 */
1213 if (expected_clock_class) {
1214 BT_CTF_OBJECT_MOVE_REF(stream_class->clock_class, expected_clock_class);
1215 }
1216
1217 BT_LOGD("Added stream class to trace: "
1218 "trace-addr=%p, trace-name=\"%s\", "
1219 "stream-class-addr=%p, stream-class-name=\"%s\", "
1220 "stream-class-id=%" PRId64,
1221 trace, bt_ctf_trace_common_get_name(trace),
1222 stream_class, bt_ctf_stream_class_common_get_name(stream_class),
1223 bt_ctf_stream_class_common_get_id(stream_class));
1224
1225 end:
1226 if (ret) {
1227 bt_ctf_object_set_parent(&stream_class->base, NULL);
1228
1229 if (ec_validation_outputs) {
1230 for (i = 0; i < event_class_count; i++) {
1231 bt_ctf_validation_output_put_types(
1232 &ec_validation_outputs[i]);
1233 }
1234 }
1235 }
1236
1237 g_free(ec_validation_outputs);
1238 bt_ctf_validation_output_put_types(&trace_sc_validation_output);
1239 bt_ctf_object_put_ref(expected_clock_class);
1240 return ret;
1241 }
1242
1243 BT_HIDDEN
1244 bt_ctf_bool bt_ctf_trace_common_has_clock_class(struct bt_ctf_trace_common *trace,
1245 struct bt_ctf_clock_class *clock_class)
1246 {
1247 struct bt_ctf_search_query query = { .value = clock_class, .found = 0 };
1248
1249 BT_ASSERT_DBG(trace);
1250 BT_ASSERT_DBG(clock_class);
1251
1252 g_ptr_array_foreach(trace->clock_classes, value_exists, &query);
1253 return query.found;
1254 }
1255
1256 BT_HIDDEN
1257 int bt_ctf_trace_common_set_native_byte_order(struct bt_ctf_trace_common *trace,
1258 enum bt_ctf_byte_order byte_order, bool allow_unspecified)
1259 {
1260 int ret = 0;
1261
1262 if (!trace) {
1263 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1264 ret = -1;
1265 goto end;
1266 }
1267
1268 if (trace->frozen) {
1269 BT_LOGW("Invalid parameter: trace is frozen: "
1270 "addr=%p, name=\"%s\"",
1271 trace, bt_ctf_trace_common_get_name(trace));
1272 ret = -1;
1273 goto end;
1274 }
1275
1276 if (byte_order == BT_CTF_BYTE_ORDER_UNSPECIFIED && !allow_unspecified) {
1277 BT_LOGW("Invalid parameter: BT_CTF_BYTE_ORDER_UNSPECIFIED byte order is not allowed: "
1278 "addr=%p, name=\"%s\"",
1279 trace, bt_ctf_trace_common_get_name(trace));
1280 ret = -1;
1281 goto end;
1282 }
1283
1284 if (byte_order != BT_CTF_BYTE_ORDER_LITTLE_ENDIAN &&
1285 byte_order != BT_CTF_BYTE_ORDER_BIG_ENDIAN &&
1286 byte_order != BT_CTF_BYTE_ORDER_NETWORK) {
1287 BT_LOGW("Invalid parameter: invalid byte order: "
1288 "addr=%p, name=\"%s\", bo=%s",
1289 trace, bt_ctf_trace_common_get_name(trace),
1290 bt_ctf_byte_order_string(byte_order));
1291 ret = -1;
1292 goto end;
1293 }
1294
1295 trace->native_byte_order = byte_order;
1296 BT_LOGT("Set trace's native byte order: "
1297 "addr=%p, name=\"%s\", bo=%s",
1298 trace, bt_ctf_trace_common_get_name(trace),
1299 bt_ctf_byte_order_string(byte_order));
1300
1301 end:
1302 return ret;
1303 }
1304
1305 BT_HIDDEN
1306 int bt_ctf_trace_common_set_packet_header_field_type(struct bt_ctf_trace_common *trace,
1307 struct bt_ctf_field_type_common *packet_header_type)
1308 {
1309 int ret = 0;
1310
1311 if (!trace) {
1312 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1313 ret = -1;
1314 goto end;
1315 }
1316
1317 if (trace->frozen) {
1318 BT_LOGW("Invalid parameter: trace is frozen: "
1319 "addr=%p, name=\"%s\"",
1320 trace, bt_ctf_trace_common_get_name(trace));
1321 ret = -1;
1322 goto end;
1323 }
1324
1325 /* packet_header_type must be a structure. */
1326 if (packet_header_type &&
1327 packet_header_type->id != BT_CTF_FIELD_TYPE_ID_STRUCT) {
1328 BT_LOGW("Invalid parameter: packet header field type must be a structure field type if it exists: "
1329 "addr=%p, name=\"%s\", ft-addr=%p, ft-id=%s",
1330 trace, bt_ctf_trace_common_get_name(trace),
1331 packet_header_type,
1332 bt_ctf_field_type_id_string(packet_header_type->id));
1333 ret = -1;
1334 goto end;
1335 }
1336
1337 bt_ctf_object_put_ref(trace->packet_header_field_type);
1338 trace->packet_header_field_type = bt_ctf_object_get_ref(packet_header_type);
1339 BT_LOGT("Set trace's packet header field type: "
1340 "addr=%p, name=\"%s\", packet-context-ft-addr=%p",
1341 trace, bt_ctf_trace_common_get_name(trace), packet_header_type);
1342 end:
1343 return ret;
1344 }
1345
1346 static
1347 int64_t get_stream_class_count(void *element)
1348 {
1349 return bt_ctf_trace_get_stream_class_count(
1350 (struct bt_ctf_trace *) element);
1351 }
1352
1353 static
1354 void *get_stream_class(void *element, int i)
1355 {
1356 return bt_ctf_trace_get_stream_class_by_index(
1357 (struct bt_ctf_trace *) element, i);
1358 }
1359
1360 static
1361 int visit_stream_class(void *object, bt_ctf_visitor visitor,void *data)
1362 {
1363 return bt_ctf_stream_class_visit(object, visitor, data);
1364 }
1365
1366 int bt_ctf_trace_visit(struct bt_ctf_trace *trace,
1367 bt_ctf_visitor visitor, void *data)
1368 {
1369 int ret;
1370 struct bt_ctf_visitor_object obj = {
1371 .object = trace,
1372 .type = BT_CTF_VISITOR_OBJECT_TYPE_TRACE
1373 };
1374
1375 if (!trace) {
1376 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1377 ret = -1;
1378 goto end;
1379 }
1380
1381 if (!visitor) {
1382 BT_LOGW_STR("Invalid parameter: visitor is NULL.");
1383 ret = -1;
1384 goto end;
1385 }
1386
1387 BT_LOGT("Visiting trace: addr=%p, name=\"%s\"",
1388 trace, bt_ctf_trace_get_name(trace));
1389 ret = bt_ctf_visitor_helper(&obj, get_stream_class_count,
1390 get_stream_class, visit_stream_class, visitor, data);
1391 end:
1392 return ret;
1393 }
1394
1395 static
1396 void bt_ctf_trace_destroy(struct bt_ctf_object *obj)
1397 {
1398 struct bt_ctf_trace *trace = (void *) obj;
1399
1400 BT_LOGD("Destroying CTF writer trace object: addr=%p, name=\"%s\"",
1401 trace, bt_ctf_trace_get_name(trace));
1402 bt_ctf_trace_common_finalize(BT_CTF_TO_COMMON(trace));
1403 g_free(trace);
1404 }
1405
1406 BT_HIDDEN
1407 struct bt_ctf_trace *bt_ctf_trace_create(void)
1408 {
1409 struct bt_ctf_trace *trace = NULL;
1410 int ret;
1411
1412 BT_LOGD_STR("Creating CTF writer trace object.");
1413 trace = g_new0(struct bt_ctf_trace, 1);
1414 if (!trace) {
1415 BT_LOGE_STR("Failed to allocate one CTF writer trace.");
1416 goto error;
1417 }
1418
1419 ret = bt_ctf_trace_common_initialize(BT_CTF_TO_COMMON(trace),
1420 bt_ctf_trace_destroy);
1421 if (ret) {
1422 /* bt_ctf_trace_common_initialize() logs errors */
1423 goto error;
1424 }
1425
1426 BT_LOGD("Created CTF writer trace object: addr=%p", trace);
1427 return trace;
1428
1429 error:
1430 BT_CTF_OBJECT_PUT_REF_AND_RESET(trace);
1431 return trace;
1432 }
1433
1434 const uint8_t *bt_ctf_trace_get_uuid(struct bt_ctf_trace *trace)
1435 {
1436 return bt_ctf_trace_common_get_uuid(BT_CTF_TO_COMMON(trace));
1437 }
1438
1439 int bt_ctf_trace_set_uuid(struct bt_ctf_trace *trace,
1440 const uint8_t *uuid)
1441 {
1442 return bt_ctf_trace_common_set_uuid(BT_CTF_TO_COMMON(trace), uuid);
1443 }
1444
1445 int bt_ctf_trace_set_environment_field_string(struct bt_ctf_trace *trace,
1446 const char *name, const char *value)
1447 {
1448 return bt_ctf_trace_common_set_environment_field_string(BT_CTF_TO_COMMON(trace),
1449 name, value);
1450 }
1451
1452 int bt_ctf_trace_set_environment_field_integer(
1453 struct bt_ctf_trace *trace, const char *name, int64_t value)
1454 {
1455 return bt_ctf_trace_common_set_environment_field_integer(
1456 BT_CTF_TO_COMMON(trace), name, value);
1457 }
1458
1459 int64_t bt_ctf_trace_get_environment_field_count(struct bt_ctf_trace *trace)
1460 {
1461 return bt_ctf_trace_common_get_environment_field_count(BT_CTF_TO_COMMON(trace));
1462 }
1463
1464 const char *
1465 bt_ctf_trace_get_environment_field_name_by_index(struct bt_ctf_trace *trace,
1466 uint64_t index)
1467 {
1468 return bt_ctf_trace_common_get_environment_field_name_by_index(
1469 BT_CTF_TO_COMMON(trace), index);
1470 }
1471
1472 struct bt_ctf_value *bt_ctf_trace_get_environment_field_value_by_index(
1473 struct bt_ctf_trace *trace, uint64_t index)
1474 {
1475 return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_environment_field_value_by_index(
1476 BT_CTF_TO_COMMON(trace), index));
1477 }
1478
1479 struct bt_ctf_value *bt_ctf_trace_get_environment_field_value_by_name(
1480 struct bt_ctf_trace *trace, const char *name)
1481 {
1482 return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_environment_field_value_by_name(
1483 BT_CTF_TO_COMMON(trace), name));
1484 }
1485
1486 BT_HIDDEN
1487 int bt_ctf_trace_add_clock_class(struct bt_ctf_trace *trace,
1488 struct bt_ctf_clock_class *clock_class)
1489 {
1490 return bt_ctf_trace_common_add_clock_class(BT_CTF_TO_COMMON(trace),
1491 (void *) clock_class);
1492 }
1493
1494 BT_HIDDEN
1495 int64_t bt_ctf_trace_get_clock_class_count(struct bt_ctf_trace *trace)
1496 {
1497 return bt_ctf_trace_common_get_clock_class_count(BT_CTF_TO_COMMON(trace));
1498 }
1499
1500 BT_HIDDEN
1501 struct bt_ctf_clock_class *bt_ctf_trace_get_clock_class_by_index(
1502 struct bt_ctf_trace *trace, uint64_t index)
1503 {
1504 return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_clock_class_by_index(
1505 BT_CTF_TO_COMMON(trace), index));
1506 }
1507
1508 static
1509 int map_clock_classes_func(struct bt_ctf_stream_class_common *stream_class,
1510 struct bt_ctf_field_type_common *packet_context_type,
1511 struct bt_ctf_field_type_common *event_header_type)
1512 {
1513 int ret = bt_ctf_stream_class_map_clock_class(
1514 BT_CTF_FROM_COMMON(stream_class),
1515 BT_CTF_FROM_COMMON(packet_context_type),
1516 BT_CTF_FROM_COMMON(event_header_type));
1517
1518 if (ret) {
1519 BT_LOGW_STR("Cannot automatically map selected stream class's field types to stream class's clock's class.");
1520 }
1521
1522 return ret;
1523 }
1524
1525 int bt_ctf_trace_add_stream_class(struct bt_ctf_trace *trace,
1526 struct bt_ctf_stream_class *stream_class)
1527 {
1528 int ret = 0;
1529 struct bt_ctf_clock_class *expected_clock_class = NULL;
1530
1531 if (!trace) {
1532 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1533 ret = -1;
1534 goto end;
1535 }
1536
1537 if (!stream_class) {
1538 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
1539 ret = -1;
1540 goto end;
1541 }
1542
1543 if (stream_class->clock) {
1544 struct bt_ctf_clock_class *stream_clock_class =
1545 stream_class->clock->clock_class;
1546
1547 /*
1548 * Make sure this clock was also added to the
1549 * trace (potentially through its CTF writer
1550 * owner).
1551 */
1552 size_t i;
1553
1554 for (i = 0; i < trace->common.clock_classes->len; i++) {
1555 if (trace->common.clock_classes->pdata[i] ==
1556 stream_clock_class) {
1557 /* Found! */
1558 break;
1559 }
1560 }
1561
1562 if (i == trace->common.clock_classes->len) {
1563 /* Not found */
1564 BT_LOGW("Stream class's clock's class is not part of the trace: "
1565 "clock-class-addr=%p, clock-class-name=\"%s\"",
1566 stream_clock_class,
1567 bt_ctf_clock_class_get_name(stream_clock_class));
1568 ret = -1;
1569 goto end;
1570 }
1571
1572 if (stream_class->common.clock_class &&
1573 stream_class->common.clock_class !=
1574 stream_class->clock->clock_class) {
1575 /*
1576 * Stream class already has an expected clock
1577 * class, but it does not match its clock's
1578 * class.
1579 */
1580 BT_LOGW("Invalid parameter: stream class's clock's "
1581 "class does not match stream class's "
1582 "expected clock class: "
1583 "stream-class-addr=%p, "
1584 "stream-class-id=%" PRId64 ", "
1585 "stream-class-name=\"%s\", "
1586 "expected-clock-class-addr=%p, "
1587 "expected-clock-class-name=\"%s\"",
1588 stream_class,
1589 bt_ctf_stream_class_get_id(stream_class),
1590 bt_ctf_stream_class_get_name(stream_class),
1591 stream_class->common.clock_class,
1592 bt_ctf_clock_class_get_name(stream_class->common.clock_class));
1593 } else if (!stream_class->common.clock_class) {
1594 /*
1595 * Set expected clock class to stream class's
1596 * clock's class.
1597 */
1598 expected_clock_class = stream_class->clock->clock_class;
1599 }
1600 }
1601
1602
1603 ret = bt_ctf_trace_common_add_stream_class(BT_CTF_TO_COMMON(trace),
1604 BT_CTF_TO_COMMON(stream_class),
1605 (bt_ctf_validation_flag_copy_field_type_func) bt_ctf_field_type_copy,
1606 expected_clock_class, map_clock_classes_func,
1607 false);
1608
1609 end:
1610 return ret;
1611 }
1612
1613 int64_t bt_ctf_trace_get_stream_count(struct bt_ctf_trace *trace)
1614 {
1615 return bt_ctf_trace_common_get_stream_count(BT_CTF_TO_COMMON(trace));
1616 }
1617
1618 struct bt_ctf_stream *bt_ctf_trace_get_stream_by_index(
1619 struct bt_ctf_trace *trace, uint64_t index)
1620 {
1621 return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_stream_by_index(
1622 BT_CTF_TO_COMMON(trace), index));
1623 }
1624
1625 int64_t bt_ctf_trace_get_stream_class_count(struct bt_ctf_trace *trace)
1626 {
1627 return bt_ctf_trace_common_get_stream_class_count(BT_CTF_TO_COMMON(trace));
1628 }
1629
1630 struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class_by_index(
1631 struct bt_ctf_trace *trace, uint64_t index)
1632 {
1633 return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_stream_class_by_index(
1634 BT_CTF_TO_COMMON(trace), index));
1635 }
1636
1637 struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class_by_id(
1638 struct bt_ctf_trace *trace, uint64_t id)
1639 {
1640 return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_stream_class_by_id(
1641 BT_CTF_TO_COMMON(trace), id));
1642 }
1643
1644 BT_HIDDEN
1645 struct bt_ctf_clock_class *bt_ctf_trace_get_clock_class_by_name(
1646 struct bt_ctf_trace *trace, const char *name)
1647 {
1648 return bt_ctf_object_get_ref(
1649 bt_ctf_trace_common_borrow_clock_class_by_name(BT_CTF_TO_COMMON(trace),
1650 name));
1651 }
1652
1653 static
1654 int append_trace_metadata(struct bt_ctf_trace *trace,
1655 struct metadata_context *context)
1656 {
1657 uint8_t *uuid = trace->common.uuid;
1658 int ret = 0;
1659
1660 if (trace->common.native_byte_order == BT_CTF_BYTE_ORDER_NATIVE ||
1661 trace->common.native_byte_order == BT_CTF_BYTE_ORDER_UNSPECIFIED) {
1662 BT_LOGW("Invalid parameter: trace's byte order cannot be BT_CTF_BYTE_ORDER_NATIVE or BT_CTF_BYTE_ORDER_UNSPECIFIED at this point; "
1663 "set it with bt_ctf_trace_set_native_byte_order(): "
1664 "addr=%p, name=\"%s\"",
1665 trace, bt_ctf_trace_get_name(trace));
1666 ret = -1;
1667 goto end;
1668 }
1669
1670 g_string_append(context->string, "trace {\n");
1671 g_string_append(context->string, "\tmajor = 1;\n");
1672 g_string_append(context->string, "\tminor = 8;\n");
1673 BT_ASSERT_DBG(trace->common.native_byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ||
1674 trace->common.native_byte_order == BT_CTF_BYTE_ORDER_BIG_ENDIAN ||
1675 trace->common.native_byte_order == BT_CTF_BYTE_ORDER_NETWORK);
1676
1677 if (trace->common.uuid_set) {
1678 g_string_append_printf(context->string,
1679 "\tuuid = \"" BT_UUID_FMT "\";\n",
1680 BT_UUID_FMT_VALUES(uuid));
1681 }
1682
1683 g_string_append_printf(context->string, "\tbyte_order = %s;\n",
1684 bt_ctf_get_byte_order_string(trace->common.native_byte_order));
1685
1686 if (trace->common.packet_header_field_type) {
1687 g_string_append(context->string, "\tpacket.header := ");
1688 context->current_indentation_level++;
1689 g_string_assign(context->field_name, "");
1690 BT_LOGD_STR("Serializing trace's packet header field type's metadata.");
1691 ret = bt_ctf_field_type_serialize_recursive(
1692 (void *) trace->common.packet_header_field_type,
1693 context);
1694 if (ret) {
1695 goto end;
1696 }
1697 context->current_indentation_level--;
1698 }
1699
1700 g_string_append(context->string, ";\n};\n\n");
1701 end:
1702 return ret;
1703 }
1704
1705 static
1706 void append_env_metadata(struct bt_ctf_trace *trace,
1707 struct metadata_context *context)
1708 {
1709 int64_t i;
1710 int64_t env_size;
1711
1712 env_size = bt_ctf_attributes_get_count(trace->common.environment);
1713 if (env_size <= 0) {
1714 return;
1715 }
1716
1717 g_string_append(context->string, "env {\n");
1718
1719 for (i = 0; i < env_size; i++) {
1720 struct bt_ctf_private_value *env_field_value_obj = NULL;
1721 const char *entry_name;
1722
1723 entry_name = bt_ctf_attributes_get_field_name(
1724 trace->common.environment, i);
1725 env_field_value_obj = bt_ctf_attributes_borrow_field_value(
1726 trace->common.environment, i);
1727
1728 BT_ASSERT_DBG(entry_name);
1729 BT_ASSERT_DBG(env_field_value_obj);
1730
1731 switch (bt_ctf_value_get_type(
1732 bt_ctf_private_value_as_value(env_field_value_obj))) {
1733 case BT_CTF_VALUE_TYPE_INTEGER:
1734 {
1735 int64_t int_value;
1736
1737 int_value = bt_ctf_value_integer_get(
1738 bt_ctf_private_value_as_value(
1739 env_field_value_obj));
1740 g_string_append_printf(context->string,
1741 "\t%s = %" PRId64 ";\n", entry_name,
1742 int_value);
1743 break;
1744 }
1745 case BT_CTF_VALUE_TYPE_STRING:
1746 {
1747 const char *str_value;
1748 char *escaped_str = NULL;
1749
1750 str_value = bt_ctf_value_string_get(
1751 bt_ctf_private_value_as_value(
1752 env_field_value_obj));
1753 escaped_str = g_strescape(str_value, NULL);
1754 if (!escaped_str) {
1755 BT_LOGE("Cannot escape string: string=\"%s\"",
1756 str_value);
1757 continue;
1758 }
1759
1760 g_string_append_printf(context->string,
1761 "\t%s = \"%s\";\n", entry_name, escaped_str);
1762 free(escaped_str);
1763 break;
1764 }
1765 default:
1766 continue;
1767 }
1768 }
1769
1770 g_string_append(context->string, "};\n\n");
1771 }
1772
1773 char *bt_ctf_trace_get_metadata_string(struct bt_ctf_trace *trace)
1774 {
1775 char *metadata = NULL;
1776 struct metadata_context *context = NULL;
1777 int err = 0;
1778 size_t i;
1779
1780 if (!trace) {
1781 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1782 goto end;
1783 }
1784
1785 context = g_new0(struct metadata_context, 1);
1786 if (!context) {
1787 BT_LOGE_STR("Failed to allocate one metadata context.");
1788 goto end;
1789 }
1790
1791 context->field_name = g_string_sized_new(DEFAULT_IDENTIFIER_SIZE);
1792 context->string = g_string_sized_new(DEFAULT_METADATA_STRING_SIZE);
1793 g_string_append(context->string, "/* CTF 1.8 */\n\n");
1794 if (append_trace_metadata(trace, context)) {
1795 /* append_trace_metadata() logs errors */
1796 goto error;
1797 }
1798 append_env_metadata(trace, context);
1799 g_ptr_array_foreach(trace->common.clock_classes,
1800 (GFunc) bt_ctf_clock_class_serialize, context);
1801
1802 for (i = 0; i < trace->common.stream_classes->len; i++) {
1803 /* bt_ctf_stream_class_serialize() logs details */
1804 err = bt_ctf_stream_class_serialize(
1805 trace->common.stream_classes->pdata[i], context);
1806 if (err) {
1807 /* bt_ctf_stream_class_serialize() logs errors */
1808 goto error;
1809 }
1810 }
1811
1812 metadata = context->string->str;
1813
1814 error:
1815 g_string_free(context->string, err ? TRUE : FALSE);
1816 g_string_free(context->field_name, TRUE);
1817 g_free(context);
1818
1819 end:
1820 return metadata;
1821 }
1822
1823 enum bt_ctf_byte_order bt_ctf_trace_get_native_byte_order(
1824 struct bt_ctf_trace *trace)
1825 {
1826 return (int) bt_ctf_trace_common_get_native_byte_order(BT_CTF_TO_COMMON(trace));
1827 }
1828
1829 int bt_ctf_trace_set_native_byte_order(struct bt_ctf_trace *trace,
1830 enum bt_ctf_byte_order byte_order)
1831 {
1832 return bt_ctf_trace_common_set_native_byte_order(BT_CTF_TO_COMMON(trace),
1833 (int) byte_order, false);
1834 }
1835
1836 struct bt_ctf_field_type *bt_ctf_trace_get_packet_header_field_type(
1837 struct bt_ctf_trace *trace)
1838 {
1839 return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_packet_header_field_type(
1840 BT_CTF_TO_COMMON(trace)));
1841 }
1842
1843 int bt_ctf_trace_set_packet_header_field_type(struct bt_ctf_trace *trace,
1844 struct bt_ctf_field_type *packet_header_type)
1845 {
1846 return bt_ctf_trace_common_set_packet_header_field_type(BT_CTF_TO_COMMON(trace),
1847 (void *) packet_header_type);
1848 }
1849
1850 const char *bt_ctf_trace_get_name(struct bt_ctf_trace *trace)
1851 {
1852 return bt_ctf_trace_common_get_name(BT_CTF_TO_COMMON(trace));
1853 }
This page took 0.104226 seconds and 3 git commands to generate.