'Symbolically execute the program in a static manner. The basic idea is that we look ahead by creating a CFG,
then perform a _controlled symbolic exploration_ based on the CFG, one path at a time. The controlled symbolic
exploration stops when it sees a branch whose both directions are all feasible, or it shall wait for a merge
from another path.
A basic block will not be executed for more than *loop_unrolling_limit* times. If that is the case, a new state
will be returned.
:param SimState state: The initial state to start the execution.
:returns:         A list of new states.'

def _execute_and_merge(self, state):

    merge_points = self._get_all_merge_points(self._cfg, self._loop_graph)
    l.debug('Merge    points:    %s', [hex(i[0]) for i in merge_points])
    initial_state = state
    initial_state.globals['loop_ctrs'] = defaultdict(int)
    manager = SimulationManager(self.project, active_states=[initial_state], immutable=False, resilience=(o.BYPASS_VERITESTING_EXCEPTIONS in initial_state.options))
    for stash in self.all_stashes:
        manager.stashes[stash] = []
    while manager.active:
        l.debug('Steps    %s    with    %d    active    states:    [    %s    ]', manager, len(manager.active), manager.active)
        if (self._deviation_filter is not None):
            manager.stash(filter_func=self._deviation_filter, from_stash='active', to_stash='deviated')
        manager.stash(filter_func=self.is_overbound, from_stash='active', to_stash='successful')
        manager.step(successor_func=self._get_successors)
        if ((self._terminator is not None) and self._terminator(manager)):
            for p in manager.unfuck:
                self._unfuck(p)
            break
        manager.stash(filter_func=self.is_not_in_cfg, to_stash='deviated')
        manager.stash(filter_func=(lambda state: ((state.history.jumpkind not in ('Ijk_Boring', 'Ijk_Call', 'Ijk_Ret', 'Ijk_NoHook')) and (not state.history.jumpkind.startswith('Ijk_Sys')))), to_stash='deadended')
        if manager.deadended:
            l.debug('Now    we    have    some    deadended    paths:    %s', manager.deadended)
        for (merge_point_addr, merge_point_looping_times) in merge_points:
            manager.stash_addr(merge_point_addr, to_stash=('_merge_%x_%d' % (merge_point_addr, merge_point_looping_times)))
        if (not manager.active):
            manager = self._join_merge_points(manager, merge_points)
    if any((len(manager.stashes[stash_name]) for stash_name in self.all_stashes)):
        manager.stashes = {name: stash for (name, stash) in manager.stashes.items() if (name in self.all_stashes)}
        for stash in manager.stashes:
            manager.apply(self._unfuck, stash=stash)
    return manager
