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