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