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