Checks the hooking procedure for this address searching for new static
        exit points to add to successors (generating entries for them)
        if this address has not been traced before. Updates previous CFG nodes
        with edges.

        :param CFGJob cfg_job:      The CFGJob instance.
        :param int current_func_addr: Address of the current function.
        :return: List of successors
        :rtype: list

def _scan_procedure(self, cfg_job, current_func_addr):
        """
        Checks the hooking procedure for this address searching for new static
        exit points to add to successors (generating entries for them)
        if this address has not been traced before. Updates previous CFG nodes
        with edges.

        :param CFGJob cfg_job:      The CFGJob instance.
        :param int current_func_addr: Address of the current function.
        :return: List of successors
        :rtype: list
        """

        addr = cfg_job.addr

        try:
            if self.project.is_hooked(addr):
                procedure = self.project.hooked_by(addr)
                name = procedure.display_name
            else:
                procedure = self.project.simos.syscall_from_addr(addr)
                name = procedure.display_name

            if addr not in self._nodes:
                cfg_node = CFGNode(addr, 0, self.model,
                                   function_address=current_func_addr,
                                   simprocedure_name=name,
                                   no_ret=procedure.NO_RET,
                                   block_id=addr,
                                   )

                self._nodes[addr] = cfg_node
                self._nodes_by_addr[addr].append(cfg_node)

            else:
                cfg_node = self._nodes[addr]

        except (SimMemoryError, SimEngineError):
            return [ ]

        self._graph_add_edge(cfg_node, cfg_job.src_node, cfg_job.jumpkind, cfg_job.src_ins_addr,
                             cfg_job.src_stmt_idx
                             )
        self._function_add_node(cfg_node, current_func_addr)

        # Add edges going to this node in function graphs
        cfg_job.apply_function_edges(self, clear=True)

        # If we have traced it before, don't trace it anymore
        if addr in self._traced_addresses:
            return [ ]
        else:
            # Mark the address as traced
            self._traced_addresses.add(addr)

        entries = [ ]

        if procedure.ADDS_EXITS:
            # Get two blocks ahead
            grandparent_nodes = list(self.graph.predecessors(cfg_job.src_node))
            if not grandparent_nodes:
                l.warning("%s is supposed to yield new exits, but it fails to do so.", name)
                return [ ]
            blocks_ahead = [
                self._lift(grandparent_nodes[0].addr).vex,
                self._lift(cfg_job.src_node.addr).vex,
            ]
            procedure.project = self.project
            procedure.arch = self.project.arch
            new_exits = procedure.static_exits(blocks_ahead)

            for addr_, jumpkind in new_exits:
                if isinstance(addr_, claripy.ast.BV) and not addr_.symbolic:
                    addr_ = addr_._model_concrete.value
                if not isinstance(addr_, int):
                    continue
                entries += self._create_jobs(addr_, jumpkind, current_func_addr, None, addr_, cfg_node, None,
                                             None
                                             )

        if not procedure.NO_RET:
            # it returns
            cfg_node.has_return = True
            self._function_exits[current_func_addr].add(addr)
            self._function_add_return_site(addr, current_func_addr)
        else:
            # the procedure does not return
            self._updated_nonreturning_functions.add(current_func_addr)

        return entries