(self, job, successor, all_successors)
return new_jobs
Process each successor generated by the job, and return a new list of succeeding jobs.

        :param VFGJob job: The VFGJob instance.
        :param SimState successor: The succeeding state.
        :param list all_successors:  A list of all successors.
        :return: A list of newly created jobs from the successor.
        :rtype: list
Process each successor generated by the job, and return a new list of succeeding jobs.
Process each successor generated by the job and return a new list of succeeding jobs .
def _handle_successor(self, job, successor, all_successors):
        """
        Process each successor generated by the job, and return a new list of succeeding jobs.

        :param VFGJob job: The VFGJob instance.
        :param SimState successor: The succeeding state.
        :param list all_successors:  A list of all successors.
        :return: A list of newly created jobs from the successor.
        :rtype: list
        """

        # Initialize parameters
        addr = job.addr
        jumpkind = successor.history.jumpkind

        #
        # Get instruction pointer
        #

        if job.is_return_jump:
            ret_target = job.call_stack.current_return_target
            if ret_target is None:
                # We have no where to go according to our call stack. However, the callstack might be corrupted
                l.debug("According to the call stack, we have nowhere to return to.")
                return [ ]

            successor.ip = ret_target

        # this try-except block is to handle cases where the instruction pointer is symbolic
        try:
            successor_addrs = successor.solver.eval_upto(successor.ip, 2)
        except SimValueError:
            # TODO: Should fall back to reading targets from CFG
            # It cannot be concretized currently. Maybe we could handle
            # it later, maybe it just cannot be concretized
            return [ ]

        if len(successor_addrs) > 1:
            # multiple concrete targets
            if job.is_return_jump:
                # It might be caused by state merging
                # We may retrieve the correct ip from call stack
                successor.ip = job.call_stack.current_return_target

            else:
                return self._handle_successor_multitargets(job, successor, all_successors)

        # Now there should be one single target for the successor
        successor_addr = successor.solver.eval_one(successor.ip)

        # Get the fake ret successor
        fakeret_successor = None
        if self._is_call_jumpkind(jumpkind):
            fakeret_successor = all_successors[-1]

            # If the function we're calling into doesn't return, we should discard it
            if self._cfg is not None:
                func = self.kb.functions.function(addr=job.call_target)
                if func is not None and func.returning is False and len(all_successors) == 2:
                    del all_successors[-1]
                    fakeret_successor = None

        if self._is_call_jumpkind(jumpkind):
            # Create a new call stack for the successor
            new_call_stack = self._create_callstack(job, successor_addr, jumpkind, fakeret_successor)
            if new_call_stack is None:
                l.debug("Cannot create a new callstack for address %#x", successor_addr)
                job.dbg_exit_status[successor] = ""
                return [ ]
            new_call_stack_suffix = new_call_stack.stack_suffix(self._context_sensitivity_level)

            new_function_key = FunctionKey.new(successor_addr, new_call_stack_suffix)
            # Save the initial state for the function
            self._save_function_initial_state(new_function_key, successor_addr, successor.copy())

            # bail out if we hit the interfunction_level cap
            if len(job.call_stack) >= self._interfunction_level:
                l.debug('We are not tracing into a new function %#08x as we hit interfunction_level limit', successor_addr)

                # mark it as skipped
                job.dbg_exit_status[successor] = "Skipped"

                job.call_skipped = True
                job.call_function_key = new_function_key

                job.call_task.skipped = True

                return [ ]

        elif jumpkind == 'Ijk_Ret':
            # Pop the current function out from the call stack
            new_call_stack = self._create_callstack(job, successor_addr, jumpkind, fakeret_successor)
            if new_call_stack is None:
                l.debug("Cannot create a new callstack for address %#x", successor_addr)
                job.dbg_exit_status[successor] = ""
                return [ ]
            new_call_stack_suffix = new_call_stack.stack_suffix(self._context_sensitivity_level)

        else:
            new_call_stack = job.call_stack
            new_call_stack_suffix = job.call_stack_suffix

        # Generate the new block ID
        new_block_id = BlockID.new(successor_addr, new_call_stack_suffix, jumpkind)

        #
        # Generate new VFG jobs
        #

        if jumpkind == "Ijk_Ret":
            assert not job.is_call_jump

            # Record this return
            self._return_target_sources[successor_addr].append(job.call_stack_suffix + (addr,))

            # Check if this return is inside our pending returns list
            if new_block_id in self._pending_returns:
                del self._pending_returns[new_block_id]

        # Check if we have reached a fix-point
        if jumpkind != 'Ijk_FakeRet' and \
                new_block_id in self._nodes:
            last_state = self._nodes[new_block_id].state

            _, _, merged = last_state.merge(successor, plugin_whitelist=self._mergeable_plugins)

            if merged:
                l.debug("%s didn't reach a fix-point", new_block_id)
            else:
                l.debug("%s reaches a fix-point.", new_block_id)
                job.dbg_exit_status[successor] = "Merged due to reaching a fix-point"
                return [ ]

        new_jobs = self._create_new_jobs(job, successor, new_block_id, new_call_stack)

        return new_jobs
def _handle_successor ( self , job , successor , all_successors ) : # Initialize parameters addr = job . addr jumpkind = successor . history . jumpkind # # Get instruction pointer # if job . is_return_jump : ret_target = job . call_stack . current_return_target if ret_target is None : # We have no where to go according to our call stack. However, the callstack might be corrupted l . debug ( "According to the call stack, we have nowhere to return to." ) return [ ] successor . ip = ret_target # this try-except block is to handle cases where the instruction pointer is symbolic try : successor_addrs = successor . solver . eval_upto ( successor . ip , 2 ) except SimValueError : # TODO: Should fall back to reading targets from CFG # It cannot be concretized currently. Maybe we could handle # it later, maybe it just cannot be concretized return [ ] if len ( successor_addrs ) > 1 : # multiple concrete targets if job . is_return_jump : # It might be caused by state merging # We may retrieve the correct ip from call stack successor . ip = job . call_stack . current_return_target else : return self . _handle_successor_multitargets ( job , successor , all_successors ) # Now there should be one single target for the successor successor_addr = successor . solver . eval_one ( successor . ip ) # Get the fake ret successor fakeret_successor = None if self . _is_call_jumpkind ( jumpkind ) : fakeret_successor = all_successors [ - 1 ] # If the function we're calling into doesn't return, we should discard it if self . _cfg is not None : func = self . kb . functions . function ( addr = job . call_target ) if func is not None and func . returning is False and len ( all_successors ) == 2 : del all_successors [ - 1 ] fakeret_successor = None if self . _is_call_jumpkind ( jumpkind ) : # Create a new call stack for the successor new_call_stack = self . _create_callstack ( job , successor_addr , jumpkind , fakeret_successor ) if new_call_stack is None : l . debug ( "Cannot create a new callstack for address %#x" , successor_addr ) job . dbg_exit_status [ successor ] = "" return [ ] new_call_stack_suffix = new_call_stack . stack_suffix ( self . _context_sensitivity_level ) new_function_key = FunctionKey . new ( successor_addr , new_call_stack_suffix ) # Save the initial state for the function self . _save_function_initial_state ( new_function_key , successor_addr , successor . copy ( ) ) # bail out if we hit the interfunction_level cap if len ( job . call_stack ) >= self . _interfunction_level : l . debug ( 'We are not tracing into a new function %#08x as we hit interfunction_level limit' , successor_addr ) # mark it as skipped job . dbg_exit_status [ successor ] = "Skipped" job . call_skipped = True job . call_function_key = new_function_key job . call_task . skipped = True return [ ] elif jumpkind == 'Ijk_Ret' : # Pop the current function out from the call stack new_call_stack = self . _create_callstack ( job , successor_addr , jumpkind , fakeret_successor ) if new_call_stack is None : l . debug ( "Cannot create a new callstack for address %#x" , successor_addr ) job . dbg_exit_status [ successor ] = "" return [ ] new_call_stack_suffix = new_call_stack . stack_suffix ( self . _context_sensitivity_level ) else : new_call_stack = job . call_stack new_call_stack_suffix = job . call_stack_suffix # Generate the new block ID new_block_id = BlockID . new ( successor_addr , new_call_stack_suffix , jumpkind ) # # Generate new VFG jobs # if jumpkind == "Ijk_Ret" : assert not job . is_call_jump # Record this return self . _return_target_sources [ successor_addr ] . append ( job . call_stack_suffix + ( addr , ) ) # Check if this return is inside our pending returns list if new_block_id in self . _pending_returns : del self . _pending_returns [ new_block_id ] # Check if we have reached a fix-point if jumpkind != 'Ijk_FakeRet' and new_block_id in self . _nodes : last_state = self . _nodes [ new_block_id ] . state _ , _ , merged = last_state . merge ( successor , plugin_whitelist = self . _mergeable_plugins ) if merged : l . debug ( "%s didn't reach a fix-point" , new_block_id ) else : l . debug ( "%s reaches a fix-point." , new_block_id ) job . dbg_exit_status [ successor ] = "Merged due to reaching a fix-point" return [ ] new_jobs = self . _create_new_jobs ( job , successor , new_block_id , new_call_stack ) return new_jobs