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