Fix: write float/double floating point numbers
[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_PACKET_SIZE = 'ctx->packet_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
114 self._obj_size_cb = {
115 pytsdl.tsdl.Struct: self._get_struct_size,
116 pytsdl.tsdl.Integer: self._get_integer_size,
117 pytsdl.tsdl.Enum: self._get_enum_size,
118 pytsdl.tsdl.FloatingPoint: self._get_floating_point_size,
119 pytsdl.tsdl.Array: self._get_array_size,
120 }
121
122 self._obj_alignment_cb = {
123 pytsdl.tsdl.Struct: self._get_struct_alignment,
124 pytsdl.tsdl.Integer: self._get_integer_alignment,
125 pytsdl.tsdl.Enum: self._get_enum_alignment,
126 pytsdl.tsdl.FloatingPoint: self._get_floating_point_alignment,
127 pytsdl.tsdl.Array: self._get_array_alignment,
128 pytsdl.tsdl.Sequence: self._get_sequence_alignment,
129 pytsdl.tsdl.String: self._get_string_alignment,
130 }
131
132 self._obj_param_ctype_cb = {
133 pytsdl.tsdl.Struct: lambda obj: 'const void*',
134 pytsdl.tsdl.Integer: self._get_integer_param_ctype,
135 pytsdl.tsdl.Enum: self._get_enum_param_ctype,
136 pytsdl.tsdl.FloatingPoint: self._get_floating_point_param_ctype,
137 pytsdl.tsdl.Array: lambda obj: 'const void*',
138 pytsdl.tsdl.Sequence: lambda obj: 'const void*',
139 pytsdl.tsdl.String: lambda obj: 'const char*',
140 }
141
142 self._write_field_obj_cb = {
143 pytsdl.tsdl.Struct: self._write_field_struct,
144 pytsdl.tsdl.Integer: self._write_field_integer,
145 pytsdl.tsdl.Enum: self._write_field_enum,
146 pytsdl.tsdl.FloatingPoint: self._write_field_floating_point,
147 pytsdl.tsdl.Array: self._write_field_array,
148 pytsdl.tsdl.Sequence: self._write_field_sequence,
149 pytsdl.tsdl.String: self._write_field_string,
150 }
151
152 self._get_src_name_funcs = {
153 'trace.packet.header.': self._get_tph_src_name,
154 'env.': self._get_env_src_name,
155 'stream.packet.context.': self._get_spc_src_name,
156 'stream.event.header.': self._get_seh_src_name,
157 'stream.event.context.': self._get_sec_src_name,
158 'event.context.': self._get_ec_src_name,
159 'event.fields.': self._get_ef_src_name,
160 }
161
162 # Finds the terminal element of a TSDL array/sequence.
163 #
164 # arrayseq: array or sequence
165 def _find_arrayseq_element(self, arrayseq):
166 el = arrayseq.element
167 t = type(arrayseq.element)
168
169 if t is pytsdl.tsdl.Array or t is pytsdl.tsdl.Sequence:
170 return self._find_arrayseq_element(el)
171
172 return el
173
174 # Validates an inner TSDL structure's field (constrained structure).
175 #
176 # fname: field name
177 # ftype: TSDL object
178 def _validate_struct_field(self, fname, ftype, inner_struct):
179 if type(ftype) is pytsdl.tsdl.Sequence:
180 if inner_struct:
181 raise RuntimeError('field "{}" is a dynamic array (not allowed here)'.format(fname))
182 else:
183 element = self._find_arrayseq_element(ftype)
184 self._validate_struct_field(fname, element, True)
185 elif type(ftype) is pytsdl.tsdl.Array:
186 # we need to check every element until we find a terminal one
187 element = self._find_arrayseq_element(ftype)
188 self._validate_struct_field(fname, element, True)
189 elif type(ftype) is pytsdl.tsdl.Variant:
190 raise RuntimeError('field "{}" contains a variant (unsupported)'.format(fname))
191 elif type(ftype) is pytsdl.tsdl.String:
192 if inner_struct:
193 raise RuntimeError('field "{}" contains a string (not allowed here)'.format(fname))
194 elif type(ftype) is pytsdl.tsdl.Struct:
195 self._validate_struct(ftype, True)
196 elif type(ftype) is pytsdl.tsdl.Integer:
197 if self._get_obj_size(ftype) > 64:
198 raise RuntimeError('integer field "{}" larger than 64-bit'.format(fname))
199 elif type(ftype) is pytsdl.tsdl.FloatingPoint:
200 if self._get_obj_size(ftype) > 64:
201 raise RuntimeError('floating point field "{}" larger than 64-bit'.format(fname))
202 elif type(ftype) is pytsdl.tsdl.Enum:
203 if self._get_obj_size(ftype) > 64:
204 raise RuntimeError('enum field "{}" larger than 64-bit'.format(fname))
205
206 # Validates an inner TSDL structure (constrained).
207 #
208 # struct: TSDL structure to validate
209 def _validate_struct(self, struct, inner_struct):
210 # just in case we call this with the wrong type
211 if type(struct) is not pytsdl.tsdl.Struct:
212 raise RuntimeError('expecting a struct')
213
214 # make sure inner structures are at least byte-aligned
215 if inner_struct:
216 if self._get_obj_alignment(struct) < 8:
217 raise RuntimeError('inner struct must be at least byte-aligned')
218
219 # check each field
220 for fname, ftype in struct.fields.items():
221 self._validate_struct_field(fname, ftype, inner_struct)
222
223 # Validates a context or fields structure.
224 #
225 # struct: context/fields TSDL structure
226 def _validate_context_fields(self, struct):
227 if type(struct) is not pytsdl.tsdl.Struct:
228 raise RuntimeError('expecting a struct')
229
230 self._validate_struct(struct, False)
231
232 # Validates a TSDL integer with optional constraints.
233 #
234 # integer: TSDL integer to validate
235 # size: expected size (None for any size)
236 # align: expected alignment (None for any alignment)
237 # signed: expected signedness (None for any signedness)
238 def _validate_integer(self, integer, size=None, align=None,
239 signed=None):
240 if type(integer) is not pytsdl.tsdl.Integer:
241 raise RuntimeError('expected integer')
242
243 if size is not None:
244 if integer.size != size:
245 raise RuntimeError('expected {}-bit integer'.format(size))
246
247 if align is not None:
248 if integer.align != align:
249 raise RuntimeError('expected integer with {}-bit alignment'.format(align))
250
251 if signed is not None:
252 if integer.signed != signed:
253 raise RuntimeError('expected {} integer'.format('signed' if signed else 'unsigned'))
254
255 # Validates a packet header.
256 #
257 # packet_header: packet header TSDL structure to validate
258 def _validate_tph(self, packet_header):
259 try:
260 self._validate_struct(packet_header, True)
261 except RuntimeError as e:
262 _perror('packet header: {}'.format(e))
263
264 # magic must be the first field
265 if 'magic' in packet_header.fields:
266 if list(packet_header.fields.keys())[0] != 'magic':
267 _perror('packet header: "magic" must be the first field')
268 else:
269 _perror('packet header: missing "magic" field')
270
271 # magic must be a 32-bit unsigned integer, 32-bit aligned
272 try:
273 self._validate_integer(packet_header['magic'], 32, 32, False)
274 except RuntimeError as e:
275 _perror('packet header: "magic": {}'.format(e))
276
277 # mandatory stream_id
278 if 'stream_id' not in packet_header.fields:
279 _perror('packet header: missing "stream_id" field')
280
281 # stream_id must be an unsigned integer
282 try:
283 self._validate_integer(packet_header['stream_id'], signed=False)
284 except RuntimeError as e:
285 _perror('packet header: "stream_id": {}'.format(e))
286
287 # only magic and stream_id allowed
288 if len(packet_header.fields) != 2:
289 _perror('packet header: only "magic" and "stream_id" fields are allowed')
290
291 # Converts a list of strings to a dotted representation. For
292 # example, ['trace', 'packet', 'header', 'magic'] is converted to
293 # 'trace.packet.header.magic'.
294 #
295 # name: list of strings to convert
296 def _dot_name_to_str(self, name):
297 return '.'.join(name)
298
299 # Compares two TSDL integers. Returns True if they are the same.
300 #
301 # int1: first TSDL integer
302 # int2: second TSDL integer
303 def _compare_integers(self, int1, int2):
304 if type(int1) is not pytsdl.tsdl.Integer:
305 return False
306
307 if type(int2) is not pytsdl.tsdl.Integer:
308 return False
309
310 size = int1.size == int2.size
311 align = int1.align == int2.align
312 cmap = int1.map == int2.map
313 base = int1.base == int2.base
314 encoding = int1.encoding == int2.encoding
315 signed = int1.signed == int2.signed
316 comps = (size, align, cmap, base, encoding, signed)
317
318 # True means 1 for sum()
319 return sum(comps) == len(comps)
320
321 # Validates a packet context.
322 #
323 # stream: TSDL stream containing the packet context to validate
324 def _validate_spc(self, stream):
325 packet_context = stream.packet_context
326 sid = stream.id
327
328 try:
329 self._validate_struct(packet_context, True)
330 except RuntimeError as e:
331 _perror('stream {}: packet context: {}'.format(sid, e))
332
333 fields = packet_context.fields
334
335 # if timestamp_begin exists, timestamp_end must exist
336 if 'timestamp_begin' in fields or 'timestamp_end' in fields:
337 if 'timestamp_begin' not in fields or 'timestamp_end' not in fields:
338 _perror('stream {}: packet context: "timestamp_begin" must exist if "timestamp_end" exists'.format(sid))
339 else:
340 # timestamp_begin and timestamp_end must have the same integer
341 # as the event header's timestamp field (should exist by now)
342 timestamp = stream.event_header['timestamp']
343
344 if not self._compare_integers(fields['timestamp_begin'], timestamp):
345 _perror('stream {}: packet context: "timestamp_begin": integer type different from event header\'s "timestamp" field'.format(sid))
346
347 if not self._compare_integers(fields['timestamp_end'], timestamp):
348 _perror('stream {}: packet context: "timestamp_end": integer type different from event header\'s "timestamp" field'.format(sid))
349
350 # content_size must exist and be an unsigned integer
351 if 'content_size' not in fields:
352 _perror('stream {}: packet context: missing "content_size" field'.format(sid))
353
354 try:
355 self._validate_integer(fields['content_size'], 32, 32, False)
356 except:
357 try:
358 self._validate_integer(fields['content_size'], 64, 64, False)
359 except:
360 _perror('stream {}: packet context: "content_size": expecting unsigned 32-bit/64-bit integer'.format(sid))
361
362 # packet_size must exist and be an unsigned integer
363 if 'packet_size' not in fields:
364 _perror('stream {}: packet context: missing "packet_size" field'.format(sid))
365
366 try:
367 self._validate_integer(fields['packet_size'], 32, 32, False)
368 except:
369 try:
370 self._validate_integer(fields['packet_size'], 64, 64, False)
371 except:
372 _perror('stream {}: packet context: "packet_size": expecting unsigned 32-bit/64-bit integer'.format(sid))
373
374 # if cpu_id exists, must be an unsigned integer
375 if 'cpu_id' in fields:
376 try:
377 self._validate_integer(fields['cpu_id'], signed=False)
378 except RuntimeError as e:
379 _perror('stream {}: packet context: "cpu_id": {}'.format(sid, e))
380
381 # Validates an event header.
382 #
383 # stream: TSDL stream containing the event header to validate
384 def _validate_seh(self, stream):
385 event_header = stream.event_header
386 sid = stream.id
387
388 try:
389 self._validate_struct(event_header, True)
390 except RuntimeError as e:
391 _perror('stream {}: event header: {}'.format(sid, e))
392
393 fields = event_header.fields
394
395 # id must exist and be an unsigned integer
396 if 'id' not in fields:
397 _perror('stream {}: event header: missing "id" field'.format(sid))
398
399 try:
400 self._validate_integer(fields['id'], signed=False)
401 except RuntimeError as e:
402 _perror('stream {}: "id": {}'.format(sid, format(e)))
403
404 # timestamp must exist, be an unsigned integer and be mapped to a valid clock
405 if 'timestamp' not in fields:
406 _perror('stream {}: event header: missing "timestamp" field'.format(sid))
407
408 try:
409 self._validate_integer(fields['timestamp'], signed=False)
410 except RuntimeError as e:
411 _perror('stream {}: event header: "timestamp": {}'.format(sid, format(e)))
412
413 if fields['timestamp'].map is None:
414 _perror('stream {}: event header: "timestamp" must be mapped to a valid clock'.format(sid))
415
416 # id must be the first field, followed by timestamp
417 if list(fields.keys())[0] != 'id':
418 _perror('stream {}: event header: "id" must be the first field'.format(sid))
419
420 if list(fields.keys())[1] != 'timestamp':
421 _perror('stream {}: event header: "timestamp" must be the second field'.format(sid))
422
423 # only id and timestamp and allowed in event header
424 if len(fields) != 2:
425 _perror('stream {}: event header: only "id" and "timestamp" fields are allowed'.format(sid))
426
427 # Validates a strean event context.
428 #
429 # stream: TSDL stream containing the stream event context
430 def _validate_sec(self, stream):
431 stream_event_context = stream.event_context
432 sid = stream.id
433
434 if stream_event_context is None:
435 return
436
437 try:
438 self._validate_context_fields(stream_event_context)
439 except RuntimeError as e:
440 _perror('stream {}: event context: {}'.format(sid, e))
441
442 # Validates an event context.
443 #
444 # stream: TSDL stream containing the TSDL event
445 # event: TSDL event containing the context to validate
446 def _validate_ec(self, stream, event):
447 event_context = event.context
448 sid = stream.id
449 eid = event.id
450
451 if event_context is None:
452 return
453
454 try:
455 self._validate_context_fields(event_context)
456 except RuntimeError as e:
457 _perror('stream {}: event {}: context: {}'.format(sid, eid, e))
458
459 # Validates an event fields.
460 #
461 # stream: TSDL stream containing the TSDL event
462 # event: TSDL event containing the fields to validate
463 def _validate_ef(self, stream, event):
464 event_fields = event.fields
465 sid = stream.id
466 eid = event.id
467
468 try:
469 self._validate_context_fields(event_fields)
470 except RuntimeError as e:
471 _perror('stream {}: event {}: fields: {}'.format(sid, eid, e))
472
473 # Validates a TSDL event.
474 #
475 # stream: TSDL stream containing the TSDL event
476 # event: TSDL event to validate
477 def _validate_event(self, stream, event):
478 # name must be a compatible C identifier
479 if not re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', event.name):
480 fmt = 'stream {}: event {}: malformed event name: "{}"'
481 _perror(fmt.format(stream.id, event.id, event.name))
482
483 self._validate_ec(stream, event)
484 self._validate_ef(stream, event)
485
486 # Validates a TSDL stream.
487 #
488 # stream: TSDL stream to validate
489 def _validate_stream(self, stream):
490 self._validate_seh(stream)
491 self._validate_spc(stream)
492 self._validate_sec(stream)
493
494 # event stuff
495 for event in stream.events:
496 self._validate_event(stream, event)
497
498 # Validates all TSDL scopes of the current TSDL document.
499 def _validate_all_scopes(self):
500 # packet header
501 self._validate_tph(self._doc.trace.packet_header)
502
503 # stream stuff
504 for stream in self._doc.streams.values():
505 self._validate_stream(stream)
506
507 # Validates the trace block.
508 def _validate_trace(self):
509 # make sure a native byte order is specified
510 if self._doc.trace.byte_order is None:
511 _perror('native byte order (trace.byte_order) is not specified')
512
513 # Validates the current TSDL document.
514 def _validate_metadata(self):
515 self._validate_trace()
516 self._validate_all_scopes()
517
518 # Returns an aligned number.
519 #
520 # 3, 4 -> 4
521 # 4, 4 -> 4
522 # 5, 4 -> 8
523 # 6, 4 -> 8
524 # 7, 4 -> 8
525 # 8, 4 -> 8
526 # 9, 4 -> 12
527 #
528 # at: number to align
529 # align: alignment (power of two)
530 def _get_alignment(self, at, align):
531 return (at + align - 1) & -align
532
533 # Converts a tree of offset variables:
534 #
535 # field
536 # a -> 0
537 # b -> 8
538 # other_struct
539 # field -> 16
540 # yeah -> 20
541 # c -> 32
542 # len -> 36
543 #
544 # to a flat dict:
545 #
546 # field_a -> 0
547 # field_b -> 8
548 # field_other_struct_field -> 16
549 # field_other_struct_yeah -> 20
550 # field_c -> 32
551 # len -> 36
552 #
553 # offvars_tree: tree of offset variables
554 # prefix: offset variable name prefix
555 # offvars: flattened offset variables
556 def _flatten_offvars_tree(self, offvars_tree, prefix=None,
557 offvars=None):
558 if offvars is None:
559 offvars = collections.OrderedDict()
560
561 for name, offset in offvars_tree.items():
562 if prefix is not None:
563 varname = '{}_{}'.format(prefix, name)
564 else:
565 varname = name
566
567 if isinstance(offset, dict):
568 self._flatten_offvars_tree(offset, varname, offvars)
569 else:
570 offvars[varname] = offset
571
572 return offvars
573
574 # Returns the size of a TSDL structure with _static size_ (must be
575 # validated first).
576 #
577 # struct: TSDL structure of which to get the size
578 # offvars_tree: optional offset variables tree (output)
579 # base_offset: base offsets for offset variables
580 def _get_struct_size(self, struct,
581 offvars_tree=None,
582 base_offset=0):
583 if offvars_tree is None:
584 offvars_tree = collections.OrderedDict()
585
586 offset = 0
587
588 for fname, ftype in struct.fields.items():
589 field_alignment = self._get_obj_alignment(ftype)
590 offset = self._get_alignment(offset, field_alignment)
591
592 if type(ftype) is pytsdl.tsdl.Struct:
593 offvars_tree[fname] = collections.OrderedDict()
594 sz = self._get_struct_size(ftype, offvars_tree[fname],
595 base_offset + offset)
596 else:
597 # only integers may act as sequence lengths
598 if type(ftype) is pytsdl.tsdl.Integer:
599 offvars_tree[fname] = base_offset + offset
600
601 sz = self._get_obj_size(ftype)
602
603 offset += sz
604
605 return offset
606
607 # Returns the size of a TSDL array.
608 #
609 # array: TSDL array of which to get the size
610 def _get_array_size(self, array):
611 element = array.element
612
613 # effective size of one element includes its alignment after its size
614 size = self._get_obj_size(element)
615 align = self._get_obj_alignment(element)
616
617 return self._get_alignment(size, align) * array.length
618
619 # Returns the size of a TSDL enumeration.
620 #
621 # enum: TSDL enumeration of which to get the size
622 def _get_enum_size(self, enum):
623 return self._get_obj_size(enum.integer)
624
625 # Returns the size of a TSDL floating point number.
626 #
627 # floating_point: TSDL floating point number of which to get the size
628 def _get_floating_point_size(self, floating_point):
629 return floating_point.exp_dig + floating_point.mant_dig
630
631 # Returns the size of a TSDL integer.
632 #
633 # integer: TSDL integer of which to get the size
634 def _get_integer_size(self, integer):
635 return integer.size
636
637 # Returns the size of a TSDL type.
638 #
639 # obj: TSDL type of which to get the size
640 def _get_obj_size(self, obj):
641 return self._obj_size_cb[type(obj)](obj)
642
643 # Returns the alignment of a TSDL structure.
644 #
645 # struct: TSDL structure of which to get the alignment
646 def _get_struct_alignment(self, struct):
647 if struct.align is not None:
648 return struct.align
649
650 cur_align = 1
651
652 for fname, ftype in struct.fields.items():
653 cur_align = max(self._get_obj_alignment(ftype), cur_align)
654
655 return cur_align
656
657 # Returns the alignment of a TSDL integer.
658 #
659 # integer: TSDL integer of which to get the alignment
660 def _get_integer_alignment(self, integer):
661 return integer.align
662
663 # Returns the alignment of a TSDL floating point number.
664 #
665 # floating_point: TSDL floating point number of which to get the
666 # alignment
667 def _get_floating_point_alignment(self, floating_point):
668 return floating_point.align
669
670 # Returns the alignment of a TSDL enumeration.
671 #
672 # enum: TSDL enumeration of which to get the alignment
673 def _get_enum_alignment(self, enum):
674 return self._get_obj_alignment(enum.integer)
675
676 # Returns the alignment of a TSDL string.
677 #
678 # string: TSDL string of which to get the alignment
679 def _get_string_alignment(self, string):
680 return 8
681
682 # Returns the alignment of a TSDL array.
683 #
684 # array: TSDL array of which to get the alignment
685 def _get_array_alignment(self, array):
686 return self._get_obj_alignment(array.element)
687
688 # Returns the alignment of a TSDL sequence.
689 #
690 # sequence: TSDL sequence of which to get the alignment
691 def _get_sequence_alignment(self, sequence):
692 return self._get_obj_alignment(sequence.element)
693
694 # Returns the alignment of a TSDL type.
695 #
696 # obj: TSDL type of which to get the alignment
697 def _get_obj_alignment(self, obj):
698 return self._obj_alignment_cb[type(obj)](obj)
699
700 # Converts a field name to a C parameter name.
701 #
702 # You should not use this function directly, but rather use one
703 # of the _*_fname_to_pname() variants depending on your scope.
704 #
705 # prefix: parameter name prefix
706 # fname: field name
707 def _fname_to_pname(self, prefix, fname):
708 return 'param_{}_{}'.format(prefix, fname)
709
710 # Converts an event fields field name to a C parameter name.
711 #
712 # fname: field name
713 def _ef_fname_to_pname(self, fname):
714 return self._fname_to_pname('ef', fname)
715
716 # Converts an event context field name to a C parameter name.
717 #
718 # fname: field name
719 def _ec_fname_to_pname(self, fname):
720 return self._fname_to_pname('ec', fname)
721
722 # Converts a stream event context field name to a C parameter name.
723 #
724 # fname: field name
725 def _sec_fname_to_pname(self, fname):
726 return self._fname_to_pname('sec', fname)
727
728 # Converts an event header field name to a C parameter name.
729 #
730 # fname: field name
731 def _eh_fname_to_pname(self, fname):
732 return self._fname_to_pname('eh', fname)
733
734 # Converts a stream packet context field name to a C parameter name.
735 #
736 # fname: field name
737 def _spc_fname_to_pname(self, fname):
738 return self._fname_to_pname('spc', fname)
739
740 # Converts a trace packet header field name to a C parameter name.
741 #
742 # fname: field name
743 def _tph_fname_to_pname(self, fname):
744 return self._fname_to_pname('tph', fname)
745
746 # Returns the equivalent C type of a TSDL integer.
747 #
748 # integer: TSDL integer of which to get the equivalent C type
749 def _get_integer_param_ctype(self, integer):
750 signed = 'u' if not integer.signed else ''
751
752 if integer.size <= 8:
753 sz = '8'
754 elif integer.size <= 16:
755 sz = '16'
756 elif integer.size <= 32:
757 sz = '32'
758 elif integer.size == 64:
759 sz = '64'
760
761 return '{}int{}_t'.format(signed, sz)
762
763 # Returns the equivalent C type of a TSDL enumeration.
764 #
765 # enum: TSDL enumeration of which to get the equivalent C type
766 def _get_enum_param_ctype(self, enum):
767 return self._get_obj_param_ctype(enum.integer)
768
769 # Returns the equivalent C type of a TSDL floating point number.
770 #
771 # fp: TSDL floating point number of which to get the equivalent C type
772 def _get_floating_point_param_ctype(self, fp):
773 if fp.exp_dig == 8 and fp.mant_dig == 24 and fp.align == 32:
774 return 'float'
775 elif fp.exp_dig == 11 and fp.mant_dig == 53 and fp.align == 64:
776 return 'double'
777 else:
778 return 'uint64_t'
779
780 # Returns the equivalent C type of a TSDL type.
781 #
782 # obj: TSDL type of which to get the equivalent C type
783 def _get_obj_param_ctype(self, obj):
784 return self._obj_param_ctype_cb[type(obj)](obj)
785
786 # Returns the check offset overflow macro call string for a given size.
787 #
788 # size: size to check
789 def _get_chk_offset_v(self, size):
790 fmt = '{}_CHK_OFFSET_V({}, {}, {});'
791 ret = fmt.format(self._prefix.upper(), self._CTX_AT,
792 self._CTX_PACKET_SIZE, size)
793
794 return ret
795
796 # Returns the check offset overflow macro call C line for a given size.
797 #
798 # size: size to check
799 def _get_chk_offset_v_cline(self, size):
800 return _CLine(self._get_chk_offset_v(size))
801
802 # Returns the offset alignment macro call string for a given alignment.
803 #
804 # size: new alignment
805 def _get_align_offset(self, align, at=None):
806 if at is None:
807 at = self._CTX_AT
808
809 fmt = '{}_ALIGN_OFFSET({}, {});'
810 ret = fmt.format(self._prefix.upper(), at, align)
811
812 return ret
813
814 # Returns the offset alignment macro call C line for a given alignment.
815 #
816 # size: new alignment
817 def _get_align_offset_cline(self, size):
818 return _CLine(self._get_align_offset(size))
819
820 # Converts a C source string with newlines to an array of C lines and
821 # returns it.
822 #
823 # s: C source string
824 def _str_to_clines(self, s):
825 lines = s.split('\n')
826
827 return [_CLine(line) for line in lines]
828
829 # Fills a given template with values and returns its C lines. The `prefix`
830 # and `ucprefix` template variable are automatically provided using the
831 # generator's context.
832 #
833 # tmpl: template
834 # kwargs: additional template variable values
835 def _template_to_clines(self, tmpl, **kwargs):
836 s = tmpl.format(prefix=self._prefix, ucprefix=self._prefix.upper(),
837 **kwargs)
838
839 return self._str_to_clines(s)
840
841 # Returns the C lines for writing a TSDL structure field.
842 #
843 # fname: field name
844 # src_name: C source pointer
845 # struct: TSDL structure
846 def _write_field_struct(self, fname, src_name, struct, scope_prefix=None):
847 size = self._get_struct_size(struct)
848 size_bytes = self._get_alignment(size, 8) // 8
849 dst = self._CTX_BUF_AT_ADDR
850
851 return [
852 # memcpy() is safe since barectf requires inner structures
853 # to be byte-aligned
854 self._get_chk_offset_v_cline(size),
855 _CLine('memcpy({}, {}, {});'.format(dst, src_name, size_bytes)),
856 _CLine('{} += {};'.format(self._CTX_AT, size)),
857 ]
858
859 # Returns the C lines for writing a TSDL integer field.
860 #
861 # fname: field name
862 # src_name: C source integer
863 # integer: TSDL integer
864 def _write_field_integer(self, fname, src_name, integer, scope_prefix=None):
865 bo = self._BO_SUFFIXES_MAP[integer.byte_order]
866 t = self._get_obj_param_ctype(integer)
867 length = self._get_obj_size(integer)
868
869 return self._template_to_clines(barectf.templates.WRITE_INTEGER,
870 sz=length, bo=bo, type=t,
871 src_name=src_name)
872
873 # Returns the C lines for writing a TSDL enumeration field.
874 #
875 # fname: field name
876 # src_name: C source integer
877 # enum: TSDL enumeration
878 def _write_field_enum(self, fname, src_name, enum, scope_prefix=None):
879 return self._write_field_obj(fname, src_name, enum.integer,
880 scope_prefix)
881
882 # Returns the C lines for writing a TSDL floating point number field.
883 #
884 # fname: field name
885 # src_name: C source pointer
886 # floating_point: TSDL floating point number
887 def _write_field_floating_point(self, fname, src_name, floating_point,
888 scope_prefix=None):
889 bo = self._BO_SUFFIXES_MAP[floating_point.byte_order]
890 t = self._get_obj_param_ctype(floating_point)
891 length = self._get_obj_size(floating_point)
892
893 if t == 'float':
894 t = 'uint32_t'
895 elif t == 'double':
896 t = 'uint64_t'
897
898 src_name_casted = '*(({}*) &{})'.format(t, src_name)
899
900 return self._template_to_clines(barectf.templates.WRITE_INTEGER,
901 sz=length, bo=bo, type=t,
902 src_name=src_name_casted)
903
904 # Returns the C lines for writing either a TSDL array field or a
905 # TSDL sequence field.
906 #
907 # fname: field name
908 # src_name: C source pointer
909 # arrayseq: TSDL array or sequence
910 # scope_prefix: preferred scope prefix
911 def _write_field_array_sequence(self, fname, src_name, arrayseq,
912 scope_prefix):
913 def length_index_varname(index):
914 return 'lens_{}_{}'.format(fname, index)
915
916 # first pass: find all lengths to multiply
917 mulops = []
918 done = False
919
920 while not done:
921 mulops.append(arrayseq.length)
922 element = arrayseq.element
923 tel = type(element)
924
925 if tel is pytsdl.tsdl.Array or tel is pytsdl.tsdl.Sequence:
926 # another array/sequence; continue
927 arrayseq = element
928 continue
929
930 # found the end
931 done = True
932
933 # align the size of the repeating element (effective repeating size)
934 el_size = self._get_obj_size(element)
935 el_align = self._get_obj_alignment(element)
936 el_size = self._get_alignment(el_size, el_align)
937
938 # this effective size is part of the operands to multiply
939 mulops.append(el_size)
940
941 # clines
942 clines = []
943
944 # fetch and save sequence lengths
945 emulops = []
946
947 for i in range(len(mulops)):
948 mulop = mulops[i]
949
950 if type(mulop) is list:
951 # offset variable to fetch
952 offvar = self._get_seq_length_src_name(mulop, scope_prefix)
953
954 if type(offvar) is int:
955 # environment constant
956 emulops.append(str(offvar))
957 continue
958
959 # save buffer position
960 line = 'ctx_at_bkup = {};'.format(self._CTX_AT)
961 clines.append(_CLine(line))
962
963 # go back to field offset
964 line = '{} = {};'.format(self._CTX_AT, offvar)
965 clines.append(_CLine(line))
966
967 # read value into specific variable
968 varname = length_index_varname(i)
969 emulops.append(varname)
970 varctype = 'uint32_t'
971 fmt = '{ctype} {cname} = *(({ctype}*) ({ctxbufataddr}));'
972 line = fmt.format(ctype=varctype, cname=varname,
973 ctxbufataddr=self._CTX_BUF_AT_ADDR)
974 clines.append(_CLine(line))
975
976 # restore buffer position
977 line = '{} = ctx_at_bkup;'.format(self._CTX_AT)
978 clines.append(_CLine(line))
979 else:
980 emulops.append(str(mulop))
981
982 # write product of sizes in bits
983 mul = ' * '.join(emulops)
984 sz_bits_varname = 'sz_bits_{}'.format(fname)
985 sz_bytes_varname = 'sz_bytes_{}'.format(fname)
986 line = 'uint32_t {} = {};'.format(sz_bits_varname, mul)
987 clines.append(_CLine(line))
988
989 # check overflow
990 clines.append(self._get_chk_offset_v_cline(sz_bits_varname))
991
992 # write product of sizes in bytes
993 line = 'uint32_t {} = {};'.format(sz_bytes_varname, sz_bits_varname)
994 clines.append(_CLine(line))
995 line = self._get_align_offset(8, at=sz_bytes_varname)
996 clines.append(_CLine(line))
997 line = '{} >>= 3;'.format(sz_bytes_varname)
998 clines.append(_CLine(line))
999
1000 # memcpy()
1001 dst = self._CTX_BUF_AT_ADDR
1002 line = 'memcpy({}, {}, {});'.format(dst, src_name, sz_bytes_varname)
1003 clines.append(_CLine(line))
1004 line = '{} += {};'.format(self._CTX_AT, sz_bits_varname)
1005 clines.append(_CLine(line))
1006
1007 return clines
1008
1009 # Returns the C lines for writing a TSDL array field.
1010 #
1011 # fname: field name
1012 # src_name: C source pointer
1013 # array: TSDL array
1014 # scope_prefix: preferred scope prefix
1015 def _write_field_array(self, fname, src_name, array, scope_prefix=None):
1016 return self._write_field_array_sequence(fname, src_name, array,
1017 scope_prefix)
1018
1019 # Returns the C lines for writing a TSDL sequence field.
1020 #
1021 # fname: field name
1022 # src_name: C source pointer
1023 # sequence: TSDL sequence
1024 # scope_prefix: preferred scope prefix
1025 def _write_field_sequence(self, fname, src_name, sequence, scope_prefix):
1026 return self._write_field_array_sequence(fname, src_name, sequence,
1027 scope_prefix)
1028
1029 # Returns a trace packet header C source name out of a sequence length
1030 # expression.
1031 #
1032 # length: sequence length expression
1033 def _get_tph_src_name(self, length):
1034 offvar = self._get_offvar_name_from_expr(length[3:], 'tph')
1035
1036 return 'ctx->{}'.format(offvar)
1037
1038 # Returns an environment C source name out of a sequence length
1039 # expression.
1040 #
1041 # length: sequence length expression
1042 def _get_env_src_name(self, length):
1043 if len(length) != 2:
1044 _perror('invalid sequence length: "{}"'.format(self._dot_name_to_str(length)))
1045
1046 fname = length[1]
1047
1048 if fname not in self._doc.env:
1049 _perror('cannot find field env.{}'.format(fname))
1050
1051 env_length = self._doc.env[fname]
1052
1053 if type(env_length) is not int:
1054 _perror('env.{} is not a constant integer'.format(fname))
1055
1056 return self._doc.env[fname]
1057
1058 # Returns a stream packet context C source name out of a sequence length
1059 # expression.
1060 #
1061 # length: sequence length expression
1062 def _get_spc_src_name(self, length):
1063 offvar = self._get_offvar_name_from_expr(length[3:], 'spc')
1064
1065 return 'ctx->{}'.format(offvar)
1066
1067 # Returns a stream event header C source name out of a sequence length
1068 # expression.
1069 #
1070 # length: sequence length expression
1071 def _get_seh_src_name(self, length):
1072 return self._get_offvar_name_from_expr(length[3:], 'seh')
1073
1074 # Returns a stream event context C source name out of a sequence length
1075 # expression.
1076 #
1077 # length: sequence length expression
1078 def _get_sec_src_name(self, length):
1079 return self._get_offvar_name_from_expr(length[3:], 'sec')
1080
1081 # Returns an event context C source name out of a sequence length
1082 # expression.
1083 #
1084 # length: sequence length expression
1085 def _get_ec_src_name(self, length):
1086 return self._get_offvar_name_from_expr(length[2:], 'ec')
1087
1088 # Returns an event fields C source name out of a sequence length
1089 # expression.
1090 #
1091 # length: sequence length expression
1092 def _get_ef_src_name(self, length):
1093 return self._get_offvar_name_from_expr(length[2:], 'ef')
1094
1095 # Returns a C source name out of a sequence length expression.
1096 #
1097 # length: sequence length expression
1098 # scope_prefix: preferred scope prefix
1099 def _get_seq_length_src_name(self, length, scope_prefix=None):
1100 length_dot = self._dot_name_to_str(length)
1101
1102 for prefix, get_src_name in self._get_src_name_funcs.items():
1103 if length_dot.startswith(prefix):
1104 return get_src_name(length)
1105
1106 return self._get_offvar_name_from_expr(length, scope_prefix)
1107
1108 # Returns the C lines for writing a TSDL string field.
1109 #
1110 # fname: field name
1111 # src_name: C source pointer
1112 # string: TSDL string
1113 def _write_field_string(self, fname, src_name, string, scope_prefix=None):
1114 clines = []
1115
1116 # get string length
1117 sz_bytes_varname = 'slen_bytes_{}'.format(fname)
1118 line = 'size_t {} = strlen({}) + 1;'.format(sz_bytes_varname, src_name)
1119 clines.append(_CLine(line))
1120
1121 # check offset overflow
1122 sz_bits_varname = 'slen_bits_{}'.format(fname)
1123 line = 'size_t {} = ({} << 3);'.format(sz_bits_varname,
1124 sz_bytes_varname)
1125 clines.append(_CLine(line))
1126 cline = self._get_chk_offset_v_cline(sz_bits_varname)
1127 clines.append(cline)
1128
1129 # memcpy()
1130 dst = self._CTX_BUF_AT_ADDR
1131 line = 'memcpy({}, {}, {});'.format(dst, src_name, sz_bytes_varname)
1132 clines.append(_CLine(line))
1133
1134 # update bit position
1135 line = '{} += {};'.format(self._CTX_AT, sz_bits_varname)
1136 clines.append(_CLine(line))
1137
1138 return clines
1139
1140 # Returns the C lines for writing a TSDL type field.
1141 #
1142 # fname: field name
1143 # src_name: C source pointer
1144 # ftype: TSDL type
1145 # scope_prefix: preferred scope prefix
1146 def _write_field_obj(self, fname, src_name, ftype, scope_prefix):
1147 return self._write_field_obj_cb[type(ftype)](fname, src_name, ftype,
1148 scope_prefix)
1149
1150 # Returns an offset variable name out of an offset name.
1151 #
1152 # name: offset name
1153 # prefix: offset variable name prefix
1154 def _get_offvar_name(self, name, prefix=None):
1155 parts = ['off']
1156
1157 if prefix is not None:
1158 parts.append(prefix)
1159
1160 parts.append(name)
1161
1162 return '_'.join(parts)
1163
1164 # Returns an offset variable name out of an expression (array of
1165 # strings).
1166 #
1167 # expr: array of strings
1168 # prefix: offset variable name prefix
1169 def _get_offvar_name_from_expr(self, expr, prefix=None):
1170 return self._get_offvar_name('_'.join(expr), prefix)
1171
1172 # Returns the C lines for writing a TSDL field.
1173 #
1174 # fname: field name
1175 # ftype: TSDL field type
1176 # scope_name: scope name
1177 # scope_prefix: preferred scope prefix
1178 # param_name_cb: callback to get the C parameter name out of the
1179 # field name
1180 def _field_to_clines(self, fname, ftype, scope_name, scope_prefix,
1181 param_name_cb):
1182 clines = []
1183 pname = param_name_cb(fname)
1184 align = self._get_obj_alignment(ftype)
1185
1186 # group comment
1187 fmt = '/* write {}.{} ({}) */'
1188 line = fmt.format(scope_name, fname,
1189 self._TSDL_TYPE_NAMES_MAP[type(ftype)])
1190 clines.append(_CLine(line))
1191
1192 # align bit index before writing to the buffer
1193 cline = self._get_align_offset_cline(align)
1194 clines.append(cline)
1195
1196 # write offset variables
1197 if type(ftype) is pytsdl.tsdl.Struct:
1198 offvars_tree = collections.OrderedDict()
1199 self._get_struct_size(ftype, offvars_tree)
1200 offvars = self._flatten_offvars_tree(offvars_tree)
1201
1202 # as many offset as there are child fields because a future
1203 # sequence could refer to any of those fields
1204 for lname, offset in offvars.items():
1205 offvar = self._get_offvar_name('_'.join([fname, lname]),
1206 scope_prefix)
1207 fmt = 'uint32_t {} = (uint32_t) {} + {};'
1208 line = fmt.format(offvar, self._CTX_AT, offset);
1209 clines.append(_CLine(line))
1210 elif type(ftype) is pytsdl.tsdl.Integer:
1211 # offset of this simple field is the current bit index
1212 offvar = self._get_offvar_name(fname, scope_prefix)
1213 line = 'uint32_t {} = (uint32_t) {};'.format(offvar, self._CTX_AT)
1214 clines.append(_CLine(line))
1215
1216 clines += self._write_field_obj(fname, pname, ftype, scope_prefix)
1217
1218 return clines
1219
1220 # Joins C line groups and returns C lines.
1221 #
1222 # cline_groups: C line groups to join
1223 def _join_cline_groups(self, cline_groups):
1224 if not cline_groups:
1225 return cline_groups
1226
1227 output_clines = cline_groups[0]
1228
1229 for clines in cline_groups[1:]:
1230 output_clines.append('')
1231 output_clines += clines
1232
1233 return output_clines
1234
1235 # Returns the C lines for writing a complete TSDL structure (top level
1236 # scope).
1237 #
1238 # struct: TSDL structure
1239 # scope_name: scope name
1240 # scope_prefix: preferred scope prefix
1241 # param_name_cb: callback to get the C parameter name out of the
1242 # field name
1243 def _struct_to_clines(self, struct, scope_name, scope_prefix,
1244 param_name_cb):
1245 cline_groups = []
1246
1247 for fname, ftype in struct.fields.items():
1248 clines = self._field_to_clines(fname, ftype, scope_name,
1249 scope_prefix, param_name_cb)
1250 cline_groups.append(clines)
1251
1252 return self._join_cline_groups(cline_groups)
1253
1254 # Returns the offset variables of a TSDL structure.
1255 #
1256 # struct: TSDL structure
1257 def _get_struct_size_offvars(self, struct):
1258 offvars_tree = collections.OrderedDict()
1259 size = self._get_struct_size(struct, offvars_tree)
1260 offvars = self._flatten_offvars_tree(offvars_tree)
1261
1262 return size, offvars
1263
1264 # Returns the size and offset variables of the current trace packet header.
1265 def _get_tph_size_offvars(self):
1266 return self._get_struct_size_offvars(self._doc.trace.packet_header)
1267
1268 # Returns the size and offset variables of the a stream packet context.
1269 #
1270 # stream: TSDL stream
1271 def _get_spc_size_offvars(self, stream):
1272 return self._get_struct_size_offvars(stream.packet_context)
1273
1274 # Returns the C lines for the barectf context C structure entries for
1275 # offsets.
1276 #
1277 # prefix: offset variable names prefix
1278 # offvars: offset variables
1279 def _offvars_to_ctx_clines(self, prefix, offvars):
1280 clines = []
1281
1282 for name in offvars.keys():
1283 offvar = self._get_offvar_name(name, prefix)
1284 clines.append(_CLine('uint32_t {};'.format(offvar)))
1285
1286 return clines
1287
1288 # Generates a barectf context C structure.
1289 #
1290 # stream: TSDL stream
1291 # hide_sid: True to hide the stream ID
1292 def _gen_barectf_ctx_struct(self, stream, hide_sid=False):
1293 # get offset variables for both the packet header and packet context
1294 tph_size, tph_offvars = self._get_tph_size_offvars()
1295 spc_size, spc_offvars = self._get_spc_size_offvars(stream)
1296 clines = self._offvars_to_ctx_clines('tph', tph_offvars)
1297 clines += self._offvars_to_ctx_clines('spc', spc_offvars)
1298
1299 # indent C
1300 clines_indented = []
1301 for cline in clines:
1302 clines_indented.append(_CLine('\t' + cline))
1303
1304 # clock callback
1305 clock_cb = '\t/* (no clock callback) */'
1306
1307 if not self._manual_clock:
1308 ctype = self._get_clock_ctype(stream)
1309 fmt = '\t{} (*clock_cb)(void*);\n\tvoid* clock_cb_data;'
1310 clock_cb = fmt.format(ctype)
1311
1312 # fill template
1313 sid = ''
1314
1315 if not hide_sid:
1316 sid = stream.id
1317
1318 t = barectf.templates.BARECTF_CTX
1319 struct = t.format(prefix=self._prefix, sid=sid,
1320 ctx_fields='\n'.join(clines_indented),
1321 clock_cb=clock_cb)
1322
1323 return struct
1324
1325 # Generates all barectf context C structures.
1326 def _gen_barectf_contexts_struct(self):
1327 hide_sid = False
1328
1329 if len(self._doc.streams) == 1:
1330 hide_sid = True
1331
1332 structs = []
1333
1334 for stream in self._doc.streams.values():
1335 struct = self._gen_barectf_ctx_struct(stream, hide_sid)
1336 structs.append(struct)
1337
1338 return '\n\n'.join(structs)
1339
1340 # Returns the C type of the clock used by the event header of a
1341 # TSDL stream.
1342 #
1343 # stream: TSDL stream containing the event header to inspect
1344 def _get_clock_ctype(self, stream):
1345 return self._get_obj_param_ctype(stream.event_header['timestamp'])
1346
1347 # Generates the manual clock value C parameter for a given stream.
1348 #
1349 # stream: TSDL stream
1350 def _gen_manual_clock_param(self, stream):
1351 return '{} param_clock'.format(self._get_clock_ctype(stream))
1352
1353 # Generates the body of a barectf_open() function.
1354 #
1355 # stream: TSDL stream
1356 def _gen_barectf_func_open_body(self, stream):
1357 clines = []
1358
1359 # keep clock value (for timestamp_begin)
1360 if self._stream_has_timestamp_begin_end(stream):
1361 # get clock value ASAP
1362 clk_type = self._get_clock_ctype(stream)
1363 clk = self._gen_get_clock_value()
1364 line = '{} clk_value = {};'.format(clk_type, clk)
1365 clines.append(_CLine(line))
1366 clines.append(_CLine(''))
1367
1368 # reset bit position to write the packet context (after packet header)
1369 spc_offset = self._get_stream_packet_context_offset(stream)
1370 fmt = '{} = {};'
1371 line = fmt.format(self._CTX_AT, spc_offset)
1372 clines.append(_CLine(line))
1373
1374 # bit position at beginning of event (to reset in case we run
1375 # out of space)
1376 line = 'uint32_t ctx_at_begin = {};'.format(self._CTX_AT)
1377 clines.append(_CLine(line))
1378 clines.append(_CLine(''))
1379
1380 # packet context fields
1381 fcline_groups = []
1382 scope_name = 'stream.packet.context'
1383 scope_prefix = 'spc'
1384
1385 for fname, ftype in stream.packet_context.fields.items():
1386 # packet size
1387 if fname == 'packet_size':
1388 fclines = self._field_to_clines(fname, ftype, scope_name,
1389 scope_prefix,
1390 lambda x: 'ctx->packet_size')
1391 fcline_groups.append(fclines)
1392
1393 # content size (skip)
1394 elif fname == 'content_size':
1395 fclines = self._field_to_clines(fname, ftype, scope_name,
1396 scope_prefix, lambda x: '0')
1397 fcline_groups.append(fclines)
1398
1399 # timestamp_begin
1400 elif fname == 'timestamp_begin':
1401 fclines = self._field_to_clines(fname, ftype, scope_name,
1402 scope_prefix,
1403 lambda x: 'clk_value')
1404 fcline_groups.append(fclines)
1405
1406 # timestamp_end (skip)
1407 elif fname == 'timestamp_end':
1408 fclines = self._field_to_clines(fname, ftype, scope_name,
1409 scope_prefix, lambda x: '0')
1410 fcline_groups.append(fclines)
1411
1412 # anything else
1413 else:
1414 fclines = self._field_to_clines(fname, ftype, scope_name,
1415 scope_prefix,
1416 self._spc_fname_to_pname)
1417 fcline_groups.append(fclines)
1418
1419 # return 0
1420 fcline_groups.append([_CLine('return 0;')])
1421
1422 clines += self._join_cline_groups(fcline_groups)
1423
1424 # get source
1425 cblock = _CBlock(clines)
1426 src = self._cblock_to_source(cblock)
1427
1428 return src
1429
1430 _SPC_KNOWN_FIELDS = [
1431 'content_size',
1432 'packet_size',
1433 'timestamp_begin',
1434 'timestamp_end',
1435 ]
1436
1437 # Generates a barectf_open() function.
1438 #
1439 # stream: TSDL stream
1440 # gen_body: also generate function body
1441 # hide_sid: True to hide the stream ID
1442 def _gen_barectf_func_open(self, stream, gen_body, hide_sid=False):
1443 params = []
1444
1445 # manual clock
1446 if self._manual_clock:
1447 clock_param = self._gen_manual_clock_param(stream)
1448 params.append(clock_param)
1449
1450 # packet context
1451 for fname, ftype in stream.packet_context.fields.items():
1452 if fname in self._SPC_KNOWN_FIELDS:
1453 continue
1454
1455 ptype = self._get_obj_param_ctype(ftype)
1456 pname = self._spc_fname_to_pname(fname)
1457 param = '{} {}'.format(ptype, pname)
1458 params.append(param)
1459
1460 params_str = ''
1461
1462 if params:
1463 params_str = ',\n\t'.join([''] + params)
1464
1465 # fill template
1466 sid = ''
1467
1468 if not hide_sid:
1469 sid = stream.id
1470
1471 t = barectf.templates.FUNC_OPEN
1472 func = t.format(si=self._si_str, prefix=self._prefix, sid=sid,
1473 params=params_str)
1474
1475 if gen_body:
1476 func += '\n{\n'
1477 func += self._gen_barectf_func_open_body(stream)
1478 func += '\n}'
1479 else:
1480 func += ';'
1481
1482 return func
1483
1484 # Generates the body of a barectf_init() function.
1485 #
1486 # stream: TSDL stream
1487 def _gen_barectf_func_init_body(self, stream):
1488 clines = []
1489
1490 line = 'uint32_t ctx_at_bkup;'
1491 clines.append(_CLine(line))
1492
1493 # bit position at beginning of event (to reset in case we run
1494 # out of space)
1495 line = 'uint32_t ctx_at_begin = {};'.format(self._CTX_AT)
1496 clines.append(_CLine(line))
1497 clines.append(_CLine(''))
1498
1499 # set context parameters
1500 clines.append(_CLine("/* barectf context parameters */"))
1501 clines.append(_CLine('ctx->buf = buf;'))
1502 clines.append(_CLine('ctx->packet_size = buf_size * 8;'))
1503 clines.append(_CLine('{} = 0;'.format(self._CTX_AT)))
1504
1505 if not self._manual_clock:
1506 clines.append(_CLine('ctx->clock_cb = clock_cb;'))
1507 clines.append(_CLine('ctx->clock_cb_data = clock_cb_data;'))
1508
1509 # set context offsets
1510 clines.append(_CLine(''))
1511 clines.append(_CLine("/* barectf context offsets */"))
1512 ph_size, ph_offvars = self._get_tph_size_offvars()
1513 pc_size, pc_offvars = self._get_spc_size_offvars(stream)
1514 pc_alignment = self._get_obj_alignment(stream.packet_context)
1515 pc_offset = self._get_alignment(ph_size, pc_alignment)
1516
1517 for offvar, offset in ph_offvars.items():
1518 offvar_field = self._get_offvar_name(offvar, 'tph')
1519 line = 'ctx->{} = {};'.format(offvar_field, offset)
1520 clines.append(_CLine(line))
1521
1522 for offvar, offset in pc_offvars.items():
1523 offvar_field = self._get_offvar_name(offvar, 'spc')
1524 line = 'ctx->{} = {};'.format(offvar_field, pc_offset + offset)
1525 clines.append(_CLine(line))
1526
1527 clines.append(_CLine(''))
1528
1529 # packet header fields
1530 fcline_groups = []
1531 scope_name = 'trace.packet.header'
1532 scope_prefix = 'tph'
1533
1534 for fname, ftype in self._doc.trace.packet_header.fields.items():
1535 # magic number
1536 if fname == 'magic':
1537 fclines = self._field_to_clines(fname, ftype, scope_name,
1538 scope_prefix,
1539 lambda x: '0xc1fc1fc1UL')
1540 fcline_groups.append(fclines)
1541
1542 # stream ID
1543 elif fname == 'stream_id':
1544 fclines = self._field_to_clines(fname, ftype, scope_name,
1545 scope_prefix,
1546 lambda x: str(stream.id))
1547 fcline_groups.append(fclines)
1548
1549 # return 0
1550 fcline_groups.append([_CLine('return 0;')])
1551
1552 clines += self._join_cline_groups(fcline_groups)
1553
1554 # get source
1555 cblock = _CBlock(clines)
1556 src = self._cblock_to_source(cblock)
1557
1558 return src
1559
1560 # Generates a barectf_init() function.
1561 #
1562 # stream: TSDL stream
1563 # gen_body: also generate function body
1564 # hide_sid: True to hide the stream ID
1565 def _gen_barectf_func_init(self, stream, gen_body, hide_sid=False):
1566 # fill template
1567 sid = ''
1568
1569 if not hide_sid:
1570 sid = stream.id
1571
1572 params = ''
1573
1574 if not self._manual_clock:
1575 ts_ftype = stream.event_header['timestamp']
1576 ts_ptype = self._get_obj_param_ctype(ts_ftype)
1577 fmt = ',\n\t{} (*clock_cb)(void*),\n\tvoid* clock_cb_data'
1578 params = fmt.format(ts_ptype)
1579
1580 t = barectf.templates.FUNC_INIT
1581 func = t.format(si=self._si_str, prefix=self._prefix, sid=sid,
1582 params=params)
1583
1584 if gen_body:
1585 func += '\n{\n'
1586 func += self._gen_barectf_func_init_body(stream)
1587 func += '\n}'
1588 else:
1589 func += ';'
1590
1591 return func
1592
1593 # Generates the C expression to get the clock value depending on
1594 # whether we're in manual clock mode or not.
1595 def _gen_get_clock_value(self):
1596 if self._manual_clock:
1597 return 'param_clock'
1598 else:
1599 return self._CTX_CALL_CLOCK_CB
1600
1601 # Returns True if the given TSDL stream has timestamp_begin and
1602 # timestamp_end fields.
1603 #
1604 # stream: TSDL stream to check
1605 def _stream_has_timestamp_begin_end(self, stream):
1606 return self._has_timestamp_begin_end[stream.id]
1607
1608 # Returns the packet context offset (from the beginning of the
1609 # packet) of a given TSDL stream
1610 #
1611 # stream: TSDL stream
1612 def _get_stream_packet_context_offset(self, stream):
1613 return self._packet_context_offsets[stream.id]
1614
1615 # Generates the C lines to write a barectf context field, saving
1616 # and restoring the current bit position accordingly.
1617 #
1618 # src_name: C source name
1619 # prefix: offset variable prefix
1620 # name: offset variable name
1621 # integer: TSDL integer to write
1622 def _gen_write_ctx_field_integer(self, src_name, prefix, name, integer):
1623 clines = []
1624
1625 # save buffer position
1626 line = 'ctx_at_bkup = {};'.format(self._CTX_AT)
1627 clines.append(_CLine(line))
1628
1629 # go back to field offset
1630 offvar = self._get_offvar_name(name, prefix)
1631 line = '{} = ctx->{};'.format(self._CTX_AT, offvar)
1632 clines.append(_CLine(line))
1633
1634 # write value
1635 clines += self._write_field_integer(None, src_name, integer)
1636
1637 # restore buffer position
1638 line = '{} = ctx_at_bkup;'.format(self._CTX_AT)
1639 clines.append(_CLine(line))
1640
1641 return clines
1642
1643 # Generates the body of a barectf_close() function.
1644 #
1645 # stream: TSDL stream
1646 def _gen_barectf_func_close_body(self, stream):
1647 clines = []
1648
1649 line = 'uint32_t ctx_at_bkup;'
1650 clines.append(_CLine(line))
1651
1652 # bit position at beginning of event (to reset in case we run
1653 # out of space)
1654 line = 'uint32_t ctx_at_begin = {};'.format(self._CTX_AT)
1655 clines.append(_CLine(line))
1656
1657 # update timestamp end if present
1658 if self._stream_has_timestamp_begin_end(stream):
1659 clines.append(_CLine(''))
1660 clines.append(_CLine("/* update packet context's timestamp_end */"))
1661
1662 # get clock value ASAP
1663 clk_type = self._get_clock_ctype(stream)
1664 clk = self._gen_get_clock_value()
1665 line = '{} clk_value = {};'.format(clk_type, clk)
1666 clines.append(_CLine(line))
1667
1668 # write timestamp_end
1669 timestamp_end_integer = stream.packet_context['timestamp_end']
1670 clines += self._gen_write_ctx_field_integer('clk_value', 'spc',
1671 'timestamp_end',
1672 timestamp_end_integer)
1673
1674 # update content_size
1675 clines.append(_CLine(''))
1676 clines.append(_CLine("/* update packet context's content_size */"))
1677 content_size_integer = stream.packet_context['content_size']
1678 clines += self._gen_write_ctx_field_integer('ctx_at_bkup', 'spc',
1679 'content_size',
1680 content_size_integer)
1681
1682 # return 0
1683 clines.append(_CLine('\n'))
1684 clines.append(_CLine('return 0;'))
1685
1686 # get source
1687 cblock = _CBlock(clines)
1688 src = self._cblock_to_source(cblock)
1689
1690 return src
1691
1692 # Generates a barectf_close() function.
1693 #
1694 # stream: TSDL stream
1695 # gen_body: also generate function body
1696 # hide_sid: True to hide the stream ID
1697 def _gen_barectf_func_close(self, stream, gen_body, hide_sid=False):
1698 # fill template
1699 sid = ''
1700
1701 if not hide_sid:
1702 sid = stream.id
1703
1704 params = ''
1705
1706 if self._manual_clock:
1707 clock_param = self._gen_manual_clock_param(stream)
1708 params = ',\n\t{}'.format(clock_param)
1709
1710 t = barectf.templates.FUNC_CLOSE
1711 func = t.format(si=self._si_str, prefix=self._prefix, sid=sid,
1712 params=params)
1713
1714 if gen_body:
1715 func += '\n{\n'
1716 func += self._gen_barectf_func_close_body(stream)
1717 func += '\n}'
1718 else:
1719 func += ';'
1720
1721 return func
1722
1723 # Generates all barectf_init() function.
1724 #
1725 # gen_body: also generate function bodies
1726 def _gen_barectf_funcs_init(self, gen_body):
1727 hide_sid = False
1728
1729 if len(self._doc.streams) == 1:
1730 hide_sid = True
1731
1732 funcs = []
1733
1734 for stream in self._doc.streams.values():
1735 funcs.append(self._gen_barectf_func_init(stream, gen_body,
1736 hide_sid))
1737
1738 return funcs
1739
1740 # Generates all barectf_open() function.
1741 #
1742 # gen_body: also generate function bodies
1743 def _gen_barectf_funcs_open(self, gen_body):
1744 hide_sid = False
1745
1746 if len(self._doc.streams) == 1:
1747 hide_sid = True
1748
1749 funcs = []
1750
1751 for stream in self._doc.streams.values():
1752 funcs.append(self._gen_barectf_func_open(stream, gen_body,
1753 hide_sid))
1754
1755 return funcs
1756
1757 # Generates the body of a barectf_trace() function.
1758 #
1759 # stream: TSDL stream of TSDL event to trace
1760 # event: TSDL event to trace
1761 def _gen_barectf_func_trace_event_body(self, stream, event):
1762 clines = []
1763
1764 # get clock value ASAP
1765 clk_type = self._get_clock_ctype(stream)
1766 clk = self._gen_get_clock_value()
1767 line = '{} clk_value = {};'.format(clk_type, clk)
1768 clines.append(_CLine(line))
1769 clines.append(_CLine(''))
1770
1771 # bit position backup (could be used)
1772 clines.append(_CLine('uint32_t ctx_at_bkup;'))
1773
1774 # bit position at beginning of event (to reset in case we run
1775 # out of space)
1776 line = 'uint32_t ctx_at_begin = {};'.format(self._CTX_AT)
1777 clines.append(_CLine(line))
1778 clines.append(_CLine(''))
1779
1780 # event header
1781 fcline_groups = []
1782 scope_name = 'event.header'
1783 scope_prefix = 'eh'
1784
1785 for fname, ftype in stream.event_header.fields.items():
1786 # id
1787 if fname == 'id':
1788 fclines = self._field_to_clines(fname, ftype, scope_name,
1789 scope_prefix,
1790 lambda x: str(event.id))
1791 fcline_groups.append(fclines)
1792
1793 # timestamp
1794 elif fname == 'timestamp':
1795 fclines = self._field_to_clines(fname, ftype, scope_name,
1796 scope_prefix,
1797 lambda x: 'clk_value')
1798 fcline_groups.append(fclines)
1799
1800 # stream event context
1801 if stream.event_context is not None:
1802 fclines = self._struct_to_clines(stream.event_context,
1803 'stream.event.context', 'sec',
1804 self._sec_fname_to_pname)
1805 fcline_groups.append(fclines)
1806
1807 # event context
1808 if event.context is not None:
1809 fclines = self._struct_to_clines(event.context,
1810 'event.context', 'ec',
1811 self._ec_fname_to_pname)
1812 fcline_groups.append(fclines)
1813
1814 # event fields
1815 if event.fields is not None:
1816 fclines = self._struct_to_clines(event.fields,
1817 'event.fields', 'ef',
1818 self._ef_fname_to_pname)
1819 fcline_groups.append(fclines)
1820
1821 # return 0
1822 fcline_groups.append([_CLine('return 0;')])
1823
1824 clines += self._join_cline_groups(fcline_groups)
1825
1826 # get source
1827 cblock = _CBlock(clines)
1828 src = self._cblock_to_source(cblock)
1829
1830 return src
1831
1832 # Generates a barectf_trace() function.
1833 #
1834 # stream: TSDL stream containing the TSDL event to trace
1835 # event: TSDL event to trace
1836 # gen_body: also generate function body
1837 # hide_sid: True to hide the stream ID
1838 def _gen_barectf_func_trace_event(self, stream, event, gen_body, hide_sid):
1839 params = []
1840
1841 # manual clock
1842 if self._manual_clock:
1843 clock_param = self._gen_manual_clock_param(stream)
1844 params.append(clock_param)
1845
1846 # stream event context params
1847 if stream.event_context is not None:
1848 for fname, ftype in stream.event_context.fields.items():
1849 ptype = self._get_obj_param_ctype(ftype)
1850 pname = self._sec_fname_to_pname(fname)
1851 param = '{} {}'.format(ptype, pname)
1852 params.append(param)
1853
1854 # event context params
1855 if event.context is not None:
1856 for fname, ftype in event.context.fields.items():
1857 ptype = self._get_obj_param_ctype(ftype)
1858 pname = self._ec_fname_to_pname(fname)
1859 param = '{} {}'.format(ptype, pname)
1860 params.append(param)
1861
1862 # event fields params
1863 if event.fields is not None:
1864 for fname, ftype in event.fields.fields.items():
1865 ptype = self._get_obj_param_ctype(ftype)
1866 pname = self._ef_fname_to_pname(fname)
1867 param = '{} {}'.format(ptype, pname)
1868 params.append(param)
1869
1870 params_str = ''
1871
1872 if params:
1873 params_str = ',\n\t'.join([''] + params)
1874
1875 # fill template
1876 sid = ''
1877
1878 if not hide_sid:
1879 sid = stream.id
1880
1881 t = barectf.templates.FUNC_TRACE
1882 func = t.format(si=self._si_str, prefix=self._prefix, sid=sid,
1883 evname=event.name, params=params_str)
1884
1885 if gen_body:
1886 func += '\n{\n'
1887 func += self._gen_barectf_func_trace_event_body(stream, event)
1888 func += '\n}'
1889 else:
1890 func += ';'
1891
1892 return func
1893
1894 # Generates all barectf_trace() functions of a given TSDL stream.
1895 #
1896 # stream: TSDL stream containing the TSDL events to trace
1897 # gen_body: also generate function body
1898 # hide_sid: True to hide the stream ID
1899 def _gen_barectf_funcs_trace_stream(self, stream, gen_body, hide_sid):
1900 funcs = []
1901
1902 for event in stream.events:
1903 funcs.append(self._gen_barectf_func_trace_event(stream, event,
1904 gen_body, hide_sid))
1905
1906 return funcs
1907
1908 # Generates all barectf_trace() function.
1909 #
1910 # gen_body: also generate function bodies
1911 def _gen_barectf_funcs_trace(self, gen_body):
1912 hide_sid = False
1913
1914 if len(self._doc.streams) == 1:
1915 hide_sid = True
1916
1917 funcs = []
1918
1919 for stream in self._doc.streams.values():
1920 funcs += self._gen_barectf_funcs_trace_stream(stream, gen_body,
1921 hide_sid)
1922
1923 return funcs
1924
1925 # Generates all barectf_close() function.
1926 #
1927 # gen_body: also generate function bodies
1928 def _gen_barectf_funcs_close(self, gen_body):
1929 hide_sid = False
1930
1931 if len(self._doc.streams) == 1:
1932 hide_sid = True
1933
1934 funcs = []
1935
1936 for stream in self._doc.streams.values():
1937 funcs.append(self._gen_barectf_func_close(stream, gen_body,
1938 hide_sid))
1939
1940 return funcs
1941
1942 # Generate all barectf functions
1943 #
1944 # gen_body: also generate function bodies
1945 def _gen_barectf_functions(self, gen_body):
1946 init_funcs = self._gen_barectf_funcs_init(gen_body)
1947 open_funcs = self._gen_barectf_funcs_open(gen_body)
1948 close_funcs = self._gen_barectf_funcs_close(gen_body)
1949 trace_funcs = self._gen_barectf_funcs_trace(gen_body)
1950
1951 return init_funcs + open_funcs + close_funcs + trace_funcs
1952
1953 # Generates the barectf header C source
1954 def _gen_barectf_header(self):
1955 ctx_structs = self._gen_barectf_contexts_struct()
1956 functions = self._gen_barectf_functions(self._static_inline)
1957 functions_str = '\n\n'.join(functions)
1958 t = barectf.templates.HEADER
1959 header = t.format(prefix=self._prefix, ucprefix=self._prefix.upper(),
1960 barectf_ctx=ctx_structs, functions=functions_str)
1961
1962 return header
1963
1964 _BO_DEF_MAP = {
1965 pytsdl.tsdl.ByteOrder.BE: 'BIG_ENDIAN',
1966 pytsdl.tsdl.ByteOrder.LE: 'LITTLE_ENDIAN',
1967 }
1968
1969 # Generates the barectf bitfield.h header.
1970 def _gen_barectf_bitfield_header(self):
1971 header = barectf.templates.BITFIELD
1972 header = header.replace('$prefix$', self._prefix)
1973 header = header.replace('$PREFIX$', self._prefix.upper())
1974 endian_def = self._BO_DEF_MAP[self._doc.trace.byte_order]
1975 header = header.replace('$ENDIAN_DEF$', endian_def)
1976
1977 return header
1978
1979 # Generates the main barectf C source file.
1980 def _gen_barectf_csrc(self):
1981 functions = self._gen_barectf_functions(True)
1982 functions_str = '\n\n'.join(functions)
1983 t = barectf.templates.CSRC
1984 csrc = t.format(prefix=self._prefix, ucprefix=self._prefix.upper(),
1985 functions=functions_str)
1986
1987 return csrc
1988
1989 # Writes a file to the generator's output.
1990 #
1991 # name: file name
1992 # contents: file contents
1993 def _write_file(self, name, contents):
1994 path = os.path.join(self._output, name)
1995 try:
1996 with open(path, 'w') as f:
1997 f.write(contents)
1998 except Exception as e:
1999 _perror('cannot write "{}": {}'.format(path, e))
2000
2001 # Converts a C block to actual C source lines.
2002 #
2003 # cblock: C block
2004 # indent: initial indentation
2005 def _cblock_to_source_lines(self, cblock, indent=1):
2006 src = []
2007 indentstr = '\t' * indent
2008
2009 for line in cblock:
2010 if type(line) is _CBlock:
2011 src += self._cblock_to_source_lines(line, indent + 1)
2012 else:
2013 src.append(indentstr + line)
2014
2015 return src
2016
2017 # Converts a C block to an actual C source string.
2018 #
2019 # cblock: C block
2020 # indent: initial indentation
2021 def _cblock_to_source(self, cblock, indent=1):
2022 lines = self._cblock_to_source_lines(cblock, indent)
2023
2024 return '\n'.join(lines)
2025
2026 # Sets the generator parameters.
2027 def _set_params(self):
2028 # streams have timestamp_begin/timestamp_end fields
2029 self._has_timestamp_begin_end = {}
2030
2031 for stream in self._doc.streams.values():
2032 has = 'timestamp_begin' in stream.packet_context.fields
2033 self._has_timestamp_begin_end[stream.id] = has
2034
2035 # packet header size with alignment
2036 self._packet_context_offsets = {}
2037
2038 tph_size = self._get_struct_size(self._doc.trace.packet_header)
2039
2040 for stream in self._doc.streams.values():
2041 spc_alignment = self._get_obj_alignment(stream.packet_context)
2042 spc_offset = self._get_alignment(tph_size, spc_alignment)
2043 self._packet_context_offsets[stream.id] = spc_offset
2044
2045 # Generates barectf C files.
2046 #
2047 # metadata: metadata path
2048 # output: output directory
2049 # prefix: prefix
2050 # static_inline: generate static inline functions
2051 # manual_clock: do not use a clock callback: pass clock value to
2052 # tracing functions
2053 def gen_barectf(self, metadata, output, prefix, static_inline,
2054 manual_clock):
2055 self._metadata = metadata
2056 self._output = output
2057 self._prefix = prefix
2058 self._static_inline = static_inline
2059 self._manual_clock = manual_clock
2060 self._si_str = ''
2061
2062 if static_inline:
2063 self._si_str = 'static inline '
2064
2065 # open CTF metadata file
2066 _pinfo('opening CTF metadata file "{}"'.format(self._metadata))
2067
2068 try:
2069 with open(metadata) as f:
2070 self._tsdl = f.read()
2071 except:
2072 _perror('cannot open/read CTF metadata file "{}"'.format(metadata))
2073
2074 # parse CTF metadata
2075 _pinfo('parsing CTF metadata file')
2076
2077 try:
2078 self._doc = self._parser.parse(self._tsdl)
2079 except pytsdl.parser.ParseError as e:
2080 _perror('parse error: {}'.format(e))
2081
2082 # validate CTF metadata against barectf constraints
2083 _pinfo('validating CTF metadata file')
2084 self._validate_metadata()
2085 _psuccess('CTF metadata file is valid')
2086
2087 # set parameters for this generation
2088 self._set_params()
2089
2090 # generate header
2091 _pinfo('generating barectf header files')
2092 header = self._gen_barectf_header()
2093 self._write_file('{}.h'.format(self._prefix), header)
2094 header = self._gen_barectf_bitfield_header()
2095 self._write_file('{}_bitfield.h'.format(self._prefix), header)
2096
2097 # generate C source file
2098 if not self._static_inline:
2099 _pinfo('generating barectf C source file')
2100 csrc = self._gen_barectf_csrc()
2101 self._write_file('{}.c'.format(self._prefix), csrc)
2102
2103 _psuccess('done')
2104
2105
2106 def run():
2107 args = _parse_args()
2108 generator = BarectfCodeGenerator()
2109 generator.gen_barectf(args.metadata, args.output, args.prefix,
2110 args.static_inline, args.manual_clock)
This page took 0.079494 seconds and 5 git commands to generate.