tests: LD_PRELOAD libstdc++.so in bt_run_in_py_env
[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 if (stream_class) {
1228 bt_ctf_object_set_parent(&stream_class->base, NULL);
1229 }
1230
1231 if (ec_validation_outputs) {
1232 for (i = 0; i < event_class_count; i++) {
1233 bt_ctf_validation_output_put_types(
1234 &ec_validation_outputs[i]);
1235 }
1236 }
1237 }
1238
1239 g_free(ec_validation_outputs);
1240 bt_ctf_validation_output_put_types(&trace_sc_validation_output);
1241 bt_ctf_object_put_ref(expected_clock_class);
1242 return ret;
1243 }
1244
1245 BT_HIDDEN
1246 bt_ctf_bool bt_ctf_trace_common_has_clock_class(struct bt_ctf_trace_common *trace,
1247 struct bt_ctf_clock_class *clock_class)
1248 {
1249 struct bt_ctf_search_query query = { .value = clock_class, .found = 0 };
1250
1251 BT_ASSERT_DBG(trace);
1252 BT_ASSERT_DBG(clock_class);
1253
1254 g_ptr_array_foreach(trace->clock_classes, value_exists, &query);
1255 return query.found;
1256 }
1257
1258 BT_HIDDEN
1259 int bt_ctf_trace_common_set_native_byte_order(struct bt_ctf_trace_common *trace,
1260 enum bt_ctf_byte_order byte_order, bool allow_unspecified)
1261 {
1262 int ret = 0;
1263
1264 if (!trace) {
1265 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1266 ret = -1;
1267 goto end;
1268 }
1269
1270 if (trace->frozen) {
1271 BT_LOGW("Invalid parameter: trace is frozen: "
1272 "addr=%p, name=\"%s\"",
1273 trace, bt_ctf_trace_common_get_name(trace));
1274 ret = -1;
1275 goto end;
1276 }
1277
1278 if (byte_order == BT_CTF_BYTE_ORDER_UNSPECIFIED && !allow_unspecified) {
1279 BT_LOGW("Invalid parameter: BT_CTF_BYTE_ORDER_UNSPECIFIED byte order is not allowed: "
1280 "addr=%p, name=\"%s\"",
1281 trace, bt_ctf_trace_common_get_name(trace));
1282 ret = -1;
1283 goto end;
1284 }
1285
1286 if (byte_order != BT_CTF_BYTE_ORDER_LITTLE_ENDIAN &&
1287 byte_order != BT_CTF_BYTE_ORDER_BIG_ENDIAN &&
1288 byte_order != BT_CTF_BYTE_ORDER_NETWORK) {
1289 BT_LOGW("Invalid parameter: invalid byte order: "
1290 "addr=%p, name=\"%s\", bo=%s",
1291 trace, bt_ctf_trace_common_get_name(trace),
1292 bt_ctf_byte_order_string(byte_order));
1293 ret = -1;
1294 goto end;
1295 }
1296
1297 trace->native_byte_order = byte_order;
1298 BT_LOGT("Set trace's native byte order: "
1299 "addr=%p, name=\"%s\", bo=%s",
1300 trace, bt_ctf_trace_common_get_name(trace),
1301 bt_ctf_byte_order_string(byte_order));
1302
1303 end:
1304 return ret;
1305 }
1306
1307 BT_HIDDEN
1308 int bt_ctf_trace_common_set_packet_header_field_type(struct bt_ctf_trace_common *trace,
1309 struct bt_ctf_field_type_common *packet_header_type)
1310 {
1311 int ret = 0;
1312
1313 if (!trace) {
1314 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1315 ret = -1;
1316 goto end;
1317 }
1318
1319 if (trace->frozen) {
1320 BT_LOGW("Invalid parameter: trace is frozen: "
1321 "addr=%p, name=\"%s\"",
1322 trace, bt_ctf_trace_common_get_name(trace));
1323 ret = -1;
1324 goto end;
1325 }
1326
1327 /* packet_header_type must be a structure. */
1328 if (packet_header_type &&
1329 packet_header_type->id != BT_CTF_FIELD_TYPE_ID_STRUCT) {
1330 BT_LOGW("Invalid parameter: packet header field type must be a structure field type if it exists: "
1331 "addr=%p, name=\"%s\", ft-addr=%p, ft-id=%s",
1332 trace, bt_ctf_trace_common_get_name(trace),
1333 packet_header_type,
1334 bt_ctf_field_type_id_string(packet_header_type->id));
1335 ret = -1;
1336 goto end;
1337 }
1338
1339 bt_ctf_object_put_ref(trace->packet_header_field_type);
1340 trace->packet_header_field_type = bt_ctf_object_get_ref(packet_header_type);
1341 BT_LOGT("Set trace's packet header field type: "
1342 "addr=%p, name=\"%s\", packet-context-ft-addr=%p",
1343 trace, bt_ctf_trace_common_get_name(trace), packet_header_type);
1344 end:
1345 return ret;
1346 }
1347
1348 static
1349 int64_t get_stream_class_count(void *element)
1350 {
1351 return bt_ctf_trace_get_stream_class_count(
1352 (struct bt_ctf_trace *) element);
1353 }
1354
1355 static
1356 void *get_stream_class(void *element, int i)
1357 {
1358 return bt_ctf_trace_get_stream_class_by_index(
1359 (struct bt_ctf_trace *) element, i);
1360 }
1361
1362 static
1363 int visit_stream_class(void *object, bt_ctf_visitor visitor,void *data)
1364 {
1365 return bt_ctf_stream_class_visit(object, visitor, data);
1366 }
1367
1368 int bt_ctf_trace_visit(struct bt_ctf_trace *trace,
1369 bt_ctf_visitor visitor, void *data)
1370 {
1371 int ret;
1372 struct bt_ctf_visitor_object obj = {
1373 .object = trace,
1374 .type = BT_CTF_VISITOR_OBJECT_TYPE_TRACE
1375 };
1376
1377 if (!trace) {
1378 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1379 ret = -1;
1380 goto end;
1381 }
1382
1383 if (!visitor) {
1384 BT_LOGW_STR("Invalid parameter: visitor is NULL.");
1385 ret = -1;
1386 goto end;
1387 }
1388
1389 BT_LOGT("Visiting trace: addr=%p, name=\"%s\"",
1390 trace, bt_ctf_trace_get_name(trace));
1391 ret = bt_ctf_visitor_helper(&obj, get_stream_class_count,
1392 get_stream_class, visit_stream_class, visitor, data);
1393 end:
1394 return ret;
1395 }
1396
1397 static
1398 void bt_ctf_trace_destroy(struct bt_ctf_object *obj)
1399 {
1400 struct bt_ctf_trace *trace = (void *) obj;
1401
1402 BT_LOGD("Destroying CTF writer trace object: addr=%p, name=\"%s\"",
1403 trace, bt_ctf_trace_get_name(trace));
1404 bt_ctf_trace_common_finalize(BT_CTF_TO_COMMON(trace));
1405 g_free(trace);
1406 }
1407
1408 BT_HIDDEN
1409 struct bt_ctf_trace *bt_ctf_trace_create(void)
1410 {
1411 struct bt_ctf_trace *trace = NULL;
1412 int ret;
1413
1414 BT_LOGD_STR("Creating CTF writer trace object.");
1415 trace = g_new0(struct bt_ctf_trace, 1);
1416 if (!trace) {
1417 BT_LOGE_STR("Failed to allocate one CTF writer trace.");
1418 goto error;
1419 }
1420
1421 ret = bt_ctf_trace_common_initialize(BT_CTF_TO_COMMON(trace),
1422 bt_ctf_trace_destroy);
1423 if (ret) {
1424 /* bt_ctf_trace_common_initialize() logs errors */
1425 goto error;
1426 }
1427
1428 BT_LOGD("Created CTF writer trace object: addr=%p", trace);
1429 return trace;
1430
1431 error:
1432 BT_CTF_OBJECT_PUT_REF_AND_RESET(trace);
1433 return trace;
1434 }
1435
1436 const uint8_t *bt_ctf_trace_get_uuid(struct bt_ctf_trace *trace)
1437 {
1438 return bt_ctf_trace_common_get_uuid(BT_CTF_TO_COMMON(trace));
1439 }
1440
1441 int bt_ctf_trace_set_uuid(struct bt_ctf_trace *trace,
1442 const uint8_t *uuid)
1443 {
1444 return bt_ctf_trace_common_set_uuid(BT_CTF_TO_COMMON(trace), uuid);
1445 }
1446
1447 int bt_ctf_trace_set_environment_field_string(struct bt_ctf_trace *trace,
1448 const char *name, const char *value)
1449 {
1450 return bt_ctf_trace_common_set_environment_field_string(BT_CTF_TO_COMMON(trace),
1451 name, value);
1452 }
1453
1454 int bt_ctf_trace_set_environment_field_integer(
1455 struct bt_ctf_trace *trace, const char *name, int64_t value)
1456 {
1457 return bt_ctf_trace_common_set_environment_field_integer(
1458 BT_CTF_TO_COMMON(trace), name, value);
1459 }
1460
1461 int64_t bt_ctf_trace_get_environment_field_count(struct bt_ctf_trace *trace)
1462 {
1463 return bt_ctf_trace_common_get_environment_field_count(BT_CTF_TO_COMMON(trace));
1464 }
1465
1466 const char *
1467 bt_ctf_trace_get_environment_field_name_by_index(struct bt_ctf_trace *trace,
1468 uint64_t index)
1469 {
1470 return bt_ctf_trace_common_get_environment_field_name_by_index(
1471 BT_CTF_TO_COMMON(trace), index);
1472 }
1473
1474 struct bt_ctf_value *bt_ctf_trace_get_environment_field_value_by_index(
1475 struct bt_ctf_trace *trace, uint64_t index)
1476 {
1477 return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_environment_field_value_by_index(
1478 BT_CTF_TO_COMMON(trace), index));
1479 }
1480
1481 struct bt_ctf_value *bt_ctf_trace_get_environment_field_value_by_name(
1482 struct bt_ctf_trace *trace, const char *name)
1483 {
1484 return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_environment_field_value_by_name(
1485 BT_CTF_TO_COMMON(trace), name));
1486 }
1487
1488 BT_HIDDEN
1489 int bt_ctf_trace_add_clock_class(struct bt_ctf_trace *trace,
1490 struct bt_ctf_clock_class *clock_class)
1491 {
1492 return bt_ctf_trace_common_add_clock_class(BT_CTF_TO_COMMON(trace),
1493 (void *) clock_class);
1494 }
1495
1496 BT_HIDDEN
1497 int64_t bt_ctf_trace_get_clock_class_count(struct bt_ctf_trace *trace)
1498 {
1499 return bt_ctf_trace_common_get_clock_class_count(BT_CTF_TO_COMMON(trace));
1500 }
1501
1502 BT_HIDDEN
1503 struct bt_ctf_clock_class *bt_ctf_trace_get_clock_class_by_index(
1504 struct bt_ctf_trace *trace, uint64_t index)
1505 {
1506 return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_clock_class_by_index(
1507 BT_CTF_TO_COMMON(trace), index));
1508 }
1509
1510 static
1511 int map_clock_classes_func(struct bt_ctf_stream_class_common *stream_class,
1512 struct bt_ctf_field_type_common *packet_context_type,
1513 struct bt_ctf_field_type_common *event_header_type)
1514 {
1515 int ret = bt_ctf_stream_class_map_clock_class(
1516 BT_CTF_FROM_COMMON(stream_class),
1517 BT_CTF_FROM_COMMON(packet_context_type),
1518 BT_CTF_FROM_COMMON(event_header_type));
1519
1520 if (ret) {
1521 BT_LOGW_STR("Cannot automatically map selected stream class's field types to stream class's clock's class.");
1522 }
1523
1524 return ret;
1525 }
1526
1527 int bt_ctf_trace_add_stream_class(struct bt_ctf_trace *trace,
1528 struct bt_ctf_stream_class *stream_class)
1529 {
1530 int ret = 0;
1531 struct bt_ctf_clock_class *expected_clock_class = NULL;
1532
1533 if (!trace) {
1534 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1535 ret = -1;
1536 goto end;
1537 }
1538
1539 if (!stream_class) {
1540 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
1541 ret = -1;
1542 goto end;
1543 }
1544
1545 if (stream_class->clock) {
1546 struct bt_ctf_clock_class *stream_clock_class =
1547 stream_class->clock->clock_class;
1548
1549 /*
1550 * Make sure this clock was also added to the
1551 * trace (potentially through its CTF writer
1552 * owner).
1553 */
1554 size_t i;
1555
1556 for (i = 0; i < trace->common.clock_classes->len; i++) {
1557 if (trace->common.clock_classes->pdata[i] ==
1558 stream_clock_class) {
1559 /* Found! */
1560 break;
1561 }
1562 }
1563
1564 if (i == trace->common.clock_classes->len) {
1565 /* Not found */
1566 BT_LOGW("Stream class's clock's class is not part of the trace: "
1567 "clock-class-addr=%p, clock-class-name=\"%s\"",
1568 stream_clock_class,
1569 bt_ctf_clock_class_get_name(stream_clock_class));
1570 ret = -1;
1571 goto end;
1572 }
1573
1574 if (stream_class->common.clock_class &&
1575 stream_class->common.clock_class !=
1576 stream_class->clock->clock_class) {
1577 /*
1578 * Stream class already has an expected clock
1579 * class, but it does not match its clock's
1580 * class.
1581 */
1582 BT_LOGW("Invalid parameter: stream class's clock's "
1583 "class does not match stream class's "
1584 "expected clock class: "
1585 "stream-class-addr=%p, "
1586 "stream-class-id=%" PRId64 ", "
1587 "stream-class-name=\"%s\", "
1588 "expected-clock-class-addr=%p, "
1589 "expected-clock-class-name=\"%s\"",
1590 stream_class,
1591 bt_ctf_stream_class_get_id(stream_class),
1592 bt_ctf_stream_class_get_name(stream_class),
1593 stream_class->common.clock_class,
1594 bt_ctf_clock_class_get_name(stream_class->common.clock_class));
1595 } else if (!stream_class->common.clock_class) {
1596 /*
1597 * Set expected clock class to stream class's
1598 * clock's class.
1599 */
1600 expected_clock_class = stream_class->clock->clock_class;
1601 }
1602 }
1603
1604
1605 ret = bt_ctf_trace_common_add_stream_class(BT_CTF_TO_COMMON(trace),
1606 BT_CTF_TO_COMMON(stream_class),
1607 (bt_ctf_validation_flag_copy_field_type_func) bt_ctf_field_type_copy,
1608 expected_clock_class, map_clock_classes_func,
1609 false);
1610
1611 end:
1612 return ret;
1613 }
1614
1615 int64_t bt_ctf_trace_get_stream_count(struct bt_ctf_trace *trace)
1616 {
1617 return bt_ctf_trace_common_get_stream_count(BT_CTF_TO_COMMON(trace));
1618 }
1619
1620 struct bt_ctf_stream *bt_ctf_trace_get_stream_by_index(
1621 struct bt_ctf_trace *trace, uint64_t index)
1622 {
1623 return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_stream_by_index(
1624 BT_CTF_TO_COMMON(trace), index));
1625 }
1626
1627 int64_t bt_ctf_trace_get_stream_class_count(struct bt_ctf_trace *trace)
1628 {
1629 return bt_ctf_trace_common_get_stream_class_count(BT_CTF_TO_COMMON(trace));
1630 }
1631
1632 struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class_by_index(
1633 struct bt_ctf_trace *trace, uint64_t index)
1634 {
1635 return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_stream_class_by_index(
1636 BT_CTF_TO_COMMON(trace), index));
1637 }
1638
1639 struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class_by_id(
1640 struct bt_ctf_trace *trace, uint64_t id)
1641 {
1642 return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_stream_class_by_id(
1643 BT_CTF_TO_COMMON(trace), id));
1644 }
1645
1646 BT_HIDDEN
1647 struct bt_ctf_clock_class *bt_ctf_trace_get_clock_class_by_name(
1648 struct bt_ctf_trace *trace, const char *name)
1649 {
1650 return bt_ctf_object_get_ref(
1651 bt_ctf_trace_common_borrow_clock_class_by_name(BT_CTF_TO_COMMON(trace),
1652 name));
1653 }
1654
1655 static
1656 int append_trace_metadata(struct bt_ctf_trace *trace,
1657 struct metadata_context *context)
1658 {
1659 uint8_t *uuid = trace->common.uuid;
1660 int ret = 0;
1661
1662 if (trace->common.native_byte_order == BT_CTF_BYTE_ORDER_NATIVE ||
1663 trace->common.native_byte_order == BT_CTF_BYTE_ORDER_UNSPECIFIED) {
1664 BT_LOGW("Invalid parameter: trace's byte order cannot be BT_CTF_BYTE_ORDER_NATIVE or BT_CTF_BYTE_ORDER_UNSPECIFIED at this point; "
1665 "set it with bt_ctf_trace_set_native_byte_order(): "
1666 "addr=%p, name=\"%s\"",
1667 trace, bt_ctf_trace_get_name(trace));
1668 ret = -1;
1669 goto end;
1670 }
1671
1672 g_string_append(context->string, "trace {\n");
1673 g_string_append(context->string, "\tmajor = 1;\n");
1674 g_string_append(context->string, "\tminor = 8;\n");
1675 BT_ASSERT_DBG(trace->common.native_byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ||
1676 trace->common.native_byte_order == BT_CTF_BYTE_ORDER_BIG_ENDIAN ||
1677 trace->common.native_byte_order == BT_CTF_BYTE_ORDER_NETWORK);
1678
1679 if (trace->common.uuid_set) {
1680 g_string_append_printf(context->string,
1681 "\tuuid = \"" BT_UUID_FMT "\";\n",
1682 BT_UUID_FMT_VALUES(uuid));
1683 }
1684
1685 g_string_append_printf(context->string, "\tbyte_order = %s;\n",
1686 bt_ctf_get_byte_order_string(trace->common.native_byte_order));
1687
1688 if (trace->common.packet_header_field_type) {
1689 g_string_append(context->string, "\tpacket.header := ");
1690 context->current_indentation_level++;
1691 g_string_assign(context->field_name, "");
1692 BT_LOGD_STR("Serializing trace's packet header field type's metadata.");
1693 ret = bt_ctf_field_type_serialize_recursive(
1694 (void *) trace->common.packet_header_field_type,
1695 context);
1696 if (ret) {
1697 goto end;
1698 }
1699 context->current_indentation_level--;
1700 }
1701
1702 g_string_append(context->string, ";\n};\n\n");
1703 end:
1704 return ret;
1705 }
1706
1707 static
1708 void append_env_metadata(struct bt_ctf_trace *trace,
1709 struct metadata_context *context)
1710 {
1711 int64_t i;
1712 int64_t env_size;
1713
1714 env_size = bt_ctf_attributes_get_count(trace->common.environment);
1715 if (env_size <= 0) {
1716 return;
1717 }
1718
1719 g_string_append(context->string, "env {\n");
1720
1721 for (i = 0; i < env_size; i++) {
1722 struct bt_ctf_private_value *env_field_value_obj = NULL;
1723 const char *entry_name;
1724
1725 entry_name = bt_ctf_attributes_get_field_name(
1726 trace->common.environment, i);
1727 env_field_value_obj = bt_ctf_attributes_borrow_field_value(
1728 trace->common.environment, i);
1729
1730 BT_ASSERT_DBG(entry_name);
1731 BT_ASSERT_DBG(env_field_value_obj);
1732
1733 switch (bt_ctf_value_get_type(
1734 bt_ctf_private_value_as_value(env_field_value_obj))) {
1735 case BT_CTF_VALUE_TYPE_INTEGER:
1736 {
1737 int64_t int_value;
1738
1739 int_value = bt_ctf_value_integer_get(
1740 bt_ctf_private_value_as_value(
1741 env_field_value_obj));
1742 g_string_append_printf(context->string,
1743 "\t%s = %" PRId64 ";\n", entry_name,
1744 int_value);
1745 break;
1746 }
1747 case BT_CTF_VALUE_TYPE_STRING:
1748 {
1749 const char *str_value;
1750 char *escaped_str = NULL;
1751
1752 str_value = bt_ctf_value_string_get(
1753 bt_ctf_private_value_as_value(
1754 env_field_value_obj));
1755 escaped_str = g_strescape(str_value, NULL);
1756 if (!escaped_str) {
1757 BT_LOGE("Cannot escape string: string=\"%s\"",
1758 str_value);
1759 continue;
1760 }
1761
1762 g_string_append_printf(context->string,
1763 "\t%s = \"%s\";\n", entry_name, escaped_str);
1764 free(escaped_str);
1765 break;
1766 }
1767 default:
1768 continue;
1769 }
1770 }
1771
1772 g_string_append(context->string, "};\n\n");
1773 }
1774
1775 char *bt_ctf_trace_get_metadata_string(struct bt_ctf_trace *trace)
1776 {
1777 char *metadata = NULL;
1778 struct metadata_context *context = NULL;
1779 int err = 0;
1780 size_t i;
1781
1782 if (!trace) {
1783 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1784 goto end;
1785 }
1786
1787 context = g_new0(struct metadata_context, 1);
1788 if (!context) {
1789 BT_LOGE_STR("Failed to allocate one metadata context.");
1790 goto end;
1791 }
1792
1793 context->field_name = g_string_sized_new(DEFAULT_IDENTIFIER_SIZE);
1794 context->string = g_string_sized_new(DEFAULT_METADATA_STRING_SIZE);
1795 g_string_append(context->string, "/* CTF 1.8 */\n\n");
1796 if (append_trace_metadata(trace, context)) {
1797 /* append_trace_metadata() logs errors */
1798 goto error;
1799 }
1800 append_env_metadata(trace, context);
1801 g_ptr_array_foreach(trace->common.clock_classes,
1802 (GFunc) bt_ctf_clock_class_serialize, context);
1803
1804 for (i = 0; i < trace->common.stream_classes->len; i++) {
1805 /* bt_ctf_stream_class_serialize() logs details */
1806 err = bt_ctf_stream_class_serialize(
1807 trace->common.stream_classes->pdata[i], context);
1808 if (err) {
1809 /* bt_ctf_stream_class_serialize() logs errors */
1810 goto error;
1811 }
1812 }
1813
1814 metadata = context->string->str;
1815
1816 error:
1817 g_string_free(context->string, err ? TRUE : FALSE);
1818 g_string_free(context->field_name, TRUE);
1819 g_free(context);
1820
1821 end:
1822 return metadata;
1823 }
1824
1825 enum bt_ctf_byte_order bt_ctf_trace_get_native_byte_order(
1826 struct bt_ctf_trace *trace)
1827 {
1828 return (int) bt_ctf_trace_common_get_native_byte_order(BT_CTF_TO_COMMON(trace));
1829 }
1830
1831 int bt_ctf_trace_set_native_byte_order(struct bt_ctf_trace *trace,
1832 enum bt_ctf_byte_order byte_order)
1833 {
1834 return bt_ctf_trace_common_set_native_byte_order(BT_CTF_TO_COMMON(trace),
1835 (int) byte_order, false);
1836 }
1837
1838 struct bt_ctf_field_type *bt_ctf_trace_get_packet_header_field_type(
1839 struct bt_ctf_trace *trace)
1840 {
1841 return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_packet_header_field_type(
1842 BT_CTF_TO_COMMON(trace)));
1843 }
1844
1845 int bt_ctf_trace_set_packet_header_field_type(struct bt_ctf_trace *trace,
1846 struct bt_ctf_field_type *packet_header_type)
1847 {
1848 return bt_ctf_trace_common_set_packet_header_field_type(BT_CTF_TO_COMMON(trace),
1849 (void *) packet_header_type);
1850 }
1851
1852 const char *bt_ctf_trace_get_name(struct bt_ctf_trace *trace)
1853 {
1854 return bt_ctf_trace_common_get_name(BT_CTF_TO_COMMON(trace));
1855 }
This page took 0.084716 seconds and 4 git commands to generate.