2f314e0f530872da52f50333181a106abc2b7894
[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_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 else:
761 # if the integer is signed and of uncommon size, the sign bit is
762 # at a custom position anyway so we use a 64-bit unsigned
763 signed = 'u'
764
765 if integer.signed:
766 sz = '64'
767 else:
768 if integer.size <= 8:
769 sz = '8'
770 elif integer.size <= 16:
771 sz = '16'
772 elif integer.size <= 32:
773 sz = '32'
774 else:
775 sz = '64'
776
777 return '{}int{}_t'.format(signed, sz)
778
779 # Returns the equivalent C type of a TSDL enumeration.
780 #
781 # enum: TSDL enumeration of which to get the equivalent C type
782 def _get_enum_param_ctype(self, enum):
783 return self._get_obj_param_ctype(enum.integer)
784
785 # Returns the equivalent C type of a TSDL floating point number.
786 #
787 # fp: TSDL floating point number of which to get the equivalent C type
788 def _get_floating_point_param_ctype(self, fp):
789 if fp.exp_dig == 8 and fp.mant_dig == 24 and fp.align == 32:
790 return 'float'
791 elif fp.exp_dig == 11 and fp.mant_dig == 53 and fp.align == 64:
792 return 'double'
793 else:
794 return 'uint64_t'
795
796 # Returns the equivalent C type of a TSDL type.
797 #
798 # obj: TSDL type of which to get the equivalent C type
799 def _get_obj_param_ctype(self, obj):
800 return self._obj_param_ctype_cb[type(obj)](obj)
801
802 # Returns the check offset overflow macro call string for a given size.
803 #
804 # size: size to check
805 def _get_chk_offset_v(self, size):
806 fmt = '{}_CHK_OFFSET_V({}, {}, {});'
807 ret = fmt.format(self._prefix.upper(), self._CTX_AT,
808 self._CTX_PACKET_SIZE, size)
809
810 return ret
811
812 # Returns the check offset overflow macro call C line for a given size.
813 #
814 # size: size to check
815 def _get_chk_offset_v_cline(self, size):
816 return _CLine(self._get_chk_offset_v(size))
817
818 # Returns the offset alignment macro call string for a given alignment.
819 #
820 # size: new alignment
821 def _get_align_offset(self, align, at=None):
822 if at is None:
823 at = self._CTX_AT
824
825 fmt = '{}_ALIGN_OFFSET({}, {});'
826 ret = fmt.format(self._prefix.upper(), at, align)
827
828 return ret
829
830 # Returns the offset alignment macro call C line for a given alignment.
831 #
832 # size: new alignment
833 def _get_align_offset_cline(self, size):
834 return _CLine(self._get_align_offset(size))
835
836 # Converts a C source string with newlines to an array of C lines and
837 # returns it.
838 #
839 # s: C source string
840 def _str_to_clines(self, s):
841 lines = s.split('\n')
842
843 return [_CLine(line) for line in lines]
844
845 # Fills a given template with values and returns its C lines. The `prefix`
846 # and `ucprefix` template variable are automatically provided using the
847 # generator's context.
848 #
849 # tmpl: template
850 # kwargs: additional template variable values
851 def _template_to_clines(self, tmpl, **kwargs):
852 s = tmpl.format(prefix=self._prefix, ucprefix=self._prefix.upper(),
853 **kwargs)
854
855 return self._str_to_clines(s)
856
857 # Returns the C lines for writing a TSDL structure field.
858 #
859 # fname: field name
860 # src_name: C source pointer
861 # struct: TSDL structure
862 def _write_field_struct(self, fname, src_name, struct, scope_prefix=None):
863 size = self._get_struct_size(struct)
864 size_bytes = self._get_alignment(size, 8) // 8
865 dst = self._CTX_BUF_AT_ADDR
866
867 return [
868 # memcpy() is safe since barectf requires inner structures
869 # to be byte-aligned
870 self._get_chk_offset_v_cline(size),
871 _CLine('memcpy({}, {}, {});'.format(dst, src_name, size_bytes)),
872 _CLine('{} += {};'.format(self._CTX_AT, size)),
873 ]
874
875 # Returns the C lines for writing a TSDL integer field.
876 #
877 # fname: field name
878 # src_name: C source integer
879 # integer: TSDL integer
880 def _write_field_integer(self, fname, src_name, integer, scope_prefix=None):
881 bo = self._BO_SUFFIXES_MAP[integer.byte_order]
882 t = self._get_obj_param_ctype(integer)
883 length = self._get_obj_size(integer)
884
885 return self._template_to_clines(barectf.templates.WRITE_INTEGER,
886 sz=length, bo=bo, type=t,
887 src_name=src_name)
888
889 # Returns the C lines for writing a TSDL enumeration field.
890 #
891 # fname: field name
892 # src_name: C source integer
893 # enum: TSDL enumeration
894 def _write_field_enum(self, fname, src_name, enum, scope_prefix=None):
895 return self._write_field_obj(fname, src_name, enum.integer)
896
897 # Returns the C lines for writing a TSDL floating point number field.
898 #
899 # fname: field name
900 # src_name: C source pointer
901 # floating_point: TSDL floating point number
902 def _write_field_floating_point(self, fname, src_name, floating_point,
903 scope_prefix=None):
904 bo = self._BO_SUFFIXES_MAP[floating_point.byte_order]
905 t = self._get_obj_param_ctype(floating_point)
906 length = self._get_obj_size(floating_point)
907
908 if t == 'float':
909 t = 'uint32_t'
910 elif t == 'double':
911 t = 'uint64_t'
912
913 src_name_casted = '({}) {}'.format(t, src_name)
914
915 return self._template_to_clines(barectf.templates.WRITE_INTEGER,
916 sz=length, bo=bo, type=t,
917 src_name=src_name_casted)
918
919 # Returns the C lines for writing either a TSDL array field or a
920 # TSDL sequence field.
921 #
922 # fname: field name
923 # src_name: C source pointer
924 # arrayseq: TSDL array or sequence
925 # scope_prefix: preferred scope prefix
926 def _write_field_array_sequence(self, fname, src_name, arrayseq,
927 scope_prefix):
928 def length_index_varname(index):
929 return 'lens_{}_{}'.format(fname, index)
930
931 # first pass: find all lengths to multiply
932 mulops = []
933 done = False
934
935 while not done:
936 mulops.append(arrayseq.length)
937 element = arrayseq.element
938 tel = type(element)
939
940 if tel is pytsdl.tsdl.Array or tel is pytsdl.tsdl.Sequence:
941 # another array/sequence; continue
942 arrayseq = element
943 continue
944
945 # found the end
946 done = True
947
948 # align the size of the repeating element (effective repeating size)
949 el_size = self._get_obj_size(element)
950 el_align = self._get_obj_alignment(element)
951 el_size = self._get_alignment(el_size, el_align)
952
953 # this effective size is part of the operands to multiply
954 mulops.append(el_size)
955
956 # clines
957 clines = []
958
959 # fetch and save sequence lengths
960 emulops = []
961
962 for i in range(len(mulops)):
963 mulop = mulops[i]
964
965 if type(mulop) is list:
966 # offset variable to fetch
967 offvar = self._get_seq_length_src_name(mulop, scope_prefix)
968
969 if type(offvar) is int:
970 # environment constant
971 emulops.append(str(offvar))
972 continue
973
974 # save buffer position
975 line = 'ctx_at_bkup = {};'.format(self._CTX_AT)
976 clines.append(_CLine(line))
977
978 # go back to field offset
979 line = '{} = {};'.format(self._CTX_AT, offvar)
980 clines.append(_CLine(line))
981
982 # read value into specific variable
983 varname = length_index_varname(i)
984 emulops.append(varname)
985 varctype = 'uint32_t'
986 fmt = '{ctype} {cname} = *(({ctype}*) ({ctxbufataddr}));'
987 line = fmt.format(ctype=varctype, cname=varname,
988 ctxbufataddr=self._CTX_BUF_AT_ADDR)
989 clines.append(_CLine(line))
990
991 # restore buffer position
992 line = '{} = ctx_at_bkup;'.format(self._CTX_AT)
993 clines.append(_CLine(line))
994 else:
995 emulops.append(str(mulop))
996
997 # write product of sizes in bits
998 mul = ' * '.join(emulops)
999 sz_bits_varname = 'sz_bits_{}'.format(fname)
1000 sz_bytes_varname = 'sz_bytes_{}'.format(fname)
1001 line = 'uint32_t {} = {};'.format(sz_bits_varname, mul)
1002 clines.append(_CLine(line))
1003
1004 # check overflow
1005 clines.append(self._get_chk_offset_v_cline(sz_bits_varname))
1006
1007 # write product of sizes in bytes
1008 line = 'uint32_t {} = {};'.format(sz_bytes_varname, sz_bits_varname)
1009 clines.append(_CLine(line))
1010 line = self._get_align_offset(8, at=sz_bytes_varname)
1011 clines.append(_CLine(line))
1012 line = '{} >>= 3;'.format(sz_bytes_varname)
1013 clines.append(_CLine(line))
1014
1015 # memcpy()
1016 dst = self._CTX_BUF_AT_ADDR
1017 line = 'memcpy({}, {}, {});'.format(dst, src_name, sz_bytes_varname)
1018 clines.append(_CLine(line))
1019 line = '{} += {};'.format(self._CTX_AT, sz_bits_varname)
1020 clines.append(_CLine(line))
1021
1022 return clines
1023
1024 # Returns the C lines for writing a TSDL array field.
1025 #
1026 # fname: field name
1027 # src_name: C source pointer
1028 # array: TSDL array
1029 # scope_prefix: preferred scope prefix
1030 def _write_field_array(self, fname, src_name, array, scope_prefix=None):
1031 return self._write_field_array_sequence(fname, src_name, array,
1032 scope_prefix)
1033
1034 # Returns the C lines for writing a TSDL sequence field.
1035 #
1036 # fname: field name
1037 # src_name: C source pointer
1038 # sequence: TSDL sequence
1039 # scope_prefix: preferred scope prefix
1040 def _write_field_sequence(self, fname, src_name, sequence, scope_prefix):
1041 return self._write_field_array_sequence(fname, src_name, sequence,
1042 scope_prefix)
1043
1044 # Returns a trace packet header C source name out of a sequence length
1045 # expression.
1046 #
1047 # length: sequence length expression
1048 def _get_tph_src_name(self, length):
1049 offvar = self._get_offvar_name_from_expr(length[3:], 'tph')
1050
1051 return 'ctx->{}'.format(offvar)
1052
1053 # Returns an environment C source name out of a sequence length
1054 # expression.
1055 #
1056 # length: sequence length expression
1057 def _get_env_src_name(self, length):
1058 if len(length) != 2:
1059 _perror('invalid sequence length: "{}"'.format(self._dot_name_to_str(length)))
1060
1061 fname = length[1]
1062
1063 if fname not in self._doc.env:
1064 _perror('cannot find field env.{}'.format(fname))
1065
1066 env_length = self._doc.env[fname]
1067
1068 if type(env_length) is not int:
1069 _perror('env.{} is not a constant integer'.format(fname))
1070
1071 return self._doc.env[fname]
1072
1073 # Returns a stream packet context C source name out of a sequence length
1074 # expression.
1075 #
1076 # length: sequence length expression
1077 def _get_spc_src_name(self, length):
1078 offvar = self._get_offvar_name_from_expr(length[3:], 'spc')
1079
1080 return 'ctx->{}'.format(offvar)
1081
1082 # Returns a stream event header C source name out of a sequence length
1083 # expression.
1084 #
1085 # length: sequence length expression
1086 def _get_seh_src_name(self, length):
1087 return self._get_offvar_name_from_expr(length[3:], 'seh')
1088
1089 # Returns a stream event context C source name out of a sequence length
1090 # expression.
1091 #
1092 # length: sequence length expression
1093 def _get_sec_src_name(self, length):
1094 return self._get_offvar_name_from_expr(length[3:], 'sec')
1095
1096 # Returns an event context C source name out of a sequence length
1097 # expression.
1098 #
1099 # length: sequence length expression
1100 def _get_ec_src_name(self, length):
1101 return self._get_offvar_name_from_expr(length[2:], 'ec')
1102
1103 # Returns an event fields C source name out of a sequence length
1104 # expression.
1105 #
1106 # length: sequence length expression
1107 def _get_ef_src_name(self, length):
1108 return self._get_offvar_name_from_expr(length[2:], 'ef')
1109
1110 # Returns a C source name out of a sequence length expression.
1111 #
1112 # length: sequence length expression
1113 # scope_prefix: preferred scope prefix
1114 def _get_seq_length_src_name(self, length, scope_prefix=None):
1115 length_dot = self._dot_name_to_str(length)
1116
1117 for prefix, get_src_name in self._get_src_name_funcs.items():
1118 if length_dot.startswith(prefix):
1119 return get_src_name(length)
1120
1121 return self._get_offvar_name_from_expr(length, scope_prefix)
1122
1123 # Returns the C lines for writing a TSDL string field.
1124 #
1125 # fname: field name
1126 # src_name: C source pointer
1127 # string: TSDL string
1128 def _write_field_string(self, fname, src_name, string, scope_prefix=None):
1129 clines = []
1130
1131 # get string length
1132 sz_bytes_varname = 'slen_bytes_{}'.format(fname)
1133 line = 'size_t {} = strlen({}) + 1;'.format(sz_bytes_varname, src_name)
1134 clines.append(_CLine(line))
1135
1136 # check offset overflow
1137 sz_bits_varname = 'slen_bits_{}'.format(fname)
1138 line = 'size_t {} = ({} << 3);'.format(sz_bits_varname,
1139 sz_bytes_varname)
1140 clines.append(_CLine(line))
1141 cline = self._get_chk_offset_v_cline(sz_bits_varname)
1142 clines.append(cline)
1143
1144 # memcpy()
1145 dst = self._CTX_BUF_AT_ADDR
1146 line = 'memcpy({}, {}, {});'.format(dst, src_name, sz_bytes_varname)
1147 clines.append(_CLine(line))
1148
1149 # update bit position
1150 line = '{} += {};'.format(self._CTX_AT, sz_bits_varname)
1151 clines.append(_CLine(line))
1152
1153 return clines
1154
1155 # Returns the C lines for writing a TSDL type field.
1156 #
1157 # fname: field name
1158 # src_name: C source pointer
1159 # ftype: TSDL type
1160 # scope_prefix: preferred scope prefix
1161 def _write_field_obj(self, fname, src_name, ftype, scope_prefix):
1162 return self._write_field_obj_cb[type(ftype)](fname, src_name, ftype,
1163 scope_prefix)
1164
1165 # Returns an offset variable name out of an offset name.
1166 #
1167 # name: offset name
1168 # prefix: offset variable name prefix
1169 def _get_offvar_name(self, name, prefix=None):
1170 parts = ['off']
1171
1172 if prefix is not None:
1173 parts.append(prefix)
1174
1175 parts.append(name)
1176
1177 return '_'.join(parts)
1178
1179 # Returns an offset variable name out of an expression (array of
1180 # strings).
1181 #
1182 # expr: array of strings
1183 # prefix: offset variable name prefix
1184 def _get_offvar_name_from_expr(self, expr, prefix=None):
1185 return self._get_offvar_name('_'.join(expr), prefix)
1186
1187 # Returns the C lines for writing a TSDL field.
1188 #
1189 # fname: field name
1190 # ftype: TSDL field type
1191 # scope_name: scope name
1192 # scope_prefix: preferred scope prefix
1193 # param_name_cb: callback to get the C parameter name out of the
1194 # field name
1195 def _field_to_clines(self, fname, ftype, scope_name, scope_prefix,
1196 param_name_cb):
1197 clines = []
1198 pname = param_name_cb(fname)
1199 align = self._get_obj_alignment(ftype)
1200
1201 # group comment
1202 fmt = '/* write {}.{} ({}) */'
1203 line = fmt.format(scope_name, fname,
1204 self._TSDL_TYPE_NAMES_MAP[type(ftype)])
1205 clines.append(_CLine(line))
1206
1207 # align bit index before writing to the buffer
1208 cline = self._get_align_offset_cline(align)
1209 clines.append(cline)
1210
1211 # write offset variables
1212 if type(ftype) is pytsdl.tsdl.Struct:
1213 offvars_tree = collections.OrderedDict()
1214 self._get_struct_size(ftype, offvars_tree)
1215 offvars = self._flatten_offvars_tree(offvars_tree)
1216
1217 # as many offset as there are child fields because a future
1218 # sequence could refer to any of those fields
1219 for lname, offset in offvars.items():
1220 offvar = self._get_offvar_name('_'.join([fname, lname]),
1221 scope_prefix)
1222 fmt = 'uint32_t {} = (uint32_t) {} + {};'
1223 line = fmt.format(offvar, self._CTX_AT, offset);
1224 clines.append(_CLine(line))
1225 elif type(ftype) is pytsdl.tsdl.Integer:
1226 # offset of this simple field is the current bit index
1227 offvar = self._get_offvar_name(fname, scope_prefix)
1228 line = 'uint32_t {} = (uint32_t) {};'.format(offvar, self._CTX_AT)
1229 clines.append(_CLine(line))
1230
1231 clines += self._write_field_obj(fname, pname, ftype, scope_prefix)
1232
1233 return clines
1234
1235 # Joins C line groups and returns C lines.
1236 #
1237 # cline_groups: C line groups to join
1238 def _join_cline_groups(self, cline_groups):
1239 if not cline_groups:
1240 return cline_groups
1241
1242 output_clines = cline_groups[0]
1243
1244 for clines in cline_groups[1:]:
1245 output_clines.append('')
1246 output_clines += clines
1247
1248 return output_clines
1249
1250 # Returns the C lines for writing a complete TSDL structure (top level
1251 # scope).
1252 #
1253 # struct: TSDL structure
1254 # scope_name: scope name
1255 # scope_prefix: preferred scope prefix
1256 # param_name_cb: callback to get the C parameter name out of the
1257 # field name
1258 def _struct_to_clines(self, struct, scope_name, scope_prefix,
1259 param_name_cb):
1260 cline_groups = []
1261
1262 for fname, ftype in struct.fields.items():
1263 clines = self._field_to_clines(fname, ftype, scope_name,
1264 scope_prefix, param_name_cb)
1265 cline_groups.append(clines)
1266
1267 return self._join_cline_groups(cline_groups)
1268
1269 # Returns the offset variables of a TSDL structure.
1270 #
1271 # struct: TSDL structure
1272 def _get_struct_size_offvars(self, struct):
1273 offvars_tree = collections.OrderedDict()
1274 size = self._get_struct_size(struct, offvars_tree)
1275 offvars = self._flatten_offvars_tree(offvars_tree)
1276
1277 return size, offvars
1278
1279 # Returns the size and offset variables of the current trace packet header.
1280 def _get_tph_size_offvars(self):
1281 return self._get_struct_size_offvars(self._doc.trace.packet_header)
1282
1283 # Returns the size and offset variables of the a stream packet context.
1284 #
1285 # stream: TSDL stream
1286 def _get_spc_size_offvars(self, stream):
1287 return self._get_struct_size_offvars(stream.packet_context)
1288
1289 # Returns the C lines for the barectf context C structure entries for
1290 # offsets.
1291 #
1292 # prefix: offset variable names prefix
1293 # offvars: offset variables
1294 def _offvars_to_ctx_clines(self, prefix, offvars):
1295 clines = []
1296
1297 for name in offvars.keys():
1298 offvar = self._get_offvar_name(name, prefix)
1299 clines.append(_CLine('uint32_t {};'.format(offvar)))
1300
1301 return clines
1302
1303 # Generates a barectf context C structure.
1304 #
1305 # stream: TSDL stream
1306 # hide_sid: True to hide the stream ID
1307 def _gen_barectf_ctx_struct(self, stream, hide_sid=False):
1308 # get offset variables for both the packet header and packet context
1309 tph_size, tph_offvars = self._get_tph_size_offvars()
1310 spc_size, spc_offvars = self._get_spc_size_offvars(stream)
1311 clines = self._offvars_to_ctx_clines('tph', tph_offvars)
1312 clines += self._offvars_to_ctx_clines('spc', spc_offvars)
1313
1314 # indent C
1315 clines_indented = []
1316 for cline in clines:
1317 clines_indented.append(_CLine('\t' + cline))
1318
1319 # clock callback
1320 clock_cb = '\t/* (no clock callback) */'
1321
1322 if not self._manual_clock:
1323 ctype = self._get_clock_ctype(stream)
1324 fmt = '\t{} (*clock_cb)(void*);\n\tvoid* clock_cb_data;'
1325 clock_cb = fmt.format(ctype)
1326
1327 # fill template
1328 sid = ''
1329
1330 if not hide_sid:
1331 sid = stream.id
1332
1333 t = barectf.templates.BARECTF_CTX
1334 struct = t.format(prefix=self._prefix, sid=sid,
1335 ctx_fields='\n'.join(clines_indented),
1336 clock_cb=clock_cb)
1337
1338 return struct
1339
1340 # Generates all barectf context C structures.
1341 def _gen_barectf_contexts_struct(self):
1342 hide_sid = False
1343
1344 if len(self._doc.streams) == 1:
1345 hide_sid = True
1346
1347 structs = []
1348
1349 for stream in self._doc.streams.values():
1350 struct = self._gen_barectf_ctx_struct(stream, hide_sid)
1351 structs.append(struct)
1352
1353 return '\n\n'.join(structs)
1354
1355 # Returns the C type of the clock used by the event header of a
1356 # TSDL stream.
1357 #
1358 # stream: TSDL stream containing the event header to inspect
1359 def _get_clock_ctype(self, stream):
1360 return self._get_obj_param_ctype(stream.event_header['timestamp'])
1361
1362 # Generates the manual clock value C parameter for a given stream.
1363 #
1364 # stream: TSDL stream
1365 def _gen_manual_clock_param(self, stream):
1366 return '{} param_clock'.format(self._get_clock_ctype(stream))
1367
1368 # Generates the body of a barectf_open() function.
1369 #
1370 # stream: TSDL stream
1371 def _gen_barectf_func_open_body(self, stream):
1372 clines = []
1373
1374 # keep clock value (for timestamp_begin)
1375 if self._stream_has_timestamp_begin_end(stream):
1376 # get clock value ASAP
1377 clk_type = self._get_clock_ctype(stream)
1378 clk = self._gen_get_clock_value()
1379 line = '{} clk_value = {};'.format(clk_type, clk)
1380 clines.append(_CLine(line))
1381 clines.append(_CLine(''))
1382
1383 # reset bit position to write the packet context (after packet header)
1384 spc_offset = self._get_stream_packet_context_offset(stream)
1385 fmt = '{} = {};'
1386 line = fmt.format(self._CTX_AT, spc_offset)
1387 clines.append(_CLine(line))
1388
1389 # bit position at beginning of event (to reset in case we run
1390 # out of space)
1391 line = 'uint32_t ctx_at_begin = {};'.format(self._CTX_AT)
1392 clines.append(_CLine(line))
1393
1394 # packet context fields
1395 fcline_groups = []
1396 scope_name = 'stream.packet.context'
1397 scope_prefix = 'spc'
1398
1399 for fname, ftype in stream.packet_context.fields.items():
1400 # packet size
1401 if fname == 'packet_size':
1402 fclines = self._field_to_clines(fname, ftype, scope_name,
1403 scope_prefix,
1404 lambda x: 'ctx->packet_size')
1405 fcline_groups.append(fclines)
1406
1407 # content size (skip)
1408 elif fname == 'content_size':
1409 fclines = self._field_to_clines(fname, ftype, scope_name,
1410 scope_prefix, lambda x: '0')
1411 fcline_groups.append(fclines)
1412
1413 # timestamp_begin
1414 elif fname == 'timestamp_begin':
1415 fclines = self._field_to_clines(fname, ftype, scope_name,
1416 scope_prefix,
1417 lambda x: 'clk_value')
1418 fcline_groups.append(fclines)
1419
1420 # timestamp_end (skip)
1421 elif fname == 'timestamp_end':
1422 fclines = self._field_to_clines(fname, ftype, scope_name,
1423 scope_prefix, lambda x: '0')
1424 fcline_groups.append(fclines)
1425
1426 # anything else
1427 else:
1428 fclines = self._field_to_clines(fname, ftype, scope_name,
1429 scope_prefix,
1430 self._spc_fname_to_pname)
1431 fcline_groups.append(fclines)
1432
1433 # return 0
1434 fcline_groups.append([_CLine('return 0;')])
1435
1436 clines += self._join_cline_groups(fcline_groups)
1437
1438 # get source
1439 cblock = _CBlock(clines)
1440 src = self._cblock_to_source(cblock)
1441
1442 return src
1443
1444 _SPC_KNOWN_FIELDS = [
1445 'content_size',
1446 'packet_size',
1447 'timestamp_begin',
1448 'timestamp_end',
1449 ]
1450
1451 # Generates a barectf_open() function.
1452 #
1453 # stream: TSDL stream
1454 # gen_body: also generate function body
1455 # hide_sid: True to hide the stream ID
1456 def _gen_barectf_func_open(self, stream, gen_body, hide_sid=False):
1457 params = []
1458
1459 # manual clock
1460 if self._manual_clock:
1461 clock_param = self._gen_manual_clock_param(stream)
1462 params.append(clock_param)
1463
1464 # packet context
1465 for fname, ftype in stream.packet_context.fields.items():
1466 if fname in self._SPC_KNOWN_FIELDS:
1467 continue
1468
1469 ptype = self._get_obj_param_ctype(ftype)
1470 pname = self._spc_fname_to_pname(fname)
1471 param = '{} {}'.format(ptype, pname)
1472 params.append(param)
1473
1474 params_str = ''
1475
1476 if params:
1477 params_str = ',\n\t'.join([''] + params)
1478
1479 # fill template
1480 sid = ''
1481
1482 if not hide_sid:
1483 sid = stream.id
1484
1485 t = barectf.templates.FUNC_OPEN
1486 func = t.format(si=self._si_str, prefix=self._prefix, sid=sid,
1487 params=params_str)
1488
1489 if gen_body:
1490 func += '\n{\n'
1491 func += self._gen_barectf_func_open_body(stream)
1492 func += '\n}'
1493 else:
1494 func += ';'
1495
1496 return func
1497
1498 # Generates the body of a barectf_init() function.
1499 #
1500 # stream: TSDL stream
1501 def _gen_barectf_func_init_body(self, stream):
1502 clines = []
1503
1504 line = 'uint32_t ctx_at_bkup;'
1505 clines.append(_CLine(line))
1506
1507 # bit position at beginning of event (to reset in case we run
1508 # out of space)
1509 line = 'uint32_t ctx_at_begin = {};'.format(self._CTX_AT)
1510 clines.append(_CLine(line))
1511
1512 # set context parameters
1513 clines.append(_CLine(''))
1514 clines.append(_CLine("/* barectf context parameters */"))
1515 clines.append(_CLine('ctx->buf = buf;'))
1516 clines.append(_CLine('ctx->packet_size = buf_size * 8;'))
1517 clines.append(_CLine('{} = 0;'.format(self._CTX_AT)))
1518
1519 if not self._manual_clock:
1520 clines.append(_CLine('ctx->clock_cb = clock_cb;'))
1521 clines.append(_CLine('ctx->clock_cb_data = clock_cb_data;'))
1522
1523 # set context offsets
1524 clines.append(_CLine(''))
1525 clines.append(_CLine("/* barectf context offsets */"))
1526 ph_size, ph_offvars = self._get_tph_size_offvars()
1527 pc_size, pc_offvars = self._get_spc_size_offvars(stream)
1528 pc_alignment = self._get_obj_alignment(stream.packet_context)
1529 pc_offset = self._get_alignment(ph_size, pc_alignment)
1530
1531 for offvar, offset in ph_offvars.items():
1532 offvar_field = self._get_offvar_name(offvar, 'tph')
1533 line = 'ctx->{} = {};'.format(offvar_field, offset)
1534 clines.append(_CLine(line))
1535
1536 for offvar, offset in pc_offvars.items():
1537 offvar_field = self._get_offvar_name(offvar, 'spc')
1538 line = 'ctx->{} = {};'.format(offvar_field, pc_offset + offset)
1539 clines.append(_CLine(line))
1540
1541 clines.append(_CLine(''))
1542
1543 # packet header fields
1544 fcline_groups = []
1545 scope_name = 'trace.packet.header'
1546 scope_prefix = 'tph'
1547
1548 for fname, ftype in self._doc.trace.packet_header.fields.items():
1549 # magic number
1550 if fname == 'magic':
1551 fclines = self._field_to_clines(fname, ftype, scope_name,
1552 scope_prefix,
1553 lambda x: '0xc1fc1fc1UL')
1554 fcline_groups.append(fclines)
1555
1556 # stream ID
1557 elif fname == 'stream_id':
1558 fclines = self._field_to_clines(fname, ftype, scope_name,
1559 scope_prefix,
1560 lambda x: str(stream.id))
1561 fcline_groups.append(fclines)
1562
1563 # return 0
1564 fcline_groups.append([_CLine('return 0;')])
1565
1566 clines += self._join_cline_groups(fcline_groups)
1567
1568 # get source
1569 cblock = _CBlock(clines)
1570 src = self._cblock_to_source(cblock)
1571
1572 return src
1573
1574 # Generates a barectf_init() function.
1575 #
1576 # stream: TSDL stream
1577 # gen_body: also generate function body
1578 # hide_sid: True to hide the stream ID
1579 def _gen_barectf_func_init(self, stream, gen_body, hide_sid=False):
1580 # fill template
1581 sid = ''
1582
1583 if not hide_sid:
1584 sid = stream.id
1585
1586 params = ''
1587
1588 if not self._manual_clock:
1589 ts_ftype = stream.event_header['timestamp']
1590 ts_ptype = self._get_obj_param_ctype(ts_ftype)
1591 fmt = ',\n\t{} (*clock_cb)(void*),\n\tvoid* clock_cb_data'
1592 params = fmt.format(ts_ptype)
1593
1594 t = barectf.templates.FUNC_INIT
1595 func = t.format(si=self._si_str, prefix=self._prefix, sid=sid,
1596 params=params)
1597
1598 if gen_body:
1599 func += '\n{\n'
1600 func += self._gen_barectf_func_init_body(stream)
1601 func += '\n}'
1602 else:
1603 func += ';'
1604
1605 return func
1606
1607 # Generates the C expression to get the clock value depending on
1608 # whether we're in manual clock mode or not.
1609 def _gen_get_clock_value(self):
1610 if self._manual_clock:
1611 return 'param_clock'
1612 else:
1613 return self._CTX_CALL_CLOCK_CB
1614
1615 # Returns True if the given TSDL stream has timestamp_begin and
1616 # timestamp_end fields.
1617 #
1618 # stream: TSDL stream to check
1619 def _stream_has_timestamp_begin_end(self, stream):
1620 return self._has_timestamp_begin_end[stream.id]
1621
1622 # Returns the packet context offset (from the beginning of the
1623 # packet) of a given TSDL stream
1624 #
1625 # stream: TSDL stream
1626 def _get_stream_packet_context_offset(self, stream):
1627 return self._packet_context_offsets[stream.id]
1628
1629 # Generates the C lines to write a barectf context field, saving
1630 # and restoring the current bit position accordingly.
1631 #
1632 # src_name: C source name
1633 # prefix: offset variable prefix
1634 # name: offset variable name
1635 # integer: TSDL integer to write
1636 def _gen_write_ctx_field_integer(self, src_name, prefix, name, integer):
1637 clines = []
1638
1639 # save buffer position
1640 line = 'ctx_at_bkup = {};'.format(self._CTX_AT)
1641 clines.append(_CLine(line))
1642
1643 # go back to field offset
1644 offvar = self._get_offvar_name(name, prefix)
1645 line = '{} = ctx->{};'.format(self._CTX_AT, offvar)
1646 clines.append(_CLine(line))
1647
1648 # write value
1649 clines += self._write_field_integer(None, src_name, integer)
1650
1651 # restore buffer position
1652 line = '{} = ctx_at_bkup;'.format(self._CTX_AT)
1653 clines.append(_CLine(line))
1654
1655 return clines
1656
1657 # Generates the body of a barectf_close() function.
1658 #
1659 # stream: TSDL stream
1660 def _gen_barectf_func_close_body(self, stream):
1661 clines = []
1662
1663 line = 'uint32_t ctx_at_bkup;'
1664 clines.append(_CLine(line))
1665
1666 # bit position at beginning of event (to reset in case we run
1667 # out of space)
1668 line = 'uint32_t ctx_at_begin = {};'.format(self._CTX_AT)
1669 clines.append(_CLine(line))
1670
1671 # update timestamp end if present
1672 if self._stream_has_timestamp_begin_end(stream):
1673 clines.append(_CLine(''))
1674 clines.append(_CLine("/* update packet context's timestamp_end */"))
1675
1676 # get clock value ASAP
1677 clk_type = self._get_clock_ctype(stream)
1678 clk = self._gen_get_clock_value()
1679 line = '{} clk_value = {};'.format(clk_type, clk)
1680 clines.append(_CLine(line))
1681
1682 # write timestamp_end
1683 timestamp_end_integer = stream.packet_context['timestamp_end']
1684 clines += self._gen_write_ctx_field_integer('clk_value', 'spc',
1685 'timestamp_end',
1686 timestamp_end_integer)
1687
1688 # update content_size
1689 clines.append(_CLine(''))
1690 clines.append(_CLine("/* update packet context's content_size */"))
1691 content_size_integer = stream.packet_context['content_size']
1692 clines += self._gen_write_ctx_field_integer('ctx_at_bkup', 'spc',
1693 'content_size',
1694 content_size_integer)
1695
1696 # return 0
1697 clines.append(_CLine('\n'))
1698 clines.append(_CLine('return 0;'))
1699
1700 # get source
1701 cblock = _CBlock(clines)
1702 src = self._cblock_to_source(cblock)
1703
1704 return src
1705
1706 # Generates a barectf_close() function.
1707 #
1708 # stream: TSDL stream
1709 # gen_body: also generate function body
1710 # hide_sid: True to hide the stream ID
1711 def _gen_barectf_func_close(self, stream, gen_body, hide_sid=False):
1712 # fill template
1713 sid = ''
1714
1715 if not hide_sid:
1716 sid = stream.id
1717
1718 params = ''
1719
1720 if self._manual_clock:
1721 clock_param = self._gen_manual_clock_param(stream)
1722 params = ',\n\t{}'.format(clock_param)
1723
1724 t = barectf.templates.FUNC_CLOSE
1725 func = t.format(si=self._si_str, prefix=self._prefix, sid=sid,
1726 params=params)
1727
1728 if gen_body:
1729 func += '\n{\n'
1730 func += self._gen_barectf_func_close_body(stream)
1731 func += '\n}'
1732 else:
1733 func += ';'
1734
1735 return func
1736
1737 # Generates all barectf_init() function.
1738 #
1739 # gen_body: also generate function bodies
1740 def _gen_barectf_funcs_init(self, gen_body):
1741 hide_sid = False
1742
1743 if len(self._doc.streams) == 1:
1744 hide_sid = True
1745
1746 funcs = []
1747
1748 for stream in self._doc.streams.values():
1749 funcs.append(self._gen_barectf_func_init(stream, gen_body,
1750 hide_sid))
1751
1752 return funcs
1753
1754 # Generates all barectf_open() function.
1755 #
1756 # gen_body: also generate function bodies
1757 def _gen_barectf_funcs_open(self, gen_body):
1758 hide_sid = False
1759
1760 if len(self._doc.streams) == 1:
1761 hide_sid = True
1762
1763 funcs = []
1764
1765 for stream in self._doc.streams.values():
1766 funcs.append(self._gen_barectf_func_open(stream, gen_body,
1767 hide_sid))
1768
1769 return funcs
1770
1771 # Generates the body of a barectf_trace() function.
1772 #
1773 # stream: TSDL stream of TSDL event to trace
1774 # event: TSDL event to trace
1775 def _gen_barectf_func_trace_event_body(self, stream, event):
1776 clines = []
1777
1778 # get clock value ASAP
1779 clk_type = self._get_clock_ctype(stream)
1780 clk = self._gen_get_clock_value()
1781 line = '{} clk_value = {};'.format(clk_type, clk)
1782 clines.append(_CLine(line))
1783 clines.append(_CLine(''))
1784
1785 # bit position backup (could be used)
1786 clines.append(_CLine('uint32_t ctx_at_bkup;'))
1787
1788 # bit position at beginning of event (to reset in case we run
1789 # out of space)
1790 line = 'uint32_t ctx_at_begin = {};'.format(self._CTX_AT)
1791 clines.append(_CLine(line))
1792
1793 # event header
1794 fcline_groups = []
1795 scope_name = 'event.header'
1796 scope_prefix = 'eh'
1797
1798 for fname, ftype in stream.event_header.fields.items():
1799 # id
1800 if fname == 'id':
1801 fclines = self._field_to_clines(fname, ftype, scope_name,
1802 scope_prefix,
1803 lambda x: str(event.id))
1804 fcline_groups.append(fclines)
1805
1806 # timestamp
1807 elif fname == 'timestamp':
1808 fclines = self._field_to_clines(fname, ftype, scope_name,
1809 scope_prefix,
1810 lambda x: 'clk_value')
1811 fcline_groups.append(fclines)
1812
1813 # stream event context
1814 if stream.event_context is not None:
1815 fclines = self._struct_to_clines(stream.event_context,
1816 'stream.event.context', 'sec',
1817 self._sec_fname_to_pname)
1818 fcline_groups.append(fclines)
1819
1820 # event context
1821 if event.context is not None:
1822 fclines = self._struct_to_clines(event.context,
1823 'event.context', 'ec',
1824 self._ec_fname_to_pname)
1825 fcline_groups.append(fclines)
1826
1827 # event fields
1828 if event.fields is not None:
1829 fclines = self._struct_to_clines(event.fields,
1830 'event.fields', 'ef',
1831 self._ef_fname_to_pname)
1832 fcline_groups.append(fclines)
1833
1834 # return 0
1835 fcline_groups.append([_CLine('return 0;')])
1836
1837 clines += self._join_cline_groups(fcline_groups)
1838
1839 # get source
1840 cblock = _CBlock(clines)
1841 src = self._cblock_to_source(cblock)
1842
1843 return src
1844
1845 # Generates a barectf_trace() function.
1846 #
1847 # stream: TSDL stream containing the TSDL event to trace
1848 # event: TSDL event to trace
1849 # gen_body: also generate function body
1850 # hide_sid: True to hide the stream ID
1851 def _gen_barectf_func_trace_event(self, stream, event, gen_body, hide_sid):
1852 params = []
1853
1854 # manual clock
1855 if self._manual_clock:
1856 clock_param = self._gen_manual_clock_param(stream)
1857 params.append(clock_param)
1858
1859 # stream event context params
1860 if stream.event_context is not None:
1861 for fname, ftype in stream.event_context.fields.items():
1862 ptype = self._get_obj_param_ctype(ftype)
1863 pname = self._sec_fname_to_pname(fname)
1864 param = '{} {}'.format(ptype, pname)
1865 params.append(param)
1866
1867 # event context params
1868 if event.context is not None:
1869 for fname, ftype in event.context.fields.items():
1870 ptype = self._get_obj_param_ctype(ftype)
1871 pname = self._ec_fname_to_pname(fname)
1872 param = '{} {}'.format(ptype, pname)
1873 params.append(param)
1874
1875 # event fields params
1876 if event.fields is not None:
1877 for fname, ftype in event.fields.fields.items():
1878 ptype = self._get_obj_param_ctype(ftype)
1879 pname = self._ef_fname_to_pname(fname)
1880 param = '{} {}'.format(ptype, pname)
1881 params.append(param)
1882
1883 params_str = ''
1884
1885 if params:
1886 params_str = ',\n\t'.join([''] + params)
1887
1888 # fill template
1889 sid = ''
1890
1891 if not hide_sid:
1892 sid = stream.id
1893
1894 t = barectf.templates.FUNC_TRACE
1895 func = t.format(si=self._si_str, prefix=self._prefix, sid=sid,
1896 evname=event.name, params=params_str)
1897
1898 if gen_body:
1899 func += '\n{\n'
1900 func += self._gen_barectf_func_trace_event_body(stream, event)
1901 func += '\n}'
1902 else:
1903 func += ';'
1904
1905 return func
1906
1907 # Generates all barectf_trace() functions of a given TSDL stream.
1908 #
1909 # stream: TSDL stream containing the TSDL events to trace
1910 # gen_body: also generate function body
1911 # hide_sid: True to hide the stream ID
1912 def _gen_barectf_funcs_trace_stream(self, stream, gen_body, hide_sid):
1913 funcs = []
1914
1915 for event in stream.events:
1916 funcs.append(self._gen_barectf_func_trace_event(stream, event,
1917 gen_body, hide_sid))
1918
1919 return funcs
1920
1921 # Generates all barectf_trace() function.
1922 #
1923 # gen_body: also generate function bodies
1924 def _gen_barectf_funcs_trace(self, gen_body):
1925 hide_sid = False
1926
1927 if len(self._doc.streams) == 1:
1928 hide_sid = True
1929
1930 funcs = []
1931
1932 for stream in self._doc.streams.values():
1933 funcs += self._gen_barectf_funcs_trace_stream(stream, gen_body,
1934 hide_sid)
1935
1936 return funcs
1937
1938 # Generates all barectf_close() function.
1939 #
1940 # gen_body: also generate function bodies
1941 def _gen_barectf_funcs_close(self, gen_body):
1942 hide_sid = False
1943
1944 if len(self._doc.streams) == 1:
1945 hide_sid = True
1946
1947 funcs = []
1948
1949 for stream in self._doc.streams.values():
1950 funcs.append(self._gen_barectf_func_close(stream, gen_body,
1951 hide_sid))
1952
1953 return funcs
1954
1955 # Generate all barectf functions
1956 #
1957 # gen_body: also generate function bodies
1958 def _gen_barectf_functions(self, gen_body):
1959 init_funcs = self._gen_barectf_funcs_init(gen_body)
1960 open_funcs = self._gen_barectf_funcs_open(gen_body)
1961 close_funcs = self._gen_barectf_funcs_close(gen_body)
1962 trace_funcs = self._gen_barectf_funcs_trace(gen_body)
1963
1964 return init_funcs + open_funcs + close_funcs + trace_funcs
1965
1966 # Generates the barectf header C source
1967 def _gen_barectf_header(self):
1968 ctx_structs = self._gen_barectf_contexts_struct()
1969 functions = self._gen_barectf_functions(self._static_inline)
1970 functions_str = '\n\n'.join(functions)
1971 t = barectf.templates.HEADER
1972 header = t.format(prefix=self._prefix, ucprefix=self._prefix.upper(),
1973 barectf_ctx=ctx_structs, functions=functions_str)
1974
1975 return header
1976
1977 _BO_DEF_MAP = {
1978 pytsdl.tsdl.ByteOrder.BE: 'BIG_ENDIAN',
1979 pytsdl.tsdl.ByteOrder.LE: 'LITTLE_ENDIAN',
1980 }
1981
1982 # Generates the barectf bitfield.h header.
1983 def _gen_barectf_bitfield_header(self):
1984 header = barectf.templates.BITFIELD
1985 header = header.replace('$prefix$', self._prefix)
1986 header = header.replace('$PREFIX$', self._prefix.upper())
1987 endian_def = self._BO_DEF_MAP[self._doc.trace.byte_order]
1988 header = header.replace('$ENDIAN_DEF$', endian_def)
1989
1990 return header
1991
1992 # Generates the main barectf C source file.
1993 def _gen_barectf_csrc(self):
1994 functions = self._gen_barectf_functions(True)
1995 functions_str = '\n\n'.join(functions)
1996 t = barectf.templates.CSRC
1997 csrc = t.format(prefix=self._prefix, ucprefix=self._prefix.upper(),
1998 functions=functions_str)
1999
2000 return csrc
2001
2002 # Writes a file to the generator's output.
2003 #
2004 # name: file name
2005 # contents: file contents
2006 def _write_file(self, name, contents):
2007 path = os.path.join(self._output, name)
2008 try:
2009 with open(path, 'w') as f:
2010 f.write(contents)
2011 except Exception as e:
2012 _perror('cannot write "{}": {}'.format(path, e))
2013
2014 # Converts a C block to actual C source lines.
2015 #
2016 # cblock: C block
2017 # indent: initial indentation
2018 def _cblock_to_source_lines(self, cblock, indent=1):
2019 src = []
2020 indentstr = '\t' * indent
2021
2022 for line in cblock:
2023 if type(line) is _CBlock:
2024 src += self._cblock_to_source_lines(line, indent + 1)
2025 else:
2026 src.append(indentstr + line)
2027
2028 return src
2029
2030 # Converts a C block to an actual C source string.
2031 #
2032 # cblock: C block
2033 # indent: initial indentation
2034 def _cblock_to_source(self, cblock, indent=1):
2035 lines = self._cblock_to_source_lines(cblock, indent)
2036
2037 return '\n'.join(lines)
2038
2039 # Sets the generator parameters.
2040 def _set_params(self):
2041 # streams have timestamp_begin/timestamp_end fields
2042 self._has_timestamp_begin_end = {}
2043
2044 for stream in self._doc.streams.values():
2045 has = 'timestamp_begin' in stream.packet_context.fields
2046 self._has_timestamp_begin_end[stream.id] = has
2047
2048 # packet header size with alignment
2049 self._packet_context_offsets = {}
2050
2051 tph_size = self._get_struct_size(self._doc.trace.packet_header)
2052
2053 for stream in self._doc.streams.values():
2054 spc_alignment = self._get_obj_alignment(stream.packet_context)
2055 spc_offset = self._get_alignment(tph_size, spc_alignment)
2056 self._packet_context_offsets[stream.id] = spc_offset
2057
2058 # Generates barectf C files.
2059 #
2060 # metadata: metadata path
2061 # output: output directory
2062 # prefix: prefix
2063 # static_inline: generate static inline functions
2064 # manual_clock: do not use a clock callback: pass clock value to
2065 # tracing functions
2066 def gen_barectf(self, metadata, output, prefix, static_inline,
2067 manual_clock):
2068 self._metadata = metadata
2069 self._output = output
2070 self._prefix = prefix
2071 self._static_inline = static_inline
2072 self._manual_clock = manual_clock
2073 self._si_str = ''
2074
2075 if static_inline:
2076 self._si_str = 'static inline '
2077
2078 # open CTF metadata file
2079 _pinfo('opening CTF metadata file "{}"'.format(self._metadata))
2080
2081 try:
2082 with open(metadata) as f:
2083 self._tsdl = f.read()
2084 except:
2085 _perror('cannot open/read CTF metadata file "{}"'.format(metadata))
2086
2087 # parse CTF metadata
2088 _pinfo('parsing CTF metadata file')
2089
2090 try:
2091 self._doc = self._parser.parse(self._tsdl)
2092 except pytsdl.parser.ParseError as e:
2093 _perror('parse error: {}'.format(e))
2094
2095 # validate CTF metadata against barectf constraints
2096 _pinfo('validating CTF metadata file')
2097 self._validate_metadata()
2098 _psuccess('CTF metadata file is valid')
2099
2100 # set parameters for this generation
2101 self._set_params()
2102
2103 # generate header
2104 _pinfo('generating barectf header files')
2105 header = self._gen_barectf_header()
2106 self._write_file('{}.h'.format(self._prefix), header)
2107 header = self._gen_barectf_bitfield_header()
2108 self._write_file('{}_bitfield.h'.format(self._prefix), header)
2109
2110 # generate C source file
2111 if not self._static_inline:
2112 _pinfo('generating barectf C source file')
2113 csrc = self._gen_barectf_csrc()
2114 self._write_file('{}.c'.format(self._prefix), csrc)
2115
2116 _psuccess('done')
2117
2118
2119 def run():
2120 args = _parse_args()
2121 generator = BarectfCodeGenerator()
2122 generator.gen_barectf(args.metadata, args.output, args.prefix,
2123 args.static_inline, args.manual_clock)
This page took 0.07458 seconds and 3 git commands to generate.