cpp-common/bt2c/fmt.hpp: use `wise_enum::string_type` in `EnableIfIsWiseEnum` definition
[babeltrace.git] / src / plugins / ctf / common / src / msg-iter / msg-iter.cpp
1 /*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright (c) 2015-2018 EfficiOS Inc. and Linux Foundation
5 * Copyright (c) 2015-2018 Philippe Proulx <pproulx@efficios.com>
6 *
7 * Babeltrace - CTF message iterator
8 */
9
10 #include <stddef.h>
11 #include <stdint.h>
12 #include <stdio.h>
13
14 #include "common/assert.h"
15 #include "common/common.h"
16 #include "cpp-common/bt2c/fmt.hpp"
17 #include "cpp-common/bt2c/logging.hpp"
18 #include "cpp-common/bt2c/make-span.hpp"
19 #include "cpp-common/vendor/fmt/format.h"
20
21 #include "../bfcr/bfcr.hpp"
22 #include "msg-iter.hpp"
23
24 /* A visit stack entry */
25 struct stack_entry
26 {
27 /*
28 * Current base field, one of:
29 *
30 * * string
31 * * structure
32 * * array
33 * * sequence
34 * * variant
35 *
36 * Field is borrowed.
37 */
38 bt_field *base;
39
40 /* Index of next field to set */
41 size_t index;
42 };
43
44 /* Visit stack */
45 struct stack
46 {
47 struct ctf_msg_iter *msg_it;
48
49 /* Entries (struct stack_entry) */
50 GArray *entries;
51
52 /* Number of active entries */
53 size_t size;
54 };
55
56 /* State */
57 enum state
58 {
59 STATE_INIT,
60 STATE_SWITCH_PACKET,
61 STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN,
62 STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE,
63 STATE_AFTER_TRACE_PACKET_HEADER,
64 STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN,
65 STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE,
66 STATE_AFTER_STREAM_PACKET_CONTEXT,
67 STATE_EMIT_MSG_STREAM_BEGINNING,
68 STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS,
69 STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS,
70 STATE_EMIT_MSG_DISCARDED_EVENTS,
71 STATE_EMIT_MSG_DISCARDED_PACKETS,
72 STATE_EMIT_MSG_PACKET_BEGINNING,
73 STATE_DSCOPE_EVENT_HEADER_BEGIN,
74 STATE_DSCOPE_EVENT_HEADER_CONTINUE,
75 STATE_AFTER_EVENT_HEADER,
76 STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN,
77 STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE,
78 STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN,
79 STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE,
80 STATE_DSCOPE_EVENT_PAYLOAD_BEGIN,
81 STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE,
82 STATE_EMIT_MSG_EVENT,
83 STATE_EMIT_QUEUED_MSG_EVENT,
84 STATE_SKIP_PACKET_PADDING,
85 STATE_EMIT_MSG_PACKET_END_MULTI,
86 STATE_EMIT_MSG_PACKET_END_SINGLE,
87 STATE_EMIT_QUEUED_MSG_PACKET_END,
88 STATE_CHECK_EMIT_MSG_STREAM_END,
89 STATE_EMIT_MSG_STREAM_END,
90 STATE_DONE,
91 };
92
93 static __attribute__((used)) const char *format_as(state state)
94 {
95 switch (state) {
96 case STATE_INIT:
97 return "STATE_INIT";
98
99 case STATE_SWITCH_PACKET:
100 return "STATE_SWITCH_PACKET";
101
102 case STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN:
103 return "STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN";
104
105 case STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE:
106 return "STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE";
107
108 case STATE_AFTER_TRACE_PACKET_HEADER:
109 return "STATE_AFTER_TRACE_PACKET_HEADER";
110
111 case STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN:
112 return "STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN";
113
114 case STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE:
115 return "STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE";
116
117 case STATE_AFTER_STREAM_PACKET_CONTEXT:
118 return "STATE_AFTER_STREAM_PACKET_CONTEXT";
119
120 case STATE_EMIT_MSG_STREAM_BEGINNING:
121 return "STATE_EMIT_MSG_STREAM_BEGINNING";
122
123 case STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS:
124 return "STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS";
125
126 case STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS:
127 return "STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS";
128
129 case STATE_EMIT_MSG_DISCARDED_EVENTS:
130 return "STATE_EMIT_MSG_DISCARDED_EVENTS";
131
132 case STATE_EMIT_MSG_DISCARDED_PACKETS:
133 return "STATE_EMIT_MSG_DISCARDED_PACKETS";
134
135 case STATE_EMIT_MSG_PACKET_BEGINNING:
136 return "STATE_EMIT_MSG_PACKET_BEGINNING";
137
138 case STATE_DSCOPE_EVENT_HEADER_BEGIN:
139 return "STATE_DSCOPE_EVENT_HEADER_BEGIN";
140
141 case STATE_DSCOPE_EVENT_HEADER_CONTINUE:
142 return "STATE_DSCOPE_EVENT_HEADER_CONTINUE";
143
144 case STATE_AFTER_EVENT_HEADER:
145 return "STATE_AFTER_EVENT_HEADER";
146
147 case STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN:
148 return "STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN";
149
150 case STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE:
151 return "STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE";
152
153 case STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN:
154 return "STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN";
155
156 case STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE:
157 return "STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE";
158
159 case STATE_DSCOPE_EVENT_PAYLOAD_BEGIN:
160 return "STATE_DSCOPE_EVENT_PAYLOAD_BEGIN";
161
162 case STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE:
163 return "STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE";
164
165 case STATE_EMIT_MSG_EVENT:
166 return "STATE_EMIT_MSG_EVENT";
167
168 case STATE_EMIT_QUEUED_MSG_EVENT:
169 return "STATE_EMIT_QUEUED_MSG_EVENT";
170
171 case STATE_SKIP_PACKET_PADDING:
172 return "STATE_SKIP_PACKET_PADDING";
173
174 case STATE_EMIT_MSG_PACKET_END_MULTI:
175 return "STATE_EMIT_MSG_PACKET_END_MULTI";
176
177 case STATE_EMIT_MSG_PACKET_END_SINGLE:
178 return "STATE_EMIT_MSG_PACKET_END_SINGLE";
179
180 case STATE_EMIT_QUEUED_MSG_PACKET_END:
181 return "STATE_EMIT_QUEUED_MSG_PACKET_END";
182
183 case STATE_CHECK_EMIT_MSG_STREAM_END:
184 return "STATE_CHECK_EMIT_MSG_STREAM_END";
185
186 case STATE_EMIT_MSG_STREAM_END:
187 return "STATE_EMIT_MSG_STREAM_END";
188
189 case STATE_DONE:
190 return "STATE_DONE";
191 }
192
193 bt_common_abort();
194 }
195
196 struct end_of_packet_snapshots
197 {
198 uint64_t discarded_events = 0;
199 uint64_t packets = 0;
200 uint64_t beginning_clock = 0;
201 uint64_t end_clock = 0;
202 };
203
204 /* CTF message iterator */
205 struct ctf_msg_iter
206 {
207 explicit ctf_msg_iter(bt2c::Logger loggerParam) noexcept : logger {std::move(loggerParam)}
208 {
209 }
210
211 /* Visit stack */
212 struct stack *stack = nullptr;
213
214 /* Current message iterator to create messages (weak) */
215 bt_self_message_iterator *self_msg_iter = nullptr;
216
217 /*
218 * True if library objects are unavailable during the decoding and
219 * should not be created/used.
220 */
221 bool dry_run = false;
222
223 /*
224 * Current dynamic scope field pointer.
225 *
226 * This is set by read_dscope_begin_state() and contains the
227 * value of one of the pointers in `dscopes` below.
228 */
229 bt_field *cur_dscope_field = nullptr;
230
231 /*
232 * True if we're done filling a string field from a text
233 * array/sequence payload.
234 */
235 bool done_filling_string = false;
236
237 /* Trace and classes */
238 /* True to set IR fields */
239 bool set_ir_fields = false;
240
241 struct
242 {
243 struct ctf_trace_class *tc = nullptr;
244 struct ctf_stream_class *sc = nullptr;
245 struct ctf_event_class *ec = nullptr;
246 } meta;
247
248 /* Current packet (NULL if not created yet) */
249 bt_packet *packet = nullptr;
250
251 /* Current stream (NULL if not set yet) */
252 bt_stream *stream = nullptr;
253
254 /* Current event (NULL if not created yet) */
255 bt_event *event = nullptr;
256
257 /* Current event message (NULL if not created yet) */
258 bt_message *event_msg = nullptr;
259
260 /*
261 * True if we need to emit a packet beginning message before we emit
262 * the next event message or the packet end message.
263 */
264 bool emit_delayed_packet_beginning_msg = false;
265
266 /*
267 * True if this is the first packet we are reading, and therefore if we
268 * should emit a stream beginning message.
269 */
270 bool emit_stream_beginning_message = false;
271
272 /*
273 * True if we need to emit a stream end message at the end of the
274 * current stream. A live stream may never receive any data and thus
275 * never send a stream beginning message which removes the need to emit
276 * a stream end message.
277 */
278 bool emit_stream_end_message = false;
279
280 /* Database of current dynamic scopes */
281 struct
282 {
283 bt_field *stream_packet_context = nullptr;
284 bt_field *event_common_context = nullptr;
285 bt_field *event_spec_context = nullptr;
286 bt_field *event_payload = nullptr;
287 } dscopes;
288
289 /* Current state */
290 enum state state = STATE_INIT;
291
292 /* Current medium buffer data */
293 struct
294 {
295 /* Last address provided by medium */
296 const uint8_t *addr = nullptr;
297
298 /* Buffer size provided by medium (bytes) */
299 size_t sz = 0;
300
301 /* Offset within whole packet of addr (bits) */
302 size_t packet_offset = 0;
303
304 /* Current position from addr (bits) */
305 size_t at = 0;
306
307 /* Position of the last event header from addr (bits) */
308 size_t last_eh_at = 0;
309 } buf;
310
311 /* Binary type reader */
312 struct bt_bfcr *bfcr = nullptr;
313
314 /* Current medium data */
315 struct
316 {
317 struct ctf_msg_iter_medium_ops medops;
318 size_t max_request_sz = 0;
319 void *data = nullptr;
320 } medium;
321
322 /* Current packet size (bits) (-1 if unknown) */
323 int64_t cur_exp_packet_total_size = 0;
324
325 /* Current content size (bits) (-1 if unknown) */
326 int64_t cur_exp_packet_content_size = 0;
327
328 /* Current stream class ID */
329 int64_t cur_stream_class_id = 0;
330
331 /* Current event class ID */
332 int64_t cur_event_class_id = 0;
333
334 /* Current data stream ID */
335 int64_t cur_data_stream_id = 0;
336
337 /*
338 * Offset, in the underlying media, of the current packet's
339 * start (-1 if unknown).
340 */
341 off_t cur_packet_offset = 0;
342
343 /* Default clock's current value */
344 uint64_t default_clock_snapshot = 0;
345
346 /* End of current packet snapshots */
347 struct end_of_packet_snapshots snapshots;
348
349 /* End of previous packet snapshots */
350 struct end_of_packet_snapshots prev_packet_snapshots;
351
352 /* Stored values (for sequence lengths, variant tags) */
353 GArray *stored_values = nullptr;
354
355 bt2c::Logger logger;
356 };
357
358 static struct stack *stack_new(struct ctf_msg_iter *msg_it)
359 {
360 struct stack *stack = NULL;
361
362 stack = g_new0(struct stack, 1);
363 if (!stack) {
364 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger, "Failed to allocate one stack.");
365 goto error;
366 }
367
368 stack->msg_it = msg_it;
369 stack->entries = g_array_new(FALSE, TRUE, sizeof(struct stack_entry));
370 if (!stack->entries) {
371 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger, "Failed to allocate a GArray.");
372 goto error;
373 }
374
375 BT_CPPLOGD_SPEC(msg_it->logger, "Created stack: msg-it-addr={}, stack-addr={}",
376 fmt::ptr(msg_it), fmt::ptr(stack));
377 goto end;
378
379 error:
380 g_free(stack);
381 stack = NULL;
382
383 end:
384 return stack;
385 }
386
387 static void stack_destroy(struct stack *stack)
388 {
389 struct ctf_msg_iter *msg_it;
390
391 BT_ASSERT_DBG(stack);
392 msg_it = stack->msg_it;
393 BT_CPPLOGD_SPEC(msg_it->logger, "Destroying stack: addr={}", fmt::ptr(stack));
394
395 if (stack->entries) {
396 g_array_free(stack->entries, TRUE);
397 }
398
399 g_free(stack);
400 }
401
402 static void stack_push(struct stack *stack, bt_field *base)
403 {
404 struct stack_entry *entry;
405 struct ctf_msg_iter *msg_it;
406
407 BT_ASSERT_DBG(stack);
408 msg_it = stack->msg_it;
409 BT_ASSERT_DBG(base);
410 BT_CPPLOGT_SPEC(msg_it->logger,
411 "Pushing base field on stack: stack-addr={}, "
412 "stack-size-before={}, stack-size-after={}",
413 fmt::ptr(stack), stack->size, stack->size + 1);
414
415 if (stack->entries->len == stack->size) {
416 g_array_set_size(stack->entries, stack->size + 1);
417 }
418
419 entry = &bt_g_array_index(stack->entries, struct stack_entry, stack->size);
420 entry->base = base;
421 entry->index = 0;
422 stack->size++;
423 }
424
425 static inline unsigned int stack_size(struct stack *stack)
426 {
427 BT_ASSERT_DBG(stack);
428 return stack->size;
429 }
430
431 static void stack_pop(struct stack *stack)
432 {
433 struct ctf_msg_iter *msg_it;
434
435 BT_ASSERT_DBG(stack);
436 BT_ASSERT_DBG(stack_size(stack));
437 msg_it = stack->msg_it;
438 BT_CPPLOGT_SPEC(msg_it->logger,
439 "Popping from stack: "
440 "stack-addr={}, stack-size-before={}, stack-size-after={}",
441 fmt::ptr(stack), stack->size, stack->size - 1);
442 stack->size--;
443 }
444
445 static inline struct stack_entry *stack_top(struct stack *stack)
446 {
447 BT_ASSERT_DBG(stack);
448 BT_ASSERT_DBG(stack_size(stack));
449 return &bt_g_array_index(stack->entries, struct stack_entry, stack->size - 1);
450 }
451
452 static inline bool stack_empty(struct stack *stack)
453 {
454 return stack_size(stack) == 0;
455 }
456
457 static void stack_clear(struct stack *stack)
458 {
459 BT_ASSERT_DBG(stack);
460 stack->size = 0;
461 }
462
463 static inline enum ctf_msg_iter_status
464 msg_iter_status_from_m_status(enum ctf_msg_iter_medium_status m_status)
465 {
466 /* They are the same */
467 return (ctf_msg_iter_status) m_status;
468 }
469
470 static inline size_t buf_size_bits(struct ctf_msg_iter *msg_it)
471 {
472 return msg_it->buf.sz * 8;
473 }
474
475 static inline size_t buf_available_bits(struct ctf_msg_iter *msg_it)
476 {
477 return buf_size_bits(msg_it) - msg_it->buf.at;
478 }
479
480 static inline size_t packet_at(struct ctf_msg_iter *msg_it)
481 {
482 return msg_it->buf.packet_offset + msg_it->buf.at;
483 }
484
485 static inline void buf_consume_bits(struct ctf_msg_iter *msg_it, size_t incr)
486 {
487 BT_CPPLOGT_SPEC(msg_it->logger, "Advancing cursor: msg-it-addr={}, cur-before={}, cur-after={}",
488 fmt::ptr(msg_it), msg_it->buf.at, msg_it->buf.at + incr);
489 msg_it->buf.at += incr;
490 }
491
492 static enum ctf_msg_iter_status request_medium_bytes(struct ctf_msg_iter *msg_it)
493 {
494 uint8_t *buffer_addr = NULL;
495 size_t buffer_sz = 0;
496 enum ctf_msg_iter_medium_status m_status;
497
498 BT_CPPLOGD_SPEC(msg_it->logger,
499 "Calling user function (request bytes): msg-it-addr={}, "
500 "request-size={}",
501 fmt::ptr(msg_it), msg_it->medium.max_request_sz);
502 m_status = msg_it->medium.medops.request_bytes(msg_it->medium.max_request_sz, &buffer_addr,
503 &buffer_sz, msg_it->medium.data);
504 BT_CPPLOGD_SPEC(msg_it->logger, "User function returned: status={}, buf-addr={}, buf-size={}",
505 m_status, fmt::ptr(buffer_addr), buffer_sz);
506 if (m_status == CTF_MSG_ITER_MEDIUM_STATUS_OK) {
507 BT_ASSERT(buffer_sz != 0);
508
509 /* New packet offset is old one + old size (in bits) */
510 msg_it->buf.packet_offset += buf_size_bits(msg_it);
511
512 /* Restart at the beginning of the new medium buffer */
513 msg_it->buf.at = 0;
514 msg_it->buf.last_eh_at = SIZE_MAX;
515
516 /* New medium buffer size */
517 msg_it->buf.sz = buffer_sz;
518
519 /* New medium buffer address */
520 msg_it->buf.addr = buffer_addr;
521
522 BT_CPPLOGD_SPEC(msg_it->logger,
523 "User function returned new bytes: "
524 "packet-offset={}, cur={}, size={}, addr={}",
525 msg_it->buf.packet_offset, msg_it->buf.at, msg_it->buf.sz,
526 fmt::ptr(msg_it->buf.addr));
527 BT_CPPLOGT_MEM_SPEC(msg_it->logger, bt2c::makeSpan(buffer_addr, buffer_sz),
528 "Returned bytes at {}:", fmt::ptr(buffer_addr));
529 } else if (m_status == CTF_MSG_ITER_MEDIUM_STATUS_EOF) {
530 /*
531 * User returned end of stream: validate that we're not
532 * in the middle of a packet header, packet context, or
533 * event.
534 */
535 if (msg_it->cur_exp_packet_total_size >= 0) {
536 if (packet_at(msg_it) == msg_it->cur_exp_packet_total_size) {
537 goto end;
538 }
539 } else {
540 if (packet_at(msg_it) == 0) {
541 goto end;
542 }
543
544 if (msg_it->buf.last_eh_at != SIZE_MAX && msg_it->buf.at == msg_it->buf.last_eh_at) {
545 goto end;
546 }
547 }
548
549 /* All other states are invalid */
550 BT_CPPLOGE_APPEND_CAUSE_SPEC(
551 msg_it->logger,
552 "User function returned {}, but message iterator is in an unexpected state: "
553 "state={}, cur-packet-size={}, cur={}, "
554 "packet-cur={}, last-eh-at={}",
555 m_status, msg_it->state, msg_it->cur_exp_packet_total_size, msg_it->buf.at,
556 packet_at(msg_it), msg_it->buf.last_eh_at);
557 m_status = CTF_MSG_ITER_MEDIUM_STATUS_ERROR;
558 } else if (m_status < 0) {
559 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
560 "User function failed: "
561 "status={}",
562 m_status);
563 }
564
565 end:
566 return msg_iter_status_from_m_status(m_status);
567 }
568
569 static inline enum ctf_msg_iter_status buf_ensure_available_bits(struct ctf_msg_iter *msg_it)
570 {
571 enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
572
573 if (G_UNLIKELY(buf_available_bits(msg_it) == 0)) {
574 /*
575 * This _cannot_ return CTF_MSG_ITER_STATUS_OK
576 * _and_ no bits.
577 */
578 status = request_medium_bytes(msg_it);
579 }
580
581 return status;
582 }
583
584 static enum ctf_msg_iter_status
585 read_dscope_begin_state(struct ctf_msg_iter *msg_it, struct ctf_field_class *dscope_fc,
586 enum state done_state, enum state continue_state, bt_field *dscope_field)
587 {
588 enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
589 enum bt_bfcr_status bfcr_status;
590 size_t consumed_bits;
591
592 msg_it->cur_dscope_field = dscope_field;
593 BT_CPPLOGT_SPEC(msg_it->logger, "Starting BFCR: msg-it-addr={}, bfcr-addr={}, fc-addr={}",
594 fmt::ptr(msg_it), fmt::ptr(msg_it->bfcr), fmt::ptr(dscope_fc));
595 consumed_bits = bt_bfcr_start(msg_it->bfcr, dscope_fc, msg_it->buf.addr, msg_it->buf.at,
596 packet_at(msg_it), msg_it->buf.sz, &bfcr_status);
597 BT_CPPLOGT_SPEC(msg_it->logger, "BFCR consumed bits: size={}", consumed_bits);
598
599 switch (bfcr_status) {
600 case BT_BFCR_STATUS_OK:
601 /* Field class was read completely */
602 BT_CPPLOGT_STR_SPEC(msg_it->logger, "Field was completely decoded.");
603 msg_it->state = done_state;
604 break;
605 case BT_BFCR_STATUS_EOF:
606 BT_CPPLOGT_STR_SPEC(msg_it->logger, "BFCR needs more data to decode field completely.");
607 msg_it->state = continue_state;
608 break;
609 default:
610 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
611 "BFCR failed to start: msg-it-addr={}, bfcr-addr={}, "
612 "status={}",
613 fmt::ptr(msg_it), fmt::ptr(msg_it->bfcr), bfcr_status);
614 status = CTF_MSG_ITER_STATUS_ERROR;
615 goto end;
616 }
617
618 /* Consume bits now since we know we're not in an error state */
619 buf_consume_bits(msg_it, consumed_bits);
620
621 end:
622 return status;
623 }
624
625 static enum ctf_msg_iter_status read_dscope_continue_state(struct ctf_msg_iter *msg_it,
626 enum state done_state)
627 {
628 enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
629 enum bt_bfcr_status bfcr_status;
630 size_t consumed_bits;
631
632 BT_CPPLOGT_SPEC(msg_it->logger, "Continuing BFCR: msg-it-addr={}, bfcr-addr={}",
633 fmt::ptr(msg_it), fmt::ptr(msg_it->bfcr));
634
635 status = buf_ensure_available_bits(msg_it);
636 if (status != CTF_MSG_ITER_STATUS_OK) {
637 if (status < 0) {
638 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
639 "Cannot ensure that buffer has at least one byte: "
640 "msg-addr={}, status={}",
641 fmt::ptr(msg_it), status);
642 } else {
643 BT_CPPLOGT_SPEC(msg_it->logger,
644 "Cannot ensure that buffer has at least one byte: "
645 "msg-addr={}, status={}",
646 fmt::ptr(msg_it), status);
647 }
648
649 goto end;
650 }
651
652 consumed_bits = bt_bfcr_continue(msg_it->bfcr, msg_it->buf.addr, msg_it->buf.sz, &bfcr_status);
653 BT_CPPLOGT_SPEC(msg_it->logger, "BFCR consumed bits: size={}", consumed_bits);
654
655 switch (bfcr_status) {
656 case BT_BFCR_STATUS_OK:
657 /* Type was read completely. */
658 BT_CPPLOGT_STR_SPEC(msg_it->logger, "Field was completely decoded.");
659 msg_it->state = done_state;
660 break;
661 case BT_BFCR_STATUS_EOF:
662 /* Stay in this continue state. */
663 BT_CPPLOGT_STR_SPEC(msg_it->logger, "BFCR needs more data to decode field completely.");
664 break;
665 default:
666 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
667 "BFCR failed to continue: msg-it-addr={}, bfcr-addr={}, "
668 "status={}",
669 fmt::ptr(msg_it), fmt::ptr(msg_it->bfcr), bfcr_status);
670 status = CTF_MSG_ITER_STATUS_ERROR;
671 goto end;
672 }
673
674 /* Consume bits now since we know we're not in an error state. */
675 buf_consume_bits(msg_it, consumed_bits);
676 end:
677 return status;
678 }
679
680 static void release_event_dscopes(struct ctf_msg_iter *msg_it)
681 {
682 msg_it->dscopes.event_common_context = NULL;
683 msg_it->dscopes.event_spec_context = NULL;
684 msg_it->dscopes.event_payload = NULL;
685 }
686
687 static void release_all_dscopes(struct ctf_msg_iter *msg_it)
688 {
689 msg_it->dscopes.stream_packet_context = NULL;
690
691 release_event_dscopes(msg_it);
692 }
693
694 static enum ctf_msg_iter_status switch_packet_state(struct ctf_msg_iter *msg_it)
695 {
696 enum ctf_msg_iter_status status;
697
698 /*
699 * We don't put the stream class here because we need to make
700 * sure that all the packets processed by the same message
701 * iterator refer to the same stream class (the first one).
702 */
703 BT_ASSERT(msg_it);
704
705 if (msg_it->cur_exp_packet_total_size != -1) {
706 msg_it->cur_packet_offset += msg_it->cur_exp_packet_total_size;
707 }
708
709 BT_CPPLOGD_SPEC(msg_it->logger,
710 "Switching packet: msg-it-addr={}, cur={}, "
711 "packet-offset={}",
712 fmt::ptr(msg_it), msg_it->buf.at, msg_it->cur_packet_offset);
713 stack_clear(msg_it->stack);
714 msg_it->meta.ec = NULL;
715 BT_PACKET_PUT_REF_AND_RESET(msg_it->packet);
716 BT_MESSAGE_PUT_REF_AND_RESET(msg_it->event_msg);
717 release_all_dscopes(msg_it);
718 msg_it->cur_dscope_field = NULL;
719
720 if (msg_it->medium.medops.switch_packet) {
721 enum ctf_msg_iter_medium_status medium_status;
722
723 medium_status = msg_it->medium.medops.switch_packet(msg_it->medium.data);
724 if (medium_status == CTF_MSG_ITER_MEDIUM_STATUS_EOF) {
725 /* No more packets. */
726 msg_it->state = STATE_CHECK_EMIT_MSG_STREAM_END;
727 status = CTF_MSG_ITER_STATUS_OK;
728 goto end;
729 } else if (medium_status != CTF_MSG_ITER_MEDIUM_STATUS_OK) {
730 status = msg_iter_status_from_m_status(medium_status);
731 goto end;
732 }
733
734 /*
735 * After the packet switch, the medium might want to give us a
736 * different buffer for the new packet.
737 */
738 status = request_medium_bytes(msg_it);
739 if (status != CTF_MSG_ITER_STATUS_OK) {
740 goto end;
741 }
742 }
743
744 /*
745 * Adjust current buffer so that addr points to the beginning of the new
746 * packet.
747 */
748 if (msg_it->buf.addr) {
749 size_t consumed_bytes = (size_t) (msg_it->buf.at / CHAR_BIT);
750
751 /* Packets are assumed to start on a byte frontier. */
752 if (msg_it->buf.at % CHAR_BIT) {
753 BT_CPPLOGE_APPEND_CAUSE_SPEC(
754 msg_it->logger,
755 "Cannot switch packet: current position is not a multiple of 8: "
756 "msg-it-addr={}, cur={}",
757 fmt::ptr(msg_it), msg_it->buf.at);
758 status = CTF_MSG_ITER_STATUS_ERROR;
759 goto end;
760 }
761
762 msg_it->buf.addr += consumed_bytes;
763 msg_it->buf.sz -= consumed_bytes;
764 msg_it->buf.at = 0;
765 msg_it->buf.packet_offset = 0;
766 BT_CPPLOGD_SPEC(msg_it->logger, "Adjusted buffer: addr={}, size={}",
767 fmt::ptr(msg_it->buf.addr), msg_it->buf.sz);
768 }
769
770 msg_it->cur_exp_packet_content_size = -1;
771 msg_it->cur_exp_packet_total_size = -1;
772 msg_it->cur_stream_class_id = -1;
773 msg_it->cur_event_class_id = -1;
774 msg_it->cur_data_stream_id = -1;
775 msg_it->prev_packet_snapshots = msg_it->snapshots;
776 msg_it->snapshots.discarded_events = UINT64_C(-1);
777 msg_it->snapshots.packets = UINT64_C(-1);
778 msg_it->snapshots.beginning_clock = UINT64_C(-1);
779 msg_it->snapshots.end_clock = UINT64_C(-1);
780 msg_it->state = STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN;
781
782 status = CTF_MSG_ITER_STATUS_OK;
783 end:
784 return status;
785 }
786
787 static enum ctf_msg_iter_status read_packet_header_begin_state(struct ctf_msg_iter *msg_it)
788 {
789 struct ctf_field_class *packet_header_fc = NULL;
790 enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
791
792 /*
793 * Make sure at least one bit is available for this packet. An
794 * empty packet is impossible. If we reach the end of the medium
795 * at this point, then it's considered the end of the stream.
796 */
797 status = buf_ensure_available_bits(msg_it);
798 switch (status) {
799 case CTF_MSG_ITER_STATUS_OK:
800 break;
801 case CTF_MSG_ITER_STATUS_EOF:
802 status = CTF_MSG_ITER_STATUS_OK;
803 msg_it->state = STATE_CHECK_EMIT_MSG_STREAM_END;
804 goto end;
805 default:
806 goto end;
807 }
808
809 /* Packet header class is common to the whole trace class. */
810 packet_header_fc = msg_it->meta.tc->packet_header_fc;
811 if (!packet_header_fc) {
812 msg_it->state = STATE_AFTER_TRACE_PACKET_HEADER;
813 goto end;
814 }
815
816 msg_it->cur_stream_class_id = -1;
817 msg_it->cur_event_class_id = -1;
818 msg_it->cur_data_stream_id = -1;
819 BT_CPPLOGD_SPEC(msg_it->logger,
820 "Decoding packet header field: "
821 "msg-it-addr={}, trace-class-addr={}, fc-addr={}",
822 fmt::ptr(msg_it), fmt::ptr(msg_it->meta.tc), fmt::ptr(packet_header_fc));
823 status = read_dscope_begin_state(msg_it, packet_header_fc, STATE_AFTER_TRACE_PACKET_HEADER,
824 STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE, NULL);
825 if (status < 0) {
826 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
827 "Cannot decode packet header field: "
828 "msg-it-addr={}, trace-class-addr={}, "
829 "fc-addr={}",
830 fmt::ptr(msg_it), fmt::ptr(msg_it->meta.tc),
831 fmt::ptr(packet_header_fc));
832 }
833
834 end:
835 return status;
836 }
837
838 static enum ctf_msg_iter_status read_packet_header_continue_state(struct ctf_msg_iter *msg_it)
839 {
840 return read_dscope_continue_state(msg_it, STATE_AFTER_TRACE_PACKET_HEADER);
841 }
842
843 static inline enum ctf_msg_iter_status set_current_stream_class(struct ctf_msg_iter *msg_it)
844 {
845 enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
846 struct ctf_stream_class *new_stream_class = NULL;
847
848 if (msg_it->cur_stream_class_id == -1) {
849 /*
850 * No current stream class ID field, therefore only one
851 * stream class.
852 */
853 if (msg_it->meta.tc->stream_classes->len != 1) {
854 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
855 "Need exactly one stream class since there's "
856 "no stream class ID field: "
857 "msg-it-addr={}",
858 fmt::ptr(msg_it));
859 status = CTF_MSG_ITER_STATUS_ERROR;
860 goto end;
861 }
862
863 new_stream_class = (ctf_stream_class *) msg_it->meta.tc->stream_classes->pdata[0];
864 msg_it->cur_stream_class_id = new_stream_class->id;
865 }
866
867 new_stream_class =
868 ctf_trace_class_borrow_stream_class_by_id(msg_it->meta.tc, msg_it->cur_stream_class_id);
869 if (!new_stream_class) {
870 BT_CPPLOGE_APPEND_CAUSE_SPEC(
871 msg_it->logger,
872 "No stream class with ID of stream class ID to use in trace class: "
873 "msg-it-addr={}, stream-class-id={}, "
874 "trace-class-addr={}",
875 fmt::ptr(msg_it), msg_it->cur_stream_class_id, fmt::ptr(msg_it->meta.tc));
876 status = CTF_MSG_ITER_STATUS_ERROR;
877 goto end;
878 }
879
880 if (msg_it->meta.sc) {
881 if (new_stream_class != msg_it->meta.sc) {
882 BT_CPPLOGE_APPEND_CAUSE_SPEC(
883 msg_it->logger,
884 "Two packets refer to two different stream classes within the same packet sequence: "
885 "msg-it-addr={}, prev-stream-class-addr={}, "
886 "prev-stream-class-id={}, "
887 "next-stream-class-addr={}, "
888 "next-stream-class-id={}, "
889 "trace-addr={}",
890 fmt::ptr(msg_it), fmt::ptr(msg_it->meta.sc), msg_it->meta.sc->id,
891 fmt::ptr(new_stream_class), new_stream_class->id, fmt::ptr(msg_it->meta.tc));
892 status = CTF_MSG_ITER_STATUS_ERROR;
893 goto end;
894 }
895 } else {
896 msg_it->meta.sc = new_stream_class;
897 }
898
899 BT_CPPLOGD_SPEC(msg_it->logger,
900 "Set current stream class: "
901 "msg-it-addr={}, stream-class-addr={}, "
902 "stream-class-id={}",
903 fmt::ptr(msg_it), fmt::ptr(msg_it->meta.sc), msg_it->meta.sc->id);
904
905 end:
906 return status;
907 }
908
909 static inline enum ctf_msg_iter_status set_current_stream(struct ctf_msg_iter *msg_it)
910 {
911 enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
912 bt_stream *stream = NULL;
913
914 BT_CPPLOGD_SPEC(msg_it->logger,
915 "Calling user function (get stream): msg-it-addr={}, "
916 "stream-class-addr={}, stream-class-id={}",
917 fmt::ptr(msg_it), fmt::ptr(msg_it->meta.sc), msg_it->meta.sc->id);
918 stream = msg_it->medium.medops.borrow_stream(msg_it->meta.sc->ir_sc, msg_it->cur_data_stream_id,
919 msg_it->medium.data);
920 bt_stream_get_ref(stream);
921 BT_CPPLOGD_SPEC(msg_it->logger, "User function returned: stream-addr={}", fmt::ptr(stream));
922 if (!stream) {
923 BT_CPPLOGE_APPEND_CAUSE_SPEC(
924 msg_it->logger,
925 "User function failed to return a stream object for the given stream class.");
926 status = CTF_MSG_ITER_STATUS_ERROR;
927 goto end;
928 }
929
930 if (msg_it->stream && stream != msg_it->stream) {
931 BT_CPPLOGE_APPEND_CAUSE_SPEC(
932 msg_it->logger,
933 "User function returned a different stream than the previous one for the same sequence of packets.");
934 status = CTF_MSG_ITER_STATUS_ERROR;
935 goto end;
936 }
937
938 BT_STREAM_MOVE_REF(msg_it->stream, stream);
939
940 end:
941 bt_stream_put_ref(stream);
942 return status;
943 }
944
945 static inline enum ctf_msg_iter_status set_current_packet(struct ctf_msg_iter *msg_it)
946 {
947 enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
948 bt_packet *packet = NULL;
949
950 BT_CPPLOGD_SPEC(msg_it->logger,
951 "Creating packet from stream: "
952 "msg-it-addr={}, stream-addr={}, "
953 "stream-class-addr={}, "
954 "stream-class-id={}",
955 fmt::ptr(msg_it), fmt::ptr(msg_it->stream), fmt::ptr(msg_it->meta.sc),
956 msg_it->meta.sc->id);
957
958 /* Create packet */
959 BT_ASSERT(msg_it->stream);
960 packet = bt_packet_create(msg_it->stream);
961 if (!packet) {
962 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
963 "Cannot create packet from stream: "
964 "msg-it-addr={}, stream-addr={}, "
965 "stream-class-addr={}, "
966 "stream-class-id={}",
967 fmt::ptr(msg_it), fmt::ptr(msg_it->stream),
968 fmt::ptr(msg_it->meta.sc), msg_it->meta.sc->id);
969 goto error;
970 }
971
972 goto end;
973
974 error:
975 BT_PACKET_PUT_REF_AND_RESET(packet);
976 status = CTF_MSG_ITER_STATUS_ERROR;
977
978 end:
979 BT_PACKET_MOVE_REF(msg_it->packet, packet);
980 return status;
981 }
982
983 static enum ctf_msg_iter_status after_packet_header_state(struct ctf_msg_iter *msg_it)
984 {
985 enum ctf_msg_iter_status status;
986
987 status = set_current_stream_class(msg_it);
988 if (status != CTF_MSG_ITER_STATUS_OK) {
989 goto end;
990 }
991
992 if (!msg_it->dry_run) {
993 status = set_current_stream(msg_it);
994 if (status != CTF_MSG_ITER_STATUS_OK) {
995 goto end;
996 }
997
998 status = set_current_packet(msg_it);
999 if (status != CTF_MSG_ITER_STATUS_OK) {
1000 goto end;
1001 }
1002 }
1003
1004 msg_it->state = STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN;
1005
1006 status = CTF_MSG_ITER_STATUS_OK;
1007
1008 end:
1009 return status;
1010 }
1011
1012 static enum ctf_msg_iter_status read_packet_context_begin_state(struct ctf_msg_iter *msg_it)
1013 {
1014 enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
1015 struct ctf_field_class *packet_context_fc;
1016
1017 BT_ASSERT(msg_it->meta.sc);
1018 packet_context_fc = msg_it->meta.sc->packet_context_fc;
1019 if (!packet_context_fc) {
1020 BT_CPPLOGD_SPEC(msg_it->logger,
1021 "No packet packet context field class in stream class: continuing: "
1022 "msg-it-addr={}, stream-class-addr={}, "
1023 "stream-class-id={}",
1024 fmt::ptr(msg_it), fmt::ptr(msg_it->meta.sc), msg_it->meta.sc->id);
1025 msg_it->state = STATE_AFTER_STREAM_PACKET_CONTEXT;
1026 goto end;
1027 }
1028
1029 if (packet_context_fc->in_ir && !msg_it->dry_run) {
1030 BT_ASSERT(!msg_it->dscopes.stream_packet_context);
1031 BT_ASSERT(msg_it->packet);
1032 msg_it->dscopes.stream_packet_context = bt_packet_borrow_context_field(msg_it->packet);
1033 BT_ASSERT(msg_it->dscopes.stream_packet_context);
1034 }
1035
1036 BT_CPPLOGD_SPEC(msg_it->logger,
1037 "Decoding packet context field: "
1038 "msg-it-addr={}, stream-class-addr={}, "
1039 "stream-class-id={}, fc-addr={}",
1040 fmt::ptr(msg_it), fmt::ptr(msg_it->meta.sc), msg_it->meta.sc->id,
1041 fmt::ptr(packet_context_fc));
1042 status = read_dscope_begin_state(msg_it, packet_context_fc, STATE_AFTER_STREAM_PACKET_CONTEXT,
1043 STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE,
1044 msg_it->dscopes.stream_packet_context);
1045 if (status < 0) {
1046 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
1047 "Cannot decode packet context field: "
1048 "msg-it-addr={}, stream-class-addr={}, "
1049 "stream-class-id={}, fc-addr={}",
1050 fmt::ptr(msg_it), fmt::ptr(msg_it->meta.sc),
1051 msg_it->meta.sc->id, fmt::ptr(packet_context_fc));
1052 }
1053
1054 end:
1055 return status;
1056 }
1057
1058 static enum ctf_msg_iter_status read_packet_context_continue_state(struct ctf_msg_iter *msg_it)
1059 {
1060 return read_dscope_continue_state(msg_it, STATE_AFTER_STREAM_PACKET_CONTEXT);
1061 }
1062
1063 static enum ctf_msg_iter_status set_current_packet_content_sizes(struct ctf_msg_iter *msg_it)
1064 {
1065 enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
1066
1067 if (msg_it->cur_exp_packet_total_size == -1) {
1068 if (msg_it->cur_exp_packet_content_size != -1) {
1069 msg_it->cur_exp_packet_total_size = msg_it->cur_exp_packet_content_size;
1070 }
1071 } else {
1072 if (msg_it->cur_exp_packet_content_size == -1) {
1073 msg_it->cur_exp_packet_content_size = msg_it->cur_exp_packet_total_size;
1074 }
1075 }
1076
1077 BT_ASSERT(
1078 (msg_it->cur_exp_packet_total_size >= 0 && msg_it->cur_exp_packet_content_size >= 0) ||
1079 (msg_it->cur_exp_packet_total_size < 0 && msg_it->cur_exp_packet_content_size < 0));
1080
1081 if (msg_it->cur_exp_packet_content_size > msg_it->cur_exp_packet_total_size) {
1082 BT_CPPLOGE_APPEND_CAUSE_SPEC(
1083 msg_it->logger,
1084 "Invalid packet or content size: "
1085 "content size is greater than packet size: "
1086 "msg-it-addr={}, packet-context-field-addr={}, "
1087 "packet-size={}, content-size={}",
1088 fmt::ptr(msg_it), fmt::ptr(msg_it->dscopes.stream_packet_context),
1089 msg_it->cur_exp_packet_total_size, msg_it->cur_exp_packet_content_size);
1090 status = CTF_MSG_ITER_STATUS_ERROR;
1091 goto end;
1092 }
1093
1094 BT_CPPLOGD_SPEC(msg_it->logger,
1095 "Set current packet and content sizes: "
1096 "msg-it-addr={}, packet-size={}, content-size={}",
1097 fmt::ptr(msg_it), msg_it->cur_exp_packet_total_size,
1098 msg_it->cur_exp_packet_content_size);
1099
1100 end:
1101 return status;
1102 }
1103
1104 static enum ctf_msg_iter_status after_packet_context_state(struct ctf_msg_iter *msg_it)
1105 {
1106 enum ctf_msg_iter_status status;
1107
1108 status = set_current_packet_content_sizes(msg_it);
1109 if (status != CTF_MSG_ITER_STATUS_OK) {
1110 goto end;
1111 }
1112
1113 if (msg_it->emit_stream_beginning_message) {
1114 msg_it->state = STATE_EMIT_MSG_STREAM_BEGINNING;
1115 } else {
1116 msg_it->state = STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS;
1117 }
1118
1119 end:
1120 return status;
1121 }
1122
1123 static enum ctf_msg_iter_status read_event_header_begin_state(struct ctf_msg_iter *msg_it)
1124 {
1125 enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
1126 struct ctf_field_class *event_header_fc = NULL;
1127
1128 /* Reset the position of the last event header */
1129 msg_it->buf.last_eh_at = msg_it->buf.at;
1130 msg_it->cur_event_class_id = -1;
1131
1132 /* Check if we have some content left */
1133 if (msg_it->cur_exp_packet_content_size >= 0) {
1134 if (G_UNLIKELY(packet_at(msg_it) == msg_it->cur_exp_packet_content_size)) {
1135 /* No more events! */
1136 BT_CPPLOGD_SPEC(msg_it->logger,
1137 "Reached end of packet: msg-it-addr={}, "
1138 "cur={}",
1139 fmt::ptr(msg_it), packet_at(msg_it));
1140 msg_it->state = STATE_EMIT_MSG_PACKET_END_MULTI;
1141 goto end;
1142 } else if (G_UNLIKELY(packet_at(msg_it) > msg_it->cur_exp_packet_content_size)) {
1143 /* That's not supposed to happen */
1144 BT_CPPLOGD_SPEC(
1145 msg_it->logger,
1146 "Before decoding event header field: cursor is passed the packet's content: "
1147 "msg-it-addr={}, content-size={}, "
1148 "cur={}",
1149 fmt::ptr(msg_it), msg_it->cur_exp_packet_content_size, packet_at(msg_it));
1150 status = CTF_MSG_ITER_STATUS_ERROR;
1151 goto end;
1152 }
1153 } else {
1154 /*
1155 * "Infinite" content: we're done when the medium has
1156 * nothing else for us.
1157 */
1158 status = buf_ensure_available_bits(msg_it);
1159 switch (status) {
1160 case CTF_MSG_ITER_STATUS_OK:
1161 break;
1162 case CTF_MSG_ITER_STATUS_EOF:
1163 status = CTF_MSG_ITER_STATUS_OK;
1164 msg_it->state = STATE_EMIT_MSG_PACKET_END_SINGLE;
1165 goto end;
1166 default:
1167 goto end;
1168 }
1169 }
1170
1171 release_event_dscopes(msg_it);
1172 BT_ASSERT(msg_it->meta.sc);
1173 event_header_fc = msg_it->meta.sc->event_header_fc;
1174 if (!event_header_fc) {
1175 msg_it->state = STATE_AFTER_EVENT_HEADER;
1176 goto end;
1177 }
1178
1179 BT_CPPLOGD_SPEC(msg_it->logger,
1180 "Decoding event header field: "
1181 "msg-it-addr={}, stream-class-addr={}, "
1182 "stream-class-id={}, "
1183 "fc-addr={}",
1184 fmt::ptr(msg_it), fmt::ptr(msg_it->meta.sc), msg_it->meta.sc->id,
1185 fmt::ptr(event_header_fc));
1186 status = read_dscope_begin_state(msg_it, event_header_fc, STATE_AFTER_EVENT_HEADER,
1187 STATE_DSCOPE_EVENT_HEADER_CONTINUE, NULL);
1188 if (status < 0) {
1189 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
1190 "Cannot decode event header field: "
1191 "msg-it-addr={}, stream-class-addr={}, "
1192 "stream-class-id={}, fc-addr={}",
1193 fmt::ptr(msg_it), fmt::ptr(msg_it->meta.sc),
1194 msg_it->meta.sc->id, fmt::ptr(event_header_fc));
1195 }
1196
1197 end:
1198 return status;
1199 }
1200
1201 static enum ctf_msg_iter_status read_event_header_continue_state(struct ctf_msg_iter *msg_it)
1202 {
1203 return read_dscope_continue_state(msg_it, STATE_AFTER_EVENT_HEADER);
1204 }
1205
1206 static inline enum ctf_msg_iter_status set_current_event_class(struct ctf_msg_iter *msg_it)
1207 {
1208 enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
1209
1210 struct ctf_event_class *new_event_class = NULL;
1211
1212 if (msg_it->cur_event_class_id == -1) {
1213 /*
1214 * No current event class ID field, therefore only one
1215 * event class.
1216 */
1217 if (msg_it->meta.sc->event_classes->len != 1) {
1218 BT_CPPLOGE_APPEND_CAUSE_SPEC(
1219 msg_it->logger,
1220 "Need exactly one event class since there's no event class ID field: "
1221 "msg-it-addr={}",
1222 fmt::ptr(msg_it));
1223 status = CTF_MSG_ITER_STATUS_ERROR;
1224 goto end;
1225 }
1226
1227 new_event_class = (ctf_event_class *) msg_it->meta.sc->event_classes->pdata[0];
1228 msg_it->cur_event_class_id = new_event_class->id;
1229 }
1230
1231 new_event_class =
1232 ctf_stream_class_borrow_event_class_by_id(msg_it->meta.sc, msg_it->cur_event_class_id);
1233 if (!new_event_class) {
1234 BT_CPPLOGE_APPEND_CAUSE_SPEC(
1235 msg_it->logger,
1236 "No event class with ID of event class ID to use in stream class: "
1237 "msg-it-addr={}, stream-class-id={}, "
1238 "event-class-id={}, "
1239 "trace-class-addr={}",
1240 fmt::ptr(msg_it), msg_it->meta.sc->id, msg_it->cur_event_class_id,
1241 fmt::ptr(msg_it->meta.tc));
1242 status = CTF_MSG_ITER_STATUS_ERROR;
1243 goto end;
1244 }
1245
1246 msg_it->meta.ec = new_event_class;
1247 BT_CPPLOGD_SPEC(msg_it->logger,
1248 "Set current event class: "
1249 "msg-it-addr={}, event-class-addr={}, "
1250 "event-class-id={}, "
1251 "event-class-name=\"{}\"",
1252 fmt::ptr(msg_it), fmt::ptr(msg_it->meta.ec), msg_it->meta.ec->id,
1253 msg_it->meta.ec->name->str);
1254
1255 end:
1256 return status;
1257 }
1258
1259 static inline enum ctf_msg_iter_status set_current_event_message(struct ctf_msg_iter *msg_it)
1260 {
1261 enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
1262 bt_message *msg = NULL;
1263
1264 BT_ASSERT_DBG(msg_it->meta.ec);
1265 BT_ASSERT_DBG(msg_it->packet);
1266 BT_CPPLOGD_SPEC(msg_it->logger,
1267 "Creating event message from event class and packet: "
1268 "msg-it-addr={}, ec-addr={}, ec-name=\"{}\", packet-addr={}",
1269 fmt::ptr(msg_it), fmt::ptr(msg_it->meta.ec), msg_it->meta.ec->name->str,
1270 fmt::ptr(msg_it->packet));
1271 BT_ASSERT_DBG(msg_it->self_msg_iter);
1272 BT_ASSERT_DBG(msg_it->meta.sc);
1273
1274 if (bt_stream_class_borrow_default_clock_class(msg_it->meta.sc->ir_sc)) {
1275 msg = bt_message_event_create_with_packet_and_default_clock_snapshot(
1276 msg_it->self_msg_iter, msg_it->meta.ec->ir_ec, msg_it->packet,
1277 msg_it->default_clock_snapshot);
1278 } else {
1279 msg = bt_message_event_create_with_packet(msg_it->self_msg_iter, msg_it->meta.ec->ir_ec,
1280 msg_it->packet);
1281 }
1282
1283 if (!msg) {
1284 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
1285 "Cannot create event message: "
1286 "msg-it-addr={}, ec-addr={}, ec-name=\"{}\", "
1287 "packet-addr={}",
1288 fmt::ptr(msg_it), fmt::ptr(msg_it->meta.ec),
1289 msg_it->meta.ec->name->str, fmt::ptr(msg_it->packet));
1290 goto error;
1291 }
1292
1293 goto end;
1294
1295 error:
1296 BT_MESSAGE_PUT_REF_AND_RESET(msg);
1297 status = CTF_MSG_ITER_STATUS_ERROR;
1298
1299 end:
1300 BT_MESSAGE_MOVE_REF(msg_it->event_msg, msg);
1301 return status;
1302 }
1303
1304 static enum ctf_msg_iter_status after_event_header_state(struct ctf_msg_iter *msg_it)
1305 {
1306 enum ctf_msg_iter_status status;
1307
1308 status = set_current_event_class(msg_it);
1309 if (status != CTF_MSG_ITER_STATUS_OK) {
1310 goto end;
1311 }
1312
1313 if (G_UNLIKELY(msg_it->dry_run)) {
1314 goto next_state;
1315 }
1316
1317 status = set_current_event_message(msg_it);
1318 if (status != CTF_MSG_ITER_STATUS_OK) {
1319 goto end;
1320 }
1321
1322 msg_it->event = bt_message_event_borrow_event(msg_it->event_msg);
1323 BT_ASSERT_DBG(msg_it->event);
1324
1325 next_state:
1326 msg_it->state = STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN;
1327
1328 end:
1329 return status;
1330 }
1331
1332 static enum ctf_msg_iter_status read_event_common_context_begin_state(struct ctf_msg_iter *msg_it)
1333 {
1334 enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
1335 struct ctf_field_class *event_common_context_fc;
1336
1337 event_common_context_fc = msg_it->meta.sc->event_common_context_fc;
1338 if (!event_common_context_fc) {
1339 msg_it->state = STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN;
1340 goto end;
1341 }
1342
1343 if (event_common_context_fc->in_ir && !msg_it->dry_run) {
1344 BT_ASSERT_DBG(!msg_it->dscopes.event_common_context);
1345 msg_it->dscopes.event_common_context = bt_event_borrow_common_context_field(msg_it->event);
1346 BT_ASSERT_DBG(msg_it->dscopes.event_common_context);
1347 }
1348
1349 BT_CPPLOGT_SPEC(msg_it->logger,
1350 "Decoding event common context field: "
1351 "msg-it-addr={}, stream-class-addr={}, "
1352 "stream-class-id={}, "
1353 "fc-addr={}",
1354 fmt::ptr(msg_it), fmt::ptr(msg_it->meta.sc), msg_it->meta.sc->id,
1355 fmt::ptr(event_common_context_fc));
1356 status = read_dscope_begin_state(
1357 msg_it, event_common_context_fc, STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN,
1358 STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE, msg_it->dscopes.event_common_context);
1359 if (status < 0) {
1360 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
1361 "Cannot decode event common context field: "
1362 "msg-it-addr={}, stream-class-addr={}, "
1363 "stream-class-id={}, fc-addr={}",
1364 fmt::ptr(msg_it), fmt::ptr(msg_it->meta.sc),
1365 msg_it->meta.sc->id, fmt::ptr(event_common_context_fc));
1366 }
1367
1368 end:
1369 return status;
1370 }
1371
1372 static enum ctf_msg_iter_status
1373 read_event_common_context_continue_state(struct ctf_msg_iter *msg_it)
1374 {
1375 return read_dscope_continue_state(msg_it, STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN);
1376 }
1377
1378 static enum ctf_msg_iter_status read_event_spec_context_begin_state(struct ctf_msg_iter *msg_it)
1379 {
1380 enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
1381 struct ctf_field_class *event_spec_context_fc;
1382
1383 event_spec_context_fc = msg_it->meta.ec->spec_context_fc;
1384 if (!event_spec_context_fc) {
1385 msg_it->state = STATE_DSCOPE_EVENT_PAYLOAD_BEGIN;
1386 goto end;
1387 }
1388
1389 if (event_spec_context_fc->in_ir && !msg_it->dry_run) {
1390 BT_ASSERT_DBG(!msg_it->dscopes.event_spec_context);
1391 msg_it->dscopes.event_spec_context = bt_event_borrow_specific_context_field(msg_it->event);
1392 BT_ASSERT_DBG(msg_it->dscopes.event_spec_context);
1393 }
1394
1395 BT_CPPLOGT_SPEC(msg_it->logger,
1396 "Decoding event specific context field: "
1397 "msg-it-addr={}, event-class-addr={}, "
1398 "event-class-name=\"{}\", event-class-id={}, "
1399 "fc-addr={}",
1400 fmt::ptr(msg_it), fmt::ptr(msg_it->meta.ec), msg_it->meta.ec->name->str,
1401 msg_it->meta.ec->id, fmt::ptr(event_spec_context_fc));
1402 status = read_dscope_begin_state(
1403 msg_it, event_spec_context_fc, STATE_DSCOPE_EVENT_PAYLOAD_BEGIN,
1404 STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE, msg_it->dscopes.event_spec_context);
1405 if (status < 0) {
1406 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
1407 "Cannot decode event specific context field: "
1408 "msg-it-addr={}, event-class-addr={}, "
1409 "event-class-name=\"{}\", "
1410 "event-class-id={}, fc-addr={}",
1411 fmt::ptr(msg_it), fmt::ptr(msg_it->meta.ec),
1412 msg_it->meta.ec->name->str, msg_it->meta.ec->id,
1413 fmt::ptr(event_spec_context_fc));
1414 }
1415
1416 end:
1417 return status;
1418 }
1419
1420 static enum ctf_msg_iter_status read_event_spec_context_continue_state(struct ctf_msg_iter *msg_it)
1421 {
1422 return read_dscope_continue_state(msg_it, STATE_DSCOPE_EVENT_PAYLOAD_BEGIN);
1423 }
1424
1425 static enum ctf_msg_iter_status read_event_payload_begin_state(struct ctf_msg_iter *msg_it)
1426 {
1427 enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
1428 struct ctf_field_class *event_payload_fc;
1429
1430 event_payload_fc = msg_it->meta.ec->payload_fc;
1431 if (!event_payload_fc) {
1432 msg_it->state = STATE_EMIT_MSG_EVENT;
1433 goto end;
1434 }
1435
1436 if (event_payload_fc->in_ir && !msg_it->dry_run) {
1437 BT_ASSERT_DBG(!msg_it->dscopes.event_payload);
1438 msg_it->dscopes.event_payload = bt_event_borrow_payload_field(msg_it->event);
1439 BT_ASSERT_DBG(msg_it->dscopes.event_payload);
1440 }
1441
1442 BT_CPPLOGT_SPEC(msg_it->logger,
1443 "Decoding event payload field: "
1444 "msg-it-addr={}, event-class-addr={}, "
1445 "event-class-name=\"{}\", event-class-id={}, "
1446 "fc-addr={}",
1447 fmt::ptr(msg_it), fmt::ptr(msg_it->meta.ec), msg_it->meta.ec->name->str,
1448 msg_it->meta.ec->id, fmt::ptr(event_payload_fc));
1449 status =
1450 read_dscope_begin_state(msg_it, event_payload_fc, STATE_EMIT_MSG_EVENT,
1451 STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE, msg_it->dscopes.event_payload);
1452 if (status < 0) {
1453 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
1454 "Cannot decode event payload field: "
1455 "msg-it-addr={}, event-class-addr={}, "
1456 "event-class-name=\"{}\", "
1457 "event-class-id={}, fc-addr={}",
1458 fmt::ptr(msg_it), fmt::ptr(msg_it->meta.ec),
1459 msg_it->meta.ec->name->str, msg_it->meta.ec->id,
1460 fmt::ptr(event_payload_fc));
1461 }
1462
1463 end:
1464 return status;
1465 }
1466
1467 static enum ctf_msg_iter_status read_event_payload_continue_state(struct ctf_msg_iter *msg_it)
1468 {
1469 return read_dscope_continue_state(msg_it, STATE_EMIT_MSG_EVENT);
1470 }
1471
1472 static enum ctf_msg_iter_status skip_packet_padding_state(struct ctf_msg_iter *msg_it)
1473 {
1474 enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
1475 size_t bits_to_skip;
1476 const enum state next_state = STATE_SWITCH_PACKET;
1477
1478 BT_ASSERT(msg_it->cur_exp_packet_total_size > 0);
1479 bits_to_skip = msg_it->cur_exp_packet_total_size - packet_at(msg_it);
1480 if (bits_to_skip == 0) {
1481 msg_it->state = next_state;
1482 goto end;
1483 } else {
1484 size_t bits_to_consume;
1485
1486 BT_CPPLOGD_SPEC(msg_it->logger,
1487 "Trying to skip {} bits of padding: msg-it-addr={}, size={}", bits_to_skip,
1488 fmt::ptr(msg_it), bits_to_skip);
1489 status = buf_ensure_available_bits(msg_it);
1490 if (status != CTF_MSG_ITER_STATUS_OK) {
1491 goto end;
1492 }
1493
1494 bits_to_consume = MIN(buf_available_bits(msg_it), bits_to_skip);
1495 BT_CPPLOGD_SPEC(msg_it->logger, "Skipping {} bits of padding: msg-it-addr={}, size={}",
1496 bits_to_consume, fmt::ptr(msg_it), bits_to_consume);
1497 buf_consume_bits(msg_it, bits_to_consume);
1498 bits_to_skip = msg_it->cur_exp_packet_total_size - packet_at(msg_it);
1499 if (bits_to_skip == 0) {
1500 msg_it->state = next_state;
1501 goto end;
1502 }
1503 }
1504
1505 end:
1506 return status;
1507 }
1508
1509 static enum ctf_msg_iter_status check_emit_msg_discarded_events(struct ctf_msg_iter *msg_it)
1510 {
1511 msg_it->state = STATE_EMIT_MSG_DISCARDED_EVENTS;
1512
1513 if (!msg_it->meta.sc->has_discarded_events) {
1514 msg_it->state = STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS;
1515 goto end;
1516 }
1517
1518 if (msg_it->prev_packet_snapshots.discarded_events == UINT64_C(-1)) {
1519 if (msg_it->snapshots.discarded_events == 0 ||
1520 msg_it->snapshots.discarded_events == UINT64_C(-1)) {
1521 /*
1522 * Stream's first packet with no discarded
1523 * events or no information about discarded
1524 * events: do not emit.
1525 */
1526 msg_it->state = STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS;
1527 }
1528 } else {
1529 /*
1530 * If the previous packet has a value for this counter,
1531 * then this counter is defined for the whole stream.
1532 */
1533 BT_ASSERT(msg_it->snapshots.discarded_events != UINT64_C(-1));
1534
1535 if (msg_it->snapshots.discarded_events - msg_it->prev_packet_snapshots.discarded_events ==
1536 0) {
1537 /*
1538 * No discarded events since previous packet: do
1539 * not emit.
1540 */
1541 msg_it->state = STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS;
1542 }
1543 }
1544
1545 end:
1546 return CTF_MSG_ITER_STATUS_OK;
1547 }
1548
1549 static enum ctf_msg_iter_status check_emit_msg_discarded_packets(struct ctf_msg_iter *msg_it)
1550 {
1551 msg_it->state = STATE_EMIT_MSG_DISCARDED_PACKETS;
1552
1553 if (!msg_it->meta.sc->has_discarded_packets) {
1554 msg_it->state = STATE_EMIT_MSG_PACKET_BEGINNING;
1555 goto end;
1556 }
1557
1558 if (msg_it->prev_packet_snapshots.packets == UINT64_C(-1)) {
1559 /*
1560 * Stream's first packet or no information about
1561 * discarded packets: do not emit. In other words, if
1562 * this is the first packet and its sequence number is
1563 * not 0, do not consider that packets were previously
1564 * lost: we might be reading a partial stream (LTTng
1565 * snapshot for example).
1566 */
1567 msg_it->state = STATE_EMIT_MSG_PACKET_BEGINNING;
1568 } else {
1569 /*
1570 * If the previous packet has a value for this counter,
1571 * then this counter is defined for the whole stream.
1572 */
1573 BT_ASSERT(msg_it->snapshots.packets != UINT64_C(-1));
1574
1575 if (msg_it->snapshots.packets - msg_it->prev_packet_snapshots.packets <= 1) {
1576 /*
1577 * No discarded packets since previous packet:
1578 * do not emit.
1579 */
1580 msg_it->state = STATE_EMIT_MSG_PACKET_BEGINNING;
1581 }
1582 }
1583
1584 end:
1585 return CTF_MSG_ITER_STATUS_OK;
1586 }
1587
1588 static inline enum state check_emit_msg_stream_end(struct ctf_msg_iter *msg_it)
1589 {
1590 enum state next_state;
1591
1592 if (msg_it->emit_stream_end_message) {
1593 next_state = STATE_EMIT_MSG_STREAM_END;
1594 } else {
1595 next_state = STATE_DONE;
1596 }
1597
1598 return next_state;
1599 }
1600
1601 static inline enum ctf_msg_iter_status handle_state(struct ctf_msg_iter *msg_it)
1602 {
1603 enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
1604 const enum state state = msg_it->state;
1605
1606 BT_CPPLOGT_SPEC(msg_it->logger, "Handling state: msg-it-addr={}, state={}", fmt::ptr(msg_it),
1607 state);
1608
1609 // TODO: optimalize!
1610 switch (state) {
1611 case STATE_INIT:
1612 msg_it->state = STATE_SWITCH_PACKET;
1613 break;
1614 case STATE_SWITCH_PACKET:
1615 status = switch_packet_state(msg_it);
1616 break;
1617 case STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN:
1618 status = read_packet_header_begin_state(msg_it);
1619 break;
1620 case STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE:
1621 status = read_packet_header_continue_state(msg_it);
1622 break;
1623 case STATE_AFTER_TRACE_PACKET_HEADER:
1624 status = after_packet_header_state(msg_it);
1625 break;
1626 case STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN:
1627 status = read_packet_context_begin_state(msg_it);
1628 break;
1629 case STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE:
1630 status = read_packet_context_continue_state(msg_it);
1631 break;
1632 case STATE_AFTER_STREAM_PACKET_CONTEXT:
1633 status = after_packet_context_state(msg_it);
1634 break;
1635 case STATE_EMIT_MSG_STREAM_BEGINNING:
1636 msg_it->state = STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS;
1637 break;
1638 case STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS:
1639 status = check_emit_msg_discarded_events(msg_it);
1640 break;
1641 case STATE_EMIT_MSG_DISCARDED_EVENTS:
1642 msg_it->state = STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS;
1643 break;
1644 case STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS:
1645 status = check_emit_msg_discarded_packets(msg_it);
1646 break;
1647 case STATE_EMIT_MSG_DISCARDED_PACKETS:
1648 msg_it->state = STATE_EMIT_MSG_PACKET_BEGINNING;
1649 break;
1650 case STATE_EMIT_MSG_PACKET_BEGINNING:
1651 msg_it->state = STATE_DSCOPE_EVENT_HEADER_BEGIN;
1652 break;
1653 case STATE_DSCOPE_EVENT_HEADER_BEGIN:
1654 status = read_event_header_begin_state(msg_it);
1655 break;
1656 case STATE_DSCOPE_EVENT_HEADER_CONTINUE:
1657 status = read_event_header_continue_state(msg_it);
1658 break;
1659 case STATE_AFTER_EVENT_HEADER:
1660 status = after_event_header_state(msg_it);
1661 break;
1662 case STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN:
1663 status = read_event_common_context_begin_state(msg_it);
1664 break;
1665 case STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE:
1666 status = read_event_common_context_continue_state(msg_it);
1667 break;
1668 case STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN:
1669 status = read_event_spec_context_begin_state(msg_it);
1670 break;
1671 case STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE:
1672 status = read_event_spec_context_continue_state(msg_it);
1673 break;
1674 case STATE_DSCOPE_EVENT_PAYLOAD_BEGIN:
1675 status = read_event_payload_begin_state(msg_it);
1676 break;
1677 case STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE:
1678 status = read_event_payload_continue_state(msg_it);
1679 break;
1680 case STATE_EMIT_MSG_EVENT:
1681 msg_it->state = STATE_DSCOPE_EVENT_HEADER_BEGIN;
1682 break;
1683 case STATE_EMIT_QUEUED_MSG_EVENT:
1684 msg_it->state = STATE_EMIT_MSG_EVENT;
1685 break;
1686 case STATE_SKIP_PACKET_PADDING:
1687 status = skip_packet_padding_state(msg_it);
1688 break;
1689 case STATE_EMIT_MSG_PACKET_END_MULTI:
1690 msg_it->state = STATE_SKIP_PACKET_PADDING;
1691 break;
1692 case STATE_EMIT_MSG_PACKET_END_SINGLE:
1693 msg_it->state = STATE_EMIT_MSG_STREAM_END;
1694 break;
1695 case STATE_EMIT_QUEUED_MSG_PACKET_END:
1696 msg_it->state = STATE_EMIT_MSG_PACKET_END_SINGLE;
1697 break;
1698 case STATE_CHECK_EMIT_MSG_STREAM_END:
1699 msg_it->state = check_emit_msg_stream_end(msg_it);
1700 break;
1701 case STATE_EMIT_MSG_STREAM_END:
1702 msg_it->state = STATE_DONE;
1703 break;
1704 case STATE_DONE:
1705 break;
1706 default:
1707 BT_CPPLOGF_SPEC(msg_it->logger,
1708 "Unknown CTF plugin message iterator state: "
1709 "msg-it-addr={}, state={}",
1710 fmt::ptr(msg_it), msg_it->state);
1711 bt_common_abort();
1712 }
1713
1714 BT_CPPLOGT_SPEC(msg_it->logger,
1715 "Handled state: msg-it-addr={}, status={}, "
1716 "prev-state={}, cur-state={}",
1717 fmt::ptr(msg_it), status, state, msg_it->state);
1718 return status;
1719 }
1720
1721 void ctf_msg_iter_reset_for_next_stream_file(struct ctf_msg_iter *msg_it)
1722 {
1723 BT_ASSERT(msg_it);
1724 BT_CPPLOGD_SPEC(msg_it->logger, "Resetting message iterator: addr={}", fmt::ptr(msg_it));
1725 stack_clear(msg_it->stack);
1726 msg_it->meta.sc = NULL;
1727 msg_it->meta.ec = NULL;
1728 BT_PACKET_PUT_REF_AND_RESET(msg_it->packet);
1729 BT_STREAM_PUT_REF_AND_RESET(msg_it->stream);
1730 BT_MESSAGE_PUT_REF_AND_RESET(msg_it->event_msg);
1731 release_all_dscopes(msg_it);
1732 msg_it->cur_dscope_field = NULL;
1733
1734 msg_it->buf.addr = NULL;
1735 msg_it->buf.sz = 0;
1736 msg_it->buf.at = 0;
1737 msg_it->buf.last_eh_at = SIZE_MAX;
1738 msg_it->buf.packet_offset = 0;
1739 msg_it->state = STATE_INIT;
1740 msg_it->cur_exp_packet_content_size = -1;
1741 msg_it->cur_exp_packet_total_size = -1;
1742 msg_it->cur_packet_offset = -1;
1743 msg_it->cur_event_class_id = -1;
1744 msg_it->snapshots.beginning_clock = UINT64_C(-1);
1745 msg_it->snapshots.end_clock = UINT64_C(-1);
1746 }
1747
1748 /**
1749 * Resets the internal state of a CTF message iterator.
1750 */
1751 void ctf_msg_iter_reset(struct ctf_msg_iter *msg_it)
1752 {
1753 ctf_msg_iter_reset_for_next_stream_file(msg_it);
1754 msg_it->cur_stream_class_id = -1;
1755 msg_it->cur_data_stream_id = -1;
1756 msg_it->snapshots.discarded_events = UINT64_C(-1);
1757 msg_it->snapshots.packets = UINT64_C(-1);
1758 msg_it->prev_packet_snapshots.discarded_events = UINT64_C(-1);
1759 msg_it->prev_packet_snapshots.packets = UINT64_C(-1);
1760 msg_it->prev_packet_snapshots.beginning_clock = UINT64_C(-1);
1761 msg_it->prev_packet_snapshots.end_clock = UINT64_C(-1);
1762 msg_it->emit_stream_beginning_message = true;
1763 msg_it->emit_stream_end_message = false;
1764 }
1765
1766 static bt_field *borrow_next_field(struct ctf_msg_iter *msg_it)
1767 {
1768 bt_field *next_field = NULL;
1769 bt_field *base_field;
1770 const bt_field_class *base_fc;
1771 bt_field_class_type base_fc_type;
1772 size_t index;
1773
1774 BT_ASSERT_DBG(!stack_empty(msg_it->stack));
1775 index = stack_top(msg_it->stack)->index;
1776 base_field = stack_top(msg_it->stack)->base;
1777 BT_ASSERT_DBG(base_field);
1778 base_fc = bt_field_borrow_class_const(base_field);
1779 BT_ASSERT_DBG(base_fc);
1780 base_fc_type = bt_field_class_get_type(base_fc);
1781
1782 if (base_fc_type == BT_FIELD_CLASS_TYPE_STRUCTURE) {
1783 BT_ASSERT_DBG(index < bt_field_class_structure_get_member_count(
1784 bt_field_borrow_class_const(base_field)));
1785 next_field = bt_field_structure_borrow_member_field_by_index(base_field, index);
1786 } else if (bt_field_class_type_is(base_fc_type, BT_FIELD_CLASS_TYPE_ARRAY)) {
1787 BT_ASSERT_DBG(index < bt_field_array_get_length(base_field));
1788 next_field = bt_field_array_borrow_element_field_by_index(base_field, index);
1789 } else if (bt_field_class_type_is(base_fc_type, BT_FIELD_CLASS_TYPE_VARIANT)) {
1790 BT_ASSERT_DBG(index == 0);
1791 next_field = bt_field_variant_borrow_selected_option_field(base_field);
1792 } else {
1793 bt_common_abort();
1794 }
1795
1796 BT_ASSERT_DBG(next_field);
1797 return next_field;
1798 }
1799
1800 static void update_default_clock(struct ctf_msg_iter *msg_it, uint64_t new_val,
1801 uint64_t new_val_size)
1802 {
1803 uint64_t new_val_mask;
1804 uint64_t cur_value_masked;
1805
1806 BT_ASSERT_DBG(new_val_size > 0);
1807
1808 /*
1809 * Special case for a 64-bit new value, which is the limit
1810 * of a clock value as of this version: overwrite the
1811 * current value directly.
1812 */
1813 if (new_val_size == 64) {
1814 msg_it->default_clock_snapshot = new_val;
1815 goto end;
1816 }
1817
1818 new_val_mask = (1ULL << new_val_size) - 1;
1819 cur_value_masked = msg_it->default_clock_snapshot & new_val_mask;
1820
1821 if (new_val < cur_value_masked) {
1822 /*
1823 * It looks like a wrap happened on the number of bits
1824 * of the requested new value. Assume that the clock
1825 * value wrapped only one time.
1826 */
1827 msg_it->default_clock_snapshot += new_val_mask + 1;
1828 }
1829
1830 /* Clear the low bits of the current clock value. */
1831 msg_it->default_clock_snapshot &= ~new_val_mask;
1832
1833 /* Set the low bits of the current clock value. */
1834 msg_it->default_clock_snapshot |= new_val;
1835
1836 end:
1837 BT_CPPLOGT_SPEC(msg_it->logger,
1838 "Updated default clock's value from integer field's value: "
1839 "value={}",
1840 msg_it->default_clock_snapshot);
1841 }
1842
1843 /*
1844 * Ensure the message iterator's `stored_values` array is large enough to
1845 * accommodate `storing_index`.
1846 *
1847 * We may need more slots in the array than initially allocated if more
1848 * metadata arrives along the way.
1849 */
1850 static void ensure_stored_values_size(ctf_msg_iter *msg_it, uint64_t storing_index)
1851 {
1852 if (G_UNLIKELY(storing_index >= msg_it->stored_values->len)) {
1853 g_array_set_size(msg_it->stored_values, msg_it->meta.tc->stored_value_count);
1854 }
1855 }
1856
1857 static enum bt_bfcr_status bfcr_unsigned_int_cb(uint64_t value, struct ctf_field_class *fc,
1858 void *data)
1859 {
1860 ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
1861 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
1862
1863 bt_field *field = NULL;
1864
1865 BT_CPPLOGT_SPEC(msg_it->logger,
1866 "Unsigned integer function called from BFCR: "
1867 "msg-it-addr={}, bfcr-addr={}, fc-addr={}, "
1868 "fc-type={}, fc-in-ir={}, value={}",
1869 fmt::ptr(msg_it), fmt::ptr(msg_it->bfcr), fmt::ptr(fc), fc->type, fc->in_ir,
1870 value);
1871
1872 ctf_field_class_int *int_fc = ctf_field_class_as_int(fc);
1873
1874 if (G_LIKELY(int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE)) {
1875 goto update_def_clock;
1876 }
1877
1878 switch (int_fc->meaning) {
1879 case CTF_FIELD_CLASS_MEANING_EVENT_CLASS_ID:
1880 msg_it->cur_event_class_id = value;
1881 break;
1882 case CTF_FIELD_CLASS_MEANING_DATA_STREAM_ID:
1883 msg_it->cur_data_stream_id = value;
1884 break;
1885 case CTF_FIELD_CLASS_MEANING_PACKET_BEGINNING_TIME:
1886 msg_it->snapshots.beginning_clock = value;
1887 break;
1888 case CTF_FIELD_CLASS_MEANING_PACKET_END_TIME:
1889 msg_it->snapshots.end_clock = value;
1890 break;
1891 case CTF_FIELD_CLASS_MEANING_STREAM_CLASS_ID:
1892 msg_it->cur_stream_class_id = value;
1893 break;
1894 case CTF_FIELD_CLASS_MEANING_MAGIC:
1895 if (value != 0xc1fc1fc1) {
1896 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
1897 "Invalid CTF magic number: msg-it-addr={}, magic={}",
1898 fmt::ptr(msg_it), value);
1899 status = BT_BFCR_STATUS_ERROR;
1900 goto end;
1901 }
1902
1903 break;
1904 case CTF_FIELD_CLASS_MEANING_PACKET_COUNTER_SNAPSHOT:
1905 msg_it->snapshots.packets = value;
1906 break;
1907 case CTF_FIELD_CLASS_MEANING_DISC_EV_REC_COUNTER_SNAPSHOT:
1908 msg_it->snapshots.discarded_events = value;
1909 break;
1910 case CTF_FIELD_CLASS_MEANING_EXP_PACKET_TOTAL_SIZE:
1911 msg_it->cur_exp_packet_total_size = value;
1912 break;
1913 case CTF_FIELD_CLASS_MEANING_EXP_PACKET_CONTENT_SIZE:
1914 msg_it->cur_exp_packet_content_size = value;
1915 break;
1916 default:
1917 bt_common_abort();
1918 }
1919
1920 update_def_clock:
1921 if (G_UNLIKELY(int_fc->mapped_clock_class)) {
1922 update_default_clock(msg_it, value, int_fc->base.size);
1923 }
1924
1925 if (G_UNLIKELY(int_fc->storing_index >= 0)) {
1926 ensure_stored_values_size(msg_it, int_fc->storing_index);
1927 bt_g_array_index(msg_it->stored_values, uint64_t, (uint64_t) int_fc->storing_index) = value;
1928 }
1929
1930 if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) {
1931 goto end;
1932 }
1933
1934 field = borrow_next_field(msg_it);
1935 BT_ASSERT_DBG(field);
1936 BT_ASSERT_DBG(bt_field_borrow_class_const(field) == fc->ir_fc);
1937 BT_ASSERT_DBG(bt_field_class_type_is(bt_field_get_class_type(field),
1938 BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER));
1939 bt_field_integer_unsigned_set_value(field, value);
1940 stack_top(msg_it->stack)->index++;
1941
1942 end:
1943 return status;
1944 }
1945
1946 static enum bt_bfcr_status bfcr_unsigned_int_char_cb(uint64_t value, struct ctf_field_class *fc,
1947 void *data)
1948 {
1949 int ret;
1950 ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
1951 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
1952 bt_field *string_field = NULL;
1953 char str[2] = {'\0', '\0'};
1954
1955 BT_CPPLOGT_SPEC(msg_it->logger,
1956 "Unsigned integer character function called from BFCR: "
1957 "msg-it-addr={}, bfcr-addr={}, fc-addr={}, "
1958 "fc-type={}, fc-in-ir={}, value={}",
1959 fmt::ptr(msg_it), fmt::ptr(msg_it->bfcr), fmt::ptr(fc), fc->type, fc->in_ir,
1960 value);
1961
1962 ctf_field_class_int *int_fc = ctf_field_class_as_int(fc);
1963 BT_ASSERT_DBG(int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE);
1964 BT_ASSERT_DBG(!int_fc->mapped_clock_class);
1965 BT_ASSERT_DBG(int_fc->storing_index < 0);
1966
1967 if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) {
1968 goto end;
1969 }
1970
1971 if (msg_it->done_filling_string) {
1972 goto end;
1973 }
1974
1975 if (value == 0) {
1976 msg_it->done_filling_string = true;
1977 goto end;
1978 }
1979
1980 string_field = stack_top(msg_it->stack)->base;
1981 BT_ASSERT_DBG(bt_field_get_class_type(string_field) == BT_FIELD_CLASS_TYPE_STRING);
1982
1983 /* Append character */
1984 str[0] = (char) value;
1985 ret = bt_field_string_append_with_length(string_field, str, 1);
1986 if (ret) {
1987 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
1988 "Cannot append character to string field's value: "
1989 "msg-it-addr={}, field-addr={}, ret={}",
1990 fmt::ptr(msg_it), fmt::ptr(string_field), ret);
1991 status = BT_BFCR_STATUS_ERROR;
1992 goto end;
1993 }
1994
1995 end:
1996 return status;
1997 }
1998
1999 static enum bt_bfcr_status bfcr_signed_int_cb(int64_t value, struct ctf_field_class *fc, void *data)
2000 {
2001 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
2002 bt_field *field = NULL;
2003 ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
2004
2005 BT_CPPLOGT_SPEC(msg_it->logger,
2006 "Signed integer function called from BFCR: "
2007 "msg-it-addr={}, bfcr-addr={}, fc-addr={}, "
2008 "fc-type={}, fc-in-ir={}, value={}",
2009 fmt::ptr(msg_it), fmt::ptr(msg_it->bfcr), fmt::ptr(fc), fc->type, fc->in_ir,
2010 value);
2011
2012 ctf_field_class_int *int_fc = ctf_field_class_as_int(fc);
2013 BT_ASSERT_DBG(int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE);
2014
2015 if (G_UNLIKELY(int_fc->storing_index >= 0)) {
2016 ensure_stored_values_size(msg_it, int_fc->storing_index);
2017 bt_g_array_index(msg_it->stored_values, uint64_t, (uint64_t) int_fc->storing_index) =
2018 (uint64_t) value;
2019 }
2020
2021 if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) {
2022 goto end;
2023 }
2024
2025 field = borrow_next_field(msg_it);
2026 BT_ASSERT_DBG(field);
2027 BT_ASSERT_DBG(bt_field_borrow_class_const(field) == fc->ir_fc);
2028 BT_ASSERT_DBG(
2029 bt_field_class_type_is(bt_field_get_class_type(field), BT_FIELD_CLASS_TYPE_SIGNED_INTEGER));
2030 bt_field_integer_signed_set_value(field, value);
2031 stack_top(msg_it->stack)->index++;
2032
2033 end:
2034 return status;
2035 }
2036
2037 static enum bt_bfcr_status bfcr_floating_point_cb(double value, struct ctf_field_class *fc,
2038 void *data)
2039 {
2040 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
2041 bt_field *field = NULL;
2042 ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
2043 bt_field_class_type type;
2044
2045 BT_CPPLOGT_SPEC(msg_it->logger,
2046 "Floating point number function called from BFCR: "
2047 "msg-it-addr={}, bfcr-addr={}, fc-addr={}, "
2048 "fc-type={}, fc-in-ir={}, value={}",
2049 fmt::ptr(msg_it), fmt::ptr(msg_it->bfcr), fmt::ptr(fc), fc->type, fc->in_ir,
2050 value);
2051
2052 if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) {
2053 goto end;
2054 }
2055
2056 field = borrow_next_field(msg_it);
2057 type = bt_field_get_class_type(field);
2058 BT_ASSERT_DBG(field);
2059 BT_ASSERT_DBG(bt_field_borrow_class_const(field) == fc->ir_fc);
2060 BT_ASSERT_DBG(bt_field_class_type_is(type, BT_FIELD_CLASS_TYPE_REAL));
2061
2062 if (type == BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL) {
2063 bt_field_real_single_precision_set_value(field, (float) value);
2064 } else {
2065 bt_field_real_double_precision_set_value(field, value);
2066 }
2067 stack_top(msg_it->stack)->index++;
2068
2069 end:
2070 return status;
2071 }
2072
2073 static enum bt_bfcr_status bfcr_string_begin_cb(struct ctf_field_class *fc, void *data)
2074 {
2075 bt_field *field = NULL;
2076 ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
2077
2078 BT_CPPLOGT_SPEC(msg_it->logger,
2079 "String (beginning) function called from BFCR: "
2080 "msg-it-addr={}, bfcr-addr={}, fc-addr={}, "
2081 "fc-type={}, fc-in-ir={}",
2082 fmt::ptr(msg_it), fmt::ptr(msg_it->bfcr), fmt::ptr(fc), fc->type, fc->in_ir);
2083
2084 if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) {
2085 goto end;
2086 }
2087
2088 field = borrow_next_field(msg_it);
2089 BT_ASSERT_DBG(field);
2090 BT_ASSERT_DBG(bt_field_borrow_class_const(field) == fc->ir_fc);
2091 BT_ASSERT_DBG(bt_field_get_class_type(field) == BT_FIELD_CLASS_TYPE_STRING);
2092 bt_field_string_clear(field);
2093
2094 /*
2095 * Push on stack. Not a compound class per se, but we know that
2096 * only bfcr_string_cb() may be called between this call and a
2097 * subsequent call to bfcr_string_end_cb().
2098 */
2099 stack_push(msg_it->stack, field);
2100
2101 end:
2102 return BT_BFCR_STATUS_OK;
2103 }
2104
2105 static enum bt_bfcr_status bfcr_string_cb(const char *value, size_t len, struct ctf_field_class *fc,
2106 void *data)
2107 {
2108 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
2109 bt_field *field = NULL;
2110 ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
2111 int ret;
2112
2113 BT_CPPLOGT_SPEC(msg_it->logger,
2114 "String (substring) function called from BFCR: "
2115 "msg-it-addr={}, bfcr-addr={}, fc-addr={}, "
2116 "fc-type={}, fc-in-ir={}, string-length={}",
2117 fmt::ptr(msg_it), fmt::ptr(msg_it->bfcr), fmt::ptr(fc), fc->type, fc->in_ir,
2118 len);
2119
2120 if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) {
2121 goto end;
2122 }
2123
2124 field = stack_top(msg_it->stack)->base;
2125 BT_ASSERT_DBG(field);
2126
2127 /* Append current substring */
2128 ret = bt_field_string_append_with_length(field, value, len);
2129 if (ret) {
2130 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
2131 "Cannot append substring to string field's value: "
2132 "msg-it-addr={}, field-addr={}, string-length={}, "
2133 "ret={}",
2134 fmt::ptr(msg_it), fmt::ptr(field), len, ret);
2135 status = BT_BFCR_STATUS_ERROR;
2136 goto end;
2137 }
2138
2139 end:
2140 return status;
2141 }
2142
2143 static enum bt_bfcr_status bfcr_string_end_cb(struct ctf_field_class *fc, void *data)
2144 {
2145 ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
2146
2147 BT_CPPLOGT_SPEC(msg_it->logger,
2148 "String (end) function called from BFCR: "
2149 "msg-it-addr={}, bfcr-addr={}, fc-addr={}, "
2150 "fc-type={}, fc-in-ir={}",
2151 fmt::ptr(msg_it), fmt::ptr(msg_it->bfcr), fmt::ptr(fc), fc->type, fc->in_ir);
2152
2153 if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) {
2154 goto end;
2155 }
2156
2157 /* Pop string field */
2158 stack_pop(msg_it->stack);
2159
2160 /* Go to next field */
2161 stack_top(msg_it->stack)->index++;
2162
2163 end:
2164 return BT_BFCR_STATUS_OK;
2165 }
2166
2167 static enum bt_bfcr_status bfcr_compound_begin_cb(struct ctf_field_class *fc, void *data)
2168 {
2169 ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
2170 bt_field *field;
2171
2172 BT_CPPLOGT_SPEC(msg_it->logger,
2173 "Compound (beginning) function called from BFCR: "
2174 "msg-it-addr={}, bfcr-addr={}, fc-addr={}, "
2175 "fc-type={}, fc-in-ir={}",
2176 fmt::ptr(msg_it), fmt::ptr(msg_it->bfcr), fmt::ptr(fc), fc->type, fc->in_ir);
2177
2178 if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) {
2179 goto end;
2180 }
2181
2182 /* Borrow field */
2183 if (stack_empty(msg_it->stack)) {
2184 /* Root: already set by read_dscope_begin_state() */
2185 field = msg_it->cur_dscope_field;
2186 } else {
2187 field = borrow_next_field(msg_it);
2188 BT_ASSERT_DBG(field);
2189 }
2190
2191 /* Push field */
2192 BT_ASSERT_DBG(field);
2193 BT_ASSERT_DBG(bt_field_borrow_class_const(field) == fc->ir_fc);
2194 stack_push(msg_it->stack, field);
2195
2196 /*
2197 * Change BFCR "unsigned int" callback if it's a text
2198 * array/sequence.
2199 */
2200 if (fc->type == CTF_FIELD_CLASS_TYPE_ARRAY || fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE) {
2201 ctf_field_class_array_base *array_fc = ctf_field_class_as_array_base(fc);
2202
2203 if (array_fc->is_text) {
2204 BT_ASSERT_DBG(bt_field_get_class_type(field) == BT_FIELD_CLASS_TYPE_STRING);
2205 msg_it->done_filling_string = false;
2206 bt_field_string_clear(field);
2207 bt_bfcr_set_unsigned_int_cb(msg_it->bfcr, bfcr_unsigned_int_char_cb);
2208 }
2209 }
2210
2211 end:
2212 return BT_BFCR_STATUS_OK;
2213 }
2214
2215 static enum bt_bfcr_status bfcr_compound_end_cb(struct ctf_field_class *fc, void *data)
2216 {
2217 ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
2218
2219 BT_CPPLOGT_SPEC(msg_it->logger,
2220 "Compound (end) function called from BFCR: "
2221 "msg-it-addr={}, bfcr-addr={}, fc-addr={}, "
2222 "fc-type={}, fc-in-ir={}",
2223 fmt::ptr(msg_it), fmt::ptr(msg_it->bfcr), fmt::ptr(fc), fc->type, fc->in_ir);
2224
2225 if (G_UNLIKELY(!fc->in_ir || msg_it->dry_run)) {
2226 goto end;
2227 }
2228
2229 BT_ASSERT_DBG(!stack_empty(msg_it->stack));
2230 BT_ASSERT_DBG(bt_field_borrow_class_const(stack_top(msg_it->stack)->base) == fc->ir_fc);
2231
2232 /*
2233 * Reset BFCR "unsigned int" callback if it's a text
2234 * array/sequence.
2235 */
2236 if (fc->type == CTF_FIELD_CLASS_TYPE_ARRAY || fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE) {
2237 ctf_field_class_array_base *array_fc = ctf_field_class_as_array_base(fc);
2238
2239 if (array_fc->is_text) {
2240 BT_ASSERT_DBG(bt_field_get_class_type(stack_top(msg_it->stack)->base) ==
2241 BT_FIELD_CLASS_TYPE_STRING);
2242 bt_bfcr_set_unsigned_int_cb(msg_it->bfcr, bfcr_unsigned_int_cb);
2243 }
2244 }
2245
2246 /* Pop stack */
2247 stack_pop(msg_it->stack);
2248
2249 /* If the stack is not empty, increment the base's index */
2250 if (!stack_empty(msg_it->stack)) {
2251 stack_top(msg_it->stack)->index++;
2252 }
2253
2254 end:
2255 return BT_BFCR_STATUS_OK;
2256 }
2257
2258 static int64_t bfcr_get_sequence_length_cb(struct ctf_field_class *fc, void *data)
2259 {
2260 bt_field *seq_field;
2261 ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
2262 struct ctf_field_class_sequence *seq_fc = ctf_field_class_as_sequence(fc);
2263 int64_t length;
2264 int ret;
2265
2266 length =
2267 (uint64_t) bt_g_array_index(msg_it->stored_values, uint64_t, seq_fc->stored_length_index);
2268
2269 if (G_UNLIKELY(msg_it->dry_run)) {
2270 goto end;
2271 }
2272
2273 seq_field = stack_top(msg_it->stack)->base;
2274 BT_ASSERT_DBG(seq_field);
2275
2276 /*
2277 * bfcr_get_sequence_length_cb() also gets called back for a
2278 * text sequence, but the destination field is a string field.
2279 * Only set the field's sequence length if the destination field
2280 * is a sequence field.
2281 */
2282 if (!seq_fc->base.is_text) {
2283 BT_ASSERT_DBG(bt_field_class_type_is(bt_field_get_class_type(seq_field),
2284 BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY));
2285 ret = bt_field_array_dynamic_set_length(seq_field, (uint64_t) length);
2286 if (ret) {
2287 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
2288 "Cannot set dynamic array field's length field: "
2289 "msg-it-addr={}, field-addr={}, "
2290 "length={}",
2291 fmt::ptr(msg_it), fmt::ptr(seq_field), length);
2292 length = -1;
2293 }
2294 }
2295
2296 end:
2297 return length;
2298 }
2299
2300 static struct ctf_field_class *
2301 bfcr_borrow_variant_selected_field_class_cb(struct ctf_field_class *fc, void *data)
2302 {
2303 int ret;
2304 uint64_t i;
2305 int64_t option_index = -1;
2306 ctf_msg_iter *msg_it = (ctf_msg_iter *) data;
2307 ctf_field_class_variant *var_fc = ctf_field_class_as_variant(fc);
2308 struct ctf_named_field_class *selected_option = NULL;
2309 struct ctf_field_class *ret_fc = NULL;
2310 union
2311 {
2312 uint64_t u;
2313 int64_t i;
2314 } tag;
2315
2316 /* Get variant's tag */
2317 tag.u = bt_g_array_index(msg_it->stored_values, uint64_t, var_fc->stored_tag_index);
2318
2319 /*
2320 * Check each range to find the selected option's index.
2321 */
2322 if (var_fc->tag_fc->base.is_signed) {
2323 for (i = 0; i < var_fc->ranges->len; i++) {
2324 struct ctf_field_class_variant_range *range =
2325 ctf_field_class_variant_borrow_range_by_index(var_fc, i);
2326
2327 if (tag.i >= range->range.lower.i && tag.i <= range->range.upper.i) {
2328 option_index = (int64_t) range->option_index;
2329 break;
2330 }
2331 }
2332 } else {
2333 for (i = 0; i < var_fc->ranges->len; i++) {
2334 struct ctf_field_class_variant_range *range =
2335 ctf_field_class_variant_borrow_range_by_index(var_fc, i);
2336
2337 if (tag.u >= range->range.lower.u && tag.u <= range->range.upper.u) {
2338 option_index = (int64_t) range->option_index;
2339 break;
2340 }
2341 }
2342 }
2343
2344 if (option_index < 0) {
2345 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
2346 "Cannot find variant field class's option: "
2347 "msg-it-addr={}, var-fc-addr={}, u-tag={}, "
2348 "i-tag={}",
2349 fmt::ptr(msg_it), fmt::ptr(var_fc), tag.u, tag.i);
2350 ret_fc = NULL;
2351 goto end;
2352 }
2353
2354 selected_option =
2355 ctf_field_class_variant_borrow_option_by_index(var_fc, (uint64_t) option_index);
2356
2357 if (selected_option->fc->in_ir && !msg_it->dry_run) {
2358 bt_field *var_field = stack_top(msg_it->stack)->base;
2359
2360 ret = bt_field_variant_select_option_by_index(var_field, option_index);
2361 if (ret) {
2362 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
2363 "Cannot select variant field's option field: "
2364 "msg-it-addr={}, var-field-addr={}, "
2365 "opt-index={}",
2366 fmt::ptr(msg_it), fmt::ptr(var_field), option_index);
2367 ret_fc = NULL;
2368 goto end;
2369 }
2370 }
2371
2372 ret_fc = selected_option->fc;
2373
2374 end:
2375 return ret_fc;
2376 }
2377
2378 static bt_message *create_msg_stream_beginning(struct ctf_msg_iter *msg_it)
2379 {
2380 bt_message *msg;
2381
2382 BT_ASSERT(msg_it->stream);
2383 BT_ASSERT(msg_it->self_msg_iter);
2384 msg = bt_message_stream_beginning_create(msg_it->self_msg_iter, msg_it->stream);
2385 if (!msg) {
2386 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
2387 "Cannot create stream beginning message: "
2388 "msg-it-addr={}, stream-addr={}",
2389 fmt::ptr(msg_it), fmt::ptr(msg_it->stream));
2390 }
2391
2392 return msg;
2393 }
2394
2395 static bt_message *create_msg_stream_end(struct ctf_msg_iter *msg_it)
2396 {
2397 bt_message *msg;
2398
2399 if (!msg_it->stream) {
2400 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
2401 "Cannot create stream end message because stream is NULL: "
2402 "msg-it-addr={}",
2403 fmt::ptr(msg_it));
2404 msg = NULL;
2405 goto end;
2406 }
2407
2408 BT_ASSERT(msg_it->self_msg_iter);
2409 msg = bt_message_stream_end_create(msg_it->self_msg_iter, msg_it->stream);
2410 if (!msg) {
2411 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
2412 "Cannot create stream end message: "
2413 "msg-it-addr={}, stream-addr={}",
2414 fmt::ptr(msg_it), fmt::ptr(msg_it->stream));
2415 }
2416
2417 end:
2418 return msg;
2419 }
2420
2421 static bt_message *create_msg_packet_beginning(struct ctf_msg_iter *msg_it, bool use_default_cs)
2422 {
2423 bt_message *msg;
2424 const bt_stream_class *sc = msg_it->meta.sc->ir_sc;
2425
2426 BT_ASSERT(msg_it->packet);
2427 BT_ASSERT(sc);
2428 BT_ASSERT(msg_it->self_msg_iter);
2429
2430 if (msg_it->meta.sc->packets_have_ts_begin) {
2431 BT_ASSERT(msg_it->snapshots.beginning_clock != UINT64_C(-1));
2432 uint64_t raw_cs_value;
2433
2434 /*
2435 * Either use the decoded packet `timestamp_begin` field or the
2436 * current stream's default clock_snapshot.
2437 */
2438 if (use_default_cs) {
2439 raw_cs_value = msg_it->default_clock_snapshot;
2440 } else {
2441 raw_cs_value = msg_it->snapshots.beginning_clock;
2442 }
2443
2444 msg = bt_message_packet_beginning_create_with_default_clock_snapshot(
2445 msg_it->self_msg_iter, msg_it->packet, raw_cs_value);
2446 } else {
2447 msg = bt_message_packet_beginning_create(msg_it->self_msg_iter, msg_it->packet);
2448 }
2449
2450 if (!msg) {
2451 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
2452 "Cannot create packet beginning message: "
2453 "msg-it-addr={}, packet-addr={}",
2454 fmt::ptr(msg_it), fmt::ptr(msg_it->packet));
2455 goto end;
2456 }
2457
2458 end:
2459 return msg;
2460 }
2461
2462 static bt_message *emit_delayed_packet_beg_msg(struct ctf_msg_iter *msg_it)
2463 {
2464 bool packet_beg_ts_need_fix_up;
2465
2466 msg_it->emit_delayed_packet_beginning_msg = false;
2467
2468 /*
2469 * Only fix the packet's timestamp_begin if it's larger than the first
2470 * event of the packet. If there was no event in the packet, the
2471 * `default_clock_snapshot` field will be either equal or greater than
2472 * `snapshots.beginning_clock` so there is not fix needed.
2473 */
2474 packet_beg_ts_need_fix_up = msg_it->default_clock_snapshot < msg_it->snapshots.beginning_clock;
2475
2476 /* create_msg_packet_beginning() logs errors */
2477 return create_msg_packet_beginning(msg_it, packet_beg_ts_need_fix_up);
2478 }
2479
2480 static bt_message *create_msg_packet_end(struct ctf_msg_iter *msg_it)
2481 {
2482 bt_message *msg;
2483 bool update_default_cs = true;
2484
2485 if (!msg_it->packet) {
2486 msg = NULL;
2487 goto end;
2488 }
2489
2490 /*
2491 * Check if we need to emit the delayed packet
2492 * beginning message instead of the packet end message.
2493 */
2494 if (G_UNLIKELY(msg_it->emit_delayed_packet_beginning_msg)) {
2495 msg = emit_delayed_packet_beg_msg(msg_it);
2496 /* Don't forget to emit the packet end message. */
2497 msg_it->state = STATE_EMIT_QUEUED_MSG_PACKET_END;
2498 goto end;
2499 }
2500
2501 /* Check if may be affected by lttng-crash timestamp_end quirk. */
2502 if (G_UNLIKELY(msg_it->meta.tc->quirks.lttng_crash)) {
2503 /*
2504 * Check if the `timestamp_begin` field is non-zero but
2505 * `timestamp_end` is zero. It means the trace is affected by
2506 * the lttng-crash packet `timestamp_end` quirk and must be
2507 * fixed up by omitting to update the default clock snapshot to
2508 * the `timestamp_end` as is typically done.
2509 */
2510 if (msg_it->snapshots.beginning_clock != 0 && msg_it->snapshots.end_clock == 0) {
2511 update_default_cs = false;
2512 }
2513 }
2514
2515 /*
2516 * Check if may be affected by lttng event-after-packet `timestamp_end`
2517 * quirk.
2518 */
2519 if (msg_it->meta.tc->quirks.lttng_event_after_packet) {
2520 /*
2521 * Check if `timestamp_end` is smaller then the current
2522 * default_clock_snapshot (which is set to the last event
2523 * decoded). It means the trace is affected by the lttng
2524 * `event-after-packet` packet `timestamp_end` quirk and must
2525 * be fixed up by omitting to update the default clock snapshot
2526 * to the `timestamp_end` as is typically done.
2527 */
2528 if (msg_it->snapshots.end_clock < msg_it->default_clock_snapshot) {
2529 update_default_cs = false;
2530 }
2531 }
2532
2533 /* Update default clock from packet's end time. */
2534 if (msg_it->snapshots.end_clock != UINT64_C(-1) && update_default_cs) {
2535 msg_it->default_clock_snapshot = msg_it->snapshots.end_clock;
2536 }
2537
2538 BT_ASSERT(msg_it->self_msg_iter);
2539
2540 if (msg_it->meta.sc->packets_have_ts_end) {
2541 BT_ASSERT(msg_it->snapshots.end_clock != UINT64_C(-1));
2542 msg = bt_message_packet_end_create_with_default_clock_snapshot(
2543 msg_it->self_msg_iter, msg_it->packet, msg_it->default_clock_snapshot);
2544 } else {
2545 msg = bt_message_packet_end_create(msg_it->self_msg_iter, msg_it->packet);
2546 }
2547
2548 if (!msg) {
2549 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
2550 "Cannot create packet end message: "
2551 "msg-it-addr={}, packet-addr={}",
2552 fmt::ptr(msg_it), fmt::ptr(msg_it->packet));
2553 goto end;
2554 }
2555
2556 BT_PACKET_PUT_REF_AND_RESET(msg_it->packet);
2557
2558 end:
2559 return msg;
2560 }
2561
2562 static bt_message *create_msg_discarded_events(struct ctf_msg_iter *msg_it)
2563 {
2564 bt_message *msg;
2565 uint64_t beginning_raw_value = UINT64_C(-1);
2566 uint64_t end_raw_value = UINT64_C(-1);
2567
2568 BT_ASSERT(msg_it->self_msg_iter);
2569 BT_ASSERT(msg_it->stream);
2570 BT_ASSERT(msg_it->meta.sc->has_discarded_events);
2571
2572 if (msg_it->meta.sc->discarded_events_have_default_cs) {
2573 if (msg_it->prev_packet_snapshots.discarded_events == UINT64_C(-1)) {
2574 /*
2575 * We discarded events, but before (and possibly
2576 * including) the current packet: use this packet's time
2577 * range, and do not have a specific count.
2578 */
2579 beginning_raw_value = msg_it->snapshots.beginning_clock;
2580 end_raw_value = msg_it->snapshots.end_clock;
2581 } else {
2582 beginning_raw_value = msg_it->prev_packet_snapshots.end_clock;
2583 end_raw_value = msg_it->snapshots.end_clock;
2584 }
2585
2586 BT_ASSERT(beginning_raw_value != UINT64_C(-1));
2587 BT_ASSERT(end_raw_value != UINT64_C(-1));
2588 msg = bt_message_discarded_events_create_with_default_clock_snapshots(
2589 msg_it->self_msg_iter, msg_it->stream, beginning_raw_value, end_raw_value);
2590 } else {
2591 msg = bt_message_discarded_events_create(msg_it->self_msg_iter, msg_it->stream);
2592 }
2593
2594 if (!msg) {
2595 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
2596 "Cannot create discarded events message: "
2597 "msg-it-addr={}, stream-addr={}",
2598 fmt::ptr(msg_it), fmt::ptr(msg_it->stream));
2599 goto end;
2600 }
2601
2602 if (msg_it->prev_packet_snapshots.discarded_events != UINT64_C(-1)) {
2603 bt_message_discarded_events_set_count(msg,
2604 msg_it->snapshots.discarded_events -
2605 msg_it->prev_packet_snapshots.discarded_events);
2606 }
2607
2608 end:
2609 return msg;
2610 }
2611
2612 static bt_message *create_msg_discarded_packets(struct ctf_msg_iter *msg_it)
2613 {
2614 bt_message *msg;
2615
2616 BT_ASSERT(msg_it->self_msg_iter);
2617 BT_ASSERT(msg_it->stream);
2618 BT_ASSERT(msg_it->meta.sc->has_discarded_packets);
2619 BT_ASSERT(msg_it->prev_packet_snapshots.packets != UINT64_C(-1));
2620
2621 if (msg_it->meta.sc->discarded_packets_have_default_cs) {
2622 BT_ASSERT(msg_it->prev_packet_snapshots.end_clock != UINT64_C(-1));
2623 BT_ASSERT(msg_it->snapshots.beginning_clock != UINT64_C(-1));
2624 msg = bt_message_discarded_packets_create_with_default_clock_snapshots(
2625 msg_it->self_msg_iter, msg_it->stream, msg_it->prev_packet_snapshots.end_clock,
2626 msg_it->snapshots.beginning_clock);
2627 } else {
2628 msg = bt_message_discarded_packets_create(msg_it->self_msg_iter, msg_it->stream);
2629 }
2630
2631 if (!msg) {
2632 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
2633 "Cannot create discarded packets message: "
2634 "msg-it-addr={}, stream-addr={}",
2635 fmt::ptr(msg_it), fmt::ptr(msg_it->stream));
2636 goto end;
2637 }
2638
2639 bt_message_discarded_packets_set_count(msg, msg_it->snapshots.packets -
2640 msg_it->prev_packet_snapshots.packets - 1);
2641
2642 end:
2643 return msg;
2644 }
2645
2646 ctf_msg_iter_up ctf_msg_iter_create(struct ctf_trace_class *tc, size_t max_request_sz,
2647 struct ctf_msg_iter_medium_ops medops, void *data,
2648 bt_self_message_iterator *self_msg_iter,
2649 const bt2c::Logger& parentLogger)
2650 {
2651 struct bt_bfcr_cbs cbs = {
2652 .classes =
2653 {
2654 .signed_int = bfcr_signed_int_cb,
2655 .unsigned_int = bfcr_unsigned_int_cb,
2656 .floating_point = bfcr_floating_point_cb,
2657 .string_begin = bfcr_string_begin_cb,
2658 .string = bfcr_string_cb,
2659 .string_end = bfcr_string_end_cb,
2660 .compound_begin = bfcr_compound_begin_cb,
2661 .compound_end = bfcr_compound_end_cb,
2662 },
2663 .query =
2664 {
2665 .get_sequence_length = bfcr_get_sequence_length_cb,
2666 .borrow_variant_selected_field_class = bfcr_borrow_variant_selected_field_class_cb,
2667 },
2668 };
2669
2670 BT_ASSERT(tc);
2671 BT_ASSERT(medops.request_bytes);
2672 BT_ASSERT(medops.borrow_stream);
2673 BT_ASSERT(max_request_sz > 0);
2674
2675 bt2c::Logger logger {parentLogger, "PLUGIN/CTF/MSG-ITER"};
2676 BT_CPPLOGD_SPEC(logger,
2677 "Creating CTF plugin message iterator: "
2678 "trace-addr={}, max-request-size={}, "
2679 "data={}, log-level={}",
2680 fmt::ptr(tc), max_request_sz, fmt::ptr(data), logger.level());
2681
2682 ctf_msg_iter_up msg_it {new ctf_msg_iter {std::move(logger)}};
2683 msg_it->self_msg_iter = self_msg_iter;
2684 msg_it->meta.tc = tc;
2685 msg_it->medium.medops = medops;
2686 msg_it->medium.max_request_sz = max_request_sz;
2687 msg_it->medium.data = data;
2688 msg_it->stack = stack_new(msg_it.get());
2689 msg_it->stored_values = g_array_new(FALSE, TRUE, sizeof(uint64_t));
2690 g_array_set_size(msg_it->stored_values, tc->stored_value_count);
2691
2692 if (!msg_it->stack) {
2693 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger, "Failed to create field stack.");
2694 goto error;
2695 }
2696
2697 msg_it->bfcr = bt_bfcr_create(cbs, msg_it.get(), msg_it->logger);
2698 if (!msg_it->bfcr) {
2699 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
2700 "Failed to create binary class reader (BFCR).");
2701 goto error;
2702 }
2703
2704 ctf_msg_iter_reset(msg_it.get());
2705 BT_CPPLOGD_SPEC(msg_it->logger,
2706 "Created CTF plugin message iterator: "
2707 "trace-addr={}, max-request-size={}, "
2708 "data={}, msg-it-addr={}, log-level={}",
2709 fmt::ptr(tc), max_request_sz, fmt::ptr(data), fmt::ptr(msg_it),
2710 msg_it->logger.level());
2711 msg_it->cur_packet_offset = 0;
2712
2713 end:
2714 return msg_it;
2715
2716 error:
2717 msg_it.reset();
2718 goto end;
2719 }
2720
2721 void ctf_msg_iter_destroy(struct ctf_msg_iter *msg_it)
2722 {
2723 BT_PACKET_PUT_REF_AND_RESET(msg_it->packet);
2724 BT_STREAM_PUT_REF_AND_RESET(msg_it->stream);
2725 release_all_dscopes(msg_it);
2726
2727 BT_CPPLOGD_SPEC(msg_it->logger, "Destroying CTF plugin message iterator: addr={}",
2728 fmt::ptr(msg_it));
2729
2730 if (msg_it->stack) {
2731 BT_CPPLOGD_STR_SPEC(msg_it->logger, "Destroying field stack.");
2732 stack_destroy(msg_it->stack);
2733 }
2734
2735 if (msg_it->bfcr) {
2736 BT_CPPLOGD_SPEC(msg_it->logger, "Destroying BFCR: bfcr-addr={}", fmt::ptr(msg_it->bfcr));
2737 bt_bfcr_destroy(msg_it->bfcr);
2738 }
2739
2740 if (msg_it->stored_values) {
2741 g_array_free(msg_it->stored_values, TRUE);
2742 }
2743
2744 delete msg_it;
2745 }
2746
2747 void ctf_msg_iter_deleter::operator()(ctf_msg_iter *iter) noexcept
2748 {
2749 ctf_msg_iter_destroy(iter);
2750 }
2751
2752 enum ctf_msg_iter_status ctf_msg_iter_get_next_message(struct ctf_msg_iter *msg_it,
2753 const bt_message **message)
2754 {
2755 enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
2756
2757 BT_ASSERT_DBG(msg_it);
2758 BT_ASSERT_DBG(message);
2759 BT_CPPLOGD_SPEC(msg_it->logger, "Getting next message: msg-it-addr={}", fmt::ptr(msg_it));
2760
2761 while (true) {
2762 status = handle_state(msg_it);
2763 if (G_UNLIKELY(status == CTF_MSG_ITER_STATUS_AGAIN)) {
2764 BT_CPPLOGD_STR_SPEC(msg_it->logger, "Medium returned CTF_MSG_ITER_STATUS_AGAIN.");
2765 goto end;
2766 } else if (G_UNLIKELY(status != CTF_MSG_ITER_STATUS_OK)) {
2767 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
2768 "Cannot handle state: msg-it-addr={}, state={}",
2769 fmt::ptr(msg_it), msg_it->state);
2770 goto end;
2771 }
2772
2773 switch (msg_it->state) {
2774 case STATE_EMIT_MSG_EVENT:
2775 BT_ASSERT_DBG(msg_it->event_msg);
2776
2777 /*
2778 * Check if we need to emit the delayed packet
2779 * beginning message instead of the event message.
2780 */
2781 if (G_UNLIKELY(msg_it->emit_delayed_packet_beginning_msg)) {
2782 *message = emit_delayed_packet_beg_msg(msg_it);
2783 if (!*message) {
2784 status = CTF_MSG_ITER_STATUS_ERROR;
2785 }
2786
2787 /*
2788 * Don't forget to emit the event message of
2789 * the event record that was just decoded.
2790 */
2791 msg_it->state = STATE_EMIT_QUEUED_MSG_EVENT;
2792
2793 } else {
2794 *message = msg_it->event_msg;
2795 msg_it->event_msg = NULL;
2796 }
2797 goto end;
2798 case STATE_EMIT_MSG_DISCARDED_EVENTS:
2799 /* create_msg_discarded_events() logs errors */
2800 *message = create_msg_discarded_events(msg_it);
2801
2802 if (!*message) {
2803 status = CTF_MSG_ITER_STATUS_ERROR;
2804 }
2805
2806 goto end;
2807 case STATE_EMIT_MSG_DISCARDED_PACKETS:
2808 /* create_msg_discarded_packets() logs errors */
2809 *message = create_msg_discarded_packets(msg_it);
2810
2811 if (!*message) {
2812 status = CTF_MSG_ITER_STATUS_ERROR;
2813 }
2814
2815 goto end;
2816 case STATE_EMIT_MSG_PACKET_BEGINNING:
2817 if (G_UNLIKELY(msg_it->meta.tc->quirks.barectf_event_before_packet)) {
2818 msg_it->emit_delayed_packet_beginning_msg = true;
2819 /*
2820 * There is no message to return yet as this
2821 * packet beginning message is delayed until we
2822 * decode the first event message of the
2823 * packet.
2824 */
2825 break;
2826 } else {
2827 /* create_msg_packet_beginning() logs errors */
2828 *message = create_msg_packet_beginning(msg_it, false);
2829 if (!*message) {
2830 status = CTF_MSG_ITER_STATUS_ERROR;
2831 }
2832 }
2833
2834 goto end;
2835 case STATE_EMIT_MSG_PACKET_END_SINGLE:
2836 case STATE_EMIT_MSG_PACKET_END_MULTI:
2837 /* create_msg_packet_end() logs errors */
2838 *message = create_msg_packet_end(msg_it);
2839
2840 if (!*message) {
2841 status = CTF_MSG_ITER_STATUS_ERROR;
2842 }
2843
2844 goto end;
2845 case STATE_EMIT_MSG_STREAM_BEGINNING:
2846 /* create_msg_stream_beginning() logs errors */
2847 *message = create_msg_stream_beginning(msg_it);
2848 msg_it->emit_stream_beginning_message = false;
2849 msg_it->emit_stream_end_message = true;
2850
2851 if (!*message) {
2852 status = CTF_MSG_ITER_STATUS_ERROR;
2853 }
2854
2855 goto end;
2856 case STATE_EMIT_MSG_STREAM_END:
2857 /* create_msg_stream_end() logs errors */
2858 *message = create_msg_stream_end(msg_it);
2859 msg_it->emit_stream_end_message = false;
2860
2861 if (!*message) {
2862 status = CTF_MSG_ITER_STATUS_ERROR;
2863 }
2864
2865 goto end;
2866 case STATE_DONE:
2867 status = CTF_MSG_ITER_STATUS_EOF;
2868 goto end;
2869 default:
2870 /* Non-emitting state: continue */
2871 break;
2872 }
2873 }
2874
2875 end:
2876 return status;
2877 }
2878
2879 static enum ctf_msg_iter_status decode_until_state(struct ctf_msg_iter *msg_it,
2880 enum state target_state_1,
2881 enum state target_state_2)
2882 {
2883 enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
2884
2885 BT_ASSERT_DBG(msg_it);
2886
2887 do {
2888 /*
2889 * Check if we reached the state at which we want to stop
2890 * decoding.
2891 */
2892 if (msg_it->state == target_state_1 || msg_it->state == target_state_2) {
2893 goto end;
2894 }
2895
2896 status = handle_state(msg_it);
2897 if (G_UNLIKELY(status == CTF_MSG_ITER_STATUS_AGAIN)) {
2898 BT_CPPLOGD_STR_SPEC(msg_it->logger, "Medium returned CTF_MSG_ITER_STATUS_AGAIN.");
2899 goto end;
2900 } else if (G_UNLIKELY(status != CTF_MSG_ITER_STATUS_OK)) {
2901 BT_CPPLOGE_APPEND_CAUSE_SPEC(msg_it->logger,
2902 "Cannot handle state: msg-it-addr={}, state={}",
2903 fmt::ptr(msg_it), msg_it->state);
2904 goto end;
2905 }
2906
2907 switch (msg_it->state) {
2908 case STATE_INIT:
2909 case STATE_SWITCH_PACKET:
2910 case STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN:
2911 case STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE:
2912 case STATE_AFTER_TRACE_PACKET_HEADER:
2913 case STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN:
2914 case STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE:
2915 case STATE_AFTER_STREAM_PACKET_CONTEXT:
2916 case STATE_EMIT_MSG_STREAM_BEGINNING:
2917 case STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS:
2918 case STATE_EMIT_MSG_DISCARDED_EVENTS:
2919 case STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS:
2920 case STATE_EMIT_MSG_DISCARDED_PACKETS:
2921 case STATE_EMIT_MSG_PACKET_BEGINNING:
2922 case STATE_DSCOPE_EVENT_HEADER_BEGIN:
2923 case STATE_DSCOPE_EVENT_HEADER_CONTINUE:
2924 case STATE_AFTER_EVENT_HEADER:
2925 case STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN:
2926 case STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE:
2927 case STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN:
2928 case STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE:
2929 case STATE_DSCOPE_EVENT_PAYLOAD_BEGIN:
2930 case STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE:
2931 case STATE_EMIT_MSG_EVENT:
2932 case STATE_EMIT_QUEUED_MSG_EVENT:
2933 case STATE_SKIP_PACKET_PADDING:
2934 case STATE_EMIT_MSG_PACKET_END_MULTI:
2935 case STATE_EMIT_MSG_PACKET_END_SINGLE:
2936 case STATE_EMIT_QUEUED_MSG_PACKET_END:
2937 case STATE_EMIT_MSG_STREAM_END:
2938 break;
2939 case STATE_DONE:
2940 /* fall-through */
2941 default:
2942 /* We should never get to the STATE_DONE state. */
2943 BT_CPPLOGF_SPEC(msg_it->logger, "Unexpected state: msg-it-addr={}, state={}",
2944 fmt::ptr(msg_it), msg_it->state);
2945 bt_common_abort();
2946 }
2947 } while (true);
2948
2949 end:
2950 return status;
2951 }
2952
2953 static enum ctf_msg_iter_status read_packet_header_context_fields(struct ctf_msg_iter *msg_it)
2954 {
2955 int ret;
2956 enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
2957
2958 status = decode_until_state(msg_it, STATE_EMIT_MSG_PACKET_BEGINNING, (state) -1);
2959 if (status != CTF_MSG_ITER_STATUS_OK) {
2960 goto end;
2961 }
2962
2963 ret = set_current_packet_content_sizes(msg_it);
2964 if (ret) {
2965 status = CTF_MSG_ITER_STATUS_ERROR;
2966 goto end;
2967 }
2968
2969 end:
2970 return status;
2971 }
2972
2973 enum ctf_msg_iter_status ctf_msg_iter_seek(struct ctf_msg_iter *msg_it, off_t offset)
2974 {
2975 enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
2976 enum ctf_msg_iter_medium_status medium_status;
2977
2978 BT_ASSERT(msg_it);
2979 BT_ASSERT(offset >= 0);
2980 BT_ASSERT(msg_it->medium.medops.seek);
2981
2982 medium_status = msg_it->medium.medops.seek(offset, msg_it->medium.data);
2983 if (medium_status != CTF_MSG_ITER_MEDIUM_STATUS_OK) {
2984 if (medium_status == CTF_MSG_ITER_MEDIUM_STATUS_EOF) {
2985 status = CTF_MSG_ITER_STATUS_EOF;
2986 } else {
2987 status = CTF_MSG_ITER_STATUS_ERROR;
2988 goto end;
2989 }
2990 }
2991
2992 ctf_msg_iter_reset(msg_it);
2993 msg_it->cur_packet_offset = offset;
2994
2995 end:
2996 return status;
2997 }
2998
2999 static enum ctf_msg_iter_status clock_snapshot_at_msg_iter_state(struct ctf_msg_iter *msg_it,
3000 enum state target_state_1,
3001 enum state target_state_2,
3002 uint64_t *clock_snapshot)
3003 {
3004 enum ctf_msg_iter_status status = CTF_MSG_ITER_STATUS_OK;
3005
3006 BT_ASSERT_DBG(msg_it);
3007 BT_ASSERT_DBG(clock_snapshot);
3008 status = decode_until_state(msg_it, target_state_1, target_state_2);
3009 if (status != CTF_MSG_ITER_STATUS_OK) {
3010 goto end;
3011 }
3012
3013 *clock_snapshot = msg_it->default_clock_snapshot;
3014 end:
3015 return status;
3016 }
3017
3018 enum ctf_msg_iter_status
3019 ctf_msg_iter_curr_packet_first_event_clock_snapshot(struct ctf_msg_iter *msg_it,
3020 uint64_t *first_clock_snapshot)
3021 {
3022 return clock_snapshot_at_msg_iter_state(msg_it, STATE_AFTER_EVENT_HEADER, (state) -1,
3023 first_clock_snapshot);
3024 }
3025
3026 enum ctf_msg_iter_status
3027 ctf_msg_iter_curr_packet_last_event_clock_snapshot(struct ctf_msg_iter *msg_it,
3028 uint64_t *last_clock_snapshot)
3029 {
3030 return clock_snapshot_at_msg_iter_state(msg_it, STATE_EMIT_MSG_PACKET_END_SINGLE,
3031 STATE_EMIT_MSG_PACKET_END_MULTI, last_clock_snapshot);
3032 }
3033
3034 enum ctf_msg_iter_status
3035 ctf_msg_iter_get_packet_properties(struct ctf_msg_iter *msg_it,
3036 struct ctf_msg_iter_packet_properties *props)
3037 {
3038 enum ctf_msg_iter_status status;
3039
3040 BT_ASSERT_DBG(msg_it);
3041 BT_ASSERT_DBG(props);
3042 status = read_packet_header_context_fields(msg_it);
3043 if (status != CTF_MSG_ITER_STATUS_OK) {
3044 goto end;
3045 }
3046
3047 props->exp_packet_total_size = msg_it->cur_exp_packet_total_size;
3048 props->exp_packet_content_size = msg_it->cur_exp_packet_content_size;
3049 props->stream_class_id = (uint64_t) msg_it->cur_stream_class_id;
3050 props->data_stream_id = msg_it->cur_data_stream_id;
3051 props->snapshots.discarded_events = msg_it->snapshots.discarded_events;
3052 props->snapshots.packets = msg_it->snapshots.packets;
3053 props->snapshots.beginning_clock = msg_it->snapshots.beginning_clock;
3054 props->snapshots.end_clock = msg_it->snapshots.end_clock;
3055
3056 end:
3057 return status;
3058 }
3059
3060 void ctf_msg_iter_set_dry_run(struct ctf_msg_iter *msg_it, bool val)
3061 {
3062 msg_it->dry_run = val;
3063 }
This page took 0.144268 seconds and 4 git commands to generate.