Ejemplo n.º 1
0
static void
gdbsim_store_register (int regno)
{
  if (regno == -1)
    {
      for (regno = 0; regno < NUM_REGS; regno++)
	gdbsim_store_register (regno);
      return;
    }
  else if (REGISTER_SIM_REGNO (regno) >= 0)
    {
      char tmp[MAX_REGISTER_SIZE];
      int nr_bytes;
      deprecated_read_register_gen (regno, tmp);
      nr_bytes = sim_store_register (gdbsim_desc,
				     REGISTER_SIM_REGNO (regno),
				     tmp, DEPRECATED_REGISTER_RAW_SIZE (regno));
      if (nr_bytes > 0 && nr_bytes != DEPRECATED_REGISTER_RAW_SIZE (regno))
	internal_error (__FILE__, __LINE__,
			"Register size different to expected");
      /* FIXME: cagney/2002-05-27: Should check `nr_bytes == 0'
	 indicating that GDB and the SIM have different ideas about
	 which registers are fetchable.  */
      if (sr_get_debug ())
	{
	  printf_filtered ("gdbsim_store_register: %d", regno);
	  /* FIXME: We could print something more intelligible.  */
	  dump_mem (tmp, DEPRECATED_REGISTER_RAW_SIZE (regno));
	}
    }
}
Ejemplo n.º 2
0
static void
gdbsim_fetch_register (int regno)
{
  if (regno == -1)
    {
      for (regno = 0; regno < NUM_REGS; regno++)
	gdbsim_fetch_register (regno);
      return;
    }

  switch (REGISTER_SIM_REGNO (regno))
    {
    case LEGACY_SIM_REGNO_IGNORE:
      break;
    case SIM_REGNO_DOES_NOT_EXIST:
      {
	/* For moment treat a `does not exist' register the same way
           as an ``unavailable'' register.  */
	char buf[MAX_REGISTER_SIZE];
	int nr_bytes;
	memset (buf, 0, MAX_REGISTER_SIZE);
	supply_register (regno, buf);
	set_register_cached (regno, -1);
	break;
      }
    default:
      {
	static int warn_user = 1;
	char buf[MAX_REGISTER_SIZE];
	int nr_bytes;
	gdb_assert (regno >= 0 && regno < NUM_REGS);
	memset (buf, 0, MAX_REGISTER_SIZE);
	nr_bytes = sim_fetch_register (gdbsim_desc,
				       REGISTER_SIM_REGNO (regno),
				       buf, DEPRECATED_REGISTER_RAW_SIZE (regno));
	if (nr_bytes > 0 && nr_bytes != DEPRECATED_REGISTER_RAW_SIZE (regno) && warn_user)
	  {
	    fprintf_unfiltered (gdb_stderr,
				"Size of register %s (%d/%d) incorrect (%d instead of %d))",
				REGISTER_NAME (regno),
				regno, REGISTER_SIM_REGNO (regno),
				nr_bytes, DEPRECATED_REGISTER_RAW_SIZE (regno));
	    warn_user = 0;
	  }
	/* FIXME: cagney/2002-05-27: Should check `nr_bytes == 0'
	   indicating that GDB and the SIM have different ideas about
	   which registers are fetchable.  */
	/* Else if (nr_bytes < 0): an old simulator, that doesn't
	   think to return the register size.  Just assume all is ok.  */
	supply_register (regno, buf);
	if (sr_get_debug ())
	  {
	    printf_filtered ("gdbsim_fetch_register: %d", regno);
	    /* FIXME: We could print something more intelligible.  */
	    dump_mem (buf, DEPRECATED_REGISTER_RAW_SIZE (regno));
	  }
	break;
      }
    }
}
Ejemplo n.º 3
0
void
fetch_inferior_registers (int regno)
{
  unsigned int regaddr;
  char buf[MAX_REGISTER_SIZE];
  int i;
  char zerobuf[MAX_REGISTER_SIZE];
  memset (zerobuf, 0, MAX_REGISTER_SIZE);

  deprecated_registers_fetched ();

  for (regno = 1; regno < NUM_REGS; regno++)
    {
      regaddr = register_ptrace_addr (regno);
      for (i = 0; i < DEPRECATED_REGISTER_RAW_SIZE (regno); i += sizeof (int))
	{
	  *(int *) &buf[i] = ptrace (PT_READ_U, PIDGET (inferior_ptid),
				     (PTRACE_ARG3_TYPE) regaddr, 0);
	  regaddr += sizeof (int);
	}
      supply_register (regno, buf);
    }

  supply_register (ZERO_REGNUM, zerobuf);
  /* Frame ptr reg must appear to be 0; it is faked by stack handling code. */
  supply_register (DEPRECATED_FP_REGNUM, zerobuf);
}
Ejemplo n.º 4
0
static int
register_changed_p (int regnum)
{
  char raw_buffer[MAX_REGISTER_SIZE];

  if (! frame_register_read (deprecated_selected_frame, regnum, raw_buffer))
    return -1;

  if (memcmp (&old_regs[DEPRECATED_REGISTER_BYTE (regnum)], raw_buffer,
	      DEPRECATED_REGISTER_RAW_SIZE (regnum)) == 0)
    return 0;

  /* Found a changed register. Return 1. */

  memcpy (&old_regs[DEPRECATED_REGISTER_BYTE (regnum)], raw_buffer,
	  DEPRECATED_REGISTER_RAW_SIZE (regnum));

  return 1;
}
void
fetch_inferior_registers (int regno)
{
  int reglo, reghi;
  int i;
  unsigned long ecp;

  if (regno == -1)
    {
      reglo = 0;
      reghi = NUM_REGS - 1;
    }
  else
    reglo = reghi = regno;

  ecp = registers_addr (PIDGET (inferior_ptid));

  {
    char buf[MAX_REGISTER_SIZE];
    for (regno = reglo; regno <= reghi; regno++)
      {
	int ptrace_fun = PTRACE_PEEKTHREAD;
	
#ifdef M68K
	ptrace_fun = regno == SP_REGNUM ? PTRACE_PEEKUSP : PTRACE_PEEKTHREAD;
#endif
	
	for (i = 0; i < DEPRECATED_REGISTER_RAW_SIZE (regno); i += sizeof (int))
	  {
	    unsigned int reg;
	    
	    errno = 0;
	    reg = ptrace (ptrace_fun, PIDGET (inferior_ptid),
			  (PTRACE_ARG3_TYPE) (ecp + regmap[regno] + i), 0);
	    if (errno)
	      perror_with_name ("ptrace(PTRACE_PEEKUSP)");
	    
	    *(int *) &buf[i] = reg;
	  }
	supply_register (regno, buf);
      }
  }
}
void
store_inferior_registers (int regno)
{
  int reglo, reghi;
  int i;
  unsigned long ecp;

  if (regno == -1)
    {
      reglo = 0;
      reghi = NUM_REGS - 1;
    }
  else
    reglo = reghi = regno;

  ecp = registers_addr (PIDGET (inferior_ptid));

  for (regno = reglo; regno <= reghi; regno++)
    {
      int ptrace_fun = PTRACE_POKEUSER;

      if (CANNOT_STORE_REGISTER (regno))
	continue;

#ifdef M68K
      ptrace_fun = regno == SP_REGNUM ? PTRACE_POKEUSP : PTRACE_POKEUSER;
#endif

      for (i = 0; i < DEPRECATED_REGISTER_RAW_SIZE (regno); i += sizeof (int))
	{
	  unsigned int reg;

	  reg = *(unsigned int *) &deprecated_registers[DEPRECATED_REGISTER_BYTE (regno) + i];

	  errno = 0;
	  ptrace (ptrace_fun, PIDGET (inferior_ptid),
		  (PTRACE_ARG3_TYPE) (ecp + regmap[regno] + i), reg);
	  if (errno)
	    perror_with_name ("ptrace(PTRACE_POKEUSP)");
	}
    }
}
Ejemplo n.º 7
0
/* Parse a string of hex digits starting at HEX, supply them as the
   value of register REGNO, skip any whitespace, and return a pointer
   to the next character.

   There is a function in monitor.c, monitor_supply_register, which is
   supposed to do this job.  However, there is some rather odd stuff
   in there (whitespace characters don't terminate numbers, for
   example) that is incorrect for ROM68k.  It's basically impossible
   to safely tweak monitor_supply_register --- it's used by a zillion
   other monitors; who knows what behaviors they're depending on.  So
   instead, we'll just use our own function, which can behave exactly
   the way we want it to.  */
static char *
rom68k_supply_one_register (int regno, unsigned char *hex)
{
    ULONGEST value;
    unsigned char regbuf[MAX_REGISTER_SIZE];

    value = 0;
    while (*hex != '\0')
        if (is_hex_digit (*hex))
            value = (value * 16) + hex_digit_value (*hex++);
        else
            break;

    /* Skip any whitespace.  */
    while (is_whitespace (*hex))
        hex++;

    store_unsigned_integer (regbuf, DEPRECATED_REGISTER_RAW_SIZE (regno), value);
    supply_register (regno, regbuf);

    return hex;
}
Ejemplo n.º 8
0
/* Store at least register REGNO, or all regs if REGNO == -1.  */
void
gnu_store_registers (int regno)
{
  struct proc *thread;

  /* Make sure we know about new threads.  */
  inf_update_procs (current_inferior);

  thread = inf_tid_to_thread (current_inferior, PIDGET (inferior_ptid));
  if (!thread)
    error ("Couldn't store registers into thread %d: No such thread",
	   PIDGET (inferior_ptid));

  if (regno < I386_NUM_GREGS || regno == -1)
    {
      thread_state_t state;
      thread_state_data_t old_state;
      int was_aborted = thread->aborted;
      int was_valid = thread->state_valid;
      int trace;

      if (!was_aborted && was_valid)
	memcpy (&old_state, &thread->state, sizeof (old_state));

      state = proc_get_state (thread, 1);
      if (!state)
	{
	  warning ("Couldn't store registers into %s", proc_string (thread));
	  return;
	}

      /* Save the T bit.  We might try to restore the %eflags register
         below, but changing the T bit would seriously confuse GDB.  */
      trace = ((struct i386_thread_state *)state)->efl & 0x100;

      if (!was_aborted && was_valid)
	/* See which registers have changed after aborting the thread.  */
	{
	  int check_regno;

	  for (check_regno = 0; check_regno < I386_NUM_GREGS; check_regno++)
	    if ((thread->fetched_regs & (1 << check_regno))
		&& memcpy (REG_ADDR (&old_state, check_regno),
			   REG_ADDR (state, check_regno),
			   DEPRECATED_REGISTER_RAW_SIZE (check_regno)))
	      /* Register CHECK_REGNO has changed!  Ack!  */
	      {
		warning ("Register %s changed after the thread was aborted",
			 REGISTER_NAME (check_regno));
		if (regno >= 0 && regno != check_regno)
		  /* Update GDB's copy of the register.  */
		  supply_register (check_regno, REG_ADDR (state, check_regno));
		else
		  warning ("... also writing this register!  Suspicious...");
	      }
	}

#define fill(state, regno)                                               \
  memcpy (REG_ADDR(state, regno), &deprecated_registers[DEPRECATED_REGISTER_BYTE (regno)],     \
          DEPRECATED_REGISTER_RAW_SIZE (regno))

      if (regno == -1)
	{
	  int i;

	  proc_debug (thread, "storing all registers");

	  for (i = 0; i < I386_NUM_GREGS; i++)
	    if (deprecated_register_valid[i])
	      fill (state, i);
	}
      else
	{
	  proc_debug (thread, "storing register %s", REGISTER_NAME (regno));

	  gdb_assert (deprecated_register_valid[regno]);
	  fill (state, regno);
	}

      /* Restore the T bit.  */
      ((struct i386_thread_state *)state)->efl &= ~0x100;
      ((struct i386_thread_state *)state)->efl |= trace;
    }

#undef fill

  if (regno >= I386_NUM_GREGS || regno == -1)
    {
      proc_debug (thread, "storing floating-point registers");

      store_fpregs (thread, regno);
    }
}
void
store_inferior_registers (int regno)
{
  unsigned int regaddr;
  char buf[80];
  int i;
  unsigned int offset = U_REGS_OFFSET;
  int scratch;

  if (regno >= 0)
    {
      unsigned int addr, len, offset;

      if (CANNOT_STORE_REGISTER (regno))
	return;

      offset = 0;
      len = DEPRECATED_REGISTER_RAW_SIZE (regno);

      /* Requests for register zero actually want the save_state's
	 ss_flags member.  As RM says: "Oh, what a hack!"  */
      if (regno == 0)
	{
	  save_state_t ss;
	  addr = HPPAH_OFFSETOF (save_state_t, ss_flags);
	  len = sizeof (ss.ss_flags);

	  /* Note that ss_flags is always an int, no matter what
	     DEPRECATED_REGISTER_RAW_SIZE(0) says.  Assuming all HP-UX
	     PA machines are big-endian, put it at the least
	     significant end of the value, and zap the rest of the
	     buffer.  */
	  offset = DEPRECATED_REGISTER_RAW_SIZE (0) - len;
	}

      /* Floating-point registers come from the ss_fpblock area.  */
      else if (regno >= HPPA_FP0_REGNUM)
	addr = (HPPAH_OFFSETOF (save_state_t, ss_fpblock) 
		+ (DEPRECATED_REGISTER_BYTE (regno) - DEPRECATED_REGISTER_BYTE (HPPA_FP0_REGNUM)));

      /* Wide registers come from the ss_wide area.
	 I think it's more PC to test (ss_flags & SS_WIDEREGS) to select
	 between ss_wide and ss_narrow than to use the raw register size.
	 But checking ss_flags would require an extra ptrace call for
	 every register reference.  Bleah.  */
      else if (len == 8)
	addr = (HPPAH_OFFSETOF (save_state_t, ss_wide) 
		+ DEPRECATED_REGISTER_BYTE (regno));

      /* Narrow registers come from the ss_narrow area.  Note that
	 ss_narrow starts with gr1, not gr0.  */
      else if (len == 4)
	addr = (HPPAH_OFFSETOF (save_state_t, ss_narrow)
		+ (DEPRECATED_REGISTER_BYTE (regno) - DEPRECATED_REGISTER_BYTE (1)));
      else
	internal_error (__FILE__, __LINE__,
			"hppah-nat.c (write_register): unexpected register size");

#ifdef GDB_TARGET_IS_HPPA_20W
      /* Unbelieveable.  The PC head and tail must be written in 64bit hunks
	 or we will get an error.  Worse yet, the oddball ptrace/ttrace
	 layering will not allow us to perform a 64bit register store.

	 What a crock.  */
      if (regno == HPPA_PCOQ_HEAD_REGNUM || regno == HPPA_PCOQ_TAIL_REGNUM && len == 8)
	{
	  CORE_ADDR temp;

	  temp = *(CORE_ADDR *)&deprecated_registers[DEPRECATED_REGISTER_BYTE (regno)];

	  /* Set the priv level (stored in the low two bits of the PC.  */
	  temp |= 0x3;

	  ttrace_write_reg_64 (PIDGET (inferior_ptid), (CORE_ADDR)addr,
	                       (CORE_ADDR)&temp);

	  /* If we fail to write the PC, give a true error instead of
	     just a warning.  */
	  if (errno != 0)
	    {
	      char *err = safe_strerror (errno);
	      char *msg = alloca (strlen (err) + 128);
	      sprintf (msg, "writing `%s' register: %s",
		        REGISTER_NAME (regno), err);
	      perror_with_name (msg);
	    }
	  return;
	}

      /* Another crock.  HPUX complains if you write a nonzero value to
	 the high part of IPSW.  What will it take for HP to catch a
	 clue about building sensible interfaces?  */
     if (regno == HPPA_IPSW_REGNUM && len == 8)
	*(int *)&deprecated_registers[DEPRECATED_REGISTER_BYTE (regno)] = 0;
#endif

      for (i = 0; i < len; i += sizeof (int))
	{
	  errno = 0;
	  call_ptrace (PT_WUREGS, PIDGET (inferior_ptid),
	               (PTRACE_ARG3_TYPE) addr + i,
		       *(int *) &deprecated_registers[DEPRECATED_REGISTER_BYTE (regno) + i]);
	  if (errno != 0)
	    {
	      /* Warning, not error, in case we are attached; sometimes
		 the kernel doesn't let us at the registers. */
	      char *err = safe_strerror (errno);
	      char *msg = alloca (strlen (err) + 128);
	      sprintf (msg, "writing `%s' register: %s",
		        REGISTER_NAME (regno), err);
	      /* If we fail to write the PC, give a true error instead of
		 just a warning.  */
	      if (regno == HPPA_PCOQ_HEAD_REGNUM || regno == HPPA_PCOQ_TAIL_REGNUM)
		perror_with_name (msg);
	      else
		warning (msg);
	      return;
	    }
	}
    }
  else
    for (regno = 0; regno < NUM_REGS; regno++)
      store_inferior_registers (regno);
}
/* Fetch a register's value from the process's U area.  */
static void
fetch_register (int regno)
{
  char buf[MAX_REGISTER_SIZE];
  unsigned int addr, len, offset;
  int i;

  offset = 0;
  len = DEPRECATED_REGISTER_RAW_SIZE (regno);

  /* Requests for register zero actually want the save_state's
     ss_flags member.  As RM says: "Oh, what a hack!"  */
  if (regno == 0)
    {
      save_state_t ss;
      addr = HPPAH_OFFSETOF (save_state_t, ss_flags);
      len = sizeof (ss.ss_flags);

      /* Note that ss_flags is always an int, no matter what
	 DEPRECATED_REGISTER_RAW_SIZE(0) says.  Assuming all HP-UX PA
	 machines are big-endian, put it at the least significant end
	 of the value, and zap the rest of the buffer.  */
      offset = DEPRECATED_REGISTER_RAW_SIZE (0) - len;
      memset (buf, 0, sizeof (buf));
    }

  /* Floating-point registers come from the ss_fpblock area.  */
  else if (regno >= HPPA_FP0_REGNUM)
    addr = (HPPAH_OFFSETOF (save_state_t, ss_fpblock) 
	    + (DEPRECATED_REGISTER_BYTE (regno) - DEPRECATED_REGISTER_BYTE (HPPA_FP0_REGNUM)));

  /* Wide registers come from the ss_wide area.
     I think it's more PC to test (ss_flags & SS_WIDEREGS) to select
     between ss_wide and ss_narrow than to use the raw register size.
     But checking ss_flags would require an extra ptrace call for
     every register reference.  Bleah.  */
  else if (len == 8)
    addr = (HPPAH_OFFSETOF (save_state_t, ss_wide) 
	    + DEPRECATED_REGISTER_BYTE (regno));

  /* Narrow registers come from the ss_narrow area.  Note that
     ss_narrow starts with gr1, not gr0.  */
  else if (len == 4)
    addr = (HPPAH_OFFSETOF (save_state_t, ss_narrow)
	    + (DEPRECATED_REGISTER_BYTE (regno) - DEPRECATED_REGISTER_BYTE (1)));

  else
    internal_error (__FILE__, __LINE__,
		    "hppa-nat.c (fetch_register): unexpected register size");

  for (i = 0; i < len; i += sizeof (int))
    {
      errno = 0;
      /* Copy an int from the U area to buf.  Fill the least
         significant end if len != raw_size.  */
      * (int *) &buf[offset + i] =
	  call_ptrace (PT_RUREGS, PIDGET (inferior_ptid),
		       (PTRACE_ARG3_TYPE) addr + i, 0);
      if (errno != 0)
	{
	  /* Warning, not error, in case we are attached; sometimes
	     the kernel doesn't let us at the registers. */
	  char *err = safe_strerror (errno);
	  char *msg = alloca (strlen (err) + 128);
	  sprintf (msg, "reading `%s' register: %s",
		   REGISTER_NAME (regno), err);
	  warning (msg);
	  return;
	}
    }

  /* If we're reading an address from the instruction address queue,
     mask out the bottom two bits --- they contain the privilege
     level.  */
  if (regno == HPPA_PCOQ_HEAD_REGNUM || regno == HPPA_PCOQ_TAIL_REGNUM)
    buf[len - 1] &= ~0x3;

  supply_register (regno, buf);
}
Ejemplo n.º 11
0
/* Write given values into registers. The registers and values are
   given as pairs. The corresponding MI command is 
   -data-write-register-values <format> [<regnum1> <value1>...<regnumN> <valueN>]*/
enum mi_cmd_result
mi_cmd_data_write_register_values (char *command, char **argv, int argc)
{
  int regnum;
  int i;
  int numregs;
  LONGEST value;
  char format;

  /* Note that the test for a valid register must include checking the
     REGISTER_NAME because NUM_REGS may be allocated for the union of
     the register sets within a family of related processors.  In this
     case, some entries of REGISTER_NAME will change depending upon
     the particular processor being debugged.  */

  numregs = NUM_REGS;

  if (argc == 0)
    {
      xasprintf (&mi_error_message,
		 "mi_cmd_data_write_register_values: Usage: -data-write-register-values <format> [<regnum1> <value1>...<regnumN> <valueN>]");
      return MI_CMD_ERROR;
    }

  format = (int) argv[0][0];

  if (!target_has_registers)
    {
      xasprintf (&mi_error_message,
		 "mi_cmd_data_write_register_values: No registers.");
      return MI_CMD_ERROR;
    }

  if (!(argc - 1))
    {
      xasprintf (&mi_error_message,
		 "mi_cmd_data_write_register_values: No regs and values specified.");
      return MI_CMD_ERROR;
    }

  if ((argc - 1) % 2)
    {
      xasprintf (&mi_error_message,
		 "mi_cmd_data_write_register_values: Regs and vals are not in pairs.");
      return MI_CMD_ERROR;
    }

  for (i = 1; i < argc; i = i + 2)
    {
      regnum = atoi (argv[i]);

      if (regnum >= 0
	  && regnum < numregs
	  && REGISTER_NAME (regnum) != NULL
	  && *REGISTER_NAME (regnum) != '\000')
	{
	  void *buffer;
	  struct cleanup *old_chain;

	  /* Get the value as a number */
	  value = parse_and_eval_address (argv[i + 1]);
	  /* Get the value into an array */
	  buffer = xmalloc (DEPRECATED_REGISTER_SIZE);
	  old_chain = make_cleanup (xfree, buffer);
	  store_signed_integer (buffer, DEPRECATED_REGISTER_SIZE, value);
	  /* Write it down */
	  deprecated_write_register_bytes (DEPRECATED_REGISTER_BYTE (regnum), buffer, DEPRECATED_REGISTER_RAW_SIZE (regnum));
	  /* Free the buffer.  */
	  do_cleanups (old_chain);
	}
      else
	{
	  xasprintf (&mi_error_message, "bad register number");
	  return MI_CMD_ERROR;
	}
    }
  return MI_CMD_DONE;
}
Ejemplo n.º 12
0
/* Output one register's contents in the desired format. */
static int
get_register (int regnum, int format)
{
  char raw_buffer[MAX_REGISTER_SIZE];
  char virtual_buffer[MAX_REGISTER_SIZE];
  int optim;
  int realnum;
  CORE_ADDR addr;
  enum lval_type lval;
  static struct ui_stream *stb = NULL;

  stb = ui_out_stream_new (uiout);

  if (format == 'N')
    format = 0;

  frame_register (deprecated_selected_frame, regnum, &optim, &lval, &addr,
		  &realnum, raw_buffer);

  if (optim)
    {
      xasprintf (&mi_error_message, "Optimized out");
      return -1;
    }

  /* Convert raw data to virtual format if necessary.  */

  if (DEPRECATED_REGISTER_CONVERTIBLE_P ()
      && DEPRECATED_REGISTER_CONVERTIBLE (regnum))
    {
      DEPRECATED_REGISTER_CONVERT_TO_VIRTUAL (regnum,
				   register_type (current_gdbarch, regnum),
				   raw_buffer, virtual_buffer);
    }
  else
    memcpy (virtual_buffer, raw_buffer, DEPRECATED_REGISTER_VIRTUAL_SIZE (regnum));

  if (format == 'r')
    {
      int j;
      char *ptr, buf[1024];

      strcpy (buf, "0x");
      ptr = buf + 2;
      for (j = 0; j < DEPRECATED_REGISTER_RAW_SIZE (regnum); j++)
	{
	  int idx = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? j
	  : DEPRECATED_REGISTER_RAW_SIZE (regnum) - 1 - j;
	  sprintf (ptr, "%02x", (unsigned char) raw_buffer[idx]);
	  ptr += 2;
	}
      ui_out_field_string (uiout, "value", buf);
      /*fputs_filtered (buf, gdb_stdout); */
    }
  else
    {
      val_print (register_type (current_gdbarch, regnum), virtual_buffer, 0, 0,
		 stb->stream, format, 1, 0, Val_pretty_default);
      ui_out_field_stream (uiout, "value", stb);
      ui_out_stream_delete (stb);
    }
  return 1;
}