aboutsummaryrefslogtreecommitdiff
path: root/gdb/mips-tdep.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/mips-tdep.c')
-rw-r--r--gdb/mips-tdep.c2213
1 files changed, 1890 insertions, 323 deletions
diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c
index 67409f6..58e1a8b 100644
--- a/gdb/mips-tdep.c
+++ b/gdb/mips-tdep.c
@@ -61,14 +61,29 @@ enum
enum mips_abi
{
- MIPS_ABI_UNKNOWN,
+ MIPS_ABI_UNKNOWN = 0,
MIPS_ABI_N32,
MIPS_ABI_O32,
+ MIPS_ABI_N64,
MIPS_ABI_O64,
MIPS_ABI_EABI32,
- MIPS_ABI_EABI64
+ MIPS_ABI_EABI64,
+ MIPS_ABI_LAST
};
+static const char *mips_abi_string;
+
+static const char *mips_abi_strings[] = {
+ "auto",
+ "n32",
+ "o32",
+ "n64",
+ "o64",
+ "eabi32",
+ "eabi64",
+ NULL
+};
+
struct frame_extra_info
{
mips_extra_func_info_t proc_desc;
@@ -106,12 +121,6 @@ enum mips_fpu_type
#endif
static int mips_fpu_type_auto = 1;
static enum mips_fpu_type mips_fpu_type = MIPS_DEFAULT_FPU_TYPE;
-#define MIPS_FPU_TYPE mips_fpu_type
-
-/* Do not use "TARGET_IS_MIPS64" to test the size of floating point registers */
-#ifndef FP_REGISTER_DOUBLE
-#define FP_REGISTER_DOUBLE (REGISTER_VIRTUAL_SIZE(FP0_REGNUM) == 8)
-#endif
static int mips_debug = 0;
@@ -123,13 +132,12 @@ struct gdbarch_tdep
/* mips options */
enum mips_abi mips_abi;
- const char *mips_abi_string;
+ enum mips_abi found_abi;
enum mips_fpu_type mips_fpu_type;
int mips_last_arg_regnum;
int mips_last_fp_arg_regnum;
int mips_default_saved_regsize;
int mips_fp_register_double;
- int mips_regs_have_home_p;
int mips_default_stack_argsize;
int gdb_target_is_mips64;
int default_mask_address_p;
@@ -137,35 +145,18 @@ struct gdbarch_tdep
enum gdb_osabi osabi;
};
-#if GDB_MULTI_ARCH
-#undef MIPS_EABI
#define MIPS_EABI (gdbarch_tdep (current_gdbarch)->mips_abi == MIPS_ABI_EABI32 \
|| gdbarch_tdep (current_gdbarch)->mips_abi == MIPS_ABI_EABI64)
-#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
/* Return the currently configured (or set) saved register size. */
-#if GDB_MULTI_ARCH
-#undef MIPS_DEFAULT_SAVED_REGSIZE
#define MIPS_DEFAULT_SAVED_REGSIZE (gdbarch_tdep (current_gdbarch)->mips_default_saved_regsize)
-#elif !defined (MIPS_DEFAULT_SAVED_REGSIZE)
-#define MIPS_DEFAULT_SAVED_REGSIZE MIPS_REGSIZE
-#endif
static const char *mips_saved_regsize_string = size_auto;
@@ -182,6 +173,97 @@ mips_saved_regsize (void)
return 4;
}
+/* Functions for setting and testing a bit in a minimal symbol that
+ marks it as 16-bit function. The MSB of the minimal symbol's
+ "info" field is used for this purpose. This field is already
+ being used to store the symbol size, so the assumption is
+ that the symbol size cannot exceed 2^31.
+
+ ELF_MAKE_MSYMBOL_SPECIAL tests whether an ELF symbol is "special",
+ i.e. refers to a 16-bit function, and sets a "special" bit in a
+ minimal symbol to mark it as a 16-bit function
+
+ MSYMBOL_IS_SPECIAL tests the "special" bit in a minimal symbol
+ MSYMBOL_SIZE returns the size of the minimal symbol, i.e.
+ the "info" field with the "special" bit masked out */
+
+static void
+mips_elf_make_msymbol_special (asymbol *sym, struct minimal_symbol *msym)
+{
+ if (((elf_symbol_type *)(sym))->internal_elf_sym.st_other == STO_MIPS16)
+ {
+ MSYMBOL_INFO (msym) = (char *)
+ (((long) MSYMBOL_INFO (msym)) | 0x80000000);
+ SYMBOL_VALUE_ADDRESS (msym) |= 1;
+ }
+}
+
+static int
+msymbol_is_special (struct minimal_symbol *msym)
+{
+ return (((long) MSYMBOL_INFO (msym) & 0x80000000) != 0);
+}
+
+static long
+msymbol_size (struct minimal_symbol *msym)
+{
+ return ((long) MSYMBOL_INFO (msym) & 0x7fffffff);
+}
+
+/* XFER a value from the big/little/left end of the register.
+ Depending on the size of the value it might occupy the entire
+ register or just part of it. Make an allowance for this, aligning
+ things accordingly. */
+
+static void
+mips_xfer_register (struct regcache *regcache, int reg_num, int length,
+ enum bfd_endian endian, bfd_byte *in, const bfd_byte *out,
+ int buf_offset)
+{
+ bfd_byte *reg = alloca (MAX_REGISTER_RAW_SIZE);
+ int reg_offset = 0;
+ /* Need to transfer the left or right part of the register, based on
+ the targets byte order. */
+ switch (endian)
+ {
+ case BFD_ENDIAN_BIG:
+ reg_offset = REGISTER_RAW_SIZE (reg_num) - length;
+ break;
+ case BFD_ENDIAN_LITTLE:
+ reg_offset = 0;
+ break;
+ case BFD_ENDIAN_UNKNOWN: /* Indicates no alignment. */
+ reg_offset = 0;
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "bad switch");
+ }
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stderr,
+ "xfer $%d, reg offset %d, buf offset %d, length %d, ",
+ reg_num, reg_offset, buf_offset, length);
+ if (mips_debug && out != NULL)
+ {
+ int i;
+ fprintf_unfiltered (gdb_stdlog, "out ");
+ for (i = 0; i < length; i++)
+ fprintf_unfiltered (gdb_stdlog, "%02x", out[buf_offset + i]);
+ }
+ if (in != NULL)
+ regcache_raw_read_part (regcache, reg_num, reg_offset, length, in + buf_offset);
+ if (out != NULL)
+ regcache_raw_write_part (regcache, reg_num, reg_offset, length, out + buf_offset);
+ if (mips_debug && in != NULL)
+ {
+ int i;
+ fprintf_unfiltered (gdb_stdlog, "in ");
+ for (i = 0; i < length; i++)
+ fprintf_unfiltered (gdb_stdlog, "%02x", in[buf_offset + i]);
+ }
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, "\n");
+}
+
/* Determine if a MIPS3 or later cpu is operating in MIPS{1,2} FPU
compatiblity mode. A return value of 1 means that we have
physical 64-bit registers, but should treat them as 32-bit registers. */
@@ -212,31 +294,13 @@ mips2_fp_compat (void)
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
-
-/* Does the caller allocate a ``home'' for each register used in the
- function call? The N32 ABI and MIPS_EABI do not, the others do. */
-
-#if GDB_MULTI_ARCH
-#undef MIPS_REGS_HAVE_HOME_P
-#define MIPS_REGS_HAVE_HOME_P (gdbarch_tdep (current_gdbarch)->mips_regs_have_home_p)
-#elif !defined (MIPS_REGS_HAVE_HOME_P)
-#define MIPS_REGS_HAVE_HOME_P (!MIPS_EABI)
-#endif
/* The amount of space reserved on the stack for registers. This is
different to MIPS_SAVED_REGSIZE as it determines the alignment of
data allocated after the registers have run out. */
-#if GDB_MULTI_ARCH
-#undef MIPS_DEFAULT_STACK_ARGSIZE
#define MIPS_DEFAULT_STACK_ARGSIZE (gdbarch_tdep (current_gdbarch)->mips_default_stack_argsize)
-#elif !defined (MIPS_DEFAULT_STACK_ARGSIZE)
-#define MIPS_DEFAULT_STACK_ARGSIZE (MIPS_DEFAULT_SAVED_REGSIZE)
-#endif
#define MIPS_STACK_ARGSIZE (mips_stack_argsize ())
@@ -253,17 +317,9 @@ mips_stack_argsize (void)
return 4;
}
-#if GDB_MULTI_ARCH
-#undef GDB_TARGET_IS_MIPS64
#define GDB_TARGET_IS_MIPS64 (gdbarch_tdep (current_gdbarch)->gdb_target_is_mips64 + 0)
-#endif
-#if GDB_MULTI_ARCH
-#undef MIPS_DEFAULT_MASK_ADDRESS_P
#define MIPS_DEFAULT_MASK_ADDRESS_P (gdbarch_tdep (current_gdbarch)->default_mask_address_p)
-#elif !defined (MIPS_DEFAULT_MASK_ADDRESS_P)
-#define MIPS_DEFAULT_MASK_ADDRESS_P (0)
-#endif
#define VM_MIN_ADDRESS (CORE_ADDR)0x400000
@@ -278,7 +334,7 @@ static CORE_ADDR heuristic_proc_start (CORE_ADDR);
static CORE_ADDR read_next_frame_reg (struct frame_info *, int);
-int mips_set_processor_type (char *);
+static int mips_set_processor_type (char *);
static void mips_show_processor_type_command (char *, int);
@@ -314,7 +370,7 @@ static struct cmd_list_element *showmipscmdlist = NULL;
char *mips_generic_reg_names[] = MIPS_REGISTER_NAMES;
char **mips_processor_reg_names = mips_generic_reg_names;
-char *
+static const char *
mips_register_name (int i)
{
return mips_processor_reg_names[i];
@@ -425,6 +481,8 @@ static unsigned int heuristic_fence_post = 0;
#define PROC_REG_OFFSET(proc) ((proc)->pdr.regoffset)
#define PROC_FREG_OFFSET(proc) ((proc)->pdr.fregoffset)
#define PROC_PC_REG(proc) ((proc)->pdr.pcreg)
+/* FIXME drow/2002-06-10: If a pointer on the host is bigger than a long,
+ this will corrupt pdr.iline. Fortunately we don't use it. */
#define PROC_SYMBOL(proc) (*(struct symbol**)&(proc)->pdr.isym)
#define _PROC_MAGIC_ 0x0F0F0F0F
#define PROC_DESC_IS_DUMMY(proc) ((proc)->pdr.isym == _PROC_MAGIC_)
@@ -455,7 +513,7 @@ mips_print_extra_frame_info (struct frame_info *fi)
static int mips64_transfers_32bit_regs_p = 0;
-int
+static int
mips_register_raw_size (int reg_nr)
{
if (mips64_transfers_32bit_regs_p)
@@ -472,7 +530,7 @@ mips_register_raw_size (int reg_nr)
/* Convert between RAW and VIRTUAL registers. The RAW register size
defines the remote-gdb packet. */
-int
+static int
mips_register_convertible (int reg_nr)
{
if (mips64_transfers_32bit_regs_p)
@@ -481,7 +539,7 @@ mips_register_convertible (int reg_nr)
return (REGISTER_RAW_SIZE (reg_nr) > REGISTER_VIRTUAL_SIZE (reg_nr));
}
-void
+static void
mips_register_convert_to_virtual (int n, struct type *virtual_type,
char *raw_buf, char *virt_buf)
{
@@ -495,7 +553,7 @@ mips_register_convert_to_virtual (int n, struct type *virtual_type,
TYPE_LENGTH (virtual_type));
}
-void
+static void
mips_register_convert_to_raw (struct type *virtual_type, int n,
char *virt_buf, char *raw_buf)
{
@@ -510,20 +568,96 @@ mips_register_convert_to_raw (struct type *virtual_type, int n,
TYPE_LENGTH (virtual_type));
}
+void
+mips_register_convert_to_type (int regnum, struct type *type, char *buffer)
+{
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+ && REGISTER_RAW_SIZE (regnum) == 4
+ && (regnum) >= FP0_REGNUM && (regnum) < FP0_REGNUM + 32
+ && TYPE_CODE(type) == TYPE_CODE_FLT
+ && TYPE_LENGTH(type) == 8)
+ {
+ char temp[4];
+ memcpy (temp, ((char *)(buffer))+4, 4);
+ memcpy (((char *)(buffer))+4, (buffer), 4);
+ memcpy (((char *)(buffer)), temp, 4);
+ }
+}
+
+void
+mips_register_convert_from_type (int regnum, struct type *type, char *buffer)
+{
+if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+ && REGISTER_RAW_SIZE (regnum) == 4
+ && (regnum) >= FP0_REGNUM && (regnum) < FP0_REGNUM + 32
+ && TYPE_CODE(type) == TYPE_CODE_FLT
+ && TYPE_LENGTH(type) == 8)
+ {
+ char temp[4];
+ memcpy (temp, ((char *)(buffer))+4, 4);
+ memcpy (((char *)(buffer))+4, (buffer), 4);
+ memcpy (((char *)(buffer)), temp, 4);
+ }
+}
+
+/* Return the GDB type object for the "standard" data type
+ of data in register REG.
+
+ Note: kevinb/2002-08-01: The definition below should faithfully
+ reproduce the behavior of each of the REGISTER_VIRTUAL_TYPE
+ definitions found in config/mips/tm-*.h. I'm concerned about
+ the ``FCRCS_REGNUM <= reg && reg <= LAST_EMBED_REGNUM'' clause
+ though. In some cases FP_REGNUM is in this range, and I doubt
+ that this code is correct for the 64-bit case. */
+
+static struct type *
+mips_register_virtual_type (int reg)
+{
+ if (FP0_REGNUM <= reg && reg < FP0_REGNUM + 32)
+ {
+ /* Floating point registers... */
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ return builtin_type_ieee_double_big;
+ else
+ return builtin_type_ieee_double_little;
+ }
+ else if (reg == PS_REGNUM /* CR */)
+ return builtin_type_uint32;
+ else if (FCRCS_REGNUM <= reg && reg <= LAST_EMBED_REGNUM)
+ return builtin_type_uint32;
+ else
+ {
+ /* Everything else...
+ Return type appropriate for width of register. */
+ if (MIPS_REGSIZE == TYPE_LENGTH (builtin_type_uint64))
+ return builtin_type_uint64;
+ else
+ return builtin_type_uint32;
+ }
+}
+
+/* TARGET_READ_SP -- Remove useless bits from the stack pointer. */
+
+static CORE_ADDR
+mips_read_sp (void)
+{
+ return ADDR_BITS_REMOVE (read_register (SP_REGNUM));
+}
+
/* Should the upper word of 64-bit addresses be zeroed? */
-enum cmd_auto_boolean mask_address_var = CMD_AUTO_BOOLEAN_AUTO;
+enum auto_boolean mask_address_var = AUTO_BOOLEAN_AUTO;
static int
mips_mask_address_p (void)
{
switch (mask_address_var)
{
- case CMD_AUTO_BOOLEAN_TRUE:
+ case AUTO_BOOLEAN_TRUE:
return 1;
- case CMD_AUTO_BOOLEAN_FALSE:
+ case AUTO_BOOLEAN_FALSE:
return 0;
break;
- case CMD_AUTO_BOOLEAN_AUTO:
+ case AUTO_BOOLEAN_AUTO:
return MIPS_DEFAULT_MASK_ADDRESS_P;
default:
internal_error (__FILE__, __LINE__,
@@ -533,17 +667,17 @@ mips_mask_address_p (void)
}
static void
-show_mask_address (char *cmd, int from_tty)
+show_mask_address (char *cmd, int from_tty, struct cmd_list_element *c)
{
switch (mask_address_var)
{
- case CMD_AUTO_BOOLEAN_TRUE:
+ case AUTO_BOOLEAN_TRUE:
printf_filtered ("The 32 bit mips address mask is enabled\n");
break;
- case CMD_AUTO_BOOLEAN_FALSE:
+ case AUTO_BOOLEAN_FALSE:
printf_filtered ("The 32 bit mips address mask is disabled\n");
break;
- case CMD_AUTO_BOOLEAN_AUTO:
+ case AUTO_BOOLEAN_AUTO:
printf_filtered ("The 32 bit address mask is set automatically. Currently %s\n",
mips_mask_address_p () ? "enabled" : "disabled");
break;
@@ -555,13 +689,51 @@ show_mask_address (char *cmd, int from_tty)
}
/* Should call_function allocate stack space for a struct return? */
-int
-mips_use_struct_convention (int gcc_p, struct type *type)
+
+static int
+mips_eabi_use_struct_convention (int gcc_p, struct type *type)
{
- if (MIPS_EABI)
- return (TYPE_LENGTH (type) > 2 * MIPS_SAVED_REGSIZE);
- else
- return 1; /* Structures are returned by ref in extra arg0 */
+ return (TYPE_LENGTH (type) > 2 * MIPS_SAVED_REGSIZE);
+}
+
+static int
+mips_n32n64_use_struct_convention (int gcc_p, struct type *type)
+{
+ return (TYPE_LENGTH (type) > 2 * MIPS_SAVED_REGSIZE);
+}
+
+static int
+mips_o32_use_struct_convention (int gcc_p, struct type *type)
+{
+ return 1; /* Structures are returned by ref in extra arg0. */
+}
+
+/* Should call_function pass struct by reference?
+ For each architecture, structs are passed either by
+ value or by reference, depending on their size. */
+
+static int
+mips_eabi_reg_struct_has_addr (int gcc_p, struct type *type)
+{
+ enum type_code typecode = TYPE_CODE (check_typedef (type));
+ int len = TYPE_LENGTH (check_typedef (type));
+
+ if (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION)
+ return (len > MIPS_SAVED_REGSIZE);
+
+ return 0;
+}
+
+static int
+mips_n32n64_reg_struct_has_addr (int gcc_p, struct type *type)
+{
+ return 0; /* Assumption: N32/N64 never passes struct by ref. */
+}
+
+static int
+mips_o32_reg_struct_has_addr (int gcc_p, struct type *type)
+{
+ return 0; /* Assumption: O32/O64 never passes struct by ref. */
}
/* Tell if the program counter value in MEMADDR is in a MIPS16 function. */
@@ -580,7 +752,7 @@ pc_is_mips16 (bfd_vma memaddr)
MIPS16 or normal MIPS. */
sym = lookup_minimal_symbol_by_pc (memaddr);
if (sym)
- return MSYMBOL_IS_SPECIAL (sym);
+ return msymbol_is_special (sym);
else
return 0;
}
@@ -748,7 +920,7 @@ mips32_relative_offset (unsigned long inst)
/* Determine whate to set a single step breakpoint while considering
branch prediction */
-CORE_ADDR
+static CORE_ADDR
mips32_next_pc (CORE_ADDR pc)
{
unsigned long inst;
@@ -1064,7 +1236,6 @@ static CORE_ADDR
add_offset_16 (CORE_ADDR pc, int offset)
{
return ((offset << 2) | ((pc + 2) & (0xf0000000)));
-
}
static CORE_ADDR
@@ -1188,7 +1359,7 @@ extended_mips16_next_pc (CORE_ADDR pc,
return pc;
}
-CORE_ADDR
+static CORE_ADDR
mips16_next_pc (CORE_ADDR pc)
{
unsigned int insn = fetch_mips_16 (pc);
@@ -1210,9 +1381,17 @@ mips_next_pc (CORE_ADDR pc)
}
/* Guaranteed to set fci->saved_regs to some values (it never leaves it
- NULL). */
+ NULL).
-void
+ Note: kevinb/2002-08-09: The only caller of this function is (and
+ should remain) mips_frame_init_saved_regs(). In fact,
+ aside from calling mips_find_saved_regs(), mips_frame_init_saved_regs()
+ does nothing more than set frame->saved_regs[SP_REGNUM]. These two
+ functions should really be combined and now that there is only one
+ caller, it should be straightforward. (Watch out for multiple returns
+ though.) */
+
+static void
mips_find_saved_regs (struct frame_info *fci)
{
int ireg;
@@ -1362,9 +1541,20 @@ mips_find_saved_regs (struct frame_info *fci)
were saved. */
reg_position = fci->frame + PROC_FREG_OFFSET (proc_desc);
- /* The freg_offset points to where the first *double* register
- is saved. So skip to the high-order word. */
- if (!GDB_TARGET_IS_MIPS64)
+ /* Apparently, the freg_offset gives the offset to the first 64 bit
+ saved.
+
+ When the ABI specifies 64 bit saved registers, the FREG_OFFSET
+ designates the first saved 64 bit register.
+
+ When the ABI specifies 32 bit saved registers, the ``64 bit saved
+ DOUBLE'' consists of two adjacent 32 bit registers, Hence
+ FREG_OFFSET, designates the address of the lower register of the
+ register pair. Adjust the offset so that it designates the upper
+ register of the pair -- i.e., the address of the first saved 32
+ bit register. */
+
+ if (MIPS_SAVED_REGSIZE == 4)
reg_position += MIPS_SAVED_REGSIZE;
/* Fill in the offsets for the float registers which float_mask says
@@ -1379,6 +1569,23 @@ mips_find_saved_regs (struct frame_info *fci)
fci->saved_regs[PC_REGNUM] = fci->saved_regs[RA_REGNUM];
}
+/* Set up the 'saved_regs' array. This is a data structure containing
+ the addresses on the stack where each register has been saved, for
+ each stack frame. Registers that have not been saved will have
+ zero here. The stack pointer register is special: rather than the
+ address where the stack register has been saved, saved_regs[SP_REGNUM]
+ will have the actual value of the previous frame's stack register. */
+
+static void
+mips_frame_init_saved_regs (struct frame_info *frame)
+{
+ if (frame->saved_regs == NULL)
+ {
+ mips_find_saved_regs (frame);
+ }
+ frame->saved_regs[SP_REGNUM] = frame->frame;
+}
+
static CORE_ADDR
read_next_frame_reg (struct frame_info *fi, int regno)
{
@@ -1391,7 +1598,7 @@ read_next_frame_reg (struct frame_info *fi, int regno)
else
{
if (fi->saved_regs == NULL)
- mips_find_saved_regs (fi);
+ FRAME_INIT_SAVED_REGS (fi);
if (fi->saved_regs[regno])
return read_memory_integer (ADDR_BITS_REMOVE (fi->saved_regs[regno]), MIPS_SAVED_REGSIZE);
}
@@ -1474,12 +1681,12 @@ mips_init_frame_pc_first (int fromleaf, struct frame_info *prev)
pc = ((fromleaf) ? SAVED_PC_AFTER_CALL (prev->next) :
prev->next ? FRAME_SAVED_PC (prev->next) : read_pc ());
- tmp = mips_skip_stub (pc);
+ tmp = SKIP_TRAMPOLINE_CODE (pc);
prev->pc = tmp ? tmp : pc;
}
-CORE_ADDR
+static CORE_ADDR
mips_frame_saved_pc (struct frame_info *frame)
{
CORE_ADDR saved_pc;
@@ -1932,6 +2139,30 @@ heuristic_proc_desc (CORE_ADDR start_pc, CORE_ADDR limit_pc,
return &temp_proc_desc;
}
+struct mips_objfile_private
+{
+ bfd_size_type size;
+ char *contents;
+};
+
+/* Global used to communicate between non_heuristic_proc_desc and
+ compare_pdr_entries within qsort (). */
+static bfd *the_bfd;
+
+static int
+compare_pdr_entries (const void *a, const void *b)
+{
+ CORE_ADDR lhs = bfd_get_32 (the_bfd, (bfd_byte *) a);
+ CORE_ADDR rhs = bfd_get_32 (the_bfd, (bfd_byte *) b);
+
+ if (lhs < rhs)
+ return -1;
+ else if (lhs == rhs)
+ return 0;
+ else
+ return 1;
+}
+
static mips_extra_func_info_t
non_heuristic_proc_desc (CORE_ADDR pc, CORE_ADDR *addrptr)
{
@@ -1939,23 +2170,145 @@ non_heuristic_proc_desc (CORE_ADDR pc, CORE_ADDR *addrptr)
mips_extra_func_info_t proc_desc;
struct block *b = block_for_pc (pc);
struct symbol *sym;
+ struct obj_section *sec;
+ struct mips_objfile_private *priv;
+
+ if (PC_IN_CALL_DUMMY (pc, 0, 0))
+ return NULL;
find_pc_partial_function (pc, NULL, &startaddr, NULL);
if (addrptr)
*addrptr = startaddr;
- if (b == NULL || PC_IN_CALL_DUMMY (pc, 0, 0))
- sym = NULL;
- else
+
+ priv = NULL;
+
+ sec = find_pc_section (pc);
+ if (sec != NULL)
{
- if (startaddr > BLOCK_START (b))
- /* This is the "pathological" case referred to in a comment in
- print_frame_info. It might be better to move this check into
- symbol reading. */
- sym = NULL;
- else
- sym = lookup_symbol (MIPS_EFI_SYMBOL_NAME, b, LABEL_NAMESPACE, 0, NULL);
+ priv = (struct mips_objfile_private *) sec->objfile->obj_private;
+
+ /* Search the ".pdr" section generated by GAS. This includes most of
+ the information normally found in ECOFF PDRs. */
+
+ the_bfd = sec->objfile->obfd;
+ if (priv == NULL
+ && (the_bfd->format == bfd_object
+ && bfd_get_flavour (the_bfd) == bfd_target_elf_flavour
+ && elf_elfheader (the_bfd)->e_ident[EI_CLASS] == ELFCLASS64))
+ {
+ /* Right now GAS only outputs the address as a four-byte sequence.
+ This means that we should not bother with this method on 64-bit
+ targets (until that is fixed). */
+
+ priv = obstack_alloc (& sec->objfile->psymbol_obstack,
+ sizeof (struct mips_objfile_private));
+ priv->size = 0;
+ sec->objfile->obj_private = priv;
+ }
+ else if (priv == NULL)
+ {
+ asection *bfdsec;
+
+ priv = obstack_alloc (& sec->objfile->psymbol_obstack,
+ sizeof (struct mips_objfile_private));
+
+ bfdsec = bfd_get_section_by_name (sec->objfile->obfd, ".pdr");
+ if (bfdsec != NULL)
+ {
+ priv->size = bfd_section_size (sec->objfile->obfd, bfdsec);
+ priv->contents = obstack_alloc (& sec->objfile->psymbol_obstack,
+ priv->size);
+ bfd_get_section_contents (sec->objfile->obfd, bfdsec,
+ priv->contents, 0, priv->size);
+
+ /* In general, the .pdr section is sorted. However, in the
+ presence of multiple code sections (and other corner cases)
+ it can become unsorted. Sort it so that we can use a faster
+ binary search. */
+ qsort (priv->contents, priv->size / 32, 32, compare_pdr_entries);
+ }
+ else
+ priv->size = 0;
+
+ sec->objfile->obj_private = priv;
+ }
+ the_bfd = NULL;
+
+ if (priv->size != 0)
+ {
+ int low, mid, high;
+ char *ptr;
+
+ low = 0;
+ high = priv->size / 32;
+
+ do
+ {
+ CORE_ADDR pdr_pc;
+
+ mid = (low + high) / 2;
+
+ ptr = priv->contents + mid * 32;
+ pdr_pc = bfd_get_signed_32 (sec->objfile->obfd, ptr);
+ pdr_pc += ANOFFSET (sec->objfile->section_offsets,
+ SECT_OFF_TEXT (sec->objfile));
+ if (pdr_pc == startaddr)
+ break;
+ if (pdr_pc > startaddr)
+ high = mid;
+ else
+ low = mid + 1;
+ }
+ while (low != high);
+
+ if (low != high)
+ {
+ struct symbol *sym = find_pc_function (pc);
+
+ /* Fill in what we need of the proc_desc. */
+ proc_desc = (mips_extra_func_info_t)
+ obstack_alloc (&sec->objfile->psymbol_obstack,
+ sizeof (struct mips_extra_func_info));
+ PROC_LOW_ADDR (proc_desc) = startaddr;
+
+ /* Only used for dummy frames. */
+ PROC_HIGH_ADDR (proc_desc) = 0;
+
+ PROC_FRAME_OFFSET (proc_desc)
+ = bfd_get_32 (sec->objfile->obfd, ptr + 20);
+ PROC_FRAME_REG (proc_desc) = bfd_get_32 (sec->objfile->obfd,
+ ptr + 24);
+ PROC_FRAME_ADJUST (proc_desc) = 0;
+ PROC_REG_MASK (proc_desc) = bfd_get_32 (sec->objfile->obfd,
+ ptr + 4);
+ PROC_FREG_MASK (proc_desc) = bfd_get_32 (sec->objfile->obfd,
+ ptr + 12);
+ PROC_REG_OFFSET (proc_desc) = bfd_get_32 (sec->objfile->obfd,
+ ptr + 8);
+ PROC_FREG_OFFSET (proc_desc)
+ = bfd_get_32 (sec->objfile->obfd, ptr + 16);
+ PROC_PC_REG (proc_desc) = bfd_get_32 (sec->objfile->obfd,
+ ptr + 28);
+ proc_desc->pdr.isym = (long) sym;
+
+ return proc_desc;
+ }
+ }
}
+ if (b == NULL)
+ return NULL;
+
+ if (startaddr > BLOCK_START (b))
+ {
+ /* This is the "pathological" case referred to in a comment in
+ print_frame_info. It might be better to move this check into
+ symbol reading. */
+ return NULL;
+ }
+
+ sym = lookup_symbol (MIPS_EFI_SYMBOL_NAME, b, LABEL_NAMESPACE, 0, NULL);
+
/* If we never found a PDR for this function in symbol reading, then
examine prologues to find the information. */
if (sym)
@@ -1991,7 +2344,7 @@ find_proc_desc (CORE_ADDR pc, struct frame_info *next_frame, int cur_frame)
{
struct symtab_and_line val;
struct symbol *proc_symbol =
- PROC_DESC_IS_DUMMY (proc_desc) ? 0 : PROC_SYMBOL (proc_desc);
+ PROC_DESC_IS_DUMMY (proc_desc) ? 0 : PROC_SYMBOL (proc_desc);
if (proc_symbol)
{
@@ -2003,8 +2356,8 @@ find_proc_desc (CORE_ADDR pc, struct frame_info *next_frame, int cur_frame)
if (!proc_symbol || pc < val.pc)
{
mips_extra_func_info_t found_heuristic =
- heuristic_proc_desc (PROC_LOW_ADDR (proc_desc),
- pc, next_frame, cur_frame);
+ heuristic_proc_desc (PROC_LOW_ADDR (proc_desc),
+ pc, next_frame, cur_frame);
if (found_heuristic)
proc_desc = found_heuristic;
}
@@ -2037,14 +2390,15 @@ static CORE_ADDR
get_frame_pointer (struct frame_info *frame,
mips_extra_func_info_t proc_desc)
{
- return ADDR_BITS_REMOVE (
- read_next_frame_reg (frame, PROC_FRAME_REG (proc_desc)) +
- PROC_FRAME_OFFSET (proc_desc) - PROC_FRAME_ADJUST (proc_desc));
+ return ADDR_BITS_REMOVE (read_next_frame_reg (frame,
+ PROC_FRAME_REG (proc_desc)) +
+ PROC_FRAME_OFFSET (proc_desc) -
+ PROC_FRAME_ADJUST (proc_desc));
}
-mips_extra_func_info_t cached_proc_desc;
+static mips_extra_func_info_t cached_proc_desc;
-CORE_ADDR
+static CORE_ADDR
mips_frame_chain (struct frame_info *frame)
{
mips_extra_func_info_t proc_desc;
@@ -2056,7 +2410,7 @@ mips_frame_chain (struct frame_info *frame)
/* Check if the PC is inside a call stub. If it is, fetch the
PC of the caller of that stub. */
- if ((tmp = mips_skip_stub (saved_pc)) != 0)
+ if ((tmp = SKIP_TRAMPOLINE_CODE (saved_pc)) != 0)
saved_pc = tmp;
/* Look up the procedure descriptor for this PC. */
@@ -2071,22 +2425,24 @@ mips_frame_chain (struct frame_info *frame)
we loop forever if we see a zero size frame. */
if (PROC_FRAME_REG (proc_desc) == SP_REGNUM
&& PROC_FRAME_OFFSET (proc_desc) == 0
- /* The previous frame from a sigtramp frame might be frameless
- and have frame size zero. */
- && !frame->signal_handler_caller)
+ /* The previous frame from a sigtramp frame might be frameless
+ and have frame size zero. */
+ && !frame->signal_handler_caller
+ /* Check if this is a call dummy frame. */
+ && frame->pc != CALL_DUMMY_ADDRESS ())
return 0;
else
return get_frame_pointer (frame, proc_desc);
}
-void
+static void
mips_init_extra_frame_info (int fromleaf, struct frame_info *fci)
{
int regnum;
/* Use proc_desc calculated in frame_chain */
mips_extra_func_info_t proc_desc =
- fci->next ? cached_proc_desc : find_proc_desc (fci->pc, fci->next, 1);
+ fci->next ? cached_proc_desc : find_proc_desc (fci->pc, fci->next, 1);
fci->extra_info = (struct frame_extra_info *)
frame_obstack_alloc (sizeof (struct frame_extra_info));
@@ -2121,6 +2477,12 @@ mips_init_extra_frame_info (int fromleaf, struct frame_info *fci)
memcpy (fci->saved_regs, temp_saved_regs, SIZEOF_FRAME_SAVED_REGS);
fci->saved_regs[PC_REGNUM]
= fci->saved_regs[RA_REGNUM];
+ /* Set value of previous frame's stack pointer. Remember that
+ saved_regs[SP_REGNUM] is special in that it contains the
+ value of the stack pointer register. The other saved_regs
+ values are addresses (in the inferior) at which a given
+ register's value may be found. */
+ fci->saved_regs[SP_REGNUM] = fci->frame;
}
}
@@ -2176,7 +2538,7 @@ fp_register_arg_p (enum type_code typecode, struct type *arg_type)
&& (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION)
&& TYPE_NFIELDS (arg_type) == 1
&& TYPE_CODE (TYPE_FIELD_TYPE (arg_type, 0)) == TYPE_CODE_FLT))
- && MIPS_FPU_TYPE != MIPS_FPU_NONE);
+ && MIPS_FPU_TYPE != MIPS_FPU_NONE);
}
/* On o32, argument passing in GPRs depends on the alignment of the type being
@@ -2208,12 +2570,18 @@ mips_type_needs_double_align (struct type *type)
return 0;
}
-CORE_ADDR
-mips_push_arguments (int nargs,
- struct value **args,
- CORE_ADDR sp,
- int struct_return,
- CORE_ADDR struct_addr)
+/* Macros to round N up or down to the next A boundary;
+ A must be a power of two. */
+
+#define ROUND_DOWN(n,a) ((n) & ~((a)-1))
+#define ROUND_UP(n,a) (((n)+(a)-1) & ~((a)-1))
+
+static CORE_ADDR
+mips_eabi_push_arguments (int nargs,
+ struct value **args,
+ CORE_ADDR sp,
+ int struct_return,
+ CORE_ADDR struct_addr)
{
int argreg;
int float_argreg;
@@ -2221,44 +2589,40 @@ mips_push_arguments (int nargs,
int len = 0;
int stack_offset = 0;
- /* Macros to round N up or down to the next A boundary; A must be
- a power of two. */
-#define ROUND_DOWN(n,a) ((n) & ~((a)-1))
-#define ROUND_UP(n,a) (((n)+(a)-1) & ~((a)-1))
-
/* First ensure that the stack and structure return address (if any)
- are properly aligned. The stack has to be at least 64-bit aligned
- even on 32-bit machines, because doubles must be 64-bit aligned.
- On at least one MIPS variant, stack frames need to be 128-bit
- aligned, so we round to this widest known alignment. */
+ are properly aligned. The stack has to be at least 64-bit
+ aligned even on 32-bit machines, because doubles must be 64-bit
+ aligned. For n32 and n64, stack frames need to be 128-bit
+ aligned, so we round to this widest known alignment. */
+
sp = ROUND_DOWN (sp, 16);
struct_addr = ROUND_DOWN (struct_addr, 16);
- /* Now make space on the stack for the args. We allocate more
+ /* Now make space on the stack for the args. We allocate more
than necessary for EABI, because the first few arguments are
- passed in registers, but that's OK. */
+ passed in registers, but that's OK. */
for (argnum = 0; argnum < nargs; argnum++)
- len += ROUND_UP (TYPE_LENGTH (VALUE_TYPE (args[argnum])), MIPS_STACK_ARGSIZE);
+ len += ROUND_UP (TYPE_LENGTH (VALUE_TYPE (args[argnum])),
+ MIPS_STACK_ARGSIZE);
sp -= ROUND_UP (len, 16);
if (mips_debug)
- fprintf_unfiltered (gdb_stdlog, "mips_push_arguments: sp=0x%lx allocated %d\n",
- (long) sp, ROUND_UP (len, 16));
+ fprintf_unfiltered (gdb_stdlog,
+ "mips_eabi_push_arguments: sp=0x%s allocated %d\n",
+ paddr_nz (sp), ROUND_UP (len, 16));
/* Initialize the integer and float register pointers. */
argreg = A0_REGNUM;
float_argreg = FPA0_REGNUM;
- /* the struct_return pointer occupies the first parameter-passing reg */
+ /* The struct_return pointer occupies the first parameter-passing reg. */
if (struct_return)
{
if (mips_debug)
fprintf_unfiltered (gdb_stdlog,
- "mips_push_arguments: struct_return reg=%d 0x%lx\n",
- argreg, (long) struct_addr);
+ "mips_eabi_push_arguments: struct_return reg=%d 0x%s\n",
+ argreg, paddr_nz (struct_addr));
write_register (argreg++, struct_addr);
- if (MIPS_REGS_HAVE_HOME_P)
- stack_offset += MIPS_STACK_ARGSIZE;
}
/* Now load as many as possible of the first arguments into
@@ -2267,7 +2631,7 @@ mips_push_arguments (int nargs,
for (argnum = 0; argnum < nargs; argnum++)
{
char *val;
- char valbuf[MAX_REGISTER_RAW_SIZE];
+ char *valbuf = alloca (MAX_REGISTER_RAW_SIZE);
struct value *arg = args[argnum];
struct type *arg_type = check_typedef (VALUE_TYPE (arg));
int len = TYPE_LENGTH (arg_type);
@@ -2275,13 +2639,12 @@ mips_push_arguments (int nargs,
if (mips_debug)
fprintf_unfiltered (gdb_stdlog,
- "mips_push_arguments: %d len=%d type=%d",
+ "mips_eabi_push_arguments: %d len=%d type=%d",
argnum + 1, len, (int) typecode);
/* The EABI passes structures that do not fit in a register by
- reference. In all other cases, pass the structure by value. */
- if (MIPS_EABI
- && len > MIPS_SAVED_REGSIZE
+ reference. */
+ if (len > MIPS_SAVED_REGSIZE
&& (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION))
{
store_address (valbuf, MIPS_SAVED_REGSIZE, VALUE_ADDRESS (arg));
@@ -2297,8 +2660,8 @@ mips_push_arguments (int nargs,
/* 32-bit ABIs always start floating point arguments in an
even-numbered floating point register. Round the FP register
up before the check to see if there are any FP registers
- left. Non MIPS_EABI targets also pass the FP in the integer
- registers so also round up normal registers. */
+ left. Non MIPS_EABI targets also pass the FP in the integer
+ registers so also round up normal registers. */
if (!FP_REGISTER_DOUBLE
&& fp_register_arg_p (typecode, arg_type))
{
@@ -2317,7 +2680,7 @@ mips_push_arguments (int nargs,
because those registers are normally skipped. */
/* MIPS_EABI squeezes a struct that contains a single floating
point value into an FP register instead of pushing it onto the
- stack. */
+ stack. */
if (fp_register_arg_p (typecode, arg_type)
&& float_argreg <= MIPS_LAST_FP_ARG_REGNUM)
{
@@ -2332,13 +2695,6 @@ mips_push_arguments (int nargs,
fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
float_argreg, phex (regval, 4));
write_register (float_argreg++, regval);
- if (!MIPS_EABI)
- {
- if (mips_debug)
- fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
- argreg, phex (regval, 4));
- write_register (argreg++, regval);
- }
/* Write the high word of the double to the odd register(s). */
regval = extract_unsigned_integer (val + 4 - low_offset, 4);
@@ -2346,42 +2702,801 @@ mips_push_arguments (int nargs,
fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
float_argreg, phex (regval, 4));
write_register (float_argreg++, regval);
- if (!MIPS_EABI)
+ }
+ else
+ {
+ /* 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. */
+ LONGEST regval = extract_unsigned_integer (val, len);
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
+ float_argreg, phex (regval, len));
+ write_register (float_argreg++, regval);
+ }
+ }
+ else
+ {
+ /* Copy the argument to general registers or the stack in
+ register-sized pieces. Large arguments are split between
+ registers and stack. */
+ /* Note: structs whose size is not a multiple of MIPS_REGSIZE
+ are treated specially: Irix cc passes them in registers
+ where gcc sometimes puts them on the stack. For maximum
+ compatibility, we will put them in both places. */
+ int odd_sized_struct = ((len > MIPS_SAVED_REGSIZE) &&
+ (len % MIPS_SAVED_REGSIZE != 0));
+
+ /* Note: Floating-point values that didn't fit into an FP
+ register are only written to memory. */
+ while (len > 0)
+ {
+ /* Remember if the argument was written to the stack. */
+ int stack_used_p = 0;
+ int partial_len =
+ len < MIPS_SAVED_REGSIZE ? len : MIPS_SAVED_REGSIZE;
+
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " -- partial=%d",
+ partial_len);
+
+ /* Write this portion of the argument to the stack. */
+ if (argreg > MIPS_LAST_ARG_REGNUM
+ || odd_sized_struct
+ || fp_register_arg_p (typecode, arg_type))
{
+ /* Should shorter than int integer values be
+ promoted to int before being stored? */
+ int longword_offset = 0;
+ CORE_ADDR addr;
+ stack_used_p = 1;
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ {
+ if (MIPS_STACK_ARGSIZE == 8 &&
+ (typecode == TYPE_CODE_INT ||
+ typecode == TYPE_CODE_PTR ||
+ typecode == TYPE_CODE_FLT) && len <= 4)
+ longword_offset = MIPS_STACK_ARGSIZE - len;
+ else if ((typecode == TYPE_CODE_STRUCT ||
+ typecode == TYPE_CODE_UNION) &&
+ TYPE_LENGTH (arg_type) < MIPS_STACK_ARGSIZE)
+ longword_offset = MIPS_STACK_ARGSIZE - len;
+ }
+
if (mips_debug)
- fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
- argreg, phex (regval, 4));
- write_register (argreg++, regval);
+ {
+ fprintf_unfiltered (gdb_stdlog, " - stack_offset=0x%s",
+ paddr_nz (stack_offset));
+ fprintf_unfiltered (gdb_stdlog, " longword_offset=0x%s",
+ paddr_nz (longword_offset));
+ }
+
+ addr = sp + stack_offset + longword_offset;
+
+ if (mips_debug)
+ {
+ int i;
+ fprintf_unfiltered (gdb_stdlog, " @0x%s ",
+ paddr_nz (addr));
+ for (i = 0; i < partial_len; i++)
+ {
+ fprintf_unfiltered (gdb_stdlog, "%02x",
+ val[i] & 0xff);
+ }
+ }
+ write_memory (addr, val, partial_len);
}
+ /* Note!!! This is NOT an else clause. Odd sized
+ structs may go thru BOTH paths. Floating point
+ arguments will not. */
+ /* Write this portion of the argument to a general
+ purpose register. */
+ if (argreg <= MIPS_LAST_ARG_REGNUM
+ && !fp_register_arg_p (typecode, arg_type))
+ {
+ LONGEST regval = extract_unsigned_integer (val, partial_len);
+
+ if (mips_debug)
+ fprintf_filtered (gdb_stdlog, " - reg=%d val=%s",
+ argreg,
+ phex (regval, MIPS_SAVED_REGSIZE));
+ write_register (argreg, regval);
+ argreg++;
+ }
+
+ len -= partial_len;
+ val += partial_len;
+
+ /* Compute the the offset into the stack at which we
+ will copy the next parameter.
+
+ In the new EABI (and the NABI32), the stack_offset
+ only needs to be adjusted when it has been used. */
+
+ if (stack_used_p)
+ stack_offset += ROUND_UP (partial_len, MIPS_STACK_ARGSIZE);
+ }
+ }
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, "\n");
+ }
+
+ /* Return adjusted stack pointer. */
+ return sp;
+}
+
+/* N32/N64 version of push_arguments. */
+
+static CORE_ADDR
+mips_n32n64_push_arguments (int nargs,
+ struct value **args,
+ CORE_ADDR sp,
+ int struct_return,
+ CORE_ADDR struct_addr)
+{
+ int argreg;
+ int float_argreg;
+ int argnum;
+ int len = 0;
+ int stack_offset = 0;
+
+ /* First ensure that the stack and structure return address (if any)
+ are properly aligned. The stack has to be at least 64-bit
+ aligned even on 32-bit machines, because doubles must be 64-bit
+ aligned. For n32 and n64, stack frames need to be 128-bit
+ aligned, so we round to this widest known alignment. */
+
+ sp = ROUND_DOWN (sp, 16);
+ struct_addr = ROUND_DOWN (struct_addr, 16);
+
+ /* Now make space on the stack for the args. */
+ for (argnum = 0; argnum < nargs; argnum++)
+ len += ROUND_UP (TYPE_LENGTH (VALUE_TYPE (args[argnum])),
+ MIPS_STACK_ARGSIZE);
+ sp -= ROUND_UP (len, 16);
+
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "mips_n32n64_push_arguments: sp=0x%s allocated %d\n",
+ paddr_nz (sp), ROUND_UP (len, 16));
+
+ /* Initialize the integer and float register pointers. */
+ argreg = A0_REGNUM;
+ float_argreg = FPA0_REGNUM;
+
+ /* The struct_return pointer occupies the first parameter-passing reg. */
+ if (struct_return)
+ {
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "mips_n32n64_push_arguments: struct_return reg=%d 0x%s\n",
+ argreg, paddr_nz (struct_addr));
+ write_register (argreg++, struct_addr);
+ }
+
+ /* Now load as many as possible of the first arguments into
+ registers, and push the rest onto the stack. Loop thru args
+ from first to last. */
+ for (argnum = 0; argnum < nargs; argnum++)
+ {
+ char *val;
+ char *valbuf = alloca (MAX_REGISTER_RAW_SIZE);
+ struct value *arg = args[argnum];
+ struct type *arg_type = check_typedef (VALUE_TYPE (arg));
+ int len = TYPE_LENGTH (arg_type);
+ enum type_code typecode = TYPE_CODE (arg_type);
+
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "mips_n32n64_push_arguments: %d len=%d type=%d",
+ argnum + 1, len, (int) typecode);
+
+ val = (char *) VALUE_CONTENTS (arg);
+
+ if (fp_register_arg_p (typecode, arg_type)
+ && float_argreg <= MIPS_LAST_FP_ARG_REGNUM)
+ {
+ /* 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. */
+ LONGEST regval = extract_unsigned_integer (val, len);
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
+ float_argreg, phex (regval, len));
+ write_register (float_argreg++, regval);
+
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
+ argreg, phex (regval, len));
+ write_register (argreg, regval);
+ argreg += 1;
+ }
+ else
+ {
+ /* Copy the argument to general registers or the stack in
+ register-sized pieces. Large arguments are split between
+ registers and stack. */
+ /* Note: structs whose size is not a multiple of MIPS_REGSIZE
+ are treated specially: Irix cc passes them in registers
+ where gcc sometimes puts them on the stack. For maximum
+ compatibility, we will put them in both places. */
+ int odd_sized_struct = ((len > MIPS_SAVED_REGSIZE) &&
+ (len % MIPS_SAVED_REGSIZE != 0));
+ /* Note: Floating-point values that didn't fit into an FP
+ register are only written to memory. */
+ while (len > 0)
+ {
+ /* Rememer if the argument was written to the stack. */
+ int stack_used_p = 0;
+ int partial_len = len < MIPS_SAVED_REGSIZE ?
+ len : MIPS_SAVED_REGSIZE;
+
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " -- partial=%d",
+ partial_len);
+
+ /* Write this portion of the argument to the stack. */
+ if (argreg > MIPS_LAST_ARG_REGNUM
+ || odd_sized_struct
+ || fp_register_arg_p (typecode, arg_type))
+ {
+ /* Should shorter than int integer values be
+ promoted to int before being stored? */
+ int longword_offset = 0;
+ CORE_ADDR addr;
+ stack_used_p = 1;
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ {
+ if (MIPS_STACK_ARGSIZE == 8 &&
+ (typecode == TYPE_CODE_INT ||
+ typecode == TYPE_CODE_PTR ||
+ typecode == TYPE_CODE_FLT) && len <= 4)
+ longword_offset = MIPS_STACK_ARGSIZE - len;
+ else if ((typecode == TYPE_CODE_STRUCT ||
+ typecode == TYPE_CODE_UNION) &&
+ TYPE_LENGTH (arg_type) < MIPS_STACK_ARGSIZE)
+ longword_offset = MIPS_STACK_ARGSIZE - len;
+ }
+
+ if (mips_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, " - stack_offset=0x%s",
+ paddr_nz (stack_offset));
+ fprintf_unfiltered (gdb_stdlog, " longword_offset=0x%s",
+ paddr_nz (longword_offset));
+ }
+
+ addr = sp + stack_offset + longword_offset;
+
+ if (mips_debug)
+ {
+ int i;
+ fprintf_unfiltered (gdb_stdlog, " @0x%s ",
+ paddr_nz (addr));
+ for (i = 0; i < partial_len; i++)
+ {
+ fprintf_unfiltered (gdb_stdlog, "%02x",
+ val[i] & 0xff);
+ }
+ }
+ write_memory (addr, val, partial_len);
+ }
+
+ /* Note!!! This is NOT an else clause. Odd sized
+ structs may go thru BOTH paths. Floating point
+ arguments will not. */
+ /* Write this portion of the argument to a general
+ purpose register. */
+ if (argreg <= MIPS_LAST_ARG_REGNUM
+ && !fp_register_arg_p (typecode, arg_type))
+ {
+ LONGEST regval = extract_unsigned_integer (val, partial_len);
+
+ /* A non-floating-point argument being passed in a
+ general register. If a struct or union, and if
+ the remaining length is smaller than the register
+ size, we have to adjust the register value on
+ big endian targets.
+
+ It does not seem to be necessary to do the
+ same for integral types.
+
+ cagney/2001-07-23: gdb/179: Also, GCC, when
+ outputting LE O32 with sizeof (struct) <
+ MIPS_SAVED_REGSIZE, generates a left shift as
+ part of storing the argument in a register a
+ register (the left shift isn't generated when
+ sizeof (struct) >= MIPS_SAVED_REGSIZE). Since it
+ is quite possible that this is GCC contradicting
+ the LE/O32 ABI, GDB has not been adjusted to
+ accommodate this. Either someone needs to
+ demonstrate that the LE/O32 ABI specifies such a
+ left shift OR this new ABI gets identified as
+ such and GDB gets tweaked accordingly. */
+
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+ && partial_len < MIPS_SAVED_REGSIZE
+ && (typecode == TYPE_CODE_STRUCT ||
+ typecode == TYPE_CODE_UNION))
+ regval <<= ((MIPS_SAVED_REGSIZE - partial_len) *
+ TARGET_CHAR_BIT);
+
+ if (mips_debug)
+ fprintf_filtered (gdb_stdlog, " - reg=%d val=%s",
+ argreg,
+ phex (regval, MIPS_SAVED_REGSIZE));
+ write_register (argreg, regval);
+ argreg++;
+ }
+
+ len -= partial_len;
+ val += partial_len;
+
+ /* Compute the the offset into the stack at which we
+ will copy the next parameter.
+
+ In N32 (N64?), the stack_offset only needs to be
+ adjusted when it has been used. */
+
+ if (stack_used_p)
+ stack_offset += ROUND_UP (partial_len, MIPS_STACK_ARGSIZE);
+ }
+ }
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, "\n");
+ }
+
+ /* Return adjusted stack pointer. */
+ return sp;
+}
+
+/* O32 version of push_arguments. */
+
+static CORE_ADDR
+mips_o32_push_arguments (int nargs,
+ struct value **args,
+ CORE_ADDR sp,
+ int struct_return,
+ CORE_ADDR struct_addr)
+{
+ int argreg;
+ int float_argreg;
+ int argnum;
+ int len = 0;
+ int stack_offset = 0;
+
+ /* First ensure that the stack and structure return address (if any)
+ are properly aligned. The stack has to be at least 64-bit
+ aligned even on 32-bit machines, because doubles must be 64-bit
+ aligned. For n32 and n64, stack frames need to be 128-bit
+ aligned, so we round to this widest known alignment. */
+
+ sp = ROUND_DOWN (sp, 16);
+ struct_addr = ROUND_DOWN (struct_addr, 16);
+
+ /* Now make space on the stack for the args. */
+ for (argnum = 0; argnum < nargs; argnum++)
+ len += ROUND_UP (TYPE_LENGTH (VALUE_TYPE (args[argnum])),
+ MIPS_STACK_ARGSIZE);
+ sp -= ROUND_UP (len, 16);
+
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "mips_o32_push_arguments: sp=0x%s allocated %d\n",
+ paddr_nz (sp), ROUND_UP (len, 16));
+
+ /* Initialize the integer and float register pointers. */
+ argreg = A0_REGNUM;
+ float_argreg = FPA0_REGNUM;
+
+ /* The struct_return pointer occupies the first parameter-passing reg. */
+ if (struct_return)
+ {
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "mips_o32_push_arguments: struct_return reg=%d 0x%s\n",
+ argreg, paddr_nz (struct_addr));
+ write_register (argreg++, struct_addr);
+ stack_offset += MIPS_STACK_ARGSIZE;
+ }
+
+ /* Now load as many as possible of the first arguments into
+ registers, and push the rest onto the stack. Loop thru args
+ from first to last. */
+ for (argnum = 0; argnum < nargs; argnum++)
+ {
+ char *val;
+ char *valbuf = alloca (MAX_REGISTER_RAW_SIZE);
+ struct value *arg = args[argnum];
+ struct type *arg_type = check_typedef (VALUE_TYPE (arg));
+ int len = TYPE_LENGTH (arg_type);
+ enum type_code typecode = TYPE_CODE (arg_type);
+
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "mips_o32_push_arguments: %d len=%d type=%d",
+ argnum + 1, len, (int) typecode);
+
+ val = (char *) VALUE_CONTENTS (arg);
+
+ /* 32-bit ABIs always start floating point arguments in an
+ even-numbered floating point register. Round the FP register
+ up before the check to see if there are any FP registers
+ left. O32/O64 targets also pass the FP in the integer
+ registers so also round up normal registers. */
+ if (!FP_REGISTER_DOUBLE
+ && fp_register_arg_p (typecode, arg_type))
+ {
+ if ((float_argreg & 1))
+ float_argreg++;
+ }
+
+ /* Floating point arguments passed in registers have to be
+ treated specially. On 32-bit architectures, doubles
+ are passed in register pairs; the even register gets
+ the low word, and the odd register gets the high word.
+ On O32/O64, the first two floating point arguments are
+ also copied to general registers, because MIPS16 functions
+ don't use float registers for arguments. This duplication of
+ arguments in general registers can't hurt non-MIPS16 functions
+ because those registers are normally skipped. */
+
+ if (fp_register_arg_p (typecode, arg_type)
+ && float_argreg <= MIPS_LAST_FP_ARG_REGNUM)
+ {
+ if (!FP_REGISTER_DOUBLE && len == 8)
+ {
+ int low_offset = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? 4 : 0;
+ unsigned long regval;
+
+ /* Write the low word of the double to the even register(s). */
+ regval = extract_unsigned_integer (val + low_offset, 4);
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
+ float_argreg, phex (regval, 4));
+ write_register (float_argreg++, regval);
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
+ argreg, phex (regval, 4));
+ write_register (argreg++, regval);
+
+ /* Write the high word of the double to the odd register(s). */
+ regval = extract_unsigned_integer (val + 4 - low_offset, 4);
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
+ float_argreg, phex (regval, 4));
+ write_register (float_argreg++, regval);
+
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
+ argreg, phex (regval, 4));
+ write_register (argreg++, regval);
}
else
{
/* 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. */
+ above to ensure that it is even register aligned. */
LONGEST regval = extract_unsigned_integer (val, len);
if (mips_debug)
fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
float_argreg, phex (regval, 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. */
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
+ argreg, phex (regval, len));
+ write_register (argreg, regval);
+ argreg += FP_REGISTER_DOUBLE ? 1 : 2;
+ }
+ /* Reserve space for the FP register. */
+ stack_offset += ROUND_UP (len, MIPS_STACK_ARGSIZE);
+ }
+ else
+ {
+ /* Copy the argument to general registers or the stack in
+ register-sized pieces. Large arguments are split between
+ registers and stack. */
+ /* Note: structs whose size is not a multiple of MIPS_REGSIZE
+ are treated specially: Irix cc passes them in registers
+ where gcc sometimes puts them on the stack. For maximum
+ compatibility, we will put them in both places. */
+ int odd_sized_struct = ((len > MIPS_SAVED_REGSIZE) &&
+ (len % MIPS_SAVED_REGSIZE != 0));
+ /* Structures should be aligned to eight bytes (even arg registers)
+ on MIPS_ABI_O32, if their first member has double precision. */
+ if (MIPS_SAVED_REGSIZE < 8
+ && mips_type_needs_double_align (arg_type))
+ {
+ if ((argreg & 1))
+ argreg++;
+ }
+ /* Note: Floating-point values that didn't fit into an FP
+ register are only written to memory. */
+ while (len > 0)
+ {
+ /* Remember if the argument was written to the stack. */
+ int stack_used_p = 0;
+ int partial_len =
+ len < MIPS_SAVED_REGSIZE ? len : MIPS_SAVED_REGSIZE;
+
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " -- partial=%d",
+ partial_len);
+
+ /* Write this portion of the argument to the stack. */
+ if (argreg > MIPS_LAST_ARG_REGNUM
+ || odd_sized_struct
+ || fp_register_arg_p (typecode, arg_type))
{
- /* 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. */
+ /* Should shorter than int integer values be
+ promoted to int before being stored? */
+ int longword_offset = 0;
+ CORE_ADDR addr;
+ stack_used_p = 1;
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ {
+ if (MIPS_STACK_ARGSIZE == 8 &&
+ (typecode == TYPE_CODE_INT ||
+ typecode == TYPE_CODE_PTR ||
+ typecode == TYPE_CODE_FLT) && len <= 4)
+ longword_offset = MIPS_STACK_ARGSIZE - len;
+ }
+
if (mips_debug)
- fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
- argreg, phex (regval, len));
+ {
+ fprintf_unfiltered (gdb_stdlog, " - stack_offset=0x%s",
+ paddr_nz (stack_offset));
+ fprintf_unfiltered (gdb_stdlog, " longword_offset=0x%s",
+ paddr_nz (longword_offset));
+ }
+
+ addr = sp + stack_offset + longword_offset;
+
+ if (mips_debug)
+ {
+ int i;
+ fprintf_unfiltered (gdb_stdlog, " @0x%s ",
+ paddr_nz (addr));
+ for (i = 0; i < partial_len; i++)
+ {
+ fprintf_unfiltered (gdb_stdlog, "%02x",
+ val[i] & 0xff);
+ }
+ }
+ write_memory (addr, val, partial_len);
+ }
+
+ /* Note!!! This is NOT an else clause. Odd sized
+ structs may go thru BOTH paths. Floating point
+ arguments will not. */
+ /* Write this portion of the argument to a general
+ purpose register. */
+ if (argreg <= MIPS_LAST_ARG_REGNUM
+ && !fp_register_arg_p (typecode, arg_type))
+ {
+ LONGEST regval = extract_signed_integer (val, partial_len);
+ /* Value may need to be sign extended, because
+ MIPS_REGSIZE != MIPS_SAVED_REGSIZE. */
+
+ /* A non-floating-point argument being passed in a
+ general register. If a struct or union, and if
+ the remaining length is smaller than the register
+ size, we have to adjust the register value on
+ big endian targets.
+
+ It does not seem to be necessary to do the
+ same for integral types.
+
+ Also don't do this adjustment on O64 binaries.
+
+ cagney/2001-07-23: gdb/179: Also, GCC, when
+ outputting LE O32 with sizeof (struct) <
+ MIPS_SAVED_REGSIZE, generates a left shift as
+ part of storing the argument in a register a
+ register (the left shift isn't generated when
+ sizeof (struct) >= MIPS_SAVED_REGSIZE). Since it
+ is quite possible that this is GCC contradicting
+ the LE/O32 ABI, GDB has not been adjusted to
+ accommodate this. Either someone needs to
+ demonstrate that the LE/O32 ABI specifies such a
+ left shift OR this new ABI gets identified as
+ such and GDB gets tweaked accordingly. */
+
+ if (MIPS_SAVED_REGSIZE < 8
+ && TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+ && partial_len < MIPS_SAVED_REGSIZE
+ && (typecode == TYPE_CODE_STRUCT ||
+ typecode == TYPE_CODE_UNION))
+ regval <<= ((MIPS_SAVED_REGSIZE - partial_len) *
+ TARGET_CHAR_BIT);
+
+ if (mips_debug)
+ fprintf_filtered (gdb_stdlog, " - reg=%d val=%s",
+ argreg,
+ phex (regval, MIPS_SAVED_REGSIZE));
write_register (argreg, regval);
- argreg += FP_REGISTER_DOUBLE ? 1 : 2;
+ argreg++;
+
+ /* Prevent subsequent floating point arguments from
+ being passed in floating point registers. */
+ float_argreg = MIPS_LAST_FP_ARG_REGNUM + 1;
}
+
+ len -= partial_len;
+ val += partial_len;
+
+ /* Compute the the offset into the stack at which we
+ will copy the next parameter.
+
+ In older ABIs, the caller reserved space for
+ registers that contained arguments. This was loosely
+ refered to as their "home". Consequently, space is
+ always allocated. */
+
+ stack_offset += ROUND_UP (partial_len, MIPS_STACK_ARGSIZE);
+ }
+ }
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, "\n");
+ }
+
+ /* Return adjusted stack pointer. */
+ return sp;
+}
+
+/* O64 version of push_arguments. */
+
+static CORE_ADDR
+mips_o64_push_arguments (int nargs,
+ struct value **args,
+ CORE_ADDR sp,
+ int struct_return,
+ CORE_ADDR struct_addr)
+{
+ int argreg;
+ int float_argreg;
+ int argnum;
+ int len = 0;
+ int stack_offset = 0;
+
+ /* First ensure that the stack and structure return address (if any)
+ are properly aligned. The stack has to be at least 64-bit
+ aligned even on 32-bit machines, because doubles must be 64-bit
+ aligned. For n32 and n64, stack frames need to be 128-bit
+ aligned, so we round to this widest known alignment. */
+
+ sp = ROUND_DOWN (sp, 16);
+ struct_addr = ROUND_DOWN (struct_addr, 16);
+
+ /* Now make space on the stack for the args. */
+ for (argnum = 0; argnum < nargs; argnum++)
+ len += ROUND_UP (TYPE_LENGTH (VALUE_TYPE (args[argnum])),
+ MIPS_STACK_ARGSIZE);
+ sp -= ROUND_UP (len, 16);
+
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "mips_o64_push_arguments: sp=0x%s allocated %d\n",
+ paddr_nz (sp), ROUND_UP (len, 16));
+
+ /* Initialize the integer and float register pointers. */
+ argreg = A0_REGNUM;
+ float_argreg = FPA0_REGNUM;
+
+ /* The struct_return pointer occupies the first parameter-passing reg. */
+ if (struct_return)
+ {
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "mips_o64_push_arguments: struct_return reg=%d 0x%s\n",
+ argreg, paddr_nz (struct_addr));
+ write_register (argreg++, struct_addr);
+ stack_offset += MIPS_STACK_ARGSIZE;
+ }
+
+ /* Now load as many as possible of the first arguments into
+ registers, and push the rest onto the stack. Loop thru args
+ from first to last. */
+ for (argnum = 0; argnum < nargs; argnum++)
+ {
+ char *val;
+ char *valbuf = alloca (MAX_REGISTER_RAW_SIZE);
+ struct value *arg = args[argnum];
+ struct type *arg_type = check_typedef (VALUE_TYPE (arg));
+ int len = TYPE_LENGTH (arg_type);
+ enum type_code typecode = TYPE_CODE (arg_type);
+
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "mips_o64_push_arguments: %d len=%d type=%d",
+ argnum + 1, len, (int) typecode);
+
+ val = (char *) VALUE_CONTENTS (arg);
+
+ /* 32-bit ABIs always start floating point arguments in an
+ even-numbered floating point register. Round the FP register
+ up before the check to see if there are any FP registers
+ left. O32/O64 targets also pass the FP in the integer
+ registers so also round up normal registers. */
+ if (!FP_REGISTER_DOUBLE
+ && fp_register_arg_p (typecode, arg_type))
+ {
+ if ((float_argreg & 1))
+ float_argreg++;
+ }
+
+ /* Floating point arguments passed in registers have to be
+ treated specially. On 32-bit architectures, doubles
+ are passed in register pairs; the even register gets
+ the low word, and the odd register gets the high word.
+ On O32/O64, the first two floating point arguments are
+ also copied to general registers, because MIPS16 functions
+ don't use float registers for arguments. This duplication of
+ arguments in general registers can't hurt non-MIPS16 functions
+ because those registers are normally skipped. */
+
+ if (fp_register_arg_p (typecode, arg_type)
+ && float_argreg <= MIPS_LAST_FP_ARG_REGNUM)
+ {
+ if (!FP_REGISTER_DOUBLE && len == 8)
+ {
+ int low_offset = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? 4 : 0;
+ unsigned long regval;
+
+ /* Write the low word of the double to the even register(s). */
+ regval = extract_unsigned_integer (val + low_offset, 4);
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
+ float_argreg, phex (regval, 4));
+ write_register (float_argreg++, regval);
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
+ argreg, phex (regval, 4));
+ write_register (argreg++, regval);
+
+ /* Write the high word of the double to the odd register(s). */
+ regval = extract_unsigned_integer (val + 4 - low_offset, 4);
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
+ float_argreg, phex (regval, 4));
+ write_register (float_argreg++, regval);
+
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
+ argreg, phex (regval, 4));
+ write_register (argreg++, regval);
+ }
+ else
+ {
+ /* 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. */
+ LONGEST regval = extract_unsigned_integer (val, len);
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
+ float_argreg, phex (regval, len));
+ write_register (float_argreg++, regval);
+ /* 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. */
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
+ argreg, phex (regval, len));
+ write_register (argreg, regval);
+ argreg += FP_REGISTER_DOUBLE ? 1 : 2;
}
- /* Reserve space for the FP register. */
- if (MIPS_REGS_HAVE_HOME_P)
- stack_offset += ROUND_UP (len, MIPS_STACK_ARGSIZE);
+ /* Reserve space for the FP register. */
+ stack_offset += ROUND_UP (len, MIPS_STACK_ARGSIZE);
}
else
{
@@ -2395,20 +3510,21 @@ mips_push_arguments (int nargs,
int odd_sized_struct = ((len > MIPS_SAVED_REGSIZE) &&
(len % MIPS_SAVED_REGSIZE != 0));
/* Structures should be aligned to eight bytes (even arg registers)
- on MIPS_ABI_O32 if their first member has double precision. */
- if (gdbarch_tdep (current_gdbarch)->mips_abi == MIPS_ABI_O32
+ on MIPS_ABI_O32, if their first member has double precision. */
+ if (MIPS_SAVED_REGSIZE < 8
&& mips_type_needs_double_align (arg_type))
{
if ((argreg & 1))
argreg++;
}
/* Note: Floating-point values that didn't fit into an FP
- register are only written to memory. */
+ register are only written to memory. */
while (len > 0)
{
- /* Rememer if the argument was written to the stack. */
+ /* Remember if the argument was written to the stack. */
int stack_used_p = 0;
- int partial_len = len < MIPS_SAVED_REGSIZE ? len : MIPS_SAVED_REGSIZE;
+ int partial_len =
+ len < MIPS_SAVED_REGSIZE ? len : MIPS_SAVED_REGSIZE;
if (mips_debug)
fprintf_unfiltered (gdb_stdlog, " -- partial=%d",
@@ -2431,18 +3547,14 @@ mips_push_arguments (int nargs,
typecode == TYPE_CODE_PTR ||
typecode == TYPE_CODE_FLT) && len <= 4)
longword_offset = MIPS_STACK_ARGSIZE - len;
- else if ((typecode == TYPE_CODE_STRUCT ||
- typecode == TYPE_CODE_UNION) &&
- TYPE_LENGTH (arg_type) < MIPS_STACK_ARGSIZE)
- longword_offset = MIPS_STACK_ARGSIZE - len;
}
if (mips_debug)
{
- fprintf_unfiltered (gdb_stdlog, " - stack_offset=0x%lx",
- (long) stack_offset);
- fprintf_unfiltered (gdb_stdlog, " longword_offset=0x%lx",
- (long) longword_offset);
+ fprintf_unfiltered (gdb_stdlog, " - stack_offset=0x%s",
+ paddr_nz (stack_offset));
+ fprintf_unfiltered (gdb_stdlog, " longword_offset=0x%s",
+ paddr_nz (longword_offset));
}
addr = sp + stack_offset + longword_offset;
@@ -2450,10 +3562,12 @@ mips_push_arguments (int nargs,
if (mips_debug)
{
int i;
- fprintf_unfiltered (gdb_stdlog, " @0x%lx ", (long) addr);
+ fprintf_unfiltered (gdb_stdlog, " @0x%s ",
+ paddr_nz (addr));
for (i = 0; i < partial_len; i++)
{
- fprintf_unfiltered (gdb_stdlog, "%02x", val[i] & 0xff);
+ fprintf_unfiltered (gdb_stdlog, "%02x",
+ val[i] & 0xff);
}
}
write_memory (addr, val, partial_len);
@@ -2461,13 +3575,15 @@ mips_push_arguments (int nargs,
/* Note!!! This is NOT an else clause. Odd sized
structs may go thru BOTH paths. Floating point
- arguments will not. */
+ arguments will not. */
/* Write this portion of the argument to a general
- purpose register. */
+ purpose register. */
if (argreg <= MIPS_LAST_ARG_REGNUM
&& !fp_register_arg_p (typecode, arg_type))
{
- LONGEST regval = extract_unsigned_integer (val, partial_len);
+ LONGEST regval = extract_signed_integer (val, partial_len);
+ /* Value may need to be sign extended, because
+ MIPS_REGSIZE != MIPS_SAVED_REGSIZE. */
/* A non-floating-point argument being passed in a
general register. If a struct or union, and if
@@ -2478,8 +3594,7 @@ mips_push_arguments (int nargs,
It does not seem to be necessary to do the
same for integral types.
- Also don't do this adjustment on EABI and O64
- binaries.
+ Also don't do this adjustment on O64 binaries.
cagney/2001-07-23: gdb/179: Also, GCC, when
outputting LE O32 with sizeof (struct) <
@@ -2494,8 +3609,7 @@ mips_push_arguments (int nargs,
left shift OR this new ABI gets identified as
such and GDB gets tweaked accordingly. */
- if (!MIPS_EABI
- && MIPS_SAVED_REGSIZE < 8
+ if (MIPS_SAVED_REGSIZE < 8
&& TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
&& partial_len < MIPS_SAVED_REGSIZE
&& (typecode == TYPE_CODE_STRUCT ||
@@ -2510,11 +3624,9 @@ mips_push_arguments (int nargs,
write_register (argreg, regval);
argreg++;
- /* If this is the old ABI, prevent subsequent floating
- point arguments from being passed in floating point
- registers. */
- if (!MIPS_EABI)
- float_argreg = MIPS_LAST_FP_ARG_REGNUM + 1;
+ /* Prevent subsequent floating point arguments from
+ being passed in floating point registers. */
+ float_argreg = MIPS_LAST_FP_ARG_REGNUM + 1;
}
len -= partial_len;
@@ -2526,13 +3638,9 @@ mips_push_arguments (int nargs,
In older ABIs, the caller reserved space for
registers that contained arguments. This was loosely
refered to as their "home". Consequently, space is
- always allocated.
+ always allocated. */
- In the new EABI (and the NABI32), the stack_offset
- only needs to be adjusted when it has been used.. */
-
- if (MIPS_REGS_HAVE_HOME_P || stack_used_p)
- stack_offset += ROUND_UP (partial_len, MIPS_STACK_ARGSIZE);
+ stack_offset += ROUND_UP (partial_len, MIPS_STACK_ARGSIZE);
}
}
if (mips_debug)
@@ -2543,7 +3651,7 @@ mips_push_arguments (int nargs,
return sp;
}
-CORE_ADDR
+static CORE_ADDR
mips_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
{
/* Set the return address register to point to the entry
@@ -2555,7 +3663,7 @@ mips_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
static void
mips_push_register (CORE_ADDR * sp, int regno)
{
- char buffer[MAX_REGISTER_RAW_SIZE];
+ char *buffer = alloca (MAX_REGISTER_RAW_SIZE);
int regsize;
int offset;
if (MIPS_SAVED_REGSIZE < REGISTER_RAW_SIZE (regno))
@@ -2578,7 +3686,7 @@ mips_push_register (CORE_ADDR * sp, int regno)
/* MASK(i,j) == (1<<i) + (1<<(i+1)) + ... + (1<<j)). Assume i<=j<(MIPS_NUMREGS-1). */
#define MASK(i,j) (((1 << ((j)+1))-1) ^ ((1 << (i))-1))
-void
+static void
mips_push_dummy_frame (void)
{
int ireg;
@@ -2657,7 +3765,7 @@ mips_push_dummy_frame (void)
PROC_PC_REG (proc_desc) = RA_REGNUM;
}
-void
+static void
mips_pop_frame (void)
{
register int regnum;
@@ -2668,7 +3776,7 @@ mips_pop_frame (void)
write_register (PC_REGNUM, FRAME_SAVED_PC (frame));
if (frame->saved_regs == NULL)
- mips_find_saved_regs (frame);
+ FRAME_INIT_SAVED_REGS (frame);
for (regnum = 0; regnum < NUM_REGS; regnum++)
{
if (regnum != SP_REGNUM && regnum != PC_REGNUM
@@ -2677,6 +3785,7 @@ mips_pop_frame (void)
read_memory_integer (frame->saved_regs[regnum],
MIPS_SAVED_REGSIZE));
}
+
write_register (SP_REGNUM, new_sp);
flush_cached_frames ();
@@ -2715,6 +3824,13 @@ mips_pop_frame (void)
}
}
+static void
+mips_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
+ struct value **args, struct type *type, int gcc_p)
+{
+ write_register(T9_REGNUM, fun);
+}
+
/* Floating point register management.
Background: MIPS1 & 2 fp registers are 32 bits wide. To support
@@ -2834,7 +3950,7 @@ mips_read_fp_register_double (int regno, char *rare_buffer)
static void
mips_print_register (int regnum, int all)
{
- char raw_buffer[MAX_REGISTER_RAW_SIZE];
+ char *raw_buffer = alloca (MAX_REGISTER_RAW_SIZE);
/* Get the data in raw format. */
if (!frame_register_read (selected_frame, regnum, raw_buffer))
@@ -2851,7 +3967,7 @@ mips_print_register (int regnum, int all)
|| mips2_fp_compat ())
&& !((regnum - FP0_REGNUM) & 1))
{
- char dbuffer[2 * MAX_REGISTER_RAW_SIZE];
+ char *dbuffer = alloca (2 * MAX_REGISTER_RAW_SIZE);
mips_read_fp_register_double (regnum, dbuffer);
@@ -2986,7 +4102,7 @@ static int
do_gp_register_row (int regnum)
{
/* do values for GP (int) regs */
- char raw_buffer[MAX_REGISTER_RAW_SIZE];
+ char *raw_buffer = alloca (MAX_REGISTER_RAW_SIZE);
int ncols = (MIPS_REGSIZE == 8 ? 4 : 8); /* display cols per row */
int col, byte;
int start_regnum = regnum;
@@ -3044,7 +4160,7 @@ do_gp_register_row (int regnum)
/* MIPS_DO_REGISTERS_INFO(): called by "info register" command */
-void
+static void
mips_do_registers_info (int regnum, int fpregs)
{
if (regnum != -1) /* do one specified register */
@@ -3072,15 +4188,6 @@ mips_do_registers_info (int regnum, int fpregs)
}
}
-/* Return number of args passed to a frame. described by FIP.
- Can return -1, meaning no way to tell. */
-
-int
-mips_frame_num_args (struct frame_info *frame)
-{
- return -1;
-}
-
/* Is this a branch with a delay slot? */
static int is_delayed (unsigned long);
@@ -3319,7 +4426,7 @@ mips16_skip_prologue (CORE_ADDR pc)
We must skip more in the case where part of the prologue is in the
delay slot of a non-prologue instruction). */
-CORE_ADDR
+static CORE_ADDR
mips_skip_prologue (CORE_ADDR pc)
{
/* See if we can determine the end of the prologue via the symbol table.
@@ -3454,10 +4561,29 @@ return_value_location (struct type *valtype,
/* Given a return value in `regbuf' with a type `valtype', extract and
copy its value into `valbuf'. */
-void
-mips_extract_return_value (struct type *valtype,
- char regbuf[REGISTER_BYTES],
- char *valbuf)
+static void
+mips_eabi_extract_return_value (struct type *valtype,
+ char regbuf[REGISTER_BYTES],
+ char *valbuf)
+{
+ struct return_value_word lo;
+ struct return_value_word hi;
+ return_value_location (valtype, &hi, &lo);
+
+ memcpy (valbuf + lo.buf_offset,
+ regbuf + REGISTER_BYTE (lo.reg) + lo.reg_offset,
+ lo.len);
+
+ if (hi.len > 0)
+ memcpy (valbuf + hi.buf_offset,
+ regbuf + REGISTER_BYTE (hi.reg) + hi.reg_offset,
+ hi.len);
+}
+
+static void
+mips_o64_extract_return_value (struct type *valtype,
+ char regbuf[REGISTER_BYTES],
+ char *valbuf)
{
struct return_value_word lo;
struct return_value_word hi;
@@ -3476,10 +4602,34 @@ mips_extract_return_value (struct type *valtype,
/* Given a return value in `valbuf' with a type `valtype', write it's
value into the appropriate register. */
-void
-mips_store_return_value (struct type *valtype, char *valbuf)
+static void
+mips_eabi_store_return_value (struct type *valtype, char *valbuf)
+{
+ char *raw_buffer = alloca (MAX_REGISTER_RAW_SIZE);
+ struct return_value_word lo;
+ struct return_value_word hi;
+ return_value_location (valtype, &hi, &lo);
+
+ memset (raw_buffer, 0, sizeof (raw_buffer));
+ memcpy (raw_buffer + lo.reg_offset, valbuf + lo.buf_offset, lo.len);
+ write_register_bytes (REGISTER_BYTE (lo.reg),
+ raw_buffer,
+ REGISTER_RAW_SIZE (lo.reg));
+
+ if (hi.len > 0)
+ {
+ memset (raw_buffer, 0, sizeof (raw_buffer));
+ memcpy (raw_buffer + hi.reg_offset, valbuf + hi.buf_offset, hi.len);
+ write_register_bytes (REGISTER_BYTE (hi.reg),
+ raw_buffer,
+ REGISTER_RAW_SIZE (hi.reg));
+ }
+}
+
+static void
+mips_o64_store_return_value (struct type *valtype, char *valbuf)
{
- char raw_buffer[MAX_REGISTER_RAW_SIZE];
+ char *raw_buffer = alloca (MAX_REGISTER_RAW_SIZE);
struct return_value_word lo;
struct return_value_word hi;
return_value_location (valtype, &hi, &lo);
@@ -3500,10 +4650,274 @@ mips_store_return_value (struct type *valtype, char *valbuf)
}
}
+/* O32 ABI stuff. */
+
+static void
+mips_o32_xfer_return_value (struct type *type,
+ struct regcache *regcache,
+ bfd_byte *in, const bfd_byte *out)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ if (TYPE_CODE (type) == TYPE_CODE_FLT
+ && TYPE_LENGTH (type) == 4
+ && tdep->mips_fpu_type != MIPS_FPU_NONE)
+ {
+ /* A single-precision floating-point value. It fits in the
+ least significant part of FP0. */
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stderr, "Return float in $fp0\n");
+ mips_xfer_register (regcache, FP0_REGNUM, TYPE_LENGTH (type),
+ TARGET_BYTE_ORDER, in, out, 0);
+ }
+ else if (TYPE_CODE (type) == TYPE_CODE_FLT
+ && TYPE_LENGTH (type) == 8
+ && tdep->mips_fpu_type != MIPS_FPU_NONE)
+ {
+ /* A double-precision floating-point value. It fits in the
+ least significant part of FP0/FP1 but with byte ordering
+ based on the target (???). */
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stderr, "Return float in $fp0/$fp1\n");
+ switch (TARGET_BYTE_ORDER)
+ {
+ case BFD_ENDIAN_LITTLE:
+ mips_xfer_register (regcache, FP0_REGNUM + 0, 4,
+ TARGET_BYTE_ORDER, in, out, 0);
+ mips_xfer_register (regcache, FP0_REGNUM + 1, 4,
+ TARGET_BYTE_ORDER, in, out, 4);
+ break;
+ case BFD_ENDIAN_BIG:
+ mips_xfer_register (regcache, FP0_REGNUM + 1, 4,
+ TARGET_BYTE_ORDER, in, out, 0);
+ mips_xfer_register (regcache, FP0_REGNUM + 0, 4,
+ TARGET_BYTE_ORDER, in, out, 4);
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "bad switch");
+ }
+ }
+#if 0
+ else if (TYPE_CODE (type) == TYPE_CODE_STRUCT
+ && TYPE_NFIELDS (type) <= 2
+ && TYPE_NFIELDS (type) >= 1
+ && ((TYPE_NFIELDS (type) == 1
+ && (TYPE_CODE (TYPE_FIELD_TYPE (type, 0))
+ == TYPE_CODE_FLT))
+ || (TYPE_NFIELDS (type) == 2
+ && (TYPE_CODE (TYPE_FIELD_TYPE (type, 0))
+ == TYPE_CODE_FLT)
+ && (TYPE_CODE (TYPE_FIELD_TYPE (type, 1))
+ == TYPE_CODE_FLT)))
+ && tdep->mips_fpu_type != MIPS_FPU_NONE)
+ {
+ /* A struct that contains one or two floats. Each value is part
+ in the least significant part of their floating point
+ register.. */
+ bfd_byte *reg = alloca (MAX_REGISTER_RAW_SIZE);
+ int regnum;
+ int field;
+ for (field = 0, regnum = FP0_REGNUM;
+ field < TYPE_NFIELDS (type);
+ field++, regnum += 2)
+ {
+ int offset = (FIELD_BITPOS (TYPE_FIELDS (type)[field])
+ / TARGET_CHAR_BIT);
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stderr, "Return float struct+%d\n", offset);
+ mips_xfer_register (regcache, regnum, TYPE_LENGTH (TYPE_FIELD_TYPE (type, field)),
+ TARGET_BYTE_ORDER, in, out, offset);
+ }
+ }
+#endif
+#if 0
+ else if (TYPE_CODE (type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (type) == TYPE_CODE_UNION)
+ {
+ /* A structure or union. Extract the left justified value,
+ regardless of the byte order. I.e. DO NOT USE
+ mips_xfer_lower. */
+ int offset;
+ int regnum;
+ for (offset = 0, regnum = V0_REGNUM;
+ offset < TYPE_LENGTH (type);
+ offset += REGISTER_RAW_SIZE (regnum), regnum++)
+ {
+ int xfer = REGISTER_RAW_SIZE (regnum);
+ if (offset + xfer > TYPE_LENGTH (type))
+ xfer = TYPE_LENGTH (type) - offset;
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stderr, "Return struct+%d:%d in $%d\n",
+ offset, xfer, regnum);
+ mips_xfer_register (regcache, regnum, xfer, BFD_ENDIAN_UNKNOWN,
+ in, out, offset);
+ }
+ }
+#endif
+ else
+ {
+ /* A scalar extract each part but least-significant-byte
+ justified. o32 thinks registers are 4 byte, regardless of
+ the ISA. mips_stack_argsize controls this. */
+ int offset;
+ int regnum;
+ for (offset = 0, regnum = V0_REGNUM;
+ offset < TYPE_LENGTH (type);
+ offset += mips_stack_argsize (), regnum++)
+ {
+ int xfer = mips_stack_argsize ();
+ int pos = 0;
+ if (offset + xfer > TYPE_LENGTH (type))
+ xfer = TYPE_LENGTH (type) - offset;
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stderr, "Return scalar+%d:%d in $%d\n",
+ offset, xfer, regnum);
+ mips_xfer_register (regcache, regnum, xfer, TARGET_BYTE_ORDER,
+ in, out, offset);
+ }
+ }
+}
+
+static void
+mips_o32_extract_return_value (struct type *type,
+ struct regcache *regcache,
+ void *valbuf)
+{
+ mips_o32_xfer_return_value (type, regcache, valbuf, NULL);
+}
+
+static void
+mips_o32_store_return_value (struct type *type, char *valbuf)
+{
+ mips_o32_xfer_return_value (type, current_regcache, NULL, valbuf);
+}
+
+/* N32/N44 ABI stuff. */
+
+static void
+mips_n32n64_xfer_return_value (struct type *type,
+ struct regcache *regcache,
+ bfd_byte *in, const bfd_byte *out)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ if (TYPE_CODE (type) == TYPE_CODE_FLT
+ && tdep->mips_fpu_type != MIPS_FPU_NONE)
+ {
+ /* A floating-point value belongs in the least significant part
+ of FP0. */
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stderr, "Return float in $fp0\n");
+ mips_xfer_register (regcache, FP0_REGNUM, TYPE_LENGTH (type),
+ TARGET_BYTE_ORDER, in, out, 0);
+ }
+ else if (TYPE_CODE (type) == TYPE_CODE_STRUCT
+ && TYPE_NFIELDS (type) <= 2
+ && TYPE_NFIELDS (type) >= 1
+ && ((TYPE_NFIELDS (type) == 1
+ && (TYPE_CODE (TYPE_FIELD_TYPE (type, 0))
+ == TYPE_CODE_FLT))
+ || (TYPE_NFIELDS (type) == 2
+ && (TYPE_CODE (TYPE_FIELD_TYPE (type, 0))
+ == TYPE_CODE_FLT)
+ && (TYPE_CODE (TYPE_FIELD_TYPE (type, 1))
+ == TYPE_CODE_FLT)))
+ && tdep->mips_fpu_type != MIPS_FPU_NONE)
+ {
+ /* A struct that contains one or two floats. Each value is part
+ in the least significant part of their floating point
+ register.. */
+ bfd_byte *reg = alloca (MAX_REGISTER_RAW_SIZE);
+ int regnum;
+ int field;
+ for (field = 0, regnum = FP0_REGNUM;
+ field < TYPE_NFIELDS (type);
+ field++, regnum += 2)
+ {
+ int offset = (FIELD_BITPOS (TYPE_FIELDS (type)[field])
+ / TARGET_CHAR_BIT);
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stderr, "Return float struct+%d\n", offset);
+ mips_xfer_register (regcache, regnum, TYPE_LENGTH (TYPE_FIELD_TYPE (type, field)),
+ TARGET_BYTE_ORDER, in, out, offset);
+ }
+ }
+ else if (TYPE_CODE (type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (type) == TYPE_CODE_UNION)
+ {
+ /* A structure or union. Extract the left justified value,
+ regardless of the byte order. I.e. DO NOT USE
+ mips_xfer_lower. */
+ int offset;
+ int regnum;
+ for (offset = 0, regnum = V0_REGNUM;
+ offset < TYPE_LENGTH (type);
+ offset += REGISTER_RAW_SIZE (regnum), regnum++)
+ {
+ int xfer = REGISTER_RAW_SIZE (regnum);
+ if (offset + xfer > TYPE_LENGTH (type))
+ xfer = TYPE_LENGTH (type) - offset;
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stderr, "Return struct+%d:%d in $%d\n",
+ offset, xfer, regnum);
+ mips_xfer_register (regcache, regnum, xfer, BFD_ENDIAN_UNKNOWN,
+ in, out, offset);
+ }
+ }
+ else
+ {
+ /* A scalar extract each part but least-significant-byte
+ justified. */
+ int offset;
+ int regnum;
+ for (offset = 0, regnum = V0_REGNUM;
+ offset < TYPE_LENGTH (type);
+ offset += REGISTER_RAW_SIZE (regnum), regnum++)
+ {
+ int xfer = REGISTER_RAW_SIZE (regnum);
+ int pos = 0;
+ if (offset + xfer > TYPE_LENGTH (type))
+ xfer = TYPE_LENGTH (type) - offset;
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stderr, "Return scalar+%d:%d in $%d\n",
+ offset, xfer, regnum);
+ mips_xfer_register (regcache, regnum, xfer, TARGET_BYTE_ORDER,
+ in, out, offset);
+ }
+ }
+}
+
+static void
+mips_n32n64_extract_return_value (struct type *type,
+ struct regcache *regcache,
+ void *valbuf)
+{
+ mips_n32n64_xfer_return_value (type, regcache, valbuf, NULL);
+}
+
+static void
+mips_n32n64_store_return_value (struct type *type, char *valbuf)
+{
+ mips_n32n64_xfer_return_value (type, current_regcache, NULL, valbuf);
+}
+
+static void
+mips_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
+{
+ /* Nothing to do -- push_arguments does all the work. */
+}
+
+static CORE_ADDR
+mips_extract_struct_value_address (struct regcache *ignore)
+{
+ /* FIXME: This will only work at random. The caller passes the
+ struct_return address in V0, but it is not preserved. It may
+ still be there, or this may be a random value. */
+ return read_register (V0_REGNUM);
+}
+
/* Exported procedure: Is PC in the signal trampoline code */
-int
-in_sigtramp (CORE_ADDR pc, char *ignore)
+static int
+mips_pc_in_sigtramp (CORE_ADDR pc, char *ignore)
{
if (sigtramp_address == 0)
fixup_sigtramp ();
@@ -3567,10 +4981,7 @@ set_mipsfpu_single_command (char *args, int from_tty)
{
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;
- }
+ gdbarch_tdep (current_gdbarch)->mips_fpu_type = MIPS_FPU_SINGLE;
}
static void
@@ -3578,10 +4989,7 @@ set_mipsfpu_double_command (char *args, int from_tty)
{
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;
- }
+ gdbarch_tdep (current_gdbarch)->mips_fpu_type = MIPS_FPU_DOUBLE;
}
static void
@@ -3589,10 +4997,7 @@ set_mipsfpu_none_command (char *args, int from_tty)
{
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;
- }
+ gdbarch_tdep (current_gdbarch)->mips_fpu_type = MIPS_FPU_NONE;
}
static void
@@ -3635,7 +5040,7 @@ mips_show_processor_type_command (char *args, int from_tty)
/* Modify the actual processor type. */
-int
+static int
mips_set_processor_type (char *str)
{
int i;
@@ -3737,7 +5142,7 @@ gdb_print_insn_mips (bfd_vma memaddr, disassemble_info *info)
(if necessary) to point to the actual memory location where the
breakpoint should be inserted. */
-const unsigned char *
+static const unsigned char *
mips_breakpoint_from_pc (CORE_ADDR * pcptr, int *lenptr)
{
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
@@ -3819,7 +5224,7 @@ mips_breakpoint_from_pc (CORE_ADDR * pcptr, int *lenptr)
This function implements the SKIP_TRAMPOLINE_CODE macro.
*/
-CORE_ADDR
+static CORE_ADDR
mips_skip_stub (CORE_ADDR pc)
{
char *name;
@@ -3902,7 +5307,7 @@ mips_skip_stub (CORE_ADDR pc)
/* Return non-zero if the PC is inside a call thunk (aka stub or trampoline).
This implements the IN_SOLIB_CALL_TRAMPOLINE macro. */
-int
+static int
mips_in_call_stub (CORE_ADDR pc, char *name)
{
CORE_ADDR start_addr;
@@ -3930,7 +5335,7 @@ mips_in_call_stub (CORE_ADDR pc, char *name)
/* Return non-zero if the PC is inside a return thunk (aka stub or trampoline).
This implements the IN_SOLIB_RETURN_TRAMPOLINE macro. */
-int
+static int
mips_in_return_stub (CORE_ADDR pc, char *name)
{
CORE_ADDR start_addr;
@@ -3980,7 +5385,7 @@ mips_ignore_helper (CORE_ADDR pc)
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
+static CORE_ADDR
mips_call_dummy_address (void)
{
struct minimal_symbol *sym;
@@ -4126,6 +5531,47 @@ mips_integer_to_address (struct type *type, void *buf)
TYPE_LENGTH (builtin_type_void_data_ptr));
}
+static void
+mips_find_abi_section (bfd *abfd, asection *sect, void *obj)
+{
+ enum mips_abi *abip = (enum mips_abi *) obj;
+ const char *name = bfd_get_section_name (abfd, sect);
+
+ if (*abip != MIPS_ABI_UNKNOWN)
+ return;
+
+ if (strncmp (name, ".mdebug.", 8) != 0)
+ return;
+
+ if (strcmp (name, ".mdebug.abi32") == 0)
+ *abip = MIPS_ABI_O32;
+ else if (strcmp (name, ".mdebug.abiN32") == 0)
+ *abip = MIPS_ABI_N32;
+ else if (strcmp (name, ".mdebug.abiN64") == 0)
+ *abip = MIPS_ABI_N64;
+ else if (strcmp (name, ".mdebug.abiO64") == 0)
+ *abip = MIPS_ABI_O64;
+ else if (strcmp (name, ".mdebug.eabi32") == 0)
+ *abip = MIPS_ABI_EABI32;
+ else if (strcmp (name, ".mdebug.eabi64") == 0)
+ *abip = MIPS_ABI_EABI64;
+ else
+ warning ("unsupported ABI %s.", name + 8);
+}
+
+static enum mips_abi
+global_mips_abi (void)
+{
+ int i;
+
+ for (i = 0; mips_abi_strings[i] != NULL; i++)
+ if (mips_abi_strings[i] == mips_abi_string)
+ return (enum mips_abi) i;
+
+ internal_error (__FILE__, __LINE__,
+ "unknown ABI string");
+}
+
static struct gdbarch *
mips_gdbarch_init (struct gdbarch_info info,
struct gdbarch_list *arches)
@@ -4135,7 +5581,7 @@ mips_gdbarch_init (struct gdbarch_info info,
struct gdbarch *gdbarch;
struct gdbarch_tdep *tdep;
int elf_flags;
- enum mips_abi mips_abi;
+ enum mips_abi mips_abi, found_abi, wanted_abi;
enum gdb_osabi osabi = GDB_OSABI_UNKNOWN;
/* Reset the disassembly info, in case it was set to something
@@ -4157,7 +5603,7 @@ mips_gdbarch_init (struct gdbarch_info info,
osabi = gdbarch_lookup_osabi (info.abfd);
}
- /* Check ELF_FLAGS to see if it specifies the ABI being used. */
+ /* Check ELF_FLAGS to see if it specifies the ABI being used. */
switch ((elf_flags & EF_MIPS_ABI))
{
case E_MIPS_ABI_O32:
@@ -4180,7 +5626,16 @@ mips_gdbarch_init (struct gdbarch_info info,
break;
}
- /* Try the architecture for any hint of the corect ABI */
+ /* GCC creates a pseudo-section whose name describes the ABI. */
+ if (mips_abi == MIPS_ABI_UNKNOWN && info.abfd != NULL)
+ bfd_map_over_sections (info.abfd, mips_find_abi_section, &mips_abi);
+
+ /* If we have no bfd, then mips_abi will still be MIPS_ABI_UNKNOWN.
+ Use the ABI from the last architecture if there is one. */
+ if (info.abfd == NULL && arches != NULL)
+ mips_abi = gdbarch_tdep (arches->gdbarch)->found_abi;
+
+ /* Try the architecture for any hint of the correct ABI. */
if (mips_abi == MIPS_ABI_UNKNOWN
&& info.bfd_arch_info != NULL
&& info.bfd_arch_info->arch == bfd_arch_mips)
@@ -4196,14 +5651,27 @@ mips_gdbarch_init (struct gdbarch_info info,
break;
case bfd_mach_mips8000:
case bfd_mach_mips10000:
- mips_abi = MIPS_ABI_N32;
+ /* On Irix, ELF64 executables use the N64 ABI. The
+ pseudo-sections which describe the ABI aren't present
+ on IRIX. (Even for executables created by gcc.) */
+ if (bfd_get_flavour (info.abfd) == bfd_target_elf_flavour
+ && elf_elfheader (info.abfd)->e_ident[EI_CLASS] == ELFCLASS64)
+ mips_abi = MIPS_ABI_N64;
+ else
+ mips_abi = MIPS_ABI_N32;
break;
}
}
-#ifdef MIPS_DEFAULT_ABI
+
if (mips_abi == MIPS_ABI_UNKNOWN)
- mips_abi = MIPS_DEFAULT_ABI;
-#endif
+ mips_abi = MIPS_ABI_O32;
+
+ /* Now that we have found what the ABI for this binary would be,
+ check whether the user is overriding it. */
+ found_abi = mips_abi;
+ wanted_abi = global_mips_abi ();
+ if (wanted_abi != MIPS_ABI_UNKNOWN)
+ mips_abi = wanted_abi;
if (gdbarch_debug)
{
@@ -4213,6 +5681,9 @@ mips_gdbarch_init (struct gdbarch_info info,
fprintf_unfiltered (gdb_stdlog,
"mips_gdbarch_init: mips_abi = %d\n",
mips_abi);
+ fprintf_unfiltered (gdb_stdlog,
+ "mips_gdbarch_init: found_mips_abi = %d\n",
+ found_abi);
}
/* try to find a pre-existing architecture */
@@ -4221,7 +5692,7 @@ mips_gdbarch_init (struct gdbarch_info info,
arches = gdbarch_list_lookup_by_info (arches->next, &info))
{
/* MIPS needs to be pedantic about which ABI the object is
- using. */
+ using. */
if (gdbarch_tdep (arches->gdbarch)->elf_flags != elf_flags)
continue;
if (gdbarch_tdep (arches->gdbarch)->mips_abi != mips_abi)
@@ -4230,88 +5701,115 @@ mips_gdbarch_init (struct gdbarch_info info,
return arches->gdbarch;
}
- /* Need a new architecture. Fill in a target specific vector. */
+ /* 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;
tdep->osabi = osabi;
- /* Initially set everything according to the default ABI/ISA. */
+ /* Initially set everything according to the default ABI/ISA. */
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);
set_gdbarch_register_raw_size (gdbarch, mips_register_raw_size);
+ set_gdbarch_max_register_raw_size (gdbarch, 8);
+ set_gdbarch_max_register_virtual_size (gdbarch, 8);
+ tdep->found_abi = found_abi;
tdep->mips_abi = mips_abi;
+ set_gdbarch_elf_make_msymbol_special (gdbarch,
+ mips_elf_make_msymbol_special);
+
switch (mips_abi)
{
case MIPS_ABI_O32:
- tdep->mips_abi_string = "o32";
+ set_gdbarch_push_arguments (gdbarch, mips_o32_push_arguments);
+ set_gdbarch_deprecated_store_return_value (gdbarch, mips_o32_store_return_value);
+ set_gdbarch_extract_return_value (gdbarch, mips_o32_extract_return_value);
tdep->mips_default_saved_regsize = 4;
tdep->mips_default_stack_argsize = 4;
tdep->mips_fp_register_double = 0;
tdep->mips_last_arg_regnum = A0_REGNUM + 4 - 1;
tdep->mips_last_fp_arg_regnum = FPA0_REGNUM + 4 - 1;
- tdep->mips_regs_have_home_p = 1;
tdep->gdb_target_is_mips64 = 0;
tdep->default_mask_address_p = 0;
set_gdbarch_long_bit (gdbarch, 32);
set_gdbarch_ptr_bit (gdbarch, 32);
set_gdbarch_long_long_bit (gdbarch, 64);
+ set_gdbarch_reg_struct_has_addr (gdbarch,
+ mips_o32_reg_struct_has_addr);
+ set_gdbarch_use_struct_convention (gdbarch,
+ mips_o32_use_struct_convention);
break;
case MIPS_ABI_O64:
- tdep->mips_abi_string = "o64";
+ set_gdbarch_push_arguments (gdbarch, mips_o64_push_arguments);
+ set_gdbarch_deprecated_store_return_value (gdbarch, mips_o64_store_return_value);
+ set_gdbarch_deprecated_extract_return_value (gdbarch, mips_o64_extract_return_value);
tdep->mips_default_saved_regsize = 8;
tdep->mips_default_stack_argsize = 8;
tdep->mips_fp_register_double = 1;
tdep->mips_last_arg_regnum = A0_REGNUM + 4 - 1;
tdep->mips_last_fp_arg_regnum = FPA0_REGNUM + 4 - 1;
- tdep->mips_regs_have_home_p = 1;
tdep->gdb_target_is_mips64 = 1;
tdep->default_mask_address_p = 0;
set_gdbarch_long_bit (gdbarch, 32);
set_gdbarch_ptr_bit (gdbarch, 32);
set_gdbarch_long_long_bit (gdbarch, 64);
+ set_gdbarch_reg_struct_has_addr (gdbarch,
+ mips_o32_reg_struct_has_addr);
+ set_gdbarch_use_struct_convention (gdbarch,
+ mips_o32_use_struct_convention);
break;
case MIPS_ABI_EABI32:
- tdep->mips_abi_string = "eabi32";
+ set_gdbarch_push_arguments (gdbarch, mips_eabi_push_arguments);
+ set_gdbarch_deprecated_store_return_value (gdbarch, mips_eabi_store_return_value);
+ set_gdbarch_deprecated_extract_return_value (gdbarch, mips_eabi_extract_return_value);
tdep->mips_default_saved_regsize = 4;
tdep->mips_default_stack_argsize = 4;
tdep->mips_fp_register_double = 0;
tdep->mips_last_arg_regnum = A0_REGNUM + 8 - 1;
tdep->mips_last_fp_arg_regnum = FPA0_REGNUM + 8 - 1;
- tdep->mips_regs_have_home_p = 0;
tdep->gdb_target_is_mips64 = 0;
tdep->default_mask_address_p = 0;
set_gdbarch_long_bit (gdbarch, 32);
set_gdbarch_ptr_bit (gdbarch, 32);
set_gdbarch_long_long_bit (gdbarch, 64);
+ set_gdbarch_reg_struct_has_addr (gdbarch,
+ mips_eabi_reg_struct_has_addr);
+ set_gdbarch_use_struct_convention (gdbarch,
+ mips_eabi_use_struct_convention);
break;
case MIPS_ABI_EABI64:
- tdep->mips_abi_string = "eabi64";
+ set_gdbarch_push_arguments (gdbarch, mips_eabi_push_arguments);
+ set_gdbarch_deprecated_store_return_value (gdbarch, mips_eabi_store_return_value);
+ set_gdbarch_deprecated_extract_return_value (gdbarch, mips_eabi_extract_return_value);
tdep->mips_default_saved_regsize = 8;
tdep->mips_default_stack_argsize = 8;
tdep->mips_fp_register_double = 1;
tdep->mips_last_arg_regnum = A0_REGNUM + 8 - 1;
tdep->mips_last_fp_arg_regnum = FPA0_REGNUM + 8 - 1;
- tdep->mips_regs_have_home_p = 0;
tdep->gdb_target_is_mips64 = 1;
tdep->default_mask_address_p = 0;
set_gdbarch_long_bit (gdbarch, 64);
set_gdbarch_ptr_bit (gdbarch, 64);
set_gdbarch_long_long_bit (gdbarch, 64);
+ set_gdbarch_reg_struct_has_addr (gdbarch,
+ mips_eabi_reg_struct_has_addr);
+ set_gdbarch_use_struct_convention (gdbarch,
+ mips_eabi_use_struct_convention);
break;
case MIPS_ABI_N32:
- tdep->mips_abi_string = "n32";
- tdep->mips_default_saved_regsize = 4;
+ set_gdbarch_push_arguments (gdbarch, mips_n32n64_push_arguments);
+ set_gdbarch_deprecated_store_return_value (gdbarch, mips_n32n64_store_return_value);
+ set_gdbarch_extract_return_value (gdbarch, mips_n32n64_extract_return_value);
+ tdep->mips_default_saved_regsize = 8;
tdep->mips_default_stack_argsize = 8;
tdep->mips_fp_register_double = 1;
tdep->mips_last_arg_regnum = A0_REGNUM + 8 - 1;
tdep->mips_last_fp_arg_regnum = FPA0_REGNUM + 8 - 1;
- tdep->mips_regs_have_home_p = 0;
- tdep->gdb_target_is_mips64 = 0;
+ tdep->gdb_target_is_mips64 = 1;
tdep->default_mask_address_p = 0;
set_gdbarch_long_bit (gdbarch, 32);
set_gdbarch_ptr_bit (gdbarch, 32);
@@ -4327,21 +5825,46 @@ mips_gdbarch_init (struct gdbarch_info info,
tm_print_insn_info.mach = info.bfd_arch_info->mach;
else
tm_print_insn_info.mach = bfd_mach_mips8000;
+
+ set_gdbarch_use_struct_convention (gdbarch,
+ mips_n32n64_use_struct_convention);
+ set_gdbarch_reg_struct_has_addr (gdbarch,
+ mips_n32n64_reg_struct_has_addr);
break;
- default:
- tdep->mips_abi_string = "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);
+ case MIPS_ABI_N64:
+ set_gdbarch_push_arguments (gdbarch, mips_n32n64_push_arguments);
+ set_gdbarch_deprecated_store_return_value (gdbarch, mips_n32n64_store_return_value);
+ set_gdbarch_extract_return_value (gdbarch, mips_n32n64_extract_return_value);
+ tdep->mips_default_saved_regsize = 8;
+ tdep->mips_default_stack_argsize = 8;
+ tdep->mips_fp_register_double = 1;
tdep->mips_last_arg_regnum = A0_REGNUM + 8 - 1;
tdep->mips_last_fp_arg_regnum = FPA0_REGNUM + 8 - 1;
- tdep->mips_regs_have_home_p = 1;
- tdep->gdb_target_is_mips64 = 0;
+ tdep->gdb_target_is_mips64 = 1;
tdep->default_mask_address_p = 0;
- set_gdbarch_long_bit (gdbarch, 32);
- set_gdbarch_ptr_bit (gdbarch, 32);
+ set_gdbarch_long_bit (gdbarch, 64);
+ set_gdbarch_ptr_bit (gdbarch, 64);
set_gdbarch_long_long_bit (gdbarch, 64);
+
+ /* Set up the disassembler info, so that we get the right
+ register names from libopcodes. */
+ tm_print_insn_info.flavour = bfd_target_elf_flavour;
+ tm_print_insn_info.arch = bfd_arch_mips;
+ if (info.bfd_arch_info != NULL
+ && info.bfd_arch_info->arch == bfd_arch_mips
+ && info.bfd_arch_info->mach)
+ tm_print_insn_info.mach = info.bfd_arch_info->mach;
+ else
+ tm_print_insn_info.mach = bfd_mach_mips8000;
+
+ set_gdbarch_use_struct_convention (gdbarch,
+ mips_n32n64_use_struct_convention);
+ set_gdbarch_reg_struct_has_addr (gdbarch,
+ mips_n32n64_reg_struct_has_addr);
break;
+ default:
+ internal_error (__FILE__, __LINE__,
+ "unknown ABI in switch");
}
/* FIXME: jlarmour/2000-04-07: There *is* a flag EF_MIPS_32BIT_MODE
@@ -4350,7 +5873,7 @@ mips_gdbarch_init (struct gdbarch_info info,
``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
+ link with libraries compiled without "-gp32". This is
unnecessarily restrictive.
We could solve this problem by adding "-gp32" multilibs to gcc,
@@ -4360,10 +5883,10 @@ mips_gdbarch_init (struct gdbarch_info info,
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
+ 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. */
+ as 32-bit programs by default. */
/* enable/disable the MIPS FPU */
if (!mips_fpu_type_auto)
@@ -4390,16 +5913,19 @@ mips_gdbarch_init (struct gdbarch_info info,
/* 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. */
+ Further work on it is required. */
+ /* NOTE: many targets (esp. embedded) do not go thru the
+ gdbarch_register_name vector at all, instead bypassing it
+ by defining REGISTER_NAMES. */
set_gdbarch_register_name (gdbarch, mips_register_name);
set_gdbarch_read_pc (gdbarch, mips_read_pc);
set_gdbarch_write_pc (gdbarch, generic_target_write_pc);
set_gdbarch_read_fp (gdbarch, generic_target_read_fp);
- set_gdbarch_read_sp (gdbarch, generic_target_read_sp);
+ set_gdbarch_read_sp (gdbarch, mips_read_sp);
set_gdbarch_write_sp (gdbarch, generic_target_write_sp);
- /* Add/remove bits from an address. The MIPS needs be careful to
- ensure that all 32 bit addresses are sign extended to 64 bits. */
+ /* Add/remove bits from an address. The MIPS needs be careful to
+ ensure that all 32 bit addresses are sign extended to 64 bits. */
set_gdbarch_addr_bits_remove (gdbarch, mips_addr_bits_remove);
/* There's a mess in stack frame creation. See comments in
@@ -4407,12 +5933,13 @@ mips_gdbarch_init (struct gdbarch_info info,
set_gdbarch_init_frame_pc_first (gdbarch, mips_init_frame_pc_first);
set_gdbarch_init_frame_pc (gdbarch, init_frame_pc_noop);
- /* Map debug register numbers onto internal register numbers. */
+ /* Map debug register numbers onto internal register numbers. */
set_gdbarch_stab_reg_to_regnum (gdbarch, mips_stab_reg_to_regnum);
set_gdbarch_ecoff_reg_to_regnum (gdbarch, mips_ecoff_reg_to_regnum);
/* Initialize a frame */
set_gdbarch_init_extra_frame_info (gdbarch, mips_init_extra_frame_info);
+ set_gdbarch_frame_init_saved_regs (gdbarch, mips_frame_init_saved_regs);
/* MIPS version of CALL_DUMMY */
@@ -4421,19 +5948,36 @@ mips_gdbarch_init (struct gdbarch_info info,
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_push_return_address (gdbarch, mips_push_return_address);
+ set_gdbarch_push_dummy_frame (gdbarch, mips_push_dummy_frame);
+ set_gdbarch_pop_frame (gdbarch, mips_pop_frame);
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_fix_call_dummy (gdbarch, mips_fix_call_dummy);
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_register_convertible (gdbarch, mips_register_convertible);
+ set_gdbarch_register_convert_to_virtual (gdbarch,
+ mips_register_convert_to_virtual);
+ set_gdbarch_register_convert_to_raw (gdbarch,
+ mips_register_convert_to_raw);
+
set_gdbarch_coerce_float_to_double (gdbarch, mips_coerce_float_to_double);
+ set_gdbarch_frame_chain (gdbarch, mips_frame_chain);
set_gdbarch_frame_chain_valid (gdbarch, func_frame_chain_valid);
+ set_gdbarch_frameless_function_invocation (gdbarch,
+ generic_frameless_function_invocation_not);
+ set_gdbarch_frame_saved_pc (gdbarch, mips_frame_saved_pc);
+ set_gdbarch_frame_args_address (gdbarch, default_frame_address);
+ set_gdbarch_frame_locals_address (gdbarch, default_frame_address);
+ set_gdbarch_frame_num_args (gdbarch, frame_num_args_unknown);
+ set_gdbarch_frame_args_skip (gdbarch, 0);
+
set_gdbarch_get_saved_register (gdbarch, mips_get_saved_register);
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
@@ -4447,13 +5991,44 @@ mips_gdbarch_init (struct gdbarch_info info,
set_gdbarch_address_to_pointer (gdbarch, address_to_signed_pointer);
set_gdbarch_integer_to_address (gdbarch, mips_integer_to_address);
+ set_gdbarch_function_start_offset (gdbarch, 0);
+
+ /* There are MIPS targets which do not yet use this since they still
+ define REGISTER_VIRTUAL_TYPE. */
+ set_gdbarch_register_virtual_type (gdbarch, mips_register_virtual_type);
+ set_gdbarch_register_virtual_size (gdbarch, generic_register_size);
+
+ set_gdbarch_do_registers_info (gdbarch, mips_do_registers_info);
+ set_gdbarch_pc_in_sigtramp (gdbarch, mips_pc_in_sigtramp);
+
/* Hook in OS ABI-specific overrides, if they have been registered. */
gdbarch_init_osabi (info, gdbarch, osabi);
+ set_gdbarch_store_struct_return (gdbarch, mips_store_struct_return);
+ set_gdbarch_extract_struct_value_address (gdbarch,
+ mips_extract_struct_value_address);
+
+ set_gdbarch_skip_trampoline_code (gdbarch, mips_skip_stub);
+
+ set_gdbarch_in_solib_call_trampoline (gdbarch, mips_in_call_stub);
+ set_gdbarch_in_solib_return_trampoline (gdbarch, mips_in_return_stub);
+
return gdbarch;
}
static void
+mips_abi_update (char *ignore_args, int from_tty,
+ struct cmd_list_element *c)
+{
+ struct gdbarch_info info;
+
+ /* Force the architecture to update, and (if it's a MIPS architecture)
+ mips_gdbarch_init will take care of the rest. */
+ gdbarch_info_init (&info);
+ gdbarch_update_p (info);
+}
+
+static void
mips_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
@@ -4494,7 +6069,7 @@ mips_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
fprintf_unfiltered (file,
"mips_dump_tdep: tdep->mips_abi = %d (%s)\n",
tdep->mips_abi,
- tdep->mips_abi_string);
+ mips_abi_strings[tdep->mips_abi]);
fprintf_unfiltered (file,
"mips_dump_tdep: mips_mask_address_p() %d (default %d)\n",
mips_mask_address_p (),
@@ -4531,9 +6106,6 @@ mips_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *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,
@@ -4563,9 +6135,6 @@ mips_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
"mips_dump_tdep: CPLUS_MARKER = %c\n",
CPLUS_MARKER);
fprintf_unfiltered (file,
- "mips_dump_tdep: DEFAULT_MIPS_TYPE = %s\n",
- DEFAULT_MIPS_TYPE);
- fprintf_unfiltered (file,
"mips_dump_tdep: DO_REGISTERS_INFO # %s\n",
XSTRING (DO_REGISTERS_INFO));
fprintf_unfiltered (file,
@@ -4575,9 +6144,6 @@ mips_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
"mips_dump_tdep: ECOFF_REG_TO_REGNUM # %s\n",
XSTRING (ECOFF_REG_TO_REGNUM (REGNUM)));
fprintf_unfiltered (file,
- "mips_dump_tdep: ELF_MAKE_MSYMBOL_SPECIAL # %s\n",
- XSTRING (ELF_MAKE_MSYMBOL_SPECIAL (SYM, MSYM)));
- fprintf_unfiltered (file,
"mips_dump_tdep: FCRCS_REGNUM = %d\n",
FCRCS_REGNUM);
fprintf_unfiltered (file,
@@ -4674,11 +6240,6 @@ mips_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
"mips_dump_tdep: MIPS_SAVED_REGSIZE = %d\n",
MIPS_SAVED_REGSIZE);
fprintf_unfiltered (file,
- "mips_dump_tdep: MSYMBOL_IS_SPECIAL = function?\n");
- fprintf_unfiltered (file,
- "mips_dump_tdep: MSYMBOL_SIZE # %s\n",
- XSTRING (MSYMBOL_SIZE (MSYM)));
- fprintf_unfiltered (file,
"mips_dump_tdep: OP_LDFPR = used?\n");
fprintf_unfiltered (file,
"mips_dump_tdep: OP_LDGPR = used?\n");
@@ -4870,6 +6431,11 @@ _initialize_mips_tdep (void)
static struct cmd_list_element *mipsfpulist = NULL;
struct cmd_list_element *c;
+ mips_abi_string = mips_abi_strings [MIPS_ABI_UNKNOWN];
+ if (MIPS_ABI_LAST + 1
+ != sizeof (mips_abi_strings) / sizeof (mips_abi_strings[0]))
+ internal_error (__FILE__, __LINE__, "mips_abi_strings out of sync");
+
gdbarch_register (bfd_arch_mips, mips_gdbarch_init, mips_dump_tdep);
if (!tm_print_insn) /* Someone may have already set it */
tm_print_insn = gdb_print_insn_mips;
@@ -4912,6 +6478,22 @@ This option can be set to one of:\n\
&setmipscmdlist),
&showmipscmdlist);
+ /* Allow the user to override the ABI. */
+ c = add_set_enum_cmd
+ ("abi", class_obscure, mips_abi_strings, &mips_abi_string,
+ "Set the ABI used by this program.\n"
+ "This option can be set to one of:\n"
+ " auto - the default ABI associated with the current binary\n"
+ " o32\n"
+ " o64\n"
+ " n32\n"
+ " n64\n"
+ " eabi32\n"
+ " eabi64",
+ &setmipscmdlist);
+ add_show_from_set (c, &showmipscmdlist);
+ set_cmd_sfunc (c, mips_abi_update);
+
/* Let the user turn off floating point and set the fence post for
heuristic_proc_start. */
@@ -4940,21 +6522,6 @@ This option can be set to one of:\n\
"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\
-Set this to be able to access processor-type-specific registers.\n\
-",
- &setlist);
- set_cmd_cfunc (c, mips_set_processor_type_command);
- c = add_show_from_set (c, &showlist);
- set_cmd_cfunc (c, mips_show_processor_type_command);
-
- tmp_mips_processor_type = xstrdup (DEFAULT_MIPS_TYPE);
- mips_set_processor_type_command (xstrdup (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
because the user can always use "999999" or some such for unlimited. */
@@ -4973,13 +6540,13 @@ search. The only need to set it is when debugging a stripped executable.",
/* Allow the user to control whether the upper bits of 64-bit
addresses should be zeroed. */
- c = add_set_auto_boolean_cmd ("mask-address", no_class, &mask_address_var,
- "Set zeroing of upper 32 bits of 64-bit addresses.\n\
-Use \"on\" to enable the masking, \"off\" to disable it and \"auto\" to allow GDB to determine\n\
-the correct value.\n",
- &setmipscmdlist);
- add_cmd ("mask-address", no_class, show_mask_address,
- "Show current mask-address value", &showmipscmdlist);
+ add_setshow_auto_boolean_cmd ("mask-address", no_class, &mask_address_var, "\
+Set zeroing of upper 32 bits of 64-bit addresses.\n\
+Use \"on\" to enable the masking, \"off\" to disable it and \"auto\" to \n\
+allow GDB to determine the correct value.\n", "\
+Show zeroing of upper 32 bits of 64-bit addresses.",
+ NULL, show_mask_address,
+ &setmipscmdlist, &showmipscmdlist);
/* Allow the user to control the size of 32 bit registers within the
raw remote packet. */