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