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