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)
10 #define BT_COMP_LOG_SELF_COMP (bfcr->self_comp)
11 #define BT_LOG_OUTPUT_LEVEL (bfcr->log_level)
12 #define BT_LOG_TAG "PLUGIN/CTF/BFCR"
13 #include "logging/comp-logging.h"
21 #include "common/assert.h"
23 #include "compat/bitfield.h"
24 #include "common/common.h"
25 #include <babeltrace2/babeltrace.h>
26 #include "common/align.h"
30 #include "../metadata/ctf-meta.hpp"
32 #define DIV8(_x) ((_x) >> 3)
33 #define BYTES_TO_BITS(_x) ((_x) *8)
34 #define BITS_TO_BYTES_FLOOR(_x) DIV8(_x)
35 #define BITS_TO_BYTES_CEIL(_x) DIV8((_x) + 7)
36 #define IN_BYTE_OFFSET(_at) ((_at) &7)
38 /* A visit stack entry */
42 * Current class of base field, one of:
49 struct ctf_field_class
*base_class
;
51 /* Length of base field (always 1 for a variant class) */
54 /* Index of next field to read */
65 /* Entries (struct stack_entry) */
68 /* Number of active entries */
75 BFCR_STATE_NEXT_FIELD
,
76 BFCR_STATE_ALIGN_BASIC
,
77 BFCR_STATE_ALIGN_COMPOUND
,
78 BFCR_STATE_READ_BASIC_BEGIN
,
79 BFCR_STATE_READ_BASIC_CONTINUE
,
83 /* Binary class reader */
86 bt_logging_level log_level
;
89 bt_self_component
*self_comp
;
94 /* Current basic field class */
95 struct ctf_field_class
*cur_basic_field_class
;
98 enum bfcr_state state
;
101 * Last basic field class's byte order.
103 * This is used to detect errors since two contiguous basic
104 * classes for which the common boundary is not the boundary of
105 * a byte cannot have different byte orders.
107 * This is set to CTF_BYTE_ORDER_UNKNOWN on reset and when the last
108 * basic field class was a string class.
110 enum ctf_byte_order last_bo
;
112 /* Current byte order (copied to last_bo after a successful read) */
113 enum ctf_byte_order cur_bo
;
115 /* Stitch buffer infos */
121 /* Offset, within stitch buffer, of first bit */
124 /* Length (bits) of data in stitch buffer from offset */
128 /* User buffer infos */
134 /* Offset of data from address (bits) */
137 /* Current position from offset (bits) */
140 /* Offset of offset within whole packet (bits) */
141 size_t packet_offset
;
143 /* Data size in buffer (bits) */
146 /* Buffer size (bytes) */
153 /* Callback functions */
154 struct bt_bfcr_cbs cbs
;
161 static inline const char *bfcr_state_string(enum bfcr_state state
)
164 case BFCR_STATE_NEXT_FIELD
:
166 case BFCR_STATE_ALIGN_BASIC
:
167 return "ALIGN_BASIC";
168 case BFCR_STATE_ALIGN_COMPOUND
:
169 return "ALIGN_COMPOUND";
170 case BFCR_STATE_READ_BASIC_BEGIN
:
171 return "READ_BASIC_BEGIN";
172 case BFCR_STATE_READ_BASIC_CONTINUE
:
173 return "READ_BASIC_CONTINUE";
174 case BFCR_STATE_DONE
:
181 static struct stack
*stack_new(struct bt_bfcr
*bfcr
)
183 struct stack
*stack
= NULL
;
185 stack
= g_new0(struct stack
, 1);
187 BT_COMP_LOGE_STR("Failed to allocate one stack.");
192 stack
->entries
= g_array_new(FALSE
, TRUE
, sizeof(struct stack_entry
));
193 if (!stack
->entries
) {
194 BT_COMP_LOGE_STR("Failed to allocate a GArray.");
198 BT_COMP_LOGD("Created stack: addr=%p", stack
);
206 static void stack_destroy(struct stack
*stack
)
208 struct bt_bfcr
*bfcr
;
215 BT_COMP_LOGD("Destroying stack: addr=%p", stack
);
217 if (stack
->entries
) {
218 g_array_free(stack
->entries
, TRUE
);
224 static int stack_push(struct stack
*stack
, struct ctf_field_class
*base_class
, size_t base_len
)
226 struct stack_entry
*entry
;
227 struct bt_bfcr
*bfcr
;
229 BT_ASSERT_DBG(stack
);
230 BT_ASSERT_DBG(base_class
);
232 BT_COMP_LOGT("Pushing field class on stack: stack-addr=%p, "
233 "fc-addr=%p, fc-type=%d, base-length=%zu, "
234 "stack-size-before=%zu, stack-size-after=%zu",
235 stack
, base_class
, base_class
->type
, base_len
, stack
->size
, stack
->size
+ 1);
237 if (stack
->entries
->len
== stack
->size
) {
238 g_array_set_size(stack
->entries
, stack
->size
+ 1);
241 entry
= &bt_g_array_index(stack
->entries
, struct stack_entry
, stack
->size
);
242 entry
->base_class
= base_class
;
243 entry
->base_len
= base_len
;
249 static inline int64_t get_compound_field_class_length(struct bt_bfcr
*bfcr
,
250 struct ctf_field_class
*fc
)
255 case CTF_FIELD_CLASS_TYPE_STRUCT
:
257 ctf_field_class_struct
*struct_fc
= ctf_field_class_as_struct(fc
);
259 length
= (int64_t) struct_fc
->members
->len
;
262 case CTF_FIELD_CLASS_TYPE_VARIANT
:
264 /* Variant field classes always "contain" a single class */
268 case CTF_FIELD_CLASS_TYPE_ARRAY
:
270 struct ctf_field_class_array
*array_fc
= ctf_field_class_as_array(fc
);
272 length
= (int64_t) array_fc
->length
;
275 case CTF_FIELD_CLASS_TYPE_SEQUENCE
:
276 length
= bfcr
->user
.cbs
.query
.get_sequence_length(fc
, bfcr
->user
.data
);
285 static int stack_push_with_len(struct bt_bfcr
*bfcr
, struct ctf_field_class
*base_class
)
288 int64_t length
= get_compound_field_class_length(bfcr
, base_class
);
291 BT_COMP_LOGW("Cannot get compound field class's field count: "
292 "bfcr-addr=%p, fc-addr=%p, fc-type=%d",
293 bfcr
, base_class
, base_class
->type
);
294 ret
= BT_BFCR_STATUS_ERROR
;
298 ret
= stack_push(bfcr
->stack
, base_class
, (size_t) length
);
304 static inline unsigned int stack_size(struct stack
*stack
)
306 BT_ASSERT_DBG(stack
);
310 static void stack_pop(struct stack
*stack
)
312 struct bt_bfcr
*bfcr
;
314 BT_ASSERT_DBG(stack
);
315 BT_ASSERT_DBG(stack_size(stack
));
317 BT_COMP_LOGT("Popping from stack: "
318 "stack-addr=%p, stack-size-before=%u, stack-size-after=%u",
319 stack
, stack
->entries
->len
, stack
->entries
->len
- 1);
323 static inline bool stack_empty(struct stack
*stack
)
325 return stack_size(stack
) == 0;
328 static void stack_clear(struct stack
*stack
)
330 BT_ASSERT_DBG(stack
);
334 static inline struct stack_entry
*stack_top(struct stack
*stack
)
336 BT_ASSERT_DBG(stack
);
337 BT_ASSERT_DBG(stack_size(stack
));
338 return &bt_g_array_index(stack
->entries
, struct stack_entry
, stack
->size
- 1);
341 static inline size_t available_bits(struct bt_bfcr
*bfcr
)
343 return bfcr
->buf
.sz
- bfcr
->buf
.at
;
346 static inline void consume_bits(struct bt_bfcr
*bfcr
, size_t incr
)
348 BT_COMP_LOGT("Advancing cursor: bfcr-addr=%p, cur-before=%zu, cur-after=%zu", bfcr
,
349 bfcr
->buf
.at
, bfcr
->buf
.at
+ incr
);
350 bfcr
->buf
.at
+= incr
;
353 static inline bool has_enough_bits(struct bt_bfcr
*bfcr
, size_t sz
)
355 return available_bits(bfcr
) >= sz
;
358 static inline bool at_least_one_bit_left(struct bt_bfcr
*bfcr
)
360 return has_enough_bits(bfcr
, 1);
363 static inline size_t packet_at(struct bt_bfcr
*bfcr
)
365 return bfcr
->buf
.packet_offset
+ bfcr
->buf
.at
;
368 static inline size_t buf_at_from_addr(struct bt_bfcr
*bfcr
)
373 * ====== offset ===== (17)
375 * xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
377 * addr (0) ==== at ==== (12)
381 * =============================== (29)
383 return bfcr
->buf
.offset
+ bfcr
->buf
.at
;
386 static void stitch_reset(struct bt_bfcr
*bfcr
)
388 bfcr
->stitch
.offset
= 0;
392 static inline size_t stitch_at_from_addr(struct bt_bfcr
*bfcr
)
394 return bfcr
->stitch
.offset
+ bfcr
->stitch
.at
;
397 static void stitch_append_from_buf(struct bt_bfcr
*bfcr
, size_t sz
)
399 size_t stitch_byte_at
;
407 stitch_byte_at
= BITS_TO_BYTES_FLOOR(stitch_at_from_addr(bfcr
));
408 buf_byte_at
= BITS_TO_BYTES_FLOOR(buf_at_from_addr(bfcr
));
409 nb_bytes
= BITS_TO_BYTES_CEIL(sz
);
410 BT_ASSERT(nb_bytes
> 0);
411 BT_ASSERT(bfcr
->buf
.addr
);
412 memcpy(&bfcr
->stitch
.buf
[stitch_byte_at
], &bfcr
->buf
.addr
[buf_byte_at
], nb_bytes
);
413 bfcr
->stitch
.at
+= sz
;
414 consume_bits(bfcr
, sz
);
417 static void stitch_append_from_remaining_buf(struct bt_bfcr
*bfcr
)
419 stitch_append_from_buf(bfcr
, available_bits(bfcr
));
422 static void stitch_set_from_remaining_buf(struct bt_bfcr
*bfcr
)
425 bfcr
->stitch
.offset
= IN_BYTE_OFFSET(buf_at_from_addr(bfcr
));
426 stitch_append_from_remaining_buf(bfcr
);
429 static inline void read_unsigned_bitfield(struct bt_bfcr
*bfcr
, const uint8_t *buf
, size_t at
,
430 unsigned int field_size
, enum ctf_byte_order bo
,
434 case CTF_BYTE_ORDER_BIG
:
435 bt_bitfield_read_be(buf
, uint8_t, at
, field_size
, v
);
437 case CTF_BYTE_ORDER_LITTLE
:
438 bt_bitfield_read_le(buf
, uint8_t, at
, field_size
, v
);
444 BT_COMP_LOGT("Read unsigned bit array: cur=%zu, size=%u, "
445 "bo=%d, val=%" PRIu64
,
446 at
, field_size
, bo
, *v
);
449 static inline void read_signed_bitfield(struct bt_bfcr
*bfcr
, const uint8_t *buf
, size_t at
,
450 unsigned int field_size
, enum ctf_byte_order bo
, int64_t *v
)
453 case CTF_BYTE_ORDER_BIG
:
454 bt_bitfield_read_be(buf
, uint8_t, at
, field_size
, v
);
456 case CTF_BYTE_ORDER_LITTLE
:
457 bt_bitfield_read_le(buf
, uint8_t, at
, field_size
, v
);
463 BT_COMP_LOGT("Read signed bit array: cur=%zu, size=%u, "
464 "bo=%d, val=%" PRId64
,
465 at
, field_size
, bo
, *v
);
468 typedef enum bt_bfcr_status (*read_basic_and_call_cb_t
)(struct bt_bfcr
*, const uint8_t *, size_t);
470 static inline enum bt_bfcr_status
validate_contiguous_bo(struct bt_bfcr
*bfcr
,
471 enum ctf_byte_order next_bo
)
473 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
475 /* Always valid when at a byte boundary */
476 if (packet_at(bfcr
) % 8 == 0) {
480 /* Always valid if last byte order is unknown */
481 if (bfcr
->last_bo
== CTF_BYTE_ORDER_UNKNOWN
) {
485 /* Always valid if next byte order is unknown */
486 if (next_bo
== CTF_BYTE_ORDER_UNKNOWN
) {
490 /* Make sure last byte order is compatible with the next byte order */
491 switch (bfcr
->last_bo
) {
492 case CTF_BYTE_ORDER_BIG
:
493 if (next_bo
!= CTF_BYTE_ORDER_BIG
) {
494 status
= BT_BFCR_STATUS_ERROR
;
497 case CTF_BYTE_ORDER_LITTLE
:
498 if (next_bo
!= CTF_BYTE_ORDER_LITTLE
) {
499 status
= BT_BFCR_STATUS_ERROR
;
503 status
= BT_BFCR_STATUS_ERROR
;
508 BT_COMP_LOGW("Cannot read bit array: two different byte orders not at a byte boundary: "
509 "bfcr-addr=%p, last-bo=%d, next-bo=%d",
510 bfcr
, bfcr
->last_bo
, next_bo
);
516 static enum bt_bfcr_status
read_basic_float_and_call_cb(struct bt_bfcr
*bfcr
, const uint8_t *buf
,
520 unsigned int field_size
;
521 enum ctf_byte_order bo
;
522 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
523 ctf_field_class_float
*fc
= ctf_field_class_as_float(bfcr
->cur_basic_field_class
);
526 field_size
= fc
->base
.size
;
527 bo
= fc
->base
.byte_order
;
530 switch (field_size
) {
540 read_unsigned_bitfield(bfcr
, buf
, at
, field_size
, bo
, &v
);
541 f32
.u
= (uint32_t) v
;
542 dblval
= (double) f32
.f
;
553 read_unsigned_bitfield(bfcr
, buf
, at
, field_size
, bo
, &f64
.u
);
558 /* Only 32-bit and 64-bit fields are supported currently */
562 BT_COMP_LOGT("Read floating point number value: bfcr=%p, cur=%zu, val=%f", bfcr
, at
, dblval
);
564 if (bfcr
->user
.cbs
.classes
.floating_point
) {
565 BT_COMP_LOGT("Calling user function (floating point number).");
566 status
= bfcr
->user
.cbs
.classes
.floating_point(dblval
, bfcr
->cur_basic_field_class
,
568 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
569 if (status
!= BT_BFCR_STATUS_OK
) {
570 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s", bfcr
,
571 bt_bfcr_status_string(status
));
578 static inline enum bt_bfcr_status
read_basic_int_and_call_cb(struct bt_bfcr
*bfcr
,
579 const uint8_t *buf
, size_t at
)
581 unsigned int field_size
;
582 enum ctf_byte_order bo
;
583 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
584 ctf_field_class_int
*fc
= ctf_field_class_as_int(bfcr
->cur_basic_field_class
);
586 field_size
= fc
->base
.size
;
587 bo
= fc
->base
.byte_order
;
590 * Update current byte order now because we could be reading
591 * the integer value of an enumeration class, and thus we know
592 * here the actual supporting integer class's byte order.
599 read_signed_bitfield(bfcr
, buf
, at
, field_size
, bo
, &v
);
601 if (bfcr
->user
.cbs
.classes
.signed_int
) {
602 BT_COMP_LOGT("Calling user function (signed integer).");
604 bfcr
->user
.cbs
.classes
.signed_int(v
, bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
605 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
606 if (status
!= BT_BFCR_STATUS_OK
) {
607 BT_COMP_LOGW("User function failed: "
608 "bfcr-addr=%p, status=%s",
609 bfcr
, bt_bfcr_status_string(status
));
615 read_unsigned_bitfield(bfcr
, buf
, at
, field_size
, bo
, &v
);
617 if (bfcr
->user
.cbs
.classes
.unsigned_int
) {
618 BT_COMP_LOGT("Calling user function (unsigned integer).");
619 status
= bfcr
->user
.cbs
.classes
.unsigned_int(v
, bfcr
->cur_basic_field_class
,
621 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
622 if (status
!= BT_BFCR_STATUS_OK
) {
623 BT_COMP_LOGW("User function failed: "
624 "bfcr-addr=%p, status=%s",
625 bfcr
, bt_bfcr_status_string(status
));
633 static inline enum bt_bfcr_status
634 read_bit_array_class_and_call_continue(struct bt_bfcr
*bfcr
,
635 read_basic_and_call_cb_t read_basic_and_call_cb
)
639 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
640 ctf_field_class_bit_array
*fc
= ctf_field_class_as_bit_array(bfcr
->cur_basic_field_class
);
642 if (!at_least_one_bit_left(bfcr
)) {
643 BT_COMP_LOGT("Reached end of data: bfcr-addr=%p", bfcr
);
644 status
= BT_BFCR_STATUS_EOF
;
648 available
= available_bits(bfcr
);
649 needed_bits
= fc
->size
- bfcr
->stitch
.at
;
650 BT_COMP_LOGT("Continuing basic field decoding: "
651 "bfcr-addr=%p, field-size=%u, needed-size=%zu, "
652 "available-size=%zu",
653 bfcr
, fc
->size
, needed_bits
, available
);
654 if (needed_bits
<= available
) {
655 /* We have all the bits; append to stitch, then decode */
656 stitch_append_from_buf(bfcr
, needed_bits
);
657 status
= read_basic_and_call_cb(bfcr
, bfcr
->stitch
.buf
, bfcr
->stitch
.offset
);
658 if (status
!= BT_BFCR_STATUS_OK
) {
659 BT_COMP_LOGW("Cannot read basic field: "
660 "bfcr-addr=%p, fc-addr=%p, status=%s",
661 bfcr
, bfcr
->cur_basic_field_class
, bt_bfcr_status_string(status
));
665 if (stack_empty(bfcr
->stack
)) {
666 /* Root is a basic class */
667 bfcr
->state
= BFCR_STATE_DONE
;
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
;
677 /* We are here; it means we don't have enough data to decode this */
678 BT_COMP_LOGT_STR("Not enough data to read the next basic field: appending to stitch buffer.");
679 stitch_append_from_remaining_buf(bfcr
);
680 status
= BT_BFCR_STATUS_EOF
;
686 static inline enum bt_bfcr_status
687 read_bit_array_class_and_call_begin(struct bt_bfcr
*bfcr
,
688 read_basic_and_call_cb_t read_basic_and_call_cb
)
691 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
692 ctf_field_class_bit_array
*fc
= ctf_field_class_as_bit_array(bfcr
->cur_basic_field_class
);
694 if (!at_least_one_bit_left(bfcr
)) {
695 BT_COMP_LOGT("Reached end of data: bfcr-addr=%p", bfcr
);
696 status
= BT_BFCR_STATUS_EOF
;
700 status
= validate_contiguous_bo(bfcr
, fc
->byte_order
);
701 if (status
!= BT_BFCR_STATUS_OK
) {
702 /* validate_contiguous_bo() logs errors */
706 available
= available_bits(bfcr
);
708 if (fc
->size
<= available
) {
709 /* We have all the bits; decode and set now */
710 BT_ASSERT_DBG(bfcr
->buf
.addr
);
711 status
= read_basic_and_call_cb(bfcr
, bfcr
->buf
.addr
, buf_at_from_addr(bfcr
));
712 if (status
!= BT_BFCR_STATUS_OK
) {
713 BT_COMP_LOGW("Cannot read basic field: "
714 "bfcr-addr=%p, fc-addr=%p, status=%s",
715 bfcr
, bfcr
->cur_basic_field_class
, bt_bfcr_status_string(status
));
719 consume_bits(bfcr
, fc
->size
);
721 if (stack_empty(bfcr
->stack
)) {
722 /* Root is a basic class */
723 bfcr
->state
= BFCR_STATE_DONE
;
725 /* Go to next field */
726 stack_top(bfcr
->stack
)->index
++;
727 bfcr
->state
= BFCR_STATE_NEXT_FIELD
;
728 bfcr
->last_bo
= bfcr
->cur_bo
;
734 /* We are here; it means we don't have enough data to decode this */
735 BT_COMP_LOGT_STR("Not enough data to read the next basic field: setting stitch buffer.");
736 stitch_set_from_remaining_buf(bfcr
);
737 bfcr
->state
= BFCR_STATE_READ_BASIC_CONTINUE
;
738 status
= BT_BFCR_STATUS_EOF
;
744 static inline enum bt_bfcr_status
read_basic_int_class_and_call_begin(struct bt_bfcr
*bfcr
)
746 return read_bit_array_class_and_call_begin(bfcr
, read_basic_int_and_call_cb
);
749 static inline enum bt_bfcr_status
read_basic_int_class_and_call_continue(struct bt_bfcr
*bfcr
)
751 return read_bit_array_class_and_call_continue(bfcr
, read_basic_int_and_call_cb
);
754 static inline enum bt_bfcr_status
read_basic_float_class_and_call_begin(struct bt_bfcr
*bfcr
)
756 return read_bit_array_class_and_call_begin(bfcr
, read_basic_float_and_call_cb
);
759 static inline enum bt_bfcr_status
read_basic_float_class_and_call_continue(struct bt_bfcr
*bfcr
)
761 return read_bit_array_class_and_call_continue(bfcr
, read_basic_float_and_call_cb
);
764 static inline enum bt_bfcr_status
read_basic_string_class_and_call(struct bt_bfcr
*bfcr
, bool begin
)
767 const uint8_t *result
;
768 size_t available_bytes
;
769 const uint8_t *first_chr
;
770 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
772 if (!at_least_one_bit_left(bfcr
)) {
773 BT_COMP_LOGT("Reached end of data: bfcr-addr=%p", bfcr
);
774 status
= BT_BFCR_STATUS_EOF
;
778 BT_ASSERT_DBG(buf_at_from_addr(bfcr
) % 8 == 0);
779 available_bytes
= BITS_TO_BYTES_FLOOR(available_bits(bfcr
));
780 buf_at_bytes
= BITS_TO_BYTES_FLOOR(buf_at_from_addr(bfcr
));
781 BT_ASSERT_DBG(bfcr
->buf
.addr
);
782 first_chr
= &bfcr
->buf
.addr
[buf_at_bytes
];
783 result
= (const uint8_t *) memchr(first_chr
, '\0', available_bytes
);
785 if (begin
&& bfcr
->user
.cbs
.classes
.string_begin
) {
786 BT_COMP_LOGT("Calling user function (string, beginning).");
787 status
= bfcr
->user
.cbs
.classes
.string_begin(bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
788 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
789 if (status
!= BT_BFCR_STATUS_OK
) {
790 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s", bfcr
,
791 bt_bfcr_status_string(status
));
797 /* No null character yet */
798 if (bfcr
->user
.cbs
.classes
.string
) {
799 BT_COMP_LOGT("Calling user function (substring).");
800 status
= bfcr
->user
.cbs
.classes
.string((const char *) first_chr
, available_bytes
,
801 bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
802 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
803 if (status
!= BT_BFCR_STATUS_OK
) {
804 BT_COMP_LOGW("User function failed: "
805 "bfcr-addr=%p, status=%s",
806 bfcr
, bt_bfcr_status_string(status
));
811 consume_bits(bfcr
, BYTES_TO_BITS(available_bytes
));
812 bfcr
->state
= BFCR_STATE_READ_BASIC_CONTINUE
;
813 status
= BT_BFCR_STATUS_EOF
;
815 /* Found the null character */
816 size_t result_len
= (size_t) (result
- first_chr
);
818 if (bfcr
->user
.cbs
.classes
.string
&& result_len
) {
819 BT_COMP_LOGT("Calling user function (substring).");
820 status
= bfcr
->user
.cbs
.classes
.string((const char *) first_chr
, result_len
,
821 bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
822 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
823 if (status
!= BT_BFCR_STATUS_OK
) {
824 BT_COMP_LOGW("User function failed: "
825 "bfcr-addr=%p, status=%s",
826 bfcr
, bt_bfcr_status_string(status
));
831 if (bfcr
->user
.cbs
.classes
.string_end
) {
832 BT_COMP_LOGT("Calling user function (string, end).");
834 bfcr
->user
.cbs
.classes
.string_end(bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
835 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
836 if (status
!= BT_BFCR_STATUS_OK
) {
837 BT_COMP_LOGW("User function failed: "
838 "bfcr-addr=%p, status=%s",
839 bfcr
, bt_bfcr_status_string(status
));
844 consume_bits(bfcr
, BYTES_TO_BITS(result_len
+ 1));
846 if (stack_empty(bfcr
->stack
)) {
847 /* Root is a basic class */
848 bfcr
->state
= BFCR_STATE_DONE
;
850 /* Go to next field */
851 stack_top(bfcr
->stack
)->index
++;
852 bfcr
->state
= BFCR_STATE_NEXT_FIELD
;
853 bfcr
->last_bo
= bfcr
->cur_bo
;
861 static inline enum bt_bfcr_status
read_basic_begin_state(struct bt_bfcr
*bfcr
)
863 enum bt_bfcr_status status
;
865 BT_ASSERT_DBG(bfcr
->cur_basic_field_class
);
867 switch (bfcr
->cur_basic_field_class
->type
) {
868 case CTF_FIELD_CLASS_TYPE_INT
:
869 case CTF_FIELD_CLASS_TYPE_ENUM
:
870 status
= read_basic_int_class_and_call_begin(bfcr
);
872 case CTF_FIELD_CLASS_TYPE_FLOAT
:
873 status
= read_basic_float_class_and_call_begin(bfcr
);
875 case CTF_FIELD_CLASS_TYPE_STRING
:
876 status
= read_basic_string_class_and_call(bfcr
, true);
885 static inline enum bt_bfcr_status
read_basic_continue_state(struct bt_bfcr
*bfcr
)
887 enum bt_bfcr_status status
;
889 BT_ASSERT_DBG(bfcr
->cur_basic_field_class
);
891 switch (bfcr
->cur_basic_field_class
->type
) {
892 case CTF_FIELD_CLASS_TYPE_INT
:
893 case CTF_FIELD_CLASS_TYPE_ENUM
:
894 status
= read_basic_int_class_and_call_continue(bfcr
);
896 case CTF_FIELD_CLASS_TYPE_FLOAT
:
897 status
= read_basic_float_class_and_call_continue(bfcr
);
899 case CTF_FIELD_CLASS_TYPE_STRING
:
900 status
= read_basic_string_class_and_call(bfcr
, false);
909 static inline size_t bits_to_skip_to_align_to(struct bt_bfcr
*bfcr
, size_t align
)
911 size_t aligned_packet_at
;
913 aligned_packet_at
= BT_ALIGN(packet_at(bfcr
), align
);
914 return aligned_packet_at
- packet_at(bfcr
);
917 static inline enum bt_bfcr_status
align_class_state(struct bt_bfcr
*bfcr
,
918 struct ctf_field_class
*field_class
,
919 enum bfcr_state next_state
)
921 unsigned int field_alignment
;
923 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
925 /* Get field's alignment */
926 field_alignment
= field_class
->alignment
;
929 * 0 means "undefined" for variants; what we really want is 1
932 BT_ASSERT_DBG(field_alignment
>= 1);
934 /* Compute how many bits we need to skip */
935 skip_bits
= bits_to_skip_to_align_to(bfcr
, (size_t) field_alignment
);
937 /* Nothing to skip? aligned */
938 if (skip_bits
== 0) {
939 bfcr
->state
= next_state
;
943 /* Make sure there's at least one bit left */
944 if (!at_least_one_bit_left(bfcr
)) {
945 status
= BT_BFCR_STATUS_EOF
;
949 /* Consume as many bits as possible in what's left */
950 consume_bits(bfcr
, MIN(available_bits(bfcr
), skip_bits
));
952 /* Are we done now? */
953 skip_bits
= bits_to_skip_to_align_to(bfcr
, field_alignment
);
954 if (skip_bits
== 0) {
955 /* Yes: go to next state */
956 bfcr
->state
= next_state
;
959 /* No: need more data */
960 BT_COMP_LOGT("Reached end of data when aligning: bfcr-addr=%p", bfcr
);
961 status
= BT_BFCR_STATUS_EOF
;
968 static inline enum bt_bfcr_status
next_field_state(struct bt_bfcr
*bfcr
)
971 struct stack_entry
*top
;
972 struct ctf_field_class
*next_field_class
= NULL
;
973 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
975 if (stack_empty(bfcr
->stack
)) {
979 top
= stack_top(bfcr
->stack
);
981 /* Are we done with this base class? */
982 while (top
->index
== top
->base_len
) {
983 if (bfcr
->user
.cbs
.classes
.compound_end
) {
984 BT_COMP_LOGT("Calling user function (compound, end).");
985 status
= bfcr
->user
.cbs
.classes
.compound_end(top
->base_class
, bfcr
->user
.data
);
986 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
987 if (status
!= BT_BFCR_STATUS_OK
) {
988 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s", bfcr
,
989 bt_bfcr_status_string(status
));
994 stack_pop(bfcr
->stack
);
996 /* Are we done with the root class? */
997 if (stack_empty(bfcr
->stack
)) {
998 bfcr
->state
= BFCR_STATE_DONE
;
1002 top
= stack_top(bfcr
->stack
);
1006 /* Get next field's class */
1007 switch (top
->base_class
->type
) {
1008 case CTF_FIELD_CLASS_TYPE_STRUCT
:
1009 next_field_class
= ctf_field_class_struct_borrow_member_by_index(
1010 ctf_field_class_as_struct(top
->base_class
), (uint64_t) top
->index
)
1013 case CTF_FIELD_CLASS_TYPE_ARRAY
:
1014 case CTF_FIELD_CLASS_TYPE_SEQUENCE
:
1016 ctf_field_class_array_base
*array_fc
= ctf_field_class_as_array_base(top
->base_class
);
1018 next_field_class
= array_fc
->elem_fc
;
1021 case CTF_FIELD_CLASS_TYPE_VARIANT
:
1022 /* Variant classes are dynamic: the user should know! */
1023 next_field_class
= bfcr
->user
.cbs
.query
.borrow_variant_selected_field_class(
1024 top
->base_class
, bfcr
->user
.data
);
1030 if (!next_field_class
) {
1031 BT_COMP_LOGW("Cannot get the field class of the next field: "
1032 "bfcr-addr=%p, base-fc-addr=%p, base-fc-type=%d, "
1034 bfcr
, top
->base_class
, top
->base_class
->type
, top
->index
);
1035 status
= BT_BFCR_STATUS_ERROR
;
1039 if (next_field_class
->is_compound
) {
1040 if (bfcr
->user
.cbs
.classes
.compound_begin
) {
1041 BT_COMP_LOGT("Calling user function (compound, begin).");
1042 status
= bfcr
->user
.cbs
.classes
.compound_begin(next_field_class
, bfcr
->user
.data
);
1043 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
1044 if (status
!= BT_BFCR_STATUS_OK
) {
1045 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s", bfcr
,
1046 bt_bfcr_status_string(status
));
1051 ret
= stack_push_with_len(bfcr
, next_field_class
);
1053 /* stack_push_with_len() logs errors */
1054 status
= BT_BFCR_STATUS_ERROR
;
1058 /* Next state: align a compound class */
1059 bfcr
->state
= BFCR_STATE_ALIGN_COMPOUND
;
1061 /* Replace current basic field class */
1062 BT_COMP_LOGT("Replacing current basic field class: "
1063 "bfcr-addr=%p, cur-basic-fc-addr=%p, "
1064 "next-basic-fc-addr=%p",
1065 bfcr
, bfcr
->cur_basic_field_class
, next_field_class
);
1066 bfcr
->cur_basic_field_class
= next_field_class
;
1068 /* Next state: align a basic class */
1069 bfcr
->state
= BFCR_STATE_ALIGN_BASIC
;
1076 static inline enum bt_bfcr_status
handle_state(struct bt_bfcr
*bfcr
)
1078 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
1080 BT_COMP_LOGT("Handling state: bfcr-addr=%p, state=%s", bfcr
, bfcr_state_string(bfcr
->state
));
1082 switch (bfcr
->state
) {
1083 case BFCR_STATE_NEXT_FIELD
:
1084 status
= next_field_state(bfcr
);
1086 case BFCR_STATE_ALIGN_BASIC
:
1087 status
= align_class_state(bfcr
, bfcr
->cur_basic_field_class
, BFCR_STATE_READ_BASIC_BEGIN
);
1089 case BFCR_STATE_ALIGN_COMPOUND
:
1090 status
= align_class_state(bfcr
, stack_top(bfcr
->stack
)->base_class
, BFCR_STATE_NEXT_FIELD
);
1092 case BFCR_STATE_READ_BASIC_BEGIN
:
1093 status
= read_basic_begin_state(bfcr
);
1095 case BFCR_STATE_READ_BASIC_CONTINUE
:
1096 status
= read_basic_continue_state(bfcr
);
1098 case BFCR_STATE_DONE
:
1102 BT_COMP_LOGT("Handled state: bfcr-addr=%p, status=%s", bfcr
, bt_bfcr_status_string(status
));
1106 struct bt_bfcr
*bt_bfcr_create(struct bt_bfcr_cbs cbs
, void *data
, bt_logging_level log_level
,
1107 bt_self_component
*self_comp
)
1109 struct bt_bfcr
*bfcr
;
1111 BT_COMP_LOG_CUR_LVL(BT_LOG_DEBUG
, log_level
, self_comp
,
1112 "Creating binary field class reader (BFCR).");
1113 bfcr
= g_new0(struct bt_bfcr
, 1);
1115 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR
, log_level
, self_comp
,
1116 "Failed to allocate one binary class reader.");
1120 bfcr
->log_level
= log_level
;
1121 bfcr
->self_comp
= self_comp
;
1122 bfcr
->stack
= stack_new(bfcr
);
1124 BT_COMP_LOGE_STR("Cannot create BFCR's stack.");
1125 bt_bfcr_destroy(bfcr
);
1130 bfcr
->state
= BFCR_STATE_NEXT_FIELD
;
1131 bfcr
->user
.cbs
= cbs
;
1132 bfcr
->user
.data
= data
;
1133 BT_COMP_LOGD("Created BFCR: addr=%p", bfcr
);
1139 void bt_bfcr_destroy(struct bt_bfcr
*bfcr
)
1142 stack_destroy(bfcr
->stack
);
1145 BT_COMP_LOGD("Destroying BFCR: addr=%p", bfcr
);
1149 static void reset(struct bt_bfcr
*bfcr
)
1151 BT_COMP_LOGD("Resetting BFCR: addr=%p", bfcr
);
1152 stack_clear(bfcr
->stack
);
1154 bfcr
->buf
.addr
= NULL
;
1155 bfcr
->last_bo
= CTF_BYTE_ORDER_UNKNOWN
;
1158 static void update_packet_offset(struct bt_bfcr
*bfcr
)
1160 BT_COMP_LOGT("Updating packet offset for next call: "
1161 "bfcr-addr=%p, cur-packet-offset=%zu, next-packet-offset=%zu",
1162 bfcr
, bfcr
->buf
.packet_offset
, bfcr
->buf
.packet_offset
+ bfcr
->buf
.at
);
1163 bfcr
->buf
.packet_offset
+= bfcr
->buf
.at
;
1166 size_t bt_bfcr_start(struct bt_bfcr
*bfcr
, struct ctf_field_class
*cls
, const uint8_t *buf
,
1167 size_t offset
, size_t packet_offset
, size_t sz
, enum bt_bfcr_status
*status
)
1169 BT_ASSERT_DBG(bfcr
);
1170 BT_ASSERT_DBG(BYTES_TO_BITS(sz
) >= offset
);
1172 bfcr
->buf
.addr
= buf
;
1173 bfcr
->buf
.offset
= offset
;
1175 bfcr
->buf
.packet_offset
= packet_offset
;
1176 bfcr
->buf
.buf_sz
= sz
;
1177 bfcr
->buf
.sz
= BYTES_TO_BITS(sz
) - offset
;
1178 *status
= BT_BFCR_STATUS_OK
;
1180 BT_COMP_LOGT("Starting decoding: bfcr-addr=%p, fc-addr=%p, "
1181 "buf-addr=%p, buf-size=%zu, offset=%zu, "
1182 "packet-offset=%zu",
1183 bfcr
, cls
, buf
, sz
, offset
, packet_offset
);
1185 /* Set root class */
1186 if (cls
->is_compound
) {
1187 /* Compound class: push on visit stack */
1190 if (bfcr
->user
.cbs
.classes
.compound_begin
) {
1191 BT_COMP_LOGT("Calling user function (compound, begin).");
1192 *status
= bfcr
->user
.cbs
.classes
.compound_begin(cls
, bfcr
->user
.data
);
1193 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(*status
));
1194 if (*status
!= BT_BFCR_STATUS_OK
) {
1195 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s", bfcr
,
1196 bt_bfcr_status_string(*status
));
1201 stack_ret
= stack_push_with_len(bfcr
, cls
);
1203 /* stack_push_with_len() logs errors */
1204 *status
= BT_BFCR_STATUS_ERROR
;
1208 bfcr
->state
= BFCR_STATE_ALIGN_COMPOUND
;
1210 /* Basic class: set as current basic class */
1211 bfcr
->cur_basic_field_class
= cls
;
1212 bfcr
->state
= BFCR_STATE_ALIGN_BASIC
;
1215 /* Run the machine! */
1216 BT_COMP_LOGT_STR("Running the state machine.");
1219 *status
= handle_state(bfcr
);
1220 if (*status
!= BT_BFCR_STATUS_OK
|| bfcr
->state
== BFCR_STATE_DONE
) {
1225 /* Update packet offset for next time */
1226 update_packet_offset(bfcr
);
1229 return bfcr
->buf
.at
;
1232 size_t bt_bfcr_continue(struct bt_bfcr
*bfcr
, const uint8_t *buf
, size_t sz
,
1233 enum bt_bfcr_status
*status
)
1235 BT_ASSERT_DBG(bfcr
);
1237 BT_ASSERT_DBG(sz
> 0);
1238 bfcr
->buf
.addr
= buf
;
1239 bfcr
->buf
.offset
= 0;
1241 bfcr
->buf
.buf_sz
= sz
;
1242 bfcr
->buf
.sz
= BYTES_TO_BITS(sz
);
1243 *status
= BT_BFCR_STATUS_OK
;
1245 BT_COMP_LOGT("Continuing decoding: bfcr-addr=%p, buf-addr=%p, buf-size=%zu", bfcr
, buf
, sz
);
1247 /* Continue running the machine */
1248 BT_COMP_LOGT_STR("Running the state machine.");
1251 *status
= handle_state(bfcr
);
1252 if (*status
!= BT_BFCR_STATUS_OK
|| bfcr
->state
== BFCR_STATE_DONE
) {
1257 /* Update packet offset for next time */
1258 update_packet_offset(bfcr
);
1259 return bfcr
->buf
.at
;
1262 void bt_bfcr_set_unsigned_int_cb(struct bt_bfcr
*bfcr
, bt_bfcr_unsigned_int_cb_func cb
)
1264 BT_ASSERT_DBG(bfcr
);
1266 bfcr
->user
.cbs
.classes
.unsigned_int
= cb
;