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_TAG "PLUGIN-CTF-BFCR"
35 #include <babeltrace/assert-internal.h>
37 #include <babeltrace/bitfield-internal.h>
38 #include <babeltrace/common-internal.h>
39 #include <babeltrace/babeltrace.h>
40 #include <babeltrace/ref.h>
41 #include <babeltrace/align-internal.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 */
74 /* Entries (struct stack_entry) */
77 /* Number of active entries */
83 BFCR_STATE_NEXT_FIELD
,
84 BFCR_STATE_ALIGN_BASIC
,
85 BFCR_STATE_ALIGN_COMPOUND
,
86 BFCR_STATE_READ_BASIC_BEGIN
,
87 BFCR_STATE_READ_BASIC_CONTINUE
,
91 /* Binary class reader */
96 /* Current basic field class */
97 struct ctf_field_class
*cur_basic_field_class
;
100 enum bfcr_state state
;
103 * Last basic field class's byte order.
105 * This is used to detect errors since two contiguous basic
106 * classes for which the common boundary is not the boundary of
107 * a byte cannot have different byte orders.
109 * This is set to -1 on reset and when the last basic field class
110 * was a string class.
112 enum ctf_byte_order last_bo
;
114 /* Current byte order (copied to last_bo after a successful read) */
115 enum ctf_byte_order cur_bo
;
117 /* Stitch buffer infos */
122 /* Offset, within stitch buffer, of first bit */
125 /* Length (bits) of data in stitch buffer from offset */
129 /* User buffer infos */
134 /* Offset of data from address (bits) */
137 /* Current position from offset (bits) */
140 /* Offset of offset within whole packet (bits) */
141 size_t packet_offset
;
143 /* Data size in buffer (bits) */
146 /* Buffer size (bytes) */
152 /* Callback functions */
153 struct bt_bfcr_cbs cbs
;
161 const char *bfcr_state_string(enum bfcr_state state
)
164 case BFCR_STATE_NEXT_FIELD
:
165 return "BFCR_STATE_NEXT_FIELD";
166 case BFCR_STATE_ALIGN_BASIC
:
167 return "BFCR_STATE_ALIGN_BASIC";
168 case BFCR_STATE_ALIGN_COMPOUND
:
169 return "BFCR_STATE_ALIGN_COMPOUND";
170 case BFCR_STATE_READ_BASIC_BEGIN
:
171 return "BFCR_STATE_READ_BASIC_BEGIN";
172 case BFCR_STATE_READ_BASIC_CONTINUE
:
173 return "BFCR_STATE_READ_BASIC_CONTINUE";
174 case BFCR_STATE_DONE
:
175 return "BFCR_STATE_DONE";
182 struct stack
*stack_new(void)
184 struct stack
*stack
= NULL
;
186 stack
= g_new0(struct stack
, 1);
188 BT_LOGE_STR("Failed to allocate one stack.");
192 stack
->entries
= g_array_new(FALSE
, TRUE
, sizeof(struct stack_entry
));
193 if (!stack
->entries
) {
194 BT_LOGE_STR("Failed to allocate a GArray.");
198 BT_LOGD("Created stack: addr=%p", stack
);
207 void stack_destroy(struct stack
*stack
)
213 BT_LOGD("Destroying stack: addr=%p", stack
);
215 if (stack
->entries
) {
216 g_array_free(stack
->entries
, TRUE
);
223 int stack_push(struct stack
*stack
, struct ctf_field_class
*base_class
,
226 struct stack_entry
*entry
;
229 BT_ASSERT(base_class
);
230 BT_LOGV("Pushing field class on stack: stack-addr=%p, "
231 "fc-addr=%p, fc-id=%d, base-length=%zu, "
232 "stack-size-before=%zu, stack-size-after=%zu",
233 stack
, base_class
, base_class
->id
,
234 base_len
, stack
->size
, stack
->size
+ 1);
236 if (stack
->entries
->len
== stack
->size
) {
237 g_array_set_size(stack
->entries
, stack
->size
+ 1);
240 entry
= &g_array_index(stack
->entries
, struct stack_entry
, stack
->size
);
241 entry
->base_class
= base_class
;
242 entry
->base_len
= base_len
;
249 int64_t get_compound_field_class_length(struct bt_bfcr
*bfcr
,
250 struct ctf_field_class
*fc
)
255 case CTF_FIELD_CLASS_ID_STRUCT
:
257 struct ctf_field_class_struct
*struct_fc
= (void *) fc
;
259 length
= (int64_t) struct_fc
->members
->len
;
262 case CTF_FIELD_CLASS_ID_VARIANT
:
264 /* Variant field classes always "contain" a single class */
268 case CTF_FIELD_CLASS_ID_ARRAY
:
270 struct ctf_field_class_array
*array_fc
= (void *) fc
;
272 length
= (int64_t) array_fc
->length
;
275 case CTF_FIELD_CLASS_ID_SEQUENCE
:
276 length
= bfcr
->user
.cbs
.query
.get_sequence_length(fc
,
287 int stack_push_with_len(struct bt_bfcr
*bfcr
, struct ctf_field_class
*base_class
)
290 int64_t length
= get_compound_field_class_length(bfcr
, base_class
);
293 BT_LOGW("Cannot get compound field class's field count: "
294 "bfcr-addr=%p, fc-addr=%p, fc-id=%d",
295 bfcr
, base_class
, base_class
->id
);
296 ret
= BT_BFCR_STATUS_ERROR
;
300 ret
= stack_push(bfcr
->stack
, base_class
, (size_t) length
);
307 unsigned int stack_size(struct stack
*stack
)
314 void stack_pop(struct stack
*stack
)
317 BT_ASSERT(stack_size(stack
));
318 BT_LOGV("Popping from stack: "
319 "stack-addr=%p, stack-size-before=%u, stack-size-after=%u",
320 stack
, stack
->entries
->len
, stack
->entries
->len
- 1);
325 bool stack_empty(struct stack
*stack
)
327 return stack_size(stack
) == 0;
331 void stack_clear(struct stack
*stack
)
338 struct stack_entry
*stack_top(struct stack
*stack
)
341 BT_ASSERT(stack_size(stack
));
342 return &g_array_index(stack
->entries
, struct stack_entry
,
347 size_t available_bits(struct bt_bfcr
*bfcr
)
349 return bfcr
->buf
.sz
- bfcr
->buf
.at
;
353 void consume_bits(struct bt_bfcr
*bfcr
, size_t incr
)
355 BT_LOGV("Advancing cursor: bfcr-addr=%p, cur-before=%zu, cur-after=%zu",
356 bfcr
, bfcr
->buf
.at
, bfcr
->buf
.at
+ incr
);
357 bfcr
->buf
.at
+= incr
;
361 bool has_enough_bits(struct bt_bfcr
*bfcr
, size_t sz
)
363 return available_bits(bfcr
) >= sz
;
367 bool at_least_one_bit_left(struct bt_bfcr
*bfcr
)
369 return has_enough_bits(bfcr
, 1);
373 size_t packet_at(struct bt_bfcr
*bfcr
)
375 return bfcr
->buf
.packet_offset
+ bfcr
->buf
.at
;
379 size_t buf_at_from_addr(struct bt_bfcr
*bfcr
)
384 * ====== offset ===== (17)
386 * xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
388 * addr (0) ==== at ==== (12)
392 * =============================== (29)
394 return bfcr
->buf
.offset
+ bfcr
->buf
.at
;
398 void stitch_reset(struct bt_bfcr
*bfcr
)
400 bfcr
->stitch
.offset
= 0;
405 size_t stitch_at_from_addr(struct bt_bfcr
*bfcr
)
407 return bfcr
->stitch
.offset
+ bfcr
->stitch
.at
;
411 void stitch_append_from_buf(struct bt_bfcr
*bfcr
, size_t sz
)
413 size_t stitch_byte_at
;
422 BITS_TO_BYTES_FLOOR(stitch_at_from_addr(bfcr
));
423 buf_byte_at
= BITS_TO_BYTES_FLOOR(buf_at_from_addr(bfcr
));
424 nb_bytes
= BITS_TO_BYTES_CEIL(sz
);
425 BT_ASSERT(nb_bytes
> 0);
426 BT_ASSERT(bfcr
->buf
.addr
);
427 memcpy(&bfcr
->stitch
.buf
[stitch_byte_at
], &bfcr
->buf
.addr
[buf_byte_at
],
429 bfcr
->stitch
.at
+= sz
;
430 consume_bits(bfcr
, sz
);
434 void stitch_append_from_remaining_buf(struct bt_bfcr
*bfcr
)
436 stitch_append_from_buf(bfcr
, available_bits(bfcr
));
440 void stitch_set_from_remaining_buf(struct bt_bfcr
*bfcr
)
443 bfcr
->stitch
.offset
= IN_BYTE_OFFSET(buf_at_from_addr(bfcr
));
444 stitch_append_from_remaining_buf(bfcr
);
448 void read_unsigned_bitfield(const uint8_t *buf
, size_t at
,
449 unsigned int field_size
, enum ctf_byte_order bo
,
453 case CTF_BYTE_ORDER_BIG
:
454 bt_bitfield_read_be(buf
, uint8_t, at
, field_size
, v
);
456 case CTF_BYTE_ORDER_LITTLE
:
457 bt_bitfield_read_le(buf
, uint8_t, at
, field_size
, v
);
463 BT_LOGV("Read unsigned bit array: cur=%zu, size=%u, "
464 "bo=%d, val=%" PRIu64
, at
, field_size
, bo
, *v
);
468 void read_signed_bitfield(const uint8_t *buf
, size_t at
,
469 unsigned int field_size
, enum ctf_byte_order bo
, int64_t *v
)
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_LOGV("Read signed bit array: cur=%zu, size=%u, "
483 "bo=%d, val=%" PRId64
, at
, field_size
, bo
, *v
);
486 typedef enum bt_bfcr_status (* read_basic_and_call_cb_t
)(struct bt_bfcr
*,
487 const uint8_t *, size_t);
490 enum bt_bfcr_status
validate_contiguous_bo(struct bt_bfcr
*bfcr
,
491 enum ctf_byte_order next_bo
)
493 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
495 /* Always valid when at a byte boundary */
496 if (packet_at(bfcr
) % 8 == 0) {
500 /* Always valid if last byte order is unknown */
501 if (bfcr
->last_bo
== -1) {
505 /* Always valid if next byte order is unknown */
510 /* Make sure last byte order is compatible with the next byte order */
511 switch (bfcr
->last_bo
) {
512 case CTF_BYTE_ORDER_BIG
:
513 if (next_bo
!= CTF_BYTE_ORDER_BIG
) {
514 status
= BT_BFCR_STATUS_ERROR
;
517 case CTF_BYTE_ORDER_LITTLE
:
518 if (next_bo
!= CTF_BYTE_ORDER_LITTLE
) {
519 status
= BT_BFCR_STATUS_ERROR
;
523 status
= BT_BFCR_STATUS_ERROR
;
528 BT_LOGW("Cannot read bit array: two different byte orders not at a byte boundary: "
529 "bfcr-addr=%p, last-bo=%d, next-bo=%d",
530 bfcr
, bfcr
->last_bo
, next_bo
);
537 enum bt_bfcr_status
read_basic_float_and_call_cb(struct bt_bfcr
*bfcr
,
538 const uint8_t *buf
, size_t at
)
541 unsigned int field_size
;
542 enum ctf_byte_order bo
;
543 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
544 struct ctf_field_class_float
*fc
= (void *) bfcr
->cur_basic_field_class
;
547 field_size
= fc
->base
.size
;
548 bo
= fc
->base
.byte_order
;
551 switch (field_size
) {
560 read_unsigned_bitfield(buf
, at
, field_size
, bo
, &v
);
561 f32
.u
= (uint32_t) v
;
562 dblval
= (double) f32
.f
;
572 read_unsigned_bitfield(buf
, at
, field_size
, bo
, &f64
.u
);
577 /* Only 32-bit and 64-bit fields are supported currently */
581 BT_LOGV("Read floating point number value: bfcr=%p, cur=%zu, val=%f",
584 if (bfcr
->user
.cbs
.classes
.floating_point
) {
585 BT_LOGV("Calling user function (floating point number).");
586 status
= bfcr
->user
.cbs
.classes
.floating_point(dblval
,
587 bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
588 BT_LOGV("User function returned: status=%s",
589 bt_bfcr_status_string(status
));
590 if (status
!= BT_BFCR_STATUS_OK
) {
591 BT_LOGW("User function failed: bfcr-addr=%p, status=%s",
592 bfcr
, bt_bfcr_status_string(status
));
600 enum bt_bfcr_status
read_basic_int_and_call_cb(struct bt_bfcr
*bfcr
,
601 const uint8_t *buf
, size_t at
)
603 unsigned int field_size
;
604 enum ctf_byte_order bo
;
605 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
606 struct ctf_field_class_int
*fc
= (void *) bfcr
->cur_basic_field_class
;
608 field_size
= fc
->base
.size
;
609 bo
= fc
->base
.byte_order
;
612 * Update current byte order now because we could be reading
613 * the integer value of an enumeration class, and thus we know
614 * here the actual supporting integer class's byte order.
621 read_signed_bitfield(buf
, at
, field_size
, bo
, &v
);
623 if (bfcr
->user
.cbs
.classes
.signed_int
) {
624 BT_LOGV("Calling user function (signed integer).");
625 status
= bfcr
->user
.cbs
.classes
.signed_int(v
,
626 bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
627 BT_LOGV("User function returned: status=%s",
628 bt_bfcr_status_string(status
));
629 if (status
!= BT_BFCR_STATUS_OK
) {
630 BT_LOGW("User function failed: "
631 "bfcr-addr=%p, status=%s",
632 bfcr
, bt_bfcr_status_string(status
));
638 read_unsigned_bitfield(buf
, at
, field_size
, bo
, &v
);
640 if (bfcr
->user
.cbs
.classes
.unsigned_int
) {
641 BT_LOGV("Calling user function (unsigned integer).");
642 status
= bfcr
->user
.cbs
.classes
.unsigned_int(v
,
643 bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
644 BT_LOGV("User function returned: status=%s",
645 bt_bfcr_status_string(status
));
646 if (status
!= BT_BFCR_STATUS_OK
) {
647 BT_LOGW("User function failed: "
648 "bfcr-addr=%p, status=%s",
649 bfcr
, bt_bfcr_status_string(status
));
658 enum bt_bfcr_status
read_bit_array_class_and_call_continue(struct bt_bfcr
*bfcr
,
659 read_basic_and_call_cb_t read_basic_and_call_cb
)
663 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
664 struct ctf_field_class_bit_array
*fc
=
665 (void *) bfcr
->cur_basic_field_class
;
667 if (!at_least_one_bit_left(bfcr
)) {
668 BT_LOGV("Reached end of data: bfcr-addr=%p", bfcr
);
669 status
= BT_BFCR_STATUS_EOF
;
673 available
= available_bits(bfcr
);
674 needed_bits
= fc
->size
- bfcr
->stitch
.at
;
675 BT_LOGV("Continuing basic field decoding: "
676 "bfcr-addr=%p, field-size=%u, needed-size=%" PRId64
", "
677 "available-size=%zu",
678 bfcr
, fc
->size
, needed_bits
, available
);
679 if (needed_bits
<= available
) {
680 /* We have all the bits; append to stitch, then decode */
681 stitch_append_from_buf(bfcr
, needed_bits
);
682 status
= read_basic_and_call_cb(bfcr
, bfcr
->stitch
.buf
,
683 bfcr
->stitch
.offset
);
684 if (status
!= BT_BFCR_STATUS_OK
) {
685 BT_LOGW("Cannot read basic field: "
686 "bfcr-addr=%p, fc-addr=%p, status=%s",
687 bfcr
, bfcr
->cur_basic_field_class
,
688 bt_bfcr_status_string(status
));
692 if (stack_empty(bfcr
->stack
)) {
693 /* Root is a basic class */
694 bfcr
->state
= BFCR_STATE_DONE
;
696 /* Go to next field */
697 stack_top(bfcr
->stack
)->index
++;
698 bfcr
->state
= BFCR_STATE_NEXT_FIELD
;
699 bfcr
->last_bo
= bfcr
->cur_bo
;
704 /* We are here; it means we don't have enough data to decode this */
705 BT_LOGV_STR("Not enough data to read the next basic field: appending to stitch buffer.");
706 stitch_append_from_remaining_buf(bfcr
);
707 status
= BT_BFCR_STATUS_EOF
;
714 enum bt_bfcr_status
read_bit_array_class_and_call_begin(struct bt_bfcr
*bfcr
,
715 read_basic_and_call_cb_t read_basic_and_call_cb
)
718 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
719 struct ctf_field_class_bit_array
*fc
=
720 (void *) bfcr
->cur_basic_field_class
;
722 if (!at_least_one_bit_left(bfcr
)) {
723 BT_LOGV("Reached end of data: bfcr-addr=%p", bfcr
);
724 status
= BT_BFCR_STATUS_EOF
;
728 status
= validate_contiguous_bo(bfcr
, fc
->byte_order
);
729 if (status
!= BT_BFCR_STATUS_OK
) {
730 /* validate_contiguous_bo() logs errors */
734 available
= available_bits(bfcr
);
736 if (fc
->size
<= available
) {
737 /* We have all the bits; decode and set now */
738 BT_ASSERT(bfcr
->buf
.addr
);
739 status
= read_basic_and_call_cb(bfcr
, bfcr
->buf
.addr
,
740 buf_at_from_addr(bfcr
));
741 if (status
!= BT_BFCR_STATUS_OK
) {
742 BT_LOGW("Cannot read basic field: "
743 "bfcr-addr=%p, fc-addr=%p, status=%s",
744 bfcr
, bfcr
->cur_basic_field_class
,
745 bt_bfcr_status_string(status
));
749 consume_bits(bfcr
, fc
->size
);
751 if (stack_empty(bfcr
->stack
)) {
752 /* Root is a basic class */
753 bfcr
->state
= BFCR_STATE_DONE
;
755 /* Go to next field */
756 stack_top(bfcr
->stack
)->index
++;
757 bfcr
->state
= BFCR_STATE_NEXT_FIELD
;
758 bfcr
->last_bo
= bfcr
->cur_bo
;
764 /* We are here; it means we don't have enough data to decode this */
765 BT_LOGV_STR("Not enough data to read the next basic field: setting stitch buffer.");
766 stitch_set_from_remaining_buf(bfcr
);
767 bfcr
->state
= BFCR_STATE_READ_BASIC_CONTINUE
;
768 status
= BT_BFCR_STATUS_EOF
;
775 enum bt_bfcr_status
read_basic_int_class_and_call_begin(
776 struct bt_bfcr
*bfcr
)
778 return read_bit_array_class_and_call_begin(bfcr
, read_basic_int_and_call_cb
);
782 enum bt_bfcr_status
read_basic_int_class_and_call_continue(
783 struct bt_bfcr
*bfcr
)
785 return read_bit_array_class_and_call_continue(bfcr
,
786 read_basic_int_and_call_cb
);
790 enum bt_bfcr_status
read_basic_float_class_and_call_begin(
791 struct bt_bfcr
*bfcr
)
793 return read_bit_array_class_and_call_begin(bfcr
,
794 read_basic_float_and_call_cb
);
798 enum bt_bfcr_status
read_basic_float_class_and_call_continue(
799 struct bt_bfcr
*bfcr
)
801 return read_bit_array_class_and_call_continue(bfcr
,
802 read_basic_float_and_call_cb
);
806 enum bt_bfcr_status
read_basic_string_class_and_call(
807 struct bt_bfcr
*bfcr
, bool begin
)
810 const uint8_t *result
;
811 size_t available_bytes
;
812 const uint8_t *first_chr
;
813 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
815 if (!at_least_one_bit_left(bfcr
)) {
816 BT_LOGV("Reached end of data: bfcr-addr=%p", bfcr
);
817 status
= BT_BFCR_STATUS_EOF
;
821 BT_ASSERT(buf_at_from_addr(bfcr
) % 8 == 0);
822 available_bytes
= BITS_TO_BYTES_FLOOR(available_bits(bfcr
));
823 buf_at_bytes
= BITS_TO_BYTES_FLOOR(buf_at_from_addr(bfcr
));
824 BT_ASSERT(bfcr
->buf
.addr
);
825 first_chr
= &bfcr
->buf
.addr
[buf_at_bytes
];
826 result
= memchr(first_chr
, '\0', available_bytes
);
828 if (begin
&& bfcr
->user
.cbs
.classes
.string_begin
) {
829 BT_LOGV("Calling user function (string, beginning).");
830 status
= bfcr
->user
.cbs
.classes
.string_begin(
831 bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
832 BT_LOGV("User function returned: status=%s",
833 bt_bfcr_status_string(status
));
834 if (status
!= BT_BFCR_STATUS_OK
) {
835 BT_LOGW("User function failed: bfcr-addr=%p, status=%s",
836 bfcr
, bt_bfcr_status_string(status
));
842 /* No null character yet */
843 if (bfcr
->user
.cbs
.classes
.string
) {
844 BT_LOGV("Calling user function (substring).");
845 status
= bfcr
->user
.cbs
.classes
.string(
846 (const char *) first_chr
,
847 available_bytes
, bfcr
->cur_basic_field_class
,
849 BT_LOGV("User function returned: status=%s",
850 bt_bfcr_status_string(status
));
851 if (status
!= BT_BFCR_STATUS_OK
) {
852 BT_LOGW("User function failed: "
853 "bfcr-addr=%p, status=%s",
854 bfcr
, bt_bfcr_status_string(status
));
859 consume_bits(bfcr
, BYTES_TO_BITS(available_bytes
));
860 bfcr
->state
= BFCR_STATE_READ_BASIC_CONTINUE
;
861 status
= BT_BFCR_STATUS_EOF
;
863 /* Found the null character */
864 size_t result_len
= (size_t) (result
- first_chr
);
866 if (bfcr
->user
.cbs
.classes
.string
&& result_len
) {
867 BT_LOGV("Calling user function (substring).");
868 status
= bfcr
->user
.cbs
.classes
.string(
869 (const char *) first_chr
,
870 result_len
, bfcr
->cur_basic_field_class
,
872 BT_LOGV("User function returned: status=%s",
873 bt_bfcr_status_string(status
));
874 if (status
!= BT_BFCR_STATUS_OK
) {
875 BT_LOGW("User function failed: "
876 "bfcr-addr=%p, status=%s",
877 bfcr
, bt_bfcr_status_string(status
));
882 if (bfcr
->user
.cbs
.classes
.string_end
) {
883 BT_LOGV("Calling user function (string, end).");
884 status
= bfcr
->user
.cbs
.classes
.string_end(
885 bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
886 BT_LOGV("User function returned: status=%s",
887 bt_bfcr_status_string(status
));
888 if (status
!= BT_BFCR_STATUS_OK
) {
889 BT_LOGW("User function failed: "
890 "bfcr-addr=%p, status=%s",
891 bfcr
, bt_bfcr_status_string(status
));
896 consume_bits(bfcr
, BYTES_TO_BITS(result_len
+ 1));
898 if (stack_empty(bfcr
->stack
)) {
899 /* Root is a basic class */
900 bfcr
->state
= BFCR_STATE_DONE
;
902 /* Go to next field */
903 stack_top(bfcr
->stack
)->index
++;
904 bfcr
->state
= BFCR_STATE_NEXT_FIELD
;
905 bfcr
->last_bo
= bfcr
->cur_bo
;
914 enum bt_bfcr_status
read_basic_begin_state(struct bt_bfcr
*bfcr
)
916 enum bt_bfcr_status status
;
918 BT_ASSERT(bfcr
->cur_basic_field_class
);
920 switch (bfcr
->cur_basic_field_class
->id
) {
921 case CTF_FIELD_CLASS_ID_INT
:
922 case CTF_FIELD_CLASS_ID_ENUM
:
923 status
= read_basic_int_class_and_call_begin(bfcr
);
925 case CTF_FIELD_CLASS_ID_FLOAT
:
926 status
= read_basic_float_class_and_call_begin(bfcr
);
928 case CTF_FIELD_CLASS_ID_STRING
:
929 status
= read_basic_string_class_and_call(bfcr
, true);
939 enum bt_bfcr_status
read_basic_continue_state(struct bt_bfcr
*bfcr
)
941 enum bt_bfcr_status status
;
943 BT_ASSERT(bfcr
->cur_basic_field_class
);
945 switch (bfcr
->cur_basic_field_class
->id
) {
946 case CTF_FIELD_CLASS_ID_INT
:
947 case CTF_FIELD_CLASS_ID_ENUM
:
948 status
= read_basic_int_class_and_call_continue(bfcr
);
950 case CTF_FIELD_CLASS_ID_FLOAT
:
951 status
= read_basic_float_class_and_call_continue(bfcr
);
953 case CTF_FIELD_CLASS_ID_STRING
:
954 status
= read_basic_string_class_and_call(bfcr
, false);
964 size_t bits_to_skip_to_align_to(struct bt_bfcr
*bfcr
, size_t align
)
966 size_t aligned_packet_at
;
968 aligned_packet_at
= ALIGN(packet_at(bfcr
), align
);
969 return aligned_packet_at
- packet_at(bfcr
);
973 enum bt_bfcr_status
align_class_state(struct bt_bfcr
*bfcr
,
974 struct ctf_field_class
*field_class
, enum bfcr_state next_state
)
976 unsigned int field_alignment
;
978 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
980 /* Get field's alignment */
981 field_alignment
= field_class
->alignment
;
984 * 0 means "undefined" for variants; what we really want is 1
987 BT_ASSERT(field_alignment
>= 1);
989 /* Compute how many bits we need to skip */
990 skip_bits
= bits_to_skip_to_align_to(bfcr
, (size_t) field_alignment
);
992 /* Nothing to skip? aligned */
993 if (skip_bits
== 0) {
994 bfcr
->state
= next_state
;
998 /* Make sure there's at least one bit left */
999 if (!at_least_one_bit_left(bfcr
)) {
1000 status
= BT_BFCR_STATUS_EOF
;
1004 /* Consume as many bits as possible in what's left */
1005 consume_bits(bfcr
, MIN(available_bits(bfcr
), skip_bits
));
1007 /* Are we done now? */
1008 skip_bits
= bits_to_skip_to_align_to(bfcr
, field_alignment
);
1009 if (skip_bits
== 0) {
1010 /* Yes: go to next state */
1011 bfcr
->state
= next_state
;
1014 /* No: need more data */
1015 BT_LOGV("Reached end of data when aligning: bfcr-addr=%p", bfcr
);
1016 status
= BT_BFCR_STATUS_EOF
;
1024 enum bt_bfcr_status
next_field_state(struct bt_bfcr
*bfcr
)
1027 struct stack_entry
*top
;
1028 struct ctf_field_class
*next_field_class
= NULL
;
1029 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
1031 if (stack_empty(bfcr
->stack
)) {
1035 top
= stack_top(bfcr
->stack
);
1037 /* Are we done with this base class? */
1038 while (top
->index
== top
->base_len
) {
1039 if (bfcr
->user
.cbs
.classes
.compound_end
) {
1040 BT_LOGV("Calling user function (compound, end).");
1041 status
= bfcr
->user
.cbs
.classes
.compound_end(
1042 top
->base_class
, bfcr
->user
.data
);
1043 BT_LOGV("User function returned: status=%s",
1044 bt_bfcr_status_string(status
));
1045 if (status
!= BT_BFCR_STATUS_OK
) {
1046 BT_LOGW("User function failed: bfcr-addr=%p, status=%s",
1047 bfcr
, bt_bfcr_status_string(status
));
1052 stack_pop(bfcr
->stack
);
1054 /* Are we done with the root class? */
1055 if (stack_empty(bfcr
->stack
)) {
1056 bfcr
->state
= BFCR_STATE_DONE
;
1060 top
= stack_top(bfcr
->stack
);
1064 /* Get next field's class */
1065 switch (top
->base_class
->id
) {
1066 case CTF_FIELD_CLASS_ID_STRUCT
:
1067 next_field_class
= ctf_field_class_struct_borrow_member_by_index(
1068 (void *) top
->base_class
, (uint64_t) top
->index
)->fc
;
1070 case CTF_FIELD_CLASS_ID_ARRAY
:
1071 case CTF_FIELD_CLASS_ID_SEQUENCE
:
1073 struct ctf_field_class_array_base
*array_fc
=
1074 (void *) top
->base_class
;
1076 next_field_class
= array_fc
->elem_fc
;
1079 case CTF_FIELD_CLASS_ID_VARIANT
:
1080 /* Variant classes are dynamic: the user should know! */
1082 bfcr
->user
.cbs
.query
.borrow_variant_selected_field_class(
1083 top
->base_class
, bfcr
->user
.data
);
1089 if (!next_field_class
) {
1090 BT_LOGW("Cannot get the field class of the next field: "
1091 "bfcr-addr=%p, base-fc-addr=%p, base-fc-id=%d, "
1093 bfcr
, top
->base_class
, top
->base_class
->id
, top
->index
);
1094 status
= BT_BFCR_STATUS_ERROR
;
1098 if (next_field_class
->is_compound
) {
1099 if (bfcr
->user
.cbs
.classes
.compound_begin
) {
1100 BT_LOGV("Calling user function (compound, begin).");
1101 status
= bfcr
->user
.cbs
.classes
.compound_begin(
1102 next_field_class
, bfcr
->user
.data
);
1103 BT_LOGV("User function returned: status=%s",
1104 bt_bfcr_status_string(status
));
1105 if (status
!= BT_BFCR_STATUS_OK
) {
1106 BT_LOGW("User function failed: bfcr-addr=%p, status=%s",
1107 bfcr
, bt_bfcr_status_string(status
));
1112 ret
= stack_push_with_len(bfcr
, next_field_class
);
1114 /* stack_push_with_len() logs errors */
1115 status
= BT_BFCR_STATUS_ERROR
;
1119 /* Next state: align a compound class */
1120 bfcr
->state
= BFCR_STATE_ALIGN_COMPOUND
;
1122 /* Replace current basic field class */
1123 BT_LOGV("Replacing current basic field class: "
1124 "bfcr-addr=%p, cur-basic-fc-addr=%p, "
1125 "next-basic-fc-addr=%p",
1126 bfcr
, bfcr
->cur_basic_field_class
, next_field_class
);
1127 bfcr
->cur_basic_field_class
= next_field_class
;
1129 /* Next state: align a basic class */
1130 bfcr
->state
= BFCR_STATE_ALIGN_BASIC
;
1138 enum bt_bfcr_status
handle_state(struct bt_bfcr
*bfcr
)
1140 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
1142 BT_LOGV("Handling state: bfcr-addr=%p, state=%s",
1143 bfcr
, bfcr_state_string(bfcr
->state
));
1145 switch (bfcr
->state
) {
1146 case BFCR_STATE_NEXT_FIELD
:
1147 status
= next_field_state(bfcr
);
1149 case BFCR_STATE_ALIGN_BASIC
:
1150 status
= align_class_state(bfcr
, bfcr
->cur_basic_field_class
,
1151 BFCR_STATE_READ_BASIC_BEGIN
);
1153 case BFCR_STATE_ALIGN_COMPOUND
:
1154 status
= align_class_state(bfcr
, stack_top(bfcr
->stack
)->base_class
,
1155 BFCR_STATE_NEXT_FIELD
);
1157 case BFCR_STATE_READ_BASIC_BEGIN
:
1158 status
= read_basic_begin_state(bfcr
);
1160 case BFCR_STATE_READ_BASIC_CONTINUE
:
1161 status
= read_basic_continue_state(bfcr
);
1163 case BFCR_STATE_DONE
:
1167 BT_LOGV("Handled state: bfcr-addr=%p, status=%s",
1168 bfcr
, bt_bfcr_status_string(status
));
1173 struct bt_bfcr
*bt_bfcr_create(struct bt_bfcr_cbs cbs
, void *data
)
1175 struct bt_bfcr
*bfcr
;
1177 BT_LOGD_STR("Creating binary class reader (BFCR).");
1178 bfcr
= g_new0(struct bt_bfcr
, 1);
1180 BT_LOGE_STR("Failed to allocate one binary class reader.");
1184 bfcr
->stack
= stack_new();
1186 BT_LOGE_STR("Cannot create BFCR's stack.");
1187 bt_bfcr_destroy(bfcr
);
1192 bfcr
->state
= BFCR_STATE_NEXT_FIELD
;
1193 bfcr
->user
.cbs
= cbs
;
1194 bfcr
->user
.data
= data
;
1195 BT_LOGD("Created BFCR: addr=%p", bfcr
);
1202 void bt_bfcr_destroy(struct bt_bfcr
*bfcr
)
1205 stack_destroy(bfcr
->stack
);
1208 BT_LOGD("Destroying BFCR: addr=%p", bfcr
);
1213 void reset(struct bt_bfcr
*bfcr
)
1215 BT_LOGD("Resetting BFCR: addr=%p", bfcr
);
1216 stack_clear(bfcr
->stack
);
1218 bfcr
->buf
.addr
= NULL
;
1223 void update_packet_offset(struct bt_bfcr
*bfcr
)
1225 BT_LOGV("Updating packet offset for next call: "
1226 "bfcr-addr=%p, cur-packet-offset=%zu, next-packet-offset=%zu",
1227 bfcr
, bfcr
->buf
.packet_offset
,
1228 bfcr
->buf
.packet_offset
+ bfcr
->buf
.at
);
1229 bfcr
->buf
.packet_offset
+= bfcr
->buf
.at
;
1233 size_t bt_bfcr_start(struct bt_bfcr
*bfcr
,
1234 struct ctf_field_class
*cls
, const uint8_t *buf
,
1235 size_t offset
, size_t packet_offset
, size_t sz
,
1236 enum bt_bfcr_status
*status
)
1239 BT_ASSERT(BYTES_TO_BITS(sz
) >= offset
);
1241 bfcr
->buf
.addr
= buf
;
1242 bfcr
->buf
.offset
= offset
;
1244 bfcr
->buf
.packet_offset
= packet_offset
;
1245 bfcr
->buf
.buf_sz
= sz
;
1246 bfcr
->buf
.sz
= BYTES_TO_BITS(sz
) - offset
;
1247 *status
= BT_BFCR_STATUS_OK
;
1249 BT_LOGV("Starting decoding: bfcr-addr=%p, fc-addr=%p, "
1250 "buf-addr=%p, buf-size=%zu, offset=%zu, "
1251 "packet-offset=%zu",
1252 bfcr
, cls
, buf
, sz
, offset
, packet_offset
);
1254 /* Set root class */
1255 if (cls
->is_compound
) {
1256 /* Compound class: push on visit stack */
1259 if (bfcr
->user
.cbs
.classes
.compound_begin
) {
1260 BT_LOGV("Calling user function (compound, begin).");
1261 *status
= bfcr
->user
.cbs
.classes
.compound_begin(
1262 cls
, bfcr
->user
.data
);
1263 BT_LOGV("User function returned: status=%s",
1264 bt_bfcr_status_string(*status
));
1265 if (*status
!= BT_BFCR_STATUS_OK
) {
1266 BT_LOGW("User function failed: bfcr-addr=%p, status=%s",
1267 bfcr
, bt_bfcr_status_string(*status
));
1272 stack_ret
= stack_push_with_len(bfcr
, cls
);
1274 /* stack_push_with_len() logs errors */
1275 *status
= BT_BFCR_STATUS_ERROR
;
1279 bfcr
->state
= BFCR_STATE_ALIGN_COMPOUND
;
1281 /* Basic class: set as current basic class */
1282 bfcr
->cur_basic_field_class
= cls
;
1283 bfcr
->state
= BFCR_STATE_ALIGN_BASIC
;
1286 /* Run the machine! */
1287 BT_LOGV_STR("Running the state machine.");
1290 *status
= handle_state(bfcr
);
1291 if (*status
!= BT_BFCR_STATUS_OK
||
1292 bfcr
->state
== BFCR_STATE_DONE
) {
1297 /* Update packet offset for next time */
1298 update_packet_offset(bfcr
);
1301 return bfcr
->buf
.at
;
1305 size_t bt_bfcr_continue(struct bt_bfcr
*bfcr
, const uint8_t *buf
, size_t sz
,
1306 enum bt_bfcr_status
*status
)
1311 bfcr
->buf
.addr
= buf
;
1312 bfcr
->buf
.offset
= 0;
1314 bfcr
->buf
.buf_sz
= sz
;
1315 bfcr
->buf
.sz
= BYTES_TO_BITS(sz
);
1316 *status
= BT_BFCR_STATUS_OK
;
1318 BT_LOGV("Continuing decoding: bfcr-addr=%p, buf-addr=%p, buf-size=%zu",
1321 /* Continue running the machine */
1322 BT_LOGV_STR("Running the state machine.");
1325 *status
= handle_state(bfcr
);
1326 if (*status
!= BT_BFCR_STATUS_OK
||
1327 bfcr
->state
== BFCR_STATE_DONE
) {
1332 /* Update packet offset for next time */
1333 update_packet_offset(bfcr
);
1334 return bfcr
->buf
.at
;
1338 void bt_bfcr_set_unsigned_int_cb(struct bt_bfcr
*bfcr
,
1339 bt_bfcr_unsigned_int_cb_func cb
)
1343 bfcr
->user
.cbs
.classes
.unsigned_int
= cb
;