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_COMP_LOG_SELF_COMP (bfcr->self_comp)
27 #define BT_LOG_OUTPUT_LEVEL (bfcr->log_level)
28 #define BT_LOG_TAG "PLUGIN/CTF/BFCR"
29 #include "plugins/comp-logging.h"
37 #include "common/assert.h"
39 #include "compat/bitfield.h"
40 #include "common/common.h"
41 #include <babeltrace2/babeltrace.h>
42 #include "common/align.h"
46 #include "../metadata/ctf-meta.h"
48 #define DIV8(_x) ((_x) >> 3)
49 #define BYTES_TO_BITS(_x) ((_x) * 8)
50 #define BITS_TO_BYTES_FLOOR(_x) DIV8(_x)
51 #define BITS_TO_BYTES_CEIL(_x) DIV8((_x) + 7)
52 #define IN_BYTE_OFFSET(_at) ((_at) & 7)
54 /* A visit stack entry */
57 * Current class of base field, one of:
64 struct ctf_field_class
*base_class
;
66 /* Length of base field (always 1 for a variant class) */
69 /* Index of next field to read */
79 /* Entries (struct stack_entry) */
82 /* Number of active entries */
88 BFCR_STATE_NEXT_FIELD
,
89 BFCR_STATE_ALIGN_BASIC
,
90 BFCR_STATE_ALIGN_COMPOUND
,
91 BFCR_STATE_READ_BASIC_BEGIN
,
92 BFCR_STATE_READ_BASIC_CONTINUE
,
96 /* Binary class reader */
98 bt_logging_level log_level
;
101 bt_self_component
*self_comp
;
106 /* Current basic field class */
107 struct ctf_field_class
*cur_basic_field_class
;
110 enum bfcr_state state
;
113 * Last basic field class's byte order.
115 * This is used to detect errors since two contiguous basic
116 * classes for which the common boundary is not the boundary of
117 * a byte cannot have different byte orders.
119 * This is set to -1 on reset and when the last basic field class
120 * was a string class.
122 enum ctf_byte_order last_bo
;
124 /* Current byte order (copied to last_bo after a successful read) */
125 enum ctf_byte_order cur_bo
;
127 /* Stitch buffer infos */
132 /* Offset, within stitch buffer, of first bit */
135 /* Length (bits) of data in stitch buffer from offset */
139 /* User buffer infos */
144 /* Offset of data from address (bits) */
147 /* Current position from offset (bits) */
150 /* Offset of offset within whole packet (bits) */
151 size_t packet_offset
;
153 /* Data size in buffer (bits) */
156 /* Buffer size (bytes) */
162 /* Callback functions */
163 struct bt_bfcr_cbs cbs
;
171 const char *bfcr_state_string(enum bfcr_state state
)
174 case BFCR_STATE_NEXT_FIELD
:
176 case BFCR_STATE_ALIGN_BASIC
:
177 return "ALIGN_BASIC";
178 case BFCR_STATE_ALIGN_COMPOUND
:
179 return "ALIGN_COMPOUND";
180 case BFCR_STATE_READ_BASIC_BEGIN
:
181 return "READ_BASIC_BEGIN";
182 case BFCR_STATE_READ_BASIC_CONTINUE
:
183 return "READ_BASIC_CONTINUE";
184 case BFCR_STATE_DONE
:
192 struct stack
*stack_new(struct bt_bfcr
*bfcr
)
194 struct stack
*stack
= NULL
;
196 stack
= g_new0(struct stack
, 1);
198 BT_COMP_LOGE_STR("Failed to allocate one stack.");
203 stack
->entries
= g_array_new(FALSE
, TRUE
, sizeof(struct stack_entry
));
204 if (!stack
->entries
) {
205 BT_COMP_LOGE_STR("Failed to allocate a GArray.");
209 BT_COMP_LOGD("Created stack: addr=%p", stack
);
218 void stack_destroy(struct stack
*stack
)
220 struct bt_bfcr
*bfcr
;
227 BT_COMP_LOGD("Destroying stack: addr=%p", stack
);
229 if (stack
->entries
) {
230 g_array_free(stack
->entries
, TRUE
);
237 int stack_push(struct stack
*stack
, struct ctf_field_class
*base_class
,
240 struct stack_entry
*entry
;
241 struct bt_bfcr
*bfcr
;
244 BT_ASSERT(base_class
);
246 BT_COMP_LOGT("Pushing field class on stack: stack-addr=%p, "
247 "fc-addr=%p, fc-type=%d, base-length=%zu, "
248 "stack-size-before=%zu, stack-size-after=%zu",
249 stack
, base_class
, base_class
->type
,
250 base_len
, stack
->size
, stack
->size
+ 1);
252 if (stack
->entries
->len
== stack
->size
) {
253 g_array_set_size(stack
->entries
, stack
->size
+ 1);
256 entry
= &g_array_index(stack
->entries
, struct stack_entry
, stack
->size
);
257 entry
->base_class
= base_class
;
258 entry
->base_len
= base_len
;
265 int64_t get_compound_field_class_length(struct bt_bfcr
*bfcr
,
266 struct ctf_field_class
*fc
)
271 case CTF_FIELD_CLASS_TYPE_STRUCT
:
273 struct ctf_field_class_struct
*struct_fc
= (void *) fc
;
275 length
= (int64_t) struct_fc
->members
->len
;
278 case CTF_FIELD_CLASS_TYPE_VARIANT
:
280 /* Variant field classes always "contain" a single class */
284 case CTF_FIELD_CLASS_TYPE_ARRAY
:
286 struct ctf_field_class_array
*array_fc
= (void *) fc
;
288 length
= (int64_t) array_fc
->length
;
291 case CTF_FIELD_CLASS_TYPE_SEQUENCE
:
292 length
= bfcr
->user
.cbs
.query
.get_sequence_length(fc
,
303 int stack_push_with_len(struct bt_bfcr
*bfcr
, struct ctf_field_class
*base_class
)
306 int64_t length
= get_compound_field_class_length(bfcr
, base_class
);
309 BT_COMP_LOGW("Cannot get compound field class's field count: "
310 "bfcr-addr=%p, fc-addr=%p, fc-type=%d",
311 bfcr
, base_class
, base_class
->type
);
312 ret
= BT_BFCR_STATUS_ERROR
;
316 ret
= stack_push(bfcr
->stack
, base_class
, (size_t) length
);
323 unsigned int stack_size(struct stack
*stack
)
330 void stack_pop(struct stack
*stack
)
332 struct bt_bfcr
*bfcr
;
335 BT_ASSERT(stack_size(stack
));
337 BT_COMP_LOGT("Popping from stack: "
338 "stack-addr=%p, stack-size-before=%u, stack-size-after=%u",
339 stack
, stack
->entries
->len
, stack
->entries
->len
- 1);
344 bool stack_empty(struct stack
*stack
)
346 return stack_size(stack
) == 0;
350 void stack_clear(struct stack
*stack
)
357 struct stack_entry
*stack_top(struct stack
*stack
)
360 BT_ASSERT(stack_size(stack
));
361 return &g_array_index(stack
->entries
, struct stack_entry
,
366 size_t available_bits(struct bt_bfcr
*bfcr
)
368 return bfcr
->buf
.sz
- bfcr
->buf
.at
;
372 void consume_bits(struct bt_bfcr
*bfcr
, size_t incr
)
374 BT_COMP_LOGT("Advancing cursor: bfcr-addr=%p, cur-before=%zu, cur-after=%zu",
375 bfcr
, bfcr
->buf
.at
, bfcr
->buf
.at
+ incr
);
376 bfcr
->buf
.at
+= incr
;
380 bool has_enough_bits(struct bt_bfcr
*bfcr
, size_t sz
)
382 return available_bits(bfcr
) >= sz
;
386 bool at_least_one_bit_left(struct bt_bfcr
*bfcr
)
388 return has_enough_bits(bfcr
, 1);
392 size_t packet_at(struct bt_bfcr
*bfcr
)
394 return bfcr
->buf
.packet_offset
+ bfcr
->buf
.at
;
398 size_t buf_at_from_addr(struct bt_bfcr
*bfcr
)
403 * ====== offset ===== (17)
405 * xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
407 * addr (0) ==== at ==== (12)
411 * =============================== (29)
413 return bfcr
->buf
.offset
+ bfcr
->buf
.at
;
417 void stitch_reset(struct bt_bfcr
*bfcr
)
419 bfcr
->stitch
.offset
= 0;
424 size_t stitch_at_from_addr(struct bt_bfcr
*bfcr
)
426 return bfcr
->stitch
.offset
+ bfcr
->stitch
.at
;
430 void stitch_append_from_buf(struct bt_bfcr
*bfcr
, size_t sz
)
432 size_t stitch_byte_at
;
441 BITS_TO_BYTES_FLOOR(stitch_at_from_addr(bfcr
));
442 buf_byte_at
= BITS_TO_BYTES_FLOOR(buf_at_from_addr(bfcr
));
443 nb_bytes
= BITS_TO_BYTES_CEIL(sz
);
444 BT_ASSERT(nb_bytes
> 0);
445 BT_ASSERT(bfcr
->buf
.addr
);
446 memcpy(&bfcr
->stitch
.buf
[stitch_byte_at
], &bfcr
->buf
.addr
[buf_byte_at
],
448 bfcr
->stitch
.at
+= sz
;
449 consume_bits(bfcr
, sz
);
453 void stitch_append_from_remaining_buf(struct bt_bfcr
*bfcr
)
455 stitch_append_from_buf(bfcr
, available_bits(bfcr
));
459 void stitch_set_from_remaining_buf(struct bt_bfcr
*bfcr
)
462 bfcr
->stitch
.offset
= IN_BYTE_OFFSET(buf_at_from_addr(bfcr
));
463 stitch_append_from_remaining_buf(bfcr
);
467 void read_unsigned_bitfield(struct bt_bfcr
*bfcr
, const uint8_t *buf
, size_t at
,
468 unsigned int field_size
, enum ctf_byte_order bo
,
472 case CTF_BYTE_ORDER_BIG
:
473 bt_bitfield_read_be(buf
, uint8_t, at
, field_size
, v
);
475 case CTF_BYTE_ORDER_LITTLE
:
476 bt_bitfield_read_le(buf
, uint8_t, at
, field_size
, v
);
482 BT_COMP_LOGT("Read unsigned bit array: cur=%zu, size=%u, "
483 "bo=%d, val=%" PRIu64
, at
, field_size
, bo
, *v
);
487 void read_signed_bitfield(struct bt_bfcr
*bfcr
, const uint8_t *buf
, size_t at
,
488 unsigned int field_size
, enum ctf_byte_order bo
, int64_t *v
)
491 case CTF_BYTE_ORDER_BIG
:
492 bt_bitfield_read_be(buf
, uint8_t, at
, field_size
, v
);
494 case CTF_BYTE_ORDER_LITTLE
:
495 bt_bitfield_read_le(buf
, uint8_t, at
, field_size
, v
);
501 BT_COMP_LOGT("Read signed bit array: cur=%zu, size=%u, "
502 "bo=%d, val=%" PRId64
, at
, field_size
, bo
, *v
);
505 typedef enum bt_bfcr_status (* read_basic_and_call_cb_t
)(struct bt_bfcr
*,
506 const uint8_t *, size_t);
509 enum bt_bfcr_status
validate_contiguous_bo(struct bt_bfcr
*bfcr
,
510 enum ctf_byte_order next_bo
)
512 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
514 /* Always valid when at a byte boundary */
515 if (packet_at(bfcr
) % 8 == 0) {
519 /* Always valid if last byte order is unknown */
520 if (bfcr
->last_bo
== -1) {
524 /* Always valid if next byte order is unknown */
529 /* Make sure last byte order is compatible with the next byte order */
530 switch (bfcr
->last_bo
) {
531 case CTF_BYTE_ORDER_BIG
:
532 if (next_bo
!= CTF_BYTE_ORDER_BIG
) {
533 status
= BT_BFCR_STATUS_ERROR
;
536 case CTF_BYTE_ORDER_LITTLE
:
537 if (next_bo
!= CTF_BYTE_ORDER_LITTLE
) {
538 status
= BT_BFCR_STATUS_ERROR
;
542 status
= BT_BFCR_STATUS_ERROR
;
547 BT_COMP_LOGW("Cannot read bit array: two different byte orders not at a byte boundary: "
548 "bfcr-addr=%p, last-bo=%d, next-bo=%d",
549 bfcr
, bfcr
->last_bo
, next_bo
);
556 enum bt_bfcr_status
read_basic_float_and_call_cb(struct bt_bfcr
*bfcr
,
557 const uint8_t *buf
, size_t at
)
560 unsigned int field_size
;
561 enum ctf_byte_order bo
;
562 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
563 struct ctf_field_class_float
*fc
= (void *) bfcr
->cur_basic_field_class
;
566 field_size
= fc
->base
.size
;
567 bo
= fc
->base
.byte_order
;
570 switch (field_size
) {
579 read_unsigned_bitfield(bfcr
, buf
, at
, field_size
, bo
, &v
);
580 f32
.u
= (uint32_t) v
;
581 dblval
= (double) f32
.f
;
591 read_unsigned_bitfield(bfcr
, buf
, at
, field_size
, bo
, &f64
.u
);
596 /* Only 32-bit and 64-bit fields are supported currently */
600 BT_COMP_LOGT("Read floating point number value: bfcr=%p, cur=%zu, val=%f",
603 if (bfcr
->user
.cbs
.classes
.floating_point
) {
604 BT_COMP_LOGT("Calling user function (floating point number).");
605 status
= bfcr
->user
.cbs
.classes
.floating_point(dblval
,
606 bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
607 BT_COMP_LOGT("User function returned: status=%s",
608 bt_bfcr_status_string(status
));
609 if (status
!= BT_BFCR_STATUS_OK
) {
610 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s",
611 bfcr
, bt_bfcr_status_string(status
));
619 enum bt_bfcr_status
read_basic_int_and_call_cb(struct bt_bfcr
*bfcr
,
620 const uint8_t *buf
, size_t at
)
622 unsigned int field_size
;
623 enum ctf_byte_order bo
;
624 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
625 struct ctf_field_class_int
*fc
= (void *) bfcr
->cur_basic_field_class
;
627 field_size
= fc
->base
.size
;
628 bo
= fc
->base
.byte_order
;
631 * Update current byte order now because we could be reading
632 * the integer value of an enumeration class, and thus we know
633 * here the actual supporting integer class's byte order.
640 read_signed_bitfield(bfcr
, buf
, at
, field_size
, bo
, &v
);
642 if (bfcr
->user
.cbs
.classes
.signed_int
) {
643 BT_COMP_LOGT("Calling user function (signed integer).");
644 status
= bfcr
->user
.cbs
.classes
.signed_int(v
,
645 bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
646 BT_COMP_LOGT("User function returned: status=%s",
647 bt_bfcr_status_string(status
));
648 if (status
!= BT_BFCR_STATUS_OK
) {
649 BT_COMP_LOGW("User function failed: "
650 "bfcr-addr=%p, status=%s",
651 bfcr
, bt_bfcr_status_string(status
));
657 read_unsigned_bitfield(bfcr
, buf
, at
, field_size
, bo
, &v
);
659 if (bfcr
->user
.cbs
.classes
.unsigned_int
) {
660 BT_COMP_LOGT("Calling user function (unsigned integer).");
661 status
= bfcr
->user
.cbs
.classes
.unsigned_int(v
,
662 bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
663 BT_COMP_LOGT("User function returned: status=%s",
664 bt_bfcr_status_string(status
));
665 if (status
!= BT_BFCR_STATUS_OK
) {
666 BT_COMP_LOGW("User function failed: "
667 "bfcr-addr=%p, status=%s",
668 bfcr
, bt_bfcr_status_string(status
));
677 enum bt_bfcr_status
read_bit_array_class_and_call_continue(struct bt_bfcr
*bfcr
,
678 read_basic_and_call_cb_t read_basic_and_call_cb
)
682 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
683 struct ctf_field_class_bit_array
*fc
=
684 (void *) bfcr
->cur_basic_field_class
;
686 if (!at_least_one_bit_left(bfcr
)) {
687 BT_COMP_LOGT("Reached end of data: bfcr-addr=%p", bfcr
);
688 status
= BT_BFCR_STATUS_EOF
;
692 available
= available_bits(bfcr
);
693 needed_bits
= fc
->size
- bfcr
->stitch
.at
;
694 BT_COMP_LOGT("Continuing basic field decoding: "
695 "bfcr-addr=%p, field-size=%u, needed-size=%zu, "
696 "available-size=%zu",
697 bfcr
, fc
->size
, needed_bits
, available
);
698 if (needed_bits
<= available
) {
699 /* We have all the bits; append to stitch, then decode */
700 stitch_append_from_buf(bfcr
, needed_bits
);
701 status
= read_basic_and_call_cb(bfcr
, bfcr
->stitch
.buf
,
702 bfcr
->stitch
.offset
);
703 if (status
!= BT_BFCR_STATUS_OK
) {
704 BT_COMP_LOGW("Cannot read basic field: "
705 "bfcr-addr=%p, fc-addr=%p, status=%s",
706 bfcr
, bfcr
->cur_basic_field_class
,
707 bt_bfcr_status_string(status
));
711 if (stack_empty(bfcr
->stack
)) {
712 /* Root is a basic class */
713 bfcr
->state
= BFCR_STATE_DONE
;
715 /* Go to next field */
716 stack_top(bfcr
->stack
)->index
++;
717 bfcr
->state
= BFCR_STATE_NEXT_FIELD
;
718 bfcr
->last_bo
= bfcr
->cur_bo
;
723 /* We are here; it means we don't have enough data to decode this */
724 BT_COMP_LOGT_STR("Not enough data to read the next basic field: appending to stitch buffer.");
725 stitch_append_from_remaining_buf(bfcr
);
726 status
= BT_BFCR_STATUS_EOF
;
733 enum bt_bfcr_status
read_bit_array_class_and_call_begin(struct bt_bfcr
*bfcr
,
734 read_basic_and_call_cb_t read_basic_and_call_cb
)
737 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
738 struct ctf_field_class_bit_array
*fc
=
739 (void *) bfcr
->cur_basic_field_class
;
741 if (!at_least_one_bit_left(bfcr
)) {
742 BT_COMP_LOGT("Reached end of data: bfcr-addr=%p", bfcr
);
743 status
= BT_BFCR_STATUS_EOF
;
747 status
= validate_contiguous_bo(bfcr
, fc
->byte_order
);
748 if (status
!= BT_BFCR_STATUS_OK
) {
749 /* validate_contiguous_bo() logs errors */
753 available
= available_bits(bfcr
);
755 if (fc
->size
<= available
) {
756 /* We have all the bits; decode and set now */
757 BT_ASSERT(bfcr
->buf
.addr
);
758 status
= read_basic_and_call_cb(bfcr
, bfcr
->buf
.addr
,
759 buf_at_from_addr(bfcr
));
760 if (status
!= BT_BFCR_STATUS_OK
) {
761 BT_COMP_LOGW("Cannot read basic field: "
762 "bfcr-addr=%p, fc-addr=%p, status=%s",
763 bfcr
, bfcr
->cur_basic_field_class
,
764 bt_bfcr_status_string(status
));
768 consume_bits(bfcr
, fc
->size
);
770 if (stack_empty(bfcr
->stack
)) {
771 /* Root is a basic class */
772 bfcr
->state
= BFCR_STATE_DONE
;
774 /* Go to next field */
775 stack_top(bfcr
->stack
)->index
++;
776 bfcr
->state
= BFCR_STATE_NEXT_FIELD
;
777 bfcr
->last_bo
= bfcr
->cur_bo
;
783 /* We are here; it means we don't have enough data to decode this */
784 BT_COMP_LOGT_STR("Not enough data to read the next basic field: setting stitch buffer.");
785 stitch_set_from_remaining_buf(bfcr
);
786 bfcr
->state
= BFCR_STATE_READ_BASIC_CONTINUE
;
787 status
= BT_BFCR_STATUS_EOF
;
794 enum bt_bfcr_status
read_basic_int_class_and_call_begin(
795 struct bt_bfcr
*bfcr
)
797 return read_bit_array_class_and_call_begin(bfcr
, read_basic_int_and_call_cb
);
801 enum bt_bfcr_status
read_basic_int_class_and_call_continue(
802 struct bt_bfcr
*bfcr
)
804 return read_bit_array_class_and_call_continue(bfcr
,
805 read_basic_int_and_call_cb
);
809 enum bt_bfcr_status
read_basic_float_class_and_call_begin(
810 struct bt_bfcr
*bfcr
)
812 return read_bit_array_class_and_call_begin(bfcr
,
813 read_basic_float_and_call_cb
);
817 enum bt_bfcr_status
read_basic_float_class_and_call_continue(
818 struct bt_bfcr
*bfcr
)
820 return read_bit_array_class_and_call_continue(bfcr
,
821 read_basic_float_and_call_cb
);
825 enum bt_bfcr_status
read_basic_string_class_and_call(
826 struct bt_bfcr
*bfcr
, bool begin
)
829 const uint8_t *result
;
830 size_t available_bytes
;
831 const uint8_t *first_chr
;
832 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
834 if (!at_least_one_bit_left(bfcr
)) {
835 BT_COMP_LOGT("Reached end of data: bfcr-addr=%p", bfcr
);
836 status
= BT_BFCR_STATUS_EOF
;
840 BT_ASSERT(buf_at_from_addr(bfcr
) % 8 == 0);
841 available_bytes
= BITS_TO_BYTES_FLOOR(available_bits(bfcr
));
842 buf_at_bytes
= BITS_TO_BYTES_FLOOR(buf_at_from_addr(bfcr
));
843 BT_ASSERT(bfcr
->buf
.addr
);
844 first_chr
= &bfcr
->buf
.addr
[buf_at_bytes
];
845 result
= memchr(first_chr
, '\0', available_bytes
);
847 if (begin
&& bfcr
->user
.cbs
.classes
.string_begin
) {
848 BT_COMP_LOGT("Calling user function (string, beginning).");
849 status
= bfcr
->user
.cbs
.classes
.string_begin(
850 bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
851 BT_COMP_LOGT("User function returned: status=%s",
852 bt_bfcr_status_string(status
));
853 if (status
!= BT_BFCR_STATUS_OK
) {
854 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s",
855 bfcr
, bt_bfcr_status_string(status
));
861 /* No null character yet */
862 if (bfcr
->user
.cbs
.classes
.string
) {
863 BT_COMP_LOGT("Calling user function (substring).");
864 status
= bfcr
->user
.cbs
.classes
.string(
865 (const char *) first_chr
,
866 available_bytes
, bfcr
->cur_basic_field_class
,
868 BT_COMP_LOGT("User function returned: status=%s",
869 bt_bfcr_status_string(status
));
870 if (status
!= BT_BFCR_STATUS_OK
) {
871 BT_COMP_LOGW("User function failed: "
872 "bfcr-addr=%p, status=%s",
873 bfcr
, bt_bfcr_status_string(status
));
878 consume_bits(bfcr
, BYTES_TO_BITS(available_bytes
));
879 bfcr
->state
= BFCR_STATE_READ_BASIC_CONTINUE
;
880 status
= BT_BFCR_STATUS_EOF
;
882 /* Found the null character */
883 size_t result_len
= (size_t) (result
- first_chr
);
885 if (bfcr
->user
.cbs
.classes
.string
&& result_len
) {
886 BT_COMP_LOGT("Calling user function (substring).");
887 status
= bfcr
->user
.cbs
.classes
.string(
888 (const char *) first_chr
,
889 result_len
, bfcr
->cur_basic_field_class
,
891 BT_COMP_LOGT("User function returned: status=%s",
892 bt_bfcr_status_string(status
));
893 if (status
!= BT_BFCR_STATUS_OK
) {
894 BT_COMP_LOGW("User function failed: "
895 "bfcr-addr=%p, status=%s",
896 bfcr
, bt_bfcr_status_string(status
));
901 if (bfcr
->user
.cbs
.classes
.string_end
) {
902 BT_COMP_LOGT("Calling user function (string, end).");
903 status
= bfcr
->user
.cbs
.classes
.string_end(
904 bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
905 BT_COMP_LOGT("User function returned: status=%s",
906 bt_bfcr_status_string(status
));
907 if (status
!= BT_BFCR_STATUS_OK
) {
908 BT_COMP_LOGW("User function failed: "
909 "bfcr-addr=%p, status=%s",
910 bfcr
, bt_bfcr_status_string(status
));
915 consume_bits(bfcr
, BYTES_TO_BITS(result_len
+ 1));
917 if (stack_empty(bfcr
->stack
)) {
918 /* Root is a basic class */
919 bfcr
->state
= BFCR_STATE_DONE
;
921 /* Go to next field */
922 stack_top(bfcr
->stack
)->index
++;
923 bfcr
->state
= BFCR_STATE_NEXT_FIELD
;
924 bfcr
->last_bo
= bfcr
->cur_bo
;
933 enum bt_bfcr_status
read_basic_begin_state(struct bt_bfcr
*bfcr
)
935 enum bt_bfcr_status status
;
937 BT_ASSERT(bfcr
->cur_basic_field_class
);
939 switch (bfcr
->cur_basic_field_class
->type
) {
940 case CTF_FIELD_CLASS_TYPE_INT
:
941 case CTF_FIELD_CLASS_TYPE_ENUM
:
942 status
= read_basic_int_class_and_call_begin(bfcr
);
944 case CTF_FIELD_CLASS_TYPE_FLOAT
:
945 status
= read_basic_float_class_and_call_begin(bfcr
);
947 case CTF_FIELD_CLASS_TYPE_STRING
:
948 status
= read_basic_string_class_and_call(bfcr
, true);
958 enum bt_bfcr_status
read_basic_continue_state(struct bt_bfcr
*bfcr
)
960 enum bt_bfcr_status status
;
962 BT_ASSERT(bfcr
->cur_basic_field_class
);
964 switch (bfcr
->cur_basic_field_class
->type
) {
965 case CTF_FIELD_CLASS_TYPE_INT
:
966 case CTF_FIELD_CLASS_TYPE_ENUM
:
967 status
= read_basic_int_class_and_call_continue(bfcr
);
969 case CTF_FIELD_CLASS_TYPE_FLOAT
:
970 status
= read_basic_float_class_and_call_continue(bfcr
);
972 case CTF_FIELD_CLASS_TYPE_STRING
:
973 status
= read_basic_string_class_and_call(bfcr
, false);
983 size_t bits_to_skip_to_align_to(struct bt_bfcr
*bfcr
, size_t align
)
985 size_t aligned_packet_at
;
987 aligned_packet_at
= ALIGN(packet_at(bfcr
), align
);
988 return aligned_packet_at
- packet_at(bfcr
);
992 enum bt_bfcr_status
align_class_state(struct bt_bfcr
*bfcr
,
993 struct ctf_field_class
*field_class
, enum bfcr_state next_state
)
995 unsigned int field_alignment
;
997 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
999 /* Get field's alignment */
1000 field_alignment
= field_class
->alignment
;
1003 * 0 means "undefined" for variants; what we really want is 1
1006 BT_ASSERT(field_alignment
>= 1);
1008 /* Compute how many bits we need to skip */
1009 skip_bits
= bits_to_skip_to_align_to(bfcr
, (size_t) field_alignment
);
1011 /* Nothing to skip? aligned */
1012 if (skip_bits
== 0) {
1013 bfcr
->state
= next_state
;
1017 /* Make sure there's at least one bit left */
1018 if (!at_least_one_bit_left(bfcr
)) {
1019 status
= BT_BFCR_STATUS_EOF
;
1023 /* Consume as many bits as possible in what's left */
1024 consume_bits(bfcr
, MIN(available_bits(bfcr
), skip_bits
));
1026 /* Are we done now? */
1027 skip_bits
= bits_to_skip_to_align_to(bfcr
, field_alignment
);
1028 if (skip_bits
== 0) {
1029 /* Yes: go to next state */
1030 bfcr
->state
= next_state
;
1033 /* No: need more data */
1034 BT_COMP_LOGT("Reached end of data when aligning: bfcr-addr=%p", bfcr
);
1035 status
= BT_BFCR_STATUS_EOF
;
1043 enum bt_bfcr_status
next_field_state(struct bt_bfcr
*bfcr
)
1046 struct stack_entry
*top
;
1047 struct ctf_field_class
*next_field_class
= NULL
;
1048 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
1050 if (stack_empty(bfcr
->stack
)) {
1054 top
= stack_top(bfcr
->stack
);
1056 /* Are we done with this base class? */
1057 while (top
->index
== top
->base_len
) {
1058 if (bfcr
->user
.cbs
.classes
.compound_end
) {
1059 BT_COMP_LOGT("Calling user function (compound, end).");
1060 status
= bfcr
->user
.cbs
.classes
.compound_end(
1061 top
->base_class
, bfcr
->user
.data
);
1062 BT_COMP_LOGT("User function returned: status=%s",
1063 bt_bfcr_status_string(status
));
1064 if (status
!= BT_BFCR_STATUS_OK
) {
1065 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s",
1066 bfcr
, bt_bfcr_status_string(status
));
1071 stack_pop(bfcr
->stack
);
1073 /* Are we done with the root class? */
1074 if (stack_empty(bfcr
->stack
)) {
1075 bfcr
->state
= BFCR_STATE_DONE
;
1079 top
= stack_top(bfcr
->stack
);
1083 /* Get next field's class */
1084 switch (top
->base_class
->type
) {
1085 case CTF_FIELD_CLASS_TYPE_STRUCT
:
1086 next_field_class
= ctf_field_class_struct_borrow_member_by_index(
1087 (void *) top
->base_class
, (uint64_t) top
->index
)->fc
;
1089 case CTF_FIELD_CLASS_TYPE_ARRAY
:
1090 case CTF_FIELD_CLASS_TYPE_SEQUENCE
:
1092 struct ctf_field_class_array_base
*array_fc
=
1093 (void *) top
->base_class
;
1095 next_field_class
= array_fc
->elem_fc
;
1098 case CTF_FIELD_CLASS_TYPE_VARIANT
:
1099 /* Variant classes are dynamic: the user should know! */
1101 bfcr
->user
.cbs
.query
.borrow_variant_selected_field_class(
1102 top
->base_class
, bfcr
->user
.data
);
1108 if (!next_field_class
) {
1109 BT_COMP_LOGW("Cannot get the field class of the next field: "
1110 "bfcr-addr=%p, base-fc-addr=%p, base-fc-type=%d, "
1112 bfcr
, top
->base_class
, top
->base_class
->type
,
1114 status
= BT_BFCR_STATUS_ERROR
;
1118 if (next_field_class
->is_compound
) {
1119 if (bfcr
->user
.cbs
.classes
.compound_begin
) {
1120 BT_COMP_LOGT("Calling user function (compound, begin).");
1121 status
= bfcr
->user
.cbs
.classes
.compound_begin(
1122 next_field_class
, bfcr
->user
.data
);
1123 BT_COMP_LOGT("User function returned: status=%s",
1124 bt_bfcr_status_string(status
));
1125 if (status
!= BT_BFCR_STATUS_OK
) {
1126 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s",
1127 bfcr
, bt_bfcr_status_string(status
));
1132 ret
= stack_push_with_len(bfcr
, next_field_class
);
1134 /* stack_push_with_len() logs errors */
1135 status
= BT_BFCR_STATUS_ERROR
;
1139 /* Next state: align a compound class */
1140 bfcr
->state
= BFCR_STATE_ALIGN_COMPOUND
;
1142 /* Replace current basic field class */
1143 BT_COMP_LOGT("Replacing current basic field class: "
1144 "bfcr-addr=%p, cur-basic-fc-addr=%p, "
1145 "next-basic-fc-addr=%p",
1146 bfcr
, bfcr
->cur_basic_field_class
, next_field_class
);
1147 bfcr
->cur_basic_field_class
= next_field_class
;
1149 /* Next state: align a basic class */
1150 bfcr
->state
= BFCR_STATE_ALIGN_BASIC
;
1158 enum bt_bfcr_status
handle_state(struct bt_bfcr
*bfcr
)
1160 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
1162 BT_COMP_LOGT("Handling state: bfcr-addr=%p, state=%s",
1163 bfcr
, bfcr_state_string(bfcr
->state
));
1165 switch (bfcr
->state
) {
1166 case BFCR_STATE_NEXT_FIELD
:
1167 status
= next_field_state(bfcr
);
1169 case BFCR_STATE_ALIGN_BASIC
:
1170 status
= align_class_state(bfcr
, bfcr
->cur_basic_field_class
,
1171 BFCR_STATE_READ_BASIC_BEGIN
);
1173 case BFCR_STATE_ALIGN_COMPOUND
:
1174 status
= align_class_state(bfcr
, stack_top(bfcr
->stack
)->base_class
,
1175 BFCR_STATE_NEXT_FIELD
);
1177 case BFCR_STATE_READ_BASIC_BEGIN
:
1178 status
= read_basic_begin_state(bfcr
);
1180 case BFCR_STATE_READ_BASIC_CONTINUE
:
1181 status
= read_basic_continue_state(bfcr
);
1183 case BFCR_STATE_DONE
:
1187 BT_COMP_LOGT("Handled state: bfcr-addr=%p, status=%s",
1188 bfcr
, bt_bfcr_status_string(status
));
1193 struct bt_bfcr
*bt_bfcr_create(struct bt_bfcr_cbs cbs
, void *data
,
1194 bt_logging_level log_level
, bt_self_component
*self_comp
)
1196 struct bt_bfcr
*bfcr
;
1198 BT_COMP_LOG_CUR_LVL(BT_LOG_DEBUG
, log_level
, self_comp
,
1199 "Creating binary field class reader (BFCR).");
1200 bfcr
= g_new0(struct bt_bfcr
, 1);
1202 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR
, log_level
, self_comp
,
1203 "Failed to allocate one binary class reader.");
1207 bfcr
->log_level
= log_level
;
1208 bfcr
->self_comp
= self_comp
;
1209 bfcr
->stack
= stack_new(bfcr
);
1211 BT_COMP_LOGE_STR("Cannot create BFCR's stack.");
1212 bt_bfcr_destroy(bfcr
);
1217 bfcr
->state
= BFCR_STATE_NEXT_FIELD
;
1218 bfcr
->user
.cbs
= cbs
;
1219 bfcr
->user
.data
= data
;
1220 BT_COMP_LOGD("Created BFCR: addr=%p", bfcr
);
1227 void bt_bfcr_destroy(struct bt_bfcr
*bfcr
)
1230 stack_destroy(bfcr
->stack
);
1233 BT_COMP_LOGD("Destroying BFCR: addr=%p", bfcr
);
1238 void reset(struct bt_bfcr
*bfcr
)
1240 BT_COMP_LOGD("Resetting BFCR: addr=%p", bfcr
);
1241 stack_clear(bfcr
->stack
);
1243 bfcr
->buf
.addr
= NULL
;
1248 void update_packet_offset(struct bt_bfcr
*bfcr
)
1250 BT_COMP_LOGT("Updating packet offset for next call: "
1251 "bfcr-addr=%p, cur-packet-offset=%zu, next-packet-offset=%zu",
1252 bfcr
, bfcr
->buf
.packet_offset
,
1253 bfcr
->buf
.packet_offset
+ bfcr
->buf
.at
);
1254 bfcr
->buf
.packet_offset
+= bfcr
->buf
.at
;
1258 size_t bt_bfcr_start(struct bt_bfcr
*bfcr
,
1259 struct ctf_field_class
*cls
, const uint8_t *buf
,
1260 size_t offset
, size_t packet_offset
, size_t sz
,
1261 enum bt_bfcr_status
*status
)
1264 BT_ASSERT(BYTES_TO_BITS(sz
) >= offset
);
1266 bfcr
->buf
.addr
= buf
;
1267 bfcr
->buf
.offset
= offset
;
1269 bfcr
->buf
.packet_offset
= packet_offset
;
1270 bfcr
->buf
.buf_sz
= sz
;
1271 bfcr
->buf
.sz
= BYTES_TO_BITS(sz
) - offset
;
1272 *status
= BT_BFCR_STATUS_OK
;
1274 BT_COMP_LOGT("Starting decoding: bfcr-addr=%p, fc-addr=%p, "
1275 "buf-addr=%p, buf-size=%zu, offset=%zu, "
1276 "packet-offset=%zu",
1277 bfcr
, cls
, buf
, sz
, offset
, packet_offset
);
1279 /* Set root class */
1280 if (cls
->is_compound
) {
1281 /* Compound class: push on visit stack */
1284 if (bfcr
->user
.cbs
.classes
.compound_begin
) {
1285 BT_COMP_LOGT("Calling user function (compound, begin).");
1286 *status
= bfcr
->user
.cbs
.classes
.compound_begin(
1287 cls
, bfcr
->user
.data
);
1288 BT_COMP_LOGT("User function returned: status=%s",
1289 bt_bfcr_status_string(*status
));
1290 if (*status
!= BT_BFCR_STATUS_OK
) {
1291 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s",
1292 bfcr
, bt_bfcr_status_string(*status
));
1297 stack_ret
= stack_push_with_len(bfcr
, cls
);
1299 /* stack_push_with_len() logs errors */
1300 *status
= BT_BFCR_STATUS_ERROR
;
1304 bfcr
->state
= BFCR_STATE_ALIGN_COMPOUND
;
1306 /* Basic class: set as current basic class */
1307 bfcr
->cur_basic_field_class
= cls
;
1308 bfcr
->state
= BFCR_STATE_ALIGN_BASIC
;
1311 /* Run the machine! */
1312 BT_COMP_LOGT_STR("Running the state machine.");
1315 *status
= handle_state(bfcr
);
1316 if (*status
!= BT_BFCR_STATUS_OK
||
1317 bfcr
->state
== BFCR_STATE_DONE
) {
1322 /* Update packet offset for next time */
1323 update_packet_offset(bfcr
);
1326 return bfcr
->buf
.at
;
1330 size_t bt_bfcr_continue(struct bt_bfcr
*bfcr
, const uint8_t *buf
, size_t sz
,
1331 enum bt_bfcr_status
*status
)
1336 bfcr
->buf
.addr
= buf
;
1337 bfcr
->buf
.offset
= 0;
1339 bfcr
->buf
.buf_sz
= sz
;
1340 bfcr
->buf
.sz
= BYTES_TO_BITS(sz
);
1341 *status
= BT_BFCR_STATUS_OK
;
1343 BT_COMP_LOGT("Continuing decoding: bfcr-addr=%p, buf-addr=%p, buf-size=%zu",
1346 /* Continue running the machine */
1347 BT_COMP_LOGT_STR("Running the state machine.");
1350 *status
= handle_state(bfcr
);
1351 if (*status
!= BT_BFCR_STATUS_OK
||
1352 bfcr
->state
== BFCR_STATE_DONE
) {
1357 /* Update packet offset for next time */
1358 update_packet_offset(bfcr
);
1359 return bfcr
->buf
.at
;
1363 void bt_bfcr_set_unsigned_int_cb(struct bt_bfcr
*bfcr
,
1364 bt_bfcr_unsigned_int_cb_func cb
)
1368 bfcr
->user
.cbs
.classes
.unsigned_int
= cb
;