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