port: namespace align.h with BT_ prefix
[babeltrace.git] / src / plugins / ctf / common / bfcr / bfcr.c
1 /*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation
5 * Copyright (c) 2015-2016 Philippe Proulx <pproulx@efficios.com>
6 *
7 * Babeltrace - CTF binary field class reader (BFCR)
8 */
9
10 #define BT_COMP_LOG_SELF_COMP (bfcr->self_comp)
11 #define BT_LOG_OUTPUT_LEVEL (bfcr->log_level)
12 #define BT_LOG_TAG "PLUGIN/CTF/BFCR"
13 #include "logging/comp-logging.h"
14
15 #include <stdlib.h>
16 #include <stdint.h>
17 #include <inttypes.h>
18 #include <stdio.h>
19 #include <stddef.h>
20 #include <stdbool.h>
21 #include "common/assert.h"
22 #include <string.h>
23 #include "compat/bitfield.h"
24 #include "common/common.h"
25 #include <babeltrace2/babeltrace.h>
26 #include "common/align.h"
27 #include <glib.h>
28
29 #include "bfcr.h"
30 #include "../metadata/ctf-meta.h"
31
32 #define DIV8(_x) ((_x) >> 3)
33 #define BYTES_TO_BITS(_x) ((_x) * 8)
34 #define BITS_TO_BYTES_FLOOR(_x) DIV8(_x)
35 #define BITS_TO_BYTES_CEIL(_x) DIV8((_x) + 7)
36 #define IN_BYTE_OFFSET(_at) ((_at) & 7)
37
38 /* A visit stack entry */
39 struct stack_entry {
40 /*
41 * Current class of base field, one of:
42 *
43 * * Structure
44 * * Array
45 * * Sequence
46 * * Variant
47 */
48 struct ctf_field_class *base_class;
49
50 /* Length of base field (always 1 for a variant class) */
51 int64_t base_len;
52
53 /* Index of next field to read */
54 int64_t index;
55 };
56
57 struct bt_bfcr;
58
59 /* Visit stack */
60 struct stack {
61 struct bt_bfcr *bfcr;
62
63 /* Entries (struct stack_entry) */
64 GArray *entries;
65
66 /* Number of active entries */
67 size_t size;
68 };
69
70 /* Reading states */
71 enum bfcr_state {
72 BFCR_STATE_NEXT_FIELD,
73 BFCR_STATE_ALIGN_BASIC,
74 BFCR_STATE_ALIGN_COMPOUND,
75 BFCR_STATE_READ_BASIC_BEGIN,
76 BFCR_STATE_READ_BASIC_CONTINUE,
77 BFCR_STATE_DONE,
78 };
79
80 /* Binary class reader */
81 struct bt_bfcr {
82 bt_logging_level log_level;
83
84 /* Weak */
85 bt_self_component *self_comp;
86
87 /* BFCR stack */
88 struct stack *stack;
89
90 /* Current basic field class */
91 struct ctf_field_class *cur_basic_field_class;
92
93 /* Current state */
94 enum bfcr_state state;
95
96 /*
97 * Last basic field class's byte order.
98 *
99 * This is used to detect errors since two contiguous basic
100 * classes for which the common boundary is not the boundary of
101 * a byte cannot have different byte orders.
102 *
103 * This is set to CTF_BYTE_ORDER_UNKNOWN on reset and when the last
104 * basic field class was a string class.
105 */
106 enum ctf_byte_order last_bo;
107
108 /* Current byte order (copied to last_bo after a successful read) */
109 enum ctf_byte_order cur_bo;
110
111 /* Stitch buffer infos */
112 struct {
113 /* Stitch buffer */
114 uint8_t buf[16];
115
116 /* Offset, within stitch buffer, of first bit */
117 size_t offset;
118
119 /* Length (bits) of data in stitch buffer from offset */
120 size_t at;
121 } stitch;
122
123 /* User buffer infos */
124 struct {
125 /* Address */
126 const uint8_t *addr;
127
128 /* Offset of data from address (bits) */
129 size_t offset;
130
131 /* Current position from offset (bits) */
132 size_t at;
133
134 /* Offset of offset within whole packet (bits) */
135 size_t packet_offset;
136
137 /* Data size in buffer (bits) */
138 size_t sz;
139
140 /* Buffer size (bytes) */
141 size_t buf_sz;
142 } buf;
143
144 /* User stuff */
145 struct {
146 /* Callback functions */
147 struct bt_bfcr_cbs cbs;
148
149 /* Private data */
150 void *data;
151 } user;
152 };
153
154 static inline
155 const char *bfcr_state_string(enum bfcr_state state)
156 {
157 switch (state) {
158 case BFCR_STATE_NEXT_FIELD:
159 return "NEXT_FIELD";
160 case BFCR_STATE_ALIGN_BASIC:
161 return "ALIGN_BASIC";
162 case BFCR_STATE_ALIGN_COMPOUND:
163 return "ALIGN_COMPOUND";
164 case BFCR_STATE_READ_BASIC_BEGIN:
165 return "READ_BASIC_BEGIN";
166 case BFCR_STATE_READ_BASIC_CONTINUE:
167 return "READ_BASIC_CONTINUE";
168 case BFCR_STATE_DONE:
169 return "DONE";
170 default:
171 return "(unknown)";
172 }
173 }
174
175 static
176 struct stack *stack_new(struct bt_bfcr *bfcr)
177 {
178 struct stack *stack = NULL;
179
180 stack = g_new0(struct stack, 1);
181 if (!stack) {
182 BT_COMP_LOGE_STR("Failed to allocate one stack.");
183 goto error;
184 }
185
186 stack->bfcr = bfcr;
187 stack->entries = g_array_new(FALSE, TRUE, sizeof(struct stack_entry));
188 if (!stack->entries) {
189 BT_COMP_LOGE_STR("Failed to allocate a GArray.");
190 goto error;
191 }
192
193 BT_COMP_LOGD("Created stack: addr=%p", stack);
194 return stack;
195
196 error:
197 g_free(stack);
198 return NULL;
199 }
200
201 static
202 void stack_destroy(struct stack *stack)
203 {
204 struct bt_bfcr *bfcr;
205
206 if (!stack) {
207 return;
208 }
209
210 bfcr = stack->bfcr;
211 BT_COMP_LOGD("Destroying stack: addr=%p", stack);
212
213 if (stack->entries) {
214 g_array_free(stack->entries, TRUE);
215 }
216
217 g_free(stack);
218 }
219
220 static
221 int stack_push(struct stack *stack, struct ctf_field_class *base_class,
222 size_t base_len)
223 {
224 struct stack_entry *entry;
225 struct bt_bfcr *bfcr;
226
227 BT_ASSERT_DBG(stack);
228 BT_ASSERT_DBG(base_class);
229 bfcr = stack->bfcr;
230 BT_COMP_LOGT("Pushing field class on stack: stack-addr=%p, "
231 "fc-addr=%p, fc-type=%d, base-length=%zu, "
232 "stack-size-before=%zu, stack-size-after=%zu",
233 stack, base_class, base_class->type,
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
248 static inline
249 int64_t get_compound_field_class_length(struct bt_bfcr *bfcr,
250 struct ctf_field_class *fc)
251 {
252 int64_t length;
253
254 switch (fc->type) {
255 case CTF_FIELD_CLASS_TYPE_STRUCT:
256 {
257 struct ctf_field_class_struct *struct_fc = (void *) fc;
258
259 length = (int64_t) struct_fc->members->len;
260 break;
261 }
262 case CTF_FIELD_CLASS_TYPE_VARIANT:
263 {
264 /* Variant field classes always "contain" a single class */
265 length = 1;
266 break;
267 }
268 case CTF_FIELD_CLASS_TYPE_ARRAY:
269 {
270 struct ctf_field_class_array *array_fc = (void *) fc;
271
272 length = (int64_t) array_fc->length;
273 break;
274 }
275 case CTF_FIELD_CLASS_TYPE_SEQUENCE:
276 length = bfcr->user.cbs.query.get_sequence_length(fc,
277 bfcr->user.data);
278 break;
279 default:
280 bt_common_abort();
281 }
282
283 return length;
284 }
285
286 static
287 int 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_COMP_LOGW("Cannot get compound field class's field count: "
294 "bfcr-addr=%p, fc-addr=%p, fc-type=%d",
295 bfcr, base_class, base_class->type);
296 ret = BT_BFCR_STATUS_ERROR;
297 goto end;
298 }
299
300 ret = stack_push(bfcr->stack, base_class, (size_t) length);
301
302 end:
303 return ret;
304 }
305
306 static inline
307 unsigned int stack_size(struct stack *stack)
308 {
309 BT_ASSERT_DBG(stack);
310 return stack->size;
311 }
312
313 static
314 void stack_pop(struct stack *stack)
315 {
316 struct bt_bfcr *bfcr;
317
318 BT_ASSERT_DBG(stack);
319 BT_ASSERT_DBG(stack_size(stack));
320 bfcr = stack->bfcr;
321 BT_COMP_LOGT("Popping from stack: "
322 "stack-addr=%p, stack-size-before=%u, stack-size-after=%u",
323 stack, stack->entries->len, stack->entries->len - 1);
324 stack->size--;
325 }
326
327 static inline
328 bool stack_empty(struct stack *stack)
329 {
330 return stack_size(stack) == 0;
331 }
332
333 static
334 void stack_clear(struct stack *stack)
335 {
336 BT_ASSERT_DBG(stack);
337 stack->size = 0;
338 }
339
340 static inline
341 struct stack_entry *stack_top(struct stack *stack)
342 {
343 BT_ASSERT_DBG(stack);
344 BT_ASSERT_DBG(stack_size(stack));
345 return &g_array_index(stack->entries, struct stack_entry,
346 stack->size - 1);
347 }
348
349 static inline
350 size_t available_bits(struct bt_bfcr *bfcr)
351 {
352 return bfcr->buf.sz - bfcr->buf.at;
353 }
354
355 static inline
356 void consume_bits(struct bt_bfcr *bfcr, size_t incr)
357 {
358 BT_COMP_LOGT("Advancing cursor: bfcr-addr=%p, cur-before=%zu, cur-after=%zu",
359 bfcr, bfcr->buf.at, bfcr->buf.at + incr);
360 bfcr->buf.at += incr;
361 }
362
363 static inline
364 bool has_enough_bits(struct bt_bfcr *bfcr, size_t sz)
365 {
366 return available_bits(bfcr) >= sz;
367 }
368
369 static inline
370 bool at_least_one_bit_left(struct bt_bfcr *bfcr)
371 {
372 return has_enough_bits(bfcr, 1);
373 }
374
375 static inline
376 size_t packet_at(struct bt_bfcr *bfcr)
377 {
378 return bfcr->buf.packet_offset + bfcr->buf.at;
379 }
380
381 static inline
382 size_t buf_at_from_addr(struct bt_bfcr *bfcr)
383 {
384 /*
385 * Considering this:
386 *
387 * ====== offset ===== (17)
388 *
389 * xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
390 * ^
391 * addr (0) ==== at ==== (12)
392 *
393 * We want this:
394 *
395 * =============================== (29)
396 */
397 return bfcr->buf.offset + bfcr->buf.at;
398 }
399
400 static
401 void stitch_reset(struct bt_bfcr *bfcr)
402 {
403 bfcr->stitch.offset = 0;
404 bfcr->stitch.at = 0;
405 }
406
407 static inline
408 size_t stitch_at_from_addr(struct bt_bfcr *bfcr)
409 {
410 return bfcr->stitch.offset + bfcr->stitch.at;
411 }
412
413 static
414 void stitch_append_from_buf(struct bt_bfcr *bfcr, size_t sz)
415 {
416 size_t stitch_byte_at;
417 size_t buf_byte_at;
418 size_t nb_bytes;
419
420 if (sz == 0) {
421 return;
422 }
423
424 stitch_byte_at =
425 BITS_TO_BYTES_FLOOR(stitch_at_from_addr(bfcr));
426 buf_byte_at = BITS_TO_BYTES_FLOOR(buf_at_from_addr(bfcr));
427 nb_bytes = BITS_TO_BYTES_CEIL(sz);
428 BT_ASSERT(nb_bytes > 0);
429 BT_ASSERT(bfcr->buf.addr);
430 memcpy(&bfcr->stitch.buf[stitch_byte_at], &bfcr->buf.addr[buf_byte_at],
431 nb_bytes);
432 bfcr->stitch.at += sz;
433 consume_bits(bfcr, sz);
434 }
435
436 static
437 void stitch_append_from_remaining_buf(struct bt_bfcr *bfcr)
438 {
439 stitch_append_from_buf(bfcr, available_bits(bfcr));
440 }
441
442 static
443 void stitch_set_from_remaining_buf(struct bt_bfcr *bfcr)
444 {
445 stitch_reset(bfcr);
446 bfcr->stitch.offset = IN_BYTE_OFFSET(buf_at_from_addr(bfcr));
447 stitch_append_from_remaining_buf(bfcr);
448 }
449
450 static inline
451 void read_unsigned_bitfield(struct bt_bfcr *bfcr, const uint8_t *buf, size_t at,
452 unsigned int field_size, enum ctf_byte_order bo,
453 uint64_t *v)
454 {
455 switch (bo) {
456 case CTF_BYTE_ORDER_BIG:
457 bt_bitfield_read_be(buf, uint8_t, at, field_size, v);
458 break;
459 case CTF_BYTE_ORDER_LITTLE:
460 bt_bitfield_read_le(buf, uint8_t, at, field_size, v);
461 break;
462 default:
463 bt_common_abort();
464 }
465
466 BT_COMP_LOGT("Read unsigned bit array: cur=%zu, size=%u, "
467 "bo=%d, val=%" PRIu64, at, field_size, bo, *v);
468 }
469
470 static inline
471 void read_signed_bitfield(struct bt_bfcr *bfcr, const uint8_t *buf, size_t at,
472 unsigned int field_size, enum ctf_byte_order bo, int64_t *v)
473 {
474 switch (bo) {
475 case CTF_BYTE_ORDER_BIG:
476 bt_bitfield_read_be(buf, uint8_t, at, field_size, v);
477 break;
478 case CTF_BYTE_ORDER_LITTLE:
479 bt_bitfield_read_le(buf, uint8_t, at, field_size, v);
480 break;
481 default:
482 bt_common_abort();
483 }
484
485 BT_COMP_LOGT("Read signed bit array: cur=%zu, size=%u, "
486 "bo=%d, val=%" PRId64, at, field_size, bo, *v);
487 }
488
489 typedef enum bt_bfcr_status (* read_basic_and_call_cb_t)(struct bt_bfcr *,
490 const uint8_t *, size_t);
491
492 static inline
493 enum bt_bfcr_status validate_contiguous_bo(struct bt_bfcr *bfcr,
494 enum ctf_byte_order next_bo)
495 {
496 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
497
498 /* Always valid when at a byte boundary */
499 if (packet_at(bfcr) % 8 == 0) {
500 goto end;
501 }
502
503 /* Always valid if last byte order is unknown */
504 if (bfcr->last_bo == CTF_BYTE_ORDER_UNKNOWN) {
505 goto end;
506 }
507
508 /* Always valid if next byte order is unknown */
509 if (next_bo == CTF_BYTE_ORDER_UNKNOWN) {
510 goto end;
511 }
512
513 /* Make sure last byte order is compatible with the next byte order */
514 switch (bfcr->last_bo) {
515 case CTF_BYTE_ORDER_BIG:
516 if (next_bo != CTF_BYTE_ORDER_BIG) {
517 status = BT_BFCR_STATUS_ERROR;
518 }
519 break;
520 case CTF_BYTE_ORDER_LITTLE:
521 if (next_bo != CTF_BYTE_ORDER_LITTLE) {
522 status = BT_BFCR_STATUS_ERROR;
523 }
524 break;
525 default:
526 status = BT_BFCR_STATUS_ERROR;
527 }
528
529 end:
530 if (status < 0) {
531 BT_COMP_LOGW("Cannot read bit array: two different byte orders not at a byte boundary: "
532 "bfcr-addr=%p, last-bo=%d, next-bo=%d",
533 bfcr, bfcr->last_bo, next_bo);
534 }
535
536 return status;
537 }
538
539 static
540 enum bt_bfcr_status read_basic_float_and_call_cb(struct bt_bfcr *bfcr,
541 const uint8_t *buf, size_t at)
542 {
543 double dblval;
544 unsigned int field_size;
545 enum ctf_byte_order bo;
546 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
547 struct ctf_field_class_float *fc = (void *) bfcr->cur_basic_field_class;
548
549 BT_ASSERT_DBG(fc);
550 field_size = fc->base.size;
551 bo = fc->base.byte_order;
552 bfcr->cur_bo = bo;
553
554 switch (field_size) {
555 case 32:
556 {
557 uint64_t v;
558 union {
559 uint32_t u;
560 float f;
561 } f32;
562
563 read_unsigned_bitfield(bfcr, buf, at, field_size, bo, &v);
564 f32.u = (uint32_t) v;
565 dblval = (double) f32.f;
566 break;
567 }
568 case 64:
569 {
570 union {
571 uint64_t u;
572 double d;
573 } f64;
574
575 read_unsigned_bitfield(bfcr, buf, at, field_size, bo, &f64.u);
576 dblval = f64.d;
577 break;
578 }
579 default:
580 /* Only 32-bit and 64-bit fields are supported currently */
581 bt_common_abort();
582 }
583
584 BT_COMP_LOGT("Read floating point number value: bfcr=%p, cur=%zu, val=%f",
585 bfcr, at, dblval);
586
587 if (bfcr->user.cbs.classes.floating_point) {
588 BT_COMP_LOGT("Calling user function (floating point number).");
589 status = bfcr->user.cbs.classes.floating_point(dblval,
590 bfcr->cur_basic_field_class, bfcr->user.data);
591 BT_COMP_LOGT("User function returned: status=%s",
592 bt_bfcr_status_string(status));
593 if (status != BT_BFCR_STATUS_OK) {
594 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s",
595 bfcr, bt_bfcr_status_string(status));
596 }
597 }
598
599 return status;
600 }
601
602 static inline
603 enum bt_bfcr_status read_basic_int_and_call_cb(struct bt_bfcr *bfcr,
604 const uint8_t *buf, size_t at)
605 {
606 unsigned int field_size;
607 enum ctf_byte_order bo;
608 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
609 struct ctf_field_class_int *fc = (void *) bfcr->cur_basic_field_class;
610
611 field_size = fc->base.size;
612 bo = fc->base.byte_order;
613
614 /*
615 * Update current byte order now because we could be reading
616 * the integer value of an enumeration class, and thus we know
617 * here the actual supporting integer class's byte order.
618 */
619 bfcr->cur_bo = bo;
620
621 if (fc->is_signed) {
622 int64_t v;
623
624 read_signed_bitfield(bfcr, buf, at, field_size, bo, &v);
625
626 if (bfcr->user.cbs.classes.signed_int) {
627 BT_COMP_LOGT("Calling user function (signed integer).");
628 status = bfcr->user.cbs.classes.signed_int(v,
629 bfcr->cur_basic_field_class, bfcr->user.data);
630 BT_COMP_LOGT("User function returned: status=%s",
631 bt_bfcr_status_string(status));
632 if (status != BT_BFCR_STATUS_OK) {
633 BT_COMP_LOGW("User function failed: "
634 "bfcr-addr=%p, status=%s",
635 bfcr, bt_bfcr_status_string(status));
636 }
637 }
638 } else {
639 uint64_t v;
640
641 read_unsigned_bitfield(bfcr, buf, at, field_size, bo, &v);
642
643 if (bfcr->user.cbs.classes.unsigned_int) {
644 BT_COMP_LOGT("Calling user function (unsigned integer).");
645 status = bfcr->user.cbs.classes.unsigned_int(v,
646 bfcr->cur_basic_field_class, bfcr->user.data);
647 BT_COMP_LOGT("User function returned: status=%s",
648 bt_bfcr_status_string(status));
649 if (status != BT_BFCR_STATUS_OK) {
650 BT_COMP_LOGW("User function failed: "
651 "bfcr-addr=%p, status=%s",
652 bfcr, bt_bfcr_status_string(status));
653 }
654 }
655 }
656
657 return status;
658 }
659
660 static inline
661 enum bt_bfcr_status read_bit_array_class_and_call_continue(struct bt_bfcr *bfcr,
662 read_basic_and_call_cb_t read_basic_and_call_cb)
663 {
664 size_t available;
665 size_t needed_bits;
666 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
667 struct ctf_field_class_bit_array *fc =
668 (void *) bfcr->cur_basic_field_class;
669
670 if (!at_least_one_bit_left(bfcr)) {
671 BT_COMP_LOGT("Reached end of data: bfcr-addr=%p", bfcr);
672 status = BT_BFCR_STATUS_EOF;
673 goto end;
674 }
675
676 available = available_bits(bfcr);
677 needed_bits = fc->size - bfcr->stitch.at;
678 BT_COMP_LOGT("Continuing basic field decoding: "
679 "bfcr-addr=%p, field-size=%u, needed-size=%zu, "
680 "available-size=%zu",
681 bfcr, fc->size, needed_bits, available);
682 if (needed_bits <= available) {
683 /* We have all the bits; append to stitch, then decode */
684 stitch_append_from_buf(bfcr, needed_bits);
685 status = read_basic_and_call_cb(bfcr, bfcr->stitch.buf,
686 bfcr->stitch.offset);
687 if (status != BT_BFCR_STATUS_OK) {
688 BT_COMP_LOGW("Cannot read basic field: "
689 "bfcr-addr=%p, fc-addr=%p, status=%s",
690 bfcr, bfcr->cur_basic_field_class,
691 bt_bfcr_status_string(status));
692 goto end;
693 }
694
695 if (stack_empty(bfcr->stack)) {
696 /* Root is a basic class */
697 bfcr->state = BFCR_STATE_DONE;
698 } else {
699 /* Go to next field */
700 stack_top(bfcr->stack)->index++;
701 bfcr->state = BFCR_STATE_NEXT_FIELD;
702 bfcr->last_bo = bfcr->cur_bo;
703 }
704 goto end;
705 }
706
707 /* We are here; it means we don't have enough data to decode this */
708 BT_COMP_LOGT_STR("Not enough data to read the next basic field: appending to stitch buffer.");
709 stitch_append_from_remaining_buf(bfcr);
710 status = BT_BFCR_STATUS_EOF;
711
712 end:
713 return status;
714 }
715
716 static inline
717 enum bt_bfcr_status read_bit_array_class_and_call_begin(struct bt_bfcr *bfcr,
718 read_basic_and_call_cb_t read_basic_and_call_cb)
719 {
720 size_t available;
721 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
722 struct ctf_field_class_bit_array *fc =
723 (void *) bfcr->cur_basic_field_class;
724
725 if (!at_least_one_bit_left(bfcr)) {
726 BT_COMP_LOGT("Reached end of data: bfcr-addr=%p", bfcr);
727 status = BT_BFCR_STATUS_EOF;
728 goto end;
729 }
730
731 status = validate_contiguous_bo(bfcr, fc->byte_order);
732 if (status != BT_BFCR_STATUS_OK) {
733 /* validate_contiguous_bo() logs errors */
734 goto end;
735 }
736
737 available = available_bits(bfcr);
738
739 if (fc->size <= available) {
740 /* We have all the bits; decode and set now */
741 BT_ASSERT_DBG(bfcr->buf.addr);
742 status = read_basic_and_call_cb(bfcr, bfcr->buf.addr,
743 buf_at_from_addr(bfcr));
744 if (status != BT_BFCR_STATUS_OK) {
745 BT_COMP_LOGW("Cannot read basic field: "
746 "bfcr-addr=%p, fc-addr=%p, status=%s",
747 bfcr, bfcr->cur_basic_field_class,
748 bt_bfcr_status_string(status));
749 goto end;
750 }
751
752 consume_bits(bfcr, fc->size);
753
754 if (stack_empty(bfcr->stack)) {
755 /* Root is a basic class */
756 bfcr->state = BFCR_STATE_DONE;
757 } else {
758 /* Go to next field */
759 stack_top(bfcr->stack)->index++;
760 bfcr->state = BFCR_STATE_NEXT_FIELD;
761 bfcr->last_bo = bfcr->cur_bo;
762 }
763
764 goto end;
765 }
766
767 /* We are here; it means we don't have enough data to decode this */
768 BT_COMP_LOGT_STR("Not enough data to read the next basic field: setting stitch buffer.");
769 stitch_set_from_remaining_buf(bfcr);
770 bfcr->state = BFCR_STATE_READ_BASIC_CONTINUE;
771 status = BT_BFCR_STATUS_EOF;
772
773 end:
774 return status;
775 }
776
777 static inline
778 enum bt_bfcr_status read_basic_int_class_and_call_begin(
779 struct bt_bfcr *bfcr)
780 {
781 return read_bit_array_class_and_call_begin(bfcr, read_basic_int_and_call_cb);
782 }
783
784 static inline
785 enum bt_bfcr_status read_basic_int_class_and_call_continue(
786 struct bt_bfcr *bfcr)
787 {
788 return read_bit_array_class_and_call_continue(bfcr,
789 read_basic_int_and_call_cb);
790 }
791
792 static inline
793 enum bt_bfcr_status read_basic_float_class_and_call_begin(
794 struct bt_bfcr *bfcr)
795 {
796 return read_bit_array_class_and_call_begin(bfcr,
797 read_basic_float_and_call_cb);
798 }
799
800 static inline
801 enum bt_bfcr_status read_basic_float_class_and_call_continue(
802 struct bt_bfcr *bfcr)
803 {
804 return read_bit_array_class_and_call_continue(bfcr,
805 read_basic_float_and_call_cb);
806 }
807
808 static inline
809 enum bt_bfcr_status read_basic_string_class_and_call(
810 struct bt_bfcr *bfcr, bool begin)
811 {
812 size_t buf_at_bytes;
813 const uint8_t *result;
814 size_t available_bytes;
815 const uint8_t *first_chr;
816 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
817
818 if (!at_least_one_bit_left(bfcr)) {
819 BT_COMP_LOGT("Reached end of data: bfcr-addr=%p", bfcr);
820 status = BT_BFCR_STATUS_EOF;
821 goto end;
822 }
823
824 BT_ASSERT_DBG(buf_at_from_addr(bfcr) % 8 == 0);
825 available_bytes = BITS_TO_BYTES_FLOOR(available_bits(bfcr));
826 buf_at_bytes = BITS_TO_BYTES_FLOOR(buf_at_from_addr(bfcr));
827 BT_ASSERT_DBG(bfcr->buf.addr);
828 first_chr = &bfcr->buf.addr[buf_at_bytes];
829 result = memchr(first_chr, '\0', available_bytes);
830
831 if (begin && bfcr->user.cbs.classes.string_begin) {
832 BT_COMP_LOGT("Calling user function (string, beginning).");
833 status = bfcr->user.cbs.classes.string_begin(
834 bfcr->cur_basic_field_class, bfcr->user.data);
835 BT_COMP_LOGT("User function returned: status=%s",
836 bt_bfcr_status_string(status));
837 if (status != BT_BFCR_STATUS_OK) {
838 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s",
839 bfcr, bt_bfcr_status_string(status));
840 goto end;
841 }
842 }
843
844 if (!result) {
845 /* No null character yet */
846 if (bfcr->user.cbs.classes.string) {
847 BT_COMP_LOGT("Calling user function (substring).");
848 status = bfcr->user.cbs.classes.string(
849 (const char *) first_chr,
850 available_bytes, bfcr->cur_basic_field_class,
851 bfcr->user.data);
852 BT_COMP_LOGT("User function returned: status=%s",
853 bt_bfcr_status_string(status));
854 if (status != BT_BFCR_STATUS_OK) {
855 BT_COMP_LOGW("User function failed: "
856 "bfcr-addr=%p, status=%s",
857 bfcr, bt_bfcr_status_string(status));
858 goto end;
859 }
860 }
861
862 consume_bits(bfcr, BYTES_TO_BITS(available_bytes));
863 bfcr->state = BFCR_STATE_READ_BASIC_CONTINUE;
864 status = BT_BFCR_STATUS_EOF;
865 } else {
866 /* Found the null character */
867 size_t result_len = (size_t) (result - first_chr);
868
869 if (bfcr->user.cbs.classes.string && result_len) {
870 BT_COMP_LOGT("Calling user function (substring).");
871 status = bfcr->user.cbs.classes.string(
872 (const char *) first_chr,
873 result_len, bfcr->cur_basic_field_class,
874 bfcr->user.data);
875 BT_COMP_LOGT("User function returned: status=%s",
876 bt_bfcr_status_string(status));
877 if (status != BT_BFCR_STATUS_OK) {
878 BT_COMP_LOGW("User function failed: "
879 "bfcr-addr=%p, status=%s",
880 bfcr, bt_bfcr_status_string(status));
881 goto end;
882 }
883 }
884
885 if (bfcr->user.cbs.classes.string_end) {
886 BT_COMP_LOGT("Calling user function (string, end).");
887 status = bfcr->user.cbs.classes.string_end(
888 bfcr->cur_basic_field_class, bfcr->user.data);
889 BT_COMP_LOGT("User function returned: status=%s",
890 bt_bfcr_status_string(status));
891 if (status != BT_BFCR_STATUS_OK) {
892 BT_COMP_LOGW("User function failed: "
893 "bfcr-addr=%p, status=%s",
894 bfcr, bt_bfcr_status_string(status));
895 goto end;
896 }
897 }
898
899 consume_bits(bfcr, BYTES_TO_BITS(result_len + 1));
900
901 if (stack_empty(bfcr->stack)) {
902 /* Root is a basic class */
903 bfcr->state = BFCR_STATE_DONE;
904 } else {
905 /* Go to next field */
906 stack_top(bfcr->stack)->index++;
907 bfcr->state = BFCR_STATE_NEXT_FIELD;
908 bfcr->last_bo = bfcr->cur_bo;
909 }
910 }
911
912 end:
913 return status;
914 }
915
916 static inline
917 enum bt_bfcr_status read_basic_begin_state(struct bt_bfcr *bfcr)
918 {
919 enum bt_bfcr_status status;
920
921 BT_ASSERT_DBG(bfcr->cur_basic_field_class);
922
923 switch (bfcr->cur_basic_field_class->type) {
924 case CTF_FIELD_CLASS_TYPE_INT:
925 case CTF_FIELD_CLASS_TYPE_ENUM:
926 status = read_basic_int_class_and_call_begin(bfcr);
927 break;
928 case CTF_FIELD_CLASS_TYPE_FLOAT:
929 status = read_basic_float_class_and_call_begin(bfcr);
930 break;
931 case CTF_FIELD_CLASS_TYPE_STRING:
932 status = read_basic_string_class_and_call(bfcr, true);
933 break;
934 default:
935 bt_common_abort();
936 }
937
938 return status;
939 }
940
941 static inline
942 enum bt_bfcr_status read_basic_continue_state(struct bt_bfcr *bfcr)
943 {
944 enum bt_bfcr_status status;
945
946 BT_ASSERT_DBG(bfcr->cur_basic_field_class);
947
948 switch (bfcr->cur_basic_field_class->type) {
949 case CTF_FIELD_CLASS_TYPE_INT:
950 case CTF_FIELD_CLASS_TYPE_ENUM:
951 status = read_basic_int_class_and_call_continue(bfcr);
952 break;
953 case CTF_FIELD_CLASS_TYPE_FLOAT:
954 status = read_basic_float_class_and_call_continue(bfcr);
955 break;
956 case CTF_FIELD_CLASS_TYPE_STRING:
957 status = read_basic_string_class_and_call(bfcr, false);
958 break;
959 default:
960 bt_common_abort();
961 }
962
963 return status;
964 }
965
966 static inline
967 size_t bits_to_skip_to_align_to(struct bt_bfcr *bfcr, size_t align)
968 {
969 size_t aligned_packet_at;
970
971 aligned_packet_at = BT_ALIGN(packet_at(bfcr), align);
972 return aligned_packet_at - packet_at(bfcr);
973 }
974
975 static inline
976 enum bt_bfcr_status align_class_state(struct bt_bfcr *bfcr,
977 struct ctf_field_class *field_class, enum bfcr_state next_state)
978 {
979 unsigned int field_alignment;
980 size_t skip_bits;
981 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
982
983 /* Get field's alignment */
984 field_alignment = field_class->alignment;
985
986 /*
987 * 0 means "undefined" for variants; what we really want is 1
988 * (always aligned)
989 */
990 BT_ASSERT_DBG(field_alignment >= 1);
991
992 /* Compute how many bits we need to skip */
993 skip_bits = bits_to_skip_to_align_to(bfcr, (size_t) field_alignment);
994
995 /* Nothing to skip? aligned */
996 if (skip_bits == 0) {
997 bfcr->state = next_state;
998 goto end;
999 }
1000
1001 /* Make sure there's at least one bit left */
1002 if (!at_least_one_bit_left(bfcr)) {
1003 status = BT_BFCR_STATUS_EOF;
1004 goto end;
1005 }
1006
1007 /* Consume as many bits as possible in what's left */
1008 consume_bits(bfcr, MIN(available_bits(bfcr), skip_bits));
1009
1010 /* Are we done now? */
1011 skip_bits = bits_to_skip_to_align_to(bfcr, field_alignment);
1012 if (skip_bits == 0) {
1013 /* Yes: go to next state */
1014 bfcr->state = next_state;
1015 goto end;
1016 } else {
1017 /* No: need more data */
1018 BT_COMP_LOGT("Reached end of data when aligning: bfcr-addr=%p", bfcr);
1019 status = BT_BFCR_STATUS_EOF;
1020 }
1021
1022 end:
1023 return status;
1024 }
1025
1026 static inline
1027 enum bt_bfcr_status next_field_state(struct bt_bfcr *bfcr)
1028 {
1029 int ret;
1030 struct stack_entry *top;
1031 struct ctf_field_class *next_field_class = NULL;
1032 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
1033
1034 if (stack_empty(bfcr->stack)) {
1035 goto end;
1036 }
1037
1038 top = stack_top(bfcr->stack);
1039
1040 /* Are we done with this base class? */
1041 while (top->index == top->base_len) {
1042 if (bfcr->user.cbs.classes.compound_end) {
1043 BT_COMP_LOGT("Calling user function (compound, end).");
1044 status = bfcr->user.cbs.classes.compound_end(
1045 top->base_class, bfcr->user.data);
1046 BT_COMP_LOGT("User function returned: status=%s",
1047 bt_bfcr_status_string(status));
1048 if (status != BT_BFCR_STATUS_OK) {
1049 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s",
1050 bfcr, bt_bfcr_status_string(status));
1051 goto end;
1052 }
1053 }
1054
1055 stack_pop(bfcr->stack);
1056
1057 /* Are we done with the root class? */
1058 if (stack_empty(bfcr->stack)) {
1059 bfcr->state = BFCR_STATE_DONE;
1060 goto end;
1061 }
1062
1063 top = stack_top(bfcr->stack);
1064 top->index++;
1065 }
1066
1067 /* Get next field's class */
1068 switch (top->base_class->type) {
1069 case CTF_FIELD_CLASS_TYPE_STRUCT:
1070 next_field_class = ctf_field_class_struct_borrow_member_by_index(
1071 (void *) top->base_class, (uint64_t) top->index)->fc;
1072 break;
1073 case CTF_FIELD_CLASS_TYPE_ARRAY:
1074 case CTF_FIELD_CLASS_TYPE_SEQUENCE:
1075 {
1076 struct ctf_field_class_array_base *array_fc =
1077 (void *) top->base_class;
1078
1079 next_field_class = array_fc->elem_fc;
1080 break;
1081 }
1082 case CTF_FIELD_CLASS_TYPE_VARIANT:
1083 /* Variant classes are dynamic: the user should know! */
1084 next_field_class =
1085 bfcr->user.cbs.query.borrow_variant_selected_field_class(
1086 top->base_class, bfcr->user.data);
1087 break;
1088 default:
1089 break;
1090 }
1091
1092 if (!next_field_class) {
1093 BT_COMP_LOGW("Cannot get the field class of the next field: "
1094 "bfcr-addr=%p, base-fc-addr=%p, base-fc-type=%d, "
1095 "index=%" PRId64,
1096 bfcr, top->base_class, top->base_class->type,
1097 top->index);
1098 status = BT_BFCR_STATUS_ERROR;
1099 goto end;
1100 }
1101
1102 if (next_field_class->is_compound) {
1103 if (bfcr->user.cbs.classes.compound_begin) {
1104 BT_COMP_LOGT("Calling user function (compound, begin).");
1105 status = bfcr->user.cbs.classes.compound_begin(
1106 next_field_class, bfcr->user.data);
1107 BT_COMP_LOGT("User function returned: status=%s",
1108 bt_bfcr_status_string(status));
1109 if (status != BT_BFCR_STATUS_OK) {
1110 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s",
1111 bfcr, bt_bfcr_status_string(status));
1112 goto end;
1113 }
1114 }
1115
1116 ret = stack_push_with_len(bfcr, next_field_class);
1117 if (ret) {
1118 /* stack_push_with_len() logs errors */
1119 status = BT_BFCR_STATUS_ERROR;
1120 goto end;
1121 }
1122
1123 /* Next state: align a compound class */
1124 bfcr->state = BFCR_STATE_ALIGN_COMPOUND;
1125 } else {
1126 /* Replace current basic field class */
1127 BT_COMP_LOGT("Replacing current basic field class: "
1128 "bfcr-addr=%p, cur-basic-fc-addr=%p, "
1129 "next-basic-fc-addr=%p",
1130 bfcr, bfcr->cur_basic_field_class, next_field_class);
1131 bfcr->cur_basic_field_class = next_field_class;
1132
1133 /* Next state: align a basic class */
1134 bfcr->state = BFCR_STATE_ALIGN_BASIC;
1135 }
1136
1137 end:
1138 return status;
1139 }
1140
1141 static inline
1142 enum bt_bfcr_status handle_state(struct bt_bfcr *bfcr)
1143 {
1144 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
1145
1146 BT_COMP_LOGT("Handling state: bfcr-addr=%p, state=%s",
1147 bfcr, bfcr_state_string(bfcr->state));
1148
1149 switch (bfcr->state) {
1150 case BFCR_STATE_NEXT_FIELD:
1151 status = next_field_state(bfcr);
1152 break;
1153 case BFCR_STATE_ALIGN_BASIC:
1154 status = align_class_state(bfcr, bfcr->cur_basic_field_class,
1155 BFCR_STATE_READ_BASIC_BEGIN);
1156 break;
1157 case BFCR_STATE_ALIGN_COMPOUND:
1158 status = align_class_state(bfcr, stack_top(bfcr->stack)->base_class,
1159 BFCR_STATE_NEXT_FIELD);
1160 break;
1161 case BFCR_STATE_READ_BASIC_BEGIN:
1162 status = read_basic_begin_state(bfcr);
1163 break;
1164 case BFCR_STATE_READ_BASIC_CONTINUE:
1165 status = read_basic_continue_state(bfcr);
1166 break;
1167 case BFCR_STATE_DONE:
1168 break;
1169 }
1170
1171 BT_COMP_LOGT("Handled state: bfcr-addr=%p, status=%s",
1172 bfcr, bt_bfcr_status_string(status));
1173 return status;
1174 }
1175
1176 BT_HIDDEN
1177 struct bt_bfcr *bt_bfcr_create(struct bt_bfcr_cbs cbs, void *data,
1178 bt_logging_level log_level, bt_self_component *self_comp)
1179 {
1180 struct bt_bfcr *bfcr;
1181
1182 BT_COMP_LOG_CUR_LVL(BT_LOG_DEBUG, log_level, self_comp,
1183 "Creating binary field class reader (BFCR).");
1184 bfcr = g_new0(struct bt_bfcr, 1);
1185 if (!bfcr) {
1186 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_comp,
1187 "Failed to allocate one binary class reader.");
1188 goto end;
1189 }
1190
1191 bfcr->log_level = log_level;
1192 bfcr->self_comp = self_comp;
1193 bfcr->stack = stack_new(bfcr);
1194 if (!bfcr->stack) {
1195 BT_COMP_LOGE_STR("Cannot create BFCR's stack.");
1196 bt_bfcr_destroy(bfcr);
1197 bfcr = NULL;
1198 goto end;
1199 }
1200
1201 bfcr->state = BFCR_STATE_NEXT_FIELD;
1202 bfcr->user.cbs = cbs;
1203 bfcr->user.data = data;
1204 BT_COMP_LOGD("Created BFCR: addr=%p", bfcr);
1205
1206 end:
1207 return bfcr;
1208 }
1209
1210 BT_HIDDEN
1211 void bt_bfcr_destroy(struct bt_bfcr *bfcr)
1212 {
1213 if (bfcr->stack) {
1214 stack_destroy(bfcr->stack);
1215 }
1216
1217 BT_COMP_LOGD("Destroying BFCR: addr=%p", bfcr);
1218 g_free(bfcr);
1219 }
1220
1221 static
1222 void reset(struct bt_bfcr *bfcr)
1223 {
1224 BT_COMP_LOGD("Resetting BFCR: addr=%p", bfcr);
1225 stack_clear(bfcr->stack);
1226 stitch_reset(bfcr);
1227 bfcr->buf.addr = NULL;
1228 bfcr->last_bo = CTF_BYTE_ORDER_UNKNOWN;
1229 }
1230
1231 static
1232 void update_packet_offset(struct bt_bfcr *bfcr)
1233 {
1234 BT_COMP_LOGT("Updating packet offset for next call: "
1235 "bfcr-addr=%p, cur-packet-offset=%zu, next-packet-offset=%zu",
1236 bfcr, bfcr->buf.packet_offset,
1237 bfcr->buf.packet_offset + bfcr->buf.at);
1238 bfcr->buf.packet_offset += bfcr->buf.at;
1239 }
1240
1241 BT_HIDDEN
1242 size_t bt_bfcr_start(struct bt_bfcr *bfcr,
1243 struct ctf_field_class *cls, const uint8_t *buf,
1244 size_t offset, size_t packet_offset, size_t sz,
1245 enum bt_bfcr_status *status)
1246 {
1247 BT_ASSERT_DBG(bfcr);
1248 BT_ASSERT_DBG(BYTES_TO_BITS(sz) >= offset);
1249 reset(bfcr);
1250 bfcr->buf.addr = buf;
1251 bfcr->buf.offset = offset;
1252 bfcr->buf.at = 0;
1253 bfcr->buf.packet_offset = packet_offset;
1254 bfcr->buf.buf_sz = sz;
1255 bfcr->buf.sz = BYTES_TO_BITS(sz) - offset;
1256 *status = BT_BFCR_STATUS_OK;
1257
1258 BT_COMP_LOGT("Starting decoding: bfcr-addr=%p, fc-addr=%p, "
1259 "buf-addr=%p, buf-size=%zu, offset=%zu, "
1260 "packet-offset=%zu",
1261 bfcr, cls, buf, sz, offset, packet_offset);
1262
1263 /* Set root class */
1264 if (cls->is_compound) {
1265 /* Compound class: push on visit stack */
1266 int stack_ret;
1267
1268 if (bfcr->user.cbs.classes.compound_begin) {
1269 BT_COMP_LOGT("Calling user function (compound, begin).");
1270 *status = bfcr->user.cbs.classes.compound_begin(
1271 cls, bfcr->user.data);
1272 BT_COMP_LOGT("User function returned: status=%s",
1273 bt_bfcr_status_string(*status));
1274 if (*status != BT_BFCR_STATUS_OK) {
1275 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s",
1276 bfcr, bt_bfcr_status_string(*status));
1277 goto end;
1278 }
1279 }
1280
1281 stack_ret = stack_push_with_len(bfcr, cls);
1282 if (stack_ret) {
1283 /* stack_push_with_len() logs errors */
1284 *status = BT_BFCR_STATUS_ERROR;
1285 goto end;
1286 }
1287
1288 bfcr->state = BFCR_STATE_ALIGN_COMPOUND;
1289 } else {
1290 /* Basic class: set as current basic class */
1291 bfcr->cur_basic_field_class = cls;
1292 bfcr->state = BFCR_STATE_ALIGN_BASIC;
1293 }
1294
1295 /* Run the machine! */
1296 BT_COMP_LOGT_STR("Running the state machine.");
1297
1298 while (true) {
1299 *status = handle_state(bfcr);
1300 if (*status != BT_BFCR_STATUS_OK ||
1301 bfcr->state == BFCR_STATE_DONE) {
1302 break;
1303 }
1304 }
1305
1306 /* Update packet offset for next time */
1307 update_packet_offset(bfcr);
1308
1309 end:
1310 return bfcr->buf.at;
1311 }
1312
1313 BT_HIDDEN
1314 size_t bt_bfcr_continue(struct bt_bfcr *bfcr, const uint8_t *buf, size_t sz,
1315 enum bt_bfcr_status *status)
1316 {
1317 BT_ASSERT_DBG(bfcr);
1318 BT_ASSERT_DBG(buf);
1319 BT_ASSERT_DBG(sz > 0);
1320 bfcr->buf.addr = buf;
1321 bfcr->buf.offset = 0;
1322 bfcr->buf.at = 0;
1323 bfcr->buf.buf_sz = sz;
1324 bfcr->buf.sz = BYTES_TO_BITS(sz);
1325 *status = BT_BFCR_STATUS_OK;
1326
1327 BT_COMP_LOGT("Continuing decoding: bfcr-addr=%p, buf-addr=%p, buf-size=%zu",
1328 bfcr, buf, sz);
1329
1330 /* Continue running the machine */
1331 BT_COMP_LOGT_STR("Running the state machine.");
1332
1333 while (true) {
1334 *status = handle_state(bfcr);
1335 if (*status != BT_BFCR_STATUS_OK ||
1336 bfcr->state == BFCR_STATE_DONE) {
1337 break;
1338 }
1339 }
1340
1341 /* Update packet offset for next time */
1342 update_packet_offset(bfcr);
1343 return bfcr->buf.at;
1344 }
1345
1346 BT_HIDDEN
1347 void bt_bfcr_set_unsigned_int_cb(struct bt_bfcr *bfcr,
1348 bt_bfcr_unsigned_int_cb_func cb)
1349 {
1350 BT_ASSERT_DBG(bfcr);
1351 BT_ASSERT_DBG(cb);
1352 bfcr->user.cbs.classes.unsigned_int = cb;
1353 }
This page took 0.09749 seconds and 4 git commands to generate.