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