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;
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. */
MIPS_FPU_TYPE. */
#define FP_REGISTER_DOUBLE (gdbarch_tdep (current_gdbarch)->mips_fp_register_double)
-/* 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. */
-
-#define MIPS_REGS_HAVE_HOME_P (gdbarch_tdep (current_gdbarch)->mips_regs_have_home_p)
-
/* 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. */
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);
char *mips_generic_reg_names[] = MIPS_REGISTER_NAMES;
char **mips_processor_reg_names = mips_generic_reg_names;
-const char *
+static const char *
mips_register_name (int i)
{
return mips_processor_reg_names[i];
"f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
"f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
"f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
- "fsr", "fir", "fp", "",
+ "fsr", "fir", "",/*"fp"*/ "",
"", "", "bus", "ccfg", "", "", "", "",
"", "", "port", "cmp", "", "", "epc", "prid",
};
"f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
"f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
"f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
- "fsr", "fir", "fp", "",
+ "fsr", "fir", ""/*"fp"*/, "",
"inx", "rand", "elo", "", "ctxt", "", "", "",
"", "", "ehi", "", "", "", "epc", "prid",
};
"f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
"f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
"f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
- "fsr", "fir", "fp", "",
+ "fsr", "fir", ""/*"fp"*/, "",
"inx", "rand", "elo", "cfg", "ctxt", "", "", "",
"", "", "ehi", "", "", "", "epc", "prid",
};
static int mips64_transfers_32bit_regs_p = 0;
-int
+static int
mips_register_raw_size (int reg_nr)
{
if (mips64_transfers_32bit_regs_p)
/* 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)
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)
{
TYPE_LENGTH (virtual_type));
}
-void
+static void
mips_register_convert_to_raw (struct type *virtual_type, int n,
char *virt_buf, char *raw_buf)
{
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.
}
}
+/* 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 auto_boolean mask_address_var = AUTO_BOOLEAN_AUTO;
/* Should call_function allocate stack space for a struct return? */
-int
+static int
mips_eabi_use_struct_convention (int gcc_p, struct type *type)
{
return (TYPE_LENGTH (type) > 2 * MIPS_SAVED_REGSIZE);
}
-int
+static int
mips_n32n64_use_struct_convention (int gcc_p, struct type *type)
{
return (TYPE_LENGTH (type) > 2 * MIPS_SAVED_REGSIZE);
}
-int
+static int
mips_o32_use_struct_convention (int gcc_p, struct type *type)
{
return 1; /* Structures are returned by ref in extra arg0. */
return 0; /* Assumption: N32/N64 never passes struct by ref. */
}
-int
+static int
mips_o32_reg_struct_has_addr (int gcc_p, struct type *type)
{
return 0; /* Assumption: O32/O64 never passes struct by ref. */
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;
}
/* 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;
return pc;
}
-CORE_ADDR
+static CORE_ADDR
mips16_next_pc (CORE_ADDR pc)
{
unsigned int insn = fetch_mips_16 (pc);
static CORE_ADDR
read_next_frame_reg (struct frame_info *fi, int regno)
{
- for (; fi; fi = fi->next)
+ int optimized;
+ CORE_ADDR addr;
+ int realnum;
+ enum lval_type lval;
+ void *raw_buffer = alloca (MAX_REGISTER_RAW_SIZE);
+ frame_register_unwind (fi, regno, &optimized, &lval, &addr, &realnum,
+ raw_buffer);
+ /* FIXME: cagney/2002-09-13: This is just soooo bad. The MIPS
+ should have a pseudo register range that correspons to the ABI's,
+ rather than the ISA's, view of registers. These registers would
+ then implicitly describe their size and hence could be used
+ without the below munging. */
+ if (lval == lval_memory)
{
- /* We have to get the saved sp from the sigcontext
- if it is a signal handler frame. */
- if (regno == SP_REGNUM && !fi->signal_handler_caller)
- return fi->frame;
- else
+ if (regno < 32)
{
- if (fi->saved_regs == NULL)
- FRAME_INIT_SAVED_REGS (fi);
- if (fi->saved_regs[regno])
- return read_memory_integer (ADDR_BITS_REMOVE (fi->saved_regs[regno]), MIPS_SAVED_REGSIZE);
+ /* Only MIPS_SAVED_REGSIZE bytes of GP registers are
+ saved. */
+ return read_memory_integer (addr, MIPS_SAVED_REGSIZE);
}
}
- return read_signed_register (regno);
+
+ return extract_signed_integer (raw_buffer, REGISTER_VIRTUAL_SIZE (regno));
}
/* mips_addr_bits_remove - remove useless address bits */
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;
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;
/* 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. */
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;
#define ROUND_DOWN(n,a) ((n) & ~((a)-1))
#define ROUND_UP(n,a) (((n)+(a)-1) & ~((a)-1))
-CORE_ADDR
-mips_push_arguments (int nargs,
- struct value **args,
- CORE_ADDR sp,
- int struct_return,
- CORE_ADDR struct_addr)
+/* Adjust the address downward (direction of stack growth) so that it
+ is correctly aligned for a new stack frame. */
+static CORE_ADDR
+mips_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ return ROUND_DOWN (addr, 16);
+}
+
+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;
int argnum;
int len = 0;
int stack_offset = 0;
- struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
/* First ensure that the stack and structure return address (if any)
are properly aligned. The stack has to be at least 64-bit
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%s allocated %d\n",
+ 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%s\n",
+ "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
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));
/* 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))
{
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)
{
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);
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);
- }
-
}
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. */
- if (MIPS_REGS_HAVE_HOME_P)
- stack_offset += ROUND_UP (len, MIPS_STACK_ARGSIZE);
}
else
{
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 (tdep->mips_abi == MIPS_ABI_O32
- && 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",
/* 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);
- /* 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 EABI and 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_EABI
- && 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++;
-
- /* 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;
}
len -= 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.
-
In the new EABI (and the NABI32), the stack_offset
- only needs to be adjusted when it has been used.. */
+ only needs to be adjusted when it has been used. */
- if (MIPS_REGS_HAVE_HOME_P || stack_used_p)
+ if (stack_used_p)
stack_offset += ROUND_UP (partial_len, MIPS_STACK_ARGSIZE);
}
}
return sp;
}
-CORE_ADDR
+/* N32/N64 version of push_arguments. */
+
+static CORE_ADDR
mips_n32n64_push_arguments (int nargs,
struct value **args,
CORE_ADDR sp,
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)
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)
return sp;
}
-CORE_ADDR
-mips_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
-{
- /* Set the return address register to point to the entry
- point of the program, where a breakpoint lies in wait. */
- write_register (RA_REGNUM, CALL_DUMMY_ADDRESS ());
- return sp;
-}
+/* O32 version of push_arguments. */
-static void
-mips_push_register (CORE_ADDR * sp, int regno)
+static CORE_ADDR
+mips_o32_push_arguments (int nargs,
+ struct value **args,
+ CORE_ADDR sp,
+ int struct_return,
+ CORE_ADDR struct_addr)
{
- char *buffer = alloca (MAX_REGISTER_RAW_SIZE);
- int regsize;
- int offset;
- if (MIPS_SAVED_REGSIZE < REGISTER_RAW_SIZE (regno))
+ 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)
{
- regsize = MIPS_SAVED_REGSIZE;
- offset = (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
- ? REGISTER_RAW_SIZE (regno) - MIPS_SAVED_REGSIZE
- : 0);
+ 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;
}
- else
+
+ /* 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++)
{
- regsize = REGISTER_RAW_SIZE (regno);
- offset = 0;
- }
- *sp -= regsize;
- read_register_gen (regno, buffer);
- write_memory (*sp, buffer + offset, regsize);
-}
+ 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);
-/* 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))
+ if (mips_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "mips_o32_push_arguments: %d len=%d type=%d",
+ argnum + 1, len, (int) typecode);
-void
-mips_push_dummy_frame (void)
-{
- int ireg;
- struct linked_proc_info *link = (struct linked_proc_info *)
- xmalloc (sizeof (struct linked_proc_info));
- mips_extra_func_info_t proc_desc = &link->info;
- CORE_ADDR sp = ADDR_BITS_REMOVE (read_signed_register (SP_REGNUM));
- CORE_ADDR old_sp = sp;
- link->next = linked_proc_desc_table;
- linked_proc_desc_table = link;
+ val = (char *) VALUE_CONTENTS (arg);
-/* FIXME! are these correct ? */
-#define PUSH_FP_REGNUM 16 /* must be a register preserved across calls */
-#define GEN_REG_SAVE_MASK MASK(1,16)|MASK(24,28)|(1<<(MIPS_NUMREGS-1))
-#define FLOAT_REG_SAVE_MASK MASK(0,19)
-#define FLOAT_SINGLE_REG_SAVE_MASK \
- ((1<<18)|(1<<16)|(1<<14)|(1<<12)|(1<<10)|(1<<8)|(1<<6)|(1<<4)|(1<<2)|(1<<0))
- /*
- * The registers we must save are all those not preserved across
- * procedure calls. Dest_Reg (see tm-mips.h) must also be saved.
- * In addition, we must save the PC, PUSH_FP_REGNUM, MMLO/-HI
- * and FP Control/Status registers.
+ /* 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. */
+ 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))
+ {
+ /* 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, " - 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++;
+
+ /* 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. */
+ 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))
+ {
+ /* 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, " - 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++;
+
+ /* 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;
+}
+
+static CORE_ADDR
+mips_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
+{
+ /* Set the return address register to point to the entry
+ point of the program, where a breakpoint lies in wait. */
+ write_register (RA_REGNUM, CALL_DUMMY_ADDRESS ());
+ return sp;
+}
+
+static void
+mips_push_register (CORE_ADDR * sp, int regno)
+{
+ char *buffer = alloca (MAX_REGISTER_RAW_SIZE);
+ int regsize;
+ int offset;
+ if (MIPS_SAVED_REGSIZE < REGISTER_RAW_SIZE (regno))
+ {
+ regsize = MIPS_SAVED_REGSIZE;
+ offset = (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+ ? REGISTER_RAW_SIZE (regno) - MIPS_SAVED_REGSIZE
+ : 0);
+ }
+ else
+ {
+ regsize = REGISTER_RAW_SIZE (regno);
+ offset = 0;
+ }
+ *sp -= regsize;
+ read_register_gen (regno, buffer);
+ write_memory (*sp, buffer + offset, regsize);
+}
+
+/* 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))
+
+static void
+mips_push_dummy_frame (void)
+{
+ int ireg;
+ struct linked_proc_info *link = (struct linked_proc_info *)
+ xmalloc (sizeof (struct linked_proc_info));
+ mips_extra_func_info_t proc_desc = &link->info;
+ CORE_ADDR sp = ADDR_BITS_REMOVE (read_signed_register (SP_REGNUM));
+ CORE_ADDR old_sp = sp;
+ link->next = linked_proc_desc_table;
+ linked_proc_desc_table = link;
+
+/* FIXME! are these correct ? */
+#define PUSH_FP_REGNUM 16 /* must be a register preserved across calls */
+#define GEN_REG_SAVE_MASK MASK(1,16)|MASK(24,28)|(1<<(MIPS_NUMREGS-1))
+#define FLOAT_REG_SAVE_MASK MASK(0,19)
+#define FLOAT_SINGLE_REG_SAVE_MASK \
+ ((1<<18)|(1<<16)|(1<<14)|(1<<12)|(1<<10)|(1<<8)|(1<<6)|(1<<4)|(1<<2)|(1<<0))
+ /*
+ * The registers we must save are all those not preserved across
+ * procedure calls. Dest_Reg (see tm-mips.h) must also be saved.
+ * In addition, we must save the PC, PUSH_FP_REGNUM, MMLO/-HI
+ * and FP Control/Status registers.
*
*
* Dummy frame layout:
PROC_PC_REG (proc_desc) = RA_REGNUM;
}
-void
+static void
mips_pop_frame (void)
{
register int regnum;
if (frame->saved_regs == NULL)
FRAME_INIT_SAVED_REGS (frame);
for (regnum = 0; regnum < NUM_REGS; regnum++)
- {
- if (regnum != SP_REGNUM && regnum != PC_REGNUM
- && frame->saved_regs[regnum])
- write_register (regnum,
- read_memory_integer (frame->saved_regs[regnum],
- MIPS_SAVED_REGSIZE));
- }
+ if (regnum != SP_REGNUM && regnum != PC_REGNUM
+ && frame->saved_regs[regnum])
+ {
+ /* Floating point registers must not be sign extended,
+ in case MIPS_SAVED_REGSIZE = 4 but sizeof (FP0_REGNUM) == 8. */
+
+ if (FP0_REGNUM <= regnum && regnum < FP0_REGNUM + 32)
+ write_register (regnum,
+ read_memory_unsigned_integer (frame->saved_regs[regnum],
+ MIPS_SAVED_REGSIZE));
+ else
+ write_register (regnum,
+ read_memory_integer (frame->saved_regs[regnum],
+ MIPS_SAVED_REGSIZE));
+ }
+
write_register (SP_REGNUM, new_sp);
flush_cached_frames ();
}
}
+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
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))
/* 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 */
}
}
-/* 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);
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.
/* 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;
/* 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 = alloca (MAX_REGISTER_RAW_SIZE);
struct return_value_word lo;
}
}
+/* 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 *regcache)
+{
+ /* 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. */
+ LONGEST val;
+
+ regcache_cooked_read_signed (regcache, V0_REGNUM, &val);
+ return val;
+}
+
/* 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 ();
/* Modify the actual processor type. */
-int
+static int
mips_set_processor_type (char *str)
{
int i;
(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)
This function implements the SKIP_TRAMPOLINE_CODE macro.
*/
-CORE_ADDR
+static CORE_ADDR
mips_skip_stub (CORE_ADDR pc)
{
char *name;
/* 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;
/* 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;
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;
static void
mips_get_saved_register (char *raw_buffer,
- int *optimized,
+ int *optimizedp,
CORE_ADDR *addrp,
struct frame_info *frame,
int regnum,
- enum lval_type *lval)
+ enum lval_type *lvalp)
{
- CORE_ADDR addr;
+ CORE_ADDR addrx;
+ enum lval_type lvalx;
+ int optimizedx;
+ int realnum;
if (!target_has_registers)
error ("No registers.");
- /* Normal systems don't optimize out things with register numbers. */
- if (optimized != NULL)
- *optimized = 0;
- addr = find_saved_register (frame, regnum);
- if (addr != 0)
+ /* Make certain that all needed parameters are present. */
+ if (addrp == NULL)
+ addrp = &addrx;
+ if (lvalp == NULL)
+ lvalp = &lvalx;
+ if (optimizedp == NULL)
+ optimizedp = &optimizedx;
+ frame_register_unwind (get_next_frame (frame), regnum, optimizedp, lvalp,
+ addrp, &realnum, raw_buffer);
+ /* FIXME: cagney/2002-09-13: This is just so bad. The MIPS should
+ have a pseudo register range that correspons to the ABI's, rather
+ than the ISA's, view of registers. These registers would then
+ implicitly describe their size and hence could be used without
+ the below munging. */
+ if ((*lvalp) == lval_memory)
{
- if (lval != NULL)
- *lval = lval_memory;
- if (regnum == SP_REGNUM)
- {
- if (raw_buffer != NULL)
- {
- /* Put it back in target format. */
- store_address (raw_buffer, REGISTER_RAW_SIZE (regnum),
- (LONGEST) addr);
- }
- if (addrp != NULL)
- *addrp = 0;
- return;
- }
if (raw_buffer != NULL)
{
- LONGEST val;
if (regnum < 32)
- /* Only MIPS_SAVED_REGSIZE bytes of GP registers are
- saved. */
- val = read_memory_integer (addr, MIPS_SAVED_REGSIZE);
- else
- val = read_memory_integer (addr, REGISTER_RAW_SIZE (regnum));
- store_address (raw_buffer, REGISTER_RAW_SIZE (regnum), val);
+ {
+ /* Only MIPS_SAVED_REGSIZE bytes of GP registers are
+ saved. */
+ LONGEST val = read_memory_integer ((*addrp), MIPS_SAVED_REGSIZE);
+ store_address (raw_buffer, REGISTER_RAW_SIZE (regnum), val);
+ }
}
}
- else
- {
- if (lval != NULL)
- *lval = lval_register;
- addr = REGISTER_BYTE (regnum);
- if (raw_buffer != NULL)
- read_register_gen (regnum, raw_buffer);
- }
- if (addrp != NULL)
- *addrp = addr;
}
/* Immediately after a function call, return the saved pc.
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:
}
}
-#ifdef MIPS_DEFAULT_ABI
- if (mips_abi == MIPS_ABI_UNKNOWN)
- mips_abi = MIPS_DEFAULT_ABI;
-#endif
-
if (mips_abi == MIPS_ABI_UNKNOWN)
mips_abi = MIPS_ABI_O32;
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)
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:
- set_gdbarch_push_arguments (gdbarch, mips_push_arguments);
+ 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);
mips_o32_use_struct_convention);
break;
case MIPS_ABI_O64:
- set_gdbarch_push_arguments (gdbarch, mips_push_arguments);
+ 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);
mips_o32_use_struct_convention);
break;
case MIPS_ABI_EABI32:
- set_gdbarch_push_arguments (gdbarch, mips_push_arguments);
+ 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);
mips_eabi_use_struct_convention);
break;
case MIPS_ABI_EABI64:
- set_gdbarch_push_arguments (gdbarch, mips_push_arguments);
+ 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);
break;
case MIPS_ABI_N32:
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 = 1;
tdep->default_mask_address_p = 0;
set_gdbarch_long_bit (gdbarch, 32);
break;
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 = 0;
tdep->gdb_target_is_mips64 = 1;
tdep->default_mask_address_p = 0;
set_gdbarch_long_bit (gdbarch, 64);
``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,
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)
/* 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_fp (gdbarch, mips_read_sp); /* Draft FRAME base. */
+ 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
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);
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_register_convertible (gdbarch, generic_register_convertible_not);
+ set_gdbarch_frame_align (gdbarch, mips_frame_align);
+ 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);
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;
}
fprintf_unfiltered (file,
"mips_dump_tdep: FP_REGISTER_DOUBLE = %d\n",
FP_REGISTER_DOUBLE);
- fprintf_unfiltered (file,
- "mips_dump_tdep: MIPS_REGS_HAVE_HOME_P = %d\n",
- MIPS_REGS_HAVE_HOME_P);
fprintf_unfiltered (file,
"mips_dump_tdep: MIPS_DEFAULT_STACK_ARGSIZE = %d\n",
MIPS_DEFAULT_STACK_ARGSIZE);
fprintf_unfiltered (file,
"mips_dump_tdep: 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,
"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,
"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,