Keep only integers in inner struct offsets
[barectf.git] / barectf / cli.py
1 # The MIT License (MIT)
2 #
3 # Copyright (c) 2014 Philippe Proulx <philippe.proulx@efficios.com>
4 #
5 # Permission is hereby granted, free of charge, to any person obtaining a copy
6 # of this software and associated documentation files (the "Software"), to deal
7 # in the Software without restriction, including without limitation the rights
8 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 # copies of the Software, and to permit persons to whom the Software is
10 # furnished to do so, subject to the following conditions:
11 #
12 # The above copyright notice and this permission notice shall be included in
13 # all copies or substantial portions of the Software.
14 #
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 # THE SOFTWARE.
22 from termcolor import cprint, colored
23 import pytsdl.parser
24 import pytsdl.tsdl
25 import collections
26 import argparse
27 import sys
28 import os
29 import re
30
31
32 def _perror(msg, exit_code=1):
33 cprint('Error: {}'.format(msg), 'red', attrs=['bold'], file=sys.stderr)
34 sys.exit(exit_code)
35
36
37 def _pinfo(msg):
38 cprint(':: {}'.format(msg), 'blue', attrs=['bold'], file=sys.stderr)
39
40
41 def _parse_args():
42 ap = argparse.ArgumentParser()
43
44 ap.add_argument('-O', '--output', metavar='OUTPUT', action='store',
45 default=os.getcwd(),
46 help='output directory of C files')
47 ap.add_argument('-p', '--prefix', metavar='PREFIX', action='store',
48 default='barectf',
49 help='custom prefix for C function and structure names')
50 ap.add_argument('-s', '--static-inline', action='store_true',
51 help='generate static inline C functions')
52 ap.add_argument('-c', '--manual-clock', action='store_true',
53 help='do not use a clock callback: pass clock value to tracing functions')
54 ap.add_argument('metadata', metavar='METADATA', action='store',
55 help='CTF metadata input file')
56
57 # parse args
58 args = ap.parse_args()
59
60 # validate output directory
61 if not os.path.isdir(args.output):
62 _perror('"{}" is not an existing directory'.format(args.output))
63
64 # validate prefix
65 if not re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', args.prefix):
66 _perror('"{}" is not a valid C identifier'.format(args.prefix))
67
68 # validate that metadata file exists
69 if not os.path.isfile(args.metadata):
70 _perror('"{}" is not an existing file'.format(args.metadata))
71
72 return args
73
74
75 # TODO: prettify this function
76 def _validate_struct(struct):
77 # just in case we call this with the wrong type
78 if type(struct) is not pytsdl.tsdl.Struct:
79 raise RuntimeError('expecting a struct')
80
81 # make sure inner structures are at least byte-aligned
82 if _get_obj_alignment(struct) < 8:
83 raise RuntimeError('inner struct must be at least byte-aligned')
84
85 # check each field
86 for name, ftype in struct.fields.items():
87 if type(ftype) is pytsdl.tsdl.Sequence:
88 raise RuntimeError('field "{}" is a dynamic array (not allowed here)'.format(name))
89 elif type(ftype) is pytsdl.tsdl.Array:
90 # we need to check every element type until we find a terminal one
91 end = False
92 element = ftype.element
93
94 while not end:
95 if type(element) is pytsdl.tsdl.Sequence:
96 raise RuntimeError('field "{}" contains a dynamic array (not allowed here)'.format(name))
97 elif type(element) is pytsdl.tsdl.Variant:
98 raise RuntimeError('field "{}" contains a variant (unsupported)'.format(name))
99 elif type(element) is pytsdl.tsdl.String:
100 raise RuntimeError('field "{}" contains a string (not allowed here)'.format(name))
101 elif type(element) is pytsdl.tsdl.Struct:
102 _validate_struct(element)
103 elif type(element) is pytsdl.tsdl.Integer:
104 if _get_integer_size(element) > 64:
105 raise RuntimeError('integer field "{}" larger than 64-bit'.format(name))
106 elif type(element) is pytsdl.tsdl.FloatingPoint:
107 if _get_floating_point_size(element) > 64:
108 raise RuntimeError('floating point field "{}" larger than 64-bit'.format(name))
109 elif type(element) is pytsdl.tsdl.Enum:
110 if _get_enum_size(element) > 64:
111 raise RuntimeError('enum field "{}" larger than 64-bit'.format(name))
112
113 if type(element) is pytsdl.tsdl.Array:
114 # still an array, continue
115 element = element.element
116 else:
117 # found the terminal element
118 end = True
119 elif type(ftype) is pytsdl.tsdl.Variant:
120 raise RuntimeError('field "{}" is a variant (unsupported)'.format(name))
121 elif type(ftype) is pytsdl.tsdl.String:
122 raise RuntimeError('field "{}" is a string (not allowed here)'.format(name))
123 elif type(ftype) is pytsdl.tsdl.Struct:
124 _validate_struct(ftype)
125 elif type(ftype) is pytsdl.tsdl.Integer:
126 if _get_integer_size(ftype) > 64:
127 raise RuntimeError('integer field "{}" larger than 64-bit'.format(name))
128 elif type(ftype) is pytsdl.tsdl.FloatingPoint:
129 if _get_floating_point_size(ftype) > 64:
130 raise RuntimeError('floating point field "{}" larger than 64-bit'.format(name))
131 elif type(ftype) is pytsdl.tsdl.Enum:
132 if _get_enum_size(ftype) > 64:
133 raise RuntimeError('enum field "{}" larger than 64-bit'.format(name))
134
135
136 def _validate_context_field(struct):
137 if type(struct) is not pytsdl.tsdl.Struct:
138 raise RuntimeError('expecting a struct')
139
140 for name, ftype in struct.fields.items():
141 if type(ftype) is pytsdl.tsdl.Variant:
142 raise RuntimeError('field "{}" is a variant (unsupported)'.format(name))
143 elif type(ftype) is pytsdl.tsdl.Struct:
144 # validate inner structure against barectf constraints
145 _validate_struct(ftype)
146
147
148 def _validate_integer(integer, size=None, align=None, signed=None):
149 if type(integer) is not pytsdl.tsdl.Integer:
150 raise RuntimeError('expected integer')
151
152 if size is not None:
153 if integer.size != size:
154 raise RuntimeError('expected {}-bit integer'.format(size))
155
156 if align is not None:
157 if integer.align != align:
158 raise RuntimeError('expected integer with {}-bit alignment'.format(align))
159
160 if signed is not None:
161 if integer.signed != signed:
162 raise RuntimeError('expected {} integer'.format('signed' if signed else 'unsigned'))
163
164
165 def _validate_packet_header(packet_header):
166 try:
167 _validate_struct(packet_header)
168 except RuntimeError as e:
169 _perror('packet header: {}'.format(e))
170
171 # magic must be the first field
172 if 'magic' in packet_header.fields:
173 if list(packet_header.fields.keys())[0] != 'magic':
174 _perror('packet header: "magic" must be the first field')
175 else:
176 _perror('packet header: missing "magic" field')
177
178 # magic must be a 32-bit unsigned integer, 32-bit aligned
179 try:
180 _validate_integer(packet_header['magic'], 32, 32, False)
181 except RuntimeError as e:
182 _perror('packet header: "magic": {}'.format(e))
183
184 # mandatory stream_id
185 if 'stream_id' not in packet_header.fields:
186 _perror('packet header: missing "stream_id" field')
187
188 # stream_id must be an unsigned integer
189 try:
190 _validate_integer(packet_header['stream_id'], signed=False)
191 except RuntimeError as e:
192 _perror('packet header: "stream_id": {}'.format(e))
193
194
195 def _dot_name_to_str(name):
196 return '.'.join(name)
197
198
199 def _compare_integers(int1, int2):
200 if type(int1) is not pytsdl.tsdl.Integer:
201 return False
202
203 if type(int2) is not pytsdl.tsdl.Integer:
204 return False
205
206 size = int1.size == int2.size
207 align = int1.align == int2.align
208 cmap = int1.map == int2.map
209 base = int1.base == int2.base
210 encoding = int1.encoding == int2.encoding
211 signed = int1.signed == int2.signed
212 comps = (size, align, cmap, base, encoding, signed)
213
214 # True means 1 for sum()
215 return sum(comps) == len(comps)
216
217
218 def _validate_packet_context(doc, stream):
219 packet_context = stream.packet_context
220 sid = stream.id
221
222 try:
223 _validate_struct(packet_context)
224 except RuntimeError as e:
225 _perror('stream {}: packet context: {}'.format(sid, e))
226
227 fields = packet_context.fields
228
229 # if timestamp_begin exists, timestamp_end must exist
230 if 'timestamp_begin' in fields or 'timestamp_end' in fields:
231 if 'timestamp_begin' not in fields or 'timestamp_end' not in fields:
232 _perror('stream {}: packet context: "timestamp_begin" must exist if "timestamp_end" exists'.format(sid))
233 else:
234 # timestamp_begin and timestamp_end must have the same integer
235 # as the event header's timestamp field (should exist by now)
236 timestamp = stream.event_header['timestamp']
237
238 if not _compare_integers(fields['timestamp_begin'], timestamp):
239 _perror('stream {}: packet context: "timestamp_begin": integer type different from event header\'s "timestamp" field'.format(sid))
240
241 if not _compare_integers(fields['timestamp_end'], timestamp):
242 _perror('stream {}: packet context: "timestamp_end": integer type different from event header\'s "timestamp" field'.format(sid))
243
244 # content_size must exist and be an unsigned integer
245 if 'content_size' not in fields:
246 _perror('stream {}: packet context: missing "content_size" field'.format(sid))
247
248 try:
249 _validate_integer(fields['content_size'], 32, 32, False)
250 except:
251 try:
252 _validate_integer(fields['content_size'], 64, 64, False)
253 except:
254 _perror('stream {}: packet context: "content_size": expecting unsigned 32-bit/64-bit integer'.format(sid))
255
256 # packet_size must exist and be an unsigned integer
257 if 'packet_size' not in fields:
258 _perror('stream {}: packet context: missing "packet_size" field'.format(sid))
259
260 try:
261 _validate_integer(fields['packet_size'], 32, 32, False)
262 except:
263 try:
264 _validate_integer(fields['packet_size'], 64, 64, False)
265 except:
266 _perror('stream {}: packet context: "packet_size": expecting unsigned 32-bit/64-bit integer'.format(sid))
267
268 # if cpu_id exists, must be an unsigned integer
269 if 'cpu_id' in fields:
270 try:
271 _validate_integer(fields['cpu_id'], signed=False)
272 except RuntimeError as e:
273 _perror('stream {}: packet context: "cpu_id": {}'.format(sid, e))
274
275
276 def _validate_event_header(doc, stream):
277 event_header = stream.event_header
278 sid = stream.id
279
280 try:
281 _validate_struct(event_header)
282 except RuntimeError as e:
283 _perror('stream {}: event header: {}'.format(sid, e))
284
285 fields = event_header.fields
286
287 # id must exist and be an unsigned integer
288 if 'id' not in fields:
289 _perror('stream {}: event header: missing "id" field'.format(sid))
290
291 try:
292 _validate_integer(fields['id'], signed=False)
293 except RuntimeError as e:
294 _perror('stream {}: "id": {}'.format(sid, format(e)))
295
296
297 # timestamp must exist, be an unsigned integer and be mapped to a valid clock
298 if 'timestamp' not in fields:
299 _perror('stream {}: event header: missing "timestamp" field'.format(sid))
300
301 try:
302 _validate_integer(fields['timestamp'], signed=False)
303 except RuntimeError as e:
304 _perror('stream {}: "timestamp": {}'.format(sid, format(e)))
305
306
307 def _validate_stream_event_context(doc, stream):
308 stream_event_context = stream.event_context
309 sid = stream.id
310
311 if stream_event_context is None:
312 return
313
314 try:
315 _validate_context_field(stream_event_context)
316 except RuntimeError as e:
317 _perror('stream {}: event context: {}'.format(sid, e))
318
319
320 def _validate_all_scopes(doc):
321 # packet header
322 _validate_packet_header(doc.trace.packet_header)
323
324 # stream stuff
325 for stream_id, stream in doc.streams.items():
326 _validate_event_header(doc, stream)
327 _validate_packet_context(doc, stream)
328 _validate_stream_event_context(doc, stream)
329
330
331 def _validate_metadata(doc):
332 _validate_all_scopes(doc)
333
334
335 # 3, 4 -> 4
336 # 4, 4 -> 4
337 # 5, 4 -> 8
338 # 6, 4 -> 8
339 # 7, 4 -> 8
340 # 8, 4 -> 8
341 # 9, 4 -> 12
342 def _get_alignment(at, align):
343 return (at + align - 1) & -align
344
345
346 def _offset_vars_tree_to_vars(offset_vars_tree, prefix='',
347 offset_vars=collections.OrderedDict()):
348 for name, offset in offset_vars_tree.items():
349 varname = '{}_{}'.format(prefix, name)
350
351 if isinstance(offset, dict):
352 _offset_vars_tree_to_vars(offset, varname, offset_vars)
353 else:
354 offset_vars[varname] = offset
355
356 return offset_vars
357
358
359 # returns the size of a struct with _static size_
360 def _get_struct_size(struct, offset_vars_tree=collections.OrderedDict(),
361 base_offset=0):
362 offset = 0
363
364 for fname, ftype in struct.fields.items():
365 field_alignment = _get_obj_alignment(ftype)
366 offset = _get_alignment(offset, field_alignment)
367
368 if type(ftype) is pytsdl.tsdl.Struct:
369 offset_vars_tree[fname] = collections.OrderedDict()
370 sz = _get_struct_size(ftype, offset_vars_tree[fname],
371 base_offset + offset)
372 else:
373 # only integers may act as sequence lengths
374 if type(ftype) is pytsdl.tsdl.Integer:
375 offset_vars_tree[fname] = base_offset + offset
376
377 sz = _get_obj_size(ftype)
378
379 offset += sz
380
381 return offset
382
383
384 def _get_array_size(array):
385 element = array.element
386
387 # effective size of one element includes its alignment after its size
388 size = _get_obj_size(element)
389 align = _get_obj_alignment(element)
390
391 return _get_alignment(size, align) * array.length
392
393
394 def _get_enum_size(enum):
395 return _get_obj_size(enum.integer)
396
397
398 def _get_floating_point_size(floating_point):
399 return floating_point.exp_dig + floating_point.mant_dig
400
401
402 def _get_integer_size(integer):
403 return integer.size
404
405
406 _obj_size_cb = {
407 pytsdl.tsdl.Integer: _get_integer_size,
408 pytsdl.tsdl.Enum: _get_enum_size,
409 pytsdl.tsdl.FloatingPoint: _get_floating_point_size,
410 pytsdl.tsdl.Array: _get_array_size,
411 }
412
413
414 def _get_obj_size(obj):
415 return _obj_size_cb[type(obj)](obj)
416
417
418 def _get_struct_alignment(struct):
419 if struct.align is not None:
420 return struct.align
421
422 cur_align = 1
423
424 for fname, ftype in struct.fields.items():
425 cur_align = max(_get_obj_alignment(ftype), cur_align)
426
427 return cur_align
428
429
430 def _get_integer_alignment(integer):
431 return integer.align
432
433
434 def _get_floating_point_alignment(floating_point):
435 return floating_point.align
436
437
438 def _get_enum_alignment(enum):
439 return _get_obj_alignment(enum.integer)
440
441
442 def _get_string_alignment(string):
443 return 8
444
445 def _get_array_alignment(array):
446 return _get_obj_alignment(array.element)
447
448
449 def _get_sequence_alignment(sequence):
450 return _get_obj_alignment(sequence.element)
451
452
453 _obj_alignment_cb = {
454 pytsdl.tsdl.Struct: _get_struct_alignment,
455 pytsdl.tsdl.Integer: _get_integer_alignment,
456 pytsdl.tsdl.Enum: _get_enum_alignment,
457 pytsdl.tsdl.FloatingPoint: _get_floating_point_alignment,
458 pytsdl.tsdl.Array: _get_array_alignment,
459 pytsdl.tsdl.Sequence: _get_sequence_alignment,
460 pytsdl.tsdl.String: _get_string_alignment,
461 }
462
463
464 def _get_obj_alignment(obj):
465 return _obj_alignment_cb[type(obj)](obj)
466
467
468 _CTX_AT = 'ctx->at'
469 _CTX_BUF = 'ctx->buf'
470 _CTX_BUF_AT = '{}[{} >> 3]'.format(_CTX_BUF, _CTX_AT)
471 _CTX_BUF_AT_ADDR = '&{}'.format(_CTX_BUF_AT)
472 _ALIGN_OFFSET = 'ALIGN_OFFSET'
473
474
475 def _field_name_to_param_name(fname):
476 return 'param_{}'.format(fname)
477
478
479 def _get_integer_param_type(integer):
480 signed = 'u' if not integer.signed else ''
481
482 if integer.size == 8:
483 sz = '8'
484 elif integer.size == 16:
485 sz = '16'
486 elif integer.size == 32:
487 sz = '32'
488 elif integer.size == 64:
489 sz = '64'
490 else:
491 # if the integer is signed and of uncommon size, the sign bit is
492 # at a custom position anyway so we use a 64-bit unsigned
493 signed = 'u'
494
495 if integer.signed:
496 sz = '64'
497 else:
498 if integer.size < 16:
499 sz = '8'
500 elif integer.size < 32:
501 sz = '16'
502 elif integer.size < 64:
503 sz = '32'
504 else:
505 sz = '64'
506
507 return '{}int{}_t'.format(signed, sz)
508
509
510 def _get_enum_param_type(enum):
511 return _get_obj_param_type(enum.integer)
512
513
514 def _get_floating_point_param_type(fp):
515 if fp.exp_dig == 8 and fp.mant_dig == 24 and fp.align == 32:
516 return 'float'
517 elif fp.exp_dig == 11 and fp.mant_dig == 53 and fp.align == 64:
518 return 'double'
519 else:
520 return 'uint64_t'
521
522
523 _obj_param_type_cb = {
524 pytsdl.tsdl.Struct: lambda obj: 'const void*',
525 pytsdl.tsdl.Integer: _get_integer_param_type,
526 pytsdl.tsdl.Enum: _get_enum_param_type,
527 pytsdl.tsdl.FloatingPoint: _get_floating_point_param_type,
528 pytsdl.tsdl.Array: lambda obj: 'const void*',
529 pytsdl.tsdl.Sequence: lambda obj: 'const void*',
530 pytsdl.tsdl.String: lambda obj: 'const char*',
531 }
532
533
534 def _get_obj_param_type(obj):
535 return _obj_param_type_cb[type(obj)](obj)
536
537
538 class _CBlock(list):
539 pass
540
541
542 class _CLine(str):
543 pass
544
545
546 def _write_field_struct(doc, fname, struct):
547 size = _get_struct_size(struct)
548 size_bytes = _get_alignment(size, 8) // 8
549
550 dst = _CTX_BUF_AT_ADDR
551 src = _field_name_to_param_name(fname)
552
553 return [
554 # memcpy() is safe since barectf requires inner structures
555 # to be byte-aligned
556 _CLine('memcpy({}, {}, {});'.format(dst, src, size_bytes)),
557 _CLine('{} += {};'.format(_CTX_AT, size)),
558 ]
559
560
561 _bo_suffixes_map = {
562 pytsdl.tsdl.ByteOrder.BE: 'be',
563 pytsdl.tsdl.ByteOrder.LE: 'le',
564 }
565
566
567 def _write_field_integer(doc, fname, integer):
568 bo = _bo_suffixes_map[integer.byte_order]
569 ptr = _CTX_BUF
570 t = _get_obj_param_type(integer)
571 start = _CTX_AT
572 length = _get_obj_size(integer)
573 value = _field_name_to_param_name(fname)
574 fmt = 'barectf_bitfield_write_{}({}, {}, {}, {}, {});'
575
576 return [
577 _CLine(fmt.format(bo, ptr, t, start, length, value)),
578 _CLine('{} += {};'.format(_CTX_AT, length))
579 ]
580
581
582 def _write_field_enum(doc, fname, enum):
583 return _write_field_obj(doc, fname, enum.integer)
584
585
586 def _write_field_floating_point(doc, fname, floating_point):
587 bo = _bo_suffixes_map[floating_point.byte_order]
588 ptr = _CTX_BUF
589 t = _get_obj_param_type(floating_point)
590 start = _CTX_AT
591 length = _get_obj_size(floating_point)
592 value = _field_name_to_param_name(fname)
593 fmt = 'barectf_bitfield_write_{}({}, {}, {}, {}, {});'
594
595 return [
596 _CLine(fmt.format(bo, ptr, t, start, length, value)),
597 _CLine('{} += {};'.format(_CTX_AT, length))
598 ]
599
600
601 def _write_field_array(doc, fname, array):
602 lines = []
603
604 # array index variable declaration
605 iv = 'ia_{}'.format(fname)
606 lines.append(_CLine('uint32_t {};'.format(iv)))
607
608 # for loop using array's static length
609 line = 'for ({iv} = 0; {iv} < {l}; ++{iv}) {{'.format(iv=iv, l=array.length)
610 lines.append(_CLine(line))
611
612 # for loop statements
613 for_block = _CBlock()
614
615 # align bit index before writing to the buffer
616 element_align = _get_obj_alignment(array.element)
617 line = '{}({}, {});'.format(_ALIGN_OFFSET, _CTX_AT, element_align)
618 for_block.append(_CLine(line))
619
620 # write element to the buffer
621 for_block += _write_field_obj(doc, fname, array.element)
622 lines.append(for_block)
623
624 # for loop end
625 lines.append(_CLine('}'))
626
627 return lines
628
629
630 def _write_field_sequence(doc, fname, sequence):
631 return [
632 _CLine('would write sequence here;'),
633 ]
634
635
636 def _write_field_string(doc, fname, string):
637 lines = []
638
639 # source pointer (function parameter)
640 src = _field_name_to_param_name(fname)
641
642 # string index variable declaration
643 iv = 'is_{}'.format(fname)
644 lines.append(_CLine('uint32_t {};'.format(iv)))
645
646 # for loop; loop until the end of the source string is reached
647 fmt = "for ({iv} = 0; {src}[{iv}] != '\\0'; ++{iv}, {ctxat} += 8) {{"
648 lines.append(_CLine(fmt.format(iv=iv, src=src, ctxat=_CTX_AT)))
649
650 # for loop statements
651 for_block = _CBlock()
652
653 # write byte to the buffer
654 line = '{} = {}[{}]'.format(_CTX_BUF_AT, src, iv)
655 for_block.append(_CLine(line))
656
657 # append for loop
658 lines.append(for_block)
659 lines.append(_CLine('}'))
660
661 # write NULL character to the buffer
662 lines.append(_CLine("{} = '\\0';".format(_CTX_BUF_AT)))
663 lines.append(_CLine('{} += 8;'.format(_CTX_AT)))
664
665 return lines
666
667
668 _write_field_obj_cb = {
669 pytsdl.tsdl.Struct: _write_field_struct,
670 pytsdl.tsdl.Integer: _write_field_integer,
671 pytsdl.tsdl.Enum: _write_field_enum,
672 pytsdl.tsdl.FloatingPoint: _write_field_floating_point,
673 pytsdl.tsdl.Array: _write_field_array,
674 pytsdl.tsdl.Sequence: _write_field_sequence,
675 pytsdl.tsdl.String: _write_field_string,
676 }
677
678
679 def _write_field_obj(doc, fname, ftype):
680 return _write_field_obj_cb[type(ftype)](doc, fname, ftype)
681
682
683 def _struct_to_c_lines(doc, struct):
684 lines = []
685
686 for fname, ftype in struct.fields.items():
687 pname = _field_name_to_param_name(fname)
688 align = _get_obj_alignment(ftype)
689
690 # align bit index before writing to the buffer
691 line = '{}({}, {});'.format(_ALIGN_OFFSET, _CTX_AT, align)
692 lines.append(line)
693
694 # write offset variables
695 if type(ftype) is pytsdl.tsdl.Struct:
696 offset_vars_tree = collections.OrderedDict()
697 _get_struct_size(ftype, offset_vars_tree)
698 offset_vars = _offset_vars_tree_to_vars(offset_vars_tree)
699
700 # as many offset as there are child fields because a future
701 # sequence could refer to any of those fields
702 for lname, offset in offset_vars.items():
703 fmt = 'uint32_t off_{}_{} = {} + {};'
704 line = fmt.format(fname, lname, _CTX_AT, offset);
705 lines.append(_CLine(line))
706 else:
707 # offset of this simple field is the current bit index
708 line = 'uint32_t off_{} = {};'.format(fname, _CTX_AT)
709 lines.append(_CLine(line))
710
711 lines += _write_field_obj(doc, fname, ftype)
712
713 return lines
714
715
716 def gen_barectf(metadata, output, prefix, static_inline, manual_clock):
717 # open CTF metadata file
718 try:
719 with open(metadata) as f:
720 tsdl = f.read()
721 except:
722 _perror('cannot open/read CTF metadata file "{}"'.format(metadata))
723
724 # parse CTF metadata
725 parser = pytsdl.parser.Parser()
726
727 try:
728 doc = parser.parse(tsdl)
729 except pytsdl.parser.ParseError as e:
730 _perror('parse error: {}'.format(e))
731
732 # validate CTF metadata against barectf constraints
733 _validate_metadata(doc)
734
735 import json
736
737 lines = _struct_to_c_lines(doc, doc.streams[0].get_event(0).fields)
738
739 print(json.dumps(lines, indent=4))
740
741
742 def run():
743 args = _parse_args()
744 gen_barectf(args.metadata, args.output, args.prefix, args.static_inline,
745 args.manual_clock)
This page took 0.045038 seconds and 5 git commands to generate.