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