ctf plugins: prepend trace's hostname, if exists, to trace name
[babeltrace.git] / lib / ctf-ir / trace.c
CommitLineData
bc37ae52
JG
1/*
2 * trace.c
3 *
4 * Babeltrace CTF IR - Trace
5 *
6 * Copyright 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
7 *
8 * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 */
28
e011d2c1
PP
29#define BT_LOG_TAG "TRACE"
30#include <babeltrace/lib-logging-internal.h>
31
bc37ae52 32#include <babeltrace/ctf-ir/trace-internal.h>
ac0c6bdd 33#include <babeltrace/ctf-ir/clock-class-internal.h>
bc37ae52
JG
34#include <babeltrace/ctf-ir/stream-internal.h>
35#include <babeltrace/ctf-ir/stream-class-internal.h>
09840de5 36#include <babeltrace/ctf-ir/event-internal.h>
272df73e
PP
37#include <babeltrace/ctf-ir/event-class.h>
38#include <babeltrace/ctf-ir/event-class-internal.h>
bc37ae52 39#include <babeltrace/ctf-writer/functor-internal.h>
ac0c6bdd 40#include <babeltrace/ctf-writer/clock-internal.h>
2e33ac5a 41#include <babeltrace/ctf-ir/field-types-internal.h>
44e0a4f5 42#include <babeltrace/ctf-ir/attributes-internal.h>
09840de5 43#include <babeltrace/ctf-ir/validation-internal.h>
8bf65fbd 44#include <babeltrace/ctf-ir/visitor-internal.h>
654c1444 45#include <babeltrace/ctf-ir/utils.h>
3d9990ac 46#include <babeltrace/compiler-internal.h>
dac5c838 47#include <babeltrace/values.h>
95c09b3a 48#include <babeltrace/values-internal.h>
83509119 49#include <babeltrace/ref.h>
c55a9f58 50#include <babeltrace/types.h>
3d9990ac 51#include <babeltrace/endian-internal.h>
dc3fffef 52#include <inttypes.h>
544d0515 53#include <stdint.h>
4a32fda0 54#include <string.h>
0fbb9a9f 55#include <stdlib.h>
bc37ae52
JG
56
57#define DEFAULT_IDENTIFIER_SIZE 128
58#define DEFAULT_METADATA_STRING_SIZE 4096
59
50ad4244
JG
60struct listener_wrapper {
61 bt_ctf_listener_cb listener;
2204c381
JG
62 void *data;
63};
64
3602afb0
PP
65struct bt_ctf_trace_is_static_listener_elem {
66 bt_ctf_trace_is_static_listener func;
67 void *data;
68};
69
bc37ae52 70static
83509119 71void bt_ctf_trace_destroy(struct bt_object *obj);
bc37ae52 72static
09840de5 73void bt_ctf_trace_freeze(struct bt_ctf_trace *trace);
bc37ae52 74
bc37ae52
JG
75static
76const unsigned int field_type_aliases_alignments[] = {
77 [FIELD_TYPE_ALIAS_UINT5_T] = 1,
78 [FIELD_TYPE_ALIAS_UINT8_T ... FIELD_TYPE_ALIAS_UINT16_T] = 8,
79 [FIELD_TYPE_ALIAS_UINT27_T] = 1,
80 [FIELD_TYPE_ALIAS_UINT32_T ... FIELD_TYPE_ALIAS_UINT64_T] = 8,
81};
82
83static
84const unsigned int field_type_aliases_sizes[] = {
85 [FIELD_TYPE_ALIAS_UINT5_T] = 5,
86 [FIELD_TYPE_ALIAS_UINT8_T] = 8,
87 [FIELD_TYPE_ALIAS_UINT16_T] = 16,
88 [FIELD_TYPE_ALIAS_UINT27_T] = 27,
89 [FIELD_TYPE_ALIAS_UINT32_T] = 32,
90 [FIELD_TYPE_ALIAS_UINT64_T] = 64,
91};
92
bc37ae52
JG
93struct bt_ctf_trace *bt_ctf_trace_create(void)
94{
95 struct bt_ctf_trace *trace = NULL;
488e09a7 96 struct bt_ctf_field_type *packet_header_type = NULL;
bc37ae52
JG
97
98 trace = g_new0(struct bt_ctf_trace, 1);
99 if (!trace) {
95c09b3a 100 BT_LOGE_STR("Failed to allocate one trace.");
bc37ae52
JG
101 goto error;
102 }
103
95c09b3a 104 BT_LOGD_STR("Creating trace object.");
391c8f0d 105 trace->native_byte_order = BT_CTF_BYTE_ORDER_NATIVE;
83509119 106 bt_object_init(trace, bt_ctf_trace_destroy);
bc37ae52 107 trace->clocks = g_ptr_array_new_with_free_func(
83509119 108 (GDestroyNotify) bt_put);
95c09b3a
PP
109 if (!trace->clocks) {
110 BT_LOGE_STR("Failed to allocate one GPtrArray.");
111 goto error;
112 }
113
bc37ae52 114 trace->streams = g_ptr_array_new_with_free_func(
e6a8e8e4 115 (GDestroyNotify) bt_object_release);
95c09b3a
PP
116 if (!trace->streams) {
117 BT_LOGE_STR("Failed to allocate one GPtrArray.");
118 goto error;
119 }
120
bc37ae52 121 trace->stream_classes = g_ptr_array_new_with_free_func(
e6a8e8e4 122 (GDestroyNotify) bt_object_release);
95c09b3a
PP
123 if (!trace->stream_classes) {
124 BT_LOGE_STR("Failed to allocate one GPtrArray.");
83509119 125 goto error;
bc37ae52
JG
126 }
127
488e09a7
PP
128 packet_header_type = bt_ctf_field_type_structure_create();
129 if (!packet_header_type) {
83509119 130 goto error;
bc37ae52
JG
131 }
132
488e09a7
PP
133 BT_MOVE(trace->packet_header_type, packet_header_type);
134
7f800dc7
PP
135 /* Create the environment array object */
136 trace->environment = bt_ctf_attributes_create();
137 if (!trace->environment) {
95c09b3a 138 BT_LOGE_STR("Cannot create empty attributes object.");
83509119 139 goto error;
7f800dc7
PP
140 }
141
9b888ff3
JG
142 trace->listeners = g_ptr_array_new_with_free_func(
143 (GDestroyNotify) g_free);
144 if (!trace->listeners) {
95c09b3a 145 BT_LOGE_STR("Failed to allocate one GPtrArray.");
9b888ff3
JG
146 goto error;
147 }
148
3602afb0
PP
149 trace->is_static_listeners = g_array_new(FALSE, TRUE,
150 sizeof(struct bt_ctf_trace_is_static_listener_elem));
151 if (!trace->is_static_listeners) {
152 BT_LOGE_STR("Failed to allocate one GArray.");
153 goto error;
154 }
155
95c09b3a 156 BT_LOGD("Created trace object: addr=%p", trace);
bc37ae52
JG
157 return trace;
158
bc37ae52 159error:
83509119 160 BT_PUT(trace);
488e09a7 161 bt_put(packet_header_type);
bc37ae52
JG
162 return trace;
163}
164
e96045d4
JG
165const char *bt_ctf_trace_get_name(struct bt_ctf_trace *trace)
166{
167 const char *name = NULL;
168
95c09b3a
PP
169 if (!trace) {
170 BT_LOGW_STR("Invalid parameter: trace is NULL.");
171 goto end;
172 }
173
174 if (!trace->name) {
e96045d4
JG
175 goto end;
176 }
177
178 name = trace->name->str;
179end:
180 return name;
181}
182
183int bt_ctf_trace_set_name(struct bt_ctf_trace *trace, const char *name)
184{
185 int ret = 0;
186
95c09b3a
PP
187 if (!trace) {
188 BT_LOGW_STR("Invalid parameter: trace is NULL.");
189 ret = -1;
190 goto end;
191 }
192
193 if (!name) {
194 BT_LOGW_STR("Invalid parameter: name is NULL.");
195 ret = -1;
196 goto end;
197 }
198
199 if (trace->frozen) {
200 BT_LOGW("Invalid parameter: trace is frozen: "
201 "addr=%p, name=\"%s\"",
202 trace, bt_ctf_trace_get_name(trace));
e96045d4
JG
203 ret = -1;
204 goto end;
205 }
206
207 trace->name = trace->name ? g_string_assign(trace->name, name) :
208 g_string_new(name);
209 if (!trace->name) {
95c09b3a 210 BT_LOGE_STR("Failed to allocate one GString.");
e96045d4
JG
211 ret = -1;
212 goto end;
213 }
95c09b3a
PP
214
215 BT_LOGV("Set trace's name: addr=%p, name=\"%s\"", trace, name);
216
e96045d4
JG
217end:
218 return ret;
219}
220
4a32fda0
PP
221const unsigned char *bt_ctf_trace_get_uuid(struct bt_ctf_trace *trace)
222{
223 return trace && trace->uuid_set ? trace->uuid : NULL;
224}
225
226int bt_ctf_trace_set_uuid(struct bt_ctf_trace *trace, const unsigned char *uuid)
227{
228 int ret = 0;
229
95c09b3a
PP
230 if (!trace) {
231 BT_LOGW_STR("Invalid parameter: trace is NULL.");
232 ret = -1;
233 goto end;
234 }
235
236 if (!uuid) {
237 BT_LOGW_STR("Invalid parameter: UUID is NULL.");
238 ret = -1;
239 goto end;
240 }
241
242 if (trace->frozen) {
243 BT_LOGW("Invalid parameter: trace is frozen: "
244 "addr=%p, name=\"%s\"",
245 trace, bt_ctf_trace_get_name(trace));
4a32fda0
PP
246 ret = -1;
247 goto end;
248 }
249
250 memcpy(trace->uuid, uuid, sizeof(uuid_t));
c55a9f58 251 trace->uuid_set = BT_TRUE;
95c09b3a
PP
252 BT_LOGV("Set trace's UUID: addr=%p, name=\"%s\", "
253 "uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"",
254 trace, bt_ctf_trace_get_name(trace),
255 (unsigned int) uuid[0],
256 (unsigned int) uuid[1],
257 (unsigned int) uuid[2],
258 (unsigned int) uuid[3],
259 (unsigned int) uuid[4],
260 (unsigned int) uuid[5],
261 (unsigned int) uuid[6],
262 (unsigned int) uuid[7],
263 (unsigned int) uuid[8],
264 (unsigned int) uuid[9],
265 (unsigned int) uuid[10],
266 (unsigned int) uuid[11],
267 (unsigned int) uuid[12],
268 (unsigned int) uuid[13],
269 (unsigned int) uuid[14],
270 (unsigned int) uuid[15]);
4a32fda0
PP
271
272end:
273 return ret;
274}
275
83509119 276void bt_ctf_trace_destroy(struct bt_object *obj)
bc37ae52
JG
277{
278 struct bt_ctf_trace *trace;
bc37ae52 279
83509119 280 trace = container_of(obj, struct bt_ctf_trace, base);
95c09b3a
PP
281
282 BT_LOGD("Destroying trace object: addr=%p, name=\"%s\"",
283 trace, bt_ctf_trace_get_name(trace));
284
bc37ae52 285 if (trace->environment) {
95c09b3a 286 BT_LOGD_STR("Destroying environment attributes.");
7f800dc7 287 bt_ctf_attributes_destroy(trace->environment);
bc37ae52
JG
288 }
289
e96045d4
JG
290 if (trace->name) {
291 g_string_free(trace->name, TRUE);
292 }
293
bc37ae52 294 if (trace->clocks) {
95c09b3a 295 BT_LOGD_STR("Putting clock classes.");
bc37ae52
JG
296 g_ptr_array_free(trace->clocks, TRUE);
297 }
298
299 if (trace->streams) {
607ff9b8 300 BT_LOGD_STR("Destroying streams.");
bc37ae52
JG
301 g_ptr_array_free(trace->streams, TRUE);
302 }
303
304 if (trace->stream_classes) {
607ff9b8 305 BT_LOGD_STR("Destroying stream classes.");
bc37ae52
JG
306 g_ptr_array_free(trace->stream_classes, TRUE);
307 }
308
9b888ff3
JG
309 if (trace->listeners) {
310 g_ptr_array_free(trace->listeners, TRUE);
311 }
312
3602afb0
PP
313 if (trace->is_static_listeners) {
314 g_array_free(trace->is_static_listeners, TRUE);
315 }
316
95c09b3a 317 BT_LOGD_STR("Putting packet header field type.");
83509119 318 bt_put(trace->packet_header_type);
bc37ae52
JG
319 g_free(trace);
320}
321
7f800dc7 322int bt_ctf_trace_set_environment_field(struct bt_ctf_trace *trace,
dac5c838 323 const char *name, struct bt_value *value)
bc37ae52 324{
bc37ae52
JG
325 int ret = 0;
326
95c09b3a
PP
327 if (!trace) {
328 BT_LOGW_STR("Invalid parameter: trace is NULL.");
329 ret = -1;
330 goto end;
331 }
332
333 if (!name) {
334 BT_LOGW_STR("Invalid parameter: name is NULL.");
335 ret = -1;
336 goto end;
337 }
338
339 if (!value) {
340 BT_LOGW_STR("Invalid parameter: value is NULL.");
341 ret = -1;
342 goto end;
343 }
344
345 if (bt_ctf_validate_identifier(name)) {
346 BT_LOGW("Invalid parameter: environment field's name is not a valid CTF identifier: "
347 "trace-addr=%p, trace-name=\"%s\", "
348 "env-name=\"%s\"",
349 trace, bt_ctf_trace_get_name(trace), name);
bc37ae52 350 ret = -1;
7f800dc7 351 goto end;
bc37ae52
JG
352 }
353
95c09b3a
PP
354 if (!bt_value_is_integer(value) && !bt_value_is_string(value)) {
355 BT_LOGW("Invalid parameter: environment field's value is not an integer or string value: "
356 "trace-addr=%p, trace-name=\"%s\", "
357 "env-name=\"%s\", env-value-type=%s",
358 trace, bt_ctf_trace_get_name(trace), name,
359 bt_value_type_string(bt_value_get_type(value)));
360 ret = -1;
361 goto end;
362 }
363
364 if (trace->is_static) {
365 BT_LOGW("Invalid parameter: trace is static: "
366 "addr=%p, name=\"%s\"",
367 trace, bt_ctf_trace_get_name(trace));
bc37ae52 368 ret = -1;
7f800dc7 369 goto end;
bc37ae52
JG
370 }
371
a0d12916
JG
372 if (trace->frozen) {
373 /*
374 * New environment fields may be added to a frozen trace,
375 * but existing fields may not be changed.
376 *
377 * The object passed is frozen like all other attributes.
378 */
dac5c838 379 struct bt_value *attribute =
a0d12916
JG
380 bt_ctf_attributes_get_field_value_by_name(
381 trace->environment, name);
382
383 if (attribute) {
95c09b3a
PP
384 BT_LOGW("Invalid parameter: trace is frozen and environment field already exists with this name: "
385 "trace-addr=%p, trace-name=\"%s\", "
386 "env-name=\"%s\"",
387 trace, bt_ctf_trace_get_name(trace), name);
83509119 388 BT_PUT(attribute);
a0d12916
JG
389 ret = -1;
390 goto end;
391 }
392
dac5c838 393 bt_value_freeze(value);
a0d12916
JG
394 }
395
7f800dc7
PP
396 ret = bt_ctf_attributes_set_field_value(trace->environment, name,
397 value);
95c09b3a
PP
398 if (ret) {
399 BT_LOGE("Cannot set environment field's value: "
400 "trace-addr=%p, trace-name=\"%s\", "
401 "env-name=\"%s\"",
402 trace, bt_ctf_trace_get_name(trace), name);
403 } else {
404 BT_LOGV("Set environment field's value: "
405 "trace-addr=%p, trace-name=\"%s\", "
406 "env-name=\"%s\", value-addr=%p",
407 trace, bt_ctf_trace_get_name(trace), name, value);
408 }
bc37ae52 409
7f800dc7
PP
410end:
411 return ret;
412}
bc37ae52 413
7f800dc7
PP
414int bt_ctf_trace_set_environment_field_string(struct bt_ctf_trace *trace,
415 const char *name, const char *value)
416{
417 int ret = 0;
dac5c838 418 struct bt_value *env_value_string_obj = NULL;
7f800dc7 419
95c09b3a
PP
420 if (!value) {
421 BT_LOGW_STR("Invalid parameter: value is NULL.");
bc37ae52 422 ret = -1;
7f800dc7 423 goto end;
bc37ae52
JG
424 }
425
dac5c838 426 env_value_string_obj = bt_value_string_create_init(value);
7f800dc7 427 if (!env_value_string_obj) {
95c09b3a 428 BT_LOGE_STR("Cannot create string value object.");
7f800dc7
PP
429 ret = -1;
430 goto end;
bc37ae52
JG
431 }
432
95c09b3a 433 /* bt_ctf_trace_set_environment_field() logs errors */
7f800dc7
PP
434 ret = bt_ctf_trace_set_environment_field(trace, name,
435 env_value_string_obj);
436
437end:
95c09b3a 438 bt_put(env_value_string_obj);
3487c9f3
JG
439 return ret;
440}
441
7f800dc7
PP
442int bt_ctf_trace_set_environment_field_integer(struct bt_ctf_trace *trace,
443 const char *name, int64_t value)
3487c9f3 444{
3487c9f3 445 int ret = 0;
dac5c838 446 struct bt_value *env_value_integer_obj = NULL;
3487c9f3 447
dac5c838 448 env_value_integer_obj = bt_value_integer_create_init(value);
7f800dc7 449 if (!env_value_integer_obj) {
95c09b3a 450 BT_LOGE_STR("Cannot create integer value object.");
3487c9f3 451 ret = -1;
7f800dc7 452 goto end;
3487c9f3
JG
453 }
454
95c09b3a 455 /* bt_ctf_trace_set_environment_field() logs errors */
7f800dc7
PP
456 ret = bt_ctf_trace_set_environment_field(trace, name,
457 env_value_integer_obj);
95c09b3a 458
7f800dc7 459end:
95c09b3a 460 bt_put(env_value_integer_obj);
bc37ae52
JG
461 return ret;
462}
463
544d0515 464int64_t bt_ctf_trace_get_environment_field_count(struct bt_ctf_trace *trace)
e6fa2160 465{
544d0515 466 int64_t ret = 0;
e6fa2160
JG
467
468 if (!trace) {
95c09b3a 469 BT_LOGW_STR("Invalid parameter: trace is NULL.");
9ac68eb1 470 ret = (int64_t) -1;
e6fa2160
JG
471 goto end;
472 }
473
7f800dc7 474 ret = bt_ctf_attributes_get_count(trace->environment);
95c09b3a 475 assert(ret >= 0);
e6fa2160 476
e6fa2160 477end:
7f800dc7 478 return ret;
e6fa2160
JG
479}
480
481const char *
9ac68eb1
PP
482bt_ctf_trace_get_environment_field_name_by_index(struct bt_ctf_trace *trace,
483 uint64_t index)
e6fa2160 484{
e6fa2160
JG
485 const char *ret = NULL;
486
7f800dc7 487 if (!trace) {
95c09b3a 488 BT_LOGW_STR("Invalid parameter: trace is NULL.");
e6fa2160
JG
489 goto end;
490 }
491
7f800dc7
PP
492 ret = bt_ctf_attributes_get_field_name(trace->environment, index);
493
e6fa2160
JG
494end:
495 return ret;
496}
497
9ac68eb1
PP
498struct bt_value *bt_ctf_trace_get_environment_field_value_by_index(
499 struct bt_ctf_trace *trace, uint64_t index)
e6fa2160 500{
dac5c838 501 struct bt_value *ret = NULL;
e6fa2160 502
7f800dc7 503 if (!trace) {
95c09b3a 504 BT_LOGW_STR("Invalid parameter: trace is NULL.");
e6fa2160
JG
505 goto end;
506 }
507
7f800dc7
PP
508 ret = bt_ctf_attributes_get_field_value(trace->environment, index);
509
e6fa2160
JG
510end:
511 return ret;
512}
513
dac5c838 514struct bt_value *bt_ctf_trace_get_environment_field_value_by_name(
7f800dc7 515 struct bt_ctf_trace *trace, const char *name)
e6fa2160 516{
dac5c838 517 struct bt_value *ret = NULL;
e6fa2160 518
95c09b3a
PP
519 if (!trace) {
520 BT_LOGW_STR("Invalid parameter: trace is NULL.");
521 goto end;
522 }
523
524 if (!name) {
525 BT_LOGW_STR("Invalid parameter: name is NULL.");
e6fa2160
JG
526 goto end;
527 }
528
7f800dc7
PP
529 ret = bt_ctf_attributes_get_field_value_by_name(trace->environment,
530 name);
531
e6fa2160
JG
532end:
533 return ret;
534}
535
ac0c6bdd
PP
536int bt_ctf_trace_add_clock_class(struct bt_ctf_trace *trace,
537 struct bt_ctf_clock_class *clock_class)
bc37ae52
JG
538{
539 int ret = 0;
bc37ae52 540
95c09b3a
PP
541 if (!trace) {
542 BT_LOGW_STR("Invalid parameter: trace is NULL.");
543 ret = -1;
544 goto end;
545 }
546
547 if (trace->is_static) {
548 BT_LOGW("Invalid parameter: trace is static: "
549 "addr=%p, name=\"%s\"",
550 trace, bt_ctf_trace_get_name(trace));
551 ret = -1;
552 goto end;
553 }
554
555 if (!bt_ctf_clock_class_is_valid(clock_class)) {
556 BT_LOGW("Invalid parameter: clock class is invalid: "
557 "trace-addr=%p, trace-name=\"%s\", "
558 "clock-class-addr=%p, clock-class-name=\"%s\"",
559 trace, bt_ctf_trace_get_name(trace),
560 clock_class, bt_ctf_clock_class_get_name(clock_class));
bc37ae52
JG
561 ret = -1;
562 goto end;
563 }
564
ac0c6bdd 565 /* Check for duplicate clock classes */
c9d90a34 566 if (bt_ctf_trace_has_clock_class(trace, clock_class)) {
95c09b3a
PP
567 BT_LOGW("Invalid parameter: clock class already exists in trace: "
568 "trace-addr=%p, trace-name=\"%s\", "
569 "clock-class-addr=%p, clock-class-name=\"%s\"",
570 trace, bt_ctf_trace_get_name(trace),
571 clock_class, bt_ctf_clock_class_get_name(clock_class));
bc37ae52
JG
572 ret = -1;
573 goto end;
574 }
575
ac0c6bdd
PP
576 bt_get(clock_class);
577 g_ptr_array_add(trace->clocks, clock_class);
cfeb617e 578
6474e016 579 if (trace->frozen) {
95c09b3a 580 BT_LOGV_STR("Freezing added clock class because trace is frozen.");
ac0c6bdd 581 bt_ctf_clock_class_freeze(clock_class);
6474e016 582 }
95c09b3a
PP
583
584 BT_LOGV("Added clock class to trace: "
585 "trace-addr=%p, trace-name=\"%s\", "
586 "clock-class-addr=%p, clock-class-name=\"%s\"",
587 trace, bt_ctf_trace_get_name(trace),
588 clock_class, bt_ctf_clock_class_get_name(clock_class));
589
bc37ae52
JG
590end:
591 return ret;
592}
593
544d0515 594int64_t bt_ctf_trace_get_clock_class_count(struct bt_ctf_trace *trace)
884cd6c3 595{
9ac68eb1 596 int64_t ret = (int64_t) -1;
884cd6c3
JG
597
598 if (!trace) {
95c09b3a 599 BT_LOGW_STR("Invalid parameter: trace is NULL.");
884cd6c3
JG
600 goto end;
601 }
602
603 ret = trace->clocks->len;
604end:
605 return ret;
606}
607
9ac68eb1
PP
608struct bt_ctf_clock_class *bt_ctf_trace_get_clock_class_by_index(
609 struct bt_ctf_trace *trace, uint64_t index)
884cd6c3 610{
ac0c6bdd 611 struct bt_ctf_clock_class *clock_class = NULL;
884cd6c3 612
95c09b3a
PP
613 if (!trace) {
614 BT_LOGW_STR("Invalid parameter: trace is NULL.");
615 goto end;
616 }
617
618 if (index >= trace->clocks->len) {
619 BT_LOGW("Invalid parameter: index is out of bounds: "
620 "addr=%p, name=\"%s\", "
621 "index=%" PRIu64 ", count=%u",
622 trace, bt_ctf_trace_get_name(trace),
623 index, trace->clocks->len);
884cd6c3
JG
624 goto end;
625 }
626
ac0c6bdd
PP
627 clock_class = g_ptr_array_index(trace->clocks, index);
628 bt_get(clock_class);
884cd6c3 629end:
ac0c6bdd 630 return clock_class;
884cd6c3
JG
631}
632
e011d2c1
PP
633static
634bool packet_header_field_type_is_valid(struct bt_ctf_trace *trace,
635 struct bt_ctf_field_type *packet_header_type)
636{
637 int ret;
638 bool is_valid = true;
639 struct bt_ctf_field_type *field_type = NULL;
640
641 if (!packet_header_type) {
642 /*
643 * No packet header field type: trace must have only
644 * one stream. At this point the stream class being
645 * added is not part of the trace yet, so we validate
646 * that the trace contains no stream classes yet.
647 */
648 if (trace->stream_classes->len >= 1) {
649 BT_LOGW_STR("Invalid packet header field type: "
650 "packet header field type does not exist but there's more than one stream class in the trace.");
651 goto invalid;
652 }
653
654 /* No packet header field type: valid at this point */
655 goto end;
656 }
657
658 /* Packet header field type, if it exists, must be a structure */
659 if (!bt_ctf_field_type_is_structure(packet_header_type)) {
660 BT_LOGW("Invalid packet header field type: must be a structure field type if it exists: "
661 "ft-addr=%p, ft-id=%s",
662 packet_header_type,
663 bt_ctf_field_type_id_string(packet_header_type->id));
664 goto invalid;
665 }
666
667 /*
668 * If there's a `magic` field, it must be a 32-bit unsigned
669 * integer field type. Also it must be the first field of the
670 * packet header field type.
671 */
672 field_type = bt_ctf_field_type_structure_get_field_type_by_name(
673 packet_header_type, "magic");
674 if (field_type) {
675 const char *field_name;
676
677 if (!bt_ctf_field_type_is_integer(field_type)) {
678 BT_LOGW("Invalid packet header field type: `magic` field must be an integer field type: "
679 "magic-ft-addr=%p, magic-ft-id=%s",
680 field_type,
681 bt_ctf_field_type_id_string(field_type->id));
682 goto invalid;
683 }
684
685 if (bt_ctf_field_type_integer_is_signed(field_type)) {
686 BT_LOGW("Invalid packet header field type: `magic` field must be an unsigned integer field type: "
687 "magic-ft-addr=%p", field_type);
688 goto invalid;
689 }
690
691 if (bt_ctf_field_type_integer_get_size(field_type) != 32) {
692 BT_LOGW("Invalid packet header field type: `magic` field must be a 32-bit unsigned integer field type: "
693 "magic-ft-addr=%p, magic-ft-size=%u",
694 field_type,
695 bt_ctf_field_type_integer_get_size(field_type));
696 goto invalid;
697 }
698
699 ret = bt_ctf_field_type_structure_get_field_by_index(
700 packet_header_type, &field_name, NULL, 0);
701 assert(ret == 0);
702
703 if (strcmp(field_name, "magic") != 0) {
704 BT_LOGW("Invalid packet header field type: `magic` field must be the first field: "
705 "magic-ft-addr=%p, first-field-name=\"%s\"",
706 field_type, field_name);
707 goto invalid;
708 }
709
710 BT_PUT(field_type);
711 }
712
713 /*
714 * If there's a `uuid` field, it must be an array field type of
715 * length 16 with an 8-bit unsigned integer element field type.
716 */
717 field_type = bt_ctf_field_type_structure_get_field_type_by_name(
718 packet_header_type, "uuid");
719 if (field_type) {
720 struct bt_ctf_field_type *elem_ft;
721
722 if (!bt_ctf_field_type_is_array(field_type)) {
723 BT_LOGW("Invalid packet header field type: `uuid` field must be an array field type: "
724 "uuid-ft-addr=%p, uuid-ft-id=%s",
725 field_type,
726 bt_ctf_field_type_id_string(field_type->id));
727 goto invalid;
728 }
729
730 if (bt_ctf_field_type_array_get_length(field_type) != 16) {
731 BT_LOGW("Invalid packet header field type: `uuid` array field type's length must be 16: "
732 "uuid-ft-addr=%p, uuid-ft-length=%" PRId64,
733 field_type,
734 bt_ctf_field_type_array_get_length(field_type));
735 goto invalid;
736 }
737
738 elem_ft = bt_ctf_field_type_array_get_element_type(field_type);
739 assert(elem_ft);
740
741 if (!bt_ctf_field_type_is_integer(elem_ft)) {
742 BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an integer field type: "
743 "elem-ft-addr=%p, elem-ft-id=%s",
744 elem_ft,
745 bt_ctf_field_type_id_string(elem_ft->id));
746 bt_put(elem_ft);
747 goto invalid;
748 }
749
750 if (bt_ctf_field_type_integer_is_signed(elem_ft)) {
751 BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an unsigned integer field type: "
752 "elem-ft-addr=%p", elem_ft);
753 bt_put(elem_ft);
754 goto invalid;
755 }
756
757 if (bt_ctf_field_type_integer_get_size(elem_ft) != 8) {
758 BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an 8-bit unsigned integer field type: "
759 "elem-ft-addr=%p, elem-ft-size=%u",
760 elem_ft,
761 bt_ctf_field_type_integer_get_size(elem_ft));
762 bt_put(elem_ft);
763 goto invalid;
764 }
765
766 bt_put(elem_ft);
767 BT_PUT(field_type);
768 }
769
770 /*
771 * The `stream_id` field must exist if there's more than one
772 * stream classes in the trace.
773 */
774 field_type = bt_ctf_field_type_structure_get_field_type_by_name(
775 packet_header_type, "stream_id");
776
777 if (!field_type && trace->stream_classes->len >= 1) {
778 BT_LOGW_STR("Invalid packet header field type: "
779 "`stream_id` field does not exist but there's more than one stream class in the trace.");
780 goto invalid;
781 }
782
783 /*
784 * If there's a `stream_id` field, it must be an unsigned
785 * integer field type.
786 */
787 if (field_type) {
788 if (!bt_ctf_field_type_is_integer(field_type)) {
789 BT_LOGW("Invalid packet header field type: `stream_id` field must be an integer field type: "
790 "stream-id-ft-addr=%p, stream-id-ft-id=%s",
791 field_type,
792 bt_ctf_field_type_id_string(field_type->id));
793 goto invalid;
794 }
795
796 if (bt_ctf_field_type_integer_is_signed(field_type)) {
797 BT_LOGW("Invalid packet header field type: `stream_id` field must be an unsigned integer field type: "
798 "stream-id-ft-addr=%p", field_type);
799 goto invalid;
800 }
801
802 BT_PUT(field_type);
803 }
804
805 goto end;
806
807invalid:
808 is_valid = false;
809
810end:
811 bt_put(field_type);
812 return is_valid;
813}
814
815static
816bool packet_context_field_type_is_valid(struct bt_ctf_trace *trace,
817 struct bt_ctf_stream_class *stream_class,
818 struct bt_ctf_field_type *packet_context_type)
819{
820 bool is_valid = true;
821 struct bt_ctf_field_type *field_type = NULL;
822
823 if (!packet_context_type) {
824 /* No packet context field type: valid at this point */
825 goto end;
826 }
827
828 /* Packet context field type, if it exists, must be a structure */
829 if (!bt_ctf_field_type_is_structure(packet_context_type)) {
830 BT_LOGW("Invalid packet context field type: must be a structure field type if it exists: "
831 "ft-addr=%p, ft-id=%s",
832 packet_context_type,
833 bt_ctf_field_type_id_string(packet_context_type->id));
834 goto invalid;
835 }
836
837 /*
838 * If there's a `packet_size` field, it must be an unsigned
839 * integer field type.
840 */
841 field_type = bt_ctf_field_type_structure_get_field_type_by_name(
842 packet_context_type, "packet_size");
843 if (field_type) {
844 if (!bt_ctf_field_type_is_integer(field_type)) {
845 BT_LOGW("Invalid packet context field type: `packet_size` field must be an integer field type: "
846 "packet-size-ft-addr=%p, packet-size-ft-id=%s",
847 field_type,
848 bt_ctf_field_type_id_string(field_type->id));
849 goto invalid;
850 }
851
852 if (bt_ctf_field_type_integer_is_signed(field_type)) {
853 BT_LOGW("Invalid packet context field type: `packet_size` field must be an unsigned integer field type: "
854 "packet-size-ft-addr=%p", field_type);
855 goto invalid;
856 }
857
858 BT_PUT(field_type);
859 }
860
861 /*
862 * If there's a `content_size` field, it must be an unsigned
863 * integer field type.
864 */
865 field_type = bt_ctf_field_type_structure_get_field_type_by_name(
866 packet_context_type, "content_size");
867 if (field_type) {
868 if (!bt_ctf_field_type_is_integer(field_type)) {
869 BT_LOGW("Invalid packet context field type: `content_size` field must be an integer field type: "
870 "content-size-ft-addr=%p, content-size-ft-id=%s",
871 field_type,
872 bt_ctf_field_type_id_string(field_type->id));
873 goto invalid;
874 }
875
876 if (bt_ctf_field_type_integer_is_signed(field_type)) {
877 BT_LOGW("Invalid packet context field type: `content_size` field must be an unsigned integer field type: "
878 "content-size-ft-addr=%p", field_type);
879 goto invalid;
880 }
881
882 BT_PUT(field_type);
883 }
884
885 /*
886 * If there's a `events_discarded` field, it must be an unsigned
887 * integer field type.
888 */
889 field_type = bt_ctf_field_type_structure_get_field_type_by_name(
890 packet_context_type, "events_discarded");
891 if (field_type) {
892 if (!bt_ctf_field_type_is_integer(field_type)) {
893 BT_LOGW("Invalid packet context field type: `events_discarded` field must be an integer field type: "
894 "events-discarded-ft-addr=%p, events-discarded-ft-id=%s",
895 field_type,
896 bt_ctf_field_type_id_string(field_type->id));
897 goto invalid;
898 }
899
900 if (bt_ctf_field_type_integer_is_signed(field_type)) {
901 BT_LOGW("Invalid packet context field type: `events_discarded` field must be an unsigned integer field type: "
902 "events-discarded-ft-addr=%p", field_type);
903 goto invalid;
904 }
905
906 BT_PUT(field_type);
907 }
908
909 /*
910 * If there's a `timestamp_begin` field, it must be an unsigned
911 * integer field type. Also, if the trace is not a CTF writer's
912 * trace, then we cannot automatically set the mapped clock
913 * class of this field, so it must have a mapped clock class.
914 */
915 field_type = bt_ctf_field_type_structure_get_field_type_by_name(
916 packet_context_type, "timestamp_begin");
917 if (field_type) {
918 if (!bt_ctf_field_type_is_integer(field_type)) {
919 BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be an integer field type: "
920 "timestamp-begin-ft-addr=%p, timestamp-begin-ft-id=%s",
921 field_type,
922 bt_ctf_field_type_id_string(field_type->id));
923 goto invalid;
924 }
925
926 if (bt_ctf_field_type_integer_is_signed(field_type)) {
927 BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be an unsigned integer field type: "
928 "timestamp-begin-ft-addr=%p", field_type);
929 goto invalid;
930 }
931
932 if (!trace->is_created_by_writer) {
933 struct bt_ctf_clock_class *clock_class =
934 bt_ctf_field_type_integer_get_mapped_clock_class(
935 field_type);
936
937 bt_put(clock_class);
938 if (!clock_class) {
939 BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be mapped to a clock class: "
940 "timestamp-begin-ft-addr=%p", field_type);
941 goto invalid;
942 }
943 }
944
945 BT_PUT(field_type);
946 }
947
948 /*
949 * If there's a `timestamp_end` field, it must be an unsigned
950 * integer field type. Also, if the trace is not a CTF writer's
951 * trace, then we cannot automatically set the mapped clock
952 * class of this field, so it must have a mapped clock class.
953 */
954 field_type = bt_ctf_field_type_structure_get_field_type_by_name(
955 packet_context_type, "timestamp_end");
956 if (field_type) {
957 if (!bt_ctf_field_type_is_integer(field_type)) {
958 BT_LOGW("Invalid packet context field type: `timestamp_end` field must be an integer field type: "
959 "timestamp-end-ft-addr=%p, timestamp-end-ft-id=%s",
960 field_type,
961 bt_ctf_field_type_id_string(field_type->id));
962 goto invalid;
963 }
964
965 if (bt_ctf_field_type_integer_is_signed(field_type)) {
966 BT_LOGW("Invalid packet context field type: `timestamp_end` field must be an unsigned integer field type: "
967 "timestamp-end-ft-addr=%p", field_type);
968 goto invalid;
969 }
970
971 if (!trace->is_created_by_writer) {
972 struct bt_ctf_clock_class *clock_class =
973 bt_ctf_field_type_integer_get_mapped_clock_class(
974 field_type);
975
976 bt_put(clock_class);
977 if (!clock_class) {
978 BT_LOGW("Invalid packet context field type: `timestamp_end` field must be mapped to a clock class: "
979 "timestamp-end-ft-addr=%p", field_type);
980 goto invalid;
981 }
982 }
983
984 BT_PUT(field_type);
985 }
986
987 goto end;
988
989invalid:
990 is_valid = false;
991
992end:
993 bt_put(field_type);
994 return is_valid;
995}
996
997static
998bool event_header_field_type_is_valid(struct bt_ctf_trace *trace,
999 struct bt_ctf_stream_class *stream_class,
1000 struct bt_ctf_field_type *event_header_type)
1001{
1002 bool is_valid = true;
1003 struct bt_ctf_field_type *field_type = NULL;
1004
1005 /*
1006 * We do not validate that the `timestamp` field exists here
1007 * because CTF does not require this exact name to be mapped to
1008 * a clock class.
1009 */
1010
1011 if (!event_header_type) {
1012 /*
1013 * No event header field type: stream class must have
1014 * only one event class.
1015 */
1016 if (bt_ctf_stream_class_get_event_class_count(stream_class) > 1) {
1017 BT_LOGW_STR("Invalid event header field type: "
1018 "event header field type does not exist but there's more than one event class in the stream class.");
1019 goto invalid;
1020 }
1021
1022 /* No event header field type: valid at this point */
1023 goto end;
1024 }
1025
1026 /* Event header field type, if it exists, must be a structure */
1027 if (!bt_ctf_field_type_is_structure(event_header_type)) {
1028 BT_LOGW("Invalid event header field type: must be a structure field type if it exists: "
1029 "ft-addr=%p, ft-id=%s",
1030 event_header_type,
1031 bt_ctf_field_type_id_string(event_header_type->id));
1032 goto invalid;
1033 }
1034
1035 /*
1036 * If there's an `id` field, it must be an unsigned integer
1037 * field type or an enumeration field type with an unsigned
1038 * integer container field type.
1039 */
1040 field_type = bt_ctf_field_type_structure_get_field_type_by_name(
1041 event_header_type, "id");
1042 if (field_type) {
1043 struct bt_ctf_field_type *int_ft;
1044
1045 if (bt_ctf_field_type_is_integer(field_type)) {
1046 int_ft = bt_get(field_type);
1047 } else if (bt_ctf_field_type_is_enumeration(field_type)) {
1048 int_ft = bt_ctf_field_type_enumeration_get_container_type(
1049 field_type);
1050 } else {
1051 BT_LOGW("Invalid event header field type: `id` field must be an integer or enumeration field type: "
1052 "id-ft-addr=%p, id-ft-id=%s",
1053 field_type,
1054 bt_ctf_field_type_id_string(field_type->id));
1055 goto invalid;
1056 }
1057
1058 assert(int_ft);
1059 if (bt_ctf_field_type_integer_is_signed(int_ft)) {
1060 BT_LOGW("Invalid event header field type: `id` field must be an unsigned integer or enumeration field type: "
1061 "id-ft-addr=%p", int_ft);
1062 goto invalid;
1063 }
1064
1065 bt_put(int_ft);
1066 BT_PUT(field_type);
1067 }
1068
1069 goto end;
1070
1071invalid:
1072 is_valid = false;
1073
1074end:
1075 bt_put(field_type);
1076 return is_valid;
1077}
1078
ef0c4a15
JG
1079int bt_ctf_trace_add_stream_class(struct bt_ctf_trace *trace,
1080 struct bt_ctf_stream_class *stream_class)
1081{
544d0515
PP
1082 int ret;
1083 int64_t i;
ef0c4a15 1084 int64_t stream_id;
09840de5
PP
1085 struct bt_ctf_validation_output trace_sc_validation_output = { 0 };
1086 struct bt_ctf_validation_output *ec_validation_outputs = NULL;
1087 const enum bt_ctf_validation_flag trace_sc_validation_flags =
1088 BT_CTF_VALIDATION_FLAG_TRACE |
1089 BT_CTF_VALIDATION_FLAG_STREAM;
1090 const enum bt_ctf_validation_flag ec_validation_flags =
1091 BT_CTF_VALIDATION_FLAG_EVENT;
1092 struct bt_ctf_field_type *packet_header_type = NULL;
1093 struct bt_ctf_field_type *packet_context_type = NULL;
1094 struct bt_ctf_field_type *event_header_type = NULL;
1095 struct bt_ctf_field_type *stream_event_ctx_type = NULL;
544d0515 1096 int64_t event_class_count;
2789e5d9 1097 struct bt_ctf_trace *current_parent_trace = NULL;
ef0c4a15 1098
95c09b3a
PP
1099 if (!trace) {
1100 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1101 ret = -1;
1102 goto end;
1103 }
1104
1105 if (!stream_class) {
1106 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
1107 ret = -1;
1108 goto end;
1109 }
1110
1111 if (trace->is_static) {
1112 BT_LOGW_STR("Invalid parameter: trace is static.");
ef0c4a15
JG
1113 ret = -1;
1114 goto end;
1115 }
1116
95c09b3a
PP
1117 BT_LOGD("Adding stream class to trace: "
1118 "trace-addr=%p, trace-name=\"%s\", "
1119 "stream-class-addr=%p, stream-class-name=\"%s\", "
1120 "stream-class-id=%" PRId64,
1121 trace, bt_ctf_trace_get_name(trace),
1122 stream_class, bt_ctf_stream_class_get_name(stream_class),
1123 bt_ctf_stream_class_get_id(stream_class));
1124
d490fcbe
PP
1125 /*
1126 * At the end of this function we freeze the trace, so its
1127 * native byte order must NOT be BT_CTF_BYTE_ORDER_NATIVE.
1128 */
1129 if (trace->native_byte_order == BT_CTF_BYTE_ORDER_NATIVE) {
95c09b3a
PP
1130 BT_LOGW_STR("Invalid parameter: trace's byte order cannot be BT_CTF_BYTE_ORDER_NATIVE at this point; "
1131 "set it with bt_ctf_trace_set_native_byte_order().");
d490fcbe
PP
1132 ret = -1;
1133 goto end;
1134 }
1135
2789e5d9
JG
1136 current_parent_trace = bt_ctf_stream_class_get_trace(stream_class);
1137 if (current_parent_trace) {
1138 /* Stream class is already associated to a trace, abort. */
95c09b3a
PP
1139 BT_LOGW("Invalid parameter: stream class is already part of a trace: "
1140 "stream-class-trace-addr=%p, "
1141 "stream-class-trace-name=\"%s\"",
1142 current_parent_trace,
1143 bt_ctf_trace_get_name(current_parent_trace));
2789e5d9
JG
1144 ret = -1;
1145 goto end;
1146 }
1147
09840de5
PP
1148 event_class_count =
1149 bt_ctf_stream_class_get_event_class_count(stream_class);
1150 assert(event_class_count >= 0);
1151
fe13b5c0 1152 if (stream_class->clock) {
ac0c6bdd
PP
1153 struct bt_ctf_clock_class *stream_clock_class =
1154 stream_class->clock->clock_class;
1155
1156 if (trace->is_created_by_writer) {
1157 /*
1158 * Make sure this clock was also added to the
1159 * trace (potentially through its CTF writer
1160 * owner).
1161 */
1162 size_t i;
1163
1164 for (i = 0; i < trace->clocks->len; i++) {
1165 if (trace->clocks->pdata[i] ==
1166 stream_clock_class) {
1167 /* Found! */
1168 break;
1169 }
1170 }
1171
1172 if (i == trace->clocks->len) {
1173 /* Not found */
95c09b3a
PP
1174 BT_LOGW("Stream class's clock's class is not part of the trace: "
1175 "clock-class-addr=%p, clock-class-name=\"%s\"",
1176 stream_clock_class,
1177 bt_ctf_clock_class_get_name(stream_clock_class));
fe13b5c0
PP
1178 ret = -1;
1179 goto end;
1180 }
1181 } else {
ac0c6bdd
PP
1182 /*
1183 * This trace was NOT created by a CTF writer,
1184 * thus do not allow the stream class to add to
1185 * have a clock at all. Those are two
1186 * independent APIs (non-writer and writer
1187 * APIs), and isolating them simplifies things.
1188 */
95c09b3a
PP
1189 BT_LOGW("Cannot add stream class with a clock to a trace which was not created by a CTF writer object: "
1190 "clock-class-addr=%p, clock-class-name=\"%s\"",
1191 stream_clock_class,
1192 bt_ctf_clock_class_get_name(stream_clock_class));
ac0c6bdd
PP
1193 ret = -1;
1194 goto end;
fe13b5c0
PP
1195 }
1196 }
1197
09840de5
PP
1198 /*
1199 * We're about to freeze both the trace and the stream class.
1200 * Also, each event class contained in this stream class are
1201 * already frozen.
1202 *
1203 * This trace, this stream class, and all its event classes
1204 * should be valid at this point.
1205 *
1206 * Validate trace and stream class first, then each event
1207 * class of this stream class can be validated individually.
1208 */
1209 packet_header_type =
1210 bt_ctf_trace_get_packet_header_type(trace);
1211 packet_context_type =
1212 bt_ctf_stream_class_get_packet_context_type(stream_class);
1213 event_header_type =
1214 bt_ctf_stream_class_get_event_header_type(stream_class);
1215 stream_event_ctx_type =
1216 bt_ctf_stream_class_get_event_context_type(stream_class);
95c09b3a
PP
1217
1218 BT_LOGD("Validating trace and stream class field types.");
09840de5
PP
1219 ret = bt_ctf_validate_class_types(trace->environment,
1220 packet_header_type, packet_context_type, event_header_type,
1221 stream_event_ctx_type, NULL, NULL, trace->valid,
1222 stream_class->valid, 1, &trace_sc_validation_output,
1223 trace_sc_validation_flags);
1224 BT_PUT(packet_header_type);
1225 BT_PUT(packet_context_type);
1226 BT_PUT(event_header_type);
1227 BT_PUT(stream_event_ctx_type);
1228
2bd7f864 1229 if (ret) {
09840de5
PP
1230 /*
1231 * This means something went wrong during the validation
1232 * process, not that the objects are invalid.
1233 */
95c09b3a
PP
1234 BT_LOGE("Failed to validate trace and stream class field types: "
1235 "ret=%d", ret);
2bd7f864
JG
1236 goto end;
1237 }
1238
09840de5
PP
1239 if ((trace_sc_validation_output.valid_flags &
1240 trace_sc_validation_flags) !=
1241 trace_sc_validation_flags) {
1242 /* Invalid trace/stream class */
95c09b3a
PP
1243 BT_LOGW("Invalid trace or stream class field types: "
1244 "valid-flags=0x%x",
1245 trace_sc_validation_output.valid_flags);
09840de5
PP
1246 ret = -1;
1247 goto end;
1248 }
1249
1250 if (event_class_count > 0) {
1251 ec_validation_outputs = g_new0(struct bt_ctf_validation_output,
1252 event_class_count);
1253 if (!ec_validation_outputs) {
95c09b3a 1254 BT_LOGE_STR("Failed to allocate one validation output structure.");
09840de5
PP
1255 ret = -1;
1256 goto end;
1257 }
1258 }
1259
1260 /* Validate each event class individually */
6474e016 1261 for (i = 0; i < event_class_count; i++) {
09840de5 1262 struct bt_ctf_event_class *event_class =
9ac68eb1
PP
1263 bt_ctf_stream_class_get_event_class_by_index(
1264 stream_class, i);
09840de5
PP
1265 struct bt_ctf_field_type *event_context_type = NULL;
1266 struct bt_ctf_field_type *event_payload_type = NULL;
1267
1268 event_context_type =
1269 bt_ctf_event_class_get_context_type(event_class);
1270 event_payload_type =
1271 bt_ctf_event_class_get_payload_type(event_class);
1272
1273 /*
1274 * It is important to use the field types returned by
1275 * the previous trace and stream class validation here
1276 * because copies could have been made.
1277 */
95c09b3a
PP
1278 BT_LOGD("Validating event class's field types: "
1279 "addr=%p, name=\"%s\", id=%" PRId64,
1280 event_class, bt_ctf_event_class_get_name(event_class),
1281 bt_ctf_event_class_get_id(event_class));
09840de5
PP
1282 ret = bt_ctf_validate_class_types(trace->environment,
1283 trace_sc_validation_output.packet_header_type,
1284 trace_sc_validation_output.packet_context_type,
1285 trace_sc_validation_output.event_header_type,
1286 trace_sc_validation_output.stream_event_ctx_type,
1287 event_context_type, event_payload_type,
1288 1, 1, event_class->valid, &ec_validation_outputs[i],
1289 ec_validation_flags);
1290 BT_PUT(event_context_type);
1291 BT_PUT(event_payload_type);
1292 BT_PUT(event_class);
1293
1294 if (ret) {
95c09b3a
PP
1295 BT_LOGE("Failed to validate event class field types: "
1296 "ret=%d", ret);
09840de5
PP
1297 goto end;
1298 }
1299
1300 if ((ec_validation_outputs[i].valid_flags &
1301 ec_validation_flags) != ec_validation_flags) {
1302 /* Invalid event class */
95c09b3a
PP
1303 BT_LOGW("Invalid event class field types: "
1304 "valid-flags=0x%x",
1305 ec_validation_outputs[i].valid_flags);
09840de5
PP
1306 ret = -1;
1307 goto end;
1308 }
1309 }
1310
ef0c4a15
JG
1311 stream_id = bt_ctf_stream_class_get_id(stream_class);
1312 if (stream_id < 0) {
1313 stream_id = trace->next_stream_id++;
9ac68eb1 1314 if (stream_id < 0) {
95c09b3a 1315 BT_LOGE_STR("No more stream class IDs available.");
9ac68eb1
PP
1316 ret = -1;
1317 goto end;
1318 }
ef0c4a15
JG
1319
1320 /* Try to assign a new stream id */
1321 for (i = 0; i < trace->stream_classes->len; i++) {
1322 if (stream_id == bt_ctf_stream_class_get_id(
1323 trace->stream_classes->pdata[i])) {
1324 /* Duplicate stream id found */
95c09b3a
PP
1325 BT_LOGW("Duplicate stream class ID: "
1326 "id=%" PRId64, (int64_t) stream_id);
ef0c4a15
JG
1327 ret = -1;
1328 goto end;
1329 }
1330 }
1331
0ddffae5 1332 if (bt_ctf_stream_class_set_id_no_check(stream_class,
95c09b3a 1333 stream_id)) {
ef0c4a15 1334 /* TODO Should retry with a different stream id */
95c09b3a
PP
1335 BT_LOGE("Cannot set stream class's ID: "
1336 "id=%" PRId64, (int64_t) stream_id);
ef0c4a15
JG
1337 ret = -1;
1338 goto end;
1339 }
1340 }
1341
e011d2c1
PP
1342 /*
1343 * At this point all the field types in the validation output
1344 * are valid. Validate the semantics of some scopes according to
1345 * the CTF specification.
1346 */
1347 if (!packet_header_field_type_is_valid(trace,
1348 trace_sc_validation_output.packet_header_type)) {
95c09b3a 1349 BT_LOGW_STR("Invalid trace's packet header field type.");
e011d2c1
PP
1350 ret = -1;
1351 goto end;
1352 }
1353
1354 if (!packet_context_field_type_is_valid(trace,
1355 stream_class,
1356 trace_sc_validation_output.packet_context_type)) {
95c09b3a 1357 BT_LOGW_STR("Invalid stream class's packet context field type.");
e011d2c1
PP
1358 ret = -1;
1359 goto end;
1360 }
1361
1362 if (!event_header_field_type_is_valid(trace,
1363 stream_class,
1364 trace_sc_validation_output.event_header_type)) {
95c09b3a 1365 BT_LOGW_STR("Invalid steam class's event header field type.");
e011d2c1
PP
1366 ret = -1;
1367 goto end;
1368 }
1369
1370 /*
1371 * Now is the time to automatically map specific field types of
1372 * the stream class's packet context and event header field
1373 * types to the stream class's clock's class if they are not
1374 * mapped to a clock class yet. We do it here because we know
1375 * that after this point, everything is frozen so it won't be
1376 * possible for the user to modify the stream class's clock, or
1377 * to map those field types to other clock classes.
1378 */
1379 if (trace->is_created_by_writer) {
1380 if (bt_ctf_stream_class_map_clock_class(stream_class,
1381 trace_sc_validation_output.packet_context_type,
1382 trace_sc_validation_output.event_header_type)) {
95c09b3a 1383 BT_LOGW_STR("Cannot automatically map selected stream class's field types to stream class's clock's class.");
e011d2c1
PP
1384 ret = -1;
1385 goto end;
1386 }
1387 }
1388
e6a8e8e4 1389 bt_object_set_parent(stream_class, trace);
ef0c4a15
JG
1390 g_ptr_array_add(trace->stream_classes, stream_class);
1391
1392 /*
09840de5
PP
1393 * At this point we know that the function will be successful.
1394 * Therefore we can replace the trace and stream class field
1395 * types with what's in their validation output structure and
1396 * mark them as valid. We can also replace the field types of
1397 * all the event classes of the stream class and mark them as
1398 * valid.
1399 */
1400 bt_ctf_validation_replace_types(trace, stream_class, NULL,
1401 &trace_sc_validation_output, trace_sc_validation_flags);
1402 trace->valid = 1;
1403 stream_class->valid = 1;
1404
1405 /*
1406 * Put what was not moved in bt_ctf_validation_replace_types().
1407 */
1408 bt_ctf_validation_output_put_types(&trace_sc_validation_output);
1409
6474e016 1410 for (i = 0; i < event_class_count; i++) {
09840de5 1411 struct bt_ctf_event_class *event_class =
9ac68eb1
PP
1412 bt_ctf_stream_class_get_event_class_by_index(
1413 stream_class, i);
09840de5
PP
1414
1415 bt_ctf_validation_replace_types(NULL, NULL, event_class,
1416 &ec_validation_outputs[i], ec_validation_flags);
1417 event_class->valid = 1;
1418 BT_PUT(event_class);
1419
1420 /*
1421 * Put what was not moved in
1422 * bt_ctf_validation_replace_types().
1423 */
1424 bt_ctf_validation_output_put_types(&ec_validation_outputs[i]);
1425 }
1426
09840de5
PP
1427 /*
1428 * Freeze the trace and the stream class.
1429 */
f67f3a6e 1430 bt_ctf_stream_class_freeze(stream_class);
09840de5
PP
1431 bt_ctf_trace_freeze(trace);
1432
9b888ff3
JG
1433 /* Notifiy listeners of the trace's schema modification. */
1434 bt_ctf_stream_class_visit(stream_class,
d9a13d86 1435 bt_ctf_trace_object_modification, trace);
95c09b3a
PP
1436 BT_LOGD("Added stream class to trace: "
1437 "trace-addr=%p, trace-name=\"%s\", "
1438 "stream-class-addr=%p, stream-class-name=\"%s\", "
1439 "stream-class-id=%" PRId64,
1440 trace, bt_ctf_trace_get_name(trace),
1441 stream_class, bt_ctf_stream_class_get_name(stream_class),
1442 bt_ctf_stream_class_get_id(stream_class));
1443
ef0c4a15 1444end:
d3814b54 1445 if (ret) {
e6a8e8e4 1446 bt_object_set_parent(stream_class, NULL);
09840de5
PP
1447
1448 if (ec_validation_outputs) {
6474e016 1449 for (i = 0; i < event_class_count; i++) {
09840de5
PP
1450 bt_ctf_validation_output_put_types(
1451 &ec_validation_outputs[i]);
1452 }
1453 }
d3814b54 1454 }
09840de5
PP
1455
1456 g_free(ec_validation_outputs);
1457 bt_ctf_validation_output_put_types(&trace_sc_validation_output);
2789e5d9 1458 bt_put(current_parent_trace);
09840de5
PP
1459 assert(!packet_header_type);
1460 assert(!packet_context_type);
1461 assert(!event_header_type);
1462 assert(!stream_event_ctx_type);
ef0c4a15
JG
1463 return ret;
1464}
1465
544d0515 1466int64_t bt_ctf_trace_get_stream_count(struct bt_ctf_trace *trace)
c1e730fe 1467{
544d0515 1468 int64_t ret;
c1e730fe
PP
1469
1470 if (!trace) {
95c09b3a 1471 BT_LOGW_STR("Invalid parameter: trace is NULL.");
9ac68eb1 1472 ret = (int64_t) -1;
c1e730fe
PP
1473 goto end;
1474 }
1475
9ac68eb1 1476 ret = (int64_t) trace->streams->len;
c1e730fe
PP
1477
1478end:
1479 return ret;
1480}
1481
9ac68eb1
PP
1482struct bt_ctf_stream *bt_ctf_trace_get_stream_by_index(
1483 struct bt_ctf_trace *trace,
1484 uint64_t index)
c1e730fe
PP
1485{
1486 struct bt_ctf_stream *stream = NULL;
1487
95c09b3a
PP
1488 if (!trace) {
1489 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1490 goto end;
1491 }
1492
1493 if (index >= trace->streams->len) {
1494 BT_LOGW("Invalid parameter: index is out of bounds: "
1495 "addr=%p, name=\"%s\", "
1496 "index=%" PRIu64 ", count=%u",
1497 trace, bt_ctf_trace_get_name(trace),
1498 index, trace->streams->len);
c1e730fe
PP
1499 goto end;
1500 }
1501
1502 stream = bt_get(g_ptr_array_index(trace->streams, index));
1503
1504end:
1505 return stream;
1506}
1507
544d0515 1508int64_t bt_ctf_trace_get_stream_class_count(struct bt_ctf_trace *trace)
ef0c4a15 1509{
544d0515 1510 int64_t ret;
ef0c4a15
JG
1511
1512 if (!trace) {
95c09b3a 1513 BT_LOGW_STR("Invalid parameter: trace is NULL.");
9ac68eb1 1514 ret = (int64_t) -1;
ef0c4a15
JG
1515 goto end;
1516 }
1517
9ac68eb1 1518 ret = (int64_t) trace->stream_classes->len;
ef0c4a15
JG
1519end:
1520 return ret;
1521}
1522
9ac68eb1
PP
1523struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class_by_index(
1524 struct bt_ctf_trace *trace, uint64_t index)
ef0c4a15
JG
1525{
1526 struct bt_ctf_stream_class *stream_class = NULL;
1527
95c09b3a
PP
1528 if (!trace) {
1529 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1530 goto end;
1531 }
1532
1533 if (index >= trace->stream_classes->len) {
1534 BT_LOGW("Invalid parameter: index is out of bounds: "
1535 "addr=%p, name=\"%s\", "
1536 "index=%" PRIu64 ", count=%u",
1537 trace, bt_ctf_trace_get_name(trace),
1538 index, trace->stream_classes->len);
ef0c4a15
JG
1539 goto end;
1540 }
1541
1542 stream_class = g_ptr_array_index(trace->stream_classes, index);
83509119 1543 bt_get(stream_class);
ef0c4a15
JG
1544end:
1545 return stream_class;
1546}
1547
4841ccc1 1548struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class_by_id(
9ac68eb1 1549 struct bt_ctf_trace *trace, uint64_t id_param)
4841ccc1
PP
1550{
1551 int i;
1552 struct bt_ctf_stream_class *stream_class = NULL;
9ac68eb1 1553 int64_t id = (int64_t) id_param;
4841ccc1 1554
95c09b3a
PP
1555 if (!trace) {
1556 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1557 goto end;
1558 }
1559
1560 if (id < 0) {
1561 BT_LOGW("Invalid parameter: invalid stream class's ID: "
1562 "trace-addr=%p, trace-name=\"%s\", id=%" PRIu64,
1563 trace, bt_ctf_trace_get_name(trace), id_param);
4841ccc1
PP
1564 goto end;
1565 }
1566
6474e016 1567 for (i = 0; i < trace->stream_classes->len; i++) {
4841ccc1
PP
1568 struct bt_ctf_stream_class *stream_class_candidate;
1569
1570 stream_class_candidate =
1571 g_ptr_array_index(trace->stream_classes, i);
1572
1573 if (bt_ctf_stream_class_get_id(stream_class_candidate) ==
1574 (int64_t) id) {
1575 stream_class = stream_class_candidate;
83509119 1576 bt_get(stream_class);
4841ccc1
PP
1577 goto end;
1578 }
1579 }
1580
1581end:
1582 return stream_class;
1583}
1584
ac0c6bdd 1585struct bt_ctf_clock_class *bt_ctf_trace_get_clock_class_by_name(
7e4347a3
PP
1586 struct bt_ctf_trace *trace, const char *name)
1587{
1588 size_t i;
ac0c6bdd 1589 struct bt_ctf_clock_class *clock_class = NULL;
7e4347a3 1590
95c09b3a
PP
1591 if (!trace) {
1592 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1593 goto end;
1594 }
1595
1596 if (!name) {
1597 BT_LOGW_STR("Invalid parameter: name is NULL.");
7e4347a3
PP
1598 goto end;
1599 }
1600
6474e016 1601 for (i = 0; i < trace->clocks->len; i++) {
ac0c6bdd 1602 struct bt_ctf_clock_class *cur_clk =
7e4347a3 1603 g_ptr_array_index(trace->clocks, i);
ac0c6bdd 1604 const char *cur_clk_name = bt_ctf_clock_class_get_name(cur_clk);
7e4347a3
PP
1605
1606 if (!cur_clk_name) {
1607 goto end;
1608 }
1609
1610 if (!strcmp(cur_clk_name, name)) {
ac0c6bdd
PP
1611 clock_class = cur_clk;
1612 bt_get(clock_class);
7e4347a3
PP
1613 goto end;
1614 }
1615 }
1616
1617end:
ac0c6bdd 1618 return clock_class;
7e4347a3
PP
1619}
1620
c9d90a34 1621BT_HIDDEN
c55a9f58 1622bt_bool bt_ctf_trace_has_clock_class(struct bt_ctf_trace *trace,
c9d90a34
PP
1623 struct bt_ctf_clock_class *clock_class)
1624{
1625 struct search_query query = { .value = clock_class, .found = 0 };
1626
1627 assert(trace);
1628 assert(clock_class);
1629
1630 g_ptr_array_foreach(trace->clocks, value_exists, &query);
1631 return query.found;
1632}
1633
bc37ae52 1634BT_HIDDEN
dc3fffef 1635const char *get_byte_order_string(enum bt_ctf_byte_order byte_order)
bc37ae52
JG
1636{
1637 const char *string;
1638
1639 switch (byte_order) {
dc3fffef 1640 case BT_CTF_BYTE_ORDER_LITTLE_ENDIAN:
bc37ae52
JG
1641 string = "le";
1642 break;
dc3fffef 1643 case BT_CTF_BYTE_ORDER_BIG_ENDIAN:
bc37ae52
JG
1644 string = "be";
1645 break;
dc3fffef
PP
1646 case BT_CTF_BYTE_ORDER_NATIVE:
1647 string = "native";
bc37ae52 1648 break;
dc3fffef 1649 default:
0fbb9a9f 1650 abort();
bc37ae52
JG
1651 }
1652
1653 return string;
1654}
1655
1656static
1657int append_trace_metadata(struct bt_ctf_trace *trace,
1658 struct metadata_context *context)
1659{
1660 unsigned char *uuid = trace->uuid;
e011d2c1 1661 int ret = 0;
bc37ae52 1662
4a32fda0 1663 if (trace->native_byte_order == BT_CTF_BYTE_ORDER_NATIVE) {
95c09b3a
PP
1664 BT_LOGW("Invalid parameter: trace's byte order cannot be BT_CTF_BYTE_ORDER_NATIVE at this point; "
1665 "set it with bt_ctf_trace_set_native_byte_order(): "
1666 "addr=%p, name=\"%s\"",
1667 trace, bt_ctf_trace_get_name(trace));
4a32fda0
PP
1668 ret = -1;
1669 goto end;
1670 }
bc37ae52 1671
4a32fda0 1672 g_string_append(context->string, "trace {\n");
bc37ae52
JG
1673 g_string_append(context->string, "\tmajor = 1;\n");
1674 g_string_append(context->string, "\tminor = 8;\n");
dc3fffef
PP
1675 assert(trace->native_byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ||
1676 trace->native_byte_order == BT_CTF_BYTE_ORDER_BIG_ENDIAN ||
1677 trace->native_byte_order == BT_CTF_BYTE_ORDER_NETWORK);
4a32fda0
PP
1678
1679 if (trace->uuid_set) {
1680 g_string_append_printf(context->string,
1681 "\tuuid = \"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\";\n",
1682 uuid[0], uuid[1], uuid[2], uuid[3],
1683 uuid[4], uuid[5], uuid[6], uuid[7],
1684 uuid[8], uuid[9], uuid[10], uuid[11],
1685 uuid[12], uuid[13], uuid[14], uuid[15]);
1686 }
1687
bc37ae52 1688 g_string_append_printf(context->string, "\tbyte_order = %s;\n",
dc3fffef 1689 get_byte_order_string(trace->native_byte_order));
bc37ae52 1690
e011d2c1
PP
1691 if (trace->packet_header_type) {
1692 g_string_append(context->string, "\tpacket.header := ");
1693 context->current_indentation_level++;
1694 g_string_assign(context->field_name, "");
95c09b3a 1695 BT_LOGD_STR("Serializing trace's packet header field type's metadata.");
e011d2c1
PP
1696 ret = bt_ctf_field_type_serialize(trace->packet_header_type,
1697 context);
1698 if (ret) {
1699 goto end;
1700 }
1701 context->current_indentation_level--;
bc37ae52 1702 }
bc37ae52
JG
1703
1704 g_string_append(context->string, ";\n};\n\n");
1705end:
1706 return ret;
1707}
1708
bc37ae52
JG
1709static
1710void append_env_metadata(struct bt_ctf_trace *trace,
1711 struct metadata_context *context)
1712{
544d0515
PP
1713 int64_t i;
1714 int64_t env_size;
7f800dc7
PP
1715
1716 env_size = bt_ctf_attributes_get_count(trace->environment);
7f800dc7 1717 if (env_size <= 0) {
bc37ae52
JG
1718 return;
1719 }
1720
1721 g_string_append(context->string, "env {\n");
7f800dc7 1722
6474e016 1723 for (i = 0; i < env_size; i++) {
dac5c838 1724 struct bt_value *env_field_value_obj = NULL;
7f800dc7 1725 const char *entry_name;
7f800dc7
PP
1726
1727 entry_name = bt_ctf_attributes_get_field_name(
1728 trace->environment, i);
1729 env_field_value_obj = bt_ctf_attributes_get_field_value(
1730 trace->environment, i);
1731
95c09b3a
PP
1732 assert(entry_name);
1733 assert(env_field_value_obj);
7f800dc7 1734
dac5c838
PP
1735 switch (bt_value_get_type(env_field_value_obj)) {
1736 case BT_VALUE_TYPE_INTEGER:
b8248cc0
PP
1737 {
1738 int ret;
1739 int64_t int_value;
1740
dac5c838 1741 ret = bt_value_integer_get(env_field_value_obj,
7f800dc7 1742 &int_value);
95c09b3a 1743 assert(ret == 0);
7f800dc7
PP
1744 g_string_append_printf(context->string,
1745 "\t%s = %" PRId64 ";\n", entry_name,
1746 int_value);
1747 break;
b8248cc0 1748 }
dac5c838 1749 case BT_VALUE_TYPE_STRING:
7f800dc7
PP
1750 {
1751 int ret;
1752 const char *str_value;
1753 char *escaped_str = NULL;
1754
dac5c838 1755 ret = bt_value_string_get(env_field_value_obj,
7f800dc7 1756 &str_value);
95c09b3a 1757 assert(ret == 0);
7f800dc7 1758 escaped_str = g_strescape(str_value, NULL);
7f800dc7 1759 if (!escaped_str) {
95c09b3a
PP
1760 BT_LOGE("Cannot escape string: string=\"%s\"",
1761 str_value);
7f800dc7
PP
1762 goto loop_next;
1763 }
1764
1765 g_string_append_printf(context->string,
1766 "\t%s = \"%s\";\n", entry_name, escaped_str);
1767 free(escaped_str);
1768 break;
1769 }
7f800dc7
PP
1770 default:
1771 goto loop_next;
1772 }
1773
1774loop_next:
83509119 1775 BT_PUT(env_field_value_obj);
7f800dc7
PP
1776 }
1777
bc37ae52
JG
1778 g_string_append(context->string, "};\n\n");
1779}
1780
1781char *bt_ctf_trace_get_metadata_string(struct bt_ctf_trace *trace)
1782{
1783 char *metadata = NULL;
1784 struct metadata_context *context = NULL;
1785 int err = 0;
1786 size_t i;
1787
1788 if (!trace) {
95c09b3a 1789 BT_LOGW_STR("Invalid parameter: trace is NULL.");
bc37ae52
JG
1790 goto end;
1791 }
1792
1793 context = g_new0(struct metadata_context, 1);
1794 if (!context) {
95c09b3a 1795 BT_LOGE_STR("Failed to allocate one metadata context.");
bc37ae52
JG
1796 goto end;
1797 }
1798
1799 context->field_name = g_string_sized_new(DEFAULT_IDENTIFIER_SIZE);
1800 context->string = g_string_sized_new(DEFAULT_METADATA_STRING_SIZE);
1801 g_string_append(context->string, "/* CTF 1.8 */\n\n");
1802 if (append_trace_metadata(trace, context)) {
95c09b3a 1803 /* append_trace_metadata() logs errors */
bc37ae52
JG
1804 goto error;
1805 }
1806 append_env_metadata(trace, context);
1807 g_ptr_array_foreach(trace->clocks,
ac0c6bdd 1808 (GFunc)bt_ctf_clock_class_serialize, context);
bc37ae52
JG
1809
1810 for (i = 0; i < trace->stream_classes->len; i++) {
95c09b3a 1811 /* bt_ctf_stream_class_serialize() logs details */
bc37ae52
JG
1812 err = bt_ctf_stream_class_serialize(
1813 trace->stream_classes->pdata[i], context);
1814 if (err) {
95c09b3a 1815 /* bt_ctf_stream_class_serialize() logs errors */
bc37ae52
JG
1816 goto error;
1817 }
1818 }
1819
1820 metadata = context->string->str;
95c09b3a 1821
bc37ae52
JG
1822error:
1823 g_string_free(context->string, err ? TRUE : FALSE);
1824 g_string_free(context->field_name, TRUE);
1825 g_free(context);
95c09b3a 1826
bc37ae52
JG
1827end:
1828 return metadata;
1829}
1830
8a716c8d
PP
1831enum bt_ctf_byte_order bt_ctf_trace_get_native_byte_order(
1832 struct bt_ctf_trace *trace)
4ed90fb3
JG
1833{
1834 enum bt_ctf_byte_order ret = BT_CTF_BYTE_ORDER_UNKNOWN;
1835
1836 if (!trace) {
95c09b3a 1837 BT_LOGW_STR("Invalid parameter: trace is NULL.");
4ed90fb3
JG
1838 goto end;
1839 }
1840
dc3fffef
PP
1841 ret = trace->native_byte_order;
1842
4ed90fb3
JG
1843end:
1844 return ret;
1845}
1846
391c8f0d 1847int bt_ctf_trace_set_native_byte_order(struct bt_ctf_trace *trace,
bc37ae52
JG
1848 enum bt_ctf_byte_order byte_order)
1849{
1850 int ret = 0;
bc37ae52 1851
95c09b3a
PP
1852 if (!trace) {
1853 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1854 ret = -1;
1855 goto end;
1856 }
1857
1858 if (trace->frozen) {
1859 BT_LOGW("Invalid parameter: trace is frozen: "
1860 "addr=%p, name=\"%s\"",
1861 trace, bt_ctf_trace_get_name(trace));
bc37ae52
JG
1862 ret = -1;
1863 goto end;
1864 }
1865
dc3fffef
PP
1866 if (byte_order != BT_CTF_BYTE_ORDER_LITTLE_ENDIAN &&
1867 byte_order != BT_CTF_BYTE_ORDER_BIG_ENDIAN &&
1868 byte_order != BT_CTF_BYTE_ORDER_NETWORK) {
95c09b3a
PP
1869 BT_LOGW("Invalid parameter: invalid byte order: "
1870 "addr=%p, name=\"%s\", bo=%s",
1871 trace, bt_ctf_trace_get_name(trace),
1872 bt_ctf_byte_order_string(byte_order));
bc37ae52
JG
1873 ret = -1;
1874 goto end;
1875 }
1876
dc3fffef 1877 trace->native_byte_order = byte_order;
95c09b3a
PP
1878 BT_LOGV("Set trace's native byte order: "
1879 "addr=%p, name=\"%s\", bo=%s",
1880 trace, bt_ctf_trace_get_name(trace),
1881 bt_ctf_byte_order_string(byte_order));
dc3fffef 1882
bc37ae52
JG
1883end:
1884 return ret;
1885}
1886
d246b111
JG
1887struct bt_ctf_field_type *bt_ctf_trace_get_packet_header_type(
1888 struct bt_ctf_trace *trace)
1889{
1890 struct bt_ctf_field_type *field_type = NULL;
1891
1892 if (!trace) {
95c09b3a 1893 BT_LOGW_STR("Invalid parameter: trace is NULL.");
d246b111
JG
1894 goto end;
1895 }
1896
83509119 1897 bt_get(trace->packet_header_type);
d246b111
JG
1898 field_type = trace->packet_header_type;
1899end:
1900 return field_type;
1901}
1902
1903int bt_ctf_trace_set_packet_header_type(struct bt_ctf_trace *trace,
1904 struct bt_ctf_field_type *packet_header_type)
1905{
1906 int ret = 0;
1907
95c09b3a
PP
1908 if (!trace) {
1909 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1910 ret = -1;
1911 goto end;
1912 }
1913
1914 if (trace->frozen) {
1915 BT_LOGW("Invalid parameter: trace is frozen: "
1916 "addr=%p, name=\"%s\"",
1917 trace, bt_ctf_trace_get_name(trace));
d246b111
JG
1918 ret = -1;
1919 goto end;
1920 }
1921
835b2d10
JG
1922 /* packet_header_type must be a structure. */
1923 if (packet_header_type &&
95c09b3a
PP
1924 !bt_ctf_field_type_is_structure(packet_header_type)) {
1925 BT_LOGW("Invalid parameter: packet header field type must be a structure field type if it exists: "
1926 "addr=%p, name=\"%s\", ft-addr=%p, ft-id=%s",
1927 trace, bt_ctf_trace_get_name(trace),
1928 packet_header_type,
1929 bt_ctf_field_type_id_string(packet_header_type->id));
d246b111
JG
1930 ret = -1;
1931 goto end;
1932 }
1933
83509119 1934 bt_put(trace->packet_header_type);
835b2d10 1935 trace->packet_header_type = bt_get(packet_header_type);
95c09b3a
PP
1936 BT_LOGV("Set trace's packet header field type: "
1937 "addr=%p, name=\"%s\", packet-context-ft-addr=%p",
1938 trace, bt_ctf_trace_get_name(trace), packet_header_type);
d246b111
JG
1939end:
1940 return ret;
1941}
1942
8bf65fbd 1943static
544d0515 1944int64_t get_stream_class_count(void *element)
8bf65fbd
JG
1945{
1946 return bt_ctf_trace_get_stream_class_count(
1947 (struct bt_ctf_trace *) element);
1948}
1949
1950static
1951void *get_stream_class(void *element, int i)
1952{
9ac68eb1 1953 return bt_ctf_trace_get_stream_class_by_index(
8bf65fbd
JG
1954 (struct bt_ctf_trace *) element, i);
1955}
1956
1957static
d9a13d86 1958int visit_stream_class(void *object, bt_ctf_visitor visitor,void *data)
8bf65fbd 1959{
d9a13d86 1960 return bt_ctf_stream_class_visit(object, visitor, data);
8bf65fbd
JG
1961}
1962
1963int bt_ctf_trace_visit(struct bt_ctf_trace *trace,
d9a13d86 1964 bt_ctf_visitor visitor, void *data)
8bf65fbd
JG
1965{
1966 int ret;
d9a13d86
PP
1967 struct bt_ctf_object obj =
1968 { .object = trace, .type = BT_CTF_OBJECT_TYPE_TRACE };
8bf65fbd 1969
95c09b3a
PP
1970 if (!trace) {
1971 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1972 ret = -1;
1973 goto end;
1974 }
1975
1976 if (!visitor) {
1977 BT_LOGW_STR("Invalid parameter: visitor is NULL.");
8bf65fbd
JG
1978 ret = -1;
1979 goto end;
1980 }
1981
95c09b3a
PP
1982 BT_LOGV("Visiting trace: addr=%p, name=\"%s\"",
1983 trace, bt_ctf_trace_get_name(trace));
d9a13d86 1984 ret = visitor_helper(&obj, get_stream_class_count,
8bf65fbd
JG
1985 get_stream_class, visit_stream_class, visitor, data);
1986end:
1987 return ret;
1988}
1989
1990static
d9a13d86 1991int invoke_listener(struct bt_ctf_object *object, void *data)
8bf65fbd 1992{
9b888ff3 1993 struct listener_wrapper *listener_wrapper = data;
8bf65fbd 1994
d9a13d86 1995 listener_wrapper->listener(object, listener_wrapper->data);
9b888ff3 1996 return 0;
8bf65fbd
JG
1997}
1998
95c09b3a 1999// TODO: add logging to this function once we use it internally.
50ad4244
JG
2000int bt_ctf_trace_add_listener(struct bt_ctf_trace *trace,
2001 bt_ctf_listener_cb listener, void *listener_data)
2204c381
JG
2002{
2003 int ret = 0;
50ad4244
JG
2004 struct listener_wrapper *listener_wrapper =
2005 g_new0(struct listener_wrapper, 1);
2204c381 2006
50ad4244 2007 if (!trace || !listener || !listener_wrapper) {
2204c381
JG
2008 ret = -1;
2009 goto error;
2010 }
2011
50ad4244
JG
2012 listener_wrapper->listener = listener;
2013 listener_wrapper->data = listener_data;
8bf65fbd 2014
50ad4244 2015 /* Visit the current schema. */
9b888ff3 2016 ret = bt_ctf_trace_visit(trace, invoke_listener, listener_wrapper);
8bf65fbd
JG
2017 if (ret) {
2018 goto error;
2019 }
2020
50ad4244
JG
2021 /*
2022 * Add listener to the array of callbacks which will be invoked on
2023 * schema changes.
2024 */
2025 g_ptr_array_add(trace->listeners, listener_wrapper);
2204c381
JG
2026 return ret;
2027error:
50ad4244 2028 g_free(listener_wrapper);
2204c381
JG
2029 return ret;
2030}
2031
bc37ae52 2032BT_HIDDEN
d9a13d86 2033int bt_ctf_trace_object_modification(struct bt_ctf_object *object,
9b888ff3
JG
2034 void *trace_ptr)
2035{
2036 size_t i;
2037 struct bt_ctf_trace *trace = trace_ptr;
2038
2039 assert(trace);
d9a13d86 2040 assert(object);
9b888ff3
JG
2041
2042 if (trace->listeners->len == 0) {
2043 goto end;
2044 }
2045
2046 for (i = 0; i < trace->listeners->len; i++) {
2047 struct listener_wrapper *listener =
2048 g_ptr_array_index(trace->listeners, i);
2049
d9a13d86 2050 listener->listener(object, listener->data);
9b888ff3
JG
2051 }
2052end:
2053 return 0;
2054}
2055
2056BT_HIDDEN
bc37ae52
JG
2057struct bt_ctf_field_type *get_field_type(enum field_type_alias alias)
2058{
a25e0d14 2059 int ret;
bc37ae52 2060 unsigned int alignment, size;
8bdcb82e 2061 struct bt_ctf_field_type *field_type = NULL;
bc37ae52
JG
2062
2063 if (alias >= NR_FIELD_TYPE_ALIAS) {
8bdcb82e 2064 goto end;
bc37ae52
JG
2065 }
2066
2067 alignment = field_type_aliases_alignments[alias];
2068 size = field_type_aliases_sizes[alias];
2069 field_type = bt_ctf_field_type_integer_create(size);
a25e0d14
JG
2070 ret = bt_ctf_field_type_set_alignment(field_type, alignment);
2071 if (ret) {
2072 BT_PUT(field_type);
2073 }
8bdcb82e 2074end:
bc37ae52
JG
2075 return field_type;
2076}
2077
f67f3a6e 2078static
09840de5 2079void bt_ctf_trace_freeze(struct bt_ctf_trace *trace)
f67f3a6e 2080{
6474e016
PP
2081 int i;
2082
95c09b3a
PP
2083 if (trace->frozen) {
2084 return;
2085 }
2086
2087 BT_LOGD("Freezing trace: addr=%p, name=\"%s\"",
2088 trace, bt_ctf_trace_get_name(trace));
2089 BT_LOGD_STR("Freezing packet header field type.");
09840de5 2090 bt_ctf_field_type_freeze(trace->packet_header_type);
95c09b3a 2091 BT_LOGD_STR("Freezing environment attributes.");
f67f3a6e 2092 bt_ctf_attributes_freeze(trace->environment);
6474e016 2093
95c09b3a
PP
2094 if (trace->clocks->len > 0) {
2095 BT_LOGD_STR("Freezing clock classes.");
2096 }
2097
6474e016 2098 for (i = 0; i < trace->clocks->len; i++) {
ac0c6bdd 2099 struct bt_ctf_clock_class *clock_class =
6474e016
PP
2100 g_ptr_array_index(trace->clocks, i);
2101
ac0c6bdd 2102 bt_ctf_clock_class_freeze(clock_class);
6474e016
PP
2103 }
2104
f67f3a6e
JG
2105 trace->frozen = 1;
2106}
2107
c55a9f58 2108bt_bool bt_ctf_trace_is_static(struct bt_ctf_trace *trace)
5acf2ae6 2109{
c55a9f58 2110 bt_bool is_static = BT_FALSE;
5acf2ae6
PP
2111
2112 if (!trace) {
95c09b3a 2113 BT_LOGW_STR("Invalid parameter: trace is NULL.");
5acf2ae6
PP
2114 goto end;
2115 }
2116
2117 is_static = trace->is_static;
2118
2119end:
2120 return is_static;
2121}
2122
2123int bt_ctf_trace_set_is_static(struct bt_ctf_trace *trace)
2124{
2125 int ret = 0;
3602afb0 2126 size_t i;
5acf2ae6
PP
2127
2128 if (!trace) {
95c09b3a 2129 BT_LOGW_STR("Invalid parameter: trace is NULL.");
5acf2ae6
PP
2130 ret = -1;
2131 goto end;
2132 }
2133
c55a9f58 2134 trace->is_static = BT_TRUE;
5acf2ae6 2135 bt_ctf_trace_freeze(trace);
95c09b3a
PP
2136 BT_LOGV("Set trace static: addr=%p, name=\"%s\"",
2137 trace, bt_ctf_trace_get_name(trace));
5acf2ae6 2138
3602afb0
PP
2139 /* Call all the "trace is static" listeners */
2140 for (i = 0; i < trace->is_static_listeners->len; i++) {
2141 struct bt_ctf_trace_is_static_listener_elem elem =
2142 g_array_index(trace->is_static_listeners,
2143 struct bt_ctf_trace_is_static_listener_elem, i);
2144
2145 if (elem.func) {
2146 elem.func(trace, elem.data);
2147 }
2148 }
2149
2150end:
2151 return ret;
2152}
2153
2154int bt_ctf_trace_add_is_static_listener(struct bt_ctf_trace *trace,
2155 bt_ctf_trace_is_static_listener listener, void *data)
2156{
2157 int i;
2158 struct bt_ctf_trace_is_static_listener_elem new_elem = {
2159 .func = listener,
2160 .data = data,
2161 };
2162
2163 if (!trace) {
2164 BT_LOGW_STR("Invalid parameter: trace is NULL.");
2165 i = -1;
2166 goto end;
2167 }
2168
2169 if (!listener) {
2170 BT_LOGW_STR("Invalid parameter: listener is NULL.");
2171 i = -1;
2172 goto end;
2173 }
2174
2175 if (trace->is_static) {
2176 BT_LOGW("Invalid parameter: trace is already static: "
2177 "addr=%p, name=\"%s\"",
2178 trace, bt_ctf_trace_get_name(trace));
2179 i = -1;
2180 goto end;
2181 }
2182
2183 /* Find the next available spot */
2184 for (i = 0; i < trace->is_static_listeners->len; i++) {
2185 struct bt_ctf_trace_is_static_listener_elem elem =
2186 g_array_index(trace->is_static_listeners,
2187 struct bt_ctf_trace_is_static_listener_elem, i);
2188
2189 if (!elem.func) {
2190 break;
2191 }
2192 }
2193
2194 if (i == trace->is_static_listeners->len) {
2195 g_array_append_val(trace->is_static_listeners, new_elem);
2196 } else {
2197 g_array_insert_val(trace->is_static_listeners, i, new_elem);
2198 }
2199
2200 BT_LOGV("Added \"trace is static\" listener: "
2201 "trace-addr=%p, trace-name=\"%s\", func-addr=%p, "
2202 "data-addr=%p, listener-id=%d",
2203 trace, bt_ctf_trace_get_name(trace), listener, data, i);
2204
2205end:
2206 return i;
2207}
2208
2209int bt_ctf_trace_remove_is_static_listener(
2210 struct bt_ctf_trace *trace, int listener_id)
2211{
2212 int ret = 0;
2213 struct bt_ctf_trace_is_static_listener_elem *elem;
2214
2215 if (!trace) {
2216 BT_LOGW_STR("Invalid parameter: trace is NULL.");
2217 ret = -1;
2218 goto end;
2219 }
2220
2221 if (listener_id < 0) {
2222 BT_LOGW("Invalid listener ID: must be zero or positive: "
2223 "listener-id=%d", listener_id);
2224 ret = -1;
2225 goto end;
2226 }
2227
2228 if (listener_id >= trace->is_static_listeners->len) {
2229 BT_LOGW("Invalid parameter: no listener with this listener ID: "
2230 "addr=%p, name=\"%s\", listener-id=%d",
2231 trace, bt_ctf_trace_get_name(trace),
2232 listener_id);
2233 ret = -1;
2234 goto end;
2235 }
2236
2237 elem = &g_array_index(trace->is_static_listeners,
2238 struct bt_ctf_trace_is_static_listener_elem,
2239 listener_id);
2240 if (!elem->func) {
2241 BT_LOGW("Invalid parameter: no listener with this listener ID: "
2242 "addr=%p, name=\"%s\", listener-id=%d",
2243 trace, bt_ctf_trace_get_name(trace),
2244 listener_id);
2245 ret = -1;
2246 goto end;
2247 }
2248
2249 elem->func = NULL;
2250 elem->data = NULL;
2251 BT_LOGV("Removed \"trace is static\" listener: "
2252 "trace-addr=%p, trace-name=\"%s\", "
2253 "listener-id=%d", trace, bt_ctf_trace_get_name(trace),
2254 listener_id);
2255
5acf2ae6
PP
2256end:
2257 return ret;
2258}
This page took 0.140988 seconds and 4 git commands to generate.