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