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