Port: use SIZE_MAX as max size_t value
[babeltrace.git] / plugins / ctf / common / notif-iter / notif-iter.c
1 /*
2 * Babeltrace - CTF notification iterator
3 *
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
26 #define BT_LOG_TAG "PLUGIN-CTF-NOTIF-ITER"
27 #include "logging.h"
28
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>
37 #include <babeltrace/ctf-ir/field-types-internal.h>
38 #include <babeltrace/ctf-ir/field-path.h>
39 #include <babeltrace/ctf-ir/field-path-internal.h>
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>
44 #include <babeltrace/ctf-ir/clock-class.h>
45 #include <babeltrace/ctf-ir/event-class.h>
46 #include <babeltrace/graph/notification-packet.h>
47 #include <babeltrace/graph/notification-event.h>
48 #include <babeltrace/graph/notification-stream.h>
49 #include <babeltrace/graph/clock-class-priority-map.h>
50 #include <babeltrace/ref.h>
51 #include <glib.h>
52 #include <stdlib.h>
53
54 #include "notif-iter.h"
55 #include "../btr/btr.h"
56
57 struct bt_ctf_notif_iter;
58
59 /* A visit stack entry */
60 struct 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 */
79 struct stack {
80 /* Entries (struct stack_entry *) (top is last element) */
81 GPtrArray *entries;
82 };
83
84 /* State */
85 enum 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
108 struct 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
117 struct 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
135 struct 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
141 /* CTF notification iterator */
142 struct bt_ctf_notif_iter {
143 /* Visit stack */
144 struct stack *stack;
145
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
165 /* Current stream (NULL if not set yet) */
166 struct bt_ctf_stream *stream;
167
168 /*
169 * Current timestamp_end field (to consider before switching packets).
170 */
171 struct bt_ctf_field *cur_timestamp_end;
172
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
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
198 /* Current state */
199 enum state state;
200
201 /* Current medium buffer data */
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;
214
215 /* Position of the last event header from addr (bits) */
216 size_t last_eh_at;
217 } buf;
218
219 /* Binary type reader */
220 struct bt_ctf_btr *btr;
221
222 /* Current medium data */
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) */
230 int64_t cur_packet_size;
231
232 /* Current content size (bits) (-1 if unknown) */
233 int64_t cur_content_size;
234
235 /* bt_ctf_clock_class to uint64_t. */
236 GHashTable *clock_states;
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;
252 };
253
254 static inline
255 const 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
303 static
304 int bt_ctf_notif_iter_switch_packet(struct bt_ctf_notif_iter *notit);
305
306 static
307 enum bt_ctf_btr_status btr_timestamp_end_cb(void *value,
308 struct bt_ctf_field_type *type, void *data);
309
310 static
311 void 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
319 static
320 struct 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) {
326 BT_LOGE_STR("Failed to allocate one stack.");
327 goto error;
328 }
329
330 stack->entries = g_ptr_array_new_with_free_func(stack_entry_free_func);
331 if (!stack->entries) {
332 BT_LOGE_STR("Failed to allocate a GPtrArray.");
333 goto error;
334 }
335
336 BT_LOGD("Created stack: notit-addr=%p, stack-addr=%p", notit, stack);
337 return stack;
338
339 error:
340 g_free(stack);
341 return NULL;
342 }
343
344 static
345 void stack_destroy(struct stack *stack)
346 {
347 assert(stack);
348 BT_LOGD("Destroying stack: addr=%p", stack);
349 g_ptr_array_free(stack->entries, TRUE);
350 g_free(stack);
351 }
352
353 static
354 int stack_push(struct stack *stack, struct bt_ctf_field *base)
355 {
356 int ret = 0;
357 struct stack_entry *entry;
358
359 assert(stack);
360 assert(base);
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);
364 entry = g_new0(struct stack_entry, 1);
365 if (!entry) {
366 BT_LOGE_STR("Failed to allocate one stack entry.");
367 ret = -1;
368 goto end;
369 }
370
371 entry->base = bt_get(base);
372 g_ptr_array_add(stack->entries, entry);
373
374 end:
375 return ret;
376 }
377
378 static inline
379 unsigned int stack_size(struct stack *stack)
380 {
381 assert(stack);
382
383 return stack->entries->len;
384 }
385
386 static
387 void stack_pop(struct stack *stack)
388 {
389 assert(stack);
390 assert(stack_size(stack));
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);
394 g_ptr_array_remove_index(stack->entries, stack->entries->len - 1);
395 }
396
397 static inline
398 struct 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
406 static inline
407 bool stack_empty(struct stack *stack)
408 {
409 return stack_size(stack) == 0;
410 }
411
412 static
413 void stack_clear(struct stack *stack)
414 {
415 assert(stack);
416
417 if (!stack_empty(stack)) {
418 BT_LOGV("Clearing stack: stack-addr=%p, stack-size=%u",
419 stack, stack->entries->len);
420 g_ptr_array_remove_range(stack->entries, 0, stack_size(stack));
421 }
422
423 assert(stack_empty(stack));
424 }
425
426 static inline
427 enum bt_ctf_notif_iter_status notif_iter_status_from_m_status(
428 enum bt_ctf_notif_iter_medium_status m_status)
429 {
430 return (int) m_status;
431 }
432
433 static inline
434 size_t buf_size_bits(struct bt_ctf_notif_iter *notit)
435 {
436 return notit->buf.sz * 8;
437 }
438
439 static inline
440 size_t buf_available_bits(struct bt_ctf_notif_iter *notit)
441 {
442 return buf_size_bits(notit) - notit->buf.at;
443 }
444
445 static inline
446 size_t packet_at(struct bt_ctf_notif_iter *notit)
447 {
448 return notit->buf.packet_offset + notit->buf.at;
449 }
450
451 static inline
452 void buf_consume_bits(struct bt_ctf_notif_iter *notit, size_t incr)
453 {
454 BT_LOGV("Advancing cursor: notit-addr=%p, cur-before=%zu, cur-after=%zu",
455 notit, notit->buf.at, notit->buf.at + incr);
456 notit->buf.at += incr;
457 }
458
459 static
460 enum bt_ctf_notif_iter_status request_medium_bytes(
461 struct bt_ctf_notif_iter *notit)
462 {
463 uint8_t *buffer_addr = NULL;
464 size_t buffer_sz = 0;
465 enum bt_ctf_notif_iter_medium_status m_status;
466
467 BT_LOGV("Calling user function (request bytes): notit-addr=%p, "
468 "request-size=%zu", notit, notit->medium.max_request_sz);
469 m_status = notit->medium.medops.request_bytes(
470 notit->medium.max_request_sz, &buffer_addr,
471 &buffer_sz, notit->medium.data);
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);
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;
483 notit->buf.last_eh_at = SIZE_MAX;
484
485 /* New medium buffer size */
486 notit->buf.sz = buffer_sz;
487
488 /* New medium buffer address */
489 notit->buf.addr = buffer_addr;
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);
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
580 bad_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
588 good_state:
589 bt_put(eh_ft);
590 bt_put(sec_ft);
591 bt_put(ec_ft);
592 } else if (m_status < 0) {
593 BT_LOGW("User function failed: status=%s",
594 bt_ctf_notif_iter_medium_status_string(m_status));
595 }
596
597 return notif_iter_status_from_m_status(m_status);
598 }
599
600 static inline
601 enum 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
617 static
618 enum 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) {
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
640 goto end;
641 }
642
643 bt_put(*dscope_field);
644 notit->cur_dscope_field = dscope_field;
645 BT_LOGV("Starting BTR: notit-addr=%p, btr-addr=%p, ft-addr=%p",
646 notit, notit->btr, dscope_field_type);
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);
650 BT_LOGV("BTR consumed bits: size=%zu", consumed_bits);
651
652 switch (btr_status) {
653 case BT_CTF_BTR_STATUS_OK:
654 /* type was read completely */
655 BT_LOGV_STR("Field was completely decoded.");
656 notit->state = done_state;
657 break;
658 case BT_CTF_BTR_STATUS_EOF:
659 BT_LOGV_STR("BTR needs more data to decode field completely.");
660 notit->state = continue_state;
661 break;
662 default:
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));
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
673 end:
674 return status;
675 }
676
677 static
678 enum 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) {
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
697 goto end;
698 }
699
700 BT_LOGV("Continuing BTR: notit-addr=%p, btr-addr=%p",
701 notit, notit->btr);
702 consumed_bits = bt_ctf_btr_continue(notit->btr, notit->buf.addr,
703 notit->buf.sz, &btr_status);
704 BT_LOGV("BTR consumed bits: size=%zu", consumed_bits);
705
706 switch (btr_status) {
707 case BT_CTF_BTR_STATUS_OK:
708 /* Type was read completely. */
709 BT_LOGV_STR("Field was completely decoded.");
710 notit->state = done_state;
711 break;
712 case BT_CTF_BTR_STATUS_EOF:
713 /* Stay in this continue state. */
714 BT_LOGV_STR("BTR needs more data to decode field completely.");
715 break;
716 default:
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));
720 status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
721 goto end;
722 }
723
724 /* Consume bits now since we know we're not in an error state. */
725 buf_consume_bits(notit, consumed_bits);
726 end:
727 return status;
728 }
729
730 static
731 void put_event_dscopes(struct bt_ctf_notif_iter *notit)
732 {
733 BT_LOGV_STR("Putting event header field.");
734 BT_PUT(notit->dscopes.stream_event_header);
735 BT_LOGV_STR("Putting stream event context field.");
736 BT_PUT(notit->dscopes.stream_event_context);
737 BT_LOGV_STR("Putting event context field.");
738 BT_PUT(notit->dscopes.event_context);
739 BT_LOGV_STR("Putting event payload field.");
740 BT_PUT(notit->dscopes.event_payload);
741 }
742
743 static
744 void put_all_dscopes(struct bt_ctf_notif_iter *notit)
745 {
746 BT_LOGV_STR("Putting packet header field.");
747 BT_PUT(notit->dscopes.trace_packet_header);
748 BT_LOGV_STR("Putting packet context field.");
749 BT_PUT(notit->dscopes.stream_packet_context);
750 put_event_dscopes(notit);
751 }
752
753 static
754 enum bt_ctf_notif_iter_status read_packet_header_begin_state(
755 struct bt_ctf_notif_iter *notit)
756 {
757 struct bt_ctf_field_type *packet_header_type = NULL;
758 enum bt_ctf_notif_iter_status ret = BT_CTF_NOTIF_ITER_STATUS_OK;
759
760 if (bt_ctf_notif_iter_switch_packet(notit)) {
761 BT_LOGW("Cannot switch packet: notit-addr=%p", notit);
762 ret = BT_CTF_NOTIF_ITER_STATUS_ERROR;
763 goto end;
764 }
765
766 /* Packet header type is common to the whole trace. */
767 packet_header_type = bt_ctf_trace_get_packet_header_type(
768 notit->meta.trace);
769 if (!packet_header_type) {
770 notit->state = STATE_AFTER_TRACE_PACKET_HEADER;
771 goto end;
772 }
773
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);
778 ret = read_dscope_begin_state(notit, packet_header_type,
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 }
790 end:
791 BT_PUT(packet_header_type);
792 return ret;
793 }
794
795 static
796 enum 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,
800 STATE_AFTER_TRACE_PACKET_HEADER);
801 }
802
803 static inline
804 bool is_struct_type(struct bt_ctf_field_type *field_type)
805 {
806 return bt_ctf_field_type_get_type_id(field_type) ==
807 BT_CTF_FIELD_TYPE_ID_STRUCT;
808 }
809
810 static inline
811 bool is_variant_type(struct bt_ctf_field_type *field_type)
812 {
813 return bt_ctf_field_type_get_type_id(field_type) ==
814 BT_CTF_FIELD_TYPE_ID_VARIANT;
815 }
816
817 static
818 struct stream_class_field_path_cache *
819 create_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) {
833 BT_LOGE_STR("Failed to allocate one stream class field path cache.");
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(
842 event_header);
843 assert(count >= 0);
844
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) {
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);
861 goto error;
862 }
863
864 if (v != -1 && id != -1) {
865 break;
866 }
867
868 if (v == -1 && strcmp(name, "v") == 0) {
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(
882 packet_context);
883 assert(count >= 0);
884
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) {
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);
907 goto error;
908 }
909
910 if (timestamp_end == -1 &&
911 strcmp(name, "timestamp_end") == 0) {
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;
922 g_hash_table_insert(notit->field_overrides,
923 bt_get(field_type), override);
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;
941 end:
942 BT_PUT(event_header);
943 BT_PUT(packet_context);
944 return cache_entry;
945 error:
946 g_free(cache_entry);
947 cache_entry = NULL;
948 goto end;
949 }
950
951 static
952 struct 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,
964 stream_class);
965 g_hash_table_insert(notit->sc_field_path_caches,
966 bt_get(stream_class), (gpointer) cache_entry);
967 }
968
969 return cache_entry;
970 }
971
972 static inline
973 enum bt_ctf_notif_iter_status set_current_stream_class(
974 struct bt_ctf_notif_iter *notit)
975 {
976 enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
977 struct bt_ctf_field_type *packet_header_type = NULL;
978 struct bt_ctf_field_type *stream_id_field_type = NULL;
979 struct bt_ctf_stream_class *new_stream_class = NULL;
980 uint64_t stream_id;
981
982 /* Clear the current stream class field path cache. */
983 notit->cur_sc_field_path_cache = NULL;
984
985 /* Is there any "stream_id" field in the packet header? */
986 packet_header_type = bt_ctf_trace_get_packet_header_type(
987 notit->meta.trace);
988 if (!packet_header_type) {
989 /*
990 * No packet header, therefore no `stream_id` field,
991 * therefore only one stream class.
992 */
993 goto single_stream_class;
994 }
995
996 assert(is_struct_type(packet_header_type));
997
998 // TODO: optimalize!
999 stream_id_field_type =
1000 bt_ctf_field_type_structure_get_field_type_by_name(
1001 packet_header_type, "stream_id");
1002 if (stream_id_field_type) {
1003 /* Find appropriate stream class using current stream ID */
1004 int ret;
1005 struct bt_ctf_field *stream_id_field = NULL;
1006
1007 assert(notit->dscopes.trace_packet_header);
1008
1009 // TODO: optimalize!
1010 stream_id_field = bt_ctf_field_structure_get_field(
1011 notit->dscopes.trace_packet_header, "stream_id");
1012 assert(stream_id_field);
1013 ret = bt_ctf_field_unsigned_integer_get_value(
1014 stream_id_field, &stream_id);
1015 assert(!ret);
1016 BT_PUT(stream_id_field);
1017 } else {
1018 single_stream_class:
1019 /* Only one stream: pick the first stream class */
1020 assert(bt_ctf_trace_get_stream_class_count(
1021 notit->meta.trace) == 1);
1022 stream_id = 0;
1023 }
1024
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
1031 new_stream_class = bt_ctf_trace_get_stream_class_by_id(
1032 notit->meta.trace, stream_id);
1033 if (!new_stream_class) {
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));
1039 status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
1040 goto end;
1041 }
1042
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
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
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(
1080 notit, notit->meta.stream_class);
1081 if (!notit->cur_sc_field_path_cache) {
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));
1088 status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
1089 goto end;
1090 }
1091 end:
1092 BT_PUT(packet_header_type);
1093 BT_PUT(stream_id_field_type);
1094 bt_put(new_stream_class);
1095 return status;
1096 }
1097
1098 static
1099 enum 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
1112 static
1113 enum 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(
1121 notit->meta.stream_class);
1122 if (!packet_context_type) {
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));
1129 notit->state = STATE_AFTER_STREAM_PACKET_CONTEXT;
1130 goto end;
1131 }
1132
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);
1141 status = read_dscope_begin_state(notit, packet_context_type,
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 }
1155
1156 end:
1157 BT_PUT(packet_context_type);
1158 return status;
1159 }
1160
1161 static
1162 enum 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,
1166 STATE_AFTER_STREAM_PACKET_CONTEXT);
1167 }
1168
1169 static
1170 enum 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;
1176 uint64_t content_size = -1ULL, packet_size = -1ULL;
1177
1178 if (!notit->dscopes.stream_packet_context) {
1179 goto end;
1180 }
1181
1182 packet_size_field = bt_ctf_field_structure_get_field(
1183 notit->dscopes.stream_packet_context, "packet_size");
1184 content_size_field = bt_ctf_field_structure_get_field(
1185 notit->dscopes.stream_packet_context, "content_size");
1186 if (packet_size_field) {
1187 int ret = bt_ctf_field_unsigned_integer_get_value(
1188 packet_size_field, &packet_size);
1189
1190 assert(ret == 0);
1191 if (packet_size == 0) {
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);
1195 status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
1196 goto end;
1197 } else if ((packet_size % 8) != 0) {
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);
1203 status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
1204 goto end;
1205 }
1206 }
1207
1208 if (content_size_field) {
1209 int ret = bt_ctf_field_unsigned_integer_get_value(
1210 content_size_field, &content_size);
1211
1212 assert(ret == 0);
1213 } else {
1214 content_size = packet_size;
1215 }
1216
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
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 }
1237 notit->cur_content_size = content_size;
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);
1241 end:
1242 BT_PUT(packet_size_field);
1243 BT_PUT(content_size_field);
1244 return status;
1245 }
1246
1247 static
1248 enum 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
1261 static
1262 enum 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
1268 /* Reset the position of the last event header */
1269 notit->buf.last_eh_at = notit->buf.at;
1270
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! */
1275 BT_LOGV("Reached end of packet: notit-addr=%p, "
1276 "cur=%zu", notit, packet_at(notit));
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 */
1281 BT_LOGV("Before decoding event header field: cursor is passed the packet's content: "
1282 "notit-addr=%p, content-size=%" PRId64 ", "
1283 "cur=%zu", notit, notit->cur_content_size,
1284 packet_at(notit));
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) {
1293 notit->state = STATE_AFTER_STREAM_EVENT_HEADER;
1294 goto end;
1295 }
1296
1297 put_event_dscopes(notit);
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);
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);
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 }
1320 end:
1321 BT_PUT(event_header_type);
1322
1323 return status;
1324 }
1325
1326 static
1327 enum 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
1334 static inline
1335 enum 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) {
1353 /*
1354 * No event header, therefore no event class ID field,
1355 * therefore only one event class.
1356 */
1357 goto single_event_class;
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
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 }
1407 }
1408
1409 end_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;
1418 int ret = 0;
1419
1420 // TODO: optimalize!
1421 id_field = bt_ctf_field_structure_get_field(
1422 notit->dscopes.stream_event_header, "id");
1423 if (!id_field) {
1424 goto check_event_id;
1425 }
1426
1427 if (bt_ctf_field_is_integer(id_field)) {
1428 ret = bt_ctf_field_unsigned_integer_get_value(
1429 id_field, &event_id);
1430 } else if (bt_ctf_field_is_enumeration(id_field)) {
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 }
1440
1441 assert(ret == 0);
1442 BT_PUT(id_field);
1443 }
1444
1445 check_event_id:
1446 if (event_id == -1ULL) {
1447 single_event_class:
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
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);
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) {
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);
1475 status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
1476 goto end;
1477 }
1478
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
1486 end:
1487 BT_PUT(event_header_type);
1488 BT_PUT(id_field_type);
1489 BT_PUT(v_field_type);
1490
1491 return status;
1492 }
1493
1494 static
1495 enum 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
1500 status = set_current_event_class(notit);
1501 if (status != BT_CTF_NOTIF_ITER_STATUS_OK) {
1502 goto end;
1503 }
1504
1505 notit->state = STATE_DSCOPE_STREAM_EVENT_CONTEXT_BEGIN;
1506
1507 end:
1508 return status;
1509 }
1510
1511 static
1512 enum 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) {
1521 notit->state = STATE_DSCOPE_EVENT_CONTEXT_BEGIN;
1522 goto end;
1523 }
1524
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);
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);
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 }
1547
1548 end:
1549 BT_PUT(stream_event_context_type);
1550
1551 return status;
1552 }
1553
1554 static
1555 enum 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
1562 static
1563 enum 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) {
1572 notit->state = STATE_DSCOPE_EVENT_PAYLOAD_BEGIN;
1573 goto end;
1574 }
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);
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);
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 }
1598
1599 end:
1600 BT_PUT(event_context_type);
1601
1602 return status;
1603 }
1604
1605 static
1606 enum 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
1613 static
1614 enum 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) {
1623 notit->state = STATE_EMIT_NOTIF_EVENT;
1624 goto end;
1625 }
1626
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);
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);
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 }
1649
1650 end:
1651 BT_PUT(event_payload_type);
1652
1653 return status;
1654 }
1655
1656 static
1657 enum 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
1663 static
1664 enum 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;
1677
1678 BT_LOGV("Trying to skip %zu bits of padding: notit-addr=%p, size=%zu",
1679 bits_to_skip, notit, bits_to_skip);
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);
1686 BT_LOGV("Skipping %zu bits of padding: notit-addr=%p, size=%zu",
1687 bits_to_consume, notit, bits_to_consume);
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
1696 end:
1697 return status;
1698 }
1699
1700 static inline
1701 enum 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;
1704 const enum state state = notit->state;
1705
1706 BT_LOGV("Handling state: notit-addr=%p, state=%s",
1707 notit, state_string(state));
1708
1709 // TODO: optimalize!
1710 switch (state) {
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;
1771 default:
1772 BT_LOGD("Unknown CTF plugin notification iterator state: "
1773 "notit-addr=%p, state=%d", notit, notit->state);
1774 abort();
1775 }
1776
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));
1781 return status;
1782 }
1783
1784 /**
1785 * Resets the internal state of a CTF notification iterator.
1786 */
1787 static
1788 void bt_ctf_notif_iter_reset(struct bt_ctf_notif_iter *notit)
1789 {
1790 assert(notit);
1791 BT_LOGD("Resetting notification iterator: addr=%p", notit);
1792 stack_clear(notit->stack);
1793 BT_PUT(notit->meta.stream_class);
1794 BT_PUT(notit->meta.event_class);
1795 BT_PUT(notit->packet);
1796 BT_PUT(notit->stream);
1797 put_all_dscopes(notit);
1798 notit->buf.addr = NULL;
1799 notit->buf.sz = 0;
1800 notit->buf.at = 0;
1801 notit->buf.last_eh_at = SIZE_MAX;
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
1808 static
1809 int bt_ctf_notif_iter_switch_packet(struct bt_ctf_notif_iter *notit)
1810 {
1811 int ret = 0;
1812
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 */
1818 assert(notit);
1819 BT_LOGV("Switching packet: notit-addr=%p, cur=%zu",
1820 notit, notit->buf.at);
1821 stack_clear(notit->stack);
1822 BT_PUT(notit->meta.event_class);
1823 BT_PUT(notit->packet);
1824 BT_PUT(notit->cur_timestamp_end);
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) {
1836 BT_LOGW("Cannot switch packet: current position is not a multiple of 8: "
1837 "notit-addr=%p, cur=%zu", notit, notit->buf.at);
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;
1846 BT_LOGV("Adjusted buffer: addr=%p, size=%zu",
1847 notit->buf.addr, notit->buf.sz);
1848 }
1849
1850 notit->cur_content_size = -1;
1851 notit->cur_packet_size = -1;
1852 notit->cur_sc_field_path_cache = NULL;
1853
1854 end:
1855 return ret;
1856 }
1857
1858 static
1859 struct 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;
1869 assert(base_field);
1870 base_type = bt_ctf_field_get_type(base_field);
1871 assert(base_type);
1872
1873 switch (bt_ctf_field_type_get_type_id(base_type)) {
1874 case BT_CTF_FIELD_TYPE_ID_STRUCT:
1875 next_field = bt_ctf_field_structure_get_field_by_index(
1876 base_field, index);
1877 break;
1878 case BT_CTF_FIELD_TYPE_ID_ARRAY:
1879 next_field = bt_ctf_field_array_get_field(base_field, index);
1880 break;
1881 case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
1882 next_field = bt_ctf_field_sequence_get_field(base_field, index);
1883 break;
1884 case BT_CTF_FIELD_TYPE_ID_VARIANT:
1885 next_field = bt_ctf_field_variant_get_current_field(base_field);
1886 break;
1887 default:
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)));
1893 abort();
1894 }
1895
1896 BT_PUT(base_type);
1897 return next_field;
1898 }
1899
1900 static
1901 void 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);
1913 assert(bt_ctf_field_type_is_integer(value_type));
1914 requested_new_value_size =
1915 bt_ctf_field_type_integer_get_size(value_type);
1916 assert(requested_new_value_size > 0);
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;
1948 end:
1949 BT_LOGV("Updated clock's value from integer field's value: "
1950 "value=%" PRIu64, *state);
1951 bt_put(value_type);
1952 }
1953
1954 static
1955 enum bt_ctf_btr_status update_clock(struct bt_ctf_notif_iter *notit,
1956 struct bt_ctf_field *int_field)
1957 {
1958 gboolean clock_class_found;
1959 uint64_t *clock_state = NULL;
1960 struct bt_ctf_field_type *int_field_type = NULL;
1961 enum bt_ctf_btr_status ret = BT_CTF_BTR_STATUS_OK;
1962 struct bt_ctf_clock_class *clock_class = NULL;
1963
1964 int_field_type = bt_ctf_field_get_type(int_field);
1965 assert(int_field_type);
1966 clock_class = bt_ctf_field_type_integer_get_mapped_clock_class(
1967 int_field_type);
1968 if (likely(!clock_class)) {
1969 goto end;
1970 }
1971
1972 clock_class_found = g_hash_table_lookup_extended(notit->clock_states,
1973 clock_class, NULL, (gpointer) &clock_state);
1974 if (!clock_class_found) {
1975 clock_state = g_new0(uint64_t, 1);
1976 if (!clock_state) {
1977 BT_LOGE_STR("Failed to allocate a uint64_t.");
1978 ret = BT_CTF_BTR_STATUS_ENOMEM;
1979 goto end;
1980 }
1981
1982 g_hash_table_insert(notit->clock_states, bt_get(clock_class),
1983 clock_state);
1984 }
1985
1986 /* Update the clock's state. */
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);
1992 update_clock_state(clock_state, int_field);
1993 end:
1994 bt_put(int_field_type);
1995 bt_put(clock_class);
1996 return ret;
1997 }
1998
1999 static
2000 enum bt_ctf_btr_status btr_unsigned_int_common(uint64_t value,
2001 struct bt_ctf_field_type *type, void *data,
2002 struct bt_ctf_field **out_int_field)
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
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
2018 /* Create next field */
2019 field = get_next_field(notit);
2020 if (!field) {
2021 BT_LOGW("Cannot get next field: notit-addr=%p", notit);
2022 status = BT_CTF_BTR_STATUS_ERROR;
2023 goto end_no_put;
2024 }
2025
2026 switch(bt_ctf_field_type_get_type_id(type)) {
2027 case BT_CTF_FIELD_TYPE_ID_INTEGER:
2028 /* Integer field is created field */
2029 BT_MOVE(int_field, field);
2030 bt_get(type);
2031 break;
2032 case BT_CTF_FIELD_TYPE_ID_ENUM:
2033 int_field = bt_ctf_field_enumeration_get_container(field);
2034 assert(int_field);
2035 type = bt_ctf_field_get_type(int_field);
2036 assert(type);
2037 break;
2038 default:
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)));
2044 abort();
2045 }
2046
2047 assert(int_field);
2048 ret = bt_ctf_field_unsigned_integer_set_value(int_field, value);
2049 assert(ret == 0);
2050 stack_top(notit->stack)->index++;
2051 *out_int_field = int_field;
2052 BT_PUT(field);
2053 BT_PUT(type);
2054
2055 end_no_put:
2056 return status;
2057 }
2058
2059 static
2060 enum 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
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)));
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
2081 static
2082 enum bt_ctf_btr_status btr_unsigned_int_cb(uint64_t value,
2083 struct bt_ctf_field_type *type, void *data)
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
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);
2098 if (unlikely(override)) {
2099 /* Override function logs errors */
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) {
2106 /* btr_unsigned_int_common() logs errors */
2107 goto end;
2108 }
2109
2110 status = update_clock(notit, field);
2111 BT_PUT(field);
2112 end:
2113 return status;
2114 }
2115
2116 static
2117 enum bt_ctf_btr_status btr_signed_int_cb(int64_t value,
2118 struct bt_ctf_field_type *type, void *data)
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
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
2134 /* create next field */
2135 field = get_next_field(notit);
2136 if (!field) {
2137 BT_LOGW("Cannot get next field: notit-addr=%p", notit);
2138 status = BT_CTF_BTR_STATUS_ERROR;
2139 goto end_no_put;
2140 }
2141
2142 switch(bt_ctf_field_type_get_type_id(type)) {
2143 case BT_CTF_FIELD_TYPE_ID_INTEGER:
2144 /* Integer field is created field */
2145 BT_MOVE(int_field, field);
2146 bt_get(type);
2147 break;
2148 case BT_CTF_FIELD_TYPE_ID_ENUM:
2149 int_field = bt_ctf_field_enumeration_get_container(field);
2150 assert(int_field);
2151 type = bt_ctf_field_get_type(int_field);
2152 assert(type);
2153 break;
2154 default:
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)));
2160 abort();
2161 }
2162
2163 assert(int_field);
2164 ret = bt_ctf_field_signed_integer_set_value(int_field, value);
2165 assert(!ret);
2166 stack_top(notit->stack)->index++;
2167 status = update_clock(notit, int_field);
2168 BT_PUT(field);
2169 BT_PUT(int_field);
2170 BT_PUT(type);
2171
2172 end_no_put:
2173 return status;
2174 }
2175
2176 static
2177 enum 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
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
2193 /* Create next field */
2194 field = get_next_field(notit);
2195 if (!field) {
2196 BT_LOGW("Cannot get next field: notit-addr=%p", notit);
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
2205 end:
2206 BT_PUT(field);
2207 return status;
2208 }
2209
2210 static
2211 enum 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
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
2226 /* Create next field */
2227 field = get_next_field(notit);
2228 if (!field) {
2229 BT_LOGW("Cannot get next field: notit-addr=%p", notit);
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) {
2241 BT_LOGE("Cannot push string field on stack: "
2242 "notit-addr=%p, field-addr=%p", notit, field);
2243 status = BT_CTF_BTR_STATUS_ERROR;
2244 goto end;
2245 }
2246
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) {
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);
2257 status = BT_CTF_BTR_STATUS_ERROR;
2258 goto end;
2259 }
2260
2261 end:
2262 BT_PUT(field);
2263
2264 return status;
2265 }
2266
2267 static
2268 enum 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
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
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) {
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);
2294 status = BT_CTF_BTR_STATUS_ERROR;
2295 goto end;
2296 }
2297
2298 end:
2299 return status;
2300 }
2301
2302 static
2303 enum 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
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
2315 /* Pop string field */
2316 stack_pop(notit->stack);
2317
2318 /* Go to next field */
2319 stack_top(notit->stack)->index++;
2320 return BT_CTF_BTR_STATUS_OK;
2321 }
2322
2323 enum 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
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
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);
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 }
2361 } else {
2362 field = get_next_field(notit);
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 }
2368 }
2369
2370 /* Push field */
2371 assert(field);
2372 ret = stack_push(notit->stack, field);
2373 if (ret) {
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);
2380 status = BT_CTF_BTR_STATUS_ERROR;
2381 goto end;
2382 }
2383
2384 end:
2385 BT_PUT(field);
2386
2387 return status;
2388 }
2389
2390 enum 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
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)));
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
2414 static
2415 struct 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
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
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:
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();
2457 }
2458
2459 if (!field) {
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)));
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);
2475 assert(field_type);
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) {
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);
2495 goto end;
2496 }
2497
2498 /* Move next field -> field */
2499 BT_MOVE(field, next_field);
2500 }
2501
2502 end:
2503 return field;
2504 }
2505
2506 static
2507 int64_t btr_get_sequence_length_cb(struct bt_ctf_field_type *type, void *data)
2508 {
2509 int64_t ret = -1;
2510 int iret;
2511 struct bt_ctf_field *seq_field;
2512 struct bt_ctf_field_path *field_path;
2513 struct bt_ctf_notif_iter *notit = data;
2514 struct bt_ctf_field *length_field = NULL;
2515 uint64_t length;
2516
2517 field_path = bt_ctf_field_type_sequence_get_length_field_path(type);
2518 assert(field_path);
2519 length_field = resolve_field(notit, field_path);
2520 if (!length_field) {
2521 BT_LOGW("Cannot resolve sequence field type's length field path: "
2522 "notit-addr=%p, ft-addr=%p",
2523 notit, type);
2524 goto end;
2525 }
2526
2527 iret = bt_ctf_field_unsigned_integer_get_value(length_field, &length);
2528 if (iret) {
2529 BT_LOGE("Cannot get value of sequence length field: "
2530 "notit-addr=%p, field-addr=%p",
2531 notit, length_field);
2532 goto end;
2533 }
2534
2535 seq_field = stack_top(notit->stack)->base;
2536 iret = bt_ctf_field_sequence_set_length(seq_field, length_field);
2537 if (iret) {
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);
2542 goto end;
2543 }
2544
2545 ret = (int64_t) length;
2546
2547 end:
2548 BT_PUT(length_field);
2549 BT_PUT(field_path);
2550
2551 return ret;
2552 }
2553
2554 static
2555 struct 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;
2560 struct bt_ctf_field *var_field;
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);
2566 assert(path);
2567 tag_field = resolve_field(notit, path);
2568 if (!tag_field) {
2569 BT_LOGW("Cannot resolve variant field type's tag field path: "
2570 "notit-addr=%p, ft-addr=%p",
2571 notit, type);
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 */
2587 var_field = stack_top(notit->stack)->base;
2588 selected_field = bt_ctf_field_variant_get_field(var_field, tag_field);
2589 if (!selected_field) {
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);
2593 goto end;
2594 }
2595
2596 selected_field_type = bt_ctf_field_get_type(selected_field);
2597
2598 end:
2599 BT_PUT(tag_field);
2600 BT_PUT(selected_field);
2601 BT_PUT(path);
2602
2603 return selected_field_type;
2604 }
2605
2606 static
2607 int set_event_clocks(struct bt_ctf_event *event,
2608 struct bt_ctf_notif_iter *notit)
2609 {
2610 int ret;
2611 GHashTableIter iter;
2612 struct bt_ctf_clock_class *clock_class;
2613 uint64_t *clock_state;
2614
2615 g_hash_table_iter_init(&iter, notit->clock_states);
2616
2617 while (g_hash_table_iter_next(&iter, (gpointer) &clock_class,
2618 (gpointer) &clock_state)) {
2619 struct bt_ctf_clock_value *clock_value;
2620
2621 clock_value = bt_ctf_clock_value_create(clock_class,
2622 *clock_state);
2623 if (!clock_value) {
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));
2629 ret = -1;
2630 goto end;
2631 }
2632 ret = bt_ctf_event_set_clock_value(event, clock_value);
2633 bt_put(clock_value);
2634 if (ret) {
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);
2653 goto end;
2654 }
2655 }
2656
2657 ret = 0;
2658 end:
2659 return ret;
2660 }
2661
2662 static
2663 struct bt_ctf_event *create_event(struct bt_ctf_notif_iter *notit)
2664 {
2665 int ret;
2666 struct bt_ctf_event *event;
2667
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
2676 /* Create event object. */
2677 event = bt_ctf_event_create(notit->meta.event_class);
2678 if (!event) {
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));
2686 goto error;
2687 }
2688
2689 /* Set header, stream event context, context, and payload fields. */
2690 ret = bt_ctf_event_set_header(event,
2691 notit->dscopes.stream_event_header);
2692 if (ret) {
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);
2701 goto error;
2702 }
2703
2704 ret = bt_ctf_event_set_stream_event_context(event,
2705 notit->dscopes.stream_event_context);
2706 if (ret) {
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);
2715 goto error;
2716 }
2717
2718 ret = bt_ctf_event_set_event_context(event,
2719 notit->dscopes.event_context);
2720 if (ret) {
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);
2729 goto error;
2730 }
2731
2732 ret = bt_ctf_event_set_event_payload(event,
2733 notit->dscopes.event_payload);
2734 if (ret) {
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);
2743 goto error;
2744 }
2745
2746 ret = set_event_clocks(event, notit);
2747 if (ret) {
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));
2755 goto error;
2756 }
2757
2758 /* Associate with current packet. */
2759 assert(notit->packet);
2760 ret = bt_ctf_event_set_packet(event, notit->packet);
2761 if (ret) {
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);
2770 goto error;
2771 }
2772
2773 goto end;
2774
2775 error:
2776 BT_PUT(event);
2777
2778 end:
2779 return event;
2780 }
2781
2782 static
2783 uint64_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
2806 end:
2807 bt_put(stream_instance_id_field);
2808 return stream_instance_id;
2809 }
2810
2811 static
2812 int set_stream(struct bt_ctf_notif_iter *notit)
2813 {
2814 int ret = 0;
2815 struct bt_ctf_stream *stream = NULL;
2816
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));
2823 stream = bt_get(notit->medium.medops.get_stream(
2824 notit->meta.stream_class, get_cur_stream_instance_id(notit),
2825 notit->medium.data));
2826 BT_LOGV("User function returned: stream-addr=%p", stream);
2827 if (!stream) {
2828 BT_LOGW_STR("User function failed to return a stream object for the given stream class.");
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
2841 end:
2842 bt_put(stream);
2843 return ret;
2844 }
2845
2846 static
2847 void 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) {
2858 goto error;
2859 }
2860
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,
2866 notit, notit->stream, notit->meta.stream_class,
2867 bt_ctf_stream_class_get_name(notit->meta.stream_class),
2868 bt_ctf_stream_class_get_id(notit->meta.stream_class));
2869
2870 /* Create packet */
2871 packet = bt_ctf_packet_create(notit->stream);
2872 if (!packet) {
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,
2878 notit, notit->stream, notit->meta.stream_class,
2879 bt_ctf_stream_class_get_name(notit->meta.stream_class),
2880 bt_ctf_stream_class_get_id(notit->meta.stream_class));
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,
2887 notit->dscopes.trace_packet_header);
2888 if (ret) {
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",
2896 notit, packet, notit->stream, notit->meta.stream_class,
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);
2900 goto error;
2901 }
2902 }
2903
2904 if (notit->dscopes.stream_packet_context) {
2905 ret = bt_ctf_packet_set_context(packet,
2906 notit->dscopes.stream_packet_context);
2907 if (ret) {
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",
2915 notit, packet, notit->stream, notit->meta.stream_class,
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);
2919 goto error;
2920 }
2921 }
2922
2923 goto end;
2924
2925 error:
2926 BT_PUT(packet);
2927
2928 end:
2929 BT_MOVE(notit->packet, packet);
2930 }
2931
2932 static
2933 void notify_new_packet(struct bt_ctf_notif_iter *notit,
2934 struct bt_notification **notification)
2935 {
2936 struct bt_notification *ret;
2937
2938 /* Initialize the iterator's current packet */
2939 create_packet(notit);
2940 if (!notit->packet) {
2941 BT_LOGE("Cannot create packet for packet notification: "
2942 "notit-addr=%p", notit);
2943 return;
2944 }
2945
2946 ret = bt_notification_packet_begin_create(notit->packet);
2947 if (!ret) {
2948 BT_LOGE("Cannot create packet beginning notification: "
2949 "notit-addr=%p, packet-addr=%p",
2950 notit, notit->packet);
2951 return;
2952 }
2953 *notification = ret;
2954 }
2955
2956 static
2957 void notify_end_of_packet(struct bt_ctf_notif_iter *notit,
2958 struct bt_notification **notification)
2959 {
2960 struct bt_notification *ret;
2961
2962 if (!notit->packet) {
2963 return;
2964 }
2965
2966 ret = bt_notification_packet_end_create(notit->packet);
2967 if (!ret) {
2968 BT_LOGE("Cannot create packet end notification: "
2969 "notit-addr=%p, packet-addr=%p",
2970 notit, notit->packet);
2971 return;
2972 }
2973 BT_PUT(notit->packet);
2974 *notification = ret;
2975 }
2976
2977 static
2978 void notify_event(struct bt_ctf_notif_iter *notit,
2979 struct bt_clock_class_priority_map *cc_prio_map,
2980 struct bt_notification **notification)
2981 {
2982 struct bt_ctf_event *event = NULL;
2983 struct bt_notification *ret = NULL;
2984
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
2993 /* Create event */
2994 event = create_event(notit);
2995 if (!event) {
2996 BT_LOGE("Cannot create event for event notification: "
2997 "notit-addr=%p", notit);
2998 goto end;
2999 }
3000
3001 ret = bt_notification_event_create(event, cc_prio_map);
3002 if (!ret) {
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);
3007 goto end;
3008 }
3009 *notification = ret;
3010 end:
3011 BT_PUT(event);
3012 }
3013
3014 static
3015 void 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);
3033 assert(count >= 0);
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) {
3042 BT_LOGE("Cannot get structure field's field: "
3043 "field-addr=%p, index=%d",
3044 packet_header, i);
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 }
3055
3056 end:
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
3062 BT_HIDDEN
3063 struct bt_ctf_notif_iter *bt_ctf_notif_iter_create(struct bt_ctf_trace *trace,
3064 size_t max_request_sz,
3065 struct bt_ctf_notif_iter_medium_ops medops, void *data)
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);
3087 assert(medops.get_stream);
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);
3092 notit = g_new0(struct bt_ctf_notif_iter, 1);
3093 if (!notit) {
3094 BT_LOGE_STR("Failed to allocate one CTF plugin notification iterator.");
3095 goto end;
3096 }
3097 notit->clock_states = g_hash_table_new_full(g_direct_hash,
3098 g_direct_equal, bt_put, g_free);
3099 if (!notit->clock_states) {
3100 BT_LOGE_STR("Failed to allocate a GHashTable.");
3101 goto error;
3102 }
3103 notit->meta.trace = bt_get(trace);
3104 notit->medium.medops = medops;
3105 notit->medium.max_request_sz = max_request_sz;
3106 notit->medium.data = data;
3107 notit->stack = stack_new(notit);
3108 if (!notit->stack) {
3109 BT_LOGE_STR("Failed to create field stack.");
3110 goto error;
3111 }
3112
3113 notit->btr = bt_ctf_btr_create(cbs, notit);
3114 if (!notit->btr) {
3115 BT_LOGE_STR("Failed to create binary type reader (BTR).");
3116 goto error;
3117 }
3118
3119 bt_ctf_notif_iter_reset(notit);
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,
3122 g_direct_equal, bt_put, g_free);
3123 if (!notit->sc_field_path_caches) {
3124 BT_LOGE_STR("Failed to allocate a GHashTable.");
3125 goto error;
3126 }
3127
3128 notit->field_overrides = g_hash_table_new_full(g_direct_hash,
3129 g_direct_equal, bt_put, g_free);
3130 if (!notit->field_overrides) {
3131 BT_LOGE_STR("Failed to allocate a GHashTable.");
3132 goto error;
3133 }
3134
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
3141 end:
3142 return notit;
3143
3144 error:
3145 bt_ctf_notif_iter_destroy(notit);
3146 notit = NULL;
3147 goto end;
3148 }
3149
3150 void 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);
3156 BT_PUT(notit->stream);
3157 BT_PUT(notit->cur_timestamp_end);
3158 put_all_dscopes(notit);
3159
3160 BT_LOGD("Destroying CTF plugin notification iterator: addr=%p", notit);
3161
3162 if (notit->stack) {
3163 BT_LOGD_STR("Destroying field stack.");
3164 stack_destroy(notit->stack);
3165 }
3166
3167 if (notit->btr) {
3168 BT_LOGD("Destroying BTR: btr-addr=%p", notit->btr);
3169 bt_ctf_btr_destroy(notit->btr);
3170 }
3171
3172 if (notit->clock_states) {
3173 g_hash_table_destroy(notit->clock_states);
3174 }
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 }
3183
3184 g_free(notit);
3185 }
3186
3187 enum bt_ctf_notif_iter_status bt_ctf_notif_iter_get_next_notification(
3188 struct bt_ctf_notif_iter *notit,
3189 struct bt_clock_class_priority_map *cc_prio_map,
3190 struct bt_notification **notification)
3191 {
3192 enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
3193
3194 assert(notit);
3195 assert(notification);
3196
3197 BT_LOGV("Getting next notification: notit-addr=%p, cc-prio-map-addr=%p",
3198 notit, cc_prio_map);
3199
3200 while (true) {
3201 status = handle_state(notit);
3202 if (status == BT_CTF_NOTIF_ITER_STATUS_AGAIN) {
3203 BT_LOGV_STR("Medium returned BT_CTF_NOTIF_ITER_STATUS_AGAIN.");
3204 goto end;
3205 }
3206 if (status != BT_CTF_NOTIF_ITER_STATUS_OK) {
3207 if (status == BT_CTF_NOTIF_ITER_STATUS_EOF) {
3208 BT_LOGV_STR("Medium returned BT_CTF_NOTIF_ITER_STATUS_EOF.");
3209 } else {
3210 BT_LOGW("Cannot handle state: "
3211 "notit-addr=%p, state=%s",
3212 notit, state_string(notit->state));
3213 }
3214 goto end;
3215 }
3216
3217 switch (notit->state) {
3218 case STATE_EMIT_NOTIF_NEW_PACKET:
3219 /* notify_new_packet() logs errors */
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:
3226 /* notify_event() logs errors */
3227 notify_event(notit, cc_prio_map, notification);
3228 if (!*notification) {
3229 status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
3230 }
3231 goto end;
3232 case STATE_EMIT_NOTIF_END_OF_PACKET:
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
3240 assert(field_type);
3241 btr_status = update_clock(notit,
3242 notit->cur_timestamp_end);
3243 BT_PUT(field_type);
3244 if (btr_status != BT_CTF_BTR_STATUS_OK) {
3245 BT_LOGW("Cannot update stream's clock value: "
3246 "notit-addr=%p", notit);
3247 status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
3248 goto end;
3249 }
3250 }
3251
3252 /* notify_end_of_packet() logs errors */
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
3264 end:
3265 return status;
3266 }
3267
3268 BT_HIDDEN
3269 enum 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) {
3286 BT_LOGV_STR("Medium returned BT_CTF_NOTIF_ITER_STATUS_AGAIN.");
3287 goto end;
3288 }
3289 if (status != BT_CTF_NOTIF_ITER_STATUS_OK) {
3290 if (status == BT_CTF_NOTIF_ITER_STATUS_EOF) {
3291 BT_LOGV_STR("Medium returned BT_CTF_NOTIF_ITER_STATUS_EOF.");
3292 } else {
3293 BT_LOGW("Cannot handle state: "
3294 "notit-addr=%p, state=%s",
3295 notit, state_string(notit->state));
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 */
3321 BT_LOGF("Unexpected state: notit-addr=%p, state=%s",
3322 notit, state_string(notit->state));
3323 abort();
3324 }
3325 }
3326
3327 set_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
3336 end:
3337 return status;
3338 }
3339
3340 BT_HIDDEN
3341 void 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.123946 seconds and 5 git commands to generate.