cpp-common/bt2c/logging.hpp: remove no-formatting ("str") alternatives
[babeltrace.git] / src / plugins / ctf / common / src / bfcr / bfcr.cpp
CommitLineData
5cd6d0e5 1/*
0235b0db 2 * SPDX-License-Identifier: MIT
5cd6d0e5
PP
3 *
4 * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation
5 * Copyright (c) 2015-2016 Philippe Proulx <pproulx@efficios.com>
6 *
0235b0db 7 * Babeltrace - CTF binary field class reader (BFCR)
5cd6d0e5
PP
8 */
9
c802cacb 10#include "common/align.h"
578e048b 11#include "common/assert.h"
578e048b 12#include "common/common.h"
c802cacb 13#include "compat/bitfield.h"
0f5c5d5c
SM
14#include "cpp-common/bt2c/logging.hpp"
15#include "cpp-common/vendor/fmt/format.h"
5cd6d0e5 16
5656cea5 17#include "../metadata/tsdl/ctf-meta.hpp"
c802cacb 18#include "bfcr.hpp"
5cd6d0e5 19
4164020e
SM
20#define DIV8(_x) ((_x) >> 3)
21#define BYTES_TO_BITS(_x) ((_x) *8)
22#define BITS_TO_BYTES_FLOOR(_x) DIV8(_x)
23#define BITS_TO_BYTES_CEIL(_x) DIV8((_x) + 7)
24#define IN_BYTE_OFFSET(_at) ((_at) &7)
5cd6d0e5
PP
25
26/* A visit stack entry */
4164020e
SM
27struct stack_entry
28{
29 /*
30 * Current class of base field, one of:
31 *
32 * * Structure
33 * * Array
34 * * Sequence
35 * * Variant
36 */
37 struct ctf_field_class *base_class;
38
39 /* Length of base field (always 1 for a variant class) */
40 int64_t base_len;
41
42 /* Index of next field to read */
43 int64_t index;
5cd6d0e5
PP
44};
45
46/* Visit stack */
4164020e
SM
47struct stack
48{
49 struct bt_bfcr *bfcr;
80870e64 50
4164020e
SM
51 /* Entries (struct stack_entry) */
52 GArray *entries;
5cd6d0e5 53
4164020e
SM
54 /* Number of active entries */
55 size_t size;
5cd6d0e5
PP
56};
57
58/* Reading states */
4164020e
SM
59enum bfcr_state
60{
61 BFCR_STATE_NEXT_FIELD,
62 BFCR_STATE_ALIGN_BASIC,
63 BFCR_STATE_ALIGN_COMPOUND,
64 BFCR_STATE_READ_BASIC_BEGIN,
65 BFCR_STATE_READ_BASIC_CONTINUE,
66 BFCR_STATE_DONE,
5cd6d0e5
PP
67};
68
0f5c5d5c
SM
69static const char *format_as(bfcr_state state) noexcept
70{
71 switch (state) {
72 case BFCR_STATE_NEXT_FIELD:
73 return "NEXT_FIELD";
74
75 case BFCR_STATE_ALIGN_BASIC:
76 return "ALIGN_BASIC";
77
78 case BFCR_STATE_ALIGN_COMPOUND:
79 return "ALIGN_COMPOUND";
80
81 case BFCR_STATE_READ_BASIC_BEGIN:
82 return "READ_BASIC_BEGIN";
83
84 case BFCR_STATE_READ_BASIC_CONTINUE:
85 return "READ_BASIC_CONTINUE";
86
87 case BFCR_STATE_DONE:
88 return "DONE";
89 }
90
91 bt_common_abort();
92}
93
5cd6d0e5 94/* Binary class reader */
4164020e
SM
95struct bt_bfcr
96{
0f5c5d5c
SM
97 explicit bt_bfcr(const bt2c::Logger& parentLogger) : logger {parentLogger, "PLUGIN/CTF/BFCR"}
98 {
99 }
4164020e 100
0f5c5d5c 101 bt2c::Logger logger;
4164020e
SM
102
103 /* BFCR stack */
afb0f12b 104 struct stack *stack = nullptr;
4164020e
SM
105
106 /* Current basic field class */
afb0f12b 107 struct ctf_field_class *cur_basic_field_class = nullptr;
4164020e
SM
108
109 /* Current state */
afb0f12b 110 enum bfcr_state state = static_cast<bfcr_state>(0);
4164020e
SM
111
112 /*
113 * Last basic field class's byte order.
114 *
115 * This is used to detect errors since two contiguous basic
116 * classes for which the common boundary is not the boundary of
117 * a byte cannot have different byte orders.
118 *
119 * This is set to CTF_BYTE_ORDER_UNKNOWN on reset and when the last
120 * basic field class was a string class.
121 */
afb0f12b 122 enum ctf_byte_order last_bo = CTF_BYTE_ORDER_UNKNOWN;
4164020e
SM
123
124 /* Current byte order (copied to last_bo after a successful read) */
afb0f12b 125 enum ctf_byte_order cur_bo = CTF_BYTE_ORDER_UNKNOWN;
4164020e
SM
126
127 /* Stitch buffer infos */
128 struct
129 {
130 /* Stitch buffer */
afb0f12b 131 uint8_t buf[16] {};
4164020e
SM
132
133 /* Offset, within stitch buffer, of first bit */
afb0f12b 134 size_t offset = 0;
4164020e
SM
135
136 /* Length (bits) of data in stitch buffer from offset */
afb0f12b 137 size_t at = 0;
4164020e
SM
138 } stitch;
139
140 /* User buffer infos */
141 struct
142 {
143 /* Address */
afb0f12b 144 const uint8_t *addr = nullptr;
4164020e
SM
145
146 /* Offset of data from address (bits) */
afb0f12b 147 size_t offset = 0;
4164020e
SM
148
149 /* Current position from offset (bits) */
afb0f12b 150 size_t at = 0;
4164020e
SM
151
152 /* Offset of offset within whole packet (bits) */
afb0f12b 153 size_t packet_offset = 0;
4164020e
SM
154
155 /* Data size in buffer (bits) */
afb0f12b 156 size_t sz = 0;
4164020e
SM
157
158 /* Buffer size (bytes) */
afb0f12b 159 size_t buf_sz = 0;
4164020e
SM
160 } buf;
161
162 /* User stuff */
163 struct
164 {
165 /* Callback functions */
afb0f12b 166 bt_bfcr_cbs cbs {};
4164020e
SM
167
168 /* Private data */
afb0f12b 169 void *data = nullptr;
4164020e 170 } user;
5cd6d0e5
PP
171};
172
4164020e 173static struct stack *stack_new(struct bt_bfcr *bfcr)
5cd6d0e5 174{
4164020e 175 struct stack *stack = NULL;
5cd6d0e5 176
4164020e
SM
177 stack = g_new0(struct stack, 1);
178 if (!stack) {
e27adb90 179 BT_CPPLOGE_SPEC(bfcr->logger, "Failed to allocate one stack.");
4164020e
SM
180 goto error;
181 }
5cd6d0e5 182
4164020e
SM
183 stack->bfcr = bfcr;
184 stack->entries = g_array_new(FALSE, TRUE, sizeof(struct stack_entry));
185 if (!stack->entries) {
e27adb90 186 BT_CPPLOGE_SPEC(bfcr->logger, "Failed to allocate a GArray.");
4164020e
SM
187 goto error;
188 }
5cd6d0e5 189
0f5c5d5c 190 BT_CPPLOGD_SPEC(bfcr->logger, "Created stack: addr={}", fmt::ptr(stack));
4164020e 191 return stack;
5cd6d0e5
PP
192
193error:
4164020e
SM
194 g_free(stack);
195 return NULL;
5cd6d0e5
PP
196}
197
4164020e 198static void stack_destroy(struct stack *stack)
5cd6d0e5 199{
4164020e 200 struct bt_bfcr *bfcr;
80870e64 201
4164020e
SM
202 if (!stack) {
203 return;
204 }
5cd6d0e5 205
4164020e 206 bfcr = stack->bfcr;
0f5c5d5c 207 BT_CPPLOGD_SPEC(bfcr->logger, "Destroying stack: addr={}", fmt::ptr(stack));
5cd6d0e5 208
4164020e
SM
209 if (stack->entries) {
210 g_array_free(stack->entries, TRUE);
211 }
5cd6d0e5 212
4164020e 213 g_free(stack);
5cd6d0e5
PP
214}
215
4164020e 216static int stack_push(struct stack *stack, struct ctf_field_class *base_class, size_t base_len)
5cd6d0e5 217{
4164020e
SM
218 struct stack_entry *entry;
219 struct bt_bfcr *bfcr;
220
221 BT_ASSERT_DBG(stack);
222 BT_ASSERT_DBG(base_class);
223 bfcr = stack->bfcr;
0f5c5d5c
SM
224 BT_CPPLOGT_SPEC(bfcr->logger,
225 "Pushing field class on stack: stack-addr={}, "
226 "fc-addr={}, fc-type={}, base-length={}, "
227 "stack-size-before={}, stack-size-after={}",
228 fmt::ptr(stack), fmt::ptr(base_class), (int) base_class->type, base_len,
229 stack->size, stack->size + 1);
4164020e
SM
230
231 if (stack->entries->len == stack->size) {
232 g_array_set_size(stack->entries, stack->size + 1);
233 }
234
d50d46f3 235 entry = &bt_g_array_index(stack->entries, struct stack_entry, stack->size);
4164020e
SM
236 entry->base_class = base_class;
237 entry->base_len = base_len;
238 entry->index = 0;
239 stack->size++;
240 return 0;
5cd6d0e5
PP
241}
242
4164020e
SM
243static inline int64_t get_compound_field_class_length(struct bt_bfcr *bfcr,
244 struct ctf_field_class *fc)
5cd6d0e5 245{
4164020e
SM
246 int64_t length;
247
248 switch (fc->type) {
249 case CTF_FIELD_CLASS_TYPE_STRUCT:
250 {
251 ctf_field_class_struct *struct_fc = ctf_field_class_as_struct(fc);
252
253 length = (int64_t) struct_fc->members->len;
254 break;
255 }
256 case CTF_FIELD_CLASS_TYPE_VARIANT:
257 {
258 /* Variant field classes always "contain" a single class */
259 length = 1;
260 break;
261 }
262 case CTF_FIELD_CLASS_TYPE_ARRAY:
263 {
264 struct ctf_field_class_array *array_fc = ctf_field_class_as_array(fc);
265
266 length = (int64_t) array_fc->length;
267 break;
268 }
269 case CTF_FIELD_CLASS_TYPE_SEQUENCE:
270 length = bfcr->user.cbs.query.get_sequence_length(fc, bfcr->user.data);
271 break;
272 default:
273 bt_common_abort();
274 }
275
276 return length;
5cd6d0e5
PP
277}
278
4164020e 279static int stack_push_with_len(struct bt_bfcr *bfcr, struct ctf_field_class *base_class)
5cd6d0e5 280{
4164020e
SM
281 int ret;
282 int64_t length = get_compound_field_class_length(bfcr, base_class);
5cd6d0e5 283
4164020e 284 if (length < 0) {
0f5c5d5c
SM
285 BT_CPPLOGW_SPEC(bfcr->logger,
286 "Cannot get compound field class's field count: "
287 "bfcr-addr={}, fc-addr={}, fc-type={}",
288 fmt::ptr(bfcr), fmt::ptr(base_class), (int) base_class->type);
4164020e
SM
289 ret = BT_BFCR_STATUS_ERROR;
290 goto end;
291 }
5cd6d0e5 292
4164020e 293 ret = stack_push(bfcr->stack, base_class, (size_t) length);
5cd6d0e5
PP
294
295end:
4164020e 296 return ret;
5cd6d0e5
PP
297}
298
4164020e 299static inline unsigned int stack_size(struct stack *stack)
5cd6d0e5 300{
4164020e
SM
301 BT_ASSERT_DBG(stack);
302 return stack->size;
5cd6d0e5
PP
303}
304
4164020e 305static void stack_pop(struct stack *stack)
5cd6d0e5 306{
4164020e
SM
307 struct bt_bfcr *bfcr;
308
309 BT_ASSERT_DBG(stack);
310 BT_ASSERT_DBG(stack_size(stack));
311 bfcr = stack->bfcr;
0f5c5d5c
SM
312 BT_CPPLOGT_SPEC(bfcr->logger,
313 "Popping from stack: "
314 "stack-addr={}, stack-size-before={}, stack-size-after={}",
315 fmt::ptr(stack), stack->entries->len, stack->entries->len - 1);
4164020e 316 stack->size--;
5cd6d0e5
PP
317}
318
4164020e 319static inline bool stack_empty(struct stack *stack)
5cd6d0e5 320{
4164020e 321 return stack_size(stack) == 0;
5cd6d0e5
PP
322}
323
4164020e 324static void stack_clear(struct stack *stack)
5cd6d0e5 325{
4164020e
SM
326 BT_ASSERT_DBG(stack);
327 stack->size = 0;
5cd6d0e5
PP
328}
329
4164020e 330static inline struct stack_entry *stack_top(struct stack *stack)
5cd6d0e5 331{
4164020e
SM
332 BT_ASSERT_DBG(stack);
333 BT_ASSERT_DBG(stack_size(stack));
d50d46f3 334 return &bt_g_array_index(stack->entries, struct stack_entry, stack->size - 1);
5cd6d0e5
PP
335}
336
4164020e 337static inline size_t available_bits(struct bt_bfcr *bfcr)
5cd6d0e5 338{
4164020e 339 return bfcr->buf.sz - bfcr->buf.at;
5cd6d0e5
PP
340}
341
4164020e 342static inline void consume_bits(struct bt_bfcr *bfcr, size_t incr)
5cd6d0e5 343{
0f5c5d5c
SM
344 BT_CPPLOGT_SPEC(bfcr->logger, "Advancing cursor: bfcr-addr={}, cur-before={}, cur-after={}",
345 fmt::ptr(bfcr), bfcr->buf.at, bfcr->buf.at + incr);
4164020e 346 bfcr->buf.at += incr;
5cd6d0e5
PP
347}
348
4164020e 349static inline bool has_enough_bits(struct bt_bfcr *bfcr, size_t sz)
5cd6d0e5 350{
4164020e 351 return available_bits(bfcr) >= sz;
5cd6d0e5
PP
352}
353
4164020e 354static inline bool at_least_one_bit_left(struct bt_bfcr *bfcr)
5cd6d0e5 355{
4164020e 356 return has_enough_bits(bfcr, 1);
5cd6d0e5
PP
357}
358
4164020e 359static inline size_t packet_at(struct bt_bfcr *bfcr)
5cd6d0e5 360{
4164020e 361 return bfcr->buf.packet_offset + bfcr->buf.at;
5cd6d0e5
PP
362}
363
4164020e 364static inline size_t buf_at_from_addr(struct bt_bfcr *bfcr)
5cd6d0e5 365{
4164020e
SM
366 /*
367 * Considering this:
368 *
369 * ====== offset ===== (17)
370 *
371 * xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
372 * ^
373 * addr (0) ==== at ==== (12)
374 *
375 * We want this:
376 *
377 * =============================== (29)
378 */
379 return bfcr->buf.offset + bfcr->buf.at;
5cd6d0e5
PP
380}
381
4164020e 382static void stitch_reset(struct bt_bfcr *bfcr)
5cd6d0e5 383{
4164020e
SM
384 bfcr->stitch.offset = 0;
385 bfcr->stitch.at = 0;
5cd6d0e5
PP
386}
387
4164020e 388static inline size_t stitch_at_from_addr(struct bt_bfcr *bfcr)
5cd6d0e5 389{
4164020e 390 return bfcr->stitch.offset + bfcr->stitch.at;
5cd6d0e5
PP
391}
392
4164020e 393static void stitch_append_from_buf(struct bt_bfcr *bfcr, size_t sz)
5cd6d0e5 394{
4164020e
SM
395 size_t stitch_byte_at;
396 size_t buf_byte_at;
397 size_t nb_bytes;
398
399 if (sz == 0) {
400 return;
401 }
402
403 stitch_byte_at = BITS_TO_BYTES_FLOOR(stitch_at_from_addr(bfcr));
404 buf_byte_at = BITS_TO_BYTES_FLOOR(buf_at_from_addr(bfcr));
405 nb_bytes = BITS_TO_BYTES_CEIL(sz);
406 BT_ASSERT(nb_bytes > 0);
407 BT_ASSERT(bfcr->buf.addr);
408 memcpy(&bfcr->stitch.buf[stitch_byte_at], &bfcr->buf.addr[buf_byte_at], nb_bytes);
409 bfcr->stitch.at += sz;
410 consume_bits(bfcr, sz);
5cd6d0e5
PP
411}
412
4164020e 413static void stitch_append_from_remaining_buf(struct bt_bfcr *bfcr)
5cd6d0e5 414{
4164020e 415 stitch_append_from_buf(bfcr, available_bits(bfcr));
5cd6d0e5
PP
416}
417
4164020e 418static void stitch_set_from_remaining_buf(struct bt_bfcr *bfcr)
5cd6d0e5 419{
4164020e
SM
420 stitch_reset(bfcr);
421 bfcr->stitch.offset = IN_BYTE_OFFSET(buf_at_from_addr(bfcr));
422 stitch_append_from_remaining_buf(bfcr);
5cd6d0e5
PP
423}
424
4164020e
SM
425static inline void read_unsigned_bitfield(struct bt_bfcr *bfcr, const uint8_t *buf, size_t at,
426 unsigned int field_size, enum ctf_byte_order bo,
427 uint64_t *v)
5cd6d0e5 428{
4164020e
SM
429 switch (bo) {
430 case CTF_BYTE_ORDER_BIG:
431 bt_bitfield_read_be(buf, uint8_t, at, field_size, v);
432 break;
433 case CTF_BYTE_ORDER_LITTLE:
434 bt_bitfield_read_le(buf, uint8_t, at, field_size, v);
435 break;
436 default:
437 bt_common_abort();
438 }
439
0f5c5d5c
SM
440 BT_CPPLOGT_SPEC(bfcr->logger, "Read unsigned bit array: cur={}, size={}, bo={}, val={}", at,
441 field_size, (int) bo, *v);
5cd6d0e5
PP
442}
443
4164020e
SM
444static inline void read_signed_bitfield(struct bt_bfcr *bfcr, const uint8_t *buf, size_t at,
445 unsigned int field_size, enum ctf_byte_order bo, int64_t *v)
5cd6d0e5 446{
4164020e
SM
447 switch (bo) {
448 case CTF_BYTE_ORDER_BIG:
449 bt_bitfield_read_be(buf, uint8_t, at, field_size, v);
450 break;
451 case CTF_BYTE_ORDER_LITTLE:
452 bt_bitfield_read_le(buf, uint8_t, at, field_size, v);
453 break;
454 default:
455 bt_common_abort();
456 }
457
0f5c5d5c
SM
458 BT_CPPLOGT_SPEC(bfcr->logger, "Read signed bit array: cur={}, size={}, bo={}, val={}", at,
459 field_size, (int) bo, *v);
5cd6d0e5
PP
460}
461
4164020e 462typedef enum bt_bfcr_status (*read_basic_and_call_cb_t)(struct bt_bfcr *, const uint8_t *, size_t);
5cd6d0e5 463
4164020e
SM
464static inline enum bt_bfcr_status validate_contiguous_bo(struct bt_bfcr *bfcr,
465 enum ctf_byte_order next_bo)
5cd6d0e5 466{
4164020e
SM
467 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
468
469 /* Always valid when at a byte boundary */
470 if (packet_at(bfcr) % 8 == 0) {
471 goto end;
472 }
473
474 /* Always valid if last byte order is unknown */
475 if (bfcr->last_bo == CTF_BYTE_ORDER_UNKNOWN) {
476 goto end;
477 }
478
479 /* Always valid if next byte order is unknown */
480 if (next_bo == CTF_BYTE_ORDER_UNKNOWN) {
481 goto end;
482 }
483
484 /* Make sure last byte order is compatible with the next byte order */
485 switch (bfcr->last_bo) {
486 case CTF_BYTE_ORDER_BIG:
487 if (next_bo != CTF_BYTE_ORDER_BIG) {
488 status = BT_BFCR_STATUS_ERROR;
489 }
490 break;
491 case CTF_BYTE_ORDER_LITTLE:
492 if (next_bo != CTF_BYTE_ORDER_LITTLE) {
493 status = BT_BFCR_STATUS_ERROR;
494 }
495 break;
496 default:
497 status = BT_BFCR_STATUS_ERROR;
498 }
5cd6d0e5
PP
499
500end:
4164020e 501 if (status < 0) {
0f5c5d5c
SM
502 BT_CPPLOGW_SPEC(bfcr->logger,
503 "Cannot read bit array: two different byte orders not at a byte boundary: "
504 "bfcr-addr={}, last-bo={}, next-bo={}",
505 fmt::ptr(bfcr), (int) bfcr->last_bo, (int) next_bo);
4164020e 506 }
5cd6d0e5 507
4164020e 508 return status;
5cd6d0e5
PP
509}
510
4164020e
SM
511static enum bt_bfcr_status read_basic_float_and_call_cb(struct bt_bfcr *bfcr, const uint8_t *buf,
512 size_t at)
5cd6d0e5 513{
4164020e
SM
514 double dblval;
515 unsigned int field_size;
516 enum ctf_byte_order bo;
517 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
518 ctf_field_class_float *fc = ctf_field_class_as_float(bfcr->cur_basic_field_class);
519
520 BT_ASSERT_DBG(fc);
521 field_size = fc->base.size;
522 bo = fc->base.byte_order;
523 bfcr->cur_bo = bo;
524
525 switch (field_size) {
526 case 32:
527 {
528 uint64_t v;
529 union
530 {
531 uint32_t u;
532 float f;
533 } f32;
534
535 read_unsigned_bitfield(bfcr, buf, at, field_size, bo, &v);
536 f32.u = (uint32_t) v;
537 dblval = (double) f32.f;
538 break;
539 }
540 case 64:
541 {
542 union
543 {
544 uint64_t u;
545 double d;
546 } f64;
547
548 read_unsigned_bitfield(bfcr, buf, at, field_size, bo, &f64.u);
549 dblval = f64.d;
550 break;
551 }
552 default:
553 /* Only 32-bit and 64-bit fields are supported currently */
554 bt_common_abort();
555 }
556
0f5c5d5c
SM
557 BT_CPPLOGT_SPEC(bfcr->logger, "Read floating point number value: bfcr={}, cur={}, val={}",
558 fmt::ptr(bfcr), at, dblval);
4164020e
SM
559
560 if (bfcr->user.cbs.classes.floating_point) {
0f5c5d5c 561 BT_CPPLOGT_SPEC(bfcr->logger, "Calling user function (floating point number).");
4164020e
SM
562 status = bfcr->user.cbs.classes.floating_point(dblval, bfcr->cur_basic_field_class,
563 bfcr->user.data);
0f5c5d5c 564 BT_CPPLOGT_SPEC(bfcr->logger, "User function returned: status={}", status);
4164020e 565 if (status != BT_BFCR_STATUS_OK) {
0f5c5d5c
SM
566 BT_CPPLOGW_SPEC(bfcr->logger, "User function failed: bfcr-addr={}, status={}",
567 fmt::ptr(bfcr), status);
4164020e
SM
568 }
569 }
570
571 return status;
5cd6d0e5
PP
572}
573
4164020e
SM
574static inline enum bt_bfcr_status read_basic_int_and_call_cb(struct bt_bfcr *bfcr,
575 const uint8_t *buf, size_t at)
5cd6d0e5 576{
4164020e
SM
577 unsigned int field_size;
578 enum ctf_byte_order bo;
579 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
580 ctf_field_class_int *fc = ctf_field_class_as_int(bfcr->cur_basic_field_class);
581
582 field_size = fc->base.size;
583 bo = fc->base.byte_order;
584
585 /*
586 * Update current byte order now because we could be reading
587 * the integer value of an enumeration class, and thus we know
588 * here the actual supporting integer class's byte order.
589 */
590 bfcr->cur_bo = bo;
591
592 if (fc->is_signed) {
593 int64_t v;
594
595 read_signed_bitfield(bfcr, buf, at, field_size, bo, &v);
596
597 if (bfcr->user.cbs.classes.signed_int) {
0f5c5d5c 598 BT_CPPLOGT_SPEC(bfcr->logger, "Calling user function (signed integer).");
4164020e
SM
599 status =
600 bfcr->user.cbs.classes.signed_int(v, bfcr->cur_basic_field_class, bfcr->user.data);
0f5c5d5c 601 BT_CPPLOGT_SPEC(bfcr->logger, "User function returned: status={}", status);
4164020e 602 if (status != BT_BFCR_STATUS_OK) {
0f5c5d5c
SM
603 BT_CPPLOGW_SPEC(bfcr->logger,
604 "User function failed: "
605 "bfcr-addr={}, status={}",
606 fmt::ptr(bfcr), status);
4164020e
SM
607 }
608 }
609 } else {
610 uint64_t v;
611
612 read_unsigned_bitfield(bfcr, buf, at, field_size, bo, &v);
613
614 if (bfcr->user.cbs.classes.unsigned_int) {
0f5c5d5c 615 BT_CPPLOGT_SPEC(bfcr->logger, "Calling user function (unsigned integer).");
4164020e
SM
616 status = bfcr->user.cbs.classes.unsigned_int(v, bfcr->cur_basic_field_class,
617 bfcr->user.data);
0f5c5d5c 618 BT_CPPLOGT_SPEC(bfcr->logger, "User function returned: status={}", status);
4164020e 619 if (status != BT_BFCR_STATUS_OK) {
0f5c5d5c
SM
620 BT_CPPLOGW_SPEC(bfcr->logger,
621 "User function failed: "
622 "bfcr-addr={}, status={}",
623 fmt::ptr(bfcr), status);
4164020e
SM
624 }
625 }
626 }
627
628 return status;
5cd6d0e5
PP
629}
630
4164020e
SM
631static inline enum bt_bfcr_status
632read_bit_array_class_and_call_continue(struct bt_bfcr *bfcr,
633 read_basic_and_call_cb_t read_basic_and_call_cb)
5cd6d0e5 634{
4164020e
SM
635 size_t available;
636 size_t needed_bits;
637 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
638 ctf_field_class_bit_array *fc = ctf_field_class_as_bit_array(bfcr->cur_basic_field_class);
639
640 if (!at_least_one_bit_left(bfcr)) {
0f5c5d5c 641 BT_CPPLOGT_SPEC(bfcr->logger, "Reached end of data: bfcr-addr={}", fmt::ptr(bfcr));
4164020e
SM
642 status = BT_BFCR_STATUS_EOF;
643 goto end;
644 }
645
646 available = available_bits(bfcr);
647 needed_bits = fc->size - bfcr->stitch.at;
0f5c5d5c
SM
648 BT_CPPLOGT_SPEC(bfcr->logger,
649 "Continuing basic field decoding: "
650 "bfcr-addr={}, field-size={}, needed-size={}, "
651 "available-size={}",
652 fmt::ptr(bfcr), fc->size, needed_bits, available);
4164020e
SM
653 if (needed_bits <= available) {
654 /* We have all the bits; append to stitch, then decode */
655 stitch_append_from_buf(bfcr, needed_bits);
656 status = read_basic_and_call_cb(bfcr, bfcr->stitch.buf, bfcr->stitch.offset);
657 if (status != BT_BFCR_STATUS_OK) {
0f5c5d5c
SM
658 BT_CPPLOGW_SPEC(bfcr->logger,
659 "Cannot read basic field: "
660 "bfcr-addr={}, fc-addr={}, status={}",
661 fmt::ptr(bfcr), fmt::ptr(bfcr->cur_basic_field_class), status);
4164020e
SM
662 goto end;
663 }
664
665 if (stack_empty(bfcr->stack)) {
666 /* Root is a basic class */
667 bfcr->state = BFCR_STATE_DONE;
668 } else {
669 /* Go to next field */
670 stack_top(bfcr->stack)->index++;
671 bfcr->state = BFCR_STATE_NEXT_FIELD;
672 bfcr->last_bo = bfcr->cur_bo;
673 }
674 goto end;
675 }
676
677 /* We are here; it means we don't have enough data to decode this */
e27adb90
PP
678 BT_CPPLOGT_SPEC(bfcr->logger,
679 "Not enough data to read the next basic field: appending to stitch buffer.");
4164020e
SM
680 stitch_append_from_remaining_buf(bfcr);
681 status = BT_BFCR_STATUS_EOF;
5cd6d0e5
PP
682
683end:
4164020e 684 return status;
5cd6d0e5
PP
685}
686
4164020e
SM
687static inline enum bt_bfcr_status
688read_bit_array_class_and_call_begin(struct bt_bfcr *bfcr,
689 read_basic_and_call_cb_t read_basic_and_call_cb)
5cd6d0e5 690{
4164020e
SM
691 size_t available;
692 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
693 ctf_field_class_bit_array *fc = ctf_field_class_as_bit_array(bfcr->cur_basic_field_class);
694
695 if (!at_least_one_bit_left(bfcr)) {
0f5c5d5c 696 BT_CPPLOGT_SPEC(bfcr->logger, "Reached end of data: bfcr-addr={}", fmt::ptr(bfcr));
4164020e
SM
697 status = BT_BFCR_STATUS_EOF;
698 goto end;
699 }
700
701 status = validate_contiguous_bo(bfcr, fc->byte_order);
702 if (status != BT_BFCR_STATUS_OK) {
703 /* validate_contiguous_bo() logs errors */
704 goto end;
705 }
706
707 available = available_bits(bfcr);
708
709 if (fc->size <= available) {
710 /* We have all the bits; decode and set now */
711 BT_ASSERT_DBG(bfcr->buf.addr);
712 status = read_basic_and_call_cb(bfcr, bfcr->buf.addr, buf_at_from_addr(bfcr));
713 if (status != BT_BFCR_STATUS_OK) {
0f5c5d5c
SM
714 BT_CPPLOGW_SPEC(bfcr->logger,
715 "Cannot read basic field: "
716 "bfcr-addr={}, fc-addr={}, status={}",
717 fmt::ptr(bfcr), fmt::ptr(bfcr->cur_basic_field_class), status);
4164020e
SM
718 goto end;
719 }
720
721 consume_bits(bfcr, fc->size);
722
723 if (stack_empty(bfcr->stack)) {
724 /* Root is a basic class */
725 bfcr->state = BFCR_STATE_DONE;
726 } else {
727 /* Go to next field */
728 stack_top(bfcr->stack)->index++;
729 bfcr->state = BFCR_STATE_NEXT_FIELD;
730 bfcr->last_bo = bfcr->cur_bo;
731 }
732
733 goto end;
734 }
735
736 /* We are here; it means we don't have enough data to decode this */
e27adb90
PP
737 BT_CPPLOGT_SPEC(bfcr->logger,
738 "Not enough data to read the next basic field: setting stitch buffer.");
4164020e
SM
739 stitch_set_from_remaining_buf(bfcr);
740 bfcr->state = BFCR_STATE_READ_BASIC_CONTINUE;
741 status = BT_BFCR_STATUS_EOF;
5cd6d0e5
PP
742
743end:
4164020e 744 return status;
5cd6d0e5
PP
745}
746
4164020e 747static inline enum bt_bfcr_status read_basic_int_class_and_call_begin(struct bt_bfcr *bfcr)
5cd6d0e5 748{
4164020e 749 return read_bit_array_class_and_call_begin(bfcr, read_basic_int_and_call_cb);
5cd6d0e5
PP
750}
751
4164020e 752static inline enum bt_bfcr_status read_basic_int_class_and_call_continue(struct bt_bfcr *bfcr)
5cd6d0e5 753{
4164020e 754 return read_bit_array_class_and_call_continue(bfcr, read_basic_int_and_call_cb);
5cd6d0e5
PP
755}
756
4164020e 757static inline enum bt_bfcr_status read_basic_float_class_and_call_begin(struct bt_bfcr *bfcr)
5cd6d0e5 758{
4164020e 759 return read_bit_array_class_and_call_begin(bfcr, read_basic_float_and_call_cb);
5cd6d0e5
PP
760}
761
4164020e 762static inline enum bt_bfcr_status read_basic_float_class_and_call_continue(struct bt_bfcr *bfcr)
5cd6d0e5 763{
4164020e 764 return read_bit_array_class_and_call_continue(bfcr, read_basic_float_and_call_cb);
5cd6d0e5
PP
765}
766
4164020e 767static inline enum bt_bfcr_status read_basic_string_class_and_call(struct bt_bfcr *bfcr, bool begin)
5cd6d0e5 768{
4164020e
SM
769 size_t buf_at_bytes;
770 const uint8_t *result;
771 size_t available_bytes;
772 const uint8_t *first_chr;
773 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
774
775 if (!at_least_one_bit_left(bfcr)) {
0f5c5d5c 776 BT_CPPLOGT_SPEC(bfcr->logger, "Reached end of data: bfcr-addr={}", fmt::ptr(bfcr));
4164020e
SM
777 status = BT_BFCR_STATUS_EOF;
778 goto end;
779 }
780
781 BT_ASSERT_DBG(buf_at_from_addr(bfcr) % 8 == 0);
782 available_bytes = BITS_TO_BYTES_FLOOR(available_bits(bfcr));
783 buf_at_bytes = BITS_TO_BYTES_FLOOR(buf_at_from_addr(bfcr));
784 BT_ASSERT_DBG(bfcr->buf.addr);
785 first_chr = &bfcr->buf.addr[buf_at_bytes];
786 result = (const uint8_t *) memchr(first_chr, '\0', available_bytes);
787
788 if (begin && bfcr->user.cbs.classes.string_begin) {
0f5c5d5c 789 BT_CPPLOGT_SPEC(bfcr->logger, "Calling user function (string, beginning).");
4164020e 790 status = bfcr->user.cbs.classes.string_begin(bfcr->cur_basic_field_class, bfcr->user.data);
0f5c5d5c 791 BT_CPPLOGT_SPEC(bfcr->logger, "User function returned: status={}", status);
4164020e 792 if (status != BT_BFCR_STATUS_OK) {
0f5c5d5c
SM
793 BT_CPPLOGW_SPEC(bfcr->logger, "User function failed: bfcr-addr={}, status={}",
794 fmt::ptr(bfcr), status);
4164020e
SM
795 goto end;
796 }
797 }
798
799 if (!result) {
800 /* No null character yet */
801 if (bfcr->user.cbs.classes.string) {
0f5c5d5c 802 BT_CPPLOGT_SPEC(bfcr->logger, "Calling user function (substring).");
4164020e
SM
803 status = bfcr->user.cbs.classes.string((const char *) first_chr, available_bytes,
804 bfcr->cur_basic_field_class, bfcr->user.data);
0f5c5d5c 805 BT_CPPLOGT_SPEC(bfcr->logger, "User function returned: status={}", status);
4164020e 806 if (status != BT_BFCR_STATUS_OK) {
0f5c5d5c
SM
807 BT_CPPLOGW_SPEC(bfcr->logger,
808 "User function failed: "
809 "bfcr-addr={}, status={}",
810 fmt::ptr(bfcr), status);
4164020e
SM
811 goto end;
812 }
813 }
814
815 consume_bits(bfcr, BYTES_TO_BITS(available_bytes));
816 bfcr->state = BFCR_STATE_READ_BASIC_CONTINUE;
817 status = BT_BFCR_STATUS_EOF;
818 } else {
819 /* Found the null character */
820 size_t result_len = (size_t) (result - first_chr);
821
822 if (bfcr->user.cbs.classes.string && result_len) {
0f5c5d5c 823 BT_CPPLOGT_SPEC(bfcr->logger, "Calling user function (substring).");
4164020e
SM
824 status = bfcr->user.cbs.classes.string((const char *) first_chr, result_len,
825 bfcr->cur_basic_field_class, bfcr->user.data);
0f5c5d5c 826 BT_CPPLOGT_SPEC(bfcr->logger, "User function returned: status={}", status);
4164020e 827 if (status != BT_BFCR_STATUS_OK) {
0f5c5d5c
SM
828 BT_CPPLOGW_SPEC(bfcr->logger,
829 "User function failed: "
830 "bfcr-addr={}, status={}",
831 fmt::ptr(bfcr), status);
4164020e
SM
832 goto end;
833 }
834 }
835
836 if (bfcr->user.cbs.classes.string_end) {
0f5c5d5c 837 BT_CPPLOGT_SPEC(bfcr->logger, "Calling user function (string, end).");
4164020e
SM
838 status =
839 bfcr->user.cbs.classes.string_end(bfcr->cur_basic_field_class, bfcr->user.data);
0f5c5d5c 840 BT_CPPLOGT_SPEC(bfcr->logger, "User function returned: status={}", status);
4164020e 841 if (status != BT_BFCR_STATUS_OK) {
0f5c5d5c
SM
842 BT_CPPLOGW_SPEC(bfcr->logger,
843 "User function failed: "
844 "bfcr-addr={}, status={}",
845 fmt::ptr(bfcr), status);
4164020e
SM
846 goto end;
847 }
848 }
849
850 consume_bits(bfcr, BYTES_TO_BITS(result_len + 1));
851
852 if (stack_empty(bfcr->stack)) {
853 /* Root is a basic class */
854 bfcr->state = BFCR_STATE_DONE;
855 } else {
856 /* Go to next field */
857 stack_top(bfcr->stack)->index++;
858 bfcr->state = BFCR_STATE_NEXT_FIELD;
859 bfcr->last_bo = bfcr->cur_bo;
860 }
861 }
5cd6d0e5
PP
862
863end:
4164020e 864 return status;
5cd6d0e5
PP
865}
866
4164020e 867static inline enum bt_bfcr_status read_basic_begin_state(struct bt_bfcr *bfcr)
5cd6d0e5 868{
4164020e
SM
869 enum bt_bfcr_status status;
870
871 BT_ASSERT_DBG(bfcr->cur_basic_field_class);
872
873 switch (bfcr->cur_basic_field_class->type) {
874 case CTF_FIELD_CLASS_TYPE_INT:
875 case CTF_FIELD_CLASS_TYPE_ENUM:
876 status = read_basic_int_class_and_call_begin(bfcr);
877 break;
878 case CTF_FIELD_CLASS_TYPE_FLOAT:
879 status = read_basic_float_class_and_call_begin(bfcr);
880 break;
881 case CTF_FIELD_CLASS_TYPE_STRING:
882 status = read_basic_string_class_and_call(bfcr, true);
883 break;
884 default:
885 bt_common_abort();
886 }
887
888 return status;
5cd6d0e5
PP
889}
890
4164020e 891static inline enum bt_bfcr_status read_basic_continue_state(struct bt_bfcr *bfcr)
5cd6d0e5 892{
4164020e
SM
893 enum bt_bfcr_status status;
894
895 BT_ASSERT_DBG(bfcr->cur_basic_field_class);
896
897 switch (bfcr->cur_basic_field_class->type) {
898 case CTF_FIELD_CLASS_TYPE_INT:
899 case CTF_FIELD_CLASS_TYPE_ENUM:
900 status = read_basic_int_class_and_call_continue(bfcr);
901 break;
902 case CTF_FIELD_CLASS_TYPE_FLOAT:
903 status = read_basic_float_class_and_call_continue(bfcr);
904 break;
905 case CTF_FIELD_CLASS_TYPE_STRING:
906 status = read_basic_string_class_and_call(bfcr, false);
907 break;
908 default:
909 bt_common_abort();
910 }
911
912 return status;
5cd6d0e5
PP
913}
914
4164020e 915static inline size_t bits_to_skip_to_align_to(struct bt_bfcr *bfcr, size_t align)
5cd6d0e5 916{
4164020e 917 size_t aligned_packet_at;
5cd6d0e5 918
4164020e
SM
919 aligned_packet_at = BT_ALIGN(packet_at(bfcr), align);
920 return aligned_packet_at - packet_at(bfcr);
5cd6d0e5
PP
921}
922
4164020e
SM
923static inline enum bt_bfcr_status align_class_state(struct bt_bfcr *bfcr,
924 struct ctf_field_class *field_class,
925 enum bfcr_state next_state)
5cd6d0e5 926{
4164020e
SM
927 unsigned int field_alignment;
928 size_t skip_bits;
929 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
930
931 /* Get field's alignment */
932 field_alignment = field_class->alignment;
933
934 /*
935 * 0 means "undefined" for variants; what we really want is 1
936 * (always aligned)
937 */
938 BT_ASSERT_DBG(field_alignment >= 1);
939
940 /* Compute how many bits we need to skip */
941 skip_bits = bits_to_skip_to_align_to(bfcr, (size_t) field_alignment);
942
943 /* Nothing to skip? aligned */
944 if (skip_bits == 0) {
945 bfcr->state = next_state;
946 goto end;
947 }
948
949 /* Make sure there's at least one bit left */
950 if (!at_least_one_bit_left(bfcr)) {
951 status = BT_BFCR_STATUS_EOF;
952 goto end;
953 }
954
955 /* Consume as many bits as possible in what's left */
956 consume_bits(bfcr, MIN(available_bits(bfcr), skip_bits));
957
958 /* Are we done now? */
959 skip_bits = bits_to_skip_to_align_to(bfcr, field_alignment);
960 if (skip_bits == 0) {
961 /* Yes: go to next state */
962 bfcr->state = next_state;
963 goto end;
964 } else {
965 /* No: need more data */
0f5c5d5c
SM
966 BT_CPPLOGT_SPEC(bfcr->logger, "Reached end of data when aligning: bfcr-addr={}",
967 fmt::ptr(bfcr));
4164020e
SM
968 status = BT_BFCR_STATUS_EOF;
969 }
5cd6d0e5
PP
970
971end:
4164020e 972 return status;
5cd6d0e5
PP
973}
974
4164020e 975static inline enum bt_bfcr_status next_field_state(struct bt_bfcr *bfcr)
5cd6d0e5 976{
4164020e
SM
977 int ret;
978 struct stack_entry *top;
979 struct ctf_field_class *next_field_class = NULL;
980 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
981
982 if (stack_empty(bfcr->stack)) {
983 goto end;
984 }
985
986 top = stack_top(bfcr->stack);
987
988 /* Are we done with this base class? */
989 while (top->index == top->base_len) {
990 if (bfcr->user.cbs.classes.compound_end) {
0f5c5d5c 991 BT_CPPLOGT_SPEC(bfcr->logger, "Calling user function (compound, end).");
4164020e 992 status = bfcr->user.cbs.classes.compound_end(top->base_class, bfcr->user.data);
0f5c5d5c 993 BT_CPPLOGT_SPEC(bfcr->logger, "User function returned: status={}", status);
4164020e 994 if (status != BT_BFCR_STATUS_OK) {
0f5c5d5c
SM
995 BT_CPPLOGW_SPEC(bfcr->logger, "User function failed: bfcr-addr={}, status={}",
996 fmt::ptr(bfcr), status);
4164020e
SM
997 goto end;
998 }
999 }
1000
1001 stack_pop(bfcr->stack);
1002
1003 /* Are we done with the root class? */
1004 if (stack_empty(bfcr->stack)) {
1005 bfcr->state = BFCR_STATE_DONE;
1006 goto end;
1007 }
1008
1009 top = stack_top(bfcr->stack);
1010 top->index++;
1011 }
1012
1013 /* Get next field's class */
1014 switch (top->base_class->type) {
1015 case CTF_FIELD_CLASS_TYPE_STRUCT:
1016 next_field_class = ctf_field_class_struct_borrow_member_by_index(
1017 ctf_field_class_as_struct(top->base_class), (uint64_t) top->index)
1018 ->fc;
1019 break;
1020 case CTF_FIELD_CLASS_TYPE_ARRAY:
1021 case CTF_FIELD_CLASS_TYPE_SEQUENCE:
1022 {
1023 ctf_field_class_array_base *array_fc = ctf_field_class_as_array_base(top->base_class);
1024
1025 next_field_class = array_fc->elem_fc;
1026 break;
1027 }
1028 case CTF_FIELD_CLASS_TYPE_VARIANT:
1029 /* Variant classes are dynamic: the user should know! */
1030 next_field_class = bfcr->user.cbs.query.borrow_variant_selected_field_class(
1031 top->base_class, bfcr->user.data);
1032 break;
1033 default:
1034 break;
1035 }
1036
1037 if (!next_field_class) {
0f5c5d5c
SM
1038 BT_CPPLOGW_SPEC(bfcr->logger,
1039 "Cannot get the field class of the next field: "
1040 "bfcr-addr={}, base-fc-addr={}, base-fc-type={}, index={}",
1041 fmt::ptr(bfcr), fmt::ptr(top->base_class), (int) top->base_class->type,
1042 top->index);
4164020e
SM
1043 status = BT_BFCR_STATUS_ERROR;
1044 goto end;
1045 }
1046
1047 if (next_field_class->is_compound) {
1048 if (bfcr->user.cbs.classes.compound_begin) {
0f5c5d5c 1049 BT_CPPLOGT_SPEC(bfcr->logger, "Calling user function (compound, begin).");
4164020e 1050 status = bfcr->user.cbs.classes.compound_begin(next_field_class, bfcr->user.data);
0f5c5d5c 1051 BT_CPPLOGT_SPEC(bfcr->logger, "User function returned: status={}", status);
4164020e 1052 if (status != BT_BFCR_STATUS_OK) {
0f5c5d5c
SM
1053 BT_CPPLOGW_SPEC(bfcr->logger, "User function failed: bfcr-addr={}, status={}",
1054 fmt::ptr(bfcr), status);
4164020e
SM
1055 goto end;
1056 }
1057 }
1058
1059 ret = stack_push_with_len(bfcr, next_field_class);
1060 if (ret) {
1061 /* stack_push_with_len() logs errors */
1062 status = BT_BFCR_STATUS_ERROR;
1063 goto end;
1064 }
1065
1066 /* Next state: align a compound class */
1067 bfcr->state = BFCR_STATE_ALIGN_COMPOUND;
1068 } else {
1069 /* Replace current basic field class */
0f5c5d5c
SM
1070 BT_CPPLOGT_SPEC(bfcr->logger,
1071 "Replacing current basic field class: "
1072 "bfcr-addr={}, cur-basic-fc-addr={}, "
1073 "next-basic-fc-addr={}",
1074 fmt::ptr(bfcr), fmt::ptr(bfcr->cur_basic_field_class),
1075 fmt::ptr(next_field_class));
4164020e
SM
1076 bfcr->cur_basic_field_class = next_field_class;
1077
1078 /* Next state: align a basic class */
1079 bfcr->state = BFCR_STATE_ALIGN_BASIC;
1080 }
5cd6d0e5
PP
1081
1082end:
4164020e 1083 return status;
5cd6d0e5
PP
1084}
1085
4164020e 1086static inline enum bt_bfcr_status handle_state(struct bt_bfcr *bfcr)
5cd6d0e5 1087{
4164020e
SM
1088 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
1089
0f5c5d5c
SM
1090 BT_CPPLOGT_SPEC(bfcr->logger, "Handling state: bfcr-addr={}, state={}", fmt::ptr(bfcr),
1091 bfcr->state);
4164020e
SM
1092
1093 switch (bfcr->state) {
1094 case BFCR_STATE_NEXT_FIELD:
1095 status = next_field_state(bfcr);
1096 break;
1097 case BFCR_STATE_ALIGN_BASIC:
1098 status = align_class_state(bfcr, bfcr->cur_basic_field_class, BFCR_STATE_READ_BASIC_BEGIN);
1099 break;
1100 case BFCR_STATE_ALIGN_COMPOUND:
1101 status = align_class_state(bfcr, stack_top(bfcr->stack)->base_class, BFCR_STATE_NEXT_FIELD);
1102 break;
1103 case BFCR_STATE_READ_BASIC_BEGIN:
1104 status = read_basic_begin_state(bfcr);
1105 break;
1106 case BFCR_STATE_READ_BASIC_CONTINUE:
1107 status = read_basic_continue_state(bfcr);
1108 break;
1109 case BFCR_STATE_DONE:
1110 break;
1111 }
1112
0f5c5d5c 1113 BT_CPPLOGT_SPEC(bfcr->logger, "Handled state: bfcr-addr={}, status={}", fmt::ptr(bfcr), status);
4164020e 1114 return status;
5cd6d0e5
PP
1115}
1116
0f5c5d5c 1117struct bt_bfcr *bt_bfcr_create(struct bt_bfcr_cbs cbs, void *data, const bt2c::Logger& logger)
5cd6d0e5 1118{
e27adb90 1119 BT_CPPLOGD_SPEC(logger, "Creating binary field class reader (BFCR).");
4164020e 1120
0f5c5d5c 1121 bt_bfcr *bfcr = new bt_bfcr {logger};
4164020e
SM
1122 bfcr->stack = stack_new(bfcr);
1123 if (!bfcr->stack) {
e27adb90 1124 BT_CPPLOGE_SPEC(bfcr->logger, "Cannot create BFCR's stack.");
4164020e
SM
1125 bt_bfcr_destroy(bfcr);
1126 bfcr = NULL;
1127 goto end;
1128 }
1129
1130 bfcr->state = BFCR_STATE_NEXT_FIELD;
1131 bfcr->user.cbs = cbs;
1132 bfcr->user.data = data;
0f5c5d5c 1133 BT_CPPLOGD_SPEC(bfcr->logger, "Created BFCR: addr={}", fmt::ptr(bfcr));
5cd6d0e5
PP
1134
1135end:
4164020e 1136 return bfcr;
5cd6d0e5
PP
1137}
1138
5cd6d0e5
PP
1139void bt_bfcr_destroy(struct bt_bfcr *bfcr)
1140{
4164020e
SM
1141 if (bfcr->stack) {
1142 stack_destroy(bfcr->stack);
1143 }
5cd6d0e5 1144
0f5c5d5c 1145 BT_CPPLOGD_SPEC(bfcr->logger, "Destroying BFCR: addr={}", fmt::ptr(bfcr));
afb0f12b 1146 delete bfcr;
5cd6d0e5
PP
1147}
1148
4164020e 1149static void reset(struct bt_bfcr *bfcr)
5cd6d0e5 1150{
0f5c5d5c 1151 BT_CPPLOGD_SPEC(bfcr->logger, "Resetting BFCR: addr={}", fmt::ptr(bfcr));
4164020e
SM
1152 stack_clear(bfcr->stack);
1153 stitch_reset(bfcr);
1154 bfcr->buf.addr = NULL;
1155 bfcr->last_bo = CTF_BYTE_ORDER_UNKNOWN;
5cd6d0e5
PP
1156}
1157
4164020e 1158static void update_packet_offset(struct bt_bfcr *bfcr)
5cd6d0e5 1159{
0f5c5d5c
SM
1160 BT_CPPLOGT_SPEC(bfcr->logger,
1161 "Updating packet offset for next call: "
1162 "bfcr-addr={}, cur-packet-offset={}, next-packet-offset={}",
1163 fmt::ptr(bfcr), bfcr->buf.packet_offset,
1164 bfcr->buf.packet_offset + bfcr->buf.at);
4164020e 1165 bfcr->buf.packet_offset += bfcr->buf.at;
5cd6d0e5
PP
1166}
1167
4164020e
SM
1168size_t bt_bfcr_start(struct bt_bfcr *bfcr, struct ctf_field_class *cls, const uint8_t *buf,
1169 size_t offset, size_t packet_offset, size_t sz, enum bt_bfcr_status *status)
5cd6d0e5 1170{
4164020e
SM
1171 BT_ASSERT_DBG(bfcr);
1172 BT_ASSERT_DBG(BYTES_TO_BITS(sz) >= offset);
1173 reset(bfcr);
1174 bfcr->buf.addr = buf;
1175 bfcr->buf.offset = offset;
1176 bfcr->buf.at = 0;
1177 bfcr->buf.packet_offset = packet_offset;
1178 bfcr->buf.buf_sz = sz;
1179 bfcr->buf.sz = BYTES_TO_BITS(sz) - offset;
1180 *status = BT_BFCR_STATUS_OK;
1181
0f5c5d5c
SM
1182 BT_CPPLOGT_SPEC(bfcr->logger,
1183 "Starting decoding: bfcr-addr={}, fc-addr={}, "
1184 "buf-addr={}, buf-size={}, offset={}, "
1185 "packet-offset={}",
1186 fmt::ptr(bfcr), fmt::ptr(cls), fmt::ptr(buf), sz, offset, packet_offset);
4164020e
SM
1187
1188 /* Set root class */
1189 if (cls->is_compound) {
1190 /* Compound class: push on visit stack */
1191 int stack_ret;
1192
1193 if (bfcr->user.cbs.classes.compound_begin) {
0f5c5d5c 1194 BT_CPPLOGT_SPEC(bfcr->logger, "Calling user function (compound, begin).");
4164020e 1195 *status = bfcr->user.cbs.classes.compound_begin(cls, bfcr->user.data);
0f5c5d5c 1196 BT_CPPLOGT_SPEC(bfcr->logger, "User function returned: status={}", *status);
4164020e 1197 if (*status != BT_BFCR_STATUS_OK) {
0f5c5d5c
SM
1198 BT_CPPLOGW_SPEC(bfcr->logger, "User function failed: bfcr-addr={}, status={}",
1199 fmt::ptr(bfcr), *status);
4164020e
SM
1200 goto end;
1201 }
1202 }
1203
1204 stack_ret = stack_push_with_len(bfcr, cls);
1205 if (stack_ret) {
1206 /* stack_push_with_len() logs errors */
1207 *status = BT_BFCR_STATUS_ERROR;
1208 goto end;
1209 }
1210
1211 bfcr->state = BFCR_STATE_ALIGN_COMPOUND;
1212 } else {
1213 /* Basic class: set as current basic class */
1214 bfcr->cur_basic_field_class = cls;
1215 bfcr->state = BFCR_STATE_ALIGN_BASIC;
1216 }
1217
1218 /* Run the machine! */
e27adb90 1219 BT_CPPLOGT_SPEC(bfcr->logger, "Running the state machine.");
4164020e
SM
1220
1221 while (true) {
1222 *status = handle_state(bfcr);
1223 if (*status != BT_BFCR_STATUS_OK || bfcr->state == BFCR_STATE_DONE) {
1224 break;
1225 }
1226 }
1227
1228 /* Update packet offset for next time */
1229 update_packet_offset(bfcr);
5cd6d0e5
PP
1230
1231end:
4164020e 1232 return bfcr->buf.at;
5cd6d0e5
PP
1233}
1234
5cd6d0e5 1235size_t bt_bfcr_continue(struct bt_bfcr *bfcr, const uint8_t *buf, size_t sz,
4164020e 1236 enum bt_bfcr_status *status)
5cd6d0e5 1237{
4164020e
SM
1238 BT_ASSERT_DBG(bfcr);
1239 BT_ASSERT_DBG(buf);
1240 BT_ASSERT_DBG(sz > 0);
1241 bfcr->buf.addr = buf;
1242 bfcr->buf.offset = 0;
1243 bfcr->buf.at = 0;
1244 bfcr->buf.buf_sz = sz;
1245 bfcr->buf.sz = BYTES_TO_BITS(sz);
1246 *status = BT_BFCR_STATUS_OK;
1247
0f5c5d5c
SM
1248 BT_CPPLOGT_SPEC(bfcr->logger, "Continuing decoding: bfcr-addr={}, buf-addr={}, buf-size={}",
1249 fmt::ptr(bfcr), fmt::ptr(buf), sz);
4164020e
SM
1250
1251 /* Continue running the machine */
e27adb90 1252 BT_CPPLOGT_SPEC(bfcr->logger, "Running the state machine.");
4164020e
SM
1253
1254 while (true) {
1255 *status = handle_state(bfcr);
1256 if (*status != BT_BFCR_STATUS_OK || bfcr->state == BFCR_STATE_DONE) {
1257 break;
1258 }
1259 }
1260
1261 /* Update packet offset for next time */
1262 update_packet_offset(bfcr);
1263 return bfcr->buf.at;
5cd6d0e5
PP
1264}
1265
4164020e 1266void bt_bfcr_set_unsigned_int_cb(struct bt_bfcr *bfcr, bt_bfcr_unsigned_int_cb_func cb)
5cd6d0e5 1267{
4164020e
SM
1268 BT_ASSERT_DBG(bfcr);
1269 BT_ASSERT_DBG(cb);
1270 bfcr->user.cbs.classes.unsigned_int = cb;
5cd6d0e5 1271}
This page took 0.144083 seconds and 4 git commands to generate.