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