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