1 # The MIT License (MIT)
3 # Copyright (c) 2014 Philippe Proulx <philippe.proulx@efficios.com>
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:
12 # The above copyright notice and this permission notice shall be included in
13 # all copies or substantial portions of the Software.
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
22 from termcolor
import cprint
, colored
23 import barectf
.templates
33 def _perror(msg
, exit_code
=1):
34 cprint('error: {}'.format(msg
), 'red', attrs
=['bold'], file=sys
.stderr
)
39 cprint(':: {}'.format(msg
), 'blue', attrs
=['bold'])
43 cprint('{}'.format(msg
), 'green', attrs
=['bold'])
47 ap
= argparse
.ArgumentParser()
49 ap
.add_argument('-O', '--output', metavar
='OUTPUT', action
='store',
51 help='output directory of C files')
52 ap
.add_argument('-p', '--prefix', metavar
='PREFIX', action
='store',
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')
63 args
= ap
.parse_args()
65 # validate output directory
66 if not os
.path
.isdir(args
.output
):
67 _perror('"{}" is not an existing directory'.format(args
.output
))
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
))
73 # validate that metadata file exists
74 if not os
.path
.isfile(args
.metadata
):
75 _perror('"{}" is not an existing file'.format(args
.metadata
))
88 class BarectfCodeGenerator
:
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)'
97 pytsdl
.tsdl
.ByteOrder
.BE
: 'be',
98 pytsdl
.tsdl
.ByteOrder
.LE
: 'le',
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',
112 self
._parser
= pytsdl
.parser
.Parser()
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
,
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
,
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*',
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
,
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
,
162 # Validates an inner TSDL structure's field (constrained structure).
166 def _validate_inner_struct_field(self
, fname
, ftype
):
167 if type(ftype
) is pytsdl
.tsdl
.Sequence
:
168 raise RuntimeError('field "{}" is a dynamic array (not allowed here)'.format(fname
))
169 elif type(ftype
) is pytsdl
.tsdl
.Array
:
170 # we need to check every element until we find a terminal one
171 self
._validate
_inner
_struct
_field
(fname
, ftype
.element
)
172 elif type(ftype
) is pytsdl
.tsdl
.Variant
:
173 raise RuntimeError('field "{}" is a variant (unsupported)'.format(fname
))
174 elif type(ftype
) is pytsdl
.tsdl
.String
:
175 raise RuntimeError('field "{}" is a string (not allowed here)'.format(fname
))
176 elif type(ftype
) is pytsdl
.tsdl
.Struct
:
177 self
._validate
_inner
_struct
(ftype
)
178 elif type(ftype
) is pytsdl
.tsdl
.Integer
:
179 if self
._get
_obj
_size
(ftype
) > 64:
180 raise RuntimeError('integer field "{}" larger than 64-bit'.format(fname
))
181 elif type(ftype
) is pytsdl
.tsdl
.FloatingPoint
:
182 if self
._get
_obj
_size
(ftype
) > 64:
183 raise RuntimeError('floating point field "{}" larger than 64-bit'.format(fname
))
184 elif type(ftype
) is pytsdl
.tsdl
.Enum
:
185 if self
._get
_obj
_size
(ftype
) > 64:
186 raise RuntimeError('enum field "{}" larger than 64-bit'.format(fname
))
188 # Validates an inner TSDL structure (constrained).
190 # struct: TSDL structure to validate
191 def _validate_inner_struct(self
, struct
):
192 # just in case we call this with the wrong type
193 if type(struct
) is not pytsdl
.tsdl
.Struct
:
194 raise RuntimeError('expecting a struct')
196 # make sure inner structures are at least byte-aligned
197 if self
._get
_obj
_alignment
(struct
) < 8:
198 raise RuntimeError('inner struct must be at least byte-aligned')
201 for fname
, ftype
in struct
.fields
.items():
202 self
._validate
_inner
_struct
_field
(fname
, ftype
)
204 # Validates a context or fields structure.
206 # struct: context/fields TSDL structure
207 def _validate_context_fields(self
, struct
):
208 if type(struct
) is not pytsdl
.tsdl
.Struct
:
209 raise RuntimeError('expecting a struct')
211 for fname
, ftype
in struct
.fields
.items():
212 if type(ftype
) is pytsdl
.tsdl
.Variant
:
213 raise RuntimeError('field "{}" is a variant (unsupported)'.format(fname
))
214 elif type(ftype
) is pytsdl
.tsdl
.Struct
:
215 # validate inner structure against barectf constraints
216 self
._validate
_inner
_struct
(ftype
)
217 elif type(ftype
) is pytsdl
.tsdl
.Array
or type(ftype
) is pytsdl
.tsdl
.Sequence
:
222 if type(el
) is pytsdl
.tsdl
.Struct
:
223 self
._validate
_inner
_struct
(el
)
224 if type(el
) is pytsdl
.tsdl
.Array
or type(el
) is pytsdl
.tsdl
.Sequence
:
230 # Validates a TSDL integer with optional constraints.
232 # integer: TSDL integer to validate
233 # size: expected size (None for any size)
234 # align: expected alignment (None for any alignment)
235 # signed: expected signedness (None for any signedness)
236 def _validate_integer(self
, integer
, size
=None, align
=None,
238 if type(integer
) is not pytsdl
.tsdl
.Integer
:
239 raise RuntimeError('expected integer')
242 if integer
.size
!= size
:
243 raise RuntimeError('expected {}-bit integer'.format(size
))
245 if align
is not None:
246 if integer
.align
!= align
:
247 raise RuntimeError('expected integer with {}-bit alignment'.format(align
))
249 if signed
is not None:
250 if integer
.signed
!= signed
:
251 raise RuntimeError('expected {} integer'.format('signed' if signed
else 'unsigned'))
253 # Validates a packet header.
255 # packet_header: packet header TSDL structure to validate
256 def _validate_tph(self
, packet_header
):
258 self
._validate
_inner
_struct
(packet_header
)
259 except RuntimeError as e
:
260 _perror('packet header: {}'.format(e
))
262 # magic must be the first field
263 if 'magic' in packet_header
.fields
:
264 if list(packet_header
.fields
.keys())[0] != 'magic':
265 _perror('packet header: "magic" must be the first field')
267 _perror('packet header: missing "magic" field')
269 # magic must be a 32-bit unsigned integer, 32-bit aligned
271 self
._validate
_integer
(packet_header
['magic'], 32, 32, False)
272 except RuntimeError as e
:
273 _perror('packet header: "magic": {}'.format(e
))
275 # mandatory stream_id
276 if 'stream_id' not in packet_header
.fields
:
277 _perror('packet header: missing "stream_id" field')
279 # stream_id must be an unsigned integer
281 self
._validate
_integer
(packet_header
['stream_id'], signed
=False)
282 except RuntimeError as e
:
283 _perror('packet header: "stream_id": {}'.format(e
))
285 # only magic and stream_id allowed
286 if len(packet_header
.fields
) != 2:
287 _perror('packet header: only "magic" and "stream_id" fields are allowed')
289 # Converts a list of strings to a dotted representation. For
290 # example, ['trace', 'packet', 'header', 'magic'] is converted to
291 # 'trace.packet.header.magic'.
293 # name: list of strings to convert
294 def _dot_name_to_str(self
, name
):
295 return '.'.join(name
)
297 # Compares two TSDL integers. Returns True if they are the same.
299 # int1: first TSDL integer
300 # int2: second TSDL integer
301 def _compare_integers(self
, int1
, int2
):
302 if type(int1
) is not pytsdl
.tsdl
.Integer
:
305 if type(int2
) is not pytsdl
.tsdl
.Integer
:
308 size
= int1
.size
== int2
.size
309 align
= int1
.align
== int2
.align
310 cmap
= int1
.map == int2
.map
311 base
= int1
.base
== int2
.base
312 encoding
= int1
.encoding
== int2
.encoding
313 signed
= int1
.signed
== int2
.signed
314 comps
= (size
, align
, cmap
, base
, encoding
, signed
)
316 # True means 1 for sum()
317 return sum(comps
) == len(comps
)
319 # Validates a packet context.
321 # stream: TSDL stream containing the packet context to validate
322 def _validate_spc(self
, stream
):
323 packet_context
= stream
.packet_context
327 self
._validate
_inner
_struct
(packet_context
)
328 except RuntimeError as e
:
329 _perror('stream {}: packet context: {}'.format(sid
, e
))
331 fields
= packet_context
.fields
333 # if timestamp_begin exists, timestamp_end must exist
334 if 'timestamp_begin' in fields
or 'timestamp_end' in fields
:
335 if 'timestamp_begin' not in fields
or 'timestamp_end' not in fields
:
336 _perror('stream {}: packet context: "timestamp_begin" must exist if "timestamp_end" exists'.format(sid
))
338 # timestamp_begin and timestamp_end must have the same integer
339 # as the event header's timestamp field (should exist by now)
340 timestamp
= stream
.event_header
['timestamp']
342 if not self
._compare
_integers
(fields
['timestamp_begin'], timestamp
):
343 _perror('stream {}: packet context: "timestamp_begin": integer type different from event header\'s "timestamp" field'.format(sid
))
345 if not self
._compare
_integers
(fields
['timestamp_end'], timestamp
):
346 _perror('stream {}: packet context: "timestamp_end": integer type different from event header\'s "timestamp" field'.format(sid
))
348 # content_size must exist and be an unsigned integer
349 if 'content_size' not in fields
:
350 _perror('stream {}: packet context: missing "content_size" field'.format(sid
))
353 self
._validate
_integer
(fields
['content_size'], 32, 32, False)
356 self
._validate
_integer
(fields
['content_size'], 64, 64, False)
358 _perror('stream {}: packet context: "content_size": expecting unsigned 32-bit/64-bit integer'.format(sid
))
360 # packet_size must exist and be an unsigned integer
361 if 'packet_size' not in fields
:
362 _perror('stream {}: packet context: missing "packet_size" field'.format(sid
))
365 self
._validate
_integer
(fields
['packet_size'], 32, 32, False)
368 self
._validate
_integer
(fields
['packet_size'], 64, 64, False)
370 _perror('stream {}: packet context: "packet_size": expecting unsigned 32-bit/64-bit integer'.format(sid
))
372 # if cpu_id exists, must be an unsigned integer
373 if 'cpu_id' in fields
:
375 self
._validate
_integer
(fields
['cpu_id'], signed
=False)
376 except RuntimeError as e
:
377 _perror('stream {}: packet context: "cpu_id": {}'.format(sid
, e
))
379 # Validates an event header.
381 # stream: TSDL stream containing the event header to validate
382 def _validate_seh(self
, stream
):
383 event_header
= stream
.event_header
387 self
._validate
_inner
_struct
(event_header
)
388 except RuntimeError as e
:
389 _perror('stream {}: event header: {}'.format(sid
, e
))
391 fields
= event_header
.fields
393 # id must exist and be an unsigned integer
394 if 'id' not in fields
:
395 _perror('stream {}: event header: missing "id" field'.format(sid
))
398 self
._validate
_integer
(fields
['id'], signed
=False)
399 except RuntimeError as e
:
400 _perror('stream {}: "id": {}'.format(sid
, format(e
)))
402 # timestamp must exist, be an unsigned integer and be mapped to a valid clock
403 if 'timestamp' not in fields
:
404 _perror('stream {}: event header: missing "timestamp" field'.format(sid
))
407 self
._validate
_integer
(fields
['timestamp'], signed
=False)
408 except RuntimeError as e
:
409 _perror('stream {}: event header: "timestamp": {}'.format(sid
, format(e
)))
411 if fields
['timestamp'].map is None:
412 _perror('stream {}: event header: "timestamp" must be mapped to a valid clock'.format(sid
))
414 # id must be the first field, followed by timestamp
415 if list(fields
.keys())[0] != 'id':
416 _perror('stream {}: event header: "id" must be the first field'.format(sid
))
418 if list(fields
.keys())[1] != 'timestamp':
419 _perror('stream {}: event header: "timestamp" must be the second field'.format(sid
))
421 # only id and timestamp and allowed in event header
423 _perror('stream {}: event header: only "id" and "timestamp" fields are allowed'.format(sid
))
425 # Validates a strean event context.
427 # stream: TSDL stream containing the stream event context
428 def _validate_sec(self
, stream
):
429 stream_event_context
= stream
.event_context
432 if stream_event_context
is None:
436 self
._validate
_context
_fields
(stream_event_context
)
437 except RuntimeError as e
:
438 _perror('stream {}: event context: {}'.format(sid
, e
))
440 # Validates an event context.
442 # stream: TSDL stream containing the TSDL event
443 # event: TSDL event containing the context to validate
444 def _validate_ec(self
, stream
, event
):
445 event_context
= event
.context
449 if event_context
is None:
453 self
._validate
_context
_fields
(event_context
)
454 except RuntimeError as e
:
455 _perror('stream {}: event {}: context: {}'.format(sid
, eid
, e
))
457 # Validates an event fields.
459 # stream: TSDL stream containing the TSDL event
460 # event: TSDL event containing the fields to validate
461 def _validate_ef(self
, stream
, event
):
462 event_fields
= event
.fields
467 self
._validate
_context
_fields
(event_fields
)
468 except RuntimeError as e
:
469 _perror('stream {}: event {}: fields: {}'.format(sid
, eid
, e
))
471 # Validates a TSDL event.
473 # stream: TSDL stream containing the TSDL event
474 # event: TSDL event to validate
475 def _validate_event(self
, stream
, event
):
476 # name must be a compatible C identifier
477 if not re
.match(r
'^[a-zA-Z_][a-zA-Z0-9_]*$', event
.name
):
478 fmt
= 'stream {}: event {}: malformed event name: "{}"'
479 _perror(fmt
.format(stream
.id, event
.id, event
.name
))
481 self
._validate
_ec
(stream
, event
)
482 self
._validate
_ef
(stream
, event
)
484 # Validates a TSDL stream.
486 # stream: TSDL stream to validate
487 def _validate_stream(self
, stream
):
488 self
._validate
_seh
(stream
)
489 self
._validate
_spc
(stream
)
490 self
._validate
_sec
(stream
)
493 for event
in stream
.events
:
494 self
._validate
_event
(stream
, event
)
496 # Validates all TSDL scopes of the current TSDL document.
497 def _validate_all_scopes(self
):
499 self
._validate
_tph
(self
._doc
.trace
.packet_header
)
502 for stream
in self
._doc
.streams
.values():
503 self
._validate
_stream
(stream
)
505 # Validates the trace block.
506 def _validate_trace(self
):
507 # make sure a native byte order is specified
508 if self
._doc
.trace
.byte_order
is None:
509 _perror('native byte order (trace.byte_order) is not specified')
511 # Validates the current TSDL document.
512 def _validate_metadata(self
):
513 self
._validate
_trace
()
514 self
._validate
_all
_scopes
()
516 # Returns an aligned number.
526 # at: number to align
527 # align: alignment (power of two)
528 def _get_alignment(self
, at
, align
):
529 return (at
+ align
- 1) & -align
531 # Converts a tree of offset variables:
546 # field_other_struct_field -> 16
547 # field_other_struct_yeah -> 20
551 # offvars_tree: tree of offset variables
552 # prefix: offset variable name prefix
553 # offvars: flattened offset variables
554 def _flatten_offvars_tree(self
, offvars_tree
, prefix
=None,
557 offvars
= collections
.OrderedDict()
559 for name
, offset
in offvars_tree
.items():
560 if prefix
is not None:
561 varname
= '{}_{}'.format(prefix
, name
)
565 if isinstance(offset
, dict):
566 self
._flatten
_offvars
_tree
(offset
, varname
, offvars
)
568 offvars
[varname
] = offset
572 # Returns the size of a TSDL structure with _static size_ (must be
575 # struct: TSDL structure of which to get the size
576 # offvars_tree: optional offset variables tree (output)
577 # base_offset: base offsets for offset variables
578 def _get_struct_size(self
, struct
,
581 if offvars_tree
is None:
582 offvars_tree
= collections
.OrderedDict()
586 for fname
, ftype
in struct
.fields
.items():
587 field_alignment
= self
._get
_obj
_alignment
(ftype
)
588 offset
= self
._get
_alignment
(offset
, field_alignment
)
590 if type(ftype
) is pytsdl
.tsdl
.Struct
:
591 offvars_tree
[fname
] = collections
.OrderedDict()
592 sz
= self
._get
_struct
_size
(ftype
, offvars_tree
[fname
],
593 base_offset
+ offset
)
595 # only integers may act as sequence lengths
596 if type(ftype
) is pytsdl
.tsdl
.Integer
:
597 offvars_tree
[fname
] = base_offset
+ offset
599 sz
= self
._get
_obj
_size
(ftype
)
605 # Returns the size of a TSDL array.
607 # array: TSDL array of which to get the size
608 def _get_array_size(self
, array
):
609 element
= array
.element
611 # effective size of one element includes its alignment after its size
612 size
= self
._get
_obj
_size
(element
)
613 align
= self
._get
_obj
_alignment
(element
)
615 return self
._get
_alignment
(size
, align
) * array
.length
617 # Returns the size of a TSDL enumeration.
619 # enum: TSDL enumeration of which to get the size
620 def _get_enum_size(self
, enum
):
621 return self
._get
_obj
_size
(enum
.integer
)
623 # Returns the size of a TSDL floating point number.
625 # floating_point: TSDL floating point number of which to get the size
626 def _get_floating_point_size(self
, floating_point
):
627 return floating_point
.exp_dig
+ floating_point
.mant_dig
629 # Returns the size of a TSDL integer.
631 # integer: TSDL integer of which to get the size
632 def _get_integer_size(self
, integer
):
635 # Returns the size of a TSDL type.
637 # obj: TSDL type of which to get the size
638 def _get_obj_size(self
, obj
):
639 return self
._obj
_size
_cb
[type(obj
)](obj
)
641 # Returns the alignment of a TSDL structure.
643 # struct: TSDL structure of which to get the alignment
644 def _get_struct_alignment(self
, struct
):
645 if struct
.align
is not None:
650 for fname
, ftype
in struct
.fields
.items():
651 cur_align
= max(self
._get
_obj
_alignment
(ftype
), cur_align
)
655 # Returns the alignment of a TSDL integer.
657 # integer: TSDL integer of which to get the alignment
658 def _get_integer_alignment(self
, integer
):
661 # Returns the alignment of a TSDL floating point number.
663 # floating_point: TSDL floating point number of which to get the
665 def _get_floating_point_alignment(self
, floating_point
):
666 return floating_point
.align
668 # Returns the alignment of a TSDL enumeration.
670 # enum: TSDL enumeration of which to get the alignment
671 def _get_enum_alignment(self
, enum
):
672 return self
._get
_obj
_alignment
(enum
.integer
)
674 # Returns the alignment of a TSDL string.
676 # string: TSDL string of which to get the alignment
677 def _get_string_alignment(self
, string
):
680 # Returns the alignment of a TSDL array.
682 # array: TSDL array of which to get the alignment
683 def _get_array_alignment(self
, array
):
684 return self
._get
_obj
_alignment
(array
.element
)
686 # Returns the alignment of a TSDL sequence.
688 # sequence: TSDL sequence of which to get the alignment
689 def _get_sequence_alignment(self
, sequence
):
690 return self
._get
_obj
_alignment
(sequence
.element
)
692 # Returns the alignment of a TSDL type.
694 # obj: TSDL type of which to get the alignment
695 def _get_obj_alignment(self
, obj
):
696 return self
._obj
_alignment
_cb
[type(obj
)](obj
)
698 # Converts a field name to a C parameter name.
700 # You should not use this function directly, but rather use one
701 # of the _*_fname_to_pname() variants depending on your scope.
703 # prefix: parameter name prefix
705 def _fname_to_pname(self
, prefix
, fname
):
706 return 'param_{}_{}'.format(prefix
, fname
)
708 # Converts an event fields field name to a C parameter name.
711 def _ef_fname_to_pname(self
, fname
):
712 return self
._fname
_to
_pname
('ef', fname
)
714 # Converts an event context field name to a C parameter name.
717 def _ec_fname_to_pname(self
, fname
):
718 return self
._fname
_to
_pname
('ec', fname
)
720 # Converts a stream event context field name to a C parameter name.
723 def _sec_fname_to_pname(self
, fname
):
724 return self
._fname
_to
_pname
('sec', fname
)
726 # Converts an event header field name to a C parameter name.
729 def _eh_fname_to_pname(self
, fname
):
730 return self
._fname
_to
_pname
('eh', fname
)
732 # Converts a stream packet context field name to a C parameter name.
735 def _spc_fname_to_pname(self
, fname
):
736 return self
._fname
_to
_pname
('spc', fname
)
738 # Converts a trace packet header field name to a C parameter name.
741 def _tph_fname_to_pname(self
, fname
):
742 return self
._fname
_to
_pname
('tph', fname
)
744 # Returns the equivalent C type of a TSDL integer.
746 # integer: TSDL integer of which to get the equivalent C type
747 def _get_integer_param_ctype(self
, integer
):
748 signed
= 'u' if not integer
.signed
else ''
750 if integer
.size
== 8:
752 elif integer
.size
== 16:
754 elif integer
.size
== 32:
756 elif integer
.size
== 64:
759 # if the integer is signed and of uncommon size, the sign bit is
760 # at a custom position anyway so we use a 64-bit unsigned
766 if integer
.size
< 16:
768 elif integer
.size
< 32:
770 elif integer
.size
< 64:
775 return '{}int{}_t'.format(signed
, sz
)
777 # Returns the equivalent C type of a TSDL enumeration.
779 # enum: TSDL enumeration of which to get the equivalent C type
780 def _get_enum_param_ctype(self
, enum
):
781 return self
._get
_obj
_param
_ctype
(enum
.integer
)
783 # Returns the equivalent C type of a TSDL floating point number.
785 # fp: TSDL floating point number of which to get the equivalent C type
786 def _get_floating_point_param_ctype(self
, fp
):
787 if fp
.exp_dig
== 8 and fp
.mant_dig
== 24 and fp
.align
== 32:
789 elif fp
.exp_dig
== 11 and fp
.mant_dig
== 53 and fp
.align
== 64:
794 # Returns the equivalent C type of a TSDL type.
796 # obj: TSDL type of which to get the equivalent C type
797 def _get_obj_param_ctype(self
, obj
):
798 return self
._obj
_param
_ctype
_cb
[type(obj
)](obj
)
800 # Returns the check offset overflow macro call string for a given size.
802 # size: size to check
803 def _get_chk_offset_v(self
, size
):
804 fmt
= '{}_CHK_OFFSET_V({}, {}, {});'
805 ret
= fmt
.format(self
._prefix
.upper(), self
._CTX
_AT
,
806 self
._CTX
_PACKET
_SIZE
, size
)
810 # Returns the check offset overflow macro call C line for a given size.
812 # size: size to check
813 def _get_chk_offset_v_cline(self
, size
):
814 return _CLine(self
._get
_chk
_offset
_v
(size
))
816 # Returns the offset alignment macro call string for a given alignment.
818 # size: new alignment
819 def _get_align_offset(self
, align
, at
=None):
823 fmt
= '{}_ALIGN_OFFSET({}, {});'
824 ret
= fmt
.format(self
._prefix
.upper(), at
, align
)
828 # Returns the offset alignment macro call C line for a given alignment.
830 # size: new alignment
831 def _get_align_offset_cline(self
, size
):
832 return _CLine(self
._get
_align
_offset
(size
))
834 # Converts a C source string with newlines to an array of C lines and
838 def _str_to_clines(self
, s
):
839 lines
= s
.split('\n')
841 return [_CLine(line
) for line
in lines
]
843 # Fills a given template with values and returns its C lines. The `prefix`
844 # and `ucprefix` template variable are automatically provided using the
845 # generator's context.
848 # kwargs: additional template variable values
849 def _template_to_clines(self
, tmpl
, **kwargs
):
850 s
= tmpl
.format(prefix
=self
._prefix
, ucprefix
=self
._prefix
.upper(),
853 return self
._str
_to
_clines
(s
)
855 # Returns the C lines for writing a TSDL structure field.
858 # src_name: C source pointer
859 # struct: TSDL structure
860 def _write_field_struct(self
, fname
, src_name
, struct
, scope_prefix
=None):
861 size
= self
._get
_struct
_size
(struct
)
862 size_bytes
= self
._get
_alignment
(size
, 8) // 8
863 dst
= self
._CTX
_BUF
_AT
_ADDR
866 # memcpy() is safe since barectf requires inner structures
868 self
._get
_chk
_offset
_v
_cline
(size
),
869 _CLine('memcpy({}, {}, {});'.format(dst
, src_name
, size_bytes
)),
870 _CLine('{} += {};'.format(self
._CTX
_AT
, size
)),
873 # Returns the C lines for writing a TSDL integer field.
876 # src_name: C source integer
877 # integer: TSDL integer
878 def _write_field_integer(self
, fname
, src_name
, integer
, scope_prefix
=None):
879 bo
= self
._BO
_SUFFIXES
_MAP
[integer
.byte_order
]
880 t
= self
._get
_obj
_param
_ctype
(integer
)
881 length
= self
._get
_obj
_size
(integer
)
883 return self
._template
_to
_clines
(barectf
.templates
.WRITE_INTEGER
,
884 sz
=length
, bo
=bo
, type=t
,
887 # Returns the C lines for writing a TSDL enumeration field.
890 # src_name: C source integer
891 # enum: TSDL enumeration
892 def _write_field_enum(self
, fname
, src_name
, enum
, scope_prefix
=None):
893 return self
._write
_field
_obj
(fname
, src_name
, enum
.integer
)
895 # Returns the C lines for writing a TSDL floating point number field.
898 # src_name: C source pointer
899 # floating_point: TSDL floating point number
900 def _write_field_floating_point(self
, fname
, src_name
, floating_point
,
902 bo
= self
._BO
_SUFFIXES
_MAP
[floating_point
.byte_order
]
903 t
= self
._get
_obj
_param
_ctype
(floating_point
)
904 length
= self
._get
_obj
_size
(floating_point
)
911 src_name_casted
= '({}) {}'.format(t
, src_name
)
913 return self
._template
_to
_clines
(barectf
.templates
.WRITE_INTEGER
,
914 sz
=length
, bo
=bo
, type=t
,
915 src_name
=src_name_casted
)
917 # Returns the C lines for writing either a TSDL array field or a
918 # TSDL sequence field.
921 # src_name: C source pointer
922 # arrayseq: TSDL array or sequence
923 # scope_prefix: preferred scope prefix
924 def _write_field_array_sequence(self
, fname
, src_name
, arrayseq
,
926 def length_index_varname(index
):
927 return 'lens_{}_{}'.format(fname
, index
)
929 # first pass: find all lengths to multiply
934 mulops
.append(arrayseq
.length
)
935 element
= arrayseq
.element
938 if tel
is pytsdl
.tsdl
.Array
or tel
is pytsdl
.tsdl
.Sequence
:
939 # another array/sequence; continue
946 # align the size of the repeating element (effective repeating size)
947 el_size
= self
._get
_obj
_size
(element
)
948 el_align
= self
._get
_obj
_alignment
(element
)
949 el_size
= self
._get
_alignment
(el_size
, el_align
)
951 # this effective size is part of the operands to multiply
952 mulops
.append(el_size
)
957 # fetch and save sequence lengths
960 for i
in range(len(mulops
)):
963 if type(mulop
) is list:
964 # offset variable to fetch
965 offvar
= self
._get
_seq
_length
_src
_name
(mulop
, scope_prefix
)
967 if type(offvar
) is int:
968 # environment constant
969 emulops
.append(str(offvar
))
972 # save buffer position
973 line
= 'ctx_at_bkup = {};'.format(self
._CTX
_AT
)
974 clines
.append(_CLine(line
))
976 # go back to field offset
977 line
= '{} = {};'.format(self
._CTX
_AT
, offvar
)
978 clines
.append(_CLine(line
))
980 # read value into specific variable
981 varname
= length_index_varname(i
)
982 emulops
.append(varname
)
983 varctype
= 'uint32_t'
984 fmt
= '{ctype} {cname} = *(({ctype}*) ({ctxbufataddr}));'
985 line
= fmt
.format(ctype
=varctype
, cname
=varname
,
986 ctxbufataddr
=self
._CTX
_BUF
_AT
_ADDR
)
987 clines
.append(_CLine(line
))
989 # restore buffer position
990 line
= '{} = ctx_at_bkup;'.format(self
._CTX
_AT
)
991 clines
.append(_CLine(line
))
993 emulops
.append(str(mulop
))
995 # write product of sizes in bits
996 mul
= ' * '.join(emulops
)
997 sz_bits_varname
= 'sz_bits_{}'.format(fname
)
998 sz_bytes_varname
= 'sz_bytes_{}'.format(fname
)
999 line
= 'uint32_t {} = {};'.format(sz_bits_varname
, mul
)
1000 clines
.append(_CLine(line
))
1003 clines
.append(self
._get
_chk
_offset
_v
_cline
(sz_bits_varname
))
1005 # write product of sizes in bytes
1006 line
= 'uint32_t {} = {};'.format(sz_bytes_varname
, sz_bits_varname
)
1007 clines
.append(_CLine(line
))
1008 line
= self
._get
_align
_offset
(8, at
=sz_bytes_varname
)
1009 clines
.append(_CLine(line
))
1010 line
= '{} >>= 3;'.format(sz_bytes_varname
)
1011 clines
.append(_CLine(line
))
1014 dst
= self
._CTX
_BUF
_AT
_ADDR
1015 line
= 'memcpy({}, {}, {});'.format(dst
, src_name
, sz_bytes_varname
)
1016 clines
.append(_CLine(line
))
1017 line
= '{} += {};'.format(self
._CTX
_AT
, sz_bits_varname
)
1018 clines
.append(_CLine(line
))
1022 # Returns the C lines for writing a TSDL array field.
1025 # src_name: C source pointer
1027 # scope_prefix: preferred scope prefix
1028 def _write_field_array(self
, fname
, src_name
, array
, scope_prefix
=None):
1029 return self
._write
_field
_array
_sequence
(fname
, src_name
, array
,
1032 # Returns the C lines for writing a TSDL sequence field.
1035 # src_name: C source pointer
1036 # sequence: TSDL sequence
1037 # scope_prefix: preferred scope prefix
1038 def _write_field_sequence(self
, fname
, src_name
, sequence
, scope_prefix
):
1039 return self
._write
_field
_array
_sequence
(fname
, src_name
, sequence
,
1042 # Returns a trace packet header C source name out of a sequence length
1045 # length: sequence length expression
1046 def _get_tph_src_name(self
, length
):
1047 offvar
= self
._get
_offvar
_name
_from
_expr
(length
[3:], 'tph')
1049 return 'ctx->{}'.format(offvar
)
1051 # Returns an environment C source name out of a sequence length
1054 # length: sequence length expression
1055 def _get_env_src_name(self
, length
):
1056 if len(length
) != 2:
1057 _perror('invalid sequence length: "{}"'.format(self
._dot
_name
_to
_str
(length
)))
1061 if fname
not in self
._doc
.env
:
1062 _perror('cannot find field env.{}'.format(fname
))
1064 env_length
= self
._doc
.env
[fname
]
1066 if type(env_length
) is not int:
1067 _perror('env.{} is not a constant integer'.format(fname
))
1069 return self
._doc
.env
[fname
]
1071 # Returns a stream packet context C source name out of a sequence length
1074 # length: sequence length expression
1075 def _get_spc_src_name(self
, length
):
1076 offvar
= self
._get
_offvar
_name
_from
_expr
(length
[3:], 'spc')
1078 return 'ctx->{}'.format(offvar
)
1080 # Returns a stream event header C source name out of a sequence length
1083 # length: sequence length expression
1084 def _get_seh_src_name(self
, length
):
1085 return self
._get
_offvar
_name
_from
_expr
(length
[3:], 'seh')
1087 # Returns a stream event context C source name out of a sequence length
1090 # length: sequence length expression
1091 def _get_sec_src_name(self
, length
):
1092 return self
._get
_offvar
_name
_from
_expr
(length
[3:], 'sec')
1094 # Returns an event context C source name out of a sequence length
1097 # length: sequence length expression
1098 def _get_ec_src_name(self
, length
):
1099 return self
._get
_offvar
_name
_from
_expr
(length
[2:], 'ec')
1101 # Returns an event fields C source name out of a sequence length
1104 # length: sequence length expression
1105 def _get_ef_src_name(self
, length
):
1106 return self
._get
_offvar
_name
_from
_expr
(length
[2:], 'ef')
1108 # Returns a C source name out of a sequence length expression.
1110 # length: sequence length expression
1111 # scope_prefix: preferred scope prefix
1112 def _get_seq_length_src_name(self
, length
, scope_prefix
=None):
1113 length_dot
= self
._dot
_name
_to
_str
(length
)
1115 for prefix
, get_src_name
in self
._get
_src
_name
_funcs
.items():
1116 if length_dot
.startswith(prefix
):
1117 return get_src_name(length
)
1119 return self
._get
_offvar
_name
_from
_expr
(length
, scope_prefix
)
1121 # Returns the C lines for writing a TSDL string field.
1124 # src_name: C source pointer
1125 # string: TSDL string
1126 def _write_field_string(self
, fname
, src_name
, string
, scope_prefix
=None):
1130 sz_bytes_varname
= 'slen_bytes_{}'.format(fname
)
1131 line
= 'size_t {} = strlen({}) + 1;'.format(sz_bytes_varname
, src_name
)
1132 clines
.append(_CLine(line
))
1134 # check offset overflow
1135 sz_bits_varname
= 'slen_bits_{}'.format(fname
)
1136 line
= 'size_t {} = ({} << 3);'.format(sz_bits_varname
,
1138 clines
.append(_CLine(line
))
1139 cline
= self
._get
_chk
_offset
_v
_cline
(sz_bits_varname
)
1140 clines
.append(cline
)
1143 dst
= self
._CTX
_BUF
_AT
_ADDR
1144 line
= 'memcpy({}, {}, {});'.format(dst
, src_name
, sz_bytes_varname
)
1145 clines
.append(_CLine(line
))
1147 # update bit position
1148 line
= '{} += {};'.format(self
._CTX
_AT
, sz_bits_varname
)
1149 clines
.append(_CLine(line
))
1153 # Returns the C lines for writing a TSDL type field.
1156 # src_name: C source pointer
1158 # scope_prefix: preferred scope prefix
1159 def _write_field_obj(self
, fname
, src_name
, ftype
, scope_prefix
):
1160 return self
._write
_field
_obj
_cb
[type(ftype
)](fname
, src_name
, ftype
,
1163 # Returns an offset variable name out of an offset name.
1166 # prefix: offset variable name prefix
1167 def _get_offvar_name(self
, name
, prefix
=None):
1170 if prefix
is not None:
1171 parts
.append(prefix
)
1175 return '_'.join(parts
)
1177 # Returns an offset variable name out of an expression (array of
1180 # expr: array of strings
1181 # prefix: offset variable name prefix
1182 def _get_offvar_name_from_expr(self
, expr
, prefix
=None):
1183 return self
._get
_offvar
_name
('_'.join(expr
), prefix
)
1185 # Returns the C lines for writing a TSDL field.
1188 # ftype: TSDL field type
1189 # scope_name: scope name
1190 # scope_prefix: preferred scope prefix
1191 # param_name_cb: callback to get the C parameter name out of the
1193 def _field_to_clines(self
, fname
, ftype
, scope_name
, scope_prefix
,
1196 pname
= param_name_cb(fname
)
1197 align
= self
._get
_obj
_alignment
(ftype
)
1200 fmt
= '/* write {}.{} ({}) */'
1201 line
= fmt
.format(scope_name
, fname
,
1202 self
._TSDL
_TYPE
_NAMES
_MAP
[type(ftype
)])
1203 clines
.append(_CLine(line
))
1205 # align bit index before writing to the buffer
1206 cline
= self
._get
_align
_offset
_cline
(align
)
1207 clines
.append(cline
)
1209 # write offset variables
1210 if type(ftype
) is pytsdl
.tsdl
.Struct
:
1211 offvars_tree
= collections
.OrderedDict()
1212 self
._get
_struct
_size
(ftype
, offvars_tree
)
1213 offvars
= self
._flatten
_offvars
_tree
(offvars_tree
)
1215 # as many offset as there are child fields because a future
1216 # sequence could refer to any of those fields
1217 for lname
, offset
in offvars
.items():
1218 offvar
= self
._get
_offvar
_name
('_'.join([fname
, lname
]),
1220 fmt
= 'uint32_t {} = (uint32_t) {} + {};'
1221 line
= fmt
.format(offvar
, self
._CTX
_AT
, offset
);
1222 clines
.append(_CLine(line
))
1223 elif type(ftype
) is pytsdl
.tsdl
.Integer
:
1224 # offset of this simple field is the current bit index
1225 offvar
= self
._get
_offvar
_name
(fname
, scope_prefix
)
1226 line
= 'uint32_t {} = (uint32_t) {};'.format(offvar
, self
._CTX
_AT
)
1227 clines
.append(_CLine(line
))
1229 clines
+= self
._write
_field
_obj
(fname
, pname
, ftype
, scope_prefix
)
1233 # Joins C line groups and returns C lines.
1235 # cline_groups: C line groups to join
1236 def _join_cline_groups(self
, cline_groups
):
1237 if not cline_groups
:
1240 output_clines
= cline_groups
[0]
1242 for clines
in cline_groups
[1:]:
1243 output_clines
.append('')
1244 output_clines
+= clines
1246 return output_clines
1248 # Returns the C lines for writing a complete TSDL structure (top level
1251 # struct: TSDL structure
1252 # scope_name: scope name
1253 # scope_prefix: preferred scope prefix
1254 # param_name_cb: callback to get the C parameter name out of the
1256 def _struct_to_clines(self
, struct
, scope_name
, scope_prefix
,
1260 for fname
, ftype
in struct
.fields
.items():
1261 clines
= self
._field
_to
_clines
(fname
, ftype
, scope_name
,
1262 scope_prefix
, param_name_cb
)
1263 cline_groups
.append(clines
)
1265 return self
._join
_cline
_groups
(cline_groups
)
1267 # Returns the offset variables of a TSDL structure.
1269 # struct: TSDL structure
1270 def _get_struct_size_offvars(self
, struct
):
1271 offvars_tree
= collections
.OrderedDict()
1272 size
= self
._get
_struct
_size
(struct
, offvars_tree
)
1273 offvars
= self
._flatten
_offvars
_tree
(offvars_tree
)
1275 return size
, offvars
1277 # Returns the size and offset variables of the current trace packet header.
1278 def _get_tph_size_offvars(self
):
1279 return self
._get
_struct
_size
_offvars
(self
._doc
.trace
.packet_header
)
1281 # Returns the size and offset variables of the a stream packet context.
1283 # stream: TSDL stream
1284 def _get_spc_size_offvars(self
, stream
):
1285 return self
._get
_struct
_size
_offvars
(stream
.packet_context
)
1287 # Returns the C lines for the barectf context C structure entries for
1290 # prefix: offset variable names prefix
1291 # offvars: offset variables
1292 def _offvars_to_ctx_clines(self
, prefix
, offvars
):
1295 for name
in offvars
.keys():
1296 offvar
= self
._get
_offvar
_name
(name
, prefix
)
1297 clines
.append(_CLine('uint32_t {};'.format(offvar
)))
1301 # Generates a barectf context C structure.
1303 # stream: TSDL stream
1304 # hide_sid: True to hide the stream ID
1305 def _gen_barectf_ctx_struct(self
, stream
, hide_sid
=False):
1306 # get offset variables for both the packet header and packet context
1307 tph_size
, tph_offvars
= self
._get
_tph
_size
_offvars
()
1308 spc_size
, spc_offvars
= self
._get
_spc
_size
_offvars
(stream
)
1309 clines
= self
._offvars
_to
_ctx
_clines
('tph', tph_offvars
)
1310 clines
+= self
._offvars
_to
_ctx
_clines
('spc', spc_offvars
)
1313 clines_indented
= []
1314 for cline
in clines
:
1315 clines_indented
.append(_CLine('\t' + cline
))
1318 clock_cb
= '\t/* (no clock callback) */'
1320 if not self
._manual
_clock
:
1321 ctype
= self
._get
_clock
_ctype
(stream
)
1322 fmt
= '\t{} (*clock_cb)(void*);\n\tvoid* clock_cb_data;'
1323 clock_cb
= fmt
.format(ctype
)
1331 t
= barectf
.templates
.BARECTF_CTX
1332 struct
= t
.format(prefix
=self
._prefix
, sid
=sid
,
1333 ctx_fields
='\n'.join(clines_indented
),
1338 # Generates all barectf context C structures.
1339 def _gen_barectf_contexts_struct(self
):
1342 if len(self
._doc
.streams
) == 1:
1347 for stream
in self
._doc
.streams
.values():
1348 struct
= self
._gen
_barectf
_ctx
_struct
(stream
, hide_sid
)
1349 structs
.append(struct
)
1351 return '\n\n'.join(structs
)
1353 # Returns the C type of the clock used by the event header of a
1356 # stream: TSDL stream containing the event header to inspect
1357 def _get_clock_ctype(self
, stream
):
1358 return self
._get
_obj
_param
_ctype
(stream
.event_header
['timestamp'])
1360 # Generates the manual clock value C parameter for a given stream.
1362 # stream: TSDL stream
1363 def _gen_manual_clock_param(self
, stream
):
1364 return '{} param_clock'.format(self
._get
_clock
_ctype
(stream
))
1366 # Generates the body of a barectf_open() function.
1368 # stream: TSDL stream
1369 def _gen_barectf_func_open_body(self
, stream
):
1372 # keep clock value (for timestamp_begin)
1373 if self
._stream
_has
_timestamp
_begin
_end
(stream
):
1374 # get clock value ASAP
1375 clk_type
= self
._get
_clock
_ctype
(stream
)
1376 clk
= self
._gen
_get
_clock
_value
()
1377 line
= '{} clk_value = {};'.format(clk_type
, clk
)
1378 clines
.append(_CLine(line
))
1379 clines
.append(_CLine(''))
1381 # packet context fields
1383 scope_name
= 'stream.packet.context'
1384 scope_prefix
= 'spc'
1386 for fname
, ftype
in stream
.packet_context
.fields
.items():
1388 if fname
== 'packet_size':
1389 fclines
= self
._field
_to
_clines
(fname
, ftype
, scope_name
,
1391 lambda x
: 'ctx->packet_size')
1392 fcline_groups
.append(fclines
)
1394 # content size (skip)
1395 elif fname
== 'content_size':
1396 fclines
= self
._field
_to
_clines
(fname
, ftype
, scope_name
,
1397 scope_prefix
, lambda x
: '0')
1398 fcline_groups
.append(fclines
)
1401 elif fname
== 'timestamp_begin':
1402 fclines
= self
._field
_to
_clines
(fname
, ftype
, scope_name
,
1404 lambda x
: 'clk_value')
1405 fcline_groups
.append(fclines
)
1407 # timestamp_end (skip)
1408 elif fname
== 'timestamp_end':
1409 fclines
= self
._field
_to
_clines
(fname
, ftype
, scope_name
,
1410 scope_prefix
, lambda x
: '0')
1411 fcline_groups
.append(fclines
)
1415 fclines
= self
._field
_to
_clines
(fname
, ftype
, scope_name
,
1417 self
._spc
_fname
_to
_pname
)
1418 fcline_groups
.append(fclines
)
1421 fcline_groups
.append([_CLine('return 0;')])
1423 clines
+= self
._join
_cline
_groups
(fcline_groups
)
1426 cblock
= _CBlock(clines
)
1427 src
= self
._cblock
_to
_source
(cblock
)
1431 _SPC_KNOWN_FIELDS
= [
1438 # Generates a barectf_open() function.
1440 # stream: TSDL stream
1441 # gen_body: also generate function body
1442 # hide_sid: True to hide the stream ID
1443 def _gen_barectf_func_open(self
, stream
, gen_body
, hide_sid
=False):
1447 if self
._manual
_clock
:
1448 clock_param
= self
._gen
_manual
_clock
_param
(stream
)
1449 params
.append(clock_param
)
1452 for fname
, ftype
in stream
.packet_context
.fields
.items():
1453 if fname
in self
._SPC
_KNOWN
_FIELDS
:
1456 ptype
= self
._get
_obj
_param
_ctype
(ftype
)
1457 pname
= self
._spc
_fname
_to
_pname
(fname
)
1458 param
= '{} {}'.format(ptype
, pname
)
1459 params
.append(param
)
1464 params_str
= ',\n\t'.join([''] + params
)
1472 t
= barectf
.templates
.FUNC_OPEN
1473 func
= t
.format(si
=self
._si
_str
, prefix
=self
._prefix
, sid
=sid
,
1478 func
+= self
._gen
_barectf
_func
_open
_body
(stream
)
1485 # Generates the body of a barectf_init() function.
1487 # stream: TSDL stream
1488 def _gen_barectf_func_init_body(self
, stream
):
1491 line
= 'uint32_t ctx_at_bkup;'
1492 clines
.append(_CLine(line
))
1494 # set context parameters
1495 clines
.append(_CLine(''))
1496 clines
.append(_CLine("/* barectf context parameters */"))
1497 clines
.append(_CLine('ctx->buf = buf;'))
1498 clines
.append(_CLine('ctx->packet_size = buf_size * 8;'))
1499 clines
.append(_CLine('{} = 0;'.format(self
._CTX
_AT
)))
1501 if not self
._manual
_clock
:
1502 clines
.append(_CLine('ctx->clock_cb = clock_cb;'))
1503 clines
.append(_CLine('ctx->clock_cb_data = clock_cb_data;'))
1505 # set context offsets
1506 clines
.append(_CLine(''))
1507 clines
.append(_CLine("/* barectf context offsets */"))
1508 ph_size
, ph_offvars
= self
._get
_tph
_size
_offvars
()
1509 pc_size
, pc_offvars
= self
._get
_spc
_size
_offvars
(stream
)
1510 pc_alignment
= self
._get
_obj
_alignment
(stream
.packet_context
)
1511 pc_offset
= self
._get
_alignment
(ph_size
, pc_alignment
)
1513 for offvar
, offset
in ph_offvars
.items():
1514 offvar_field
= self
._get
_offvar
_name
(offvar
, 'tph')
1515 line
= 'ctx->{} = {};'.format(offvar_field
, offset
)
1516 clines
.append(_CLine(line
))
1518 for offvar
, offset
in pc_offvars
.items():
1519 offvar_field
= self
._get
_offvar
_name
(offvar
, 'spc')
1520 line
= 'ctx->{} = {};'.format(offvar_field
, pc_offset
+ offset
)
1521 clines
.append(_CLine(line
))
1523 clines
.append(_CLine(''))
1525 # packet header fields
1527 scope_name
= 'trace.packet.header'
1528 scope_prefix
= 'tph'
1530 for fname
, ftype
in self
._doc
.trace
.packet_header
.fields
.items():
1532 if fname
== 'magic':
1533 fclines
= self
._field
_to
_clines
(fname
, ftype
, scope_name
,
1535 lambda x
: '0xc1fc1fc1UL')
1536 fcline_groups
.append(fclines
)
1539 elif fname
== 'stream_id':
1540 fclines
= self
._field
_to
_clines
(fname
, ftype
, scope_name
,
1542 lambda x
: str(stream
.id))
1543 fcline_groups
.append(fclines
)
1546 fcline_groups
.append([_CLine('return 0;')])
1548 clines
+= self
._join
_cline
_groups
(fcline_groups
)
1551 cblock
= _CBlock(clines
)
1552 src
= self
._cblock
_to
_source
(cblock
)
1556 # Generates a barectf_init() function.
1558 # stream: TSDL stream
1559 # gen_body: also generate function body
1560 # hide_sid: True to hide the stream ID
1561 def _gen_barectf_func_init(self
, stream
, gen_body
, hide_sid
=False):
1570 if not self
._manual
_clock
:
1571 ts_ftype
= stream
.event_header
['timestamp']
1572 ts_ptype
= self
._get
_obj
_param
_ctype
(ts_ftype
)
1573 fmt
= ',\n\t{} (*clock_cb)(void*),\n\tvoid* clock_cb_data'
1574 params
= fmt
.format(ts_ptype
)
1576 t
= barectf
.templates
.FUNC_INIT
1577 func
= t
.format(si
=self
._si
_str
, prefix
=self
._prefix
, sid
=sid
,
1582 func
+= self
._gen
_barectf
_func
_init
_body
(stream
)
1589 # Generates the C expression to get the clock value depending on
1590 # whether we're in manual clock mode or not.
1591 def _gen_get_clock_value(self
):
1592 if self
._manual
_clock
:
1593 return 'param_clock'
1595 return self
._CTX
_CALL
_CLOCK
_CB
1597 # Returns True if the given TSDL stream has timestamp_begin and
1598 # timestamp_end fields.
1600 # stream: TSDL stream to check
1601 def _stream_has_timestamp_begin_end(self
, stream
):
1602 return self
._has
_timestamp
_begin
_end
[stream
.id]
1604 # Generates the C lines to write a barectf context field, saving
1605 # and restoring the current bit position accordingly.
1607 # src_name: C source name
1608 # prefix: offset variable prefix
1609 # name: offset variable name
1610 # integer: TSDL integer to write
1611 def _gen_write_ctx_field_integer(self
, src_name
, prefix
, name
, integer
):
1614 # save buffer position
1615 line
= 'ctx_at_bkup = {};'.format(self
._CTX
_AT
)
1616 clines
.append(_CLine(line
))
1618 # go back to field offset
1619 offvar
= self
._get
_offvar
_name
(name
, prefix
)
1620 line
= '{} = ctx->{};'.format(self
._CTX
_AT
, offvar
)
1621 clines
.append(_CLine(line
))
1624 clines
+= self
._write
_field
_integer
(None, src_name
, integer
)
1626 # restore buffer position
1627 line
= '{} = ctx_at_bkup;'.format(self
._CTX
_AT
)
1628 clines
.append(_CLine(line
))
1632 # Generates the body of a barectf_close() function.
1634 # stream: TSDL stream
1635 def _gen_barectf_func_close_body(self
, stream
):
1638 line
= 'uint32_t ctx_at_bkup;'
1639 clines
.append(_CLine(line
))
1641 # update timestamp end if present
1642 if self
._stream
_has
_timestamp
_begin
_end
(stream
):
1643 clines
.append(_CLine(''))
1644 clines
.append(_CLine("/* update packet context's timestamp_end */"))
1646 # get clock value ASAP
1647 clk_type
= self
._get
_clock
_ctype
(stream
)
1648 clk
= self
._gen
_get
_clock
_value
()
1649 line
= '{} clk_value = {};'.format(clk_type
, clk
)
1650 clines
.append(_CLine(line
))
1652 # write timestamp_end
1653 timestamp_end_integer
= stream
.packet_context
['timestamp_end']
1654 clines
+= self
._gen
_write
_ctx
_field
_integer
('clk_value', 'spc',
1656 timestamp_end_integer
)
1658 # update content_size
1659 clines
.append(_CLine(''))
1660 clines
.append(_CLine("/* update packet context's content_size */"))
1661 content_size_integer
= stream
.packet_context
['content_size']
1662 clines
+= self
._gen
_write
_ctx
_field
_integer
('ctx_at_bkup', 'spc',
1664 content_size_integer
)
1667 clines
.append(_CLine('\n'))
1668 clines
.append(_CLine('return 0;'))
1671 cblock
= _CBlock(clines
)
1672 src
= self
._cblock
_to
_source
(cblock
)
1676 # Generates a barectf_close() function.
1678 # stream: TSDL stream
1679 # gen_body: also generate function body
1680 # hide_sid: True to hide the stream ID
1681 def _gen_barectf_func_close(self
, stream
, gen_body
, hide_sid
=False):
1690 if self
._manual
_clock
:
1691 clock_param
= self
._gen
_manual
_clock
_param
(stream
)
1692 params
= ',\n\t{}'.format(clock_param
)
1694 t
= barectf
.templates
.FUNC_CLOSE
1695 func
= t
.format(si
=self
._si
_str
, prefix
=self
._prefix
, sid
=sid
,
1700 func
+= self
._gen
_barectf
_func
_close
_body
(stream
)
1707 # Generates all barectf_init() function.
1709 # gen_body: also generate function bodies
1710 def _gen_barectf_funcs_init(self
, gen_body
):
1713 if len(self
._doc
.streams
) == 1:
1718 for stream
in self
._doc
.streams
.values():
1719 funcs
.append(self
._gen
_barectf
_func
_init
(stream
, gen_body
,
1724 # Generates all barectf_open() function.
1726 # gen_body: also generate function bodies
1727 def _gen_barectf_funcs_open(self
, gen_body
):
1730 if len(self
._doc
.streams
) == 1:
1735 for stream
in self
._doc
.streams
.values():
1736 funcs
.append(self
._gen
_barectf
_func
_open
(stream
, gen_body
,
1741 # Generates the body of a barectf_trace() function.
1743 # stream: TSDL stream of TSDL event to trace
1744 # event: TSDL event to trace
1745 def _gen_barectf_func_trace_event_body(self
, stream
, event
):
1748 clines
.append(_CLine('uint32_t ctx_at_bkup;'))
1750 # get clock value ASAP
1751 clk_type
= self
._get
_clock
_ctype
(stream
)
1752 clk
= self
._gen
_get
_clock
_value
()
1753 line
= '{} clk_value = {};'.format(clk_type
, clk
)
1754 clines
.append(_CLine(line
))
1755 clines
.append(_CLine(''))
1759 scope_name
= 'event.header'
1762 for fname
, ftype
in stream
.event_header
.fields
.items():
1765 fclines
= self
._field
_to
_clines
(fname
, ftype
, scope_name
,
1767 lambda x
: str(event
.id))
1768 fcline_groups
.append(fclines
)
1771 elif fname
== 'timestamp':
1772 fclines
= self
._field
_to
_clines
(fname
, ftype
, scope_name
,
1774 lambda x
: 'clk_value')
1775 fcline_groups
.append(fclines
)
1777 # stream event context
1778 if stream
.event_context
is not None:
1779 fclines
= self
._struct
_to
_clines
(stream
.event_context
,
1780 'stream.event.context', 'sec',
1781 self
._sec
_fname
_to
_pname
)
1782 fcline_groups
.append(fclines
)
1785 if event
.context
is not None:
1786 fclines
= self
._struct
_to
_clines
(event
.context
,
1787 'event.context', 'ec',
1788 self
._ec
_fname
_to
_pname
)
1789 fcline_groups
.append(fclines
)
1792 if event
.fields
is not None:
1793 fclines
= self
._struct
_to
_clines
(event
.fields
,
1794 'event.fields', 'ef',
1795 self
._ef
_fname
_to
_pname
)
1796 fcline_groups
.append(fclines
)
1799 fcline_groups
.append([_CLine('return 0;')])
1801 clines
+= self
._join
_cline
_groups
(fcline_groups
)
1804 cblock
= _CBlock(clines
)
1805 src
= self
._cblock
_to
_source
(cblock
)
1809 # Generates a barectf_trace() function.
1811 # stream: TSDL stream containing the TSDL event to trace
1812 # event: TSDL event to trace
1813 # gen_body: also generate function body
1814 # hide_sid: True to hide the stream ID
1815 def _gen_barectf_func_trace_event(self
, stream
, event
, gen_body
, hide_sid
):
1819 if self
._manual
_clock
:
1820 clock_param
= self
._gen
_manual
_clock
_param
(stream
)
1821 params
.append(clock_param
)
1823 # stream event context params
1824 if stream
.event_context
is not None:
1825 for fname
, ftype
in stream
.event_context
.fields
.items():
1826 ptype
= self
._get
_obj
_param
_ctype
(ftype
)
1827 pname
= self
._sec
_fname
_to
_pname
(fname
)
1828 param
= '{} {}'.format(ptype
, pname
)
1829 params
.append(param
)
1831 # event context params
1832 if event
.context
is not None:
1833 for fname
, ftype
in event
.context
.fields
.items():
1834 ptype
= self
._get
_obj
_param
_ctype
(ftype
)
1835 pname
= self
._ec
_fname
_to
_pname
(fname
)
1836 param
= '{} {}'.format(ptype
, pname
)
1837 params
.append(param
)
1839 # event fields params
1840 if event
.fields
is not None:
1841 for fname
, ftype
in event
.fields
.fields
.items():
1842 ptype
= self
._get
_obj
_param
_ctype
(ftype
)
1843 pname
= self
._ef
_fname
_to
_pname
(fname
)
1844 param
= '{} {}'.format(ptype
, pname
)
1845 params
.append(param
)
1850 params_str
= ',\n\t'.join([''] + params
)
1858 t
= barectf
.templates
.FUNC_TRACE
1859 func
= t
.format(si
=self
._si
_str
, prefix
=self
._prefix
, sid
=sid
,
1860 evname
=event
.name
, params
=params_str
)
1864 func
+= self
._gen
_barectf
_func
_trace
_event
_body
(stream
, event
)
1871 # Generates all barectf_trace() functions of a given TSDL stream.
1873 # stream: TSDL stream containing the TSDL events to trace
1874 # gen_body: also generate function body
1875 # hide_sid: True to hide the stream ID
1876 def _gen_barectf_funcs_trace_stream(self
, stream
, gen_body
, hide_sid
):
1879 for event
in stream
.events
:
1880 funcs
.append(self
._gen
_barectf
_func
_trace
_event
(stream
, event
,
1881 gen_body
, hide_sid
))
1885 # Generates all barectf_trace() function.
1887 # gen_body: also generate function bodies
1888 def _gen_barectf_funcs_trace(self
, gen_body
):
1891 if len(self
._doc
.streams
) == 1:
1896 for stream
in self
._doc
.streams
.values():
1897 funcs
+= self
._gen
_barectf
_funcs
_trace
_stream
(stream
, gen_body
,
1902 # Generates all barectf_close() function.
1904 # gen_body: also generate function bodies
1905 def _gen_barectf_funcs_close(self
, gen_body
):
1908 if len(self
._doc
.streams
) == 1:
1913 for stream
in self
._doc
.streams
.values():
1914 funcs
.append(self
._gen
_barectf
_func
_close
(stream
, gen_body
,
1919 # Generate all barectf functions
1921 # gen_body: also generate function bodies
1922 def _gen_barectf_functions(self
, gen_body
):
1923 init_funcs
= self
._gen
_barectf
_funcs
_init
(gen_body
)
1924 open_funcs
= self
._gen
_barectf
_funcs
_open
(gen_body
)
1925 close_funcs
= self
._gen
_barectf
_funcs
_close
(gen_body
)
1926 trace_funcs
= self
._gen
_barectf
_funcs
_trace
(gen_body
)
1928 return init_funcs
+ open_funcs
+ close_funcs
+ trace_funcs
1930 # Generates the barectf header C source
1931 def _gen_barectf_header(self
):
1932 ctx_structs
= self
._gen
_barectf
_contexts
_struct
()
1933 functions
= self
._gen
_barectf
_functions
(self
._static
_inline
)
1934 functions_str
= '\n\n'.join(functions
)
1935 t
= barectf
.templates
.HEADER
1936 header
= t
.format(prefix
=self
._prefix
, ucprefix
=self
._prefix
.upper(),
1937 barectf_ctx
=ctx_structs
, functions
=functions_str
)
1942 pytsdl
.tsdl
.ByteOrder
.BE
: 'BIG_ENDIAN',
1943 pytsdl
.tsdl
.ByteOrder
.LE
: 'LITTLE_ENDIAN',
1946 # Generates the barectf bitfield.h header.
1947 def _gen_barectf_bitfield_header(self
):
1948 header
= barectf
.templates
.BITFIELD
1949 header
= header
.replace('$prefix$', self
._prefix
)
1950 header
= header
.replace('$PREFIX$', self
._prefix
.upper())
1951 endian_def
= self
._BO
_DEF
_MAP
[self
._doc
.trace
.byte_order
]
1952 header
= header
.replace('$ENDIAN_DEF$', endian_def
)
1956 # Generates the main barectf C source file.
1957 def _gen_barectf_csrc(self
):
1958 functions
= self
._gen
_barectf
_functions
(True)
1959 functions_str
= '\n\n'.join(functions
)
1960 t
= barectf
.templates
.CSRC
1961 csrc
= t
.format(prefix
=self
._prefix
, ucprefix
=self
._prefix
.upper(),
1962 functions
=functions_str
)
1966 # Writes a file to the generator's output.
1969 # contents: file contents
1970 def _write_file(self
, name
, contents
):
1971 path
= os
.path
.join(self
._output
, name
)
1973 with
open(path
, 'w') as f
:
1975 except Exception as e
:
1976 _perror('cannot write "{}": {}'.format(path
, e
))
1978 # Converts a C block to actual C source lines.
1981 # indent: initial indentation
1982 def _cblock_to_source_lines(self
, cblock
, indent
=1):
1984 indentstr
= '\t' * indent
1987 if type(line
) is _CBlock
:
1988 src
+= self
._cblock
_to
_source
_lines
(line
, indent
+ 1)
1990 src
.append(indentstr
+ line
)
1994 # Converts a C block to an actual C source string.
1997 # indent: initial indentation
1998 def _cblock_to_source(self
, cblock
, indent
=1):
1999 lines
= self
._cblock
_to
_source
_lines
(cblock
, indent
)
2001 return '\n'.join(lines
)
2003 # Sets the generator parameters.
2004 def _set_params(self
):
2005 # streams have timestamp_begin/timestamp_end fields
2006 self
._has
_timestamp
_begin
_end
= {}
2008 for stream
in self
._doc
.streams
.values():
2009 has
= 'timestamp_begin' in stream
.packet_context
.fields
2010 self
._has
_timestamp
_begin
_end
[stream
.id] = has
2012 # Generates barectf C files.
2014 # metadata: metadata path
2015 # output: output directory
2017 # static_inline: generate static inline functions
2018 # manual_clock: do not use a clock callback: pass clock value to
2020 def gen_barectf(self
, metadata
, output
, prefix
, static_inline
,
2022 self
._metadata
= metadata
2023 self
._output
= output
2024 self
._prefix
= prefix
2025 self
._static
_inline
= static_inline
2026 self
._manual
_clock
= manual_clock
2030 self
._si
_str
= 'static inline '
2032 # open CTF metadata file
2033 _pinfo('opening CTF metadata file "{}"'.format(self
._metadata
))
2036 with
open(metadata
) as f
:
2037 self
._tsdl
= f
.read()
2039 _perror('cannot open/read CTF metadata file "{}"'.format(metadata
))
2041 # parse CTF metadata
2042 _pinfo('parsing CTF metadata file')
2045 self
._doc
= self
._parser
.parse(self
._tsdl
)
2046 except pytsdl
.parser
.ParseError
as e
:
2047 _perror('parse error: {}'.format(e
))
2049 # validate CTF metadata against barectf constraints
2050 _pinfo('validating CTF metadata file')
2051 self
._validate
_metadata
()
2052 _psuccess('CTF metadata file is valid')
2054 # set parameters for this generation
2058 _pinfo('generating barectf header files')
2059 header
= self
._gen
_barectf
_header
()
2060 self
._write
_file
('{}.h'.format(self
._prefix
), header
)
2061 header
= self
._gen
_barectf
_bitfield
_header
()
2062 self
._write
_file
('{}_bitfield.h'.format(self
._prefix
), header
)
2064 # generate C source file
2065 if not self
._static
_inline
:
2066 _pinfo('generating barectf C source file')
2067 csrc
= self
._gen
_barectf
_csrc
()
2068 self
._write
_file
('{}.c'.format(self
._prefix
), csrc
)
2074 args
= _parse_args()
2075 generator
= BarectfCodeGenerator()
2076 generator
.gen_barectf(args
.metadata
, args
.output
, args
.prefix
,
2077 args
.static_inline
, args
.manual_clock
)
This page took 0.0767330000000001 seconds and 5 git commands to generate.