/* Target-dependent code for the MIPS architecture, for GDB, the GNU Debugger.
- Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998
- Free Software Foundation, Inc.
+ Copyright 1988-1999, Free Software Foundation, Inc.
Contributed by Alessandro Forin(af@cs.cmu.edu) at CMU
and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin.
#include "target.h"
#include "opcode/mips.h"
+#include "elf/mips.h"
+#include "elf-bfd.h"
+
struct frame_extra_info
{
#endif
+/* MIPS specific per-architecture information */
+struct gdbarch_tdep
+ {
+ /* from the elf header */
+ int elf_flags;
+ /* mips options */
+ int mips_eabi;
+ enum mips_fpu_type mips_fpu_type;
+ int mips_last_arg_regnum;
+ int mips_last_fp_arg_regnum;
+ int mips_saved_regsize;
+ int mips_fp_register_double;
+ };
+
+#if GDB_MULTI_ARCH
+#undef MIPS_EABI
+#define MIPS_EABI (gdbarch_tdep (current_gdbarch)->mips_eabi)
+#endif
+
+#if GDB_MULTI_ARCH
+#undef MIPS_LAST_FP_ARG_REGNUM
+#define MIPS_LAST_FP_ARG_REGNUM (gdbarch_tdep (current_gdbarch)->mips_last_fp_arg_regnum)
+#endif
+
+#if GDB_MULTI_ARCH
+#undef MIPS_LAST_ARG_REGNUM
+#define MIPS_LAST_ARG_REGNUM (gdbarch_tdep (current_gdbarch)->mips_last_arg_regnum)
+#endif
+
+#if GDB_MULTI_ARCH
+#undef MIPS_FPU_TYPE
+#define MIPS_FPU_TYPE (gdbarch_tdep (current_gdbarch)->mips_fpu_type)
+#endif
+
+#if GDB_MULTI_ARCH
+#undef MIPS_SAVED_REGSIZE
+#define MIPS_SAVED_REGSIZE (gdbarch_tdep (current_gdbarch)->mips_saved_regsize)
+#endif
+
+/* Indicate that the ABI makes use of double-precision registers
+ provided by the FPU (rather than combining pairs of registers to
+ form double-precision values). Do not use "TARGET_IS_MIPS64" to
+ determine if the ABI is using double-precision registers. See also
+ MIPS_FPU_TYPE. */
+#if GDB_MULTI_ARCH
+#undef FP_REGISTER_DOUBLE
+#define FP_REGISTER_DOUBLE (gdbarch_tdep (current_gdbarch)->mips_fp_register_double)
+#endif
+
+
#define VM_MIN_ADDRESS (CORE_ADDR)0x400000
#if 0
static CORE_ADDR read_next_frame_reg PARAMS ((struct frame_info *, int));
-void mips_set_processor_type_command PARAMS ((char *, int));
-
int mips_set_processor_type PARAMS ((char *));
static void mips_show_processor_type_command PARAMS ((char *, int));
&& fi->extra_info
&& fi->extra_info->proc_desc
&& fi->extra_info->proc_desc->pdr.framereg < NUM_REGS)
- printf_filtered (" frame pointer is at %s+%d\n",
+ printf_filtered (" frame pointer is at %s+%s\n",
REGISTER_NAME (fi->extra_info->proc_desc->pdr.framereg),
- fi->extra_info->proc_desc->pdr.frameoffset);
+ paddr_d (fi->extra_info->proc_desc->pdr.frameoffset));
+}
+
+/* Convert between RAW and VIRTUAL registers. The RAW register size
+ defines the remote-gdb packet. */
+
+static int mips64_transfers_32bit_regs_p = 0;
+
+int
+mips_register_raw_size (reg_nr)
+ int reg_nr;
+{
+ if (mips64_transfers_32bit_regs_p)
+ return REGISTER_VIRTUAL_SIZE (reg_nr);
+ else
+ return MIPS_REGSIZE;
+}
+
+int
+mips_register_convertible (reg_nr)
+ int reg_nr;
+{
+ if (mips64_transfers_32bit_regs_p)
+ return 0;
+ else
+ return (REGISTER_RAW_SIZE (reg_nr) > REGISTER_VIRTUAL_SIZE (reg_nr));
+}
+
+void
+mips_register_convert_to_virtual (n, virtual_type, raw_buf, virt_buf)
+ int n;
+ struct type *virtual_type;
+ char *raw_buf;
+ char *virt_buf;
+{
+ if (TARGET_BYTE_ORDER == BIG_ENDIAN)
+ memcpy (virt_buf,
+ raw_buf + (REGISTER_RAW_SIZE (n) - TYPE_LENGTH (virtual_type)),
+ TYPE_LENGTH (virtual_type));
+ else
+ memcpy (virt_buf,
+ raw_buf,
+ TYPE_LENGTH (virtual_type));
+}
+
+void
+mips_register_convert_to_raw (virtual_type, n, virt_buf, raw_buf)
+ struct type *virtual_type;
+ int n;
+ char *virt_buf;
+ char *raw_buf;
+{
+ memset (raw_buf, 0, REGISTER_RAW_SIZE (n));
+ if (TARGET_BYTE_ORDER == BIG_ENDIAN)
+ memcpy (raw_buf + (REGISTER_RAW_SIZE (n) - TYPE_LENGTH (virtual_type)),
+ virt_buf,
+ TYPE_LENGTH (virtual_type));
+ else
+ memcpy (raw_buf,
+ virt_buf,
+ TYPE_LENGTH (virtual_type));
}
/* Should the upper word of 64-bit addresses be zeroed? */
print_unpack (char *comment,
struct upk_mips16 *u)
{
- printf ("%s %04x ,f(%d) off(%08x) (x(%x) y(%x)\n",
- comment, u->inst, u->fmt, u->offset, u->regx, u->regy);
+ printf ("%s %04x ,f(%d) off(%s) (x(%x) y(%x)\n",
+ comment, u->inst, u->fmt, paddr (u->offset), u->regx, u->regy);
}
/* The EXT-I, EXT-ri nad EXT-I8 instructions all have the same
if (fi->saved_regs == NULL)
mips_find_saved_regs (fi);
if (fi->saved_regs[regno])
- return read_memory_integer (fi->saved_regs[regno], MIPS_SAVED_REGSIZE);
+ return read_memory_integer (ADDR_BITS_REMOVE (fi->saved_regs[regno]), MIPS_SAVED_REGSIZE);
}
}
return read_register (regno);
{
/* This is a floating point value that fits entirely
in a single register. */
+ /* On 32 bit ABI's the float_argreg is further adjusted
+ above to ensure that it is even register aligned. */
CORE_ADDR regval = extract_address (val, len);
write_register (float_argreg++, regval);
if (!MIPS_EABI)
{
+ /* CAGNEY: 32 bit MIPS ABI's always reserve two FP
+ registers for each argument. The below is (my
+ guess) to ensure that the corresponding integer
+ register has reserved the same space. */
write_register (argreg, regval);
argreg += FP_REGISTER_DOUBLE ? 1 : 2;
}
if (read_relative_register_raw_bytes (regnum, raw_buffer))
error ("can't read register %d (%s)", regnum, REGISTER_NAME (regnum));
/* pad small registers */
- for (byte = 0; byte < (MIPS_REGSIZE - REGISTER_RAW_SIZE (regnum)); byte++)
+ for (byte = 0; byte < (MIPS_REGSIZE - REGISTER_VIRTUAL_SIZE (regnum)); byte++)
printf_filtered (" ");
/* Now print the register value in hex, endian order. */
if (TARGET_BYTE_ORDER == BIG_ENDIAN)
- for (byte = 0; byte < REGISTER_RAW_SIZE (regnum); byte++)
+ for (byte = REGISTER_RAW_SIZE (regnum) - REGISTER_VIRTUAL_SIZE (regnum);
+ byte < REGISTER_RAW_SIZE (regnum);
+ byte++)
printf_filtered ("%02x", (unsigned char) raw_buffer[byte]);
else
- for (byte = REGISTER_RAW_SIZE (regnum) - 1; byte >= 0; byte--)
+ for (byte = REGISTER_VIRTUAL_SIZE (regnum) - 1;
+ byte >= 0;
+ byte--)
printf_filtered ("%02x", (unsigned char) raw_buffer[byte]);
printf_filtered (" ");
col++;
{
mips_fpu_type = MIPS_FPU_SINGLE;
mips_fpu_type_auto = 0;
+ if (GDB_MULTI_ARCH)
+ {
+ gdbarch_tdep (current_gdbarch)->mips_fpu_type = MIPS_FPU_SINGLE;
+ }
}
static void set_mipsfpu_double_command PARAMS ((char *, int));
{
mips_fpu_type = MIPS_FPU_DOUBLE;
mips_fpu_type_auto = 0;
+ if (GDB_MULTI_ARCH)
+ {
+ gdbarch_tdep (current_gdbarch)->mips_fpu_type = MIPS_FPU_DOUBLE;
+ }
}
static void set_mipsfpu_none_command PARAMS ((char *, int));
{
mips_fpu_type = MIPS_FPU_NONE;
mips_fpu_type_auto = 0;
+ if (GDB_MULTI_ARCH)
+ {
+ gdbarch_tdep (current_gdbarch)->mips_fpu_type = MIPS_FPU_NONE;
+ }
}
static void set_mipsfpu_auto_command PARAMS ((char *, int));
}
+
+static gdbarch_init_ftype mips_gdbarch_init;
+static struct gdbarch *
+mips_gdbarch_init (info, arches)
+ struct gdbarch_info info;
+ struct gdbarch_list *arches;
+{
+ static LONGEST mips_call_dummy_words[] =
+ {0};
+ struct gdbarch *gdbarch;
+ struct gdbarch_tdep *tdep;
+ int elf_flags;
+ char *ef_mips_abi;
+ int ef_mips_bitptrs;
+ int ef_mips_arch;
+
+ /* Extract the elf_flags if available */
+ if (info.abfd != NULL
+ && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+ elf_flags = elf_elfheader (info.abfd)->e_flags;
+ else
+ elf_flags = 0;
+
+ /* try to find a pre-existing architecture */
+ for (arches = gdbarch_list_lookup_by_info (arches, &info);
+ arches != NULL;
+ arches = gdbarch_list_lookup_by_info (arches->next, &info))
+ {
+ /* MIPS needs to be pedantic about which ABI the object is
+ using. */
+ if (gdbarch_tdep (current_gdbarch)->elf_flags != elf_flags)
+ continue;
+ return arches->gdbarch;
+ }
+
+ /* Need a new architecture. Fill in a target specific vector. */
+ tdep = (struct gdbarch_tdep *) xmalloc (sizeof (struct gdbarch_tdep));
+ gdbarch = gdbarch_alloc (&info, tdep);
+ tdep->elf_flags = elf_flags;
+
+ /* Initially set everything according to the ABI. */
+ set_gdbarch_short_bit (gdbarch, 16);
+ set_gdbarch_int_bit (gdbarch, 32);
+ set_gdbarch_float_bit (gdbarch, 32);
+ set_gdbarch_double_bit (gdbarch, 64);
+ set_gdbarch_long_double_bit (gdbarch, 64);
+ switch ((elf_flags & EF_MIPS_ABI))
+ {
+ case E_MIPS_ABI_O32:
+ ef_mips_abi = "o32";
+ tdep->mips_eabi = 0;
+ tdep->mips_saved_regsize = 4;
+ tdep->mips_fp_register_double = 0;
+ set_gdbarch_long_bit (gdbarch, 32);
+ set_gdbarch_ptr_bit (gdbarch, 32);
+ set_gdbarch_long_long_bit (gdbarch, 64);
+ break;
+ case E_MIPS_ABI_O64:
+ ef_mips_abi = "o64";
+ tdep->mips_eabi = 0;
+ tdep->mips_saved_regsize = 8;
+ tdep->mips_fp_register_double = 1;
+ set_gdbarch_long_bit (gdbarch, 32);
+ set_gdbarch_ptr_bit (gdbarch, 32);
+ set_gdbarch_long_long_bit (gdbarch, 64);
+ break;
+ case E_MIPS_ABI_EABI32:
+ ef_mips_abi = "eabi32";
+ tdep->mips_eabi = 1;
+ tdep->mips_saved_regsize = 4;
+ tdep->mips_fp_register_double = 0;
+ set_gdbarch_long_bit (gdbarch, 32);
+ set_gdbarch_ptr_bit (gdbarch, 32);
+ set_gdbarch_long_long_bit (gdbarch, 64);
+ break;
+ case E_MIPS_ABI_EABI64:
+ ef_mips_abi = "eabi64";
+ tdep->mips_eabi = 1;
+ tdep->mips_saved_regsize = 8;
+ tdep->mips_fp_register_double = 1;
+ set_gdbarch_long_bit (gdbarch, 64);
+ set_gdbarch_ptr_bit (gdbarch, 64);
+ set_gdbarch_long_long_bit (gdbarch, 64);
+ break;
+ default:
+ ef_mips_abi = "default";
+ tdep->mips_eabi = 0;
+ tdep->mips_saved_regsize = MIPS_REGSIZE;
+ tdep->mips_fp_register_double = (REGISTER_VIRTUAL_SIZE (FP0_REGNUM) == 8);
+ set_gdbarch_long_bit (gdbarch, 32);
+ set_gdbarch_ptr_bit (gdbarch, 32);
+ set_gdbarch_long_long_bit (gdbarch, 64);
+ break;
+ }
+
+ /* determine the ISA */
+ switch (elf_flags & EF_MIPS_ARCH)
+ {
+ case E_MIPS_ARCH_1:
+ ef_mips_arch = 1;
+ break;
+ case E_MIPS_ARCH_2:
+ ef_mips_arch = 2;
+ break;
+ case E_MIPS_ARCH_3:
+ ef_mips_arch = 3;
+ break;
+ case E_MIPS_ARCH_4:
+ ef_mips_arch = 0;
+ break;
+ default:
+ break;
+ }
+
+#if 0
+ /* determine the size of a pointer */
+ if ((elf_flags & EF_MIPS_32BITPTRS))
+ {
+ ef_mips_bitptrs = 32;
+ }
+ else if ((elf_flags & EF_MIPS_64BITPTRS))
+ {
+ ef_mips_bitptrs = 64;
+ }
+ else
+ {
+ ef_mips_bitptrs = 0;
+ }
+#endif
+
+ /* Select either of the two alternative ABI's */
+ if (tdep->mips_eabi)
+ {
+ /* EABI uses R4 through R11 for args */
+ tdep->mips_last_arg_regnum = 11;
+ /* EABI uses F12 through F19 for args */
+ tdep->mips_last_fp_arg_regnum = FP0_REGNUM + 19;
+ }
+ else
+ {
+ /* old ABI uses R4 through R7 for args */
+ tdep->mips_last_arg_regnum = 7;
+ /* old ABI uses F12 through F15 for args */
+ tdep->mips_last_fp_arg_regnum = FP0_REGNUM + 15;
+ }
+
+ /* enable/disable the MIPS FPU */
+ if (!mips_fpu_type_auto)
+ tdep->mips_fpu_type = mips_fpu_type;
+ else if (info.bfd_arch_info != NULL
+ && info.bfd_arch_info->arch == bfd_arch_mips)
+ switch (info.bfd_arch_info->mach)
+ {
+ case bfd_mach_mips4100:
+ tdep->mips_fpu_type = MIPS_FPU_NONE;
+ break;
+ default:
+ tdep->mips_fpu_type = MIPS_FPU_DOUBLE;
+ break;
+ }
+ else
+ tdep->mips_fpu_type = MIPS_FPU_DOUBLE;
+
+ /* MIPS version of register names. NOTE: At present the MIPS
+ register name management is part way between the old -
+ #undef/#define REGISTER_NAMES and the new REGISTER_NAME(nr).
+ Further work on it is required. */
+ set_gdbarch_register_name (gdbarch, mips_register_name);
+ set_gdbarch_read_pc (gdbarch, generic_target_read_pc);
+ set_gdbarch_write_pc (gdbarch, generic_target_write_pc);
+ set_gdbarch_read_fp (gdbarch, generic_target_read_fp);
+ set_gdbarch_write_fp (gdbarch, generic_target_write_fp);
+ set_gdbarch_read_sp (gdbarch, generic_target_read_sp);
+ set_gdbarch_write_sp (gdbarch, generic_target_write_sp);
+
+ /* Initialize a frame */
+ set_gdbarch_init_extra_frame_info (gdbarch, mips_init_extra_frame_info);
+
+ /* MIPS version of CALL_DUMMY */
+
+ set_gdbarch_call_dummy_p (gdbarch, 1);
+ set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0);
+ set_gdbarch_use_generic_dummy_frames (gdbarch, 0);
+ set_gdbarch_call_dummy_location (gdbarch, AT_ENTRY_POINT);
+ set_gdbarch_call_dummy_address (gdbarch, mips_call_dummy_address);
+ set_gdbarch_call_dummy_start_offset (gdbarch, 0);
+ set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 1);
+ set_gdbarch_call_dummy_breakpoint_offset (gdbarch, 0);
+ set_gdbarch_call_dummy_length (gdbarch, 0);
+ set_gdbarch_pc_in_call_dummy (gdbarch, pc_in_call_dummy_at_entry_point);
+ set_gdbarch_call_dummy_words (gdbarch, mips_call_dummy_words);
+ set_gdbarch_sizeof_call_dummy_words (gdbarch, sizeof (mips_call_dummy_words));
+ set_gdbarch_push_return_address (gdbarch, mips_push_return_address);
+ set_gdbarch_push_arguments (gdbarch, mips_push_arguments);
+ set_gdbarch_register_convertible (gdbarch, generic_register_convertible_not);
+
+ set_gdbarch_frame_chain_valid (gdbarch, default_frame_chain_valid);
+ set_gdbarch_get_saved_register (gdbarch, default_get_saved_register);
+
+ if (gdbarch_debug)
+ {
+ fprintf_unfiltered (gdb_stderr,
+ "mips_gdbarch_init: (info)elf_flags = 0x%x\n",
+ elf_flags);
+ fprintf_unfiltered (gdb_stderr,
+ "mips_gdbarch_init: (info)ef_mips_abi = %s\n",
+ ef_mips_abi);
+ fprintf_unfiltered (gdb_stderr,
+ "mips_gdbarch_init: (info)ef_mips_arch = %d\n",
+ ef_mips_arch);
+ fprintf_unfiltered (gdb_stderr,
+ "mips_gdbarch_init: (info)ef_mips_bitptrs = %d\n",
+ ef_mips_bitptrs);
+ fprintf_unfiltered (gdb_stderr,
+ "mips_gdbarch_init: MIPS_EABI = %d\n",
+ tdep->mips_eabi);
+ fprintf_unfiltered (gdb_stderr,
+ "mips_gdbarch_init: MIPS_LAST_ARG_REGNUM = %d\n",
+ tdep->mips_last_arg_regnum);
+ fprintf_unfiltered (gdb_stderr,
+ "mips_gdbarch_init: MIPS_LAST_FP_ARG_REGNUM = %d (%d)\n",
+ tdep->mips_last_fp_arg_regnum,
+ tdep->mips_last_fp_arg_regnum - FP0_REGNUM);
+ fprintf_unfiltered (gdb_stderr,
+ "mips_gdbarch_init: tdep->mips_fpu_type = %d (%s)\n",
+ tdep->mips_fpu_type,
+ (tdep->mips_fpu_type == MIPS_FPU_NONE ? "none"
+ : tdep->mips_fpu_type == MIPS_FPU_SINGLE ? "single"
+ : tdep->mips_fpu_type == MIPS_FPU_DOUBLE ? "double"
+ : "???"));
+ fprintf_unfiltered (gdb_stderr,
+ "mips_gdbarch_init: tdep->mips_saved_regsize = %d\n",
+ tdep->mips_saved_regsize);
+ fprintf_unfiltered (gdb_stderr,
+ "mips_gdbarch_init: tdep->mips_fp_register_double = %d (%s)\n",
+ tdep->mips_fp_register_double,
+ (tdep->mips_fp_register_double ? "true" : "false"));
+ }
+
+ return gdbarch;
+}
+
+
void
_initialize_mips_tdep ()
{
static struct cmd_list_element *mipsfpulist = NULL;
struct cmd_list_element *c;
+ if (GDB_MULTI_ARCH)
+ register_gdbarch_init (bfd_arch_mips, mips_gdbarch_init);
if (!tm_print_insn) /* Someone may have already set it */
tm_print_insn = gdb_print_insn_mips;
"Show current use of MIPS floating-point coprocessor target.",
&showlist);
+#if !GDB_MULTI_ARCH
c = add_set_cmd ("processor", class_support, var_string_noescape,
(char *) &tmp_mips_processor_type,
"Set the type of MIPS processor in use.\n\
tmp_mips_processor_type = strsave (DEFAULT_MIPS_TYPE);
mips_set_processor_type_command (strsave (DEFAULT_MIPS_TYPE), 0);
+#endif
/* We really would like to have both "0" and "unlimited" work, but
command.c doesn't deal with that. So make it a var_zinteger
Use \"on\" to enable the masking, and \"off\" to disable it.\n\
Without an argument, zeroing of upper address bits is enabled.", &setlist),
&showlist);
+
+ /* Allow the user to control the size of 32 bit registers within the
+ raw remote packet. */
+ add_show_from_set (add_set_cmd ("remote-mips64-transfers-32bit-regs",
+ class_obscure,
+ var_boolean,
+ (char *)&mips64_transfers_32bit_regs_p, "\
+Set compatibility with MIPS targets that transfers 32 and 64 bit quantities.\n\
+Use \"on\" to enable backward compatibility with older MIPS 64 GDB+target\n\
+that would transfer 32 bits for some registers (e.g. SR, FSR) and\n\
+64 bits for others. Use \"off\" to disable compatibility mode",
+ &setlist),
+ &showlist);
}