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