docs: def _get_simsuccessors(self, addr, job, current_function_addr=None):
          """
          Create the SimSuccessors instance for a block.
  
          :param int addr:                  Address of the block.
          :param CFGJob job:                The CFG job instance with an input state inside.
          :param int current_function_addr: Address of the current function.
          :return:                          A SimSuccessors instance
          :rtype:                           SimSuccessors
          """
  
          exception_info = None
          state = job.state
          saved_state = job.state  # We don't have to make a copy here
  
          # respect the basic block size from base graph
          block_size = None
          if self._base_graph is not None:
              for n in self._base_graph.nodes():
                  if n.addr == addr:
                      block_size = n.size
                      break
  
          try:
              sim_successors = None
  
              if not self._keep_state:
                  if self.project.is_hooked(addr):
                      old_proc = self.project._sim_procedures[addr]
                      is_continuation = old_proc.is_continuation
                  elif self.project.simos.is_syscall_addr(addr):
                      old_proc = self.project.simos.syscall_from_addr(addr)
                      is_continuation = False  # syscalls don't support continuation
                  else:
                      old_proc = None
                      is_continuation = None
  
                  if old_proc is not None and \
                          not is_continuation and \
                          not old_proc.ADDS_EXITS and \
                          not old_proc.NO_RET:
                      # DON'T CREATE USELESS SIMPROCEDURES if we don't care about the accuracy of states
                      # When generating CFG, a SimProcedure will not be created as it is but be created as a
                      # ReturnUnconstrained stub if it satisfies the following conditions:
                      # - It doesn't add any new exits.
                      # - It returns as normal.
                      # In this way, we can speed up the CFG generation by quite a lot as we avoid simulating
                      # those functions like read() and puts(), which has no impact on the overall control flow at all.
                      #
                      # Special notes about SimProcedure continuation: Any SimProcedure instance that is a continuation
                      # will add new exits, otherwise the original SimProcedure wouldn't have been executed anyway. Hence
                      # it's reasonable for us to always simulate a SimProcedure with continuation.
  
                      old_name = None
  
                      if old_proc.is_syscall:
                          new_stub = SIM_PROCEDURES["stubs"]["syscall"]
                          ret_to = state.regs.ip_at_syscall
                      else:
                          # normal SimProcedures
                          new_stub = SIM_PROCEDURES["stubs"]["ReturnUnconstrained"]
                          ret_to = None
  
                      old_name = old_proc.display_name
  
                      # instantiate the stub
                      new_stub_inst = new_stub(display_name=old_name)
  
                      sim_successors = self.project.engines.procedure_engine.process(
                          state,
                          new_stub_inst,
                          force_addr=addr,
                          ret_to=ret_to,
                      )
  
              if sim_successors is None:
                  jumpkind = state.history.jumpkind
                  jumpkind = 'Ijk_Boring' if jumpkind is None else jumpkind
                  sim_successors = self.project.factory.successors(
                          state,
                          jumpkind=jumpkind,
                          size=block_size,
                          opt_level=self._iropt_level)
  
          except (SimFastPathError, SimSolverModeError) as ex:
  
              if saved_state.mode == 'fastpath':
                  # Got a SimFastPathError or SimSolverModeError in FastPath mode.
                  # We wanna switch to symbolic mode for current IRSB.
                  l.debug('Switch to symbolic mode for address %#x', addr)
                  # Make a copy of the current 'fastpath' state
  
                  l.debug('Symbolic jumps at basic block %#x.', addr)
  
                  new_state = None
                  if addr != current_function_addr:
                      new_state = self._get_symbolic_function_initial_state(current_function_addr)
  
                  if new_state is None:
                      new_state = state.copy()
                      new_state.set_mode('symbolic')
                  new_state.options.add(o.DO_RET_EMULATION)
                  # Remove bad constraints
                  # FIXME: This is so hackish...
                  new_state.solver._solver.constraints = [c for c in new_state.solver.constraints if
                                                      c.op != 'BoolV' or c.args[0] is not False]
                  new_state.solver._solver._result = None
                  # Swap them
                  saved_state, job.state = job.state, new_state
                  sim_successors, exception_info, _ = self._get_simsuccessors(addr, job)
  
              else:
                  exception_info = sys.exc_info()
                  # Got a SimSolverModeError in symbolic mode. We are screwed.
                  # Skip this IRSB
                  l.debug("Caught a SimIRSBError %s. Don't panic, this is usually expected.", ex)
                  inst = SIM_PROCEDURES["stubs"]["PathTerminator"]()
                  sim_successors = SimEngineProcedure().process(state, inst)
  
          except SimIRSBError:
              exception_info = sys.exc_info()
              # It's a tragedy that we came across some instructions that VEX
              # does not support. I'll create a terminating stub there
              l.debug("Caught a SimIRSBError during CFG recovery. Creating a PathTerminator.", exc_info=True)
              inst = SIM_PROCEDURES["stubs"]["PathTerminator"]()
              sim_successors = SimEngineProcedure().process(state, inst)
  
          except claripy.ClaripyError:
              exception_info = sys.exc_info()
              l.debug("Caught a ClaripyError during CFG recovery. Don't panic, this is usually expected.", exc_info=True)
              # Generate a PathTerminator to terminate the current path
              inst = SIM_PROCEDURES["stubs"]["PathTerminator"]()
              sim_successors = SimEngineProcedure().process(state, inst)
  
          except SimError:
              exception_info = sys.exc_info()
              l.debug("Caught a SimError during CFG recovery. Don't panic, this is usually expected.", exc_info=True)
              # Generate a PathTerminator to terminate the current path
              inst = SIM_PROCEDURES["stubs"]["PathTerminator"]()
              sim_successors = SimEngineProcedure().process(state, inst)
  
          except AngrExitError as ex:
              exception_info = sys.exc_info()
              l.debug("Caught a AngrExitError during CFG recovery. Don't panic, this is usually expected.", exc_info=True)
              # Generate a PathTerminator to terminate the current path
              inst = SIM_PROCEDURES["stubs"]["PathTerminator"]()
              sim_successors = SimEngineProcedure().process(state, inst)
  
          except AngrError:
              exception_info = sys.exc_info()
              section = self.project.loader.main_object.find_section_containing(addr)
              if section is None:
                  sec_name = 'No section'
              else:
                  sec_name = section.name
              # AngrError shouldn't really happen though
              l.debug("Caught an AngrError during CFG recovery at %#x (%s)",
                      addr, sec_name, exc_info=True)
              # We might be on a wrong branch, and is likely to encounter the
              # "No bytes in memory xxx" exception
              # Just ignore it
              sim_successors = None
  
          return sim_successors, exception_info, saved_state