2 * SPDX-License-Identifier: MIT
4 * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation
5 * Copyright (c) 2015-2016 Philippe Proulx <pproulx@efficios.com>
7 * Babeltrace - CTF binary field class reader (BFCR)
19 #include <babeltrace2/babeltrace.h>
21 #define BT_COMP_LOG_SELF_COMP (bfcr->self_comp)
22 #define BT_LOG_OUTPUT_LEVEL (bfcr->log_level)
23 #define BT_LOG_TAG "PLUGIN/CTF/BFCR"
24 #include "logging/comp-logging.h"
26 #include "common/align.h"
27 #include "common/assert.h"
28 #include "common/common.h"
29 #include "compat/bitfield.h"
31 #include "../metadata/ctf-meta.hpp"
34 #define DIV8(_x) ((_x) >> 3)
35 #define BYTES_TO_BITS(_x) ((_x) *8)
36 #define BITS_TO_BYTES_FLOOR(_x) DIV8(_x)
37 #define BITS_TO_BYTES_CEIL(_x) DIV8((_x) + 7)
38 #define IN_BYTE_OFFSET(_at) ((_at) &7)
40 /* A visit stack entry */
44 * Current class of base field, one of:
51 struct ctf_field_class
*base_class
;
53 /* Length of base field (always 1 for a variant class) */
56 /* Index of next field to read */
67 /* Entries (struct stack_entry) */
70 /* Number of active entries */
77 BFCR_STATE_NEXT_FIELD
,
78 BFCR_STATE_ALIGN_BASIC
,
79 BFCR_STATE_ALIGN_COMPOUND
,
80 BFCR_STATE_READ_BASIC_BEGIN
,
81 BFCR_STATE_READ_BASIC_CONTINUE
,
85 /* Binary class reader */
88 bt_logging_level log_level
;
91 bt_self_component
*self_comp
;
96 /* Current basic field class */
97 struct ctf_field_class
*cur_basic_field_class
;
100 enum bfcr_state state
;
103 * Last basic field class's byte order.
105 * This is used to detect errors since two contiguous basic
106 * classes for which the common boundary is not the boundary of
107 * a byte cannot have different byte orders.
109 * This is set to CTF_BYTE_ORDER_UNKNOWN on reset and when the last
110 * basic field class was a string class.
112 enum ctf_byte_order last_bo
;
114 /* Current byte order (copied to last_bo after a successful read) */
115 enum ctf_byte_order cur_bo
;
117 /* Stitch buffer infos */
123 /* Offset, within stitch buffer, of first bit */
126 /* Length (bits) of data in stitch buffer from offset */
130 /* User buffer infos */
136 /* Offset of data from address (bits) */
139 /* Current position from offset (bits) */
142 /* Offset of offset within whole packet (bits) */
143 size_t packet_offset
;
145 /* Data size in buffer (bits) */
148 /* Buffer size (bytes) */
155 /* Callback functions */
156 struct bt_bfcr_cbs cbs
;
163 static inline const char *bfcr_state_string(enum bfcr_state state
)
166 case BFCR_STATE_NEXT_FIELD
:
168 case BFCR_STATE_ALIGN_BASIC
:
169 return "ALIGN_BASIC";
170 case BFCR_STATE_ALIGN_COMPOUND
:
171 return "ALIGN_COMPOUND";
172 case BFCR_STATE_READ_BASIC_BEGIN
:
173 return "READ_BASIC_BEGIN";
174 case BFCR_STATE_READ_BASIC_CONTINUE
:
175 return "READ_BASIC_CONTINUE";
176 case BFCR_STATE_DONE
:
183 static struct stack
*stack_new(struct bt_bfcr
*bfcr
)
185 struct stack
*stack
= NULL
;
187 stack
= g_new0(struct stack
, 1);
189 BT_COMP_LOGE_STR("Failed to allocate one stack.");
194 stack
->entries
= g_array_new(FALSE
, TRUE
, sizeof(struct stack_entry
));
195 if (!stack
->entries
) {
196 BT_COMP_LOGE_STR("Failed to allocate a GArray.");
200 BT_COMP_LOGD("Created stack: addr=%p", stack
);
208 static void stack_destroy(struct stack
*stack
)
210 struct bt_bfcr
*bfcr
;
217 BT_COMP_LOGD("Destroying stack: addr=%p", stack
);
219 if (stack
->entries
) {
220 g_array_free(stack
->entries
, TRUE
);
226 static int stack_push(struct stack
*stack
, struct ctf_field_class
*base_class
, size_t base_len
)
228 struct stack_entry
*entry
;
229 struct bt_bfcr
*bfcr
;
231 BT_ASSERT_DBG(stack
);
232 BT_ASSERT_DBG(base_class
);
234 BT_COMP_LOGT("Pushing field class on stack: stack-addr=%p, "
235 "fc-addr=%p, fc-type=%d, base-length=%zu, "
236 "stack-size-before=%zu, stack-size-after=%zu",
237 stack
, base_class
, base_class
->type
, base_len
, stack
->size
, stack
->size
+ 1);
239 if (stack
->entries
->len
== stack
->size
) {
240 g_array_set_size(stack
->entries
, stack
->size
+ 1);
243 entry
= &bt_g_array_index(stack
->entries
, struct stack_entry
, stack
->size
);
244 entry
->base_class
= base_class
;
245 entry
->base_len
= base_len
;
251 static inline int64_t get_compound_field_class_length(struct bt_bfcr
*bfcr
,
252 struct ctf_field_class
*fc
)
257 case CTF_FIELD_CLASS_TYPE_STRUCT
:
259 ctf_field_class_struct
*struct_fc
= ctf_field_class_as_struct(fc
);
261 length
= (int64_t) struct_fc
->members
->len
;
264 case CTF_FIELD_CLASS_TYPE_VARIANT
:
266 /* Variant field classes always "contain" a single class */
270 case CTF_FIELD_CLASS_TYPE_ARRAY
:
272 struct ctf_field_class_array
*array_fc
= ctf_field_class_as_array(fc
);
274 length
= (int64_t) array_fc
->length
;
277 case CTF_FIELD_CLASS_TYPE_SEQUENCE
:
278 length
= bfcr
->user
.cbs
.query
.get_sequence_length(fc
, bfcr
->user
.data
);
287 static int stack_push_with_len(struct bt_bfcr
*bfcr
, struct ctf_field_class
*base_class
)
290 int64_t length
= get_compound_field_class_length(bfcr
, base_class
);
293 BT_COMP_LOGW("Cannot get compound field class's field count: "
294 "bfcr-addr=%p, fc-addr=%p, fc-type=%d",
295 bfcr
, base_class
, base_class
->type
);
296 ret
= BT_BFCR_STATUS_ERROR
;
300 ret
= stack_push(bfcr
->stack
, base_class
, (size_t) length
);
306 static inline unsigned int stack_size(struct stack
*stack
)
308 BT_ASSERT_DBG(stack
);
312 static void stack_pop(struct stack
*stack
)
314 struct bt_bfcr
*bfcr
;
316 BT_ASSERT_DBG(stack
);
317 BT_ASSERT_DBG(stack_size(stack
));
319 BT_COMP_LOGT("Popping from stack: "
320 "stack-addr=%p, stack-size-before=%u, stack-size-after=%u",
321 stack
, stack
->entries
->len
, stack
->entries
->len
- 1);
325 static inline bool stack_empty(struct stack
*stack
)
327 return stack_size(stack
) == 0;
330 static void stack_clear(struct stack
*stack
)
332 BT_ASSERT_DBG(stack
);
336 static inline struct stack_entry
*stack_top(struct stack
*stack
)
338 BT_ASSERT_DBG(stack
);
339 BT_ASSERT_DBG(stack_size(stack
));
340 return &bt_g_array_index(stack
->entries
, struct stack_entry
, stack
->size
- 1);
343 static inline size_t available_bits(struct bt_bfcr
*bfcr
)
345 return bfcr
->buf
.sz
- bfcr
->buf
.at
;
348 static inline void consume_bits(struct bt_bfcr
*bfcr
, size_t incr
)
350 BT_COMP_LOGT("Advancing cursor: bfcr-addr=%p, cur-before=%zu, cur-after=%zu", bfcr
,
351 bfcr
->buf
.at
, bfcr
->buf
.at
+ incr
);
352 bfcr
->buf
.at
+= incr
;
355 static inline bool has_enough_bits(struct bt_bfcr
*bfcr
, size_t sz
)
357 return available_bits(bfcr
) >= sz
;
360 static inline bool at_least_one_bit_left(struct bt_bfcr
*bfcr
)
362 return has_enough_bits(bfcr
, 1);
365 static inline size_t packet_at(struct bt_bfcr
*bfcr
)
367 return bfcr
->buf
.packet_offset
+ bfcr
->buf
.at
;
370 static inline size_t buf_at_from_addr(struct bt_bfcr
*bfcr
)
375 * ====== offset ===== (17)
377 * xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
379 * addr (0) ==== at ==== (12)
383 * =============================== (29)
385 return bfcr
->buf
.offset
+ bfcr
->buf
.at
;
388 static void stitch_reset(struct bt_bfcr
*bfcr
)
390 bfcr
->stitch
.offset
= 0;
394 static inline size_t stitch_at_from_addr(struct bt_bfcr
*bfcr
)
396 return bfcr
->stitch
.offset
+ bfcr
->stitch
.at
;
399 static void stitch_append_from_buf(struct bt_bfcr
*bfcr
, size_t sz
)
401 size_t stitch_byte_at
;
409 stitch_byte_at
= BITS_TO_BYTES_FLOOR(stitch_at_from_addr(bfcr
));
410 buf_byte_at
= BITS_TO_BYTES_FLOOR(buf_at_from_addr(bfcr
));
411 nb_bytes
= BITS_TO_BYTES_CEIL(sz
);
412 BT_ASSERT(nb_bytes
> 0);
413 BT_ASSERT(bfcr
->buf
.addr
);
414 memcpy(&bfcr
->stitch
.buf
[stitch_byte_at
], &bfcr
->buf
.addr
[buf_byte_at
], nb_bytes
);
415 bfcr
->stitch
.at
+= sz
;
416 consume_bits(bfcr
, sz
);
419 static void stitch_append_from_remaining_buf(struct bt_bfcr
*bfcr
)
421 stitch_append_from_buf(bfcr
, available_bits(bfcr
));
424 static void stitch_set_from_remaining_buf(struct bt_bfcr
*bfcr
)
427 bfcr
->stitch
.offset
= IN_BYTE_OFFSET(buf_at_from_addr(bfcr
));
428 stitch_append_from_remaining_buf(bfcr
);
431 static inline void read_unsigned_bitfield(struct bt_bfcr
*bfcr
, const uint8_t *buf
, size_t at
,
432 unsigned int field_size
, enum ctf_byte_order bo
,
436 case CTF_BYTE_ORDER_BIG
:
437 bt_bitfield_read_be(buf
, uint8_t, at
, field_size
, v
);
439 case CTF_BYTE_ORDER_LITTLE
:
440 bt_bitfield_read_le(buf
, uint8_t, at
, field_size
, v
);
446 BT_COMP_LOGT("Read unsigned bit array: cur=%zu, size=%u, "
447 "bo=%d, val=%" PRIu64
,
448 at
, field_size
, bo
, *v
);
451 static inline void read_signed_bitfield(struct bt_bfcr
*bfcr
, const uint8_t *buf
, size_t at
,
452 unsigned int field_size
, enum ctf_byte_order bo
, int64_t *v
)
455 case CTF_BYTE_ORDER_BIG
:
456 bt_bitfield_read_be(buf
, uint8_t, at
, field_size
, v
);
458 case CTF_BYTE_ORDER_LITTLE
:
459 bt_bitfield_read_le(buf
, uint8_t, at
, field_size
, v
);
465 BT_COMP_LOGT("Read signed bit array: cur=%zu, size=%u, "
466 "bo=%d, val=%" PRId64
,
467 at
, field_size
, bo
, *v
);
470 typedef enum bt_bfcr_status (*read_basic_and_call_cb_t
)(struct bt_bfcr
*, const uint8_t *, size_t);
472 static inline enum bt_bfcr_status
validate_contiguous_bo(struct bt_bfcr
*bfcr
,
473 enum ctf_byte_order next_bo
)
475 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
477 /* Always valid when at a byte boundary */
478 if (packet_at(bfcr
) % 8 == 0) {
482 /* Always valid if last byte order is unknown */
483 if (bfcr
->last_bo
== CTF_BYTE_ORDER_UNKNOWN
) {
487 /* Always valid if next byte order is unknown */
488 if (next_bo
== CTF_BYTE_ORDER_UNKNOWN
) {
492 /* Make sure last byte order is compatible with the next byte order */
493 switch (bfcr
->last_bo
) {
494 case CTF_BYTE_ORDER_BIG
:
495 if (next_bo
!= CTF_BYTE_ORDER_BIG
) {
496 status
= BT_BFCR_STATUS_ERROR
;
499 case CTF_BYTE_ORDER_LITTLE
:
500 if (next_bo
!= CTF_BYTE_ORDER_LITTLE
) {
501 status
= BT_BFCR_STATUS_ERROR
;
505 status
= BT_BFCR_STATUS_ERROR
;
510 BT_COMP_LOGW("Cannot read bit array: two different byte orders not at a byte boundary: "
511 "bfcr-addr=%p, last-bo=%d, next-bo=%d",
512 bfcr
, bfcr
->last_bo
, next_bo
);
518 static enum bt_bfcr_status
read_basic_float_and_call_cb(struct bt_bfcr
*bfcr
, const uint8_t *buf
,
522 unsigned int field_size
;
523 enum ctf_byte_order bo
;
524 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
525 ctf_field_class_float
*fc
= ctf_field_class_as_float(bfcr
->cur_basic_field_class
);
528 field_size
= fc
->base
.size
;
529 bo
= fc
->base
.byte_order
;
532 switch (field_size
) {
542 read_unsigned_bitfield(bfcr
, buf
, at
, field_size
, bo
, &v
);
543 f32
.u
= (uint32_t) v
;
544 dblval
= (double) f32
.f
;
555 read_unsigned_bitfield(bfcr
, buf
, at
, field_size
, bo
, &f64
.u
);
560 /* Only 32-bit and 64-bit fields are supported currently */
564 BT_COMP_LOGT("Read floating point number value: bfcr=%p, cur=%zu, val=%f", bfcr
, at
, dblval
);
566 if (bfcr
->user
.cbs
.classes
.floating_point
) {
567 BT_COMP_LOGT("Calling user function (floating point number).");
568 status
= bfcr
->user
.cbs
.classes
.floating_point(dblval
, bfcr
->cur_basic_field_class
,
570 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
571 if (status
!= BT_BFCR_STATUS_OK
) {
572 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s", bfcr
,
573 bt_bfcr_status_string(status
));
580 static inline enum bt_bfcr_status
read_basic_int_and_call_cb(struct bt_bfcr
*bfcr
,
581 const uint8_t *buf
, size_t at
)
583 unsigned int field_size
;
584 enum ctf_byte_order bo
;
585 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
586 ctf_field_class_int
*fc
= ctf_field_class_as_int(bfcr
->cur_basic_field_class
);
588 field_size
= fc
->base
.size
;
589 bo
= fc
->base
.byte_order
;
592 * Update current byte order now because we could be reading
593 * the integer value of an enumeration class, and thus we know
594 * here the actual supporting integer class's byte order.
601 read_signed_bitfield(bfcr
, buf
, at
, field_size
, bo
, &v
);
603 if (bfcr
->user
.cbs
.classes
.signed_int
) {
604 BT_COMP_LOGT("Calling user function (signed integer).");
606 bfcr
->user
.cbs
.classes
.signed_int(v
, bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
607 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
608 if (status
!= BT_BFCR_STATUS_OK
) {
609 BT_COMP_LOGW("User function failed: "
610 "bfcr-addr=%p, status=%s",
611 bfcr
, bt_bfcr_status_string(status
));
617 read_unsigned_bitfield(bfcr
, buf
, at
, field_size
, bo
, &v
);
619 if (bfcr
->user
.cbs
.classes
.unsigned_int
) {
620 BT_COMP_LOGT("Calling user function (unsigned integer).");
621 status
= bfcr
->user
.cbs
.classes
.unsigned_int(v
, bfcr
->cur_basic_field_class
,
623 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
624 if (status
!= BT_BFCR_STATUS_OK
) {
625 BT_COMP_LOGW("User function failed: "
626 "bfcr-addr=%p, status=%s",
627 bfcr
, bt_bfcr_status_string(status
));
635 static inline enum bt_bfcr_status
636 read_bit_array_class_and_call_continue(struct bt_bfcr
*bfcr
,
637 read_basic_and_call_cb_t read_basic_and_call_cb
)
641 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
642 ctf_field_class_bit_array
*fc
= ctf_field_class_as_bit_array(bfcr
->cur_basic_field_class
);
644 if (!at_least_one_bit_left(bfcr
)) {
645 BT_COMP_LOGT("Reached end of data: bfcr-addr=%p", bfcr
);
646 status
= BT_BFCR_STATUS_EOF
;
650 available
= available_bits(bfcr
);
651 needed_bits
= fc
->size
- bfcr
->stitch
.at
;
652 BT_COMP_LOGT("Continuing basic field decoding: "
653 "bfcr-addr=%p, field-size=%u, needed-size=%zu, "
654 "available-size=%zu",
655 bfcr
, fc
->size
, needed_bits
, available
);
656 if (needed_bits
<= available
) {
657 /* We have all the bits; append to stitch, then decode */
658 stitch_append_from_buf(bfcr
, needed_bits
);
659 status
= read_basic_and_call_cb(bfcr
, bfcr
->stitch
.buf
, bfcr
->stitch
.offset
);
660 if (status
!= BT_BFCR_STATUS_OK
) {
661 BT_COMP_LOGW("Cannot read basic field: "
662 "bfcr-addr=%p, fc-addr=%p, status=%s",
663 bfcr
, bfcr
->cur_basic_field_class
, bt_bfcr_status_string(status
));
667 if (stack_empty(bfcr
->stack
)) {
668 /* Root is a basic class */
669 bfcr
->state
= BFCR_STATE_DONE
;
671 /* Go to next field */
672 stack_top(bfcr
->stack
)->index
++;
673 bfcr
->state
= BFCR_STATE_NEXT_FIELD
;
674 bfcr
->last_bo
= bfcr
->cur_bo
;
679 /* We are here; it means we don't have enough data to decode this */
680 BT_COMP_LOGT_STR("Not enough data to read the next basic field: appending to stitch buffer.");
681 stitch_append_from_remaining_buf(bfcr
);
682 status
= BT_BFCR_STATUS_EOF
;
688 static inline enum bt_bfcr_status
689 read_bit_array_class_and_call_begin(struct bt_bfcr
*bfcr
,
690 read_basic_and_call_cb_t read_basic_and_call_cb
)
693 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
694 ctf_field_class_bit_array
*fc
= ctf_field_class_as_bit_array(bfcr
->cur_basic_field_class
);
696 if (!at_least_one_bit_left(bfcr
)) {
697 BT_COMP_LOGT("Reached end of data: bfcr-addr=%p", bfcr
);
698 status
= BT_BFCR_STATUS_EOF
;
702 status
= validate_contiguous_bo(bfcr
, fc
->byte_order
);
703 if (status
!= BT_BFCR_STATUS_OK
) {
704 /* validate_contiguous_bo() logs errors */
708 available
= available_bits(bfcr
);
710 if (fc
->size
<= available
) {
711 /* We have all the bits; decode and set now */
712 BT_ASSERT_DBG(bfcr
->buf
.addr
);
713 status
= read_basic_and_call_cb(bfcr
, bfcr
->buf
.addr
, buf_at_from_addr(bfcr
));
714 if (status
!= BT_BFCR_STATUS_OK
) {
715 BT_COMP_LOGW("Cannot read basic field: "
716 "bfcr-addr=%p, fc-addr=%p, status=%s",
717 bfcr
, bfcr
->cur_basic_field_class
, bt_bfcr_status_string(status
));
721 consume_bits(bfcr
, fc
->size
);
723 if (stack_empty(bfcr
->stack
)) {
724 /* Root is a basic class */
725 bfcr
->state
= BFCR_STATE_DONE
;
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
;
736 /* We are here; it means we don't have enough data to decode this */
737 BT_COMP_LOGT_STR("Not enough data to read the next basic field: setting stitch buffer.");
738 stitch_set_from_remaining_buf(bfcr
);
739 bfcr
->state
= BFCR_STATE_READ_BASIC_CONTINUE
;
740 status
= BT_BFCR_STATUS_EOF
;
746 static inline enum bt_bfcr_status
read_basic_int_class_and_call_begin(struct bt_bfcr
*bfcr
)
748 return read_bit_array_class_and_call_begin(bfcr
, read_basic_int_and_call_cb
);
751 static inline enum bt_bfcr_status
read_basic_int_class_and_call_continue(struct bt_bfcr
*bfcr
)
753 return read_bit_array_class_and_call_continue(bfcr
, read_basic_int_and_call_cb
);
756 static inline enum bt_bfcr_status
read_basic_float_class_and_call_begin(struct bt_bfcr
*bfcr
)
758 return read_bit_array_class_and_call_begin(bfcr
, read_basic_float_and_call_cb
);
761 static inline enum bt_bfcr_status
read_basic_float_class_and_call_continue(struct bt_bfcr
*bfcr
)
763 return read_bit_array_class_and_call_continue(bfcr
, read_basic_float_and_call_cb
);
766 static inline enum bt_bfcr_status
read_basic_string_class_and_call(struct bt_bfcr
*bfcr
, bool begin
)
769 const uint8_t *result
;
770 size_t available_bytes
;
771 const uint8_t *first_chr
;
772 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
774 if (!at_least_one_bit_left(bfcr
)) {
775 BT_COMP_LOGT("Reached end of data: bfcr-addr=%p", bfcr
);
776 status
= BT_BFCR_STATUS_EOF
;
780 BT_ASSERT_DBG(buf_at_from_addr(bfcr
) % 8 == 0);
781 available_bytes
= BITS_TO_BYTES_FLOOR(available_bits(bfcr
));
782 buf_at_bytes
= BITS_TO_BYTES_FLOOR(buf_at_from_addr(bfcr
));
783 BT_ASSERT_DBG(bfcr
->buf
.addr
);
784 first_chr
= &bfcr
->buf
.addr
[buf_at_bytes
];
785 result
= (const uint8_t *) memchr(first_chr
, '\0', available_bytes
);
787 if (begin
&& bfcr
->user
.cbs
.classes
.string_begin
) {
788 BT_COMP_LOGT("Calling user function (string, beginning).");
789 status
= bfcr
->user
.cbs
.classes
.string_begin(bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
790 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
791 if (status
!= BT_BFCR_STATUS_OK
) {
792 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s", bfcr
,
793 bt_bfcr_status_string(status
));
799 /* No null character yet */
800 if (bfcr
->user
.cbs
.classes
.string
) {
801 BT_COMP_LOGT("Calling user function (substring).");
802 status
= bfcr
->user
.cbs
.classes
.string((const char *) first_chr
, available_bytes
,
803 bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
804 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
805 if (status
!= BT_BFCR_STATUS_OK
) {
806 BT_COMP_LOGW("User function failed: "
807 "bfcr-addr=%p, status=%s",
808 bfcr
, bt_bfcr_status_string(status
));
813 consume_bits(bfcr
, BYTES_TO_BITS(available_bytes
));
814 bfcr
->state
= BFCR_STATE_READ_BASIC_CONTINUE
;
815 status
= BT_BFCR_STATUS_EOF
;
817 /* Found the null character */
818 size_t result_len
= (size_t) (result
- first_chr
);
820 if (bfcr
->user
.cbs
.classes
.string
&& result_len
) {
821 BT_COMP_LOGT("Calling user function (substring).");
822 status
= bfcr
->user
.cbs
.classes
.string((const char *) first_chr
, result_len
,
823 bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
824 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
825 if (status
!= BT_BFCR_STATUS_OK
) {
826 BT_COMP_LOGW("User function failed: "
827 "bfcr-addr=%p, status=%s",
828 bfcr
, bt_bfcr_status_string(status
));
833 if (bfcr
->user
.cbs
.classes
.string_end
) {
834 BT_COMP_LOGT("Calling user function (string, end).");
836 bfcr
->user
.cbs
.classes
.string_end(bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
837 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
838 if (status
!= BT_BFCR_STATUS_OK
) {
839 BT_COMP_LOGW("User function failed: "
840 "bfcr-addr=%p, status=%s",
841 bfcr
, bt_bfcr_status_string(status
));
846 consume_bits(bfcr
, BYTES_TO_BITS(result_len
+ 1));
848 if (stack_empty(bfcr
->stack
)) {
849 /* Root is a basic class */
850 bfcr
->state
= BFCR_STATE_DONE
;
852 /* Go to next field */
853 stack_top(bfcr
->stack
)->index
++;
854 bfcr
->state
= BFCR_STATE_NEXT_FIELD
;
855 bfcr
->last_bo
= bfcr
->cur_bo
;
863 static inline enum bt_bfcr_status
read_basic_begin_state(struct bt_bfcr
*bfcr
)
865 enum bt_bfcr_status status
;
867 BT_ASSERT_DBG(bfcr
->cur_basic_field_class
);
869 switch (bfcr
->cur_basic_field_class
->type
) {
870 case CTF_FIELD_CLASS_TYPE_INT
:
871 case CTF_FIELD_CLASS_TYPE_ENUM
:
872 status
= read_basic_int_class_and_call_begin(bfcr
);
874 case CTF_FIELD_CLASS_TYPE_FLOAT
:
875 status
= read_basic_float_class_and_call_begin(bfcr
);
877 case CTF_FIELD_CLASS_TYPE_STRING
:
878 status
= read_basic_string_class_and_call(bfcr
, true);
887 static inline enum bt_bfcr_status
read_basic_continue_state(struct bt_bfcr
*bfcr
)
889 enum bt_bfcr_status status
;
891 BT_ASSERT_DBG(bfcr
->cur_basic_field_class
);
893 switch (bfcr
->cur_basic_field_class
->type
) {
894 case CTF_FIELD_CLASS_TYPE_INT
:
895 case CTF_FIELD_CLASS_TYPE_ENUM
:
896 status
= read_basic_int_class_and_call_continue(bfcr
);
898 case CTF_FIELD_CLASS_TYPE_FLOAT
:
899 status
= read_basic_float_class_and_call_continue(bfcr
);
901 case CTF_FIELD_CLASS_TYPE_STRING
:
902 status
= read_basic_string_class_and_call(bfcr
, false);
911 static inline size_t bits_to_skip_to_align_to(struct bt_bfcr
*bfcr
, size_t align
)
913 size_t aligned_packet_at
;
915 aligned_packet_at
= BT_ALIGN(packet_at(bfcr
), align
);
916 return aligned_packet_at
- packet_at(bfcr
);
919 static inline enum bt_bfcr_status
align_class_state(struct bt_bfcr
*bfcr
,
920 struct ctf_field_class
*field_class
,
921 enum bfcr_state next_state
)
923 unsigned int field_alignment
;
925 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
927 /* Get field's alignment */
928 field_alignment
= field_class
->alignment
;
931 * 0 means "undefined" for variants; what we really want is 1
934 BT_ASSERT_DBG(field_alignment
>= 1);
936 /* Compute how many bits we need to skip */
937 skip_bits
= bits_to_skip_to_align_to(bfcr
, (size_t) field_alignment
);
939 /* Nothing to skip? aligned */
940 if (skip_bits
== 0) {
941 bfcr
->state
= next_state
;
945 /* Make sure there's at least one bit left */
946 if (!at_least_one_bit_left(bfcr
)) {
947 status
= BT_BFCR_STATUS_EOF
;
951 /* Consume as many bits as possible in what's left */
952 consume_bits(bfcr
, MIN(available_bits(bfcr
), skip_bits
));
954 /* Are we done now? */
955 skip_bits
= bits_to_skip_to_align_to(bfcr
, field_alignment
);
956 if (skip_bits
== 0) {
957 /* Yes: go to next state */
958 bfcr
->state
= next_state
;
961 /* No: need more data */
962 BT_COMP_LOGT("Reached end of data when aligning: bfcr-addr=%p", bfcr
);
963 status
= BT_BFCR_STATUS_EOF
;
970 static inline enum bt_bfcr_status
next_field_state(struct bt_bfcr
*bfcr
)
973 struct stack_entry
*top
;
974 struct ctf_field_class
*next_field_class
= NULL
;
975 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
977 if (stack_empty(bfcr
->stack
)) {
981 top
= stack_top(bfcr
->stack
);
983 /* Are we done with this base class? */
984 while (top
->index
== top
->base_len
) {
985 if (bfcr
->user
.cbs
.classes
.compound_end
) {
986 BT_COMP_LOGT("Calling user function (compound, end).");
987 status
= bfcr
->user
.cbs
.classes
.compound_end(top
->base_class
, bfcr
->user
.data
);
988 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
989 if (status
!= BT_BFCR_STATUS_OK
) {
990 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s", bfcr
,
991 bt_bfcr_status_string(status
));
996 stack_pop(bfcr
->stack
);
998 /* Are we done with the root class? */
999 if (stack_empty(bfcr
->stack
)) {
1000 bfcr
->state
= BFCR_STATE_DONE
;
1004 top
= stack_top(bfcr
->stack
);
1008 /* Get next field's class */
1009 switch (top
->base_class
->type
) {
1010 case CTF_FIELD_CLASS_TYPE_STRUCT
:
1011 next_field_class
= ctf_field_class_struct_borrow_member_by_index(
1012 ctf_field_class_as_struct(top
->base_class
), (uint64_t) top
->index
)
1015 case CTF_FIELD_CLASS_TYPE_ARRAY
:
1016 case CTF_FIELD_CLASS_TYPE_SEQUENCE
:
1018 ctf_field_class_array_base
*array_fc
= ctf_field_class_as_array_base(top
->base_class
);
1020 next_field_class
= array_fc
->elem_fc
;
1023 case CTF_FIELD_CLASS_TYPE_VARIANT
:
1024 /* Variant classes are dynamic: the user should know! */
1025 next_field_class
= bfcr
->user
.cbs
.query
.borrow_variant_selected_field_class(
1026 top
->base_class
, bfcr
->user
.data
);
1032 if (!next_field_class
) {
1033 BT_COMP_LOGW("Cannot get the field class of the next field: "
1034 "bfcr-addr=%p, base-fc-addr=%p, base-fc-type=%d, "
1036 bfcr
, top
->base_class
, top
->base_class
->type
, top
->index
);
1037 status
= BT_BFCR_STATUS_ERROR
;
1041 if (next_field_class
->is_compound
) {
1042 if (bfcr
->user
.cbs
.classes
.compound_begin
) {
1043 BT_COMP_LOGT("Calling user function (compound, begin).");
1044 status
= bfcr
->user
.cbs
.classes
.compound_begin(next_field_class
, bfcr
->user
.data
);
1045 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
1046 if (status
!= BT_BFCR_STATUS_OK
) {
1047 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s", bfcr
,
1048 bt_bfcr_status_string(status
));
1053 ret
= stack_push_with_len(bfcr
, next_field_class
);
1055 /* stack_push_with_len() logs errors */
1056 status
= BT_BFCR_STATUS_ERROR
;
1060 /* Next state: align a compound class */
1061 bfcr
->state
= BFCR_STATE_ALIGN_COMPOUND
;
1063 /* Replace current basic field class */
1064 BT_COMP_LOGT("Replacing current basic field class: "
1065 "bfcr-addr=%p, cur-basic-fc-addr=%p, "
1066 "next-basic-fc-addr=%p",
1067 bfcr
, bfcr
->cur_basic_field_class
, next_field_class
);
1068 bfcr
->cur_basic_field_class
= next_field_class
;
1070 /* Next state: align a basic class */
1071 bfcr
->state
= BFCR_STATE_ALIGN_BASIC
;
1078 static inline enum bt_bfcr_status
handle_state(struct bt_bfcr
*bfcr
)
1080 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
1082 BT_COMP_LOGT("Handling state: bfcr-addr=%p, state=%s", bfcr
, bfcr_state_string(bfcr
->state
));
1084 switch (bfcr
->state
) {
1085 case BFCR_STATE_NEXT_FIELD
:
1086 status
= next_field_state(bfcr
);
1088 case BFCR_STATE_ALIGN_BASIC
:
1089 status
= align_class_state(bfcr
, bfcr
->cur_basic_field_class
, BFCR_STATE_READ_BASIC_BEGIN
);
1091 case BFCR_STATE_ALIGN_COMPOUND
:
1092 status
= align_class_state(bfcr
, stack_top(bfcr
->stack
)->base_class
, BFCR_STATE_NEXT_FIELD
);
1094 case BFCR_STATE_READ_BASIC_BEGIN
:
1095 status
= read_basic_begin_state(bfcr
);
1097 case BFCR_STATE_READ_BASIC_CONTINUE
:
1098 status
= read_basic_continue_state(bfcr
);
1100 case BFCR_STATE_DONE
:
1104 BT_COMP_LOGT("Handled state: bfcr-addr=%p, status=%s", bfcr
, bt_bfcr_status_string(status
));
1108 struct bt_bfcr
*bt_bfcr_create(struct bt_bfcr_cbs cbs
, void *data
, bt_logging_level log_level
,
1109 bt_self_component
*self_comp
)
1111 struct bt_bfcr
*bfcr
;
1113 BT_COMP_LOG_CUR_LVL(BT_LOG_DEBUG
, log_level
, self_comp
,
1114 "Creating binary field class reader (BFCR).");
1115 bfcr
= g_new0(struct bt_bfcr
, 1);
1117 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR
, log_level
, self_comp
,
1118 "Failed to allocate one binary class reader.");
1122 bfcr
->log_level
= log_level
;
1123 bfcr
->self_comp
= self_comp
;
1124 bfcr
->stack
= stack_new(bfcr
);
1126 BT_COMP_LOGE_STR("Cannot create BFCR's stack.");
1127 bt_bfcr_destroy(bfcr
);
1132 bfcr
->state
= BFCR_STATE_NEXT_FIELD
;
1133 bfcr
->user
.cbs
= cbs
;
1134 bfcr
->user
.data
= data
;
1135 BT_COMP_LOGD("Created BFCR: addr=%p", bfcr
);
1141 void bt_bfcr_destroy(struct bt_bfcr
*bfcr
)
1144 stack_destroy(bfcr
->stack
);
1147 BT_COMP_LOGD("Destroying BFCR: addr=%p", bfcr
);
1151 static void reset(struct bt_bfcr
*bfcr
)
1153 BT_COMP_LOGD("Resetting BFCR: addr=%p", bfcr
);
1154 stack_clear(bfcr
->stack
);
1156 bfcr
->buf
.addr
= NULL
;
1157 bfcr
->last_bo
= CTF_BYTE_ORDER_UNKNOWN
;
1160 static void update_packet_offset(struct bt_bfcr
*bfcr
)
1162 BT_COMP_LOGT("Updating packet offset for next call: "
1163 "bfcr-addr=%p, cur-packet-offset=%zu, next-packet-offset=%zu",
1164 bfcr
, bfcr
->buf
.packet_offset
, bfcr
->buf
.packet_offset
+ bfcr
->buf
.at
);
1165 bfcr
->buf
.packet_offset
+= bfcr
->buf
.at
;
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
)
1171 BT_ASSERT_DBG(bfcr
);
1172 BT_ASSERT_DBG(BYTES_TO_BITS(sz
) >= offset
);
1174 bfcr
->buf
.addr
= buf
;
1175 bfcr
->buf
.offset
= offset
;
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
;
1182 BT_COMP_LOGT("Starting decoding: bfcr-addr=%p, fc-addr=%p, "
1183 "buf-addr=%p, buf-size=%zu, offset=%zu, "
1184 "packet-offset=%zu",
1185 bfcr
, cls
, buf
, sz
, offset
, packet_offset
);
1187 /* Set root class */
1188 if (cls
->is_compound
) {
1189 /* Compound class: push on visit stack */
1192 if (bfcr
->user
.cbs
.classes
.compound_begin
) {
1193 BT_COMP_LOGT("Calling user function (compound, begin).");
1194 *status
= bfcr
->user
.cbs
.classes
.compound_begin(cls
, bfcr
->user
.data
);
1195 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(*status
));
1196 if (*status
!= BT_BFCR_STATUS_OK
) {
1197 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s", bfcr
,
1198 bt_bfcr_status_string(*status
));
1203 stack_ret
= stack_push_with_len(bfcr
, cls
);
1205 /* stack_push_with_len() logs errors */
1206 *status
= BT_BFCR_STATUS_ERROR
;
1210 bfcr
->state
= BFCR_STATE_ALIGN_COMPOUND
;
1212 /* Basic class: set as current basic class */
1213 bfcr
->cur_basic_field_class
= cls
;
1214 bfcr
->state
= BFCR_STATE_ALIGN_BASIC
;
1217 /* Run the machine! */
1218 BT_COMP_LOGT_STR("Running the state machine.");
1221 *status
= handle_state(bfcr
);
1222 if (*status
!= BT_BFCR_STATUS_OK
|| bfcr
->state
== BFCR_STATE_DONE
) {
1227 /* Update packet offset for next time */
1228 update_packet_offset(bfcr
);
1231 return bfcr
->buf
.at
;
1234 size_t bt_bfcr_continue(struct bt_bfcr
*bfcr
, const uint8_t *buf
, size_t sz
,
1235 enum bt_bfcr_status
*status
)
1237 BT_ASSERT_DBG(bfcr
);
1239 BT_ASSERT_DBG(sz
> 0);
1240 bfcr
->buf
.addr
= buf
;
1241 bfcr
->buf
.offset
= 0;
1243 bfcr
->buf
.buf_sz
= sz
;
1244 bfcr
->buf
.sz
= BYTES_TO_BITS(sz
);
1245 *status
= BT_BFCR_STATUS_OK
;
1247 BT_COMP_LOGT("Continuing decoding: bfcr-addr=%p, buf-addr=%p, buf-size=%zu", bfcr
, buf
, sz
);
1249 /* Continue running the machine */
1250 BT_COMP_LOGT_STR("Running the state machine.");
1253 *status
= handle_state(bfcr
);
1254 if (*status
!= BT_BFCR_STATUS_OK
|| bfcr
->state
== BFCR_STATE_DONE
) {
1259 /* Update packet offset for next time */
1260 update_packet_offset(bfcr
);
1261 return bfcr
->buf
.at
;
1264 void bt_bfcr_set_unsigned_int_cb(struct bt_bfcr
*bfcr
, bt_bfcr_unsigned_int_cb_func cb
)
1266 BT_ASSERT_DBG(bfcr
);
1268 bfcr
->user
.cbs
.classes
.unsigned_int
= cb
;