return args
-# TODO: prettify this function
-def _validate_struct(struct):
- # just in case we call this with the wrong type
- if type(struct) is not pytsdl.tsdl.Struct:
- raise RuntimeError('expecting a struct')
-
- # make sure inner structures are at least byte-aligned
- if _get_obj_alignment(struct) < 8:
- raise RuntimeError('inner struct must be at least byte-aligned')
-
- # check each field
- for name, ftype in struct.fields.items():
- if type(ftype) is pytsdl.tsdl.Sequence:
- raise RuntimeError('field "{}" is a dynamic array (not allowed here)'.format(name))
- elif type(ftype) is pytsdl.tsdl.Array:
- # we need to check every element type until we find a terminal one
- end = False
- element = ftype.element
-
- while not end:
- if type(element) is pytsdl.tsdl.Sequence:
- raise RuntimeError('field "{}" contains a dynamic array (not allowed here)'.format(name))
- elif type(element) is pytsdl.tsdl.Variant:
- raise RuntimeError('field "{}" contains a variant (unsupported)'.format(name))
- elif type(element) is pytsdl.tsdl.String:
- raise RuntimeError('field "{}" contains a string (not allowed here)'.format(name))
- elif type(element) is pytsdl.tsdl.Struct:
- _validate_struct(element)
- elif type(element) is pytsdl.tsdl.Integer:
- if _get_integer_size(element) > 64:
- raise RuntimeError('integer field "{}" larger than 64-bit'.format(name))
- elif type(element) is pytsdl.tsdl.FloatingPoint:
- if _get_floating_point_size(element) > 64:
- raise RuntimeError('floating point field "{}" larger than 64-bit'.format(name))
- elif type(element) is pytsdl.tsdl.Enum:
- if _get_enum_size(element) > 64:
- raise RuntimeError('enum field "{}" larger than 64-bit'.format(name))
-
- if type(element) is pytsdl.tsdl.Array:
- # still an array, continue
- element = element.element
- else:
- # found the terminal element
- end = True
- elif type(ftype) is pytsdl.tsdl.Variant:
- raise RuntimeError('field "{}" is a variant (unsupported)'.format(name))
- elif type(ftype) is pytsdl.tsdl.String:
- raise RuntimeError('field "{}" is a string (not allowed here)'.format(name))
- elif type(ftype) is pytsdl.tsdl.Struct:
- _validate_struct(ftype)
- elif type(ftype) is pytsdl.tsdl.Integer:
- if _get_integer_size(ftype) > 64:
- raise RuntimeError('integer field "{}" larger than 64-bit'.format(name))
- elif type(ftype) is pytsdl.tsdl.FloatingPoint:
- if _get_floating_point_size(ftype) > 64:
- raise RuntimeError('floating point field "{}" larger than 64-bit'.format(name))
- elif type(ftype) is pytsdl.tsdl.Enum:
- if _get_enum_size(ftype) > 64:
- raise RuntimeError('enum field "{}" larger than 64-bit'.format(name))
-
-
-def _validate_context_field(struct):
- if type(struct) is not pytsdl.tsdl.Struct:
- raise RuntimeError('expecting a struct')
-
- for name, ftype in struct.fields.items():
- if type(ftype) is pytsdl.tsdl.Variant:
- raise RuntimeError('field "{}" is a variant (unsupported)'.format(name))
- elif type(ftype) is pytsdl.tsdl.Struct:
- # validate inner structure against barectf constraints
- _validate_struct(ftype)
-
-
-def _validate_integer(integer, size=None, align=None, signed=None):
- if type(integer) is not pytsdl.tsdl.Integer:
- raise RuntimeError('expected integer')
-
- if size is not None:
- if integer.size != size:
- raise RuntimeError('expected {}-bit integer'.format(size))
-
- if align is not None:
- if integer.align != align:
- raise RuntimeError('expected integer with {}-bit alignment'.format(align))
-
- if signed is not None:
- if integer.signed != signed:
- raise RuntimeError('expected {} integer'.format('signed' if signed else 'unsigned'))
+class _CBlock(list):
+ pass
-def _validate_packet_header(packet_header):
- try:
- _validate_struct(packet_header)
- except RuntimeError as e:
- _perror('packet header: {}'.format(e))
+class _CLine(str):
+ pass
- # magic must be the first field
- if 'magic' in packet_header.fields:
- if list(packet_header.fields.keys())[0] != 'magic':
- _perror('packet header: "magic" must be the first field')
- else:
- _perror('packet header: missing "magic" field')
- # magic must be a 32-bit unsigned integer, 32-bit aligned
- try:
- _validate_integer(packet_header['magic'], 32, 32, False)
- except RuntimeError as e:
- _perror('packet header: "magic": {}'.format(e))
+class BarectfCodeGenerator:
+ _CTX_AT = 'ctx->at'
+ _CTX_BUF = 'ctx->buf'
+ _CTX_BUF_SIZE = 'ctx->buf_size'
+ _CTX_BUF_AT = '{}[{} >> 3]'.format(_CTX_BUF, _CTX_AT)
+ _CTX_BUF_AT_ADDR = '&{}'.format(_CTX_BUF_AT)
+
+ _bo_suffixes_map = {
+ pytsdl.tsdl.ByteOrder.BE: 'be',
+ pytsdl.tsdl.ByteOrder.LE: 'le',
+ }
+
+ _tsdl_type_names_map = {
+ pytsdl.tsdl.Integer: 'integer',
+ pytsdl.tsdl.FloatingPoint: 'floating point',
+ pytsdl.tsdl.Enum: 'enumeration',
+ pytsdl.tsdl.String: 'string',
+ pytsdl.tsdl.Array: 'static array',
+ pytsdl.tsdl.Sequence: 'dynamic array',
+ pytsdl.tsdl.Struct: 'structure',
+ }
+
+ def __init__(self):
+ self._parser = pytsdl.parser.Parser()
+ self._obj_size_cb = {
+ pytsdl.tsdl.Struct: self._get_struct_size,
+ pytsdl.tsdl.Integer: self._get_integer_size,
+ pytsdl.tsdl.Enum: self._get_enum_size,
+ pytsdl.tsdl.FloatingPoint: self._get_floating_point_size,
+ pytsdl.tsdl.Array: self._get_array_size,
+ }
+ self._obj_alignment_cb = {
+ pytsdl.tsdl.Struct: self._get_struct_alignment,
+ pytsdl.tsdl.Integer: self._get_integer_alignment,
+ pytsdl.tsdl.Enum: self._get_enum_alignment,
+ pytsdl.tsdl.FloatingPoint: self._get_floating_point_alignment,
+ pytsdl.tsdl.Array: self._get_array_alignment,
+ pytsdl.tsdl.Sequence: self._get_sequence_alignment,
+ pytsdl.tsdl.String: self._get_string_alignment,
+ }
+ self._obj_param_ctype_cb = {
+ pytsdl.tsdl.Struct: lambda obj: 'const void*',
+ pytsdl.tsdl.Integer: self._get_integer_param_ctype,
+ pytsdl.tsdl.Enum: self._get_enum_param_ctype,
+ pytsdl.tsdl.FloatingPoint: self._get_floating_point_param_ctype,
+ pytsdl.tsdl.Array: lambda obj: 'const void*',
+ pytsdl.tsdl.Sequence: lambda obj: 'const void*',
+ pytsdl.tsdl.String: lambda obj: 'const char*',
+ }
+ self._write_field_obj_cb = {
+ pytsdl.tsdl.Struct: self._write_field_struct,
+ pytsdl.tsdl.Integer: self._write_field_integer,
+ pytsdl.tsdl.Enum: self._write_field_enum,
+ pytsdl.tsdl.FloatingPoint: self._write_field_floating_point,
+ pytsdl.tsdl.Array: self._write_field_array,
+ pytsdl.tsdl.Sequence: self._write_field_sequence,
+ pytsdl.tsdl.String: self._write_field_string,
+ }
+
+ # TODO: prettify this function
+ def _validate_struct(self, struct):
+ # just in case we call this with the wrong type
+ if type(struct) is not pytsdl.tsdl.Struct:
+ raise RuntimeError('expecting a struct')
+
+ # make sure inner structures are at least byte-aligned
+ if self._get_obj_alignment(struct) < 8:
+ raise RuntimeError('inner struct must be at least byte-aligned')
+
+ # check each field
+ for name, ftype in struct.fields.items():
+ if type(ftype) is pytsdl.tsdl.Sequence:
+ raise RuntimeError('field "{}" is a dynamic array (not allowed here)'.format(name))
+ elif type(ftype) is pytsdl.tsdl.Array:
+ # we need to check every element until we find a terminal one
+ element = ftype.element
+
+ while True:
+ if type(element) is pytsdl.tsdl.Sequence:
+ raise RuntimeError('field "{}" contains a dynamic array (not allowed here)'.format(name))
+ elif type(element) is pytsdl.tsdl.Variant:
+ raise RuntimeError('field "{}" contains a variant (unsupported)'.format(name))
+ elif type(element) is pytsdl.tsdl.String:
+ raise RuntimeError('field "{}" contains a string (not allowed here)'.format(name))
+ elif type(element) is pytsdl.tsdl.Struct:
+ _validate_struct(element)
+ elif type(element) is pytsdl.tsdl.Integer:
+ if self._get_obj_size(element) > 64:
+ raise RuntimeError('integer field "{}" larger than 64-bit'.format(name))
+ elif type(element) is pytsdl.tsdl.FloatingPoint:
+ if self._get_obj_size(element) > 64:
+ raise RuntimeError('floating point field "{}" larger than 64-bit'.format(name))
+ elif type(element) is pytsdl.tsdl.Enum:
+ if self._get_obj_size(element) > 64:
+ raise RuntimeError('enum field "{}" larger than 64-bit'.format(name))
+
+ if type(element) is pytsdl.tsdl.Array:
+ # still an array, continue
+ element = element.element
+ else:
+ # found the terminal element
+ break
+ elif type(ftype) is pytsdl.tsdl.Variant:
+ raise RuntimeError('field "{}" is a variant (unsupported)'.format(name))
+ elif type(ftype) is pytsdl.tsdl.String:
+ raise RuntimeError('field "{}" is a string (not allowed here)'.format(name))
+ elif type(ftype) is pytsdl.tsdl.Struct:
+ _validate_struct(ftype)
+ elif type(ftype) is pytsdl.tsdl.Integer:
+ if self._get_obj_size(ftype) > 64:
+ raise RuntimeError('integer field "{}" larger than 64-bit'.format(name))
+ elif type(ftype) is pytsdl.tsdl.FloatingPoint:
+ if self._get_obj_size(ftype) > 64:
+ raise RuntimeError('floating point field "{}" larger than 64-bit'.format(name))
+ elif type(ftype) is pytsdl.tsdl.Enum:
+ if self._get_obj_size(ftype) > 64:
+ raise RuntimeError('enum field "{}" larger than 64-bit'.format(name))
+
+ def _validate_context_field(self, struct):
+ if type(struct) is not pytsdl.tsdl.Struct:
+ raise RuntimeError('expecting a struct')
+
+ for name, ftype in struct.fields.items():
+ if type(ftype) is pytsdl.tsdl.Variant:
+ raise RuntimeError('field "{}" is a variant (unsupported)'.format(name))
+ elif type(ftype) is pytsdl.tsdl.Struct:
+ # validate inner structure against barectf constraints
+ self._validate_struct(ftype)
+
+ def _validate_integer(self, integer, size=None, align=None,
+ signed=None):
+ if type(integer) is not pytsdl.tsdl.Integer:
+ raise RuntimeError('expected integer')
+
+ if size is not None:
+ if integer.size != size:
+ raise RuntimeError('expected {}-bit integer'.format(size))
+
+ if align is not None:
+ if integer.align != align:
+ raise RuntimeError('expected integer with {}-bit alignment'.format(align))
+
+ if signed is not None:
+ if integer.signed != signed:
+ raise RuntimeError('expected {} integer'.format('signed' if signed else 'unsigned'))
+
+ def _validate_packet_header(self, packet_header):
+ try:
+ self._validate_struct(packet_header)
+ except RuntimeError as e:
+ _perror('packet header: {}'.format(e))
- # mandatory stream_id
- if 'stream_id' not in packet_header.fields:
- _perror('packet header: missing "stream_id" field')
+ # magic must be the first field
+ if 'magic' in packet_header.fields:
+ if list(packet_header.fields.keys())[0] != 'magic':
+ _perror('packet header: "magic" must be the first field')
+ else:
+ _perror('packet header: missing "magic" field')
- # stream_id must be an unsigned integer
- try:
- _validate_integer(packet_header['stream_id'], signed=False)
- except RuntimeError as e:
- _perror('packet header: "stream_id": {}'.format(e))
+ # magic must be a 32-bit unsigned integer, 32-bit aligned
+ try:
+ self._validate_integer(packet_header['magic'], 32, 32, False)
+ except RuntimeError as e:
+ _perror('packet header: "magic": {}'.format(e))
+ # mandatory stream_id
+ if 'stream_id' not in packet_header.fields:
+ _perror('packet header: missing "stream_id" field')
-def _dot_name_to_str(name):
- return '.'.join(name)
+ # stream_id must be an unsigned integer
+ try:
+ self._validate_integer(packet_header['stream_id'], signed=False)
+ except RuntimeError as e:
+ _perror('packet header: "stream_id": {}'.format(e))
+ def _dot_name_to_str(self, name):
+ return '.'.join(name)
-def _compare_integers(int1, int2):
- if type(int1) is not pytsdl.tsdl.Integer:
- return False
- if type(int2) is not pytsdl.tsdl.Integer:
- return False
+ def _compare_integers(self, int1, int2):
+ if type(int1) is not pytsdl.tsdl.Integer:
+ return False
- size = int1.size == int2.size
- align = int1.align == int2.align
- cmap = int1.map == int2.map
- base = int1.base == int2.base
- encoding = int1.encoding == int2.encoding
- signed = int1.signed == int2.signed
- comps = (size, align, cmap, base, encoding, signed)
+ if type(int2) is not pytsdl.tsdl.Integer:
+ return False
- # True means 1 for sum()
- return sum(comps) == len(comps)
+ size = int1.size == int2.size
+ align = int1.align == int2.align
+ cmap = int1.map == int2.map
+ base = int1.base == int2.base
+ encoding = int1.encoding == int2.encoding
+ signed = int1.signed == int2.signed
+ comps = (size, align, cmap, base, encoding, signed)
+ # True means 1 for sum()
+ return sum(comps) == len(comps)
-def _validate_packet_context(doc, stream):
- packet_context = stream.packet_context
- sid = stream.id
+ def _validate_packet_context(self, stream):
+ packet_context = stream.packet_context
+ sid = stream.id
- try:
- _validate_struct(packet_context)
- except RuntimeError as e:
- _perror('stream {}: packet context: {}'.format(sid, e))
+ try:
+ self._validate_struct(packet_context)
+ except RuntimeError as e:
+ _perror('stream {}: packet context: {}'.format(sid, e))
- fields = packet_context.fields
+ fields = packet_context.fields
- # if timestamp_begin exists, timestamp_end must exist
- if 'timestamp_begin' in fields or 'timestamp_end' in fields:
- if 'timestamp_begin' not in fields or 'timestamp_end' not in fields:
- _perror('stream {}: packet context: "timestamp_begin" must exist if "timestamp_end" exists'.format(sid))
- else:
- # timestamp_begin and timestamp_end must have the same integer
- # as the event header's timestamp field (should exist by now)
- timestamp = stream.event_header['timestamp']
+ # if timestamp_begin exists, timestamp_end must exist
+ if 'timestamp_begin' in fields or 'timestamp_end' in fields:
+ if 'timestamp_begin' not in fields or 'timestamp_end' not in fields:
+ _perror('stream {}: packet context: "timestamp_begin" must exist if "timestamp_end" exists'.format(sid))
+ else:
+ # timestamp_begin and timestamp_end must have the same integer
+ # as the event header's timestamp field (should exist by now)
+ timestamp = stream.event_header['timestamp']
- if not _compare_integers(fields['timestamp_begin'], timestamp):
- _perror('stream {}: packet context: "timestamp_begin": integer type different from event header\'s "timestamp" field'.format(sid))
+ if not self._compare_integers(fields['timestamp_begin'], timestamp):
+ _perror('stream {}: packet context: "timestamp_begin": integer type different from event header\'s "timestamp" field'.format(sid))
- if not _compare_integers(fields['timestamp_end'], timestamp):
- _perror('stream {}: packet context: "timestamp_end": integer type different from event header\'s "timestamp" field'.format(sid))
+ if not self._compare_integers(fields['timestamp_end'], timestamp):
+ _perror('stream {}: packet context: "timestamp_end": integer type different from event header\'s "timestamp" field'.format(sid))
- # content_size must exist and be an unsigned integer
- if 'content_size' not in fields:
- _perror('stream {}: packet context: missing "content_size" field'.format(sid))
+ # content_size must exist and be an unsigned integer
+ if 'content_size' not in fields:
+ _perror('stream {}: packet context: missing "content_size" field'.format(sid))
- try:
- _validate_integer(fields['content_size'], 32, 32, False)
- except:
try:
- _validate_integer(fields['content_size'], 64, 64, False)
+ self._validate_integer(fields['content_size'], 32, 32, False)
except:
- _perror('stream {}: packet context: "content_size": expecting unsigned 32-bit/64-bit integer'.format(sid))
+ try:
+ self._validate_integer(fields['content_size'], 64, 64, False)
+ except:
+ _perror('stream {}: packet context: "content_size": expecting unsigned 32-bit/64-bit integer'.format(sid))
- # packet_size must exist and be an unsigned integer
- if 'packet_size' not in fields:
- _perror('stream {}: packet context: missing "packet_size" field'.format(sid))
+ # packet_size must exist and be an unsigned integer
+ if 'packet_size' not in fields:
+ _perror('stream {}: packet context: missing "packet_size" field'.format(sid))
- try:
- _validate_integer(fields['packet_size'], 32, 32, False)
- except:
try:
- _validate_integer(fields['packet_size'], 64, 64, False)
+ self._validate_integer(fields['packet_size'], 32, 32, False)
except:
- _perror('stream {}: packet context: "packet_size": expecting unsigned 32-bit/64-bit integer'.format(sid))
+ try:
+ self._validate_integer(fields['packet_size'], 64, 64, False)
+ except:
+ _perror('stream {}: packet context: "packet_size": expecting unsigned 32-bit/64-bit integer'.format(sid))
+
+ # if cpu_id exists, must be an unsigned integer
+ if 'cpu_id' in fields:
+ try:
+ self._validate_integer(fields['cpu_id'], signed=False)
+ except RuntimeError as e:
+ _perror('stream {}: packet context: "cpu_id": {}'.format(sid, e))
+
+ def _validate_event_header(self, stream):
+ event_header = stream.event_header
+ sid = stream.id
- # if cpu_id exists, must be an unsigned integer
- if 'cpu_id' in fields:
try:
- _validate_integer(fields['cpu_id'], signed=False)
+ self._validate_struct(event_header)
except RuntimeError as e:
- _perror('stream {}: packet context: "cpu_id": {}'.format(sid, e))
-
-
-def _validate_event_header(doc, stream):
- event_header = stream.event_header
- sid = stream.id
-
- try:
- _validate_struct(event_header)
- except RuntimeError as e:
- _perror('stream {}: event header: {}'.format(sid, e))
-
- fields = event_header.fields
-
- # id must exist and be an unsigned integer
- if 'id' not in fields:
- _perror('stream {}: event header: missing "id" field'.format(sid))
+ _perror('stream {}: event header: {}'.format(sid, e))
- try:
- _validate_integer(fields['id'], signed=False)
- except RuntimeError as e:
- _perror('stream {}: "id": {}'.format(sid, format(e)))
+ fields = event_header.fields
+ # id must exist and be an unsigned integer
+ if 'id' not in fields:
+ _perror('stream {}: event header: missing "id" field'.format(sid))
- # timestamp must exist, be an unsigned integer and be mapped to a valid clock
- if 'timestamp' not in fields:
- _perror('stream {}: event header: missing "timestamp" field'.format(sid))
-
- try:
- _validate_integer(fields['timestamp'], signed=False)
- except RuntimeError as e:
- _perror('stream {}: "timestamp": {}'.format(sid, format(e)))
-
-
-def _validate_stream_event_context(doc, stream):
- stream_event_context = stream.event_context
- sid = stream.id
-
- if stream_event_context is None:
- return
-
- try:
- _validate_context_field(stream_event_context)
- except RuntimeError as e:
- _perror('stream {}: event context: {}'.format(sid, e))
-
-
-def _validate_all_scopes(doc):
- # packet header
- _validate_packet_header(doc.trace.packet_header)
-
- # stream stuff
- for stream_id, stream in doc.streams.items():
- _validate_event_header(doc, stream)
- _validate_packet_context(doc, stream)
- _validate_stream_event_context(doc, stream)
-
-
-def _validate_metadata(doc):
- _validate_all_scopes(doc)
-
-
-# 3, 4 -> 4
-# 4, 4 -> 4
-# 5, 4 -> 8
-# 6, 4 -> 8
-# 7, 4 -> 8
-# 8, 4 -> 8
-# 9, 4 -> 12
-def _get_alignment(at, align):
- return (at + align - 1) & -align
-
-
-def _offset_vars_tree_to_vars(offset_vars_tree, prefix='',
- offset_vars=collections.OrderedDict()):
- for name, offset in offset_vars_tree.items():
- varname = '{}_{}'.format(prefix, name)
-
- if isinstance(offset, dict):
- _offset_vars_tree_to_vars(offset, varname, offset_vars)
- else:
- offset_vars[varname] = offset
-
- return offset_vars
-
-
-# returns the size of a struct with _static size_
-def _get_struct_size(struct, offset_vars_tree=collections.OrderedDict(),
- base_offset=0):
- offset = 0
-
- for fname, ftype in struct.fields.items():
- field_alignment = _get_obj_alignment(ftype)
- offset = _get_alignment(offset, field_alignment)
-
- if type(ftype) is pytsdl.tsdl.Struct:
- offset_vars_tree[fname] = collections.OrderedDict()
- sz = _get_struct_size(ftype, offset_vars_tree[fname],
- base_offset + offset)
- else:
- # only integers may act as sequence lengths
- if type(ftype) is pytsdl.tsdl.Integer:
- offset_vars_tree[fname] = base_offset + offset
-
- sz = _get_obj_size(ftype)
-
- offset += sz
-
- return offset
-
+ try:
+ self._validate_integer(fields['id'], signed=False)
+ except RuntimeError as e:
+ _perror('stream {}: "id": {}'.format(sid, format(e)))
-def _get_array_size(array):
- element = array.element
- # effective size of one element includes its alignment after its size
- size = _get_obj_size(element)
- align = _get_obj_alignment(element)
+ # timestamp must exist, be an unsigned integer and be mapped to a valid clock
+ if 'timestamp' not in fields:
+ _perror('stream {}: event header: missing "timestamp" field'.format(sid))
- return _get_alignment(size, align) * array.length
+ try:
+ self._validate_integer(fields['timestamp'], signed=False)
+ except RuntimeError as e:
+ _perror('stream {}: "timestamp": {}'.format(sid, format(e)))
+ def _validate_stream_event_context(self, stream):
+ stream_event_context = stream.event_context
+ sid = stream.id
-def _get_enum_size(enum):
- return _get_obj_size(enum.integer)
+ if stream_event_context is None:
+ return
+ try:
+ self._validate_context_field(stream_event_context)
+ except RuntimeError as e:
+ _perror('stream {}: event context: {}'.format(sid, e))
+
+ def _validate_all_scopes(self):
+ # packet header
+ self._validate_packet_header(self._doc.trace.packet_header)
+
+ # stream stuff
+ for stream_id, stream in self._doc.streams.items():
+ self._validate_event_header(stream)
+ self._validate_packet_context(stream)
+ self._validate_stream_event_context(stream)
+
+ def _validate_metadata(self):
+ self._validate_all_scopes()
+
+ # 3, 4 -> 4
+ # 4, 4 -> 4
+ # 5, 4 -> 8
+ # 6, 4 -> 8
+ # 7, 4 -> 8
+ # 8, 4 -> 8
+ # 9, 4 -> 12
+ def _get_alignment(self, at, align):
+ return (at + align - 1) & -align
+
+ # this converts a tree of offset variables:
+ #
+ # field
+ # a -> 0
+ # b -> 8
+ # other_struct
+ # field -> 16
+ # yeah -> 20
+ # c -> 32
+ # len -> 36
+ #
+ # to a flat dict:
+ #
+ # field_a -> 0
+ # field_b -> 8
+ # field_other_struct_field -> 16
+ # field_other_struct_yeah -> 20
+ # field_c -> 32
+ # len -> 36
+ def _offvars_tree_to_vars(self, offvars_tree, prefix=None,
+ off_vars=collections.OrderedDict()):
+ for name, offset in offvars_tree.items():
+ if prefix is not None:
+ varname = '{}_{}'.format(prefix, name)
+ else:
+ varname = name
-def _get_floating_point_size(floating_point):
- return floating_point.exp_dig + floating_point.mant_dig
+ if isinstance(offset, dict):
+ self._offvars_tree_to_vars(offset, varname, off_vars)
+ else:
+ off_vars[varname] = offset
+ return off_vars
-def _get_integer_size(integer):
- return integer.size
+ # returns the size of a struct with _static size_
+ def _get_struct_size(self, struct,
+ offvars_tree=collections.OrderedDict(),
+ base_offset=0):
+ offset = 0
+ for fname, ftype in struct.fields.items():
+ field_alignment = self._get_obj_alignment(ftype)
+ offset = self._get_alignment(offset, field_alignment)
-_obj_size_cb = {
- pytsdl.tsdl.Struct: _get_struct_size,
- pytsdl.tsdl.Integer: _get_integer_size,
- pytsdl.tsdl.Enum: _get_enum_size,
- pytsdl.tsdl.FloatingPoint: _get_floating_point_size,
- pytsdl.tsdl.Array: _get_array_size,
-}
+ if type(ftype) is pytsdl.tsdl.Struct:
+ offvars_tree[fname] = collections.OrderedDict()
+ sz = self._get_struct_size(ftype, offvars_tree[fname],
+ base_offset + offset)
+ else:
+ # only integers may act as sequence lengths
+ if type(ftype) is pytsdl.tsdl.Integer:
+ offvars_tree[fname] = base_offset + offset
+ sz = self._get_obj_size(ftype)
-def _get_obj_size(obj):
- return _obj_size_cb[type(obj)](obj)
+ offset += sz
+ return offset
-def _get_struct_alignment(struct):
- if struct.align is not None:
- return struct.align
+ def _get_array_size(self, array):
+ element = array.element
- cur_align = 1
+ # effective size of one element includes its alignment after its size
+ size = self._get_obj_size(element)
+ align = self._get_obj_alignment(element)
- for fname, ftype in struct.fields.items():
- cur_align = max(_get_obj_alignment(ftype), cur_align)
+ return self._get_alignment(size, align) * array.length
- return cur_align
+ def _get_enum_size(self, enum):
+ return self._get_obj_size(enum.integer)
+ def _get_floating_point_size(self, floating_point):
+ return floating_point.exp_dig + floating_point.mant_dig
-def _get_integer_alignment(integer):
- return integer.align
+ def _get_integer_size(self, integer):
+ return integer.size
+ def _get_obj_size(self, obj):
+ return self._obj_size_cb[type(obj)](obj)
-def _get_floating_point_alignment(floating_point):
- return floating_point.align
+ def _get_struct_alignment(self, struct):
+ if struct.align is not None:
+ return struct.align
+ cur_align = 1
-def _get_enum_alignment(enum):
- return _get_obj_alignment(enum.integer)
+ for fname, ftype in struct.fields.items():
+ cur_align = max(self._get_obj_alignment(ftype), cur_align)
+ return cur_align
-def _get_string_alignment(string):
- return 8
+ def _get_integer_alignment(self, integer):
+ return integer.align
-def _get_array_alignment(array):
- return _get_obj_alignment(array.element)
+ def _get_floating_point_alignment(self, floating_point):
+ return floating_point.align
+ def _get_enum_alignment(self, enum):
+ return self._get_obj_alignment(enum.integer)
-def _get_sequence_alignment(sequence):
- return _get_obj_alignment(sequence.element)
+ def _get_string_alignment(self, string):
+ return 8
+ def _get_array_alignment(self, array):
+ return self._get_obj_alignment(array.element)
-_obj_alignment_cb = {
- pytsdl.tsdl.Struct: _get_struct_alignment,
- pytsdl.tsdl.Integer: _get_integer_alignment,
- pytsdl.tsdl.Enum: _get_enum_alignment,
- pytsdl.tsdl.FloatingPoint: _get_floating_point_alignment,
- pytsdl.tsdl.Array: _get_array_alignment,
- pytsdl.tsdl.Sequence: _get_sequence_alignment,
- pytsdl.tsdl.String: _get_string_alignment,
-}
+ def _get_sequence_alignment(self, sequence):
+ return self._get_obj_alignment(sequence.element)
+ def _get_obj_alignment(self, obj):
+ return self._obj_alignment_cb[type(obj)](obj)
-def _get_obj_alignment(obj):
- return _obj_alignment_cb[type(obj)](obj)
+ def _name_to_param_name(self, prefix, name):
+ return 'param_{}_{}'.format(prefix, name)
+ def _ev_f_name_to_param_name(self, name):
+ return self._name_to_param_name('evf', name)
-_CTX_AT = 'ctx->at'
-_CTX_BUF = 'ctx->buf'
-_CTX_BUF_SIZE = 'ctx->buf_size'
-_CTX_BUF_AT = '{}[{} >> 3]'.format(_CTX_BUF, _CTX_AT)
-_CTX_BUF_AT_ADDR = '&{}'.format(_CTX_BUF_AT)
-_ALIGN_OFFSET = 'ALIGN_OFFSET'
-_CHECK_OFFSET_OVERFLOW_FMT = \
- 'CHECK_OFFSET_OVERFLOW({}, {}, {{}});'.format(_CTX_AT, _CTX_BUF_SIZE)
+ def _ev_c_name_to_param_name(self, name):
+ return self._name_to_param_name('evc', name)
+ def _ev_sec_name_to_param_name(self, name):
+ return self._name_to_param_name('evsec', name)
-def _field_name_to_param_name(fname):
- return 'param_{}'.format(fname)
+ def _ev_h_name_to_param_name(self, name):
+ return self._name_to_param_name('evh', name)
+ def _s_pc_name_to_param_name(self, name):
+ return self._name_to_param_name('spc', name)
-def _get_integer_param_type(integer):
- signed = 'u' if not integer.signed else ''
+ def _s_ph_name_to_param_name(self, name):
+ return self._name_to_param_name('sph', name)
- if integer.size == 8:
- sz = '8'
- elif integer.size == 16:
- sz = '16'
- elif integer.size == 32:
- sz = '32'
- elif integer.size == 64:
- sz = '64'
- else:
- # if the integer is signed and of uncommon size, the sign bit is
- # at a custom position anyway so we use a 64-bit unsigned
- signed = 'u'
+ def _get_integer_param_ctype(self, integer):
+ signed = 'u' if not integer.signed else ''
- if integer.signed:
+ if integer.size == 8:
+ sz = '8'
+ elif integer.size == 16:
+ sz = '16'
+ elif integer.size == 32:
+ sz = '32'
+ elif integer.size == 64:
sz = '64'
else:
- if integer.size < 16:
- sz = '8'
- elif integer.size < 32:
- sz = '16'
- elif integer.size < 64:
- sz = '32'
- else:
- sz = '64'
-
- return '{}int{}_t'.format(signed, sz)
-
-
-def _get_enum_param_type(enum):
- return _get_obj_param_type(enum.integer)
-
-
-def _get_floating_point_param_type(fp):
- if fp.exp_dig == 8 and fp.mant_dig == 24 and fp.align == 32:
- return 'float'
- elif fp.exp_dig == 11 and fp.mant_dig == 53 and fp.align == 64:
- return 'double'
- else:
- return 'uint64_t'
-
-
-_obj_param_type_cb = {
- pytsdl.tsdl.Struct: lambda obj: 'const void*',
- pytsdl.tsdl.Integer: _get_integer_param_type,
- pytsdl.tsdl.Enum: _get_enum_param_type,
- pytsdl.tsdl.FloatingPoint: _get_floating_point_param_type,
- pytsdl.tsdl.Array: lambda obj: 'const void*',
- pytsdl.tsdl.Sequence: lambda obj: 'const void*',
- pytsdl.tsdl.String: lambda obj: 'const char*',
-}
-
-
-def _get_obj_param_type(obj):
- return _obj_param_type_cb[type(obj)](obj)
-
-
-class _CBlock(list):
- pass
-
-
-class _CLine(str):
- pass
-
-
-def _get_check_offset_overflow_cline(size):
- return _CLine(_CHECK_OFFSET_OVERFLOW_FMT.format(size))
-
-
-def _write_field_struct(doc, fname, struct):
- size = _get_struct_size(struct)
- size_bytes = _get_alignment(size, 8) // 8
-
- dst = _CTX_BUF_AT_ADDR
- src = _field_name_to_param_name(fname)
+ # if the integer is signed and of uncommon size, the sign bit is
+ # at a custom position anyway so we use a 64-bit unsigned
+ signed = 'u'
- return [
- # memcpy() is safe since barectf requires inner structures
- # to be byte-aligned
- _get_check_offset_overflow_cline(size),
- _CLine('memcpy({}, {}, {});'.format(dst, src, size_bytes)),
- _CLine('{} += {};'.format(_CTX_AT, size)),
- ]
-
-
-_bo_suffixes_map = {
- pytsdl.tsdl.ByteOrder.BE: 'be',
- pytsdl.tsdl.ByteOrder.LE: 'le',
-}
-
-
-def _write_field_integer(doc, fname, integer):
- bo = _bo_suffixes_map[integer.byte_order]
- ptr = _CTX_BUF
- t = _get_obj_param_type(integer)
- start = _CTX_AT
- length = _get_obj_size(integer)
- value = _field_name_to_param_name(fname)
- fmt = 'barectf_bitfield_write_{}({}, {}, {}, {}, {});'
-
- return [
- _get_check_offset_overflow_cline(length),
- _CLine(fmt.format(bo, ptr, t, start, length, value)),
- _CLine('{} += {};'.format(_CTX_AT, length))
- ]
-
-
-def _write_field_enum(doc, fname, enum):
- return _write_field_obj(doc, fname, enum.integer)
-
-
-def _write_field_floating_point(doc, fname, floating_point):
- bo = _bo_suffixes_map[floating_point.byte_order]
- ptr = _CTX_BUF
- t = _get_obj_param_type(floating_point)
- start = _CTX_AT
- length = _get_obj_size(floating_point)
- value = _field_name_to_param_name(fname)
- fmt = 'barectf_bitfield_write_{}({}, {}, {}, {}, {});'
-
- return [
- _get_check_offset_overflow_cline(length),
- _CLine(fmt.format(bo, ptr, t, start, length, value)),
- _CLine('{} += {};'.format(_CTX_AT, length))
- ]
-
-
-def _write_field_array(doc, fname, array):
- lines = []
-
- # array index variable declaration
- iv = 'ia_{}'.format(fname)
- lines.append(_CLine('uint32_t {};'.format(iv)))
-
- # for loop using array's static length
- line = 'for ({iv} = 0; {iv} < {l}; ++{iv}) {{'.format(iv=iv, l=array.length)
- lines.append(_CLine(line))
-
- # for loop statements
- for_block = _CBlock()
+ if integer.signed:
+ sz = '64'
+ else:
+ if integer.size < 16:
+ sz = '8'
+ elif integer.size < 32:
+ sz = '16'
+ elif integer.size < 64:
+ sz = '32'
+ else:
+ sz = '64'
- # align bit index before writing to the buffer
- element_align = _get_obj_alignment(array.element)
- line = '{}({}, {});'.format(_ALIGN_OFFSET, _CTX_AT, element_align)
- for_block.append(_CLine(line))
+ return '{}int{}_t'.format(signed, sz)
- # write element to the buffer
- for_block += _write_field_obj(doc, fname, array.element)
- lines.append(for_block)
+ def _get_enum_param_ctype(self, enum):
+ return self._get_obj_param_ctype(enum.integer)
- # for loop end
- lines.append(_CLine('}'))
+ def _get_floating_point_param_ctype(self, fp):
+ if fp.exp_dig == 8 and fp.mant_dig == 24 and fp.align == 32:
+ return 'float'
+ elif fp.exp_dig == 11 and fp.mant_dig == 53 and fp.align == 64:
+ return 'double'
+ else:
+ return 'uint64_t'
+
+ def _get_obj_param_ctype(self, obj):
+ return self._obj_param_ctype_cb[type(obj)](obj)
+
+ def _get_chk_offset_v(self, size):
+ fmt = '{}_CHK_OFFSET_V({}, {}, {});'
+ ret = fmt.format(self._prefix.upper(), self._CTX_AT,
+ self._CTX_BUF_SIZE, size)
+
+ return ret
+
+ def _get_chk_offset_v_cline(self, size):
+ return _CLine(self._get_chk_offset_v(size))
+
+ def _get_align_offset(self, align):
+ fmt = '{}_ALIGN_OFFSET({}, {});'
+ ret = fmt.format(self._prefix.upper(), self._CTX_AT, align)
+
+ return ret
+
+ def _get_align_offset_cline(self, size):
+ return _CLine(self._get_align_offset(size))
+
+ def _write_field_struct(self, fname, src_name, struct):
+ size = self._get_struct_size(struct)
+ size_bytes = self._get_alignment(size, 8) // 8
+ dst = self._CTX_BUF_AT_ADDR
+
+ return [
+ # memcpy() is safe since barectf requires inner structures
+ # to be byte-aligned
+ self._get_chk_offset_v_cline(size),
+ _CLine('memcpy({}, {}, {});'.format(dst, src_name, size_bytes)),
+ _CLine('{} += {};'.format(self._CTX_AT, size)),
+ ]
+
+ def _write_field_integer(self, fname, src_name, integer):
+ bo = self._bo_suffixes_map[integer.byte_order]
+ ptr = self._CTX_BUF
+ t = self._get_obj_param_ctype(integer)
+ start = self._CTX_AT
+ length = self._get_obj_size(integer)
+ fmt = 'barectf_bitfield_write_{}({}, {}, {}, {}, {});'
+
+ return [
+ self._get_chk_offset_v_cline(length),
+ _CLine(fmt.format(bo, ptr, t, start, length, src_name)),
+ _CLine('{} += {};'.format(self._CTX_AT, length))
+ ]
+
+ def _write_field_enum(self, fname, src_name, enum):
+ return self._write_field_obj(fname, src_name, enum.integer)
+
+ def _write_field_floating_point(self, fname, src_name, floating_point):
+ bo = self._bo_suffixes_map[floating_point.byte_order]
+ ptr = self._CTX_BUF
+ t = self._get_obj_param_ctype(floating_point)
+ start = self._CTX_AT
+ length = self._get_obj_size(floating_point)
+ fmt = 'barectf_bitfield_write_{}({}, {}, {}, {}, {});'
+
+ return [
+ self._get_chk_offset_v_cline(length),
+ _CLine(fmt.format(bo, ptr, t, start, length, src_name)),
+ _CLine('{} += {};'.format(self._CTX_AT, length))
+ ]
+
+ def _write_field_array(self, fname, src_name, array):
+ lines = []
- return lines
+ # array index variable declaration
+ iv = 'ia_{}'.format(fname)
+ lines.append(_CLine('uint32_t {};'.format(iv)))
+ # for loop using array's static length
+ line = 'for ({iv} = 0; {iv} < {l}; ++{iv}) {{'.format(iv=iv, l=array.length)
+ lines.append(_CLine(line))
-def _write_field_sequence(doc, fname, sequence):
- return [
- _CLine('would write sequence here;'),
- ]
+ # for loop statements
+ for_block = _CBlock()
+ # align bit index before writing to the buffer
+ element_align = self._get_obj_alignment(array.element)
+ cline = self._get_align_offset_cline(element_align)
+ for_block.append(cline)
-def _write_field_string(doc, fname, string):
- lines = []
+ # write element to the buffer
+ for_block += self._write_field_obj(fname, src_name, array.element)
+ lines.append(for_block)
- # source pointer (function parameter)
- src = _field_name_to_param_name(fname)
+ # for loop end
+ lines.append(_CLine('}'))
- # string index variable declaration
- iv = 'is_{}'.format(fname)
- lines.append(_CLine('uint32_t {};'.format(iv)))
+ return lines
- # for loop; loop until the end of the source string is reached
- fmt = "for ({iv} = 0; {src}[{iv}] != '\\0'; ++{iv}, {ctxat} += 8) {{"
- lines.append(_CLine(fmt.format(iv=iv, src=src, ctxat=_CTX_AT)))
+ def _write_field_sequence(self, fname, src_name, sequence):
+ return [
+ _CLine('would write sequence here;'),
+ ]
- # for loop statements
- for_block = _CBlock()
+ def _write_field_string(self, fname, src_name, string):
+ lines = []
- # check offset overflow
- for_block.append(_get_check_offset_overflow_cline(8))
+ # string index variable declaration
+ iv = 'is_{}'.format(fname)
+ lines.append(_CLine('uint32_t {};'.format(iv)))
- # write byte to the buffer
- line = '{} = {}[{}]'.format(_CTX_BUF_AT, src, iv)
- for_block.append(_CLine(line))
+ # for loop; loop until the end of the source string is reached
+ fmt = "for ({iv} = 0; {src}[{iv}] != '\\0'; ++{iv}, {ctxat} += 8) {{"
+ line = fmt.format(iv=iv, src=src_name, ctxat=self._CTX_AT)
+ lines.append(_CLine(line))
- # append for loop
- lines.append(for_block)
- lines.append(_CLine('}'))
+ # for loop statements
+ for_block = _CBlock()
- # write NULL character to the buffer
- lines.append(_CLine("{} = '\\0';".format(_CTX_BUF_AT)))
- lines.append(_CLine('{} += 8;'.format(_CTX_AT)))
+ # check offset overflow
+ for_block.append(self._get_chk_offset_v_cline(8))
- return lines
+ # write byte to the buffer
+ fmt = '{dst} = {src}[{iv}];'
+ line = fmt.format(dst=self._CTX_BUF_AT, iv=iv, src=src_name)
+ for_block.append(_CLine(line))
+ # append for loop
+ lines.append(for_block)
+ lines.append(_CLine('}'))
-_write_field_obj_cb = {
- pytsdl.tsdl.Struct: _write_field_struct,
- pytsdl.tsdl.Integer: _write_field_integer,
- pytsdl.tsdl.Enum: _write_field_enum,
- pytsdl.tsdl.FloatingPoint: _write_field_floating_point,
- pytsdl.tsdl.Array: _write_field_array,
- pytsdl.tsdl.Sequence: _write_field_sequence,
- pytsdl.tsdl.String: _write_field_string,
-}
+ # write NULL character to the buffer
+ lines.append(_CLine("{} = '\\0';".format(self._CTX_BUF_AT)))
+ lines.append(_CLine('{} += 8;'.format(self._CTX_AT)))
+ return lines
-def _write_field_obj(doc, fname, ftype):
- return _write_field_obj_cb[type(ftype)](doc, fname, ftype)
+ def _write_field_obj(self, fname, src_name, ftype):
+ return self._write_field_obj_cb[type(ftype)](fname, src_name, ftype)
+ def _get_offvar_name(self, name):
+ return 'off_{}'.format(name)
-def _struct_to_clines(doc, struct):
- line_groups = []
+ def _get_offvar_name_from_expr(self, expr):
+ return self._get_offvar_name('_'.join(expr))
- for fname, ftype in struct.fields.items():
+ def _field_to_cline(self, fname, ftype, scope_name, param_name_cb):
lines = []
- pname = _field_name_to_param_name(fname)
- align = _get_obj_alignment(ftype)
+ pname = param_name_cb(fname)
+ align = self._get_obj_alignment(ftype)
+
+ # group comment
+ fmt = '/* write {} field "{}" ({}) */'
+ line = fmt.format(scope_name, fname,
+ self._tsdl_type_names_map[type(ftype)])
+ lines.append(_CLine(line))
# align bit index before writing to the buffer
- line = '{}({}, {});'.format(_ALIGN_OFFSET, _CTX_AT, align)
- lines.append(line)
+ cline = self._get_align_offset_cline(align)
+ lines.append(cline)
# write offset variables
if type(ftype) is pytsdl.tsdl.Struct:
- offset_vars_tree = collections.OrderedDict()
- _get_struct_size(ftype, offset_vars_tree)
- offset_vars = _offset_vars_tree_to_vars(offset_vars_tree)
+ offvars_tree = collections.OrderedDict()
+ self._get_struct_size(ftype, offvars_tree)
+ off_vars = self._offvars_tree_to_vars(offvars_tree)
# as many offset as there are child fields because a future
# sequence could refer to any of those fields
- for lname, offset in offset_vars.items():
- fmt = 'uint32_t off_{}_{} = {} + {};'
- line = fmt.format(fname, lname, _CTX_AT, offset);
+ for lname, offset in off_vars.items():
+ print(fname, lname)
+ offvar = self._get_offvar_name('_'.join([fname, lname]))
+ fmt = 'uint32_t {} = {} + {};'
+ line = fmt.format(offvar, self._CTX_AT, offset);
lines.append(_CLine(line))
elif type(ftype) is pytsdl.tsdl.Integer:
# offset of this simple field is the current bit index
- line = 'uint32_t off_{} = {};'.format(fname, _CTX_AT)
+ offvar = self._get_offvar_name(fname)
+ line = 'uint32_t {} = {};'.format(offvar, self._CTX_AT)
lines.append(_CLine(line))
- lines += _write_field_obj(doc, fname, ftype)
- line_groups.append(lines)
-
- if not line_groups:
- return line_groups
+ lines += self._write_field_obj(fname, pname, ftype)
- output_lines = line_groups[0]
+ return lines
- for lines in line_groups[1:]:
- output_lines.append('')
- output_lines += lines
+ def _struct_to_clines(self, struct, scope_name, param_name_cb):
+ line_groups = []
- return output_lines
+ for fname, ftype in struct.fields.items():
+ lines = self._field_to_cline(fname, ftype, scope_name,
+ param_name_cb)
+ line_groups.append(lines)
+ if not line_groups:
+ return line_groups
-def _cblock_to_source_lines(cblock, indent=1):
- src = []
- indentstr = '\t' * indent
+ output_lines = line_groups[0]
- for line in cblock:
- if type(line) is _CBlock:
- src += _cblock_to_source_lines(line, indent + 1)
- else:
- src.append(indentstr + line)
+ for lines in line_groups[1:]:
+ output_lines.append('')
+ output_lines += lines
- return src
+ return output_lines
+ def _cblock_to_source_lines(self, cblock, indent=1):
+ src = []
+ indentstr = '\t' * indent
-def _cblock_to_source(cblock, indent=1):
- lines = _cblock_to_source_lines(cblock, indent)
+ for line in cblock:
+ if type(line) is _CBlock:
+ src += self._cblock_to_source_lines(line, indent + 1)
+ else:
+ src.append(indentstr + line)
- return '\n'.join(lines)
+ return src
+ def _cblock_to_source(self, cblock, indent=1):
+ lines = self._cblock_to_source_lines(cblock, indent)
-def gen_barectf(metadata, output, prefix, static_inline, manual_clock):
- # open CTF metadata file
- try:
- with open(metadata) as f:
- tsdl = f.read()
- except:
- _perror('cannot open/read CTF metadata file "{}"'.format(metadata))
+ return '\n'.join(lines)
- # parse CTF metadata
- parser = pytsdl.parser.Parser()
+ def gen_barectf(self, metadata, output, prefix, static_inline,
+ manual_clock):
+ self._metadata = metadata
+ self._output = output
+ self._prefix = prefix
+ self._static_inline = static_inline
+ self._manual_clock = manual_clock
- try:
- doc = parser.parse(tsdl)
- except pytsdl.parser.ParseError as e:
- _perror('parse error: {}'.format(e))
+ # open CTF metadata file
+ try:
+ with open(metadata) as f:
+ self._tsdl = f.read()
+ except:
+ _perror('cannot open/read CTF metadata file "{}"'.format(metadata))
- # validate CTF metadata against barectf constraints
- _validate_metadata(doc)
+ # parse CTF metadata
+ try:
+ self._doc = self._parser.parse(self._tsdl)
+ except pytsdl.parser.ParseError as e:
+ _perror('parse error: {}'.format(e))
- import json
+ # validate CTF metadata against barectf constraints
+ self._validate_metadata()
- clines = _struct_to_clines(doc, doc.streams[0].get_event(0).fields)
- print(_cblock_to_source(_CBlock(clines)))
+ clines = self._struct_to_clines(self._doc.streams[0].get_event(0).fields,
+ 'stream event context',
+ self._ev_f_name_to_param_name)
+ source = self._cblock_to_source(_CBlock(clines))
def run():
args = _parse_args()
- gen_barectf(args.metadata, args.output, args.prefix, args.static_inline,
- args.manual_clock)
+ generator = BarectfCodeGenerator()
+ generator.gen_barectf(args.metadata, args.output, args.prefix,
+ args.static_inline, args.manual_clock)