docs: 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