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
32 def _perror(msg
, exit_code
=1):
33 cprint('Error: {}'.format(msg
), 'red', attrs
=['bold'], file=sys
.stderr
)
38 cprint(':: {}'.format(msg
), 'blue', attrs
=['bold'], file=sys
.stderr
)
42 ap
= argparse
.ArgumentParser()
44 ap
.add_argument('-O', '--output', metavar
='OUTPUT', action
='store',
46 help='output directory of C files')
47 ap
.add_argument('-p', '--prefix', metavar
='PREFIX', action
='store',
49 help='custom prefix for C function and structure names')
50 ap
.add_argument('-s', '--static-inline', action
='store_true',
51 help='generate static inline C functions')
52 ap
.add_argument('-c', '--manual-clock', action
='store_true',
53 help='do not use a clock callback: pass clock value to tracing functions')
54 ap
.add_argument('metadata', metavar
='METADATA', action
='store',
55 help='CTF metadata input file')
58 args
= ap
.parse_args()
60 # validate output directory
61 if not os
.path
.isdir(args
.output
):
62 _perror('"{}" is not an existing directory'.format(args
.output
))
65 if not re
.match(r
'^[a-zA-Z_][a-zA-Z0-9_]*$', args
.prefix
):
66 _perror('"{}" is not a valid C identifier'.format(args
.prefix
))
68 # validate that metadata file exists
69 if not os
.path
.isfile(args
.metadata
):
70 _perror('"{}" is not an existing file'.format(args
.metadata
))
83 class BarectfCodeGenerator
:
86 _CTX_BUF_SIZE
= 'ctx->buf_size'
87 _CTX_BUF_AT
= '{}[{} >> 3]'.format(_CTX_BUF
, _CTX_AT
)
88 _CTX_BUF_AT_ADDR
= '&{}'.format(_CTX_BUF_AT
)
91 pytsdl
.tsdl
.ByteOrder
.BE
: 'be',
92 pytsdl
.tsdl
.ByteOrder
.LE
: 'le',
95 _tsdl_type_names_map
= {
96 pytsdl
.tsdl
.Integer
: 'integer',
97 pytsdl
.tsdl
.FloatingPoint
: 'floating point',
98 pytsdl
.tsdl
.Enum
: 'enumeration',
99 pytsdl
.tsdl
.String
: 'string',
100 pytsdl
.tsdl
.Array
: 'static array',
101 pytsdl
.tsdl
.Sequence
: 'dynamic array',
102 pytsdl
.tsdl
.Struct
: 'structure',
106 self
._parser
= pytsdl
.parser
.Parser()
107 self
._obj
_size
_cb
= {
108 pytsdl
.tsdl
.Struct
: self
._get
_struct
_size
,
109 pytsdl
.tsdl
.Integer
: self
._get
_integer
_size
,
110 pytsdl
.tsdl
.Enum
: self
._get
_enum
_size
,
111 pytsdl
.tsdl
.FloatingPoint
: self
._get
_floating
_point
_size
,
112 pytsdl
.tsdl
.Array
: self
._get
_array
_size
,
114 self
._obj
_alignment
_cb
= {
115 pytsdl
.tsdl
.Struct
: self
._get
_struct
_alignment
,
116 pytsdl
.tsdl
.Integer
: self
._get
_integer
_alignment
,
117 pytsdl
.tsdl
.Enum
: self
._get
_enum
_alignment
,
118 pytsdl
.tsdl
.FloatingPoint
: self
._get
_floating
_point
_alignment
,
119 pytsdl
.tsdl
.Array
: self
._get
_array
_alignment
,
120 pytsdl
.tsdl
.Sequence
: self
._get
_sequence
_alignment
,
121 pytsdl
.tsdl
.String
: self
._get
_string
_alignment
,
123 self
._obj
_param
_ctype
_cb
= {
124 pytsdl
.tsdl
.Struct
: lambda obj
: 'const void*',
125 pytsdl
.tsdl
.Integer
: self
._get
_integer
_param
_ctype
,
126 pytsdl
.tsdl
.Enum
: self
._get
_enum
_param
_ctype
,
127 pytsdl
.tsdl
.FloatingPoint
: self
._get
_floating
_point
_param
_ctype
,
128 pytsdl
.tsdl
.Array
: lambda obj
: 'const void*',
129 pytsdl
.tsdl
.Sequence
: lambda obj
: 'const void*',
130 pytsdl
.tsdl
.String
: lambda obj
: 'const char*',
132 self
._write
_field
_obj
_cb
= {
133 pytsdl
.tsdl
.Struct
: self
._write
_field
_struct
,
134 pytsdl
.tsdl
.Integer
: self
._write
_field
_integer
,
135 pytsdl
.tsdl
.Enum
: self
._write
_field
_enum
,
136 pytsdl
.tsdl
.FloatingPoint
: self
._write
_field
_floating
_point
,
137 pytsdl
.tsdl
.Array
: self
._write
_field
_array
,
138 pytsdl
.tsdl
.Sequence
: self
._write
_field
_sequence
,
139 pytsdl
.tsdl
.String
: self
._write
_field
_string
,
142 # TODO: prettify this function
143 def _validate_struct(self
, struct
):
144 # just in case we call this with the wrong type
145 if type(struct
) is not pytsdl
.tsdl
.Struct
:
146 raise RuntimeError('expecting a struct')
148 # make sure inner structures are at least byte-aligned
149 if self
._get
_obj
_alignment
(struct
) < 8:
150 raise RuntimeError('inner struct must be at least byte-aligned')
153 for fname
, ftype
in struct
.fields
.items():
154 if type(ftype
) is pytsdl
.tsdl
.Sequence
:
155 raise RuntimeError('field "{}" is a dynamic array (not allowed here)'.format(fname
))
156 elif type(ftype
) is pytsdl
.tsdl
.Array
:
157 # we need to check every element until we find a terminal one
158 element
= ftype
.element
161 if type(element
) is pytsdl
.tsdl
.Sequence
:
162 raise RuntimeError('field "{}" contains a dynamic array (not allowed here)'.format(fname
))
163 elif type(element
) is pytsdl
.tsdl
.Variant
:
164 raise RuntimeError('field "{}" contains a variant (unsupported)'.format(fname
))
165 elif type(element
) is pytsdl
.tsdl
.String
:
166 raise RuntimeError('field "{}" contains a string (not allowed here)'.format(fname
))
167 elif type(element
) is pytsdl
.tsdl
.Struct
:
168 _validate_struct(element
)
169 elif type(element
) is pytsdl
.tsdl
.Integer
:
170 if self
._get
_obj
_size
(element
) > 64:
171 raise RuntimeError('integer field "{}" larger than 64-bit'.format(fname
))
172 elif type(element
) is pytsdl
.tsdl
.FloatingPoint
:
173 if self
._get
_obj
_size
(element
) > 64:
174 raise RuntimeError('floating point field "{}" larger than 64-bit'.format(fname
))
175 elif type(element
) is pytsdl
.tsdl
.Enum
:
176 if self
._get
_obj
_size
(element
) > 64:
177 raise RuntimeError('enum field "{}" larger than 64-bit'.format(fname
))
179 if type(element
) is pytsdl
.tsdl
.Array
:
180 # still an array, continue
181 element
= element
.element
183 # found the terminal element
185 elif type(ftype
) is pytsdl
.tsdl
.Variant
:
186 raise RuntimeError('field "{}" is a variant (unsupported)'.format(fname
))
187 elif type(ftype
) is pytsdl
.tsdl
.String
:
188 raise RuntimeError('field "{}" is a string (not allowed here)'.format(fname
))
189 elif type(ftype
) is pytsdl
.tsdl
.Struct
:
190 self
._validate
_struct
(ftype
)
191 elif type(ftype
) is pytsdl
.tsdl
.Integer
:
192 if self
._get
_obj
_size
(ftype
) > 64:
193 raise RuntimeError('integer field "{}" larger than 64-bit'.format(fname
))
194 elif type(ftype
) is pytsdl
.tsdl
.FloatingPoint
:
195 if self
._get
_obj
_size
(ftype
) > 64:
196 raise RuntimeError('floating point field "{}" larger than 64-bit'.format(fname
))
197 elif type(ftype
) is pytsdl
.tsdl
.Enum
:
198 if self
._get
_obj
_size
(ftype
) > 64:
199 raise RuntimeError('enum field "{}" larger than 64-bit'.format(fname
))
201 def _validate_context_field(self
, struct
):
202 if type(struct
) is not pytsdl
.tsdl
.Struct
:
203 raise RuntimeError('expecting a struct')
205 for fname
, ftype
in struct
.fields
.items():
206 if type(ftype
) is pytsdl
.tsdl
.Variant
:
207 raise RuntimeError('field "{}" is a variant (unsupported)'.format(fname
))
208 elif type(ftype
) is pytsdl
.tsdl
.Struct
:
209 # validate inner structure against barectf constraints
210 self
._validate
_struct
(ftype
)
212 def _validate_integer(self
, integer
, size
=None, align
=None,
214 if type(integer
) is not pytsdl
.tsdl
.Integer
:
215 raise RuntimeError('expected integer')
218 if integer
.size
!= size
:
219 raise RuntimeError('expected {}-bit integer'.format(size
))
221 if align
is not None:
222 if integer
.align
!= align
:
223 raise RuntimeError('expected integer with {}-bit alignment'.format(align
))
225 if signed
is not None:
226 if integer
.signed
!= signed
:
227 raise RuntimeError('expected {} integer'.format('signed' if signed
else 'unsigned'))
229 def _validate_packet_header(self
, packet_header
):
231 self
._validate
_struct
(packet_header
)
232 except RuntimeError as e
:
233 _perror('packet header: {}'.format(e
))
235 # magic must be the first field
236 if 'magic' in packet_header
.fields
:
237 if list(packet_header
.fields
.keys())[0] != 'magic':
238 _perror('packet header: "magic" must be the first field')
240 _perror('packet header: missing "magic" field')
242 # magic must be a 32-bit unsigned integer, 32-bit aligned
244 self
._validate
_integer
(packet_header
['magic'], 32, 32, False)
245 except RuntimeError as e
:
246 _perror('packet header: "magic": {}'.format(e
))
248 # mandatory stream_id
249 if 'stream_id' not in packet_header
.fields
:
250 _perror('packet header: missing "stream_id" field')
252 # stream_id must be an unsigned integer
254 self
._validate
_integer
(packet_header
['stream_id'], signed
=False)
255 except RuntimeError as e
:
256 _perror('packet header: "stream_id": {}'.format(e
))
258 def _dot_name_to_str(self
, name
):
259 return '.'.join(name
)
261 def _compare_integers(self
, int1
, int2
):
262 if type(int1
) is not pytsdl
.tsdl
.Integer
:
265 if type(int2
) is not pytsdl
.tsdl
.Integer
:
268 size
= int1
.size
== int2
.size
269 align
= int1
.align
== int2
.align
270 cmap
= int1
.map == int2
.map
271 base
= int1
.base
== int2
.base
272 encoding
= int1
.encoding
== int2
.encoding
273 signed
= int1
.signed
== int2
.signed
274 comps
= (size
, align
, cmap
, base
, encoding
, signed
)
276 # True means 1 for sum()
277 return sum(comps
) == len(comps
)
279 def _validate_packet_context(self
, stream
):
280 packet_context
= stream
.packet_context
284 self
._validate
_struct
(packet_context
)
285 except RuntimeError as e
:
286 _perror('stream {}: packet context: {}'.format(sid
, e
))
288 fields
= packet_context
.fields
290 # if timestamp_begin exists, timestamp_end must exist
291 if 'timestamp_begin' in fields
or 'timestamp_end' in fields
:
292 if 'timestamp_begin' not in fields
or 'timestamp_end' not in fields
:
293 _perror('stream {}: packet context: "timestamp_begin" must exist if "timestamp_end" exists'.format(sid
))
295 # timestamp_begin and timestamp_end must have the same integer
296 # as the event header's timestamp field (should exist by now)
297 timestamp
= stream
.event_header
['timestamp']
299 if not self
._compare
_integers
(fields
['timestamp_begin'], timestamp
):
300 _perror('stream {}: packet context: "timestamp_begin": integer type different from event header\'s "timestamp" field'.format(sid
))
302 if not self
._compare
_integers
(fields
['timestamp_end'], timestamp
):
303 _perror('stream {}: packet context: "timestamp_end": integer type different from event header\'s "timestamp" field'.format(sid
))
305 # content_size must exist and be an unsigned integer
306 if 'content_size' not in fields
:
307 _perror('stream {}: packet context: missing "content_size" field'.format(sid
))
310 self
._validate
_integer
(fields
['content_size'], 32, 32, False)
313 self
._validate
_integer
(fields
['content_size'], 64, 64, False)
315 _perror('stream {}: packet context: "content_size": expecting unsigned 32-bit/64-bit integer'.format(sid
))
317 # packet_size must exist and be an unsigned integer
318 if 'packet_size' not in fields
:
319 _perror('stream {}: packet context: missing "packet_size" field'.format(sid
))
322 self
._validate
_integer
(fields
['packet_size'], 32, 32, False)
325 self
._validate
_integer
(fields
['packet_size'], 64, 64, False)
327 _perror('stream {}: packet context: "packet_size": expecting unsigned 32-bit/64-bit integer'.format(sid
))
329 # if cpu_id exists, must be an unsigned integer
330 if 'cpu_id' in fields
:
332 self
._validate
_integer
(fields
['cpu_id'], signed
=False)
333 except RuntimeError as e
:
334 _perror('stream {}: packet context: "cpu_id": {}'.format(sid
, e
))
336 def _validate_event_header(self
, stream
):
337 event_header
= stream
.event_header
341 self
._validate
_struct
(event_header
)
342 except RuntimeError as e
:
343 _perror('stream {}: event header: {}'.format(sid
, e
))
345 fields
= event_header
.fields
347 # id must exist and be an unsigned integer
348 if 'id' not in fields
:
349 _perror('stream {}: event header: missing "id" field'.format(sid
))
352 self
._validate
_integer
(fields
['id'], signed
=False)
353 except RuntimeError as e
:
354 _perror('stream {}: "id": {}'.format(sid
, format(e
)))
357 # timestamp must exist, be an unsigned integer and be mapped to a valid clock
358 if 'timestamp' not in fields
:
359 _perror('stream {}: event header: missing "timestamp" field'.format(sid
))
362 self
._validate
_integer
(fields
['timestamp'], signed
=False)
363 except RuntimeError as e
:
364 _perror('stream {}: "timestamp": {}'.format(sid
, format(e
)))
366 def _validate_stream_event_context(self
, stream
):
367 stream_event_context
= stream
.event_context
370 if stream_event_context
is None:
374 self
._validate
_context
_field
(stream_event_context
)
375 except RuntimeError as e
:
376 _perror('stream {}: event context: {}'.format(sid
, e
))
378 def _validate_event_context(self
, stream
, event
):
379 event_context
= event
.context
383 if event_context
is None:
387 self
._validate
_context
_field
(event_context
)
388 except RuntimeError as e
:
389 _perror('stream {}: event {}: context: {}'.format(sid
, eid
, e
))
391 def _validate_event_fields(self
, stream
, event
):
392 event_fields
= event
.fields
397 self
._validate
_context
_field
(event_fields
)
398 except RuntimeError as e
:
399 _perror('stream {}: event {}: fields: {}'.format(sid
, eid
, e
))
401 def _validate_all_scopes(self
):
403 self
._validate
_packet
_header
(self
._doc
.trace
.packet_header
)
406 for stream
in self
._doc
.streams
.values():
407 self
._validate
_event
_header
(stream
)
408 self
._validate
_packet
_context
(stream
)
409 self
._validate
_stream
_event
_context
(stream
)
412 for event
in stream
.events
:
413 self
._validate
_event
_context
(stream
, event
)
414 self
._validate
_event
_fields
(stream
, event
)
416 def _validate_metadata(self
):
417 self
._validate
_all
_scopes
()
426 def _get_alignment(self
, at
, align
):
427 return (at
+ align
- 1) & -align
429 # this converts a tree of offset variables:
444 # field_other_struct_field -> 16
445 # field_other_struct_yeah -> 20
448 def _offvars_tree_to_vars(self
, offvars_tree
, prefix
=None,
449 off_vars
=collections
.OrderedDict()):
450 for name
, offset
in offvars_tree
.items():
451 if prefix
is not None:
452 varname
= '{}_{}'.format(prefix
, name
)
456 if isinstance(offset
, dict):
457 self
._offvars
_tree
_to
_vars
(offset
, varname
, off_vars
)
459 off_vars
[varname
] = offset
463 # returns the size of a struct with _static size_
464 def _get_struct_size(self
, struct
,
465 offvars_tree
=collections
.OrderedDict(),
469 for fname
, ftype
in struct
.fields
.items():
470 field_alignment
= self
._get
_obj
_alignment
(ftype
)
471 offset
= self
._get
_alignment
(offset
, field_alignment
)
473 if type(ftype
) is pytsdl
.tsdl
.Struct
:
474 offvars_tree
[fname
] = collections
.OrderedDict()
475 sz
= self
._get
_struct
_size
(ftype
, offvars_tree
[fname
],
476 base_offset
+ offset
)
478 # only integers may act as sequence lengths
479 if type(ftype
) is pytsdl
.tsdl
.Integer
:
480 offvars_tree
[fname
] = base_offset
+ offset
482 sz
= self
._get
_obj
_size
(ftype
)
488 def _get_array_size(self
, array
):
489 element
= array
.element
491 # effective size of one element includes its alignment after its size
492 size
= self
._get
_obj
_size
(element
)
493 align
= self
._get
_obj
_alignment
(element
)
495 return self
._get
_alignment
(size
, align
) * array
.length
497 def _get_enum_size(self
, enum
):
498 return self
._get
_obj
_size
(enum
.integer
)
500 def _get_floating_point_size(self
, floating_point
):
501 return floating_point
.exp_dig
+ floating_point
.mant_dig
503 def _get_integer_size(self
, integer
):
506 def _get_obj_size(self
, obj
):
507 return self
._obj
_size
_cb
[type(obj
)](obj
)
509 def _get_struct_alignment(self
, struct
):
510 if struct
.align
is not None:
515 for fname
, ftype
in struct
.fields
.items():
516 cur_align
= max(self
._get
_obj
_alignment
(ftype
), cur_align
)
520 def _get_integer_alignment(self
, integer
):
523 def _get_floating_point_alignment(self
, floating_point
):
524 return floating_point
.align
526 def _get_enum_alignment(self
, enum
):
527 return self
._get
_obj
_alignment
(enum
.integer
)
529 def _get_string_alignment(self
, string
):
532 def _get_array_alignment(self
, array
):
533 return self
._get
_obj
_alignment
(array
.element
)
535 def _get_sequence_alignment(self
, sequence
):
536 return self
._get
_obj
_alignment
(sequence
.element
)
538 def _get_obj_alignment(self
, obj
):
539 return self
._obj
_alignment
_cb
[type(obj
)](obj
)
541 def _name_to_param_name(self
, prefix
, name
):
542 return 'param_{}_{}'.format(prefix
, name
)
544 def _ev_f_name_to_param_name(self
, name
):
545 return self
._name
_to
_param
_name
('evf', name
)
547 def _ev_c_name_to_param_name(self
, name
):
548 return self
._name
_to
_param
_name
('evc', name
)
550 def _ev_sec_name_to_param_name(self
, name
):
551 return self
._name
_to
_param
_name
('evsec', name
)
553 def _ev_h_name_to_param_name(self
, name
):
554 return self
._name
_to
_param
_name
('evh', name
)
556 def _s_pc_name_to_param_name(self
, name
):
557 return self
._name
_to
_param
_name
('spc', name
)
559 def _s_ph_name_to_param_name(self
, name
):
560 return self
._name
_to
_param
_name
('sph', name
)
562 def _get_integer_param_ctype(self
, integer
):
563 signed
= 'u' if not integer
.signed
else ''
565 if integer
.size
== 8:
567 elif integer
.size
== 16:
569 elif integer
.size
== 32:
571 elif integer
.size
== 64:
574 # if the integer is signed and of uncommon size, the sign bit is
575 # at a custom position anyway so we use a 64-bit unsigned
581 if integer
.size
< 16:
583 elif integer
.size
< 32:
585 elif integer
.size
< 64:
590 return '{}int{}_t'.format(signed
, sz
)
592 def _get_enum_param_ctype(self
, enum
):
593 return self
._get
_obj
_param
_ctype
(enum
.integer
)
595 def _get_floating_point_param_ctype(self
, fp
):
596 if fp
.exp_dig
== 8 and fp
.mant_dig
== 24 and fp
.align
== 32:
598 elif fp
.exp_dig
== 11 and fp
.mant_dig
== 53 and fp
.align
== 64:
603 def _get_obj_param_ctype(self
, obj
):
604 return self
._obj
_param
_ctype
_cb
[type(obj
)](obj
)
606 def _get_chk_offset_v(self
, size
):
607 fmt
= '{}_CHK_OFFSET_V({}, {}, {});'
608 ret
= fmt
.format(self
._prefix
.upper(), self
._CTX
_AT
,
609 self
._CTX
_BUF
_SIZE
, size
)
613 def _get_chk_offset_v_cline(self
, size
):
614 return _CLine(self
._get
_chk
_offset
_v
(size
))
616 def _get_align_offset(self
, align
):
617 fmt
= '{}_ALIGN_OFFSET({}, {});'
618 ret
= fmt
.format(self
._prefix
.upper(), self
._CTX
_AT
, align
)
622 def _get_align_offset_cline(self
, size
):
623 return _CLine(self
._get
_align
_offset
(size
))
625 def _write_field_struct(self
, fname
, src_name
, struct
):
626 size
= self
._get
_struct
_size
(struct
)
627 size_bytes
= self
._get
_alignment
(size
, 8) // 8
628 dst
= self
._CTX
_BUF
_AT
_ADDR
631 # memcpy() is safe since barectf requires inner structures
633 self
._get
_chk
_offset
_v
_cline
(size
),
634 _CLine('memcpy({}, {}, {});'.format(dst
, src_name
, size_bytes
)),
635 _CLine('{} += {};'.format(self
._CTX
_AT
, size
)),
638 def _write_field_integer(self
, fname
, src_name
, integer
):
639 bo
= self
._bo
_suffixes
_map
[integer
.byte_order
]
641 t
= self
._get
_obj
_param
_ctype
(integer
)
643 length
= self
._get
_obj
_size
(integer
)
644 fmt
= 'barectf_bitfield_write_{}({}, {}, {}, {}, {});'
647 self
._get
_chk
_offset
_v
_cline
(length
),
648 _CLine(fmt
.format(bo
, ptr
, t
, start
, length
, src_name
)),
649 _CLine('{} += {};'.format(self
._CTX
_AT
, length
))
652 def _write_field_enum(self
, fname
, src_name
, enum
):
653 return self
._write
_field
_obj
(fname
, src_name
, enum
.integer
)
655 def _write_field_floating_point(self
, fname
, src_name
, floating_point
):
656 bo
= self
._bo
_suffixes
_map
[floating_point
.byte_order
]
658 t
= self
._get
_obj
_param
_ctype
(floating_point
)
660 length
= self
._get
_obj
_size
(floating_point
)
661 fmt
= 'barectf_bitfield_write_{}({}, {}, {}, {}, {});'
664 self
._get
_chk
_offset
_v
_cline
(length
),
665 _CLine(fmt
.format(bo
, ptr
, t
, start
, length
, src_name
)),
666 _CLine('{} += {};'.format(self
._CTX
_AT
, length
))
669 def _write_field_array(self
, fname
, src_name
, array
):
672 # array index variable declaration
673 iv
= 'ia_{}'.format(fname
)
674 lines
.append(_CLine('uint32_t {};'.format(iv
)))
676 # for loop using array's static length
677 line
= 'for ({iv} = 0; {iv} < {l}; ++{iv}) {{'.format(iv
=iv
, l
=array
.length
)
678 lines
.append(_CLine(line
))
680 # for loop statements
681 for_block
= _CBlock()
683 # align bit index before writing to the buffer
684 element_align
= self
._get
_obj
_alignment
(array
.element
)
685 cline
= self
._get
_align
_offset
_cline
(element_align
)
686 for_block
.append(cline
)
688 # write element to the buffer
689 for_block
+= self
._write
_field
_obj
(fname
, src_name
, array
.element
)
690 lines
.append(for_block
)
693 lines
.append(_CLine('}'))
697 def _write_field_sequence(self
, fname
, src_name
, sequence
):
699 _CLine('would write sequence here;'),
702 def _write_field_string(self
, fname
, src_name
, string
):
705 # string index variable declaration
706 iv
= 'is_{}'.format(fname
)
707 lines
.append(_CLine('uint32_t {};'.format(iv
)))
709 # for loop; loop until the end of the source string is reached
710 fmt
= "for ({iv} = 0; {src}[{iv}] != '\\0'; ++{iv}, {ctxat} += 8) {{"
711 line
= fmt
.format(iv
=iv
, src
=src_name
, ctxat
=self
._CTX
_AT
)
712 lines
.append(_CLine(line
))
714 # for loop statements
715 for_block
= _CBlock()
717 # check offset overflow
718 for_block
.append(self
._get
_chk
_offset
_v
_cline
(8))
720 # write byte to the buffer
721 fmt
= '{dst} = {src}[{iv}];'
722 line
= fmt
.format(dst
=self
._CTX
_BUF
_AT
, iv
=iv
, src
=src_name
)
723 for_block
.append(_CLine(line
))
726 lines
.append(for_block
)
727 lines
.append(_CLine('}'))
729 # write NULL character to the buffer
730 lines
.append(_CLine("{} = '\\0';".format(self
._CTX
_BUF
_AT
)))
731 lines
.append(_CLine('{} += 8;'.format(self
._CTX
_AT
)))
735 def _write_field_obj(self
, fname
, src_name
, ftype
):
736 return self
._write
_field
_obj
_cb
[type(ftype
)](fname
, src_name
, ftype
)
738 def _get_offvar_name(self
, name
):
739 return 'off_{}'.format(name
)
741 def _get_offvar_name_from_expr(self
, expr
):
742 return self
._get
_offvar
_name
('_'.join(expr
))
744 def _field_to_cline(self
, fname
, ftype
, scope_name
, param_name_cb
):
746 pname
= param_name_cb(fname
)
747 align
= self
._get
_obj
_alignment
(ftype
)
750 fmt
= '/* write {} field "{}" ({}) */'
751 line
= fmt
.format(scope_name
, fname
,
752 self
._tsdl
_type
_names
_map
[type(ftype
)])
753 lines
.append(_CLine(line
))
755 # align bit index before writing to the buffer
756 cline
= self
._get
_align
_offset
_cline
(align
)
759 # write offset variables
760 if type(ftype
) is pytsdl
.tsdl
.Struct
:
761 offvars_tree
= collections
.OrderedDict()
762 self
._get
_struct
_size
(ftype
, offvars_tree
)
763 off_vars
= self
._offvars
_tree
_to
_vars
(offvars_tree
)
765 # as many offset as there are child fields because a future
766 # sequence could refer to any of those fields
767 for lname
, offset
in off_vars
.items():
768 offvar
= self
._get
_offvar
_name
('_'.join([fname
, lname
]))
769 fmt
= 'uint32_t {} = {} + {};'
770 line
= fmt
.format(offvar
, self
._CTX
_AT
, offset
);
771 lines
.append(_CLine(line
))
772 elif type(ftype
) is pytsdl
.tsdl
.Integer
:
773 # offset of this simple field is the current bit index
774 offvar
= self
._get
_offvar
_name
(fname
)
775 line
= 'uint32_t {} = {};'.format(offvar
, self
._CTX
_AT
)
776 lines
.append(_CLine(line
))
778 lines
+= self
._write
_field
_obj
(fname
, pname
, ftype
)
782 def _struct_to_clines(self
, struct
, scope_name
, param_name_cb
):
785 for fname
, ftype
in struct
.fields
.items():
786 lines
= self
._field
_to
_cline
(fname
, ftype
, scope_name
,
788 line_groups
.append(lines
)
793 output_lines
= line_groups
[0]
795 for lines
in line_groups
[1:]:
796 output_lines
.append('')
797 output_lines
+= lines
801 def _cblock_to_source_lines(self
, cblock
, indent
=1):
803 indentstr
= '\t' * indent
806 if type(line
) is _CBlock
:
807 src
+= self
._cblock
_to
_source
_lines
(line
, indent
+ 1)
809 src
.append(indentstr
+ line
)
813 def _cblock_to_source(self
, cblock
, indent
=1):
814 lines
= self
._cblock
_to
_source
_lines
(cblock
, indent
)
816 return '\n'.join(lines
)
818 def gen_barectf(self
, metadata
, output
, prefix
, static_inline
,
820 self
._metadata
= metadata
821 self
._output
= output
822 self
._prefix
= prefix
823 self
._static
_inline
= static_inline
824 self
._manual
_clock
= manual_clock
826 # open CTF metadata file
828 with
open(metadata
) as f
:
829 self
._tsdl
= f
.read()
831 _perror('cannot open/read CTF metadata file "{}"'.format(metadata
))
835 self
._doc
= self
._parser
.parse(self
._tsdl
)
836 except pytsdl
.parser
.ParseError
as e
:
837 _perror('parse error: {}'.format(e
))
839 # validate CTF metadata against barectf constraints
840 self
._validate
_metadata
()
842 clines
= self
._struct
_to
_clines
(self
._doc
.streams
[0].get_event(0).fields
,
843 'stream event context',
844 self
._ev
_f
_name
_to
_param
_name
)
845 source
= self
._cblock
_to
_source
(clines
)
851 generator
= BarectfCodeGenerator()
852 generator
.gen_barectf(args
.metadata
, args
.output
, args
.prefix
,
853 args
.static_inline
, args
.manual_clock
)
This page took 0.049036 seconds and 5 git commands to generate.