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)
16 #include <babeltrace2/babeltrace.h>
18 #define BT_COMP_LOG_SELF_COMP (bfcr->self_comp)
19 #define BT_LOG_OUTPUT_LEVEL (bfcr->log_level)
20 #define BT_LOG_TAG "PLUGIN/CTF/BFCR"
21 #include "logging/comp-logging.h"
23 #include "common/align.h"
24 #include "common/assert.h"
25 #include "common/common.h"
26 #include "compat/bitfield.h"
28 #include "../metadata/ctf-meta.hpp"
31 #define DIV8(_x) ((_x) >> 3)
32 #define BYTES_TO_BITS(_x) ((_x) *8)
33 #define BITS_TO_BYTES_FLOOR(_x) DIV8(_x)
34 #define BITS_TO_BYTES_CEIL(_x) DIV8((_x) + 7)
35 #define IN_BYTE_OFFSET(_at) ((_at) &7)
37 /* A visit stack entry */
41 * Current class of base field, one of:
48 struct ctf_field_class
*base_class
;
50 /* Length of base field (always 1 for a variant class) */
53 /* Index of next field to read */
62 /* Entries (struct stack_entry) */
65 /* Number of active entries */
72 BFCR_STATE_NEXT_FIELD
,
73 BFCR_STATE_ALIGN_BASIC
,
74 BFCR_STATE_ALIGN_COMPOUND
,
75 BFCR_STATE_READ_BASIC_BEGIN
,
76 BFCR_STATE_READ_BASIC_CONTINUE
,
80 /* Binary class reader */
83 bt_logging_level log_level
;
86 bt_self_component
*self_comp
;
91 /* Current basic field class */
92 struct ctf_field_class
*cur_basic_field_class
;
95 enum bfcr_state state
;
98 * Last basic field class's byte order.
100 * This is used to detect errors since two contiguous basic
101 * classes for which the common boundary is not the boundary of
102 * a byte cannot have different byte orders.
104 * This is set to CTF_BYTE_ORDER_UNKNOWN on reset and when the last
105 * basic field class was a string class.
107 enum ctf_byte_order last_bo
;
109 /* Current byte order (copied to last_bo after a successful read) */
110 enum ctf_byte_order cur_bo
;
112 /* Stitch buffer infos */
118 /* Offset, within stitch buffer, of first bit */
121 /* Length (bits) of data in stitch buffer from offset */
125 /* User buffer infos */
131 /* Offset of data from address (bits) */
134 /* Current position from offset (bits) */
137 /* Offset of offset within whole packet (bits) */
138 size_t packet_offset
;
140 /* Data size in buffer (bits) */
143 /* Buffer size (bytes) */
150 /* Callback functions */
151 struct bt_bfcr_cbs cbs
;
158 static inline const char *bfcr_state_string(enum bfcr_state state
)
161 case BFCR_STATE_NEXT_FIELD
:
163 case BFCR_STATE_ALIGN_BASIC
:
164 return "ALIGN_BASIC";
165 case BFCR_STATE_ALIGN_COMPOUND
:
166 return "ALIGN_COMPOUND";
167 case BFCR_STATE_READ_BASIC_BEGIN
:
168 return "READ_BASIC_BEGIN";
169 case BFCR_STATE_READ_BASIC_CONTINUE
:
170 return "READ_BASIC_CONTINUE";
171 case BFCR_STATE_DONE
:
178 static struct stack
*stack_new(struct bt_bfcr
*bfcr
)
180 struct stack
*stack
= NULL
;
182 stack
= g_new0(struct stack
, 1);
184 BT_COMP_LOGE_STR("Failed to allocate one stack.");
189 stack
->entries
= g_array_new(FALSE
, TRUE
, sizeof(struct stack_entry
));
190 if (!stack
->entries
) {
191 BT_COMP_LOGE_STR("Failed to allocate a GArray.");
195 BT_COMP_LOGD("Created stack: addr=%p", stack
);
203 static void stack_destroy(struct stack
*stack
)
205 struct bt_bfcr
*bfcr
;
212 BT_COMP_LOGD("Destroying stack: addr=%p", stack
);
214 if (stack
->entries
) {
215 g_array_free(stack
->entries
, TRUE
);
221 static int stack_push(struct stack
*stack
, struct ctf_field_class
*base_class
, size_t base_len
)
223 struct stack_entry
*entry
;
224 struct bt_bfcr
*bfcr
;
226 BT_ASSERT_DBG(stack
);
227 BT_ASSERT_DBG(base_class
);
229 BT_COMP_LOGT("Pushing field class on stack: stack-addr=%p, "
230 "fc-addr=%p, fc-type=%d, base-length=%zu, "
231 "stack-size-before=%zu, stack-size-after=%zu",
232 stack
, base_class
, base_class
->type
, base_len
, stack
->size
, stack
->size
+ 1);
234 if (stack
->entries
->len
== stack
->size
) {
235 g_array_set_size(stack
->entries
, stack
->size
+ 1);
238 entry
= &bt_g_array_index(stack
->entries
, struct stack_entry
, stack
->size
);
239 entry
->base_class
= base_class
;
240 entry
->base_len
= base_len
;
246 static inline int64_t get_compound_field_class_length(struct bt_bfcr
*bfcr
,
247 struct ctf_field_class
*fc
)
252 case CTF_FIELD_CLASS_TYPE_STRUCT
:
254 ctf_field_class_struct
*struct_fc
= ctf_field_class_as_struct(fc
);
256 length
= (int64_t) struct_fc
->members
->len
;
259 case CTF_FIELD_CLASS_TYPE_VARIANT
:
261 /* Variant field classes always "contain" a single class */
265 case CTF_FIELD_CLASS_TYPE_ARRAY
:
267 struct ctf_field_class_array
*array_fc
= ctf_field_class_as_array(fc
);
269 length
= (int64_t) array_fc
->length
;
272 case CTF_FIELD_CLASS_TYPE_SEQUENCE
:
273 length
= bfcr
->user
.cbs
.query
.get_sequence_length(fc
, bfcr
->user
.data
);
282 static int stack_push_with_len(struct bt_bfcr
*bfcr
, struct ctf_field_class
*base_class
)
285 int64_t length
= get_compound_field_class_length(bfcr
, base_class
);
288 BT_COMP_LOGW("Cannot get compound field class's field count: "
289 "bfcr-addr=%p, fc-addr=%p, fc-type=%d",
290 bfcr
, base_class
, base_class
->type
);
291 ret
= BT_BFCR_STATUS_ERROR
;
295 ret
= stack_push(bfcr
->stack
, base_class
, (size_t) length
);
301 static inline unsigned int stack_size(struct stack
*stack
)
303 BT_ASSERT_DBG(stack
);
307 static void stack_pop(struct stack
*stack
)
309 struct bt_bfcr
*bfcr
;
311 BT_ASSERT_DBG(stack
);
312 BT_ASSERT_DBG(stack_size(stack
));
314 BT_COMP_LOGT("Popping from stack: "
315 "stack-addr=%p, stack-size-before=%u, stack-size-after=%u",
316 stack
, stack
->entries
->len
, stack
->entries
->len
- 1);
320 static inline bool stack_empty(struct stack
*stack
)
322 return stack_size(stack
) == 0;
325 static void stack_clear(struct stack
*stack
)
327 BT_ASSERT_DBG(stack
);
331 static inline struct stack_entry
*stack_top(struct stack
*stack
)
333 BT_ASSERT_DBG(stack
);
334 BT_ASSERT_DBG(stack_size(stack
));
335 return &bt_g_array_index(stack
->entries
, struct stack_entry
, stack
->size
- 1);
338 static inline size_t available_bits(struct bt_bfcr
*bfcr
)
340 return bfcr
->buf
.sz
- bfcr
->buf
.at
;
343 static inline void consume_bits(struct bt_bfcr
*bfcr
, size_t incr
)
345 BT_COMP_LOGT("Advancing cursor: bfcr-addr=%p, cur-before=%zu, cur-after=%zu", bfcr
,
346 bfcr
->buf
.at
, bfcr
->buf
.at
+ incr
);
347 bfcr
->buf
.at
+= incr
;
350 static inline bool has_enough_bits(struct bt_bfcr
*bfcr
, size_t sz
)
352 return available_bits(bfcr
) >= sz
;
355 static inline bool at_least_one_bit_left(struct bt_bfcr
*bfcr
)
357 return has_enough_bits(bfcr
, 1);
360 static inline size_t packet_at(struct bt_bfcr
*bfcr
)
362 return bfcr
->buf
.packet_offset
+ bfcr
->buf
.at
;
365 static inline size_t buf_at_from_addr(struct bt_bfcr
*bfcr
)
370 * ====== offset ===== (17)
372 * xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
374 * addr (0) ==== at ==== (12)
378 * =============================== (29)
380 return bfcr
->buf
.offset
+ bfcr
->buf
.at
;
383 static void stitch_reset(struct bt_bfcr
*bfcr
)
385 bfcr
->stitch
.offset
= 0;
389 static inline size_t stitch_at_from_addr(struct bt_bfcr
*bfcr
)
391 return bfcr
->stitch
.offset
+ bfcr
->stitch
.at
;
394 static void stitch_append_from_buf(struct bt_bfcr
*bfcr
, size_t sz
)
396 size_t stitch_byte_at
;
404 stitch_byte_at
= BITS_TO_BYTES_FLOOR(stitch_at_from_addr(bfcr
));
405 buf_byte_at
= BITS_TO_BYTES_FLOOR(buf_at_from_addr(bfcr
));
406 nb_bytes
= BITS_TO_BYTES_CEIL(sz
);
407 BT_ASSERT(nb_bytes
> 0);
408 BT_ASSERT(bfcr
->buf
.addr
);
409 memcpy(&bfcr
->stitch
.buf
[stitch_byte_at
], &bfcr
->buf
.addr
[buf_byte_at
], nb_bytes
);
410 bfcr
->stitch
.at
+= sz
;
411 consume_bits(bfcr
, sz
);
414 static void stitch_append_from_remaining_buf(struct bt_bfcr
*bfcr
)
416 stitch_append_from_buf(bfcr
, available_bits(bfcr
));
419 static void stitch_set_from_remaining_buf(struct bt_bfcr
*bfcr
)
422 bfcr
->stitch
.offset
= IN_BYTE_OFFSET(buf_at_from_addr(bfcr
));
423 stitch_append_from_remaining_buf(bfcr
);
426 static inline void read_unsigned_bitfield(struct bt_bfcr
*bfcr
, const uint8_t *buf
, size_t at
,
427 unsigned int field_size
, enum ctf_byte_order bo
,
431 case CTF_BYTE_ORDER_BIG
:
432 bt_bitfield_read_be(buf
, uint8_t, at
, field_size
, v
);
434 case CTF_BYTE_ORDER_LITTLE
:
435 bt_bitfield_read_le(buf
, uint8_t, at
, field_size
, v
);
441 BT_COMP_LOGT("Read unsigned bit array: cur=%zu, size=%u, "
442 "bo=%d, val=%" PRIu64
,
443 at
, field_size
, bo
, *v
);
446 static inline void read_signed_bitfield(struct bt_bfcr
*bfcr
, const uint8_t *buf
, size_t at
,
447 unsigned int field_size
, enum ctf_byte_order bo
, int64_t *v
)
450 case CTF_BYTE_ORDER_BIG
:
451 bt_bitfield_read_be(buf
, uint8_t, at
, field_size
, v
);
453 case CTF_BYTE_ORDER_LITTLE
:
454 bt_bitfield_read_le(buf
, uint8_t, at
, field_size
, v
);
460 BT_COMP_LOGT("Read signed bit array: cur=%zu, size=%u, "
461 "bo=%d, val=%" PRId64
,
462 at
, field_size
, bo
, *v
);
465 typedef enum bt_bfcr_status (*read_basic_and_call_cb_t
)(struct bt_bfcr
*, const uint8_t *, size_t);
467 static inline enum bt_bfcr_status
validate_contiguous_bo(struct bt_bfcr
*bfcr
,
468 enum ctf_byte_order next_bo
)
470 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
472 /* Always valid when at a byte boundary */
473 if (packet_at(bfcr
) % 8 == 0) {
477 /* Always valid if last byte order is unknown */
478 if (bfcr
->last_bo
== CTF_BYTE_ORDER_UNKNOWN
) {
482 /* Always valid if next byte order is unknown */
483 if (next_bo
== CTF_BYTE_ORDER_UNKNOWN
) {
487 /* Make sure last byte order is compatible with the next byte order */
488 switch (bfcr
->last_bo
) {
489 case CTF_BYTE_ORDER_BIG
:
490 if (next_bo
!= CTF_BYTE_ORDER_BIG
) {
491 status
= BT_BFCR_STATUS_ERROR
;
494 case CTF_BYTE_ORDER_LITTLE
:
495 if (next_bo
!= CTF_BYTE_ORDER_LITTLE
) {
496 status
= BT_BFCR_STATUS_ERROR
;
500 status
= BT_BFCR_STATUS_ERROR
;
505 BT_COMP_LOGW("Cannot read bit array: two different byte orders not at a byte boundary: "
506 "bfcr-addr=%p, last-bo=%d, next-bo=%d",
507 bfcr
, bfcr
->last_bo
, next_bo
);
513 static enum bt_bfcr_status
read_basic_float_and_call_cb(struct bt_bfcr
*bfcr
, const uint8_t *buf
,
517 unsigned int field_size
;
518 enum ctf_byte_order bo
;
519 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
520 ctf_field_class_float
*fc
= ctf_field_class_as_float(bfcr
->cur_basic_field_class
);
523 field_size
= fc
->base
.size
;
524 bo
= fc
->base
.byte_order
;
527 switch (field_size
) {
537 read_unsigned_bitfield(bfcr
, buf
, at
, field_size
, bo
, &v
);
538 f32
.u
= (uint32_t) v
;
539 dblval
= (double) f32
.f
;
550 read_unsigned_bitfield(bfcr
, buf
, at
, field_size
, bo
, &f64
.u
);
555 /* Only 32-bit and 64-bit fields are supported currently */
559 BT_COMP_LOGT("Read floating point number value: bfcr=%p, cur=%zu, val=%f", bfcr
, at
, dblval
);
561 if (bfcr
->user
.cbs
.classes
.floating_point
) {
562 BT_COMP_LOGT("Calling user function (floating point number).");
563 status
= bfcr
->user
.cbs
.classes
.floating_point(dblval
, bfcr
->cur_basic_field_class
,
565 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
566 if (status
!= BT_BFCR_STATUS_OK
) {
567 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s", bfcr
,
568 bt_bfcr_status_string(status
));
575 static inline enum bt_bfcr_status
read_basic_int_and_call_cb(struct bt_bfcr
*bfcr
,
576 const uint8_t *buf
, size_t at
)
578 unsigned int field_size
;
579 enum ctf_byte_order bo
;
580 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
581 ctf_field_class_int
*fc
= ctf_field_class_as_int(bfcr
->cur_basic_field_class
);
583 field_size
= fc
->base
.size
;
584 bo
= fc
->base
.byte_order
;
587 * Update current byte order now because we could be reading
588 * the integer value of an enumeration class, and thus we know
589 * here the actual supporting integer class's byte order.
596 read_signed_bitfield(bfcr
, buf
, at
, field_size
, bo
, &v
);
598 if (bfcr
->user
.cbs
.classes
.signed_int
) {
599 BT_COMP_LOGT("Calling user function (signed integer).");
601 bfcr
->user
.cbs
.classes
.signed_int(v
, bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
602 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
603 if (status
!= BT_BFCR_STATUS_OK
) {
604 BT_COMP_LOGW("User function failed: "
605 "bfcr-addr=%p, status=%s",
606 bfcr
, bt_bfcr_status_string(status
));
612 read_unsigned_bitfield(bfcr
, buf
, at
, field_size
, bo
, &v
);
614 if (bfcr
->user
.cbs
.classes
.unsigned_int
) {
615 BT_COMP_LOGT("Calling user function (unsigned integer).");
616 status
= bfcr
->user
.cbs
.classes
.unsigned_int(v
, bfcr
->cur_basic_field_class
,
618 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
619 if (status
!= BT_BFCR_STATUS_OK
) {
620 BT_COMP_LOGW("User function failed: "
621 "bfcr-addr=%p, status=%s",
622 bfcr
, bt_bfcr_status_string(status
));
630 static inline enum bt_bfcr_status
631 read_bit_array_class_and_call_continue(struct bt_bfcr
*bfcr
,
632 read_basic_and_call_cb_t read_basic_and_call_cb
)
636 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
637 ctf_field_class_bit_array
*fc
= ctf_field_class_as_bit_array(bfcr
->cur_basic_field_class
);
639 if (!at_least_one_bit_left(bfcr
)) {
640 BT_COMP_LOGT("Reached end of data: bfcr-addr=%p", bfcr
);
641 status
= BT_BFCR_STATUS_EOF
;
645 available
= available_bits(bfcr
);
646 needed_bits
= fc
->size
- bfcr
->stitch
.at
;
647 BT_COMP_LOGT("Continuing basic field decoding: "
648 "bfcr-addr=%p, field-size=%u, needed-size=%zu, "
649 "available-size=%zu",
650 bfcr
, fc
->size
, needed_bits
, available
);
651 if (needed_bits
<= available
) {
652 /* We have all the bits; append to stitch, then decode */
653 stitch_append_from_buf(bfcr
, needed_bits
);
654 status
= read_basic_and_call_cb(bfcr
, bfcr
->stitch
.buf
, bfcr
->stitch
.offset
);
655 if (status
!= BT_BFCR_STATUS_OK
) {
656 BT_COMP_LOGW("Cannot read basic field: "
657 "bfcr-addr=%p, fc-addr=%p, status=%s",
658 bfcr
, bfcr
->cur_basic_field_class
, bt_bfcr_status_string(status
));
662 if (stack_empty(bfcr
->stack
)) {
663 /* Root is a basic class */
664 bfcr
->state
= BFCR_STATE_DONE
;
666 /* Go to next field */
667 stack_top(bfcr
->stack
)->index
++;
668 bfcr
->state
= BFCR_STATE_NEXT_FIELD
;
669 bfcr
->last_bo
= bfcr
->cur_bo
;
674 /* We are here; it means we don't have enough data to decode this */
675 BT_COMP_LOGT_STR("Not enough data to read the next basic field: appending to stitch buffer.");
676 stitch_append_from_remaining_buf(bfcr
);
677 status
= BT_BFCR_STATUS_EOF
;
683 static inline enum bt_bfcr_status
684 read_bit_array_class_and_call_begin(struct bt_bfcr
*bfcr
,
685 read_basic_and_call_cb_t read_basic_and_call_cb
)
688 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
689 ctf_field_class_bit_array
*fc
= ctf_field_class_as_bit_array(bfcr
->cur_basic_field_class
);
691 if (!at_least_one_bit_left(bfcr
)) {
692 BT_COMP_LOGT("Reached end of data: bfcr-addr=%p", bfcr
);
693 status
= BT_BFCR_STATUS_EOF
;
697 status
= validate_contiguous_bo(bfcr
, fc
->byte_order
);
698 if (status
!= BT_BFCR_STATUS_OK
) {
699 /* validate_contiguous_bo() logs errors */
703 available
= available_bits(bfcr
);
705 if (fc
->size
<= available
) {
706 /* We have all the bits; decode and set now */
707 BT_ASSERT_DBG(bfcr
->buf
.addr
);
708 status
= read_basic_and_call_cb(bfcr
, bfcr
->buf
.addr
, buf_at_from_addr(bfcr
));
709 if (status
!= BT_BFCR_STATUS_OK
) {
710 BT_COMP_LOGW("Cannot read basic field: "
711 "bfcr-addr=%p, fc-addr=%p, status=%s",
712 bfcr
, bfcr
->cur_basic_field_class
, bt_bfcr_status_string(status
));
716 consume_bits(bfcr
, fc
->size
);
718 if (stack_empty(bfcr
->stack
)) {
719 /* Root is a basic class */
720 bfcr
->state
= BFCR_STATE_DONE
;
722 /* Go to next field */
723 stack_top(bfcr
->stack
)->index
++;
724 bfcr
->state
= BFCR_STATE_NEXT_FIELD
;
725 bfcr
->last_bo
= bfcr
->cur_bo
;
731 /* We are here; it means we don't have enough data to decode this */
732 BT_COMP_LOGT_STR("Not enough data to read the next basic field: setting stitch buffer.");
733 stitch_set_from_remaining_buf(bfcr
);
734 bfcr
->state
= BFCR_STATE_READ_BASIC_CONTINUE
;
735 status
= BT_BFCR_STATUS_EOF
;
741 static inline enum bt_bfcr_status
read_basic_int_class_and_call_begin(struct bt_bfcr
*bfcr
)
743 return read_bit_array_class_and_call_begin(bfcr
, read_basic_int_and_call_cb
);
746 static inline enum bt_bfcr_status
read_basic_int_class_and_call_continue(struct bt_bfcr
*bfcr
)
748 return read_bit_array_class_and_call_continue(bfcr
, read_basic_int_and_call_cb
);
751 static inline enum bt_bfcr_status
read_basic_float_class_and_call_begin(struct bt_bfcr
*bfcr
)
753 return read_bit_array_class_and_call_begin(bfcr
, read_basic_float_and_call_cb
);
756 static inline enum bt_bfcr_status
read_basic_float_class_and_call_continue(struct bt_bfcr
*bfcr
)
758 return read_bit_array_class_and_call_continue(bfcr
, read_basic_float_and_call_cb
);
761 static inline enum bt_bfcr_status
read_basic_string_class_and_call(struct bt_bfcr
*bfcr
, bool begin
)
764 const uint8_t *result
;
765 size_t available_bytes
;
766 const uint8_t *first_chr
;
767 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
769 if (!at_least_one_bit_left(bfcr
)) {
770 BT_COMP_LOGT("Reached end of data: bfcr-addr=%p", bfcr
);
771 status
= BT_BFCR_STATUS_EOF
;
775 BT_ASSERT_DBG(buf_at_from_addr(bfcr
) % 8 == 0);
776 available_bytes
= BITS_TO_BYTES_FLOOR(available_bits(bfcr
));
777 buf_at_bytes
= BITS_TO_BYTES_FLOOR(buf_at_from_addr(bfcr
));
778 BT_ASSERT_DBG(bfcr
->buf
.addr
);
779 first_chr
= &bfcr
->buf
.addr
[buf_at_bytes
];
780 result
= (const uint8_t *) memchr(first_chr
, '\0', available_bytes
);
782 if (begin
&& bfcr
->user
.cbs
.classes
.string_begin
) {
783 BT_COMP_LOGT("Calling user function (string, beginning).");
784 status
= bfcr
->user
.cbs
.classes
.string_begin(bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
785 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
786 if (status
!= BT_BFCR_STATUS_OK
) {
787 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s", bfcr
,
788 bt_bfcr_status_string(status
));
794 /* No null character yet */
795 if (bfcr
->user
.cbs
.classes
.string
) {
796 BT_COMP_LOGT("Calling user function (substring).");
797 status
= bfcr
->user
.cbs
.classes
.string((const char *) first_chr
, available_bytes
,
798 bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
799 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
800 if (status
!= BT_BFCR_STATUS_OK
) {
801 BT_COMP_LOGW("User function failed: "
802 "bfcr-addr=%p, status=%s",
803 bfcr
, bt_bfcr_status_string(status
));
808 consume_bits(bfcr
, BYTES_TO_BITS(available_bytes
));
809 bfcr
->state
= BFCR_STATE_READ_BASIC_CONTINUE
;
810 status
= BT_BFCR_STATUS_EOF
;
812 /* Found the null character */
813 size_t result_len
= (size_t) (result
- first_chr
);
815 if (bfcr
->user
.cbs
.classes
.string
&& result_len
) {
816 BT_COMP_LOGT("Calling user function (substring).");
817 status
= bfcr
->user
.cbs
.classes
.string((const char *) first_chr
, result_len
,
818 bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
819 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
820 if (status
!= BT_BFCR_STATUS_OK
) {
821 BT_COMP_LOGW("User function failed: "
822 "bfcr-addr=%p, status=%s",
823 bfcr
, bt_bfcr_status_string(status
));
828 if (bfcr
->user
.cbs
.classes
.string_end
) {
829 BT_COMP_LOGT("Calling user function (string, end).");
831 bfcr
->user
.cbs
.classes
.string_end(bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
832 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
833 if (status
!= BT_BFCR_STATUS_OK
) {
834 BT_COMP_LOGW("User function failed: "
835 "bfcr-addr=%p, status=%s",
836 bfcr
, bt_bfcr_status_string(status
));
841 consume_bits(bfcr
, BYTES_TO_BITS(result_len
+ 1));
843 if (stack_empty(bfcr
->stack
)) {
844 /* Root is a basic class */
845 bfcr
->state
= BFCR_STATE_DONE
;
847 /* Go to next field */
848 stack_top(bfcr
->stack
)->index
++;
849 bfcr
->state
= BFCR_STATE_NEXT_FIELD
;
850 bfcr
->last_bo
= bfcr
->cur_bo
;
858 static inline enum bt_bfcr_status
read_basic_begin_state(struct bt_bfcr
*bfcr
)
860 enum bt_bfcr_status status
;
862 BT_ASSERT_DBG(bfcr
->cur_basic_field_class
);
864 switch (bfcr
->cur_basic_field_class
->type
) {
865 case CTF_FIELD_CLASS_TYPE_INT
:
866 case CTF_FIELD_CLASS_TYPE_ENUM
:
867 status
= read_basic_int_class_and_call_begin(bfcr
);
869 case CTF_FIELD_CLASS_TYPE_FLOAT
:
870 status
= read_basic_float_class_and_call_begin(bfcr
);
872 case CTF_FIELD_CLASS_TYPE_STRING
:
873 status
= read_basic_string_class_and_call(bfcr
, true);
882 static inline enum bt_bfcr_status
read_basic_continue_state(struct bt_bfcr
*bfcr
)
884 enum bt_bfcr_status status
;
886 BT_ASSERT_DBG(bfcr
->cur_basic_field_class
);
888 switch (bfcr
->cur_basic_field_class
->type
) {
889 case CTF_FIELD_CLASS_TYPE_INT
:
890 case CTF_FIELD_CLASS_TYPE_ENUM
:
891 status
= read_basic_int_class_and_call_continue(bfcr
);
893 case CTF_FIELD_CLASS_TYPE_FLOAT
:
894 status
= read_basic_float_class_and_call_continue(bfcr
);
896 case CTF_FIELD_CLASS_TYPE_STRING
:
897 status
= read_basic_string_class_and_call(bfcr
, false);
906 static inline size_t bits_to_skip_to_align_to(struct bt_bfcr
*bfcr
, size_t align
)
908 size_t aligned_packet_at
;
910 aligned_packet_at
= BT_ALIGN(packet_at(bfcr
), align
);
911 return aligned_packet_at
- packet_at(bfcr
);
914 static inline enum bt_bfcr_status
align_class_state(struct bt_bfcr
*bfcr
,
915 struct ctf_field_class
*field_class
,
916 enum bfcr_state next_state
)
918 unsigned int field_alignment
;
920 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
922 /* Get field's alignment */
923 field_alignment
= field_class
->alignment
;
926 * 0 means "undefined" for variants; what we really want is 1
929 BT_ASSERT_DBG(field_alignment
>= 1);
931 /* Compute how many bits we need to skip */
932 skip_bits
= bits_to_skip_to_align_to(bfcr
, (size_t) field_alignment
);
934 /* Nothing to skip? aligned */
935 if (skip_bits
== 0) {
936 bfcr
->state
= next_state
;
940 /* Make sure there's at least one bit left */
941 if (!at_least_one_bit_left(bfcr
)) {
942 status
= BT_BFCR_STATUS_EOF
;
946 /* Consume as many bits as possible in what's left */
947 consume_bits(bfcr
, MIN(available_bits(bfcr
), skip_bits
));
949 /* Are we done now? */
950 skip_bits
= bits_to_skip_to_align_to(bfcr
, field_alignment
);
951 if (skip_bits
== 0) {
952 /* Yes: go to next state */
953 bfcr
->state
= next_state
;
956 /* No: need more data */
957 BT_COMP_LOGT("Reached end of data when aligning: bfcr-addr=%p", bfcr
);
958 status
= BT_BFCR_STATUS_EOF
;
965 static inline enum bt_bfcr_status
next_field_state(struct bt_bfcr
*bfcr
)
968 struct stack_entry
*top
;
969 struct ctf_field_class
*next_field_class
= NULL
;
970 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
972 if (stack_empty(bfcr
->stack
)) {
976 top
= stack_top(bfcr
->stack
);
978 /* Are we done with this base class? */
979 while (top
->index
== top
->base_len
) {
980 if (bfcr
->user
.cbs
.classes
.compound_end
) {
981 BT_COMP_LOGT("Calling user function (compound, end).");
982 status
= bfcr
->user
.cbs
.classes
.compound_end(top
->base_class
, bfcr
->user
.data
);
983 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
984 if (status
!= BT_BFCR_STATUS_OK
) {
985 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s", bfcr
,
986 bt_bfcr_status_string(status
));
991 stack_pop(bfcr
->stack
);
993 /* Are we done with the root class? */
994 if (stack_empty(bfcr
->stack
)) {
995 bfcr
->state
= BFCR_STATE_DONE
;
999 top
= stack_top(bfcr
->stack
);
1003 /* Get next field's class */
1004 switch (top
->base_class
->type
) {
1005 case CTF_FIELD_CLASS_TYPE_STRUCT
:
1006 next_field_class
= ctf_field_class_struct_borrow_member_by_index(
1007 ctf_field_class_as_struct(top
->base_class
), (uint64_t) top
->index
)
1010 case CTF_FIELD_CLASS_TYPE_ARRAY
:
1011 case CTF_FIELD_CLASS_TYPE_SEQUENCE
:
1013 ctf_field_class_array_base
*array_fc
= ctf_field_class_as_array_base(top
->base_class
);
1015 next_field_class
= array_fc
->elem_fc
;
1018 case CTF_FIELD_CLASS_TYPE_VARIANT
:
1019 /* Variant classes are dynamic: the user should know! */
1020 next_field_class
= bfcr
->user
.cbs
.query
.borrow_variant_selected_field_class(
1021 top
->base_class
, bfcr
->user
.data
);
1027 if (!next_field_class
) {
1028 BT_COMP_LOGW("Cannot get the field class of the next field: "
1029 "bfcr-addr=%p, base-fc-addr=%p, base-fc-type=%d, "
1031 bfcr
, top
->base_class
, top
->base_class
->type
, top
->index
);
1032 status
= BT_BFCR_STATUS_ERROR
;
1036 if (next_field_class
->is_compound
) {
1037 if (bfcr
->user
.cbs
.classes
.compound_begin
) {
1038 BT_COMP_LOGT("Calling user function (compound, begin).");
1039 status
= bfcr
->user
.cbs
.classes
.compound_begin(next_field_class
, bfcr
->user
.data
);
1040 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(status
));
1041 if (status
!= BT_BFCR_STATUS_OK
) {
1042 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s", bfcr
,
1043 bt_bfcr_status_string(status
));
1048 ret
= stack_push_with_len(bfcr
, next_field_class
);
1050 /* stack_push_with_len() logs errors */
1051 status
= BT_BFCR_STATUS_ERROR
;
1055 /* Next state: align a compound class */
1056 bfcr
->state
= BFCR_STATE_ALIGN_COMPOUND
;
1058 /* Replace current basic field class */
1059 BT_COMP_LOGT("Replacing current basic field class: "
1060 "bfcr-addr=%p, cur-basic-fc-addr=%p, "
1061 "next-basic-fc-addr=%p",
1062 bfcr
, bfcr
->cur_basic_field_class
, next_field_class
);
1063 bfcr
->cur_basic_field_class
= next_field_class
;
1065 /* Next state: align a basic class */
1066 bfcr
->state
= BFCR_STATE_ALIGN_BASIC
;
1073 static inline enum bt_bfcr_status
handle_state(struct bt_bfcr
*bfcr
)
1075 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
1077 BT_COMP_LOGT("Handling state: bfcr-addr=%p, state=%s", bfcr
, bfcr_state_string(bfcr
->state
));
1079 switch (bfcr
->state
) {
1080 case BFCR_STATE_NEXT_FIELD
:
1081 status
= next_field_state(bfcr
);
1083 case BFCR_STATE_ALIGN_BASIC
:
1084 status
= align_class_state(bfcr
, bfcr
->cur_basic_field_class
, BFCR_STATE_READ_BASIC_BEGIN
);
1086 case BFCR_STATE_ALIGN_COMPOUND
:
1087 status
= align_class_state(bfcr
, stack_top(bfcr
->stack
)->base_class
, BFCR_STATE_NEXT_FIELD
);
1089 case BFCR_STATE_READ_BASIC_BEGIN
:
1090 status
= read_basic_begin_state(bfcr
);
1092 case BFCR_STATE_READ_BASIC_CONTINUE
:
1093 status
= read_basic_continue_state(bfcr
);
1095 case BFCR_STATE_DONE
:
1099 BT_COMP_LOGT("Handled state: bfcr-addr=%p, status=%s", bfcr
, bt_bfcr_status_string(status
));
1103 struct bt_bfcr
*bt_bfcr_create(struct bt_bfcr_cbs cbs
, void *data
, bt_logging_level log_level
,
1104 bt_self_component
*self_comp
)
1106 struct bt_bfcr
*bfcr
;
1108 BT_COMP_LOG_CUR_LVL(BT_LOG_DEBUG
, log_level
, self_comp
,
1109 "Creating binary field class reader (BFCR).");
1110 bfcr
= g_new0(struct bt_bfcr
, 1);
1112 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR
, log_level
, self_comp
,
1113 "Failed to allocate one binary class reader.");
1117 bfcr
->log_level
= log_level
;
1118 bfcr
->self_comp
= self_comp
;
1119 bfcr
->stack
= stack_new(bfcr
);
1121 BT_COMP_LOGE_STR("Cannot create BFCR's stack.");
1122 bt_bfcr_destroy(bfcr
);
1127 bfcr
->state
= BFCR_STATE_NEXT_FIELD
;
1128 bfcr
->user
.cbs
= cbs
;
1129 bfcr
->user
.data
= data
;
1130 BT_COMP_LOGD("Created BFCR: addr=%p", bfcr
);
1136 void bt_bfcr_destroy(struct bt_bfcr
*bfcr
)
1139 stack_destroy(bfcr
->stack
);
1142 BT_COMP_LOGD("Destroying BFCR: addr=%p", bfcr
);
1146 static void reset(struct bt_bfcr
*bfcr
)
1148 BT_COMP_LOGD("Resetting BFCR: addr=%p", bfcr
);
1149 stack_clear(bfcr
->stack
);
1151 bfcr
->buf
.addr
= NULL
;
1152 bfcr
->last_bo
= CTF_BYTE_ORDER_UNKNOWN
;
1155 static void update_packet_offset(struct bt_bfcr
*bfcr
)
1157 BT_COMP_LOGT("Updating packet offset for next call: "
1158 "bfcr-addr=%p, cur-packet-offset=%zu, next-packet-offset=%zu",
1159 bfcr
, bfcr
->buf
.packet_offset
, bfcr
->buf
.packet_offset
+ bfcr
->buf
.at
);
1160 bfcr
->buf
.packet_offset
+= bfcr
->buf
.at
;
1163 size_t bt_bfcr_start(struct bt_bfcr
*bfcr
, struct ctf_field_class
*cls
, const uint8_t *buf
,
1164 size_t offset
, size_t packet_offset
, size_t sz
, enum bt_bfcr_status
*status
)
1166 BT_ASSERT_DBG(bfcr
);
1167 BT_ASSERT_DBG(BYTES_TO_BITS(sz
) >= offset
);
1169 bfcr
->buf
.addr
= buf
;
1170 bfcr
->buf
.offset
= offset
;
1172 bfcr
->buf
.packet_offset
= packet_offset
;
1173 bfcr
->buf
.buf_sz
= sz
;
1174 bfcr
->buf
.sz
= BYTES_TO_BITS(sz
) - offset
;
1175 *status
= BT_BFCR_STATUS_OK
;
1177 BT_COMP_LOGT("Starting decoding: bfcr-addr=%p, fc-addr=%p, "
1178 "buf-addr=%p, buf-size=%zu, offset=%zu, "
1179 "packet-offset=%zu",
1180 bfcr
, cls
, buf
, sz
, offset
, packet_offset
);
1182 /* Set root class */
1183 if (cls
->is_compound
) {
1184 /* Compound class: push on visit stack */
1187 if (bfcr
->user
.cbs
.classes
.compound_begin
) {
1188 BT_COMP_LOGT("Calling user function (compound, begin).");
1189 *status
= bfcr
->user
.cbs
.classes
.compound_begin(cls
, bfcr
->user
.data
);
1190 BT_COMP_LOGT("User function returned: status=%s", bt_bfcr_status_string(*status
));
1191 if (*status
!= BT_BFCR_STATUS_OK
) {
1192 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s", bfcr
,
1193 bt_bfcr_status_string(*status
));
1198 stack_ret
= stack_push_with_len(bfcr
, cls
);
1200 /* stack_push_with_len() logs errors */
1201 *status
= BT_BFCR_STATUS_ERROR
;
1205 bfcr
->state
= BFCR_STATE_ALIGN_COMPOUND
;
1207 /* Basic class: set as current basic class */
1208 bfcr
->cur_basic_field_class
= cls
;
1209 bfcr
->state
= BFCR_STATE_ALIGN_BASIC
;
1212 /* Run the machine! */
1213 BT_COMP_LOGT_STR("Running the state machine.");
1216 *status
= handle_state(bfcr
);
1217 if (*status
!= BT_BFCR_STATUS_OK
|| bfcr
->state
== BFCR_STATE_DONE
) {
1222 /* Update packet offset for next time */
1223 update_packet_offset(bfcr
);
1226 return bfcr
->buf
.at
;
1229 size_t bt_bfcr_continue(struct bt_bfcr
*bfcr
, const uint8_t *buf
, size_t sz
,
1230 enum bt_bfcr_status
*status
)
1232 BT_ASSERT_DBG(bfcr
);
1234 BT_ASSERT_DBG(sz
> 0);
1235 bfcr
->buf
.addr
= buf
;
1236 bfcr
->buf
.offset
= 0;
1238 bfcr
->buf
.buf_sz
= sz
;
1239 bfcr
->buf
.sz
= BYTES_TO_BITS(sz
);
1240 *status
= BT_BFCR_STATUS_OK
;
1242 BT_COMP_LOGT("Continuing decoding: bfcr-addr=%p, buf-addr=%p, buf-size=%zu", bfcr
, buf
, sz
);
1244 /* Continue running the machine */
1245 BT_COMP_LOGT_STR("Running the state machine.");
1248 *status
= handle_state(bfcr
);
1249 if (*status
!= BT_BFCR_STATUS_OK
|| bfcr
->state
== BFCR_STATE_DONE
) {
1254 /* Update packet offset for next time */
1255 update_packet_offset(bfcr
);
1256 return bfcr
->buf
.at
;
1259 void bt_bfcr_set_unsigned_int_cb(struct bt_bfcr
*bfcr
, bt_bfcr_unsigned_int_cb_func cb
)
1261 BT_ASSERT_DBG(bfcr
);
1263 bfcr
->user
.cbs
.classes
.unsigned_int
= cb
;