This function receives an initial state and imark and processes a list of pyvex.IRStmts
        It annotates the request with a final state, last imark, and a list of SimIRStmts

def _handle_statement(self, state, successors, stmt):
        """
        This function receives an initial state and imark and processes a list of pyvex.IRStmts
        It annotates the request with a final state, last imark, and a list of SimIRStmts
        """
        if type(stmt) == pyvex.IRStmt.IMark:
            # TODO how much of this could be moved into the imark handler
            ins_addr = stmt.addr + stmt.delta
            state.scratch.ins_addr = ins_addr

            # Raise an exception if we're suddenly in self-modifying code
            for subaddr in range(stmt.len):
                if subaddr + stmt.addr in state.scratch.dirty_addrs:
                    raise SimReliftException(state)
            state._inspect('instruction', BP_AFTER)

            l.debug("IMark: %#x", stmt.addr)
            state.scratch.num_insns += 1
            state._inspect('instruction', BP_BEFORE, instruction=ins_addr)

        # process it!
        try:
            stmt_handler = self.stmt_handlers[stmt.tag_int]
        except IndexError:
            l.error("Unsupported statement type %s", (type(stmt)))
            if o.BYPASS_UNSUPPORTED_IRSTMT not in state.options:
                raise UnsupportedIRStmtError("Unsupported statement type %s" % (type(stmt)))
            state.history.add_event('resilience', resilience_type='irstmt', stmt=type(stmt).__name__, message='unsupported IRStmt')
            return None
        else:
            exit_data = stmt_handler(self, state, stmt)

        # for the exits, put *not* taking the exit on the list of constraints so
        # that we can continue on. Otherwise, add the constraints
        if exit_data is not None:
            l.debug("%s adding conditional exit", self)

            target, guard, jumpkind = exit_data

            # Produce our successor state!
            # Let SimSuccessors.add_successor handle the nitty gritty details

            cont_state = None
            exit_state = None

            if o.COPY_STATES not in state.options:
                # very special logic to try to minimize copies
                # first, check if this branch is impossible
                if guard.is_false():
                    cont_state = state
                elif o.LAZY_SOLVES not in state.options and not state.solver.satisfiable(extra_constraints=(guard,)):
                    cont_state = state

                # then, check if it's impossible to continue from this branch
                elif guard.is_true():
                    exit_state = state
                elif o.LAZY_SOLVES not in state.options and not state.solver.satisfiable(extra_constraints=(claripy.Not(guard),)):
                    exit_state = state
                else:
                    exit_state = state.copy()
                    cont_state = state
            else:
                exit_state = state.copy()
                cont_state = state

            if exit_state is not None:
                successors.add_successor(exit_state, target, guard, jumpkind,
                                         exit_stmt_idx=state.scratch.stmt_idx, exit_ins_addr=state.scratch.ins_addr)

            if cont_state is None:
                return False

            # Do our bookkeeping on the continuing state
            cont_condition = claripy.Not(guard)
            cont_state.add_constraints(cont_condition)
            cont_state.scratch.guard = claripy.And(cont_state.scratch.guard, cont_condition)

        return True