def as_bitfield(self): """ Take Enum entry type and convert into a bitfield type: uint64_t NameOfEnum : offset.num_bits; """ if self.instance is None: return [] result = [] for enum in self.instance: type_val = 64 bits = enum.origin.get('num_bits', -1) if enum.parent is not None: type_val = enum.parent.get('num_bits', type_val) e_name = enum.name.split('genz_')[-1] if int(bits) < 0: logging.warning('Enum entry "%s" has invalid bitfield value?' % e_name) enum_entry = fields.CStructEntry(e_name, num_type=type_val, bitfield=bits) if enum_entry not in result: result.append(enum_entry) return result
def struct_meta(self): """ A meta struct describing a <class> field. "raw_name" - is a name of the class as it appears in the xml file. "condensed_name" - is a trimmed class' name. "value" - a 'condensed' indexed ('hardware_types' enum defined in __init__). """ entries = [ fields.CStructEntry('raw_name', var_type='const char * const'), fields.CStructEntry('condensed_name', var_type='const char * const'), fields.CStructEntry('value', var_type='const enum %s' % self.enum.name), #name of the enum ] #FIXME: hardcoded index value! struct_instance = fields.CStruct(self.struct_name, entries=entries, ignore_ctrl_struct_enum=True) return struct_instance
def build_externs(cls, name, var_name=None): # name = 'genz_ctrl_struct_type_to_ptrs' if var_name is None: var_name = cls.ctr_ptr_info_struct_name array_type = 'extern struct %s' % var_name return [ fields.CArrayEntry(name, array_type, is_allow_empty=False), fields.CStructEntry('%s_nelems' % var_name, var_type='extern size_t', l_space='') ]
def build_struct_sizes(cls, structs: list): """ """ result = [] for struct in structs: v_type = 'ssize_t %s_size' % struct.name.lower() field_name = '(struct %s *ci)' % cls.ctrl_info_name entry = fields.CStructEntry(field_name, var_type=v_type, l_space='') result.append(entry) return result
def build_ctrl_ptr_info_struct(cls): """ struct genz_control_ptr_info { struct genz_control_structure_ptr *ptr; size_t num_ptrs; ssize_t struct_bytes; uint8_t vers; char *name; }; """ struct = fields.CStruct(cls.ctr_ptr_info_struct_name) entries = [ fields.CStructEntry('* const ptr', var_type='const struct %s' % cls.ctrl_ptr_struct_name), fields.CStructEntry('num_ptrs', var_type='const size_t'), fields.CStructEntry('struct_bytes', var_type='const ssize_t'), fields.CStructEntry( 'chained', var_type='const bool'), #structure contains chained ptr fields.CStructEntry('vers', var_type='const uint8_t'), fields.CStructEntry('name', var_type='const char * const'), ] struct.extend(entries) return struct
def build_ctrl_struct_ptr_struct(cls): """ struct genz_control_structure_ptr { const enum genz_control_ptr_flags ptr_type; const enum genz_pointer_size ptr_size; const uint32_t pointer_offset; const enum genz_control_structure_type struct_type; const char *ptr_name; ssize_t (*size_fn)(struct genz_control_info *ci); }; """ struct = fields.CStruct(cls.ctrl_ptr_struct_name) entries = [ fields.CStructEntry('ptr_type', var_type='const enum %s' % cls.ctrl_ptr_flags_name), fields.CStructEntry('ptr_size', var_type='const enum %s' % cls.ptr_size_enum_name), fields.CStructEntry('pointer_offset', var_type='const uint32_t'), fields.CStructEntry('struct_type', var_type='const enum %s' % cls.ctrl_struct_type_enum_name), fields.CStructEntry('*ptr_name', var_type='const char'), fields.CStructEntry('(*size_fn)(struct %s *ci)' % cls.ctrl_info_name, var_type='ssize_t'), ] struct.extend(entries) return struct
def build_export_symbol(self, name): """ EXPORT_SYMBOL(genz_struct_type_to_ptrs); size_t genz_struct_type_to_ptrs_nelems = sizeof(genz_struct_emtype_to_ptrs) / sizeof(genz_struct_type_to_ptrs[0]); EXPORT_SYMBOL(genz_struct_type_to_ptrs); """ export_symbol = 'EXPORT_SYMBOL(%s)' value = 'sizeof({name}) / sizeof({name}[0])'.format(name=name) return [ fields.CStructEntry(export_symbol % name, var_type='', l_space=''), fields.EStateEntry('size_t %s_nelems' % name, value, l_space='', close_bracket=';'), fields.CStructEntry(export_symbol % (name + '_nelems'), var_type='', l_space=''), ]
def parse(self, root): """ Generate a struct array of "meta" structs describing a Class. Refere to "struct_meta" property for documentation on the meta values. @param root: xml root tree to start parsing from. """ if root is None: return if self._instance is None: self._instance = fields.CArrayEntry(self.name, 'struct %s' % self.struct_name) list_of_names = [] longest_name_length = self._get_longest_name_length(root) for class_elem in root: raw_name = get_name(class_elem) trimmed_name = raw_name.lower().split('(')[0].strip() name = trim_name(trimmed_name, replaceable=' —[:](),=.\n', removable='\'|!<>@#$%^&*+–’-/') if 'switch' in name: name = 'switch' if 'bridge' in trimmed_name: name = 'bridge' if name not in list_of_names: list_of_names.append(name) enum_index = len(self.enum.entries) estate = fields.EStateEntry('GENZ_%s' % name.upper(), enum_index) spaces = ' ' * (longest_name_length - len(raw_name)) # { raw_name, condenced_name, condenced_enum_value } name = '"%s", %s"%s", %s' % (raw_name, spaces, name, estate.name) struct_entry = fields.CStructEntry(name, ignore_long_name_warning=True) struct_entry.l_space = '%s { ' % struct_entry.l_space struct_entry.str_close_symbol = ' },' self._instance.append(struct_entry) self.enum.append(estate) last_state = fields.EStateEntry('GENZ_NUM_HARDWARE_TYPES', None) self.enum.append(last_state) return self.instance
def split_entry(self, entry: fields.CStructEntry, splitbit=64): """ When struct entry bits exceeding offset_bits, the entry needs to be splitted in chunks. @param: dict or CStructEntry object to be splitted. """ if entry.num_type == -1 or entry.bitfield == None or entry.bitfield == -1: #this is not a bitfield entry, so skip it. return entry max_bit = entry.origin.get('max_bit', -1) max_bit = int(max_bit) min_bit = entry.origin.get('min_bit', -1) min_bit = int(min_bit) result = [] if not (min_bit < splitbit and max_bit >= splitbit): return [entry] split_bits = [] split_bits.append(splitbit - min_bit) split_bits.append(entry.bitfield - split_bits[0]) for index in range(len(split_bits)): bitfield = split_bits[index] name = entry.fields.get('name') entry_split = fields.CStructEntry(name=name, num_type=entry.num_type, bitfield=entry.bitfield) entry_split.name = '%s_%s' % (entry_split.name, index + 1) entry_split.definition = entry.definition entry_split.bitfield = bitfield entry_split.str_end = ' //NOTE: split bit' result.append(entry_split) return result
def _parse_structs(self, xml_structs): for struct_elem in xml_structs: struct_parser = parsers.StructBuilder(struct_elem) if struct_parser.instance not in self.structs: #duplicates check self.structs.append(struct_parser.instance) union_builder = parsers.UnionBuilder(struct_elem) if union_builder is not None and union_builder.instance is not None: self.unions.extend(union_builder.instance) enum_builder = parsers.EnumBuilder(struct_elem) if enum_builder.instance is not None and len( enum_builder.instance) > 0: for enum in enum_builder.instance: #duplicates check if enum not in self.enums: self.enums.append(enum) pointer_parser = parsers.PointerBuilder(struct_elem, data_types=self.DataTypes) if pointer_parser.instance is not None: if pointer_parser.instance not in self.pointers: pointer_parser.instance.origin = struct_parser.instance if pointer_parser.instance not in self.pointers: #duplicates check self.pointers.append(pointer_parser.instance) struct_parser.instance.child_pointers.extend( pointer_parser.instance.entries) #Parsing a table is almost a recursive process. Each <table> or #<array> entry has almost the same structure as <struct> entry. table_parser = parsers.TableBuilder(struct_elem) if table_parser.instance is not None: for cgen in table_parser.instance: for t_struct in cgen.structs: table_entry_name = 'struct %s' % t_struct.name struct_entry = fields.CStructEntry( rm_prefix(cgen.structs[0].name, 'genz_') + '[]', var_type=table_entry_name) #Adding created Table entry to the current struct_parser #entries list if not struct_entry in struct_parser.instance.entries: struct_parser.instance.append(struct_entry) #loop through table's structs and only add those that are #not already in the main structs list. # These are the struct generated from <array> fields. target = [] target.extend(cgen.structs) for ms in target: if ms not in self.struct_arrays: self.struct_arrays.insert(0, ms) struct_parser.instance.child_arrays.extend( cgen.structs) self._add_to_list(cgen.unions, self.unions) self._add_to_list(cgen.enums, self.enums) self._add_to_list(cgen.pointers, self.pointers) self._add_to_list(cgen.struct_arrays, self.struct_arrays, is_push_front=True)
def entries(self): result = [] result.append(self.DataTypes.table_index_define()) ctrl_ptr_flags = self.DataTypes.build_ptr_flags_enum() ptr_sizes = self.DataTypes.build_ptr_sizes_enum() ctrl_ptr_struct = self.DataTypes.build_ctrl_struct_ptr_struct() ctrl_ptr_info_struct = self.DataTypes.build_ctrl_ptr_info_struct() externs = self.DataTypes.build_externs(self.struct_type_to_ptrs_name) # externs.extend(self.DataTypes.build_externs(self.table_type_to_ptrs_name)) externs.extend(self.externs) externs.extend([ fields.CArrayEntry(self.table_type_to_ptrs_name, 'extern struct genz_control_ptr_info', is_allow_empty=False), fields.CStructEntry('genz_struct_type_to_ptrs_nelems', var_type='extern size_t', l_space=''), fields.CStructEntry('genz_table_type_to_ptrs_nelems', var_type='extern size_t', l_space='') ]) result.append(ctrl_ptr_flags) result.append(ptr_sizes) result.append(ctrl_ptr_info_struct) result.append(self.structs_enum) result.append(ctrl_ptr_struct) # Order of adding things Matters for C file to compile. for union in self.unions: result.append(union) for enum in self.enums: if len(enum.entries) > 1: result.append(enum) structs = [] # structs.append( # fields.CStruct('genz_control_info', str_start='', open_bracket='', close_bracket=';') # ) structs.extend(self.struct_arrays) structs.extend(self.structs) for struct in structs: if len(struct.entries) == 1: if '[]' in struct.entries[0].name: continue result.append(struct) result.extend(externs) result.extend(self.struct_enum_size_t) #tentative declaration result.insert( 0, fields.CStruct('genz_control_info', str_start='', open_bracket='', close_bracket=';')) return result
def build_control_ptr_info_array(self): """ This is a list of all the <struct>. Index by <struct> "type" number. There could be "gaps" in the type index - so add "null" entry and move on. Same thing should be created for <table>, except no need to have gaps. Assign index as you go. """ array_type = self.DataTypes.ctr_ptr_info_struct_name array_name = 'genz_struct_type_to_ptrs' table_name = 'genz_table_type_to_ptrs' struct_array = fields.CArrayEntry(array_name, 'struct %s' % array_type) table_array = fields.CArrayEntry(table_name, 'struct %s' % array_type) pointers_count = len(self.pointers) #Need to know how big the pointers list is going to be, based of the #struct's highest "type" attribute's value which indicates its position #in the array that is built here. hIndex_struct = self.find_highest_struct_index() hIndex_tbl = self.find_highest_struct_index(tag='table') for idx in range(hIndex_struct + 1): struct = self.find_struct_by_index(idx) if struct is None: null_entry = fields.NullEntry(close_bracket=',') else: name_no_genz = rm_prefix(struct.name, 'genz_').split('_structure')[0] offset = 'sizeof(struct {name})'.format(name=struct.name) name = 'NULL, 0, {offset}, {chained}, {vers}, "{stype}"'.format( offset=offset, vers=struct.vers if struct.vers is not None else '0x0', stype=name_no_genz, chained='true' if struct.is_chained else 'false') null_entry = fields.CStructEntry(name, ignore_long_name_warning=True) null_entry.l_space = '%s { ' % null_entry.l_space null_entry.str_close_symbol = ' },' struct_array.append(null_entry) for idx in range(hIndex_tbl + 1): table = self.find_struct_by_index(idx, tag='table') name_no_genz = rm_prefix(table.name, 'genz_') name = 'NULL, 0, 0, {chained}, 0x0, "{stype}"'.format( stype=name_no_genz, chained='true' if table.is_chained else 'false') null_entry = fields.CStructEntry(name, ignore_long_name_warning=True) null_entry.l_space = '%s { ' % null_entry.l_space null_entry.str_close_symbol = ' },' table_array.append(null_entry) struct_enum = self.structs_enum for index in range(pointers_count): ptr = self.pointers[index] struct = ptr.origin if struct.tag not in ['struct', 'table']: continue if struct.index is None: msg = 'NOOOOOOO!! No "type" attr in struct -> %s' % struct.name logging.critical(msg) if not isinstance(struct, fields.cstruct.CStruct): msg = 'Pointer "%s" origin is not of type CStruct!' % ptr.name logging.critical(msg) continue if struct.origin is None: logging.critical('Pointer "%s" struct "%s" origin is None?!' %\ (ptr.name, struct.name)) continue name_no_ptr = ptr.name.split('_ptrs')[0] name_no_genz = rm_prefix(name_no_ptr, 'genz_').split('_structure')[0] ptr_size = 'sizeof({name})/sizeof({name}[0])'.format(name=ptr.name) ptr_offset = 'sizeof(struct genz_{name})'.format(name=name_no_ptr) name = '{ptype}, {size}, {offset}, {chained}, {vers}, "{stype}"'.format( ptype=ptr.name, size=ptr_size, offset=ptr_offset, vers=struct.vers if struct.vers is not None else '0x0', stype=name_no_genz, chained='true' if struct.is_chained else 'false') struct_entry = fields.CStructEntry(name, ignore_long_name_warning=True) struct_entry.l_space = '%s { ' % struct_entry.l_space struct_entry.str_close_symbol = ' },' if struct.tag == 'struct': struct_array.entries[int(struct.index, 0)] = struct_entry elif struct.tag == 'table': enum = self.find_enum_value_by_name(struct.name.upper(), struct_enum) enum_val = enum.value.split('+')[-1].strip() if enum_val.isdigit(): enum_val = int(enum_val, 0) else: enum_val = 0 table_array.entries[enum_val] = struct_entry return struct_array, table_array
def create_entry(self, field, bits): """ @param field: the xml field to create a struct entry from. @param bits: the 'num_bits' attr of the <offset> field (e.g. parent of field). """ if field is None: logging.error('Failed parsing field (is None)! Root: %s' % self.root) return s_entry = None name = get_name(field) field_name = trim_name(name) # If a field has <value> entries - it is an Enum, not a struct entry. if (len(field.findall('value')) > 0): logging.info('A "%s" field is an Enum...' % field_name) if (len(field.findall('subfield')) > 0): msg = 'Both <value> and <subfield> in the "%s" field!' msg += ' What is it? Struct entry or Enum?' logging.error(msg % (field_name)) return props = field.attrib is_no_name = False if name is None: name = str(field.attrib) is_no_name = True if props.get('offset_bits', None) is None: props['offset_bits'] = bits var_type = None bitfield = props['num_bits'] if 'uuid' in field_name and not field_name.endswith('ptr'): base_bit = props.get('base_bit', None) if base_bit is not None: # ignore second half of split uuid return field_name = uuid_re.sub('', field_name) var_type = 'uuid_t' bitfield = -1 s_entry = fields.CStructEntry(name=field_name, num_type=props['offset_bits'], bitfield=bitfield, var_type=var_type) s_entry.origin = field s_entry.parent = self.root if is_no_name: s_entry.str_start = '//' s_entry.str_end = ' //FIXME: entry had no name' #FIXME: we are ignoring ... entries for now, but will be fixed later if s_entry.name == '...': s_entry.str_start = '//' s_entry.str_end = ' //FIXME: name "..." entry' #FIXME: write this to a file, but comment it out to know which entries # we can't parse. if s_entry.bitfield == 0 or s_entry.num_type == 0: s_entry.str_start = '//' s_entry.str_end = ' //FIXME: 0 bits.' return s_entry if name.lower() == 'unknown': s_entry.str_start = '//' s_entry.str_end = ' //FIXME: UNKNOWN in name' if 'rsvd' in name.lower(): s_entry.str_start = '//' s_entry.str_end = ' //FIXME: skipping rsvd(X) fields for now' s_entry = self.split_entry(s_entry) return s_entry