Add some verbosity
[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 barectf.templates
24 import pytsdl.parser
25 import pytsdl.tsdl
26 import collections
27 import argparse
28 import sys
29 import os
30 import re
31
32
33 def _perror(msg, exit_code=1):
34 cprint('Error: {}'.format(msg), 'red', attrs=['bold'], file=sys.stderr)
35 sys.exit(exit_code)
36
37
38 def _pinfo(msg):
39 cprint(':: {}'.format(msg), 'blue', attrs=['bold'])
40
41
42 def _psuccess(msg):
43 cprint('{}'.format(msg), 'green', attrs=['bold'])
44
45
46 def _parse_args():
47 ap = argparse.ArgumentParser()
48
49 ap.add_argument('-O', '--output', metavar='OUTPUT', action='store',
50 default=os.getcwd(),
51 help='output directory of C files')
52 ap.add_argument('-p', '--prefix', metavar='PREFIX', action='store',
53 default='barectf',
54 help='custom prefix for C function and structure names')
55 ap.add_argument('-s', '--static-inline', action='store_true',
56 help='generate static inline C functions')
57 ap.add_argument('-c', '--manual-clock', action='store_true',
58 help='do not use a clock callback: pass clock value to tracing functions')
59 ap.add_argument('metadata', metavar='METADATA', action='store',
60 help='CTF metadata input file')
61
62 # parse args
63 args = ap.parse_args()
64
65 # validate output directory
66 if not os.path.isdir(args.output):
67 _perror('"{}" is not an existing directory'.format(args.output))
68
69 # validate prefix
70 if not re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', args.prefix):
71 _perror('"{}" is not a valid C identifier'.format(args.prefix))
72
73 # validate that metadata file exists
74 if not os.path.isfile(args.metadata):
75 _perror('"{}" is not an existing file'.format(args.metadata))
76
77 return args
78
79
80 class _CBlock(list):
81 pass
82
83
84 class _CLine(str):
85 pass
86
87
88 class BarectfCodeGenerator:
89 _CTX_AT = 'ctx->at'
90 _CTX_BUF = 'ctx->buf'
91 _CTX_BUF_SIZE = 'ctx->buf_size'
92 _CTX_BUF_AT = '{}[{} >> 3]'.format(_CTX_BUF, _CTX_AT)
93 _CTX_BUF_AT_ADDR = '&{}'.format(_CTX_BUF_AT)
94 _CTX_CALL_CLOCK_CB = 'ctx->clock_cb(ctx->clock_cb_data)'
95
96 _bo_suffixes_map = {
97 pytsdl.tsdl.ByteOrder.BE: 'be',
98 pytsdl.tsdl.ByteOrder.LE: 'le',
99 }
100
101 _tsdl_type_names_map = {
102 pytsdl.tsdl.Integer: 'integer',
103 pytsdl.tsdl.FloatingPoint: 'floating point',
104 pytsdl.tsdl.Enum: 'enumeration',
105 pytsdl.tsdl.String: 'string',
106 pytsdl.tsdl.Array: 'static array',
107 pytsdl.tsdl.Sequence: 'dynamic array',
108 pytsdl.tsdl.Struct: 'structure',
109 }
110
111 def __init__(self):
112 self._parser = pytsdl.parser.Parser()
113 self._obj_size_cb = {
114 pytsdl.tsdl.Struct: self._get_struct_size,
115 pytsdl.tsdl.Integer: self._get_integer_size,
116 pytsdl.tsdl.Enum: self._get_enum_size,
117 pytsdl.tsdl.FloatingPoint: self._get_floating_point_size,
118 pytsdl.tsdl.Array: self._get_array_size,
119 }
120 self._obj_alignment_cb = {
121 pytsdl.tsdl.Struct: self._get_struct_alignment,
122 pytsdl.tsdl.Integer: self._get_integer_alignment,
123 pytsdl.tsdl.Enum: self._get_enum_alignment,
124 pytsdl.tsdl.FloatingPoint: self._get_floating_point_alignment,
125 pytsdl.tsdl.Array: self._get_array_alignment,
126 pytsdl.tsdl.Sequence: self._get_sequence_alignment,
127 pytsdl.tsdl.String: self._get_string_alignment,
128 }
129 self._obj_param_ctype_cb = {
130 pytsdl.tsdl.Struct: lambda obj: 'const void*',
131 pytsdl.tsdl.Integer: self._get_integer_param_ctype,
132 pytsdl.tsdl.Enum: self._get_enum_param_ctype,
133 pytsdl.tsdl.FloatingPoint: self._get_floating_point_param_ctype,
134 pytsdl.tsdl.Array: lambda obj: 'const void*',
135 pytsdl.tsdl.Sequence: lambda obj: 'const void*',
136 pytsdl.tsdl.String: lambda obj: 'const char*',
137 }
138 self._write_field_obj_cb = {
139 pytsdl.tsdl.Struct: self._write_field_struct,
140 pytsdl.tsdl.Integer: self._write_field_integer,
141 pytsdl.tsdl.Enum: self._write_field_enum,
142 pytsdl.tsdl.FloatingPoint: self._write_field_floating_point,
143 pytsdl.tsdl.Array: self._write_field_array,
144 pytsdl.tsdl.Sequence: self._write_field_sequence,
145 pytsdl.tsdl.String: self._write_field_string,
146 }
147 self._get_src_name_funcs = {
148 'trace.packet.header.': self._get_tph_src_name,
149 'env.': self._get_env_src_name,
150 'stream.packet.context.': self._get_spc_src_name,
151 'stream.event.header.': self._get_seh_src_name,
152 'stream.event.context.': self._get_sec_src_name,
153 'event.context.': self._get_ec_src_name,
154 'event.fields.': self._get_ef_src_name,
155 }
156
157 # TODO: prettify this function
158 def _validate_struct(self, struct):
159 # just in case we call this with the wrong type
160 if type(struct) is not pytsdl.tsdl.Struct:
161 raise RuntimeError('expecting a struct')
162
163 # make sure inner structures are at least byte-aligned
164 if self._get_obj_alignment(struct) < 8:
165 raise RuntimeError('inner struct must be at least byte-aligned')
166
167 # check each field
168 for fname, ftype in struct.fields.items():
169 if type(ftype) is pytsdl.tsdl.Sequence:
170 raise RuntimeError('field "{}" is a dynamic array (not allowed here)'.format(fname))
171 elif type(ftype) is pytsdl.tsdl.Array:
172 # we need to check every element until we find a terminal one
173 element = ftype.element
174
175 while True:
176 if type(element) is pytsdl.tsdl.Sequence:
177 raise RuntimeError('field "{}" contains a dynamic array (not allowed here)'.format(fname))
178 elif type(element) is pytsdl.tsdl.Variant:
179 raise RuntimeError('field "{}" contains a variant (unsupported)'.format(fname))
180 elif type(element) is pytsdl.tsdl.String:
181 raise RuntimeError('field "{}" contains a string (not allowed here)'.format(fname))
182 elif type(element) is pytsdl.tsdl.Struct:
183 _validate_struct(element)
184 elif type(element) is pytsdl.tsdl.Integer:
185 if self._get_obj_size(element) > 64:
186 raise RuntimeError('integer field "{}" larger than 64-bit'.format(fname))
187 elif type(element) is pytsdl.tsdl.FloatingPoint:
188 if self._get_obj_size(element) > 64:
189 raise RuntimeError('floating point field "{}" larger than 64-bit'.format(fname))
190 elif type(element) is pytsdl.tsdl.Enum:
191 if self._get_obj_size(element) > 64:
192 raise RuntimeError('enum field "{}" larger than 64-bit'.format(fname))
193
194 if type(element) is pytsdl.tsdl.Array:
195 # still an array, continue
196 element = element.element
197 else:
198 # found the terminal element
199 break
200 elif type(ftype) is pytsdl.tsdl.Variant:
201 raise RuntimeError('field "{}" is a variant (unsupported)'.format(fname))
202 elif type(ftype) is pytsdl.tsdl.String:
203 raise RuntimeError('field "{}" is a string (not allowed here)'.format(fname))
204 elif type(ftype) is pytsdl.tsdl.Struct:
205 self._validate_struct(ftype)
206 elif type(ftype) is pytsdl.tsdl.Integer:
207 if self._get_obj_size(ftype) > 64:
208 raise RuntimeError('integer field "{}" larger than 64-bit'.format(fname))
209 elif type(ftype) is pytsdl.tsdl.FloatingPoint:
210 if self._get_obj_size(ftype) > 64:
211 raise RuntimeError('floating point field "{}" larger than 64-bit'.format(fname))
212 elif type(ftype) is pytsdl.tsdl.Enum:
213 if self._get_obj_size(ftype) > 64:
214 raise RuntimeError('enum field "{}" larger than 64-bit'.format(fname))
215
216 def _validate_context_fields(self, struct):
217 if type(struct) is not pytsdl.tsdl.Struct:
218 raise RuntimeError('expecting a struct')
219
220 for fname, ftype in struct.fields.items():
221 if type(ftype) is pytsdl.tsdl.Variant:
222 raise RuntimeError('field "{}" is a variant (unsupported)'.format(fname))
223 elif type(ftype) is pytsdl.tsdl.Struct:
224 # validate inner structure against barectf constraints
225 self._validate_struct(ftype)
226
227 def _validate_integer(self, integer, size=None, align=None,
228 signed=None):
229 if type(integer) is not pytsdl.tsdl.Integer:
230 raise RuntimeError('expected integer')
231
232 if size is not None:
233 if integer.size != size:
234 raise RuntimeError('expected {}-bit integer'.format(size))
235
236 if align is not None:
237 if integer.align != align:
238 raise RuntimeError('expected integer with {}-bit alignment'.format(align))
239
240 if signed is not None:
241 if integer.signed != signed:
242 raise RuntimeError('expected {} integer'.format('signed' if signed else 'unsigned'))
243
244 def _validate_packet_header(self, packet_header):
245 try:
246 self._validate_struct(packet_header)
247 except RuntimeError as e:
248 _perror('packet header: {}'.format(e))
249
250 # magic must be the first field
251 if 'magic' in packet_header.fields:
252 if list(packet_header.fields.keys())[0] != 'magic':
253 _perror('packet header: "magic" must be the first field')
254 else:
255 _perror('packet header: missing "magic" field')
256
257 # magic must be a 32-bit unsigned integer, 32-bit aligned
258 try:
259 self._validate_integer(packet_header['magic'], 32, 32, False)
260 except RuntimeError as e:
261 _perror('packet header: "magic": {}'.format(e))
262
263 # mandatory stream_id
264 if 'stream_id' not in packet_header.fields:
265 _perror('packet header: missing "stream_id" field')
266
267 # stream_id must be an unsigned integer
268 try:
269 self._validate_integer(packet_header['stream_id'], signed=False)
270 except RuntimeError as e:
271 _perror('packet header: "stream_id": {}'.format(e))
272
273 # only magic and stream_id allowed
274 if len(packet_header.fields) != 2:
275 _perror('packet header: only "magic" and "stream_id" fields are allowed')
276
277 def _dot_name_to_str(self, name):
278 return '.'.join(name)
279
280 def _compare_integers(self, int1, int2):
281 if type(int1) is not pytsdl.tsdl.Integer:
282 return False
283
284 if type(int2) is not pytsdl.tsdl.Integer:
285 return False
286
287 size = int1.size == int2.size
288 align = int1.align == int2.align
289 cmap = int1.map == int2.map
290 base = int1.base == int2.base
291 encoding = int1.encoding == int2.encoding
292 signed = int1.signed == int2.signed
293 comps = (size, align, cmap, base, encoding, signed)
294
295 # True means 1 for sum()
296 return sum(comps) == len(comps)
297
298 def _validate_packet_context(self, stream):
299 packet_context = stream.packet_context
300 sid = stream.id
301
302 try:
303 self._validate_struct(packet_context)
304 except RuntimeError as e:
305 _perror('stream {}: packet context: {}'.format(sid, e))
306
307 fields = packet_context.fields
308
309 # if timestamp_begin exists, timestamp_end must exist
310 if 'timestamp_begin' in fields or 'timestamp_end' in fields:
311 if 'timestamp_begin' not in fields or 'timestamp_end' not in fields:
312 _perror('stream {}: packet context: "timestamp_begin" must exist if "timestamp_end" exists'.format(sid))
313 else:
314 # timestamp_begin and timestamp_end must have the same integer
315 # as the event header's timestamp field (should exist by now)
316 timestamp = stream.event_header['timestamp']
317
318 if not self._compare_integers(fields['timestamp_begin'], timestamp):
319 _perror('stream {}: packet context: "timestamp_begin": integer type different from event header\'s "timestamp" field'.format(sid))
320
321 if not self._compare_integers(fields['timestamp_end'], timestamp):
322 _perror('stream {}: packet context: "timestamp_end": integer type different from event header\'s "timestamp" field'.format(sid))
323
324 # content_size must exist and be an unsigned integer
325 if 'content_size' not in fields:
326 _perror('stream {}: packet context: missing "content_size" field'.format(sid))
327
328 try:
329 self._validate_integer(fields['content_size'], 32, 32, False)
330 except:
331 try:
332 self._validate_integer(fields['content_size'], 64, 64, False)
333 except:
334 _perror('stream {}: packet context: "content_size": expecting unsigned 32-bit/64-bit integer'.format(sid))
335
336 # packet_size must exist and be an unsigned integer
337 if 'packet_size' not in fields:
338 _perror('stream {}: packet context: missing "packet_size" field'.format(sid))
339
340 try:
341 self._validate_integer(fields['packet_size'], 32, 32, False)
342 except:
343 try:
344 self._validate_integer(fields['packet_size'], 64, 64, False)
345 except:
346 _perror('stream {}: packet context: "packet_size": expecting unsigned 32-bit/64-bit integer'.format(sid))
347
348 # if cpu_id exists, must be an unsigned integer
349 if 'cpu_id' in fields:
350 try:
351 self._validate_integer(fields['cpu_id'], signed=False)
352 except RuntimeError as e:
353 _perror('stream {}: packet context: "cpu_id": {}'.format(sid, e))
354
355 def _validate_event_header(self, stream):
356 event_header = stream.event_header
357 sid = stream.id
358
359 try:
360 self._validate_struct(event_header)
361 except RuntimeError as e:
362 _perror('stream {}: event header: {}'.format(sid, e))
363
364 fields = event_header.fields
365
366 # id must exist and be an unsigned integer
367 if 'id' not in fields:
368 _perror('stream {}: event header: missing "id" field'.format(sid))
369
370 try:
371 self._validate_integer(fields['id'], signed=False)
372 except RuntimeError as e:
373 _perror('stream {}: "id": {}'.format(sid, format(e)))
374
375
376 # timestamp must exist, be an unsigned integer and be mapped to a valid clock
377 if 'timestamp' not in fields:
378 _perror('stream {}: event header: missing "timestamp" field'.format(sid))
379
380 try:
381 self._validate_integer(fields['timestamp'], signed=False)
382 except RuntimeError as e:
383 _perror('stream {}: event header: "timestamp": {}'.format(sid, format(e)))
384
385 if fields['timestamp'].map is None:
386 _perror('stream {}: event header: "timestamp" must be mapped to a valid clock'.format(sid))
387
388 # id must be the first field, followed by timestamp
389 if list(fields.keys())[0] != 'id':
390 _perror('stream {}: event header: "id" must be the first field'.format(sid))
391
392 if list(fields.keys())[1] != 'timestamp':
393 _perror('stream {}: event header: "timestamp" must be the second field'.format(sid))
394
395 # only id and timestamp and allowed in event header
396 if len(fields) != 2:
397 _perror('stream {}: event header: only "id" and "timestamp" fields are allowed'.format(sid))
398
399 def _validate_stream_event_context(self, stream):
400 stream_event_context = stream.event_context
401 sid = stream.id
402
403 if stream_event_context is None:
404 return
405
406 try:
407 self._validate_context_fields(stream_event_context)
408 except RuntimeError as e:
409 _perror('stream {}: event context: {}'.format(sid, e))
410
411 def _validate_event_context(self, stream, event):
412 event_context = event.context
413 sid = stream.id
414 eid = event.id
415
416 if event_context is None:
417 return
418
419 try:
420 self._validate_context_fields(event_context)
421 except RuntimeError as e:
422 _perror('stream {}: event {}: context: {}'.format(sid, eid, e))
423
424 def _validate_event_fields(self, stream, event):
425 event_fields = event.fields
426 sid = stream.id
427 eid = event.id
428
429 try:
430 self._validate_context_fields(event_fields)
431 except RuntimeError as e:
432 _perror('stream {}: event {}: fields: {}'.format(sid, eid, e))
433
434 def _validate_all_scopes(self):
435 # packet header
436 self._validate_packet_header(self._doc.trace.packet_header)
437
438 # stream stuff
439 for stream in self._doc.streams.values():
440 self._validate_event_header(stream)
441 self._validate_packet_context(stream)
442 self._validate_stream_event_context(stream)
443
444 # event stuff
445 for event in stream.events:
446 self._validate_event_context(stream, event)
447 self._validate_event_fields(stream, event)
448
449 def _validate_metadata(self):
450 self._validate_all_scopes()
451
452 # 3, 4 -> 4
453 # 4, 4 -> 4
454 # 5, 4 -> 8
455 # 6, 4 -> 8
456 # 7, 4 -> 8
457 # 8, 4 -> 8
458 # 9, 4 -> 12
459 def _get_alignment(self, at, align):
460 return (at + align - 1) & -align
461
462 # this converts a tree of offset variables:
463 #
464 # field
465 # a -> 0
466 # b -> 8
467 # other_struct
468 # field -> 16
469 # yeah -> 20
470 # c -> 32
471 # len -> 36
472 #
473 # to a flat dict:
474 #
475 # field_a -> 0
476 # field_b -> 8
477 # field_other_struct_field -> 16
478 # field_other_struct_yeah -> 20
479 # field_c -> 32
480 # len -> 36
481 def _flatten_offvars_tree(self, offvars_tree, prefix=None,
482 offvars=None):
483 if offvars is None:
484 offvars = collections.OrderedDict()
485
486 for name, offset in offvars_tree.items():
487 if prefix is not None:
488 varname = '{}_{}'.format(prefix, name)
489 else:
490 varname = name
491
492 if isinstance(offset, dict):
493 self._flatten_offvars_tree(offset, varname, offvars)
494 else:
495 offvars[varname] = offset
496
497 return offvars
498
499 # returns the size of a struct with _static size_
500 def _get_struct_size(self, struct,
501 offvars_tree=None,
502 base_offset=0):
503 if offvars_tree is None:
504 offvars_tree = collections.OrderedDict()
505
506 offset = 0
507
508 for fname, ftype in struct.fields.items():
509 field_alignment = self._get_obj_alignment(ftype)
510 offset = self._get_alignment(offset, field_alignment)
511
512 if type(ftype) is pytsdl.tsdl.Struct:
513 offvars_tree[fname] = collections.OrderedDict()
514 sz = self._get_struct_size(ftype, offvars_tree[fname],
515 base_offset + offset)
516 else:
517 # only integers may act as sequence lengths
518 if type(ftype) is pytsdl.tsdl.Integer:
519 offvars_tree[fname] = base_offset + offset
520
521 sz = self._get_obj_size(ftype)
522
523 offset += sz
524
525 return offset
526
527 def _get_array_size(self, array):
528 element = array.element
529
530 # effective size of one element includes its alignment after its size
531 size = self._get_obj_size(element)
532 align = self._get_obj_alignment(element)
533
534 return self._get_alignment(size, align) * array.length
535
536 def _get_enum_size(self, enum):
537 return self._get_obj_size(enum.integer)
538
539 def _get_floating_point_size(self, floating_point):
540 return floating_point.exp_dig + floating_point.mant_dig
541
542 def _get_integer_size(self, integer):
543 return integer.size
544
545 def _get_obj_size(self, obj):
546 return self._obj_size_cb[type(obj)](obj)
547
548 def _get_struct_alignment(self, struct):
549 if struct.align is not None:
550 return struct.align
551
552 cur_align = 1
553
554 for fname, ftype in struct.fields.items():
555 cur_align = max(self._get_obj_alignment(ftype), cur_align)
556
557 return cur_align
558
559 def _get_integer_alignment(self, integer):
560 return integer.align
561
562 def _get_floating_point_alignment(self, floating_point):
563 return floating_point.align
564
565 def _get_enum_alignment(self, enum):
566 return self._get_obj_alignment(enum.integer)
567
568 def _get_string_alignment(self, string):
569 return 8
570
571 def _get_array_alignment(self, array):
572 return self._get_obj_alignment(array.element)
573
574 def _get_sequence_alignment(self, sequence):
575 return self._get_obj_alignment(sequence.element)
576
577 def _get_obj_alignment(self, obj):
578 return self._obj_alignment_cb[type(obj)](obj)
579
580 def _fname_to_pname(self, prefix, name):
581 return 'param_{}_{}'.format(prefix, name)
582
583 def _ef_fname_to_pname(self, name):
584 return self._fname_to_pname('ef', name)
585
586 def _ec_fname_to_pname(self, name):
587 return self._fname_to_pname('ec', name)
588
589 def _sec_fname_to_pname(self, name):
590 return self._fname_to_pname('sec', name)
591
592 def _eh_fname_to_pname(self, name):
593 return self._fname_to_pname('eh', name)
594
595 def _spc_fname_to_pname(self, name):
596 return self._fname_to_pname('spc', name)
597
598 def _tph_fname_to_pname(self, name):
599 return self._fname_to_pname('tph', name)
600
601 def _get_integer_param_ctype(self, integer):
602 signed = 'u' if not integer.signed else ''
603
604 if integer.size == 8:
605 sz = '8'
606 elif integer.size == 16:
607 sz = '16'
608 elif integer.size == 32:
609 sz = '32'
610 elif integer.size == 64:
611 sz = '64'
612 else:
613 # if the integer is signed and of uncommon size, the sign bit is
614 # at a custom position anyway so we use a 64-bit unsigned
615 signed = 'u'
616
617 if integer.signed:
618 sz = '64'
619 else:
620 if integer.size < 16:
621 sz = '8'
622 elif integer.size < 32:
623 sz = '16'
624 elif integer.size < 64:
625 sz = '32'
626 else:
627 sz = '64'
628
629 return '{}int{}_t'.format(signed, sz)
630
631 def _get_enum_param_ctype(self, enum):
632 return self._get_obj_param_ctype(enum.integer)
633
634 def _get_floating_point_param_ctype(self, fp):
635 if fp.exp_dig == 8 and fp.mant_dig == 24 and fp.align == 32:
636 return 'float'
637 elif fp.exp_dig == 11 and fp.mant_dig == 53 and fp.align == 64:
638 return 'double'
639 else:
640 return 'uint64_t'
641
642 def _get_obj_param_ctype(self, obj):
643 return self._obj_param_ctype_cb[type(obj)](obj)
644
645 def _get_chk_offset_v(self, size):
646 fmt = '{}_CHK_OFFSET_V({}, {}, {});'
647 ret = fmt.format(self._prefix.upper(), self._CTX_AT,
648 self._CTX_BUF_SIZE, size)
649
650 return ret
651
652 def _get_chk_offset_v_cline(self, size):
653 return _CLine(self._get_chk_offset_v(size))
654
655 def _get_align_offset(self, align):
656 fmt = '{}_ALIGN_OFFSET({}, {});'
657 ret = fmt.format(self._prefix.upper(), self._CTX_AT, align)
658
659 return ret
660
661 def _get_align_offset_cline(self, size):
662 return _CLine(self._get_align_offset(size))
663
664 def _str_to_clines(self, s):
665 lines = s.split('\n')
666
667 return [_CLine(line) for line in lines]
668
669 def _template_to_clines(self, tmpl, **kwargs):
670 s = tmpl.format(prefix=self._prefix, ucprefix=self._prefix.upper(),
671 **kwargs)
672
673 return self._str_to_clines(s)
674
675 def _write_field_struct(self, fname, src_name, struct, scope_prefix):
676 size = self._get_struct_size(struct)
677 size_bytes = self._get_alignment(size, 8) // 8
678 dst = self._CTX_BUF_AT_ADDR
679
680 return [
681 # memcpy() is safe since barectf requires inner structures
682 # to be byte-aligned
683 self._get_chk_offset_v_cline(size),
684 _CLine('memcpy({}, {}, {});'.format(dst, src_name, size_bytes)),
685 _CLine('{} += {};'.format(self._CTX_AT, size)),
686 ]
687
688 def _write_field_integer(self, fname, src_name, integer, scope_prefix=None):
689 bo = self._bo_suffixes_map[integer.byte_order]
690 t = self._get_obj_param_ctype(integer)
691 length = self._get_obj_size(integer)
692
693 return self._template_to_clines(barectf.templates.WRITE_INTEGER,
694 sz=length, bo=bo, type=t,
695 src_name=src_name)
696
697 def _write_field_enum(self, fname, src_name, enum, scope_prefix=None):
698 return self._write_field_obj(fname, src_name, enum.integer)
699
700 def _write_field_floating_point(self, fname, src_name, floating_point,
701 scope_prefix=None):
702 bo = self._bo_suffixes_map[floating_point.byte_order]
703 t = self._get_obj_param_ctype(floating_point)
704 length = self._get_obj_size(floating_point)
705
706 return self._template_to_clines(barectf.templates.WRITE_INTEGER,
707 sz=length, bo=bo, type=t,
708 src_name=src_name)
709
710 def _write_field_array(self, fname, src_name, array, scope_prefix=None):
711 clines = []
712
713 # array index variable declaration
714 iv = 'ia_{}'.format(fname)
715 clines.append(_CLine('uint32_t {};'.format(iv)))
716
717 # for loop using array's static length
718 line = 'for ({iv} = 0; {iv} < {l}; ++{iv}) {{'.format(iv=iv,
719 l=array.length)
720 clines.append(_CLine(line))
721
722 # for loop statements
723 for_block = _CBlock()
724
725 # align bit index before writing to the buffer
726 element_align = self._get_obj_alignment(array.element)
727 cline = self._get_align_offset_cline(element_align)
728 for_block.append(cline)
729
730 # write element to the buffer
731 for_block += self._write_field_obj(fname, src_name, array.element,
732 scope_prefix)
733 clines.append(for_block)
734
735 # for loop end
736 clines.append(_CLine('}'))
737
738 return clines
739
740 def _get_tph_src_name(self, length):
741 offvar = self._get_offvar_name_from_expr(length[3:], 'tph')
742
743 return 'ctx->{}'.format(offvar)
744
745 def _get_env_src_name(self, length):
746 if len(length) != 2:
747 _perror('invalid sequence length: "{}"'.format(self._dot_name_to_str(length)))
748
749 fname = length[1]
750
751 if fname not in self._doc.env:
752 _perror('cannot find field env.{}'.format(fname))
753
754 return str(self._doc.env[fname])
755
756 def _get_spc_src_name(self, length):
757 offvar = self._get_offvar_name_from_expr(length[3:], 'spc')
758
759 return 'ctx->{}'.format(offvar)
760
761 def _get_seh_src_name(self, length):
762 return self._get_offvar_name_from_expr(length[3:], 'seh')
763
764 def _get_sec_src_name(self, length):
765 return self._get_offvar_name_from_expr(length[3:], 'sec')
766
767 def _get_ec_src_name(self, length):
768 return self._get_offvar_name_from_expr(length[2:], 'ec')
769
770 def _get_ef_src_name(self, length):
771 return self._get_offvar_name_from_expr(length[2:], 'ef')
772
773 def _seq_length_to_src_name(self, length, scope_prefix=None):
774 length_dot = self._dot_name_to_str(length)
775
776 for prefix, get_src_name in self._get_src_name_funcs.items():
777 if length_dot.startswith(prefix):
778 return get_src_name(length)
779
780 return self._get_offvar_name_from_expr(length, scope_prefix)
781
782 def _write_field_sequence(self, fname, src_name, sequence, scope_prefix):
783 clines = []
784
785 # sequence index variable declaration
786 iv = 'is_{}'.format(fname)
787 clines.append(_CLine('uint32_t {};'.format(iv)))
788
789 # sequence length offset variable
790 length_offvar = self._seq_length_to_src_name(sequence.length,
791 scope_prefix)
792
793 # for loop using sequence's static length
794 line = 'for ({iv} = 0; {iv} < {l}; ++{iv}) {{'.format(iv=iv,
795 l=length_offvar)
796 clines.append(_CLine(line))
797
798 # for loop statements
799 for_block = _CBlock()
800
801 # align bit index before writing to the buffer
802 element_align = self._get_obj_alignment(sequence.element)
803 cline = self._get_align_offset_cline(element_align)
804 for_block.append(cline)
805
806 # write element to the buffer
807 for_block += self._write_field_obj(fname, src_name, sequence.element,
808 scope_prefix)
809 clines.append(for_block)
810
811 # for loop end
812 clines.append(_CLine('}'))
813
814 return clines
815
816 def _write_field_string(self, fname, src_name, string, scope_prefix=None):
817 clines = []
818
819 # string index variable declaration
820 iv = 'is_{}'.format(fname)
821 clines.append(_CLine('uint32_t {};'.format(iv)))
822
823 # for loop; loop until the end of the source string is reached
824 fmt = "for ({iv} = 0; {src}[{iv}] != '\\0'; ++{iv}, {ctxat} += 8) {{"
825 line = fmt.format(iv=iv, src=src_name, ctxat=self._CTX_AT)
826 clines.append(_CLine(line))
827
828 # for loop statements
829 for_block = _CBlock()
830
831 # check offset overflow
832 for_block.append(self._get_chk_offset_v_cline(8))
833
834 # write byte to the buffer
835 fmt = '{dst} = {src}[{iv}];'
836 line = fmt.format(dst=self._CTX_BUF_AT, iv=iv, src=src_name)
837 for_block.append(_CLine(line))
838
839 # append for loop
840 clines.append(for_block)
841 clines.append(_CLine('}'))
842
843 # write NULL character to the buffer
844 clines.append(_CLine("{} = '\\0';".format(self._CTX_BUF_AT)))
845 clines.append(_CLine('{} += 8;'.format(self._CTX_AT)))
846
847 return clines
848
849 def _write_field_obj(self, fname, src_name, ftype, scope_prefix):
850 return self._write_field_obj_cb[type(ftype)](fname, src_name, ftype,
851 scope_prefix)
852
853 def _get_offvar_name(self, name, prefix=None):
854 parts = ['off']
855
856 if prefix is not None:
857 parts.append(prefix)
858
859 parts.append(name)
860
861 return '_'.join(parts)
862
863 def _get_offvar_name_from_expr(self, expr, prefix=None):
864 return self._get_offvar_name('_'.join(expr), prefix)
865
866 def _field_to_clines(self, fname, ftype, scope_name, scope_prefix,
867 param_name_cb):
868 clines = []
869 pname = param_name_cb(fname)
870 align = self._get_obj_alignment(ftype)
871
872 # group comment
873 fmt = '/* write {}.{} ({}) */'
874 line = fmt.format(scope_name, fname,
875 self._tsdl_type_names_map[type(ftype)])
876 clines.append(_CLine(line))
877
878 # align bit index before writing to the buffer
879 cline = self._get_align_offset_cline(align)
880 clines.append(cline)
881
882 # write offset variables
883 if type(ftype) is pytsdl.tsdl.Struct:
884 offvars_tree = collections.OrderedDict()
885 self._get_struct_size(ftype, offvars_tree)
886 offvars = self._flatten_offvars_tree(offvars_tree)
887
888 # as many offset as there are child fields because a future
889 # sequence could refer to any of those fields
890 for lname, offset in offvars.items():
891 offvar = self._get_offvar_name('_'.join([fname, lname]),
892 scope_prefix)
893 fmt = 'uint32_t {} = {} + {};'
894 line = fmt.format(offvar, self._CTX_AT, offset);
895 clines.append(_CLine(line))
896 elif type(ftype) is pytsdl.tsdl.Integer:
897 # offset of this simple field is the current bit index
898 offvar = self._get_offvar_name(fname, scope_prefix)
899 line = 'uint32_t {} = {};'.format(offvar, self._CTX_AT)
900 clines.append(_CLine(line))
901
902 clines += self._write_field_obj(fname, pname, ftype, scope_prefix)
903
904 return clines
905
906 def _join_cline_groups(self, cline_groups):
907 if not cline_groups:
908 return cline_groups
909
910 output_clines = cline_groups[0]
911
912 for clines in cline_groups[1:]:
913 output_clines.append('')
914 output_clines += clines
915
916 return output_clines
917
918 def _struct_to_clines(self, struct, scope_name, scope_prefix,
919 param_name_cb):
920 cline_groups = []
921
922 for fname, ftype in struct.fields.items():
923 clines = self._field_to_clines(fname, ftype, scope_name,
924 scope_prefix, param_name_cb)
925 cline_groups.append(clines)
926
927 return self._join_cline_groups(cline_groups)
928
929 def _get_struct_size_offvars(self, struct):
930 offvars_tree = collections.OrderedDict()
931 size = self._get_struct_size(struct, offvars_tree)
932 offvars = self._flatten_offvars_tree(offvars_tree)
933
934 return size, offvars
935
936 def _get_ph_size_offvars(self):
937 return self._get_struct_size_offvars(self._doc.trace.packet_header)
938
939 def _get_pc_size_offvars(self, stream):
940 return self._get_struct_size_offvars(stream.packet_context)
941
942 def _offvars_to_ctx_clines(self, prefix, offvars):
943 clines = []
944
945 for name in offvars.keys():
946 offvar = self._get_offvar_name(name, prefix)
947 clines.append(_CLine('uint32_t {};'.format(offvar)))
948
949 return clines
950
951 def _gen_barectf_ctx_struct(self, stream, hide_sid=False):
952 # get offset variables for both the packet header and packet context
953 ph_size, ph_offvars = self._get_ph_size_offvars()
954 pc_size, pc_offvars = self._get_pc_size_offvars(stream)
955 clines = self._offvars_to_ctx_clines('tph', ph_offvars)
956 clines += self._offvars_to_ctx_clines('spc', pc_offvars)
957
958 # indent C
959 clines_indented = []
960 for cline in clines:
961 clines_indented.append(_CLine('\t' + cline))
962
963 # clock callback
964 clock_cb = '\t/* (no clock callback) */'
965
966 if not self._manual_clock:
967 ctype = self._get_clock_type(stream)
968 fmt = '\t{} (*clock_cb)(void*),\n\tvoid* clock_cb_data;'
969 clock_cb = fmt.format(ctype)
970
971 # fill template
972 sid = ''
973
974 if not hide_sid:
975 sid = stream.id
976
977 t = barectf.templates.BARECTF_CTX
978 struct = t.format(prefix=self._prefix, sid=sid,
979 ctx_fields='\n'.join(clines_indented),
980 clock_cb=clock_cb)
981
982 return struct
983
984 def _gen_barectf_contexts_struct(self):
985 hide_sid = False
986
987 if len(self._doc.streams) == 1:
988 hide_sid = True
989
990 structs = []
991
992 for stream in self._doc.streams.values():
993 struct = self._gen_barectf_ctx_struct(stream, hide_sid)
994 structs.append(struct)
995
996 return '\n\n'.join(structs)
997
998 _packet_context_known_fields = [
999 'content_size',
1000 'packet_size',
1001 'timestamp_begin',
1002 'timestamp_end',
1003 ]
1004
1005 def _get_clock_type(self, stream):
1006 return self._get_obj_param_ctype(stream.event_header['timestamp'])
1007
1008 def _gen_manual_clock_param(self, stream):
1009 return '{} param_clock'.format(self._get_clock_type(stream))
1010
1011 def _gen_barectf_func_open_body(self, stream):
1012 clines = []
1013
1014 # keep clock value (for timestamp_begin)
1015 if self._stream_has_timestamp_begin_end(stream):
1016 # get clock value ASAP
1017 clk_type = self._get_clock_type(stream)
1018 clk = self._gen_get_clock_value()
1019 line = '{} clk_value = {};'.format(clk_type, clk)
1020 clines.append(_CLine(line))
1021 clines.append(_CLine(''))
1022
1023 # packet context fields
1024 fcline_groups = []
1025 scope_name = 'stream.packet.context'
1026 scope_prefix = 'spc'
1027
1028 for fname, ftype in stream.packet_context.fields.items():
1029 # packet size
1030 if fname == 'packet_size':
1031 fclines = self._field_to_clines(fname, ftype, scope_name,
1032 scope_prefix,
1033 lambda x: 'ctx->buffer_size')
1034 fcline_groups.append(fclines)
1035
1036 # content size (skip)
1037 elif fname == 'content_size':
1038 fclines = self._field_to_clines(fname, ftype, scope_name,
1039 scope_prefix, lambda x: '0')
1040 fcline_groups.append(fclines)
1041
1042 # timestamp_begin
1043 elif fname == 'timestamp_begin':
1044 fclines = self._field_to_clines(fname, ftype, scope_name,
1045 scope_prefix,
1046 lambda x: 'clk_value')
1047 fcline_groups.append(fclines)
1048
1049 # timestamp_end (skip)
1050 elif fname == 'timestamp_end':
1051 fclines = self._field_to_clines(fname, ftype, scope_name,
1052 scope_prefix, lambda x: '0')
1053 fcline_groups.append(fclines)
1054
1055 # anything else
1056 else:
1057 fclines = self._field_to_clines(fname, ftype, scope_name,
1058 scope_prefix,
1059 self._spc_fname_to_pname)
1060 fcline_groups.append(fclines)
1061
1062 # return 0
1063 fcline_groups.append([_CLine('return 0;')])
1064
1065 clines += self._join_cline_groups(fcline_groups)
1066
1067 # get source
1068 cblock = _CBlock(clines)
1069 src = self._cblock_to_source(cblock)
1070
1071 return src
1072
1073 def _gen_barectf_func_open(self, stream, gen_body, hide_sid=False):
1074 params = []
1075
1076 # manual clock
1077 if self._manual_clock:
1078 clock_param = self._gen_manual_clock_param(stream)
1079 params.append(clock_param)
1080
1081 # packet context
1082 for fname, ftype in stream.packet_context.fields.items():
1083 if fname in self._packet_context_known_fields:
1084 continue
1085
1086 ptype = self._get_obj_param_ctype(ftype)
1087 pname = self._spc_fname_to_pname(fname)
1088 param = '{} {}'.format(ptype, pname)
1089 params.append(param)
1090
1091 params_str = ''
1092
1093 if params:
1094 params_str = ',\n\t'.join([''] + params)
1095
1096 # fill template
1097 sid = ''
1098
1099 if not hide_sid:
1100 sid = stream.id
1101
1102 t = barectf.templates.FUNC_OPEN
1103 func = t.format(si=self._si_str, prefix=self._prefix, sid=sid,
1104 params=params_str)
1105
1106 if gen_body:
1107 func += '\n{\n'
1108 func += self._gen_barectf_func_open_body(stream)
1109 func += '\n}'
1110 else:
1111 func += ';'
1112
1113 return func
1114
1115 def _gen_barectf_func_init_body(self, stream):
1116 clines = []
1117
1118 line = 'uint32_t ctx_at_bkup;'
1119 clines.append(_CLine(line))
1120
1121 # set context parameters
1122 clines.append(_CLine(''))
1123 clines.append(_CLine("/* barectf context parameters */"))
1124 clines.append(_CLine('ctx->buf = buf;'))
1125 clines.append(_CLine('ctx->buf_size = buf_size * 8;'))
1126 clines.append(_CLine('{} = 0;'.format(self._CTX_AT)))
1127
1128 if not self._manual_clock:
1129 clines.append(_CLine('ctx->clock_cb = clock_cb;'))
1130 clines.append(_CLine('ctx->clock_cb_data = clock_cb_data;'))
1131
1132 # set context offsets
1133 clines.append(_CLine(''))
1134 clines.append(_CLine("/* barectf context offsets */"))
1135 ph_size, ph_offvars = self._get_ph_size_offvars()
1136 pc_size, pc_offvars = self._get_pc_size_offvars(stream)
1137 pc_alignment = self._get_obj_alignment(stream.packet_context)
1138 pc_offset = self._get_alignment(ph_size, pc_alignment)
1139
1140 for offvar, offset in ph_offvars.items():
1141 offvar_field = self._get_offvar_name(offvar, 'tph')
1142 line = 'ctx->{} = {};'.format(offvar_field, offset)
1143 clines.append(_CLine(line))
1144
1145 for offvar, offset in pc_offvars.items():
1146 offvar_field = self._get_offvar_name(offvar, 'spc')
1147 line = 'ctx->{} = {};'.format(offvar_field, pc_offset + offset)
1148 clines.append(_CLine(line))
1149
1150 clines.append(_CLine(''))
1151
1152 # packet header fields
1153 fcline_groups = []
1154 scope_name = 'trace.packet.header'
1155 scope_prefix = 'tph'
1156
1157 for fname, ftype in self._doc.trace.packet_header.fields.items():
1158 # magic number
1159 if fname == 'magic':
1160 fclines = self._field_to_clines(fname, ftype, scope_name,
1161 scope_prefix,
1162 lambda x: '0xc1fc1fc1UL')
1163 fcline_groups.append(fclines)
1164
1165 # stream ID
1166 elif fname == 'stream_id':
1167 fclines = self._field_to_clines(fname, ftype, scope_name,
1168 scope_prefix,
1169 lambda x: str(stream.id))
1170 fcline_groups.append(fclines)
1171
1172 # return 0
1173 fcline_groups.append([_CLine('return 0;')])
1174
1175 clines += self._join_cline_groups(fcline_groups)
1176
1177 # get source
1178 cblock = _CBlock(clines)
1179 src = self._cblock_to_source(cblock)
1180
1181 return src
1182
1183 def _gen_barectf_func_init(self, stream, gen_body, hide_sid=False):
1184 # fill template
1185 sid = ''
1186
1187 if not hide_sid:
1188 sid = stream.id
1189
1190 params = ''
1191
1192 if not self._manual_clock:
1193 ts_ftype = stream.event_header['timestamp']
1194 ts_ptype = self._get_obj_param_ctype(ts_ftype)
1195 fmt = ',\n\t{} (*clock_cb)(void*),\n\tvoid* clock_cb_data'
1196 params = fmt.format(ts_ptype)
1197
1198 t = barectf.templates.FUNC_INIT
1199 func = t.format(si=self._si_str, prefix=self._prefix, sid=sid,
1200 params=params)
1201
1202 if gen_body:
1203 func += '\n{\n'
1204 func += self._gen_barectf_func_init_body(stream)
1205 func += '\n}'
1206 else:
1207 func += ';'
1208
1209 return func
1210
1211 def _gen_get_clock_value(self):
1212 if self._manual_clock:
1213 return 'param_clock'
1214 else:
1215 return self._CTX_CALL_CLOCK_CB
1216
1217 def _stream_has_timestamp_begin_end(self, stream):
1218 return self._has_timestamp_begin_end[stream.id]
1219
1220 def _gen_write_ctx_field_integer(self, src_name, prefix, name, obj):
1221 clines = []
1222
1223 # save buffer position
1224 line = 'ctx_at_bkup = {};'.format(self._CTX_AT)
1225 clines.append(_CLine(line))
1226
1227 # go back to field offset
1228 offvar = self._get_offvar_name(name, prefix)
1229 line = '{} = ctx->{};'.format(self._CTX_AT, offvar)
1230 clines.append(_CLine(line))
1231
1232 # write value
1233 clines += self._write_field_integer(None, src_name, obj)
1234
1235 # restore buffer position
1236 line = '{} = ctx_at_bkup;'.format(self._CTX_AT)
1237 clines.append(_CLine(line))
1238
1239 return clines
1240
1241 def _gen_barectf_func_close_body(self, stream):
1242 clines = []
1243
1244 line = 'uint32_t ctx_at_bkup;'
1245 clines.append(_CLine(line))
1246
1247 # update timestamp end if present
1248 if self._stream_has_timestamp_begin_end(stream):
1249 clines.append(_CLine(''))
1250 clines.append(_CLine("/* update packet context's timestamp_end */"))
1251
1252 # get clock value ASAP
1253 clk_type = self._get_clock_type(stream)
1254 clk = self._gen_get_clock_value()
1255 line = '{} clk_value = {};'.format(clk_type, clk)
1256 clines.append(_CLine(line))
1257
1258 # write timestamp_end
1259 timestamp_end_integer = stream.packet_context['timestamp_end']
1260 clines += self._gen_write_ctx_field_integer('clk_value', 'pc',
1261 'timestamp_end',
1262 timestamp_end_integer)
1263
1264 # update content_size
1265 clines.append(_CLine(''))
1266 clines.append(_CLine("/* update packet context's content_size */"))
1267 content_size_integer = stream.packet_context['content_size']
1268 clines += self._gen_write_ctx_field_integer('ctx_at_bkup', 'pc',
1269 'content_size',
1270 content_size_integer)
1271
1272 # get source
1273 cblock = _CBlock(clines)
1274 src = self._cblock_to_source(cblock)
1275
1276 return src
1277
1278 def _gen_barectf_func_close(self, stream, gen_body, hide_sid=False):
1279 # fill template
1280 sid = ''
1281
1282 if not hide_sid:
1283 sid = stream.id
1284
1285 params = ''
1286
1287 if self._manual_clock:
1288 clock_param = self._gen_manual_clock_param(stream)
1289 params = ',\n\t{}'.format(clock_param)
1290
1291 t = barectf.templates.FUNC_CLOSE
1292 func = t.format(si=self._si_str, prefix=self._prefix, sid=sid,
1293 params=params)
1294
1295 if gen_body:
1296 func += '\n{\n'
1297 func += self._gen_barectf_func_close_body(stream)
1298 func += '\n}'
1299 else:
1300 func += ';'
1301
1302 return func
1303
1304 def _gen_barectf_funcs_init(self, gen_body):
1305 hide_sid = False
1306
1307 if len(self._doc.streams) == 1:
1308 hide_sid = True
1309
1310 funcs = []
1311
1312 for stream in self._doc.streams.values():
1313 funcs.append(self._gen_barectf_func_init(stream, gen_body,
1314 hide_sid))
1315
1316 return funcs
1317
1318 def _gen_barectf_funcs_open(self, gen_body):
1319 hide_sid = False
1320
1321 if len(self._doc.streams) == 1:
1322 hide_sid = True
1323
1324 funcs = []
1325
1326 for stream in self._doc.streams.values():
1327 funcs.append(self._gen_barectf_func_open(stream, gen_body,
1328 hide_sid))
1329
1330 return funcs
1331
1332 def _gen_barectf_func_trace_event_body(self, stream, event):
1333 clines = []
1334
1335 # get clock value ASAP
1336 clk_type = self._get_clock_type(stream)
1337 clk = self._gen_get_clock_value()
1338 line = '{} clk_value = {};'.format(clk_type, clk)
1339 clines.append(_CLine(line))
1340 clines.append(_CLine(''))
1341
1342 # event header
1343 fcline_groups = []
1344 scope_name = 'event.header'
1345 scope_prefix = 'eh'
1346
1347 for fname, ftype in stream.event_header.fields.items():
1348 # id
1349 if fname == 'id':
1350 fclines = self._field_to_clines(fname, ftype, scope_name,
1351 scope_prefix,
1352 lambda x: str(event.id))
1353 fcline_groups.append(fclines)
1354
1355 # timestamp
1356 elif fname == 'timestamp':
1357 fclines = self._field_to_clines(fname, ftype, scope_name,
1358 scope_prefix,
1359 lambda x: 'clk_value')
1360 fcline_groups.append(fclines)
1361
1362 # stream event context
1363 if stream.event_context is not None:
1364 fclines = self._struct_to_clines(stream.event_context,
1365 'stream.event.context', 'sec',
1366 self._sec_fname_to_pname)
1367 fcline_groups.append(fclines)
1368
1369 # event context
1370 if event.context is not None:
1371 fclines = self._struct_to_clines(event.context,
1372 'event.context', 'ec',
1373 self._ec_fname_to_pname)
1374 fcline_groups.append(fclines)
1375
1376 # event fields
1377 if event.fields is not None:
1378 fclines = self._struct_to_clines(event.fields,
1379 'event.fields', 'ef',
1380 self._ef_fname_to_pname)
1381 fcline_groups.append(fclines)
1382
1383 # return 0
1384 fcline_groups.append([_CLine('return 0;')])
1385
1386 clines += self._join_cline_groups(fcline_groups)
1387
1388 # get source
1389 cblock = _CBlock(clines)
1390 src = self._cblock_to_source(cblock)
1391
1392 return src
1393
1394 def _gen_barectf_func_trace_event(self, stream, event, gen_body, hide_sid):
1395 params = []
1396
1397 # manual clock
1398 if self._manual_clock:
1399 clock_param = self._gen_manual_clock_param(stream)
1400 params.append(clock_param)
1401
1402 # stream event context params
1403 if stream.event_context is not None:
1404 for fname, ftype in stream.event_context.fields.items():
1405 ptype = self._get_obj_param_ctype(ftype)
1406 pname = self._sec_fname_to_pname(fname)
1407 param = '{} {}'.format(ptype, pname)
1408 params.append(param)
1409
1410 # event context params
1411 if event.context is not None:
1412 for fname, ftype in event.context.fields.items():
1413 ptype = self._get_obj_param_ctype(ftype)
1414 pname = self._ec_fname_to_pname(fname)
1415 param = '{} {}'.format(ptype, pname)
1416 params.append(param)
1417
1418 # event fields params
1419 if event.fields is not None:
1420 for fname, ftype in event.fields.fields.items():
1421 ptype = self._get_obj_param_ctype(ftype)
1422 pname = self._ef_fname_to_pname(fname)
1423 param = '{} {}'.format(ptype, pname)
1424 params.append(param)
1425
1426 params_str = ''
1427
1428 if params:
1429 params_str = ',\n\t'.join([''] + params)
1430
1431 # fill template
1432 sid = ''
1433
1434 if not hide_sid:
1435 sid = stream.id
1436
1437 t = barectf.templates.FUNC_TRACE
1438 func = t.format(si=self._si_str, prefix=self._prefix, sid=sid,
1439 evname=event.name, params=params_str)
1440
1441 if gen_body:
1442 func += '\n{\n'
1443 func += self._gen_barectf_func_trace_event_body(stream, event)
1444 func += '\n}'
1445 else:
1446 func += ';'
1447
1448 return func
1449
1450 def _gen_barectf_funcs_trace_stream(self, stream, gen_body, hide_sid):
1451 funcs = []
1452
1453 for event in stream.events:
1454 funcs.append(self._gen_barectf_func_trace_event(stream, event,
1455 gen_body, hide_sid))
1456
1457 return funcs
1458
1459 def _gen_barectf_funcs_trace(self, gen_body):
1460 hide_sid = False
1461
1462 if len(self._doc.streams) == 1:
1463 hide_sid = True
1464
1465 funcs = []
1466
1467 for stream in self._doc.streams.values():
1468 funcs += self._gen_barectf_funcs_trace_stream(stream, gen_body,
1469 hide_sid)
1470
1471 return funcs
1472
1473 def _gen_barectf_funcs_close(self, gen_body):
1474 hide_sid = False
1475
1476 if len(self._doc.streams) == 1:
1477 hide_sid = True
1478
1479 funcs = []
1480
1481 for stream in self._doc.streams.values():
1482 funcs.append(self._gen_barectf_func_close(stream, gen_body,
1483 hide_sid))
1484
1485 return funcs
1486
1487 def _gen_barectf_header(self):
1488 ctx_structs = self._gen_barectf_contexts_struct()
1489 init_funcs = self._gen_barectf_funcs_init(self._static_inline)
1490 open_funcs = self._gen_barectf_funcs_open(self._static_inline)
1491 close_funcs = self._gen_barectf_funcs_close(self._static_inline)
1492 trace_funcs = self._gen_barectf_funcs_trace(self._static_inline)
1493 functions = init_funcs + open_funcs + close_funcs + trace_funcs
1494 functions_str = '\n\n'.join(functions)
1495 t = barectf.templates.HEADER
1496 header = t.format(prefix=self._prefix, ucprefix=self._prefix.upper(),
1497 barectf_ctx=ctx_structs, functions=functions_str)
1498
1499 return header
1500
1501 def _cblock_to_source_lines(self, cblock, indent=1):
1502 src = []
1503 indentstr = '\t' * indent
1504
1505 for line in cblock:
1506 if type(line) is _CBlock:
1507 src += self._cblock_to_source_lines(line, indent + 1)
1508 else:
1509 src.append(indentstr + line)
1510
1511 return src
1512
1513 def _cblock_to_source(self, cblock, indent=1):
1514 lines = self._cblock_to_source_lines(cblock, indent)
1515
1516 return '\n'.join(lines)
1517
1518 def _set_params(self):
1519 self._has_timestamp_begin_end = {}
1520
1521 for stream in self._doc.streams.values():
1522 has = 'timestamp_begin' in stream.packet_context.fields
1523 self._has_timestamp_begin_end[stream.id] = has
1524
1525 def gen_barectf(self, metadata, output, prefix, static_inline,
1526 manual_clock):
1527 self._metadata = metadata
1528 self._output = output
1529 self._prefix = prefix
1530 self._static_inline = static_inline
1531 self._manual_clock = manual_clock
1532 self._si_str = ''
1533
1534 if static_inline:
1535 self._si_str = 'static inline '
1536
1537 # open CTF metadata file
1538 _pinfo('opening CTF metadata file "{}"'.format(self._metadata))
1539
1540 try:
1541 with open(metadata) as f:
1542 self._tsdl = f.read()
1543 except:
1544 _perror('cannot open/read CTF metadata file "{}"'.format(metadata))
1545
1546 # parse CTF metadata
1547 _pinfo('parsing CTF metadata file')
1548
1549 try:
1550 self._doc = self._parser.parse(self._tsdl)
1551 except pytsdl.parser.ParseError as e:
1552 _perror('parse error: {}'.format(e))
1553
1554 # validate CTF metadata against barectf constraints
1555 _pinfo('validating CTF metadata file')
1556 self._validate_metadata()
1557 _psuccess('CTF metadata file is valid')
1558
1559 # set parameters for this generation
1560 self._set_params()
1561
1562 # generate header
1563 _pinfo('generating barectf header file')
1564 self._gen_barectf_header()
1565
1566
1567 def run():
1568 args = _parse_args()
1569 generator = BarectfCodeGenerator()
1570 generator.gen_barectf(args.metadata, args.output, args.prefix,
1571 args.static_inline, args.manual_clock)
This page took 0.083811 seconds and 5 git commands to generate.