def gen_typedef(self): """ Generates an internal typedef definition for this function. :param typedef_name: Overrides automatic type name generation w/ value. """ _tmp, tmp = None, None # Fix for an insiduous bug with string identifiers (e.g. int_fast32_t) _tmp = self.func_decl.type.type.type\ if isinstance(self.func_decl.type.type, TypeDecl) else\ IdentifierType(names=self.func_decl.type.type.names) # Use TypeDecl/PtrDecl depending on whether return value is a pointer tmp = PtrDecl([], TypeDecl(self.typedef_name, [], _tmp))\ if self.ret_var.ptr else TypeDecl(self.typedef_name, [], _tmp) _tmp_fdecl = PtrDecl([], FuncDecl(self.param_list, tmp)) # Update base type so its registered a MyriadCType subclass self.base_type = type(self.typedef_name, (MyriadCType, ), {'mtype': IdentifierType([self.typedef_name])})() # Create typedef so its registered by the pycparser AST self.fun_typedef = Typedef(name=self.typedef_name, quals=[], storage=['typedef'], type=_tmp_fdecl, coord=None)
def gen_memo_flag_node(self,self_touch): val = 'true' if self_touch else 'false' type_ = TypeDecl(declname = self.memo_flag_name, quals=[], type=IdentifierType(names=['bool'])) return Decl(name=self.entity, quals=[], storage=[], funcspec=[], type= type_, init=ID(name=val), bitsize=None)
def touch_definition_node(self): type_ = FuncDecl(args=None, type=TypeDecl(declname=self.c_touch_name, quals=[], type=IdentifierType(names=['void']))) return FuncDef(decl=Decl(name=self.c_touch_name, quals=[], storage=[], funcspec=[], type=type_, init=None, bitsize=None), param_decls=None, body=Compound(block_items=[]))
def translate_FunDecl(c_ast): args = [] if c_ast.args is not None: for a in c_ast.args.params: args.append(translate_Decl(a)) subst = unify( c_ast.type, TypeDecl(Var("declname"), [], IdentifierType(Var("ret_type")))) name = subst.lookup("declname") ret_type = subst.lookup("ret_type") return (name, args, ret_type)
def _generateTypeDefForDecl(self, decl: Decl) -> str: typedefs = "" for param in filter(lambda p: utils.is_function_pointer_type(p.type), decl.type.args.params): name = utils.create_typedef_name_for_fnc_ptr(decl, param) param.type.type.type.declname = name typedef = Typedef(name, param.quals, ["typedef"], param.type) param.type = TypeDecl(param.name, param.type.quals, None, IdentifierType([name])) typedefs += f"{self.cGen.visit_Typedef(typedef)};\n" return typedefs
def translate_typ(c_ast): if isinstance(c_ast, FuncDecl): return translate_FunDecl(c_ast) elif isinstance(c_ast, TypeDecl): pat = TypeDecl(Var("declname"), [], IdentifierType(Var("names"))) t = unify(pat, c_ast) return t.lookup("names") elif isinstance(c_ast, ArrayDecl): pat = ArrayDecl(Var("element_type"), Var("dim", True), []) t = unify(pat, c_ast) elem_typ = translate_typ(t.lookup("element_type")) return (elem_typ, t.lookup("dim", None)) else: NYI(c_ast)
def make_decl(name, offset, type_name): nonlocal decls, pad_count, parser, prev_end if isinstance(offset, str): assert offset[:2] == '0x' offset = int(offset, 16) if prev_end < offset: pad_str = f"char _padding{pad_count}[{offset - prev_end}];" decls.append(parser.parse(pad_str).ext[0]) pad_count += 1 type_decl = TypeDecl(name.replace(".", "__"), None, IdentifierType([mangle_name(type_name)])) decls.append(Decl(None, None, None, None, type_decl, None, None)) req_graph.setdefault(type_name, set()).add(parent_name) if offset != -1: size = pointer_size if type_name.endswith('*') else int( types[type_name]['size'], 16) prev_end = offset + size
def basic_type(name: Union[str, List[str]]) -> TypeDecl: names = [name] if isinstance(name, str) else name idtype = IdentifierType(names=names) return TypeDecl(declname=None, quals=[], type=idtype)
def basic_type(names: List[str]) -> TypeDecl: idtype = IdentifierType(names=names) return TypeDecl(declname=None, quals=[], type=idtype)
def basic_type(name: str) -> TypeDecl: idtype = IdentifierType(names=[name]) return TypeDecl(declname=None, quals=[], type=idtype)
def print_header(message): generator = CGenerator() parser = CParser() def del_spaces(name): if name.startswith('(extension in '): idx = name.index('):') name = '_extension_in_' + name[14:idx] + "__" + name[idx + 2:] # file private types if ' in _' in name: idx = name.index(' in _') end = name.index(')', idx) start = name.rindex('(', None, idx) namespace = name[:start] if '>' in namespace: namespace = mangle_name(namespace[:-1]) + '.' name = namespace + name[start + 1:idx] + name[end + 1:] return name def mangle_name(human): if human in ('void*', 'voidp', 'Metadata*'): return human if human == '()': return 'void' info = types[human] if 'getGenericParams' in info and info['getGenericParams']: name = remove_generic(human) else: name = human if name.startswith('?Unknown type of'): name = name.replace('?Unknown type of ', 'XXX_unknown_type_of_') if name.startswith("Static #"): spl = name.split(' ', 4) return "_static_no" + spl[1][1:] + "_in_" + spl[ 3] + "__func" + str(hash(spl[4]))[1:] name = del_spaces(name) outp = f'swift_{info["kind"]}__' if info['kind'] == "Tuple": elems = [] for e in info['tupleElements']: name = mangle_name(e['type']) if e['label']: name += "__as_" + e['label'] elems.append(name) outp += "with__" + "__and__".join(elems) elif info['kind'] == "Existential": protos = [] for p in info['protocols']: protos.append( del_spaces(script.exports.demangle(p)).replace(".", "__")) if info['isClassBounded']: protos.append("Swift__AnyObject") if protos: outp += "conforming_to__" + "__and__".join(protos) else: outp += "Any" if info.get('getSuperclassConstraint'): outp += "__inheriting_from_" + mangle_name( info['getSuperclassConstraint']) elif info['kind'] == 'Function': return "func_" + str(hash(name))[1:] else: outp += name.replace(".", "_") if 'getGenericParams' in info and info['getGenericParams']: gen_params = [ mangle_name(param) for param in info['getGenericParams'] ] outp += "__of__" + "__and__".join(gen_params) return outp def make_decl(name, offset, type_name): nonlocal decls, pad_count, parser, prev_end if isinstance(offset, str): assert offset[:2] == '0x' offset = int(offset, 16) if prev_end < offset: pad_str = f"char _padding{pad_count}[{offset - prev_end}];" decls.append(parser.parse(pad_str).ext[0]) pad_count += 1 type_decl = TypeDecl(name.replace(".", "__"), None, IdentifierType([mangle_name(type_name)])) decls.append(Decl(None, None, None, None, type_decl, None, None)) req_graph.setdefault(type_name, set()).add(parent_name) if offset != -1: size = pointer_size if type_name.endswith('*') else int( types[type_name]['size'], 16) prev_end = offset + size #print("#include <stdint.h>") print("#pragma pack(1)") print("typedef void *voidp;") print("typedef struct Metadata_s Metadata;") types = json.loads(message) req_graph = {} ptr_types = {'void*', 'voidp', 'Metadata*'} ctypes = {} for name, info in types.items(): pad_count = 0 decls = [] prev_end = 0 ctype = None parent_name = name if info['kind'] == "Tuple": for i, elem in enumerate(info['tupleElements']): make_decl(elem['label'] or f'_{i}', elem['offset'], elem['type']) ctype = Struct(mangle_name(name) + "_s", decls) elif info['kind'] == "ObjCClassWrapper": print( f'typedef struct {mangle_name(name)}_s *{mangle_name(name)};') elif info['kind'] in ("Struct", "Class"): if info['kind'] == 'Class': make_decl('_isa', '0x0', 'Metadata*') #make_decl('_refCounts', hex(pointer_size), 'size_t') for i, field in enumerate(info['fields']): make_decl(field['name'], field['offset'], field['type']) ctype = Struct(mangle_name(name) + "_s", decls) if info['kind'] == 'Class': ctype = PtrDecl(None, ctype) elif info['kind'] == "Existential": if info['isClassBounded'] or info.get( 'getSuperclassConstraint'): # class existential container make_decl(f'heap_object', -1, 'void*') else: # opaque existential container decls.append( parser.parse("void *heapObjectOrInlineData0;").ext[0]) for i in range(1, 3): decls.append( parser.parse( "void *nothingOrInlineData{};".format(i)).ext[0]) make_decl("dynamicType", -1, "Metadata*") for i in range(info['witnessTableCount']): make_decl(f'_witnessTable{i + 1}', -1, 'void*') ctype = Struct(mangle_name(name) + "_s", decls) elif info['kind'] in ("Enum", "Optional"): if info['enumCases'] and info['enumCases'][0]['name'] is None: # C-like enum # we don't have case names or values, so just generate a typedef to an int type print( f"typedef uint{int(info['size'], 16) * 8}_t {mangle_name(name)};" ) elif len(info['enumCases']) == 0: ctype = Struct(mangle_name(name) + "_s", decls) elif len(info['enumCases']) == 1 and info['enumCases'][0]['type']: make_decl(info['enumCases'][0]['name'], 0, info['enumCases'][0]['type']) ctype = Struct(mangle_name(name) + "_s", decls) else: print( f'typedef struct {mangle_name(name)}_s {{ char _data[{info["size"]}]; }} {mangle_name(name)};' ) elif info['kind'] == 'Opaque': if 'getCType' in info: ctype_names = { 'pointer': 'void*', 'int8': 'int8_t', 'int16': 'int16_t', 'int32': 'int32_t', 'int64': 'int64_t', 'int64': 'int64_t', } print( f'typedef {ctype_names[info["getCType"]]} {mangle_name(name)};' ) elif name == 'Builtin.NativeObject': print(f'typedef void *{mangle_name(name)};') else: print(f'typedef char {mangle_name(name)}[{info["size"]}];') elif info['kind'] == 'Function': print(f"typedef void *func_{str(hash(name))[1:]};" ) # TODO: proper names else: print(f'typedef char {mangle_name(name)}[{info["size"]}];') if ctype: type_decl = TypeDecl(mangle_name(name), None, ctype) ctypes[name] = type_decl type_decl_forward = Struct(mangle_name(name) + "_s", []) if isinstance(type_decl, PtrDecl): ptr_types.add(name) type_decl_forward = PtrDecl(None, type_decl_forward) print( generator.visit( Typedef(mangle_name(name), None, ['typedef'], type_decl_forward)) + ";") for name in ptr_types: req_graph.pop(name, None) for name in top_sort(req_graph): if name in ctypes: print(f"\n// {name}") print( generator.visit( Typedef(mangle_name(name), None, ['typedef'], ctypes[name])) + ";")
def touch_declaration_node(self): return FuncDecl(args=None, type=TypeDecl(declname=self.c_touch_name, quals=[], type=IdentifierType(names=['void'])))
def __init__(self, ident: str, base_type: MyriadCType, ptr: bool = False, quals: list = None, storage: list = None, arr_id: str = None, init=None): """ Initializes a scalar variable, i.e. a base type, a pointer type, or an array type containing the base scalar type (variable/fixed length). :param str ident: Name of the scalar variable to be created. :param MyriadCType base_type: Underlying C AST base type (e.g. MInt). :param bool ptr: Indicates whether this is a pointer. :param list quals: C AST scope qualifiers (e.g. "static") :param list storage: C AST storage qualifiers (e.g. "const") :param str arr_id: Array length ID specifier (None if this isn't one) :param init: Initial value given to this scalar # TODO: NOT IMPLEMENTED """ # Always call super first super().__init__(ident, quals=quals, storage=storage) #: Represents the underlying C type via a MyriadCType subclass. self.base_type = base_type #: Indicates if this is a pointer (or an array of pointers). self.ptr = ptr #: Indicates whether this is actually an array of this scalar type self.arr_id = arr_id #: Underlying C AST type declaration, used for C generation. self.type_decl = TypeDecl(declname=self.ident, quals=self.quals, type=self.base_type.mtype) #: Optional pointer declaration, used for scalar pointers. self.ptr_decl = PtrDecl(quals=[], type=self.type_decl) #: Optional array declaration, used for scalar arrays self.arr_decl = None if self.arr_id is not None: # Array of scalars or array of pointers (first arg is base type) self.arr_decl = ArrayDecl(self.ptr_decl if ptr else self.type_decl, dim=ID(name=self.arr_id), dim_quals=[]) # TODO: Process init in some way #: Initial value of this scalar at the C level. self.init = init if init is not None: warn("Setting init is deprecated", DeprecationWarning) # Override superclass and re-initialize internal top-level declaration # Order of choosing declaration: # 1. If it's an array declaration (aka arr_id isn't None), use that # 2. Otherwise: # a) If ptr is true, use the ptr declaration # b) Otherwise, use the regular type declaration if self.arr_id is None: self.decl = Decl(name=self.ident, quals=self.quals, storage=self.storage, funcspec=[], type=self.ptr_decl if ptr else self.type_decl, init=self.init, bitsize=None) else: self.decl = Decl(name=self.ident, quals=self.quals, storage=self.storage, funcspec=[], type=self.arr_decl, init=None, bitsize=None)
def do_parse_struct(struct: Union[ca.Struct, ca.Union], typemap: TypeMap) -> Struct: is_union = isinstance(struct, ca.Union) assert struct.decls is not None, "enforced by caller" assert struct.decls, "Empty structs are not valid C" fields: Dict[int, List[StructField]] = defaultdict(list) union_size = 0 align = 1 offset = 0 bit_offset = 0 has_bitfields = False for decl in struct.decls: if not isinstance(decl, ca.Decl): continue field_name = f"{struct.name}.{decl.name}" type = decl.type if decl.bitsize is not None: # A bitfield "type a : b;" has the following effects on struct layout: # - align the struct as if it contained a 'type' field. # - allocate the next 'b' bits of the struct, going from high bits to low # within each byte. # - ensure that 'a' can be loaded using a single load of the size given by # 'type' (lw/lh/lb, unsigned counterparts). If it straddles a 'type' # alignment boundary, skip all bits up to that boundary and then use the # next 'b' bits from there instead. has_bitfields = True width = parse_constant_int(decl.bitsize, typemap) ssize, salign, substr = parse_struct_member(type, field_name, typemap, allow_unsized=False) align = max(align, salign) if width == 0: continue if ssize != salign or substr is not None: raise DecompFailure( f"Bitfield {field_name} is not of primitive type") if width > ssize * 8: raise DecompFailure( f"Width of bitfield {field_name} exceeds its type") if is_union: union_size = max(union_size, ssize) else: if offset // ssize != (offset + (bit_offset + width - 1) // 8) // ssize: bit_offset = 0 offset = (offset + ssize) & -ssize bit_offset += width offset += bit_offset // 8 bit_offset &= 7 continue if not is_union and bit_offset != 0: bit_offset = 0 offset += 1 if decl.name is not None: ssize, salign, substr = parse_struct_member(type, field_name, typemap, allow_unsized=False) align = max(align, salign) offset = (offset + salign - 1) & -salign fields[offset].append( StructField( type=type, size=ssize, name=decl.name, )) if is_union: union_size = max(union_size, ssize) else: offset += ssize elif isinstance(type, (ca.Struct, ca.Union)) and type.decls is not None: substr = parse_struct(type, typemap) if type.name is not None: # Struct defined within another, which is silly but valid C. # parse_struct already makes sure it gets defined in the global # namespace, so no more to do here. pass else: # C extension: anonymous struct/union, whose members are flattened align = max(align, substr.align) offset = (offset + substr.align - 1) & -substr.align for off, sfields in substr.fields.items(): for field in sfields: fields[offset + off].append(field) if is_union: union_size = max(union_size, substr.size) else: offset += substr.size elif isinstance(type, ca.Enum): parse_enum(type, typemap) if not is_union and bit_offset != 0: bit_offset = 0 offset += 1 # If there is a typedef for this struct, prefer using that name if struct in typemap.struct_typedefs: ctype = typemap.struct_typedefs[struct] elif struct.name and struct.name in typemap.struct_typedefs: ctype = typemap.struct_typedefs[struct.name] else: ctype = TypeDecl(declname=None, quals=[], type=struct, align=[]) size = union_size if is_union else offset size = (size + align - 1) & -align return Struct(type=ctype, fields=fields, has_bitfields=has_bitfields, size=size, align=align)
def identify_nested(ast_tree): ast = ast_tree old_stdout = sys.stdout sys.stdout = mystdout = StringIO() aux_ast = duplicate_element(ast) list = [] extern_while = get_extern_while_body(aux_ast) identify_nested_algorithms_bodies(extern_while, list) labelname_inner = config.variables_2['round'] rounds_list_inner = config.rounds_list_2 delete_round_phase_inner = config.delete_round_phase message_inner = config.msg_structure_fields_2 variables_inner = config.variables_2 if list: list.reverse() labels = config.rounds_list_2 labels.append('ERR_ROUND') code = None cop = duplicate_element(ast) if len(list) >= config.number_of_nested_algorithms: extern = get_extern_while_body(cop) if isinstance(extern.block_items[0], If): myif = extern.block_items[0] list1 = [] list2 = [] aux1 = [] aux2 = [] identify_nested_algorithms_bodies(extern.block_items[0].iftrue, list1) if list1: sys.stdout = old_stdout for elem in list1: conditii = [] whiles_to_if(elem.stmt, conditii) identify_recv_exits(elem.stmt, conditii) remove_mbox(elem.stmt, config.mailbox_2, config.clean_mailbox_2) aux1 = elem.stmt parent = find_parent(ast, elem) index = parent.block_items.index(elem) parent.block_items.remove(elem) coord = elem.coord new_id = ID("inner_algorithm", coord) func = FuncCall(new_id, None, coord) assign_unique_coord(func, coord) parent.block_items.insert(index, func) identify_nested_algorithms_bodies( extern.block_items[0].iffalse, list2) if list2: for elem in list2: conditii = [] whiles_to_if(elem.stmt, conditii) identify_recv_exits(elem.stmt, conditii) remove_mbox(elem.stmt, config.mailbox_2, config.clean_mailbox_2) aux2 = elem.stmt parent = find_parent(ast, elem) index = parent.block_items.index(elem) parent.block_items.remove(elem) coord = elem.coord new_id = ID("inner_algorithm", coord) func = FuncCall(new_id, None, coord) assign_unique_coord(func, coord) parent.block_items.insert(index, func) if aux1 and aux2: myif.iftrue = None myif.iffalse = None myif.iftrue = aux1 myif.iffalse = aux2 trees_dict, trees_paths_dict, is_job = get_paths_trees( cop, labels, labels, config.variables_2['round']) print_rounds(labels, trees_dict, trees_paths_dict, config.variables_2['round'], is_job, delete_round_phase_inner, message_inner, variables_inner, rounds_list_inner[0]) code = mystdout.getvalue() sys.stdout = old_stdout return ast, code else: for elem in list: # print generator.visit(elem), "AAAAAAAAAAA" conditii = [] whiles_to_if(elem.stmt, conditii) identify_recv_exits(elem.stmt, conditii) remove_mbox(elem.stmt, config.mailbox_2, config.clean_mailbox_2) # print generator.visit(elem) trees_dict, trees_paths_dict, is_job = get_paths_trees( elem.stmt, labels, labels, config.variables_2['round']) # print_code(trees_dict, trees_paths_dict, labels) print_rounds(labels, trees_dict, trees_paths_dict, config.variables_2['round'], is_job, delete_round_phase_inner, message_inner, variables_inner, rounds_list_inner[0]) parent = find_parent(ast, elem) index = parent.block_items.index(elem) parent.block_items.remove(elem) coord = elem.coord new_id = ID("inner_algorithm", coord) func = FuncCall(new_id, None, coord) assign_unique_coord(func, coord) parent.block_items.insert(index, func) # print generator.visit(parent.block_items[index]) # print generator.visit(ast) # print generator.visit(func) funcdecl = FuncDecl( None, TypeDecl('inner_algorithm', None, IdentifierType(['int']))) decl = Decl('inner_algorithm', None, None, None, funcdecl, None, None) funcdef = FuncDef(decl, None, None) code = mystdout.getvalue() funcdef.body = Compound([code]) # print generator.visit(ast) sys.stdout = old_stdout return ast, code else: sys.stdout = old_stdout print "pe else" return ast_tree