7f7fa7622247abb3e09288960429722d3f9cf8a1
[babeltrace.git] / formats / ctf / writer / event-types.c
1 /*
2 * event-types.c
3 *
4 * Babeltrace CTF Writer
5 *
6 * Copyright 2013 EfficiOS Inc.
7 *
8 * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 */
28
29 #include <babeltrace/ctf-writer/event-types.h>
30 #include <babeltrace/ctf-writer/event-types-internal.h>
31 #include <babeltrace/ctf-writer/writer-internal.h>
32 #include <babeltrace/compiler.h>
33 #include <babeltrace/endian.h>
34 #include <float.h>
35 #include <inttypes.h>
36 #include <stdlib.h>
37
38 struct range_overlap_query {
39 int64_t range_start, range_end;
40 int overlaps;
41 GQuark mapping_name;
42 };
43
44 static
45 void bt_ctf_field_type_integer_destroy(struct bt_ctf_ref *);
46 static
47 void bt_ctf_field_type_enumeration_destroy(struct bt_ctf_ref *);
48 static
49 void bt_ctf_field_type_floating_point_destroy(struct bt_ctf_ref *);
50 static
51 void bt_ctf_field_type_structure_destroy(struct bt_ctf_ref *);
52 static
53 void bt_ctf_field_type_variant_destroy(struct bt_ctf_ref *);
54 static
55 void bt_ctf_field_type_array_destroy(struct bt_ctf_ref *);
56 static
57 void bt_ctf_field_type_sequence_destroy(struct bt_ctf_ref *);
58 static
59 void bt_ctf_field_type_string_destroy(struct bt_ctf_ref *);
60
61 static
62 void (* const type_destroy_funcs[])(struct bt_ctf_ref *) = {
63 [CTF_TYPE_INTEGER] = bt_ctf_field_type_integer_destroy,
64 [CTF_TYPE_ENUM] =
65 bt_ctf_field_type_enumeration_destroy,
66 [CTF_TYPE_FLOAT] =
67 bt_ctf_field_type_floating_point_destroy,
68 [CTF_TYPE_STRUCT] = bt_ctf_field_type_structure_destroy,
69 [CTF_TYPE_VARIANT] = bt_ctf_field_type_variant_destroy,
70 [CTF_TYPE_ARRAY] = bt_ctf_field_type_array_destroy,
71 [CTF_TYPE_SEQUENCE] = bt_ctf_field_type_sequence_destroy,
72 [CTF_TYPE_STRING] = bt_ctf_field_type_string_destroy,
73 };
74
75 static
76 void generic_field_type_freeze(struct bt_ctf_field_type *);
77 static
78 void bt_ctf_field_type_enumeration_freeze(struct bt_ctf_field_type *);
79 static
80 void bt_ctf_field_type_structure_freeze(struct bt_ctf_field_type *);
81 static
82 void bt_ctf_field_type_variant_freeze(struct bt_ctf_field_type *);
83 static
84 void bt_ctf_field_type_array_freeze(struct bt_ctf_field_type *);
85 static
86 void bt_ctf_field_type_sequence_freeze(struct bt_ctf_field_type *);
87
88 static
89 type_freeze_func const type_freeze_funcs[] = {
90 [CTF_TYPE_INTEGER] = generic_field_type_freeze,
91 [CTF_TYPE_ENUM] = bt_ctf_field_type_enumeration_freeze,
92 [CTF_TYPE_FLOAT] = generic_field_type_freeze,
93 [CTF_TYPE_STRUCT] = bt_ctf_field_type_structure_freeze,
94 [CTF_TYPE_VARIANT] = bt_ctf_field_type_variant_freeze,
95 [CTF_TYPE_ARRAY] = bt_ctf_field_type_array_freeze,
96 [CTF_TYPE_SEQUENCE] = bt_ctf_field_type_sequence_freeze,
97 [CTF_TYPE_STRING] = generic_field_type_freeze,
98 };
99
100 static
101 int bt_ctf_field_type_integer_serialize(struct bt_ctf_field_type *,
102 struct metadata_context *);
103 static
104 int bt_ctf_field_type_enumeration_serialize(struct bt_ctf_field_type *,
105 struct metadata_context *);
106 static
107 int bt_ctf_field_type_floating_point_serialize(
108 struct bt_ctf_field_type *, struct metadata_context *);
109 static
110 int bt_ctf_field_type_structure_serialize(struct bt_ctf_field_type *,
111 struct metadata_context *);
112 static
113 int bt_ctf_field_type_variant_serialize(struct bt_ctf_field_type *,
114 struct metadata_context *);
115 static
116 int bt_ctf_field_type_array_serialize(struct bt_ctf_field_type *,
117 struct metadata_context *);
118 static
119 int bt_ctf_field_type_sequence_serialize(struct bt_ctf_field_type *,
120 struct metadata_context *);
121 static
122 int bt_ctf_field_type_string_serialize(struct bt_ctf_field_type *,
123 struct metadata_context *);
124
125 static
126 type_serialize_func const type_serialize_funcs[] = {
127 [CTF_TYPE_INTEGER] = bt_ctf_field_type_integer_serialize,
128 [CTF_TYPE_ENUM] =
129 bt_ctf_field_type_enumeration_serialize,
130 [CTF_TYPE_FLOAT] =
131 bt_ctf_field_type_floating_point_serialize,
132 [CTF_TYPE_STRUCT] =
133 bt_ctf_field_type_structure_serialize,
134 [CTF_TYPE_VARIANT] = bt_ctf_field_type_variant_serialize,
135 [CTF_TYPE_ARRAY] = bt_ctf_field_type_array_serialize,
136 [CTF_TYPE_SEQUENCE] = bt_ctf_field_type_sequence_serialize,
137 [CTF_TYPE_STRING] = bt_ctf_field_type_string_serialize,
138 };
139
140 static
141 void bt_ctf_field_type_integer_set_byte_order(struct bt_ctf_field_type *,
142 int byte_order);
143 static
144 void bt_ctf_field_type_floating_point_set_byte_order(
145 struct bt_ctf_field_type *, int byte_order);
146
147 static
148 void (* const set_byte_order_funcs[])(struct bt_ctf_field_type *,
149 int) = {
150 [CTF_TYPE_INTEGER] =
151 bt_ctf_field_type_integer_set_byte_order,
152 [CTF_TYPE_FLOAT] =
153 bt_ctf_field_type_floating_point_set_byte_order,
154 [CTF_TYPE_ENUM ... CTF_TYPE_SEQUENCE] = NULL,
155 };
156
157
158 static
159 void destroy_enumeration_mapping(struct enumeration_mapping *mapping)
160 {
161 g_free(mapping);
162 }
163
164 static
165 void destroy_structure_field(struct structure_field *field)
166 {
167 if (field->type) {
168 bt_ctf_field_type_put(field->type);
169 }
170
171 g_free(field);
172 }
173
174 static
175 void check_ranges_overlap(gpointer element, gpointer query)
176 {
177 struct enumeration_mapping *mapping = element;
178 struct range_overlap_query *overlap_query = query;
179
180 if (mapping->range_start <= overlap_query->range_end
181 && overlap_query->range_start <= mapping->range_end) {
182 overlap_query->overlaps = 1;
183 overlap_query->mapping_name = mapping->string;
184 }
185
186 overlap_query->overlaps |=
187 mapping->string == overlap_query->mapping_name;
188 }
189
190 static
191 void bt_ctf_field_type_init(struct bt_ctf_field_type *type)
192 {
193 enum ctf_type_id type_id = type->declaration->id;
194 int ret;
195
196 assert(type && (type_id > CTF_TYPE_UNKNOWN) &&
197 (type_id < NR_CTF_TYPES));
198
199 bt_ctf_ref_init(&type->ref_count);
200 type->freeze = type_freeze_funcs[type_id];
201 type->serialize = type_serialize_funcs[type_id];
202 ret = bt_ctf_field_type_set_byte_order(type, BT_CTF_BYTE_ORDER_NATIVE);
203 assert(!ret);
204 type->declaration->alignment = 1;
205 }
206
207 static
208 int add_structure_field(GPtrArray *fields,
209 GHashTable *field_name_to_index,
210 struct bt_ctf_field_type *field_type,
211 const char *field_name)
212 {
213 int ret = 0;
214 GQuark name_quark = g_quark_from_string(field_name);
215 struct structure_field *field;
216
217 /* Make sure structure does not contain a field of the same name */
218 if (g_hash_table_lookup_extended(field_name_to_index,
219 GUINT_TO_POINTER(name_quark), NULL, NULL)) {
220 ret = -1;
221 goto end;
222 }
223
224 field = g_new0(struct structure_field, 1);
225 if (!field) {
226 ret = -1;
227 goto end;
228 }
229
230 bt_ctf_field_type_get(field_type);
231 field->name = name_quark;
232 field->type = field_type;
233 g_hash_table_insert(field_name_to_index,
234 (gpointer) (unsigned long) name_quark,
235 (gpointer) (unsigned long) fields->len);
236 g_ptr_array_add(fields, field);
237 bt_ctf_field_type_freeze(field_type);
238 end:
239 return ret;
240 }
241
242 BT_HIDDEN
243 int bt_ctf_field_type_validate(struct bt_ctf_field_type *type)
244 {
245 int ret = 0;
246
247 if (!type) {
248 ret = -1;
249 goto end;
250 }
251
252 if (type->declaration->id == CTF_TYPE_ENUM) {
253 struct bt_ctf_field_type_enumeration *enumeration =
254 container_of(type, struct bt_ctf_field_type_enumeration,
255 parent);
256
257 ret = enumeration->entries->len ? 0 : -1;
258 }
259 end:
260 return ret;
261 }
262
263 struct bt_ctf_field_type *bt_ctf_field_type_integer_create(unsigned int size)
264 {
265 struct bt_ctf_field_type_integer *integer =
266 g_new0(struct bt_ctf_field_type_integer, 1);
267
268 if (!integer || size > 64) {
269 return NULL;
270 }
271
272 integer->parent.declaration = &integer->declaration.p;
273 integer->parent.declaration->id = CTF_TYPE_INTEGER;
274 integer->declaration.len = size;
275 integer->declaration.base = BT_CTF_INTEGER_BASE_DECIMAL;
276 integer->declaration.encoding = CTF_STRING_NONE;
277 bt_ctf_field_type_init(&integer->parent);
278 return &integer->parent;
279 }
280
281 int bt_ctf_field_type_integer_set_signed(struct bt_ctf_field_type *type,
282 int is_signed)
283 {
284 int ret = 0;
285 struct bt_ctf_field_type_integer *integer;
286
287 if (!type || type->frozen ||
288 type->declaration->id != CTF_TYPE_INTEGER) {
289 ret = -1;
290 goto end;
291 }
292
293 integer = container_of(type, struct bt_ctf_field_type_integer, parent);
294 if (is_signed && integer->declaration.len <= 1) {
295 ret = -1;
296 goto end;
297 }
298
299 integer->declaration.signedness = !!is_signed;
300 end:
301 return ret;
302 }
303
304 int bt_ctf_field_type_integer_set_base(struct bt_ctf_field_type *type,
305 enum bt_ctf_integer_base base)
306 {
307 int ret = 0;
308
309 if (!type || type->frozen ||
310 type->declaration->id != CTF_TYPE_INTEGER) {
311 ret = -1;
312 goto end;
313 }
314
315 switch (base) {
316 case BT_CTF_INTEGER_BASE_BINARY:
317 case BT_CTF_INTEGER_BASE_OCTAL:
318 case BT_CTF_INTEGER_BASE_DECIMAL:
319 case BT_CTF_INTEGER_BASE_HEXADECIMAL:
320 {
321 struct bt_ctf_field_type_integer *integer = container_of(type,
322 struct bt_ctf_field_type_integer, parent);
323 integer->declaration.base = base;
324 break;
325 }
326 default:
327 ret = -1;
328 }
329 end:
330 return ret;
331 }
332
333 int bt_ctf_field_type_integer_set_encoding(struct bt_ctf_field_type *type,
334 enum ctf_string_encoding encoding)
335 {
336 int ret = 0;
337 struct bt_ctf_field_type_integer *integer;
338
339 if (!type || type->frozen ||
340 (type->declaration->id != CTF_TYPE_INTEGER) ||
341 (encoding < CTF_STRING_NONE) ||
342 (encoding >= CTF_STRING_UNKNOWN)) {
343 ret = -1;
344 goto end;
345 }
346
347 integer = container_of(type, struct bt_ctf_field_type_integer, parent);
348 integer->declaration.encoding = encoding;
349 end:
350 return ret;
351 }
352
353 struct bt_ctf_field_type *bt_ctf_field_type_enumeration_create(
354 struct bt_ctf_field_type *integer_container_type)
355 {
356 struct bt_ctf_field_type_enumeration *enumeration = NULL;
357
358 if (!integer_container_type) {
359 goto error;
360 }
361
362 enumeration = g_new0(struct bt_ctf_field_type_enumeration, 1);
363 if (!enumeration) {
364 goto error;
365 }
366
367 enumeration->parent.declaration = &enumeration->declaration.p;
368 enumeration->parent.declaration->id = CTF_TYPE_ENUM;
369 bt_ctf_field_type_get(integer_container_type);
370 enumeration->container = integer_container_type;
371 enumeration->entries = g_ptr_array_new_with_free_func(
372 (GDestroyNotify)destroy_enumeration_mapping);
373 bt_ctf_field_type_init(&enumeration->parent);
374 return &enumeration->parent;
375 error:
376 g_free(enumeration);
377 return NULL;
378 }
379
380 int bt_ctf_field_type_enumeration_add_mapping(
381 struct bt_ctf_field_type *type, const char *string,
382 int64_t range_start, int64_t range_end)
383 {
384 int ret = 0;
385 GQuark mapping_name;
386 struct enumeration_mapping *mapping;
387 struct bt_ctf_field_type_enumeration *enumeration;
388 struct range_overlap_query query;
389 char *escaped_string;
390
391 if (!type || (type->declaration->id != CTF_TYPE_ENUM) ||
392 type->frozen ||
393 (range_end < range_start)) {
394 ret = -1;
395 goto end;
396 }
397
398 if (!string || strlen(string) == 0) {
399 ret = -1;
400 goto end;
401 }
402
403 escaped_string = g_strescape(string, NULL);
404 if (!escaped_string) {
405 ret = -1;
406 goto end;
407 }
408
409 mapping_name = g_quark_from_string(escaped_string);
410 query = (struct range_overlap_query) { .range_start = range_start,
411 .range_end = range_end,
412 .mapping_name = mapping_name,
413 .overlaps = 0 };
414 enumeration = container_of(type, struct bt_ctf_field_type_enumeration,
415 parent);
416
417 /* Check that the range does not overlap with one already present */
418 g_ptr_array_foreach(enumeration->entries, check_ranges_overlap, &query);
419 if (query.overlaps) {
420 ret = -1;
421 goto error_free;
422 }
423
424 mapping = g_new(struct enumeration_mapping, 1);
425 if (!mapping) {
426 ret = -1;
427 goto error_free;
428 }
429
430 *mapping = (struct enumeration_mapping) {.range_start = range_start,
431 .range_end = range_end, .string = mapping_name};
432 g_ptr_array_add(enumeration->entries, mapping);
433 error_free:
434 free(escaped_string);
435 end:
436 return ret;
437 }
438
439 struct bt_ctf_field_type *bt_ctf_field_type_floating_point_create(void)
440 {
441 struct bt_ctf_field_type_floating_point *floating_point =
442 g_new0(struct bt_ctf_field_type_floating_point, 1);
443
444 if (!floating_point) {
445 goto end;
446 }
447
448 floating_point->declaration.sign = &floating_point->sign;
449 floating_point->declaration.mantissa = &floating_point->mantissa;
450 floating_point->declaration.exp = &floating_point->exp;
451 floating_point->sign.len = 1;
452 floating_point->parent.declaration = &floating_point->declaration.p;
453 floating_point->parent.declaration->id = CTF_TYPE_FLOAT;
454 floating_point->declaration.exp->len =
455 sizeof(float) * CHAR_BIT - FLT_MANT_DIG;
456 floating_point->declaration.mantissa->len = FLT_MANT_DIG - 1;
457 floating_point->sign.p.alignment = 1;
458 floating_point->mantissa.p.alignment = 1;
459 floating_point->exp.p.alignment = 1;
460
461 bt_ctf_field_type_init(&floating_point->parent);
462 end:
463 return floating_point ? &floating_point->parent : NULL;
464 }
465
466 int bt_ctf_field_type_floating_point_set_exponent_digits(
467 struct bt_ctf_field_type *type,
468 unsigned int exponent_digits)
469 {
470 int ret = 0;
471 struct bt_ctf_field_type_floating_point *floating_point;
472
473 if (!type || type->frozen ||
474 (type->declaration->id != CTF_TYPE_FLOAT)) {
475 ret = -1;
476 goto end;
477 }
478
479 floating_point = container_of(type,
480 struct bt_ctf_field_type_floating_point, parent);
481 if ((exponent_digits != sizeof(float) * CHAR_BIT - FLT_MANT_DIG) &&
482 (exponent_digits != sizeof(double) * CHAR_BIT - DBL_MANT_DIG) &&
483 (exponent_digits !=
484 sizeof(long double) * CHAR_BIT - LDBL_MANT_DIG)) {
485 ret = -1;
486 goto end;
487 }
488
489 floating_point->declaration.exp->len = exponent_digits;
490 end:
491 return ret;
492 }
493
494 int bt_ctf_field_type_floating_point_set_mantissa_digits(
495 struct bt_ctf_field_type *type,
496 unsigned int mantissa_digits)
497 {
498 int ret = 0;
499 struct bt_ctf_field_type_floating_point *floating_point;
500
501 if (!type || type->frozen ||
502 (type->declaration->id != CTF_TYPE_FLOAT)) {
503 ret = -1;
504 goto end;
505 }
506
507 floating_point = container_of(type,
508 struct bt_ctf_field_type_floating_point, parent);
509
510 if ((mantissa_digits != FLT_MANT_DIG) &&
511 (mantissa_digits != DBL_MANT_DIG) &&
512 (mantissa_digits != LDBL_MANT_DIG)) {
513 ret = -1;
514 goto end;
515 }
516
517 floating_point->declaration.mantissa->len = mantissa_digits - 1;
518 end:
519 return ret;
520 }
521
522 struct bt_ctf_field_type *bt_ctf_field_type_structure_create(void)
523 {
524 struct bt_ctf_field_type_structure *structure =
525 g_new0(struct bt_ctf_field_type_structure, 1);
526
527 if (!structure) {
528 goto error;
529 }
530
531 structure->parent.declaration = &structure->declaration.p;
532 structure->parent.declaration->id = CTF_TYPE_STRUCT;
533 bt_ctf_field_type_init(&structure->parent);
534 structure->fields = g_ptr_array_new_with_free_func(
535 (GDestroyNotify)destroy_structure_field);
536 structure->field_name_to_index = g_hash_table_new(NULL, NULL);
537 return &structure->parent;
538 error:
539 return NULL;
540 }
541
542 int bt_ctf_field_type_structure_add_field(struct bt_ctf_field_type *type,
543 struct bt_ctf_field_type *field_type,
544 const char *field_name)
545 {
546 int ret = 0;
547 struct bt_ctf_field_type_structure *structure;
548
549 if (!type || !field_type || type->frozen ||
550 validate_identifier(field_name) ||
551 (type->declaration->id != CTF_TYPE_STRUCT) ||
552 bt_ctf_field_type_validate(field_type)) {
553 goto end;
554 }
555
556 structure = container_of(type,
557 struct bt_ctf_field_type_structure, parent);
558 if (add_structure_field(structure->fields,
559 structure->field_name_to_index, field_type, field_name)) {
560 ret = -1;
561 goto end;
562 }
563
564 if (type->declaration->alignment < field_type->declaration->alignment) {
565 type->declaration->alignment =
566 field_type->declaration->alignment;
567 }
568 end:
569 return ret;
570 }
571
572 struct bt_ctf_field_type *bt_ctf_field_type_variant_create(
573 struct bt_ctf_field_type *enum_tag, const char *tag_name)
574 {
575 struct bt_ctf_field_type_variant *variant = NULL;
576
577 if (!enum_tag || validate_identifier(tag_name) ||
578 (enum_tag->declaration->id != CTF_TYPE_ENUM)) {
579 goto error;
580 }
581
582 variant = g_new0(struct bt_ctf_field_type_variant, 1);
583 if (!variant) {
584 goto error;
585 }
586
587 variant->parent.declaration = &variant->declaration.p;
588 variant->parent.declaration->id = CTF_TYPE_VARIANT;
589 variant->tag_name = g_string_new(tag_name);
590 bt_ctf_field_type_init(&variant->parent);
591 variant->field_name_to_index = g_hash_table_new(NULL, NULL);
592 variant->fields = g_ptr_array_new_with_free_func(
593 (GDestroyNotify)destroy_structure_field);
594 bt_ctf_field_type_get(enum_tag);
595 variant->tag = container_of(enum_tag,
596 struct bt_ctf_field_type_enumeration, parent);
597 return &variant->parent;
598 error:
599 return NULL;
600 }
601
602 int bt_ctf_field_type_variant_add_field(struct bt_ctf_field_type *type,
603 struct bt_ctf_field_type *field_type,
604 const char *field_name)
605 {
606 size_t i;
607 int ret = 0;
608 int name_found = 0;
609 struct bt_ctf_field_type_variant *variant;
610 GQuark field_name_quark = g_quark_from_string(field_name);
611
612 if (!type || !field_type || type->frozen ||
613 validate_identifier(field_name) ||
614 (type->declaration->id != CTF_TYPE_VARIANT) ||
615 bt_ctf_field_type_validate(field_type)) {
616 ret = -1;
617 goto end;
618 }
619
620 variant = container_of(type, struct bt_ctf_field_type_variant, parent);
621 /* Make sure this name is present in the enum tag */
622 for (i = 0; i < variant->tag->entries->len; i++) {
623 struct enumeration_mapping *mapping =
624 g_ptr_array_index(variant->tag->entries, i);
625
626 if (mapping->string == field_name_quark) {
627 name_found = 1;
628 break;
629 }
630 }
631
632 if (!name_found || add_structure_field(variant->fields,
633 variant->field_name_to_index, field_type, field_name)) {
634 ret = -1;
635 goto end;
636 }
637 end:
638 return ret;
639 }
640
641 struct bt_ctf_field_type *bt_ctf_field_type_array_create(
642 struct bt_ctf_field_type *element_type,
643 unsigned int length)
644 {
645 struct bt_ctf_field_type_array *array = NULL;
646
647 if (!element_type || length == 0 ||
648 bt_ctf_field_type_validate(element_type)) {
649 goto error;
650 }
651
652 array = g_new0(struct bt_ctf_field_type_array, 1);
653 if (!array) {
654 goto error;
655 }
656
657 array->parent.declaration = &array->declaration.p;
658 array->parent.declaration->id = CTF_TYPE_ARRAY;
659 bt_ctf_field_type_init(&array->parent);
660 bt_ctf_field_type_get(element_type);
661 array->element_type = element_type;
662 array->length = length;
663 array->parent.declaration->alignment =
664 element_type->declaration->alignment;
665 return &array->parent;
666 error:
667 return NULL;
668 }
669
670 struct bt_ctf_field_type *bt_ctf_field_type_sequence_create(
671 struct bt_ctf_field_type *element_type,
672 const char *length_field_name)
673 {
674 struct bt_ctf_field_type_sequence *sequence = NULL;
675
676 if (!element_type || validate_identifier(length_field_name) ||
677 bt_ctf_field_type_validate(element_type)) {
678 goto error;
679 }
680
681 sequence = g_new0(struct bt_ctf_field_type_sequence, 1);
682 if (!sequence) {
683 goto error;
684 }
685
686 sequence->parent.declaration = &sequence->declaration.p;
687 sequence->parent.declaration->id = CTF_TYPE_SEQUENCE;
688 bt_ctf_field_type_init(&sequence->parent);
689 bt_ctf_field_type_get(element_type);
690 sequence->element_type = element_type;
691 sequence->length_field_name = g_string_new(length_field_name);
692 sequence->parent.declaration->alignment =
693 element_type->declaration->alignment;
694 return &sequence->parent;
695 error:
696 return NULL;
697 }
698
699 struct bt_ctf_field_type *bt_ctf_field_type_string_create(void)
700 {
701 struct bt_ctf_field_type_string *string =
702 g_new0(struct bt_ctf_field_type_string, 1);
703
704 if (!string) {
705 return NULL;
706 }
707
708 string->parent.declaration = &string->declaration.p;
709 string->parent.declaration->id = CTF_TYPE_STRING;
710 bt_ctf_field_type_init(&string->parent);
711 string->declaration.encoding = CTF_STRING_UTF8;
712 string->parent.declaration->alignment = CHAR_BIT;
713 return &string->parent;
714 }
715
716 int bt_ctf_field_type_string_set_encoding(
717 struct bt_ctf_field_type *type,
718 enum ctf_string_encoding encoding)
719 {
720 int ret = 0;
721 struct bt_ctf_field_type_string *string;
722
723 if (!type || type->declaration->id != CTF_TYPE_STRING ||
724 (encoding != CTF_STRING_UTF8 &&
725 encoding != CTF_STRING_ASCII)) {
726 ret = -1;
727 goto end;
728 }
729
730 string = container_of(type, struct bt_ctf_field_type_string, parent);
731 string->declaration.encoding = encoding;
732 end:
733 return ret;
734 }
735
736 int bt_ctf_field_type_set_alignment(struct bt_ctf_field_type *type,
737 unsigned int alignment)
738 {
739 int ret = 0;
740
741 /* Alignment must be bit-aligned (1) or byte aligned */
742 if (!type || type->frozen || (alignment != 1 && (alignment & 0x7))) {
743 ret = -1;
744 goto end;
745 }
746
747 if (type->declaration->id == CTF_TYPE_STRING &&
748 alignment != CHAR_BIT) {
749 ret = -1;
750 goto end;
751 }
752
753 type->declaration->alignment = alignment;
754 ret = 0;
755 end:
756 return ret;
757 }
758
759 int bt_ctf_field_type_set_byte_order(struct bt_ctf_field_type *type,
760 enum bt_ctf_byte_order byte_order)
761 {
762 int ret = 0;
763 int internal_byte_order;
764 enum ctf_type_id type_id;
765
766 if (!type || type->frozen) {
767 ret = -1;
768 goto end;
769 }
770
771 type_id = type->declaration->id;
772 switch (byte_order) {
773 case BT_CTF_BYTE_ORDER_NATIVE:
774 internal_byte_order = (G_BYTE_ORDER == G_LITTLE_ENDIAN ?
775 LITTLE_ENDIAN : BIG_ENDIAN);
776 break;
777 case BT_CTF_BYTE_ORDER_LITTLE_ENDIAN:
778 internal_byte_order = LITTLE_ENDIAN;
779 break;
780 case BT_CTF_BYTE_ORDER_BIG_ENDIAN:
781 case BT_CTF_BYTE_ORDER_NETWORK:
782 internal_byte_order = BIG_ENDIAN;
783 break;
784 default:
785 ret = -1;
786 goto end;
787 }
788
789 if (set_byte_order_funcs[type_id]) {
790 set_byte_order_funcs[type_id](type, internal_byte_order);
791 }
792 end:
793 return ret;
794 }
795
796 void bt_ctf_field_type_get(struct bt_ctf_field_type *type)
797 {
798 if (!type) {
799 return;
800 }
801
802 bt_ctf_ref_get(&type->ref_count);
803 }
804
805 void bt_ctf_field_type_put(struct bt_ctf_field_type *type)
806 {
807 enum ctf_type_id type_id;
808
809 if (!type) {
810 return;
811 }
812
813 type_id = type->declaration->id;
814 assert(type_id > CTF_TYPE_UNKNOWN && type_id < NR_CTF_TYPES);
815 bt_ctf_ref_put(&type->ref_count, type_destroy_funcs[type_id]);
816 }
817
818 BT_HIDDEN
819 void bt_ctf_field_type_freeze(struct bt_ctf_field_type *type)
820 {
821 if (!type) {
822 return;
823 }
824
825 type->freeze(type);
826 }
827
828 BT_HIDDEN
829 enum ctf_type_id bt_ctf_field_type_get_type_id(
830 struct bt_ctf_field_type *type)
831 {
832 if (!type) {
833 return CTF_TYPE_UNKNOWN;
834 }
835
836 return type->declaration->id;
837 }
838
839 BT_HIDDEN
840 struct bt_ctf_field_type *bt_ctf_field_type_structure_get_type(
841 struct bt_ctf_field_type_structure *structure,
842 const char *name)
843 {
844 struct bt_ctf_field_type *type = NULL;
845 struct structure_field *field;
846 GQuark name_quark = g_quark_try_string(name);
847 size_t index;
848
849 if (!name_quark) {
850 goto end;
851 }
852
853 if (!g_hash_table_lookup_extended(structure->field_name_to_index,
854 GUINT_TO_POINTER(name_quark), NULL, (gpointer *)&index)) {
855 goto end;
856 }
857
858 field = structure->fields->pdata[index];
859 type = field->type;
860 end:
861 return type;
862 }
863
864 BT_HIDDEN
865 struct bt_ctf_field_type *bt_ctf_field_type_array_get_element_type(
866 struct bt_ctf_field_type_array *array)
867 {
868 assert(array);
869 return array->element_type;
870 }
871
872 BT_HIDDEN
873 struct bt_ctf_field_type *bt_ctf_field_type_sequence_get_element_type(
874 struct bt_ctf_field_type_sequence *sequence)
875 {
876 assert(sequence);
877 return sequence->element_type;
878 }
879
880 BT_HIDDEN
881 struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type(
882 struct bt_ctf_field_type_variant *variant,
883 int64_t tag_value)
884 {
885 struct bt_ctf_field_type *type = NULL;
886 GQuark field_name_quark;
887 gpointer index;
888 struct structure_field *field_entry;
889 struct range_overlap_query query = {.range_start = tag_value,
890 .range_end = tag_value, .mapping_name = 0, .overlaps = 0};
891
892 g_ptr_array_foreach(variant->tag->entries, check_ranges_overlap,
893 &query);
894 if (!query.overlaps) {
895 goto end;
896 }
897
898 field_name_quark = query.mapping_name;
899 if (!g_hash_table_lookup_extended(variant->field_name_to_index,
900 GUINT_TO_POINTER(field_name_quark), NULL, &index)) {
901 goto end;
902 }
903
904 field_entry = g_ptr_array_index(variant->fields, (size_t)index);
905 type = field_entry->type;
906 end:
907 return type;
908 }
909
910 BT_HIDDEN
911 int bt_ctf_field_type_serialize(struct bt_ctf_field_type *type,
912 struct metadata_context *context)
913 {
914 int ret;
915
916 if (!type || !context) {
917 ret = -1;
918 goto end;
919 }
920
921 ret = type->serialize(type, context);
922 end:
923 return ret;
924 }
925
926 static
927 void bt_ctf_field_type_integer_destroy(struct bt_ctf_ref *ref)
928 {
929 struct bt_ctf_field_type_integer *integer;
930
931 if (!ref) {
932 return;
933 }
934
935 integer = container_of(
936 container_of(ref, struct bt_ctf_field_type, ref_count),
937 struct bt_ctf_field_type_integer, parent);
938 g_free(integer);
939 }
940
941 static
942 void bt_ctf_field_type_enumeration_destroy(struct bt_ctf_ref *ref)
943 {
944 struct bt_ctf_field_type_enumeration *enumeration;
945
946 if (!ref) {
947 return;
948 }
949
950 enumeration = container_of(
951 container_of(ref, struct bt_ctf_field_type, ref_count),
952 struct bt_ctf_field_type_enumeration, parent);
953 g_ptr_array_free(enumeration->entries, TRUE);
954 bt_ctf_field_type_put(enumeration->container);
955 g_free(enumeration);
956 }
957
958 static
959 void bt_ctf_field_type_floating_point_destroy(struct bt_ctf_ref *ref)
960 {
961 struct bt_ctf_field_type_floating_point *floating_point;
962
963 if (!ref) {
964 return;
965 }
966
967 floating_point = container_of(
968 container_of(ref, struct bt_ctf_field_type, ref_count),
969 struct bt_ctf_field_type_floating_point, parent);
970 g_free(floating_point);
971 }
972
973 static
974 void bt_ctf_field_type_structure_destroy(struct bt_ctf_ref *ref)
975 {
976 struct bt_ctf_field_type_structure *structure;
977
978 if (!ref) {
979 return;
980 }
981
982 structure = container_of(
983 container_of(ref, struct bt_ctf_field_type, ref_count),
984 struct bt_ctf_field_type_structure, parent);
985 g_ptr_array_free(structure->fields, TRUE);
986 g_hash_table_destroy(structure->field_name_to_index);
987 g_free(structure);
988 }
989
990 static
991 void bt_ctf_field_type_variant_destroy(struct bt_ctf_ref *ref)
992 {
993 struct bt_ctf_field_type_variant *variant;
994
995 if (!ref) {
996 return;
997 }
998
999 variant = container_of(
1000 container_of(ref, struct bt_ctf_field_type, ref_count),
1001 struct bt_ctf_field_type_variant, parent);
1002 g_ptr_array_free(variant->fields, TRUE);
1003 g_hash_table_destroy(variant->field_name_to_index);
1004 g_string_free(variant->tag_name, TRUE);
1005 bt_ctf_field_type_put(&variant->tag->parent);
1006 g_free(variant);
1007 }
1008
1009 static
1010 void bt_ctf_field_type_array_destroy(struct bt_ctf_ref *ref)
1011 {
1012 struct bt_ctf_field_type_array *array;
1013
1014 if (!ref) {
1015 return;
1016 }
1017
1018 array = container_of(
1019 container_of(ref, struct bt_ctf_field_type, ref_count),
1020 struct bt_ctf_field_type_array, parent);
1021 bt_ctf_field_type_put(array->element_type);
1022 g_free(array);
1023 }
1024
1025 static
1026 void bt_ctf_field_type_sequence_destroy(struct bt_ctf_ref *ref)
1027 {
1028 struct bt_ctf_field_type_sequence *sequence;
1029
1030 if (!ref) {
1031 return;
1032 }
1033
1034 sequence = container_of(
1035 container_of(ref, struct bt_ctf_field_type, ref_count),
1036 struct bt_ctf_field_type_sequence, parent);
1037 bt_ctf_field_type_put(sequence->element_type);
1038 g_string_free(sequence->length_field_name, TRUE);
1039 g_free(sequence);
1040 }
1041
1042 static
1043 void bt_ctf_field_type_string_destroy(struct bt_ctf_ref *ref)
1044 {
1045 struct bt_ctf_field_type_string *string;
1046
1047 if (!ref) {
1048 return;
1049 }
1050
1051 string = container_of(
1052 container_of(ref, struct bt_ctf_field_type, ref_count),
1053 struct bt_ctf_field_type_string, parent);
1054 g_free(string);
1055 }
1056
1057 static
1058 void generic_field_type_freeze(struct bt_ctf_field_type *type)
1059 {
1060 type->frozen = 1;
1061 }
1062
1063 static
1064 void bt_ctf_field_type_enumeration_freeze(struct bt_ctf_field_type *type)
1065 {
1066 struct bt_ctf_field_type_enumeration *enumeration_type = container_of(
1067 type, struct bt_ctf_field_type_enumeration, parent);
1068
1069 generic_field_type_freeze(type);
1070 bt_ctf_field_type_freeze(enumeration_type->container);
1071 }
1072
1073 static
1074 void freeze_structure_field(struct structure_field *field)
1075 {
1076 bt_ctf_field_type_freeze(field->type);
1077 }
1078
1079 static
1080 void bt_ctf_field_type_structure_freeze(struct bt_ctf_field_type *type)
1081 {
1082 struct bt_ctf_field_type_structure *structure_type = container_of(
1083 type, struct bt_ctf_field_type_structure, parent);
1084
1085 generic_field_type_freeze(type);
1086 g_ptr_array_foreach(structure_type->fields, (GFunc)freeze_structure_field,
1087 NULL);
1088 }
1089
1090 static
1091 void bt_ctf_field_type_variant_freeze(struct bt_ctf_field_type *type)
1092 {
1093 struct bt_ctf_field_type_variant *variant_type = container_of(
1094 type, struct bt_ctf_field_type_variant, parent);
1095
1096 generic_field_type_freeze(type);
1097 g_ptr_array_foreach(variant_type->fields, (GFunc)freeze_structure_field,
1098 NULL);
1099 }
1100
1101 static
1102 void bt_ctf_field_type_array_freeze(struct bt_ctf_field_type *type)
1103 {
1104 struct bt_ctf_field_type_array *array_type = container_of(
1105 type, struct bt_ctf_field_type_array, parent);
1106
1107 generic_field_type_freeze(type);
1108 bt_ctf_field_type_freeze(array_type->element_type);
1109 }
1110
1111 static
1112 void bt_ctf_field_type_sequence_freeze(struct bt_ctf_field_type *type)
1113 {
1114 struct bt_ctf_field_type_sequence *sequence_type = container_of(
1115 type, struct bt_ctf_field_type_sequence, parent);
1116
1117 generic_field_type_freeze(type);
1118 bt_ctf_field_type_freeze(sequence_type->element_type);
1119 }
1120
1121 static
1122 const char *get_encoding_string(enum ctf_string_encoding encoding)
1123 {
1124 const char *encoding_string;
1125
1126 switch (encoding) {
1127 case CTF_STRING_NONE:
1128 encoding_string = "none";
1129 break;
1130 case CTF_STRING_ASCII:
1131 encoding_string = "ASCII";
1132 break;
1133 case CTF_STRING_UTF8:
1134 encoding_string = "UTF8";
1135 break;
1136 default:
1137 encoding_string = "unknown";
1138 break;
1139 }
1140
1141 return encoding_string;
1142 }
1143
1144 static
1145 const char *get_integer_base_string(enum bt_ctf_integer_base base)
1146 {
1147 const char *base_string;
1148
1149 switch (base) {
1150 case BT_CTF_INTEGER_BASE_DECIMAL:
1151 base_string = "decimal";
1152 break;
1153 case BT_CTF_INTEGER_BASE_HEXADECIMAL:
1154 base_string = "hexadecimal";
1155 break;
1156 case BT_CTF_INTEGER_BASE_OCTAL:
1157 base_string = "octal";
1158 break;
1159 case BT_CTF_INTEGER_BASE_BINARY:
1160 base_string = "binary";
1161 break;
1162 default:
1163 base_string = "unknown";
1164 break;
1165 }
1166
1167 return base_string;
1168 }
1169
1170 static
1171 int bt_ctf_field_type_integer_serialize(struct bt_ctf_field_type *type,
1172 struct metadata_context *context)
1173 {
1174 struct bt_ctf_field_type_integer *integer = container_of(type,
1175 struct bt_ctf_field_type_integer, parent);
1176
1177 g_string_append_printf(context->string,
1178 "integer { size = %zu; align = %zu; signed = %s; encoding = %s; base = %s; byte_order = %s; }",
1179 integer->declaration.len, type->declaration->alignment,
1180 (integer->declaration.signedness ? "true" : "false"),
1181 get_encoding_string(integer->declaration.encoding),
1182 get_integer_base_string(integer->declaration.base),
1183 get_byte_order_string(integer->declaration.byte_order));
1184 return 0;
1185 }
1186
1187 static
1188 int bt_ctf_field_type_enumeration_serialize(struct bt_ctf_field_type *type,
1189 struct metadata_context *context)
1190 {
1191 size_t entry;
1192 int ret;
1193 struct bt_ctf_field_type_enumeration *enumeration = container_of(type,
1194 struct bt_ctf_field_type_enumeration, parent);
1195
1196 ret = bt_ctf_field_type_validate(type);
1197 if (ret) {
1198 goto end;
1199 }
1200
1201 g_string_append(context->string, "enum : ");
1202 ret = bt_ctf_field_type_serialize(enumeration->container, context);
1203 if (ret) {
1204 goto end;
1205 }
1206
1207 g_string_append(context->string, " { ");
1208 for (entry = 0; entry < enumeration->entries->len; entry++) {
1209 struct enumeration_mapping *mapping =
1210 enumeration->entries->pdata[entry];
1211
1212 if (mapping->range_start == mapping->range_end) {
1213 g_string_append_printf(context->string,
1214 "\"%s\" = %" PRId64,
1215 g_quark_to_string(mapping->string),
1216 mapping->range_start);
1217 } else {
1218 g_string_append_printf(context->string,
1219 "\"%s\" = %" PRId64 " ... %" PRId64,
1220 g_quark_to_string(mapping->string),
1221 mapping->range_start, mapping->range_end);
1222 }
1223
1224 g_string_append(context->string,
1225 ((entry != (enumeration->entries->len - 1)) ?
1226 ", " : " }"));
1227 }
1228
1229 if (context->field_name->len) {
1230 g_string_append_printf(context->string, " %s",
1231 context->field_name->str);
1232 g_string_assign(context->field_name, "");
1233 }
1234 end:
1235 return ret;
1236 }
1237
1238 static
1239 int bt_ctf_field_type_floating_point_serialize(struct bt_ctf_field_type *type,
1240 struct metadata_context *context)
1241 {
1242 struct bt_ctf_field_type_floating_point *floating_point = container_of(
1243 type, struct bt_ctf_field_type_floating_point, parent);
1244
1245 g_string_append_printf(context->string,
1246 "floating_point { exp_dig = %zu; mant_dig = %zu; byte_order = %s; align = %zu; }",
1247 floating_point->declaration.exp->len,
1248 floating_point->declaration.mantissa->len + 1,
1249 get_byte_order_string(floating_point->declaration.byte_order),
1250 type->declaration->alignment);
1251 return 0;
1252 }
1253
1254 static
1255 int bt_ctf_field_type_structure_serialize(struct bt_ctf_field_type *type,
1256 struct metadata_context *context)
1257 {
1258 size_t i;
1259 unsigned int indent;
1260 int ret = 0;
1261 struct bt_ctf_field_type_structure *structure = container_of(type,
1262 struct bt_ctf_field_type_structure, parent);
1263 GString *structure_field_name = context->field_name;
1264
1265 context->field_name = g_string_new("");
1266
1267 context->current_indentation_level++;
1268 g_string_append(context->string, "struct {\n");
1269
1270 for (i = 0; i < structure->fields->len; i++) {
1271 struct structure_field *field;
1272
1273 for (indent = 0; indent < context->current_indentation_level;
1274 indent++) {
1275 g_string_append_c(context->string, '\t');
1276 }
1277
1278 field = structure->fields->pdata[i];
1279 g_string_assign(context->field_name,
1280 g_quark_to_string(field->name));
1281 ret = bt_ctf_field_type_serialize(field->type, context);
1282 if (ret) {
1283 goto end;
1284 }
1285
1286 if (context->field_name->len) {
1287 g_string_append_printf(context->string, " %s",
1288 context->field_name->str);
1289 }
1290 g_string_append(context->string, ";\n");
1291 }
1292
1293 context->current_indentation_level--;
1294 for (indent = 0; indent < context->current_indentation_level;
1295 indent++) {
1296 g_string_append_c(context->string, '\t');
1297 }
1298
1299 g_string_append_printf(context->string, "} align(%zu)",
1300 type->declaration->alignment);
1301 end:
1302 g_string_free(context->field_name, TRUE);
1303 context->field_name = structure_field_name;
1304 return ret;
1305 }
1306
1307 static
1308 int bt_ctf_field_type_variant_serialize(struct bt_ctf_field_type *type,
1309 struct metadata_context *context)
1310 {
1311 size_t i;
1312 unsigned int indent;
1313 int ret = 0;
1314 struct bt_ctf_field_type_variant *variant = container_of(
1315 type, struct bt_ctf_field_type_variant, parent);
1316 GString *variant_field_name = context->field_name;
1317
1318 context->field_name = g_string_new("");
1319 g_string_append_printf(context->string,
1320 "variant <%s> {\n", variant->tag_name->str);
1321 context->current_indentation_level++;
1322 for (i = 0; i < variant->fields->len; i++) {
1323 struct structure_field *field = variant->fields->pdata[i];
1324
1325 g_string_assign(context->field_name,
1326 g_quark_to_string(field->name));
1327 for (indent = 0; indent < context->current_indentation_level;
1328 indent++) {
1329 g_string_append_c(context->string, '\t');
1330 }
1331
1332 g_string_assign(context->field_name,
1333 g_quark_to_string(field->name));
1334 ret = bt_ctf_field_type_serialize(field->type, context);
1335 if (ret) {
1336 goto end;
1337 }
1338
1339 if (context->field_name->len) {
1340 g_string_append_printf(context->string, " %s;",
1341 context->field_name->str);
1342 }
1343
1344 g_string_append_c(context->string, '\n');
1345 }
1346
1347 context->current_indentation_level--;
1348 for (indent = 0; indent < context->current_indentation_level;
1349 indent++) {
1350 g_string_append_c(context->string, '\t');
1351 }
1352
1353 g_string_append(context->string, "}");
1354 end:
1355 g_string_free(context->field_name, TRUE);
1356 context->field_name = variant_field_name;
1357 return ret;
1358 }
1359
1360 static
1361 int bt_ctf_field_type_array_serialize(struct bt_ctf_field_type *type,
1362 struct metadata_context *context)
1363 {
1364 int ret = 0;
1365 struct bt_ctf_field_type_array *array = container_of(type,
1366 struct bt_ctf_field_type_array, parent);
1367
1368 ret = bt_ctf_field_type_serialize(array->element_type, context);
1369 if (ret) {
1370 goto end;
1371 }
1372
1373 if (context->field_name->len) {
1374 g_string_append_printf(context->string, " %s[%u]",
1375 context->field_name->str, array->length);
1376 g_string_assign(context->field_name, "");
1377 } else {
1378 g_string_append_printf(context->string, "[%u]", array->length);
1379 }
1380 end:
1381 return ret;
1382 }
1383
1384 static
1385 int bt_ctf_field_type_sequence_serialize(struct bt_ctf_field_type *type,
1386 struct metadata_context *context)
1387 {
1388 int ret = 0;
1389 struct bt_ctf_field_type_sequence *sequence = container_of(
1390 type, struct bt_ctf_field_type_sequence, parent);
1391
1392 ret = bt_ctf_field_type_serialize(sequence->element_type, context);
1393 if (ret) {
1394 goto end;
1395 }
1396
1397 if (context->field_name->len) {
1398 g_string_append_printf(context->string, " %s[%s]",
1399 context->field_name->str,
1400 sequence->length_field_name->str);
1401 g_string_assign(context->field_name, "");
1402 } else {
1403 g_string_append_printf(context->string, "[%s]",
1404 sequence->length_field_name->str);
1405 }
1406 end:
1407 return ret;
1408 }
1409
1410 static
1411 int bt_ctf_field_type_string_serialize(struct bt_ctf_field_type *type,
1412 struct metadata_context *context)
1413 {
1414 struct bt_ctf_field_type_string *string = container_of(
1415 type, struct bt_ctf_field_type_string, parent);
1416
1417 g_string_append_printf(context->string,
1418 "string { encoding = %s; }",
1419 get_encoding_string(string->declaration.encoding));
1420 return 0;
1421 }
1422
1423 static
1424 void bt_ctf_field_type_integer_set_byte_order(struct bt_ctf_field_type *type,
1425 int byte_order)
1426 {
1427 struct bt_ctf_field_type_integer *integer_type = container_of(type,
1428 struct bt_ctf_field_type_integer, parent);
1429
1430 integer_type->declaration.byte_order = byte_order;
1431 }
1432
1433 static
1434 void bt_ctf_field_type_floating_point_set_byte_order(
1435 struct bt_ctf_field_type *type, int byte_order)
1436 {
1437 struct bt_ctf_field_type_floating_point *floating_point_type =
1438 container_of(type, struct bt_ctf_field_type_floating_point,
1439 parent);
1440
1441 floating_point_type->declaration.byte_order = byte_order;
1442 floating_point_type->sign.byte_order = byte_order;
1443 floating_point_type->mantissa.byte_order = byte_order;
1444 floating_point_type->exp.byte_order = byte_order;
1445 }
This page took 0.093512 seconds and 4 git commands to generate.