cpp-common/bt2c/fmt.hpp: use `wise_enum::string_type` in `EnableIfIsWiseEnum` definition
[babeltrace.git] / src / plugins / ctf / common / src / bfcr / bfcr.cpp
1 /*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation
5 * Copyright (c) 2015-2016 Philippe Proulx <pproulx@efficios.com>
6 *
7 * Babeltrace - CTF binary field class reader (BFCR)
8 */
9
10 #include "common/align.h"
11 #include "common/assert.h"
12 #include "common/common.h"
13 #include "compat/bitfield.h"
14 #include "cpp-common/bt2c/logging.hpp"
15 #include "cpp-common/vendor/fmt/format.h"
16
17 #include "../metadata/tsdl/ctf-meta.hpp"
18 #include "bfcr.hpp"
19
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)
25
26 /* A visit stack entry */
27 struct 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;
44 };
45
46 /* Visit stack */
47 struct stack
48 {
49 struct bt_bfcr *bfcr;
50
51 /* Entries (struct stack_entry) */
52 GArray *entries;
53
54 /* Number of active entries */
55 size_t size;
56 };
57
58 /* Reading states */
59 enum 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,
67 };
68
69 static 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
94 /* Binary class reader */
95 struct bt_bfcr
96 {
97 explicit bt_bfcr(const bt2c::Logger& parentLogger) : logger {parentLogger, "PLUGIN/CTF/BFCR"}
98 {
99 }
100
101 bt2c::Logger logger;
102
103 /* BFCR stack */
104 struct stack *stack = nullptr;
105
106 /* Current basic field class */
107 struct ctf_field_class *cur_basic_field_class = nullptr;
108
109 /* Current state */
110 enum bfcr_state state = static_cast<bfcr_state>(0);
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 */
122 enum ctf_byte_order last_bo = CTF_BYTE_ORDER_UNKNOWN;
123
124 /* Current byte order (copied to last_bo after a successful read) */
125 enum ctf_byte_order cur_bo = CTF_BYTE_ORDER_UNKNOWN;
126
127 /* Stitch buffer infos */
128 struct
129 {
130 /* Stitch buffer */
131 uint8_t buf[16] {};
132
133 /* Offset, within stitch buffer, of first bit */
134 size_t offset = 0;
135
136 /* Length (bits) of data in stitch buffer from offset */
137 size_t at = 0;
138 } stitch;
139
140 /* User buffer infos */
141 struct
142 {
143 /* Address */
144 const uint8_t *addr = nullptr;
145
146 /* Offset of data from address (bits) */
147 size_t offset = 0;
148
149 /* Current position from offset (bits) */
150 size_t at = 0;
151
152 /* Offset of offset within whole packet (bits) */
153 size_t packet_offset = 0;
154
155 /* Data size in buffer (bits) */
156 size_t sz = 0;
157
158 /* Buffer size (bytes) */
159 size_t buf_sz = 0;
160 } buf;
161
162 /* User stuff */
163 struct
164 {
165 /* Callback functions */
166 bt_bfcr_cbs cbs {};
167
168 /* Private data */
169 void *data = nullptr;
170 } user;
171 };
172
173 static struct stack *stack_new(struct bt_bfcr *bfcr)
174 {
175 struct stack *stack = NULL;
176
177 stack = g_new0(struct stack, 1);
178 if (!stack) {
179 BT_CPPLOGE_STR_SPEC(bfcr->logger, "Failed to allocate one stack.");
180 goto error;
181 }
182
183 stack->bfcr = bfcr;
184 stack->entries = g_array_new(FALSE, TRUE, sizeof(struct stack_entry));
185 if (!stack->entries) {
186 BT_CPPLOGE_STR_SPEC(bfcr->logger, "Failed to allocate a GArray.");
187 goto error;
188 }
189
190 BT_CPPLOGD_SPEC(bfcr->logger, "Created stack: addr={}", fmt::ptr(stack));
191 return stack;
192
193 error:
194 g_free(stack);
195 return NULL;
196 }
197
198 static void stack_destroy(struct stack *stack)
199 {
200 struct bt_bfcr *bfcr;
201
202 if (!stack) {
203 return;
204 }
205
206 bfcr = stack->bfcr;
207 BT_CPPLOGD_SPEC(bfcr->logger, "Destroying stack: addr={}", fmt::ptr(stack));
208
209 if (stack->entries) {
210 g_array_free(stack->entries, TRUE);
211 }
212
213 g_free(stack);
214 }
215
216 static int stack_push(struct stack *stack, struct ctf_field_class *base_class, size_t base_len)
217 {
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;
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);
230
231 if (stack->entries->len == stack->size) {
232 g_array_set_size(stack->entries, stack->size + 1);
233 }
234
235 entry = &bt_g_array_index(stack->entries, struct stack_entry, stack->size);
236 entry->base_class = base_class;
237 entry->base_len = base_len;
238 entry->index = 0;
239 stack->size++;
240 return 0;
241 }
242
243 static inline int64_t get_compound_field_class_length(struct bt_bfcr *bfcr,
244 struct ctf_field_class *fc)
245 {
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;
277 }
278
279 static int stack_push_with_len(struct bt_bfcr *bfcr, struct ctf_field_class *base_class)
280 {
281 int ret;
282 int64_t length = get_compound_field_class_length(bfcr, base_class);
283
284 if (length < 0) {
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);
289 ret = BT_BFCR_STATUS_ERROR;
290 goto end;
291 }
292
293 ret = stack_push(bfcr->stack, base_class, (size_t) length);
294
295 end:
296 return ret;
297 }
298
299 static inline unsigned int stack_size(struct stack *stack)
300 {
301 BT_ASSERT_DBG(stack);
302 return stack->size;
303 }
304
305 static void stack_pop(struct stack *stack)
306 {
307 struct bt_bfcr *bfcr;
308
309 BT_ASSERT_DBG(stack);
310 BT_ASSERT_DBG(stack_size(stack));
311 bfcr = stack->bfcr;
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);
316 stack->size--;
317 }
318
319 static inline bool stack_empty(struct stack *stack)
320 {
321 return stack_size(stack) == 0;
322 }
323
324 static void stack_clear(struct stack *stack)
325 {
326 BT_ASSERT_DBG(stack);
327 stack->size = 0;
328 }
329
330 static inline struct stack_entry *stack_top(struct stack *stack)
331 {
332 BT_ASSERT_DBG(stack);
333 BT_ASSERT_DBG(stack_size(stack));
334 return &bt_g_array_index(stack->entries, struct stack_entry, stack->size - 1);
335 }
336
337 static inline size_t available_bits(struct bt_bfcr *bfcr)
338 {
339 return bfcr->buf.sz - bfcr->buf.at;
340 }
341
342 static inline void consume_bits(struct bt_bfcr *bfcr, size_t incr)
343 {
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);
346 bfcr->buf.at += incr;
347 }
348
349 static inline bool has_enough_bits(struct bt_bfcr *bfcr, size_t sz)
350 {
351 return available_bits(bfcr) >= sz;
352 }
353
354 static inline bool at_least_one_bit_left(struct bt_bfcr *bfcr)
355 {
356 return has_enough_bits(bfcr, 1);
357 }
358
359 static inline size_t packet_at(struct bt_bfcr *bfcr)
360 {
361 return bfcr->buf.packet_offset + bfcr->buf.at;
362 }
363
364 static inline size_t buf_at_from_addr(struct bt_bfcr *bfcr)
365 {
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;
380 }
381
382 static void stitch_reset(struct bt_bfcr *bfcr)
383 {
384 bfcr->stitch.offset = 0;
385 bfcr->stitch.at = 0;
386 }
387
388 static inline size_t stitch_at_from_addr(struct bt_bfcr *bfcr)
389 {
390 return bfcr->stitch.offset + bfcr->stitch.at;
391 }
392
393 static void stitch_append_from_buf(struct bt_bfcr *bfcr, size_t sz)
394 {
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);
411 }
412
413 static void stitch_append_from_remaining_buf(struct bt_bfcr *bfcr)
414 {
415 stitch_append_from_buf(bfcr, available_bits(bfcr));
416 }
417
418 static void stitch_set_from_remaining_buf(struct bt_bfcr *bfcr)
419 {
420 stitch_reset(bfcr);
421 bfcr->stitch.offset = IN_BYTE_OFFSET(buf_at_from_addr(bfcr));
422 stitch_append_from_remaining_buf(bfcr);
423 }
424
425 static 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)
428 {
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
440 BT_CPPLOGT_SPEC(bfcr->logger, "Read unsigned bit array: cur={}, size={}, bo={}, val={}", at,
441 field_size, (int) bo, *v);
442 }
443
444 static 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)
446 {
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
458 BT_CPPLOGT_SPEC(bfcr->logger, "Read signed bit array: cur={}, size={}, bo={}, val={}", at,
459 field_size, (int) bo, *v);
460 }
461
462 typedef enum bt_bfcr_status (*read_basic_and_call_cb_t)(struct bt_bfcr *, const uint8_t *, size_t);
463
464 static inline enum bt_bfcr_status validate_contiguous_bo(struct bt_bfcr *bfcr,
465 enum ctf_byte_order next_bo)
466 {
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 }
499
500 end:
501 if (status < 0) {
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);
506 }
507
508 return status;
509 }
510
511 static enum bt_bfcr_status read_basic_float_and_call_cb(struct bt_bfcr *bfcr, const uint8_t *buf,
512 size_t at)
513 {
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
557 BT_CPPLOGT_SPEC(bfcr->logger, "Read floating point number value: bfcr={}, cur={}, val={}",
558 fmt::ptr(bfcr), at, dblval);
559
560 if (bfcr->user.cbs.classes.floating_point) {
561 BT_CPPLOGT_SPEC(bfcr->logger, "Calling user function (floating point number).");
562 status = bfcr->user.cbs.classes.floating_point(dblval, bfcr->cur_basic_field_class,
563 bfcr->user.data);
564 BT_CPPLOGT_SPEC(bfcr->logger, "User function returned: status={}", status);
565 if (status != BT_BFCR_STATUS_OK) {
566 BT_CPPLOGW_SPEC(bfcr->logger, "User function failed: bfcr-addr={}, status={}",
567 fmt::ptr(bfcr), status);
568 }
569 }
570
571 return status;
572 }
573
574 static inline enum bt_bfcr_status read_basic_int_and_call_cb(struct bt_bfcr *bfcr,
575 const uint8_t *buf, size_t at)
576 {
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) {
598 BT_CPPLOGT_SPEC(bfcr->logger, "Calling user function (signed integer).");
599 status =
600 bfcr->user.cbs.classes.signed_int(v, bfcr->cur_basic_field_class, bfcr->user.data);
601 BT_CPPLOGT_SPEC(bfcr->logger, "User function returned: status={}", status);
602 if (status != BT_BFCR_STATUS_OK) {
603 BT_CPPLOGW_SPEC(bfcr->logger,
604 "User function failed: "
605 "bfcr-addr={}, status={}",
606 fmt::ptr(bfcr), status);
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) {
615 BT_CPPLOGT_SPEC(bfcr->logger, "Calling user function (unsigned integer).");
616 status = bfcr->user.cbs.classes.unsigned_int(v, bfcr->cur_basic_field_class,
617 bfcr->user.data);
618 BT_CPPLOGT_SPEC(bfcr->logger, "User function returned: status={}", status);
619 if (status != BT_BFCR_STATUS_OK) {
620 BT_CPPLOGW_SPEC(bfcr->logger,
621 "User function failed: "
622 "bfcr-addr={}, status={}",
623 fmt::ptr(bfcr), status);
624 }
625 }
626 }
627
628 return status;
629 }
630
631 static inline enum bt_bfcr_status
632 read_bit_array_class_and_call_continue(struct bt_bfcr *bfcr,
633 read_basic_and_call_cb_t read_basic_and_call_cb)
634 {
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)) {
641 BT_CPPLOGT_SPEC(bfcr->logger, "Reached end of data: bfcr-addr={}", fmt::ptr(bfcr));
642 status = BT_BFCR_STATUS_EOF;
643 goto end;
644 }
645
646 available = available_bits(bfcr);
647 needed_bits = fc->size - bfcr->stitch.at;
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);
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) {
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);
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 */
678 BT_CPPLOGT_STR_SPEC(
679 bfcr->logger, "Not enough data to read the next basic field: appending to stitch buffer.");
680 stitch_append_from_remaining_buf(bfcr);
681 status = BT_BFCR_STATUS_EOF;
682
683 end:
684 return status;
685 }
686
687 static inline enum bt_bfcr_status
688 read_bit_array_class_and_call_begin(struct bt_bfcr *bfcr,
689 read_basic_and_call_cb_t read_basic_and_call_cb)
690 {
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)) {
696 BT_CPPLOGT_SPEC(bfcr->logger, "Reached end of data: bfcr-addr={}", fmt::ptr(bfcr));
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) {
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);
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 */
737 BT_CPPLOGT_STR_SPEC(bfcr->logger,
738 "Not enough data to read the next basic field: setting stitch buffer.");
739 stitch_set_from_remaining_buf(bfcr);
740 bfcr->state = BFCR_STATE_READ_BASIC_CONTINUE;
741 status = BT_BFCR_STATUS_EOF;
742
743 end:
744 return status;
745 }
746
747 static inline enum bt_bfcr_status read_basic_int_class_and_call_begin(struct bt_bfcr *bfcr)
748 {
749 return read_bit_array_class_and_call_begin(bfcr, read_basic_int_and_call_cb);
750 }
751
752 static inline enum bt_bfcr_status read_basic_int_class_and_call_continue(struct bt_bfcr *bfcr)
753 {
754 return read_bit_array_class_and_call_continue(bfcr, read_basic_int_and_call_cb);
755 }
756
757 static inline enum bt_bfcr_status read_basic_float_class_and_call_begin(struct bt_bfcr *bfcr)
758 {
759 return read_bit_array_class_and_call_begin(bfcr, read_basic_float_and_call_cb);
760 }
761
762 static inline enum bt_bfcr_status read_basic_float_class_and_call_continue(struct bt_bfcr *bfcr)
763 {
764 return read_bit_array_class_and_call_continue(bfcr, read_basic_float_and_call_cb);
765 }
766
767 static inline enum bt_bfcr_status read_basic_string_class_and_call(struct bt_bfcr *bfcr, bool begin)
768 {
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)) {
776 BT_CPPLOGT_SPEC(bfcr->logger, "Reached end of data: bfcr-addr={}", fmt::ptr(bfcr));
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) {
789 BT_CPPLOGT_SPEC(bfcr->logger, "Calling user function (string, beginning).");
790 status = bfcr->user.cbs.classes.string_begin(bfcr->cur_basic_field_class, bfcr->user.data);
791 BT_CPPLOGT_SPEC(bfcr->logger, "User function returned: status={}", status);
792 if (status != BT_BFCR_STATUS_OK) {
793 BT_CPPLOGW_SPEC(bfcr->logger, "User function failed: bfcr-addr={}, status={}",
794 fmt::ptr(bfcr), status);
795 goto end;
796 }
797 }
798
799 if (!result) {
800 /* No null character yet */
801 if (bfcr->user.cbs.classes.string) {
802 BT_CPPLOGT_SPEC(bfcr->logger, "Calling user function (substring).");
803 status = bfcr->user.cbs.classes.string((const char *) first_chr, available_bytes,
804 bfcr->cur_basic_field_class, bfcr->user.data);
805 BT_CPPLOGT_SPEC(bfcr->logger, "User function returned: status={}", status);
806 if (status != BT_BFCR_STATUS_OK) {
807 BT_CPPLOGW_SPEC(bfcr->logger,
808 "User function failed: "
809 "bfcr-addr={}, status={}",
810 fmt::ptr(bfcr), status);
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) {
823 BT_CPPLOGT_SPEC(bfcr->logger, "Calling user function (substring).");
824 status = bfcr->user.cbs.classes.string((const char *) first_chr, result_len,
825 bfcr->cur_basic_field_class, bfcr->user.data);
826 BT_CPPLOGT_SPEC(bfcr->logger, "User function returned: status={}", status);
827 if (status != BT_BFCR_STATUS_OK) {
828 BT_CPPLOGW_SPEC(bfcr->logger,
829 "User function failed: "
830 "bfcr-addr={}, status={}",
831 fmt::ptr(bfcr), status);
832 goto end;
833 }
834 }
835
836 if (bfcr->user.cbs.classes.string_end) {
837 BT_CPPLOGT_SPEC(bfcr->logger, "Calling user function (string, end).");
838 status =
839 bfcr->user.cbs.classes.string_end(bfcr->cur_basic_field_class, bfcr->user.data);
840 BT_CPPLOGT_SPEC(bfcr->logger, "User function returned: status={}", status);
841 if (status != BT_BFCR_STATUS_OK) {
842 BT_CPPLOGW_SPEC(bfcr->logger,
843 "User function failed: "
844 "bfcr-addr={}, status={}",
845 fmt::ptr(bfcr), status);
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 }
862
863 end:
864 return status;
865 }
866
867 static inline enum bt_bfcr_status read_basic_begin_state(struct bt_bfcr *bfcr)
868 {
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;
889 }
890
891 static inline enum bt_bfcr_status read_basic_continue_state(struct bt_bfcr *bfcr)
892 {
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;
913 }
914
915 static inline size_t bits_to_skip_to_align_to(struct bt_bfcr *bfcr, size_t align)
916 {
917 size_t aligned_packet_at;
918
919 aligned_packet_at = BT_ALIGN(packet_at(bfcr), align);
920 return aligned_packet_at - packet_at(bfcr);
921 }
922
923 static 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)
926 {
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 */
966 BT_CPPLOGT_SPEC(bfcr->logger, "Reached end of data when aligning: bfcr-addr={}",
967 fmt::ptr(bfcr));
968 status = BT_BFCR_STATUS_EOF;
969 }
970
971 end:
972 return status;
973 }
974
975 static inline enum bt_bfcr_status next_field_state(struct bt_bfcr *bfcr)
976 {
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) {
991 BT_CPPLOGT_SPEC(bfcr->logger, "Calling user function (compound, end).");
992 status = bfcr->user.cbs.classes.compound_end(top->base_class, bfcr->user.data);
993 BT_CPPLOGT_SPEC(bfcr->logger, "User function returned: status={}", status);
994 if (status != BT_BFCR_STATUS_OK) {
995 BT_CPPLOGW_SPEC(bfcr->logger, "User function failed: bfcr-addr={}, status={}",
996 fmt::ptr(bfcr), status);
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) {
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);
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) {
1049 BT_CPPLOGT_SPEC(bfcr->logger, "Calling user function (compound, begin).");
1050 status = bfcr->user.cbs.classes.compound_begin(next_field_class, bfcr->user.data);
1051 BT_CPPLOGT_SPEC(bfcr->logger, "User function returned: status={}", status);
1052 if (status != BT_BFCR_STATUS_OK) {
1053 BT_CPPLOGW_SPEC(bfcr->logger, "User function failed: bfcr-addr={}, status={}",
1054 fmt::ptr(bfcr), status);
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 */
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));
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 }
1081
1082 end:
1083 return status;
1084 }
1085
1086 static inline enum bt_bfcr_status handle_state(struct bt_bfcr *bfcr)
1087 {
1088 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
1089
1090 BT_CPPLOGT_SPEC(bfcr->logger, "Handling state: bfcr-addr={}, state={}", fmt::ptr(bfcr),
1091 bfcr->state);
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
1113 BT_CPPLOGT_SPEC(bfcr->logger, "Handled state: bfcr-addr={}, status={}", fmt::ptr(bfcr), status);
1114 return status;
1115 }
1116
1117 struct bt_bfcr *bt_bfcr_create(struct bt_bfcr_cbs cbs, void *data, const bt2c::Logger& logger)
1118 {
1119 BT_CPPLOGD_STR_SPEC(logger, "Creating binary field class reader (BFCR).");
1120
1121 bt_bfcr *bfcr = new bt_bfcr {logger};
1122 bfcr->stack = stack_new(bfcr);
1123 if (!bfcr->stack) {
1124 BT_CPPLOGE_STR_SPEC(bfcr->logger, "Cannot create BFCR's stack.");
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;
1133 BT_CPPLOGD_SPEC(bfcr->logger, "Created BFCR: addr={}", fmt::ptr(bfcr));
1134
1135 end:
1136 return bfcr;
1137 }
1138
1139 void bt_bfcr_destroy(struct bt_bfcr *bfcr)
1140 {
1141 if (bfcr->stack) {
1142 stack_destroy(bfcr->stack);
1143 }
1144
1145 BT_CPPLOGD_SPEC(bfcr->logger, "Destroying BFCR: addr={}", fmt::ptr(bfcr));
1146 delete bfcr;
1147 }
1148
1149 static void reset(struct bt_bfcr *bfcr)
1150 {
1151 BT_CPPLOGD_SPEC(bfcr->logger, "Resetting BFCR: addr={}", fmt::ptr(bfcr));
1152 stack_clear(bfcr->stack);
1153 stitch_reset(bfcr);
1154 bfcr->buf.addr = NULL;
1155 bfcr->last_bo = CTF_BYTE_ORDER_UNKNOWN;
1156 }
1157
1158 static void update_packet_offset(struct bt_bfcr *bfcr)
1159 {
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);
1165 bfcr->buf.packet_offset += bfcr->buf.at;
1166 }
1167
1168 size_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)
1170 {
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
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);
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) {
1194 BT_CPPLOGT_SPEC(bfcr->logger, "Calling user function (compound, begin).");
1195 *status = bfcr->user.cbs.classes.compound_begin(cls, bfcr->user.data);
1196 BT_CPPLOGT_SPEC(bfcr->logger, "User function returned: status={}", *status);
1197 if (*status != BT_BFCR_STATUS_OK) {
1198 BT_CPPLOGW_SPEC(bfcr->logger, "User function failed: bfcr-addr={}, status={}",
1199 fmt::ptr(bfcr), *status);
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! */
1219 BT_CPPLOGT_STR_SPEC(bfcr->logger, "Running the state machine.");
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);
1230
1231 end:
1232 return bfcr->buf.at;
1233 }
1234
1235 size_t bt_bfcr_continue(struct bt_bfcr *bfcr, const uint8_t *buf, size_t sz,
1236 enum bt_bfcr_status *status)
1237 {
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
1248 BT_CPPLOGT_SPEC(bfcr->logger, "Continuing decoding: bfcr-addr={}, buf-addr={}, buf-size={}",
1249 fmt::ptr(bfcr), fmt::ptr(buf), sz);
1250
1251 /* Continue running the machine */
1252 BT_CPPLOGT_STR_SPEC(bfcr->logger, "Running the state machine.");
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;
1264 }
1265
1266 void bt_bfcr_set_unsigned_int_cb(struct bt_bfcr *bfcr, bt_bfcr_unsigned_int_cb_func cb)
1267 {
1268 BT_ASSERT_DBG(bfcr);
1269 BT_ASSERT_DBG(cb);
1270 bfcr->user.cbs.classes.unsigned_int = cb;
1271 }
This page took 0.112078 seconds and 4 git commands to generate.