ust registry: Refactor representation of nested types
[lttng-tools.git] / src / bin / lttng-sessiond / ust-metadata.c
1 /*
2 * Copyright (C) 2010-2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7
8 #define _LGPL_SOURCE
9 #include <stdint.h>
10 #include <string.h>
11 #include <stdarg.h>
12 #include <stdio.h>
13 #include <limits.h>
14 #include <unistd.h>
15 #include <inttypes.h>
16 #include <common/common.h>
17 #include <common/time.h>
18
19 #include "ust-registry.h"
20 #include "ust-clock.h"
21 #include "ust-app.h"
22
23 #ifndef max_t
24 #define max_t(type, a, b) ((type) ((a) > (b) ? (a) : (b)))
25 #endif
26
27 #define NR_CLOCK_OFFSET_SAMPLES 10
28
29 struct offset_sample {
30 int64_t offset; /* correlation offset */
31 uint64_t measure_delta; /* lower is better */
32 };
33
34 static
35 int _lttng_field_statedump(struct ust_registry_session *session,
36 const struct ustctl_field *fields, size_t nr_fields,
37 size_t *iter_field, size_t nesting);
38
39 static inline
40 int fls(unsigned int x)
41 {
42 int r = 32;
43
44 if (!x)
45 return 0;
46 if (!(x & 0xFFFF0000U)) {
47 x <<= 16;
48 r -= 16;
49 }
50 if (!(x & 0xFF000000U)) {
51 x <<= 8;
52 r -= 8;
53 }
54 if (!(x & 0xF0000000U)) {
55 x <<= 4;
56 r -= 4;
57 }
58 if (!(x & 0xC0000000U)) {
59 x <<= 2;
60 r -= 2;
61 }
62 if (!(x & 0x80000000U)) {
63 r -= 1;
64 }
65 return r;
66 }
67
68 static inline
69 int get_count_order(unsigned int count)
70 {
71 int order;
72
73 order = fls(count) - 1;
74 if (count & (count - 1)) {
75 order++;
76 }
77 assert(order >= 0);
78 return order;
79 }
80
81 /*
82 * Returns offset where to write in metadata array, or negative error value on error.
83 */
84 static
85 ssize_t metadata_reserve(struct ust_registry_session *session, size_t len)
86 {
87 size_t new_len = session->metadata_len + len;
88 size_t new_alloc_len = new_len;
89 size_t old_alloc_len = session->metadata_alloc_len;
90 ssize_t ret;
91
92 if (new_alloc_len > (UINT32_MAX >> 1))
93 return -EINVAL;
94 if ((old_alloc_len << 1) > (UINT32_MAX >> 1))
95 return -EINVAL;
96
97 if (new_alloc_len > old_alloc_len) {
98 char *newptr;
99
100 new_alloc_len =
101 max_t(size_t, 1U << get_count_order(new_alloc_len), old_alloc_len << 1);
102 newptr = realloc(session->metadata, new_alloc_len);
103 if (!newptr)
104 return -ENOMEM;
105 session->metadata = newptr;
106 /* We zero directly the memory from start of allocation. */
107 memset(&session->metadata[old_alloc_len], 0, new_alloc_len - old_alloc_len);
108 session->metadata_alloc_len = new_alloc_len;
109 }
110 ret = session->metadata_len;
111 session->metadata_len += len;
112 return ret;
113 }
114
115 static
116 int metadata_file_append(struct ust_registry_session *session,
117 const char *str, size_t len)
118 {
119 ssize_t written;
120
121 if (session->metadata_fd < 0) {
122 return 0;
123 }
124 /* Write to metadata file */
125 written = lttng_write(session->metadata_fd, str, len);
126 if (written != len) {
127 return -1;
128 }
129 return 0;
130 }
131
132 /*
133 * We have exclusive access to our metadata buffer (protected by the
134 * ust_lock), so we can do racy operations such as looking for
135 * remaining space left in packet and write, since mutual exclusion
136 * protects us from concurrent writes.
137 */
138 static
139 int lttng_metadata_printf(struct ust_registry_session *session,
140 const char *fmt, ...)
141 {
142 char *str = NULL;
143 size_t len;
144 va_list ap;
145 ssize_t offset;
146 int ret;
147
148 va_start(ap, fmt);
149 ret = vasprintf(&str, fmt, ap);
150 va_end(ap);
151 if (ret < 0)
152 return -ENOMEM;
153
154 len = strlen(str);
155 offset = metadata_reserve(session, len);
156 if (offset < 0) {
157 ret = offset;
158 goto end;
159 }
160 memcpy(&session->metadata[offset], str, len);
161 ret = metadata_file_append(session, str, len);
162 if (ret) {
163 PERROR("Error appending to metadata file");
164 goto end;
165 }
166 DBG3("Append to metadata: \"%s\"", str);
167 ret = 0;
168
169 end:
170 free(str);
171 return ret;
172 }
173
174 static
175 int print_tabs(struct ust_registry_session *session, size_t nesting)
176 {
177 size_t i;
178
179 for (i = 0; i < nesting; i++) {
180 int ret;
181
182 ret = lttng_metadata_printf(session, " ");
183 if (ret) {
184 return ret;
185 }
186 }
187 return 0;
188 }
189
190 static
191 void sanitize_ctf_identifier(char *out, const char *in)
192 {
193 size_t i;
194
195 for (i = 0; i < LTTNG_UST_SYM_NAME_LEN; i++) {
196 switch (in[i]) {
197 case '.':
198 case '$':
199 case ':':
200 out[i] = '_';
201 break;
202 default:
203 out[i] = in[i];
204 }
205 }
206 }
207
208 static
209 int print_escaped_ctf_string(struct ust_registry_session *session, const char *string)
210 {
211 int ret = 0;
212 size_t i;
213 char cur;
214
215 i = 0;
216 cur = string[i];
217 while (cur != '\0') {
218 switch (cur) {
219 case '\n':
220 ret = lttng_metadata_printf(session, "%s", "\\n");
221 break;
222 case '\\':
223 case '"':
224 ret = lttng_metadata_printf(session, "%c", '\\');
225 if (ret) {
226 goto error;
227 }
228 /* We still print the current char */
229 /* Fallthrough */
230 default:
231 ret = lttng_metadata_printf(session, "%c", cur);
232 break;
233 }
234
235 if (ret) {
236 goto error;
237 }
238
239 cur = string[++i];
240 }
241 error:
242 return ret;
243 }
244
245 /* Called with session registry mutex held. */
246 static
247 int ust_metadata_enum_statedump(struct ust_registry_session *session,
248 const char *enum_name,
249 uint64_t enum_id,
250 const struct ustctl_integer_type *container_type,
251 const char *field_name, size_t *iter_field, size_t nesting)
252 {
253 struct ust_registry_enum *reg_enum;
254 const struct ustctl_enum_entry *entries;
255 size_t nr_entries;
256 int ret = 0;
257 size_t i;
258 char identifier[LTTNG_UST_SYM_NAME_LEN];
259
260 rcu_read_lock();
261 reg_enum = ust_registry_lookup_enum_by_id(session, enum_name, enum_id);
262 rcu_read_unlock();
263 /* reg_enum can still be used because session registry mutex is held. */
264 if (!reg_enum) {
265 ret = -ENOENT;
266 goto end;
267 }
268 entries = reg_enum->entries;
269 nr_entries = reg_enum->nr_entries;
270
271 ret = print_tabs(session, nesting);
272 if (ret) {
273 goto end;
274 }
275 ret = lttng_metadata_printf(session,
276 "enum : integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u; } {\n",
277 container_type->size,
278 container_type->alignment,
279 container_type->signedness,
280 (container_type->encoding == ustctl_encode_none)
281 ? "none"
282 : (container_type->encoding == ustctl_encode_UTF8)
283 ? "UTF8"
284 : "ASCII",
285 container_type->base);
286 if (ret) {
287 goto end;
288 }
289 nesting++;
290 /* Dump all entries */
291 for (i = 0; i < nr_entries; i++) {
292 const struct ustctl_enum_entry *entry = &entries[i];
293 int j, len;
294
295 ret = print_tabs(session, nesting);
296 if (ret) {
297 goto end;
298 }
299 ret = lttng_metadata_printf(session,
300 "\"");
301 if (ret) {
302 goto end;
303 }
304 len = strlen(entry->string);
305 /* Escape the character '"' */
306 for (j = 0; j < len; j++) {
307 char c = entry->string[j];
308
309 switch (c) {
310 case '"':
311 ret = lttng_metadata_printf(session,
312 "\\\"");
313 break;
314 case '\\':
315 ret = lttng_metadata_printf(session,
316 "\\\\");
317 break;
318 default:
319 ret = lttng_metadata_printf(session,
320 "%c", c);
321 break;
322 }
323 if (ret) {
324 goto end;
325 }
326 }
327 ret = lttng_metadata_printf(session, "\"");
328 if (ret) {
329 goto end;
330 }
331
332 if (entry->u.extra.options &
333 USTCTL_UST_ENUM_ENTRY_OPTION_IS_AUTO) {
334 ret = lttng_metadata_printf(session, ",\n");
335 if (ret) {
336 goto end;
337 }
338 } else {
339 ret = lttng_metadata_printf(session,
340 " = ");
341 if (ret) {
342 goto end;
343 }
344
345 if (entry->start.signedness) {
346 ret = lttng_metadata_printf(session,
347 "%lld", (long long) entry->start.value);
348 } else {
349 ret = lttng_metadata_printf(session,
350 "%llu", entry->start.value);
351 }
352 if (ret) {
353 goto end;
354 }
355
356 if (entry->start.signedness == entry->end.signedness &&
357 entry->start.value ==
358 entry->end.value) {
359 ret = lttng_metadata_printf(session, ",\n");
360 } else {
361 if (entry->end.signedness) {
362 ret = lttng_metadata_printf(session,
363 " ... %lld,\n",
364 (long long) entry->end.value);
365 } else {
366 ret = lttng_metadata_printf(session,
367 " ... %llu,\n",
368 entry->end.value);
369 }
370 }
371 if (ret) {
372 goto end;
373 }
374 }
375 }
376 nesting--;
377 sanitize_ctf_identifier(identifier, field_name);
378 ret = print_tabs(session, nesting);
379 if (ret) {
380 goto end;
381 }
382 ret = lttng_metadata_printf(session, "} _%s;\n",
383 identifier);
384 end:
385 (*iter_field)++;
386 return ret;
387 }
388
389 static
390 int _lttng_variant_statedump(struct ust_registry_session *session,
391 uint32_t nr_choices, const char *tag_name,
392 uint32_t alignment,
393 const struct ustctl_field *fields, size_t nr_fields,
394 size_t *iter_field, size_t nesting)
395 {
396 const struct ustctl_field *variant = &fields[*iter_field];
397 uint32_t i;
398 int ret;
399 char identifier[LTTNG_UST_SYM_NAME_LEN];
400
401 if (variant->type.atype != ustctl_atype_variant) {
402 ret = -EINVAL;
403 goto end;
404 }
405 (*iter_field)++;
406 sanitize_ctf_identifier(identifier, tag_name);
407 if (alignment) {
408 ret = print_tabs(session, nesting);
409 if (ret) {
410 goto end;
411 }
412 ret = lttng_metadata_printf(session,
413 "struct { } align(%u) _%s_padding;\n",
414 alignment * CHAR_BIT,
415 variant->name);
416 if (ret) {
417 goto end;
418 }
419 }
420 ret = print_tabs(session, nesting);
421 if (ret) {
422 goto end;
423 }
424 ret = lttng_metadata_printf(session,
425 "variant <_%s> {\n",
426 identifier);
427 if (ret) {
428 goto end;
429 }
430
431 for (i = 0; i < nr_choices; i++) {
432 if (*iter_field >= nr_fields) {
433 ret = -EOVERFLOW;
434 goto end;
435 }
436 ret = _lttng_field_statedump(session,
437 fields, nr_fields,
438 iter_field, nesting + 1);
439 if (ret) {
440 goto end;
441 }
442 }
443 sanitize_ctf_identifier(identifier, variant->name);
444 ret = print_tabs(session, nesting);
445 if (ret) {
446 goto end;
447 }
448 ret = lttng_metadata_printf(session,
449 "} _%s;\n",
450 identifier);
451 if (ret) {
452 goto end;
453 }
454 end:
455 return ret;
456 }
457
458 static
459 int _lttng_field_statedump(struct ust_registry_session *session,
460 const struct ustctl_field *fields, size_t nr_fields,
461 size_t *iter_field, size_t nesting)
462 {
463 int ret = 0;
464 const char *bo_be = " byte_order = be;";
465 const char *bo_le = " byte_order = le;";
466 const char *bo_native = "";
467 const char *bo_reverse;
468 const struct ustctl_field *field;
469
470 if (*iter_field >= nr_fields) {
471 ret = -EOVERFLOW;
472 goto end;
473 }
474 field = &fields[*iter_field];
475
476 if (session->byte_order == BIG_ENDIAN) {
477 bo_reverse = bo_le;
478 } else {
479 bo_reverse = bo_be;
480 }
481
482 switch (field->type.atype) {
483 case ustctl_atype_integer:
484 ret = print_tabs(session, nesting);
485 if (ret) {
486 goto end;
487 }
488 ret = lttng_metadata_printf(session,
489 "integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } _%s;\n",
490 field->type.u.integer.size,
491 field->type.u.integer.alignment,
492 field->type.u.integer.signedness,
493 (field->type.u.integer.encoding == ustctl_encode_none)
494 ? "none"
495 : (field->type.u.integer.encoding == ustctl_encode_UTF8)
496 ? "UTF8"
497 : "ASCII",
498 field->type.u.integer.base,
499 field->type.u.integer.reverse_byte_order ? bo_reverse : bo_native,
500 field->name);
501 (*iter_field)++;
502 break;
503 case ustctl_atype_enum:
504 ret = ust_metadata_enum_statedump(session,
505 field->type.u.legacy.basic.enumeration.name,
506 field->type.u.legacy.basic.enumeration.id,
507 &field->type.u.legacy.basic.enumeration.container_type,
508 field->name, iter_field, nesting);
509 break;
510 case ustctl_atype_float:
511 ret = print_tabs(session, nesting);
512 if (ret) {
513 goto end;
514 }
515 ret = lttng_metadata_printf(session,
516 "floating_point { exp_dig = %u; mant_dig = %u; align = %u;%s } _%s;\n",
517 field->type.u._float.exp_dig,
518 field->type.u._float.mant_dig,
519 field->type.u._float.alignment,
520 field->type.u._float.reverse_byte_order ? bo_reverse : bo_native,
521 field->name);
522 (*iter_field)++;
523 break;
524 case ustctl_atype_array:
525 {
526 const struct ustctl_basic_type *elem_type;
527
528 ret = print_tabs(session, nesting);
529 if (ret) {
530 goto end;
531 }
532 elem_type = &field->type.u.legacy.array.elem_type;
533 /* Only integers are currently supported in arrays. */
534 if (elem_type->atype != ustctl_atype_integer) {
535 ret = -EINVAL;
536 goto end;
537 }
538 ret = lttng_metadata_printf(session,
539 "integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } _%s[%u];\n",
540 elem_type->u.basic.integer.size,
541 elem_type->u.basic.integer.alignment,
542 elem_type->u.basic.integer.signedness,
543 (elem_type->u.basic.integer.encoding == ustctl_encode_none)
544 ? "none"
545 : (elem_type->u.basic.integer.encoding == ustctl_encode_UTF8)
546 ? "UTF8"
547 : "ASCII",
548 elem_type->u.basic.integer.base,
549 elem_type->u.basic.integer.reverse_byte_order ? bo_reverse : bo_native,
550 field->name, field->type.u.legacy.array.length);
551 (*iter_field)++;
552 break;
553 }
554 case ustctl_atype_array_nestable:
555 {
556 uint32_t array_length;
557 const struct ustctl_field *array_nestable;
558 const struct ustctl_type *elem_type;
559
560 array_length = field->type.u.array_nestable.length;
561 (*iter_field)++;
562
563 if (*iter_field >= nr_fields) {
564 ret = -EOVERFLOW;
565 goto end;
566 }
567 array_nestable = &fields[*iter_field];
568 elem_type = &array_nestable->type;
569
570 /* Only integers are currently supported in arrays. */
571 if (elem_type->atype != ustctl_atype_integer) {
572 ret = -EINVAL;
573 goto end;
574 }
575
576 if (field->type.u.array_nestable.alignment) {
577 ret = print_tabs(session, nesting);
578 if (ret) {
579 goto end;
580 }
581 ret = lttng_metadata_printf(session,
582 "struct { } align(%u) _%s_padding;\n",
583 field->type.u.array_nestable.alignment * CHAR_BIT,
584 field->name);
585 if (ret) {
586 goto end;
587 }
588 }
589
590 ret = print_tabs(session, nesting);
591 if (ret) {
592 goto end;
593 }
594 ret = lttng_metadata_printf(session,
595 "integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } _%s[%u];\n",
596 elem_type->u.integer.size,
597 elem_type->u.integer.alignment,
598 elem_type->u.integer.signedness,
599 (elem_type->u.integer.encoding == ustctl_encode_none)
600 ? "none"
601 : (elem_type->u.integer.encoding == ustctl_encode_UTF8)
602 ? "UTF8"
603 : "ASCII",
604 elem_type->u.integer.base,
605 elem_type->u.integer.reverse_byte_order ? bo_reverse : bo_native,
606 field->name, array_length);
607 (*iter_field)++;
608 break;
609 }
610 case ustctl_atype_sequence:
611 {
612 const struct ustctl_basic_type *elem_type;
613 const struct ustctl_basic_type *length_type;
614
615 elem_type = &field->type.u.legacy.sequence.elem_type;
616 length_type = &field->type.u.legacy.sequence.length_type;
617 ret = print_tabs(session, nesting);
618 if (ret) {
619 goto end;
620 }
621
622 /* Only integers are currently supported in sequences. */
623 if (elem_type->atype != ustctl_atype_integer) {
624 ret = -EINVAL;
625 goto end;
626 }
627
628 ret = lttng_metadata_printf(session,
629 "integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } __%s_length;\n",
630 length_type->u.basic.integer.size,
631 (unsigned int) length_type->u.basic.integer.alignment,
632 length_type->u.basic.integer.signedness,
633 (length_type->u.basic.integer.encoding == ustctl_encode_none)
634 ? "none"
635 : ((length_type->u.basic.integer.encoding == ustctl_encode_UTF8)
636 ? "UTF8"
637 : "ASCII"),
638 length_type->u.basic.integer.base,
639 length_type->u.basic.integer.reverse_byte_order ? bo_reverse : bo_native,
640 field->name);
641 if (ret) {
642 goto end;
643 }
644
645 ret = print_tabs(session, nesting);
646 if (ret) {
647 goto end;
648 }
649 ret = lttng_metadata_printf(session,
650 "integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } _%s[ __%s_length ];\n",
651 elem_type->u.basic.integer.size,
652 (unsigned int) elem_type->u.basic.integer.alignment,
653 elem_type->u.basic.integer.signedness,
654 (elem_type->u.basic.integer.encoding == ustctl_encode_none)
655 ? "none"
656 : ((elem_type->u.basic.integer.encoding == ustctl_encode_UTF8)
657 ? "UTF8"
658 : "ASCII"),
659 elem_type->u.basic.integer.base,
660 elem_type->u.basic.integer.reverse_byte_order ? bo_reverse : bo_native,
661 field->name,
662 field->name);
663 (*iter_field)++;
664 break;
665 }
666 case ustctl_atype_sequence_nestable:
667 {
668 const struct ustctl_field *sequence_nestable;
669 const struct ustctl_type *elem_type;
670
671 (*iter_field)++;
672 if (*iter_field >= nr_fields) {
673 ret = -EOVERFLOW;
674 goto end;
675 }
676 sequence_nestable = &fields[*iter_field];
677 elem_type = &sequence_nestable->type;
678
679 /* Only integers are currently supported in sequences. */
680 if (elem_type->atype != ustctl_atype_integer) {
681 ret = -EINVAL;
682 goto end;
683 }
684
685 if (field->type.u.sequence_nestable.alignment) {
686 ret = print_tabs(session, nesting);
687 if (ret) {
688 goto end;
689 }
690 ret = lttng_metadata_printf(session,
691 "struct { } align(%u) _%s_padding;\n",
692 field->type.u.sequence_nestable.alignment * CHAR_BIT,
693 field->name);
694 if (ret) {
695 goto end;
696 }
697 }
698
699 ret = print_tabs(session, nesting);
700 if (ret) {
701 goto end;
702 }
703 ret = lttng_metadata_printf(session,
704 "integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } _%s[ _%s ];\n",
705 elem_type->u.integer.size,
706 (unsigned int) elem_type->u.integer.alignment,
707 elem_type->u.integer.signedness,
708 (elem_type->u.integer.encoding == ustctl_encode_none)
709 ? "none"
710 : ((elem_type->u.integer.encoding == ustctl_encode_UTF8)
711 ? "UTF8"
712 : "ASCII"),
713 elem_type->u.integer.base,
714 elem_type->u.integer.reverse_byte_order ? bo_reverse : bo_native,
715 field->name,
716 field->type.u.sequence_nestable.length_name);
717 (*iter_field)++;
718 break;
719 }
720 case ustctl_atype_string:
721 /* Default encoding is UTF8 */
722 ret = print_tabs(session, nesting);
723 if (ret) {
724 goto end;
725 }
726 ret = lttng_metadata_printf(session,
727 "string%s _%s;\n",
728 field->type.u.string.encoding == ustctl_encode_ASCII ?
729 " { encoding = ASCII; }" : "",
730 field->name);
731 (*iter_field)++;
732 break;
733 case ustctl_atype_variant:
734 ret = _lttng_variant_statedump(session,
735 field->type.u.legacy.variant.nr_choices,
736 field->type.u.legacy.variant.tag_name,
737 0,
738 fields, nr_fields, iter_field, nesting);
739 if (ret) {
740 goto end;
741 }
742 break;
743 case ustctl_atype_variant_nestable:
744 ret = _lttng_variant_statedump(session,
745 field->type.u.variant_nestable.nr_choices,
746 field->type.u.variant_nestable.tag_name,
747 field->type.u.variant_nestable.alignment,
748 fields, nr_fields, iter_field, nesting);
749 if (ret) {
750 goto end;
751 }
752 break;
753 case ustctl_atype_struct:
754 if (field->type.u.legacy._struct.nr_fields != 0) {
755 /* Currently only 0-length structures are supported. */
756 ret = -EINVAL;
757 goto end;
758 }
759 ret = print_tabs(session, nesting);
760 if (ret) {
761 goto end;
762 }
763 ret = lttng_metadata_printf(session,
764 "struct {} _%s;\n",
765 field->name);
766 (*iter_field)++;
767 break;
768 case ustctl_atype_struct_nestable:
769 if (field->type.u.struct_nestable.nr_fields != 0) {
770 /* Currently only 0-length structures are supported. */
771 ret = -EINVAL;
772 goto end;
773 }
774 ret = print_tabs(session, nesting);
775 if (ret) {
776 goto end;
777 }
778 if (field->type.u.struct_nestable.alignment) {
779 ret = lttng_metadata_printf(session,
780 "struct {} align(%u) _%s;\n",
781 field->type.u.struct_nestable.alignment * CHAR_BIT,
782 field->name);
783 if (ret) {
784 goto end;
785 }
786 } else {
787 ret = lttng_metadata_printf(session,
788 "struct {} _%s;\n",
789 field->name);
790 }
791 (*iter_field)++;
792 break;
793 case ustctl_atype_enum_nestable:
794 {
795 const struct ustctl_field *container_field;
796 const struct ustctl_type *container_type;
797
798 (*iter_field)++;
799 if (*iter_field >= nr_fields) {
800 ret = -EOVERFLOW;
801 goto end;
802 }
803 container_field = &fields[*iter_field];
804 container_type = &container_field->type;
805
806 /* Only integers are supported as container types. */
807 if (container_type->atype != ustctl_atype_integer) {
808 ret = -EINVAL;
809 goto end;
810 }
811 ret = ust_metadata_enum_statedump(session,
812 field->type.u.enum_nestable.name,
813 field->type.u.enum_nestable.id,
814 &container_type->u.integer,
815 field->name, iter_field, nesting);
816 break;
817 }
818 default:
819 ret = -EINVAL;
820 }
821 end:
822 return ret;
823 }
824
825 static
826 int _lttng_context_metadata_statedump(struct ust_registry_session *session,
827 size_t nr_ctx_fields,
828 struct ustctl_field *ctx)
829 {
830 int ret = 0;
831 size_t i = 0;
832
833 if (!ctx)
834 return 0;
835 for (;;) {
836 if (i >= nr_ctx_fields) {
837 break;
838 }
839 ret = _lttng_field_statedump(session, ctx,
840 nr_ctx_fields, &i, 2);
841 if (ret) {
842 break;
843 }
844 }
845 return ret;
846 }
847
848 static
849 int _lttng_fields_metadata_statedump(struct ust_registry_session *session,
850 struct ust_registry_event *event)
851 {
852 int ret = 0;
853 size_t i = 0;
854
855 for (;;) {
856 if (i >= event->nr_fields) {
857 break;
858 }
859 ret = _lttng_field_statedump(session, event->fields,
860 event->nr_fields, &i, 2);
861 if (ret) {
862 break;
863 }
864 }
865 return ret;
866 }
867
868 /*
869 * Should be called with session registry mutex held.
870 */
871 int ust_metadata_event_statedump(struct ust_registry_session *session,
872 struct ust_registry_channel *chan,
873 struct ust_registry_event *event)
874 {
875 int ret = 0;
876
877 /* Don't dump metadata events */
878 if (chan->chan_id == -1U)
879 return 0;
880
881 ret = lttng_metadata_printf(session,
882 "event {\n"
883 " name = \"%s\";\n"
884 " id = %u;\n"
885 " stream_id = %u;\n",
886 event->name,
887 event->id,
888 chan->chan_id);
889 if (ret) {
890 goto end;
891 }
892
893 ret = lttng_metadata_printf(session,
894 " loglevel = %d;\n",
895 event->loglevel_value);
896 if (ret) {
897 goto end;
898 }
899
900 if (event->model_emf_uri) {
901 ret = lttng_metadata_printf(session,
902 " model.emf.uri = \"%s\";\n",
903 event->model_emf_uri);
904 if (ret) {
905 goto end;
906 }
907 }
908
909 ret = lttng_metadata_printf(session,
910 " fields := struct {\n"
911 );
912 if (ret) {
913 goto end;
914 }
915
916 ret = _lttng_fields_metadata_statedump(session, event);
917 if (ret) {
918 goto end;
919 }
920
921 ret = lttng_metadata_printf(session,
922 " };\n"
923 "};\n\n");
924 if (ret) {
925 goto end;
926 }
927 event->metadata_dumped = 1;
928
929 end:
930 return ret;
931 }
932
933 /*
934 * Should be called with session registry mutex held.
935 */
936 int ust_metadata_channel_statedump(struct ust_registry_session *session,
937 struct ust_registry_channel *chan)
938 {
939 int ret = 0;
940
941 /* Don't dump metadata events */
942 if (chan->chan_id == -1U)
943 return 0;
944
945 if (!chan->header_type)
946 return -EINVAL;
947
948 ret = lttng_metadata_printf(session,
949 "stream {\n"
950 " id = %u;\n"
951 " event.header := %s;\n"
952 " packet.context := struct packet_context;\n",
953 chan->chan_id,
954 chan->header_type == USTCTL_CHANNEL_HEADER_COMPACT ?
955 "struct event_header_compact" :
956 "struct event_header_large");
957 if (ret) {
958 goto end;
959 }
960
961 if (chan->ctx_fields) {
962 ret = lttng_metadata_printf(session,
963 " event.context := struct {\n");
964 if (ret) {
965 goto end;
966 }
967 }
968 ret = _lttng_context_metadata_statedump(session,
969 chan->nr_ctx_fields,
970 chan->ctx_fields);
971 if (ret) {
972 goto end;
973 }
974 if (chan->ctx_fields) {
975 ret = lttng_metadata_printf(session,
976 " };\n");
977 if (ret) {
978 goto end;
979 }
980 }
981
982 ret = lttng_metadata_printf(session,
983 "};\n\n");
984 /* Flag success of metadata dump. */
985 chan->metadata_dumped = 1;
986
987 end:
988 return ret;
989 }
990
991 static
992 int _lttng_stream_packet_context_declare(struct ust_registry_session *session)
993 {
994 return lttng_metadata_printf(session,
995 "struct packet_context {\n"
996 " uint64_clock_monotonic_t timestamp_begin;\n"
997 " uint64_clock_monotonic_t timestamp_end;\n"
998 " uint64_t content_size;\n"
999 " uint64_t packet_size;\n"
1000 " uint64_t packet_seq_num;\n"
1001 " unsigned long events_discarded;\n"
1002 " uint32_t cpu_id;\n"
1003 "};\n\n"
1004 );
1005 }
1006
1007 /*
1008 * Compact header:
1009 * id: range: 0 - 30.
1010 * id 31 is reserved to indicate an extended header.
1011 *
1012 * Large header:
1013 * id: range: 0 - 65534.
1014 * id 65535 is reserved to indicate an extended header.
1015 */
1016 static
1017 int _lttng_event_header_declare(struct ust_registry_session *session)
1018 {
1019 return lttng_metadata_printf(session,
1020 "struct event_header_compact {\n"
1021 " enum : uint5_t { compact = 0 ... 30, extended = 31 } id;\n"
1022 " variant <id> {\n"
1023 " struct {\n"
1024 " uint27_clock_monotonic_t timestamp;\n"
1025 " } compact;\n"
1026 " struct {\n"
1027 " uint32_t id;\n"
1028 " uint64_clock_monotonic_t timestamp;\n"
1029 " } extended;\n"
1030 " } v;\n"
1031 "} align(%u);\n"
1032 "\n"
1033 "struct event_header_large {\n"
1034 " enum : uint16_t { compact = 0 ... 65534, extended = 65535 } id;\n"
1035 " variant <id> {\n"
1036 " struct {\n"
1037 " uint32_clock_monotonic_t timestamp;\n"
1038 " } compact;\n"
1039 " struct {\n"
1040 " uint32_t id;\n"
1041 " uint64_clock_monotonic_t timestamp;\n"
1042 " } extended;\n"
1043 " } v;\n"
1044 "} align(%u);\n\n",
1045 session->uint32_t_alignment,
1046 session->uint16_t_alignment
1047 );
1048 }
1049
1050 /*
1051 * The offset between monotonic and realtime clock can be negative if
1052 * the system sets the REALTIME clock to 0 after boot.
1053 */
1054 static
1055 int measure_single_clock_offset(struct offset_sample *sample)
1056 {
1057 uint64_t monotonic_avg, monotonic[2], measure_delta, realtime;
1058 uint64_t tcf = trace_clock_freq();
1059 struct timespec rts = { 0, 0 };
1060 int ret;
1061
1062 monotonic[0] = trace_clock_read64();
1063 ret = lttng_clock_gettime(CLOCK_REALTIME, &rts);
1064 if (ret < 0) {
1065 return ret;
1066 }
1067 monotonic[1] = trace_clock_read64();
1068 measure_delta = monotonic[1] - monotonic[0];
1069 if (measure_delta > sample->measure_delta) {
1070 /*
1071 * Discard value if it took longer to read than the best
1072 * sample so far.
1073 */
1074 return 0;
1075 }
1076 monotonic_avg = (monotonic[0] + monotonic[1]) >> 1;
1077 realtime = (uint64_t) rts.tv_sec * tcf;
1078 if (tcf == NSEC_PER_SEC) {
1079 realtime += rts.tv_nsec;
1080 } else {
1081 realtime += (uint64_t) rts.tv_nsec * tcf / NSEC_PER_SEC;
1082 }
1083 sample->offset = (int64_t) realtime - monotonic_avg;
1084 sample->measure_delta = measure_delta;
1085 return 0;
1086 }
1087
1088 /*
1089 * Approximation of NTP time of day to clock monotonic correlation,
1090 * taken at start of trace. Keep the measurement that took the less time
1091 * to complete, thus removing imprecision caused by preemption.
1092 * May return a negative offset.
1093 */
1094 static
1095 int64_t measure_clock_offset(void)
1096 {
1097 int i;
1098 struct offset_sample offset_best_sample = {
1099 .offset = 0,
1100 .measure_delta = UINT64_MAX,
1101 };
1102
1103 for (i = 0; i < NR_CLOCK_OFFSET_SAMPLES; i++) {
1104 if (measure_single_clock_offset(&offset_best_sample)) {
1105 return 0;
1106 }
1107 }
1108 return offset_best_sample.offset;
1109 }
1110
1111 static
1112 int print_metadata_session_information(struct ust_registry_session *registry)
1113 {
1114 int ret;
1115 struct ltt_session *session = NULL;
1116 char creation_datetime[ISO8601_STR_LEN];
1117
1118 rcu_read_lock();
1119 session = session_find_by_id(registry->tracing_id);
1120 if (!session) {
1121 ret = -1;
1122 goto error;
1123 }
1124
1125 /* Print the trace name */
1126 ret = lttng_metadata_printf(registry, " trace_name = \"");
1127 if (ret) {
1128 goto error;
1129 }
1130
1131 /*
1132 * This is necessary since the creation time is present in the session
1133 * name when it is generated.
1134 */
1135 if (session->has_auto_generated_name) {
1136 ret = print_escaped_ctf_string(registry, DEFAULT_SESSION_NAME);
1137 } else {
1138 ret = print_escaped_ctf_string(registry, session->name);
1139 }
1140 if (ret) {
1141 goto error;
1142 }
1143
1144 ret = lttng_metadata_printf(registry, "\";\n");
1145 if (ret) {
1146 goto error;
1147 }
1148
1149 /* Prepare creation time */
1150 ret = time_to_iso8601_str(session->creation_time, creation_datetime,
1151 sizeof(creation_datetime));
1152 if (ret) {
1153 goto error;
1154 }
1155
1156 /* Output the reste of the information */
1157 ret = lttng_metadata_printf(registry,
1158 " trace_creation_datetime = \"%s\";\n"
1159 " hostname = \"%s\";\n",
1160 creation_datetime, session->hostname);
1161 if (ret) {
1162 goto error;
1163 }
1164
1165 error:
1166 if (session) {
1167 session_put(session);
1168 }
1169 rcu_read_unlock();
1170 return ret;
1171 }
1172
1173 static
1174 int print_metadata_app_information(struct ust_registry_session *registry,
1175 struct ust_app *app)
1176 {
1177 int ret;
1178 char datetime[ISO8601_STR_LEN];
1179
1180 if (!app) {
1181 ret = 0;
1182 goto end;
1183 }
1184
1185 ret = time_to_iso8601_str(
1186 app->registration_time, datetime, sizeof(datetime));
1187 if (ret) {
1188 goto end;
1189 }
1190
1191 ret = lttng_metadata_printf(registry,
1192 " tracer_patchlevel = %u;\n"
1193 " vpid = %d;\n"
1194 " procname = \"%s\";\n"
1195 " vpid_datetime = \"%s\";\n",
1196 app->version.patchlevel, (int) app->pid, app->name,
1197 datetime);
1198
1199 end:
1200 return ret;
1201 }
1202
1203 /*
1204 * Should be called with session registry mutex held.
1205 */
1206 int ust_metadata_session_statedump(struct ust_registry_session *session,
1207 struct ust_app *app,
1208 uint32_t major,
1209 uint32_t minor)
1210 {
1211 char uuid_s[LTTNG_UUID_STR_LEN],
1212 clock_uuid_s[LTTNG_UUID_STR_LEN];
1213 int ret = 0;
1214
1215 assert(session);
1216
1217 lttng_uuid_to_str(session->uuid, uuid_s);
1218
1219 /* For crash ABI */
1220 ret = lttng_metadata_printf(session,
1221 "/* CTF %u.%u */\n\n",
1222 CTF_SPEC_MAJOR,
1223 CTF_SPEC_MINOR);
1224 if (ret) {
1225 goto end;
1226 }
1227
1228 ret = lttng_metadata_printf(session,
1229 "typealias integer { size = 8; align = %u; signed = false; } := uint8_t;\n"
1230 "typealias integer { size = 16; align = %u; signed = false; } := uint16_t;\n"
1231 "typealias integer { size = 32; align = %u; signed = false; } := uint32_t;\n"
1232 "typealias integer { size = 64; align = %u; signed = false; } := uint64_t;\n"
1233 "typealias integer { size = %u; align = %u; signed = false; } := unsigned long;\n"
1234 "typealias integer { size = 5; align = 1; signed = false; } := uint5_t;\n"
1235 "typealias integer { size = 27; align = 1; signed = false; } := uint27_t;\n"
1236 "\n"
1237 "trace {\n"
1238 " major = %u;\n"
1239 " minor = %u;\n"
1240 " uuid = \"%s\";\n"
1241 " byte_order = %s;\n"
1242 " packet.header := struct {\n"
1243 " uint32_t magic;\n"
1244 " uint8_t uuid[16];\n"
1245 " uint32_t stream_id;\n"
1246 " uint64_t stream_instance_id;\n"
1247 " };\n"
1248 "};\n\n",
1249 session->uint8_t_alignment,
1250 session->uint16_t_alignment,
1251 session->uint32_t_alignment,
1252 session->uint64_t_alignment,
1253 session->bits_per_long,
1254 session->long_alignment,
1255 CTF_SPEC_MAJOR,
1256 CTF_SPEC_MINOR,
1257 uuid_s,
1258 session->byte_order == BIG_ENDIAN ? "be" : "le"
1259 );
1260 if (ret) {
1261 goto end;
1262 }
1263
1264 ret = lttng_metadata_printf(session,
1265 "env {\n"
1266 " domain = \"ust\";\n"
1267 " tracer_name = \"lttng-ust\";\n"
1268 " tracer_major = %u;\n"
1269 " tracer_minor = %u;\n"
1270 " tracer_buffering_scheme = \"%s\";\n"
1271 " tracer_buffering_id = %u;\n"
1272 " architecture_bit_width = %u;\n",
1273 major,
1274 minor,
1275 app ? "pid" : "uid",
1276 app ? (int) app->pid : (int) session->tracing_uid,
1277 session->bits_per_long);
1278 if (ret) {
1279 goto end;
1280 }
1281
1282 ret = print_metadata_session_information(session);
1283 if (ret) {
1284 goto end;
1285 }
1286
1287 /*
1288 * If per-application registry, we can output extra information
1289 * about the application.
1290 */
1291 ret = print_metadata_app_information(session, app);
1292 if (ret) {
1293 goto end;
1294 }
1295
1296 ret = lttng_metadata_printf(session,
1297 "};\n\n"
1298 );
1299 if (ret) {
1300 goto end;
1301 }
1302
1303 ret = lttng_metadata_printf(session,
1304 "clock {\n"
1305 " name = \"%s\";\n",
1306 trace_clock_name()
1307 );
1308 if (ret) {
1309 goto end;
1310 }
1311
1312 if (!trace_clock_uuid(clock_uuid_s)) {
1313 ret = lttng_metadata_printf(session,
1314 " uuid = \"%s\";\n",
1315 clock_uuid_s
1316 );
1317 if (ret) {
1318 goto end;
1319 }
1320 }
1321
1322 ret = lttng_metadata_printf(session,
1323 " description = \"%s\";\n"
1324 " freq = %" PRIu64 "; /* Frequency, in Hz */\n"
1325 " /* clock value offset from Epoch is: offset * (1/freq) */\n"
1326 " offset = %" PRId64 ";\n"
1327 "};\n\n",
1328 trace_clock_description(),
1329 trace_clock_freq(),
1330 measure_clock_offset()
1331 );
1332 if (ret) {
1333 goto end;
1334 }
1335
1336 ret = lttng_metadata_printf(session,
1337 "typealias integer {\n"
1338 " size = 27; align = 1; signed = false;\n"
1339 " map = clock.%s.value;\n"
1340 "} := uint27_clock_monotonic_t;\n"
1341 "\n"
1342 "typealias integer {\n"
1343 " size = 32; align = %u; signed = false;\n"
1344 " map = clock.%s.value;\n"
1345 "} := uint32_clock_monotonic_t;\n"
1346 "\n"
1347 "typealias integer {\n"
1348 " size = 64; align = %u; signed = false;\n"
1349 " map = clock.%s.value;\n"
1350 "} := uint64_clock_monotonic_t;\n\n",
1351 trace_clock_name(),
1352 session->uint32_t_alignment,
1353 trace_clock_name(),
1354 session->uint64_t_alignment,
1355 trace_clock_name()
1356 );
1357 if (ret) {
1358 goto end;
1359 }
1360
1361 ret = _lttng_stream_packet_context_declare(session);
1362 if (ret) {
1363 goto end;
1364 }
1365
1366 ret = _lttng_event_header_declare(session);
1367 if (ret) {
1368 goto end;
1369 }
1370
1371 end:
1372 return ret;
1373 }
This page took 0.100574 seconds and 4 git commands to generate.