예제 #1
0
void
mips64_fill_gregset (const struct regcache *regcache,
		     mips64_elf_gregset_t *gregsetp, int regno)
{
  int regaddr, regi;
  mips64_elf_greg_t *regp = *gregsetp;
  void *src, *dst;

  if (regno == -1)
    {
      memset (regp, 0, sizeof (mips64_elf_gregset_t));
      for (regi = 1; regi < 32; regi++)
        mips64_fill_gregset (regcache, gregsetp, regi);
      mips64_fill_gregset (regcache, gregsetp,
			   mips_regnum (current_gdbarch)->lo);
      mips64_fill_gregset (regcache, gregsetp,
			   mips_regnum (current_gdbarch)->hi);
      mips64_fill_gregset (regcache, gregsetp,
			   mips_regnum (current_gdbarch)->pc);
      mips64_fill_gregset (regcache, gregsetp,
			   mips_regnum (current_gdbarch)->badvaddr);
      mips64_fill_gregset (regcache, gregsetp, MIPS_PS_REGNUM);
      mips64_fill_gregset (regcache, gregsetp,
			   mips_regnum (current_gdbarch)->cause);
      mips64_fill_gregset (regcache, gregsetp, MIPS_RESTART_REGNUM);
      return;
   }

  if (regno > 0 && regno < 32)
    regaddr = regno + MIPS64_EF_REG0;
  else if (regno == mips_regnum (current_gdbarch)->lo)
    regaddr = MIPS64_EF_LO;
  else if (regno == mips_regnum (current_gdbarch)->hi)
    regaddr = MIPS64_EF_HI;
  else if (regno == mips_regnum (current_gdbarch)->pc)
    regaddr = MIPS64_EF_CP0_EPC;
  else if (regno == mips_regnum (current_gdbarch)->badvaddr)
    regaddr = MIPS64_EF_CP0_BADVADDR;
  else if (regno == MIPS_PS_REGNUM)
    regaddr = MIPS64_EF_CP0_STATUS;
  else if (regno == mips_regnum (current_gdbarch)->cause)
    regaddr = MIPS64_EF_CP0_CAUSE;
  else if (mips_linux_restart_reg_p (current_gdbarch)
	   && regno == MIPS_RESTART_REGNUM)
    regaddr = MIPS64_EF_REG0;
  else
    regaddr = -1;

  if (regaddr != -1)
    {
      gdb_byte buf[MAX_REGISTER_SIZE];
      LONGEST val;

      regcache_raw_collect (regcache, regno, buf);
      val = extract_signed_integer (buf,
				    register_size (current_gdbarch, regno));
      dst = regp + regaddr;
      store_signed_integer (dst, 8, val);
    }
}
예제 #2
0
/* Store VALUE at ADDR in the inferior as a LEN-byte signed integer: */
void
write_memory_signed_integer(CORE_ADDR addr, int len, LONGEST value)
{
  char *buf = (char *)alloca(len);
  store_signed_integer((gdb_byte *)buf, len, value);
  write_memory(addr, (const bfd_byte *)buf, len);
}
예제 #3
0
static void
supply_32bit_reg (struct regcache *regcache, int regnum, const void *addr)
{
  gdb_byte buf[MAX_REGISTER_SIZE];
  store_signed_integer (buf, register_size (current_gdbarch, regnum),
                        extract_signed_integer (addr, 4));
  regcache_raw_supply (regcache, regnum, buf);
}
static void
supply_32bit_reg (struct regcache *regcache, int regnum, const void *addr)
{
  struct gdbarch *gdbarch = get_regcache_arch (regcache);
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  gdb_byte buf[MAX_REGISTER_SIZE];
  store_signed_integer (buf, register_size (gdbarch, regnum), byte_order,
                        extract_signed_integer (addr, 4, byte_order));
  regcache_raw_supply (regcache, regnum, buf);
}
예제 #5
0
static void
mips_fbsd_collect_reg (const struct regcache *regcache, int regnum, void *addr,
		       size_t len)
{
  struct gdbarch *gdbarch = get_regcache_arch (regcache);

  if (register_size (gdbarch, regnum) == len)
    regcache_raw_collect (regcache, regnum, addr);
  else
    {
      enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
      gdb_byte buf[MAX_REGISTER_SIZE];
      LONGEST val;

      regcache_raw_collect (regcache, regnum, buf);
      val = extract_signed_integer (buf, register_size (gdbarch, regnum),
				    byte_order);
      store_signed_integer ((gdb_byte *) addr, len, byte_order, val);
    }
}
void
mips64_fill_fpregset (const struct regcache *regcache,
		      mips64_elf_fpregset_t *fpregsetp, int regno)
{
  struct gdbarch *gdbarch = get_regcache_arch (regcache);
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  gdb_byte *to;

  if ((regno >= gdbarch_fp0_regnum (gdbarch))
      && (regno < gdbarch_fp0_regnum (gdbarch) + 32))
    {
      /* See mips_linux_o32_sigframe_init for a description of the
	 peculiar FP register layout.  */
      if (register_size (gdbarch, regno) == 4)
	{
	  int regi = regno - gdbarch_fp0_regnum (gdbarch);

	  to = (gdb_byte *) (*fpregsetp + (regi & ~1));
	  if ((gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) != (regi & 1))
	    to += 4;
	  regcache_raw_collect (regcache, regno, to);
	}
      else
	{
	  to = (gdb_byte *) (*fpregsetp + regno - gdbarch_fp0_regnum (gdbarch));
	  regcache_raw_collect (regcache, regno, to);
	}
    }
  else if (regno == mips_regnum (gdbarch)->fp_control_status)
    {
      gdb_byte buf[MAX_REGISTER_SIZE];
      LONGEST val;

      regcache_raw_collect (regcache, regno, buf);
      val = extract_signed_integer (buf, register_size (gdbarch, regno),
				    byte_order);
      to = (gdb_byte *) (*fpregsetp + 32);
      store_signed_integer (to, 4, byte_order, val);
    }
  else if (regno == mips_regnum (gdbarch)->fp_implementation_revision)
    {
      gdb_byte buf[MAX_REGISTER_SIZE];
      LONGEST val;

      regcache_raw_collect (regcache, regno, buf);
      val = extract_signed_integer (buf, register_size (gdbarch, regno),
				    byte_order);
      to = (gdb_byte *) (*fpregsetp + 32) + 4;
      store_signed_integer (to, 4, byte_order, val);
    }
  else if (regno == -1)
    {
      int regi;

      for (regi = 0; regi < 32; regi++)
	mips64_fill_fpregset (regcache, fpregsetp,
			      gdbarch_fp0_regnum (gdbarch) + regi);
      mips64_fill_fpregset (regcache, fpregsetp,
			    mips_regnum (gdbarch)->fp_control_status);
      mips64_fill_fpregset (regcache, fpregsetp,
			    (mips_regnum (gdbarch)
			      ->fp_implementation_revision));
    }
}
예제 #7
0
CORE_ADDR
microblaze_push_arguments (int nargs, struct value ** args, CORE_ADDR sp,
		      unsigned char struct_return, CORE_ADDR struct_addr)
{
  int argreg;
  int argnum;
  struct stack_arg
    {
      int len;
      char *val;
    }
   *stack_args;
  char buf[REGISTER_SIZE];
  int nstack_args = 0;
  CORE_ADDR oldsp = sp;
 

  stack_args = (struct stack_arg *) alloca (nargs * sizeof (struct stack_arg));

  argreg = FIRST_ARGREG;

  /* Align the stack. This is mostly a nop, but not always. It will be needed
     if we call a function which has argument overflow. */
  sp &= ~3;

  /* If this function returns a struct, we must pass a buffer to the function
     which it can use to save the return value. */
  if (struct_return)
    write_register (argreg++, struct_addr);

  /* FIXME: what about unions? */
  for (argnum = 0; argnum < nargs; argnum++)
    {
      char *val = (char *) VALUE_CONTENTS (args[argnum]);
      int len = TYPE_LENGTH (VALUE_TYPE (args[argnum]));
      struct type *type = VALUE_TYPE (args[argnum]);
      int olen;

      microblaze_insn_debug (("MICROBLAZE PUSH: argreg=%d; len=%d; %s\n",
			 argreg, len, TYPE_CODE (type) == TYPE_CODE_STRUCT ? "struct" : "not struct"));

      olen = len;

      if (TYPE_CODE (type) == TYPE_CODE_STRUCT && olen < REGISTER_SIZE)
	{
	  /* Small structs must be right aligned within the register,
	     the most significant bits are undefined. */
	  write_register (argreg, extract_unsigned_integer (val, len));
	  argreg++;
	  len = 0;
	}

      while (len > 0 && argreg <= LAST_ARGREG)
	{
	  write_register (argreg, extract_unsigned_integer (val, REGISTER_SIZE));
	  argreg++;
	  val += REGISTER_SIZE;
	  len -= REGISTER_SIZE;
	}

      if (len > 0)
	{
	  /* Note that this must be saved onto the stack */
	  microblaze_insn_debug (("MICROBLAZE PUSH: adding arg %d to stack\n", argnum));
	  stack_args[nstack_args].val = val;
	  stack_args[nstack_args].len = len;
	  nstack_args++;
	}
    }

  /* Set up the stack - leave space for register function parameters (LAST_ARGREG-FIRST_ARGREG+1)
  sp -= (LAST_ARGREG-FIRST_ARGREG + 1) * REGISTER_SIZE;

  /* We're done with registers and stack allocation. Now do the actual
     stack pushes. */
  while (nstack_args--)
    {
      sp -= stack_args[nstack_args].len;
      write_memory (sp, stack_args[nstack_args].val, stack_args[nstack_args].len);
      sp &= ~3;
    }

  /* Set up the stack - leave space for register function parameters (LAST_ARGREG-FIRST_ARGREG+1) */
  sp -= (LAST_ARGREG-FIRST_ARGREG + 0) * REGISTER_SIZE;

  /* Now leave space for link register and back pointer */
  sp -= REGISTER_SIZE;
  store_signed_integer(buf, REGISTER_SIZE, read_register(PR_REGNUM));
  write_memory(sp, buf, REGISTER_SIZE);
  sp -= REGISTER_SIZE;
  store_signed_integer(buf, REGISTER_SIZE, oldsp);
  write_memory(sp, buf, REGISTER_SIZE);
  
  /* Return adjusted stack pointer.  */
  return sp;
}
예제 #8
0
파일: mi-main.c 프로젝트: debrouxl/tiemu
/* DATA-MEMORY-WRITE:

   COLUMN_OFFSET: optional argument. Must be preceeded by '-o'. The
   offset from the beginning of the memory grid row where the cell to
   be written is.
   ADDR: start address of the row in the memory grid where the memory
   cell is, if OFFSET_COLUMN is specified. Otherwise, the address of
   the location to write to.
   FORMAT: a char indicating format for the ``word''. See 
   the ``x'' command.
   WORD_SIZE: size of each ``word''; 1,2,4, or 8 bytes
   VALUE: value to be written into the memory address.

   Writes VALUE into ADDR + (COLUMN_OFFSET * WORD_SIZE).

   Prints nothing. */
enum mi_cmd_result
mi_cmd_data_write_memory (char *command, char **argv, int argc)
{
  CORE_ADDR addr;
  char word_format;
  long word_size;
  /* FIXME: ezannoni 2000-02-17 LONGEST could possibly not be big
     enough when using a compiler other than GCC. */
  LONGEST value;
  void *buffer;
  struct cleanup *old_chain;
  long offset = 0;
  int optind = 0;
  char *optarg;
  enum opt
    {
      OFFSET_OPT
    };
  static struct mi_opt opts[] =
  {
    {"o", OFFSET_OPT, 1},
    0
  };

  while (1)
    {
      int opt = mi_getopt ("mi_cmd_data_write_memory", argc, argv, opts,
			   &optind, &optarg);
      if (opt < 0)
	break;
      switch ((enum opt) opt)
	{
	case OFFSET_OPT:
	  offset = atol (optarg);
	  break;
	}
    }
  argv += optind;
  argc -= optind;

  if (argc != 4)
    {
      mi_error_message = xstrprintf ("mi_cmd_data_write_memory: Usage: [-o COLUMN_OFFSET] ADDR FORMAT WORD-SIZE VALUE.");
      return MI_CMD_ERROR;
    }

  /* Extract all the arguments. */
  /* Start address of the memory dump. */
  addr = parse_and_eval_address (argv[0]);
  /* The format character to use when displaying a memory word. See
     the ``x'' command. */
  word_format = argv[1][0];
  /* The size of the memory word. */
  word_size = atol (argv[2]);

  /* Calculate the real address of the write destination. */
  addr += (offset * word_size);

  /* Get the value as a number */
  value = parse_and_eval_address (argv[3]);
  /* Get the value into an array */
  buffer = xmalloc (word_size);
  old_chain = make_cleanup (xfree, buffer);
  store_signed_integer (buffer, word_size, value);
  /* Write it down to memory */
  write_memory (addr, buffer, word_size);
  /* Free the buffer.  */
  do_cleanups (old_chain);

  return MI_CMD_DONE;
}
예제 #9
0
파일: mi-main.c 프로젝트: debrouxl/tiemu
/* 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 + NUM_PSEUDO_REGS;

  if (argc == 0)
    {
      mi_error_message = xstrprintf ("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)
    {
      mi_error_message = xstrprintf ("mi_cmd_data_write_register_values: No registers.");
      return MI_CMD_ERROR;
    }

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

  if ((argc - 1) % 2)
    {
      mi_error_message = xstrprintf ("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, register_size (current_gdbarch, regnum));
	  /* Free the buffer.  */
	  do_cleanups (old_chain);
	}
      else
	{
	  mi_error_message = xstrprintf ("bad register number");
	  return MI_CMD_ERROR;
	}
    }
  return MI_CMD_DONE;
}
예제 #10
0
static struct value *
scalar_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
{
  struct value *val;
  struct type *type1, *type2, *result_type;

  arg1 = coerce_ref (arg1);
  arg2 = coerce_ref (arg2);

  type1 = check_typedef (value_type (arg1));
  type2 = check_typedef (value_type (arg2));

  if ((TYPE_CODE (type1) != TYPE_CODE_FLT
       && TYPE_CODE (type1) != TYPE_CODE_DECFLOAT
       && !is_integral_type (type1))
      || (TYPE_CODE (type2) != TYPE_CODE_FLT
	  && TYPE_CODE (type2) != TYPE_CODE_DECFLOAT
	  && !is_integral_type (type2)))
    error (_("Argument to arithmetic operation not a number or boolean."));

  if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT
      || TYPE_CODE (type2) == TYPE_CODE_DECFLOAT)
    {
      int len_v1, len_v2, len_v;
      enum bfd_endian byte_order_v1, byte_order_v2, byte_order_v;
      gdb_byte v1[16], v2[16];
      gdb_byte v[16];

      /* If only one type is decimal float, use its type.
	 Otherwise use the bigger type.  */
      if (TYPE_CODE (type1) != TYPE_CODE_DECFLOAT)
	result_type = type2;
      else if (TYPE_CODE (type2) != TYPE_CODE_DECFLOAT)
	result_type = type1;
      else if (TYPE_LENGTH (type2) > TYPE_LENGTH (type1))
	result_type = type2;
      else
	result_type = type1;

      len_v = TYPE_LENGTH (result_type);
      byte_order_v = gdbarch_byte_order (get_type_arch (result_type));

      value_args_as_decimal (arg1, arg2, v1, &len_v1, &byte_order_v1,
					 v2, &len_v2, &byte_order_v2);

      switch (op)
	{
	case BINOP_ADD:
	case BINOP_SUB:
	case BINOP_MUL:
	case BINOP_DIV:
	case BINOP_EXP:
	  decimal_binop (op, v1, len_v1, byte_order_v1,
			     v2, len_v2, byte_order_v2,
			     v, len_v, byte_order_v);
	  break;

	default:
	  error (_("Operation not valid for decimal floating point number."));
	}

      val = value_from_decfloat (result_type, v);
    }
  else if (TYPE_CODE (type1) == TYPE_CODE_FLT
	   || TYPE_CODE (type2) == TYPE_CODE_FLT)
    {
      /* FIXME-if-picky-about-floating-accuracy: Should be doing this
         in target format.  real.c in GCC probably has the necessary
         code.  */
      DOUBLEST v1, v2, v = 0;

      v1 = value_as_double (arg1);
      v2 = value_as_double (arg2);

      switch (op)
	{
	case BINOP_ADD:
	  v = v1 + v2;
	  break;

	case BINOP_SUB:
	  v = v1 - v2;
	  break;

	case BINOP_MUL:
	  v = v1 * v2;
	  break;

	case BINOP_DIV:
	  v = v1 / v2;
	  break;

	case BINOP_EXP:
	  errno = 0;
	  v = pow (v1, v2);
	  if (errno)
	    error (_("Cannot perform exponentiation: %s"),
		   safe_strerror (errno));
	  break;

	case BINOP_MIN:
	  v = v1 < v2 ? v1 : v2;
	  break;
	      
	case BINOP_MAX:
	  v = v1 > v2 ? v1 : v2;
	  break;

	default:
	  error (_("Integer-only operation on floating point number."));
	}

      /* If only one type is float, use its type.
	 Otherwise use the bigger type.  */
      if (TYPE_CODE (type1) != TYPE_CODE_FLT)
	result_type = type2;
      else if (TYPE_CODE (type2) != TYPE_CODE_FLT)
	result_type = type1;
      else if (TYPE_LENGTH (type2) > TYPE_LENGTH (type1))
	result_type = type2;
      else
	result_type = type1;

      val = allocate_value (result_type);
      store_typed_floating (value_contents_raw (val), value_type (val), v);
    }
  else if (TYPE_CODE (type1) == TYPE_CODE_BOOL
	   || TYPE_CODE (type2) == TYPE_CODE_BOOL)
    {
      LONGEST v1, v2, v = 0;

      v1 = value_as_long (arg1);
      v2 = value_as_long (arg2);

      switch (op)
	{
	case BINOP_BITWISE_AND:
	  v = v1 & v2;
	  break;

	case BINOP_BITWISE_IOR:
	  v = v1 | v2;
	  break;

	case BINOP_BITWISE_XOR:
	  v = v1 ^ v2;
          break;
              
        case BINOP_EQUAL:
          v = v1 == v2;
          break;
          
        case BINOP_NOTEQUAL:
          v = v1 != v2;
	  break;

	default:
	  error (_("Invalid operation on booleans."));
	}

      result_type = type1;

      val = allocate_value (result_type);
      store_signed_integer (value_contents_raw (val),
			    TYPE_LENGTH (result_type),
			    gdbarch_byte_order (get_type_arch (result_type)),
			    v);
    }
  else
    /* Integral operations here.  */
    {
      /* Determine type length of the result, and if the operation should
	 be done unsigned.  For exponentiation and shift operators,
	 use the length and type of the left operand.  Otherwise,
	 use the signedness of the operand with the greater length.
	 If both operands are of equal length, use unsigned operation
	 if one of the operands is unsigned.  */
      if (op == BINOP_RSH || op == BINOP_LSH || op == BINOP_EXP)
	result_type = type1;
      else if (TYPE_LENGTH (type1) > TYPE_LENGTH (type2))
	result_type = type1;
      else if (TYPE_LENGTH (type2) > TYPE_LENGTH (type1))
	result_type = type2;
      else if (TYPE_UNSIGNED (type1))
	result_type = type1;
      else if (TYPE_UNSIGNED (type2))
	result_type = type2;
      else
	result_type = type1;

      if (TYPE_UNSIGNED (result_type))
	{
	  LONGEST v2_signed = value_as_long (arg2);
	  ULONGEST v1, v2, v = 0;

	  v1 = (ULONGEST) value_as_long (arg1);
	  v2 = (ULONGEST) v2_signed;

	  switch (op)
	    {
	    case BINOP_ADD:
	      v = v1 + v2;
	      break;

	    case BINOP_SUB:
	      v = v1 - v2;
	      break;

	    case BINOP_MUL:
	      v = v1 * v2;
	      break;

	    case BINOP_DIV:
	    case BINOP_INTDIV:
	      if (v2 != 0)
		v = v1 / v2;
	      else
		error (_("Division by zero"));
	      break;

	    case BINOP_EXP:
              v = uinteger_pow (v1, v2_signed);
	      break;

	    case BINOP_REM:
	      if (v2 != 0)
		v = v1 % v2;
	      else
		error (_("Division by zero"));
	      break;

	    case BINOP_MOD:
	      /* Knuth 1.2.4, integer only.  Note that unlike the C '%' op,
	         v1 mod 0 has a defined value, v1.  */
	      if (v2 == 0)
		{
		  v = v1;
		}
	      else
		{
		  v = v1 / v2;
		  /* Note floor(v1/v2) == v1/v2 for unsigned.  */
		  v = v1 - (v2 * v);
		}
	      break;

	    case BINOP_LSH:
	      v = v1 << v2;
	      break;

	    case BINOP_RSH:
	      v = v1 >> v2;
	      break;

	    case BINOP_BITWISE_AND:
	      v = v1 & v2;
	      break;

	    case BINOP_BITWISE_IOR:
	      v = v1 | v2;
	      break;

	    case BINOP_BITWISE_XOR:
	      v = v1 ^ v2;
	      break;

	    case BINOP_LOGICAL_AND:
	      v = v1 && v2;
	      break;

	    case BINOP_LOGICAL_OR:
	      v = v1 || v2;
	      break;

	    case BINOP_MIN:
	      v = v1 < v2 ? v1 : v2;
	      break;

	    case BINOP_MAX:
	      v = v1 > v2 ? v1 : v2;
	      break;

	    case BINOP_EQUAL:
	      v = v1 == v2;
	      break;

            case BINOP_NOTEQUAL:
              v = v1 != v2;
              break;

	    case BINOP_LESS:
	      v = v1 < v2;
	      break;

	    case BINOP_GTR:
	      v = v1 > v2;
	      break;

	    case BINOP_LEQ:
	      v = v1 <= v2;
	      break;

	    case BINOP_GEQ:
	      v = v1 >= v2;
	      break;

	    default:
	      error (_("Invalid binary operation on numbers."));
	    }

	  val = allocate_value (result_type);
	  store_unsigned_integer (value_contents_raw (val),
				  TYPE_LENGTH (value_type (val)),
				  gdbarch_byte_order
				    (get_type_arch (result_type)),
				  v);
	}
      else
	{
	  LONGEST v1, v2, v = 0;

	  v1 = value_as_long (arg1);
	  v2 = value_as_long (arg2);

	  switch (op)
	    {
	    case BINOP_ADD:
	      v = v1 + v2;
	      break;

	    case BINOP_SUB:
	      v = v1 - v2;
	      break;

	    case BINOP_MUL:
	      v = v1 * v2;
	      break;

	    case BINOP_DIV:
	    case BINOP_INTDIV:
	      if (v2 != 0)
		v = v1 / v2;
	      else
		error (_("Division by zero"));
              break;

	    case BINOP_EXP:
              v = integer_pow (v1, v2);
	      break;

	    case BINOP_REM:
	      if (v2 != 0)
		v = v1 % v2;
	      else
		error (_("Division by zero"));
	      break;

	    case BINOP_MOD:
	      /* Knuth 1.2.4, integer only.  Note that unlike the C '%' op,
	         X mod 0 has a defined value, X.  */
	      if (v2 == 0)
		{
		  v = v1;
		}
	      else
		{
		  v = v1 / v2;
		  /* Compute floor.  */
		  if (TRUNCATION_TOWARDS_ZERO && (v < 0) && ((v1 % v2) != 0))
		    {
		      v--;
		    }
		  v = v1 - (v2 * v);
		}
	      break;

	    case BINOP_LSH:
	      v = v1 << v2;
	      break;

	    case BINOP_RSH:
	      v = v1 >> v2;
	      break;

	    case BINOP_BITWISE_AND:
	      v = v1 & v2;
	      break;

	    case BINOP_BITWISE_IOR:
	      v = v1 | v2;
	      break;

	    case BINOP_BITWISE_XOR:
	      v = v1 ^ v2;
	      break;

	    case BINOP_LOGICAL_AND:
	      v = v1 && v2;
	      break;

	    case BINOP_LOGICAL_OR:
	      v = v1 || v2;
	      break;

	    case BINOP_MIN:
	      v = v1 < v2 ? v1 : v2;
	      break;

	    case BINOP_MAX:
	      v = v1 > v2 ? v1 : v2;
	      break;

	    case BINOP_EQUAL:
	      v = v1 == v2;
	      break;

            case BINOP_NOTEQUAL:
              v = v1 != v2;
              break;

	    case BINOP_LESS:
	      v = v1 < v2;
	      break;

	    case BINOP_GTR:
	      v = v1 > v2;
	      break;

	    case BINOP_LEQ:
	      v = v1 <= v2;
	      break;

	    case BINOP_GEQ:
	      v = v1 >= v2;
	      break;

	    default:
	      error (_("Invalid binary operation on numbers."));
	    }

	  val = allocate_value (result_type);
	  store_signed_integer (value_contents_raw (val),
				TYPE_LENGTH (value_type (val)),
				gdbarch_byte_order
				  (get_type_arch (result_type)),
				v);
	}
    }
예제 #11
0
static struct value *
scalar_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
{
  struct value *val;
  struct type *type1, *type2, *result_type;

  arg1 = coerce_ref (arg1);
  arg2 = coerce_ref (arg2);

  type1 = check_typedef (value_type (arg1));
  type2 = check_typedef (value_type (arg2));

  if ((!is_floating_value (arg1) && !is_integral_type (type1))
      || (!is_floating_value (arg2) && !is_integral_type (type2)))
    error (_("Argument to arithmetic operation not a number or boolean."));

  if (is_floating_type (type1) || is_floating_type (type2))
    {
      /* If only one type is floating-point, use its type.
	 Otherwise use the bigger type.  */
      if (!is_floating_type (type1))
	result_type = type2;
      else if (!is_floating_type (type2))
	result_type = type1;
      else if (TYPE_LENGTH (type2) > TYPE_LENGTH (type1))
	result_type = type2;
      else
	result_type = type1;

      val = allocate_value (result_type);

      struct type *eff_type_v1, *eff_type_v2;
      gdb::byte_vector v1, v2;
      v1.resize (TYPE_LENGTH (result_type));
      v2.resize (TYPE_LENGTH (result_type));

      value_args_as_target_float (arg1, arg2,
				  v1.data (), &eff_type_v1,
				  v2.data (), &eff_type_v2);
      target_float_binop (op, v1.data (), eff_type_v1,
			      v2.data (), eff_type_v2,
			      value_contents_raw (val), result_type);
    }
  else if (TYPE_CODE (type1) == TYPE_CODE_BOOL
	   || TYPE_CODE (type2) == TYPE_CODE_BOOL)
    {
      LONGEST v1, v2, v = 0;

      v1 = value_as_long (arg1);
      v2 = value_as_long (arg2);

      switch (op)
	{
	case BINOP_BITWISE_AND:
	  v = v1 & v2;
	  break;

	case BINOP_BITWISE_IOR:
	  v = v1 | v2;
	  break;

	case BINOP_BITWISE_XOR:
	  v = v1 ^ v2;
          break;
              
        case BINOP_EQUAL:
          v = v1 == v2;
          break;
          
        case BINOP_NOTEQUAL:
          v = v1 != v2;
	  break;

	default:
	  error (_("Invalid operation on booleans."));
	}

      result_type = type1;

      val = allocate_value (result_type);
      store_signed_integer (value_contents_raw (val),
			    TYPE_LENGTH (result_type),
			    gdbarch_byte_order (get_type_arch (result_type)),
			    v);
    }
  else
    /* Integral operations here.  */
    {
      /* Determine type length of the result, and if the operation should
	 be done unsigned.  For exponentiation and shift operators,
	 use the length and type of the left operand.  Otherwise,
	 use the signedness of the operand with the greater length.
	 If both operands are of equal length, use unsigned operation
	 if one of the operands is unsigned.  */
      if (op == BINOP_RSH || op == BINOP_LSH || op == BINOP_EXP)
	result_type = type1;
      else if (TYPE_LENGTH (type1) > TYPE_LENGTH (type2))
	result_type = type1;
      else if (TYPE_LENGTH (type2) > TYPE_LENGTH (type1))
	result_type = type2;
      else if (TYPE_UNSIGNED (type1))
	result_type = type1;
      else if (TYPE_UNSIGNED (type2))
	result_type = type2;
      else
	result_type = type1;

      if (TYPE_UNSIGNED (result_type))
	{
	  LONGEST v2_signed = value_as_long (arg2);
	  ULONGEST v1, v2, v = 0;

	  v1 = (ULONGEST) value_as_long (arg1);
	  v2 = (ULONGEST) v2_signed;

	  switch (op)
	    {
	    case BINOP_ADD:
	      v = v1 + v2;
	      break;

	    case BINOP_SUB:
	      v = v1 - v2;
	      break;

	    case BINOP_MUL:
	      v = v1 * v2;
	      break;

	    case BINOP_DIV:
	    case BINOP_INTDIV:
	      if (v2 != 0)
		v = v1 / v2;
	      else
		error (_("Division by zero"));
	      break;

	    case BINOP_EXP:
              v = uinteger_pow (v1, v2_signed);
	      break;

	    case BINOP_REM:
	      if (v2 != 0)
		v = v1 % v2;
	      else
		error (_("Division by zero"));
	      break;

	    case BINOP_MOD:
	      /* Knuth 1.2.4, integer only.  Note that unlike the C '%' op,
	         v1 mod 0 has a defined value, v1.  */
	      if (v2 == 0)
		{
		  v = v1;
		}
	      else
		{
		  v = v1 / v2;
		  /* Note floor(v1/v2) == v1/v2 for unsigned.  */
		  v = v1 - (v2 * v);
		}
	      break;

	    case BINOP_LSH:
	      v = v1 << v2;
	      break;

	    case BINOP_RSH:
	      v = v1 >> v2;
	      break;

	    case BINOP_BITWISE_AND:
	      v = v1 & v2;
	      break;

	    case BINOP_BITWISE_IOR:
	      v = v1 | v2;
	      break;

	    case BINOP_BITWISE_XOR:
	      v = v1 ^ v2;
	      break;

	    case BINOP_LOGICAL_AND:
	      v = v1 && v2;
	      break;

	    case BINOP_LOGICAL_OR:
	      v = v1 || v2;
	      break;

	    case BINOP_MIN:
	      v = v1 < v2 ? v1 : v2;
	      break;

	    case BINOP_MAX:
	      v = v1 > v2 ? v1 : v2;
	      break;

	    case BINOP_EQUAL:
	      v = v1 == v2;
	      break;

            case BINOP_NOTEQUAL:
              v = v1 != v2;
              break;

	    case BINOP_LESS:
	      v = v1 < v2;
	      break;

	    case BINOP_GTR:
	      v = v1 > v2;
	      break;

	    case BINOP_LEQ:
	      v = v1 <= v2;
	      break;

	    case BINOP_GEQ:
	      v = v1 >= v2;
	      break;

	    default:
	      error (_("Invalid binary operation on numbers."));
	    }

	  val = allocate_value (result_type);
	  store_unsigned_integer (value_contents_raw (val),
				  TYPE_LENGTH (value_type (val)),
				  gdbarch_byte_order
				    (get_type_arch (result_type)),
				  v);
	}
      else
	{
	  LONGEST v1, v2, v = 0;

	  v1 = value_as_long (arg1);
	  v2 = value_as_long (arg2);

	  switch (op)
	    {
	    case BINOP_ADD:
	      v = v1 + v2;
	      break;

	    case BINOP_SUB:
	      v = v1 - v2;
	      break;

	    case BINOP_MUL:
	      v = v1 * v2;
	      break;

	    case BINOP_DIV:
	    case BINOP_INTDIV:
	      if (v2 != 0)
		v = v1 / v2;
	      else
		error (_("Division by zero"));
              break;

	    case BINOP_EXP:
              v = integer_pow (v1, v2);
	      break;

	    case BINOP_REM:
	      if (v2 != 0)
		v = v1 % v2;
	      else
		error (_("Division by zero"));
	      break;

	    case BINOP_MOD:
	      /* Knuth 1.2.4, integer only.  Note that unlike the C '%' op,
	         X mod 0 has a defined value, X.  */
	      if (v2 == 0)
		{
		  v = v1;
		}
	      else
		{
		  v = v1 / v2;
		  /* Compute floor.  */
		  if (TRUNCATION_TOWARDS_ZERO && (v < 0) && ((v1 % v2) != 0))
		    {
		      v--;
		    }
		  v = v1 - (v2 * v);
		}
	      break;

	    case BINOP_LSH:
	      v = v1 << v2;
	      break;

	    case BINOP_RSH:
	      v = v1 >> v2;
	      break;

	    case BINOP_BITWISE_AND:
	      v = v1 & v2;
	      break;

	    case BINOP_BITWISE_IOR:
	      v = v1 | v2;
	      break;

	    case BINOP_BITWISE_XOR:
	      v = v1 ^ v2;
	      break;

	    case BINOP_LOGICAL_AND:
	      v = v1 && v2;
	      break;

	    case BINOP_LOGICAL_OR:
	      v = v1 || v2;
	      break;

	    case BINOP_MIN:
	      v = v1 < v2 ? v1 : v2;
	      break;

	    case BINOP_MAX:
	      v = v1 > v2 ? v1 : v2;
	      break;

	    case BINOP_EQUAL:
	      v = v1 == v2;
	      break;

            case BINOP_NOTEQUAL:
              v = v1 != v2;
              break;

	    case BINOP_LESS:
	      v = v1 < v2;
	      break;

	    case BINOP_GTR:
	      v = v1 > v2;
	      break;

	    case BINOP_LEQ:
	      v = v1 <= v2;
	      break;

	    case BINOP_GEQ:
	      v = v1 >= v2;
	      break;

	    default:
	      error (_("Invalid binary operation on numbers."));
	    }

	  val = allocate_value (result_type);
	  store_signed_integer (value_contents_raw (val),
				TYPE_LENGTH (value_type (val)),
				gdbarch_byte_order
				  (get_type_arch (result_type)),
				v);
	}
    }