Fix: get struct size in map
[deliverable/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.Struct: _get_struct_size,
408 pytsdl.tsdl.Integer: _get_integer_size,
409 pytsdl.tsdl.Enum: _get_enum_size,
410 pytsdl.tsdl.FloatingPoint: _get_floating_point_size,
411 pytsdl.tsdl.Array: _get_array_size,
412 }
413
414
415 def _get_obj_size(obj):
416 return _obj_size_cb[type(obj)](obj)
417
418
419 def _get_struct_alignment(struct):
420 if struct.align is not None:
421 return struct.align
422
423 cur_align = 1
424
425 for fname, ftype in struct.fields.items():
426 cur_align = max(_get_obj_alignment(ftype), cur_align)
427
428 return cur_align
429
430
431 def _get_integer_alignment(integer):
432 return integer.align
433
434
435 def _get_floating_point_alignment(floating_point):
436 return floating_point.align
437
438
439 def _get_enum_alignment(enum):
440 return _get_obj_alignment(enum.integer)
441
442
443 def _get_string_alignment(string):
444 return 8
445
446 def _get_array_alignment(array):
447 return _get_obj_alignment(array.element)
448
449
450 def _get_sequence_alignment(sequence):
451 return _get_obj_alignment(sequence.element)
452
453
454 _obj_alignment_cb = {
455 pytsdl.tsdl.Struct: _get_struct_alignment,
456 pytsdl.tsdl.Integer: _get_integer_alignment,
457 pytsdl.tsdl.Enum: _get_enum_alignment,
458 pytsdl.tsdl.FloatingPoint: _get_floating_point_alignment,
459 pytsdl.tsdl.Array: _get_array_alignment,
460 pytsdl.tsdl.Sequence: _get_sequence_alignment,
461 pytsdl.tsdl.String: _get_string_alignment,
462 }
463
464
465 def _get_obj_alignment(obj):
466 return _obj_alignment_cb[type(obj)](obj)
467
468
469 _CTX_AT = 'ctx->at'
470 _CTX_BUF = 'ctx->buf'
471 _CTX_BUF_SIZE = 'ctx->buf_size'
472 _CTX_BUF_AT = '{}[{} >> 3]'.format(_CTX_BUF, _CTX_AT)
473 _CTX_BUF_AT_ADDR = '&{}'.format(_CTX_BUF_AT)
474 _ALIGN_OFFSET = 'ALIGN_OFFSET'
475 _CHECK_OFFSET_OVERFLOW_FMT = \
476 'CHECK_OFFSET_OVERFLOW({}, {}, {{}});'.format(_CTX_AT, _CTX_BUF_SIZE)
477
478
479 def _field_name_to_param_name(fname):
480 return 'param_{}'.format(fname)
481
482
483 def _get_integer_param_type(integer):
484 signed = 'u' if not integer.signed else ''
485
486 if integer.size == 8:
487 sz = '8'
488 elif integer.size == 16:
489 sz = '16'
490 elif integer.size == 32:
491 sz = '32'
492 elif integer.size == 64:
493 sz = '64'
494 else:
495 # if the integer is signed and of uncommon size, the sign bit is
496 # at a custom position anyway so we use a 64-bit unsigned
497 signed = 'u'
498
499 if integer.signed:
500 sz = '64'
501 else:
502 if integer.size < 16:
503 sz = '8'
504 elif integer.size < 32:
505 sz = '16'
506 elif integer.size < 64:
507 sz = '32'
508 else:
509 sz = '64'
510
511 return '{}int{}_t'.format(signed, sz)
512
513
514 def _get_enum_param_type(enum):
515 return _get_obj_param_type(enum.integer)
516
517
518 def _get_floating_point_param_type(fp):
519 if fp.exp_dig == 8 and fp.mant_dig == 24 and fp.align == 32:
520 return 'float'
521 elif fp.exp_dig == 11 and fp.mant_dig == 53 and fp.align == 64:
522 return 'double'
523 else:
524 return 'uint64_t'
525
526
527 _obj_param_type_cb = {
528 pytsdl.tsdl.Struct: lambda obj: 'const void*',
529 pytsdl.tsdl.Integer: _get_integer_param_type,
530 pytsdl.tsdl.Enum: _get_enum_param_type,
531 pytsdl.tsdl.FloatingPoint: _get_floating_point_param_type,
532 pytsdl.tsdl.Array: lambda obj: 'const void*',
533 pytsdl.tsdl.Sequence: lambda obj: 'const void*',
534 pytsdl.tsdl.String: lambda obj: 'const char*',
535 }
536
537
538 def _get_obj_param_type(obj):
539 return _obj_param_type_cb[type(obj)](obj)
540
541
542 class _CBlock(list):
543 pass
544
545
546 class _CLine(str):
547 pass
548
549
550 def _get_check_offset_overflow_cline(size):
551 return _CLine(_CHECK_OFFSET_OVERFLOW_FMT.format(size))
552
553
554 def _write_field_struct(doc, fname, struct):
555 size = _get_struct_size(struct)
556 size_bytes = _get_alignment(size, 8) // 8
557
558 dst = _CTX_BUF_AT_ADDR
559 src = _field_name_to_param_name(fname)
560
561 return [
562 # memcpy() is safe since barectf requires inner structures
563 # to be byte-aligned
564 _get_check_offset_overflow_cline(size),
565 _CLine('memcpy({}, {}, {});'.format(dst, src, size_bytes)),
566 _CLine('{} += {};'.format(_CTX_AT, size)),
567 ]
568
569
570 _bo_suffixes_map = {
571 pytsdl.tsdl.ByteOrder.BE: 'be',
572 pytsdl.tsdl.ByteOrder.LE: 'le',
573 }
574
575
576 def _write_field_integer(doc, fname, integer):
577 bo = _bo_suffixes_map[integer.byte_order]
578 ptr = _CTX_BUF
579 t = _get_obj_param_type(integer)
580 start = _CTX_AT
581 length = _get_obj_size(integer)
582 value = _field_name_to_param_name(fname)
583 fmt = 'barectf_bitfield_write_{}({}, {}, {}, {}, {});'
584
585 return [
586 _get_check_offset_overflow_cline(length),
587 _CLine(fmt.format(bo, ptr, t, start, length, value)),
588 _CLine('{} += {};'.format(_CTX_AT, length))
589 ]
590
591
592 def _write_field_enum(doc, fname, enum):
593 return _write_field_obj(doc, fname, enum.integer)
594
595
596 def _write_field_floating_point(doc, fname, floating_point):
597 bo = _bo_suffixes_map[floating_point.byte_order]
598 ptr = _CTX_BUF
599 t = _get_obj_param_type(floating_point)
600 start = _CTX_AT
601 length = _get_obj_size(floating_point)
602 value = _field_name_to_param_name(fname)
603 fmt = 'barectf_bitfield_write_{}({}, {}, {}, {}, {});'
604
605 return [
606 _get_check_offset_overflow_cline(length),
607 _CLine(fmt.format(bo, ptr, t, start, length, value)),
608 _CLine('{} += {};'.format(_CTX_AT, length))
609 ]
610
611
612 def _write_field_array(doc, fname, array):
613 lines = []
614
615 # array index variable declaration
616 iv = 'ia_{}'.format(fname)
617 lines.append(_CLine('uint32_t {};'.format(iv)))
618
619 # for loop using array's static length
620 line = 'for ({iv} = 0; {iv} < {l}; ++{iv}) {{'.format(iv=iv, l=array.length)
621 lines.append(_CLine(line))
622
623 # for loop statements
624 for_block = _CBlock()
625
626 # align bit index before writing to the buffer
627 element_align = _get_obj_alignment(array.element)
628 line = '{}({}, {});'.format(_ALIGN_OFFSET, _CTX_AT, element_align)
629 for_block.append(_CLine(line))
630
631 # write element to the buffer
632 for_block += _write_field_obj(doc, fname, array.element)
633 lines.append(for_block)
634
635 # for loop end
636 lines.append(_CLine('}'))
637
638 return lines
639
640
641 def _write_field_sequence(doc, fname, sequence):
642 return [
643 _CLine('would write sequence here;'),
644 ]
645
646
647 def _write_field_string(doc, fname, string):
648 lines = []
649
650 # source pointer (function parameter)
651 src = _field_name_to_param_name(fname)
652
653 # string index variable declaration
654 iv = 'is_{}'.format(fname)
655 lines.append(_CLine('uint32_t {};'.format(iv)))
656
657 # for loop; loop until the end of the source string is reached
658 fmt = "for ({iv} = 0; {src}[{iv}] != '\\0'; ++{iv}, {ctxat} += 8) {{"
659 lines.append(_CLine(fmt.format(iv=iv, src=src, ctxat=_CTX_AT)))
660
661 # for loop statements
662 for_block = _CBlock()
663
664 # check offset overflow
665 for_block.append(_get_check_offset_overflow_cline(8))
666
667 # write byte to the buffer
668 line = '{} = {}[{}]'.format(_CTX_BUF_AT, src, iv)
669 for_block.append(_CLine(line))
670
671 # append for loop
672 lines.append(for_block)
673 lines.append(_CLine('}'))
674
675 # write NULL character to the buffer
676 lines.append(_CLine("{} = '\\0';".format(_CTX_BUF_AT)))
677 lines.append(_CLine('{} += 8;'.format(_CTX_AT)))
678
679 return lines
680
681
682 _write_field_obj_cb = {
683 pytsdl.tsdl.Struct: _write_field_struct,
684 pytsdl.tsdl.Integer: _write_field_integer,
685 pytsdl.tsdl.Enum: _write_field_enum,
686 pytsdl.tsdl.FloatingPoint: _write_field_floating_point,
687 pytsdl.tsdl.Array: _write_field_array,
688 pytsdl.tsdl.Sequence: _write_field_sequence,
689 pytsdl.tsdl.String: _write_field_string,
690 }
691
692
693 def _write_field_obj(doc, fname, ftype):
694 return _write_field_obj_cb[type(ftype)](doc, fname, ftype)
695
696
697 def _struct_to_clines(doc, struct):
698 line_groups = []
699
700 for fname, ftype in struct.fields.items():
701 lines = []
702 pname = _field_name_to_param_name(fname)
703 align = _get_obj_alignment(ftype)
704
705 # align bit index before writing to the buffer
706 line = '{}({}, {});'.format(_ALIGN_OFFSET, _CTX_AT, align)
707 lines.append(line)
708
709 # write offset variables
710 if type(ftype) is pytsdl.tsdl.Struct:
711 offset_vars_tree = collections.OrderedDict()
712 _get_struct_size(ftype, offset_vars_tree)
713 offset_vars = _offset_vars_tree_to_vars(offset_vars_tree)
714
715 # as many offset as there are child fields because a future
716 # sequence could refer to any of those fields
717 for lname, offset in offset_vars.items():
718 fmt = 'uint32_t off_{}_{} = {} + {};'
719 line = fmt.format(fname, lname, _CTX_AT, offset);
720 lines.append(_CLine(line))
721 elif type(ftype) is pytsdl.tsdl.Integer:
722 # offset of this simple field is the current bit index
723 line = 'uint32_t off_{} = {};'.format(fname, _CTX_AT)
724 lines.append(_CLine(line))
725
726 lines += _write_field_obj(doc, fname, ftype)
727 line_groups.append(lines)
728
729 if not line_groups:
730 return line_groups
731
732 output_lines = line_groups[0]
733
734 for lines in line_groups[1:]:
735 output_lines.append('')
736 output_lines += lines
737
738 return output_lines
739
740
741 def _cblock_to_source_lines(cblock, indent=1):
742 src = []
743 indentstr = '\t' * indent
744
745 for line in cblock:
746 if type(line) is _CBlock:
747 src += _cblock_to_source_lines(line, indent + 1)
748 else:
749 src.append(indentstr + line)
750
751 return src
752
753
754 def _cblock_to_source(cblock, indent=1):
755 lines = _cblock_to_source_lines(cblock, indent)
756
757 return '\n'.join(lines)
758
759
760 def gen_barectf(metadata, output, prefix, static_inline, manual_clock):
761 # open CTF metadata file
762 try:
763 with open(metadata) as f:
764 tsdl = f.read()
765 except:
766 _perror('cannot open/read CTF metadata file "{}"'.format(metadata))
767
768 # parse CTF metadata
769 parser = pytsdl.parser.Parser()
770
771 try:
772 doc = parser.parse(tsdl)
773 except pytsdl.parser.ParseError as e:
774 _perror('parse error: {}'.format(e))
775
776 # validate CTF metadata against barectf constraints
777 _validate_metadata(doc)
778
779 import json
780
781 clines = _struct_to_clines(doc, doc.streams[0].get_event(0).fields)
782 print(_cblock_to_source(_CBlock(clines)))
783
784
785 def run():
786 args = _parse_args()
787 gen_barectf(args.metadata, args.output, args.prefix, args.static_inline,
788 args.manual_clock)
This page took 0.049439 seconds and 5 git commands to generate.