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