Enforce ABI size checks
[libside.git] / src / tracer.c
1 // SPDX-License-Identifier: MIT
2 /*
3 * Copyright 2022 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 */
5
6 #include <stdint.h>
7 #include <inttypes.h>
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <stdbool.h>
11 #include <string.h>
12 #include <iconv.h>
13
14 #include <side/trace.h>
15
16 enum tracer_display_base {
17 TRACER_DISPLAY_BASE_2,
18 TRACER_DISPLAY_BASE_8,
19 TRACER_DISPLAY_BASE_10,
20 TRACER_DISPLAY_BASE_16,
21 };
22
23 union int64_value {
24 uint64_t u;
25 int64_t s;
26 };
27
28 static struct side_tracer_handle *tracer_handle;
29
30 static
31 void tracer_print_struct(const struct side_type *type_desc, const struct side_arg_vec *side_arg_vec);
32 static
33 void tracer_print_variant(const struct side_type *type_desc, const struct side_arg_variant *side_arg_variant);
34 static
35 void tracer_print_array(const struct side_type *type_desc, const struct side_arg_vec *side_arg_vec);
36 static
37 void tracer_print_vla(const struct side_type *type_desc, const struct side_arg_vec *side_arg_vec);
38 static
39 void tracer_print_vla_visitor(const struct side_type *type_desc, void *app_ctx);
40 static
41 void tracer_print_dynamic(const struct side_arg *dynamic_item);
42 static
43 uint32_t tracer_print_gather_bool_type(const struct side_type_gather *type_gather, const void *_ptr);
44 static
45 uint32_t tracer_print_gather_byte_type(const struct side_type_gather *type_gather, const void *_ptr);
46 static
47 uint32_t tracer_print_gather_integer_type(const struct side_type_gather *type_gather, const void *_ptr,
48 enum tracer_display_base default_base);
49 static
50 uint32_t tracer_print_gather_float_type(const struct side_type_gather *type_gather, const void *_ptr);
51 static
52 uint32_t tracer_print_gather_string_type(const struct side_type_gather *type_gather, const void *_ptr);
53 static
54 uint32_t tracer_print_gather_enum_type(const struct side_type_gather *type_gather, const void *_ptr);
55 static
56 uint32_t tracer_print_gather_struct(const struct side_type_gather *type_gather, const void *_ptr);
57 static
58 uint32_t tracer_print_gather_array(const struct side_type_gather *type_gather, const void *_ptr);
59 static
60 uint32_t tracer_print_gather_vla(const struct side_type_gather *type_gather, const void *_ptr,
61 const void *_length_ptr);
62 static
63 void tracer_print_type(const struct side_type *type_desc, const struct side_arg *item);
64
65 static
66 void tracer_convert_string_to_utf8(const void *p, uint8_t unit_size, enum side_type_label_byte_order byte_order,
67 size_t *strlen_with_null,
68 char **output_str)
69 {
70 size_t ret, inbytesleft = 0, outbytesleft, bufsize;
71 const char *str = p, *fromcode;
72 char *inbuf = (char *) p, *outbuf, *buf;
73 iconv_t cd;
74
75 switch (unit_size) {
76 case 1:
77 if (strlen_with_null)
78 *strlen_with_null = strlen(str) + 1;
79 *output_str = (char *) str;
80 return;
81 case 2:
82 {
83 const uint16_t *p16 = p;
84
85 switch (byte_order) {
86 case SIDE_TYPE_BYTE_ORDER_LE:
87 {
88 fromcode = "UTF-16LE";
89 break;
90 }
91 case SIDE_TYPE_BYTE_ORDER_BE:
92 {
93 fromcode = "UTF-16BE";
94 break;
95 }
96 default:
97 fprintf(stderr, "Unknown byte order\n");
98 abort();
99 }
100 for (; *p16; p16++)
101 inbytesleft += 2;
102 /*
103 * Worse case is U+FFFF UTF-16 (2 bytes) converting to
104 * { ef, bf, bf } UTF-8 (3 bytes).
105 */
106 bufsize = inbytesleft / 2 * 3 + 1;
107 break;
108 }
109 case 4:
110 {
111 const uint32_t *p32 = p;
112
113 switch (byte_order) {
114 case SIDE_TYPE_BYTE_ORDER_LE:
115 {
116 fromcode = "UTF-32LE";
117 break;
118 }
119 case SIDE_TYPE_BYTE_ORDER_BE:
120 {
121 fromcode = "UTF-32BE";
122 break;
123 }
124 default:
125 fprintf(stderr, "Unknown byte order\n");
126 abort();
127 }
128 for (; *p32; p32++)
129 inbytesleft += 4;
130 /*
131 * Each 4-byte UTF-32 character converts to at most a
132 * 4-byte UTF-8 character.
133 */
134 bufsize = inbytesleft + 1;
135 break;
136 }
137 default:
138 fprintf(stderr, "Unknown string unit size %" PRIu8 "\n", unit_size);
139 abort();
140 }
141
142 cd = iconv_open("UTF8", fromcode);
143 if (cd == (iconv_t) -1) {
144 perror("iconv_open");
145 abort();
146 }
147 buf = malloc(bufsize);
148 if (!buf) {
149 abort();
150 }
151 outbuf = (char *) buf;
152 outbytesleft = bufsize;
153 ret = iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
154 if (ret == (size_t) -1) {
155 perror("iconv");
156 abort();
157 }
158 if (inbytesleft) {
159 fprintf(stderr, "Buffer too small to convert string input\n");
160 abort();
161 }
162 (*outbuf++) = '\0';
163 if (iconv_close(cd) == -1) {
164 perror("iconv_close");
165 abort();
166 }
167 if (strlen_with_null)
168 *strlen_with_null = outbuf - buf;
169 *output_str = buf;
170 }
171
172 static
173 void tracer_print_string(const void *p, uint8_t unit_size, enum side_type_label_byte_order byte_order,
174 size_t *strlen_with_null)
175 {
176 char *output_str = NULL;
177
178 tracer_convert_string_to_utf8(p, unit_size, byte_order, strlen_with_null, &output_str);
179 printf("\"%s\"", output_str);
180 if (output_str != p)
181 free(output_str);
182 }
183
184 static
185 int64_t get_attr_integer_value(const struct side_attr *attr)
186 {
187 int64_t val;
188
189 switch (side_enum_get(attr->value.type)) {
190 case SIDE_ATTR_TYPE_U8:
191 val = attr->value.u.integer_value.side_u8;
192 break;
193 case SIDE_ATTR_TYPE_U16:
194 val = attr->value.u.integer_value.side_u16;
195 break;
196 case SIDE_ATTR_TYPE_U32:
197 val = attr->value.u.integer_value.side_u32;
198 break;
199 case SIDE_ATTR_TYPE_U64:
200 val = attr->value.u.integer_value.side_u64;
201 break;
202 case SIDE_ATTR_TYPE_S8:
203 val = attr->value.u.integer_value.side_s8;
204 break;
205 case SIDE_ATTR_TYPE_S16:
206 val = attr->value.u.integer_value.side_s16;
207 break;
208 case SIDE_ATTR_TYPE_S32:
209 val = attr->value.u.integer_value.side_s32;
210 break;
211 case SIDE_ATTR_TYPE_S64:
212 val = attr->value.u.integer_value.side_s64;
213 break;
214 default:
215 fprintf(stderr, "Unexpected attribute type\n");
216 abort();
217 }
218 return val;
219 }
220
221 static
222 enum tracer_display_base get_attr_display_base(const struct side_attr *_attr, uint32_t nr_attr,
223 enum tracer_display_base default_base)
224 {
225 uint32_t i;
226
227 for (i = 0; i < nr_attr; i++) {
228 const struct side_attr *attr = &_attr[i];
229 char *utf8_str = NULL;
230 bool cmp;
231
232 tracer_convert_string_to_utf8(side_ptr_get(attr->key.p), attr->key.unit_size,
233 side_enum_get(attr->key.byte_order), NULL, &utf8_str);
234 cmp = strcmp(utf8_str, "std.integer.base");
235 if (utf8_str != side_ptr_get(attr->key.p))
236 free(utf8_str);
237 if (!cmp) {
238 int64_t val = get_attr_integer_value(attr);
239
240 switch (val) {
241 case 2:
242 return TRACER_DISPLAY_BASE_2;
243 case 8:
244 return TRACER_DISPLAY_BASE_8;
245 case 10:
246 return TRACER_DISPLAY_BASE_10;
247 case 16:
248 return TRACER_DISPLAY_BASE_16;
249 default:
250 fprintf(stderr, "Unexpected integer display base: %" PRId64 "\n", val);
251 abort();
252 }
253 }
254 }
255 return default_base; /* Default */
256 }
257
258 static
259 void tracer_print_attr_type(const char *separator, const struct side_attr *attr)
260 {
261 char *utf8_str = NULL;
262
263 tracer_convert_string_to_utf8(side_ptr_get(attr->key.p), attr->key.unit_size,
264 side_enum_get(attr->key.byte_order), NULL, &utf8_str);
265 printf("{ key%s \"%s\", value%s ", separator, utf8_str, separator);
266 if (utf8_str != side_ptr_get(attr->key.p))
267 free(utf8_str);
268 switch (side_enum_get(attr->value.type)) {
269 case SIDE_ATTR_TYPE_BOOL:
270 printf("%s", attr->value.u.bool_value ? "true" : "false");
271 break;
272 case SIDE_ATTR_TYPE_U8:
273 printf("%" PRIu8, attr->value.u.integer_value.side_u8);
274 break;
275 case SIDE_ATTR_TYPE_U16:
276 printf("%" PRIu16, attr->value.u.integer_value.side_u16);
277 break;
278 case SIDE_ATTR_TYPE_U32:
279 printf("%" PRIu32, attr->value.u.integer_value.side_u32);
280 break;
281 case SIDE_ATTR_TYPE_U64:
282 printf("%" PRIu64, attr->value.u.integer_value.side_u64);
283 break;
284 case SIDE_ATTR_TYPE_S8:
285 printf("%" PRId8, attr->value.u.integer_value.side_s8);
286 break;
287 case SIDE_ATTR_TYPE_S16:
288 printf("%" PRId16, attr->value.u.integer_value.side_s16);
289 break;
290 case SIDE_ATTR_TYPE_S32:
291 printf("%" PRId32, attr->value.u.integer_value.side_s32);
292 break;
293 case SIDE_ATTR_TYPE_S64:
294 printf("%" PRId64, attr->value.u.integer_value.side_s64);
295 break;
296 case SIDE_ATTR_TYPE_FLOAT_BINARY16:
297 #if __HAVE_FLOAT16
298 printf("%g", (double) attr->value.u.float_value.side_float_binary16);
299 break;
300 #else
301 fprintf(stderr, "ERROR: Unsupported binary16 float type\n");
302 abort();
303 #endif
304 case SIDE_ATTR_TYPE_FLOAT_BINARY32:
305 #if __HAVE_FLOAT32
306 printf("%g", (double) attr->value.u.float_value.side_float_binary32);
307 break;
308 #else
309 fprintf(stderr, "ERROR: Unsupported binary32 float type\n");
310 abort();
311 #endif
312 case SIDE_ATTR_TYPE_FLOAT_BINARY64:
313 #if __HAVE_FLOAT64
314 printf("%g", (double) attr->value.u.float_value.side_float_binary64);
315 break;
316 #else
317 fprintf(stderr, "ERROR: Unsupported binary64 float type\n");
318 abort();
319 #endif
320 case SIDE_ATTR_TYPE_FLOAT_BINARY128:
321 #if __HAVE_FLOAT128
322 printf("%Lg", (long double) attr->value.u.float_value.side_float_binary128);
323 break;
324 #else
325 fprintf(stderr, "ERROR: Unsupported binary128 float type\n");
326 abort();
327 #endif
328 case SIDE_ATTR_TYPE_STRING:
329 tracer_print_string(side_ptr_get(attr->value.u.string_value.p),
330 attr->value.u.string_value.unit_size,
331 side_enum_get(attr->value.u.string_value.byte_order), NULL);
332 break;
333 default:
334 fprintf(stderr, "ERROR: <UNKNOWN ATTRIBUTE TYPE>");
335 abort();
336 }
337 printf(" }");
338 }
339
340 static
341 void print_attributes(const char *prefix_str, const char *separator,
342 const struct side_attr *attr, uint32_t nr_attr)
343 {
344 uint32_t i;
345
346 if (!nr_attr)
347 return;
348 printf("%s%s [ ", prefix_str, separator);
349 for (i = 0; i < nr_attr; i++) {
350 printf("%s", i ? ", " : "");
351 tracer_print_attr_type(separator, &attr[i]);
352 }
353 printf(" ]");
354 }
355
356 static
357 union int64_value tracer_load_integer_value(const struct side_type_integer *type_integer,
358 const union side_integer_value *value,
359 uint16_t offset_bits, uint16_t *_len_bits)
360 {
361 union int64_value v64;
362 uint16_t len_bits;
363 bool reverse_bo;
364
365 if (!type_integer->len_bits)
366 len_bits = type_integer->integer_size * CHAR_BIT;
367 else
368 len_bits = type_integer->len_bits;
369 if (len_bits + offset_bits > type_integer->integer_size * CHAR_BIT)
370 abort();
371 reverse_bo = side_enum_get(type_integer->byte_order) != SIDE_TYPE_BYTE_ORDER_HOST;
372 switch (type_integer->integer_size) {
373 case 1:
374 if (type_integer->signedness)
375 v64.s = value->side_s8;
376 else
377 v64.u = value->side_u8;
378 break;
379 case 2:
380 if (type_integer->signedness) {
381 int16_t side_s16;
382
383 side_s16 = value->side_s16;
384 if (reverse_bo)
385 side_s16 = side_bswap_16(side_s16);
386 v64.s = side_s16;
387 } else {
388 uint16_t side_u16;
389
390 side_u16 = value->side_u16;
391 if (reverse_bo)
392 side_u16 = side_bswap_16(side_u16);
393 v64.u = side_u16;
394 }
395 break;
396 case 4:
397 if (type_integer->signedness) {
398 int32_t side_s32;
399
400 side_s32 = value->side_s32;
401 if (reverse_bo)
402 side_s32 = side_bswap_32(side_s32);
403 v64.s = side_s32;
404 } else {
405 uint32_t side_u32;
406
407 side_u32 = value->side_u32;
408 if (reverse_bo)
409 side_u32 = side_bswap_32(side_u32);
410 v64.u = side_u32;
411 }
412 break;
413 case 8:
414 if (type_integer->signedness) {
415 int64_t side_s64;
416
417 side_s64 = value->side_s64;
418 if (reverse_bo)
419 side_s64 = side_bswap_64(side_s64);
420 v64.s = side_s64;
421 } else {
422 uint64_t side_u64;
423
424 side_u64 = value->side_u64;
425 if (reverse_bo)
426 side_u64 = side_bswap_64(side_u64);
427 v64.u = side_u64;
428 }
429 break;
430 default:
431 abort();
432 }
433 v64.u >>= offset_bits;
434 if (len_bits < 64) {
435 v64.u &= (1ULL << len_bits) - 1;
436 if (type_integer->signedness) {
437 /* Sign-extend. */
438 if (v64.u & (1ULL << (len_bits - 1)))
439 v64.u |= ~((1ULL << len_bits) - 1);
440 }
441 }
442 if (_len_bits)
443 *_len_bits = len_bits;
444 return v64;
445 }
446
447 static
448 void print_enum_labels(const struct side_enum_mappings *mappings, union int64_value v64)
449 {
450 uint32_t i, print_count = 0;
451
452 printf(", labels: [ ");
453 for (i = 0; i < mappings->nr_mappings; i++) {
454 const struct side_enum_mapping *mapping = &side_ptr_get(mappings->mappings)[i];
455
456 if (mapping->range_end < mapping->range_begin) {
457 fprintf(stderr, "ERROR: Unexpected enum range: %" PRIu64 "-%" PRIu64 "\n",
458 mapping->range_begin, mapping->range_end);
459 abort();
460 }
461 if (v64.s >= mapping->range_begin && v64.s <= mapping->range_end) {
462 printf("%s", print_count++ ? ", " : "");
463 tracer_print_string(side_ptr_get(mapping->label.p), mapping->label.unit_size,
464 side_enum_get(mapping->label.byte_order), NULL);
465 }
466 }
467 if (!print_count)
468 printf("<NO LABEL>");
469 printf(" ]");
470 }
471
472 static
473 void tracer_print_enum(const struct side_type *type_desc, const struct side_arg *item)
474 {
475 const struct side_enum_mappings *mappings = side_ptr_get(type_desc->u.side_enum.mappings);
476 const struct side_type *elem_type = side_ptr_get(type_desc->u.side_enum.elem_type);
477 union int64_value v64;
478
479 if (side_enum_get(elem_type->type) != side_enum_get(item->type)) {
480 fprintf(stderr, "ERROR: Unexpected enum element type\n");
481 abort();
482 }
483 v64 = tracer_load_integer_value(&elem_type->u.side_integer,
484 &item->u.side_static.integer_value, 0, NULL);
485 print_attributes("attr", ":", side_ptr_get(mappings->attr), mappings->nr_attr);
486 printf("%s", mappings->nr_attr ? ", " : "");
487 tracer_print_type(elem_type, item);
488 print_enum_labels(mappings, v64);
489 }
490
491 static
492 uint32_t elem_type_to_stride(const struct side_type *elem_type)
493 {
494 uint32_t stride_bit;
495
496 switch (side_enum_get(elem_type->type)) {
497 case SIDE_TYPE_BYTE:
498 stride_bit = 8;
499 break;
500
501 case SIDE_TYPE_U8:
502 case SIDE_TYPE_U16:
503 case SIDE_TYPE_U32:
504 case SIDE_TYPE_U64:
505 case SIDE_TYPE_S8:
506 case SIDE_TYPE_S16:
507 case SIDE_TYPE_S32:
508 case SIDE_TYPE_S64:
509 return elem_type->u.side_integer.integer_size * CHAR_BIT;
510 default:
511 fprintf(stderr, "ERROR: Unexpected enum bitmap element type\n");
512 abort();
513 }
514 return stride_bit;
515 }
516
517 static
518 void tracer_print_enum_bitmap(const struct side_type *type_desc,
519 const struct side_arg *item)
520 {
521 const struct side_enum_bitmap_mappings *side_enum_mappings = side_ptr_get(type_desc->u.side_enum_bitmap.mappings);
522 const struct side_type *enum_elem_type = side_ptr_get(type_desc->u.side_enum_bitmap.elem_type), *elem_type;
523 uint32_t i, print_count = 0, stride_bit, nr_items;
524 const struct side_arg *array_item;
525
526 switch (side_enum_get(enum_elem_type->type)) {
527 case SIDE_TYPE_U8: /* Fall-through */
528 case SIDE_TYPE_BYTE: /* Fall-through */
529 case SIDE_TYPE_U16: /* Fall-through */
530 case SIDE_TYPE_U32: /* Fall-through */
531 case SIDE_TYPE_U64: /* Fall-through */
532 case SIDE_TYPE_S8: /* Fall-through */
533 case SIDE_TYPE_S16: /* Fall-through */
534 case SIDE_TYPE_S32: /* Fall-through */
535 case SIDE_TYPE_S64:
536 elem_type = enum_elem_type;
537 array_item = item;
538 nr_items = 1;
539 break;
540 case SIDE_TYPE_ARRAY:
541 elem_type = side_ptr_get(enum_elem_type->u.side_array.elem_type);
542 array_item = side_ptr_get(side_ptr_get(item->u.side_static.side_array)->sav);
543 nr_items = type_desc->u.side_array.length;
544 break;
545 case SIDE_TYPE_VLA:
546 elem_type = side_ptr_get(enum_elem_type->u.side_vla.elem_type);
547 array_item = side_ptr_get(side_ptr_get(item->u.side_static.side_vla)->sav);
548 nr_items = side_ptr_get(item->u.side_static.side_vla)->len;
549 break;
550 default:
551 fprintf(stderr, "ERROR: Unexpected enum element type\n");
552 abort();
553 }
554 stride_bit = elem_type_to_stride(elem_type);
555
556 print_attributes("attr", ":", side_ptr_get(side_enum_mappings->attr), side_enum_mappings->nr_attr);
557 printf("%s", side_enum_mappings->nr_attr ? ", " : "");
558 printf("labels: [ ");
559 for (i = 0; i < side_enum_mappings->nr_mappings; i++) {
560 const struct side_enum_bitmap_mapping *mapping = &side_ptr_get(side_enum_mappings->mappings)[i];
561 bool match = false;
562 uint64_t bit;
563
564 if (mapping->range_end < mapping->range_begin) {
565 fprintf(stderr, "ERROR: Unexpected enum bitmap range: %" PRIu64 "-%" PRIu64 "\n",
566 mapping->range_begin, mapping->range_end);
567 abort();
568 }
569 for (bit = mapping->range_begin; bit <= mapping->range_end; bit++) {
570 if (bit > (nr_items * stride_bit) - 1)
571 break;
572 if (side_enum_get(elem_type->type) == SIDE_TYPE_BYTE) {
573 uint8_t v = array_item[bit / 8].u.side_static.byte_value;
574 if (v & (1ULL << (bit % 8))) {
575 match = true;
576 goto match;
577 }
578 } else {
579 union int64_value v64;
580
581 v64 = tracer_load_integer_value(&elem_type->u.side_integer,
582 &array_item[bit / stride_bit].u.side_static.integer_value,
583 0, NULL);
584 if (v64.u & (1ULL << (bit % stride_bit))) {
585 match = true;
586 goto match;
587 }
588 }
589 }
590 match:
591 if (match) {
592 printf("%s", print_count++ ? ", " : "");
593 tracer_print_string(side_ptr_get(mapping->label.p), mapping->label.unit_size,
594 side_enum_get(mapping->label.byte_order), NULL);
595 }
596 }
597 if (!print_count)
598 printf("<NO LABEL>");
599 printf(" ]");
600 }
601
602 static
603 void print_integer_binary(uint64_t v, int bits)
604 {
605 int i;
606
607 printf("0b");
608 v <<= 64 - bits;
609 for (i = 0; i < bits; i++) {
610 printf("%c", v & (1ULL << 63) ? '1' : '0');
611 v <<= 1;
612 }
613 }
614
615 static
616 void tracer_print_type_header(const char *separator,
617 const struct side_attr *attr, uint32_t nr_attr)
618 {
619 print_attributes("attr", separator, attr, nr_attr);
620 printf("%s", nr_attr ? ", " : "");
621 printf("value%s ", separator);
622 }
623
624 static
625 void tracer_print_type_bool(const char *separator,
626 const struct side_type_bool *type_bool,
627 const union side_bool_value *value,
628 uint16_t offset_bits)
629 {
630 uint32_t len_bits;
631 bool reverse_bo;
632 uint64_t v;
633
634 if (!type_bool->len_bits)
635 len_bits = type_bool->bool_size * CHAR_BIT;
636 else
637 len_bits = type_bool->len_bits;
638 if (len_bits + offset_bits > type_bool->bool_size * CHAR_BIT)
639 abort();
640 reverse_bo = side_enum_get(type_bool->byte_order) != SIDE_TYPE_BYTE_ORDER_HOST;
641 switch (type_bool->bool_size) {
642 case 1:
643 v = value->side_bool8;
644 break;
645 case 2:
646 {
647 uint16_t side_u16;
648
649 side_u16 = value->side_bool16;
650 if (reverse_bo)
651 side_u16 = side_bswap_16(side_u16);
652 v = side_u16;
653 break;
654 }
655 case 4:
656 {
657 uint32_t side_u32;
658
659 side_u32 = value->side_bool32;
660 if (reverse_bo)
661 side_u32 = side_bswap_32(side_u32);
662 v = side_u32;
663 break;
664 }
665 case 8:
666 {
667 uint64_t side_u64;
668
669 side_u64 = value->side_bool64;
670 if (reverse_bo)
671 side_u64 = side_bswap_64(side_u64);
672 v = side_u64;
673 break;
674 }
675 default:
676 abort();
677 }
678 v >>= offset_bits;
679 if (len_bits < 64)
680 v &= (1ULL << len_bits) - 1;
681 tracer_print_type_header(separator, side_ptr_get(type_bool->attr), type_bool->nr_attr);
682 printf("%s", v ? "true" : "false");
683 }
684
685 static
686 void tracer_print_type_integer(const char *separator,
687 const struct side_type_integer *type_integer,
688 const union side_integer_value *value,
689 uint16_t offset_bits,
690 enum tracer_display_base default_base)
691 {
692 enum tracer_display_base base;
693 union int64_value v64;
694 uint16_t len_bits;
695
696 v64 = tracer_load_integer_value(type_integer, value, offset_bits, &len_bits);
697 tracer_print_type_header(separator, side_ptr_get(type_integer->attr), type_integer->nr_attr);
698 base = get_attr_display_base(side_ptr_get(type_integer->attr), type_integer->nr_attr, default_base);
699 switch (base) {
700 case TRACER_DISPLAY_BASE_2:
701 print_integer_binary(v64.u, len_bits);
702 break;
703 case TRACER_DISPLAY_BASE_8:
704 /* Clear sign bits beyond len_bits */
705 if (len_bits < 64)
706 v64.u &= (1ULL << len_bits) - 1;
707 printf("0%" PRIo64, v64.u);
708 break;
709 case TRACER_DISPLAY_BASE_10:
710 if (type_integer->signedness)
711 printf("%" PRId64, v64.s);
712 else
713 printf("%" PRIu64, v64.u);
714 break;
715 case TRACER_DISPLAY_BASE_16:
716 /* Clear sign bits beyond len_bits */
717 if (len_bits < 64)
718 v64.u &= (1ULL << len_bits) - 1;
719 printf("0x%" PRIx64, v64.u);
720 break;
721 default:
722 abort();
723 }
724 }
725
726 static
727 void tracer_print_type_float(const char *separator,
728 const struct side_type_float *type_float,
729 const union side_float_value *value)
730 {
731 bool reverse_bo;
732
733 tracer_print_type_header(separator, side_ptr_get(type_float->attr), type_float->nr_attr);
734 reverse_bo = side_enum_get(type_float->byte_order) != SIDE_TYPE_FLOAT_WORD_ORDER_HOST;
735 switch (type_float->float_size) {
736 case 2:
737 {
738 #if __HAVE_FLOAT16
739 union {
740 _Float16 f;
741 uint16_t u;
742 } float16 = {
743 .f = value->side_float_binary16,
744 };
745
746 if (reverse_bo)
747 float16.u = side_bswap_16(float16.u);
748 printf("%g", (double) float16.f);
749 break;
750 #else
751 fprintf(stderr, "ERROR: Unsupported binary16 float type\n");
752 abort();
753 #endif
754 }
755 case 4:
756 {
757 #if __HAVE_FLOAT32
758 union {
759 _Float32 f;
760 uint32_t u;
761 } float32 = {
762 .f = value->side_float_binary32,
763 };
764
765 if (reverse_bo)
766 float32.u = side_bswap_32(float32.u);
767 printf("%g", (double) float32.f);
768 break;
769 #else
770 fprintf(stderr, "ERROR: Unsupported binary32 float type\n");
771 abort();
772 #endif
773 }
774 case 8:
775 {
776 #if __HAVE_FLOAT64
777 union {
778 _Float64 f;
779 uint64_t u;
780 } float64 = {
781 .f = value->side_float_binary64,
782 };
783
784 if (reverse_bo)
785 float64.u = side_bswap_64(float64.u);
786 printf("%g", (double) float64.f);
787 break;
788 #else
789 fprintf(stderr, "ERROR: Unsupported binary64 float type\n");
790 abort();
791 #endif
792 }
793 case 16:
794 {
795 #if __HAVE_FLOAT128
796 union {
797 _Float128 f;
798 char arr[16];
799 } float128 = {
800 .f = value->side_float_binary128,
801 };
802
803 if (reverse_bo)
804 side_bswap_128p(float128.arr);
805 printf("%Lg", (long double) float128.f);
806 break;
807 #else
808 fprintf(stderr, "ERROR: Unsupported binary128 float type\n");
809 abort();
810 #endif
811 }
812 default:
813 fprintf(stderr, "ERROR: Unknown float size\n");
814 abort();
815 }
816 }
817
818 static
819 void tracer_print_type(const struct side_type *type_desc, const struct side_arg *item)
820 {
821 enum side_type_label type;
822
823 switch (side_enum_get(type_desc->type)) {
824 case SIDE_TYPE_ENUM:
825 switch (side_enum_get(item->type)) {
826 case SIDE_TYPE_U8:
827 case SIDE_TYPE_U16:
828 case SIDE_TYPE_U32:
829 case SIDE_TYPE_U64:
830 case SIDE_TYPE_S8:
831 case SIDE_TYPE_S16:
832 case SIDE_TYPE_S32:
833 case SIDE_TYPE_S64:
834 break;
835 default:
836 fprintf(stderr, "ERROR: type mismatch between description and arguments\n");
837 abort();
838 break;
839 }
840 break;
841
842 case SIDE_TYPE_ENUM_BITMAP:
843 switch (side_enum_get(item->type)) {
844 case SIDE_TYPE_U8:
845 case SIDE_TYPE_BYTE:
846 case SIDE_TYPE_U16:
847 case SIDE_TYPE_U32:
848 case SIDE_TYPE_U64:
849 case SIDE_TYPE_ARRAY:
850 case SIDE_TYPE_VLA:
851 break;
852 default:
853 fprintf(stderr, "ERROR: type mismatch between description and arguments\n");
854 abort();
855 break;
856 }
857 break;
858
859 case SIDE_TYPE_GATHER_ENUM:
860 switch (side_enum_get(item->type)) {
861 case SIDE_TYPE_GATHER_INTEGER:
862 break;
863 default:
864 fprintf(stderr, "ERROR: type mismatch between description and arguments\n");
865 abort();
866 break;
867 }
868 break;
869
870 case SIDE_TYPE_DYNAMIC:
871 switch (side_enum_get(item->type)) {
872 case SIDE_TYPE_DYNAMIC_NULL:
873 case SIDE_TYPE_DYNAMIC_BOOL:
874 case SIDE_TYPE_DYNAMIC_INTEGER:
875 case SIDE_TYPE_DYNAMIC_BYTE:
876 case SIDE_TYPE_DYNAMIC_POINTER:
877 case SIDE_TYPE_DYNAMIC_FLOAT:
878 case SIDE_TYPE_DYNAMIC_STRING:
879 case SIDE_TYPE_DYNAMIC_STRUCT:
880 case SIDE_TYPE_DYNAMIC_STRUCT_VISITOR:
881 case SIDE_TYPE_DYNAMIC_VLA:
882 case SIDE_TYPE_DYNAMIC_VLA_VISITOR:
883 break;
884 default:
885 fprintf(stderr, "ERROR: Unexpected dynamic type\n");
886 abort();
887 break;
888 }
889 break;
890
891 default:
892 if (side_enum_get(type_desc->type) != side_enum_get(item->type)) {
893 fprintf(stderr, "ERROR: type mismatch between description and arguments\n");
894 abort();
895 }
896 break;
897 }
898
899 if (side_enum_get(type_desc->type) == SIDE_TYPE_ENUM || side_enum_get(type_desc->type) == SIDE_TYPE_ENUM_BITMAP || side_enum_get(type_desc->type) == SIDE_TYPE_GATHER_ENUM)
900 type = side_enum_get(type_desc->type);
901 else
902 type = side_enum_get(item->type);
903
904 printf("{ ");
905 switch (type) {
906 /* Stack-copy basic types */
907 case SIDE_TYPE_NULL:
908 tracer_print_type_header(":", side_ptr_get(type_desc->u.side_null.attr),
909 type_desc->u.side_null.nr_attr);
910 printf("<NULL TYPE>");
911 break;
912
913 case SIDE_TYPE_BOOL:
914 tracer_print_type_bool(":", &type_desc->u.side_bool, &item->u.side_static.bool_value, 0);
915 break;
916
917 case SIDE_TYPE_U8:
918 case SIDE_TYPE_U16:
919 case SIDE_TYPE_U32:
920 case SIDE_TYPE_U64:
921 case SIDE_TYPE_S8:
922 case SIDE_TYPE_S16:
923 case SIDE_TYPE_S32:
924 case SIDE_TYPE_S64:
925 tracer_print_type_integer(":", &type_desc->u.side_integer, &item->u.side_static.integer_value, 0,
926 TRACER_DISPLAY_BASE_10);
927 break;
928
929 case SIDE_TYPE_BYTE:
930 tracer_print_type_header(":", side_ptr_get(type_desc->u.side_byte.attr), type_desc->u.side_byte.nr_attr);
931 printf("0x%" PRIx8, item->u.side_static.byte_value);
932 break;
933
934 case SIDE_TYPE_POINTER:
935 tracer_print_type_integer(":", &type_desc->u.side_integer, &item->u.side_static.integer_value, 0,
936 TRACER_DISPLAY_BASE_16);
937 break;
938
939 case SIDE_TYPE_FLOAT_BINARY16:
940 case SIDE_TYPE_FLOAT_BINARY32:
941 case SIDE_TYPE_FLOAT_BINARY64:
942 case SIDE_TYPE_FLOAT_BINARY128:
943 tracer_print_type_float(":", &type_desc->u.side_float, &item->u.side_static.float_value);
944 break;
945
946 case SIDE_TYPE_STRING_UTF8:
947 case SIDE_TYPE_STRING_UTF16:
948 case SIDE_TYPE_STRING_UTF32:
949 tracer_print_type_header(":", side_ptr_get(type_desc->u.side_string.attr), type_desc->u.side_string.nr_attr);
950 tracer_print_string(side_ptr_get(item->u.side_static.string_value),
951 type_desc->u.side_string.unit_size, side_enum_get(type_desc->u.side_string.byte_order), NULL);
952 break;
953
954 /* Stack-copy compound types */
955 case SIDE_TYPE_STRUCT:
956 tracer_print_struct(type_desc, side_ptr_get(item->u.side_static.side_struct));
957 break;
958 case SIDE_TYPE_VARIANT:
959 tracer_print_variant(type_desc, side_ptr_get(item->u.side_static.side_variant));
960 break;
961 case SIDE_TYPE_ARRAY:
962 tracer_print_array(type_desc, side_ptr_get(item->u.side_static.side_array));
963 break;
964 case SIDE_TYPE_VLA:
965 tracer_print_vla(type_desc, side_ptr_get(item->u.side_static.side_vla));
966 break;
967 case SIDE_TYPE_VLA_VISITOR:
968 tracer_print_vla_visitor(type_desc, item->u.side_static.side_vla_app_visitor_ctx);
969 break;
970
971 /* Stack-copy enumeration types */
972 case SIDE_TYPE_ENUM:
973 tracer_print_enum(type_desc, item);
974 break;
975 case SIDE_TYPE_ENUM_BITMAP:
976 tracer_print_enum_bitmap(type_desc, item);
977 break;
978
979 /* Gather basic types */
980 case SIDE_TYPE_GATHER_BOOL:
981 (void) tracer_print_gather_bool_type(&type_desc->u.side_gather, side_ptr_get(item->u.side_static.side_bool_gather_ptr));
982 break;
983 case SIDE_TYPE_GATHER_INTEGER:
984 (void) tracer_print_gather_integer_type(&type_desc->u.side_gather, side_ptr_get(item->u.side_static.side_integer_gather_ptr),
985 TRACER_DISPLAY_BASE_10);
986 break;
987 case SIDE_TYPE_GATHER_BYTE:
988 (void) tracer_print_gather_byte_type(&type_desc->u.side_gather, side_ptr_get(item->u.side_static.side_byte_gather_ptr));
989 break;
990 case SIDE_TYPE_GATHER_POINTER:
991 (void) tracer_print_gather_integer_type(&type_desc->u.side_gather, side_ptr_get(item->u.side_static.side_integer_gather_ptr),
992 TRACER_DISPLAY_BASE_16);
993 break;
994 case SIDE_TYPE_GATHER_FLOAT:
995 (void) tracer_print_gather_float_type(&type_desc->u.side_gather, side_ptr_get(item->u.side_static.side_float_gather_ptr));
996 break;
997 case SIDE_TYPE_GATHER_STRING:
998 (void) tracer_print_gather_string_type(&type_desc->u.side_gather, side_ptr_get(item->u.side_static.side_string_gather_ptr));
999 break;
1000
1001 /* Gather compound type */
1002 case SIDE_TYPE_GATHER_STRUCT:
1003 (void) tracer_print_gather_struct(&type_desc->u.side_gather, side_ptr_get(item->u.side_static.side_struct_gather_ptr));
1004 break;
1005 case SIDE_TYPE_GATHER_ARRAY:
1006 (void) tracer_print_gather_array(&type_desc->u.side_gather, side_ptr_get(item->u.side_static.side_array_gather_ptr));
1007 break;
1008 case SIDE_TYPE_GATHER_VLA:
1009 (void) tracer_print_gather_vla(&type_desc->u.side_gather, side_ptr_get(item->u.side_static.side_vla_gather.ptr),
1010 side_ptr_get(item->u.side_static.side_vla_gather.length_ptr));
1011 break;
1012
1013 /* Gather enumeration types */
1014 case SIDE_TYPE_GATHER_ENUM:
1015 (void) tracer_print_gather_enum_type(&type_desc->u.side_gather, side_ptr_get(item->u.side_static.side_integer_gather_ptr));
1016 break;
1017
1018 /* Dynamic basic types */
1019 case SIDE_TYPE_DYNAMIC_NULL:
1020 case SIDE_TYPE_DYNAMIC_BOOL:
1021 case SIDE_TYPE_DYNAMIC_INTEGER:
1022 case SIDE_TYPE_DYNAMIC_BYTE:
1023 case SIDE_TYPE_DYNAMIC_POINTER:
1024 case SIDE_TYPE_DYNAMIC_FLOAT:
1025 case SIDE_TYPE_DYNAMIC_STRING:
1026
1027 /* Dynamic compound types */
1028 case SIDE_TYPE_DYNAMIC_STRUCT:
1029 case SIDE_TYPE_DYNAMIC_STRUCT_VISITOR:
1030 case SIDE_TYPE_DYNAMIC_VLA:
1031 case SIDE_TYPE_DYNAMIC_VLA_VISITOR:
1032 tracer_print_dynamic(item);
1033 break;
1034 default:
1035 fprintf(stderr, "<UNKNOWN TYPE>\n");
1036 abort();
1037 }
1038 printf(" }");
1039 }
1040
1041 static
1042 void tracer_print_field(const struct side_event_field *item_desc, const struct side_arg *item)
1043 {
1044 printf("%s: ", side_ptr_get(item_desc->field_name));
1045 tracer_print_type(&item_desc->side_type, item);
1046 }
1047
1048 static
1049 void tracer_print_struct(const struct side_type *type_desc, const struct side_arg_vec *side_arg_vec)
1050 {
1051 const struct side_arg *sav = side_ptr_get(side_arg_vec->sav);
1052 const struct side_type_struct *side_struct = side_ptr_get(type_desc->u.side_struct);
1053 uint32_t i, side_sav_len = side_arg_vec->len;
1054
1055 if (side_struct->nr_fields != side_sav_len) {
1056 fprintf(stderr, "ERROR: number of fields mismatch between description and arguments of structure\n");
1057 abort();
1058 }
1059 print_attributes("attr", ":", side_ptr_get(side_struct->attr), side_struct->nr_attr);
1060 printf("%s", side_struct->nr_attr ? ", " : "");
1061 printf("fields: { ");
1062 for (i = 0; i < side_sav_len; i++) {
1063 printf("%s", i ? ", " : "");
1064 tracer_print_field(&side_ptr_get(side_struct->fields)[i], &sav[i]);
1065 }
1066 printf(" }");
1067 }
1068
1069 static
1070 void tracer_print_variant(const struct side_type *type_desc, const struct side_arg_variant *side_arg_variant)
1071 {
1072 const struct side_type_variant *side_type_variant = side_ptr_get(type_desc->u.side_variant);
1073 const struct side_type *selector_type = &side_type_variant->selector;
1074 union int64_value v64;
1075 uint32_t i;
1076
1077 if (side_enum_get(selector_type->type) != side_enum_get(side_arg_variant->selector.type)) {
1078 fprintf(stderr, "ERROR: Unexpected variant selector type\n");
1079 abort();
1080 }
1081 switch (side_enum_get(selector_type->type)) {
1082 case SIDE_TYPE_U8:
1083 case SIDE_TYPE_U16:
1084 case SIDE_TYPE_U32:
1085 case SIDE_TYPE_U64:
1086 case SIDE_TYPE_S8:
1087 case SIDE_TYPE_S16:
1088 case SIDE_TYPE_S32:
1089 case SIDE_TYPE_S64:
1090 break;
1091 default:
1092 fprintf(stderr, "ERROR: Expecting integer variant selector type\n");
1093 abort();
1094 }
1095 v64 = tracer_load_integer_value(&selector_type->u.side_integer,
1096 &side_arg_variant->selector.u.side_static.integer_value, 0, NULL);
1097 for (i = 0; i < side_type_variant->nr_options; i++) {
1098 const struct side_variant_option *option = &side_ptr_get(side_type_variant->options)[i];
1099
1100 if (v64.s >= option->range_begin && v64.s <= option->range_end) {
1101 tracer_print_type(&option->side_type, &side_arg_variant->option);
1102 return;
1103 }
1104 }
1105 fprintf(stderr, "ERROR: Variant selector value unknown %" PRId64 "\n", v64.s);
1106 abort();
1107 }
1108
1109 static
1110 void tracer_print_array(const struct side_type *type_desc, const struct side_arg_vec *side_arg_vec)
1111 {
1112 const struct side_arg *sav = side_ptr_get(side_arg_vec->sav);
1113 uint32_t i, side_sav_len = side_arg_vec->len;
1114
1115 if (type_desc->u.side_array.length != side_sav_len) {
1116 fprintf(stderr, "ERROR: length mismatch between description and arguments of array\n");
1117 abort();
1118 }
1119 print_attributes("attr", ":", side_ptr_get(type_desc->u.side_array.attr), type_desc->u.side_array.nr_attr);
1120 printf("%s", type_desc->u.side_array.nr_attr ? ", " : "");
1121 printf("elements: ");
1122 printf("[ ");
1123 for (i = 0; i < side_sav_len; i++) {
1124 printf("%s", i ? ", " : "");
1125 tracer_print_type(side_ptr_get(type_desc->u.side_array.elem_type), &sav[i]);
1126 }
1127 printf(" ]");
1128 }
1129
1130 static
1131 void tracer_print_vla(const struct side_type *type_desc, const struct side_arg_vec *side_arg_vec)
1132 {
1133 const struct side_arg *sav = side_ptr_get(side_arg_vec->sav);
1134 uint32_t i, side_sav_len = side_arg_vec->len;
1135
1136 print_attributes("attr", ":", side_ptr_get(type_desc->u.side_vla.attr), type_desc->u.side_vla.nr_attr);
1137 printf("%s", type_desc->u.side_vla.nr_attr ? ", " : "");
1138 printf("elements: ");
1139 printf("[ ");
1140 for (i = 0; i < side_sav_len; i++) {
1141 printf("%s", i ? ", " : "");
1142 tracer_print_type(side_ptr_get(type_desc->u.side_vla.elem_type), &sav[i]);
1143 }
1144 printf(" ]");
1145 }
1146
1147 static
1148 const char *tracer_gather_access(enum side_type_gather_access_mode access_mode, const char *ptr)
1149 {
1150 switch (access_mode) {
1151 case SIDE_TYPE_GATHER_ACCESS_DIRECT:
1152 return ptr;
1153 case SIDE_TYPE_GATHER_ACCESS_POINTER:
1154 /* Dereference pointer */
1155 memcpy(&ptr, ptr, sizeof(const char *));
1156 return ptr;
1157 default:
1158 abort();
1159 }
1160 }
1161
1162 static
1163 uint32_t tracer_gather_size(enum side_type_gather_access_mode access_mode, uint32_t len)
1164 {
1165 switch (access_mode) {
1166 case SIDE_TYPE_GATHER_ACCESS_DIRECT:
1167 return len;
1168 case SIDE_TYPE_GATHER_ACCESS_POINTER:
1169 return sizeof(void *);
1170 default:
1171 abort();
1172 }
1173 }
1174
1175 static
1176 union int64_value tracer_load_gather_integer_value(const struct side_type_gather_integer *side_integer,
1177 const void *_ptr)
1178 {
1179 enum side_type_gather_access_mode access_mode =
1180 (enum side_type_gather_access_mode) side_integer->access_mode;
1181 uint32_t integer_size_bytes = side_integer->type.integer_size;
1182 const char *ptr = (const char *) _ptr;
1183 union side_integer_value value;
1184
1185 ptr = tracer_gather_access(access_mode, ptr + side_integer->offset);
1186 memcpy(&value, ptr, integer_size_bytes);
1187 return tracer_load_integer_value(&side_integer->type, &value,
1188 side_integer->offset_bits, NULL);
1189 }
1190
1191 static
1192 uint32_t tracer_print_gather_bool_type(const struct side_type_gather *type_gather, const void *_ptr)
1193 {
1194 enum side_type_gather_access_mode access_mode =
1195 (enum side_type_gather_access_mode) type_gather->u.side_bool.access_mode;
1196 uint32_t bool_size_bytes = type_gather->u.side_bool.type.bool_size;
1197 const char *ptr = (const char *) _ptr;
1198 union side_bool_value value;
1199
1200 switch (bool_size_bytes) {
1201 case 1:
1202 case 2:
1203 case 4:
1204 case 8:
1205 break;
1206 default:
1207 abort();
1208 }
1209 ptr = tracer_gather_access(access_mode, ptr + type_gather->u.side_bool.offset);
1210 memcpy(&value, ptr, bool_size_bytes);
1211 tracer_print_type_bool(":", &type_gather->u.side_bool.type, &value,
1212 type_gather->u.side_bool.offset_bits);
1213 return tracer_gather_size(access_mode, bool_size_bytes);
1214 }
1215
1216 static
1217 uint32_t tracer_print_gather_byte_type(const struct side_type_gather *type_gather, const void *_ptr)
1218 {
1219 enum side_type_gather_access_mode access_mode =
1220 (enum side_type_gather_access_mode) type_gather->u.side_byte.access_mode;
1221 const char *ptr = (const char *) _ptr;
1222 uint8_t value;
1223
1224 ptr = tracer_gather_access(access_mode, ptr + type_gather->u.side_byte.offset);
1225 memcpy(&value, ptr, 1);
1226 tracer_print_type_header(":", side_ptr_get(type_gather->u.side_byte.type.attr),
1227 type_gather->u.side_byte.type.nr_attr);
1228 printf("0x%" PRIx8, value);
1229 return tracer_gather_size(access_mode, 1);
1230 }
1231
1232 static
1233 uint32_t tracer_print_gather_integer_type(const struct side_type_gather *type_gather, const void *_ptr,
1234 enum tracer_display_base default_base)
1235 {
1236 enum side_type_gather_access_mode access_mode =
1237 (enum side_type_gather_access_mode) type_gather->u.side_integer.access_mode;
1238 uint32_t integer_size_bytes = type_gather->u.side_integer.type.integer_size;
1239 const char *ptr = (const char *) _ptr;
1240 union side_integer_value value;
1241
1242 switch (integer_size_bytes) {
1243 case 1:
1244 case 2:
1245 case 4:
1246 case 8:
1247 break;
1248 default:
1249 abort();
1250 }
1251 ptr = tracer_gather_access(access_mode, ptr + type_gather->u.side_integer.offset);
1252 memcpy(&value, ptr, integer_size_bytes);
1253 tracer_print_type_integer(":", &type_gather->u.side_integer.type, &value,
1254 type_gather->u.side_integer.offset_bits, default_base);
1255 return tracer_gather_size(access_mode, integer_size_bytes);
1256 }
1257
1258 static
1259 uint32_t tracer_print_gather_float_type(const struct side_type_gather *type_gather, const void *_ptr)
1260 {
1261 enum side_type_gather_access_mode access_mode =
1262 (enum side_type_gather_access_mode) type_gather->u.side_float.access_mode;
1263 uint32_t float_size_bytes = type_gather->u.side_float.type.float_size;
1264 const char *ptr = (const char *) _ptr;
1265 union side_float_value value;
1266
1267 switch (float_size_bytes) {
1268 case 2:
1269 case 4:
1270 case 8:
1271 case 16:
1272 break;
1273 default:
1274 abort();
1275 }
1276 ptr = tracer_gather_access(access_mode, ptr + type_gather->u.side_float.offset);
1277 memcpy(&value, ptr, float_size_bytes);
1278 tracer_print_type_float(":", &type_gather->u.side_float.type, &value);
1279 return tracer_gather_size(access_mode, float_size_bytes);
1280 }
1281
1282 static
1283 uint32_t tracer_print_gather_string_type(const struct side_type_gather *type_gather, const void *_ptr)
1284 {
1285 enum side_type_gather_access_mode access_mode =
1286 (enum side_type_gather_access_mode) type_gather->u.side_string.access_mode;
1287 const char *ptr = (const char *) _ptr;
1288 size_t string_len;
1289
1290 ptr = tracer_gather_access(access_mode, ptr + type_gather->u.side_string.offset);
1291 tracer_print_type_header(":", side_ptr_get(type_gather->u.side_string.type.attr),
1292 type_gather->u.side_string.type.nr_attr);
1293 if (ptr) {
1294 tracer_print_string(ptr, type_gather->u.side_string.type.unit_size,
1295 side_enum_get(type_gather->u.side_string.type.byte_order), &string_len);
1296 } else {
1297 printf("<NULL>");
1298 string_len = type_gather->u.side_string.type.unit_size;
1299 }
1300 return tracer_gather_size(access_mode, string_len);
1301 }
1302
1303 static
1304 uint32_t tracer_print_gather_type(const struct side_type *type_desc, const void *ptr)
1305 {
1306 uint32_t len;
1307
1308 printf("{ ");
1309 switch (side_enum_get(type_desc->type)) {
1310 /* Gather basic types */
1311 case SIDE_TYPE_GATHER_BOOL:
1312 len = tracer_print_gather_bool_type(&type_desc->u.side_gather, ptr);
1313 break;
1314 case SIDE_TYPE_GATHER_INTEGER:
1315 len = tracer_print_gather_integer_type(&type_desc->u.side_gather, ptr,
1316 TRACER_DISPLAY_BASE_10);
1317 break;
1318 case SIDE_TYPE_GATHER_BYTE:
1319 len = tracer_print_gather_byte_type(&type_desc->u.side_gather, ptr);
1320 break;
1321 case SIDE_TYPE_GATHER_POINTER:
1322 len = tracer_print_gather_integer_type(&type_desc->u.side_gather, ptr,
1323 TRACER_DISPLAY_BASE_16);
1324 break;
1325 case SIDE_TYPE_GATHER_FLOAT:
1326 len = tracer_print_gather_float_type(&type_desc->u.side_gather, ptr);
1327 break;
1328 case SIDE_TYPE_GATHER_STRING:
1329 len = tracer_print_gather_string_type(&type_desc->u.side_gather, ptr);
1330 break;
1331
1332 /* Gather enum types */
1333 case SIDE_TYPE_GATHER_ENUM:
1334 len = tracer_print_gather_enum_type(&type_desc->u.side_gather, ptr);
1335 break;
1336
1337 /* Gather compound types */
1338 case SIDE_TYPE_GATHER_STRUCT:
1339 len = tracer_print_gather_struct(&type_desc->u.side_gather, ptr);
1340 break;
1341 case SIDE_TYPE_GATHER_ARRAY:
1342 len = tracer_print_gather_array(&type_desc->u.side_gather, ptr);
1343 break;
1344 case SIDE_TYPE_GATHER_VLA:
1345 len = tracer_print_gather_vla(&type_desc->u.side_gather, ptr, ptr);
1346 break;
1347 default:
1348 fprintf(stderr, "<UNKNOWN GATHER TYPE>");
1349 abort();
1350 }
1351 printf(" }");
1352 return len;
1353 }
1354
1355 static
1356 uint32_t tracer_print_gather_enum_type(const struct side_type_gather *type_gather, const void *_ptr)
1357 {
1358 const struct side_enum_mappings *mappings = side_ptr_get(type_gather->u.side_enum.mappings);
1359 const struct side_type *enum_elem_type = side_ptr_get(type_gather->u.side_enum.elem_type);
1360 const struct side_type_gather_integer *side_integer = &enum_elem_type->u.side_gather.u.side_integer;
1361 enum side_type_gather_access_mode access_mode =
1362 (enum side_type_gather_access_mode) side_integer->access_mode;
1363 uint32_t integer_size_bytes = side_integer->type.integer_size;
1364 const char *ptr = (const char *) _ptr;
1365 union side_integer_value value;
1366 union int64_value v64;
1367
1368 switch (integer_size_bytes) {
1369 case 1:
1370 case 2:
1371 case 4:
1372 case 8:
1373 break;
1374 default:
1375 abort();
1376 }
1377 ptr = tracer_gather_access(access_mode, ptr + side_integer->offset);
1378 memcpy(&value, ptr, integer_size_bytes);
1379 v64 = tracer_load_gather_integer_value(side_integer, &value);
1380 print_attributes("attr", ":", side_ptr_get(mappings->attr), mappings->nr_attr);
1381 printf("%s", mappings->nr_attr ? ", " : "");
1382 tracer_print_gather_type(enum_elem_type, ptr);
1383 print_enum_labels(mappings, v64);
1384 return tracer_gather_size(access_mode, integer_size_bytes);
1385 }
1386
1387 static
1388 void tracer_print_gather_field(const struct side_event_field *field, const void *ptr)
1389 {
1390 printf("%s: ", side_ptr_get(field->field_name));
1391 (void) tracer_print_gather_type(&field->side_type, ptr);
1392 }
1393
1394 static
1395 uint32_t tracer_print_gather_struct(const struct side_type_gather *type_gather, const void *_ptr)
1396 {
1397 enum side_type_gather_access_mode access_mode =
1398 (enum side_type_gather_access_mode) type_gather->u.side_struct.access_mode;
1399 const struct side_type_struct *side_struct = side_ptr_get(type_gather->u.side_struct.type);
1400 const char *ptr = (const char *) _ptr;
1401 uint32_t i;
1402
1403 ptr = tracer_gather_access(access_mode, ptr + type_gather->u.side_struct.offset);
1404 print_attributes("attr", ":", side_ptr_get(side_struct->attr), side_struct->nr_attr);
1405 printf("%s", side_struct->nr_attr ? ", " : "");
1406 printf("fields: { ");
1407 for (i = 0; i < side_struct->nr_fields; i++) {
1408 printf("%s", i ? ", " : "");
1409 tracer_print_gather_field(&side_ptr_get(side_struct->fields)[i], ptr);
1410 }
1411 printf(" }");
1412 return tracer_gather_size(access_mode, type_gather->u.side_struct.size);
1413 }
1414
1415 static
1416 uint32_t tracer_print_gather_array(const struct side_type_gather *type_gather, const void *_ptr)
1417 {
1418 enum side_type_gather_access_mode access_mode =
1419 (enum side_type_gather_access_mode) type_gather->u.side_array.access_mode;
1420 const char *ptr = (const char *) _ptr, *orig_ptr;
1421 uint32_t i;
1422
1423 ptr = tracer_gather_access(access_mode, ptr + type_gather->u.side_array.offset);
1424 orig_ptr = ptr;
1425 print_attributes("attr", ":", side_ptr_get(type_gather->u.side_array.type.attr), type_gather->u.side_array.type.nr_attr);
1426 printf("%s", type_gather->u.side_array.type.nr_attr ? ", " : "");
1427 printf("elements: ");
1428 printf("[ ");
1429 for (i = 0; i < type_gather->u.side_array.type.length; i++) {
1430 const struct side_type *elem_type = side_ptr_get(type_gather->u.side_array.type.elem_type);
1431
1432 switch (side_enum_get(elem_type->type)) {
1433 case SIDE_TYPE_GATHER_VLA:
1434 fprintf(stderr, "<gather VLA only supported within gather structures>\n");
1435 abort();
1436 default:
1437 break;
1438 }
1439 printf("%s", i ? ", " : "");
1440 ptr += tracer_print_gather_type(elem_type, ptr);
1441 }
1442 printf(" ]");
1443 return tracer_gather_size(access_mode, ptr - orig_ptr);
1444 }
1445
1446 static
1447 uint32_t tracer_print_gather_vla(const struct side_type_gather *type_gather, const void *_ptr,
1448 const void *_length_ptr)
1449 {
1450 enum side_type_gather_access_mode access_mode =
1451 (enum side_type_gather_access_mode) type_gather->u.side_vla.access_mode;
1452 const struct side_type *length_type = side_ptr_get(type_gather->u.side_vla.length_type);
1453 const char *ptr = (const char *) _ptr, *orig_ptr;
1454 const char *length_ptr = (const char *) _length_ptr;
1455 union int64_value v64;
1456 uint32_t i, length;
1457
1458 /* Access length */
1459 switch (side_enum_get(length_type->type)) {
1460 case SIDE_TYPE_GATHER_INTEGER:
1461 break;
1462 default:
1463 fprintf(stderr, "<gather VLA expects integer gather length type>\n");
1464 abort();
1465 }
1466 v64 = tracer_load_gather_integer_value(&length_type->u.side_gather.u.side_integer,
1467 length_ptr);
1468 length = (uint32_t) v64.u;
1469 ptr = tracer_gather_access(access_mode, ptr + type_gather->u.side_vla.offset);
1470 orig_ptr = ptr;
1471 print_attributes("attr", ":", side_ptr_get(type_gather->u.side_vla.type.attr), type_gather->u.side_vla.type.nr_attr);
1472 printf("%s", type_gather->u.side_vla.type.nr_attr ? ", " : "");
1473 printf("elements: ");
1474 printf("[ ");
1475 for (i = 0; i < length; i++) {
1476 const struct side_type *elem_type = side_ptr_get(type_gather->u.side_vla.type.elem_type);
1477
1478 switch (side_enum_get(elem_type->type)) {
1479 case SIDE_TYPE_GATHER_VLA:
1480 fprintf(stderr, "<gather VLA only supported within gather structures>\n");
1481 abort();
1482 default:
1483 break;
1484 }
1485 printf("%s", i ? ", " : "");
1486 ptr += tracer_print_gather_type(elem_type, ptr);
1487 }
1488 printf(" ]");
1489 return tracer_gather_size(access_mode, ptr - orig_ptr);
1490 }
1491
1492 struct tracer_visitor_priv {
1493 const struct side_type *elem_type;
1494 int i;
1495 };
1496
1497 static
1498 enum side_visitor_status tracer_write_elem_cb(const struct side_tracer_visitor_ctx *tracer_ctx,
1499 const struct side_arg *elem)
1500 {
1501 struct tracer_visitor_priv *tracer_priv = (struct tracer_visitor_priv *) tracer_ctx->priv;
1502
1503 printf("%s", tracer_priv->i++ ? ", " : "");
1504 tracer_print_type(tracer_priv->elem_type, elem);
1505 return SIDE_VISITOR_STATUS_OK;
1506 }
1507
1508 static
1509 void tracer_print_vla_visitor(const struct side_type *type_desc, void *app_ctx)
1510 {
1511 enum side_visitor_status status;
1512 struct tracer_visitor_priv tracer_priv = {
1513 .elem_type = side_ptr_get(type_desc->u.side_vla_visitor.elem_type),
1514 .i = 0,
1515 };
1516 const struct side_tracer_visitor_ctx tracer_ctx = {
1517 .write_elem = tracer_write_elem_cb,
1518 .priv = &tracer_priv,
1519 };
1520 side_visitor_func func;
1521
1522 print_attributes("attr", ":", side_ptr_get(type_desc->u.side_vla_visitor.attr), type_desc->u.side_vla_visitor.nr_attr);
1523 printf("%s", type_desc->u.side_vla_visitor.nr_attr ? ", " : "");
1524 printf("elements: ");
1525 printf("[ ");
1526 func = side_ptr_get(type_desc->u.side_vla_visitor.visitor);
1527 status = func(&tracer_ctx, app_ctx);
1528 switch (status) {
1529 case SIDE_VISITOR_STATUS_OK:
1530 break;
1531 case SIDE_VISITOR_STATUS_ERROR:
1532 fprintf(stderr, "ERROR: Visitor error\n");
1533 abort();
1534 }
1535 printf(" ]");
1536 }
1537
1538 static
1539 void tracer_print_dynamic_struct(const struct side_arg_dynamic_struct *dynamic_struct)
1540 {
1541 const struct side_arg_dynamic_field *fields = side_ptr_get(dynamic_struct->fields);
1542 uint32_t i, len = dynamic_struct->len;
1543
1544 print_attributes("attr", "::", side_ptr_get(dynamic_struct->attr), dynamic_struct->nr_attr);
1545 printf("%s", dynamic_struct->nr_attr ? ", " : "");
1546 printf("fields:: ");
1547 printf("[ ");
1548 for (i = 0; i < len; i++) {
1549 printf("%s", i ? ", " : "");
1550 printf("%s:: ", side_ptr_get(fields[i].field_name));
1551 tracer_print_dynamic(&fields[i].elem);
1552 }
1553 printf(" ]");
1554 }
1555
1556 struct tracer_dynamic_struct_visitor_priv {
1557 int i;
1558 };
1559
1560 static
1561 enum side_visitor_status tracer_dynamic_struct_write_elem_cb(
1562 const struct side_tracer_dynamic_struct_visitor_ctx *tracer_ctx,
1563 const struct side_arg_dynamic_field *dynamic_field)
1564 {
1565 struct tracer_dynamic_struct_visitor_priv *tracer_priv =
1566 (struct tracer_dynamic_struct_visitor_priv *) tracer_ctx->priv;
1567
1568 printf("%s", tracer_priv->i++ ? ", " : "");
1569 printf("%s:: ", side_ptr_get(dynamic_field->field_name));
1570 tracer_print_dynamic(&dynamic_field->elem);
1571 return SIDE_VISITOR_STATUS_OK;
1572 }
1573
1574 static
1575 void tracer_print_dynamic_struct_visitor(const struct side_arg *item)
1576 {
1577 enum side_visitor_status status;
1578 struct tracer_dynamic_struct_visitor_priv tracer_priv = {
1579 .i = 0,
1580 };
1581 const struct side_tracer_dynamic_struct_visitor_ctx tracer_ctx = {
1582 .write_field = tracer_dynamic_struct_write_elem_cb,
1583 .priv = &tracer_priv,
1584 };
1585 void *app_ctx = side_ptr_get(item->u.side_dynamic.side_dynamic_struct_visitor.app_ctx);
1586
1587 print_attributes("attr", "::", side_ptr_get(item->u.side_dynamic.side_dynamic_struct_visitor.attr), item->u.side_dynamic.side_dynamic_struct_visitor.nr_attr);
1588 printf("%s", item->u.side_dynamic.side_dynamic_struct_visitor.nr_attr ? ", " : "");
1589 printf("fields:: ");
1590 printf("[ ");
1591 status = side_ptr_get(item->u.side_dynamic.side_dynamic_struct_visitor.visitor)(&tracer_ctx, app_ctx);
1592 switch (status) {
1593 case SIDE_VISITOR_STATUS_OK:
1594 break;
1595 case SIDE_VISITOR_STATUS_ERROR:
1596 fprintf(stderr, "ERROR: Visitor error\n");
1597 abort();
1598 }
1599 printf(" ]");
1600 }
1601
1602 static
1603 void tracer_print_dynamic_vla(const struct side_arg_dynamic_vla *vla)
1604 {
1605 const struct side_arg *sav = side_ptr_get(vla->sav);
1606 uint32_t i, side_sav_len = vla->len;
1607
1608 print_attributes("attr", "::", side_ptr_get(vla->attr), vla->nr_attr);
1609 printf("%s", vla->nr_attr ? ", " : "");
1610 printf("elements:: ");
1611 printf("[ ");
1612 for (i = 0; i < side_sav_len; i++) {
1613 printf("%s", i ? ", " : "");
1614 tracer_print_dynamic(&sav[i]);
1615 }
1616 printf(" ]");
1617 }
1618
1619 struct tracer_dynamic_vla_visitor_priv {
1620 int i;
1621 };
1622
1623 static
1624 enum side_visitor_status tracer_dynamic_vla_write_elem_cb(
1625 const struct side_tracer_visitor_ctx *tracer_ctx,
1626 const struct side_arg *elem)
1627 {
1628 struct tracer_dynamic_vla_visitor_priv *tracer_priv =
1629 (struct tracer_dynamic_vla_visitor_priv *) tracer_ctx->priv;
1630
1631 printf("%s", tracer_priv->i++ ? ", " : "");
1632 tracer_print_dynamic(elem);
1633 return SIDE_VISITOR_STATUS_OK;
1634 }
1635
1636 static
1637 void tracer_print_dynamic_vla_visitor(const struct side_arg *item)
1638 {
1639 enum side_visitor_status status;
1640 struct tracer_dynamic_vla_visitor_priv tracer_priv = {
1641 .i = 0,
1642 };
1643 const struct side_tracer_visitor_ctx tracer_ctx = {
1644 .write_elem = tracer_dynamic_vla_write_elem_cb,
1645 .priv = &tracer_priv,
1646 };
1647 void *app_ctx = side_ptr_get(item->u.side_dynamic.side_dynamic_vla_visitor.app_ctx);
1648
1649 print_attributes("attr", "::", side_ptr_get(item->u.side_dynamic.side_dynamic_vla_visitor.attr), item->u.side_dynamic.side_dynamic_vla_visitor.nr_attr);
1650 printf("%s", item->u.side_dynamic.side_dynamic_vla_visitor.nr_attr ? ", " : "");
1651 printf("elements:: ");
1652 printf("[ ");
1653 status = side_ptr_get(item->u.side_dynamic.side_dynamic_vla_visitor.visitor)(&tracer_ctx, app_ctx);
1654 switch (status) {
1655 case SIDE_VISITOR_STATUS_OK:
1656 break;
1657 case SIDE_VISITOR_STATUS_ERROR:
1658 fprintf(stderr, "ERROR: Visitor error\n");
1659 abort();
1660 }
1661 printf(" ]");
1662 }
1663
1664 static
1665 void tracer_print_dynamic(const struct side_arg *item)
1666 {
1667 printf("{ ");
1668 switch (side_enum_get(item->type)) {
1669 /* Dynamic basic types */
1670 case SIDE_TYPE_DYNAMIC_NULL:
1671 tracer_print_type_header("::", side_ptr_get(item->u.side_dynamic.side_null.attr),
1672 item->u.side_dynamic.side_null.nr_attr);
1673 printf("<NULL TYPE>");
1674 break;
1675 case SIDE_TYPE_DYNAMIC_BOOL:
1676 tracer_print_type_bool("::", &item->u.side_dynamic.side_bool.type, &item->u.side_dynamic.side_bool.value, 0);
1677 break;
1678 case SIDE_TYPE_DYNAMIC_INTEGER:
1679 tracer_print_type_integer("::", &item->u.side_dynamic.side_integer.type, &item->u.side_dynamic.side_integer.value, 0,
1680 TRACER_DISPLAY_BASE_10);
1681 break;
1682 case SIDE_TYPE_DYNAMIC_BYTE:
1683 tracer_print_type_header("::", side_ptr_get(item->u.side_dynamic.side_byte.type.attr), item->u.side_dynamic.side_byte.type.nr_attr);
1684 printf("0x%" PRIx8, item->u.side_dynamic.side_byte.value);
1685 break;
1686 case SIDE_TYPE_DYNAMIC_POINTER:
1687 tracer_print_type_integer("::", &item->u.side_dynamic.side_integer.type, &item->u.side_dynamic.side_integer.value, 0,
1688 TRACER_DISPLAY_BASE_16);
1689 break;
1690 case SIDE_TYPE_DYNAMIC_FLOAT:
1691 tracer_print_type_float("::", &item->u.side_dynamic.side_float.type,
1692 &item->u.side_dynamic.side_float.value);
1693 break;
1694 case SIDE_TYPE_DYNAMIC_STRING:
1695 tracer_print_type_header("::", side_ptr_get(item->u.side_dynamic.side_string.type.attr), item->u.side_dynamic.side_string.type.nr_attr);
1696 tracer_print_string((const char *)(uintptr_t) item->u.side_dynamic.side_string.value,
1697 item->u.side_dynamic.side_string.type.unit_size,
1698 side_enum_get(item->u.side_dynamic.side_string.type.byte_order), NULL);
1699 break;
1700
1701 /* Dynamic compound types */
1702 case SIDE_TYPE_DYNAMIC_STRUCT:
1703 tracer_print_dynamic_struct(side_ptr_get(item->u.side_dynamic.side_dynamic_struct));
1704 break;
1705 case SIDE_TYPE_DYNAMIC_STRUCT_VISITOR:
1706 tracer_print_dynamic_struct_visitor(item);
1707 break;
1708 case SIDE_TYPE_DYNAMIC_VLA:
1709 tracer_print_dynamic_vla(side_ptr_get(item->u.side_dynamic.side_dynamic_vla));
1710 break;
1711 case SIDE_TYPE_DYNAMIC_VLA_VISITOR:
1712 tracer_print_dynamic_vla_visitor(item);
1713 break;
1714 default:
1715 fprintf(stderr, "<UNKNOWN TYPE>\n");
1716 abort();
1717 }
1718 printf(" }");
1719 }
1720
1721 static
1722 void tracer_print_static_fields(const struct side_event_description *desc,
1723 const struct side_arg_vec *side_arg_vec,
1724 uint32_t *nr_items)
1725 {
1726 const struct side_arg *sav = side_ptr_get(side_arg_vec->sav);
1727 uint32_t i, side_sav_len = side_arg_vec->len;
1728
1729 printf("provider: %s, event: %s", side_ptr_get(desc->provider_name), side_ptr_get(desc->event_name));
1730 if (desc->nr_fields != side_sav_len) {
1731 fprintf(stderr, "ERROR: number of fields mismatch between description and arguments\n");
1732 abort();
1733 }
1734 print_attributes(", attr", ":", side_ptr_get(desc->attr), desc->nr_attr);
1735 printf("%s", side_sav_len ? ", fields: [ " : "");
1736 for (i = 0; i < side_sav_len; i++) {
1737 printf("%s", i ? ", " : "");
1738 tracer_print_field(&side_ptr_get(desc->fields)[i], &sav[i]);
1739 }
1740 if (nr_items)
1741 *nr_items = i;
1742 if (side_sav_len)
1743 printf(" ]");
1744 }
1745
1746 static
1747 void tracer_call(const struct side_event_description *desc,
1748 const struct side_arg_vec *side_arg_vec,
1749 void *priv __attribute__((unused)))
1750 {
1751 uint32_t nr_fields = 0;
1752
1753 tracer_print_static_fields(desc, side_arg_vec, &nr_fields);
1754 printf("\n");
1755 }
1756
1757 static
1758 void tracer_call_variadic(const struct side_event_description *desc,
1759 const struct side_arg_vec *side_arg_vec,
1760 const struct side_arg_dynamic_struct *var_struct,
1761 void *priv __attribute__((unused)))
1762 {
1763 uint32_t nr_fields = 0, i, var_struct_len = var_struct->len;
1764
1765 tracer_print_static_fields(desc, side_arg_vec, &nr_fields);
1766
1767 if (side_unlikely(!(desc->flags & SIDE_EVENT_FLAG_VARIADIC))) {
1768 fprintf(stderr, "ERROR: unexpected non-variadic event description\n");
1769 abort();
1770 }
1771 print_attributes(", attr ", "::", side_ptr_get(var_struct->attr), var_struct->nr_attr);
1772 printf("%s", var_struct_len ? ", fields:: [ " : "");
1773 for (i = 0; i < var_struct_len; i++, nr_fields++) {
1774 printf("%s", i ? ", " : "");
1775 printf("%s:: ", side_ptr_get(side_ptr_get(var_struct->fields)[i].field_name));
1776 tracer_print_dynamic(&side_ptr_get(var_struct->fields)[i].elem);
1777 }
1778 if (i)
1779 printf(" ]");
1780 printf("\n");
1781 }
1782
1783 static
1784 void tracer_event_notification(enum side_tracer_notification notif,
1785 struct side_event_description **events, uint32_t nr_events,
1786 void *priv __attribute__((unused)))
1787 {
1788 uint32_t i;
1789 int ret;
1790
1791 printf("----------------------------------------------------------\n");
1792 printf("Tracer notified of events %s\n",
1793 notif == SIDE_TRACER_NOTIFICATION_INSERT_EVENTS ? "inserted" : "removed");
1794 for (i = 0; i < nr_events; i++) {
1795 struct side_event_description *event = events[i];
1796
1797 /* Skip NULL pointers */
1798 if (!event)
1799 continue;
1800 printf("provider: %s, event: %s\n",
1801 side_ptr_get(event->provider_name), side_ptr_get(event->event_name));
1802 if (notif == SIDE_TRACER_NOTIFICATION_INSERT_EVENTS) {
1803 if (event->flags & SIDE_EVENT_FLAG_VARIADIC) {
1804 ret = side_tracer_callback_variadic_register(event, tracer_call_variadic, NULL);
1805 if (ret)
1806 abort();
1807 } else {
1808 ret = side_tracer_callback_register(event, tracer_call, NULL);
1809 if (ret)
1810 abort();
1811 }
1812 } else {
1813 if (event->flags & SIDE_EVENT_FLAG_VARIADIC) {
1814 ret = side_tracer_callback_variadic_unregister(event, tracer_call_variadic, NULL);
1815 if (ret)
1816 abort();
1817 } else {
1818 ret = side_tracer_callback_unregister(event, tracer_call, NULL);
1819 if (ret)
1820 abort();
1821 }
1822 }
1823 }
1824 printf("----------------------------------------------------------\n");
1825 }
1826
1827 static __attribute__((constructor))
1828 void tracer_init(void);
1829 static
1830 void tracer_init(void)
1831 {
1832 tracer_handle = side_tracer_event_notification_register(tracer_event_notification, NULL);
1833 if (!tracer_handle)
1834 abort();
1835 }
1836
1837 static __attribute__((destructor))
1838 void tracer_exit(void);
1839 static
1840 void tracer_exit(void)
1841 {
1842 side_tracer_event_notification_unregister(tracer_handle);
1843 }
This page took 0.103276 seconds and 4 git commands to generate.