about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--miasm2/arch/x86/ctype.py50
-rw-r--r--miasm2/core/ctypesmngr.py375
-rw-r--r--miasm2/core/objc.py1280
3 files changed, 1705 insertions, 0 deletions
diff --git a/miasm2/arch/x86/ctype.py b/miasm2/arch/x86/ctype.py
new file mode 100644
index 00000000..6b5844d7
--- /dev/null
+++ b/miasm2/arch/x86/ctype.py
@@ -0,0 +1,50 @@
+from miasm2.core.objc import CTypeTemplate, ObjCDecl
+
+
+class CTypeAMD64_unk(CTypeTemplate):
+    """Define C types sizes/alignement for x86_64 architecture"""
+
+    obj_char = ObjCDecl("char", 1, 1)
+    obj_short = ObjCDecl("short", 2, 2)
+    obj_int = ObjCDecl("int", 4, 4)
+    obj_long = ObjCDecl("long", 8, 8)
+
+    obj_uchar = ObjCDecl("uchar", 1, 1)
+    obj_ushort = ObjCDecl("ushort", 2, 2)
+    obj_uint = ObjCDecl("uint", 4, 4)
+    obj_ulong = ObjCDecl("ulong", 8, 8)
+    obj_void = ObjCDecl("void", 1, 1)
+
+    obj_enum = ObjCDecl("enum", 4, 4)
+
+
+    def __init__(self):
+        self.types = {
+            ('char',): self.obj_char,
+            ('short',): self.obj_short,
+            ('int',): self.obj_int,
+            ('void',): self.obj_void,
+            ('enum',): self.obj_enum,
+
+            ('signed', 'char'): self.obj_char,
+            ('unsigned', 'char'): self.obj_uchar,
+            ('signed', 'short', 'int'): self.obj_short,
+            ('short', 'int'): self.obj_short,
+            ('unsigned', 'short'): self.obj_ushort,
+            ('unsigned', 'short', 'int'): self.obj_ushort,
+            ('signed', 'int'): self.obj_int,
+            ('unsigned', 'int'): self.obj_uint,
+            ('long', 'int'): self.obj_long,
+            ('unsigned', 'long'): self.obj_ulong,
+            ('signed', 'long', 'int'): self.obj_long,
+            ('unsigned', 'long', 'int'): self.obj_ulong,
+            ('long',): self.obj_long,
+            ('unsigned', ): self.obj_uint,
+
+            ('signed', 'long', 'long', 'int'): self.obj_long,
+            ('long', 'unsigned', 'int'): self.obj_ulong,
+            ('unsigned', 'long', 'long'): self.obj_ulong,
+            ('long', 'long', 'int'): self.obj_long,
+            ('unsigned', 'long', 'long', 'int'): self.obj_ulong,
+            ('void*',): self.obj_ulong,
+        }
diff --git a/miasm2/core/ctypesmngr.py b/miasm2/core/ctypesmngr.py
new file mode 100644
index 00000000..518c328d
--- /dev/null
+++ b/miasm2/core/ctypesmngr.py
@@ -0,0 +1,375 @@
+from pycparser import c_ast
+from miasm2.core.objc import ObjCStruct, ObjCUnion, ObjCDecl, ObjCPtr, \
+    ObjCArray, _ObjCRecurse, c_to_ast
+
+
+def fix_recursive_objects(types_mngr, obj):
+    """Replace _ObjCRecurse objects by its parent"""
+
+    void_type = types_mngr.void_ptr
+
+    if isinstance(obj, ObjCStruct):
+        for i, (name, fieldtype, offset, size) in enumerate(obj.fields):
+            fieldtype = fix_recursive_objects(types_mngr, fieldtype)
+            obj.fields[i] = (name, fieldtype, offset, size)
+    elif isinstance(obj, ObjCDecl):
+        return obj
+    elif isinstance(obj, ObjCPtr):
+        target_obj = fix_recursive_objects(types_mngr, obj.objtype)
+        obj = ObjCPtr(obj.name, target_obj, void_type.align, void_type.size)
+    elif isinstance(obj, ObjCArray):
+        target_obj = fix_recursive_objects(types_mngr, obj.objtype)
+        obj = ObjCArray(target_obj, obj.elems)
+    elif isinstance(obj, ObjCUnion):
+        for i, (name, fieldtype, offset, size) in enumerate(obj.fields):
+            fieldtype = fix_recursive_objects(types_mngr, fieldtype)
+            obj.fields[i] = (name, fieldtype, offset, size)
+    elif isinstance(obj, _ObjCRecurse):
+        obj = types_mngr.get_type((obj.name,))
+    else:
+        raise NotImplementedError("Unknown type")
+    return obj
+
+
+class CTypesManager(object):
+    """Store all defined C types"""
+
+    def __init__(self, knowntypes):
+        self._types = dict(knowntypes)
+        self.cpt = 0
+
+    def gen_uniq_name(self):
+        """Generate uniq name for unamed strucs/union"""
+        cpt = self.cpt
+        self.cpt += 1
+        return "__TYPE_INTERNAL__%d" % cpt
+
+    def add_type(self, type_id, type_obj):
+        """Add new C type
+        @type_id: Type descriptor
+        @type_obj: ObjC* instance"""
+        self._types[type_id] = type_obj
+
+    def get_type(self, type_id):
+        """Get C type
+        @type_id: Type descriptor
+        """
+        return self._types[type_id]
+
+    def is_known_type(self, type_id):
+        """Return true if @type_id is known
+        @type_id: Type descriptor
+        """
+        return type_id in self._types
+
+    def add_c_decl_from_ast(self, ast):
+        """
+        Adds types from a C ast
+        @ast: C ast
+        """
+        self.ast_parse_declarations(ast)
+
+    def add_c_decl(self, c_str):
+        """
+        Adds types from a C string types declaring
+        Note: will ignore lines containing code refs ie:
+        '# 23 "miasm.h"'
+        Returns the C ast
+        @c_str: C string containing C types declarations
+        """
+        ast = c_to_ast(c_str)
+        self.add_c_decl_from_ast(ast)
+
+        return ast
+
+    @property
+    def void_ptr(self):
+        """Return the void* type"""
+        return self.get_type(('void*',))
+
+    def ast_eval_size(self, ast):
+        """Evaluates the size of a C ast object
+
+        @ast: parsed pycparser.c_ast object
+        """
+
+        if isinstance(ast, c_ast.TypeDecl):
+            result = self.ast_eval_size(ast.type)
+        elif isinstance(ast, c_ast.PtrDecl):
+            void_type = self.void_ptr
+            result = void_type.size
+        elif isinstance(ast, c_ast.IdentifierType):
+            obj = self.get_type(tuple(ast.names))
+            result = obj.size
+        else:
+            raise NotImplementedError('TODO')
+        return result
+
+    def ast_eval_int(self, ast):
+        """Eval a C ast object integer
+
+        @ast: parsed pycparser.c_ast object
+        """
+
+        if isinstance(ast, c_ast.BinaryOp):
+            left = self.ast_eval_int(ast.left)
+            right = self.ast_eval_int(ast.right)
+            if ast.op == '*':
+                result = left * right
+            elif ast.op == '/':
+                assert left % right == 0
+                result = left / right
+            elif ast.op == '+':
+                result = left + right
+            elif ast.op == '-':
+                result = left - right
+            else:
+                raise NotImplementedError("Not implemented!")
+        elif isinstance(ast, c_ast.UnaryOp):
+            if ast.op == 'sizeof' and isinstance(ast.expr, c_ast.Typename):
+                result = self.ast_eval_size(ast.expr.type)
+            else:
+                raise NotImplementedError("Not implemented!")
+
+        elif isinstance(ast, c_ast.Constant):
+            result = int(ast.value, 0)
+        elif isinstance(ast, c_ast.Cast):
+            # TODO: Can trunc intergers?
+            result = self.ast_eval_int(ast.expr)
+        else:
+            raise NotImplementedError("Not implemented!")
+        return result
+
+
+    def ast_get_align_size(self, ast):
+        """Evaluates the size/alignment of a C ast object
+
+        @ast: parsed pycparser.c_ast object
+        """
+
+        if isinstance(ast, c_ast.Decl):
+            return self.ast_get_align_size(ast.type)
+        elif isinstance(ast, c_ast.TypeDecl):
+            return self.ast_get_align_size(ast.type)
+        elif isinstance(ast, c_ast.IdentifierType):
+            assert isinstance(ast, c_ast.IdentifierType)
+            names = ast.names
+            names = tuple(names)
+            if not self.is_known_type(names):
+                raise RuntimeError("Unknown type %r" % names)
+            obj = self.get_type(names)
+        elif isinstance(ast, c_ast.ArrayDecl):
+            subobj = self.ast_get_align_size(ast.type)
+            dim = ast.dim
+            value = self.ast_eval_int(dim)
+            obj = ObjCArray(subobj, value)
+        elif isinstance(ast, c_ast.Union):
+            obj = self.ast_gen_union_align_size(ast)
+        elif isinstance(ast, c_ast.Struct):
+            obj = self.ast_gen_struct_align_size(ast)
+        elif isinstance(ast, c_ast.PtrDecl):
+            void_type = self.void_ptr
+            subobj = self.ast_get_align_size(ast.type)
+            obj = ObjCPtr('noname', subobj, void_type.align, void_type.size)
+        else:
+            raise NotImplementedError("Not implemented!")
+        assert isinstance(obj, _ObjCRecurse) or obj.align in [
+            1, 2, 4, 8, 16, 32, 64, 128, 256]
+        return obj
+
+    def struct_compute_field_offset(self, obj, offset):
+        """Compute the offset of the field @obj in the current structure"""
+        raise NotImplementedError("Abstract method")
+
+    def struct_compute_align_size(self, align_max, size):
+        """Compute the alignment and size of the current structure"""
+        raise NotImplementedError("Abstract method")
+
+    def union_compute_align_size(self, align_max, size):
+        """Compute the alignment and size of the current union"""
+        raise NotImplementedError("Abstract method")
+
+    def ast_gen_struct_align_size(self, ast):
+        """Evaluates the size/alignment of a C ast structure
+        (default packed)
+
+        @ast: parsed pycparser.c_ast object
+        """
+
+        offset = 0
+        align_max = 1
+
+        if ast.name is None:
+            name = self.gen_uniq_name()
+        else:
+            name = ast.name
+        new_obj = ObjCStruct(name)
+        if ast.decls is None:
+            # If object is unknown, it's a recursive struct
+            if self.is_known_type((name,)):
+                obj = self.get_type((name,))
+            else:
+                obj = _ObjCRecurse(name)
+            return obj
+        for arg in ast.decls:
+            obj = self.ast_get_align_size(arg)
+            align_max = max(align_max, obj.align)
+            offset = self.struct_compute_field_offset(obj, offset)
+            new_obj.add_field(arg.name, obj, offset, obj.size)
+            offset += obj.size
+
+        # Structure alignement is its field max alignement
+        align, size = self.struct_compute_align_size(align_max, offset)
+        new_obj.set_align_size(align, size)
+        self.add_type((name, ), new_obj)
+        return new_obj
+
+    def ast_gen_union_align_size(self, ast):
+        """Evaluates the size/alignment of a C ast union
+        @ast: parsed pycparser.c_ast object
+        """
+        offset = 0
+        align_max, size_max = 0, 0
+
+        if ast.name is None:
+            name = self.gen_uniq_name()
+        else:
+            name = ast.name
+        new_obj = ObjCUnion(name)
+
+        for arg in ast.decls:
+            obj = self.ast_get_align_size(arg)
+            align_max = max(align_max, obj.align)
+            size_max = max(size_max, obj.size)
+            new_obj.add_field(arg.name, obj,
+                              offset, obj.size)
+
+        align, size = self.union_compute_align_size(align_max, size_max)
+        new_obj.set_align_size(align, size)
+        self.add_type((name, ), new_obj)
+        return new_obj
+
+    def ast_gen_obj_align_size(self, ast):
+        """Evaluates the size/alignment of a C ast struct/union
+        (packed style in type manager)
+
+        @ast: parsed pycparser.c_ast object
+        """
+
+        if isinstance(ast, c_ast.Struct):
+            obj = self.ast_gen_struct_align_size(ast)
+        elif isinstance(ast, c_ast.Union):
+            obj = self.ast_gen_union_align_size(ast)
+        else:
+            raise NotImplementedError("Not implemented!")
+
+        fix_recursive_objects(self, obj)
+        return obj
+
+    def ast_parse_declarations(self, ast):
+        """Add ast types declaration to the type manager
+        (packed style in type manager)
+
+        @ast: parsed pycparser.c_ast object
+        """
+
+        for ext in ast.ext:
+            if isinstance(ext, c_ast.Decl) and\
+               ext.name is None and\
+               isinstance(ext.type, (c_ast.Struct, c_ast.Union)):
+                obj = self.ast_gen_obj_align_size(ext.type)
+                self.add_type((ext.type.name, ), obj)
+
+            elif isinstance(ext, c_ast.Typedef) and\
+                    isinstance(ext.type.type, (c_ast.Struct, c_ast.Union)) and\
+                    not ext.type.type.decls:
+                new_type = ext.name
+                obj = self.get_type((ext.type.type.name,))
+                self.add_type((ext.name,), obj)
+
+            elif isinstance(ext, c_ast.Typedef) and\
+                    isinstance(ext.type.type, (c_ast.Struct, c_ast.Union)) and\
+                    ext.type.type.decls:
+                obj = self.ast_gen_obj_align_size(ext.type.type)
+                self.add_type((ext.type.declname, ), obj)
+
+            elif isinstance(ext, c_ast.Typedef) and\
+                    isinstance(ext.type, c_ast.TypeDecl) and\
+                    isinstance(ext.type.type, c_ast.IdentifierType):
+                ext.show()
+                names = tuple(ext.type.type.names)
+                new_type = ext.name
+
+                if not self.is_known_type(names):
+                    raise RuntimeError("Unknown type %s" % repr(names))
+                obj = self.get_type(names)
+                self.add_type((new_type,), obj)
+
+            elif isinstance(ext, c_ast.Typedef) and\
+                    isinstance(ext.type.type, c_ast.Enum) and\
+                    isinstance(ext.type.type.values, c_ast.EnumeratorList):
+                # Enum are ints
+                obj = self.get_type(('enum',))
+                self.add_type((ext.name,), obj)
+
+            elif isinstance(ext, c_ast.Typedef) and\
+                    isinstance(ext.type, c_ast.ArrayDecl) and\
+                    isinstance(ext.type.type.type, c_ast.IdentifierType) and\
+                    self.is_known_type(tuple(ext.type.type.type.names)):
+                obj = self.get_type(tuple(ext.type.type.type.names))
+                array = ext.type
+
+                value = self.ast_eval_int(array.dim)
+                subobj = self.ast_get_align_size(array.type)
+
+                obj = ObjCArray(subobj, value)
+                self.add_type((ext.name,), obj)
+
+            elif isinstance(ext, c_ast.FuncDef) or\
+                    isinstance(ext.type, c_ast.FuncDecl):
+                continue
+            else:
+                raise NotImplementedError("strange type %r" % ext)
+
+
+class CTypesManagerNotPacked(CTypesManager):
+    """Store defined C types (not packed)"""
+
+    def struct_compute_field_offset(self, obj, offset):
+        """Compute the offset of the field @obj in the current structure
+        (not packed)"""
+
+        if obj.align > 1:
+            offset = (offset + obj.align - 1) & ~(obj.align - 1)
+        return offset
+
+    def struct_compute_align_size(self, align_max, size):
+        """Compute the alignment and size of the current structure
+        (not packed)"""
+        if align_max > 1:
+            size = (size + align_max - 1) & ~(align_max - 1)
+        return align_max, size
+
+    def union_compute_align_size(self, align_max, size):
+        """Compute the alignment and size of the current union
+        (not packed)"""
+        return align_max, size
+
+
+class CTypesManagerPacked(CTypesManager):
+    """Store defined C types (packed form)"""
+
+    def struct_compute_field_offset(self, _, offset):
+        """Compute the offset of the field @obj in the current structure
+        (packed form)"""
+        return offset
+
+    def struct_compute_align_size(self, _, size):
+        """Compute the alignment and size of the current structure
+        (packed form)"""
+        return 1, size
+
+    def union_compute_align_size(self, align_max, size):
+        """Compute the alignment and size of the current union
+        (packed form)"""
+        return 1, size
diff --git a/miasm2/core/objc.py b/miasm2/core/objc.py
new file mode 100644
index 00000000..1b595442
--- /dev/null
+++ b/miasm2/core/objc.py
@@ -0,0 +1,1280 @@
+"""
+C helper for Miasm:
+* raw C to Miasm expression
+* Miasm expression to raw C
+* Miasm expression to C type
+"""
+
+import re
+
+from pycparser import c_parser, c_ast
+
+from miasm2.expression.expression_reduce import ExprReducer
+from miasm2.expression.expression import ExprInt, ExprId, ExprOp, ExprMem
+
+RE_HASH_CMT = re.compile(r'^#\s*\d+.*$', flags=re.MULTILINE)
+
+
+class ObjC(object):
+    """Generic ObjC"""
+
+    def set_align_size(self, align, size):
+        """Set C object alignment and size"""
+
+        self.align = align
+        self.size = size
+
+
+class ObjCDecl(ObjC):
+    """C Declaration identified"""
+
+    def __init__(self, name, align, size):
+        super(ObjCDecl, self).__init__()
+        self.name, self.align, self.size = name, align, size
+
+    def __repr__(self):
+        return '<%s %s>' % (self.__class__.__name__, self.name)
+
+
+class ObjCInt(ObjC):
+    """C integer"""
+
+    def __init__(self):
+        super(ObjCInt, self).__init__()
+        self.size = None
+        self.align = None
+
+
+class ObjCPtr(ObjC):
+    """C Pointer"""
+
+    def __init__(self, name, objtype, void_p_align, void_p_size):
+        """Init ObjCPtr
+
+        @name: object name
+        @objtype: pointer target ObjC
+        @void_p_align: pointer alignment (in bytes)
+        @void_p_size: pointer size (in bytes)
+        """
+
+        super(ObjCPtr, self).__init__()
+        self.name, self.objtype = name, objtype
+        self.align = void_p_align
+        self.size = void_p_size
+
+    def __repr__(self):
+        return '<PTR %r>' % (self.objtype)
+
+    def __str__(self):
+        return '<PTR %r>' % (self.objtype)
+
+
+class ObjCArray(ObjC):
+    """C array (test[XX])"""
+
+    def __init__(self, objtype, elems):
+        """Init ObjCArray
+
+        @objtype: pointer target ObjC
+        @elems: number of elements in the array
+        """
+
+        super(ObjCArray, self).__init__()
+        self.elems = elems
+        self.objtype = objtype
+        self.align = objtype.align
+        self.size = elems * objtype.size
+
+    def __repr__(self):
+        return '<%r[%d]>' % (self.objtype, self.elems)
+
+
+class _ObjCRecurse(ObjC):
+    """Special C object array, used in recursive declarations. Used in parser
+    *only*: this object is not intend to be in final objects
+    """
+
+    def __init__(self, name):
+        super(_ObjCRecurse, self).__init__()
+        self.name = name
+
+    def __repr__(self):
+        return '<%r>' % (self.name)
+
+
+class ObjCStruct(ObjC):
+    """C object for structures"""
+
+    def __init__(self, name):
+        super(ObjCStruct, self).__init__()
+        self.name = name
+        self.fields = []
+
+    def add_field(self, name, objtype, offset, size):
+        """Add a field into the structure
+        @name: field name
+        @objtype: field type
+        @offset: field offset in the structure
+        @size: field size
+        """
+
+        self.fields.append((name, objtype, offset, size))
+
+    def __repr__(self):
+        return '<%s %s>' % (self.__class__.__name__, self.name)
+
+    def __str__(self):
+        out = []
+        out.append("Struct %s: (align: %d)" % (self.name, self.align))
+        out.append("  off sz  name")
+        for name, objtype, offset, size in self.fields:
+            out.append("  %-3d %-3d %-10s %r" % (offset, size, name, objtype))
+        return '\n'.join(out)
+
+
+class ObjCUnion(ObjC):
+    """C object for unions"""
+
+    def __init__(self, name):
+        super(ObjCUnion, self).__init__()
+        self.name = name
+        self.fields = []
+
+    def add_field(self, name, objtype, offset, size):
+        """Add a field into the structure
+        @name: field name
+        @objtype: field type
+        @offset: field offset in the structure
+        @size: field size
+        """
+
+        self.fields.append((name, objtype, offset, size))
+
+    def __repr__(self):
+        return '<%s %s>' % (self.__class__.__name__, self.name)
+
+    def __str__(self):
+        out = []
+        out.append("Union %s: (align: %d)" % (self.name, self.align))
+        out.append("  off sz  name")
+        for name, objtype, offset, size in self.fields:
+            out.append("  %-3d %-3d %-10s %r" % (offset, size, name, objtype))
+        return '\n'.join(out)
+
+
+def access_simplifier(expr):
+    """Expression visitor to simplify a C access represented in Miasm
+
+    @expr: Miasm expression representing the C access
+
+    Example:
+
+    IN: (In c: ['*(&((&((*(ptr_Test)).a))[0]))'])
+    [ExprOp('deref', ExprOp('addr', ExprOp('[]', ExprOp('addr',
+    ExprOp('field', ExprOp('deref', ExprId('ptr_Test', 64)),
+    ExprId('a', 64))), ExprInt(0x0, 64))))]
+
+    OUT: (In c: ['(ptr_Test)->a'])
+    [ExprOp('->', ExprId('ptr_Test', 64), ExprId('a', 64))]
+    """
+
+    if (expr.is_op("addr") and
+            expr.args[0].is_op("[]") and
+            expr.args[0].args[1] == ExprInt(0, 64)):
+        return expr.args[0].args[0]
+    elif (expr.is_op("[]") and
+          expr.args[0].is_op("addr") and
+          expr.args[1] == ExprInt(0, 64)):
+        return expr.args[0].args[0]
+    elif (expr.is_op("addr") and
+          expr.args[0].is_op("deref")):
+        return expr.args[0].args[0]
+    elif (expr.is_op("deref") and
+          expr.args[0].is_op("addr")):
+        return expr.args[0].args[0]
+    elif (expr.is_op("field") and
+          expr.args[0].is_op("deref")):
+        return ExprOp("->", expr.args[0].args[0], expr.args[1])
+    return expr
+
+
+def access_str(expr):
+    """Return the C string of a C access represented in Miasm
+
+    @expr: Miasm expression representing the C access
+
+    In:
+    ExprOp('->', ExprId('ptr_Test', 64), ExprId('a', 64))
+    OUT:
+    '(ptr_Test)->a'
+    """
+
+    if isinstance(expr, ExprId):
+        out = str(expr)
+    elif isinstance(expr, ExprInt):
+        out = str(int(expr))
+    elif expr.is_op("addr"):
+        out = "&(%s)" % access_str(expr.args[0])
+    elif expr.is_op("deref"):
+        out = "*(%s)" % access_str(expr.args[0])
+    elif expr.is_op("field"):
+        out = "(%s).%s" % (access_str(expr.args[0]), access_str(expr.args[1]))
+    elif expr.is_op("->"):
+        out = "(%s)->%s" % (access_str(expr.args[0]), access_str(expr.args[1]))
+    elif expr.is_op("[]"):
+        out = "(%s)[%s]" % (access_str(expr.args[0]), access_str(expr.args[1]))
+    else:
+        raise RuntimeError("unknown op")
+
+    return out
+
+
+class CGen(object):
+    """Generic object to represent a C expression"""
+
+    default_size = 64
+
+    def to_c(self):
+        """Generate corresponding C"""
+
+        raise NotImplementedError("Virtual")
+
+    def to_expr(self):
+        """Generate Miasm expression representing the C access"""
+
+        raise NotImplementedError("Virtual")
+
+
+class CGenInt(CGen):
+    """Int C object"""
+
+    def __init__(self, integer):
+        assert isinstance(integer, (int, long))
+        self.integer = integer
+        self.ctype = ObjCInt()
+
+    def to_c(self):
+        """Generate corresponding C"""
+
+        return "0x%X" % self.integer
+
+    def __repr__(self):
+        return "<%s %s>" % (self.__class__.__name__,
+                            self.integer)
+
+    def to_expr(self):
+        """Generate Miasm expression representing the C access"""
+
+        return ExprInt(self.integer, self.default_size)
+
+
+class CGenId(CGen):
+    """ID of a C object"""
+
+    def __init__(self, ctype, name):
+        self.ctype = ctype
+        self.name = name
+        assert isinstance(name, str)
+
+    def __repr__(self):
+        return "<%s %s>" % (self.__class__.__name__,
+                            self.name)
+
+    def to_c(self):
+        """Generate corresponding C"""
+
+        return "%s" % (self.name)
+
+    def to_expr(self):
+        """Generate Miasm expression representing the C access"""
+
+        return ExprId(self.name, self.default_size)
+
+
+class CGenField(CGen):
+    """
+    Field of a C struct/union
+
+    IN:
+    - struct (not ptr struct)
+    - field name
+    OUT:
+    - input type of the field => output type
+    - X[] => X[]
+    - X => X*
+    """
+
+    def __init__(self, struct, field, fieldtype, void_p_align, void_p_size):
+        self.struct = struct
+        self.field = field
+        assert isinstance(field, str)
+        if isinstance(fieldtype, ObjCArray):
+            ctype = fieldtype
+        else:
+            ctype = ObjCPtr(field, fieldtype, void_p_align, void_p_size)
+        self.ctype = ctype
+
+    def to_c(self):
+        """Generate corresponding C"""
+
+        if isinstance(self.ctype, ObjCArray):
+            return "(%s).%s" % (self.struct.to_c(), self.field)
+        elif isinstance(self.ctype, ObjCPtr):
+            return "&((%s).%s)" % (self.struct.to_c(), self.field)
+        else:
+            raise RuntimeError("Strange case")
+
+    def __repr__(self):
+        return "<%s %s %s>" % (self.__class__.__name__,
+                               self.struct,
+                               self.field)
+
+    def to_expr(self):
+        """Generate Miasm expression representing the C access"""
+
+        if isinstance(self.ctype, ObjCArray):
+            return ExprOp("field", self.struct.to_expr(), ExprId(self.field, self.default_size))
+        elif isinstance(self.ctype, ObjCPtr):
+            return ExprOp("addr", ExprOp("field", self.struct.to_expr(), ExprId(self.field, self.default_size)))
+        else:
+            raise RuntimeError("Strange case")
+
+
+class CGenArray(CGen):
+    """
+    C Array
+
+    This object does *not* deref the source, it only do object casting.
+
+    IN:
+    - obj
+    OUT:
+    - X* => X*
+    - ..[][] => ..[]
+    - X[] => X*
+    """
+
+    def __init__(self, name, element, void_p_align, void_p_size):
+        ctype = name.ctype
+        if isinstance(ctype, ObjCPtr):
+            pass
+        elif isinstance(ctype, ObjCArray) and isinstance(ctype.objtype, ObjCArray):
+            ctype = ctype.objtype
+        elif isinstance(ctype, ObjCArray):
+            ctype = ObjCPtr('noname', ctype.objtype, void_p_align, void_p_size)
+        else:
+            raise TypeError("Strange case")
+        self.ctype = ctype
+        self.name = name
+        self.element = element
+
+    def __repr__(self):
+        return "<%s %s>" % (self.__class__.__name__,
+                            self.name)
+
+    def to_c(self):
+        """Generate corresponding C"""
+
+        if isinstance(self.ctype, ObjCPtr):
+            out_str = "&((%s)[%d])" % (self.name.to_c(), self.element)
+        elif isinstance(self.ctype, ObjCArray):
+            out_str = "(%s)[%d]" % (self.name.to_c(), self.element)
+        else:
+            raise RuntimeError("Strange case")
+        return out_str
+
+    def to_expr(self):
+        """Generate Miasm expression representing the C access"""
+
+        if isinstance(self.ctype, ObjCPtr):
+            return ExprOp("addr", ExprOp("[]", self.name.to_expr(), ExprInt(self.element, self.default_size)))
+        elif isinstance(self.ctype, ObjCArray):
+            return ExprOp("[]", self.name.to_expr(), ExprInt(self.element, self.default_size))
+        else:
+            raise RuntimeError("Strange case")
+
+
+class CGenDeref(CGen):
+    """
+    C dereference
+
+    IN:
+    - ptr
+    OUT:
+    - X* => X
+    """
+
+    def __init__(self, mem):
+        assert isinstance(mem.ctype, ObjCPtr)
+        self.ctype = mem.ctype.objtype
+        self.mem = mem
+
+    def __repr__(self):
+        return "<%s %s>" % (self.__class__.__name__,
+                            self.mem)
+
+    def to_c(self):
+        """Generate corresponding C"""
+
+        if not isinstance(self.mem.ctype, ObjCPtr):
+            raise RuntimeError()
+        return "*(%s)" % (self.mem.to_c())
+
+    def to_expr(self):
+        """Generate Miasm expression representing the C access"""
+
+        if not isinstance(self.mem.ctype, ObjCPtr):
+            raise RuntimeError()
+        return ExprOp("deref", self.mem.to_expr())
+
+
+def ast_get_c_access_expr(ast, expr_types, lvl=0):
+    """Transform C ast object into a C Miasm expression
+
+    @ast: parsed pycparser.c_ast object
+    @expr_types: a dictionnary linking ID names to their types
+    @lvl: actual recursion level
+
+    Example:
+
+    IN:
+    StructRef: ->
+      ID: ptr_Test
+      ID: a
+
+    OUT:
+    ExprOp('->', ExprId('ptr_Test', 64), ExprId('a', 64))
+    """
+
+    if isinstance(ast, c_ast.Constant):
+        obj = ExprInt(int(ast.value), 64)
+    elif isinstance(ast, c_ast.StructRef):
+        name, field = ast.name, ast.field.name
+        name = ast_get_c_access_expr(name, expr_types)
+        if ast.type == "->":
+            s_name = name
+            s_field = ExprId(field, 64)
+            obj = ExprOp('->', s_name, s_field)
+        elif ast.type == ".":
+            s_name = name
+            s_field = ExprId(field, 64)
+            obj = ExprOp("field", s_name, s_field)
+        else:
+            raise RuntimeError("Unknown struct access")
+    elif isinstance(ast, c_ast.UnaryOp) and ast.op == "&":
+        tmp = ast_get_c_access_expr(ast.expr, expr_types, lvl + 1)
+        obj = ExprOp("addr", tmp)
+    elif isinstance(ast, c_ast.ArrayRef):
+        tmp = ast_get_c_access_expr(ast.name, expr_types, lvl + 1)
+        index = ast_get_c_access_expr(ast.subscript, expr_types, lvl + 1)
+        obj = ExprOp("[]", tmp, index)
+    elif isinstance(ast, c_ast.ID):
+        assert ast.name in expr_types
+        obj = ExprId(ast.name, 64)
+    elif isinstance(ast, c_ast.UnaryOp) and ast.op == "*":
+        tmp = ast_get_c_access_expr(ast.expr, expr_types, lvl + 1)
+        obj = ExprOp("deref", tmp)
+    else:
+        raise NotImplementedError("Unknown type")
+    return obj
+
+
+def c_to_ast(c_str):
+    """Transform a @c_str into a C ast
+    Note: will ignore lines containing code refs ie:
+    # 23 "miasm.h"
+    """
+
+    new_str = re.sub(RE_HASH_CMT, "", c_str)
+    parser = c_parser.CParser()
+    return parser.parse(new_str, filename='<stdin>')
+
+
+
+def parse_access(c_access):
+    """Parse C access
+
+    @c_access: C access string
+    """
+
+    main = '''
+    int main() {
+    %s;
+    }
+    ''' % c_access
+
+    parser = c_parser.CParser()
+    node = parser.parse(main, filename='<stdin>')
+    access = node.ext[-1].body.block_items[0]
+    return access
+
+
+class CTypeAnalyzer(ExprReducer):
+    """
+    Return the C type(s) of a native Miasm expression
+    """
+
+    def __init__(self, expr_types, types_mngr):
+        """Init TypeAnalyzer
+        @expr_types: a dictionnary linking ID names to their types
+        @types_mngr: types manager
+        """
+
+        self.expr_types = expr_types
+        self.types_mngr = types_mngr
+
+    def updt_expr_types(self, expr_types):
+        """Update expr_types
+        @expr_types: Dictionnary associating name to type
+        """
+
+        self.expr_types = expr_types
+
+    CST = ObjCInt()
+
+    def get_typeof(self, base_type, offset, deref, lvl=0):
+        """Return a list of pointers (or None) on the element at @offset of an
+        object of type @base_type
+
+        In case of no @deref, stops recursion as soon as we reached the base of
+        an object.
+        In other cases, we need to go down to the final dereferenced object
+
+        @base_type: type of main object
+        @offset: offset (in bytes) of the target sub object
+        @deref: get type for a pointer or a deref
+        @lvl: actual recursion level
+        """
+        void_type = self.types_mngr.void_ptr
+
+        if isinstance(base_type, ObjCStruct):
+            if offset == 0 and not deref:
+                # In this case, return the struct*
+                obj = ObjCPtr('noname', base_type,
+                              void_type.align, void_type.size)
+                new_type = [obj]
+                return new_type
+            for _, subtype, f_offset, size in base_type.fields:
+                if not f_offset <= offset < f_offset + size:
+                    continue
+                new_type = self.get_typeof(
+                    subtype, offset - f_offset, deref, lvl + 1)
+                break
+            else:
+                raise RuntimeError('cannot find struct field')
+        elif isinstance(base_type, ObjCArray):
+            sub_offset = offset % (base_type.objtype.size)
+            element_num = offset / (base_type.objtype.size)
+            if element_num >= base_type.elems:
+                return None
+            if offset == 0 and not deref:
+                # In this case, return the array
+                return [base_type]
+            obj = self.get_typeof(
+                base_type.objtype, sub_offset, deref, lvl + 1)
+            new_type = obj
+        elif isinstance(base_type, ObjCDecl):
+            if offset != 0:
+                return []
+            obj = ObjCPtr('noname', base_type, void_type.align, void_type.size)
+
+            new_type = [obj]
+        elif isinstance(base_type, ObjCUnion):
+            out = []
+            if offset == 0 and not deref:
+                # In this case, return the struct*
+                obj = ObjCPtr('noname', base_type,
+                              void_type.align, void_type.size)
+                new_type = [obj]
+                return new_type
+            for _, objtype, f_offset, size in base_type.fields:
+                if not f_offset <= offset < f_offset + size:
+                    continue
+                new_type = self.get_typeof(
+                    objtype, offset - f_offset, deref, lvl + 1)
+                out += new_type
+            new_type = out
+        elif isinstance(base_type, ObjCPtr):
+            obj = ObjCPtr('noname', base_type, void_type.align, void_type.size)
+            new_type = [obj]
+        else:
+            raise NotImplementedError("deref type %r" % base_type)
+        return new_type
+
+    def reduce_id(self, node, _):
+        """Get type of ExprId"""
+
+        if not(isinstance(node.expr, ExprId) and node.expr.name in self.expr_types):
+            return None
+        return [self.expr_types[node.expr.name]]
+
+    def reduce_int(self, node, _):
+        """Get type of ExprInt"""
+
+        if not isinstance(node.expr, ExprInt):
+            return None
+        return [self.CST]
+
+    def reduce_ptr_plus_cst(self, node, lvl):
+        """Get type of ptr + CST"""
+
+        if not (isinstance(node.expr, ExprOp) and
+                node.expr.op == "+" and
+                len(node.args) == 2 and
+                set(type(x) for x in node.args[0].info + node.args[1].info) == set([ObjCInt, ObjCPtr])):
+            return None
+        arg0, arg1 = node.args
+        out = []
+        ptr_offset = int(arg1.expr)
+        for info in arg0.info:
+            ptr_basetype = info.objtype
+            # Array-like: int* ptr; ptr[1] = X
+            out += self.get_typeof(ptr_basetype,
+                                   ptr_offset % ptr_basetype.size,
+                                   False,
+                                   lvl)
+
+        return out
+
+    def reduce_cst_op_cst(self, node, _):
+        """Get type of CST + CST"""
+
+        if not (isinstance(node.expr, ExprOp) and
+                node.expr.op == "+" and
+                set(type(x) for x in node.args[0].info + node.args[1].info) == set([ObjCInt])):
+            return None
+        return [self.CST]
+
+    def reduce_deref(self, node, lvl):
+        """Get type of a dereferenced expression:
+        * @NN[ptr<elem>] -> elem  (type)
+        * @64[ptr<ptr<elem>>] -> ptr<elem>
+        * @32[ptr<struct>] -> struct.00
+        """
+
+        if not isinstance(node.expr, ExprMem):
+            return None
+        if node.arg.info is None:
+            return None
+        found = []
+        for subtype in node.arg.info:
+            # subtype : ptr<elem>
+            if not isinstance(subtype, (ObjCPtr, ObjCArray)):
+                return None
+            target = subtype.objtype
+            # target : type(elem)
+            for ptr_target in self.get_typeof(target, 0, True, lvl):
+                r_target = ptr_target.objtype
+                # ptr_target: ptr<elem>
+                # r_target: elem
+                if r_target.size != node.expr.size / 8:
+                    continue
+                found.append(r_target)
+        if not found:
+            return None
+        return found
+
+    reduction_rules = [reduce_id, reduce_int,
+                       reduce_ptr_plus_cst, reduce_cst_op_cst,
+                       reduce_deref,
+                      ]
+
+    def get_type(self, expr):
+        """Return the C type(s) of the native Miasm expression @expr
+        @expr: Miasm expression"""
+
+        return self.reduce(expr)
+
+
+class ExprToAccessC(ExprReducer):
+    """
+    Generate the C access object(s) for a given native Miasm expression
+    Example:
+    IN:
+    @32[ptr_Test]
+    OUT:
+    [<CGenDeref <CGenArray <CGenField <CGenDeref <CGenId ptr_Test>> a>>>]
+
+    An expression may be represented by multiple accessor (due to unions).
+    """
+
+    def __init__(self, expr_types, types_mngr, enforce_strict_access=True):
+        """Init GenCAccess
+
+        @expr_types: a dictionnary linking ID names to their types
+        @types_mngr: types manager
+        @enforce_strict_access: If false, generate access even on expression
+        pointing to a middle of an object. If true, raise exception if such a
+        pointer is encountered
+        """
+
+        self.expr_types = expr_types
+        self.types_mngr = types_mngr
+        self.enforce_strict_access = enforce_strict_access
+
+    def updt_expr_types(self, expr_types):
+        """Update expr_types
+        @expr_types: Dictionnary associating name to type
+        """
+
+        self.expr_types = expr_types
+
+    def cgen_access(self, cgenobj, base_type, offset, deref, lvl=0):
+        """Return the access(es) which lead to the element at @offset of an
+        object of type @base_type
+
+        In case of no @deref, stops recursion as soon as we reached the base of
+        an object.
+        In other cases, we need to go down to the final dereferenced object
+
+        @cgenobj: current object access
+        @base_type: type of main object
+        @offset: offset (in bytes) of the target sub object
+        @deref: get type for a pointer or a deref
+        @lvl: actual recursion level
+
+
+        IN:
+        - base_type: struct Toto{
+            int a
+            int b
+          }
+        - base_name: var
+        - 4
+        OUT:
+        - CGenField(var, b)
+
+
+
+        IN:
+        - base_type: int a
+        - 0
+        OUT:
+        - CGenAddr(a)
+
+        IN:
+        - base_type: X = int* a
+        - 0
+        OUT:
+        - CGenAddr(X)
+
+        IN:
+        - X = int* a
+        - 8
+        OUT:
+        - ASSERT
+
+
+        IN:
+        - struct toto{
+            int a
+            int b[10]
+          }
+        - 8
+        OUT:
+        - CGenArray(CGenField(toto, b), 1)
+        """
+
+        void_type = self.types_mngr.void_ptr
+        if isinstance(base_type, ObjCStruct):
+            assert 0 <= offset < base_type.size
+            if offset == 0 and not deref:
+                # In this case, return the struct*
+                return [cgenobj]
+
+            out = []
+            for fieldname, subtype, f_offset, size in base_type.fields:
+                if not f_offset <= offset < f_offset + size:
+                    continue
+                fieldptr = CGenField(CGenDeref(cgenobj), fieldname, subtype,
+                                     void_type.align, void_type.size)
+                ret = self.cgen_access(
+                    fieldptr, subtype, offset - f_offset, deref, lvl + 1)
+                for sname in ret:
+                    finalobj = sname
+                    out.append(finalobj)
+                new_type = out
+                break
+            else:
+                raise RuntimeError('Cannot find struct field')
+        elif isinstance(base_type, ObjCArray):
+            element_num = offset / (base_type.objtype.size)
+            assert element_num < base_type.elems
+            f_offset = offset % base_type.objtype.size
+            cur_objtype = base_type
+            curobj = cgenobj
+            subtype = cur_objtype.objtype
+            if subtype == ObjCArray:
+                raise NotImplementedError("TODO")
+            else:
+                if f_offset != 0:
+                    curobj = CGenArray(curobj, element_num,
+                                       void_type.align, void_type.size)
+                    ret = self.cgen_access(
+                        curobj, curobj.ctype.objtype, f_offset, deref, lvl + 1)
+                else:
+                    curobj = CGenArray(curobj, element_num,
+                                       void_type.align, void_type.size)
+                    ret = [curobj]
+                new_type = ret
+        elif isinstance(base_type, ObjCDecl):
+            if self.enforce_strict_access:
+                if offset % base_type.size != 0:
+                    return []
+            elem_num = offset / base_type.size
+
+            nobj = CGenArray(cgenobj, elem_num,
+                             void_type.align, void_type.size)
+            new_type = [(nobj)]
+
+        elif isinstance(base_type, ObjCUnion):
+            out = []
+            if offset == 0 and not deref:
+                # In this case, return the struct*
+                return [cgenobj]
+
+            for fieldname, objtype, f_offset, size in base_type.fields:
+                if not f_offset <= offset < f_offset + size:
+                    continue
+                field = CGenField(CGenDeref(cgenobj), fieldname, objtype,
+                                  void_type.align, void_type.size)
+                new_type = self.cgen_access(
+                    field, objtype, offset - f_offset, deref, lvl + 1)
+                if new_type is None:
+                    continue
+                for sname in new_type:
+                    finalobj = sname
+                    out.append(finalobj)
+            new_type = out
+        elif isinstance(base_type, ObjCPtr):
+            elem_num = offset / base_type.size
+
+            if elem_num == 0:
+                if self.enforce_strict_access:
+                    assert offset % base_type.size == 0
+                nobj = CGenArray(cgenobj, elem_num,
+                                 void_type.align, void_type.size)
+                new_type = [(nobj)]
+            else:
+                if self.enforce_strict_access:
+                    assert offset % base_type.size == 0
+                nobj = CGenArray(cgenobj, elem_num,
+                                 void_type.align, void_type.size)
+                new_type = [(nobj)]
+
+        else:
+            raise NotImplementedError("deref type %r" % base_type)
+        return new_type
+
+    def reduce_id(self, node, _):
+        """Generate access for ExprId"""
+
+        if not (isinstance(node.expr, ExprId) and
+                node.expr.name in self.expr_types):
+            return None
+
+        out = CGenId(self.expr_types[node.expr.name], node.expr.name)
+        return [out]
+
+    def reduce_int(self, node, _):
+        """Generate access for ExprInt"""
+
+        if not isinstance(node.expr, ExprInt):
+            return None
+        return [CGenInt(int(node.expr))]
+
+    def reduce_op(self, node, lvl):
+        """Generate access for ExprOp"""
+
+        if not (isinstance(node.expr, ExprOp) and
+                node.expr.op == "+" and
+                len(node.args) == 2 and
+                set(type(x.ctype) for x in node.args[0].info + node.args[1].info) == set([ObjCInt, ObjCPtr])):
+            return None
+
+        arg0, arg1 = node.args
+        out = []
+        ptr_offset = int(arg1.expr)
+        for name in arg0.info:
+            assert isinstance(name.ctype, ObjCPtr)
+            ptr_basetype = name.ctype.objtype
+            # Array-like: int* ptr; ptr[1] = X
+            ret = self.cgen_access(name,
+                                   ptr_basetype,
+                                   ptr_offset, False, lvl)
+            for subcgenobj in ret:
+                out.append(subcgenobj)
+        return out
+
+    def reduce_mem(self, node, lvl):
+        """Generate access for ExprMem:
+        * @NN[ptr<elem>] -> elem  (type)
+        * @64[ptr<ptr<elem>>] -> ptr<elem>
+        * @32[ptr<struct>] -> struct.00
+        """
+
+        if not isinstance(node.expr, ExprMem):
+            return None
+
+        assert isinstance(node.arg.info, list)
+        found = []
+        for subcgenobj in node.arg.info:
+            assert isinstance(subcgenobj.ctype, ObjCPtr)
+            target = subcgenobj.ctype.objtype
+            # target : type(elem)
+            if isinstance(target, (ObjCStruct, ObjCUnion)):
+                for finalcgenobj in self.cgen_access(subcgenobj, target, 0, True, lvl):
+                    target = finalcgenobj.ctype.objtype
+                    if not(self.enforce_strict_access) or target.size == node.expr.size / 8:
+                        nobj = CGenDeref(finalcgenobj)
+                        found.append(nobj)
+            elif isinstance(target, ObjCArray):
+                final = target.objtype
+                if not(self.enforce_strict_access) or final.size == node.expr.size / 8:
+                    nobj = CGenDeref(subcgenobj)
+                    found.append(nobj)
+
+            else:
+                if not(self.enforce_strict_access) or target.size == node.expr.size / 8:
+                    nobj = CGenDeref(subcgenobj)
+                    found.append(nobj)
+        assert found
+        return found
+
+    reduction_rules = [reduce_id,
+                       reduce_int,
+                       reduce_op,
+                       reduce_mem,
+                      ]
+
+    def get_access(self, expr):
+        """Generate C access(es) for the native Miasm expression @expr
+        @expr: native Miasm expression
+        """
+
+        return self.reduce(expr)
+
+
+class ExprCToExpr(ExprReducer):
+    """Translate a Miasm expression (representing a C access) into a native
+    Miasm expression and its C type:
+
+    Example:
+
+    IN: ((ptr_struct -> f_mini) field x)
+    OUT: @32[ptr_struct + 0x80], int
+
+
+    Tricky cases:
+    Struct S0 {
+        int x;
+        int y[0x10];
+    }
+
+    Struct S1 {
+        int a;
+        S0 toto;
+    }
+
+    S1* ptr;
+
+    Case 1:
+    ptr->toto => ptr + 0x4
+    &(ptr->toto) => ptr + 0x4
+
+    Case 2:
+    (ptr->toto).x => @32[ptr + 0x4]
+    &((ptr->toto).x) => ptr + 0x4
+
+    Case 3:
+    (ptr->toto).y => ptr + 0x8
+    &((ptr->toto).y) => ptr + 0x8
+
+    Case 4:
+    (ptr->toto).y[1] => @32[ptr + 0x8 + 0x4]
+    &((ptr->toto).y[1]) => ptr + 0x8 + 0x4
+
+    """
+
+    def __init__(self, expr_types, types_mngr):
+        """Init ExprCAccess
+
+        @expr_types: a dictionnary linking ID names to their types
+        @types_mngr: types manager
+        """
+
+        self.expr_types = expr_types
+        self.types_mngr = types_mngr
+
+    def updt_expr_types(self, expr_types):
+        """Update expr_types
+        @expr_types: Dictionnary associating name to type
+        """
+
+        self.expr_types = expr_types
+
+    CST = "CST"
+
+    def reduce_id(self, node, _):
+        """Reduce ExprId"""
+
+        if not isinstance(node.expr, ExprId):
+            return None
+        if node.expr.name in self.expr_types:
+            out = (node.expr, self.expr_types[node.expr.name])
+        else:
+            out = (node.expr, None)
+        return out
+
+    def reduce_int(self, node, _):
+        """Reduce ExprInt"""
+
+        if not isinstance(node.expr, ExprInt):
+            return None
+        return self.CST
+
+    def reduce_op_memberof(self, node, _):
+        """Reduce -> operator"""
+
+        if not node.expr.is_op('->'):
+            return None
+        assert len(node.args) == 2
+        out = []
+        assert isinstance(node.args[1].expr, ExprId)
+        field = node.args[1].expr.name
+        src, src_type = node.args[0].info
+        assert isinstance(src_type, (ObjCPtr, ObjCArray))
+        struct_dst = src_type.objtype
+        assert isinstance(struct_dst, ObjCStruct)
+
+        found = False
+        for name, objtype, offset, _ in struct_dst.fields:
+            if name != field:
+                continue
+            expr = src + ExprInt(offset, src.size)
+            if isinstance(objtype, (ObjCArray, ObjCStruct, ObjCUnion)):
+                pass
+            else:
+                expr = ExprMem(expr, objtype.size * 8)
+            assert not found
+            found = True
+            out = (expr, objtype)
+        assert found
+        return out
+
+    def reduce_op_field(self, node, _):
+        """Reduce field operator (Struct or Union)"""
+
+        if not node.expr.is_op('field'):
+            return None
+        assert len(node.args) == 2
+        out = []
+        assert isinstance(node.args[1].expr, ExprId)
+        field = node.args[1].expr.name
+        src, src_type = node.args[0].info
+        struct_dst = src_type
+
+        if isinstance(struct_dst, ObjCStruct):
+            found = False
+            for name, objtype, offset, _ in struct_dst.fields:
+                if name != field:
+                    continue
+                expr = src + ExprInt(offset, src.size)
+                if isinstance(objtype, ObjCArray):
+                    # Case 4
+                    pass
+                elif isinstance(objtype, (ObjCStruct, ObjCUnion)):
+                    # Case 1
+                    pass
+                else:
+                    # Case 2
+                    expr = ExprMem(expr, objtype.size * 8)
+                assert not found
+                found = True
+                out = (expr, objtype)
+        elif isinstance(struct_dst, ObjCUnion):
+            found = False
+            for name, objtype, offset, _ in struct_dst.fields:
+                if name != field:
+                    continue
+                expr = src + ExprInt(offset, src.size)
+                if isinstance(objtype, ObjCArray):
+                    # Case 4
+                    pass
+                elif isinstance(objtype, (ObjCStruct, ObjCUnion)):
+                    # Case 1
+                    pass
+                else:
+                    # Case 2
+                    expr = ExprMem(expr, objtype.size * 8)
+                assert not found
+                found = True
+                out = (expr, objtype)
+        else:
+            raise NotImplementedError("unknown ObjC")
+        assert found
+        return out
+
+    def reduce_op_array(self, node, _):
+        """Reduce array operator"""
+
+        if not node.expr.is_op('[]'):
+            return None
+        assert len(node.args) == 2
+        out = []
+        assert isinstance(node.args[1].expr, ExprInt)
+        cst = node.args[1].expr
+        src, src_type = node.args[0].info
+        objtype = src_type.objtype
+        expr = src + cst * ExprInt(objtype.size, cst.size)
+        if isinstance(src_type, ObjCPtr):
+            if isinstance(objtype, ObjCArray):
+                final = objtype.objtype
+                expr = src + cst * ExprInt(final.size, cst.size)
+                objtype = final
+                expr = ExprMem(expr, final.size * 8)
+                found = True
+            else:
+                expr = ExprMem(expr, objtype.size * 8)
+                found = True
+        elif isinstance(src_type, ObjCArray):
+            if isinstance(objtype, ObjCArray):
+                final = objtype
+                found = True
+            elif isinstance(objtype, ObjCStruct):
+                found = True
+            else:
+                expr = ExprMem(expr, objtype.size * 8)
+                found = True
+        else:
+            raise NotImplementedError("Unknown access" % node.expr)
+        assert found
+        out = (expr, objtype)
+        return out
+
+    def reduce_op_addr(self, node, _):
+        """Reduce addr operator"""
+
+        if not node.expr.is_op('addr'):
+            return None
+        assert len(node.args) == 1
+        out = []
+        src, src_type = node.args[0].info
+
+        void_type = self.types_mngr.void_ptr
+
+        if isinstance(src_type, ObjCArray):
+            out = (src.arg, ObjCPtr('noname', src_type.objtype,
+                                    void_type.align, void_type.size))
+        elif isinstance(src, ExprMem):
+            out = (src.arg, ObjCPtr('noname', src_type,
+                                    void_type.align, void_type.size))
+        elif isinstance(src_type, ObjCStruct):
+            out = (src, ObjCPtr('noname', src_type,
+                                void_type.align, void_type.size))
+        elif isinstance(src_type, ObjCUnion):
+            out = (src, ObjCPtr('noname', src_type,
+                                void_type.align, void_type.size))
+        else:
+            raise NotImplementedError("unk type")
+        return out
+
+    def reduce_op_deref(self, node, _):
+        """Reduce deref operator"""
+
+        if not node.expr.is_op('deref'):
+            return None
+        out = []
+        src, src_type = node.args[0].info
+        assert isinstance(src_type, (ObjCPtr, ObjCArray))
+        size = src_type.objtype.size * 8
+        out = (ExprMem(src, size), (src_type.objtype))
+        return out
+
+    reduction_rules = [reduce_id,
+                       reduce_int,
+                       reduce_op_memberof,
+                       reduce_op_field,
+                       reduce_op_array,
+                       reduce_op_addr,
+                       reduce_op_deref,
+                      ]
+
+    def get_expr(self, expr):
+        """Translate a Miasm expression @expr (representing a C access) into a
+        native Miasm expression and its C type
+
+        @expr: Miasm expression (representing a C access)
+        """
+
+        return self.reduce(expr)
+
+
+class CHandler(object):
+    """
+    C manipulator for Miasm
+    Miasm expr <-> C
+    """
+
+    exprCToExpr_cls = ExprCToExpr
+    cTypeAnalyzer_cls = CTypeAnalyzer
+    exprToAccessC_cls = ExprToAccessC
+
+    def __init__(self, types_mngr, expr_types,
+                 simplify_c=access_simplifier,
+                 enforce_strict_access=True):
+        self.exprc2expr = self.exprCToExpr_cls(expr_types, types_mngr)
+        self.type_analyzer = self.cTypeAnalyzer_cls(expr_types, types_mngr)
+        self.access_c_gen = self.exprToAccessC_cls(expr_types,
+                                                   types_mngr,
+                                                   enforce_strict_access)
+        self.simplify_c = simplify_c
+        self.expr_types = expr_types
+
+    def updt_expr_types(self, expr_types):
+        """Update expr_types
+        @expr_types: Dictionnary associating name to type
+        """
+
+        self.expr_types = expr_types
+        self.exprc2expr.updt_expr_types(expr_types)
+        self.type_analyzer.updt_expr_types(expr_types)
+        self.access_c_gen.updt_expr_types(expr_types)
+
+    def expr_to_c(self, expr):
+        """Convert a Miasm @expr into it's C equivatlent string
+        @expr: Miasm expression"""
+
+        expr_access = self.access_c_gen.get_access(expr)
+        accesses = [access for access in expr_access.info]
+        accesses_simp = [access_str(access.to_expr().visit(self.simplify_c))
+                         for access in accesses]
+        return accesses_simp
+
+    def expr_to_types(self, expr):
+        """Get the possible types of the Miasm @expr
+        @expr: Miasm expression"""
+
+        return self.type_analyzer.get_type(expr).info
+
+    def c_to_expr(self, c_str):
+        """Convert a C string expression to a Miasm expression
+        @c_str: C string"""
+
+        ast = parse_access(c_str)
+        access_c = ast_get_c_access_expr(ast, self.expr_types)
+        return self.exprc2expr.get_expr(access_c).info[0]
+
+    def c_to_type(self, c_str):
+        """Get the type of a C string expression
+        @expr: Miasm expression"""
+
+        ast = parse_access(c_str)
+        access_c = ast_get_c_access_expr(ast, self.expr_types)
+        ret_type = self.exprc2expr.get_expr(access_c).info[1]
+        return ret_type
+
+
+class CTypeTemplate(object):
+    """Define C types sizes/alignement for a given architecture"""
+    pass