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