Rename: bt_put(), bt_get() -> bt_object_put_ref(), bt_object_get_ref()
[babeltrace.git] / plugins / ctf / common / bfcr / bfcr.c
CommitLineData
939190b3
PP
1/*
2 * Babeltrace - CTF binary field class reader (BFCR)
3 *
4 * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation
5 * Copyright (c) 2015-2016 Philippe Proulx <pproulx@efficios.com>
6 *
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:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
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
23 * SOFTWARE.
24 */
25
26#define BT_LOG_TAG "PLUGIN-CTF-BFCR"
27#include "logging.h"
28
29#include <stdlib.h>
30#include <stdint.h>
31#include <inttypes.h>
32#include <stdio.h>
33#include <stddef.h>
34#include <stdbool.h>
35#include <babeltrace/assert-internal.h>
36#include <string.h>
37#include <babeltrace/bitfield-internal.h>
38#include <babeltrace/common-internal.h>
39#include <babeltrace/babeltrace.h>
8138bfe1 40#include <babeltrace/object.h>
939190b3
PP
41#include <babeltrace/align-internal.h>
42#include <glib.h>
43
44#include "bfcr.h"
45#include "../metadata/ctf-meta.h"
46
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)
52
53/* A visit stack entry */
54struct stack_entry {
55 /*
56 * Current class of base field, one of:
57 *
58 * * Structure
59 * * Array
60 * * Sequence
61 * * Variant
62 */
63 struct ctf_field_class *base_class;
64
65 /* Length of base field (always 1 for a variant class) */
66 int64_t base_len;
67
68 /* Index of next field to read */
69 int64_t index;
70};
71
72/* Visit stack */
73struct stack {
74 /* Entries (struct stack_entry) */
75 GArray *entries;
76
77 /* Number of active entries */
78 size_t size;
79};
80
81/* Reading states */
82enum bfcr_state {
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,
88 BFCR_STATE_DONE,
89};
90
91/* Binary class reader */
92struct bt_bfcr {
93 /* Bisit stack */
94 struct stack *stack;
95
96 /* Current basic field class */
97 struct ctf_field_class *cur_basic_field_class;
98
99 /* Current state */
100 enum bfcr_state state;
101
102 /*
103 * Last basic field class's byte order.
104 *
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.
108 *
109 * This is set to -1 on reset and when the last basic field class
110 * was a string class.
111 */
112 enum ctf_byte_order last_bo;
113
114 /* Current byte order (copied to last_bo after a successful read) */
115 enum ctf_byte_order cur_bo;
116
117 /* Stitch buffer infos */
118 struct {
119 /* Stitch buffer */
120 uint8_t buf[16];
121
122 /* Offset, within stitch buffer, of first bit */
123 size_t offset;
124
125 /* Length (bits) of data in stitch buffer from offset */
126 size_t at;
127 } stitch;
128
129 /* User buffer infos */
130 struct {
131 /* Address */
132 const uint8_t *addr;
133
134 /* Offset of data from address (bits) */
135 size_t offset;
136
137 /* Current position from offset (bits) */
138 size_t at;
139
140 /* Offset of offset within whole packet (bits) */
141 size_t packet_offset;
142
143 /* Data size in buffer (bits) */
144 size_t sz;
145
146 /* Buffer size (bytes) */
147 size_t buf_sz;
148 } buf;
149
150 /* User stuff */
151 struct {
152 /* Callback functions */
153 struct bt_bfcr_cbs cbs;
154
155 /* Private data */
156 void *data;
157 } user;
158};
159
160static inline
161const char *bfcr_state_string(enum bfcr_state state)
162{
163 switch (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";
176 default:
177 return "(unknown)";
178 }
179}
180
181static
182struct stack *stack_new(void)
183{
184 struct stack *stack = NULL;
185
186 stack = g_new0(struct stack, 1);
187 if (!stack) {
188 BT_LOGE_STR("Failed to allocate one stack.");
189 goto error;
190 }
191
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.");
195 goto error;
196 }
197
198 BT_LOGD("Created stack: addr=%p", stack);
199 return stack;
200
201error:
202 g_free(stack);
203 return NULL;
204}
205
206static
207void stack_destroy(struct stack *stack)
208{
209 if (!stack) {
210 return;
211 }
212
213 BT_LOGD("Destroying stack: addr=%p", stack);
214
215 if (stack->entries) {
216 g_array_free(stack->entries, TRUE);
217 }
218
219 g_free(stack);
220}
221
222static
223int stack_push(struct stack *stack, struct ctf_field_class *base_class,
224 size_t base_len)
225{
226 struct stack_entry *entry;
227
228 BT_ASSERT(stack);
229 BT_ASSERT(base_class);
230 BT_LOGV("Pushing field class on stack: stack-addr=%p, "
af0c18e3 231 "fc-addr=%p, fc-type=%d, base-length=%zu, "
939190b3 232 "stack-size-before=%zu, stack-size-after=%zu",
af0c18e3 233 stack, base_class, base_class->type,
939190b3
PP
234 base_len, stack->size, stack->size + 1);
235
236 if (stack->entries->len == stack->size) {
237 g_array_set_size(stack->entries, stack->size + 1);
238 }
239
240 entry = &g_array_index(stack->entries, struct stack_entry, stack->size);
241 entry->base_class = base_class;
242 entry->base_len = base_len;
243 entry->index = 0;
244 stack->size++;
245 return 0;
246}
247
248static inline
249int64_t get_compound_field_class_length(struct bt_bfcr *bfcr,
250 struct ctf_field_class *fc)
251{
252 int64_t length;
253
af0c18e3
PP
254 switch (fc->type) {
255 case CTF_FIELD_CLASS_TYPE_STRUCT:
939190b3
PP
256 {
257 struct ctf_field_class_struct *struct_fc = (void *) fc;
258
259 length = (int64_t) struct_fc->members->len;
260 break;
261 }
af0c18e3 262 case CTF_FIELD_CLASS_TYPE_VARIANT:
939190b3
PP
263 {
264 /* Variant field classes always "contain" a single class */
265 length = 1;
266 break;
267 }
af0c18e3 268 case CTF_FIELD_CLASS_TYPE_ARRAY:
939190b3
PP
269 {
270 struct ctf_field_class_array *array_fc = (void *) fc;
271
272 length = (int64_t) array_fc->length;
273 break;
274 }
af0c18e3 275 case CTF_FIELD_CLASS_TYPE_SEQUENCE:
939190b3
PP
276 length = bfcr->user.cbs.query.get_sequence_length(fc,
277 bfcr->user.data);
278 break;
279 default:
280 abort();
281 }
282
283 return length;
284}
285
286static
287int stack_push_with_len(struct bt_bfcr *bfcr, struct ctf_field_class *base_class)
288{
289 int ret;
290 int64_t length = get_compound_field_class_length(bfcr, base_class);
291
292 if (length < 0) {
293 BT_LOGW("Cannot get compound field class's field count: "
af0c18e3
PP
294 "bfcr-addr=%p, fc-addr=%p, fc-type=%d",
295 bfcr, base_class, base_class->type);
939190b3
PP
296 ret = BT_BFCR_STATUS_ERROR;
297 goto end;
298 }
299
300 ret = stack_push(bfcr->stack, base_class, (size_t) length);
301
302end:
303 return ret;
304}
305
306static inline
307unsigned int stack_size(struct stack *stack)
308{
309 BT_ASSERT(stack);
310 return stack->size;
311}
312
313static
314void stack_pop(struct stack *stack)
315{
316 BT_ASSERT(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);
321 stack->size--;
322}
323
324static inline
325bool stack_empty(struct stack *stack)
326{
327 return stack_size(stack) == 0;
328}
329
330static
331void stack_clear(struct stack *stack)
332{
333 BT_ASSERT(stack);
334 stack->size = 0;
335}
336
337static inline
338struct stack_entry *stack_top(struct stack *stack)
339{
340 BT_ASSERT(stack);
341 BT_ASSERT(stack_size(stack));
342 return &g_array_index(stack->entries, struct stack_entry,
343 stack->size - 1);
344}
345
346static inline
347size_t available_bits(struct bt_bfcr *bfcr)
348{
349 return bfcr->buf.sz - bfcr->buf.at;
350}
351
352static inline
353void consume_bits(struct bt_bfcr *bfcr, size_t incr)
354{
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;
358}
359
360static inline
361bool has_enough_bits(struct bt_bfcr *bfcr, size_t sz)
362{
363 return available_bits(bfcr) >= sz;
364}
365
366static inline
367bool at_least_one_bit_left(struct bt_bfcr *bfcr)
368{
369 return has_enough_bits(bfcr, 1);
370}
371
372static inline
373size_t packet_at(struct bt_bfcr *bfcr)
374{
375 return bfcr->buf.packet_offset + bfcr->buf.at;
376}
377
378static inline
379size_t buf_at_from_addr(struct bt_bfcr *bfcr)
380{
381 /*
382 * Considering this:
383 *
384 * ====== offset ===== (17)
385 *
386 * xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
387 * ^
388 * addr (0) ==== at ==== (12)
389 *
390 * We want this:
391 *
392 * =============================== (29)
393 */
394 return bfcr->buf.offset + bfcr->buf.at;
395}
396
397static
398void stitch_reset(struct bt_bfcr *bfcr)
399{
400 bfcr->stitch.offset = 0;
401 bfcr->stitch.at = 0;
402}
403
404static inline
405size_t stitch_at_from_addr(struct bt_bfcr *bfcr)
406{
407 return bfcr->stitch.offset + bfcr->stitch.at;
408}
409
410static
411void stitch_append_from_buf(struct bt_bfcr *bfcr, size_t sz)
412{
413 size_t stitch_byte_at;
414 size_t buf_byte_at;
415 size_t nb_bytes;
416
417 if (sz == 0) {
418 return;
419 }
420
421 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],
428 nb_bytes);
429 bfcr->stitch.at += sz;
430 consume_bits(bfcr, sz);
431}
432
433static
434void stitch_append_from_remaining_buf(struct bt_bfcr *bfcr)
435{
436 stitch_append_from_buf(bfcr, available_bits(bfcr));
437}
438
439static
440void stitch_set_from_remaining_buf(struct bt_bfcr *bfcr)
441{
442 stitch_reset(bfcr);
443 bfcr->stitch.offset = IN_BYTE_OFFSET(buf_at_from_addr(bfcr));
444 stitch_append_from_remaining_buf(bfcr);
445}
446
447static inline
448void read_unsigned_bitfield(const uint8_t *buf, size_t at,
449 unsigned int field_size, enum ctf_byte_order bo,
450 uint64_t *v)
451{
452 switch (bo) {
453 case CTF_BYTE_ORDER_BIG:
454 bt_bitfield_read_be(buf, uint8_t, at, field_size, v);
455 break;
456 case CTF_BYTE_ORDER_LITTLE:
457 bt_bitfield_read_le(buf, uint8_t, at, field_size, v);
458 break;
459 default:
460 abort();
461 }
462
463 BT_LOGV("Read unsigned bit array: cur=%zu, size=%u, "
464 "bo=%d, val=%" PRIu64, at, field_size, bo, *v);
465}
466
467static inline
468void read_signed_bitfield(const uint8_t *buf, size_t at,
469 unsigned int field_size, enum ctf_byte_order bo, int64_t *v)
470{
471 switch (bo) {
472 case CTF_BYTE_ORDER_BIG:
473 bt_bitfield_read_be(buf, uint8_t, at, field_size, v);
474 break;
475 case CTF_BYTE_ORDER_LITTLE:
476 bt_bitfield_read_le(buf, uint8_t, at, field_size, v);
477 break;
478 default:
479 abort();
480 }
481
482 BT_LOGV("Read signed bit array: cur=%zu, size=%u, "
483 "bo=%d, val=%" PRId64, at, field_size, bo, *v);
484}
485
486typedef enum bt_bfcr_status (* read_basic_and_call_cb_t)(struct bt_bfcr *,
487 const uint8_t *, size_t);
488
489static inline
490enum bt_bfcr_status validate_contiguous_bo(struct bt_bfcr *bfcr,
491 enum ctf_byte_order next_bo)
492{
493 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
494
495 /* Always valid when at a byte boundary */
496 if (packet_at(bfcr) % 8 == 0) {
497 goto end;
498 }
499
500 /* Always valid if last byte order is unknown */
501 if (bfcr->last_bo == -1) {
502 goto end;
503 }
504
505 /* Always valid if next byte order is unknown */
506 if (next_bo == -1) {
507 goto end;
508 }
509
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;
515 }
516 break;
517 case CTF_BYTE_ORDER_LITTLE:
518 if (next_bo != CTF_BYTE_ORDER_LITTLE) {
519 status = BT_BFCR_STATUS_ERROR;
520 }
521 break;
522 default:
523 status = BT_BFCR_STATUS_ERROR;
524 }
525
526end:
527 if (status < 0) {
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);
531 }
532
533 return status;
534}
535
536static
537enum bt_bfcr_status read_basic_float_and_call_cb(struct bt_bfcr *bfcr,
538 const uint8_t *buf, size_t at)
539{
540 double dblval;
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;
545
546 BT_ASSERT(fc);
547 field_size = fc->base.size;
548 bo = fc->base.byte_order;
549 bfcr->cur_bo = bo;
550
551 switch (field_size) {
552 case 32:
553 {
554 uint64_t v;
555 union {
556 uint32_t u;
557 float f;
558 } f32;
559
560 read_unsigned_bitfield(buf, at, field_size, bo, &v);
561 f32.u = (uint32_t) v;
562 dblval = (double) f32.f;
563 break;
564 }
565 case 64:
566 {
567 union {
568 uint64_t u;
569 double d;
570 } f64;
571
572 read_unsigned_bitfield(buf, at, field_size, bo, &f64.u);
573 dblval = f64.d;
574 break;
575 }
576 default:
577 /* Only 32-bit and 64-bit fields are supported currently */
578 abort();
579 }
580
581 BT_LOGV("Read floating point number value: bfcr=%p, cur=%zu, val=%f",
582 bfcr, at, dblval);
583
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));
593 }
594 }
595
596 return status;
597}
598
599static inline
600enum bt_bfcr_status read_basic_int_and_call_cb(struct bt_bfcr *bfcr,
601 const uint8_t *buf, size_t at)
602{
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;
607
608 field_size = fc->base.size;
609 bo = fc->base.byte_order;
610
611 /*
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.
615 */
616 bfcr->cur_bo = bo;
617
618 if (fc->is_signed) {
619 int64_t v;
620
621 read_signed_bitfield(buf, at, field_size, bo, &v);
622
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));
633 }
634 }
635 } else {
636 uint64_t v;
637
638 read_unsigned_bitfield(buf, at, field_size, bo, &v);
639
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));
650 }
651 }
652 }
653
654 return status;
655}
656
657static inline
658enum 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)
660{
661 size_t available;
662 size_t needed_bits;
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;
666
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;
670 goto end;
671 }
672
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));
689 goto end;
690 }
691
692 if (stack_empty(bfcr->stack)) {
693 /* Root is a basic class */
694 bfcr->state = BFCR_STATE_DONE;
695 } else {
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;
700 }
701 goto end;
702 }
703
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;
708
709end:
710 return status;
711}
712
713static inline
714enum 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)
716{
717 size_t available;
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;
721
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;
725 goto end;
726 }
727
728 status = validate_contiguous_bo(bfcr, fc->byte_order);
729 if (status != BT_BFCR_STATUS_OK) {
730 /* validate_contiguous_bo() logs errors */
731 goto end;
732 }
733
734 available = available_bits(bfcr);
735
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));
746 goto end;
747 }
748
749 consume_bits(bfcr, fc->size);
750
751 if (stack_empty(bfcr->stack)) {
752 /* Root is a basic class */
753 bfcr->state = BFCR_STATE_DONE;
754 } else {
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;
759 }
760
761 goto end;
762 }
763
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;
769
770end:
771 return status;
772}
773
774static inline
775enum bt_bfcr_status read_basic_int_class_and_call_begin(
776 struct bt_bfcr *bfcr)
777{
778 return read_bit_array_class_and_call_begin(bfcr, read_basic_int_and_call_cb);
779}
780
781static inline
782enum bt_bfcr_status read_basic_int_class_and_call_continue(
783 struct bt_bfcr *bfcr)
784{
785 return read_bit_array_class_and_call_continue(bfcr,
786 read_basic_int_and_call_cb);
787}
788
789static inline
790enum bt_bfcr_status read_basic_float_class_and_call_begin(
791 struct bt_bfcr *bfcr)
792{
793 return read_bit_array_class_and_call_begin(bfcr,
794 read_basic_float_and_call_cb);
795}
796
797static inline
798enum bt_bfcr_status read_basic_float_class_and_call_continue(
799 struct bt_bfcr *bfcr)
800{
801 return read_bit_array_class_and_call_continue(bfcr,
802 read_basic_float_and_call_cb);
803}
804
805static inline
806enum bt_bfcr_status read_basic_string_class_and_call(
807 struct bt_bfcr *bfcr, bool begin)
808{
809 size_t buf_at_bytes;
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;
814
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;
818 goto end;
819 }
820
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);
827
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));
837 goto end;
838 }
839 }
840
841 if (!result) {
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,
848 bfcr->user.data);
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));
855 goto end;
856 }
857 }
858
859 consume_bits(bfcr, BYTES_TO_BITS(available_bytes));
860 bfcr->state = BFCR_STATE_READ_BASIC_CONTINUE;
861 status = BT_BFCR_STATUS_EOF;
862 } else {
863 /* Found the null character */
864 size_t result_len = (size_t) (result - first_chr);
865
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,
871 bfcr->user.data);
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));
878 goto end;
879 }
880 }
881
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));
892 goto end;
893 }
894 }
895
896 consume_bits(bfcr, BYTES_TO_BITS(result_len + 1));
897
898 if (stack_empty(bfcr->stack)) {
899 /* Root is a basic class */
900 bfcr->state = BFCR_STATE_DONE;
901 } else {
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;
906 }
907 }
908
909end:
910 return status;
911}
912
913static inline
914enum bt_bfcr_status read_basic_begin_state(struct bt_bfcr *bfcr)
915{
916 enum bt_bfcr_status status;
917
918 BT_ASSERT(bfcr->cur_basic_field_class);
919
af0c18e3
PP
920 switch (bfcr->cur_basic_field_class->type) {
921 case CTF_FIELD_CLASS_TYPE_INT:
922 case CTF_FIELD_CLASS_TYPE_ENUM:
939190b3
PP
923 status = read_basic_int_class_and_call_begin(bfcr);
924 break;
af0c18e3 925 case CTF_FIELD_CLASS_TYPE_FLOAT:
939190b3
PP
926 status = read_basic_float_class_and_call_begin(bfcr);
927 break;
af0c18e3 928 case CTF_FIELD_CLASS_TYPE_STRING:
939190b3
PP
929 status = read_basic_string_class_and_call(bfcr, true);
930 break;
931 default:
932 abort();
933 }
934
935 return status;
936}
937
938static inline
939enum bt_bfcr_status read_basic_continue_state(struct bt_bfcr *bfcr)
940{
941 enum bt_bfcr_status status;
942
943 BT_ASSERT(bfcr->cur_basic_field_class);
944
af0c18e3
PP
945 switch (bfcr->cur_basic_field_class->type) {
946 case CTF_FIELD_CLASS_TYPE_INT:
947 case CTF_FIELD_CLASS_TYPE_ENUM:
939190b3
PP
948 status = read_basic_int_class_and_call_continue(bfcr);
949 break;
af0c18e3 950 case CTF_FIELD_CLASS_TYPE_FLOAT:
939190b3
PP
951 status = read_basic_float_class_and_call_continue(bfcr);
952 break;
af0c18e3 953 case CTF_FIELD_CLASS_TYPE_STRING:
939190b3
PP
954 status = read_basic_string_class_and_call(bfcr, false);
955 break;
956 default:
957 abort();
958 }
959
960 return status;
961}
962
963static inline
964size_t bits_to_skip_to_align_to(struct bt_bfcr *bfcr, size_t align)
965{
966 size_t aligned_packet_at;
967
968 aligned_packet_at = ALIGN(packet_at(bfcr), align);
969 return aligned_packet_at - packet_at(bfcr);
970}
971
972static inline
973enum bt_bfcr_status align_class_state(struct bt_bfcr *bfcr,
974 struct ctf_field_class *field_class, enum bfcr_state next_state)
975{
976 unsigned int field_alignment;
977 size_t skip_bits;
978 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
979
980 /* Get field's alignment */
981 field_alignment = field_class->alignment;
982
983 /*
984 * 0 means "undefined" for variants; what we really want is 1
985 * (always aligned)
986 */
987 BT_ASSERT(field_alignment >= 1);
988
989 /* Compute how many bits we need to skip */
990 skip_bits = bits_to_skip_to_align_to(bfcr, (size_t) field_alignment);
991
992 /* Nothing to skip? aligned */
993 if (skip_bits == 0) {
994 bfcr->state = next_state;
995 goto end;
996 }
997
998 /* Make sure there's at least one bit left */
999 if (!at_least_one_bit_left(bfcr)) {
1000 status = BT_BFCR_STATUS_EOF;
1001 goto end;
1002 }
1003
1004 /* Consume as many bits as possible in what's left */
1005 consume_bits(bfcr, MIN(available_bits(bfcr), skip_bits));
1006
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;
1012 goto end;
1013 } else {
1014 /* No: need more data */
1015 BT_LOGV("Reached end of data when aligning: bfcr-addr=%p", bfcr);
1016 status = BT_BFCR_STATUS_EOF;
1017 }
1018
1019end:
1020 return status;
1021}
1022
1023static inline
1024enum bt_bfcr_status next_field_state(struct bt_bfcr *bfcr)
1025{
1026 int ret;
1027 struct stack_entry *top;
1028 struct ctf_field_class *next_field_class = NULL;
1029 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
1030
1031 if (stack_empty(bfcr->stack)) {
1032 goto end;
1033 }
1034
1035 top = stack_top(bfcr->stack);
1036
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));
1048 goto end;
1049 }
1050 }
1051
1052 stack_pop(bfcr->stack);
1053
1054 /* Are we done with the root class? */
1055 if (stack_empty(bfcr->stack)) {
1056 bfcr->state = BFCR_STATE_DONE;
1057 goto end;
1058 }
1059
1060 top = stack_top(bfcr->stack);
1061 top->index++;
1062 }
1063
1064 /* Get next field's class */
af0c18e3
PP
1065 switch (top->base_class->type) {
1066 case CTF_FIELD_CLASS_TYPE_STRUCT:
939190b3
PP
1067 next_field_class = ctf_field_class_struct_borrow_member_by_index(
1068 (void *) top->base_class, (uint64_t) top->index)->fc;
1069 break;
af0c18e3
PP
1070 case CTF_FIELD_CLASS_TYPE_ARRAY:
1071 case CTF_FIELD_CLASS_TYPE_SEQUENCE:
939190b3
PP
1072 {
1073 struct ctf_field_class_array_base *array_fc =
1074 (void *) top->base_class;
1075
1076 next_field_class = array_fc->elem_fc;
1077 break;
1078 }
af0c18e3 1079 case CTF_FIELD_CLASS_TYPE_VARIANT:
939190b3
PP
1080 /* Variant classes are dynamic: the user should know! */
1081 next_field_class =
1082 bfcr->user.cbs.query.borrow_variant_selected_field_class(
1083 top->base_class, bfcr->user.data);
1084 break;
1085 default:
1086 break;
1087 }
1088
1089 if (!next_field_class) {
1090 BT_LOGW("Cannot get the field class of the next field: "
af0c18e3 1091 "bfcr-addr=%p, base-fc-addr=%p, base-fc-type=%d, "
939190b3 1092 "index=%" PRId64,
af0c18e3
PP
1093 bfcr, top->base_class, top->base_class->type,
1094 top->index);
939190b3
PP
1095 status = BT_BFCR_STATUS_ERROR;
1096 goto end;
1097 }
1098
1099 if (next_field_class->is_compound) {
1100 if (bfcr->user.cbs.classes.compound_begin) {
1101 BT_LOGV("Calling user function (compound, begin).");
1102 status = bfcr->user.cbs.classes.compound_begin(
1103 next_field_class, bfcr->user.data);
1104 BT_LOGV("User function returned: status=%s",
1105 bt_bfcr_status_string(status));
1106 if (status != BT_BFCR_STATUS_OK) {
1107 BT_LOGW("User function failed: bfcr-addr=%p, status=%s",
1108 bfcr, bt_bfcr_status_string(status));
1109 goto end;
1110 }
1111 }
1112
1113 ret = stack_push_with_len(bfcr, next_field_class);
1114 if (ret) {
1115 /* stack_push_with_len() logs errors */
1116 status = BT_BFCR_STATUS_ERROR;
1117 goto end;
1118 }
1119
1120 /* Next state: align a compound class */
1121 bfcr->state = BFCR_STATE_ALIGN_COMPOUND;
1122 } else {
1123 /* Replace current basic field class */
1124 BT_LOGV("Replacing current basic field class: "
1125 "bfcr-addr=%p, cur-basic-fc-addr=%p, "
1126 "next-basic-fc-addr=%p",
1127 bfcr, bfcr->cur_basic_field_class, next_field_class);
1128 bfcr->cur_basic_field_class = next_field_class;
1129
1130 /* Next state: align a basic class */
1131 bfcr->state = BFCR_STATE_ALIGN_BASIC;
1132 }
1133
1134end:
1135 return status;
1136}
1137
1138static inline
1139enum bt_bfcr_status handle_state(struct bt_bfcr *bfcr)
1140{
1141 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
1142
1143 BT_LOGV("Handling state: bfcr-addr=%p, state=%s",
1144 bfcr, bfcr_state_string(bfcr->state));
1145
1146 switch (bfcr->state) {
1147 case BFCR_STATE_NEXT_FIELD:
1148 status = next_field_state(bfcr);
1149 break;
1150 case BFCR_STATE_ALIGN_BASIC:
1151 status = align_class_state(bfcr, bfcr->cur_basic_field_class,
1152 BFCR_STATE_READ_BASIC_BEGIN);
1153 break;
1154 case BFCR_STATE_ALIGN_COMPOUND:
1155 status = align_class_state(bfcr, stack_top(bfcr->stack)->base_class,
1156 BFCR_STATE_NEXT_FIELD);
1157 break;
1158 case BFCR_STATE_READ_BASIC_BEGIN:
1159 status = read_basic_begin_state(bfcr);
1160 break;
1161 case BFCR_STATE_READ_BASIC_CONTINUE:
1162 status = read_basic_continue_state(bfcr);
1163 break;
1164 case BFCR_STATE_DONE:
1165 break;
1166 }
1167
1168 BT_LOGV("Handled state: bfcr-addr=%p, status=%s",
1169 bfcr, bt_bfcr_status_string(status));
1170 return status;
1171}
1172
1173BT_HIDDEN
1174struct bt_bfcr *bt_bfcr_create(struct bt_bfcr_cbs cbs, void *data)
1175{
1176 struct bt_bfcr *bfcr;
1177
1178 BT_LOGD_STR("Creating binary class reader (BFCR).");
1179 bfcr = g_new0(struct bt_bfcr, 1);
1180 if (!bfcr) {
1181 BT_LOGE_STR("Failed to allocate one binary class reader.");
1182 goto end;
1183 }
1184
1185 bfcr->stack = stack_new();
1186 if (!bfcr->stack) {
1187 BT_LOGE_STR("Cannot create BFCR's stack.");
1188 bt_bfcr_destroy(bfcr);
1189 bfcr = NULL;
1190 goto end;
1191 }
1192
1193 bfcr->state = BFCR_STATE_NEXT_FIELD;
1194 bfcr->user.cbs = cbs;
1195 bfcr->user.data = data;
1196 BT_LOGD("Created BFCR: addr=%p", bfcr);
1197
1198end:
1199 return bfcr;
1200}
1201
1202BT_HIDDEN
1203void bt_bfcr_destroy(struct bt_bfcr *bfcr)
1204{
1205 if (bfcr->stack) {
1206 stack_destroy(bfcr->stack);
1207 }
1208
1209 BT_LOGD("Destroying BFCR: addr=%p", bfcr);
1210 g_free(bfcr);
1211}
1212
1213static
1214void reset(struct bt_bfcr *bfcr)
1215{
1216 BT_LOGD("Resetting BFCR: addr=%p", bfcr);
1217 stack_clear(bfcr->stack);
1218 stitch_reset(bfcr);
1219 bfcr->buf.addr = NULL;
1220 bfcr->last_bo = -1;
1221}
1222
1223static
1224void update_packet_offset(struct bt_bfcr *bfcr)
1225{
1226 BT_LOGV("Updating packet offset for next call: "
1227 "bfcr-addr=%p, cur-packet-offset=%zu, next-packet-offset=%zu",
1228 bfcr, bfcr->buf.packet_offset,
1229 bfcr->buf.packet_offset + bfcr->buf.at);
1230 bfcr->buf.packet_offset += bfcr->buf.at;
1231}
1232
1233BT_HIDDEN
1234size_t bt_bfcr_start(struct bt_bfcr *bfcr,
1235 struct ctf_field_class *cls, const uint8_t *buf,
1236 size_t offset, size_t packet_offset, size_t sz,
1237 enum bt_bfcr_status *status)
1238{
1239 BT_ASSERT(bfcr);
1240 BT_ASSERT(BYTES_TO_BITS(sz) >= offset);
1241 reset(bfcr);
1242 bfcr->buf.addr = buf;
1243 bfcr->buf.offset = offset;
1244 bfcr->buf.at = 0;
1245 bfcr->buf.packet_offset = packet_offset;
1246 bfcr->buf.buf_sz = sz;
1247 bfcr->buf.sz = BYTES_TO_BITS(sz) - offset;
1248 *status = BT_BFCR_STATUS_OK;
1249
1250 BT_LOGV("Starting decoding: bfcr-addr=%p, fc-addr=%p, "
1251 "buf-addr=%p, buf-size=%zu, offset=%zu, "
1252 "packet-offset=%zu",
1253 bfcr, cls, buf, sz, offset, packet_offset);
1254
1255 /* Set root class */
1256 if (cls->is_compound) {
1257 /* Compound class: push on visit stack */
1258 int stack_ret;
1259
1260 if (bfcr->user.cbs.classes.compound_begin) {
1261 BT_LOGV("Calling user function (compound, begin).");
1262 *status = bfcr->user.cbs.classes.compound_begin(
1263 cls, bfcr->user.data);
1264 BT_LOGV("User function returned: status=%s",
1265 bt_bfcr_status_string(*status));
1266 if (*status != BT_BFCR_STATUS_OK) {
1267 BT_LOGW("User function failed: bfcr-addr=%p, status=%s",
1268 bfcr, bt_bfcr_status_string(*status));
1269 goto end;
1270 }
1271 }
1272
1273 stack_ret = stack_push_with_len(bfcr, cls);
1274 if (stack_ret) {
1275 /* stack_push_with_len() logs errors */
1276 *status = BT_BFCR_STATUS_ERROR;
1277 goto end;
1278 }
1279
1280 bfcr->state = BFCR_STATE_ALIGN_COMPOUND;
1281 } else {
1282 /* Basic class: set as current basic class */
1283 bfcr->cur_basic_field_class = cls;
1284 bfcr->state = BFCR_STATE_ALIGN_BASIC;
1285 }
1286
1287 /* Run the machine! */
1288 BT_LOGV_STR("Running the state machine.");
1289
1290 while (true) {
1291 *status = handle_state(bfcr);
1292 if (*status != BT_BFCR_STATUS_OK ||
1293 bfcr->state == BFCR_STATE_DONE) {
1294 break;
1295 }
1296 }
1297
1298 /* Update packet offset for next time */
1299 update_packet_offset(bfcr);
1300
1301end:
1302 return bfcr->buf.at;
1303}
1304
1305BT_HIDDEN
1306size_t bt_bfcr_continue(struct bt_bfcr *bfcr, const uint8_t *buf, size_t sz,
1307 enum bt_bfcr_status *status)
1308{
1309 BT_ASSERT(bfcr);
1310 BT_ASSERT(buf);
1311 BT_ASSERT(sz > 0);
1312 bfcr->buf.addr = buf;
1313 bfcr->buf.offset = 0;
1314 bfcr->buf.at = 0;
1315 bfcr->buf.buf_sz = sz;
1316 bfcr->buf.sz = BYTES_TO_BITS(sz);
1317 *status = BT_BFCR_STATUS_OK;
1318
1319 BT_LOGV("Continuing decoding: bfcr-addr=%p, buf-addr=%p, buf-size=%zu",
1320 bfcr, buf, sz);
1321
1322 /* Continue running the machine */
1323 BT_LOGV_STR("Running the state machine.");
1324
1325 while (true) {
1326 *status = handle_state(bfcr);
1327 if (*status != BT_BFCR_STATUS_OK ||
1328 bfcr->state == BFCR_STATE_DONE) {
1329 break;
1330 }
1331 }
1332
1333 /* Update packet offset for next time */
1334 update_packet_offset(bfcr);
1335 return bfcr->buf.at;
1336}
1337
1338BT_HIDDEN
1339void bt_bfcr_set_unsigned_int_cb(struct bt_bfcr *bfcr,
1340 bt_bfcr_unsigned_int_cb_func cb)
1341{
1342 BT_ASSERT(bfcr);
1343 BT_ASSERT(cb);
1344 bfcr->user.cbs.classes.unsigned_int = cb;
1345}
This page took 0.071657 seconds and 4 git commands to generate.