+/* Old-style breakpoint macros.
+ The IDT board uses an unusual breakpoint value, and sometimes gets
+ confused when it sees the usual MIPS breakpoint instruction. */
+
+#define BIG_BREAKPOINT {0, 0x5, 0, 0xd}
+#define LITTLE_BREAKPOINT {0xd, 0, 0x5, 0}
+#define PMON_BIG_BREAKPOINT {0, 0, 0, 0xd}
+#define PMON_LITTLE_BREAKPOINT {0xd, 0, 0, 0}
+#define IDT_BIG_BREAKPOINT {0, 0, 0x0a, 0xd}
+#define IDT_LITTLE_BREAKPOINT {0xd, 0x0a, 0, 0}
+#define MIPS16_BIG_BREAKPOINT {0xe8, 0xa5}
+#define MIPS16_LITTLE_BREAKPOINT {0xa5, 0xe8}
+
+/* This function implements the BREAKPOINT_FROM_PC macro. It uses the program
+ counter value to determine whether a 16- or 32-bit breakpoint should be
+ used. It returns a pointer to a string of bytes that encode a breakpoint
+ instruction, stores the length of the string to *lenptr, and adjusts pc
+ (if necessary) to point to the actual memory location where the
+ breakpoint should be inserted. */
+
+unsigned char *
+mips_breakpoint_from_pc (pcptr, lenptr)
+ CORE_ADDR *pcptr;
+ int *lenptr;
+{
+ if (TARGET_BYTE_ORDER == BIG_ENDIAN)
+ {
+ if (pc_is_mips16 (*pcptr))
+ {
+ static char mips16_big_breakpoint[] = MIPS16_BIG_BREAKPOINT;
+ *pcptr = UNMAKE_MIPS16_ADDR (*pcptr);
+ *lenptr = sizeof (mips16_big_breakpoint);
+ return mips16_big_breakpoint;
+ }
+ else
+ {
+ static char big_breakpoint[] = BIG_BREAKPOINT;
+ static char pmon_big_breakpoint[] = PMON_BIG_BREAKPOINT;
+ static char idt_big_breakpoint[] = IDT_BIG_BREAKPOINT;
+
+ *lenptr = sizeof (big_breakpoint);
+
+ if (strcmp (target_shortname, "mips") == 0)
+ return idt_big_breakpoint;
+ else if (strcmp (target_shortname, "ddb") == 0
+ || strcmp (target_shortname, "pmon") == 0
+ || strcmp (target_shortname, "lsi") == 0)
+ return pmon_big_breakpoint;
+ else
+ return big_breakpoint;
+ }
+ }
+ else
+ {
+ if (pc_is_mips16 (*pcptr))
+ {
+ static char mips16_little_breakpoint[] = MIPS16_LITTLE_BREAKPOINT;
+ *pcptr = UNMAKE_MIPS16_ADDR (*pcptr);
+ *lenptr = sizeof (mips16_little_breakpoint);
+ return mips16_little_breakpoint;
+ }
+ else
+ {
+ static char little_breakpoint[] = LITTLE_BREAKPOINT;
+ static char pmon_little_breakpoint[] = PMON_LITTLE_BREAKPOINT;
+ static char idt_little_breakpoint[] = IDT_LITTLE_BREAKPOINT;
+
+ *lenptr = sizeof (little_breakpoint);
+
+ if (strcmp (target_shortname, "mips") == 0)
+ return idt_little_breakpoint;
+ else if (strcmp (target_shortname, "ddb") == 0
+ || strcmp (target_shortname, "pmon") == 0
+ || strcmp (target_shortname, "lsi") == 0)
+ return pmon_little_breakpoint;
+ else
+ return little_breakpoint;
+ }
+ }
+}
+
+/* If PC is in a mips16 call or return stub, return the address of the target
+ PC, which is either the callee or the caller. There are several
+ cases which must be handled:
+
+ * If the PC is in __mips16_ret_{d,s}f, this is a return stub and the
+ target PC is in $31 ($ra).
+ * If the PC is in __mips16_call_stub_{1..10}, this is a call stub
+ and the target PC is in $2.
+ * If the PC at the start of __mips16_call_stub_{s,d}f_{0..10}, i.e.
+ before the jal instruction, this is effectively a call stub
+ and the the target PC is in $2. Otherwise this is effectively
+ a return stub and the target PC is in $18.
+
+ See the source code for the stubs in gcc/config/mips/mips16.S for
+ gory details.
+
+ This function implements the SKIP_TRAMPOLINE_CODE macro.
+ */
+
+CORE_ADDR
+mips_skip_stub (pc)
+ CORE_ADDR pc;
+{
+ char *name;
+ CORE_ADDR start_addr;
+
+ /* Find the starting address and name of the function containing the PC. */
+ if (find_pc_partial_function (pc, &name, &start_addr, NULL) == 0)
+ return 0;
+
+ /* If the PC is in __mips16_ret_{d,s}f, this is a return stub and the
+ target PC is in $31 ($ra). */
+ if (strcmp (name, "__mips16_ret_sf") == 0
+ || strcmp (name, "__mips16_ret_df") == 0)
+ return read_register (RA_REGNUM);
+
+ if (strncmp (name, "__mips16_call_stub_", 19) == 0)
+ {
+ /* If the PC is in __mips16_call_stub_{1..10}, this is a call stub
+ and the target PC is in $2. */
+ if (name[19] >= '0' && name[19] <= '9')
+ return read_register (2);
+
+ /* If the PC at the start of __mips16_call_stub_{s,d}f_{0..10}, i.e.
+ before the jal instruction, this is effectively a call stub
+ and the the target PC is in $2. Otherwise this is effectively
+ a return stub and the target PC is in $18. */
+ else if (name[19] == 's' || name[19] == 'd')
+ {
+ if (pc == start_addr)
+ {
+ /* Check if the target of the stub is a compiler-generated
+ stub. Such a stub for a function bar might have a name
+ like __fn_stub_bar, and might look like this:
+ mfc1 $4,$f13
+ mfc1 $5,$f12
+ mfc1 $6,$f15
+ mfc1 $7,$f14
+ la $1,bar (becomes a lui/addiu pair)
+ jr $1
+ So scan down to the lui/addi and extract the target
+ address from those two instructions. */
+
+ CORE_ADDR target_pc = read_register (2);
+ t_inst inst;
+ int i;
+
+ /* See if the name of the target function is __fn_stub_*. */
+ if (find_pc_partial_function (target_pc, &name, NULL, NULL) == 0)
+ return target_pc;
+ if (strncmp (name, "__fn_stub_", 10) != 0
+ && strcmp (name, "etext") != 0
+ && strcmp (name, "_etext") != 0)
+ return target_pc;
+
+ /* Scan through this _fn_stub_ code for the lui/addiu pair.
+ The limit on the search is arbitrarily set to 20
+ instructions. FIXME. */
+ for (i = 0, pc = 0; i < 20; i++, target_pc += MIPS_INSTLEN)
+ {
+ inst = mips_fetch_instruction (target_pc);
+ if ((inst & 0xffff0000) == 0x3c010000) /* lui $at */
+ pc = (inst << 16) & 0xffff0000; /* high word */
+ else if ((inst & 0xffff0000) == 0x24210000) /* addiu $at */
+ return pc | (inst & 0xffff); /* low word */
+ }
+
+ /* Couldn't find the lui/addui pair, so return stub address. */
+ return target_pc;
+ }
+ else
+ /* This is the 'return' part of a call stub. The return
+ address is in $r18. */
+ return read_register (18);
+ }
+ }
+ return 0; /* not a stub */
+}
+
+
+/* Return non-zero if the PC is inside a call thunk (aka stub or trampoline).
+ This implements the IN_SOLIB_CALL_TRAMPOLINE macro. */
+
+int
+mips_in_call_stub (pc, name)
+ CORE_ADDR pc;
+ char *name;
+{
+ CORE_ADDR start_addr;
+
+ /* Find the starting address of the function containing the PC. If the
+ caller didn't give us a name, look it up at the same time. */
+ if (find_pc_partial_function (pc, name ? NULL : &name, &start_addr, NULL) == 0)
+ return 0;
+
+ if (strncmp (name, "__mips16_call_stub_", 19) == 0)
+ {
+ /* If the PC is in __mips16_call_stub_{1..10}, this is a call stub. */
+ if (name[19] >= '0' && name[19] <= '9')
+ return 1;
+ /* If the PC at the start of __mips16_call_stub_{s,d}f_{0..10}, i.e.
+ before the jal instruction, this is effectively a call stub. */
+ else if (name[19] == 's' || name[19] == 'd')
+ return pc == start_addr;
+ }
+
+ return 0; /* not a stub */
+}
+
+
+/* Return non-zero if the PC is inside a return thunk (aka stub or trampoline).
+ This implements the IN_SOLIB_RETURN_TRAMPOLINE macro. */
+
+int
+mips_in_return_stub (pc, name)
+ CORE_ADDR pc;
+ char *name;
+{
+ CORE_ADDR start_addr;
+
+ /* Find the starting address of the function containing the PC. */
+ if (find_pc_partial_function (pc, NULL, &start_addr, NULL) == 0)
+ return 0;
+
+ /* If the PC is in __mips16_ret_{d,s}f, this is a return stub. */
+ if (strcmp (name, "__mips16_ret_sf") == 0
+ || strcmp (name, "__mips16_ret_df") == 0)
+ return 1;
+
+ /* If the PC is in __mips16_call_stub_{s,d}f_{0..10} but not at the start,
+ i.e. after the jal instruction, this is effectively a return stub. */
+ if (strncmp (name, "__mips16_call_stub_", 19) == 0
+ && (name[19] == 's' || name[19] == 'd')
+ && pc != start_addr)
+ return 1;
+
+ return 0; /* not a stub */
+}
+
+
+/* Return non-zero if the PC is in a library helper function that should
+ be ignored. This implements the IGNORE_HELPER_CALL macro. */
+
+int
+mips_ignore_helper (pc)
+ CORE_ADDR pc;
+{
+ char *name;
+
+ /* Find the starting address and name of the function containing the PC. */
+ if (find_pc_partial_function (pc, &name, NULL, NULL) == 0)
+ return 0;
+
+ /* If the PC is in __mips16_ret_{d,s}f, this is a library helper function
+ that we want to ignore. */
+ return (strcmp (name, "__mips16_ret_sf") == 0
+ || strcmp (name, "__mips16_ret_df") == 0);
+}
+
+
+/* Return a location where we can set a breakpoint that will be hit
+ when an inferior function call returns. This is normally the
+ program's entry point. Executables that don't have an entry
+ point (e.g. programs in ROM) should define a symbol __CALL_DUMMY_ADDRESS
+ whose address is the location where the breakpoint should be placed. */
+
+CORE_ADDR
+mips_call_dummy_address ()
+{
+ struct minimal_symbol *sym;
+
+ sym = lookup_minimal_symbol ("__CALL_DUMMY_ADDRESS", NULL, NULL);
+ if (sym)
+ return SYMBOL_VALUE_ADDRESS (sym);
+ else
+ return entry_point_address ();
+}
+
+
+/* If the current gcc for for this target does not produce correct debugging
+ information for float parameters, both prototyped and unprototyped, then
+ define this macro. This forces gdb to always assume that floats are
+ passed as doubles and then converted in the callee.
+
+ For the mips chip, it appears that the debug info marks the parameters as
+ floats regardless of whether the function is prototyped, but the actual
+ values are passed as doubles for the non-prototyped case and floats for
+ the prototyped case. Thus we choose to make the non-prototyped case work
+ for C and break the prototyped case, since the non-prototyped case is
+ probably much more common. (FIXME). */
+
+static int
+mips_coerce_float_to_double (struct type *formal, struct type *actual)
+{
+ return current_language->la_language == language_c;
+}
+
+/* When debugging a 64 MIPS target running a 32 bit ABI, the size of
+ the register stored on the stack (32) is different to its real raw
+ size (64). The below ensures that registers are fetched from the
+ stack using their ABI size and then stored into the RAW_BUFFER
+ using their raw size.
+
+ The alternative to adding this function would be to add an ABI
+ macro - REGISTER_STACK_SIZE(). */
+
+static void
+mips_get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lval)
+ char *raw_buffer;
+ int *optimized;
+ CORE_ADDR *addrp;
+ struct frame_info *frame;
+ int regnum;
+ enum lval_type *lval;
+{
+ CORE_ADDR addr;
+
+ if (!target_has_registers)
+ error ("No registers.");
+
+ /* Normal systems don't optimize out things with register numbers. */
+ if (optimized != NULL)
+ *optimized = 0;
+ addr = find_saved_register (frame, regnum);
+ if (addr != 0)
+ {
+ if (lval != NULL)
+ *lval = lval_memory;
+ if (regnum == SP_REGNUM)
+ {
+ if (raw_buffer != NULL)
+ {
+ /* Put it back in target format. */
+ store_address (raw_buffer, REGISTER_RAW_SIZE (regnum),
+ (LONGEST) addr);
+ }
+ if (addrp != NULL)
+ *addrp = 0;
+ return;
+ }
+ if (raw_buffer != NULL)
+ {
+ LONGEST val;
+ if (regnum < 32)
+ /* Only MIPS_SAVED_REGSIZE bytes of GP registers are
+ saved. */
+ val = read_memory_integer (addr, MIPS_SAVED_REGSIZE);
+ else
+ val = read_memory_integer (addr, REGISTER_RAW_SIZE (regnum));
+ store_address (raw_buffer, REGISTER_RAW_SIZE (regnum), val);
+ }
+ }
+ else
+ {
+ if (lval != NULL)
+ *lval = lval_register;
+ addr = REGISTER_BYTE (regnum);
+ if (raw_buffer != NULL)
+ read_register_gen (regnum, raw_buffer);
+ }
+ if (addrp != NULL)
+ *addrp = addr;
+}
+
+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;
+ int ef_mips_bitptrs;
+ int ef_mips_arch;
+ enum mips_abi mips_abi;
+
+ /* 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;
+
+ /* Check ELF_FLAGS to see if it specifies the ABI being used. */
+ switch ((elf_flags & EF_MIPS_ABI))
+ {
+ case E_MIPS_ABI_O32:
+ mips_abi = MIPS_ABI_O32;
+ break;
+ case E_MIPS_ABI_O64:
+ mips_abi = MIPS_ABI_O64;
+ break;
+ case E_MIPS_ABI_EABI32:
+ mips_abi = MIPS_ABI_EABI32;
+ break;
+ case E_MIPS_ABI_EABI64:
+ mips_abi = MIPS_ABI_EABI32;
+ break;
+ default:
+ mips_abi = MIPS_ABI_UNKNOWN;
+ break;
+ }
+ /* Try the architecture for any hint of the corect ABI */
+ if (mips_abi == MIPS_ABI_UNKNOWN
+ && info.bfd_arch_info != NULL
+ && info.bfd_arch_info->arch == bfd_arch_mips)
+ {
+ switch (info.bfd_arch_info->mach)
+ {
+ case bfd_mach_mips3900:
+ mips_abi = MIPS_ABI_EABI32;
+ break;
+ case bfd_mach_mips4100:
+ case bfd_mach_mips5000:
+ mips_abi = MIPS_ABI_EABI64;
+ break;
+ }
+ }
+#ifdef MIPS_DEFAULT_ABI
+ if (mips_abi == MIPS_ABI_UNKNOWN)
+ mips_abi = MIPS_DEFAULT_ABI;
+#endif
+
+ if (gdbarch_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "mips_gdbarch_init: elf_flags = %08x\n",
+ elf_flags);
+ fprintf_unfiltered (gdb_stdlog,
+ "mips_gdbarch_init: ef_mips_arch = %d\n",
+ ef_mips_arch);
+ fprintf_unfiltered (gdb_stdlog,
+ "mips_gdbarch_init: ef_mips_bitptrs = %d\n",
+ ef_mips_bitptrs);
+ fprintf_unfiltered (gdb_stdlog,
+ "mips_gdbarch_init: mips_abi = %d\n",
+ mips_abi);
+ }
+
+ /* 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;
+ if (gdbarch_tdep (current_gdbarch)->mips_abi != mips_abi)
+ 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);
+ tdep->mips_abi = mips_abi;
+ switch (mips_abi)
+ {
+ case MIPS_ABI_O32:
+ tdep->mips_default_saved_regsize = 4;
+ tdep->mips_default_stack_argsize = 4;
+ tdep->mips_fp_register_double = 0;
+ tdep->mips_last_arg_regnum = ZERO_REGNUM + 7;
+ tdep->mips_last_fp_arg_regnum = FP0_REGNUM + 15;
+ tdep->mips_regs_have_home_p = 1;
+ set_gdbarch_long_bit (gdbarch, 32);
+ set_gdbarch_ptr_bit (gdbarch, 32);
+ set_gdbarch_long_long_bit (gdbarch, 64);
+ break;
+ case MIPS_ABI_O64:
+ tdep->mips_default_saved_regsize = 8;
+ tdep->mips_default_stack_argsize = 8;
+ tdep->mips_fp_register_double = 1;
+ tdep->mips_last_arg_regnum = ZERO_REGNUM + 7;
+ tdep->mips_last_fp_arg_regnum = FP0_REGNUM + 15;
+ tdep->mips_regs_have_home_p = 1;
+ set_gdbarch_long_bit (gdbarch, 32);
+ set_gdbarch_ptr_bit (gdbarch, 32);
+ set_gdbarch_long_long_bit (gdbarch, 64);
+ break;
+ case MIPS_ABI_EABI32:
+ tdep->mips_default_saved_regsize = 4;
+ tdep->mips_default_stack_argsize = 4;
+ tdep->mips_fp_register_double = 0;
+ tdep->mips_last_arg_regnum = ZERO_REGNUM + 11;
+ tdep->mips_last_fp_arg_regnum = FP0_REGNUM + 19;
+ tdep->mips_regs_have_home_p = 0;
+ set_gdbarch_long_bit (gdbarch, 32);
+ set_gdbarch_ptr_bit (gdbarch, 32);
+ set_gdbarch_long_long_bit (gdbarch, 64);
+ break;
+ case MIPS_ABI_EABI64:
+ tdep->mips_default_saved_regsize = 8;
+ tdep->mips_default_stack_argsize = 8;
+ tdep->mips_fp_register_double = 1;
+ tdep->mips_last_arg_regnum = ZERO_REGNUM + 11;
+ tdep->mips_last_fp_arg_regnum = FP0_REGNUM + 19;
+ tdep->mips_regs_have_home_p = 0;
+ set_gdbarch_long_bit (gdbarch, 64);
+ set_gdbarch_ptr_bit (gdbarch, 64);
+ set_gdbarch_long_long_bit (gdbarch, 64);
+ break;
+ case MIPS_ABI_N32:
+ tdep->mips_default_saved_regsize = 4;
+ tdep->mips_default_stack_argsize = 8;
+ tdep->mips_fp_register_double = 1;
+ tdep->mips_last_arg_regnum = ZERO_REGNUM + 11;
+ tdep->mips_last_fp_arg_regnum = FP0_REGNUM + 19;
+ tdep->mips_regs_have_home_p = 0;
+ set_gdbarch_long_bit (gdbarch, 32);
+ set_gdbarch_ptr_bit (gdbarch, 32);
+ set_gdbarch_long_long_bit (gdbarch, 64);
+ break;
+ default:
+ tdep->mips_default_saved_regsize = MIPS_REGSIZE;
+ tdep->mips_default_stack_argsize = MIPS_REGSIZE;
+ tdep->mips_fp_register_double = (REGISTER_VIRTUAL_SIZE (FP0_REGNUM) == 8);
+ tdep->mips_last_arg_regnum = ZERO_REGNUM + 11;
+ tdep->mips_last_fp_arg_regnum = FP0_REGNUM + 19;
+ tdep->mips_regs_have_home_p = 1;
+ set_gdbarch_long_bit (gdbarch, 32);
+ set_gdbarch_ptr_bit (gdbarch, 32);
+ set_gdbarch_long_long_bit (gdbarch, 64);
+ break;
+ }
+
+ /* FIXME: jlarmour/2000-04-07: There *is* a flag EF_MIPS_32BIT_MODE
+ that could indicate -gp32 BUT gas/config/tc-mips.c contains the
+ comment:
+
+ ``We deliberately don't allow "-gp32" to set the MIPS_32BITMODE
+ flag in object files because to do so would make it impossible to
+ link with libraries compiled without "-gp32". This is
+ unnecessarily restrictive.
+
+ We could solve this problem by adding "-gp32" multilibs to gcc,
+ but to set this flag before gcc is built with such multilibs will
+ break too many systems.''
+
+ But even more unhelpfully, the default linker output target for
+ mips64-elf is elf32-bigmips, and has EF_MIPS_32BIT_MODE set, even
+ for 64-bit programs - you need to change the ABI to change this,
+ and not all gcc targets support that currently. Therefore using
+ this flag to detect 32-bit mode would do the wrong thing given
+ the current gcc - it would make GDB treat these 64-bit programs
+ as 32-bit programs by default. */
+
+ /* 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
+
+ /* 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_mips3900:
+ case bfd_mach_mips4100:
+ case bfd_mach_mips4111:
+ tdep->mips_fpu_type = MIPS_FPU_NONE;
+ break;
+ case bfd_mach_mips4650:
+ tdep->mips_fpu_type = MIPS_FPU_SINGLE;
+ 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_coerce_float_to_double (gdbarch, mips_coerce_float_to_double);
+
+ set_gdbarch_frame_chain_valid (gdbarch, func_frame_chain_valid);
+ set_gdbarch_get_saved_register (gdbarch, mips_get_saved_register);
+
+ return gdbarch;
+}
+
+static void
+mips_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ if (tdep != NULL)
+ {
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: tdep->elf_flags = 0x%x\n",
+ tdep->elf_flags);
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: tdep->mips_abi = %d\n",
+ tdep->mips_abi);
+ }
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: FP_REGISTER_DOUBLE = %d\n",
+ FP_REGISTER_DOUBLE);
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: MIPS_DEFAULT_FPU_TYPE = %d (%s)\n",
+ MIPS_DEFAULT_FPU_TYPE,
+ (MIPS_DEFAULT_FPU_TYPE == MIPS_FPU_NONE ? "none"
+ : MIPS_DEFAULT_FPU_TYPE == MIPS_FPU_SINGLE ? "single"
+ : MIPS_DEFAULT_FPU_TYPE == MIPS_FPU_DOUBLE ? "double"
+ : "???"));
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: MIPS_EABI = %d\n",
+ MIPS_EABI);
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: MIPS_LAST_FP_ARG_REGNUM = %d\n",
+ MIPS_LAST_FP_ARG_REGNUM);
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: MIPS_LAST_ARG_REGNUM = %d\n",
+ MIPS_LAST_ARG_REGNUM);
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: MIPS_FPU_TYPE = %d (%s)\n",
+ MIPS_FPU_TYPE,
+ (MIPS_FPU_TYPE == MIPS_FPU_NONE ? "none"
+ : MIPS_FPU_TYPE == MIPS_FPU_SINGLE ? "single"
+ : MIPS_FPU_TYPE == MIPS_FPU_DOUBLE ? "double"
+ : "???"));
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: MIPS_DEFAULT_SAVED_REGSIZE = %d\n",
+ MIPS_DEFAULT_SAVED_REGSIZE);
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: MIPS_SAVED_REGSIZE = %d\n",
+ MIPS_SAVED_REGSIZE);
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: FP_REGISTER_DOUBLE = %d\n",
+ FP_REGISTER_DOUBLE);
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: MIPS_REGS_HAVE_HOME_P = %d\n",
+ MIPS_REGS_HAVE_HOME_P);
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: MIPS_DEFAULT_STACK_ARGSIZE = %d\n",
+ MIPS_DEFAULT_STACK_ARGSIZE);
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: MIPS_STACK_ARGSIZE = %d\n",
+ MIPS_STACK_ARGSIZE);
+ fprintf_unfiltered (file,
+ "mips_dump_tdep: MIPS_REGSIZE = %d\n",
+ MIPS_REGSIZE);
+}
+