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)
18 #include <babeltrace2/babeltrace.h>
20 #define BT_COMP_LOG_SELF_COMP (bfcr->self_comp)
21 #define BT_LOG_OUTPUT_LEVEL (bfcr->log_level)
22 #define BT_LOG_TAG "PLUGIN/CTF/BFCR"
23 #include "logging/comp-logging.h"
25 #include "common/align.h"
26 #include "common/assert.h"
27 #include "common/common.h"
28 #include "compat/bitfield.h"
30 #include "../metadata/ctf-meta.hpp"
33 #define DIV8(_x) ((_x) >> 3)
34 #define BYTES_TO_BITS(_x) ((_x) *8)
35 #define BITS_TO_BYTES_FLOOR(_x) DIV8(_x)
36 #define BITS_TO_BYTES_CEIL(_x) DIV8((_x) + 7)
37 #define IN_BYTE_OFFSET(_at) ((_at) &7)
39 /* A visit stack entry */
43 * Current class of base field, one of:
50 struct ctf_field_class
*base_class
;
52 /* Length of base field (always 1 for a variant class) */
55 /* Index of next field to read */
66 /* Entries (struct stack_entry) */
69 /* Number of active entries */
76 BFCR_STATE_NEXT_FIELD
,
77 BFCR_STATE_ALIGN_BASIC
,
78 BFCR_STATE_ALIGN_COMPOUND
,
79 BFCR_STATE_READ_BASIC_BEGIN
,
80 BFCR_STATE_READ_BASIC_CONTINUE
,
84 /* Binary class reader */
87 bt_logging_level log_level
;
90 bt_self_component
*self_comp
;
95 /* Current basic field class */
96 struct ctf_field_class
*cur_basic_field_class
;
99 enum bfcr_state state
;
102 * Last basic field class's byte order.
104 * This is used to detect errors since two contiguous basic
105 * classes for which the common boundary is not the boundary of
106 * a byte cannot have different byte orders.
108 * This is set to CTF_BYTE_ORDER_UNKNOWN on reset and when the last
109 * basic field class was a string class.
111 enum ctf_byte_order last_bo
;
113 /* Current byte order (copied to last_bo after a successful read) */
114 enum ctf_byte_order cur_bo
;
116 /* Stitch buffer infos */
122 /* Offset, within stitch buffer, of first bit */
125 /* Length (bits) of data in stitch buffer from offset */
129 /* User buffer infos */
135 /* Offset of data from address (bits) */
138 /* Current position from offset (bits) */
141 /* Offset of offset within whole packet (bits) */
142 size_t packet_offset
;
144 /* Data size in buffer (bits) */
147 /* Buffer size (bytes) */
154 /* Callback functions */
155 struct bt_bfcr_cbs cbs
;
162 static inline const char *bfcr_state_string(enum bfcr_state state
)
165 case BFCR_STATE_NEXT_FIELD
:
167 case BFCR_STATE_ALIGN_BASIC
:
168 return "ALIGN_BASIC";
169 case BFCR_STATE_ALIGN_COMPOUND
:
170 return "ALIGN_COMPOUND";
171 case BFCR_STATE_READ_BASIC_BEGIN
:
172 return "READ_BASIC_BEGIN";
173 case BFCR_STATE_READ_BASIC_CONTINUE
:
174 return "READ_BASIC_CONTINUE";
175 case BFCR_STATE_DONE
:
182 static struct stack
*stack_new(struct bt_bfcr
*bfcr
)
184 struct stack
*stack
= NULL
;
186 stack
= g_new0(struct stack
, 1);
188 BT_COMP_LOGE_STR("Failed to allocate one stack.");
193 stack
->entries
= g_array_new(FALSE
, TRUE
, sizeof(struct stack_entry
));
194 if (!stack
->entries
) {
195 BT_COMP_LOGE_STR("Failed to allocate a GArray.");
199 BT_COMP_LOGD("Created stack: addr=%p", stack
);
207 static void stack_destroy(struct stack
*stack
)
209 struct bt_bfcr
*bfcr
;
216 BT_COMP_LOGD("Destroying stack: addr=%p", stack
);
218 if (stack
->entries
) {
219 g_array_free(stack
->entries
, TRUE
);
225 static int stack_push(struct stack
*stack
, struct ctf_field_class
*base_class
, size_t base_len
)
227 struct stack_entry
*entry
;
228 struct bt_bfcr
*bfcr
;
230 BT_ASSERT_DBG(stack
);
231 BT_ASSERT_DBG(base_class
);
233 BT_COMP_LOGT("Pushing field class on stack: stack-addr=%p, "
234 "fc-addr=%p, fc-type=%d, base-length=%zu, "
235 "stack-size-before=%zu, stack-size-after=%zu",
236 stack
, base_class
, base_class
->type
, base_len
, stack
->size
, stack
->size
+ 1);
238 if (stack
->entries
->len
== stack
->size
) {
239 g_array_set_size(stack
->entries
, stack
->size
+ 1);
242 entry
= &bt_g_array_index(stack
->entries
, struct stack_entry
, stack
->size
);
243 entry
->base_class
= base_class
;
244 entry
->base_len
= base_len
;
250 static inline int64_t get_compound_field_class_length(struct bt_bfcr
*bfcr
,
251 struct ctf_field_class
*fc
)
256 case CTF_FIELD_CLASS_TYPE_STRUCT
:
258 ctf_field_class_struct
*struct_fc
= ctf_field_class_as_struct(fc
);
260 length
= (int64_t) struct_fc
->members
->len
;
263 case CTF_FIELD_CLASS_TYPE_VARIANT
:
265 /* Variant field classes always "contain" a single class */
269 case CTF_FIELD_CLASS_TYPE_ARRAY
:
271 struct ctf_field_class_array
*array_fc
= ctf_field_class_as_array(fc
);
273 length
= (int64_t) array_fc
->length
;
276 case CTF_FIELD_CLASS_TYPE_SEQUENCE
:
277 length
= bfcr
->user
.cbs
.query
.get_sequence_length(fc
, bfcr
->user
.data
);
286 static int stack_push_with_len(struct bt_bfcr
*bfcr
, struct ctf_field_class
*base_class
)
289 int64_t length
= get_compound_field_class_length(bfcr
, base_class
);
292 BT_COMP_LOGW("Cannot get compound field class's field count: "
293 "bfcr-addr=%p, fc-addr=%p, fc-type=%d",
294 bfcr
, base_class
, base_class
->type
);
295 ret
= BT_BFCR_STATUS_ERROR
;
299 ret
= stack_push(bfcr
->stack
, base_class
, (size_t) length
);
305 static inline unsigned int stack_size(struct stack
*stack
)
307 BT_ASSERT_DBG(stack
);
311 static void stack_pop(struct stack
*stack
)
313 struct bt_bfcr
*bfcr
;
315 BT_ASSERT_DBG(stack
);
316 BT_ASSERT_DBG(stack_size(stack
));
318 BT_COMP_LOGT("Popping from stack: "
319 "stack-addr=%p, stack-size-before=%u, stack-size-after=%u",
320 stack
, stack
->entries
->len
, stack
->entries
->len
- 1);
324 static inline bool stack_empty(struct stack
*stack
)
326 return stack_size(stack
) == 0;
329 static void stack_clear(struct stack
*stack
)
331 BT_ASSERT_DBG(stack
);
335 static inline struct stack_entry
*stack_top(struct stack
*stack
)
337 BT_ASSERT_DBG(stack
);
338 BT_ASSERT_DBG(stack_size(stack
));
339 return &bt_g_array_index(stack
->entries
, struct stack_entry
, stack
->size
- 1);
342 static inline size_t available_bits(struct bt_bfcr
*bfcr
)
344 return bfcr
->buf
.sz
- bfcr
->buf
.at
;
347 static inline void consume_bits(struct bt_bfcr
*bfcr
, size_t incr
)
349 BT_COMP_LOGT("Advancing cursor: bfcr-addr=%p, cur-before=%zu, cur-after=%zu", bfcr
,
350 bfcr
->buf
.at
, bfcr
->buf
.at
+ incr
);
351 bfcr
->buf
.at
+= incr
;
354 static inline bool has_enough_bits(struct bt_bfcr
*bfcr
, size_t sz
)
356 return available_bits(bfcr
) >= sz
;
359 static inline bool at_least_one_bit_left(struct bt_bfcr
*bfcr
)
361 return has_enough_bits(bfcr
, 1);
364 static inline size_t packet_at(struct bt_bfcr
*bfcr
)
366 return bfcr
->buf
.packet_offset
+ bfcr
->buf
.at
;
369 static inline size_t buf_at_from_addr(struct bt_bfcr
*bfcr
)
374 * ====== offset ===== (17)
376 * xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
378 * addr (0) ==== at ==== (12)
382 * =============================== (29)
384 return bfcr
->buf
.offset
+ bfcr
->buf
.at
;
387 static void stitch_reset(struct bt_bfcr
*bfcr
)
389 bfcr
->stitch
.offset
= 0;
393 static inline size_t stitch_at_from_addr(struct bt_bfcr
*bfcr
)
395 return bfcr
->stitch
.offset
+ bfcr
->stitch
.at
;
398 static void stitch_append_from_buf(struct bt_bfcr
*bfcr
, size_t sz
)
400 size_t stitch_byte_at
;
408 stitch_byte_at
= BITS_TO_BYTES_FLOOR(stitch_at_from_addr(bfcr
));
409 buf_byte_at
= BITS_TO_BYTES_FLOOR(buf_at_from_addr(bfcr
));
410 nb_bytes
= BITS_TO_BYTES_CEIL(sz
);
411 BT_ASSERT(nb_bytes
> 0);
412 BT_ASSERT(bfcr
->buf
.addr
);
413 memcpy(&bfcr
->stitch
.buf
[stitch_byte_at
], &bfcr
->buf
.addr
[buf_byte_at
], nb_bytes
);
414 bfcr
->stitch
.at
+= sz
;
415 consume_bits(bfcr
, sz
);
418 static void stitch_append_from_remaining_buf(struct bt_bfcr
*bfcr
)
420 stitch_append_from_buf(bfcr
, available_bits(bfcr
));
423 static void stitch_set_from_remaining_buf(struct bt_bfcr
*bfcr
)
426 bfcr
->stitch
.offset
= IN_BYTE_OFFSET(buf_at_from_addr(bfcr
));
427 stitch_append_from_remaining_buf(bfcr
);
430 static inline void read_unsigned_bitfield(struct bt_bfcr
*bfcr
, const uint8_t *buf
, size_t at
,
431 unsigned int field_size
, enum ctf_byte_order bo
,
435 case CTF_BYTE_ORDER_BIG
:
436 bt_bitfield_read_be(buf
, uint8_t, at
, field_size
, v
);
438 case CTF_BYTE_ORDER_LITTLE
:
439 bt_bitfield_read_le(buf
, uint8_t, at
, field_size
, v
);
445 BT_COMP_LOGT("Read unsigned bit array: cur=%zu, size=%u, "
446 "bo=%d, val=%" PRIu64
,
447 at
, field_size
, bo
, *v
);
450 static inline void read_signed_bitfield(struct bt_bfcr
*bfcr
, const uint8_t *buf
, size_t at
,
451 unsigned int field_size
, enum ctf_byte_order bo
, int64_t *v
)
454 case CTF_BYTE_ORDER_BIG
:
455 bt_bitfield_read_be(buf
, uint8_t, at
, field_size
, v
);
457 case CTF_BYTE_ORDER_LITTLE
:
458 bt_bitfield_read_le(buf
, uint8_t, at
, field_size
, v
);
464 BT_COMP_LOGT("Read signed bit array: cur=%zu, size=%u, "
465 "bo=%d, val=%" PRId64
,
466 at
, field_size
, bo
, *v
);
469 typedef enum bt_bfcr_status (*read_basic_and_call_cb_t
)(struct bt_bfcr
*, const uint8_t *, size_t);
471 static inline enum bt_bfcr_status
validate_contiguous_bo(struct bt_bfcr
*bfcr
,
472 enum ctf_byte_order next_bo
)
474 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
476 /* Always valid when at a byte boundary */
477 if (packet_at(bfcr
) % 8 == 0) {
481 /* Always valid if last byte order is unknown */
482 if (bfcr
->last_bo
== CTF_BYTE_ORDER_UNKNOWN
) {
486 /* Always valid if next byte order is unknown */
487 if (next_bo
== CTF_BYTE_ORDER_UNKNOWN
) {
491 /* Make sure last byte order is compatible with the next byte order */
492 switch (bfcr
->last_bo
) {
493 case CTF_BYTE_ORDER_BIG
:
494 if (next_bo
!= CTF_BYTE_ORDER_BIG
) {
495 status
= BT_BFCR_STATUS_ERROR
;
498 case CTF_BYTE_ORDER_LITTLE
:
499 if (next_bo
!= CTF_BYTE_ORDER_LITTLE
) {
500 status
= BT_BFCR_STATUS_ERROR
;
504 status
= BT_BFCR_STATUS_ERROR
;
509 BT_COMP_LOGW("Cannot read bit array: two different byte orders not at a byte boundary: "
510 "bfcr-addr=%p, last-bo=%d, next-bo=%d",
511 bfcr
, bfcr
->last_bo
, next_bo
);
517 static enum bt_bfcr_status
read_basic_float_and_call_cb(struct bt_bfcr
*bfcr
, const uint8_t *buf
,
521 unsigned int field_size
;
522 enum ctf_byte_order bo
;
523 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
524 ctf_field_class_float
*fc
= ctf_field_class_as_float(bfcr
->cur_basic_field_class
);
527 field_size
= fc
->base
.size
;
528 bo
= fc
->base
.byte_order
;
531 switch (field_size
) {
541 read_unsigned_bitfield(bfcr
, buf
, at
, field_size
, bo
, &v
);
542 f32
.u
= (uint32_t) v
;
543 dblval
= (double) f32
.f
;
554 read_unsigned_bitfield(bfcr
, buf
, at
, field_size
, bo
, &f64
.u
);
559 /* Only 32-bit and 64-bit fields are supported currently */
563 BT_COMP_LOGT("Read floating point number value: bfcr=%p, cur=%zu, val=%f", bfcr
, at
, dblval
);
565 if (bfcr
->user
.cbs
.classes
.floating_point
) {
566 BT_COMP_LOGT("Calling user function (floating point number).");
567 status
= bfcr
->user
.cbs
.classes
.floating_point(dblval
, bfcr
->cur_basic_field_class
,
569 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
570 if (status
!= BT_BFCR_STATUS_OK
) {
571 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s", bfcr
,
572 bt_bfcr_status_string(status
));
579 static inline enum bt_bfcr_status
read_basic_int_and_call_cb(struct bt_bfcr
*bfcr
,
580 const uint8_t *buf
, size_t at
)
582 unsigned int field_size
;
583 enum ctf_byte_order bo
;
584 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
585 ctf_field_class_int
*fc
= ctf_field_class_as_int(bfcr
->cur_basic_field_class
);
587 field_size
= fc
->base
.size
;
588 bo
= fc
->base
.byte_order
;
591 * Update current byte order now because we could be reading
592 * the integer value of an enumeration class, and thus we know
593 * here the actual supporting integer class's byte order.
600 read_signed_bitfield(bfcr
, buf
, at
, field_size
, bo
, &v
);
602 if (bfcr
->user
.cbs
.classes
.signed_int
) {
603 BT_COMP_LOGT("Calling user function (signed integer).");
605 bfcr
->user
.cbs
.classes
.signed_int(v
, bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
606 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
607 if (status
!= BT_BFCR_STATUS_OK
) {
608 BT_COMP_LOGW("User function failed: "
609 "bfcr-addr=%p, status=%s",
610 bfcr
, bt_bfcr_status_string(status
));
616 read_unsigned_bitfield(bfcr
, buf
, at
, field_size
, bo
, &v
);
618 if (bfcr
->user
.cbs
.classes
.unsigned_int
) {
619 BT_COMP_LOGT("Calling user function (unsigned integer).");
620 status
= bfcr
->user
.cbs
.classes
.unsigned_int(v
, bfcr
->cur_basic_field_class
,
622 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
623 if (status
!= BT_BFCR_STATUS_OK
) {
624 BT_COMP_LOGW("User function failed: "
625 "bfcr-addr=%p, status=%s",
626 bfcr
, bt_bfcr_status_string(status
));
634 static inline enum bt_bfcr_status
635 read_bit_array_class_and_call_continue(struct bt_bfcr
*bfcr
,
636 read_basic_and_call_cb_t read_basic_and_call_cb
)
640 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
641 ctf_field_class_bit_array
*fc
= ctf_field_class_as_bit_array(bfcr
->cur_basic_field_class
);
643 if (!at_least_one_bit_left(bfcr
)) {
644 BT_COMP_LOGT("Reached end of data: bfcr-addr=%p", bfcr
);
645 status
= BT_BFCR_STATUS_EOF
;
649 available
= available_bits(bfcr
);
650 needed_bits
= fc
->size
- bfcr
->stitch
.at
;
651 BT_COMP_LOGT("Continuing basic field decoding: "
652 "bfcr-addr=%p, field-size=%u, needed-size=%zu, "
653 "available-size=%zu",
654 bfcr
, fc
->size
, needed_bits
, available
);
655 if (needed_bits
<= available
) {
656 /* We have all the bits; append to stitch, then decode */
657 stitch_append_from_buf(bfcr
, needed_bits
);
658 status
= read_basic_and_call_cb(bfcr
, bfcr
->stitch
.buf
, bfcr
->stitch
.offset
);
659 if (status
!= BT_BFCR_STATUS_OK
) {
660 BT_COMP_LOGW("Cannot read basic field: "
661 "bfcr-addr=%p, fc-addr=%p, status=%s",
662 bfcr
, bfcr
->cur_basic_field_class
, bt_bfcr_status_string(status
));
666 if (stack_empty(bfcr
->stack
)) {
667 /* Root is a basic class */
668 bfcr
->state
= BFCR_STATE_DONE
;
670 /* Go to next field */
671 stack_top(bfcr
->stack
)->index
++;
672 bfcr
->state
= BFCR_STATE_NEXT_FIELD
;
673 bfcr
->last_bo
= bfcr
->cur_bo
;
678 /* We are here; it means we don't have enough data to decode this */
679 BT_COMP_LOGT_STR("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
;
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
)
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
);
695 if (!at_least_one_bit_left(bfcr
)) {
696 BT_COMP_LOGT("Reached end of data: bfcr-addr=%p", bfcr
);
697 status
= BT_BFCR_STATUS_EOF
;
701 status
= validate_contiguous_bo(bfcr
, fc
->byte_order
);
702 if (status
!= BT_BFCR_STATUS_OK
) {
703 /* validate_contiguous_bo() logs errors */
707 available
= available_bits(bfcr
);
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_COMP_LOGW("Cannot read basic field: "
715 "bfcr-addr=%p, fc-addr=%p, status=%s",
716 bfcr
, bfcr
->cur_basic_field_class
, bt_bfcr_status_string(status
));
720 consume_bits(bfcr
, fc
->size
);
722 if (stack_empty(bfcr
->stack
)) {
723 /* Root is a basic class */
724 bfcr
->state
= BFCR_STATE_DONE
;
726 /* Go to next field */
727 stack_top(bfcr
->stack
)->index
++;
728 bfcr
->state
= BFCR_STATE_NEXT_FIELD
;
729 bfcr
->last_bo
= bfcr
->cur_bo
;
735 /* We are here; it means we don't have enough data to decode this */
736 BT_COMP_LOGT_STR("Not enough data to read the next basic field: setting stitch buffer.");
737 stitch_set_from_remaining_buf(bfcr
);
738 bfcr
->state
= BFCR_STATE_READ_BASIC_CONTINUE
;
739 status
= BT_BFCR_STATUS_EOF
;
745 static inline enum bt_bfcr_status
read_basic_int_class_and_call_begin(struct bt_bfcr
*bfcr
)
747 return read_bit_array_class_and_call_begin(bfcr
, read_basic_int_and_call_cb
);
750 static inline enum bt_bfcr_status
read_basic_int_class_and_call_continue(struct bt_bfcr
*bfcr
)
752 return read_bit_array_class_and_call_continue(bfcr
, read_basic_int_and_call_cb
);
755 static inline enum bt_bfcr_status
read_basic_float_class_and_call_begin(struct bt_bfcr
*bfcr
)
757 return read_bit_array_class_and_call_begin(bfcr
, read_basic_float_and_call_cb
);
760 static inline enum bt_bfcr_status
read_basic_float_class_and_call_continue(struct bt_bfcr
*bfcr
)
762 return read_bit_array_class_and_call_continue(bfcr
, read_basic_float_and_call_cb
);
765 static inline enum bt_bfcr_status
read_basic_string_class_and_call(struct bt_bfcr
*bfcr
, bool begin
)
768 const uint8_t *result
;
769 size_t available_bytes
;
770 const uint8_t *first_chr
;
771 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
773 if (!at_least_one_bit_left(bfcr
)) {
774 BT_COMP_LOGT("Reached end of data: bfcr-addr=%p", bfcr
);
775 status
= BT_BFCR_STATUS_EOF
;
779 BT_ASSERT_DBG(buf_at_from_addr(bfcr
) % 8 == 0);
780 available_bytes
= BITS_TO_BYTES_FLOOR(available_bits(bfcr
));
781 buf_at_bytes
= BITS_TO_BYTES_FLOOR(buf_at_from_addr(bfcr
));
782 BT_ASSERT_DBG(bfcr
->buf
.addr
);
783 first_chr
= &bfcr
->buf
.addr
[buf_at_bytes
];
784 result
= (const uint8_t *) memchr(first_chr
, '\0', available_bytes
);
786 if (begin
&& bfcr
->user
.cbs
.classes
.string_begin
) {
787 BT_COMP_LOGT("Calling user function (string, beginning).");
788 status
= bfcr
->user
.cbs
.classes
.string_begin(bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
789 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
790 if (status
!= BT_BFCR_STATUS_OK
) {
791 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s", bfcr
,
792 bt_bfcr_status_string(status
));
798 /* No null character yet */
799 if (bfcr
->user
.cbs
.classes
.string
) {
800 BT_COMP_LOGT("Calling user function (substring).");
801 status
= bfcr
->user
.cbs
.classes
.string((const char *) first_chr
, available_bytes
,
802 bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
803 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
804 if (status
!= BT_BFCR_STATUS_OK
) {
805 BT_COMP_LOGW("User function failed: "
806 "bfcr-addr=%p, status=%s",
807 bfcr
, bt_bfcr_status_string(status
));
812 consume_bits(bfcr
, BYTES_TO_BITS(available_bytes
));
813 bfcr
->state
= BFCR_STATE_READ_BASIC_CONTINUE
;
814 status
= BT_BFCR_STATUS_EOF
;
816 /* Found the null character */
817 size_t result_len
= (size_t) (result
- first_chr
);
819 if (bfcr
->user
.cbs
.classes
.string
&& result_len
) {
820 BT_COMP_LOGT("Calling user function (substring).");
821 status
= bfcr
->user
.cbs
.classes
.string((const char *) first_chr
, result_len
,
822 bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
823 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
824 if (status
!= BT_BFCR_STATUS_OK
) {
825 BT_COMP_LOGW("User function failed: "
826 "bfcr-addr=%p, status=%s",
827 bfcr
, bt_bfcr_status_string(status
));
832 if (bfcr
->user
.cbs
.classes
.string_end
) {
833 BT_COMP_LOGT("Calling user function (string, end).");
835 bfcr
->user
.cbs
.classes
.string_end(bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
836 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
837 if (status
!= BT_BFCR_STATUS_OK
) {
838 BT_COMP_LOGW("User function failed: "
839 "bfcr-addr=%p, status=%s",
840 bfcr
, bt_bfcr_status_string(status
));
845 consume_bits(bfcr
, BYTES_TO_BITS(result_len
+ 1));
847 if (stack_empty(bfcr
->stack
)) {
848 /* Root is a basic class */
849 bfcr
->state
= BFCR_STATE_DONE
;
851 /* Go to next field */
852 stack_top(bfcr
->stack
)->index
++;
853 bfcr
->state
= BFCR_STATE_NEXT_FIELD
;
854 bfcr
->last_bo
= bfcr
->cur_bo
;
862 static inline enum bt_bfcr_status
read_basic_begin_state(struct bt_bfcr
*bfcr
)
864 enum bt_bfcr_status status
;
866 BT_ASSERT_DBG(bfcr
->cur_basic_field_class
);
868 switch (bfcr
->cur_basic_field_class
->type
) {
869 case CTF_FIELD_CLASS_TYPE_INT
:
870 case CTF_FIELD_CLASS_TYPE_ENUM
:
871 status
= read_basic_int_class_and_call_begin(bfcr
);
873 case CTF_FIELD_CLASS_TYPE_FLOAT
:
874 status
= read_basic_float_class_and_call_begin(bfcr
);
876 case CTF_FIELD_CLASS_TYPE_STRING
:
877 status
= read_basic_string_class_and_call(bfcr
, true);
886 static inline enum bt_bfcr_status
read_basic_continue_state(struct bt_bfcr
*bfcr
)
888 enum bt_bfcr_status status
;
890 BT_ASSERT_DBG(bfcr
->cur_basic_field_class
);
892 switch (bfcr
->cur_basic_field_class
->type
) {
893 case CTF_FIELD_CLASS_TYPE_INT
:
894 case CTF_FIELD_CLASS_TYPE_ENUM
:
895 status
= read_basic_int_class_and_call_continue(bfcr
);
897 case CTF_FIELD_CLASS_TYPE_FLOAT
:
898 status
= read_basic_float_class_and_call_continue(bfcr
);
900 case CTF_FIELD_CLASS_TYPE_STRING
:
901 status
= read_basic_string_class_and_call(bfcr
, false);
910 static inline size_t bits_to_skip_to_align_to(struct bt_bfcr
*bfcr
, size_t align
)
912 size_t aligned_packet_at
;
914 aligned_packet_at
= BT_ALIGN(packet_at(bfcr
), align
);
915 return aligned_packet_at
- packet_at(bfcr
);
918 static inline enum bt_bfcr_status
align_class_state(struct bt_bfcr
*bfcr
,
919 struct ctf_field_class
*field_class
,
920 enum bfcr_state next_state
)
922 unsigned int field_alignment
;
924 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
926 /* Get field's alignment */
927 field_alignment
= field_class
->alignment
;
930 * 0 means "undefined" for variants; what we really want is 1
933 BT_ASSERT_DBG(field_alignment
>= 1);
935 /* Compute how many bits we need to skip */
936 skip_bits
= bits_to_skip_to_align_to(bfcr
, (size_t) field_alignment
);
938 /* Nothing to skip? aligned */
939 if (skip_bits
== 0) {
940 bfcr
->state
= next_state
;
944 /* Make sure there's at least one bit left */
945 if (!at_least_one_bit_left(bfcr
)) {
946 status
= BT_BFCR_STATUS_EOF
;
950 /* Consume as many bits as possible in what's left */
951 consume_bits(bfcr
, MIN(available_bits(bfcr
), skip_bits
));
953 /* Are we done now? */
954 skip_bits
= bits_to_skip_to_align_to(bfcr
, field_alignment
);
955 if (skip_bits
== 0) {
956 /* Yes: go to next state */
957 bfcr
->state
= next_state
;
960 /* No: need more data */
961 BT_COMP_LOGT("Reached end of data when aligning: bfcr-addr=%p", bfcr
);
962 status
= BT_BFCR_STATUS_EOF
;
969 static inline enum bt_bfcr_status
next_field_state(struct bt_bfcr
*bfcr
)
972 struct stack_entry
*top
;
973 struct ctf_field_class
*next_field_class
= NULL
;
974 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
976 if (stack_empty(bfcr
->stack
)) {
980 top
= stack_top(bfcr
->stack
);
982 /* Are we done with this base class? */
983 while (top
->index
== top
->base_len
) {
984 if (bfcr
->user
.cbs
.classes
.compound_end
) {
985 BT_COMP_LOGT("Calling user function (compound, end).");
986 status
= bfcr
->user
.cbs
.classes
.compound_end(top
->base_class
, bfcr
->user
.data
);
987 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
988 if (status
!= BT_BFCR_STATUS_OK
) {
989 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s", bfcr
,
990 bt_bfcr_status_string(status
));
995 stack_pop(bfcr
->stack
);
997 /* Are we done with the root class? */
998 if (stack_empty(bfcr
->stack
)) {
999 bfcr
->state
= BFCR_STATE_DONE
;
1003 top
= stack_top(bfcr
->stack
);
1007 /* Get next field's class */
1008 switch (top
->base_class
->type
) {
1009 case CTF_FIELD_CLASS_TYPE_STRUCT
:
1010 next_field_class
= ctf_field_class_struct_borrow_member_by_index(
1011 ctf_field_class_as_struct(top
->base_class
), (uint64_t) top
->index
)
1014 case CTF_FIELD_CLASS_TYPE_ARRAY
:
1015 case CTF_FIELD_CLASS_TYPE_SEQUENCE
:
1017 ctf_field_class_array_base
*array_fc
= ctf_field_class_as_array_base(top
->base_class
);
1019 next_field_class
= array_fc
->elem_fc
;
1022 case CTF_FIELD_CLASS_TYPE_VARIANT
:
1023 /* Variant classes are dynamic: the user should know! */
1024 next_field_class
= bfcr
->user
.cbs
.query
.borrow_variant_selected_field_class(
1025 top
->base_class
, bfcr
->user
.data
);
1031 if (!next_field_class
) {
1032 BT_COMP_LOGW("Cannot get the field class of the next field: "
1033 "bfcr-addr=%p, base-fc-addr=%p, base-fc-type=%d, "
1035 bfcr
, top
->base_class
, top
->base_class
->type
, top
->index
);
1036 status
= BT_BFCR_STATUS_ERROR
;
1040 if (next_field_class
->is_compound
) {
1041 if (bfcr
->user
.cbs
.classes
.compound_begin
) {
1042 BT_COMP_LOGT("Calling user function (compound, begin).");
1043 status
= bfcr
->user
.cbs
.classes
.compound_begin(next_field_class
, bfcr
->user
.data
);
1044 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
1045 if (status
!= BT_BFCR_STATUS_OK
) {
1046 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s", bfcr
,
1047 bt_bfcr_status_string(status
));
1052 ret
= stack_push_with_len(bfcr
, next_field_class
);
1054 /* stack_push_with_len() logs errors */
1055 status
= BT_BFCR_STATUS_ERROR
;
1059 /* Next state: align a compound class */
1060 bfcr
->state
= BFCR_STATE_ALIGN_COMPOUND
;
1062 /* Replace current basic field class */
1063 BT_COMP_LOGT("Replacing current basic field class: "
1064 "bfcr-addr=%p, cur-basic-fc-addr=%p, "
1065 "next-basic-fc-addr=%p",
1066 bfcr
, bfcr
->cur_basic_field_class
, next_field_class
);
1067 bfcr
->cur_basic_field_class
= next_field_class
;
1069 /* Next state: align a basic class */
1070 bfcr
->state
= BFCR_STATE_ALIGN_BASIC
;
1077 static inline enum bt_bfcr_status
handle_state(struct bt_bfcr
*bfcr
)
1079 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
1081 BT_COMP_LOGT("Handling state: bfcr-addr=%p, state=%s", bfcr
, bfcr_state_string(bfcr
->state
));
1083 switch (bfcr
->state
) {
1084 case BFCR_STATE_NEXT_FIELD
:
1085 status
= next_field_state(bfcr
);
1087 case BFCR_STATE_ALIGN_BASIC
:
1088 status
= align_class_state(bfcr
, bfcr
->cur_basic_field_class
, BFCR_STATE_READ_BASIC_BEGIN
);
1090 case BFCR_STATE_ALIGN_COMPOUND
:
1091 status
= align_class_state(bfcr
, stack_top(bfcr
->stack
)->base_class
, BFCR_STATE_NEXT_FIELD
);
1093 case BFCR_STATE_READ_BASIC_BEGIN
:
1094 status
= read_basic_begin_state(bfcr
);
1096 case BFCR_STATE_READ_BASIC_CONTINUE
:
1097 status
= read_basic_continue_state(bfcr
);
1099 case BFCR_STATE_DONE
:
1103 BT_COMP_LOGT("Handled state: bfcr-addr=%p, status=%s", bfcr
, bt_bfcr_status_string(status
));
1107 struct bt_bfcr
*bt_bfcr_create(struct bt_bfcr_cbs cbs
, void *data
, bt_logging_level log_level
,
1108 bt_self_component
*self_comp
)
1110 struct bt_bfcr
*bfcr
;
1112 BT_COMP_LOG_CUR_LVL(BT_LOG_DEBUG
, log_level
, self_comp
,
1113 "Creating binary field class reader (BFCR).");
1114 bfcr
= g_new0(struct bt_bfcr
, 1);
1116 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR
, log_level
, self_comp
,
1117 "Failed to allocate one binary class reader.");
1121 bfcr
->log_level
= log_level
;
1122 bfcr
->self_comp
= self_comp
;
1123 bfcr
->stack
= stack_new(bfcr
);
1125 BT_COMP_LOGE_STR("Cannot create BFCR's stack.");
1126 bt_bfcr_destroy(bfcr
);
1131 bfcr
->state
= BFCR_STATE_NEXT_FIELD
;
1132 bfcr
->user
.cbs
= cbs
;
1133 bfcr
->user
.data
= data
;
1134 BT_COMP_LOGD("Created BFCR: addr=%p", bfcr
);
1140 void bt_bfcr_destroy(struct bt_bfcr
*bfcr
)
1143 stack_destroy(bfcr
->stack
);
1146 BT_COMP_LOGD("Destroying BFCR: addr=%p", bfcr
);
1150 static void reset(struct bt_bfcr
*bfcr
)
1152 BT_COMP_LOGD("Resetting BFCR: addr=%p", bfcr
);
1153 stack_clear(bfcr
->stack
);
1155 bfcr
->buf
.addr
= NULL
;
1156 bfcr
->last_bo
= CTF_BYTE_ORDER_UNKNOWN
;
1159 static void update_packet_offset(struct bt_bfcr
*bfcr
)
1161 BT_COMP_LOGT("Updating packet offset for next call: "
1162 "bfcr-addr=%p, cur-packet-offset=%zu, next-packet-offset=%zu",
1163 bfcr
, bfcr
->buf
.packet_offset
, bfcr
->buf
.packet_offset
+ bfcr
->buf
.at
);
1164 bfcr
->buf
.packet_offset
+= bfcr
->buf
.at
;
1167 size_t bt_bfcr_start(struct bt_bfcr
*bfcr
, struct ctf_field_class
*cls
, const uint8_t *buf
,
1168 size_t offset
, size_t packet_offset
, size_t sz
, enum bt_bfcr_status
*status
)
1170 BT_ASSERT_DBG(bfcr
);
1171 BT_ASSERT_DBG(BYTES_TO_BITS(sz
) >= offset
);
1173 bfcr
->buf
.addr
= buf
;
1174 bfcr
->buf
.offset
= offset
;
1176 bfcr
->buf
.packet_offset
= packet_offset
;
1177 bfcr
->buf
.buf_sz
= sz
;
1178 bfcr
->buf
.sz
= BYTES_TO_BITS(sz
) - offset
;
1179 *status
= BT_BFCR_STATUS_OK
;
1181 BT_COMP_LOGT("Starting decoding: bfcr-addr=%p, fc-addr=%p, "
1182 "buf-addr=%p, buf-size=%zu, offset=%zu, "
1183 "packet-offset=%zu",
1184 bfcr
, cls
, buf
, sz
, offset
, packet_offset
);
1186 /* Set root class */
1187 if (cls
->is_compound
) {
1188 /* Compound class: push on visit stack */
1191 if (bfcr
->user
.cbs
.classes
.compound_begin
) {
1192 BT_COMP_LOGT("Calling user function (compound, begin).");
1193 *status
= bfcr
->user
.cbs
.classes
.compound_begin(cls
, bfcr
->user
.data
);
1194 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(*status
));
1195 if (*status
!= BT_BFCR_STATUS_OK
) {
1196 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s", bfcr
,
1197 bt_bfcr_status_string(*status
));
1202 stack_ret
= stack_push_with_len(bfcr
, cls
);
1204 /* stack_push_with_len() logs errors */
1205 *status
= BT_BFCR_STATUS_ERROR
;
1209 bfcr
->state
= BFCR_STATE_ALIGN_COMPOUND
;
1211 /* Basic class: set as current basic class */
1212 bfcr
->cur_basic_field_class
= cls
;
1213 bfcr
->state
= BFCR_STATE_ALIGN_BASIC
;
1216 /* Run the machine! */
1217 BT_COMP_LOGT_STR("Running the state machine.");
1220 *status
= handle_state(bfcr
);
1221 if (*status
!= BT_BFCR_STATUS_OK
|| bfcr
->state
== BFCR_STATE_DONE
) {
1226 /* Update packet offset for next time */
1227 update_packet_offset(bfcr
);
1230 return bfcr
->buf
.at
;
1233 size_t bt_bfcr_continue(struct bt_bfcr
*bfcr
, const uint8_t *buf
, size_t sz
,
1234 enum bt_bfcr_status
*status
)
1236 BT_ASSERT_DBG(bfcr
);
1238 BT_ASSERT_DBG(sz
> 0);
1239 bfcr
->buf
.addr
= buf
;
1240 bfcr
->buf
.offset
= 0;
1242 bfcr
->buf
.buf_sz
= sz
;
1243 bfcr
->buf
.sz
= BYTES_TO_BITS(sz
);
1244 *status
= BT_BFCR_STATUS_OK
;
1246 BT_COMP_LOGT("Continuing decoding: bfcr-addr=%p, buf-addr=%p, buf-size=%zu", bfcr
, buf
, sz
);
1248 /* Continue running the machine */
1249 BT_COMP_LOGT_STR("Running the state machine.");
1252 *status
= handle_state(bfcr
);
1253 if (*status
!= BT_BFCR_STATUS_OK
|| bfcr
->state
== BFCR_STATE_DONE
) {
1258 /* Update packet offset for next time */
1259 update_packet_offset(bfcr
);
1260 return bfcr
->buf
.at
;
1263 void bt_bfcr_set_unsigned_int_cb(struct bt_bfcr
*bfcr
, bt_bfcr_unsigned_int_cb_func cb
)
1265 BT_ASSERT_DBG(bfcr
);
1267 bfcr
->user
.cbs
.classes
.unsigned_int
= cb
;