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); } }
/* 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); }
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); }
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)); } }
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; }
/* 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; }
/* 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; }
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); } }
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); } }