about summary refs log tree commit diff stats
path: root/miasm2
diff options
context:
space:
mode:
Diffstat (limited to 'miasm2')
-rw-r--r--miasm2/analysis/cst_propag.py178
-rw-r--r--miasm2/core/ctypesmngr.py44
-rw-r--r--miasm2/core/objc.py1049
-rw-r--r--miasm2/expression/expression_reduce.py27
-rw-r--r--miasm2/ir/ir.py14
-rw-r--r--miasm2/ir/symbexec.py12
-rw-r--r--miasm2/ir/symbexec_types.py178
7 files changed, 826 insertions, 676 deletions
diff --git a/miasm2/analysis/cst_propag.py b/miasm2/analysis/cst_propag.py
new file mode 100644
index 00000000..d55d7e60
--- /dev/null
+++ b/miasm2/analysis/cst_propag.py
@@ -0,0 +1,178 @@
+import logging
+
+from miasm2.ir.symbexec import SymbolicExecutionEngine
+from miasm2.expression.expression import ExprMem
+from miasm2.expression.expression_helper import possible_values
+from miasm2.expression.simplifications import expr_simp
+from miasm2.ir.ir import IRBlock, AssignBlock
+
+LOG_CST_PROPAG = logging.getLogger("cst_propag")
+CONSOLE_HANDLER = logging.StreamHandler()
+CONSOLE_HANDLER.setFormatter(logging.Formatter("%(levelname)-5s: %(message)s"))
+LOG_CST_PROPAG.addHandler(CONSOLE_HANDLER)
+LOG_CST_PROPAG.setLevel(logging.WARNING)
+
+
+class SymbExecState(SymbolicExecutionEngine):
+    """
+    State manager for SymbolicExecution
+    """
+    def __init__(self, ir_arch, state):
+        super(SymbExecState, self).__init__(ir_arch, {})
+        self.set_state(state)
+
+
+def add_state(ir_arch, todo, states, addr, state):
+    """
+    Add or merge the computed @state for the block at @addr. Update @todo
+    @ir_arch: IR instance
+    @todo: modified block set
+    @states: dictionnary linking a label to its entering state.
+    @addr: address of the concidered block
+    @state: computed state
+    """
+    addr = ir_arch.get_label(addr)
+    todo.add(addr)
+    if addr not in states:
+        states[addr] = state
+    else:
+        states[addr] = states[addr].merge(state)
+
+
+def is_expr_cst(ir_arch, expr):
+    """Return true if @expr is only composed of ExprInt and init_regs
+    @ir_arch: IR instance
+    @expr: Expression to test"""
+
+    elements = expr.get_r(mem_read=True)
+    for element in elements:
+        if element.is_mem():
+            continue
+        if element.is_id() and element in ir_arch.arch.regs.all_regs_ids_init:
+            continue
+        if element.is_int():
+            continue
+        return False
+    else:
+        # Expr is a constant
+        return True
+
+
+class SymbExecStateFix(SymbolicExecutionEngine):
+    """
+    Emul blocks and replace expressions with their corresponding constant if
+    any.
+
+    """
+    # Function used to test if an Expression is considered as a constant
+    is_expr_cst = lambda _, ir_arch, expr: is_expr_cst(ir_arch, expr)
+
+    def __init__(self, ir_arch, state, cst_propag_link):
+        super(SymbExecStateFix, self).__init__(ir_arch, {})
+        self.set_state(state)
+        self.cst_propag_link = cst_propag_link
+
+    def propag_expr_cst(self, expr):
+        """Propagate consttant expressions in @expr
+        @expr: Expression to update"""
+        elements = expr.get_r(mem_read=True)
+        to_propag = {}
+        for element in elements:
+            # Only ExprId can be safely propagated
+            if not element.is_id():
+                continue
+            value = self.eval_expr(element)
+            if self.is_expr_cst(self.ir_arch, value):
+                to_propag[element] = value
+        return expr_simp(expr.replace_expr(to_propag))
+
+    def emulbloc(self, irb, step=False):
+        """
+        Symbolic execution of the @irb on the current state
+        @irb: IRBlock instance
+        @step: display intermediate steps
+        """
+        assignblks = []
+        for index, assignblk in enumerate(irb.irs):
+            new_assignblk = {}
+            links = {}
+            for dst, src in assignblk.iteritems():
+                src = self.propag_expr_cst(src)
+                if dst.is_mem():
+                    ptr = dst.arg
+                    ptr = self.propag_expr_cst(ptr)
+                    dst = ExprMem(ptr, dst.size)
+                new_assignblk[dst] = src
+
+            for arg in assignblk.instr.args:
+                new_arg = self.propag_expr_cst(arg)
+                links[new_arg] = arg
+            self.cst_propag_link[(irb.label, index)] = links
+
+            self.eval_ir(assignblk)
+            assignblks.append(AssignBlock(new_assignblk, assignblk.instr))
+        self.ir_arch.blocks[irb.label] = IRBlock(irb.label, assignblks)
+
+
+def compute_cst_propagation_states(ir_arch, init_addr, init_infos):
+    """
+    Propagate "constant expressions" in a function.
+    The attribute "constant expression" is true if the expression is based on
+    constants or "init" regs values.
+
+    @ir_arch: IntermediateRepresentation instance
+    @init_addr: analysis start address
+    @init_infos: dictionnary linking expressions to their values at @init_addr
+    """
+
+    done = set()
+    state = SymbExecState.StateEngine(init_infos)
+    lbl = ir_arch.get_label(init_addr)
+    todo = set([lbl])
+    states = {lbl: state}
+
+    while todo:
+        if not todo:
+            break
+        lbl = todo.pop()
+        state = states[lbl]
+        if (lbl, state) in done:
+            continue
+        done.add((lbl, state))
+        symbexec_engine = SymbExecState(ir_arch, state)
+
+        assert lbl in ir_arch.blocks
+        addr = symbexec_engine.emul_ir_block(lbl)
+        symbexec_engine.del_mem_above_stack(ir_arch.sp)
+
+        for dst in possible_values(addr):
+            value = dst.value
+            if value.is_mem():
+                LOG_CST_PROPAG.warning('Bad destination: %s', value)
+                continue
+            elif value.is_int():
+                value = ir_arch.get_label(value)
+            add_state(ir_arch, todo, states, value,
+                      symbexec_engine.get_state())
+
+    return states
+
+
+def propagate_cst_expr(ir_arch, addr, init_infos):
+    """
+    Propagate "constant expressions" in a @ir_arch.
+    The attribute "constant expression" is true if the expression is based on
+    constants or "init" regs values.
+
+    @ir_arch: IntermediateRepresentation instance
+    @addr: analysis start address
+    @init_infos: dictionnary linking expressions to their values at @init_addr
+
+    Returns a mapping between replaced Expression and their new values.
+    """
+    states = compute_cst_propagation_states(ir_arch, addr, init_infos)
+    cst_propag_link = {}
+    for lbl, state in states.iteritems():
+        symbexec = SymbExecStateFix(ir_arch, state, cst_propag_link)
+        symbexec.emulbloc(ir_arch.blocks[lbl])
+    return cst_propag_link
diff --git a/miasm2/core/ctypesmngr.py b/miasm2/core/ctypesmngr.py
index eeffb696..4bd32cb3 100644
--- a/miasm2/core/ctypesmngr.py
+++ b/miasm2/core/ctypesmngr.py
@@ -118,10 +118,12 @@ class CTypeStruct(CTypeBase):
     """C type for structure"""
 
     def __init__(self, name, fields=None):
+        assert name is not None
         self.name = name
         if fields is None:
             fields = ()
-        for _, field in fields:
+        for field_name, field in fields:
+            assert field_name is not None
             assert isinstance(field, CTypeBase)
         self.fields = tuple(fields)
         super(CTypeStruct, self).__init__()
@@ -146,10 +148,12 @@ class CTypeUnion(CTypeBase):
     """C type for union"""
 
     def __init__(self, name, fields=None):
+        assert name is not None
         self.name = name
         if fields is None:
             fields = []
-        for _, field in fields:
+        for field_name, field in fields:
+            assert field_name is not None
             assert isinstance(field, CTypeBase)
         self.fields = tuple(fields)
         super(CTypeUnion, self).__init__()
@@ -195,7 +199,7 @@ class CTypeFunc(CTypeBase):
         if type_ret:
             assert isinstance(type_ret, CTypeBase)
         if args:
-            for arg in args:
+            for arg_name, arg in args:
                 assert isinstance(arg, CTypeBase)
             args = tuple(args)
         else:
@@ -221,7 +225,7 @@ class CTypeFunc(CTypeBase):
         return "<Func:%s (%s) %s(%s)>" % (self.type_ret,
                                           self.abi,
                                           self.name,
-                                          ", ".join([str(arg) for arg in self.args]))
+                                          ", ".join(["%s %s" % (name, arg) for (name, arg) in self.args]))
 
 
 class CTypeEllipsis(CTypeBase):
@@ -292,6 +296,7 @@ class FuncNameIdentifier(c_ast.NodeVisitor):
 class CAstTypes(object):
     """Store all defined C types and typedefs"""
     INTERNAL_PREFIX = "__GENTYPE__"
+    ANONYMOUS_PREFIX = "__ANONYMOUS__"
 
     def __init__(self, knowntypes=None, knowntypedefs=None):
         if knowntypes is None:
@@ -342,10 +347,20 @@ class CAstTypes(object):
         self.cpt += 1
         return self.INTERNAL_PREFIX + "%d" % cpt
 
+    def gen_anon_name(self):
+        """Generate name for anonymous strucs/union"""
+        cpt = self.cpt
+        self.cpt += 1
+        return self.ANONYMOUS_PREFIX + "%d" % cpt
+
     def is_generated_name(self, name):
         """Return True if the name is internal"""
         return name.startswith(self.INTERNAL_PREFIX)
 
+    def is_anonymous_name(self, name):
+        """Return True if the name is anonymous"""
+        return name.startswith(self.ANONYMOUS_PREFIX)
+
     def add_type(self, type_id, type_obj):
         """Add new C type
         @type_id: Type descriptor (CTypeBase instance)
@@ -521,7 +536,11 @@ class CAstTypes(object):
         args = []
         if ast.decls:
             for arg in ast.decls:
-                args.append((arg.name, self.ast_to_typeid(arg)))
+                if arg.name is None:
+                    arg_name = self.gen_anon_name()
+                else:
+                    arg_name = arg.name
+                args.append((arg_name, self.ast_to_typeid(arg)))
         decl = CTypeStruct(name, args)
         return decl
 
@@ -531,7 +550,11 @@ class CAstTypes(object):
         args = []
         if ast.decls:
             for arg in ast.decls:
-                args.append((arg.name, self.ast_to_typeid(arg)))
+                if arg.name is None:
+                    arg_name = self.gen_anon_name()
+                else:
+                    arg_name = arg.name
+                args.append((arg_name, self.ast_to_typeid(arg)))
         decl = CTypeUnion(name, args)
         return decl
 
@@ -568,7 +591,14 @@ class CAstTypes(object):
         type_ret = self.ast_to_typeid(ast.type)
         name, decl_info = self.get_funcname(ast.type)
         if ast.args:
-            args = [self.ast_to_typeid(arg) for arg in ast.args.params]
+            args = []
+            for arg in ast.args.params:
+                typeid = self.ast_to_typeid(arg)
+                if isinstance(typeid, CTypeEllipsis):
+                    arg_name = None
+                else:
+                    arg_name = arg.name
+                args.append((arg_name, typeid))
         else:
             args = []
 
diff --git a/miasm2/core/objc.py b/miasm2/core/objc.py
index 917d0ea9..d6c100ca 100644
--- a/miasm2/core/objc.py
+++ b/miasm2/core/objc.py
@@ -6,6 +6,7 @@ C helper for Miasm:
 """
 
 
+import warnings
 from pycparser import c_parser, c_ast
 
 from miasm2.expression.expression_reduce import ExprReducer
@@ -17,53 +18,123 @@ from miasm2.core.ctypesmngr import CTypeUnion, CTypeStruct, CTypeId, CTypePtr,\
 
 PADDING_TYPE_NAME = "___padding___"
 
+def missing_definition(objtype):
+    warnings.warn("Null size type: Missing definition? %r" % objtype)
+
+"""
+Display C type
+source: "The C Programming Language - 2nd Edition - Ritchie Kernighan.pdf"
+p. 124
+"""
+
+def objc_to_str(objc, result=None):
+    if result is None:
+        result = ""
+    while True:
+        if isinstance(objc, ObjCArray):
+            result += "[%d]" % objc.elems
+            objc = objc.objtype
+        elif isinstance(objc, ObjCPtr):
+            if not result and isinstance(objc.objtype, ObjCFunc):
+                result = objc.objtype.name
+            if isinstance(objc.objtype, (ObjCPtr, ObjCDecl, ObjCStruct, ObjCUnion)):
+                result = "*%s" % result
+            else:
+                result = "(*%s)" % result
+
+            objc = objc.objtype
+        elif isinstance(objc, (ObjCDecl, ObjCStruct, ObjCUnion)):
+            if result:
+                result = "%s %s" % (objc, result)
+            else:
+                result = str(objc)
+            break
+        elif isinstance(objc, ObjCFunc):
+            args_str = []
+            for name, arg in objc.args:
+                args_str.append(objc_to_str(arg, name))
+            args = ", ".join(args_str)
+            result += "(%s)" % args
+            objc = objc.type_ret
+        elif isinstance(objc, ObjCInt):
+            return "int"
+        elif isinstance(objc, ObjCEllipsis):
+            return "..."
+        else:
+            raise TypeError("Unknown c type")
+    return result
+
+
 class ObjC(object):
     """Generic ObjC"""
 
-    def set_align_size(self, align, size):
-        """Set C object alignment and size"""
+    def __init__(self, align, size):
+        self._align = align
+        self._size = size
 
-        self.align = align
-        self.size = size
+    @property
+    def align(self):
+        """Alignment (in bytes) of the C object"""
+        return self._align
 
-    def eq_base(self, other):
-        return (self.__class__ == other.__class__ and
-                self.align == other.align and
-                self.size == other.size)
+    @property
+    def size(self):
+        """Size (in bytes) of the C object"""
+        return self._size
+
+    def cmp_base(self, other):
+        assert self.__class__ in OBJC_PRIO
+        assert other.__class__ in OBJC_PRIO
+
+        if OBJC_PRIO[self.__class__] != OBJC_PRIO[other.__class__]:
+            return cmp(OBJC_PRIO[self.__class__], OBJC_PRIO[other.__class__])
+        if self.align != other.align:
+            return cmp(self.align, other.align)
+        return cmp(self.size, other.size)
+
+    def __hash__(self):
+        return hash((self.__class__, self._align, self._size))
+
+    def __str__(self):
+        return objc_to_str(self)
 
 
 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
+        super(ObjCDecl, self).__init__(align, size)
+        self._name = name
+
+    name = property(lambda self: self._name)
+
+    def __hash__(self):
+        return hash((super(ObjCDecl, self).__hash__(), self._name))
 
     def __repr__(self):
         return '<%s %s>' % (self.__class__.__name__, self.name)
 
     def __str__(self):
-        return '%s' % (self.name)
+        return str(self.name)
 
-    def __eq__(self, other):
-        if not self.eq_base(other):
-            return False
-        return self.name == other.name
+    def __cmp__(self, other):
+        ret = self.cmp_base(other)
+        if ret:
+            return ret
+        return cmp(self.name, other.name)
 
 
 class ObjCInt(ObjC):
     """C integer"""
 
     def __init__(self):
-        super(ObjCInt, self).__init__()
-        self.size = None
-        self.align = None
+        super(ObjCInt, self).__init__(None, None)
 
     def __str__(self):
         return 'int'
 
-    def __eq__(self, other):
-        return self.eq_base(other)
+    def __cmp__(self, other):
+        return self.cmp_base(other)
 
 
 class ObjCPtr(ObjC):
@@ -77,37 +148,38 @@ class ObjCPtr(ObjC):
         @void_p_size: pointer size (in bytes)
         """
 
-        super(ObjCPtr, self).__init__()
+        super(ObjCPtr, self).__init__(void_p_align, void_p_size)
+        self._lock = False
+
         self.objtype = objtype
-        self.align = void_p_align
-        self.size = void_p_size
+        if objtype is None:
+            self._lock = False
+
+    def get_objtype(self):
+        assert self._lock is True
+        return self._objtype
+
+    def set_objtype(self, objtype):
+        assert self._lock is False
+        self._lock = True
+        self._objtype = objtype
+
+    objtype = property(get_objtype, set_objtype)
+
+    def __hash__(self):
+        # Don't try to hash on an unlocked Ptr (still mutable)
+        assert self._lock
+        return hash((super(ObjCPtr, self).__hash__(), hash(self._objtype)))
 
     def __repr__(self):
         return '<%s %r>' % (self.__class__.__name__,
                             self.objtype.__class__)
 
-    def __str__(self):
-        target = self.objtype
-        if isinstance(target, ObjCDecl):
-            return "%s *" % target.name
-        elif isinstance(target, ObjCPtr):
-            return "%s *" % target
-        elif isinstance(target, ObjCStruct):
-            return "struct %s *" % target.name
-        elif isinstance(target, ObjCUnion):
-            return "union %s *" % target.name
-        elif isinstance(target, ObjCArray):
-            return "%s (*)[%s]" % (target.objtype, target.elems)
-        elif isinstance(target, ObjCFunc):
-            args = ", ".join([str(arg) for arg in target.args])
-            return "%s (*%s)(%s)" % (target.type_ret, target.name, args)
-        else:
-            return '*%s' % (target)
-
-    def __eq__(self, other):
-        if not self.eq_base(other):
-            return False
-        return self.objtype == other.objtype
+    def __cmp__(self, other):
+        ret = self.cmp_base(other)
+        if ret:
+            return ret
+        return cmp(self.objtype, other.objtype)
 
 
 class ObjCArray(ObjC):
@@ -120,42 +192,42 @@ class ObjCArray(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
+        super(ObjCArray, self).__init__(objtype.align, elems * objtype.size)
+        self._elems = elems
+        self._objtype = objtype
+
+    objtype = property(lambda self: self._objtype)
+    elems = property(lambda self: self._elems)
+
+    def __hash__(self):
+        return hash((super(ObjCArray, self).__hash__(), self._elems, hash(self._objtype)))
 
     def __repr__(self):
         return '<%r[%d]>' % (self.objtype, self.elems)
 
-    def __str__(self):
-        return '%s[%d]' % (self.objtype, self.elems)
-
-    def __eq__(self, other):
-        if not self.eq_base(other):
-            return False
-        return (self.elems == other.elems and
-                self.objtype == other.objtype)
+    def __cmp__(self, other):
+        ret = self.cmp_base(other)
+        if ret:
+            return ret
+        ret = cmp(self.elems, other.elems)
+        if ret:
+            return ret
+        return cmp(self.objtype, other.objtype)
 
 
 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
-        """
+    def __init__(self, name, align, size, fields):
+        super(ObjCStruct, self).__init__(align, size)
+        self._name = name
+        self._fields = tuple(fields)
 
-        self.fields.append((name, objtype, offset, size))
+    name = property(lambda self: self._name)
+    fields = property(lambda self: self._fields)
+
+    def __hash__(self):
+        return hash((super(ObjCStruct, self).__hash__(), self._name))
 
     def __repr__(self):
         out = []
@@ -169,34 +241,25 @@ class ObjCStruct(ObjC):
     def __str__(self):
         return 'struct %s' % (self.name)
 
-    def __eq__(self, other):
-        if not (self.eq_base(other) and self.name == other.name):
-            return False
-        if len(self.fields) != len(other.fields):
-            return False
-        for field_a, field_b in zip(self.fields, other.fields):
-            if field_a != field_b:
-                return False
-        return True
-
+    def __cmp__(self, other):
+        ret = self.cmp_base(other)
+        if ret:
+            return ret
+        return cmp(self.name, other.name)
 
 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
-        """
+    def __init__(self, name, align, size, fields):
+        super(ObjCUnion, self).__init__(align, size)
+        self._name = name
+        self._fields = tuple(fields)
 
-        self.fields.append((name, objtype, offset, size))
+    name = property(lambda self: self._name)
+    fields = property(lambda self: self._fields)
+
+    def __hash__(self):
+        return hash((super(ObjCUnion, self).__hash__(), self._name))
 
     def __repr__(self):
         out = []
@@ -210,40 +273,42 @@ class ObjCUnion(ObjC):
     def __str__(self):
         return 'union %s' % (self.name)
 
-    def __eq__(self, other):
-        if not (self.eq_base(other) and self.name == other.name):
-            return False
-        if len(self.fields) != len(other.fields):
-            return False
-        for field_a, field_b in zip(self.fields, other.fields):
-            if field_a != field_b:
-                return False
-        return True
-
+    def __cmp__(self, other):
+        ret = self.cmp_base(other)
+        if ret:
+            return ret
+        return cmp(self.name, other.name)
 
 class ObjCEllipsis(ObjC):
     """C integer"""
 
     def __init__(self):
-        super(ObjCEllipsis, self).__init__()
-        self.size = None
-        self.align = None
+        super(ObjCEllipsis, self).__init__(None, None)
 
-    def __eq__(self, other):
-        return self.eq_base(other)
+    align = property(lambda self: self._align)
+    size = property(lambda self: self._size)
+
+    def __cmp__(self, other):
+        return self.cmp_base(other)
 
 
 class ObjCFunc(ObjC):
     """C object for Functions"""
 
     def __init__(self, name, abi, type_ret, args, void_p_align, void_p_size):
-        super(ObjCFunc, self).__init__()
-        self.name = name
-        self.abi = abi
-        self.type_ret = type_ret
-        self.args = args
-        self.align = void_p_align
-        self.size = void_p_size
+        super(ObjCFunc, self).__init__(void_p_align, void_p_size)
+        self._name = name
+        self._abi = abi
+        self._type_ret = type_ret
+        self._args = tuple(args)
+
+    args = property(lambda self: self._args)
+    type_ret = property(lambda self: self._type_ret)
+    abi = property(lambda self: self._abi)
+    name = property(lambda self: self._name)
+
+    def __hash__(self):
+        return hash((super(ObjCFunc, self).__hash__(), hash(self._args), self._name))
 
     def __repr__(self):
         return "<%s %s>" % (self.__class__.__name__,
@@ -254,20 +319,27 @@ class ObjCFunc(ObjC):
         out.append("Function (%s)  %s: (align: %d)" % (self.abi, self.name, self.align))
         out.append("  ret: %s" % (str(self.type_ret)))
         out.append("  Args:")
-        for arg in self.args:
-            out.append("  %s" % arg)
+        for name, arg in self.args:
+            out.append("  %s %s" % (name, arg))
         return '\n'.join(out)
 
-    def __eq__(self, other):
-        if not (self.eq_base(other) and self.name == other.name and
-                self.type_ret == other.type_ret):
-            return False
-        if len(self.args) != len(other.args):
-            return False
-        for arg_a, arg_b in zip(self.args, other.args):
-            if arg_a != arg_b:
-                return False
-        return True
+    def __cmp__(self, other):
+        ret = self.cmp_base(other)
+        if ret:
+            return ret
+        return cmp(self.name, other.name)
+
+OBJC_PRIO = {
+    ObjC: 0,
+    ObjCDecl:1,
+    ObjCInt:2,
+    ObjCPtr:3,
+    ObjCArray:4,
+    ObjCStruct:5,
+    ObjCUnion:6,
+    ObjCEllipsis:7,
+    ObjCFunc:8,
+}
 
 
 def access_simplifier(expr):
@@ -342,6 +414,22 @@ class CGen(object):
 
     default_size = 64
 
+
+    def __init__(self, ctype):
+        self._ctype = ctype
+
+    @property
+    def ctype(self):
+        """Type (ObjC instance) of the current object"""
+        return self._ctype
+
+    def __hash__(self):
+        return hash(self.__class__)
+
+    def __eq__(self, other):
+        return (self.__class__ == other.__class__ and
+                self._ctype == other.ctype)
+
     def to_c(self):
         """Generate corresponding C"""
 
@@ -358,8 +446,20 @@ class CGenInt(CGen):
 
     def __init__(self, integer):
         assert isinstance(integer, (int, long))
-        self.integer = integer
-        self.ctype = ObjCInt()
+        self._integer = integer
+        super(CGenInt, self).__init__(ObjCInt())
+
+    @property
+    def integer(self):
+        """Value of the object"""
+        return self._integer
+
+    def __hash__(self):
+        return hash((super(CGenInt, self).__hash__(), self._integer))
+
+    def __eq__(self, other):
+        return (super(CGenInt, self).__eq__(other) and
+                self._integer == other.integer)
 
     def to_c(self):
         """Generate corresponding C"""
@@ -380,9 +480,21 @@ class CGenId(CGen):
     """ID of a C object"""
 
     def __init__(self, ctype, name):
-        self.ctype = ctype
-        self.name = name
+        self._name = name
         assert isinstance(name, str)
+        super(CGenId, self).__init__(ctype)
+
+    @property
+    def name(self):
+        """Name of the Id"""
+        return self._name
+
+    def __hash__(self):
+        return hash((super(CGenId, self).__hash__(), self._name))
+
+    def __eq__(self, other):
+        return (super(CGenId, self).__eq__(other) and
+                self._name == other.name)
 
     def __repr__(self):
         return "<%s %s>" % (self.__class__.__name__,
@@ -413,14 +525,32 @@ class CGenField(CGen):
     """
 
     def __init__(self, struct, field, fieldtype, void_p_align, void_p_size):
-        self.struct = struct
-        self.field = field
+        self._struct = struct
+        self._field = field
         assert isinstance(field, str)
         if isinstance(fieldtype, ObjCArray):
             ctype = fieldtype
         else:
             ctype = ObjCPtr(fieldtype, void_p_align, void_p_size)
-        self.ctype = ctype
+        super(CGenField, self).__init__(ctype)
+
+    @property
+    def struct(self):
+        """Structure containing the field"""
+        return self._struct
+
+    @property
+    def field(self):
+        """Field name"""
+        return self._field
+
+    def __hash__(self):
+        return hash((super(CGenField, self).__hash__(), self._struct, self._field))
+
+    def __eq__(self, other):
+        return (super(CGenField, self).__eq__(other) and
+                self._struct == other.struct and
+                self._field == other.field)
 
     def to_c(self):
         """Generate corresponding C"""
@@ -467,8 +597,8 @@ class CGenArray(CGen):
     - X[] => X*
     """
 
-    def __init__(self, name, element, void_p_align, void_p_size):
-        ctype = name.ctype
+    def __init__(self, base, elems, void_p_align, void_p_size):
+        ctype = base.ctype
         if isinstance(ctype, ObjCPtr):
             pass
         elif isinstance(ctype, ObjCArray) and isinstance(ctype.objtype, ObjCArray):
@@ -477,21 +607,39 @@ class CGenArray(CGen):
             ctype = ObjCPtr(ctype.objtype, void_p_align, void_p_size)
         else:
             raise TypeError("Strange case")
-        self.ctype = ctype
-        self.name = name
-        self.element = element
+        self._base = base
+        self._elems = elems
+        super(CGenArray, self).__init__(ctype)
+
+    @property
+    def base(self):
+        """Base object supporting the array"""
+        return self._base
+
+    @property
+    def elems(self):
+        """Number of elements in the array"""
+        return self._elems
+
+    def __hash__(self):
+        return hash((super(CGenArray, self).__hash__(), self._base, self._elems))
+
+    def __eq__(self, other):
+        return (super(CGenField, self).__eq__(other) and
+                self._base == other.base and
+                self._elems == other.elems)
 
     def __repr__(self):
         return "<%s %s>" % (self.__class__.__name__,
-                            self.name)
+                            self.base)
 
     def to_c(self):
         """Generate corresponding C"""
 
         if isinstance(self.ctype, ObjCPtr):
-            out_str = "&((%s)[%d])" % (self.name.to_c(), self.element)
+            out_str = "&((%s)[%d])" % (self.base.to_c(), self.elems)
         elif isinstance(self.ctype, ObjCArray):
-            out_str = "(%s)[%d]" % (self.name.to_c(), self.element)
+            out_str = "(%s)[%d]" % (self.base.to_c(), self.elems)
         else:
             raise RuntimeError("Strange case")
         return out_str
@@ -502,12 +650,12 @@ class CGenArray(CGen):
         if isinstance(self.ctype, ObjCPtr):
             return ExprOp("addr",
                           ExprOp("[]",
-                                 self.name.to_expr(),
-                                 ExprInt(self.element, self.default_size)))
+                                 self.base.to_expr(),
+                                 ExprInt(self.elems, self.default_size)))
         elif isinstance(self.ctype, ObjCArray):
             return ExprOp("[]",
-                          self.name.to_expr(),
-                          ExprInt(self.element, self.default_size))
+                          self.base.to_expr(),
+                          ExprInt(self.elems, self.default_size))
         else:
             raise RuntimeError("Strange case")
 
@@ -522,28 +670,40 @@ class CGenDeref(CGen):
     - X* => X
     """
 
-    def __init__(self, mem):
-        assert isinstance(mem.ctype, ObjCPtr)
-        self.ctype = mem.ctype.objtype
-        self.mem = mem
+    def __init__(self, ptr):
+        assert isinstance(ptr.ctype, ObjCPtr)
+        self._ptr = ptr
+        super(CGenDeref, self).__init__(ptr.ctype.objtype)
+
+    @property
+    def ptr(self):
+        """Pointer object"""
+        return self._ptr
+
+    def __hash__(self):
+        return hash((super(CGenDeref, self).__hash__(), self._ptr))
+
+    def __eq__(self, other):
+        return (super(CGenField, self).__eq__(other) and
+                self._ptr == other.ptr)
 
     def __repr__(self):
         return "<%s %s>" % (self.__class__.__name__,
-                            self.mem)
+                            self.ptr)
 
     def to_c(self):
         """Generate corresponding C"""
 
-        if not isinstance(self.mem.ctype, ObjCPtr):
+        if not isinstance(self.ptr.ctype, ObjCPtr):
             raise RuntimeError()
-        return "*(%s)" % (self.mem.to_c())
+        return "*(%s)" % (self.ptr.to_c())
 
     def to_expr(self):
         """Generate Miasm expression representing the C access"""
 
-        if not isinstance(self.mem.ctype, ObjCPtr):
+        if not isinstance(self.ptr.ctype, ObjCPtr):
             raise RuntimeError()
-        return ExprOp("deref", self.mem.to_expr())
+        return ExprOp("deref", self.ptr.to_expr())
 
 
 def ast_get_c_access_expr(ast, expr_types, lvl=0):
@@ -615,201 +775,6 @@ def parse_access(c_access):
     return access
 
 
-class CTypeAnalyzer(ExprReducer):
-    """
-    Return the C type(s) of a native Miasm expression
-    """
-
-    def __init__(self, expr_types, types_mngr, enforce_strict_access=True):
-        """Init TypeAnalyzer
-        @expr_types: a dictionnary linking ID names to their types
-        @types_mngr: types manager
-        @enforce_strict_access: If false, get type 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
-
-    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(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 self.enforce_strict_access and offset != 0:
-                return []
-            obj = ObjCPtr(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(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):
-            if self.enforce_strict_access:
-                assert offset % base_type.size == 0
-            obj = ObjCPtr(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 get_solo_type(self, node):
-        """Return the type of the @node if it has only one possible type,
-        different from not None. In othe cases, return None.
-        """
-        if node.info is None or len(node.info) != 1:
-            return None
-        return type(node.info[0])
-
-    def reduce_ptr_plus_cst(self, node, lvl):
-        """Get type of ptr + CST"""
-
-        if not node.expr.is_op("+") or len(node.args) != 2:
-            return None
-        args_types = set([self.get_solo_type(node.args[0]),
-                          self.get_solo_type(node.args[1])])
-        if args_types != 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 node.expr.is_op("+") or len(node.args) != 2:
-            return None
-        if node.args[0] is None or node.args[1] is None:
-            return None
-        args_types = set([self.get_solo_type(node.args[0]),
-                          self.get_solo_type(node.args[1])])
-        if args_types != 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 (not(self.enforce_strict_access) or
-                    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
@@ -898,109 +863,103 @@ class ExprToAccessC(ExprReducer):
         OUT:
         - CGenArray(CGenField(toto, b), 1)
         """
+        if base_type.size == 0:
+            missing_definition(base_type)
+            return set()
+
 
         void_type = self.types_mngr.void_ptr
         if isinstance(base_type, ObjCStruct):
-            assert 0 <= offset < base_type.size
+            if not 0 <= offset < base_type.size:
+                return set()
+
             if offset == 0 and not deref:
                 # In this case, return the struct*
-                return [cgenobj]
+                return set([cgenobj])
 
-            out = []
-            for fieldname, subtype, f_offset, size in base_type.fields:
-                if not f_offset <= offset < f_offset + size:
+            for fieldname, subtype, field_offset, size in base_type.fields:
+                if not field_offset <= offset < field_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
+                new_type = self.cgen_access(fieldptr, subtype,
+                                            offset - field_offset,
+                                            deref, lvl + 1)
                 break
             else:
-                raise RuntimeError('Cannot find struct field')
+                return set()
         elif isinstance(base_type, ObjCArray):
+            if base_type.objtype.size == 0:
+                missing_definition(base_type.objtype)
+                return set()
             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
+            field_offset = offset % base_type.objtype.size
+            if element_num >= base_type.elems:
+                return set()
+            if offset == 0 and not deref:
+                # In this case, return the array
+                return set([cgenobj])
+
+            curobj = CGenArray(cgenobj, element_num,
+                               void_type.align,
+                               void_type.size)
+            if field_offset == 0:
+                # We point to the start of the sub object,
+                # return it directly
+                return set([curobj])
+            new_type = self.cgen_access(curobj, base_type.objtype,
+                                        field_offset, deref, lvl + 1)
+
         elif isinstance(base_type, ObjCDecl):
-            if self.enforce_strict_access:
-                if offset % base_type.size != 0:
-                    return []
+            if self.enforce_strict_access and offset % base_type.size != 0:
+                return set()
             elem_num = offset / base_type.size
 
             nobj = CGenArray(cgenobj, elem_num,
                              void_type.align, void_type.size)
-            new_type = [(nobj)]
+            new_type = set([nobj])
 
         elif isinstance(base_type, ObjCUnion):
-            out = []
             if offset == 0 and not deref:
                 # In this case, return the struct*
-                return [cgenobj]
+                return set([cgenobj])
 
-            for fieldname, objtype, f_offset, size in base_type.fields:
-                if not f_offset <= offset < f_offset + size:
+            out = set()
+            for fieldname, objtype, field_offset, size in base_type.fields:
+                if not field_offset <= offset < field_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)
+                out.update(self.cgen_access(field, objtype,
+                                            offset - field_offset,
+                                            deref, lvl + 1))
             new_type = out
 
         elif isinstance(base_type, ObjCPtr):
             elem_num = offset / base_type.size
-            if self.enforce_strict_access:
-                assert offset % base_type.size == 0
-
+            if self.enforce_strict_access and offset % base_type.size != 0:
+                return set()
             nobj = CGenArray(cgenobj, elem_num,
                              void_type.align, void_type.size)
-            new_type = [(nobj)]
+            new_type = set([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
-
-        objc = self.expr_types[node.expr.name]
-        out = CGenId(objc, node.expr.name)
-        return [out]
+    def reduce_known_expr(self, node, ctxt, **kwargs):
+        """Generate access for known expr"""
+        if node.expr in ctxt:
+            objcs = ctxt[node.expr]
+            return set(CGenId(objc, str(node.expr)) for objc in objcs)
+        return None
 
-    def reduce_int(self, node, _):
+    def reduce_int(self, node, **kwargs):
         """Generate access for ExprInt"""
 
         if not isinstance(node.expr, ExprInt):
             return None
-        return [CGenInt(int(node.expr))]
+        return set([CGenInt(int(node.expr))])
 
     def get_solo_type(self, node):
         """Return the type of the @node if it has only one possible type,
@@ -1008,33 +967,35 @@ class ExprToAccessC(ExprReducer):
         """
         if node.info is None or len(node.info) != 1:
             return None
-        return type(node.info[0].ctype)
+        return type(list(node.info)[0].ctype)
 
-    def reduce_op(self, node, lvl):
+    def reduce_op(self, node, lvl=0, **kwargs):
         """Generate access for ExprOp"""
-
         if not node.expr.is_op("+") or len(node.args) != 2:
             return None
-        args_types = set([self.get_solo_type(node.args[0]),
-                          self.get_solo_type(node.args[1])])
-        if args_types != set([ObjCInt, ObjCPtr]):
+        type_arg1 = self.get_solo_type(node.args[1])
+        if type_arg1 != ObjCInt:
             return None
-
         arg0, arg1 = node.args
-        out = []
+        if arg0.info is None:
+            return None
+        void_type = self.types_mngr.void_ptr
+        out = set()
         ptr_offset = int(arg1.expr)
-        for name in arg0.info:
-            assert isinstance(name.ctype, ObjCPtr)
-            ptr_basetype = name.ctype.objtype
+        for info in arg0.info:
+            if isinstance(info.ctype, ObjCArray):
+                field_type = info.ctype
+            elif isinstance(info.ctype, ObjCPtr):
+                field_type = info.ctype.objtype
+            else:
+                continue
+            target_type = info.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)
+            out.update(self.cgen_access(info, field_type, ptr_offset, False, lvl))
         return out
 
-    def reduce_mem(self, node, lvl):
+    def reduce_mem(self, node, lvl=0, **kwargs):
         """Generate access for ExprMem:
         * @NN[ptr<elem>] -> elem  (type)
         * @64[ptr<ptr<elem>>] -> ptr<elem>
@@ -1045,44 +1006,61 @@ class ExprToAccessC(ExprReducer):
             return None
         if node.arg.info is None:
             return None
-        assert isinstance(node.arg.info, list)
-        found = []
+        assert isinstance(node.arg.info, set)
+        void_type = self.types_mngr.void_ptr
+        found = set()
         for subcgenobj in node.arg.info:
-            if not isinstance(subcgenobj.ctype, ObjCPtr):
-                return None
-            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
+            if isinstance(subcgenobj.ctype, ObjCArray):
+                nobj = CGenArray(subcgenobj, 0,
+                                 void_type.align,
+                                 void_type.size)
+                target = nobj.ctype.objtype
+                for finalcgenobj in self.cgen_access(nobj, target, 0, True, lvl):
+                    assert isinstance(finalcgenobj.ctype, ObjCPtr)
+                    if self.enforce_strict_access and finalcgenobj.ctype.objtype.size != node.expr.size / 8:
+                        continue
+                    found.add(CGenDeref(finalcgenobj))
+
+            elif 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 self.enforce_strict_access and target.size != node.expr.size / 8:
+                            continue
+                        found.add(CGenDeref(finalcgenobj))
+                elif isinstance(target, ObjCArray):
+                    if self.enforce_strict_access and subcgenobj.ctype.size != node.expr.size / 8:
+                        continue
+                    found.update(self.cgen_access(CGenDeref(subcgenobj), target,
+                                                  0, False, lvl))
+                else:
+                    if self.enforce_strict_access and target.size != node.expr.size / 8:
+                        continue
+                    found.add(CGenDeref(subcgenobj))
+        if not found:
+            return None
         return found
 
-    reduction_rules = [reduce_id,
+    reduction_rules = [reduce_known_expr,
                        reduce_int,
                        reduce_op,
                        reduce_mem,
                       ]
 
-    def get_access(self, expr):
+    def get_accesses(self, expr, expr_context=None):
         """Generate C access(es) for the native Miasm expression @expr
         @expr: native Miasm expression
+        @expr_context: a dictionnary linking known expressions to their
+        types. An expression is linked to a tuple of types.
         """
-
-        return self.reduce(expr)
+        if expr_context is None:
+            expr_context = self.expr_types
+        ret = self.reduce(expr, ctxt=expr_context)
+        if ret.info is None:
+            return set()
+        return ret.info
 
 
 class ExprCToExpr(ExprReducer):
@@ -1145,25 +1123,25 @@ class ExprCToExpr(ExprReducer):
 
     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:
-            objc = self.expr_types[node.expr.name]
+    def reduce_known_expr(self, node, ctxt, **kwargs):
+        """Reduce known expressions"""
+        if str(node.expr) in ctxt:
+            objc = ctxt[str(node.expr)]
             out = (node.expr, objc)
-        else:
+        elif node.expr.is_id():
             out = (node.expr, None)
+        else:
+            out = None
         return out
 
-    def reduce_int(self, node, _):
+    def reduce_int(self, node, **kwargs):
         """Reduce ExprInt"""
 
         if not isinstance(node.expr, ExprInt):
             return None
         return self.CST
 
-    def reduce_op_memberof(self, node, _):
+    def reduce_op_memberof(self, node, **kwargs):
         """Reduce -> operator"""
 
         if not node.expr.is_op('->'):
@@ -1173,6 +1151,8 @@ class ExprCToExpr(ExprReducer):
         assert isinstance(node.args[1].expr, ExprId)
         field = node.args[1].expr.name
         src, src_type = node.args[0].info
+        if src_type is None:
+            return None
         assert isinstance(src_type, (ObjCPtr, ObjCArray))
         struct_dst = src_type.objtype
         assert isinstance(struct_dst, ObjCStruct)
@@ -1192,7 +1172,7 @@ class ExprCToExpr(ExprReducer):
         assert found
         return out
 
-    def reduce_op_field(self, node, _):
+    def reduce_op_field(self, node, **kwargs):
         """Reduce field operator (Struct or Union)"""
 
         if not node.expr.is_op('field'):
@@ -1245,7 +1225,7 @@ class ExprCToExpr(ExprReducer):
         assert found
         return out
 
-    def reduce_op_array(self, node, _):
+    def reduce_op_array(self, node, **kwargs):
         """Reduce array operator"""
 
         if not node.expr.is_op('[]'):
@@ -1282,7 +1262,7 @@ class ExprCToExpr(ExprReducer):
         out = (expr, objtype)
         return out
 
-    def reduce_op_addr(self, node, _):
+    def reduce_op_addr(self, node, **kwargs):
         """Reduce addr operator"""
 
         if not node.expr.is_op('addr'):
@@ -1309,7 +1289,7 @@ class ExprCToExpr(ExprReducer):
             raise NotImplementedError("unk type")
         return out
 
-    def reduce_op_deref(self, node, _):
+    def reduce_op_deref(self, node, **kwargs):
         """Reduce deref operator"""
 
         if not node.expr.is_op('deref'):
@@ -1317,11 +1297,19 @@ class ExprCToExpr(ExprReducer):
         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))
+        void_type = self.types_mngr.void_ptr
+        if isinstance(src_type, ObjCPtr):
+            if isinstance(src_type.objtype, ObjCArray):
+                size = void_type.size*8
+            else:
+                size = src_type.objtype.size * 8
+            out = (ExprMem(src, size), (src_type.objtype))
+        else:
+            size = src_type.objtype.size * 8
+            out = (ExprMem(src, size), (src_type.objtype))
         return out
 
-    reduction_rules = [reduce_id,
+    reduction_rules = [reduce_known_expr,
                        reduce_int,
                        reduce_op_memberof,
                        reduce_op_field,
@@ -1330,14 +1318,17 @@ class ExprCToExpr(ExprReducer):
                        reduce_op_deref,
                       ]
 
-    def get_expr(self, expr):
+    def get_expr(self, expr, c_context):
         """Translate a Miasm expression @expr (representing a C access) into a
-        native Miasm expression and its C type
-
+        tuple composed of a native Miasm expression and its C type.
         @expr: Miasm expression (representing a C access)
+        @c_context: a dictionnary linking known tokens (strings) to their
+        types. A token is linked to only one type.
         """
-
-        return self.reduce(expr)
+        ret = self.reduce(expr, ctxt=c_context)
+        if ret.info is None:
+            return (None, None)
+        return ret.info
 
 
 class CTypesManager(object):
@@ -1370,22 +1361,22 @@ class CTypesManager(object):
             out = self.leaf_types.types.get(type_id, None)
             assert out is not None
         elif isinstance(type_id, CTypeUnion):
-            out = ObjCUnion(type_id.name)
+            args = []
             align_max, size_max = 0, 0
             for name, field in type_id.fields:
                 objc = self._get_objc(field, resolved, to_fix, lvl + 1)
                 resolved[field] = objc
                 align_max = max(align_max, objc.align)
                 size_max = max(size_max, objc.size)
-                out.add_field(name, objc, 0, objc.size)
+                args.append((name, objc, 0, objc.size))
 
             align, size = self.union_compute_align_size(align_max, size_max)
-            out.set_align_size(align, size)
+            out = ObjCUnion(type_id.name, align, size, args)
 
         elif isinstance(type_id, CTypeStruct):
-            out = ObjCStruct(type_id.name)
             align_max, size_max = 0, 0
 
+            args = []
             offset, align_max = 0, 1
             pad_index = 0
             for name, field in type_id.fields:
@@ -1398,13 +1389,13 @@ class CTypesManager(object):
                     pad_index += 1
                     size = new_offset - offset
                     pad_objc = self._get_objc(CTypeArray(self.padding, size), resolved, to_fix, lvl + 1)
-                    out.add_field(pad_name, pad_objc, offset, pad_objc.size)
+                    args.append((pad_name, pad_objc, offset, pad_objc.size))
                 offset = new_offset
-                out.add_field(name, objc, offset, objc.size)
+                args.append((name, objc, offset, objc.size))
                 offset += objc.size
 
             align, size = self.struct_compute_align_size(align_max, offset)
-            out.set_align_size(align, size)
+            out = ObjCStruct(type_id.name, align, size, args)
 
         elif isinstance(type_id, CTypePtr):
             target = type_id.target
@@ -1434,10 +1425,10 @@ class CTypesManager(object):
                 type_id.type_ret, resolved, to_fix, lvl + 1)
             resolved[type_id.type_ret] = type_ret
             args = []
-            for arg in type_id.args:
+            for name, arg in type_id.args:
                 objc = self._get_objc(arg, resolved, to_fix, lvl + 1)
                 resolved[arg] = objc
-                args.append(objc)
+                args.append((name, objc))
             out = ObjCFunc(type_id.name, type_id.abi, type_ret, args,
                            self.void_ptr.align, self.void_ptr.size)
         elif isinstance(type_id, CTypeEllipsis):
@@ -1486,7 +1477,7 @@ class CTypesManager(object):
             return True
         elif isinstance(objc, ObjCFunc):
             assert self.check_objc(objc.type_ret, done)
-            for arg in objc.args:
+            for name, arg in objc.args:
                 assert self.check_objc(arg, done)
             return True
         else:
@@ -1583,18 +1574,16 @@ class CHandler(object):
     """
 
     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,
-                                                   enforce_strict_access)
         self.access_c_gen = self.exprToAccessC_cls(expr_types,
                                                    types_mngr,
                                                    enforce_strict_access)
+        self.types_mngr = types_mngr
         self.simplify_c = simplify_c
         self.expr_types = expr_types
 
@@ -1605,41 +1594,75 @@ class CHandler(object):
 
         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"""
+    def expr_to_c_access(self, expr, expr_context=None):
+        """Generate the C access object(s) for a given native Miasm expression.
+        @expr: Miasm expression
+        @expr_context: a dictionnary linking known expressions to a set of types
+        """
+
+        if expr_context is None:
+            expr_context = self.expr_types
+        return self.access_c_gen.get_accesses(expr, expr_context)
+
+
+    def expr_to_c_and_types(self, expr, expr_context=None):
+        """Generate the C access string and corresponding type for a given
+        native Miasm expression.
+        @expr_context: a dictionnary linking known expressions to a set of types
+        """
+
+        accesses = set()
+        for access in self.expr_to_c_access(expr, expr_context):
+            c_str = access_str(access.to_expr().visit(self.simplify_c))
+            accesses.add((c_str, access.ctype))
+        return accesses
+
+    def expr_to_c(self, expr, expr_context=None):
+        """Convert a Miasm @expr into it's C equivalent string
+        @expr_context: a dictionnary linking known expressions to a set of types
+        """
 
-        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
+        return set(access[0]
+                   for access in self.expr_to_c_and_types(expr, expr_context))
 
-    def expr_to_types(self, expr):
+    def expr_to_types(self, expr, expr_context=None):
         """Get the possible types of the Miasm @expr
-        @expr: Miasm expression"""
+        @expr_context: a dictionnary linking known expressions to a set of types
+        """
 
-        return self.type_analyzer.get_type(expr).info
+        return set(access.ctype
+                   for access in self.expr_to_c_access(expr, expr_context))
 
-    def c_to_expr(self, c_str):
-        """Convert a C string expression to a Miasm expression
-        @c_str: C string"""
+    def c_to_expr_and_type(self, c_str, c_context):
+        """Convert a C string expression to a Miasm expression and it's
+        corresponding c type
+        @c_str: C string
+        @c_context: a dictionnary linking known tokens (strings) to its type.
+        """
 
         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]
+        access_c = ast_get_c_access_expr(ast, c_context)
+        return self.exprc2expr.get_expr(access_c, c_context)
+
+    def c_to_expr(self, c_str, c_context):
+        """Convert a C string expression to a Miasm expression
+        @c_str: C string
+        @c_context: a dictionnary linking known tokens (strings) to its type.
+        """
+
+        expr, _ = self.c_to_expr_and_type(c_str, c_context)
+        return expr
 
-    def c_to_type(self, c_str):
+    def c_to_type(self, c_str, c_context):
         """Get the type of a C string expression
-        @expr: Miasm expression"""
+        @expr: Miasm expression
+        @c_context: a dictionnary linking known tokens (strings) to its type.
+        """
 
-        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
+        _, ctype = self.c_to_expr_and_type(c_str, c_context)
+        return ctype
 
 
 class CLeafTypes(object):
diff --git a/miasm2/expression/expression_reduce.py b/miasm2/expression/expression_reduce.py
index a1be27cc..45386ca2 100644
--- a/miasm2/expression/expression_reduce.py
+++ b/miasm2/expression/expression_reduce.py
@@ -99,7 +99,7 @@ class ExprReducer(object):
             raise TypeError("Unknown Expr Type %r", type(expr))
         return node
 
-    def reduce(self, expr):
+    def reduce(self, expr, **kwargs):
         """Returns an ExprNode tree mirroring @expr tree. The ExprNode is
         computed by applying reduction rules to the expression @expr
 
@@ -107,9 +107,9 @@ class ExprReducer(object):
         """
 
         node = self.expr2node(expr)
-        return self.categorize(node, 0)
+        return self.categorize(node, lvl=0, **kwargs)
 
-    def categorize(self, node, lvl=0):
+    def categorize(self, node, lvl=0, **kwargs):
         """Recursively apply rules to @node
 
         @node: ExprNode to analyze
@@ -121,17 +121,17 @@ class ExprReducer(object):
         if isinstance(expr, (ExprId, ExprInt)):
             pass
         elif isinstance(expr, ExprMem):
-            arg = self.categorize(node.arg, lvl + 1)
+            arg = self.categorize(node.arg, lvl=lvl + 1, **kwargs)
             node = ExprNode(ExprMem(arg.expr, expr.size))
             node.arg = arg
         elif isinstance(expr, ExprSlice):
-            arg = self.categorize(node.arg, lvl + 1)
+            arg = self.categorize(node.arg, lvl=lvl + 1, **kwargs)
             node = ExprNode(ExprSlice(arg.expr, expr.start, expr.stop))
             node.arg = arg
         elif isinstance(expr, ExprOp):
             new_args = []
             for arg in node.args:
-                new_a = self.categorize(arg, lvl + 1)
+                new_a = self.categorize(arg, lvl=lvl + 1, **kwargs)
                 assert new_a.expr.size == arg.expr.size
                 new_args.append(new_a)
             node = ExprNode(ExprOp(expr.op, *[x.expr for x in new_args]))
@@ -141,27 +141,27 @@ class ExprReducer(object):
             new_args = []
             new_expr_args = []
             for arg in node.args:
-                arg = self.categorize(arg, lvl + 1)
+                arg = self.categorize(arg, lvl=lvl + 1, **kwargs)
                 new_args.append(arg)
                 new_expr_args.append(arg.expr)
             new_expr = ExprCompose(*new_expr_args)
             node = ExprNode(new_expr)
             node.args = new_args
         elif isinstance(expr, ExprCond):
-            cond = self.categorize(node.cond, lvl + 1)
-            src1 = self.categorize(node.src1, lvl + 1)
-            src2 = self.categorize(node.src2, lvl + 1)
+            cond = self.categorize(node.cond, lvl=lvl + 1, **kwargs)
+            src1 = self.categorize(node.src1, lvl=lvl + 1, **kwargs)
+            src2 = self.categorize(node.src2, lvl=lvl + 1, **kwargs)
             node = ExprNode(ExprCond(cond.expr, src1.expr, src2.expr))
             node.cond, node.src1, node.src2 = cond, src1, src2
         else:
             raise TypeError("Unknown Expr Type %r", type(expr))
 
-        node.info = self.apply_rules(node, lvl)
+        node.info = self.apply_rules(node, lvl=lvl, **kwargs)
         log_reduce.debug("\t" * lvl + "Reduce result: %s %r",
                          node.expr, node.info)
         return node
 
-    def apply_rules(self, node, lvl=0):
+    def apply_rules(self, node, lvl=0, **kwargs):
         """Find and apply reduction rules to @node
 
         @node: ExprNode to analyse
@@ -169,7 +169,8 @@ class ExprReducer(object):
         """
 
         for rule in self.reduction_rules:
-            ret = rule(self, node, lvl)
+            ret = rule(self, node, lvl=lvl, **kwargs)
+
             if ret is not None:
                 log_reduce.debug("\t" * lvl + "Rule found: %r", rule)
                 return ret
diff --git a/miasm2/ir/ir.py b/miasm2/ir/ir.py
index 603d3fd0..afb6b382 100644
--- a/miasm2/ir/ir.py
+++ b/miasm2/ir/ir.py
@@ -469,13 +469,15 @@ class IntermediateRepresentation(object):
         if (isinstance(addr, m2_expr.ExprId) and
                 isinstance(addr.name, AsmLabel)):
             addr = addr.name
-        if isinstance(addr, m2_expr.ExprInt):
+        if isinstance(addr, AsmLabel):
+            return addr
+
+        try:
             addr = int(addr)
-        if isinstance(addr, (int, long)):
-            addr = self.symbol_pool.getby_offset_create(addr)
-        elif isinstance(addr, AsmLabel):
-            addr = self.symbol_pool.getby_name_create(addr.name)
-        return addr
+        except (ValueError, TypeError):
+            return None
+
+        return self.symbol_pool.getby_offset_create(addr)
 
     def get_block(self, addr):
         """Returns the irbloc associated to an ExprId/ExprInt/label/int
diff --git a/miasm2/ir/symbexec.py b/miasm2/ir/symbexec.py
index 6d6ba630..593ab49a 100644
--- a/miasm2/ir/symbexec.py
+++ b/miasm2/ir/symbexec.py
@@ -16,6 +16,18 @@ log.addHandler(console_handler)
 log.setLevel(logging.INFO)
 
 
+def get_block(ir_arch, mdis, addr):
+    """Get IRBlock at address @addr"""
+    lbl = ir_arch.get_label(addr)
+    if not lbl in ir_arch.blocks:
+        block = mdis.dis_block(lbl.offset)
+        ir_arch.add_block(block)
+    irblock = ir_arch.get_block(lbl)
+    if irblock is None:
+        raise LookupError('No block found at that address: %s' % lbl)
+    return irblock
+
+
 class SymbolMngr(object):
     """
     Store registers and memory symbolic values
diff --git a/miasm2/ir/symbexec_types.py b/miasm2/ir/symbexec_types.py
index 297c0c9e..a8e8bdf2 100644
--- a/miasm2/ir/symbexec_types.py
+++ b/miasm2/ir/symbexec_types.py
@@ -10,7 +10,10 @@ class SymbolicStateCTypes(StateEngine):
     """Store C types of symbols"""
 
     def __init__(self, symbols):
-        self._symbols = frozenset(symbols.items())
+        tmp = {}
+        for expr, types in symbols.iteritems():
+            tmp[expr] = frozenset(types)
+        self._symbols = frozenset(tmp.iteritems())
 
     def __hash__(self):
         return hash((self.__class__, self._symbols))
@@ -34,12 +37,16 @@ class SymbolicStateCTypes(StateEngine):
 
     def merge(self, other):
         """Merge two symbolic states
-        Only expressions with equal C types in both states are kept.
+        The resulting types are the union of types of both states.
         @other: second symbolic state
         """
-        symb_a = self.symbols.items()
-        symb_b = other.symbols.items()
-        symbols = dict(set(symb_a).intersection(symb_b))
+        symb_a = self.symbols
+        symb_b = other.symbols
+        symbols = {}
+        for expr in set(symb_a).union(set(symb_b)):
+            ctypes = symb_a.get(expr, set()).union(symb_b.get(expr, set()))
+            if ctypes:
+                symbols[expr] = ctypes
         return self.__class__(symbols)
 
     @property
@@ -63,137 +70,13 @@ class SymbExecCType(SymbolicExecutionEngine):
                  func_write=None,
                  sb_expr_simp=expr_simp):
         self.chandler = chandler
+
         super(SymbExecCType, self).__init__(ir_arch,
                                             {},
                                             func_read,
                                             func_write,
                                             sb_expr_simp)
         self.symbols = dict(symbols)
-        offset_types = []
-        for name in [('int',), ('long',),
-                     ('long', 'long'),
-                     ('char',), ('short',),
-
-                     ('unsigned', 'char',), ('unsigned', 'short',),
-                     ('unsigned', 'int',), ('unsigned', 'long',),
-                     ('unsigned', 'long', 'long')]:
-            objc = self.chandler.type_analyzer.types_mngr.get_objc(CTypeId(*name))
-            offset_types.append(objc)
-        self.offset_types = offset_types
-
-    def is_type_offset(self, objc):
-        """Return True if @objc is char/short/int/long"""
-        return objc in self.offset_types
-
-    def get_tpye_int_by_size(self, size):
-        """Return a char/short/int/long type with the size equal to @size
-        @size: size in bit"""
-
-        for objc in self.offset_types:
-            if objc.size == size / 8:
-                return objc
-        return None
-
-    def is_offset_list(self, types, size):
-        """Return the corresponding char/short/int/long type of @size, if every
-        types in the list @types are type offset
-        @types: a list of c types
-        @size: size in bit"""
-
-        for arg_type in types:
-            if not self.is_type_offset(arg_type):
-                return None
-        objc = self.get_tpye_int_by_size(size)
-        if objc:
-            return objc
-        # default size
-        objc = self.offset_types[0]
-        return objc
-
-    def apply_expr_on_state_visit_cache(self, expr, state, cache, level=0):
-        """
-        Deep First evaluate nodes:
-            1. evaluate node's sons
-            2. simplify
-        """
-
-        expr = self.expr_simp(expr)
-
-        if expr in cache:
-            return cache[expr]
-        elif expr in state:
-            return state[expr]
-        elif isinstance(expr, ExprInt):
-            objc = self.get_tpye_int_by_size(expr.size)
-            if objc is None:
-                objc = self.chandler.type_analyzer.types_mngr.get_objc(CTypeId('int'))
-            return objc
-        elif isinstance(expr, ExprId):
-            if expr in state:
-                return state[expr]
-            return None
-        elif isinstance(expr, ExprMem):
-            ptr = self.apply_expr_on_state_visit_cache(expr.arg, state, cache, level + 1)
-            if ptr is None:
-                return None
-            self.chandler.type_analyzer.expr_types[self.OBJC_INTERNAL] = ptr
-            ptr_expr = ExprId(self.OBJC_INTERNAL, expr.arg.size)
-            objcs = self.chandler.expr_to_types(ExprMem(ptr_expr, expr.size))
-            if objcs is None:
-                return None
-            objc = objcs[0]
-            return objc
-        elif isinstance(expr, ExprCond):
-            src1 = self.apply_expr_on_state_visit_cache(expr.src1, state, cache, level + 1)
-            src2 = self.apply_expr_on_state_visit_cache(expr.src2, state, cache, level + 1)
-            types = [src1, src2]
-            objc = self.is_offset_list(types, expr.size)
-            if objc:
-                return objc
-            return None
-        elif isinstance(expr, ExprSlice):
-            objc = self.get_tpye_int_by_size(expr.size)
-            if objc is None:
-                # default size
-                objc = self.offset_types[0]
-            return objc
-        elif isinstance(expr, ExprOp):
-            args = []
-            types = []
-            for oarg in expr.args:
-                arg = self.apply_expr_on_state_visit_cache(oarg, state, cache, level + 1)
-                types.append(arg)
-            if None in types:
-                return None
-            objc = self.is_offset_list(types, expr.size)
-            if objc:
-                return objc
-            # Find Base + int
-            if expr.op != '+':
-                return None
-            args = list(expr.args)
-            if args[-1].is_int():
-                offset = args.pop()
-                types.pop()
-            if len(args) == 1:
-                arg, arg_type = args.pop(), types.pop()
-                self.chandler.type_analyzer.expr_types[self.OBJC_INTERNAL] = arg_type
-                ptr_expr = ExprId(self.OBJC_INTERNAL, arg.size)
-                objc = self.chandler.expr_to_types(ptr_expr + offset)
-                objc = objc[0]
-                return objc
-            return None
-        elif isinstance(expr, ExprCompose):
-            types = set()
-            for oarg in expr.args:
-                arg = self.apply_expr_on_state_visit_cache(oarg, state, cache, level + 1)
-                types.add(arg)
-            objc = self.is_offset_list(types, expr.size)
-            if objc:
-                return objc
-            return None
-        else:
-            raise TypeError("Unknown expr type")
 
     def get_state(self):
         """Return the current state of the SymbolicEngine"""
@@ -207,22 +90,43 @@ class SymbExecCType(SymbolicExecutionEngine):
         pool_out = {}
         eval_cache = {}
         for dst, src in assignblk.iteritems():
-            src = self.eval_expr(src, eval_cache)
+            objcs = self.chandler.expr_to_types(src, self.symbols)
             if isinstance(dst, ExprMem):
                 continue
             elif isinstance(dst, ExprId):
-                pool_out[dst] = src
+                pool_out[dst] = frozenset(objcs)
             else:
-                raise ValueError("affected zarb", str(dst))
+                raise ValueError("Unsupported affectation", str(dst))
         return pool_out.iteritems()
 
+    def eval_expr(self, expr, eval_cache=None):
+        return frozenset(self.chandler.expr_to_types(expr, self.symbols))
+
     def apply_change(self, dst, src):
-        objc = src
-        if objc is None and dst in self.symbols:
-            del self.symbols[dst]
+        if src is None:
+            if dst in self.symbols:
+                del self.symbols[dst]
         else:
-            self.symbols[dst] = objc
+            self.symbols[dst] = src
 
     def del_mem_above_stack(self, stack_ptr):
         """No stack deletion"""
         return
+
+    def dump_id(self):
+        """
+        Dump modififed registers symbols only
+        """
+        for expr, expr_types in sorted(self.symbols.iteritems()):
+            if not expr.is_mem():
+                print expr
+                for expr_type in expr_types:
+                    print '\t', expr_type
+
+    def dump_mem(self):
+        """
+        Dump modififed memory symbols
+        """
+        for expr, value in sorted(self.symbols.iteritems()):
+            if expr.is_mem():
+                print expr, value