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