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