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_BUF_SIZE
= 'ctx->buf_size'
92 _CTX_BUF_AT
= '{}[{} >> 3]'.format(_CTX_BUF
, _CTX_AT
)
93 _CTX_BUF_AT_ADDR
= '&{}'.format(_CTX_BUF_AT
)
94 _CTX_CALL_CLOCK_CB
= 'ctx->clock_cb(ctx->clock_cb_data)'
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()
113 self
._obj
_size
_cb
= {
114 pytsdl
.tsdl
.Struct
: self
._get
_struct
_size
,
115 pytsdl
.tsdl
.Integer
: self
._get
_integer
_size
,
116 pytsdl
.tsdl
.Enum
: self
._get
_enum
_size
,
117 pytsdl
.tsdl
.FloatingPoint
: self
._get
_floating
_point
_size
,
118 pytsdl
.tsdl
.Array
: self
._get
_array
_size
,
120 self
._obj
_alignment
_cb
= {
121 pytsdl
.tsdl
.Struct
: self
._get
_struct
_alignment
,
122 pytsdl
.tsdl
.Integer
: self
._get
_integer
_alignment
,
123 pytsdl
.tsdl
.Enum
: self
._get
_enum
_alignment
,
124 pytsdl
.tsdl
.FloatingPoint
: self
._get
_floating
_point
_alignment
,
125 pytsdl
.tsdl
.Array
: self
._get
_array
_alignment
,
126 pytsdl
.tsdl
.Sequence
: self
._get
_sequence
_alignment
,
127 pytsdl
.tsdl
.String
: self
._get
_string
_alignment
,
129 self
._obj
_param
_ctype
_cb
= {
130 pytsdl
.tsdl
.Struct
: lambda obj
: 'const void*',
131 pytsdl
.tsdl
.Integer
: self
._get
_integer
_param
_ctype
,
132 pytsdl
.tsdl
.Enum
: self
._get
_enum
_param
_ctype
,
133 pytsdl
.tsdl
.FloatingPoint
: self
._get
_floating
_point
_param
_ctype
,
134 pytsdl
.tsdl
.Array
: lambda obj
: 'const void*',
135 pytsdl
.tsdl
.Sequence
: lambda obj
: 'const void*',
136 pytsdl
.tsdl
.String
: lambda obj
: 'const char*',
138 self
._write
_field
_obj
_cb
= {
139 pytsdl
.tsdl
.Struct
: self
._write
_field
_struct
,
140 pytsdl
.tsdl
.Integer
: self
._write
_field
_integer
,
141 pytsdl
.tsdl
.Enum
: self
._write
_field
_enum
,
142 pytsdl
.tsdl
.FloatingPoint
: self
._write
_field
_floating
_point
,
143 pytsdl
.tsdl
.Array
: self
._write
_field
_array
,
144 pytsdl
.tsdl
.Sequence
: self
._write
_field
_sequence
,
145 pytsdl
.tsdl
.String
: self
._write
_field
_string
,
147 self
._get
_src
_name
_funcs
= {
148 'trace.packet.header.': self
._get
_tph
_src
_name
,
149 'env.': self
._get
_env
_src
_name
,
150 'stream.packet.context.': self
._get
_spc
_src
_name
,
151 'stream.event.header.': self
._get
_seh
_src
_name
,
152 'stream.event.context.': self
._get
_sec
_src
_name
,
153 'event.context.': self
._get
_ec
_src
_name
,
154 'event.fields.': self
._get
_ef
_src
_name
,
157 # TODO: prettify this function
158 def _validate_struct(self
, struct
):
159 # just in case we call this with the wrong type
160 if type(struct
) is not pytsdl
.tsdl
.Struct
:
161 raise RuntimeError('expecting a struct')
163 # make sure inner structures are at least byte-aligned
164 if self
._get
_obj
_alignment
(struct
) < 8:
165 raise RuntimeError('inner struct must be at least byte-aligned')
168 for fname
, ftype
in struct
.fields
.items():
169 if type(ftype
) is pytsdl
.tsdl
.Sequence
:
170 raise RuntimeError('field "{}" is a dynamic array (not allowed here)'.format(fname
))
171 elif type(ftype
) is pytsdl
.tsdl
.Array
:
172 # we need to check every element until we find a terminal one
173 element
= ftype
.element
176 if type(element
) is pytsdl
.tsdl
.Sequence
:
177 raise RuntimeError('field "{}" contains a dynamic array (not allowed here)'.format(fname
))
178 elif type(element
) is pytsdl
.tsdl
.Variant
:
179 raise RuntimeError('field "{}" contains a variant (unsupported)'.format(fname
))
180 elif type(element
) is pytsdl
.tsdl
.String
:
181 raise RuntimeError('field "{}" contains a string (not allowed here)'.format(fname
))
182 elif type(element
) is pytsdl
.tsdl
.Struct
:
183 _validate_struct(element
)
184 elif type(element
) is pytsdl
.tsdl
.Integer
:
185 if self
._get
_obj
_size
(element
) > 64:
186 raise RuntimeError('integer field "{}" larger than 64-bit'.format(fname
))
187 elif type(element
) is pytsdl
.tsdl
.FloatingPoint
:
188 if self
._get
_obj
_size
(element
) > 64:
189 raise RuntimeError('floating point field "{}" larger than 64-bit'.format(fname
))
190 elif type(element
) is pytsdl
.tsdl
.Enum
:
191 if self
._get
_obj
_size
(element
) > 64:
192 raise RuntimeError('enum field "{}" larger than 64-bit'.format(fname
))
194 if type(element
) is pytsdl
.tsdl
.Array
:
195 # still an array, continue
196 element
= element
.element
198 # found the terminal element
200 elif type(ftype
) is pytsdl
.tsdl
.Variant
:
201 raise RuntimeError('field "{}" is a variant (unsupported)'.format(fname
))
202 elif type(ftype
) is pytsdl
.tsdl
.String
:
203 raise RuntimeError('field "{}" is a string (not allowed here)'.format(fname
))
204 elif type(ftype
) is pytsdl
.tsdl
.Struct
:
205 self
._validate
_struct
(ftype
)
206 elif type(ftype
) is pytsdl
.tsdl
.Integer
:
207 if self
._get
_obj
_size
(ftype
) > 64:
208 raise RuntimeError('integer field "{}" larger than 64-bit'.format(fname
))
209 elif type(ftype
) is pytsdl
.tsdl
.FloatingPoint
:
210 if self
._get
_obj
_size
(ftype
) > 64:
211 raise RuntimeError('floating point field "{}" larger than 64-bit'.format(fname
))
212 elif type(ftype
) is pytsdl
.tsdl
.Enum
:
213 if self
._get
_obj
_size
(ftype
) > 64:
214 raise RuntimeError('enum field "{}" larger than 64-bit'.format(fname
))
216 def _validate_context_fields(self
, struct
):
217 if type(struct
) is not pytsdl
.tsdl
.Struct
:
218 raise RuntimeError('expecting a struct')
220 for fname
, ftype
in struct
.fields
.items():
221 if type(ftype
) is pytsdl
.tsdl
.Variant
:
222 raise RuntimeError('field "{}" is a variant (unsupported)'.format(fname
))
223 elif type(ftype
) is pytsdl
.tsdl
.Struct
:
224 # validate inner structure against barectf constraints
225 self
._validate
_struct
(ftype
)
227 def _validate_integer(self
, integer
, size
=None, align
=None,
229 if type(integer
) is not pytsdl
.tsdl
.Integer
:
230 raise RuntimeError('expected integer')
233 if integer
.size
!= size
:
234 raise RuntimeError('expected {}-bit integer'.format(size
))
236 if align
is not None:
237 if integer
.align
!= align
:
238 raise RuntimeError('expected integer with {}-bit alignment'.format(align
))
240 if signed
is not None:
241 if integer
.signed
!= signed
:
242 raise RuntimeError('expected {} integer'.format('signed' if signed
else 'unsigned'))
244 def _validate_packet_header(self
, packet_header
):
246 self
._validate
_struct
(packet_header
)
247 except RuntimeError as e
:
248 _perror('packet header: {}'.format(e
))
250 # magic must be the first field
251 if 'magic' in packet_header
.fields
:
252 if list(packet_header
.fields
.keys())[0] != 'magic':
253 _perror('packet header: "magic" must be the first field')
255 _perror('packet header: missing "magic" field')
257 # magic must be a 32-bit unsigned integer, 32-bit aligned
259 self
._validate
_integer
(packet_header
['magic'], 32, 32, False)
260 except RuntimeError as e
:
261 _perror('packet header: "magic": {}'.format(e
))
263 # mandatory stream_id
264 if 'stream_id' not in packet_header
.fields
:
265 _perror('packet header: missing "stream_id" field')
267 # stream_id must be an unsigned integer
269 self
._validate
_integer
(packet_header
['stream_id'], signed
=False)
270 except RuntimeError as e
:
271 _perror('packet header: "stream_id": {}'.format(e
))
273 # only magic and stream_id allowed
274 if len(packet_header
.fields
) != 2:
275 _perror('packet header: only "magic" and "stream_id" fields are allowed')
277 def _dot_name_to_str(self
, name
):
278 return '.'.join(name
)
280 def _compare_integers(self
, int1
, int2
):
281 if type(int1
) is not pytsdl
.tsdl
.Integer
:
284 if type(int2
) is not pytsdl
.tsdl
.Integer
:
287 size
= int1
.size
== int2
.size
288 align
= int1
.align
== int2
.align
289 cmap
= int1
.map == int2
.map
290 base
= int1
.base
== int2
.base
291 encoding
= int1
.encoding
== int2
.encoding
292 signed
= int1
.signed
== int2
.signed
293 comps
= (size
, align
, cmap
, base
, encoding
, signed
)
295 # True means 1 for sum()
296 return sum(comps
) == len(comps
)
298 def _validate_packet_context(self
, stream
):
299 packet_context
= stream
.packet_context
303 self
._validate
_struct
(packet_context
)
304 except RuntimeError as e
:
305 _perror('stream {}: packet context: {}'.format(sid
, e
))
307 fields
= packet_context
.fields
309 # if timestamp_begin exists, timestamp_end must exist
310 if 'timestamp_begin' in fields
or 'timestamp_end' in fields
:
311 if 'timestamp_begin' not in fields
or 'timestamp_end' not in fields
:
312 _perror('stream {}: packet context: "timestamp_begin" must exist if "timestamp_end" exists'.format(sid
))
314 # timestamp_begin and timestamp_end must have the same integer
315 # as the event header's timestamp field (should exist by now)
316 timestamp
= stream
.event_header
['timestamp']
318 if not self
._compare
_integers
(fields
['timestamp_begin'], timestamp
):
319 _perror('stream {}: packet context: "timestamp_begin": integer type different from event header\'s "timestamp" field'.format(sid
))
321 if not self
._compare
_integers
(fields
['timestamp_end'], timestamp
):
322 _perror('stream {}: packet context: "timestamp_end": integer type different from event header\'s "timestamp" field'.format(sid
))
324 # content_size must exist and be an unsigned integer
325 if 'content_size' not in fields
:
326 _perror('stream {}: packet context: missing "content_size" field'.format(sid
))
329 self
._validate
_integer
(fields
['content_size'], 32, 32, False)
332 self
._validate
_integer
(fields
['content_size'], 64, 64, False)
334 _perror('stream {}: packet context: "content_size": expecting unsigned 32-bit/64-bit integer'.format(sid
))
336 # packet_size must exist and be an unsigned integer
337 if 'packet_size' not in fields
:
338 _perror('stream {}: packet context: missing "packet_size" field'.format(sid
))
341 self
._validate
_integer
(fields
['packet_size'], 32, 32, False)
344 self
._validate
_integer
(fields
['packet_size'], 64, 64, False)
346 _perror('stream {}: packet context: "packet_size": expecting unsigned 32-bit/64-bit integer'.format(sid
))
348 # if cpu_id exists, must be an unsigned integer
349 if 'cpu_id' in fields
:
351 self
._validate
_integer
(fields
['cpu_id'], signed
=False)
352 except RuntimeError as e
:
353 _perror('stream {}: packet context: "cpu_id": {}'.format(sid
, e
))
355 def _validate_event_header(self
, stream
):
356 event_header
= stream
.event_header
360 self
._validate
_struct
(event_header
)
361 except RuntimeError as e
:
362 _perror('stream {}: event header: {}'.format(sid
, e
))
364 fields
= event_header
.fields
366 # id must exist and be an unsigned integer
367 if 'id' not in fields
:
368 _perror('stream {}: event header: missing "id" field'.format(sid
))
371 self
._validate
_integer
(fields
['id'], signed
=False)
372 except RuntimeError as e
:
373 _perror('stream {}: "id": {}'.format(sid
, format(e
)))
376 # timestamp must exist, be an unsigned integer and be mapped to a valid clock
377 if 'timestamp' not in fields
:
378 _perror('stream {}: event header: missing "timestamp" field'.format(sid
))
381 self
._validate
_integer
(fields
['timestamp'], signed
=False)
382 except RuntimeError as e
:
383 _perror('stream {}: event header: "timestamp": {}'.format(sid
, format(e
)))
385 if fields
['timestamp'].map is None:
386 _perror('stream {}: event header: "timestamp" must be mapped to a valid clock'.format(sid
))
388 # id must be the first field, followed by timestamp
389 if list(fields
.keys())[0] != 'id':
390 _perror('stream {}: event header: "id" must be the first field'.format(sid
))
392 if list(fields
.keys())[1] != 'timestamp':
393 _perror('stream {}: event header: "timestamp" must be the second field'.format(sid
))
395 # only id and timestamp and allowed in event header
397 _perror('stream {}: event header: only "id" and "timestamp" fields are allowed'.format(sid
))
399 def _validate_stream_event_context(self
, stream
):
400 stream_event_context
= stream
.event_context
403 if stream_event_context
is None:
407 self
._validate
_context
_fields
(stream_event_context
)
408 except RuntimeError as e
:
409 _perror('stream {}: event context: {}'.format(sid
, e
))
411 def _validate_event_context(self
, stream
, event
):
412 event_context
= event
.context
416 if event_context
is None:
420 self
._validate
_context
_fields
(event_context
)
421 except RuntimeError as e
:
422 _perror('stream {}: event {}: context: {}'.format(sid
, eid
, e
))
424 def _validate_event_fields(self
, stream
, event
):
425 event_fields
= event
.fields
430 self
._validate
_context
_fields
(event_fields
)
431 except RuntimeError as e
:
432 _perror('stream {}: event {}: fields: {}'.format(sid
, eid
, e
))
434 def _validate_all_scopes(self
):
436 self
._validate
_packet
_header
(self
._doc
.trace
.packet_header
)
439 for stream
in self
._doc
.streams
.values():
440 self
._validate
_event
_header
(stream
)
441 self
._validate
_packet
_context
(stream
)
442 self
._validate
_stream
_event
_context
(stream
)
445 for event
in stream
.events
:
446 self
._validate
_event
_context
(stream
, event
)
447 self
._validate
_event
_fields
(stream
, event
)
449 def _validate_metadata(self
):
450 self
._validate
_all
_scopes
()
459 def _get_alignment(self
, at
, align
):
460 return (at
+ align
- 1) & -align
462 # this converts a tree of offset variables:
477 # field_other_struct_field -> 16
478 # field_other_struct_yeah -> 20
481 def _flatten_offvars_tree(self
, offvars_tree
, prefix
=None,
484 offvars
= collections
.OrderedDict()
486 for name
, offset
in offvars_tree
.items():
487 if prefix
is not None:
488 varname
= '{}_{}'.format(prefix
, name
)
492 if isinstance(offset
, dict):
493 self
._flatten
_offvars
_tree
(offset
, varname
, offvars
)
495 offvars
[varname
] = offset
499 # returns the size of a struct with _static size_
500 def _get_struct_size(self
, struct
,
503 if offvars_tree
is None:
504 offvars_tree
= collections
.OrderedDict()
508 for fname
, ftype
in struct
.fields
.items():
509 field_alignment
= self
._get
_obj
_alignment
(ftype
)
510 offset
= self
._get
_alignment
(offset
, field_alignment
)
512 if type(ftype
) is pytsdl
.tsdl
.Struct
:
513 offvars_tree
[fname
] = collections
.OrderedDict()
514 sz
= self
._get
_struct
_size
(ftype
, offvars_tree
[fname
],
515 base_offset
+ offset
)
517 # only integers may act as sequence lengths
518 if type(ftype
) is pytsdl
.tsdl
.Integer
:
519 offvars_tree
[fname
] = base_offset
+ offset
521 sz
= self
._get
_obj
_size
(ftype
)
527 def _get_array_size(self
, array
):
528 element
= array
.element
530 # effective size of one element includes its alignment after its size
531 size
= self
._get
_obj
_size
(element
)
532 align
= self
._get
_obj
_alignment
(element
)
534 return self
._get
_alignment
(size
, align
) * array
.length
536 def _get_enum_size(self
, enum
):
537 return self
._get
_obj
_size
(enum
.integer
)
539 def _get_floating_point_size(self
, floating_point
):
540 return floating_point
.exp_dig
+ floating_point
.mant_dig
542 def _get_integer_size(self
, integer
):
545 def _get_obj_size(self
, obj
):
546 return self
._obj
_size
_cb
[type(obj
)](obj
)
548 def _get_struct_alignment(self
, struct
):
549 if struct
.align
is not None:
554 for fname
, ftype
in struct
.fields
.items():
555 cur_align
= max(self
._get
_obj
_alignment
(ftype
), cur_align
)
559 def _get_integer_alignment(self
, integer
):
562 def _get_floating_point_alignment(self
, floating_point
):
563 return floating_point
.align
565 def _get_enum_alignment(self
, enum
):
566 return self
._get
_obj
_alignment
(enum
.integer
)
568 def _get_string_alignment(self
, string
):
571 def _get_array_alignment(self
, array
):
572 return self
._get
_obj
_alignment
(array
.element
)
574 def _get_sequence_alignment(self
, sequence
):
575 return self
._get
_obj
_alignment
(sequence
.element
)
577 def _get_obj_alignment(self
, obj
):
578 return self
._obj
_alignment
_cb
[type(obj
)](obj
)
580 def _fname_to_pname(self
, prefix
, name
):
581 return 'param_{}_{}'.format(prefix
, name
)
583 def _ef_fname_to_pname(self
, name
):
584 return self
._fname
_to
_pname
('ef', name
)
586 def _ec_fname_to_pname(self
, name
):
587 return self
._fname
_to
_pname
('ec', name
)
589 def _sec_fname_to_pname(self
, name
):
590 return self
._fname
_to
_pname
('sec', name
)
592 def _eh_fname_to_pname(self
, name
):
593 return self
._fname
_to
_pname
('eh', name
)
595 def _spc_fname_to_pname(self
, name
):
596 return self
._fname
_to
_pname
('spc', name
)
598 def _tph_fname_to_pname(self
, name
):
599 return self
._fname
_to
_pname
('tph', name
)
601 def _get_integer_param_ctype(self
, integer
):
602 signed
= 'u' if not integer
.signed
else ''
604 if integer
.size
== 8:
606 elif integer
.size
== 16:
608 elif integer
.size
== 32:
610 elif integer
.size
== 64:
613 # if the integer is signed and of uncommon size, the sign bit is
614 # at a custom position anyway so we use a 64-bit unsigned
620 if integer
.size
< 16:
622 elif integer
.size
< 32:
624 elif integer
.size
< 64:
629 return '{}int{}_t'.format(signed
, sz
)
631 def _get_enum_param_ctype(self
, enum
):
632 return self
._get
_obj
_param
_ctype
(enum
.integer
)
634 def _get_floating_point_param_ctype(self
, fp
):
635 if fp
.exp_dig
== 8 and fp
.mant_dig
== 24 and fp
.align
== 32:
637 elif fp
.exp_dig
== 11 and fp
.mant_dig
== 53 and fp
.align
== 64:
642 def _get_obj_param_ctype(self
, obj
):
643 return self
._obj
_param
_ctype
_cb
[type(obj
)](obj
)
645 def _get_chk_offset_v(self
, size
):
646 fmt
= '{}_CHK_OFFSET_V({}, {}, {});'
647 ret
= fmt
.format(self
._prefix
.upper(), self
._CTX
_AT
,
648 self
._CTX
_BUF
_SIZE
, size
)
652 def _get_chk_offset_v_cline(self
, size
):
653 return _CLine(self
._get
_chk
_offset
_v
(size
))
655 def _get_align_offset(self
, align
):
656 fmt
= '{}_ALIGN_OFFSET({}, {});'
657 ret
= fmt
.format(self
._prefix
.upper(), self
._CTX
_AT
, align
)
661 def _get_align_offset_cline(self
, size
):
662 return _CLine(self
._get
_align
_offset
(size
))
664 def _str_to_clines(self
, s
):
665 lines
= s
.split('\n')
667 return [_CLine(line
) for line
in lines
]
669 def _template_to_clines(self
, tmpl
, **kwargs
):
670 s
= tmpl
.format(prefix
=self
._prefix
, ucprefix
=self
._prefix
.upper(),
673 return self
._str
_to
_clines
(s
)
675 def _write_field_struct(self
, fname
, src_name
, struct
, scope_prefix
):
676 size
= self
._get
_struct
_size
(struct
)
677 size_bytes
= self
._get
_alignment
(size
, 8) // 8
678 dst
= self
._CTX
_BUF
_AT
_ADDR
681 # memcpy() is safe since barectf requires inner structures
683 self
._get
_chk
_offset
_v
_cline
(size
),
684 _CLine('memcpy({}, {}, {});'.format(dst
, src_name
, size_bytes
)),
685 _CLine('{} += {};'.format(self
._CTX
_AT
, size
)),
688 def _write_field_integer(self
, fname
, src_name
, integer
, scope_prefix
=None):
689 bo
= self
._bo
_suffixes
_map
[integer
.byte_order
]
690 t
= self
._get
_obj
_param
_ctype
(integer
)
691 length
= self
._get
_obj
_size
(integer
)
693 return self
._template
_to
_clines
(barectf
.templates
.WRITE_INTEGER
,
694 sz
=length
, bo
=bo
, type=t
,
697 def _write_field_enum(self
, fname
, src_name
, enum
, scope_prefix
=None):
698 return self
._write
_field
_obj
(fname
, src_name
, enum
.integer
)
700 def _write_field_floating_point(self
, fname
, src_name
, floating_point
,
702 bo
= self
._bo
_suffixes
_map
[floating_point
.byte_order
]
703 t
= self
._get
_obj
_param
_ctype
(floating_point
)
704 length
= self
._get
_obj
_size
(floating_point
)
706 return self
._template
_to
_clines
(barectf
.templates
.WRITE_INTEGER
,
707 sz
=length
, bo
=bo
, type=t
,
710 def _write_field_array(self
, fname
, src_name
, array
, scope_prefix
=None):
713 # array index variable declaration
714 iv
= 'ia_{}'.format(fname
)
715 clines
.append(_CLine('uint32_t {};'.format(iv
)))
717 # for loop using array's static length
718 line
= 'for ({iv} = 0; {iv} < {l}; ++{iv}) {{'.format(iv
=iv
,
720 clines
.append(_CLine(line
))
722 # for loop statements
723 for_block
= _CBlock()
725 # align bit index before writing to the buffer
726 element_align
= self
._get
_obj
_alignment
(array
.element
)
727 cline
= self
._get
_align
_offset
_cline
(element_align
)
728 for_block
.append(cline
)
730 # write element to the buffer
731 for_block
+= self
._write
_field
_obj
(fname
, src_name
, array
.element
,
733 clines
.append(for_block
)
736 clines
.append(_CLine('}'))
740 def _get_tph_src_name(self
, length
):
741 offvar
= self
._get
_offvar
_name
_from
_expr
(length
[3:], 'tph')
743 return 'ctx->{}'.format(offvar
)
745 def _get_env_src_name(self
, length
):
747 _perror('invalid sequence length: "{}"'.format(self
._dot
_name
_to
_str
(length
)))
751 if fname
not in self
._doc
.env
:
752 _perror('cannot find field env.{}'.format(fname
))
754 return str(self
._doc
.env
[fname
])
756 def _get_spc_src_name(self
, length
):
757 offvar
= self
._get
_offvar
_name
_from
_expr
(length
[3:], 'spc')
759 return 'ctx->{}'.format(offvar
)
761 def _get_seh_src_name(self
, length
):
762 return self
._get
_offvar
_name
_from
_expr
(length
[3:], 'seh')
764 def _get_sec_src_name(self
, length
):
765 return self
._get
_offvar
_name
_from
_expr
(length
[3:], 'sec')
767 def _get_ec_src_name(self
, length
):
768 return self
._get
_offvar
_name
_from
_expr
(length
[2:], 'ec')
770 def _get_ef_src_name(self
, length
):
771 return self
._get
_offvar
_name
_from
_expr
(length
[2:], 'ef')
773 def _seq_length_to_src_name(self
, length
, scope_prefix
=None):
774 length_dot
= self
._dot
_name
_to
_str
(length
)
776 for prefix
, get_src_name
in self
._get
_src
_name
_funcs
.items():
777 if length_dot
.startswith(prefix
):
778 return get_src_name(length
)
780 return self
._get
_offvar
_name
_from
_expr
(length
, scope_prefix
)
782 def _write_field_sequence(self
, fname
, src_name
, sequence
, scope_prefix
):
785 # sequence index variable declaration
786 iv
= 'is_{}'.format(fname
)
787 clines
.append(_CLine('uint32_t {};'.format(iv
)))
789 # sequence length offset variable
790 length_offvar
= self
._seq
_length
_to
_src
_name
(sequence
.length
,
793 # for loop using sequence's static length
794 line
= 'for ({iv} = 0; {iv} < {l}; ++{iv}) {{'.format(iv
=iv
,
796 clines
.append(_CLine(line
))
798 # for loop statements
799 for_block
= _CBlock()
801 # align bit index before writing to the buffer
802 element_align
= self
._get
_obj
_alignment
(sequence
.element
)
803 cline
= self
._get
_align
_offset
_cline
(element_align
)
804 for_block
.append(cline
)
806 # write element to the buffer
807 for_block
+= self
._write
_field
_obj
(fname
, src_name
, sequence
.element
,
809 clines
.append(for_block
)
812 clines
.append(_CLine('}'))
816 def _write_field_string(self
, fname
, src_name
, string
, scope_prefix
=None):
819 # string index variable declaration
820 iv
= 'is_{}'.format(fname
)
821 clines
.append(_CLine('uint32_t {};'.format(iv
)))
823 # for loop; loop until the end of the source string is reached
824 fmt
= "for ({iv} = 0; {src}[{iv}] != '\\0'; ++{iv}, {ctxat} += 8) {{"
825 line
= fmt
.format(iv
=iv
, src
=src_name
, ctxat
=self
._CTX
_AT
)
826 clines
.append(_CLine(line
))
828 # for loop statements
829 for_block
= _CBlock()
831 # check offset overflow
832 for_block
.append(self
._get
_chk
_offset
_v
_cline
(8))
834 # write byte to the buffer
835 fmt
= '{dst} = {src}[{iv}];'
836 line
= fmt
.format(dst
=self
._CTX
_BUF
_AT
, iv
=iv
, src
=src_name
)
837 for_block
.append(_CLine(line
))
840 clines
.append(for_block
)
841 clines
.append(_CLine('}'))
843 # write NULL character to the buffer
844 clines
.append(_CLine("{} = '\\0';".format(self
._CTX
_BUF
_AT
)))
845 clines
.append(_CLine('{} += 8;'.format(self
._CTX
_AT
)))
849 def _write_field_obj(self
, fname
, src_name
, ftype
, scope_prefix
):
850 return self
._write
_field
_obj
_cb
[type(ftype
)](fname
, src_name
, ftype
,
853 def _get_offvar_name(self
, name
, prefix
=None):
856 if prefix
is not None:
861 return '_'.join(parts
)
863 def _get_offvar_name_from_expr(self
, expr
, prefix
=None):
864 return self
._get
_offvar
_name
('_'.join(expr
), prefix
)
866 def _field_to_clines(self
, fname
, ftype
, scope_name
, scope_prefix
,
869 pname
= param_name_cb(fname
)
870 align
= self
._get
_obj
_alignment
(ftype
)
873 fmt
= '/* write {}.{} ({}) */'
874 line
= fmt
.format(scope_name
, fname
,
875 self
._tsdl
_type
_names
_map
[type(ftype
)])
876 clines
.append(_CLine(line
))
878 # align bit index before writing to the buffer
879 cline
= self
._get
_align
_offset
_cline
(align
)
882 # write offset variables
883 if type(ftype
) is pytsdl
.tsdl
.Struct
:
884 offvars_tree
= collections
.OrderedDict()
885 self
._get
_struct
_size
(ftype
, offvars_tree
)
886 offvars
= self
._flatten
_offvars
_tree
(offvars_tree
)
888 # as many offset as there are child fields because a future
889 # sequence could refer to any of those fields
890 for lname
, offset
in offvars
.items():
891 offvar
= self
._get
_offvar
_name
('_'.join([fname
, lname
]),
893 fmt
= 'uint32_t {} = {} + {};'
894 line
= fmt
.format(offvar
, self
._CTX
_AT
, offset
);
895 clines
.append(_CLine(line
))
896 elif type(ftype
) is pytsdl
.tsdl
.Integer
:
897 # offset of this simple field is the current bit index
898 offvar
= self
._get
_offvar
_name
(fname
, scope_prefix
)
899 line
= 'uint32_t {} = {};'.format(offvar
, self
._CTX
_AT
)
900 clines
.append(_CLine(line
))
902 clines
+= self
._write
_field
_obj
(fname
, pname
, ftype
, scope_prefix
)
906 def _join_cline_groups(self
, cline_groups
):
910 output_clines
= cline_groups
[0]
912 for clines
in cline_groups
[1:]:
913 output_clines
.append('')
914 output_clines
+= clines
918 def _struct_to_clines(self
, struct
, scope_name
, scope_prefix
,
922 for fname
, ftype
in struct
.fields
.items():
923 clines
= self
._field
_to
_clines
(fname
, ftype
, scope_name
,
924 scope_prefix
, param_name_cb
)
925 cline_groups
.append(clines
)
927 return self
._join
_cline
_groups
(cline_groups
)
929 def _get_struct_size_offvars(self
, struct
):
930 offvars_tree
= collections
.OrderedDict()
931 size
= self
._get
_struct
_size
(struct
, offvars_tree
)
932 offvars
= self
._flatten
_offvars
_tree
(offvars_tree
)
936 def _get_ph_size_offvars(self
):
937 return self
._get
_struct
_size
_offvars
(self
._doc
.trace
.packet_header
)
939 def _get_pc_size_offvars(self
, stream
):
940 return self
._get
_struct
_size
_offvars
(stream
.packet_context
)
942 def _offvars_to_ctx_clines(self
, prefix
, offvars
):
945 for name
in offvars
.keys():
946 offvar
= self
._get
_offvar
_name
(name
, prefix
)
947 clines
.append(_CLine('uint32_t {};'.format(offvar
)))
951 def _gen_barectf_ctx_struct(self
, stream
, hide_sid
=False):
952 # get offset variables for both the packet header and packet context
953 ph_size
, ph_offvars
= self
._get
_ph
_size
_offvars
()
954 pc_size
, pc_offvars
= self
._get
_pc
_size
_offvars
(stream
)
955 clines
= self
._offvars
_to
_ctx
_clines
('tph', ph_offvars
)
956 clines
+= self
._offvars
_to
_ctx
_clines
('spc', pc_offvars
)
961 clines_indented
.append(_CLine('\t' + cline
))
964 clock_cb
= '\t/* (no clock callback) */'
966 if not self
._manual
_clock
:
967 ctype
= self
._get
_clock
_type
(stream
)
968 fmt
= '\t{} (*clock_cb)(void*),\n\tvoid* clock_cb_data;'
969 clock_cb
= fmt
.format(ctype
)
977 t
= barectf
.templates
.BARECTF_CTX
978 struct
= t
.format(prefix
=self
._prefix
, sid
=sid
,
979 ctx_fields
='\n'.join(clines_indented
),
984 def _gen_barectf_contexts_struct(self
):
987 if len(self
._doc
.streams
) == 1:
992 for stream
in self
._doc
.streams
.values():
993 struct
= self
._gen
_barectf
_ctx
_struct
(stream
, hide_sid
)
994 structs
.append(struct
)
996 return '\n\n'.join(structs
)
998 _packet_context_known_fields
= [
1005 def _get_clock_type(self
, stream
):
1006 return self
._get
_obj
_param
_ctype
(stream
.event_header
['timestamp'])
1008 def _gen_manual_clock_param(self
, stream
):
1009 return '{} param_clock'.format(self
._get
_clock
_type
(stream
))
1011 def _gen_barectf_func_open_body(self
, stream
):
1014 # keep clock value (for timestamp_begin)
1015 if self
._stream
_has
_timestamp
_begin
_end
(stream
):
1016 # get clock value ASAP
1017 clk_type
= self
._get
_clock
_type
(stream
)
1018 clk
= self
._gen
_get
_clock
_value
()
1019 line
= '{} clk_value = {};'.format(clk_type
, clk
)
1020 clines
.append(_CLine(line
))
1021 clines
.append(_CLine(''))
1023 # packet context fields
1025 scope_name
= 'stream.packet.context'
1026 scope_prefix
= 'spc'
1028 for fname
, ftype
in stream
.packet_context
.fields
.items():
1030 if fname
== 'packet_size':
1031 fclines
= self
._field
_to
_clines
(fname
, ftype
, scope_name
,
1033 lambda x
: 'ctx->buffer_size')
1034 fcline_groups
.append(fclines
)
1036 # content size (skip)
1037 elif fname
== 'content_size':
1038 fclines
= self
._field
_to
_clines
(fname
, ftype
, scope_name
,
1039 scope_prefix
, lambda x
: '0')
1040 fcline_groups
.append(fclines
)
1043 elif fname
== 'timestamp_begin':
1044 fclines
= self
._field
_to
_clines
(fname
, ftype
, scope_name
,
1046 lambda x
: 'clk_value')
1047 fcline_groups
.append(fclines
)
1049 # timestamp_end (skip)
1050 elif fname
== 'timestamp_end':
1051 fclines
= self
._field
_to
_clines
(fname
, ftype
, scope_name
,
1052 scope_prefix
, lambda x
: '0')
1053 fcline_groups
.append(fclines
)
1057 fclines
= self
._field
_to
_clines
(fname
, ftype
, scope_name
,
1059 self
._spc
_fname
_to
_pname
)
1060 fcline_groups
.append(fclines
)
1063 fcline_groups
.append([_CLine('return 0;')])
1065 clines
+= self
._join
_cline
_groups
(fcline_groups
)
1068 cblock
= _CBlock(clines
)
1069 src
= self
._cblock
_to
_source
(cblock
)
1073 def _gen_barectf_func_open(self
, stream
, gen_body
, hide_sid
=False):
1077 if self
._manual
_clock
:
1078 clock_param
= self
._gen
_manual
_clock
_param
(stream
)
1079 params
.append(clock_param
)
1082 for fname
, ftype
in stream
.packet_context
.fields
.items():
1083 if fname
in self
._packet
_context
_known
_fields
:
1086 ptype
= self
._get
_obj
_param
_ctype
(ftype
)
1087 pname
= self
._spc
_fname
_to
_pname
(fname
)
1088 param
= '{} {}'.format(ptype
, pname
)
1089 params
.append(param
)
1094 params_str
= ',\n\t'.join([''] + params
)
1102 t
= barectf
.templates
.FUNC_OPEN
1103 func
= t
.format(si
=self
._si
_str
, prefix
=self
._prefix
, sid
=sid
,
1108 func
+= self
._gen
_barectf
_func
_open
_body
(stream
)
1115 def _gen_barectf_func_init_body(self
, stream
):
1118 line
= 'uint32_t ctx_at_bkup;'
1119 clines
.append(_CLine(line
))
1121 # set context parameters
1122 clines
.append(_CLine(''))
1123 clines
.append(_CLine("/* barectf context parameters */"))
1124 clines
.append(_CLine('ctx->buf = buf;'))
1125 clines
.append(_CLine('ctx->buf_size = buf_size * 8;'))
1126 clines
.append(_CLine('{} = 0;'.format(self
._CTX
_AT
)))
1128 if not self
._manual
_clock
:
1129 clines
.append(_CLine('ctx->clock_cb = clock_cb;'))
1130 clines
.append(_CLine('ctx->clock_cb_data = clock_cb_data;'))
1132 # set context offsets
1133 clines
.append(_CLine(''))
1134 clines
.append(_CLine("/* barectf context offsets */"))
1135 ph_size
, ph_offvars
= self
._get
_ph
_size
_offvars
()
1136 pc_size
, pc_offvars
= self
._get
_pc
_size
_offvars
(stream
)
1137 pc_alignment
= self
._get
_obj
_alignment
(stream
.packet_context
)
1138 pc_offset
= self
._get
_alignment
(ph_size
, pc_alignment
)
1140 for offvar
, offset
in ph_offvars
.items():
1141 offvar_field
= self
._get
_offvar
_name
(offvar
, 'tph')
1142 line
= 'ctx->{} = {};'.format(offvar_field
, offset
)
1143 clines
.append(_CLine(line
))
1145 for offvar
, offset
in pc_offvars
.items():
1146 offvar_field
= self
._get
_offvar
_name
(offvar
, 'spc')
1147 line
= 'ctx->{} = {};'.format(offvar_field
, pc_offset
+ offset
)
1148 clines
.append(_CLine(line
))
1150 clines
.append(_CLine(''))
1152 # packet header fields
1154 scope_name
= 'trace.packet.header'
1155 scope_prefix
= 'tph'
1157 for fname
, ftype
in self
._doc
.trace
.packet_header
.fields
.items():
1159 if fname
== 'magic':
1160 fclines
= self
._field
_to
_clines
(fname
, ftype
, scope_name
,
1162 lambda x
: '0xc1fc1fc1UL')
1163 fcline_groups
.append(fclines
)
1166 elif fname
== 'stream_id':
1167 fclines
= self
._field
_to
_clines
(fname
, ftype
, scope_name
,
1169 lambda x
: str(stream
.id))
1170 fcline_groups
.append(fclines
)
1173 fcline_groups
.append([_CLine('return 0;')])
1175 clines
+= self
._join
_cline
_groups
(fcline_groups
)
1178 cblock
= _CBlock(clines
)
1179 src
= self
._cblock
_to
_source
(cblock
)
1183 def _gen_barectf_func_init(self
, stream
, gen_body
, hide_sid
=False):
1192 if not self
._manual
_clock
:
1193 ts_ftype
= stream
.event_header
['timestamp']
1194 ts_ptype
= self
._get
_obj
_param
_ctype
(ts_ftype
)
1195 fmt
= ',\n\t{} (*clock_cb)(void*),\n\tvoid* clock_cb_data'
1196 params
= fmt
.format(ts_ptype
)
1198 t
= barectf
.templates
.FUNC_INIT
1199 func
= t
.format(si
=self
._si
_str
, prefix
=self
._prefix
, sid
=sid
,
1204 func
+= self
._gen
_barectf
_func
_init
_body
(stream
)
1211 def _gen_get_clock_value(self
):
1212 if self
._manual
_clock
:
1213 return 'param_clock'
1215 return self
._CTX
_CALL
_CLOCK
_CB
1217 def _stream_has_timestamp_begin_end(self
, stream
):
1218 return self
._has
_timestamp
_begin
_end
[stream
.id]
1220 def _gen_write_ctx_field_integer(self
, src_name
, prefix
, name
, obj
):
1223 # save buffer position
1224 line
= 'ctx_at_bkup = {};'.format(self
._CTX
_AT
)
1225 clines
.append(_CLine(line
))
1227 # go back to field offset
1228 offvar
= self
._get
_offvar
_name
(name
, prefix
)
1229 line
= '{} = ctx->{};'.format(self
._CTX
_AT
, offvar
)
1230 clines
.append(_CLine(line
))
1233 clines
+= self
._write
_field
_integer
(None, src_name
, obj
)
1235 # restore buffer position
1236 line
= '{} = ctx_at_bkup;'.format(self
._CTX
_AT
)
1237 clines
.append(_CLine(line
))
1241 def _gen_barectf_func_close_body(self
, stream
):
1244 line
= 'uint32_t ctx_at_bkup;'
1245 clines
.append(_CLine(line
))
1247 # update timestamp end if present
1248 if self
._stream
_has
_timestamp
_begin
_end
(stream
):
1249 clines
.append(_CLine(''))
1250 clines
.append(_CLine("/* update packet context's timestamp_end */"))
1252 # get clock value ASAP
1253 clk_type
= self
._get
_clock
_type
(stream
)
1254 clk
= self
._gen
_get
_clock
_value
()
1255 line
= '{} clk_value = {};'.format(clk_type
, clk
)
1256 clines
.append(_CLine(line
))
1258 # write timestamp_end
1259 timestamp_end_integer
= stream
.packet_context
['timestamp_end']
1260 clines
+= self
._gen
_write
_ctx
_field
_integer
('clk_value', 'pc',
1262 timestamp_end_integer
)
1264 # update content_size
1265 clines
.append(_CLine(''))
1266 clines
.append(_CLine("/* update packet context's content_size */"))
1267 content_size_integer
= stream
.packet_context
['content_size']
1268 clines
+= self
._gen
_write
_ctx
_field
_integer
('ctx_at_bkup', 'pc',
1270 content_size_integer
)
1273 cblock
= _CBlock(clines
)
1274 src
= self
._cblock
_to
_source
(cblock
)
1278 def _gen_barectf_func_close(self
, stream
, gen_body
, hide_sid
=False):
1287 if self
._manual
_clock
:
1288 clock_param
= self
._gen
_manual
_clock
_param
(stream
)
1289 params
= ',\n\t{}'.format(clock_param
)
1291 t
= barectf
.templates
.FUNC_CLOSE
1292 func
= t
.format(si
=self
._si
_str
, prefix
=self
._prefix
, sid
=sid
,
1297 func
+= self
._gen
_barectf
_func
_close
_body
(stream
)
1304 def _gen_barectf_funcs_init(self
, gen_body
):
1307 if len(self
._doc
.streams
) == 1:
1312 for stream
in self
._doc
.streams
.values():
1313 funcs
.append(self
._gen
_barectf
_func
_init
(stream
, gen_body
,
1318 def _gen_barectf_funcs_open(self
, gen_body
):
1321 if len(self
._doc
.streams
) == 1:
1326 for stream
in self
._doc
.streams
.values():
1327 funcs
.append(self
._gen
_barectf
_func
_open
(stream
, gen_body
,
1332 def _gen_barectf_func_trace_event_body(self
, stream
, event
):
1335 # get clock value ASAP
1336 clk_type
= self
._get
_clock
_type
(stream
)
1337 clk
= self
._gen
_get
_clock
_value
()
1338 line
= '{} clk_value = {};'.format(clk_type
, clk
)
1339 clines
.append(_CLine(line
))
1340 clines
.append(_CLine(''))
1344 scope_name
= 'event.header'
1347 for fname
, ftype
in stream
.event_header
.fields
.items():
1350 fclines
= self
._field
_to
_clines
(fname
, ftype
, scope_name
,
1352 lambda x
: str(event
.id))
1353 fcline_groups
.append(fclines
)
1356 elif fname
== 'timestamp':
1357 fclines
= self
._field
_to
_clines
(fname
, ftype
, scope_name
,
1359 lambda x
: 'clk_value')
1360 fcline_groups
.append(fclines
)
1362 # stream event context
1363 if stream
.event_context
is not None:
1364 fclines
= self
._struct
_to
_clines
(stream
.event_context
,
1365 'stream.event.context', 'sec',
1366 self
._sec
_fname
_to
_pname
)
1367 fcline_groups
.append(fclines
)
1370 if event
.context
is not None:
1371 fclines
= self
._struct
_to
_clines
(event
.context
,
1372 'event.context', 'ec',
1373 self
._ec
_fname
_to
_pname
)
1374 fcline_groups
.append(fclines
)
1377 if event
.fields
is not None:
1378 fclines
= self
._struct
_to
_clines
(event
.fields
,
1379 'event.fields', 'ef',
1380 self
._ef
_fname
_to
_pname
)
1381 fcline_groups
.append(fclines
)
1384 fcline_groups
.append([_CLine('return 0;')])
1386 clines
+= self
._join
_cline
_groups
(fcline_groups
)
1389 cblock
= _CBlock(clines
)
1390 src
= self
._cblock
_to
_source
(cblock
)
1394 def _gen_barectf_func_trace_event(self
, stream
, event
, gen_body
, hide_sid
):
1398 if self
._manual
_clock
:
1399 clock_param
= self
._gen
_manual
_clock
_param
(stream
)
1400 params
.append(clock_param
)
1402 # stream event context params
1403 if stream
.event_context
is not None:
1404 for fname
, ftype
in stream
.event_context
.fields
.items():
1405 ptype
= self
._get
_obj
_param
_ctype
(ftype
)
1406 pname
= self
._sec
_fname
_to
_pname
(fname
)
1407 param
= '{} {}'.format(ptype
, pname
)
1408 params
.append(param
)
1410 # event context params
1411 if event
.context
is not None:
1412 for fname
, ftype
in event
.context
.fields
.items():
1413 ptype
= self
._get
_obj
_param
_ctype
(ftype
)
1414 pname
= self
._ec
_fname
_to
_pname
(fname
)
1415 param
= '{} {}'.format(ptype
, pname
)
1416 params
.append(param
)
1418 # event fields params
1419 if event
.fields
is not None:
1420 for fname
, ftype
in event
.fields
.fields
.items():
1421 ptype
= self
._get
_obj
_param
_ctype
(ftype
)
1422 pname
= self
._ef
_fname
_to
_pname
(fname
)
1423 param
= '{} {}'.format(ptype
, pname
)
1424 params
.append(param
)
1429 params_str
= ',\n\t'.join([''] + params
)
1437 t
= barectf
.templates
.FUNC_TRACE
1438 func
= t
.format(si
=self
._si
_str
, prefix
=self
._prefix
, sid
=sid
,
1439 evname
=event
.name
, params
=params_str
)
1443 func
+= self
._gen
_barectf
_func
_trace
_event
_body
(stream
, event
)
1450 def _gen_barectf_funcs_trace_stream(self
, stream
, gen_body
, hide_sid
):
1453 for event
in stream
.events
:
1454 funcs
.append(self
._gen
_barectf
_func
_trace
_event
(stream
, event
,
1455 gen_body
, hide_sid
))
1459 def _gen_barectf_funcs_trace(self
, gen_body
):
1462 if len(self
._doc
.streams
) == 1:
1467 for stream
in self
._doc
.streams
.values():
1468 funcs
+= self
._gen
_barectf
_funcs
_trace
_stream
(stream
, gen_body
,
1473 def _gen_barectf_funcs_close(self
, gen_body
):
1476 if len(self
._doc
.streams
) == 1:
1481 for stream
in self
._doc
.streams
.values():
1482 funcs
.append(self
._gen
_barectf
_func
_close
(stream
, gen_body
,
1487 def _gen_barectf_header(self
):
1488 ctx_structs
= self
._gen
_barectf
_contexts
_struct
()
1489 init_funcs
= self
._gen
_barectf
_funcs
_init
(self
._static
_inline
)
1490 open_funcs
= self
._gen
_barectf
_funcs
_open
(self
._static
_inline
)
1491 close_funcs
= self
._gen
_barectf
_funcs
_close
(self
._static
_inline
)
1492 trace_funcs
= self
._gen
_barectf
_funcs
_trace
(self
._static
_inline
)
1493 functions
= init_funcs
+ open_funcs
+ close_funcs
+ trace_funcs
1494 functions_str
= '\n\n'.join(functions
)
1495 t
= barectf
.templates
.HEADER
1496 header
= t
.format(prefix
=self
._prefix
, ucprefix
=self
._prefix
.upper(),
1497 barectf_ctx
=ctx_structs
, functions
=functions_str
)
1501 def _cblock_to_source_lines(self
, cblock
, indent
=1):
1503 indentstr
= '\t' * indent
1506 if type(line
) is _CBlock
:
1507 src
+= self
._cblock
_to
_source
_lines
(line
, indent
+ 1)
1509 src
.append(indentstr
+ line
)
1513 def _cblock_to_source(self
, cblock
, indent
=1):
1514 lines
= self
._cblock
_to
_source
_lines
(cblock
, indent
)
1516 return '\n'.join(lines
)
1518 def _set_params(self
):
1519 self
._has
_timestamp
_begin
_end
= {}
1521 for stream
in self
._doc
.streams
.values():
1522 has
= 'timestamp_begin' in stream
.packet_context
.fields
1523 self
._has
_timestamp
_begin
_end
[stream
.id] = has
1525 def gen_barectf(self
, metadata
, output
, prefix
, static_inline
,
1527 self
._metadata
= metadata
1528 self
._output
= output
1529 self
._prefix
= prefix
1530 self
._static
_inline
= static_inline
1531 self
._manual
_clock
= manual_clock
1535 self
._si
_str
= 'static inline '
1537 # open CTF metadata file
1538 _pinfo('opening CTF metadata file "{}"'.format(self
._metadata
))
1541 with
open(metadata
) as f
:
1542 self
._tsdl
= f
.read()
1544 _perror('cannot open/read CTF metadata file "{}"'.format(metadata
))
1546 # parse CTF metadata
1547 _pinfo('parsing CTF metadata file')
1550 self
._doc
= self
._parser
.parse(self
._tsdl
)
1551 except pytsdl
.parser
.ParseError
as e
:
1552 _perror('parse error: {}'.format(e
))
1554 # validate CTF metadata against barectf constraints
1555 _pinfo('validating CTF metadata file')
1556 self
._validate
_metadata
()
1557 _psuccess('CTF metadata file is valid')
1559 # set parameters for this generation
1563 _pinfo('generating barectf header file')
1564 self
._gen
_barectf
_header
()
1568 args
= _parse_args()
1569 generator
= BarectfCodeGenerator()
1570 generator
.gen_barectf(args
.metadata
, args
.output
, args
.prefix
,
1571 args
.static_inline
, args
.manual_clock
)