2 * Babeltrace - CTF binary field class reader (BFCR)
4 * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation
5 * Copyright (c) 2015-2016 Philippe Proulx <pproulx@efficios.com>
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 #define BT_LOG_OUTPUT_LEVEL (bfcr->log_level)
27 #define BT_LOG_TAG "PLUGIN/CTF/BFCR"
28 #include "logging/log.h"
36 #include "common/assert.h"
38 #include "compat/bitfield.h"
39 #include "common/common.h"
40 #include <babeltrace2/babeltrace.h>
41 #include "common/align.h"
45 #include "../metadata/ctf-meta.h"
47 #define DIV8(_x) ((_x) >> 3)
48 #define BYTES_TO_BITS(_x) ((_x) * 8)
49 #define BITS_TO_BYTES_FLOOR(_x) DIV8(_x)
50 #define BITS_TO_BYTES_CEIL(_x) DIV8((_x) + 7)
51 #define IN_BYTE_OFFSET(_at) ((_at) & 7)
53 /* A visit stack entry */
56 * Current class of base field, one of:
63 struct ctf_field_class
*base_class
;
65 /* Length of base field (always 1 for a variant class) */
68 /* Index of next field to read */
78 /* Entries (struct stack_entry) */
81 /* Number of active entries */
87 BFCR_STATE_NEXT_FIELD
,
88 BFCR_STATE_ALIGN_BASIC
,
89 BFCR_STATE_ALIGN_COMPOUND
,
90 BFCR_STATE_READ_BASIC_BEGIN
,
91 BFCR_STATE_READ_BASIC_CONTINUE
,
95 /* Binary class reader */
97 bt_logging_level log_level
;
102 /* Current basic field class */
103 struct ctf_field_class
*cur_basic_field_class
;
106 enum bfcr_state state
;
109 * Last basic field class's byte order.
111 * This is used to detect errors since two contiguous basic
112 * classes for which the common boundary is not the boundary of
113 * a byte cannot have different byte orders.
115 * This is set to -1 on reset and when the last basic field class
116 * was a string class.
118 enum ctf_byte_order last_bo
;
120 /* Current byte order (copied to last_bo after a successful read) */
121 enum ctf_byte_order cur_bo
;
123 /* Stitch buffer infos */
128 /* Offset, within stitch buffer, of first bit */
131 /* Length (bits) of data in stitch buffer from offset */
135 /* User buffer infos */
140 /* Offset of data from address (bits) */
143 /* Current position from offset (bits) */
146 /* Offset of offset within whole packet (bits) */
147 size_t packet_offset
;
149 /* Data size in buffer (bits) */
152 /* Buffer size (bytes) */
158 /* Callback functions */
159 struct bt_bfcr_cbs cbs
;
167 const char *bfcr_state_string(enum bfcr_state state
)
170 case BFCR_STATE_NEXT_FIELD
:
171 return "BFCR_STATE_NEXT_FIELD";
172 case BFCR_STATE_ALIGN_BASIC
:
173 return "BFCR_STATE_ALIGN_BASIC";
174 case BFCR_STATE_ALIGN_COMPOUND
:
175 return "BFCR_STATE_ALIGN_COMPOUND";
176 case BFCR_STATE_READ_BASIC_BEGIN
:
177 return "BFCR_STATE_READ_BASIC_BEGIN";
178 case BFCR_STATE_READ_BASIC_CONTINUE
:
179 return "BFCR_STATE_READ_BASIC_CONTINUE";
180 case BFCR_STATE_DONE
:
181 return "BFCR_STATE_DONE";
188 struct stack
*stack_new(struct bt_bfcr
*bfcr
)
190 struct stack
*stack
= NULL
;
192 stack
= g_new0(struct stack
, 1);
194 BT_LOGE_STR("Failed to allocate one stack.");
199 stack
->entries
= g_array_new(FALSE
, TRUE
, sizeof(struct stack_entry
));
200 if (!stack
->entries
) {
201 BT_LOGE_STR("Failed to allocate a GArray.");
205 BT_LOGD("Created stack: addr=%p", stack
);
214 void stack_destroy(struct stack
*stack
)
216 struct bt_bfcr
*bfcr
;
223 BT_LOGD("Destroying stack: addr=%p", stack
);
225 if (stack
->entries
) {
226 g_array_free(stack
->entries
, TRUE
);
233 int stack_push(struct stack
*stack
, struct ctf_field_class
*base_class
,
236 struct stack_entry
*entry
;
237 struct bt_bfcr
*bfcr
;
240 BT_ASSERT(base_class
);
242 BT_LOGV("Pushing field class on stack: stack-addr=%p, "
243 "fc-addr=%p, fc-type=%d, base-length=%zu, "
244 "stack-size-before=%zu, stack-size-after=%zu",
245 stack
, base_class
, base_class
->type
,
246 base_len
, stack
->size
, stack
->size
+ 1);
248 if (stack
->entries
->len
== stack
->size
) {
249 g_array_set_size(stack
->entries
, stack
->size
+ 1);
252 entry
= &g_array_index(stack
->entries
, struct stack_entry
, stack
->size
);
253 entry
->base_class
= base_class
;
254 entry
->base_len
= base_len
;
261 int64_t get_compound_field_class_length(struct bt_bfcr
*bfcr
,
262 struct ctf_field_class
*fc
)
267 case CTF_FIELD_CLASS_TYPE_STRUCT
:
269 struct ctf_field_class_struct
*struct_fc
= (void *) fc
;
271 length
= (int64_t) struct_fc
->members
->len
;
274 case CTF_FIELD_CLASS_TYPE_VARIANT
:
276 /* Variant field classes always "contain" a single class */
280 case CTF_FIELD_CLASS_TYPE_ARRAY
:
282 struct ctf_field_class_array
*array_fc
= (void *) fc
;
284 length
= (int64_t) array_fc
->length
;
287 case CTF_FIELD_CLASS_TYPE_SEQUENCE
:
288 length
= bfcr
->user
.cbs
.query
.get_sequence_length(fc
,
299 int stack_push_with_len(struct bt_bfcr
*bfcr
, struct ctf_field_class
*base_class
)
302 int64_t length
= get_compound_field_class_length(bfcr
, base_class
);
305 BT_LOGW("Cannot get compound field class's field count: "
306 "bfcr-addr=%p, fc-addr=%p, fc-type=%d",
307 bfcr
, base_class
, base_class
->type
);
308 ret
= BT_BFCR_STATUS_ERROR
;
312 ret
= stack_push(bfcr
->stack
, base_class
, (size_t) length
);
319 unsigned int stack_size(struct stack
*stack
)
326 void stack_pop(struct stack
*stack
)
328 struct bt_bfcr
*bfcr
;
331 BT_ASSERT(stack_size(stack
));
333 BT_LOGV("Popping from stack: "
334 "stack-addr=%p, stack-size-before=%u, stack-size-after=%u",
335 stack
, stack
->entries
->len
, stack
->entries
->len
- 1);
340 bool stack_empty(struct stack
*stack
)
342 return stack_size(stack
) == 0;
346 void stack_clear(struct stack
*stack
)
353 struct stack_entry
*stack_top(struct stack
*stack
)
356 BT_ASSERT(stack_size(stack
));
357 return &g_array_index(stack
->entries
, struct stack_entry
,
362 size_t available_bits(struct bt_bfcr
*bfcr
)
364 return bfcr
->buf
.sz
- bfcr
->buf
.at
;
368 void consume_bits(struct bt_bfcr
*bfcr
, size_t incr
)
370 BT_LOGV("Advancing cursor: bfcr-addr=%p, cur-before=%zu, cur-after=%zu",
371 bfcr
, bfcr
->buf
.at
, bfcr
->buf
.at
+ incr
);
372 bfcr
->buf
.at
+= incr
;
376 bool has_enough_bits(struct bt_bfcr
*bfcr
, size_t sz
)
378 return available_bits(bfcr
) >= sz
;
382 bool at_least_one_bit_left(struct bt_bfcr
*bfcr
)
384 return has_enough_bits(bfcr
, 1);
388 size_t packet_at(struct bt_bfcr
*bfcr
)
390 return bfcr
->buf
.packet_offset
+ bfcr
->buf
.at
;
394 size_t buf_at_from_addr(struct bt_bfcr
*bfcr
)
399 * ====== offset ===== (17)
401 * xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
403 * addr (0) ==== at ==== (12)
407 * =============================== (29)
409 return bfcr
->buf
.offset
+ bfcr
->buf
.at
;
413 void stitch_reset(struct bt_bfcr
*bfcr
)
415 bfcr
->stitch
.offset
= 0;
420 size_t stitch_at_from_addr(struct bt_bfcr
*bfcr
)
422 return bfcr
->stitch
.offset
+ bfcr
->stitch
.at
;
426 void stitch_append_from_buf(struct bt_bfcr
*bfcr
, size_t sz
)
428 size_t stitch_byte_at
;
437 BITS_TO_BYTES_FLOOR(stitch_at_from_addr(bfcr
));
438 buf_byte_at
= BITS_TO_BYTES_FLOOR(buf_at_from_addr(bfcr
));
439 nb_bytes
= BITS_TO_BYTES_CEIL(sz
);
440 BT_ASSERT(nb_bytes
> 0);
441 BT_ASSERT(bfcr
->buf
.addr
);
442 memcpy(&bfcr
->stitch
.buf
[stitch_byte_at
], &bfcr
->buf
.addr
[buf_byte_at
],
444 bfcr
->stitch
.at
+= sz
;
445 consume_bits(bfcr
, sz
);
449 void stitch_append_from_remaining_buf(struct bt_bfcr
*bfcr
)
451 stitch_append_from_buf(bfcr
, available_bits(bfcr
));
455 void stitch_set_from_remaining_buf(struct bt_bfcr
*bfcr
)
458 bfcr
->stitch
.offset
= IN_BYTE_OFFSET(buf_at_from_addr(bfcr
));
459 stitch_append_from_remaining_buf(bfcr
);
463 void read_unsigned_bitfield(struct bt_bfcr
*bfcr
, const uint8_t *buf
, size_t at
,
464 unsigned int field_size
, enum ctf_byte_order bo
,
468 case CTF_BYTE_ORDER_BIG
:
469 bt_bitfield_read_be(buf
, uint8_t, at
, field_size
, v
);
471 case CTF_BYTE_ORDER_LITTLE
:
472 bt_bitfield_read_le(buf
, uint8_t, at
, field_size
, v
);
478 BT_LOGV("Read unsigned bit array: cur=%zu, size=%u, "
479 "bo=%d, val=%" PRIu64
, at
, field_size
, bo
, *v
);
483 void read_signed_bitfield(struct bt_bfcr
*bfcr
, const uint8_t *buf
, size_t at
,
484 unsigned int field_size
, enum ctf_byte_order bo
, int64_t *v
)
487 case CTF_BYTE_ORDER_BIG
:
488 bt_bitfield_read_be(buf
, uint8_t, at
, field_size
, v
);
490 case CTF_BYTE_ORDER_LITTLE
:
491 bt_bitfield_read_le(buf
, uint8_t, at
, field_size
, v
);
497 BT_LOGV("Read signed bit array: cur=%zu, size=%u, "
498 "bo=%d, val=%" PRId64
, at
, field_size
, bo
, *v
);
501 typedef enum bt_bfcr_status (* read_basic_and_call_cb_t
)(struct bt_bfcr
*,
502 const uint8_t *, size_t);
505 enum bt_bfcr_status
validate_contiguous_bo(struct bt_bfcr
*bfcr
,
506 enum ctf_byte_order next_bo
)
508 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
510 /* Always valid when at a byte boundary */
511 if (packet_at(bfcr
) % 8 == 0) {
515 /* Always valid if last byte order is unknown */
516 if (bfcr
->last_bo
== -1) {
520 /* Always valid if next byte order is unknown */
525 /* Make sure last byte order is compatible with the next byte order */
526 switch (bfcr
->last_bo
) {
527 case CTF_BYTE_ORDER_BIG
:
528 if (next_bo
!= CTF_BYTE_ORDER_BIG
) {
529 status
= BT_BFCR_STATUS_ERROR
;
532 case CTF_BYTE_ORDER_LITTLE
:
533 if (next_bo
!= CTF_BYTE_ORDER_LITTLE
) {
534 status
= BT_BFCR_STATUS_ERROR
;
538 status
= BT_BFCR_STATUS_ERROR
;
543 BT_LOGW("Cannot read bit array: two different byte orders not at a byte boundary: "
544 "bfcr-addr=%p, last-bo=%d, next-bo=%d",
545 bfcr
, bfcr
->last_bo
, next_bo
);
552 enum bt_bfcr_status
read_basic_float_and_call_cb(struct bt_bfcr
*bfcr
,
553 const uint8_t *buf
, size_t at
)
556 unsigned int field_size
;
557 enum ctf_byte_order bo
;
558 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
559 struct ctf_field_class_float
*fc
= (void *) bfcr
->cur_basic_field_class
;
562 field_size
= fc
->base
.size
;
563 bo
= fc
->base
.byte_order
;
566 switch (field_size
) {
575 read_unsigned_bitfield(bfcr
, buf
, at
, field_size
, bo
, &v
);
576 f32
.u
= (uint32_t) v
;
577 dblval
= (double) f32
.f
;
587 read_unsigned_bitfield(bfcr
, buf
, at
, field_size
, bo
, &f64
.u
);
592 /* Only 32-bit and 64-bit fields are supported currently */
596 BT_LOGV("Read floating point number value: bfcr=%p, cur=%zu, val=%f",
599 if (bfcr
->user
.cbs
.classes
.floating_point
) {
600 BT_LOGV("Calling user function (floating point number).");
601 status
= bfcr
->user
.cbs
.classes
.floating_point(dblval
,
602 bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
603 BT_LOGV("User function returned: status=%s",
604 bt_bfcr_status_string(status
));
605 if (status
!= BT_BFCR_STATUS_OK
) {
606 BT_LOGW("User function failed: bfcr-addr=%p, status=%s",
607 bfcr
, bt_bfcr_status_string(status
));
615 enum bt_bfcr_status
read_basic_int_and_call_cb(struct bt_bfcr
*bfcr
,
616 const uint8_t *buf
, size_t at
)
618 unsigned int field_size
;
619 enum ctf_byte_order bo
;
620 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
621 struct ctf_field_class_int
*fc
= (void *) bfcr
->cur_basic_field_class
;
623 field_size
= fc
->base
.size
;
624 bo
= fc
->base
.byte_order
;
627 * Update current byte order now because we could be reading
628 * the integer value of an enumeration class, and thus we know
629 * here the actual supporting integer class's byte order.
636 read_signed_bitfield(bfcr
, buf
, at
, field_size
, bo
, &v
);
638 if (bfcr
->user
.cbs
.classes
.signed_int
) {
639 BT_LOGV("Calling user function (signed integer).");
640 status
= bfcr
->user
.cbs
.classes
.signed_int(v
,
641 bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
642 BT_LOGV("User function returned: status=%s",
643 bt_bfcr_status_string(status
));
644 if (status
!= BT_BFCR_STATUS_OK
) {
645 BT_LOGW("User function failed: "
646 "bfcr-addr=%p, status=%s",
647 bfcr
, bt_bfcr_status_string(status
));
653 read_unsigned_bitfield(bfcr
, buf
, at
, field_size
, bo
, &v
);
655 if (bfcr
->user
.cbs
.classes
.unsigned_int
) {
656 BT_LOGV("Calling user function (unsigned integer).");
657 status
= bfcr
->user
.cbs
.classes
.unsigned_int(v
,
658 bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
659 BT_LOGV("User function returned: status=%s",
660 bt_bfcr_status_string(status
));
661 if (status
!= BT_BFCR_STATUS_OK
) {
662 BT_LOGW("User function failed: "
663 "bfcr-addr=%p, status=%s",
664 bfcr
, bt_bfcr_status_string(status
));
673 enum bt_bfcr_status
read_bit_array_class_and_call_continue(struct bt_bfcr
*bfcr
,
674 read_basic_and_call_cb_t read_basic_and_call_cb
)
678 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
679 struct ctf_field_class_bit_array
*fc
=
680 (void *) bfcr
->cur_basic_field_class
;
682 if (!at_least_one_bit_left(bfcr
)) {
683 BT_LOGV("Reached end of data: bfcr-addr=%p", bfcr
);
684 status
= BT_BFCR_STATUS_EOF
;
688 available
= available_bits(bfcr
);
689 needed_bits
= fc
->size
- bfcr
->stitch
.at
;
690 BT_LOGV("Continuing basic field decoding: "
691 "bfcr-addr=%p, field-size=%u, needed-size=%zu, "
692 "available-size=%zu",
693 bfcr
, fc
->size
, needed_bits
, available
);
694 if (needed_bits
<= available
) {
695 /* We have all the bits; append to stitch, then decode */
696 stitch_append_from_buf(bfcr
, needed_bits
);
697 status
= read_basic_and_call_cb(bfcr
, bfcr
->stitch
.buf
,
698 bfcr
->stitch
.offset
);
699 if (status
!= BT_BFCR_STATUS_OK
) {
700 BT_LOGW("Cannot read basic field: "
701 "bfcr-addr=%p, fc-addr=%p, status=%s",
702 bfcr
, bfcr
->cur_basic_field_class
,
703 bt_bfcr_status_string(status
));
707 if (stack_empty(bfcr
->stack
)) {
708 /* Root is a basic class */
709 bfcr
->state
= BFCR_STATE_DONE
;
711 /* Go to next field */
712 stack_top(bfcr
->stack
)->index
++;
713 bfcr
->state
= BFCR_STATE_NEXT_FIELD
;
714 bfcr
->last_bo
= bfcr
->cur_bo
;
719 /* We are here; it means we don't have enough data to decode this */
720 BT_LOGV_STR("Not enough data to read the next basic field: appending to stitch buffer.");
721 stitch_append_from_remaining_buf(bfcr
);
722 status
= BT_BFCR_STATUS_EOF
;
729 enum bt_bfcr_status
read_bit_array_class_and_call_begin(struct bt_bfcr
*bfcr
,
730 read_basic_and_call_cb_t read_basic_and_call_cb
)
733 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
734 struct ctf_field_class_bit_array
*fc
=
735 (void *) bfcr
->cur_basic_field_class
;
737 if (!at_least_one_bit_left(bfcr
)) {
738 BT_LOGV("Reached end of data: bfcr-addr=%p", bfcr
);
739 status
= BT_BFCR_STATUS_EOF
;
743 status
= validate_contiguous_bo(bfcr
, fc
->byte_order
);
744 if (status
!= BT_BFCR_STATUS_OK
) {
745 /* validate_contiguous_bo() logs errors */
749 available
= available_bits(bfcr
);
751 if (fc
->size
<= available
) {
752 /* We have all the bits; decode and set now */
753 BT_ASSERT(bfcr
->buf
.addr
);
754 status
= read_basic_and_call_cb(bfcr
, bfcr
->buf
.addr
,
755 buf_at_from_addr(bfcr
));
756 if (status
!= BT_BFCR_STATUS_OK
) {
757 BT_LOGW("Cannot read basic field: "
758 "bfcr-addr=%p, fc-addr=%p, status=%s",
759 bfcr
, bfcr
->cur_basic_field_class
,
760 bt_bfcr_status_string(status
));
764 consume_bits(bfcr
, fc
->size
);
766 if (stack_empty(bfcr
->stack
)) {
767 /* Root is a basic class */
768 bfcr
->state
= BFCR_STATE_DONE
;
770 /* Go to next field */
771 stack_top(bfcr
->stack
)->index
++;
772 bfcr
->state
= BFCR_STATE_NEXT_FIELD
;
773 bfcr
->last_bo
= bfcr
->cur_bo
;
779 /* We are here; it means we don't have enough data to decode this */
780 BT_LOGV_STR("Not enough data to read the next basic field: setting stitch buffer.");
781 stitch_set_from_remaining_buf(bfcr
);
782 bfcr
->state
= BFCR_STATE_READ_BASIC_CONTINUE
;
783 status
= BT_BFCR_STATUS_EOF
;
790 enum bt_bfcr_status
read_basic_int_class_and_call_begin(
791 struct bt_bfcr
*bfcr
)
793 return read_bit_array_class_and_call_begin(bfcr
, read_basic_int_and_call_cb
);
797 enum bt_bfcr_status
read_basic_int_class_and_call_continue(
798 struct bt_bfcr
*bfcr
)
800 return read_bit_array_class_and_call_continue(bfcr
,
801 read_basic_int_and_call_cb
);
805 enum bt_bfcr_status
read_basic_float_class_and_call_begin(
806 struct bt_bfcr
*bfcr
)
808 return read_bit_array_class_and_call_begin(bfcr
,
809 read_basic_float_and_call_cb
);
813 enum bt_bfcr_status
read_basic_float_class_and_call_continue(
814 struct bt_bfcr
*bfcr
)
816 return read_bit_array_class_and_call_continue(bfcr
,
817 read_basic_float_and_call_cb
);
821 enum bt_bfcr_status
read_basic_string_class_and_call(
822 struct bt_bfcr
*bfcr
, bool begin
)
825 const uint8_t *result
;
826 size_t available_bytes
;
827 const uint8_t *first_chr
;
828 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
830 if (!at_least_one_bit_left(bfcr
)) {
831 BT_LOGV("Reached end of data: bfcr-addr=%p", bfcr
);
832 status
= BT_BFCR_STATUS_EOF
;
836 BT_ASSERT(buf_at_from_addr(bfcr
) % 8 == 0);
837 available_bytes
= BITS_TO_BYTES_FLOOR(available_bits(bfcr
));
838 buf_at_bytes
= BITS_TO_BYTES_FLOOR(buf_at_from_addr(bfcr
));
839 BT_ASSERT(bfcr
->buf
.addr
);
840 first_chr
= &bfcr
->buf
.addr
[buf_at_bytes
];
841 result
= memchr(first_chr
, '\0', available_bytes
);
843 if (begin
&& bfcr
->user
.cbs
.classes
.string_begin
) {
844 BT_LOGV("Calling user function (string, beginning).");
845 status
= bfcr
->user
.cbs
.classes
.string_begin(
846 bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
847 BT_LOGV("User function returned: status=%s",
848 bt_bfcr_status_string(status
));
849 if (status
!= BT_BFCR_STATUS_OK
) {
850 BT_LOGW("User function failed: bfcr-addr=%p, status=%s",
851 bfcr
, bt_bfcr_status_string(status
));
857 /* No null character yet */
858 if (bfcr
->user
.cbs
.classes
.string
) {
859 BT_LOGV("Calling user function (substring).");
860 status
= bfcr
->user
.cbs
.classes
.string(
861 (const char *) first_chr
,
862 available_bytes
, bfcr
->cur_basic_field_class
,
864 BT_LOGV("User function returned: status=%s",
865 bt_bfcr_status_string(status
));
866 if (status
!= BT_BFCR_STATUS_OK
) {
867 BT_LOGW("User function failed: "
868 "bfcr-addr=%p, status=%s",
869 bfcr
, bt_bfcr_status_string(status
));
874 consume_bits(bfcr
, BYTES_TO_BITS(available_bytes
));
875 bfcr
->state
= BFCR_STATE_READ_BASIC_CONTINUE
;
876 status
= BT_BFCR_STATUS_EOF
;
878 /* Found the null character */
879 size_t result_len
= (size_t) (result
- first_chr
);
881 if (bfcr
->user
.cbs
.classes
.string
&& result_len
) {
882 BT_LOGV("Calling user function (substring).");
883 status
= bfcr
->user
.cbs
.classes
.string(
884 (const char *) first_chr
,
885 result_len
, bfcr
->cur_basic_field_class
,
887 BT_LOGV("User function returned: status=%s",
888 bt_bfcr_status_string(status
));
889 if (status
!= BT_BFCR_STATUS_OK
) {
890 BT_LOGW("User function failed: "
891 "bfcr-addr=%p, status=%s",
892 bfcr
, bt_bfcr_status_string(status
));
897 if (bfcr
->user
.cbs
.classes
.string_end
) {
898 BT_LOGV("Calling user function (string, end).");
899 status
= bfcr
->user
.cbs
.classes
.string_end(
900 bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
901 BT_LOGV("User function returned: status=%s",
902 bt_bfcr_status_string(status
));
903 if (status
!= BT_BFCR_STATUS_OK
) {
904 BT_LOGW("User function failed: "
905 "bfcr-addr=%p, status=%s",
906 bfcr
, bt_bfcr_status_string(status
));
911 consume_bits(bfcr
, BYTES_TO_BITS(result_len
+ 1));
913 if (stack_empty(bfcr
->stack
)) {
914 /* Root is a basic class */
915 bfcr
->state
= BFCR_STATE_DONE
;
917 /* Go to next field */
918 stack_top(bfcr
->stack
)->index
++;
919 bfcr
->state
= BFCR_STATE_NEXT_FIELD
;
920 bfcr
->last_bo
= bfcr
->cur_bo
;
929 enum bt_bfcr_status
read_basic_begin_state(struct bt_bfcr
*bfcr
)
931 enum bt_bfcr_status status
;
933 BT_ASSERT(bfcr
->cur_basic_field_class
);
935 switch (bfcr
->cur_basic_field_class
->type
) {
936 case CTF_FIELD_CLASS_TYPE_INT
:
937 case CTF_FIELD_CLASS_TYPE_ENUM
:
938 status
= read_basic_int_class_and_call_begin(bfcr
);
940 case CTF_FIELD_CLASS_TYPE_FLOAT
:
941 status
= read_basic_float_class_and_call_begin(bfcr
);
943 case CTF_FIELD_CLASS_TYPE_STRING
:
944 status
= read_basic_string_class_and_call(bfcr
, true);
954 enum bt_bfcr_status
read_basic_continue_state(struct bt_bfcr
*bfcr
)
956 enum bt_bfcr_status status
;
958 BT_ASSERT(bfcr
->cur_basic_field_class
);
960 switch (bfcr
->cur_basic_field_class
->type
) {
961 case CTF_FIELD_CLASS_TYPE_INT
:
962 case CTF_FIELD_CLASS_TYPE_ENUM
:
963 status
= read_basic_int_class_and_call_continue(bfcr
);
965 case CTF_FIELD_CLASS_TYPE_FLOAT
:
966 status
= read_basic_float_class_and_call_continue(bfcr
);
968 case CTF_FIELD_CLASS_TYPE_STRING
:
969 status
= read_basic_string_class_and_call(bfcr
, false);
979 size_t bits_to_skip_to_align_to(struct bt_bfcr
*bfcr
, size_t align
)
981 size_t aligned_packet_at
;
983 aligned_packet_at
= ALIGN(packet_at(bfcr
), align
);
984 return aligned_packet_at
- packet_at(bfcr
);
988 enum bt_bfcr_status
align_class_state(struct bt_bfcr
*bfcr
,
989 struct ctf_field_class
*field_class
, enum bfcr_state next_state
)
991 unsigned int field_alignment
;
993 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
995 /* Get field's alignment */
996 field_alignment
= field_class
->alignment
;
999 * 0 means "undefined" for variants; what we really want is 1
1002 BT_ASSERT(field_alignment
>= 1);
1004 /* Compute how many bits we need to skip */
1005 skip_bits
= bits_to_skip_to_align_to(bfcr
, (size_t) field_alignment
);
1007 /* Nothing to skip? aligned */
1008 if (skip_bits
== 0) {
1009 bfcr
->state
= next_state
;
1013 /* Make sure there's at least one bit left */
1014 if (!at_least_one_bit_left(bfcr
)) {
1015 status
= BT_BFCR_STATUS_EOF
;
1019 /* Consume as many bits as possible in what's left */
1020 consume_bits(bfcr
, MIN(available_bits(bfcr
), skip_bits
));
1022 /* Are we done now? */
1023 skip_bits
= bits_to_skip_to_align_to(bfcr
, field_alignment
);
1024 if (skip_bits
== 0) {
1025 /* Yes: go to next state */
1026 bfcr
->state
= next_state
;
1029 /* No: need more data */
1030 BT_LOGV("Reached end of data when aligning: bfcr-addr=%p", bfcr
);
1031 status
= BT_BFCR_STATUS_EOF
;
1039 enum bt_bfcr_status
next_field_state(struct bt_bfcr
*bfcr
)
1042 struct stack_entry
*top
;
1043 struct ctf_field_class
*next_field_class
= NULL
;
1044 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
1046 if (stack_empty(bfcr
->stack
)) {
1050 top
= stack_top(bfcr
->stack
);
1052 /* Are we done with this base class? */
1053 while (top
->index
== top
->base_len
) {
1054 if (bfcr
->user
.cbs
.classes
.compound_end
) {
1055 BT_LOGV("Calling user function (compound, end).");
1056 status
= bfcr
->user
.cbs
.classes
.compound_end(
1057 top
->base_class
, bfcr
->user
.data
);
1058 BT_LOGV("User function returned: status=%s",
1059 bt_bfcr_status_string(status
));
1060 if (status
!= BT_BFCR_STATUS_OK
) {
1061 BT_LOGW("User function failed: bfcr-addr=%p, status=%s",
1062 bfcr
, bt_bfcr_status_string(status
));
1067 stack_pop(bfcr
->stack
);
1069 /* Are we done with the root class? */
1070 if (stack_empty(bfcr
->stack
)) {
1071 bfcr
->state
= BFCR_STATE_DONE
;
1075 top
= stack_top(bfcr
->stack
);
1079 /* Get next field's class */
1080 switch (top
->base_class
->type
) {
1081 case CTF_FIELD_CLASS_TYPE_STRUCT
:
1082 next_field_class
= ctf_field_class_struct_borrow_member_by_index(
1083 (void *) top
->base_class
, (uint64_t) top
->index
)->fc
;
1085 case CTF_FIELD_CLASS_TYPE_ARRAY
:
1086 case CTF_FIELD_CLASS_TYPE_SEQUENCE
:
1088 struct ctf_field_class_array_base
*array_fc
=
1089 (void *) top
->base_class
;
1091 next_field_class
= array_fc
->elem_fc
;
1094 case CTF_FIELD_CLASS_TYPE_VARIANT
:
1095 /* Variant classes are dynamic: the user should know! */
1097 bfcr
->user
.cbs
.query
.borrow_variant_selected_field_class(
1098 top
->base_class
, bfcr
->user
.data
);
1104 if (!next_field_class
) {
1105 BT_LOGW("Cannot get the field class of the next field: "
1106 "bfcr-addr=%p, base-fc-addr=%p, base-fc-type=%d, "
1108 bfcr
, top
->base_class
, top
->base_class
->type
,
1110 status
= BT_BFCR_STATUS_ERROR
;
1114 if (next_field_class
->is_compound
) {
1115 if (bfcr
->user
.cbs
.classes
.compound_begin
) {
1116 BT_LOGV("Calling user function (compound, begin).");
1117 status
= bfcr
->user
.cbs
.classes
.compound_begin(
1118 next_field_class
, bfcr
->user
.data
);
1119 BT_LOGV("User function returned: status=%s",
1120 bt_bfcr_status_string(status
));
1121 if (status
!= BT_BFCR_STATUS_OK
) {
1122 BT_LOGW("User function failed: bfcr-addr=%p, status=%s",
1123 bfcr
, bt_bfcr_status_string(status
));
1128 ret
= stack_push_with_len(bfcr
, next_field_class
);
1130 /* stack_push_with_len() logs errors */
1131 status
= BT_BFCR_STATUS_ERROR
;
1135 /* Next state: align a compound class */
1136 bfcr
->state
= BFCR_STATE_ALIGN_COMPOUND
;
1138 /* Replace current basic field class */
1139 BT_LOGV("Replacing current basic field class: "
1140 "bfcr-addr=%p, cur-basic-fc-addr=%p, "
1141 "next-basic-fc-addr=%p",
1142 bfcr
, bfcr
->cur_basic_field_class
, next_field_class
);
1143 bfcr
->cur_basic_field_class
= next_field_class
;
1145 /* Next state: align a basic class */
1146 bfcr
->state
= BFCR_STATE_ALIGN_BASIC
;
1154 enum bt_bfcr_status
handle_state(struct bt_bfcr
*bfcr
)
1156 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
1158 BT_LOGV("Handling state: bfcr-addr=%p, state=%s",
1159 bfcr
, bfcr_state_string(bfcr
->state
));
1161 switch (bfcr
->state
) {
1162 case BFCR_STATE_NEXT_FIELD
:
1163 status
= next_field_state(bfcr
);
1165 case BFCR_STATE_ALIGN_BASIC
:
1166 status
= align_class_state(bfcr
, bfcr
->cur_basic_field_class
,
1167 BFCR_STATE_READ_BASIC_BEGIN
);
1169 case BFCR_STATE_ALIGN_COMPOUND
:
1170 status
= align_class_state(bfcr
, stack_top(bfcr
->stack
)->base_class
,
1171 BFCR_STATE_NEXT_FIELD
);
1173 case BFCR_STATE_READ_BASIC_BEGIN
:
1174 status
= read_basic_begin_state(bfcr
);
1176 case BFCR_STATE_READ_BASIC_CONTINUE
:
1177 status
= read_basic_continue_state(bfcr
);
1179 case BFCR_STATE_DONE
:
1183 BT_LOGV("Handled state: bfcr-addr=%p, status=%s",
1184 bfcr
, bt_bfcr_status_string(status
));
1189 struct bt_bfcr
*bt_bfcr_create(struct bt_bfcr_cbs cbs
, void *data
,
1190 bt_logging_level log_level
)
1192 struct bt_bfcr
*bfcr
;
1194 BT_LOG_WRITE_CUR_LVL(BT_LOG_DEBUG
, log_level
, BT_LOG_TAG
,
1195 "Creating binary field class reader (BFCR).");
1196 bfcr
= g_new0(struct bt_bfcr
, 1);
1198 BT_LOG_WRITE_CUR_LVL(BT_LOG_ERROR
, log_level
, BT_LOG_TAG
,
1199 "Failed to allocate one binary class reader.");
1203 bfcr
->log_level
= log_level
;
1204 bfcr
->stack
= stack_new(bfcr
);
1206 BT_LOGE_STR("Cannot create BFCR's stack.");
1207 bt_bfcr_destroy(bfcr
);
1212 bfcr
->state
= BFCR_STATE_NEXT_FIELD
;
1213 bfcr
->user
.cbs
= cbs
;
1214 bfcr
->user
.data
= data
;
1215 BT_LOGD("Created BFCR: addr=%p", bfcr
);
1222 void bt_bfcr_destroy(struct bt_bfcr
*bfcr
)
1225 stack_destroy(bfcr
->stack
);
1228 BT_LOGD("Destroying BFCR: addr=%p", bfcr
);
1233 void reset(struct bt_bfcr
*bfcr
)
1235 BT_LOGD("Resetting BFCR: addr=%p", bfcr
);
1236 stack_clear(bfcr
->stack
);
1238 bfcr
->buf
.addr
= NULL
;
1243 void update_packet_offset(struct bt_bfcr
*bfcr
)
1245 BT_LOGV("Updating packet offset for next call: "
1246 "bfcr-addr=%p, cur-packet-offset=%zu, next-packet-offset=%zu",
1247 bfcr
, bfcr
->buf
.packet_offset
,
1248 bfcr
->buf
.packet_offset
+ bfcr
->buf
.at
);
1249 bfcr
->buf
.packet_offset
+= bfcr
->buf
.at
;
1253 size_t bt_bfcr_start(struct bt_bfcr
*bfcr
,
1254 struct ctf_field_class
*cls
, const uint8_t *buf
,
1255 size_t offset
, size_t packet_offset
, size_t sz
,
1256 enum bt_bfcr_status
*status
)
1259 BT_ASSERT(BYTES_TO_BITS(sz
) >= offset
);
1261 bfcr
->buf
.addr
= buf
;
1262 bfcr
->buf
.offset
= offset
;
1264 bfcr
->buf
.packet_offset
= packet_offset
;
1265 bfcr
->buf
.buf_sz
= sz
;
1266 bfcr
->buf
.sz
= BYTES_TO_BITS(sz
) - offset
;
1267 *status
= BT_BFCR_STATUS_OK
;
1269 BT_LOGV("Starting decoding: bfcr-addr=%p, fc-addr=%p, "
1270 "buf-addr=%p, buf-size=%zu, offset=%zu, "
1271 "packet-offset=%zu",
1272 bfcr
, cls
, buf
, sz
, offset
, packet_offset
);
1274 /* Set root class */
1275 if (cls
->is_compound
) {
1276 /* Compound class: push on visit stack */
1279 if (bfcr
->user
.cbs
.classes
.compound_begin
) {
1280 BT_LOGV("Calling user function (compound, begin).");
1281 *status
= bfcr
->user
.cbs
.classes
.compound_begin(
1282 cls
, bfcr
->user
.data
);
1283 BT_LOGV("User function returned: status=%s",
1284 bt_bfcr_status_string(*status
));
1285 if (*status
!= BT_BFCR_STATUS_OK
) {
1286 BT_LOGW("User function failed: bfcr-addr=%p, status=%s",
1287 bfcr
, bt_bfcr_status_string(*status
));
1292 stack_ret
= stack_push_with_len(bfcr
, cls
);
1294 /* stack_push_with_len() logs errors */
1295 *status
= BT_BFCR_STATUS_ERROR
;
1299 bfcr
->state
= BFCR_STATE_ALIGN_COMPOUND
;
1301 /* Basic class: set as current basic class */
1302 bfcr
->cur_basic_field_class
= cls
;
1303 bfcr
->state
= BFCR_STATE_ALIGN_BASIC
;
1306 /* Run the machine! */
1307 BT_LOGV_STR("Running the state machine.");
1310 *status
= handle_state(bfcr
);
1311 if (*status
!= BT_BFCR_STATUS_OK
||
1312 bfcr
->state
== BFCR_STATE_DONE
) {
1317 /* Update packet offset for next time */
1318 update_packet_offset(bfcr
);
1321 return bfcr
->buf
.at
;
1325 size_t bt_bfcr_continue(struct bt_bfcr
*bfcr
, const uint8_t *buf
, size_t sz
,
1326 enum bt_bfcr_status
*status
)
1331 bfcr
->buf
.addr
= buf
;
1332 bfcr
->buf
.offset
= 0;
1334 bfcr
->buf
.buf_sz
= sz
;
1335 bfcr
->buf
.sz
= BYTES_TO_BITS(sz
);
1336 *status
= BT_BFCR_STATUS_OK
;
1338 BT_LOGV("Continuing decoding: bfcr-addr=%p, buf-addr=%p, buf-size=%zu",
1341 /* Continue running the machine */
1342 BT_LOGV_STR("Running the state machine.");
1345 *status
= handle_state(bfcr
);
1346 if (*status
!= BT_BFCR_STATUS_OK
||
1347 bfcr
->state
== BFCR_STATE_DONE
) {
1352 /* Update packet offset for next time */
1353 update_packet_offset(bfcr
);
1354 return bfcr
->buf
.at
;
1358 void bt_bfcr_set_unsigned_int_cb(struct bt_bfcr
*bfcr
,
1359 bt_bfcr_unsigned_int_cb_func cb
)
1363 bfcr
->user
.cbs
.classes
.unsigned_int
= cb
;