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