src.ctf.fs: move internal util to ctf/common/utils
[babeltrace.git] / plugins / ctf / common / notif-iter / notif-iter.c
CommitLineData
e98a2d6e
PP
1/*
2 * Babeltrace - CTF notification iterator
06a626b8 3 *
e98a2d6e
PP
4 * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation
5 * Copyright (c) 2015-2016 Philippe Proulx <pproulx@efficios.com>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 */
25
fdf0e7a0
PP
26#define BT_LOG_TAG "PLUGIN-CTF-NOTIF-ITER"
27#include "logging.h"
28
e98a2d6e
PP
29#include <stdint.h>
30#include <inttypes.h>
31#include <stdio.h>
32#include <stddef.h>
33#include <stdbool.h>
34#include <assert.h>
35#include <string.h>
36#include <babeltrace/ctf-ir/field-types.h>
fdf0e7a0 37#include <babeltrace/ctf-ir/field-types-internal.h>
e98a2d6e 38#include <babeltrace/ctf-ir/field-path.h>
fdf0e7a0 39#include <babeltrace/ctf-ir/field-path-internal.h>
e98a2d6e
PP
40#include <babeltrace/ctf-ir/fields.h>
41#include <babeltrace/ctf-ir/stream-class.h>
42#include <babeltrace/ctf-ir/packet.h>
43#include <babeltrace/ctf-ir/stream.h>
ac0c6bdd 44#include <babeltrace/ctf-ir/clock-class.h>
e98a2d6e 45#include <babeltrace/ctf-ir/event-class.h>
b2e0c907
PP
46#include <babeltrace/graph/notification-packet.h>
47#include <babeltrace/graph/notification-event.h>
48#include <babeltrace/graph/notification-stream.h>
599faa1c 49#include <babeltrace/graph/clock-class-priority-map.h>
e98a2d6e
PP
50#include <babeltrace/ref.h>
51#include <glib.h>
0fbb9a9f 52#include <stdlib.h>
e98a2d6e 53
06a626b8
JG
54#include "notif-iter.h"
55#include "../btr/btr.h"
e98a2d6e 56
e98a2d6e
PP
57struct bt_ctf_notif_iter;
58
59/* A visit stack entry */
60struct stack_entry {
61 /*
62 * Current base field, one of:
63 *
64 * * string
65 * * structure
66 * * array
67 * * sequence
68 * * variant
69 *
70 * Field is owned by this.
71 */
72 struct bt_ctf_field *base;
73
74 /* index of next field to set */
75 size_t index;
76};
77
78/* Visit stack */
79struct stack {
80 /* Entries (struct stack_entry *) (top is last element) */
81 GPtrArray *entries;
e98a2d6e
PP
82};
83
84/* State */
85enum state {
86 STATE_INIT,
87 STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN,
88 STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE,
89 STATE_AFTER_TRACE_PACKET_HEADER,
90 STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN,
91 STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE,
92 STATE_AFTER_STREAM_PACKET_CONTEXT,
93 STATE_EMIT_NOTIF_NEW_PACKET,
94 STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN,
95 STATE_DSCOPE_STREAM_EVENT_HEADER_CONTINUE,
96 STATE_AFTER_STREAM_EVENT_HEADER,
97 STATE_DSCOPE_STREAM_EVENT_CONTEXT_BEGIN,
98 STATE_DSCOPE_STREAM_EVENT_CONTEXT_CONTINUE,
99 STATE_DSCOPE_EVENT_CONTEXT_BEGIN,
100 STATE_DSCOPE_EVENT_CONTEXT_CONTINUE,
101 STATE_DSCOPE_EVENT_PAYLOAD_BEGIN,
102 STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE,
103 STATE_EMIT_NOTIF_EVENT,
104 STATE_EMIT_NOTIF_END_OF_PACKET,
105 STATE_SKIP_PACKET_PADDING,
106};
107
5f870343
JG
108struct trace_field_path_cache {
109 /*
110 * Indexes of the stream_id and stream_instance_id field in the packet
111 * header structure, -1 if unset.
112 */
113 int stream_id;
114 int stream_instance_id;
115};
116
117struct stream_class_field_path_cache {
118 /*
119 * Indexes of the v and id fields in the stream event header structure,
120 * -1 if unset.
121 */
122 int v;
123 int id;
124
125 /*
126 * index of the timestamp_end, packet_size and content_size fields in
127 * the stream packet context structure. Set to -1 if the fields were
128 * not found.
129 */
130 int timestamp_end;
131 int packet_size;
132 int content_size;
133};
134
135struct field_cb_override {
136 enum bt_ctf_btr_status (* func)(void *value,
137 struct bt_ctf_field_type *type, void *data);
138 void *data;
139};
140
e98a2d6e
PP
141/* CTF notification iterator */
142struct bt_ctf_notif_iter {
143 /* Visit stack */
144 struct stack *stack;
145
e98a2d6e
PP
146 /*
147 * Current dynamic scope field pointer.
148 *
149 * This is set when a dynamic scope field is first created by
150 * btr_compound_begin_cb(). It points to one of the fields in
151 * dscopes below.
152 */
153 struct bt_ctf_field **cur_dscope_field;
154
155 /* Trace and classes (owned by this) */
156 struct {
157 struct bt_ctf_trace *trace;
158 struct bt_ctf_stream_class *stream_class;
159 struct bt_ctf_event_class *event_class;
160 } meta;
161
162 /* Current packet (NULL if not created yet) */
163 struct bt_ctf_packet *packet;
164
af87daef
PP
165 /* Current stream (NULL if not set yet) */
166 struct bt_ctf_stream *stream;
167
5f870343
JG
168 /*
169 * Current timestamp_end field (to consider before switching packets).
170 */
171 struct bt_ctf_field *cur_timestamp_end;
172
e98a2d6e
PP
173 /* Database of current dynamic scopes (owned by this) */
174 struct {
175 struct bt_ctf_field *trace_packet_header;
176 struct bt_ctf_field *stream_packet_context;
177 struct bt_ctf_field *stream_event_header;
178 struct bt_ctf_field *stream_event_context;
179 struct bt_ctf_field *event_context;
180 struct bt_ctf_field *event_payload;
181 } dscopes;
182
5f870343
JG
183 /*
184 * Special field overrides.
185 *
186 * Overrides are used to implement the behaviours of special fields such
187 * as "timestamp_end" (which must be ignored until the end of the
188 * packet), "id" (event id) which can be present multiple times and must
189 * be updated multiple time.
190 *
191 * This should be used to implement the behaviour of integer fields
192 * mapped to clocks and other "tagged" fields (in CTF 2).
193 *
194 * bt_ctf_field_type to struct field_cb_override
195 */
196 GHashTable *field_overrides;
197
e98a2d6e
PP
198 /* Current state */
199 enum state state;
200
2cf1d51e 201 /* Current medium buffer data */
e98a2d6e
PP
202 struct {
203 /* Last address provided by medium */
204 const uint8_t *addr;
205
206 /* Buffer size provided by medium (bytes) */
207 size_t sz;
208
209 /* Offset within whole packet of addr (bits) */
210 size_t packet_offset;
211
212 /* Current position from addr (bits) */
213 size_t at;
174e773b
PP
214
215 /* Position of the last event header from addr (bits) */
216 size_t last_eh_at;
e98a2d6e
PP
217 } buf;
218
219 /* Binary type reader */
220 struct bt_ctf_btr *btr;
221
2cf1d51e 222 /* Current medium data */
e98a2d6e
PP
223 struct {
224 struct bt_ctf_notif_iter_medium_ops medops;
225 size_t max_request_sz;
226 void *data;
227 } medium;
228
229 /* Current packet size (bits) (-1 if unknown) */
e7a4393b 230 int64_t cur_packet_size;
e98a2d6e
PP
231
232 /* Current content size (bits) (-1 if unknown) */
e7a4393b 233 int64_t cur_content_size;
c44c3e70 234
ac0c6bdd 235 /* bt_ctf_clock_class to uint64_t. */
c44c3e70 236 GHashTable *clock_states;
5f870343
JG
237
238 /*
239 * Cache of the trace-constant field paths (event header type)
240 * associated to the current trace.
241 */
242 struct trace_field_path_cache trace_field_path_cache;
243
244 /*
245 * Field path cache associated with the current stream class.
246 * Ownership of this structure belongs to the field_path_caches HT.
247 */
248 struct stream_class_field_path_cache *cur_sc_field_path_cache;
249
250 /* bt_ctf_stream_class to struct stream_class_field_path_cache. */
251 GHashTable *sc_field_path_caches;
e98a2d6e
PP
252};
253
fdf0e7a0
PP
254static inline
255const char *state_string(enum state state)
256{
257 switch (state) {
258 case STATE_INIT:
259 return "STATE_INIT";
260 case STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN:
261 return "STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN";
262 case STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE:
263 return "STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE";
264 case STATE_AFTER_TRACE_PACKET_HEADER:
265 return "STATE_AFTER_TRACE_PACKET_HEADER";
266 case STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN:
267 return "STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN";
268 case STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE:
269 return "STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE";
270 case STATE_AFTER_STREAM_PACKET_CONTEXT:
271 return "STATE_AFTER_STREAM_PACKET_CONTEXT";
272 case STATE_EMIT_NOTIF_NEW_PACKET:
273 return "STATE_EMIT_NOTIF_NEW_PACKET";
274 case STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN:
275 return "STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN";
276 case STATE_DSCOPE_STREAM_EVENT_HEADER_CONTINUE:
277 return "STATE_DSCOPE_STREAM_EVENT_HEADER_CONTINUE";
278 case STATE_AFTER_STREAM_EVENT_HEADER:
279 return "STATE_AFTER_STREAM_EVENT_HEADER";
280 case STATE_DSCOPE_STREAM_EVENT_CONTEXT_BEGIN:
281 return "STATE_DSCOPE_STREAM_EVENT_CONTEXT_BEGIN";
282 case STATE_DSCOPE_STREAM_EVENT_CONTEXT_CONTINUE:
283 return "STATE_DSCOPE_STREAM_EVENT_CONTEXT_CONTINUE";
284 case STATE_DSCOPE_EVENT_CONTEXT_BEGIN:
285 return "STATE_DSCOPE_EVENT_CONTEXT_BEGIN";
286 case STATE_DSCOPE_EVENT_CONTEXT_CONTINUE:
287 return "STATE_DSCOPE_EVENT_CONTEXT_CONTINUE";
288 case STATE_DSCOPE_EVENT_PAYLOAD_BEGIN:
289 return "STATE_DSCOPE_EVENT_PAYLOAD_BEGIN";
290 case STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE:
291 return "STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE";
292 case STATE_EMIT_NOTIF_EVENT:
293 return "STATE_EMIT_NOTIF_EVENT";
294 case STATE_EMIT_NOTIF_END_OF_PACKET:
295 return "STATE_EMIT_NOTIF_END_OF_PACKET";
296 case STATE_SKIP_PACKET_PADDING:
297 return "STATE_SKIP_PACKET_PADDING";
298 default:
299 return "(unknown)";
300 }
301}
302
2cf1d51e
JG
303static
304int bt_ctf_notif_iter_switch_packet(struct bt_ctf_notif_iter *notit);
305
5f870343
JG
306static
307enum bt_ctf_btr_status btr_timestamp_end_cb(void *value,
308 struct bt_ctf_field_type *type, void *data);
309
e98a2d6e
PP
310static
311void stack_entry_free_func(gpointer data)
312{
313 struct stack_entry *entry = data;
314
315 bt_put(entry->base);
316 g_free(entry);
317}
318
319static
320struct stack *stack_new(struct bt_ctf_notif_iter *notit)
321{
322 struct stack *stack = NULL;
323
324 stack = g_new0(struct stack, 1);
325 if (!stack) {
fdf0e7a0 326 BT_LOGE_STR("Failed to allocate one stack.");
e98a2d6e
PP
327 goto error;
328 }
329
330 stack->entries = g_ptr_array_new_with_free_func(stack_entry_free_func);
331 if (!stack->entries) {
fdf0e7a0 332 BT_LOGE_STR("Failed to allocate a GPtrArray.");
e98a2d6e
PP
333 goto error;
334 }
335
fdf0e7a0 336 BT_LOGD("Created stack: notit-addr=%p, stack-addr=%p", notit, stack);
e98a2d6e 337 return stack;
fdf0e7a0 338
e98a2d6e
PP
339error:
340 g_free(stack);
e98a2d6e
PP
341 return NULL;
342}
343
344static
345void stack_destroy(struct stack *stack)
346{
347 assert(stack);
fdf0e7a0 348 BT_LOGD("Destroying stack: addr=%p", stack);
e98a2d6e
PP
349 g_ptr_array_free(stack->entries, TRUE);
350 g_free(stack);
351}
352
353static
354int stack_push(struct stack *stack, struct bt_ctf_field *base)
355{
356 int ret = 0;
357 struct stack_entry *entry;
e98a2d6e
PP
358
359 assert(stack);
360 assert(base);
fdf0e7a0
PP
361 BT_LOGV("Pushing base field on stack: stack-addr=%p, "
362 "stack-size-before=%u, stack-size-after=%u",
363 stack, stack->entries->len, stack->entries->len + 1);
e98a2d6e
PP
364 entry = g_new0(struct stack_entry, 1);
365 if (!entry) {
fdf0e7a0 366 BT_LOGE_STR("Failed to allocate one stack entry.");
e98a2d6e
PP
367 ret = -1;
368 goto end;
369 }
370
371 entry->base = bt_get(base);
372 g_ptr_array_add(stack->entries, entry);
373
374end:
375 return ret;
376}
377
378static inline
379unsigned int stack_size(struct stack *stack)
380{
381 assert(stack);
382
383 return stack->entries->len;
384}
385
386static
387void stack_pop(struct stack *stack)
388{
389 assert(stack);
390 assert(stack_size(stack));
fdf0e7a0
PP
391 BT_LOGV("Popping from stack: "
392 "stack-addr=%p, stack-size-before=%u, stack-size-after=%u",
393 stack, stack->entries->len, stack->entries->len - 1);
e98a2d6e
PP
394 g_ptr_array_remove_index(stack->entries, stack->entries->len - 1);
395}
396
397static inline
398struct stack_entry *stack_top(struct stack *stack)
399{
400 assert(stack);
401 assert(stack_size(stack));
402
403 return g_ptr_array_index(stack->entries, stack->entries->len - 1);
404}
405
406static inline
407bool stack_empty(struct stack *stack)
408{
409 return stack_size(stack) == 0;
410}
411
412static
413void stack_clear(struct stack *stack)
414{
415 assert(stack);
416
417 if (!stack_empty(stack)) {
fdf0e7a0
PP
418 BT_LOGV("Clearing stack: stack-addr=%p, stack-size=%u",
419 stack, stack->entries->len);
e98a2d6e
PP
420 g_ptr_array_remove_range(stack->entries, 0, stack_size(stack));
421 }
422
423 assert(stack_empty(stack));
424}
425
426static inline
427enum bt_ctf_notif_iter_status notif_iter_status_from_m_status(
428 enum bt_ctf_notif_iter_medium_status m_status)
429{
dc77b521 430 return (int) m_status;
e98a2d6e
PP
431}
432
433static inline
434size_t buf_size_bits(struct bt_ctf_notif_iter *notit)
435{
fdf0e7a0 436 return notit->buf.sz * 8;
e98a2d6e
PP
437}
438
439static inline
440size_t buf_available_bits(struct bt_ctf_notif_iter *notit)
441{
442 return buf_size_bits(notit) - notit->buf.at;
443}
444
445static inline
446size_t packet_at(struct bt_ctf_notif_iter *notit)
447{
448 return notit->buf.packet_offset + notit->buf.at;
449}
450
e98a2d6e
PP
451static inline
452void buf_consume_bits(struct bt_ctf_notif_iter *notit, size_t incr)
453{
fdf0e7a0
PP
454 BT_LOGV("Advancing cursor: notit-addr=%p, cur-before=%zu, cur-after=%zu",
455 notit, notit->buf.at, notit->buf.at + incr);
e98a2d6e
PP
456 notit->buf.at += incr;
457}
458
e98a2d6e 459static
2cf1d51e
JG
460enum bt_ctf_notif_iter_status request_medium_bytes(
461 struct bt_ctf_notif_iter *notit)
e98a2d6e 462{
fdf0e7a0
PP
463 uint8_t *buffer_addr = NULL;
464 size_t buffer_sz = 0;
e98a2d6e
PP
465 enum bt_ctf_notif_iter_medium_status m_status;
466
fdf0e7a0
PP
467 BT_LOGV("Calling user function (request bytes): notit-addr=%p, "
468 "request-size=%zu", notit, notit->medium.max_request_sz);
e98a2d6e
PP
469 m_status = notit->medium.medops.request_bytes(
470 notit->medium.max_request_sz, &buffer_addr,
471 &buffer_sz, notit->medium.data);
fdf0e7a0
PP
472 BT_LOGV("User function returned: status=%s, buf-addr=%p, buf-size=%zu",
473 bt_ctf_notif_iter_medium_status_string(m_status),
474 buffer_addr, buffer_sz);
e98a2d6e
PP
475 if (m_status == BT_CTF_NOTIF_ITER_MEDIUM_STATUS_OK) {
476 assert(buffer_sz != 0);
477
478 /* New packet offset is old one + old size (in bits) */
479 notit->buf.packet_offset += buf_size_bits(notit);
480
481 /* Restart at the beginning of the new medium buffer */
482 notit->buf.at = 0;
2b186c3e 483 notit->buf.last_eh_at = SIZE_MAX;
e98a2d6e
PP
484
485 /* New medium buffer size */
486 notit->buf.sz = buffer_sz;
487
488 /* New medium buffer address */
489 notit->buf.addr = buffer_addr;
fdf0e7a0
PP
490
491 BT_LOGV("User function returned new bytes: "
492 "packet-offset=%zu, cur=%zu, size=%zu, addr=%p",
493 notit->buf.packet_offset, notit->buf.at,
494 notit->buf.sz, notit->buf.addr);
495 BT_LOGV_MEM(buffer_addr, buffer_sz, "Returned bytes at %p:",
496 buffer_addr);
0684124b
PP
497 } else if (m_status == BT_CTF_NOTIF_ITER_MEDIUM_STATUS_EOF) {
498 struct bt_ctf_field_type *eh_ft = NULL;
499 struct bt_ctf_field_type *sec_ft = NULL;
500 struct bt_ctf_field_type *ec_ft = NULL;
501
502 /*
503 * User returned end of stream: validate that we're not
504 * in the middle of a packet header, packet context, or
505 * event.
506 */
507 if (notit->state == STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN) {
508 /* Beginning of packet: always valid */
509 goto good_state;
510 }
511
512 if (!notit->meta.stream_class) {
513 goto bad_state;
514 }
515
516 eh_ft = bt_ctf_stream_class_get_event_header_type(
517 notit->meta.stream_class);
518 sec_ft = bt_ctf_stream_class_get_event_context_type(
519 notit->meta.stream_class);
520
521 if (notit->state == STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN) {
522 /*
523 * Beginning of event's header is only valid if
524 * the packet is not supposed to have a specific
525 * size (whole packet sequence has in fact only
526 * one packet).
527 */
528 if (notit->cur_packet_size == -1) {
529 goto good_state;
530 }
531 }
532
533 if (notit->state == STATE_DSCOPE_STREAM_EVENT_CONTEXT_BEGIN) {
534 /*
535 * Beginning of event's stream event context is
536 * only valid if the packet is not supposed to
537 * have a specific size (whole packet sequence
538 * has in fact only one packet), and there's no
539 * event header.
540 */
541 if (notit->cur_packet_size == -1 && !eh_ft) {
542 goto good_state;
543 }
544 }
545
546 if (!notit->meta.event_class) {
547 goto bad_state;
548 }
549
550 ec_ft = bt_ctf_event_class_get_context_type(
551 notit->meta.event_class);
552
553 if (notit->state == STATE_DSCOPE_EVENT_CONTEXT_BEGIN) {
554 /*
555 * Beginning of event's context is only valid if
556 * the packet is not supposed to have a specific
557 * size (whole packet sequence has in fact only
558 * one packet), and there's no event header and
559 * no stream event context.
560 */
561 if (notit->cur_packet_size == -1 && !eh_ft && !sec_ft) {
562 goto good_state;
563 }
564 }
565
566 if (notit->state == STATE_DSCOPE_EVENT_PAYLOAD_BEGIN) {
567 /*
568 * Beginning of event's context is only valid if
569 * the packet is not supposed to have a specific
570 * size (whole packet sequence has in fact only
571 * one packet), and there's no event header, no
572 * stream event context, and no event context.
573 */
574 if (notit->cur_packet_size == -1 && !eh_ft && !sec_ft &&
575 !ec_ft) {
576 goto good_state;
577 }
578 }
579
580bad_state:
581 /* All other states are invalid */
582 BT_LOGW("User function returned %s, but notification iterator is in an unexpected state: "
583 "state=%s",
584 bt_ctf_notif_iter_medium_status_string(m_status),
585 state_string(notit->state));
586 m_status = BT_CTF_NOTIF_ITER_MEDIUM_STATUS_ERROR;
587
588good_state:
589 bt_put(eh_ft);
590 bt_put(sec_ft);
591 bt_put(ec_ft);
fdf0e7a0
PP
592 } else if (m_status < 0) {
593 BT_LOGW("User function failed: status=%s",
594 bt_ctf_notif_iter_medium_status_string(m_status));
e98a2d6e
PP
595 }
596
597 return notif_iter_status_from_m_status(m_status);
598}
599
600static inline
601enum bt_ctf_notif_iter_status buf_ensure_available_bits(
602 struct bt_ctf_notif_iter *notit)
603{
604 enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
605
606 if (buf_available_bits(notit) == 0) {
607 /*
608 * This _cannot_ return BT_CTF_NOTIF_ITER_STATUS_OK
609 * _and_ no bits.
610 */
611 status = request_medium_bytes(notit);
612 }
613
614 return status;
615}
616
617static
618enum bt_ctf_notif_iter_status read_dscope_begin_state(
619 struct bt_ctf_notif_iter *notit,
620 struct bt_ctf_field_type *dscope_field_type,
621 enum state done_state, enum state continue_state,
622 struct bt_ctf_field **dscope_field)
623{
624 enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
625 enum bt_ctf_btr_status btr_status;
626 size_t consumed_bits;
627
628 status = buf_ensure_available_bits(notit);
629 if (status != BT_CTF_NOTIF_ITER_STATUS_OK) {
fdf0e7a0
PP
630 if (status < 0) {
631 BT_LOGW("Cannot ensure that buffer has at least one byte: "
632 "notif-addr=%p, status=%s",
633 notit, bt_ctf_notif_iter_status_string(status));
634 } else {
635 BT_LOGV("Cannot ensure that buffer has at least one byte: "
636 "notif-addr=%p, status=%s",
637 notit, bt_ctf_notif_iter_status_string(status));
638 }
639
e98a2d6e
PP
640 goto end;
641 }
642
643 bt_put(*dscope_field);
644 notit->cur_dscope_field = dscope_field;
fdf0e7a0
PP
645 BT_LOGV("Starting BTR: notit-addr=%p, btr-addr=%p, ft-addr=%p",
646 notit, notit->btr, dscope_field_type);
e98a2d6e
PP
647 consumed_bits = bt_ctf_btr_start(notit->btr, dscope_field_type,
648 notit->buf.addr, notit->buf.at, packet_at(notit),
649 notit->buf.sz, &btr_status);
fdf0e7a0 650 BT_LOGV("BTR consumed bits: size=%zu", consumed_bits);
e98a2d6e
PP
651
652 switch (btr_status) {
653 case BT_CTF_BTR_STATUS_OK:
654 /* type was read completely */
fdf0e7a0 655 BT_LOGV_STR("Field was completely decoded.");
e98a2d6e
PP
656 notit->state = done_state;
657 break;
658 case BT_CTF_BTR_STATUS_EOF:
fdf0e7a0 659 BT_LOGV_STR("BTR needs more data to decode field completely.");
e98a2d6e
PP
660 notit->state = continue_state;
661 break;
662 default:
fdf0e7a0
PP
663 BT_LOGW("BTR failed to start: notit-addr=%p, btr-addr=%p, "
664 "status=%s", notit, notit->btr,
665 bt_ctf_btr_status_string(btr_status));
e98a2d6e
PP
666 status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
667 goto end;
668 }
669
670 /* Consume bits now since we know we're not in an error state */
671 buf_consume_bits(notit, consumed_bits);
672
673end:
674 return status;
675}
676
677static
678enum bt_ctf_notif_iter_status read_dscope_continue_state(
679 struct bt_ctf_notif_iter *notit, enum state done_state)
680{
681 enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
682 enum bt_ctf_btr_status btr_status;
683 size_t consumed_bits;
684
685 status = buf_ensure_available_bits(notit);
686 if (status != BT_CTF_NOTIF_ITER_STATUS_OK) {
fdf0e7a0
PP
687 if (status < 0) {
688 BT_LOGW("Cannot ensure that buffer has at least one byte: "
689 "notif-addr=%p, status=%s",
690 notit, bt_ctf_notif_iter_status_string(status));
691 } else {
692 BT_LOGV("Cannot ensure that buffer has at least one byte: "
693 "notif-addr=%p, status=%s",
694 notit, bt_ctf_notif_iter_status_string(status));
695 }
696
e98a2d6e
PP
697 goto end;
698 }
699
fdf0e7a0
PP
700 BT_LOGV("Continuing BTR: notit-addr=%p, btr-addr=%p",
701 notit, notit->btr);
e98a2d6e 702 consumed_bits = bt_ctf_btr_continue(notit->btr, notit->buf.addr,
fdf0e7a0
PP
703 notit->buf.sz, &btr_status);
704 BT_LOGV("BTR consumed bits: size=%zu", consumed_bits);
e98a2d6e
PP
705
706 switch (btr_status) {
707 case BT_CTF_BTR_STATUS_OK:
78586d8a 708 /* Type was read completely. */
fdf0e7a0 709 BT_LOGV_STR("Field was completely decoded.");
e98a2d6e
PP
710 notit->state = done_state;
711 break;
712 case BT_CTF_BTR_STATUS_EOF:
78586d8a 713 /* Stay in this continue state. */
fdf0e7a0 714 BT_LOGV_STR("BTR needs more data to decode field completely.");
e98a2d6e
PP
715 break;
716 default:
fdf0e7a0
PP
717 BT_LOGW("BTR failed to continue: notit-addr=%p, btr-addr=%p, "
718 "status=%s", notit, notit->btr,
719 bt_ctf_btr_status_string(btr_status));
e98a2d6e
PP
720 status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
721 goto end;
722 }
723
78586d8a 724 /* Consume bits now since we know we're not in an error state. */
e98a2d6e 725 buf_consume_bits(notit, consumed_bits);
e98a2d6e
PP
726end:
727 return status;
728}
729
730static
731void put_event_dscopes(struct bt_ctf_notif_iter *notit)
732{
fdf0e7a0 733 BT_LOGV_STR("Putting event header field.");
e98a2d6e 734 BT_PUT(notit->dscopes.stream_event_header);
fdf0e7a0 735 BT_LOGV_STR("Putting stream event context field.");
e98a2d6e 736 BT_PUT(notit->dscopes.stream_event_context);
fdf0e7a0 737 BT_LOGV_STR("Putting event context field.");
e98a2d6e 738 BT_PUT(notit->dscopes.event_context);
fdf0e7a0 739 BT_LOGV_STR("Putting event payload field.");
e98a2d6e
PP
740 BT_PUT(notit->dscopes.event_payload);
741}
742
743static
744void put_all_dscopes(struct bt_ctf_notif_iter *notit)
745{
fdf0e7a0 746 BT_LOGV_STR("Putting packet header field.");
e98a2d6e 747 BT_PUT(notit->dscopes.trace_packet_header);
fdf0e7a0 748 BT_LOGV_STR("Putting packet context field.");
e98a2d6e
PP
749 BT_PUT(notit->dscopes.stream_packet_context);
750 put_event_dscopes(notit);
751}
752
753static
754enum bt_ctf_notif_iter_status read_packet_header_begin_state(
755 struct bt_ctf_notif_iter *notit)
756{
2cf1d51e
JG
757 struct bt_ctf_field_type *packet_header_type = NULL;
758 enum bt_ctf_notif_iter_status ret = BT_CTF_NOTIF_ITER_STATUS_OK;
e98a2d6e 759
2cf1d51e 760 if (bt_ctf_notif_iter_switch_packet(notit)) {
fdf0e7a0 761 BT_LOGW("Cannot switch packet: notit-addr=%p", notit);
2cf1d51e
JG
762 ret = BT_CTF_NOTIF_ITER_STATUS_ERROR;
763 goto end;
764 }
e98a2d6e 765
2cf1d51e 766 /* Packet header type is common to the whole trace. */
e98a2d6e 767 packet_header_type = bt_ctf_trace_get_packet_header_type(
78586d8a 768 notit->meta.trace);
e98a2d6e 769 if (!packet_header_type) {
835b2d10 770 notit->state = STATE_AFTER_TRACE_PACKET_HEADER;
e98a2d6e
PP
771 goto end;
772 }
773
fdf0e7a0
PP
774 BT_LOGV("Decoding packet header field:"
775 "notit-addr=%p, trace-addr=%p, trace-name=\"%s\", ft-addr=%p",
776 notit, notit->meta.trace,
777 bt_ctf_trace_get_name(notit->meta.trace), packet_header_type);
2cf1d51e 778 ret = read_dscope_begin_state(notit, packet_header_type,
fdf0e7a0
PP
779 STATE_AFTER_TRACE_PACKET_HEADER,
780 STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE,
781 &notit->dscopes.trace_packet_header);
782 if (ret < 0) {
783 BT_LOGW("Cannot decode packet header field: "
784 "notit-addr=%p, trace-addr=%p, "
785 "trace-name=\"%s\", ft-addr=%p",
786 notit, notit->meta.trace,
787 bt_ctf_trace_get_name(notit->meta.trace),
788 packet_header_type);
789 }
e98a2d6e
PP
790end:
791 BT_PUT(packet_header_type);
2cf1d51e 792 return ret;
e98a2d6e
PP
793}
794
795static
796enum bt_ctf_notif_iter_status read_packet_header_continue_state(
797 struct bt_ctf_notif_iter *notit)
798{
799 return read_dscope_continue_state(notit,
78586d8a 800 STATE_AFTER_TRACE_PACKET_HEADER);
e98a2d6e
PP
801}
802
803static inline
804bool is_struct_type(struct bt_ctf_field_type *field_type)
805{
78586d8a 806 return bt_ctf_field_type_get_type_id(field_type) ==
1487a16a 807 BT_CTF_FIELD_TYPE_ID_STRUCT;
e98a2d6e
PP
808}
809
810static inline
811bool is_variant_type(struct bt_ctf_field_type *field_type)
812{
78586d8a 813 return bt_ctf_field_type_get_type_id(field_type) ==
1487a16a 814 BT_CTF_FIELD_TYPE_ID_VARIANT;
e98a2d6e
PP
815}
816
5f870343
JG
817static
818struct stream_class_field_path_cache *
819create_stream_class_field_path_cache_entry(
820 struct bt_ctf_notif_iter *notit,
821 struct bt_ctf_stream_class *stream_class)
822{
823 int v = -1;
824 int id = -1;
825 int timestamp_end = -1;
826 int packet_size = -1;
827 int content_size = -1;
828 struct stream_class_field_path_cache *cache_entry = g_new0(
829 struct stream_class_field_path_cache, 1);
830 struct bt_ctf_field_type *event_header = NULL, *packet_context = NULL;
831
832 if (!cache_entry) {
fdf0e7a0 833 BT_LOGE_STR("Failed to allocate one stream class field path cache.");
5f870343
JG
834 goto end;
835 }
836
837 event_header = bt_ctf_stream_class_get_event_header_type(stream_class);
838 if (event_header && bt_ctf_field_type_is_structure(event_header)) {
839 int i, count;
840
841 count = bt_ctf_field_type_structure_get_field_count(
fdf0e7a0
PP
842 event_header);
843 assert(count >= 0);
844
5f870343
JG
845 for (i = 0; i < count; i++) {
846 int ret;
847 const char *name;
848
849 ret = bt_ctf_field_type_structure_get_field(
850 event_header, &name, NULL, i);
851 if (ret) {
fdf0e7a0
PP
852 BT_LOGE("Cannot get event header structure field type's field: "
853 "notit-addr=%p, stream-class-addr=%p, "
854 "stream-class-name=\"%s\", "
855 "stream-class-id=%" PRId64 ", "
856 "ft-addr=%p, index=%d",
857 notit, stream_class,
858 bt_ctf_stream_class_get_name(stream_class),
859 bt_ctf_stream_class_get_id(stream_class),
860 event_header, i);
5f870343
JG
861 goto error;
862 }
863
864 if (v != -1 && id != -1) {
865 break;
866 }
fdf0e7a0
PP
867
868 if (v == -1 && strcmp(name, "v") == 0) {
5f870343
JG
869 v = i;
870 } else if (id == -1 && !strcmp(name, "id")) {
871 id = i;
872 }
873 }
874 }
875
876 packet_context = bt_ctf_stream_class_get_packet_context_type(
877 stream_class);
878 if (packet_context && bt_ctf_field_type_is_structure(packet_context)) {
879 int i, count;
880
881 count = bt_ctf_field_type_structure_get_field_count(
fdf0e7a0
PP
882 packet_context);
883 assert(count >= 0);
884
5f870343
JG
885 for (i = 0; i < count; i++) {
886 int ret;
887 const char *name;
888 struct bt_ctf_field_type *field_type;
889
890 if (timestamp_end != -1 && packet_size != -1 &&
891 content_size != -1) {
892 break;
893 }
894
895 ret = bt_ctf_field_type_structure_get_field(
896 packet_context, &name, &field_type, i);
897 if (ret) {
fdf0e7a0
PP
898 BT_LOGE("Cannot get packet context structure field type's field: "
899 "notit-addr=%p, stream-class-addr=%p, "
900 "stream-class-name=\"%s\", "
901 "stream-class-id=%" PRId64 ", "
902 "ft-addr=%p, index=%d",
903 notit, stream_class,
904 bt_ctf_stream_class_get_name(stream_class),
905 bt_ctf_stream_class_get_id(stream_class),
906 event_header, i);
5f870343
JG
907 goto error;
908 }
909
910 if (timestamp_end == -1 &&
fdf0e7a0 911 strcmp(name, "timestamp_end") == 0) {
5f870343
JG
912 struct field_cb_override *override = g_new0(
913 struct field_cb_override, 1);
914
915 if (!override) {
916 BT_PUT(field_type);
917 goto error;
918 }
919
920 override->func = btr_timestamp_end_cb;
921 override->data = notit;
5f870343 922 g_hash_table_insert(notit->field_overrides,
fdf0e7a0 923 bt_get(field_type), override);
5f870343
JG
924 timestamp_end = i;
925 } else if (packet_size == -1 &&
926 !strcmp(name, "packet_size")) {
927 packet_size = i;
928 } else if (content_size == -1 &&
929 !strcmp(name, "content_size")) {
930 content_size = i;
931 }
932 BT_PUT(field_type);
933 }
934 }
935
936 cache_entry->v = v;
937 cache_entry->id = id;
938 cache_entry->timestamp_end = timestamp_end;
939 cache_entry->packet_size = packet_size;
940 cache_entry->content_size = content_size;
941end:
942 BT_PUT(event_header);
943 BT_PUT(packet_context);
944 return cache_entry;
945error:
946 g_free(cache_entry);
947 cache_entry = NULL;
948 goto end;
949}
950
951static
952struct stream_class_field_path_cache *get_stream_class_field_path_cache(
953 struct bt_ctf_notif_iter *notit,
954 struct bt_ctf_stream_class *stream_class)
955{
956 bool cache_entry_found;
957 struct stream_class_field_path_cache *cache_entry;
958
959 cache_entry_found = g_hash_table_lookup_extended(
960 notit->sc_field_path_caches,
961 stream_class, NULL, (gpointer) &cache_entry);
962 if (unlikely(!cache_entry_found)) {
963 cache_entry = create_stream_class_field_path_cache_entry(notit,
fdf0e7a0 964 stream_class);
5f870343 965 g_hash_table_insert(notit->sc_field_path_caches,
fdf0e7a0 966 bt_get(stream_class), (gpointer) cache_entry);
5f870343
JG
967 }
968
969 return cache_entry;
970}
971
e98a2d6e 972static inline
835b2d10
JG
973enum bt_ctf_notif_iter_status set_current_stream_class(
974 struct bt_ctf_notif_iter *notit)
e98a2d6e
PP
975{
976 enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
5f870343 977 struct bt_ctf_field_type *packet_header_type = NULL;
e98a2d6e 978 struct bt_ctf_field_type *stream_id_field_type = NULL;
115de887 979 struct bt_ctf_stream_class *new_stream_class = NULL;
e98a2d6e
PP
980 uint64_t stream_id;
981
5f870343
JG
982 /* Clear the current stream class field path cache. */
983 notit->cur_sc_field_path_cache = NULL;
984
e98a2d6e
PP
985 /* Is there any "stream_id" field in the packet header? */
986 packet_header_type = bt_ctf_trace_get_packet_header_type(
fdf0e7a0 987 notit->meta.trace);
e98a2d6e 988 if (!packet_header_type) {
fdf0e7a0
PP
989 /*
990 * No packet header, therefore no `stream_id` field,
991 * therefore only one stream class.
992 */
993 goto single_stream_class;
e98a2d6e
PP
994 }
995
996 assert(is_struct_type(packet_header_type));
997
998 // TODO: optimalize!
999 stream_id_field_type =
fdf0e7a0
PP
1000 bt_ctf_field_type_structure_get_field_type_by_name(
1001 packet_header_type, "stream_id");
e98a2d6e
PP
1002 if (stream_id_field_type) {
1003 /* Find appropriate stream class using current stream ID */
e98a2d6e 1004 int ret;
5f870343 1005 struct bt_ctf_field *stream_id_field = NULL;
e98a2d6e
PP
1006
1007 assert(notit->dscopes.trace_packet_header);
1008
1009 // TODO: optimalize!
1010 stream_id_field = bt_ctf_field_structure_get_field(
78586d8a 1011 notit->dscopes.trace_packet_header, "stream_id");
e98a2d6e
PP
1012 assert(stream_id_field);
1013 ret = bt_ctf_field_unsigned_integer_get_value(
78586d8a 1014 stream_id_field, &stream_id);
e98a2d6e
PP
1015 assert(!ret);
1016 BT_PUT(stream_id_field);
1017 } else {
fdf0e7a0 1018single_stream_class:
e98a2d6e
PP
1019 /* Only one stream: pick the first stream class */
1020 assert(bt_ctf_trace_get_stream_class_count(
78586d8a 1021 notit->meta.trace) == 1);
e98a2d6e
PP
1022 stream_id = 0;
1023 }
1024
fdf0e7a0
PP
1025 BT_LOGV("Found stream class ID to use: notit-addr=%p, "
1026 "stream-class-id=%" PRIu64 ", "
1027 "trace-addr=%p, trace-name=\"%s\"",
1028 notit, stream_id, notit->meta.trace,
1029 bt_ctf_trace_get_name(notit->meta.trace));
1030
115de887 1031 new_stream_class = bt_ctf_trace_get_stream_class_by_id(
fdf0e7a0 1032 notit->meta.trace, stream_id);
115de887 1033 if (!new_stream_class) {
fdf0e7a0
PP
1034 BT_LOGW("No stream class with ID of stream class ID to use in trace: "
1035 "notit-addr=%p, stream-class-id=%" PRIu64 ", "
1036 "trace-addr=%p, trace-name=\"%s\"",
1037 notit, stream_id, notit->meta.trace,
1038 bt_ctf_trace_get_name(notit->meta.trace));
e98a2d6e
PP
1039 status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
1040 goto end;
1041 }
1042
115de887
PP
1043 if (notit->meta.stream_class) {
1044 if (new_stream_class != notit->meta.stream_class) {
1045 BT_LOGW("Two packets refer to two different stream classes within the same packet sequence: "
1046 "notit-addr=%p, prev-stream-class-addr=%p, "
1047 "prev-stream-class-name=\"%s\", "
1048 "prev-stream-class-id=%" PRId64 ", "
1049 "next-stream-class-addr=%p, "
1050 "next-stream-class-name=\"%s\", "
1051 "next-stream-class-id=%" PRId64 ", "
1052 "trace-addr=%p, trace-name=\"%s\"",
1053 notit, notit->meta.stream_class,
1054 bt_ctf_stream_class_get_name(notit->meta.stream_class),
1055 bt_ctf_stream_class_get_id(notit->meta.stream_class),
1056 new_stream_class,
1057 bt_ctf_stream_class_get_name(new_stream_class),
1058 bt_ctf_stream_class_get_id(new_stream_class),
1059 notit->meta.trace,
1060 bt_ctf_trace_get_name(notit->meta.trace));
1061 status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
1062 goto end;
1063 }
1064 } else {
1065 BT_MOVE(notit->meta.stream_class, new_stream_class);
1066 }
1067
fdf0e7a0
PP
1068 BT_LOGV("Set current stream class: "
1069 "notit-addr=%p, stream-class-addr=%p, "
1070 "stream-class-name=\"%s\", stream-class-id=%" PRId64,
1071 notit, notit->meta.stream_class,
1072 bt_ctf_stream_class_get_name(notit->meta.stream_class),
1073 bt_ctf_stream_class_get_id(notit->meta.stream_class));
1074
5f870343
JG
1075 /*
1076 * Retrieve (or lazily create) the current stream class field path
1077 * cache.
1078 */
1079 notit->cur_sc_field_path_cache = get_stream_class_field_path_cache(
fdf0e7a0 1080 notit, notit->meta.stream_class);
5f870343 1081 if (!notit->cur_sc_field_path_cache) {
fdf0e7a0
PP
1082 BT_LOGW("Cannot retrieve stream class field path from cache: "
1083 "notit-addr=%p, stream-class-addr=%p, "
1084 "stream-class-name=\"%s\", stream-class-id=%" PRId64,
1085 notit, notit->meta.stream_class,
1086 bt_ctf_stream_class_get_name(notit->meta.stream_class),
1087 bt_ctf_stream_class_get_id(notit->meta.stream_class));
5f870343
JG
1088 status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
1089 goto end;
1090 }
e98a2d6e
PP
1091end:
1092 BT_PUT(packet_header_type);
1093 BT_PUT(stream_id_field_type);
115de887 1094 bt_put(new_stream_class);
e98a2d6e
PP
1095 return status;
1096}
1097
1098static
1099enum bt_ctf_notif_iter_status after_packet_header_state(
1100 struct bt_ctf_notif_iter *notit)
1101{
1102 enum bt_ctf_notif_iter_status status;
1103
1104 status = set_current_stream_class(notit);
1105 if (status == BT_CTF_NOTIF_ITER_STATUS_OK) {
1106 notit->state = STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN;
1107 }
1108
1109 return status;
1110}
1111
1112static
1113enum bt_ctf_notif_iter_status read_packet_context_begin_state(
1114 struct bt_ctf_notif_iter *notit)
1115{
1116 enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
1117 struct bt_ctf_field_type *packet_context_type;
1118
1119 assert(notit->meta.stream_class);
1120 packet_context_type = bt_ctf_stream_class_get_packet_context_type(
fdf0e7a0 1121 notit->meta.stream_class);
e98a2d6e 1122 if (!packet_context_type) {
fdf0e7a0
PP
1123 BT_LOGV("No packet packet context field type in stream class: continuing: "
1124 "notit-addr=%p, stream-class-addr=%p, "
1125 "stream-class-name=\"%s\", stream-class-id=%" PRId64,
1126 notit, notit->meta.stream_class,
1127 bt_ctf_stream_class_get_name(notit->meta.stream_class),
1128 bt_ctf_stream_class_get_id(notit->meta.stream_class));
835b2d10 1129 notit->state = STATE_AFTER_STREAM_PACKET_CONTEXT;
e98a2d6e
PP
1130 goto end;
1131 }
1132
fdf0e7a0
PP
1133 BT_LOGV("Decoding packet context field: "
1134 "notit-addr=%p, stream-class-addr=%p, "
1135 "stream-class-name=\"%s\", stream-class-id=%" PRId64 ", "
1136 "ft-addr=%p",
1137 notit, notit->meta.stream_class,
1138 bt_ctf_stream_class_get_name(notit->meta.stream_class),
1139 bt_ctf_stream_class_get_id(notit->meta.stream_class),
1140 packet_context_type);
e98a2d6e 1141 status = read_dscope_begin_state(notit, packet_context_type,
fdf0e7a0
PP
1142 STATE_AFTER_STREAM_PACKET_CONTEXT,
1143 STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE,
1144 &notit->dscopes.stream_packet_context);
1145 if (status < 0) {
1146 BT_LOGW("Cannot decode packet context field: "
1147 "notit-addr=%p, stream-class-addr=%p, "
1148 "stream-class-name=\"%s\", "
1149 "stream-class-id=%" PRId64 ", ft-addr=%p",
1150 notit, notit->meta.stream_class,
1151 bt_ctf_stream_class_get_name(notit->meta.stream_class),
1152 bt_ctf_stream_class_get_id(notit->meta.stream_class),
1153 packet_context_type);
1154 }
e98a2d6e
PP
1155
1156end:
1157 BT_PUT(packet_context_type);
e98a2d6e
PP
1158 return status;
1159}
1160
1161static
1162enum bt_ctf_notif_iter_status read_packet_context_continue_state(
1163 struct bt_ctf_notif_iter *notit)
1164{
1165 return read_dscope_continue_state(notit,
78586d8a 1166 STATE_AFTER_STREAM_PACKET_CONTEXT);
e98a2d6e
PP
1167}
1168
78586d8a 1169static
e98a2d6e
PP
1170enum bt_ctf_notif_iter_status set_current_packet_content_sizes(
1171 struct bt_ctf_notif_iter *notit)
1172{
1173 enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
1174 struct bt_ctf_field *packet_size_field = NULL;
1175 struct bt_ctf_field *content_size_field = NULL;
97755805 1176 uint64_t content_size = -1ULL, packet_size = -1ULL;
e98a2d6e 1177
89b08333
MD
1178 if (!notit->dscopes.stream_packet_context) {
1179 goto end;
1180 }
e98a2d6e 1181
e98a2d6e 1182 packet_size_field = bt_ctf_field_structure_get_field(
fdf0e7a0 1183 notit->dscopes.stream_packet_context, "packet_size");
e98a2d6e 1184 content_size_field = bt_ctf_field_structure_get_field(
fdf0e7a0 1185 notit->dscopes.stream_packet_context, "content_size");
e98a2d6e
PP
1186 if (packet_size_field) {
1187 int ret = bt_ctf_field_unsigned_integer_get_value(
fdf0e7a0 1188 packet_size_field, &packet_size);
e98a2d6e 1189
fdf0e7a0 1190 assert(ret == 0);
e98a2d6e 1191 if (packet_size == 0) {
fdf0e7a0
PP
1192 BT_LOGW("Invalid packet size: packet context field indicates packet size is zero: "
1193 "notit-addr=%p, packet-context-field-addr=%p",
1194 notit, notit->dscopes.stream_packet_context);
e98a2d6e
PP
1195 status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
1196 goto end;
1197 } else if ((packet_size % 8) != 0) {
fdf0e7a0
PP
1198 BT_LOGW("Invalid packet size: packet context field indicates packet size is not a multiple of 8: "
1199 "notit-addr=%p, packet-context-field-addr=%p, "
1200 "packet-size=%" PRIu64,
1201 notit, notit->dscopes.stream_packet_context,
1202 packet_size);
e98a2d6e
PP
1203 status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
1204 goto end;
1205 }
1206 }
78586d8a 1207
e98a2d6e
PP
1208 if (content_size_field) {
1209 int ret = bt_ctf_field_unsigned_integer_get_value(
1210 content_size_field, &content_size);
78586d8a 1211
fdf0e7a0 1212 assert(ret == 0);
e98a2d6e
PP
1213 } else {
1214 content_size = packet_size;
1215 }
1216
fdf0e7a0
PP
1217 if (content_size > packet_size) {
1218 BT_LOGW("Invalid packet or content size: packet context field indicates content size is greater than packet size: "
1219 "notit-addr=%p, packet-context-field-addr=%p, "
1220 "packet-size=%" PRIu64 ", content-size=%" PRIu64,
1221 notit, notit->dscopes.stream_packet_context,
1222 packet_size, content_size);
1223 status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
1224 goto end;
1225 }
1226
97755805
MD
1227 if (packet_size != -1ULL) {
1228 notit->cur_packet_size = packet_size;
1229 } else {
1230 /*
1231 * Use the content size as packet size indicator if the
1232 * packet size field is missing. This means there is no
1233 * padding in this stream.
1234 */
1235 notit->cur_packet_size = content_size;
1236 }
e98a2d6e 1237 notit->cur_content_size = content_size;
fdf0e7a0
PP
1238 BT_LOGV("Set current packet and content sizes: "
1239 "notit-addr=%p, packet-size=%" PRIu64 ", content-size=%" PRIu64,
1240 notit, packet_size, content_size);
e98a2d6e
PP
1241end:
1242 BT_PUT(packet_size_field);
1243 BT_PUT(content_size_field);
e98a2d6e
PP
1244 return status;
1245}
1246
1247static
1248enum bt_ctf_notif_iter_status after_packet_context_state(
1249 struct bt_ctf_notif_iter *notit)
1250{
1251 enum bt_ctf_notif_iter_status status;
1252
1253 status = set_current_packet_content_sizes(notit);
1254 if (status == BT_CTF_NOTIF_ITER_STATUS_OK) {
1255 notit->state = STATE_EMIT_NOTIF_NEW_PACKET;
1256 }
1257
1258 return status;
1259}
1260
1261static
1262enum bt_ctf_notif_iter_status read_event_header_begin_state(
1263 struct bt_ctf_notif_iter *notit)
1264{
1265 enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
1266 struct bt_ctf_field_type *event_header_type = NULL;
1267
174e773b
PP
1268 /* Reset the position of the last event header */
1269 notit->buf.last_eh_at = notit->buf.at;
1270
e98a2d6e
PP
1271 /* Check if we have some content left */
1272 if (notit->cur_content_size >= 0) {
1273 if (packet_at(notit) == notit->cur_content_size) {
1274 /* No more events! */
fdf0e7a0
PP
1275 BT_LOGV("Reached end of packet: notit-addr=%p, "
1276 "cur=%zu", notit, packet_at(notit));
e98a2d6e
PP
1277 notit->state = STATE_EMIT_NOTIF_END_OF_PACKET;
1278 goto end;
1279 } else if (packet_at(notit) > notit->cur_content_size) {
1280 /* That's not supposed to happen */
fdf0e7a0 1281 BT_LOGV("Before decoding event header field: cursor is passed the packet's content: "
1974687e 1282 "notit-addr=%p, content-size=%" PRId64 ", "
fdf0e7a0
PP
1283 "cur=%zu", notit, notit->cur_content_size,
1284 packet_at(notit));
e98a2d6e
PP
1285 status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
1286 goto end;
1287 }
1288 }
1289
1290 event_header_type = bt_ctf_stream_class_get_event_header_type(
1291 notit->meta.stream_class);
1292 if (!event_header_type) {
835b2d10 1293 notit->state = STATE_AFTER_STREAM_EVENT_HEADER;
e98a2d6e
PP
1294 goto end;
1295 }
1296
1297 put_event_dscopes(notit);
fdf0e7a0
PP
1298 BT_LOGV("Decoding event header field: "
1299 "notit-addr=%p, stream-class-addr=%p, "
1300 "stream-class-name=\"%s\", stream-class-id=%" PRId64 ", "
1301 "ft-addr=%p",
1302 notit, notit->meta.stream_class,
1303 bt_ctf_stream_class_get_name(notit->meta.stream_class),
1304 bt_ctf_stream_class_get_id(notit->meta.stream_class),
1305 event_header_type);
e98a2d6e
PP
1306 status = read_dscope_begin_state(notit, event_header_type,
1307 STATE_AFTER_STREAM_EVENT_HEADER,
1308 STATE_DSCOPE_STREAM_EVENT_HEADER_CONTINUE,
1309 &notit->dscopes.stream_event_header);
fdf0e7a0
PP
1310 if (status < 0) {
1311 BT_LOGW("Cannot decode event header field: "
1312 "notit-addr=%p, stream-class-addr=%p, "
1313 "stream-class-name=\"%s\", "
1314 "stream-class-id=%" PRId64 ", ft-addr=%p",
1315 notit, notit->meta.stream_class,
1316 bt_ctf_stream_class_get_name(notit->meta.stream_class),
1317 bt_ctf_stream_class_get_id(notit->meta.stream_class),
1318 event_header_type);
1319 }
e98a2d6e
PP
1320end:
1321 BT_PUT(event_header_type);
1322
1323 return status;
1324}
1325
1326static
1327enum bt_ctf_notif_iter_status read_event_header_continue_state(
1328 struct bt_ctf_notif_iter *notit)
1329{
1330 return read_dscope_continue_state(notit,
1331 STATE_AFTER_STREAM_EVENT_HEADER);
1332}
1333
1334static inline
1335enum bt_ctf_notif_iter_status set_current_event_class(struct bt_ctf_notif_iter *notit)
1336{
1337 /*
1338 * The assert() calls in this function are okay because it is
1339 * assumed here that all the metadata objects have been
1340 * validated for CTF correctness before decoding actual streams.
1341 */
1342
1343 enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
1344 struct bt_ctf_field_type *event_header_type;
1345 struct bt_ctf_field_type *id_field_type = NULL;
1346 struct bt_ctf_field_type *v_field_type = NULL;
1347 uint64_t event_id = -1ULL;
1348 int ret;
1349
1350 event_header_type = bt_ctf_stream_class_get_event_header_type(
1351 notit->meta.stream_class);
1352 if (!event_header_type) {
fdf0e7a0
PP
1353 /*
1354 * No event header, therefore no event class ID field,
1355 * therefore only one event class.
1356 */
1357 goto single_event_class;
e98a2d6e
PP
1358 }
1359
1360 /* Is there any "id"/"v" field in the event header? */
1361 assert(is_struct_type(event_header_type));
1362 id_field_type = bt_ctf_field_type_structure_get_field_type_by_name(
1363 event_header_type, "id");
1364 v_field_type = bt_ctf_field_type_structure_get_field_type_by_name(
1365 event_header_type, "v");
1366 assert(notit->dscopes.stream_event_header);
1367 if (v_field_type) {
1368 /*
1369 * _ _____ _____
1370 * | | |_ _|_ _| __ __ _
1371 * | | | | | || '_ \ / _` |
1372 * | |___| | | || | | | (_| | S P E C I A L
1373 * |_____|_| |_||_| |_|\__, | C A S E ™
1374 * |___/
1375 */
1376 struct bt_ctf_field *v_field = NULL;
1377 struct bt_ctf_field *v_struct_field = NULL;
1378 struct bt_ctf_field *v_struct_id_field = NULL;
1379
1380 // TODO: optimalize!
1381 v_field = bt_ctf_field_structure_get_field(
1382 notit->dscopes.stream_event_header, "v");
1383 assert(v_field);
1384
1385 v_struct_field =
1386 bt_ctf_field_variant_get_current_field(v_field);
1387 if (!v_struct_field) {
1388 goto end_v_field_type;
1389 }
1390
1391 // TODO: optimalize!
1392 v_struct_id_field =
1393 bt_ctf_field_structure_get_field(v_struct_field, "id");
1394 if (!v_struct_id_field) {
1395 goto end_v_field_type;
1396 }
1397
fdf0e7a0
PP
1398 if (bt_ctf_field_is_integer(v_struct_id_field)) {
1399 ret = bt_ctf_field_unsigned_integer_get_value(
1400 v_struct_id_field, &event_id);
1401 if (ret) {
1402 BT_LOGV("Cannot get value of unsigned integer field (`id`): continuing: "
1403 "notit=%p, field-addr=%p",
1404 notit, v_struct_id_field);
1405 event_id = -1ULL;
1406 }
e98a2d6e
PP
1407 }
1408
1409end_v_field_type:
1410 BT_PUT(v_field);
1411 BT_PUT(v_struct_field);
1412 BT_PUT(v_struct_id_field);
1413 }
1414
1415 if (id_field_type && event_id == -1ULL) {
1416 /* Check "id" field */
1417 struct bt_ctf_field *id_field = NULL;
fdf0e7a0 1418 int ret = 0;
e98a2d6e
PP
1419
1420 // TODO: optimalize!
1421 id_field = bt_ctf_field_structure_get_field(
1422 notit->dscopes.stream_event_header, "id");
fdf0e7a0
PP
1423 if (!id_field) {
1424 goto check_event_id;
1425 }
e98a2d6e
PP
1426
1427 if (bt_ctf_field_is_integer(id_field)) {
1428 ret = bt_ctf_field_unsigned_integer_get_value(
1429 id_field, &event_id);
fdf0e7a0 1430 } else if (bt_ctf_field_is_enumeration(id_field)) {
e98a2d6e
PP
1431 struct bt_ctf_field *container;
1432
1433 container = bt_ctf_field_enumeration_get_container(
1434 id_field);
1435 assert(container);
1436 ret = bt_ctf_field_unsigned_integer_get_value(
1437 container, &event_id);
1438 BT_PUT(container);
1439 }
fdf0e7a0
PP
1440
1441 assert(ret == 0);
e98a2d6e
PP
1442 BT_PUT(id_field);
1443 }
1444
fdf0e7a0 1445check_event_id:
e98a2d6e 1446 if (event_id == -1ULL) {
fdf0e7a0 1447single_event_class:
e98a2d6e
PP
1448 /* Event ID not found: single event? */
1449 assert(bt_ctf_stream_class_get_event_class_count(
1450 notit->meta.stream_class) == 1);
1451 event_id = 0;
1452 }
1453
fdf0e7a0
PP
1454 BT_LOGV("Found event class ID to use: notit-addr=%p, "
1455 "stream-class-addr=%p, stream-class-name=\"%s\", "
1456 "stream-class-id=%" PRId64 ", "
1457 "event-class-id=%" PRIu64,
1458 notit, notit->meta.stream_class,
1459 bt_ctf_stream_class_get_name(notit->meta.stream_class),
1460 bt_ctf_stream_class_get_id(notit->meta.stream_class),
1461 event_id);
e98a2d6e
PP
1462 BT_PUT(notit->meta.event_class);
1463 notit->meta.event_class = bt_ctf_stream_class_get_event_class_by_id(
1464 notit->meta.stream_class, event_id);
1465 if (!notit->meta.event_class) {
fdf0e7a0
PP
1466 BT_LOGW("No event class with ID of event class ID to use in stream class: "
1467 "notit-addr=%p, stream-class-addr=%p, "
1468 "stream-class-name=\"%s\", "
1469 "stream-class-id=%" PRId64 ", "
1470 "event-class-id=%" PRIu64,
1471 notit, notit->meta.stream_class,
1472 bt_ctf_stream_class_get_name(notit->meta.stream_class),
1473 bt_ctf_stream_class_get_id(notit->meta.stream_class),
1474 event_id);
e98a2d6e
PP
1475 status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
1476 goto end;
1477 }
1478
fdf0e7a0
PP
1479 BT_LOGV("Set current event class: "
1480 "notit-addr=%p, event-class-addr=%p, "
1481 "event-class-name=\"%s\", event-class-id=%" PRId64,
1482 notit, notit->meta.event_class,
1483 bt_ctf_event_class_get_name(notit->meta.event_class),
1484 bt_ctf_event_class_get_id(notit->meta.event_class));
1485
e98a2d6e
PP
1486end:
1487 BT_PUT(event_header_type);
1488 BT_PUT(id_field_type);
1489 BT_PUT(v_field_type);
1490
1491 return status;
1492}
1493
1494static
1495enum bt_ctf_notif_iter_status after_event_header_state(
1496 struct bt_ctf_notif_iter *notit)
1497{
1498 enum bt_ctf_notif_iter_status status;
1499
e98a2d6e
PP
1500 status = set_current_event_class(notit);
1501 if (status != BT_CTF_NOTIF_ITER_STATUS_OK) {
e98a2d6e
PP
1502 goto end;
1503 }
1504
1505 notit->state = STATE_DSCOPE_STREAM_EVENT_CONTEXT_BEGIN;
1506
1507end:
1508 return status;
1509}
1510
1511static
1512enum bt_ctf_notif_iter_status read_stream_event_context_begin_state(
1513 struct bt_ctf_notif_iter *notit)
1514{
1515 enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
1516 struct bt_ctf_field_type *stream_event_context_type;
1517
1518 stream_event_context_type = bt_ctf_stream_class_get_event_context_type(
1519 notit->meta.stream_class);
1520 if (!stream_event_context_type) {
835b2d10 1521 notit->state = STATE_DSCOPE_EVENT_CONTEXT_BEGIN;
e98a2d6e
PP
1522 goto end;
1523 }
1524
fdf0e7a0
PP
1525 BT_LOGV("Decoding stream event context field: "
1526 "notit-addr=%p, stream-class-addr=%p, "
1527 "stream-class-name=\"%s\", stream-class-id=%" PRId64 ", "
1528 "ft-addr=%p",
1529 notit, notit->meta.stream_class,
1530 bt_ctf_stream_class_get_name(notit->meta.stream_class),
1531 bt_ctf_stream_class_get_id(notit->meta.stream_class),
1532 stream_event_context_type);
e98a2d6e
PP
1533 status = read_dscope_begin_state(notit, stream_event_context_type,
1534 STATE_DSCOPE_EVENT_CONTEXT_BEGIN,
1535 STATE_DSCOPE_STREAM_EVENT_CONTEXT_CONTINUE,
1536 &notit->dscopes.stream_event_context);
fdf0e7a0
PP
1537 if (status < 0) {
1538 BT_LOGW("Cannot decode stream event context field: "
1539 "notit-addr=%p, stream-class-addr=%p, "
1540 "stream-class-name=\"%s\", "
1541 "stream-class-id=%" PRId64 ", ft-addr=%p",
1542 notit, notit->meta.stream_class,
1543 bt_ctf_stream_class_get_name(notit->meta.stream_class),
1544 bt_ctf_stream_class_get_id(notit->meta.stream_class),
1545 stream_event_context_type);
1546 }
e98a2d6e
PP
1547
1548end:
1549 BT_PUT(stream_event_context_type);
1550
1551 return status;
1552}
1553
1554static
1555enum bt_ctf_notif_iter_status read_stream_event_context_continue_state(
1556 struct bt_ctf_notif_iter *notit)
1557{
1558 return read_dscope_continue_state(notit,
1559 STATE_DSCOPE_EVENT_CONTEXT_BEGIN);
1560}
1561
1562static
1563enum bt_ctf_notif_iter_status read_event_context_begin_state(
1564 struct bt_ctf_notif_iter *notit)
1565{
1566 enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
1567 struct bt_ctf_field_type *event_context_type;
1568
1569 event_context_type = bt_ctf_event_class_get_context_type(
1570 notit->meta.event_class);
1571 if (!event_context_type) {
835b2d10 1572 notit->state = STATE_DSCOPE_EVENT_PAYLOAD_BEGIN;
e98a2d6e
PP
1573 goto end;
1574 }
fdf0e7a0
PP
1575
1576 BT_LOGV("Decoding event context field: "
1577 "notit-addr=%p, event-class-addr=%p, "
1578 "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
1579 "ft-addr=%p",
1580 notit, notit->meta.event_class,
1581 bt_ctf_event_class_get_name(notit->meta.event_class),
1582 bt_ctf_event_class_get_id(notit->meta.event_class),
1583 event_context_type);
e98a2d6e
PP
1584 status = read_dscope_begin_state(notit, event_context_type,
1585 STATE_DSCOPE_EVENT_PAYLOAD_BEGIN,
1586 STATE_DSCOPE_EVENT_CONTEXT_CONTINUE,
1587 &notit->dscopes.event_context);
fdf0e7a0
PP
1588 if (status < 0) {
1589 BT_LOGW("Cannot decode event context field: "
1590 "notit-addr=%p, event-class-addr=%p, "
1591 "event-class-name=\"%s\", "
1592 "event-class-id=%" PRId64 ", ft-addr=%p",
1593 notit, notit->meta.event_class,
1594 bt_ctf_event_class_get_name(notit->meta.event_class),
1595 bt_ctf_event_class_get_id(notit->meta.event_class),
1596 event_context_type);
1597 }
e98a2d6e
PP
1598
1599end:
1600 BT_PUT(event_context_type);
1601
1602 return status;
1603}
1604
1605static
1606enum bt_ctf_notif_iter_status read_event_context_continue_state(
1607 struct bt_ctf_notif_iter *notit)
1608{
1609 return read_dscope_continue_state(notit,
1610 STATE_DSCOPE_EVENT_PAYLOAD_BEGIN);
1611}
1612
1613static
1614enum bt_ctf_notif_iter_status read_event_payload_begin_state(
1615 struct bt_ctf_notif_iter *notit)
1616{
1617 enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
1618 struct bt_ctf_field_type *event_payload_type;
1619
1620 event_payload_type = bt_ctf_event_class_get_payload_type(
1621 notit->meta.event_class);
1622 if (!event_payload_type) {
835b2d10 1623 notit->state = STATE_EMIT_NOTIF_EVENT;
e98a2d6e
PP
1624 goto end;
1625 }
1626
fdf0e7a0
PP
1627 BT_LOGV("Decoding event payload field: "
1628 "notit-addr=%p, event-class-addr=%p, "
1629 "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
1630 "ft-addr=%p",
1631 notit, notit->meta.event_class,
1632 bt_ctf_event_class_get_name(notit->meta.event_class),
1633 bt_ctf_event_class_get_id(notit->meta.event_class),
1634 event_payload_type);
e98a2d6e
PP
1635 status = read_dscope_begin_state(notit, event_payload_type,
1636 STATE_EMIT_NOTIF_EVENT,
1637 STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE,
1638 &notit->dscopes.event_payload);
fdf0e7a0
PP
1639 if (status < 0) {
1640 BT_LOGW("Cannot decode event payload field: "
1641 "notit-addr=%p, event-class-addr=%p, "
1642 "event-class-name=\"%s\", "
1643 "event-class-id=%" PRId64 ", ft-addr=%p",
1644 notit, notit->meta.event_class,
1645 bt_ctf_event_class_get_name(notit->meta.event_class),
1646 bt_ctf_event_class_get_id(notit->meta.event_class),
1647 event_payload_type);
1648 }
e98a2d6e
PP
1649
1650end:
1651 BT_PUT(event_payload_type);
1652
1653 return status;
1654}
1655
1656static
1657enum bt_ctf_notif_iter_status read_event_payload_continue_state(
1658 struct bt_ctf_notif_iter *notit)
1659{
1660 return read_dscope_continue_state(notit, STATE_EMIT_NOTIF_EVENT);
1661}
1662
1663static
1664enum bt_ctf_notif_iter_status skip_packet_padding_state(
1665 struct bt_ctf_notif_iter *notit)
1666{
1667 enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
1668 size_t bits_to_skip;
1669
1670 assert(notit->cur_packet_size > 0);
1671 bits_to_skip = notit->cur_packet_size - packet_at(notit);
1672 if (bits_to_skip == 0) {
1673 notit->state = STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN;
1674 goto end;
1675 } else {
1676 size_t bits_to_consume;
fdf0e7a0
PP
1677
1678 BT_LOGV("Trying to skip %zu bits of padding: notit-addr=%p, size=%zu",
1679 bits_to_skip, notit, bits_to_skip);
e98a2d6e
PP
1680 status = buf_ensure_available_bits(notit);
1681 if (status != BT_CTF_NOTIF_ITER_STATUS_OK) {
1682 goto end;
1683 }
1684
1685 bits_to_consume = MIN(buf_available_bits(notit), bits_to_skip);
fdf0e7a0
PP
1686 BT_LOGV("Skipping %zu bits of padding: notit-addr=%p, size=%zu",
1687 bits_to_consume, notit, bits_to_consume);
e98a2d6e
PP
1688 buf_consume_bits(notit, bits_to_consume);
1689 bits_to_skip = notit->cur_packet_size - packet_at(notit);
1690 if (bits_to_skip == 0) {
1691 notit->state = STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN;
1692 goto end;
1693 }
1694 }
1695
1696end:
1697 return status;
1698}
1699
1700static inline
1701enum bt_ctf_notif_iter_status handle_state(struct bt_ctf_notif_iter *notit)
1702{
1703 enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
fdf0e7a0 1704 const enum state state = notit->state;
e98a2d6e 1705
fdf0e7a0
PP
1706 BT_LOGV("Handling state: notit-addr=%p, state=%s",
1707 notit, state_string(state));
e98a2d6e
PP
1708
1709 // TODO: optimalize!
fdf0e7a0 1710 switch (state) {
e98a2d6e
PP
1711 case STATE_INIT:
1712 notit->state = STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN;
1713 break;
1714 case STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN:
1715 status = read_packet_header_begin_state(notit);
1716 break;
1717 case STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE:
1718 status = read_packet_header_continue_state(notit);
1719 break;
1720 case STATE_AFTER_TRACE_PACKET_HEADER:
1721 status = after_packet_header_state(notit);
1722 break;
1723 case STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN:
1724 status = read_packet_context_begin_state(notit);
1725 break;
1726 case STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE:
1727 status = read_packet_context_continue_state(notit);
1728 break;
1729 case STATE_AFTER_STREAM_PACKET_CONTEXT:
1730 status = after_packet_context_state(notit);
1731 break;
1732 case STATE_EMIT_NOTIF_NEW_PACKET:
1733 notit->state = STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN;
1734 break;
1735 case STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN:
1736 status = read_event_header_begin_state(notit);
1737 break;
1738 case STATE_DSCOPE_STREAM_EVENT_HEADER_CONTINUE:
1739 status = read_event_header_continue_state(notit);
1740 break;
1741 case STATE_AFTER_STREAM_EVENT_HEADER:
1742 status = after_event_header_state(notit);
1743 break;
1744 case STATE_DSCOPE_STREAM_EVENT_CONTEXT_BEGIN:
1745 status = read_stream_event_context_begin_state(notit);
1746 break;
1747 case STATE_DSCOPE_STREAM_EVENT_CONTEXT_CONTINUE:
1748 status = read_stream_event_context_continue_state(notit);
1749 break;
1750 case STATE_DSCOPE_EVENT_CONTEXT_BEGIN:
1751 status = read_event_context_begin_state(notit);
1752 break;
1753 case STATE_DSCOPE_EVENT_CONTEXT_CONTINUE:
1754 status = read_event_context_continue_state(notit);
1755 break;
1756 case STATE_DSCOPE_EVENT_PAYLOAD_BEGIN:
1757 status = read_event_payload_begin_state(notit);
1758 break;
1759 case STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE:
1760 status = read_event_payload_continue_state(notit);
1761 break;
1762 case STATE_EMIT_NOTIF_EVENT:
1763 notit->state = STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN;
1764 break;
1765 case STATE_SKIP_PACKET_PADDING:
1766 status = skip_packet_padding_state(notit);
1767 break;
1768 case STATE_EMIT_NOTIF_END_OF_PACKET:
1769 notit->state = STATE_SKIP_PACKET_PADDING;
1770 break;
fdf0e7a0
PP
1771 default:
1772 BT_LOGD("Unknown CTF plugin notification iterator state: "
1773 "notit-addr=%p, state=%d", notit, notit->state);
1774 abort();
e98a2d6e
PP
1775 }
1776
fdf0e7a0
PP
1777 BT_LOGV("Handled state: notit-addr=%p, status=%s, "
1778 "prev-state=%s, cur-state=%s",
1779 notit, bt_ctf_notif_iter_status_string(status),
1780 state_string(state), state_string(notit->state));
e98a2d6e
PP
1781 return status;
1782}
1783
2cf1d51e
JG
1784/**
1785 * Resets the internal state of a CTF notification iterator.
2cf1d51e
JG
1786 */
1787static
e98a2d6e
PP
1788void bt_ctf_notif_iter_reset(struct bt_ctf_notif_iter *notit)
1789{
1790 assert(notit);
fdf0e7a0 1791 BT_LOGD("Resetting notification iterator: addr=%p", notit);
e98a2d6e
PP
1792 stack_clear(notit->stack);
1793 BT_PUT(notit->meta.stream_class);
1794 BT_PUT(notit->meta.event_class);
1795 BT_PUT(notit->packet);
af87daef 1796 BT_PUT(notit->stream);
e98a2d6e
PP
1797 put_all_dscopes(notit);
1798 notit->buf.addr = NULL;
1799 notit->buf.sz = 0;
1800 notit->buf.at = 0;
2b186c3e 1801 notit->buf.last_eh_at = SIZE_MAX;
e98a2d6e
PP
1802 notit->buf.packet_offset = 0;
1803 notit->state = STATE_INIT;
1804 notit->cur_content_size = -1;
1805 notit->cur_packet_size = -1;
1806}
1807
2cf1d51e
JG
1808static
1809int bt_ctf_notif_iter_switch_packet(struct bt_ctf_notif_iter *notit)
1810{
1811 int ret = 0;
1812
115de887
PP
1813 /*
1814 * We don't put the stream class here because we need to make
1815 * sure that all the packets processed by the same notification
1816 * iterator refer to the same stream class (the first one).
1817 */
2cf1d51e 1818 assert(notit);
fdf0e7a0
PP
1819 BT_LOGV("Switching packet: notit-addr=%p, cur=%zu",
1820 notit, notit->buf.at);
2cf1d51e 1821 stack_clear(notit->stack);
2cf1d51e
JG
1822 BT_PUT(notit->meta.event_class);
1823 BT_PUT(notit->packet);
5f870343 1824 BT_PUT(notit->cur_timestamp_end);
2cf1d51e
JG
1825 put_all_dscopes(notit);
1826
1827 /*
1828 * Adjust current buffer so that addr points to the beginning of the new
1829 * packet.
1830 */
1831 if (notit->buf.addr) {
1832 size_t consumed_bytes = (size_t) (notit->buf.at / CHAR_BIT);
1833
1834 /* Packets are assumed to start on a byte frontier. */
1835 if (notit->buf.at % CHAR_BIT) {
fdf0e7a0
PP
1836 BT_LOGW("Cannot switch packet: current position is not a multiple of 8: "
1837 "notit-addr=%p, cur=%zu", notit, notit->buf.at);
2cf1d51e
JG
1838 ret = -1;
1839 goto end;
1840 }
1841
1842 notit->buf.addr += consumed_bytes;
1843 notit->buf.sz -= consumed_bytes;
1844 notit->buf.at = 0;
1845 notit->buf.packet_offset = 0;
fdf0e7a0
PP
1846 BT_LOGV("Adjusted buffer: addr=%p, size=%zu",
1847 notit->buf.addr, notit->buf.sz);
2cf1d51e
JG
1848 }
1849
1850 notit->cur_content_size = -1;
1851 notit->cur_packet_size = -1;
5f870343 1852 notit->cur_sc_field_path_cache = NULL;
fdf0e7a0 1853
2cf1d51e
JG
1854end:
1855 return ret;
1856}
1857
e98a2d6e
PP
1858static
1859struct bt_ctf_field *get_next_field(struct bt_ctf_notif_iter *notit)
1860{
1861 struct bt_ctf_field *next_field = NULL;
1862 struct bt_ctf_field *base_field;
1863 struct bt_ctf_field_type *base_type;
1864 size_t index;
1865
1866 assert(!stack_empty(notit->stack));
1867 index = stack_top(notit->stack)->index;
1868 base_field = stack_top(notit->stack)->base;
fdf0e7a0 1869 assert(base_field);
e98a2d6e 1870 base_type = bt_ctf_field_get_type(base_field);
fdf0e7a0 1871 assert(base_type);
e98a2d6e
PP
1872
1873 switch (bt_ctf_field_type_get_type_id(base_type)) {
1487a16a 1874 case BT_CTF_FIELD_TYPE_ID_STRUCT:
e98a2d6e
PP
1875 next_field = bt_ctf_field_structure_get_field_by_index(
1876 base_field, index);
1877 break;
1487a16a 1878 case BT_CTF_FIELD_TYPE_ID_ARRAY:
e98a2d6e
PP
1879 next_field = bt_ctf_field_array_get_field(base_field, index);
1880 break;
1487a16a 1881 case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
e98a2d6e
PP
1882 next_field = bt_ctf_field_sequence_get_field(base_field, index);
1883 break;
1487a16a 1884 case BT_CTF_FIELD_TYPE_ID_VARIANT:
e98a2d6e
PP
1885 next_field = bt_ctf_field_variant_get_current_field(base_field);
1886 break;
1887 default:
fdf0e7a0
PP
1888 BT_LOGF("Unknown base field type ID: "
1889 "notit-addr=%p, ft-addr=%p, ft-id=%s",
1890 notit, base_type,
1891 bt_ctf_field_type_id_string(
1892 bt_ctf_field_type_get_type_id(base_type)));
0fbb9a9f 1893 abort();
e98a2d6e
PP
1894 }
1895
e98a2d6e 1896 BT_PUT(base_type);
e98a2d6e
PP
1897 return next_field;
1898}
1899
c44c3e70
JG
1900static
1901void update_clock_state(uint64_t *state,
1902 struct bt_ctf_field *value_field)
1903{
1904 struct bt_ctf_field_type *value_type = NULL;
1905 uint64_t requested_new_value;
1906 uint64_t requested_new_value_mask;
1907 uint64_t cur_value_masked;
1908 int requested_new_value_size;
1909 int ret;
1910
1911 value_type = bt_ctf_field_get_type(value_field);
1912 assert(value_type);
fdf0e7a0 1913 assert(bt_ctf_field_type_is_integer(value_type));
c44c3e70
JG
1914 requested_new_value_size =
1915 bt_ctf_field_type_integer_get_size(value_type);
1916 assert(requested_new_value_size > 0);
c44c3e70
JG
1917 ret = bt_ctf_field_unsigned_integer_get_value(value_field,
1918 &requested_new_value);
1919 assert(!ret);
1920
1921 /*
1922 * Special case for a 64-bit new value, which is the limit
1923 * of a clock value as of this version: overwrite the
1924 * current value directly.
1925 */
1926 if (requested_new_value_size == 64) {
1927 *state = requested_new_value;
1928 goto end;
1929 }
1930
1931 requested_new_value_mask = (1ULL << requested_new_value_size) - 1;
1932 cur_value_masked = *state & requested_new_value_mask;
1933
1934 if (requested_new_value < cur_value_masked) {
1935 /*
1936 * It looks like a wrap happened on the number of bits
1937 * of the requested new value. Assume that the clock
1938 * value wrapped only one time.
1939 */
1940 *state += requested_new_value_mask + 1;
1941 }
1942
1943 /* Clear the low bits of the current clock value. */
1944 *state &= ~requested_new_value_mask;
1945
1946 /* Set the low bits of the current clock value. */
1947 *state |= requested_new_value;
1948end:
fdf0e7a0
PP
1949 BT_LOGV("Updated clock's value from integer field's value: "
1950 "value=%" PRIu64, *state);
c44c3e70
JG
1951 bt_put(value_type);
1952}
1953
1954static
1955enum bt_ctf_btr_status update_clock(struct bt_ctf_notif_iter *notit,
c44c3e70
JG
1956 struct bt_ctf_field *int_field)
1957{
ac0c6bdd 1958 gboolean clock_class_found;
8cb1fb66 1959 uint64_t *clock_state = NULL;
f45bfe88 1960 struct bt_ctf_field_type *int_field_type = NULL;
c44c3e70 1961 enum bt_ctf_btr_status ret = BT_CTF_BTR_STATUS_OK;
f45bfe88 1962 struct bt_ctf_clock_class *clock_class = NULL;
c44c3e70 1963
f45bfe88 1964 int_field_type = bt_ctf_field_get_type(int_field);
fdf0e7a0 1965 assert(int_field_type);
f45bfe88
PP
1966 clock_class = bt_ctf_field_type_integer_get_mapped_clock_class(
1967 int_field_type);
ac0c6bdd 1968 if (likely(!clock_class)) {
f45bfe88 1969 goto end;
c44c3e70
JG
1970 }
1971
ac0c6bdd 1972 clock_class_found = g_hash_table_lookup_extended(notit->clock_states,
fdf0e7a0 1973 clock_class, NULL, (gpointer) &clock_state);
8cb1fb66 1974 if (!clock_class_found) {
c44c3e70
JG
1975 clock_state = g_new0(uint64_t, 1);
1976 if (!clock_state) {
fdf0e7a0 1977 BT_LOGE_STR("Failed to allocate a uint64_t.");
c44c3e70
JG
1978 ret = BT_CTF_BTR_STATUS_ENOMEM;
1979 goto end;
1980 }
fdf0e7a0 1981
ac0c6bdd 1982 g_hash_table_insert(notit->clock_states, bt_get(clock_class),
fdf0e7a0 1983 clock_state);
c44c3e70
JG
1984 }
1985
1986 /* Update the clock's state. */
fdf0e7a0
PP
1987 BT_LOGV("Updating notification iterator's clock's value from integer field: "
1988 "notit-addr=%p, clock-class-addr=%p, "
1989 "clock-class-name=\"%s\", value=%" PRIu64,
1990 notit, clock_class,
1991 bt_ctf_clock_class_get_name(clock_class), *clock_state);
c44c3e70
JG
1992 update_clock_state(clock_state, int_field);
1993end:
f45bfe88 1994 bt_put(int_field_type);
ac0c6bdd 1995 bt_put(clock_class);
c44c3e70
JG
1996 return ret;
1997}
1998
e98a2d6e 1999static
5f870343
JG
2000enum bt_ctf_btr_status btr_unsigned_int_common(uint64_t value,
2001 struct bt_ctf_field_type *type, void *data,
f45bfe88 2002 struct bt_ctf_field **out_int_field)
e98a2d6e
PP
2003{
2004 enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
2005 struct bt_ctf_field *field = NULL;
2006 struct bt_ctf_field *int_field = NULL;
2007 struct bt_ctf_notif_iter *notit = data;
2008 int ret;
2009
fdf0e7a0
PP
2010 BT_LOGV("Common unsigned integer function called from BTR: "
2011 "notit-addr=%p, btr-addr=%p, ft-addr=%p, "
2012 "ft-id=%s, value=%" PRIu64,
2013 notit, notit->btr, type,
2014 bt_ctf_field_type_id_string(
2015 bt_ctf_field_type_get_type_id(type)),
2016 value);
2017
5f870343 2018 /* Create next field */
e98a2d6e
PP
2019 field = get_next_field(notit);
2020 if (!field) {
fdf0e7a0 2021 BT_LOGW("Cannot get next field: notit-addr=%p", notit);
e98a2d6e 2022 status = BT_CTF_BTR_STATUS_ERROR;
c44c3e70 2023 goto end_no_put;
e98a2d6e
PP
2024 }
2025
2026 switch(bt_ctf_field_type_get_type_id(type)) {
1487a16a 2027 case BT_CTF_FIELD_TYPE_ID_INTEGER:
e98a2d6e
PP
2028 /* Integer field is created field */
2029 BT_MOVE(int_field, field);
c44c3e70 2030 bt_get(type);
e98a2d6e 2031 break;
1487a16a 2032 case BT_CTF_FIELD_TYPE_ID_ENUM:
e98a2d6e 2033 int_field = bt_ctf_field_enumeration_get_container(field);
fdf0e7a0 2034 assert(int_field);
c44c3e70 2035 type = bt_ctf_field_get_type(int_field);
fdf0e7a0 2036 assert(type);
e98a2d6e
PP
2037 break;
2038 default:
fdf0e7a0
PP
2039 BT_LOGF("Unexpected field type ID: "
2040 "notit-addr=%p, ft-addr=%p, ft-id=%s",
2041 notit, type,
2042 bt_ctf_field_type_id_string(
2043 bt_ctf_field_type_get_type_id(type)));
0fbb9a9f 2044 abort();
e98a2d6e
PP
2045 }
2046
fdf0e7a0 2047 assert(int_field);
5f870343 2048 ret = bt_ctf_field_unsigned_integer_set_value(int_field, value);
fdf0e7a0 2049 assert(ret == 0);
e98a2d6e 2050 stack_top(notit->stack)->index++;
f45bfe88 2051 *out_int_field = int_field;
e98a2d6e 2052 BT_PUT(field);
c44c3e70 2053 BT_PUT(type);
fdf0e7a0 2054
c44c3e70 2055end_no_put:
e98a2d6e
PP
2056 return status;
2057}
2058
5f870343
JG
2059static
2060enum bt_ctf_btr_status btr_timestamp_end_cb(void *value,
2061 struct bt_ctf_field_type *type, void *data)
2062{
2063 enum bt_ctf_btr_status status;
2064 struct bt_ctf_field *field = NULL;
2065 struct bt_ctf_notif_iter *notit = data;
2066
fdf0e7a0
PP
2067 BT_LOGV("`timestamp_end` unsigned integer function called from BTR: "
2068 "notit-addr=%p, btr-addr=%p, ft-addr=%p, "
2069 "ft-id=%s",
2070 notit, notit->btr, type,
2071 bt_ctf_field_type_id_string(
2072 bt_ctf_field_type_get_type_id(type)));
5f870343
JG
2073 status = btr_unsigned_int_common(*((uint64_t *) value), type, data,
2074 &field);
2075
2076 /* Set as the current packet's timestamp_end field. */
2077 BT_MOVE(notit->cur_timestamp_end, field);
2078 return status;
2079}
2080
e98a2d6e
PP
2081static
2082enum bt_ctf_btr_status btr_unsigned_int_cb(uint64_t value,
2083 struct bt_ctf_field_type *type, void *data)
5f870343
JG
2084{
2085 struct bt_ctf_notif_iter *notit = data;
2086 enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
2087 struct bt_ctf_field *field = NULL;
2088 struct field_cb_override *override;
2089
fdf0e7a0
PP
2090 BT_LOGV("Unsigned integer function called from BTR: "
2091 "notit-addr=%p, btr-addr=%p, ft-addr=%p, "
2092 "ft-id=%s, value=%" PRIu64,
2093 notit, notit->btr, type,
2094 bt_ctf_field_type_id_string(
2095 bt_ctf_field_type_get_type_id(type)),
2096 value);
2097 override = g_hash_table_lookup(notit->field_overrides, type);
5f870343 2098 if (unlikely(override)) {
fdf0e7a0 2099 /* Override function logs errors */
5f870343
JG
2100 status = override->func(&value, type, override->data);
2101 goto end;
2102 }
2103
2104 status = btr_unsigned_int_common(value, type, data, &field);
2105 if (status != BT_CTF_BTR_STATUS_OK) {
fdf0e7a0 2106 /* btr_unsigned_int_common() logs errors */
5f870343
JG
2107 goto end;
2108 }
2109
f45bfe88 2110 status = update_clock(notit, field);
5f870343
JG
2111 BT_PUT(field);
2112end:
2113 return status;
2114}
2115
2116static
2117enum bt_ctf_btr_status btr_signed_int_cb(int64_t value,
2118 struct bt_ctf_field_type *type, void *data)
e98a2d6e
PP
2119{
2120 enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
2121 struct bt_ctf_field *field = NULL;
2122 struct bt_ctf_field *int_field = NULL;
2123 struct bt_ctf_notif_iter *notit = data;
2124 int ret;
2125
fdf0e7a0
PP
2126 BT_LOGV("Signed integer function called from BTR: "
2127 "notit-addr=%p, btr-addr=%p, ft-addr=%p, "
2128 "ft-id=%s, value=%" PRId64,
2129 notit, notit->btr, type,
2130 bt_ctf_field_type_id_string(
2131 bt_ctf_field_type_get_type_id(type)),
2132 value);
2133
5f870343 2134 /* create next field */
e98a2d6e
PP
2135 field = get_next_field(notit);
2136 if (!field) {
fdf0e7a0 2137 BT_LOGW("Cannot get next field: notit-addr=%p", notit);
e98a2d6e 2138 status = BT_CTF_BTR_STATUS_ERROR;
c44c3e70 2139 goto end_no_put;
e98a2d6e
PP
2140 }
2141
2142 switch(bt_ctf_field_type_get_type_id(type)) {
1487a16a 2143 case BT_CTF_FIELD_TYPE_ID_INTEGER:
e98a2d6e
PP
2144 /* Integer field is created field */
2145 BT_MOVE(int_field, field);
c44c3e70 2146 bt_get(type);
e98a2d6e 2147 break;
1487a16a 2148 case BT_CTF_FIELD_TYPE_ID_ENUM:
e98a2d6e 2149 int_field = bt_ctf_field_enumeration_get_container(field);
fdf0e7a0 2150 assert(int_field);
c44c3e70 2151 type = bt_ctf_field_get_type(int_field);
fdf0e7a0 2152 assert(type);
e98a2d6e
PP
2153 break;
2154 default:
fdf0e7a0
PP
2155 BT_LOGF("Unexpected field type ID: "
2156 "notit-addr=%p, ft-addr=%p, ft-id=%s",
2157 notit, type,
2158 bt_ctf_field_type_id_string(
2159 bt_ctf_field_type_get_type_id(type)));
0fbb9a9f 2160 abort();
e98a2d6e
PP
2161 }
2162
fdf0e7a0 2163 assert(int_field);
5f870343 2164 ret = bt_ctf_field_signed_integer_set_value(int_field, value);
e98a2d6e
PP
2165 assert(!ret);
2166 stack_top(notit->stack)->index++;
f45bfe88 2167 status = update_clock(notit, int_field);
e98a2d6e
PP
2168 BT_PUT(field);
2169 BT_PUT(int_field);
c44c3e70 2170 BT_PUT(type);
fdf0e7a0 2171
c44c3e70 2172end_no_put:
e98a2d6e
PP
2173 return status;
2174}
2175
2176static
2177enum bt_ctf_btr_status btr_floating_point_cb(double value,
2178 struct bt_ctf_field_type *type, void *data)
2179{
2180 enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
2181 struct bt_ctf_field *field = NULL;
2182 struct bt_ctf_notif_iter *notit = data;
2183 int ret;
2184
fdf0e7a0
PP
2185 BT_LOGV("Floating point number function called from BTR: "
2186 "notit-addr=%p, btr-addr=%p, ft-addr=%p, "
2187 "ft-id=%s, value=%f",
2188 notit, notit->btr, type,
2189 bt_ctf_field_type_id_string(
2190 bt_ctf_field_type_get_type_id(type)),
2191 value);
2192
e98a2d6e
PP
2193 /* Create next field */
2194 field = get_next_field(notit);
2195 if (!field) {
fdf0e7a0 2196 BT_LOGW("Cannot get next field: notit-addr=%p", notit);
e98a2d6e
PP
2197 status = BT_CTF_BTR_STATUS_ERROR;
2198 goto end;
2199 }
2200
2201 ret = bt_ctf_field_floating_point_set_value(field, value);
2202 assert(!ret);
2203 stack_top(notit->stack)->index++;
2204
2205end:
2206 BT_PUT(field);
e98a2d6e
PP
2207 return status;
2208}
2209
2210static
2211enum bt_ctf_btr_status btr_string_begin_cb(
2212 struct bt_ctf_field_type *type, void *data)
2213{
2214 enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
2215 struct bt_ctf_field *field = NULL;
2216 struct bt_ctf_notif_iter *notit = data;
2217 int ret;
2218
fdf0e7a0
PP
2219 BT_LOGV("String (beginning) function called from BTR: "
2220 "notit-addr=%p, btr-addr=%p, ft-addr=%p, "
2221 "ft-id=%s",
2222 notit, notit->btr, type,
2223 bt_ctf_field_type_id_string(
2224 bt_ctf_field_type_get_type_id(type)));
2225
e98a2d6e
PP
2226 /* Create next field */
2227 field = get_next_field(notit);
2228 if (!field) {
fdf0e7a0 2229 BT_LOGW("Cannot get next field: notit-addr=%p", notit);
e98a2d6e
PP
2230 status = BT_CTF_BTR_STATUS_ERROR;
2231 goto end;
2232 }
2233
2234 /*
2235 * Push on stack. Not a compound type per se, but we know that only
2236 * btr_string_cb() may be called between this call and a subsequent
2237 * call to btr_string_end_cb().
2238 */
2239 ret = stack_push(notit->stack, field);
2240 if (ret) {
fdf0e7a0
PP
2241 BT_LOGE("Cannot push string field on stack: "
2242 "notit-addr=%p, field-addr=%p", notit, field);
e98a2d6e
PP
2243 status = BT_CTF_BTR_STATUS_ERROR;
2244 goto end;
2245 }
2246
e5df2ae3
JG
2247 /*
2248 * Initialize string field payload to an empty string since in the
2249 * case of a length 0 string the btr_string_cb won't be called and
2250 * we will end up with an unset string payload.
2251 */
2252 ret = bt_ctf_field_string_set_value(field, "");
2253 if (ret) {
fdf0e7a0
PP
2254 BT_LOGE("Cannot initialize string field's value to an empty string: "
2255 "notit-addr=%p, field-addr=%p, ret=%d",
2256 notit, field, ret);
e5df2ae3
JG
2257 status = BT_CTF_BTR_STATUS_ERROR;
2258 goto end;
2259 }
2260
e98a2d6e
PP
2261end:
2262 BT_PUT(field);
2263
2264 return status;
2265}
2266
2267static
2268enum bt_ctf_btr_status btr_string_cb(const char *value,
2269 size_t len, struct bt_ctf_field_type *type, void *data)
2270{
2271 enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
2272 struct bt_ctf_field *field = NULL;
2273 struct bt_ctf_notif_iter *notit = data;
2274 int ret;
2275
fdf0e7a0
PP
2276 BT_LOGV("String (substring) function called from BTR: "
2277 "notit-addr=%p, btr-addr=%p, ft-addr=%p, "
2278 "ft-id=%s, string-length=%zu",
2279 notit, notit->btr, type,
2280 bt_ctf_field_type_id_string(
2281 bt_ctf_field_type_get_type_id(type)),
2282 len);
2283
e98a2d6e
PP
2284 /* Get string field */
2285 field = stack_top(notit->stack)->base;
2286 assert(field);
2287
2288 /* Append current string */
2289 ret = bt_ctf_field_string_append_len(field, value, len);
2290 if (ret) {
fdf0e7a0
PP
2291 BT_LOGE("Cannot append substring to string field's value: "
2292 "notit-addr=%p, field-addr=%p, string-length=%zu, "
2293 "ret=%d", notit, field, len, ret);
e98a2d6e
PP
2294 status = BT_CTF_BTR_STATUS_ERROR;
2295 goto end;
2296 }
2297
2298end:
2299 return status;
2300}
2301
2302static
2303enum bt_ctf_btr_status btr_string_end_cb(
2304 struct bt_ctf_field_type *type, void *data)
2305{
2306 struct bt_ctf_notif_iter *notit = data;
2307
fdf0e7a0
PP
2308 BT_LOGV("String (end) function called from BTR: "
2309 "notit-addr=%p, btr-addr=%p, ft-addr=%p, "
2310 "ft-id=%s",
2311 notit, notit->btr, type,
2312 bt_ctf_field_type_id_string(
2313 bt_ctf_field_type_get_type_id(type)));
2314
e98a2d6e
PP
2315 /* Pop string field */
2316 stack_pop(notit->stack);
2317
2318 /* Go to next field */
2319 stack_top(notit->stack)->index++;
e98a2d6e
PP
2320 return BT_CTF_BTR_STATUS_OK;
2321}
2322
2323enum bt_ctf_btr_status btr_compound_begin_cb(
2324 struct bt_ctf_field_type *type, void *data)
2325{
2326 enum bt_ctf_btr_status status = BT_CTF_BTR_STATUS_OK;
2327 struct bt_ctf_notif_iter *notit = data;
2328 struct bt_ctf_field *field;
2329 int ret;
2330
fdf0e7a0
PP
2331 BT_LOGV("Compound (beginning) function called from BTR: "
2332 "notit-addr=%p, btr-addr=%p, ft-addr=%p, "
2333 "ft-id=%s",
2334 notit, notit->btr, type,
2335 bt_ctf_field_type_id_string(
2336 bt_ctf_field_type_get_type_id(type)));
2337
e98a2d6e
PP
2338 /* Create field */
2339 if (stack_empty(notit->stack)) {
2340 /* Root: create dynamic scope field */
2341 *notit->cur_dscope_field = bt_ctf_field_create(type);
2342 field = *notit->cur_dscope_field;
2343
2344 /*
2345 * Field will be put at the end of this function
2346 * (stack_push() will take one reference, but this
2347 * reference is lost upon the equivalent stack_pop()
2348 * later), so also get it for our context to own it.
2349 */
2350 bt_get(*notit->cur_dscope_field);
fdf0e7a0
PP
2351
2352 if (!field) {
2353 BT_LOGE("Cannot create compound field: "
2354 "notit-addr=%p, ft-addr=%p, ft-id=%s",
2355 notit, type,
2356 bt_ctf_field_type_id_string(
2357 bt_ctf_field_type_get_type_id(type)));
2358 status = BT_CTF_BTR_STATUS_ERROR;
2359 goto end;
2360 }
e98a2d6e
PP
2361 } else {
2362 field = get_next_field(notit);
fdf0e7a0
PP
2363 if (!field) {
2364 BT_LOGW("Cannot get next field: notit-addr=%p", notit);
2365 status = BT_CTF_BTR_STATUS_ERROR;
2366 goto end;
2367 }
e98a2d6e
PP
2368 }
2369
2370 /* Push field */
fdf0e7a0 2371 assert(field);
e98a2d6e
PP
2372 ret = stack_push(notit->stack, field);
2373 if (ret) {
fdf0e7a0
PP
2374 BT_LOGE("Cannot push compound field onto the stack: "
2375 "notit-addr=%p, ft-addr=%p, ft-id=%s, ret=%d",
2376 notit, type,
2377 bt_ctf_field_type_id_string(
2378 bt_ctf_field_type_get_type_id(type)),
2379 ret);
e98a2d6e
PP
2380 status = BT_CTF_BTR_STATUS_ERROR;
2381 goto end;
2382 }
2383
2384end:
2385 BT_PUT(field);
2386
2387 return status;
2388}
2389
2390enum bt_ctf_btr_status btr_compound_end_cb(
2391 struct bt_ctf_field_type *type, void *data)
2392{
2393 struct bt_ctf_notif_iter *notit = data;
2394
fdf0e7a0
PP
2395 BT_LOGV("Compound (end) function called from BTR: "
2396 "notit-addr=%p, btr-addr=%p, ft-addr=%p, "
2397 "ft-id=%s",
2398 notit, notit->btr, type,
2399 bt_ctf_field_type_id_string(
2400 bt_ctf_field_type_get_type_id(type)));
e98a2d6e
PP
2401 assert(!stack_empty(notit->stack));
2402
2403 /* Pop stack */
2404 stack_pop(notit->stack);
2405
2406 /* If the stack is not empty, increment the base's index */
2407 if (!stack_empty(notit->stack)) {
2408 stack_top(notit->stack)->index++;
2409 }
2410
2411 return BT_CTF_BTR_STATUS_OK;
2412}
2413
2414static
2415struct bt_ctf_field *resolve_field(struct bt_ctf_notif_iter *notit,
2416 struct bt_ctf_field_path *path)
2417{
2418 struct bt_ctf_field *field = NULL;
2419 unsigned int i;
2420
fdf0e7a0
PP
2421 if (BT_LOG_ON_VERBOSE) {
2422 GString *gstr = bt_ctf_field_path_string(path);
2423
2424 BT_LOGV("Resolving field path: notit-addr=%p, field-path=\"%s\"",
2425 notit, gstr ? gstr->str : NULL);
2426
2427 if (gstr) {
2428 g_string_free(gstr, TRUE);
2429 }
2430 }
2431
e98a2d6e
PP
2432 switch (bt_ctf_field_path_get_root_scope(path)) {
2433 case BT_CTF_SCOPE_TRACE_PACKET_HEADER:
2434 field = notit->dscopes.trace_packet_header;
2435 break;
2436 case BT_CTF_SCOPE_STREAM_PACKET_CONTEXT:
2437 field = notit->dscopes.stream_packet_context;
2438 break;
2439 case BT_CTF_SCOPE_STREAM_EVENT_HEADER:
2440 field = notit->dscopes.stream_event_header;
2441 break;
2442 case BT_CTF_SCOPE_STREAM_EVENT_CONTEXT:
2443 field = notit->dscopes.stream_event_context;
2444 break;
2445 case BT_CTF_SCOPE_EVENT_CONTEXT:
2446 field = notit->dscopes.event_context;
2447 break;
2448 case BT_CTF_SCOPE_EVENT_FIELDS:
2449 field = notit->dscopes.event_payload;
2450 break;
2451 default:
fdf0e7a0
PP
2452 BT_LOGF("Cannot resolve field path: unknown scope: "
2453 "notit-addr=%p, root-scope=%s",
2454 notit, bt_ctf_scope_string(
2455 bt_ctf_field_path_get_root_scope(path)));
2456 abort();
e98a2d6e
PP
2457 }
2458
2459 if (!field) {
fdf0e7a0
PP
2460 BT_LOGW("Cannot resolve field path: root field not found: "
2461 "notit-addr=%p, root-scope=%s",
2462 notit, bt_ctf_scope_string(
2463 bt_ctf_field_path_get_root_scope(path)));
e98a2d6e
PP
2464 goto end;
2465 }
2466
2467 bt_get(field);
2468
2469 for (i = 0; i < bt_ctf_field_path_get_index_count(path); ++i) {
2470 struct bt_ctf_field *next_field = NULL;
2471 struct bt_ctf_field_type *field_type;
2472 int index = bt_ctf_field_path_get_index(path, i);
2473
2474 field_type = bt_ctf_field_get_type(field);
fdf0e7a0 2475 assert(field_type);
e98a2d6e
PP
2476
2477 if (is_struct_type(field_type)) {
2478 next_field = bt_ctf_field_structure_get_field_by_index(
2479 field, index);
2480 } else if (is_variant_type(field_type)) {
2481 next_field =
2482 bt_ctf_field_variant_get_current_field(field);
2483 }
2484
2485 BT_PUT(field);
2486 BT_PUT(field_type);
2487
2488 if (!next_field) {
fdf0e7a0
PP
2489 BT_LOGW("Cannot find next field: "
2490 "notit-addr=%p, ft-addr=%p, ft-id=%s, index=%d",
2491 notit, field_type,
2492 bt_ctf_field_type_id_string(
2493 bt_ctf_field_type_get_type_id(field_type)),
2494 index);
e98a2d6e
PP
2495 goto end;
2496 }
2497
2498 /* Move next field -> field */
2499 BT_MOVE(field, next_field);
2500 }
2501
2502end:
2503 return field;
2504}
2505
2506static
2507int64_t btr_get_sequence_length_cb(struct bt_ctf_field_type *type, void *data)
2508{
2509 int64_t ret = -1;
2510 int iret;
fdf0e7a0 2511 struct bt_ctf_field *seq_field;
e98a2d6e
PP
2512 struct bt_ctf_field_path *field_path;
2513 struct bt_ctf_notif_iter *notit = data;
2cf1d51e 2514 struct bt_ctf_field *length_field = NULL;
e98a2d6e
PP
2515 uint64_t length;
2516
2517 field_path = bt_ctf_field_type_sequence_get_length_field_path(type);
fdf0e7a0 2518 assert(field_path);
2cf1d51e
JG
2519 length_field = resolve_field(notit, field_path);
2520 if (!length_field) {
fdf0e7a0
PP
2521 BT_LOGW("Cannot resolve sequence field type's length field path: "
2522 "notit-addr=%p, ft-addr=%p",
2523 notit, type);
e98a2d6e
PP
2524 goto end;
2525 }
2526
2cf1d51e 2527 iret = bt_ctf_field_unsigned_integer_get_value(length_field, &length);
e98a2d6e 2528 if (iret) {
fdf0e7a0
PP
2529 BT_LOGE("Cannot get value of sequence length field: "
2530 "notit-addr=%p, field-addr=%p",
2531 notit, length_field);
e98a2d6e
PP
2532 goto end;
2533 }
2534
fdf0e7a0
PP
2535 seq_field = stack_top(notit->stack)->base;
2536 iret = bt_ctf_field_sequence_set_length(seq_field, length_field);
2cf1d51e 2537 if (iret) {
fdf0e7a0
PP
2538 BT_LOGE("Cannot set sequence field's length field: "
2539 "notit-addr=%p, seq-field-addr=%p, "
2540 "length-field-addr=%p, ",
2541 notit, seq_field, length_field);
2cf1d51e
JG
2542 goto end;
2543 }
fdf0e7a0 2544
e98a2d6e
PP
2545 ret = (int64_t) length;
2546
2547end:
2cf1d51e 2548 BT_PUT(length_field);
e98a2d6e
PP
2549 BT_PUT(field_path);
2550
2551 return ret;
2552}
2553
2554static
2555struct bt_ctf_field_type *btr_get_variant_type_cb(
2556 struct bt_ctf_field_type *type, void *data)
2557{
2558 struct bt_ctf_field_path *path;
2559 struct bt_ctf_notif_iter *notit = data;
fdf0e7a0 2560 struct bt_ctf_field *var_field;
e98a2d6e
PP
2561 struct bt_ctf_field *tag_field = NULL;
2562 struct bt_ctf_field *selected_field = NULL;
2563 struct bt_ctf_field_type *selected_field_type = NULL;
2564
2565 path = bt_ctf_field_type_variant_get_tag_field_path(type);
fdf0e7a0 2566 assert(path);
e98a2d6e
PP
2567 tag_field = resolve_field(notit, path);
2568 if (!tag_field) {
fdf0e7a0
PP
2569 BT_LOGW("Cannot resolve variant field type's tag field path: "
2570 "notit-addr=%p, ft-addr=%p",
2571 notit, type);
e98a2d6e
PP
2572 goto end;
2573 }
2574
2575 /*
2576 * We found the enumeration tag field instance which should be
2577 * able to select a current field for this variant. This
2578 * callback function we're in is called _after_
2579 * compound_begin(), so the current stack top's base field is
2580 * the variant field in question. We get the selected field here
2581 * thanks to this tag field (thus creating the selected field),
2582 * which will also provide us with its type. Then, this field
2583 * will remain the current selected one until the next callback
2584 * function call which is used to fill the current selected
2585 * field.
2586 */
fdf0e7a0
PP
2587 var_field = stack_top(notit->stack)->base;
2588 selected_field = bt_ctf_field_variant_get_field(var_field, tag_field);
e98a2d6e 2589 if (!selected_field) {
fdf0e7a0
PP
2590 BT_LOGW("Cannot get variant field's selection using tag field: "
2591 "notit-addr=%p, var-field-addr=%p, tag-field-addr=%p",
2592 notit, var_field, tag_field);
e98a2d6e
PP
2593 goto end;
2594 }
2595
2596 selected_field_type = bt_ctf_field_get_type(selected_field);
2597
2598end:
2599 BT_PUT(tag_field);
2600 BT_PUT(selected_field);
f77ae72a 2601 BT_PUT(path);
e98a2d6e
PP
2602
2603 return selected_field_type;
2604}
2605
1556a1af
JG
2606static
2607int set_event_clocks(struct bt_ctf_event *event,
2608 struct bt_ctf_notif_iter *notit)
2609{
2610 int ret;
2611 GHashTableIter iter;
ac0c6bdd 2612 struct bt_ctf_clock_class *clock_class;
1556a1af
JG
2613 uint64_t *clock_state;
2614
2615 g_hash_table_iter_init(&iter, notit->clock_states);
2616
ac0c6bdd 2617 while (g_hash_table_iter_next(&iter, (gpointer) &clock_class,
1556a1af
JG
2618 (gpointer) &clock_state)) {
2619 struct bt_ctf_clock_value *clock_value;
2620
ac0c6bdd
PP
2621 clock_value = bt_ctf_clock_value_create(clock_class,
2622 *clock_state);
1556a1af 2623 if (!clock_value) {
fdf0e7a0
PP
2624 BT_LOGE("Cannot create clock value from clock class: "
2625 "notit-addr=%p, clock-class-addr=%p, "
2626 "clock-class-name=\"%s\"",
2627 notit, clock_class,
2628 bt_ctf_clock_class_get_name(clock_class));
1556a1af
JG
2629 ret = -1;
2630 goto end;
2631 }
3f3c46b8 2632 ret = bt_ctf_event_set_clock_value(event, clock_value);
1556a1af
JG
2633 bt_put(clock_value);
2634 if (ret) {
fdf0e7a0
PP
2635 struct bt_ctf_event_class *event_class =
2636 bt_ctf_event_get_class(event);
2637
2638 assert(event_class);
2639 BT_LOGE("Cannot set event's clock value: "
2640 "notit-addr=%p, event-addr=%p, "
2641 "event-class-name=\"%s\", "
2642 "event-class-id=%" PRId64 ", "
2643 "clock-class-addr=%p, "
2644 "clock-class-name=\"%s\", "
2645 "clock-value-addr=%p",
2646 notit, event,
2647 bt_ctf_event_class_get_name(event_class),
2648 bt_ctf_event_class_get_id(event_class),
2649 clock_class,
2650 bt_ctf_clock_class_get_name(clock_class),
2651 clock_value);
2652 bt_put(event_class);
1556a1af
JG
2653 goto end;
2654 }
2655 }
fdf0e7a0 2656
1556a1af
JG
2657 ret = 0;
2658end:
2659 return ret;
2660}
2661
78586d8a
JG
2662static
2663struct bt_ctf_event *create_event(struct bt_ctf_notif_iter *notit)
e98a2d6e 2664{
e98a2d6e 2665 int ret;
78586d8a 2666 struct bt_ctf_event *event;
e98a2d6e 2667
fdf0e7a0
PP
2668 BT_LOGV("Creating event for event notification: "
2669 "notit-addr=%p, event-class-addr=%p, "
2670 "event-class-name=\"%s\", "
2671 "event-class-id=%" PRId64,
2672 notit, notit->meta.event_class,
2673 bt_ctf_event_class_get_name(notit->meta.event_class),
2674 bt_ctf_event_class_get_id(notit->meta.event_class));
2675
78586d8a 2676 /* Create event object. */
e98a2d6e
PP
2677 event = bt_ctf_event_create(notit->meta.event_class);
2678 if (!event) {
fdf0e7a0
PP
2679 BT_LOGE("Cannot create event: "
2680 "notit-addr=%p, event-class-addr=%p, "
2681 "event-class-name=\"%s\", "
2682 "event-class-id=%" PRId64,
2683 notit, notit->meta.event_class,
2684 bt_ctf_event_class_get_name(notit->meta.event_class),
2685 bt_ctf_event_class_get_id(notit->meta.event_class));
e98a2d6e
PP
2686 goto error;
2687 }
2688
78586d8a 2689 /* Set header, stream event context, context, and payload fields. */
e98a2d6e
PP
2690 ret = bt_ctf_event_set_header(event,
2691 notit->dscopes.stream_event_header);
2692 if (ret) {
fdf0e7a0
PP
2693 BT_LOGE("Cannot set event's header field: "
2694 "notit-addr=%p, event-addr=%p, event-class-addr=%p, "
2695 "event-class-name=\"%s\", "
2696 "event-class-id=%" PRId64 ", field-addr=%p",
2697 notit, event, notit->meta.event_class,
2698 bt_ctf_event_class_get_name(notit->meta.event_class),
2699 bt_ctf_event_class_get_id(notit->meta.event_class),
2700 notit->dscopes.stream_event_header);
e98a2d6e
PP
2701 goto error;
2702 }
2703
2704 ret = bt_ctf_event_set_stream_event_context(event,
2705 notit->dscopes.stream_event_context);
2706 if (ret) {
fdf0e7a0
PP
2707 BT_LOGE("Cannot set event's context field: "
2708 "notit-addr=%p, event-addr=%p, event-class-addr=%p, "
2709 "event-class-name=\"%s\", "
2710 "event-class-id=%" PRId64 ", field-addr=%p",
2711 notit, event, notit->meta.event_class,
2712 bt_ctf_event_class_get_name(notit->meta.event_class),
2713 bt_ctf_event_class_get_id(notit->meta.event_class),
2714 notit->dscopes.stream_event_context);
e98a2d6e
PP
2715 goto error;
2716 }
2717
2718 ret = bt_ctf_event_set_event_context(event,
2719 notit->dscopes.event_context);
2720 if (ret) {
fdf0e7a0
PP
2721 BT_LOGE("Cannot set event's stream event context field: "
2722 "notit-addr=%p, event-addr=%p, event-class-addr=%p, "
2723 "event-class-name=\"%s\", "
2724 "event-class-id=%" PRId64 ", field-addr=%p",
2725 notit, event, notit->meta.event_class,
2726 bt_ctf_event_class_get_name(notit->meta.event_class),
2727 bt_ctf_event_class_get_id(notit->meta.event_class),
2728 notit->dscopes.event_context);
e98a2d6e
PP
2729 goto error;
2730 }
2731
9ac68eb1 2732 ret = bt_ctf_event_set_event_payload(event,
e98a2d6e
PP
2733 notit->dscopes.event_payload);
2734 if (ret) {
fdf0e7a0
PP
2735 BT_LOGE("Cannot set event's payload field: "
2736 "notit-addr=%p, event-addr=%p, event-class-addr=%p, "
2737 "event-class-name=\"%s\", "
2738 "event-class-id=%" PRId64 ", field-addr=%p",
2739 notit, event, notit->meta.event_class,
2740 bt_ctf_event_class_get_name(notit->meta.event_class),
2741 bt_ctf_event_class_get_id(notit->meta.event_class),
2742 notit->dscopes.event_payload);
e98a2d6e
PP
2743 goto error;
2744 }
2745
1556a1af
JG
2746 ret = set_event_clocks(event, notit);
2747 if (ret) {
fdf0e7a0
PP
2748 BT_LOGE("Cannot set event's clock values: "
2749 "notit-addr=%p, event-addr=%p, event-class-addr=%p, "
2750 "event-class-name=\"%s\", "
2751 "event-class-id=%" PRId64,
2752 notit, event, notit->meta.event_class,
2753 bt_ctf_event_class_get_name(notit->meta.event_class),
2754 bt_ctf_event_class_get_id(notit->meta.event_class));
1556a1af
JG
2755 goto error;
2756 }
2757
78586d8a 2758 /* Associate with current packet. */
e98a2d6e
PP
2759 assert(notit->packet);
2760 ret = bt_ctf_event_set_packet(event, notit->packet);
2761 if (ret) {
fdf0e7a0
PP
2762 BT_LOGE("Cannot set event's header field: "
2763 "notit-addr=%p, event-addr=%p, event-class-addr=%p, "
2764 "event-class-name=\"%s\", "
2765 "event-class-id=%" PRId64 ", packet-addr=%p",
2766 notit, event, notit->meta.event_class,
2767 bt_ctf_event_class_get_name(notit->meta.event_class),
2768 bt_ctf_event_class_get_id(notit->meta.event_class),
2769 notit->packet);
e98a2d6e
PP
2770 goto error;
2771 }
2772
2773 goto end;
fdf0e7a0 2774
e98a2d6e
PP
2775error:
2776 BT_PUT(event);
fdf0e7a0 2777
e98a2d6e
PP
2778end:
2779 return event;
2780}
2781
b92735af
PP
2782static
2783uint64_t get_cur_stream_instance_id(struct bt_ctf_notif_iter *notit)
2784{
2785 struct bt_ctf_field *stream_instance_id_field = NULL;
2786 uint64_t stream_instance_id = -1ULL;
2787 int ret;
2788
2789 if (!notit->dscopes.trace_packet_header) {
2790 goto end;
2791 }
2792
2793 stream_instance_id_field = bt_ctf_field_structure_get_field_by_name(
2794 notit->dscopes.trace_packet_header, "stream_instance_id");
2795 if (!stream_instance_id_field) {
2796 goto end;
2797 }
2798
2799 ret = bt_ctf_field_unsigned_integer_get_value(stream_instance_id_field,
2800 &stream_instance_id);
2801 if (ret) {
2802 stream_instance_id = -1ULL;
2803 goto end;
2804 }
2805
2806end:
2807 bt_put(stream_instance_id_field);
2808 return stream_instance_id;
2809}
2810
78586d8a 2811static
af87daef 2812int set_stream(struct bt_ctf_notif_iter *notit)
e98a2d6e 2813{
af87daef 2814 int ret = 0;
e98a2d6e 2815 struct bt_ctf_stream *stream = NULL;
e98a2d6e 2816
fdf0e7a0
PP
2817 BT_LOGV("Calling user function (get stream): notit-addr=%p, "
2818 "stream-class-addr=%p, stream-class-name=\"%s\", "
2819 "stream-class-id=%" PRId64,
2820 notit, notit->meta.stream_class,
2821 bt_ctf_stream_class_get_name(notit->meta.stream_class),
2822 bt_ctf_stream_class_get_id(notit->meta.stream_class));
af87daef 2823 stream = bt_get(notit->medium.medops.get_stream(
b92735af
PP
2824 notit->meta.stream_class, get_cur_stream_instance_id(notit),
2825 notit->medium.data));
af87daef 2826 BT_LOGV("User function returned: stream-addr=%p", stream);
e98a2d6e 2827 if (!stream) {
fdf0e7a0 2828 BT_LOGW_STR("User function failed to return a stream object for the given stream class.");
af87daef
PP
2829 ret = -1;
2830 goto end;
2831 }
2832
2833 if (notit->stream && stream != notit->stream) {
2834 BT_LOGW("User function returned a different stream than the previous one for the same sequence of packets.");
2835 ret = -1;
2836 goto end;
2837 }
2838
2839 BT_MOVE(notit->stream, stream);
2840
2841end:
2842 bt_put(stream);
2843 return ret;
2844}
2845
2846static
2847void create_packet(struct bt_ctf_notif_iter *notit)
2848{
2849 int ret;
2850 struct bt_ctf_packet *packet = NULL;
2851
2852 BT_LOGV("Creating packet for packet notification: "
2853 "notit-addr=%p", notit);
2854
2855 /* Ask the user for the stream */
2856 ret = set_stream(notit);
2857 if (ret) {
e98a2d6e
PP
2858 goto error;
2859 }
2860
fdf0e7a0
PP
2861 BT_LOGV("Creating packet from stream: "
2862 "notit-addr=%p, stream-addr=%p, "
2863 "stream-class-addr=%p, "
2864 "stream-class-name=\"%s\", "
2865 "stream-class-id=%" PRId64,
af87daef 2866 notit, notit->stream, notit->meta.stream_class,
fdf0e7a0
PP
2867 bt_ctf_stream_class_get_name(notit->meta.stream_class),
2868 bt_ctf_stream_class_get_id(notit->meta.stream_class));
2869
e98a2d6e 2870 /* Create packet */
af87daef 2871 packet = bt_ctf_packet_create(notit->stream);
e98a2d6e 2872 if (!packet) {
fdf0e7a0
PP
2873 BT_LOGE("Cannot create packet from stream: "
2874 "notit-addr=%p, stream-addr=%p, "
2875 "stream-class-addr=%p, "
2876 "stream-class-name=\"%s\", "
2877 "stream-class-id=%" PRId64,
af87daef 2878 notit, notit->stream, notit->meta.stream_class,
fdf0e7a0
PP
2879 bt_ctf_stream_class_get_name(notit->meta.stream_class),
2880 bt_ctf_stream_class_get_id(notit->meta.stream_class));
e98a2d6e
PP
2881 goto error;
2882 }
2883
2884 /* Set packet's context and header fields */
2885 if (notit->dscopes.trace_packet_header) {
2886 ret = bt_ctf_packet_set_header(packet,
fdf0e7a0 2887 notit->dscopes.trace_packet_header);
e98a2d6e 2888 if (ret) {
fdf0e7a0
PP
2889 BT_LOGE("Cannot set packet's header field: "
2890 "notit-addr=%p, packet-addr=%p, "
2891 "stream-addr=%p, "
2892 "stream-class-addr=%p, "
2893 "stream-class-name=\"%s\", "
2894 "stream-class-id=%" PRId64 ", "
2895 "field-addr=%p",
af87daef 2896 notit, packet, notit->stream, notit->meta.stream_class,
fdf0e7a0
PP
2897 bt_ctf_stream_class_get_name(notit->meta.stream_class),
2898 bt_ctf_stream_class_get_id(notit->meta.stream_class),
2899 notit->dscopes.trace_packet_header);
e98a2d6e
PP
2900 goto error;
2901 }
2902 }
2903
2904 if (notit->dscopes.stream_packet_context) {
2905 ret = bt_ctf_packet_set_context(packet,
fdf0e7a0 2906 notit->dscopes.stream_packet_context);
e98a2d6e 2907 if (ret) {
fdf0e7a0
PP
2908 BT_LOGE("Cannot set packet's context field: "
2909 "notit-addr=%p, packet-addr=%p, "
2910 "stream-addr=%p, "
2911 "stream-class-addr=%p, "
2912 "stream-class-name=\"%s\", "
2913 "stream-class-id=%" PRId64 ", "
2914 "field-addr=%p",
af87daef 2915 notit, packet, notit->stream, notit->meta.stream_class,
fdf0e7a0
PP
2916 bt_ctf_stream_class_get_name(notit->meta.stream_class),
2917 bt_ctf_stream_class_get_id(notit->meta.stream_class),
2918 notit->dscopes.trace_packet_header);
e98a2d6e
PP
2919 goto error;
2920 }
2921 }
2922
2923 goto end;
fdf0e7a0 2924
e98a2d6e
PP
2925error:
2926 BT_PUT(packet);
fdf0e7a0 2927
e98a2d6e
PP
2928end:
2929 BT_MOVE(notit->packet, packet);
2930}
2931
78586d8a
JG
2932static
2933void notify_new_packet(struct bt_ctf_notif_iter *notit,
2934 struct bt_notification **notification)
e98a2d6e 2935{
78586d8a 2936 struct bt_notification *ret;
e98a2d6e 2937
78586d8a 2938 /* Initialize the iterator's current packet */
e98a2d6e
PP
2939 create_packet(notit);
2940 if (!notit->packet) {
fdf0e7a0
PP
2941 BT_LOGE("Cannot create packet for packet notification: "
2942 "notit-addr=%p", notit);
78586d8a 2943 return;
e98a2d6e
PP
2944 }
2945
ea0e619e 2946 ret = bt_notification_packet_begin_create(notit->packet);
78586d8a 2947 if (!ret) {
fdf0e7a0
PP
2948 BT_LOGE("Cannot create packet beginning notification: "
2949 "notit-addr=%p, packet-addr=%p",
2950 notit, notit->packet);
78586d8a
JG
2951 return;
2952 }
2953 *notification = ret;
e98a2d6e
PP
2954}
2955
78586d8a
JG
2956static
2957void notify_end_of_packet(struct bt_ctf_notif_iter *notit,
2958 struct bt_notification **notification)
e98a2d6e 2959{
78586d8a 2960 struct bt_notification *ret;
e98a2d6e 2961
e98a2d6e 2962 if (!notit->packet) {
78586d8a 2963 return;
e98a2d6e
PP
2964 }
2965
78586d8a
JG
2966 ret = bt_notification_packet_end_create(notit->packet);
2967 if (!ret) {
fdf0e7a0
PP
2968 BT_LOGE("Cannot create packet end notification: "
2969 "notit-addr=%p, packet-addr=%p",
2970 notit, notit->packet);
78586d8a
JG
2971 return;
2972 }
2973 BT_PUT(notit->packet);
2974 *notification = ret;
e98a2d6e
PP
2975}
2976
78586d8a
JG
2977static
2978void notify_event(struct bt_ctf_notif_iter *notit,
0982a26d 2979 struct bt_clock_class_priority_map *cc_prio_map,
78586d8a 2980 struct bt_notification **notification)
e98a2d6e 2981{
174e773b 2982 struct bt_ctf_event *event = NULL;
78586d8a 2983 struct bt_notification *ret = NULL;
e98a2d6e 2984
174e773b
PP
2985 /* Make sure that the event contains at least one bit of data */
2986 if (notit->buf.at == notit->buf.last_eh_at) {
2987 BT_LOGE("Cannot create empty event with 0 bits of data: "
2988 "notit-addr=%p, packet-cur=%zu",
2989 notit, packet_at(notit));
2990 goto end;
2991 }
2992
e98a2d6e
PP
2993 /* Create event */
2994 event = create_event(notit);
2995 if (!event) {
fdf0e7a0
PP
2996 BT_LOGE("Cannot create event for event notification: "
2997 "notit-addr=%p", notit);
78586d8a 2998 goto end;
e98a2d6e 2999 }
e98a2d6e 3000
0982a26d 3001 ret = bt_notification_event_create(event, cc_prio_map);
78586d8a 3002 if (!ret) {
fdf0e7a0
PP
3003 BT_LOGE("Cannot create event notification: "
3004 "notit-addr=%p, event-addr=%p, "
3005 "cc-prio-map-addr=%p",
3006 notit, event, cc_prio_map);
78586d8a 3007 goto end;
e98a2d6e 3008 }
78586d8a
JG
3009 *notification = ret;
3010end:
3011 BT_PUT(event);
e98a2d6e
PP
3012}
3013
5f870343
JG
3014static
3015void init_trace_field_path_cache(struct bt_ctf_trace *trace,
3016 struct trace_field_path_cache *trace_field_path_cache)
3017{
3018 int stream_id = -1;
3019 int stream_instance_id = -1;
3020 int i, count;
3021 struct bt_ctf_field_type *packet_header = NULL;
3022
3023 packet_header = bt_ctf_trace_get_packet_header_type(trace);
3024 if (!packet_header) {
3025 goto end;
3026 }
3027
3028 if (!bt_ctf_field_type_is_structure(packet_header)) {
3029 goto end;
3030 }
3031
3032 count = bt_ctf_field_type_structure_get_field_count(packet_header);
fdf0e7a0 3033 assert(count >= 0);
5f870343
JG
3034
3035 for (i = 0; (i < count && (stream_id == -1 || stream_instance_id == -1)); i++) {
3036 int ret;
3037 const char *field_name;
3038
3039 ret = bt_ctf_field_type_structure_get_field(packet_header,
3040 &field_name, NULL, i);
3041 if (ret) {
fdf0e7a0
PP
3042 BT_LOGE("Cannot get structure field's field: "
3043 "field-addr=%p, index=%d",
3044 packet_header, i);
5f870343
JG
3045 goto end;
3046 }
3047
3048 if (stream_id == -1 && !strcmp(field_name, "stream_id")) {
3049 stream_id = i;
3050 } else if (stream_instance_id == -1 &&
3051 !strcmp(field_name, "stream_instance_id")) {
3052 stream_instance_id = i;
3053 }
3054 }
fdf0e7a0 3055
5f870343
JG
3056end:
3057 trace_field_path_cache->stream_id = stream_id;
3058 trace_field_path_cache->stream_instance_id = stream_instance_id;
3059 BT_PUT(packet_header);
3060}
3061
c44c3e70 3062BT_HIDDEN
e98a2d6e
PP
3063struct bt_ctf_notif_iter *bt_ctf_notif_iter_create(struct bt_ctf_trace *trace,
3064 size_t max_request_sz,
55314f2a 3065 struct bt_ctf_notif_iter_medium_ops medops, void *data)
e98a2d6e
PP
3066{
3067 struct bt_ctf_notif_iter *notit = NULL;
3068 struct bt_ctf_btr_cbs cbs = {
3069 .types = {
3070 .signed_int = btr_signed_int_cb,
3071 .unsigned_int = btr_unsigned_int_cb,
3072 .floating_point = btr_floating_point_cb,
3073 .string_begin = btr_string_begin_cb,
3074 .string = btr_string_cb,
3075 .string_end = btr_string_end_cb,
3076 .compound_begin = btr_compound_begin_cb,
3077 .compound_end = btr_compound_end_cb,
3078 },
3079 .query = {
3080 .get_sequence_length = btr_get_sequence_length_cb,
3081 .get_variant_type = btr_get_variant_type_cb,
3082 },
3083 };
3084
3085 assert(trace);
3086 assert(medops.request_bytes);
f3985ab1 3087 assert(medops.get_stream);
fdf0e7a0
PP
3088 BT_LOGD("Creating CTF plugin notification iterator: "
3089 "trace-addr=%p, trace-name=\"%s\", max-request-size=%zu, "
3090 "data=%p",
3091 trace, bt_ctf_trace_get_name(trace), max_request_sz, data);
e98a2d6e
PP
3092 notit = g_new0(struct bt_ctf_notif_iter, 1);
3093 if (!notit) {
fdf0e7a0 3094 BT_LOGE_STR("Failed to allocate one CTF plugin notification iterator.");
e98a2d6e
PP
3095 goto end;
3096 }
c44c3e70 3097 notit->clock_states = g_hash_table_new_full(g_direct_hash,
fdf0e7a0 3098 g_direct_equal, bt_put, g_free);
c44c3e70 3099 if (!notit->clock_states) {
fdf0e7a0 3100 BT_LOGE_STR("Failed to allocate a GHashTable.");
c44c3e70
JG
3101 goto error;
3102 }
35d47007 3103 notit->meta.trace = bt_get(trace);
e98a2d6e
PP
3104 notit->medium.medops = medops;
3105 notit->medium.max_request_sz = max_request_sz;
3106 notit->medium.data = data;
e98a2d6e
PP
3107 notit->stack = stack_new(notit);
3108 if (!notit->stack) {
fdf0e7a0 3109 BT_LOGE_STR("Failed to create field stack.");
c44c3e70 3110 goto error;
e98a2d6e
PP
3111 }
3112
55314f2a 3113 notit->btr = bt_ctf_btr_create(cbs, notit);
e98a2d6e 3114 if (!notit->btr) {
fdf0e7a0 3115 BT_LOGE_STR("Failed to create binary type reader (BTR).");
c44c3e70 3116 goto error;
e98a2d6e
PP
3117 }
3118
3119 bt_ctf_notif_iter_reset(notit);
5f870343
JG
3120 init_trace_field_path_cache(trace, &notit->trace_field_path_cache);
3121 notit->sc_field_path_caches = g_hash_table_new_full(g_direct_hash,
fdf0e7a0 3122 g_direct_equal, bt_put, g_free);
5f870343 3123 if (!notit->sc_field_path_caches) {
fdf0e7a0 3124 BT_LOGE_STR("Failed to allocate a GHashTable.");
5f870343
JG
3125 goto error;
3126 }
3127
3128 notit->field_overrides = g_hash_table_new_full(g_direct_hash,
fdf0e7a0 3129 g_direct_equal, bt_put, g_free);
5f870343 3130 if (!notit->field_overrides) {
fdf0e7a0 3131 BT_LOGE_STR("Failed to allocate a GHashTable.");
5f870343
JG
3132 goto error;
3133 }
3134
fdf0e7a0
PP
3135 BT_LOGD("Created CTF plugin notification iterator: "
3136 "trace-addr=%p, trace-name=\"%s\", max-request-size=%zu, "
3137 "data=%p, notit-addr=%p",
3138 trace, bt_ctf_trace_get_name(trace), max_request_sz, data,
3139 notit);
3140
e98a2d6e
PP
3141end:
3142 return notit;
fdf0e7a0 3143
c44c3e70
JG
3144error:
3145 bt_ctf_notif_iter_destroy(notit);
3146 notit = NULL;
3147 goto end;
e98a2d6e
PP
3148}
3149
3150void bt_ctf_notif_iter_destroy(struct bt_ctf_notif_iter *notit)
3151{
3152 BT_PUT(notit->meta.trace);
3153 BT_PUT(notit->meta.stream_class);
3154 BT_PUT(notit->meta.event_class);
3155 BT_PUT(notit->packet);
af87daef 3156 BT_PUT(notit->stream);
5f870343 3157 BT_PUT(notit->cur_timestamp_end);
e98a2d6e
PP
3158 put_all_dscopes(notit);
3159
fdf0e7a0
PP
3160 BT_LOGD("Destroying CTF plugin notification iterator: addr=%p", notit);
3161
e98a2d6e 3162 if (notit->stack) {
fdf0e7a0 3163 BT_LOGD_STR("Destroying field stack.");
e98a2d6e
PP
3164 stack_destroy(notit->stack);
3165 }
3166
3167 if (notit->btr) {
fdf0e7a0 3168 BT_LOGD("Destroying BTR: btr-addr=%p", notit->btr);
e98a2d6e
PP
3169 bt_ctf_btr_destroy(notit->btr);
3170 }
3171
c44c3e70
JG
3172 if (notit->clock_states) {
3173 g_hash_table_destroy(notit->clock_states);
3174 }
5f870343
JG
3175
3176 if (notit->sc_field_path_caches) {
3177 g_hash_table_destroy(notit->sc_field_path_caches);
3178 }
3179
3180 if (notit->field_overrides) {
3181 g_hash_table_destroy(notit->field_overrides);
3182 }
fdf0e7a0 3183
e98a2d6e
PP
3184 g_free(notit);
3185}
3186
3187enum bt_ctf_notif_iter_status bt_ctf_notif_iter_get_next_notification(
3188 struct bt_ctf_notif_iter *notit,
0982a26d 3189 struct bt_clock_class_priority_map *cc_prio_map,
78586d8a 3190 struct bt_notification **notification)
e98a2d6e
PP
3191{
3192 enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
3193
3194 assert(notit);
3195 assert(notification);
3196
fdf0e7a0
PP
3197 BT_LOGV("Getting next notification: notit-addr=%p, cc-prio-map-addr=%p",
3198 notit, cc_prio_map);
3199
e98a2d6e
PP
3200 while (true) {
3201 status = handle_state(notit);
7cdc2bab 3202 if (status == BT_CTF_NOTIF_ITER_STATUS_AGAIN) {
fdf0e7a0 3203 BT_LOGV_STR("Medium returned BT_CTF_NOTIF_ITER_STATUS_AGAIN.");
7cdc2bab
MD
3204 goto end;
3205 }
e98a2d6e
PP
3206 if (status != BT_CTF_NOTIF_ITER_STATUS_OK) {
3207 if (status == BT_CTF_NOTIF_ITER_STATUS_EOF) {
fdf0e7a0 3208 BT_LOGV_STR("Medium returned BT_CTF_NOTIF_ITER_STATUS_EOF.");
e98a2d6e 3209 } else {
fdf0e7a0
PP
3210 BT_LOGW("Cannot handle state: "
3211 "notit-addr=%p, state=%s",
3212 notit, state_string(notit->state));
e98a2d6e
PP
3213 }
3214 goto end;
3215 }
3216
3217 switch (notit->state) {
3218 case STATE_EMIT_NOTIF_NEW_PACKET:
fdf0e7a0 3219 /* notify_new_packet() logs errors */
e98a2d6e
PP
3220 notify_new_packet(notit, notification);
3221 if (!*notification) {
3222 status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
3223 }
3224 goto end;
3225 case STATE_EMIT_NOTIF_EVENT:
fdf0e7a0 3226 /* notify_event() logs errors */
0982a26d 3227 notify_event(notit, cc_prio_map, notification);
e98a2d6e
PP
3228 if (!*notification) {
3229 status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
3230 }
3231 goto end;
3232 case STATE_EMIT_NOTIF_END_OF_PACKET:
5f870343
JG
3233 /* Update clock with timestamp_end field. */
3234 if (notit->cur_timestamp_end) {
3235 enum bt_ctf_btr_status btr_status;
3236 struct bt_ctf_field_type *field_type =
3237 bt_ctf_field_get_type(
3238 notit->cur_timestamp_end);
3239
fdf0e7a0 3240 assert(field_type);
f45bfe88
PP
3241 btr_status = update_clock(notit,
3242 notit->cur_timestamp_end);
5f870343
JG
3243 BT_PUT(field_type);
3244 if (btr_status != BT_CTF_BTR_STATUS_OK) {
fdf0e7a0
PP
3245 BT_LOGW("Cannot update stream's clock value: "
3246 "notit-addr=%p", notit);
5f870343
JG
3247 status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
3248 goto end;
3249 }
3250 }
3251
fdf0e7a0 3252 /* notify_end_of_packet() logs errors */
e98a2d6e
PP
3253 notify_end_of_packet(notit, notification);
3254 if (!*notification) {
3255 status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
3256 }
3257 goto end;
3258 default:
3259 /* Non-emitting state: continue */
3260 break;
3261 }
3262 }
3263
3264end:
3265 return status;
3266}
87187cbf
PP
3267
3268BT_HIDDEN
3269enum bt_ctf_notif_iter_status bt_ctf_notif_iter_get_packet_header_context_fields(
3270 struct bt_ctf_notif_iter *notit,
3271 struct bt_ctf_field **packet_header_field,
3272 struct bt_ctf_field **packet_context_field)
3273{
3274 enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
3275
3276 assert(notit);
3277
3278 if (notit->state == STATE_EMIT_NOTIF_NEW_PACKET) {
3279 /* We're already there */
3280 goto set_fields;
3281 }
3282
3283 while (true) {
3284 status = handle_state(notit);
3285 if (status == BT_CTF_NOTIF_ITER_STATUS_AGAIN) {
fdf0e7a0 3286 BT_LOGV_STR("Medium returned BT_CTF_NOTIF_ITER_STATUS_AGAIN.");
87187cbf
PP
3287 goto end;
3288 }
3289 if (status != BT_CTF_NOTIF_ITER_STATUS_OK) {
3290 if (status == BT_CTF_NOTIF_ITER_STATUS_EOF) {
fdf0e7a0 3291 BT_LOGV_STR("Medium returned BT_CTF_NOTIF_ITER_STATUS_EOF.");
87187cbf 3292 } else {
fdf0e7a0
PP
3293 BT_LOGW("Cannot handle state: "
3294 "notit-addr=%p, state=%s",
3295 notit, state_string(notit->state));
87187cbf
PP
3296 }
3297 goto end;
3298 }
3299
3300 switch (notit->state) {
3301 case STATE_EMIT_NOTIF_NEW_PACKET:
3302 /*
3303 * Packet header and context fields are
3304 * potentially decoded (or they don't exist).
3305 */
3306 goto set_fields;
3307 case STATE_INIT:
3308 case STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN:
3309 case STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE:
3310 case STATE_AFTER_TRACE_PACKET_HEADER:
3311 case STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN:
3312 case STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE:
3313 case STATE_AFTER_STREAM_PACKET_CONTEXT:
3314 /* Non-emitting state: continue */
3315 break;
3316 default:
3317 /*
3318 * We should never get past the
3319 * STATE_EMIT_NOTIF_NEW_PACKET state.
3320 */
fdf0e7a0
PP
3321 BT_LOGF("Unexpected state: notit-addr=%p, state=%s",
3322 notit, state_string(notit->state));
0fbb9a9f 3323 abort();
87187cbf
PP
3324 }
3325 }
3326
3327set_fields:
3328 if (packet_header_field) {
3329 *packet_header_field = bt_get(notit->dscopes.trace_packet_header);
3330 }
3331
3332 if (packet_context_field) {
3333 *packet_context_field = bt_get(notit->dscopes.stream_packet_context);
3334 }
3335
3336end:
3337 return status;
3338}
6de92955
PP
3339
3340BT_HIDDEN
3341void bt_ctf_notif_iter_set_medops_data(struct bt_ctf_notif_iter *notit,
3342 void *medops_data)
3343{
3344 assert(notit);
3345 notit->medium.data = medops_data;
3346}
This page took 0.229398 seconds and 4 git commands to generate.