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 "common/assert.h"
37 #include "compat/bitfield.h"
38 #include "common/common.h"
39 #include <babeltrace2/babeltrace.h>
40 #include "common/align.h"
44 #include "../metadata/ctf-meta.h"
46 #define DIV8(_x) ((_x) >> 3)
47 #define BYTES_TO_BITS(_x) ((_x) * 8)
48 #define BITS_TO_BYTES_FLOOR(_x) DIV8(_x)
49 #define BITS_TO_BYTES_CEIL(_x) DIV8((_x) + 7)
50 #define IN_BYTE_OFFSET(_at) ((_at) & 7)
52 /* A visit stack entry */
55 * Current class of base field, one of:
62 struct ctf_field_class
*base_class
;
64 /* Length of base field (always 1 for a variant class) */
67 /* Index of next field to read */
73 /* Entries (struct stack_entry) */
76 /* Number of active entries */
82 BFCR_STATE_NEXT_FIELD
,
83 BFCR_STATE_ALIGN_BASIC
,
84 BFCR_STATE_ALIGN_COMPOUND
,
85 BFCR_STATE_READ_BASIC_BEGIN
,
86 BFCR_STATE_READ_BASIC_CONTINUE
,
90 /* Binary class reader */
95 /* Current basic field class */
96 struct ctf_field_class
*cur_basic_field_class
;
99 enum bfcr_state state
;
102 * Last basic field class's byte order.
104 * This is used to detect errors since two contiguous basic
105 * classes for which the common boundary is not the boundary of
106 * a byte cannot have different byte orders.
108 * This is set to -1 on reset and when the last basic field class
109 * was a string class.
111 enum ctf_byte_order last_bo
;
113 /* Current byte order (copied to last_bo after a successful read) */
114 enum ctf_byte_order cur_bo
;
116 /* Stitch buffer infos */
121 /* Offset, within stitch buffer, of first bit */
124 /* Length (bits) of data in stitch buffer from offset */
128 /* User buffer infos */
133 /* Offset of data from address (bits) */
136 /* Current position from offset (bits) */
139 /* Offset of offset within whole packet (bits) */
140 size_t packet_offset
;
142 /* Data size in buffer (bits) */
145 /* Buffer size (bytes) */
151 /* Callback functions */
152 struct bt_bfcr_cbs cbs
;
160 const char *bfcr_state_string(enum bfcr_state state
)
163 case BFCR_STATE_NEXT_FIELD
:
164 return "BFCR_STATE_NEXT_FIELD";
165 case BFCR_STATE_ALIGN_BASIC
:
166 return "BFCR_STATE_ALIGN_BASIC";
167 case BFCR_STATE_ALIGN_COMPOUND
:
168 return "BFCR_STATE_ALIGN_COMPOUND";
169 case BFCR_STATE_READ_BASIC_BEGIN
:
170 return "BFCR_STATE_READ_BASIC_BEGIN";
171 case BFCR_STATE_READ_BASIC_CONTINUE
:
172 return "BFCR_STATE_READ_BASIC_CONTINUE";
173 case BFCR_STATE_DONE
:
174 return "BFCR_STATE_DONE";
181 struct stack
*stack_new(void)
183 struct stack
*stack
= NULL
;
185 stack
= g_new0(struct stack
, 1);
187 BT_LOGE_STR("Failed to allocate one stack.");
191 stack
->entries
= g_array_new(FALSE
, TRUE
, sizeof(struct stack_entry
));
192 if (!stack
->entries
) {
193 BT_LOGE_STR("Failed to allocate a GArray.");
197 BT_LOGD("Created stack: addr=%p", stack
);
206 void stack_destroy(struct stack
*stack
)
212 BT_LOGD("Destroying stack: addr=%p", stack
);
214 if (stack
->entries
) {
215 g_array_free(stack
->entries
, TRUE
);
222 int stack_push(struct stack
*stack
, struct ctf_field_class
*base_class
,
225 struct stack_entry
*entry
;
228 BT_ASSERT(base_class
);
229 BT_LOGV("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
,
233 base_len
, stack
->size
, stack
->size
+ 1);
235 if (stack
->entries
->len
== stack
->size
) {
236 g_array_set_size(stack
->entries
, stack
->size
+ 1);
239 entry
= &g_array_index(stack
->entries
, struct stack_entry
, stack
->size
);
240 entry
->base_class
= base_class
;
241 entry
->base_len
= base_len
;
248 int64_t get_compound_field_class_length(struct bt_bfcr
*bfcr
,
249 struct ctf_field_class
*fc
)
254 case CTF_FIELD_CLASS_TYPE_STRUCT
:
256 struct ctf_field_class_struct
*struct_fc
= (void *) fc
;
258 length
= (int64_t) struct_fc
->members
->len
;
261 case CTF_FIELD_CLASS_TYPE_VARIANT
:
263 /* Variant field classes always "contain" a single class */
267 case CTF_FIELD_CLASS_TYPE_ARRAY
:
269 struct ctf_field_class_array
*array_fc
= (void *) fc
;
271 length
= (int64_t) array_fc
->length
;
274 case CTF_FIELD_CLASS_TYPE_SEQUENCE
:
275 length
= bfcr
->user
.cbs
.query
.get_sequence_length(fc
,
286 int stack_push_with_len(struct bt_bfcr
*bfcr
, struct ctf_field_class
*base_class
)
289 int64_t length
= get_compound_field_class_length(bfcr
, base_class
);
292 BT_LOGW("Cannot get compound field class's field count: "
293 "bfcr-addr=%p, fc-addr=%p, fc-type=%d",
294 bfcr
, base_class
, base_class
->type
);
295 ret
= BT_BFCR_STATUS_ERROR
;
299 ret
= stack_push(bfcr
->stack
, base_class
, (size_t) length
);
306 unsigned int stack_size(struct stack
*stack
)
313 void stack_pop(struct stack
*stack
)
316 BT_ASSERT(stack_size(stack
));
317 BT_LOGV("Popping from stack: "
318 "stack-addr=%p, stack-size-before=%u, stack-size-after=%u",
319 stack
, stack
->entries
->len
, stack
->entries
->len
- 1);
324 bool stack_empty(struct stack
*stack
)
326 return stack_size(stack
) == 0;
330 void stack_clear(struct stack
*stack
)
337 struct stack_entry
*stack_top(struct stack
*stack
)
340 BT_ASSERT(stack_size(stack
));
341 return &g_array_index(stack
->entries
, struct stack_entry
,
346 size_t available_bits(struct bt_bfcr
*bfcr
)
348 return bfcr
->buf
.sz
- bfcr
->buf
.at
;
352 void consume_bits(struct bt_bfcr
*bfcr
, size_t incr
)
354 BT_LOGV("Advancing cursor: bfcr-addr=%p, cur-before=%zu, cur-after=%zu",
355 bfcr
, bfcr
->buf
.at
, bfcr
->buf
.at
+ incr
);
356 bfcr
->buf
.at
+= incr
;
360 bool has_enough_bits(struct bt_bfcr
*bfcr
, size_t sz
)
362 return available_bits(bfcr
) >= sz
;
366 bool at_least_one_bit_left(struct bt_bfcr
*bfcr
)
368 return has_enough_bits(bfcr
, 1);
372 size_t packet_at(struct bt_bfcr
*bfcr
)
374 return bfcr
->buf
.packet_offset
+ bfcr
->buf
.at
;
378 size_t buf_at_from_addr(struct bt_bfcr
*bfcr
)
383 * ====== offset ===== (17)
385 * xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
387 * addr (0) ==== at ==== (12)
391 * =============================== (29)
393 return bfcr
->buf
.offset
+ bfcr
->buf
.at
;
397 void stitch_reset(struct bt_bfcr
*bfcr
)
399 bfcr
->stitch
.offset
= 0;
404 size_t stitch_at_from_addr(struct bt_bfcr
*bfcr
)
406 return bfcr
->stitch
.offset
+ bfcr
->stitch
.at
;
410 void stitch_append_from_buf(struct bt_bfcr
*bfcr
, size_t sz
)
412 size_t stitch_byte_at
;
421 BITS_TO_BYTES_FLOOR(stitch_at_from_addr(bfcr
));
422 buf_byte_at
= BITS_TO_BYTES_FLOOR(buf_at_from_addr(bfcr
));
423 nb_bytes
= BITS_TO_BYTES_CEIL(sz
);
424 BT_ASSERT(nb_bytes
> 0);
425 BT_ASSERT(bfcr
->buf
.addr
);
426 memcpy(&bfcr
->stitch
.buf
[stitch_byte_at
], &bfcr
->buf
.addr
[buf_byte_at
],
428 bfcr
->stitch
.at
+= sz
;
429 consume_bits(bfcr
, sz
);
433 void stitch_append_from_remaining_buf(struct bt_bfcr
*bfcr
)
435 stitch_append_from_buf(bfcr
, available_bits(bfcr
));
439 void stitch_set_from_remaining_buf(struct bt_bfcr
*bfcr
)
442 bfcr
->stitch
.offset
= IN_BYTE_OFFSET(buf_at_from_addr(bfcr
));
443 stitch_append_from_remaining_buf(bfcr
);
447 void read_unsigned_bitfield(const uint8_t *buf
, size_t at
,
448 unsigned int field_size
, enum ctf_byte_order bo
,
452 case CTF_BYTE_ORDER_BIG
:
453 bt_bitfield_read_be(buf
, uint8_t, at
, field_size
, v
);
455 case CTF_BYTE_ORDER_LITTLE
:
456 bt_bitfield_read_le(buf
, uint8_t, at
, field_size
, v
);
462 BT_LOGV("Read unsigned bit array: cur=%zu, size=%u, "
463 "bo=%d, val=%" PRIu64
, at
, field_size
, bo
, *v
);
467 void read_signed_bitfield(const uint8_t *buf
, size_t at
,
468 unsigned int field_size
, enum ctf_byte_order bo
, int64_t *v
)
471 case CTF_BYTE_ORDER_BIG
:
472 bt_bitfield_read_be(buf
, uint8_t, at
, field_size
, v
);
474 case CTF_BYTE_ORDER_LITTLE
:
475 bt_bitfield_read_le(buf
, uint8_t, at
, field_size
, v
);
481 BT_LOGV("Read signed bit array: cur=%zu, size=%u, "
482 "bo=%d, val=%" PRId64
, at
, field_size
, bo
, *v
);
485 typedef enum bt_bfcr_status (* read_basic_and_call_cb_t
)(struct bt_bfcr
*,
486 const uint8_t *, size_t);
489 enum bt_bfcr_status
validate_contiguous_bo(struct bt_bfcr
*bfcr
,
490 enum ctf_byte_order next_bo
)
492 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
494 /* Always valid when at a byte boundary */
495 if (packet_at(bfcr
) % 8 == 0) {
499 /* Always valid if last byte order is unknown */
500 if (bfcr
->last_bo
== -1) {
504 /* Always valid if next byte order is unknown */
509 /* Make sure last byte order is compatible with the next byte order */
510 switch (bfcr
->last_bo
) {
511 case CTF_BYTE_ORDER_BIG
:
512 if (next_bo
!= CTF_BYTE_ORDER_BIG
) {
513 status
= BT_BFCR_STATUS_ERROR
;
516 case CTF_BYTE_ORDER_LITTLE
:
517 if (next_bo
!= CTF_BYTE_ORDER_LITTLE
) {
518 status
= BT_BFCR_STATUS_ERROR
;
522 status
= BT_BFCR_STATUS_ERROR
;
527 BT_LOGW("Cannot read bit array: two different byte orders not at a byte boundary: "
528 "bfcr-addr=%p, last-bo=%d, next-bo=%d",
529 bfcr
, bfcr
->last_bo
, next_bo
);
536 enum bt_bfcr_status
read_basic_float_and_call_cb(struct bt_bfcr
*bfcr
,
537 const uint8_t *buf
, size_t at
)
540 unsigned int field_size
;
541 enum ctf_byte_order bo
;
542 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
543 struct ctf_field_class_float
*fc
= (void *) bfcr
->cur_basic_field_class
;
546 field_size
= fc
->base
.size
;
547 bo
= fc
->base
.byte_order
;
550 switch (field_size
) {
559 read_unsigned_bitfield(buf
, at
, field_size
, bo
, &v
);
560 f32
.u
= (uint32_t) v
;
561 dblval
= (double) f32
.f
;
571 read_unsigned_bitfield(buf
, at
, field_size
, bo
, &f64
.u
);
576 /* Only 32-bit and 64-bit fields are supported currently */
580 BT_LOGV("Read floating point number value: bfcr=%p, cur=%zu, val=%f",
583 if (bfcr
->user
.cbs
.classes
.floating_point
) {
584 BT_LOGV("Calling user function (floating point number).");
585 status
= bfcr
->user
.cbs
.classes
.floating_point(dblval
,
586 bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
587 BT_LOGV("User function returned: status=%s",
588 bt_bfcr_status_string(status
));
589 if (status
!= BT_BFCR_STATUS_OK
) {
590 BT_LOGW("User function failed: bfcr-addr=%p, status=%s",
591 bfcr
, bt_bfcr_status_string(status
));
599 enum bt_bfcr_status
read_basic_int_and_call_cb(struct bt_bfcr
*bfcr
,
600 const uint8_t *buf
, size_t at
)
602 unsigned int field_size
;
603 enum ctf_byte_order bo
;
604 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
605 struct ctf_field_class_int
*fc
= (void *) bfcr
->cur_basic_field_class
;
607 field_size
= fc
->base
.size
;
608 bo
= fc
->base
.byte_order
;
611 * Update current byte order now because we could be reading
612 * the integer value of an enumeration class, and thus we know
613 * here the actual supporting integer class's byte order.
620 read_signed_bitfield(buf
, at
, field_size
, bo
, &v
);
622 if (bfcr
->user
.cbs
.classes
.signed_int
) {
623 BT_LOGV("Calling user function (signed integer).");
624 status
= bfcr
->user
.cbs
.classes
.signed_int(v
,
625 bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
626 BT_LOGV("User function returned: status=%s",
627 bt_bfcr_status_string(status
));
628 if (status
!= BT_BFCR_STATUS_OK
) {
629 BT_LOGW("User function failed: "
630 "bfcr-addr=%p, status=%s",
631 bfcr
, bt_bfcr_status_string(status
));
637 read_unsigned_bitfield(buf
, at
, field_size
, bo
, &v
);
639 if (bfcr
->user
.cbs
.classes
.unsigned_int
) {
640 BT_LOGV("Calling user function (unsigned integer).");
641 status
= bfcr
->user
.cbs
.classes
.unsigned_int(v
,
642 bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
643 BT_LOGV("User function returned: status=%s",
644 bt_bfcr_status_string(status
));
645 if (status
!= BT_BFCR_STATUS_OK
) {
646 BT_LOGW("User function failed: "
647 "bfcr-addr=%p, status=%s",
648 bfcr
, bt_bfcr_status_string(status
));
657 enum bt_bfcr_status
read_bit_array_class_and_call_continue(struct bt_bfcr
*bfcr
,
658 read_basic_and_call_cb_t read_basic_and_call_cb
)
662 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
663 struct ctf_field_class_bit_array
*fc
=
664 (void *) bfcr
->cur_basic_field_class
;
666 if (!at_least_one_bit_left(bfcr
)) {
667 BT_LOGV("Reached end of data: bfcr-addr=%p", bfcr
);
668 status
= BT_BFCR_STATUS_EOF
;
672 available
= available_bits(bfcr
);
673 needed_bits
= fc
->size
- bfcr
->stitch
.at
;
674 BT_LOGV("Continuing basic field decoding: "
675 "bfcr-addr=%p, field-size=%u, needed-size=%zu, "
676 "available-size=%zu",
677 bfcr
, fc
->size
, needed_bits
, available
);
678 if (needed_bits
<= available
) {
679 /* We have all the bits; append to stitch, then decode */
680 stitch_append_from_buf(bfcr
, needed_bits
);
681 status
= read_basic_and_call_cb(bfcr
, bfcr
->stitch
.buf
,
682 bfcr
->stitch
.offset
);
683 if (status
!= BT_BFCR_STATUS_OK
) {
684 BT_LOGW("Cannot read basic field: "
685 "bfcr-addr=%p, fc-addr=%p, status=%s",
686 bfcr
, bfcr
->cur_basic_field_class
,
687 bt_bfcr_status_string(status
));
691 if (stack_empty(bfcr
->stack
)) {
692 /* Root is a basic class */
693 bfcr
->state
= BFCR_STATE_DONE
;
695 /* Go to next field */
696 stack_top(bfcr
->stack
)->index
++;
697 bfcr
->state
= BFCR_STATE_NEXT_FIELD
;
698 bfcr
->last_bo
= bfcr
->cur_bo
;
703 /* We are here; it means we don't have enough data to decode this */
704 BT_LOGV_STR("Not enough data to read the next basic field: appending to stitch buffer.");
705 stitch_append_from_remaining_buf(bfcr
);
706 status
= BT_BFCR_STATUS_EOF
;
713 enum bt_bfcr_status
read_bit_array_class_and_call_begin(struct bt_bfcr
*bfcr
,
714 read_basic_and_call_cb_t read_basic_and_call_cb
)
717 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
718 struct ctf_field_class_bit_array
*fc
=
719 (void *) bfcr
->cur_basic_field_class
;
721 if (!at_least_one_bit_left(bfcr
)) {
722 BT_LOGV("Reached end of data: bfcr-addr=%p", bfcr
);
723 status
= BT_BFCR_STATUS_EOF
;
727 status
= validate_contiguous_bo(bfcr
, fc
->byte_order
);
728 if (status
!= BT_BFCR_STATUS_OK
) {
729 /* validate_contiguous_bo() logs errors */
733 available
= available_bits(bfcr
);
735 if (fc
->size
<= available
) {
736 /* We have all the bits; decode and set now */
737 BT_ASSERT(bfcr
->buf
.addr
);
738 status
= read_basic_and_call_cb(bfcr
, bfcr
->buf
.addr
,
739 buf_at_from_addr(bfcr
));
740 if (status
!= BT_BFCR_STATUS_OK
) {
741 BT_LOGW("Cannot read basic field: "
742 "bfcr-addr=%p, fc-addr=%p, status=%s",
743 bfcr
, bfcr
->cur_basic_field_class
,
744 bt_bfcr_status_string(status
));
748 consume_bits(bfcr
, fc
->size
);
750 if (stack_empty(bfcr
->stack
)) {
751 /* Root is a basic class */
752 bfcr
->state
= BFCR_STATE_DONE
;
754 /* Go to next field */
755 stack_top(bfcr
->stack
)->index
++;
756 bfcr
->state
= BFCR_STATE_NEXT_FIELD
;
757 bfcr
->last_bo
= bfcr
->cur_bo
;
763 /* We are here; it means we don't have enough data to decode this */
764 BT_LOGV_STR("Not enough data to read the next basic field: setting stitch buffer.");
765 stitch_set_from_remaining_buf(bfcr
);
766 bfcr
->state
= BFCR_STATE_READ_BASIC_CONTINUE
;
767 status
= BT_BFCR_STATUS_EOF
;
774 enum bt_bfcr_status
read_basic_int_class_and_call_begin(
775 struct bt_bfcr
*bfcr
)
777 return read_bit_array_class_and_call_begin(bfcr
, read_basic_int_and_call_cb
);
781 enum bt_bfcr_status
read_basic_int_class_and_call_continue(
782 struct bt_bfcr
*bfcr
)
784 return read_bit_array_class_and_call_continue(bfcr
,
785 read_basic_int_and_call_cb
);
789 enum bt_bfcr_status
read_basic_float_class_and_call_begin(
790 struct bt_bfcr
*bfcr
)
792 return read_bit_array_class_and_call_begin(bfcr
,
793 read_basic_float_and_call_cb
);
797 enum bt_bfcr_status
read_basic_float_class_and_call_continue(
798 struct bt_bfcr
*bfcr
)
800 return read_bit_array_class_and_call_continue(bfcr
,
801 read_basic_float_and_call_cb
);
805 enum bt_bfcr_status
read_basic_string_class_and_call(
806 struct bt_bfcr
*bfcr
, bool begin
)
809 const uint8_t *result
;
810 size_t available_bytes
;
811 const uint8_t *first_chr
;
812 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
814 if (!at_least_one_bit_left(bfcr
)) {
815 BT_LOGV("Reached end of data: bfcr-addr=%p", bfcr
);
816 status
= BT_BFCR_STATUS_EOF
;
820 BT_ASSERT(buf_at_from_addr(bfcr
) % 8 == 0);
821 available_bytes
= BITS_TO_BYTES_FLOOR(available_bits(bfcr
));
822 buf_at_bytes
= BITS_TO_BYTES_FLOOR(buf_at_from_addr(bfcr
));
823 BT_ASSERT(bfcr
->buf
.addr
);
824 first_chr
= &bfcr
->buf
.addr
[buf_at_bytes
];
825 result
= memchr(first_chr
, '\0', available_bytes
);
827 if (begin
&& bfcr
->user
.cbs
.classes
.string_begin
) {
828 BT_LOGV("Calling user function (string, beginning).");
829 status
= bfcr
->user
.cbs
.classes
.string_begin(
830 bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
831 BT_LOGV("User function returned: status=%s",
832 bt_bfcr_status_string(status
));
833 if (status
!= BT_BFCR_STATUS_OK
) {
834 BT_LOGW("User function failed: bfcr-addr=%p, status=%s",
835 bfcr
, bt_bfcr_status_string(status
));
841 /* No null character yet */
842 if (bfcr
->user
.cbs
.classes
.string
) {
843 BT_LOGV("Calling user function (substring).");
844 status
= bfcr
->user
.cbs
.classes
.string(
845 (const char *) first_chr
,
846 available_bytes
, bfcr
->cur_basic_field_class
,
848 BT_LOGV("User function returned: status=%s",
849 bt_bfcr_status_string(status
));
850 if (status
!= BT_BFCR_STATUS_OK
) {
851 BT_LOGW("User function failed: "
852 "bfcr-addr=%p, status=%s",
853 bfcr
, bt_bfcr_status_string(status
));
858 consume_bits(bfcr
, BYTES_TO_BITS(available_bytes
));
859 bfcr
->state
= BFCR_STATE_READ_BASIC_CONTINUE
;
860 status
= BT_BFCR_STATUS_EOF
;
862 /* Found the null character */
863 size_t result_len
= (size_t) (result
- first_chr
);
865 if (bfcr
->user
.cbs
.classes
.string
&& result_len
) {
866 BT_LOGV("Calling user function (substring).");
867 status
= bfcr
->user
.cbs
.classes
.string(
868 (const char *) first_chr
,
869 result_len
, bfcr
->cur_basic_field_class
,
871 BT_LOGV("User function returned: status=%s",
872 bt_bfcr_status_string(status
));
873 if (status
!= BT_BFCR_STATUS_OK
) {
874 BT_LOGW("User function failed: "
875 "bfcr-addr=%p, status=%s",
876 bfcr
, bt_bfcr_status_string(status
));
881 if (bfcr
->user
.cbs
.classes
.string_end
) {
882 BT_LOGV("Calling user function (string, end).");
883 status
= bfcr
->user
.cbs
.classes
.string_end(
884 bfcr
->cur_basic_field_class
, bfcr
->user
.data
);
885 BT_LOGV("User function returned: status=%s",
886 bt_bfcr_status_string(status
));
887 if (status
!= BT_BFCR_STATUS_OK
) {
888 BT_LOGW("User function failed: "
889 "bfcr-addr=%p, status=%s",
890 bfcr
, bt_bfcr_status_string(status
));
895 consume_bits(bfcr
, BYTES_TO_BITS(result_len
+ 1));
897 if (stack_empty(bfcr
->stack
)) {
898 /* Root is a basic class */
899 bfcr
->state
= BFCR_STATE_DONE
;
901 /* Go to next field */
902 stack_top(bfcr
->stack
)->index
++;
903 bfcr
->state
= BFCR_STATE_NEXT_FIELD
;
904 bfcr
->last_bo
= bfcr
->cur_bo
;
913 enum bt_bfcr_status
read_basic_begin_state(struct bt_bfcr
*bfcr
)
915 enum bt_bfcr_status status
;
917 BT_ASSERT(bfcr
->cur_basic_field_class
);
919 switch (bfcr
->cur_basic_field_class
->type
) {
920 case CTF_FIELD_CLASS_TYPE_INT
:
921 case CTF_FIELD_CLASS_TYPE_ENUM
:
922 status
= read_basic_int_class_and_call_begin(bfcr
);
924 case CTF_FIELD_CLASS_TYPE_FLOAT
:
925 status
= read_basic_float_class_and_call_begin(bfcr
);
927 case CTF_FIELD_CLASS_TYPE_STRING
:
928 status
= read_basic_string_class_and_call(bfcr
, true);
938 enum bt_bfcr_status
read_basic_continue_state(struct bt_bfcr
*bfcr
)
940 enum bt_bfcr_status status
;
942 BT_ASSERT(bfcr
->cur_basic_field_class
);
944 switch (bfcr
->cur_basic_field_class
->type
) {
945 case CTF_FIELD_CLASS_TYPE_INT
:
946 case CTF_FIELD_CLASS_TYPE_ENUM
:
947 status
= read_basic_int_class_and_call_continue(bfcr
);
949 case CTF_FIELD_CLASS_TYPE_FLOAT
:
950 status
= read_basic_float_class_and_call_continue(bfcr
);
952 case CTF_FIELD_CLASS_TYPE_STRING
:
953 status
= read_basic_string_class_and_call(bfcr
, false);
963 size_t bits_to_skip_to_align_to(struct bt_bfcr
*bfcr
, size_t align
)
965 size_t aligned_packet_at
;
967 aligned_packet_at
= ALIGN(packet_at(bfcr
), align
);
968 return aligned_packet_at
- packet_at(bfcr
);
972 enum bt_bfcr_status
align_class_state(struct bt_bfcr
*bfcr
,
973 struct ctf_field_class
*field_class
, enum bfcr_state next_state
)
975 unsigned int field_alignment
;
977 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
979 /* Get field's alignment */
980 field_alignment
= field_class
->alignment
;
983 * 0 means "undefined" for variants; what we really want is 1
986 BT_ASSERT(field_alignment
>= 1);
988 /* Compute how many bits we need to skip */
989 skip_bits
= bits_to_skip_to_align_to(bfcr
, (size_t) field_alignment
);
991 /* Nothing to skip? aligned */
992 if (skip_bits
== 0) {
993 bfcr
->state
= next_state
;
997 /* Make sure there's at least one bit left */
998 if (!at_least_one_bit_left(bfcr
)) {
999 status
= BT_BFCR_STATUS_EOF
;
1003 /* Consume as many bits as possible in what's left */
1004 consume_bits(bfcr
, MIN(available_bits(bfcr
), skip_bits
));
1006 /* Are we done now? */
1007 skip_bits
= bits_to_skip_to_align_to(bfcr
, field_alignment
);
1008 if (skip_bits
== 0) {
1009 /* Yes: go to next state */
1010 bfcr
->state
= next_state
;
1013 /* No: need more data */
1014 BT_LOGV("Reached end of data when aligning: bfcr-addr=%p", bfcr
);
1015 status
= BT_BFCR_STATUS_EOF
;
1023 enum bt_bfcr_status
next_field_state(struct bt_bfcr
*bfcr
)
1026 struct stack_entry
*top
;
1027 struct ctf_field_class
*next_field_class
= NULL
;
1028 enum bt_bfcr_status status
= BT_BFCR_STATUS_OK
;
1030 if (stack_empty(bfcr
->stack
)) {
1034 top
= stack_top(bfcr
->stack
);
1036 /* Are we done with this base class? */
1037 while (top
->index
== top
->base_len
) {
1038 if (bfcr
->user
.cbs
.classes
.compound_end
) {
1039 BT_LOGV("Calling user function (compound, end).");
1040 status
= bfcr
->user
.cbs
.classes
.compound_end(
1041 top
->base_class
, bfcr
->user
.data
);
1042 BT_LOGV("User function returned: status=%s",
1043 bt_bfcr_status_string(status
));
1044 if (status
!= BT_BFCR_STATUS_OK
) {
1045 BT_LOGW("User function failed: bfcr-addr=%p, status=%s",
1046 bfcr
, bt_bfcr_status_string(status
));
1051 stack_pop(bfcr
->stack
);
1053 /* Are we done with the root class? */
1054 if (stack_empty(bfcr
->stack
)) {
1055 bfcr
->state
= BFCR_STATE_DONE
;
1059 top
= stack_top(bfcr
->stack
);
1063 /* Get next field's class */
1064 switch (top
->base_class
->type
) {
1065 case CTF_FIELD_CLASS_TYPE_STRUCT
:
1066 next_field_class
= ctf_field_class_struct_borrow_member_by_index(
1067 (void *) top
->base_class
, (uint64_t) top
->index
)->fc
;
1069 case CTF_FIELD_CLASS_TYPE_ARRAY
:
1070 case CTF_FIELD_CLASS_TYPE_SEQUENCE
:
1072 struct ctf_field_class_array_base
*array_fc
=
1073 (void *) top
->base_class
;
1075 next_field_class
= array_fc
->elem_fc
;
1078 case CTF_FIELD_CLASS_TYPE_VARIANT
:
1079 /* Variant classes are dynamic: the user should know! */
1081 bfcr
->user
.cbs
.query
.borrow_variant_selected_field_class(
1082 top
->base_class
, bfcr
->user
.data
);
1088 if (!next_field_class
) {
1089 BT_LOGW("Cannot get the field class of the next field: "
1090 "bfcr-addr=%p, base-fc-addr=%p, base-fc-type=%d, "
1092 bfcr
, top
->base_class
, top
->base_class
->type
,
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 field 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
;