/* Target-dependent code for the MIPS architecture, for GDB, the GNU Debugger.
Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
- 1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
Contributed by Alessandro Forin(af@cs.cmu.edu) at CMU
and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin.
#include "defs.h"
#include "gdb_string.h"
+#include "gdb_assert.h"
#include "frame.h"
#include "inferior.h"
#include "symtab.h"
#include "arch-utils.h"
#include "regcache.h"
#include "osabi.h"
+#include "mips-tdep.h"
+#include "block.h"
#include "opcode/mips.h"
#include "elf/mips.h"
MIPS_FPU_DOUBLE_REGSIZE = 8
};
-/* All the possible MIPS ABIs. */
-
-enum mips_abi
- {
- MIPS_ABI_UNKNOWN = 0,
- MIPS_ABI_N32,
- MIPS_ABI_O32,
- MIPS_ABI_N64,
- MIPS_ABI_O64,
- MIPS_ABI_EABI32,
- MIPS_ABI_EABI64,
- MIPS_ABI_LAST
- };
static const char *mips_abi_string;
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;
-
- enum gdb_osabi osabi;
};
#define MIPS_EABI (gdbarch_tdep (current_gdbarch)->mips_abi == MIPS_ABI_EABI32 \
#define MIPS_SAVED_REGSIZE (mips_saved_regsize())
+/* Return the MIPS ABI associated with GDBARCH. */
+enum mips_abi
+mips_abi (struct gdbarch *gdbarch)
+{
+ return gdbarch_tdep (gdbarch)->mips_abi;
+}
+
static unsigned int
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. */
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 void mips_print_register (int, int);
-static mips_extra_func_info_t
-heuristic_proc_desc (CORE_ADDR, CORE_ADDR, struct frame_info *, int);
+static mips_extra_func_info_t heuristic_proc_desc (CORE_ADDR, CORE_ADDR,
+ struct frame_info *, int);
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);
static void reinit_frame_cache_sfunc (char *, int, struct cmd_list_element *);
-static mips_extra_func_info_t
-find_proc_desc (CORE_ADDR pc, struct frame_info *next_frame, int cur_frame);
+static mips_extra_func_info_t find_proc_desc (CORE_ADDR pc,
+ struct frame_info *next_frame,
+ int cur_frame);
static CORE_ADDR after_prologue (CORE_ADDR pc,
mips_extra_func_info_t proc_desc);
/* A set of original names, to be used when restoring back to generic
registers from a specific set. */
+static char *mips_generic_reg_names[] = MIPS_REGISTER_NAMES;
-char *mips_generic_reg_names[] = MIPS_REGISTER_NAMES;
-char **mips_processor_reg_names = mips_generic_reg_names;
+/* Integer registers 0 thru 31 are handled explicitly by
+ mips_register_name(). Processor specific registers 32 and above
+ are listed in the sets of register names assigned to
+ mips_processor_reg_names. */
+static char **mips_processor_reg_names = mips_generic_reg_names;
-const char *
-mips_register_name (int i)
+/* Return the name of the register corresponding to REGNO. */
+static const char *
+mips_register_name (int regno)
{
- return mips_processor_reg_names[i];
+ /* GPR names for all ABIs other than n32/n64. */
+ static char *mips_gpr_names[] = {
+ "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
+ "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
+ "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
+ "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra",
+ };
+
+ /* GPR names for n32 and n64 ABIs. */
+ static char *mips_n32_n64_gpr_names[] = {
+ "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
+ "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
+ "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
+ "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
+ };
+
+ enum mips_abi abi = mips_abi (current_gdbarch);
+
+ /* The MIPS integer registers are always mapped from 0 to 31. The
+ names of the registers (which reflects the conventions regarding
+ register use) vary depending on the ABI. */
+ if (0 <= regno && regno < 32)
+ {
+ if (abi == MIPS_ABI_N32 || abi == MIPS_ABI_N64)
+ return mips_n32_n64_gpr_names[regno];
+ else
+ return mips_gpr_names[regno];
+ }
+ else if (32 <= regno && regno < NUM_REGS)
+ return mips_processor_reg_names[regno - 32];
+ else
+ internal_error (__FILE__, __LINE__,
+ "mips_register_name: bad register number %d", regno);
}
+
/* *INDENT-OFF* */
/* Names of IDT R3041 registers. */
char *mips_r3041_reg_names[] = {
- "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
- "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
- "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
- "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra",
"sr", "lo", "hi", "bad", "cause","pc",
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
"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",
};
/* Names of IDT R3051 registers. */
char *mips_r3051_reg_names[] = {
- "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
- "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
- "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
- "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra",
"sr", "lo", "hi", "bad", "cause","pc",
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
"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",
};
/* Names of IDT R3081 registers. */
char *mips_r3081_reg_names[] = {
- "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
- "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
- "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
- "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra",
"sr", "lo", "hi", "bad", "cause","pc",
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
"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",
};
/* Names of LSI 33k registers. */
char *mips_lsi33k_reg_names[] = {
- "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
- "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
- "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
- "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra",
"epc", "hi", "lo", "sr", "cause","badvaddr",
"dcic", "bpc", "bda", "", "", "", "", "",
"", "", "", "", "", "", "", "",
mips_print_extra_frame_info (struct frame_info *fi)
{
if (fi
- && fi->extra_info
- && fi->extra_info->proc_desc
- && fi->extra_info->proc_desc->pdr.framereg < NUM_REGS)
+ && get_frame_extra_info (fi)
+ && get_frame_extra_info (fi)->proc_desc
+ && get_frame_extra_info (fi)->proc_desc->pdr.framereg < NUM_REGS)
printf_filtered (" frame pointer is at %s+%s\n",
- REGISTER_NAME (fi->extra_info->proc_desc->pdr.framereg),
- paddr_d (fi->extra_info->proc_desc->pdr.frameoffset));
+ REGISTER_NAME (get_frame_extra_info (fi)->proc_desc->pdr.framereg),
+ paddr_d (get_frame_extra_info (fi)->proc_desc->pdr.frameoffset));
}
/* Number of bytes of storage in the actual machine representation for
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);
/* FIXME! Is this correct?? */
#define SIGFRAME_REG_SIZE MIPS_REGSIZE
#endif
- if (fci->signal_handler_caller)
+ if ((get_frame_type (fci) == SIGTRAMP_FRAME))
{
for (ireg = 0; ireg < MIPS_NUMREGS; ireg++)
{
- reg_position = fci->frame + SIGFRAME_REGSAVE_OFF
+ reg_position = get_frame_base (fci) + SIGFRAME_REGSAVE_OFF
+ ireg * SIGFRAME_REG_SIZE;
- fci->saved_regs[ireg] = reg_position;
+ get_frame_saved_regs (fci)[ireg] = reg_position;
}
for (ireg = 0; ireg < MIPS_NUMREGS; ireg++)
{
- reg_position = fci->frame + SIGFRAME_FPREGSAVE_OFF
+ reg_position = get_frame_base (fci) + SIGFRAME_FPREGSAVE_OFF
+ ireg * SIGFRAME_REG_SIZE;
- fci->saved_regs[FP0_REGNUM + ireg] = reg_position;
+ get_frame_saved_regs (fci)[FP0_REGNUM + ireg] = reg_position;
}
- fci->saved_regs[PC_REGNUM] = fci->frame + SIGFRAME_PC_OFF;
+ get_frame_saved_regs (fci)[PC_REGNUM] = get_frame_base (fci) + SIGFRAME_PC_OFF;
return;
}
- proc_desc = fci->extra_info->proc_desc;
+ proc_desc = get_frame_extra_info (fci)->proc_desc;
if (proc_desc == NULL)
/* I'm not sure how/whether this can happen. Normally when we can't
find a proc_desc, we "synthesize" one using heuristic_proc_desc
a signal, we assume that all registers have been saved.
This assumes that all register saves in a function happen before
the first function call. */
- (fci->next == NULL || fci->next->signal_handler_caller)
+ (get_next_frame (fci) == NULL
+ || (get_frame_type (get_next_frame (fci)) == SIGTRAMP_FRAME))
/* In a dummy frame we know exactly where things are saved. */
&& !PROC_DESC_IS_DUMMY (proc_desc)
/* Don't bother unless we are inside a function prologue. Outside the
prologue, we know where everything is. */
- && in_prologue (fci->pc, PROC_LOW_ADDR (proc_desc))
+ && in_prologue (get_frame_pc (fci), PROC_LOW_ADDR (proc_desc))
/* Not sure exactly what kernel_trap means, but if it means
the kernel saves the registers without a prologue doing it,
/* Scan through this function's instructions preceding the current
PC, and look for those that save registers. */
- while (addr < fci->pc)
+ while (addr < get_frame_pc (fci))
{
inst = mips_fetch_instruction (addr);
if (pc_is_mips16 (addr))
/* Fill in the offsets for the registers which gen_mask says
were saved. */
- reg_position = fci->frame + PROC_REG_OFFSET (proc_desc);
+ reg_position = get_frame_base (fci) + PROC_REG_OFFSET (proc_desc);
for (ireg = MIPS_NUMREGS - 1; gen_mask; --ireg, gen_mask <<= 1)
if (gen_mask & 0x80000000)
{
- fci->saved_regs[ireg] = reg_position;
+ get_frame_saved_regs (fci)[ireg] = reg_position;
reg_position -= MIPS_SAVED_REGSIZE;
}
int sreg_count = (inst >> 6) & 3;
/* Check if the ra register was pushed on the stack. */
- reg_position = fci->frame + PROC_REG_OFFSET (proc_desc);
+ reg_position = get_frame_base (fci) + PROC_REG_OFFSET (proc_desc);
if (inst & 0x20)
reg_position -= MIPS_SAVED_REGSIZE;
/* Check if the s0 and s1 registers were pushed on the stack. */
for (reg = 16; reg < sreg_count + 16; reg++)
{
- fci->saved_regs[reg] = reg_position;
+ get_frame_saved_regs (fci)[reg] = reg_position;
reg_position -= MIPS_SAVED_REGSIZE;
}
}
/* Fill in the offsets for the registers which float_mask says
were saved. */
- reg_position = fci->frame + PROC_FREG_OFFSET (proc_desc);
+ reg_position = get_frame_base (fci) + PROC_FREG_OFFSET (proc_desc);
/* Apparently, the freg_offset gives the offset to the first 64 bit
saved.
for (ireg = MIPS_NUMREGS - 1; float_mask; --ireg, float_mask <<= 1)
if (float_mask & 0x80000000)
{
- fci->saved_regs[FP0_REGNUM + ireg] = reg_position;
+ get_frame_saved_regs (fci)[FP0_REGNUM + ireg] = reg_position;
reg_position -= MIPS_SAVED_REGSIZE;
}
- fci->saved_regs[PC_REGNUM] = fci->saved_regs[RA_REGNUM];
+ get_frame_saved_regs (fci)[PC_REGNUM] = get_frame_saved_regs (fci)[RA_REGNUM];
}
/* Set up the 'saved_regs' array. This is a data structure containing
static void
mips_frame_init_saved_regs (struct frame_info *frame)
{
- if (frame->saved_regs == NULL)
+ if (get_frame_saved_regs (frame) == NULL)
{
mips_find_saved_regs (frame);
}
- frame->saved_regs[SP_REGNUM] = frame->frame;
+ get_frame_saved_regs (frame)[SP_REGNUM] = get_frame_base (frame);
}
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);
+
+ if (fi == NULL)
{
- /* 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
+ regcache_cooked_read (current_regcache, regno, raw_buffer);
+ }
+ else
+ {
+ 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)
{
- 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);
+ if (regno < 32)
+ {
+ /* 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 */
target_remove_breakpoint (next_pc, break_mem);
}
-static void
+static CORE_ADDR
mips_init_frame_pc_first (int fromleaf, struct frame_info *prev)
{
CORE_ADDR pc, tmp;
- pc = ((fromleaf) ? SAVED_PC_AFTER_CALL (prev->next) :
- prev->next ? FRAME_SAVED_PC (prev->next) : read_pc ());
- tmp = mips_skip_stub (pc);
- prev->pc = tmp ? tmp : pc;
+ pc = ((fromleaf)
+ ? SAVED_PC_AFTER_CALL (get_next_frame (prev))
+ : get_next_frame (prev)
+ ? DEPRECATED_FRAME_SAVED_PC (get_next_frame (prev))
+ : read_pc ());
+ tmp = SKIP_TRAMPOLINE_CODE (pc);
+ return tmp ? tmp : pc;
}
-CORE_ADDR
+static CORE_ADDR
mips_frame_saved_pc (struct frame_info *frame)
{
CORE_ADDR saved_pc;
- mips_extra_func_info_t proc_desc = frame->extra_info->proc_desc;
+ mips_extra_func_info_t proc_desc = get_frame_extra_info (frame)->proc_desc;
/* We have to get the saved pc from the sigcontext
if it is a signal handler frame. */
- int pcreg = frame->signal_handler_caller ? PC_REGNUM
+ int pcreg = (get_frame_type (frame) == SIGTRAMP_FRAME) ? PC_REGNUM
: (proc_desc ? PROC_PC_REG (proc_desc) : RA_REGNUM);
- if (proc_desc && PROC_DESC_IS_DUMMY (proc_desc))
- saved_pc = read_memory_integer (frame->frame - MIPS_SAVED_REGSIZE, MIPS_SAVED_REGSIZE);
+ if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (frame), 0, 0))
+ {
+ LONGEST tmp;
+ frame_unwind_signed_register (frame, PC_REGNUM, &tmp);
+ saved_pc = tmp;
+ }
+ else if (proc_desc && PROC_DESC_IS_DUMMY (proc_desc))
+ saved_pc = read_memory_integer (get_frame_base (frame) - MIPS_SAVED_REGSIZE, MIPS_SAVED_REGSIZE);
else
saved_pc = read_next_frame_reg (frame, pcreg);
}
static struct mips_extra_func_info temp_proc_desc;
-static CORE_ADDR temp_saved_regs[NUM_REGS];
+
+/* This hack will go away once the get_prev_frame() code has been
+ modified to set the frame's type first. That is BEFORE init extra
+ frame info et.al. is called. This is because it will become
+ possible to skip the init extra info call for sigtramp and dummy
+ frames. */
+static CORE_ADDR *temp_saved_regs;
/* Set a register's saved stack address in temp_saved_regs. If an address
has already been set for this register, do nothing; this way we will
if (start_pc < fence)
{
/* It's not clear to me why we reach this point when
- stop_soon_quietly, but with this test, at least we
+ stop_soon, but with this test, at least we
don't print out warnings for every child forked (eg, on
decstation). 22apr93 rich@cygnus.com. */
- if (!stop_soon_quietly)
+ if (stop_soon == NO_STOP_QUIETLY)
{
static int blurb_printed = 0;
CORE_ADDR cur_pc;
CORE_ADDR frame_addr = 0; /* Value of $r30. Used by gcc for frame-pointer */
restart:
+ temp_saved_regs = xrealloc (temp_saved_regs, SIZEOF_FRAME_SAVED_REGS);
memset (temp_saved_regs, '\0', SIZEOF_FRAME_SAVED_REGS);
PROC_FRAME_OFFSET (&temp_proc_desc) = 0;
PROC_FRAME_ADJUST (&temp_proc_desc) = 0; /* offset of FP from SP */
if (start_pc == 0)
return NULL;
memset (&temp_proc_desc, '\0', sizeof (temp_proc_desc));
- memset (&temp_saved_regs, '\0', SIZEOF_FRAME_SAVED_REGS);
+ temp_saved_regs = xrealloc (temp_saved_regs, SIZEOF_FRAME_SAVED_REGS);
+ memset (temp_saved_regs, '\0', SIZEOF_FRAME_SAVED_REGS);
PROC_LOW_ADDR (&temp_proc_desc) = start_pc;
PROC_FRAME_REG (&temp_proc_desc) = SP_REGNUM;
PROC_PC_REG (&temp_proc_desc) = RA_REGNUM;
struct obj_section *sec;
struct mips_objfile_private *priv;
- if (PC_IN_CALL_DUMMY (pc, 0, 0))
+ if (DEPRECATED_PC_IN_CALL_DUMMY (pc, 0, 0))
return NULL;
find_pc_partial_function (pc, NULL, &startaddr, NULL);
find_proc_desc (CORE_ADDR pc, struct frame_info *next_frame, int cur_frame)
{
mips_extra_func_info_t proc_desc;
- CORE_ADDR startaddr;
+ CORE_ADDR startaddr = 0;
proc_desc = non_heuristic_proc_desc (pc, &startaddr);
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;
CORE_ADDR tmp;
- CORE_ADDR saved_pc = FRAME_SAVED_PC (frame);
+ CORE_ADDR saved_pc = DEPRECATED_FRAME_SAVED_PC (frame);
if (saved_pc == 0 || inside_entry_file (saved_pc))
return 0;
/* 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;
+ if (DEPRECATED_PC_IN_CALL_DUMMY (saved_pc, 0, 0))
+ {
+ /* A dummy frame, uses SP not FP. Get the old SP value. If all
+ is well, frame->frame the bottom of the current frame will
+ contain that value. */
+ return get_frame_base (frame);
+ }
+
/* Look up the procedure descriptor for this PC. */
proc_desc = find_proc_desc (saved_pc, frame, 1);
if (!proc_desc)
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. */
+ && !(get_frame_type (frame) == SIGTRAMP_FRAME)
+ /* For a generic dummy frame, let get_frame_pointer() unwind a
+ register value saved as part of the dummy frame call. */
+ && !(DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (frame), 0, 0)))
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;
+ mips_extra_func_info_t proc_desc;
- /* 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->extra_info = (struct frame_extra_info *)
- frame_obstack_alloc (sizeof (struct frame_extra_info));
+ if (get_frame_type (fci) == DUMMY_FRAME)
+ return;
- fci->saved_regs = NULL;
- fci->extra_info->proc_desc =
+ /* Use proc_desc calculated in frame_chain. When there is no
+ next frame, i.e, get_next_frame (fci) == NULL, we call
+ find_proc_desc () to calculate it, passing an explicit
+ NULL as the frame parameter. */
+ proc_desc =
+ get_next_frame (fci)
+ ? cached_proc_desc
+ : find_proc_desc (get_frame_pc (fci),
+ NULL /* i.e, get_next_frame (fci) */,
+ 1);
+
+ frame_extra_info_zalloc (fci, sizeof (struct frame_extra_info));
+
+ deprecated_set_frame_saved_regs_hack (fci, NULL);
+ get_frame_extra_info (fci)->proc_desc =
proc_desc == &temp_proc_desc ? 0 : proc_desc;
if (proc_desc)
{
/* This may not be quite right, if proc has a real frame register.
Get the value of the frame relative sp, procedure might have been
interrupted by a signal at it's very start. */
- if (fci->pc == PROC_LOW_ADDR (proc_desc)
+ if (get_frame_pc (fci) == PROC_LOW_ADDR (proc_desc)
&& !PROC_DESC_IS_DUMMY (proc_desc))
- fci->frame = read_next_frame_reg (fci->next, SP_REGNUM);
+ deprecated_update_frame_base_hack (fci, read_next_frame_reg (get_next_frame (fci), SP_REGNUM));
+ else if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (fci), 0, 0))
+ /* Do not ``fix'' fci->frame. It will have the value of the
+ generic dummy frame's top-of-stack (since the draft
+ fci->frame is obtained by returning the unwound stack
+ pointer) and that is what we want. That way the fci->frame
+ value will match the top-of-stack value that was saved as
+ part of the dummy frames data. */
+ /* Do nothing. */;
else
- fci->frame = get_frame_pointer (fci->next, proc_desc);
+ deprecated_update_frame_base_hack (fci, get_frame_pointer (get_next_frame (fci), proc_desc));
if (proc_desc == &temp_proc_desc)
{
char *name;
/* Do not set the saved registers for a sigtramp frame,
- mips_find_saved_registers will do that for us.
- We can't use fci->signal_handler_caller, it is not yet set. */
- find_pc_partial_function (fci->pc, &name,
+ mips_find_saved_registers will do that for us. We can't
+ use (get_frame_type (fci) == SIGTRAMP_FRAME), it is not
+ yet set. */
+ /* FIXME: cagney/2002-11-18: This problem will go away once
+ frame.c:get_prev_frame() is modified to set the frame's
+ type before calling functions like this. */
+ find_pc_partial_function (get_frame_pc (fci), &name,
(CORE_ADDR *) NULL, (CORE_ADDR *) NULL);
- if (!PC_IN_SIGTRAMP (fci->pc, name))
+ if (!PC_IN_SIGTRAMP (get_frame_pc (fci), name))
{
frame_saved_regs_zalloc (fci);
- memcpy (fci->saved_regs, temp_saved_regs, SIZEOF_FRAME_SAVED_REGS);
- fci->saved_regs[PC_REGNUM]
- = fci->saved_regs[RA_REGNUM];
+ memcpy (get_frame_saved_regs (fci), temp_saved_regs, SIZEOF_FRAME_SAVED_REGS);
+ get_frame_saved_regs (fci)[PC_REGNUM]
+ = get_frame_saved_regs (fci)[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;
+ get_frame_saved_regs (fci)[SP_REGNUM] = get_frame_base (fci);
}
}
/* hack: if argument regs are saved, guess these contain args */
/* assume we can't tell how many args for now */
- fci->extra_info->num_args = -1;
+ get_frame_extra_info (fci)->num_args = -1;
for (regnum = MIPS_LAST_ARG_REGNUM; regnum >= A0_REGNUM; regnum--)
{
if (PROC_REG_MASK (proc_desc) & (1 << regnum))
{
- fci->extra_info->num_args = regnum - A0_REGNUM + 1;
+ get_frame_extra_info (fci)->num_args = regnum - A0_REGNUM + 1;
break;
}
}
#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))
- {
- 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);
-}
+ int argreg;
+ int float_argreg;
+ int argnum;
+ int len = 0;
+ int stack_offset = 0;
-/* 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))
+ /* 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. */
-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;
+ sp = ROUND_DOWN (sp, 16);
+ struct_addr = ROUND_DOWN (struct_addr, 16);
-/* 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 \
+ /* 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. */
+ 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;
+ deprecated_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
PROC_PC_REG (proc_desc) = RA_REGNUM;
}
-void
+static void
mips_pop_frame (void)
{
register int regnum;
struct frame_info *frame = get_current_frame ();
- CORE_ADDR new_sp = FRAME_FP (frame);
+ CORE_ADDR new_sp = get_frame_base (frame);
+ mips_extra_func_info_t proc_desc = get_frame_extra_info (frame)->proc_desc;
- mips_extra_func_info_t proc_desc = frame->extra_info->proc_desc;
-
- write_register (PC_REGNUM, FRAME_SAVED_PC (frame));
- if (frame->saved_regs == NULL)
- FRAME_INIT_SAVED_REGS (frame);
- for (regnum = 0; regnum < NUM_REGS; regnum++)
+ if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (frame), 0, 0))
{
- if (regnum != SP_REGNUM && regnum != PC_REGNUM
- && frame->saved_regs[regnum])
- write_register (regnum,
- read_memory_integer (frame->saved_regs[regnum],
- MIPS_SAVED_REGSIZE));
+ generic_pop_dummy_frame ();
+ flush_cached_frames ();
+ return;
}
+
+ write_register (PC_REGNUM, DEPRECATED_FRAME_SAVED_PC (frame));
+ if (get_frame_saved_regs (frame) == NULL)
+ DEPRECATED_FRAME_INIT_SAVED_REGS (frame);
+ for (regnum = 0; regnum < NUM_REGS; regnum++)
+ if (regnum != SP_REGNUM && regnum != PC_REGNUM
+ && get_frame_saved_regs (frame)[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 (get_frame_saved_regs (frame)[regnum],
+ MIPS_SAVED_REGSIZE));
+ else
+ write_register (regnum,
+ read_memory_integer (get_frame_saved_regs (frame)[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
int raw_size = REGISTER_RAW_SIZE (regno);
char *raw_buffer = alloca (raw_size);
- if (!frame_register_read (selected_frame, regno, raw_buffer))
+ if (!frame_register_read (deprecated_selected_frame, regno, raw_buffer))
error ("can't read register %d (%s)", regno, REGISTER_NAME (regno));
if (raw_size == 8)
{
{
/* We have a 64-bit value for this register, and we should use
all 64 bits. */
- if (!frame_register_read (selected_frame, regno, rare_buffer))
+ if (!frame_register_read (deprecated_selected_frame, regno, rare_buffer))
error ("can't read register %d (%s)", regno, REGISTER_NAME (regno));
}
else
}
static void
-mips_print_register (int regnum, int all)
-{
- char *raw_buffer = alloca (MAX_REGISTER_RAW_SIZE);
-
- /* Get the data in raw format. */
- if (!frame_register_read (selected_frame, regnum, raw_buffer))
- {
- printf_filtered ("%s: [Invalid]", REGISTER_NAME (regnum));
- return;
- }
-
- /* If we have a actual 32-bit floating point register (or we are in
- 32-bit compatibility mode), and the register is even-numbered,
- also print it as a double (spanning two registers). */
- if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT
- && (REGISTER_RAW_SIZE (regnum) == 4
- || mips2_fp_compat ())
- && !((regnum - FP0_REGNUM) & 1))
- {
- char *dbuffer = alloca (2 * MAX_REGISTER_RAW_SIZE);
-
- mips_read_fp_register_double (regnum, dbuffer);
-
- printf_filtered ("(d%d: ", regnum - FP0_REGNUM);
- val_print (mips_double_register_type (), dbuffer, 0, 0,
- gdb_stdout, 0, 1, 0, Val_pretty_default);
- printf_filtered ("); ");
- }
- fputs_filtered (REGISTER_NAME (regnum), gdb_stdout);
-
- /* The problem with printing numeric register names (r26, etc.) is that
- the user can't use them on input. Probably the best solution is to
- fix it so that either the numeric or the funky (a2, etc.) names
- are accepted on input. */
- if (regnum < MIPS_NUMREGS)
- printf_filtered ("(r%d): ", regnum);
- else
- printf_filtered (": ");
-
- /* If virtual format is floating, print it that way. */
- if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT)
- if (REGISTER_RAW_SIZE (regnum) == 8 && !mips2_fp_compat ())
- {
- /* We have a meaningful 64-bit value in this register. Show
- it as a 32-bit float and a 64-bit double. */
- int offset = 4 * (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG);
-
- printf_filtered (" (float) ");
- val_print (mips_float_register_type (), raw_buffer + offset, 0, 0,
- gdb_stdout, 0, 1, 0, Val_pretty_default);
- printf_filtered (", (double) ");
- val_print (mips_double_register_type (), raw_buffer, 0, 0,
- gdb_stdout, 0, 1, 0, Val_pretty_default);
- }
- else
- val_print (REGISTER_VIRTUAL_TYPE (regnum), raw_buffer, 0, 0,
- gdb_stdout, 0, 1, 0, Val_pretty_default);
- /* Else print as integer in hex. */
- else
- {
- int offset;
-
- if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
- offset = REGISTER_RAW_SIZE (regnum) - REGISTER_VIRTUAL_SIZE (regnum);
- else
- offset = 0;
-
- print_scalar_formatted (raw_buffer + offset,
- REGISTER_VIRTUAL_TYPE (regnum),
- 'x', 0, gdb_stdout);
- }
-}
-
-/* Replacement for generic do_registers_info.
- Print regs in pretty columns. */
-
-static int
-do_fp_register_row (int regnum)
+mips_print_fp_register (int regnum)
{ /* do values for FP (float) regs */
char *raw_buffer;
double doub, flt1, flt2; /* doubles extracted from raw hex data */
- int inv1, inv2, inv3;
+ int inv1, inv2, namelen;
raw_buffer = (char *) alloca (2 * REGISTER_RAW_SIZE (FP0_REGNUM));
+ printf_filtered ("%s:", REGISTER_NAME (regnum));
+ printf_filtered ("%*s", 4 - (int) strlen (REGISTER_NAME (regnum)), "");
+
if (REGISTER_RAW_SIZE (regnum) == 4 || mips2_fp_compat ())
{
- /* 4-byte registers: we can fit two registers per row. */
- /* Also print every pair of 4-byte regs as an 8-byte double. */
+ /* 4-byte registers: Print hex and floating. Also print even
+ numbered registers as doubles. */
mips_read_fp_register_single (regnum, raw_buffer);
flt1 = unpack_double (mips_float_register_type (), raw_buffer, &inv1);
- mips_read_fp_register_single (regnum + 1, raw_buffer);
- flt2 = unpack_double (mips_float_register_type (), raw_buffer, &inv2);
+ print_scalar_formatted (raw_buffer, builtin_type_uint32, 'x', 'w',
+ gdb_stdout);
- mips_read_fp_register_double (regnum, raw_buffer);
- doub = unpack_double (mips_double_register_type (), raw_buffer, &inv3);
-
- printf_filtered (" %-5s", REGISTER_NAME (regnum));
+ printf_filtered (" flt: ");
if (inv1)
- printf_filtered (": <invalid float>");
+ printf_filtered (" <invalid float> ");
else
printf_filtered ("%-17.9g", flt1);
- printf_filtered (" %-5s", REGISTER_NAME (regnum + 1));
- if (inv2)
- printf_filtered (": <invalid float>");
- else
- printf_filtered ("%-17.9g", flt2);
-
- printf_filtered (" dbl: ");
- if (inv3)
- printf_filtered ("<invalid double>");
- else
- printf_filtered ("%-24.17g", doub);
- printf_filtered ("\n");
+ if (regnum % 2 == 0)
+ {
+ mips_read_fp_register_double (regnum, raw_buffer);
+ doub = unpack_double (mips_double_register_type (), raw_buffer,
+ &inv2);
- /* may want to do hex display here (future enhancement) */
- regnum += 2;
+ printf_filtered (" dbl: ");
+ if (inv2)
+ printf_filtered ("<invalid double>");
+ else
+ printf_filtered ("%-24.17g", doub);
+ }
}
else
{
- /* Eight byte registers: print each one as float AND as double. */
+ /* Eight byte registers: print each one as hex, float and double. */
mips_read_fp_register_single (regnum, raw_buffer);
- flt1 = unpack_double (mips_double_register_type (), raw_buffer, &inv1);
+ flt1 = unpack_double (mips_float_register_type (), raw_buffer, &inv1);
mips_read_fp_register_double (regnum, raw_buffer);
- doub = unpack_double (mips_double_register_type (), raw_buffer, &inv3);
+ doub = unpack_double (mips_double_register_type (), raw_buffer, &inv2);
+
+
+ print_scalar_formatted (raw_buffer, builtin_type_uint64, 'x', 'g',
+ gdb_stdout);
- printf_filtered (" %-5s: ", REGISTER_NAME (regnum));
+ printf_filtered (" flt: ");
if (inv1)
printf_filtered ("<invalid float>");
else
- printf_filtered ("flt: %-17.9g", flt1);
+ printf_filtered ("%-17.9g", flt1);
printf_filtered (" dbl: ");
- if (inv3)
+ if (inv2)
printf_filtered ("<invalid double>");
else
printf_filtered ("%-24.17g", doub);
+ }
+}
- printf_filtered ("\n");
- /* may want to do hex display here (future enhancement) */
- regnum++;
+static void
+mips_print_register (int regnum, int all)
+{
+ char *raw_buffer = alloca (MAX_REGISTER_RAW_SIZE);
+ int offset;
+
+ if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT)
+ {
+ mips_print_fp_register (regnum);
+ return;
}
- return regnum;
+
+ /* Get the data in raw format. */
+ if (!frame_register_read (deprecated_selected_frame, regnum, raw_buffer))
+ {
+ printf_filtered ("%s: [Invalid]", REGISTER_NAME (regnum));
+ return;
+ }
+
+ fputs_filtered (REGISTER_NAME (regnum), gdb_stdout);
+
+ /* The problem with printing numeric register names (r26, etc.) is that
+ the user can't use them on input. Probably the best solution is to
+ fix it so that either the numeric or the funky (a2, etc.) names
+ are accepted on input. */
+ if (regnum < MIPS_NUMREGS)
+ printf_filtered ("(r%d): ", regnum);
+ else
+ printf_filtered (": ");
+
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ offset = REGISTER_RAW_SIZE (regnum) - REGISTER_VIRTUAL_SIZE (regnum);
+ else
+ offset = 0;
+
+ print_scalar_formatted (raw_buffer + offset,
+ REGISTER_VIRTUAL_TYPE (regnum),
+ 'x', 0, gdb_stdout);
+}
+
+/* Replacement for generic do_registers_info.
+ Print regs in pretty columns. */
+
+static int
+do_fp_register_row (int regnum)
+{
+ printf_filtered (" ");
+ mips_print_fp_register (regnum);
+ printf_filtered ("\n");
+ return regnum + 1;
}
+
/* Print a row's worth of GP (int) registers, with name labels above */
static int
if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT)
break; /* end row: reached FP register */
/* OK: get the data in raw format. */
- if (!frame_register_read (selected_frame, regnum, raw_buffer))
+ if (!frame_register_read (deprecated_selected_frame, regnum, raw_buffer))
error ("can't read register %d (%s)", regnum, REGISTER_NAME (regnum));
/* pad small registers */
for (byte = 0; byte < (MIPS_REGSIZE - REGISTER_VIRTUAL_SIZE (regnum)); byte++)
/* 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);
+ deprecated_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);
+ deprecated_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;
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));
+ deprecated_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));
+ deprecated_write_register_bytes (REGISTER_BYTE (hi.reg), raw_buffer,
+ REGISTER_RAW_SIZE (hi.reg));
+ }
+}
+
+/* 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;
}
-/* If the current gcc for this target does not produce correct debugging
- information for float parameters, both prototyped and unprototyped, then
- define this macro. This forces gdb to always assume that floats are
- passed as doubles and then converted in the callee.
-
- For the mips chip, it appears that the debug info marks the parameters as
- floats regardless of whether the function is prototyped, but the actual
- values are passed as doubles for the non-prototyped case and floats for
- the prototyped case. Thus we choose to make the non-prototyped case work
- for C and break the prototyped case, since the non-prototyped case is
- probably much more common. (FIXME). */
-
-static int
-mips_coerce_float_to_double (struct type *formal, struct type *actual)
-{
- return current_language->la_language == language_c;
-}
-
/* When debugging a 64 MIPS target running a 32 bit ABI, the size of
the register stored on the stack (32) is different to its real raw
size (64). The below ensures that registers are fetched from the
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;
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;
+ generic_unwind_get_saved_register (raw_buffer, optimizedp, addrp, frame,
+ regnum, lvalp);
+ /* 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.
static int
mips_stab_reg_to_regnum (int num)
{
- if (num < 32)
+ if (num >= 0 && num < 32)
return num;
- else
+ else if (num >= 38 && num < 70)
return num + FP0_REGNUM - 38;
+ else if (num == 70)
+ return HI_REGNUM;
+ else if (num == 71)
+ return LO_REGNUM;
+ else
+ {
+ /* This will hopefully (eventually) provoke a warning. Should
+ we be calling complaint() here? */
+ return NUM_REGS + NUM_PSEUDO_REGS;
+ }
}
-/* Convert a ecoff register number to a gdb REGNUM */
+
+/* Convert a dwarf, dwarf2, or ecoff register number to a gdb REGNUM */
static int
-mips_ecoff_reg_to_regnum (int num)
+mips_dwarf_dwarf2_ecoff_reg_to_regnum (int num)
{
- if (num < 32)
+ if (num >= 0 && num < 32)
return num;
- else
+ else if (num >= 32 && num < 64)
return num + FP0_REGNUM - 32;
+ else if (num == 64)
+ return HI_REGNUM;
+ else if (num == 65)
+ return LO_REGNUM;
+ else
+ {
+ /* This will hopefully (eventually) provoke a warning. Should
+ we be calling complaint() here? */
+ return NUM_REGS + NUM_PSEUDO_REGS;
+ }
}
+
/* Convert an integer into an address. By first converting the value
into a pointer and then extracting it signed, the address is
guarenteed to be correctly sign extended. */
*abip = MIPS_ABI_O32;
else if (strcmp (name, ".mdebug.abiN32") == 0)
*abip = MIPS_ABI_N32;
- else if (strcmp (name, ".mdebug.abiN64") == 0)
+ else if (strcmp (name, ".mdebug.abi64") == 0)
*abip = MIPS_ABI_N64;
else if (strcmp (name, ".mdebug.abiO64") == 0)
*abip = MIPS_ABI_O64;
struct gdbarch_tdep *tdep;
int elf_flags;
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
non-default. */
/* First of all, extract the elf_flags, if available. */
if (bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
elf_flags = elf_elfheader (info.abfd)->e_flags;
-
- /* Try to determine the OS ABI of the object we are loading. If
- we end up with `unknown', just leave it that way. */
- 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)
continue;
- if (gdbarch_tdep (arches->gdbarch)->osabi == osabi)
- return arches->gdbarch;
+ 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_deprecated_max_register_raw_size (gdbarch, 8);
+ set_gdbarch_deprecated_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);
+
+ if (info.osabi == GDB_OSABI_IRIX)
+ set_gdbarch_num_regs (gdbarch, 71);
+ else
+ set_gdbarch_num_regs (gdbarch, 90);
+
switch (mips_abi)
{
case MIPS_ABI_O32:
- set_gdbarch_push_arguments (gdbarch, mips_push_arguments);
+ set_gdbarch_deprecated_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_deprecated_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_deprecated_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_deprecated_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);
mips_eabi_use_struct_convention);
break;
case MIPS_ABI_N32:
- set_gdbarch_push_arguments (gdbarch, mips_n32n64_push_arguments);
+ set_gdbarch_deprecated_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);
mips_n32n64_reg_struct_has_addr);
break;
case MIPS_ABI_N64:
- set_gdbarch_push_arguments (gdbarch, mips_n32n64_push_arguments);
+ set_gdbarch_deprecated_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_write_sp (gdbarch, generic_target_write_sp);
+ set_gdbarch_read_fp (gdbarch, mips_read_sp); /* Draft FRAME base. */
+ set_gdbarch_read_sp (gdbarch, mips_read_sp);
+ set_gdbarch_deprecated_dummy_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
- blockframe.c near reference to INIT_FRAME_PC_FIRST. */
- set_gdbarch_init_frame_pc_first (gdbarch, mips_init_frame_pc_first);
- set_gdbarch_init_frame_pc (gdbarch, init_frame_pc_noop);
+ blockframe.c near reference to DEPRECATED_INIT_FRAME_PC_FIRST. */
+ set_gdbarch_deprecated_init_frame_pc_first (gdbarch, mips_init_frame_pc_first);
+ set_gdbarch_deprecated_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_ecoff_reg_to_regnum (gdbarch, mips_dwarf_dwarf2_ecoff_reg_to_regnum);
+ set_gdbarch_dwarf_reg_to_regnum (gdbarch, mips_dwarf_dwarf2_ecoff_reg_to_regnum);
+ set_gdbarch_dwarf2_reg_to_regnum (gdbarch, mips_dwarf_dwarf2_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);
+ set_gdbarch_deprecated_frame_init_saved_regs (gdbarch, mips_frame_init_saved_regs);
+ set_gdbarch_deprecated_init_extra_frame_info (gdbarch, mips_init_extra_frame_info);
/* MIPS version of CALL_DUMMY */
- set_gdbarch_call_dummy_p (gdbarch, 1);
- set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0);
- set_gdbarch_use_generic_dummy_frames (gdbarch, 0);
- set_gdbarch_call_dummy_location (gdbarch, AT_ENTRY_POINT);
set_gdbarch_call_dummy_address (gdbarch, mips_call_dummy_address);
- set_gdbarch_call_dummy_start_offset (gdbarch, 0);
- set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 1);
- set_gdbarch_call_dummy_breakpoint_offset (gdbarch, 0);
- set_gdbarch_call_dummy_length (gdbarch, 0);
- set_gdbarch_pc_in_call_dummy (gdbarch, pc_in_call_dummy_at_entry_point);
+ set_gdbarch_deprecated_push_return_address (gdbarch, mips_push_return_address);
+ set_gdbarch_deprecated_pop_frame (gdbarch, mips_pop_frame);
+ set_gdbarch_fix_call_dummy (gdbarch, mips_fix_call_dummy);
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_coerce_float_to_double (gdbarch, mips_coerce_float_to_double);
-
- set_gdbarch_frame_chain_valid (gdbarch, func_frame_chain_valid);
- set_gdbarch_get_saved_register (gdbarch, mips_get_saved_register);
+ set_gdbarch_deprecated_push_return_address (gdbarch, mips_push_return_address);
+ set_gdbarch_frame_align (gdbarch, mips_frame_align);
+ set_gdbarch_save_dummy_frame_tos (gdbarch, generic_save_dummy_frame_tos);
+ 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_deprecated_frame_chain (gdbarch, mips_frame_chain);
+ set_gdbarch_frameless_function_invocation (gdbarch,
+ generic_frameless_function_invocation_not);
+ set_gdbarch_deprecated_frame_saved_pc (gdbarch, mips_frame_saved_pc);
+ set_gdbarch_frame_num_args (gdbarch, frame_num_args_unknown);
+ set_gdbarch_frame_args_skip (gdbarch, 0);
+
+ set_gdbarch_deprecated_get_saved_register (gdbarch, mips_get_saved_register);
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
set_gdbarch_breakpoint_from_pc (gdbarch, mips_breakpoint_from_pc);
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_deprecated_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);
+ gdbarch_init_osabi (info, gdbarch);
+
+ set_gdbarch_deprecated_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;
}
gdbarch_update_p (info);
}
+/* Print out which MIPS ABI is in use. */
+
+static void
+show_mips_abi (char *ignore_args, int from_tty)
+{
+ if (gdbarch_bfd_arch_info (current_gdbarch)->arch != bfd_arch_mips)
+ printf_filtered (
+ "The MIPS ABI is unknown because the current architecture is not MIPS.\n");
+ else
+ {
+ enum mips_abi global_abi = global_mips_abi ();
+ enum mips_abi actual_abi = mips_abi (current_gdbarch);
+ const char *actual_abi_str = mips_abi_strings[actual_abi];
+
+ if (global_abi == MIPS_ABI_UNKNOWN)
+ printf_filtered ("The MIPS ABI is set automatically (currently \"%s\").\n",
+ actual_abi_str);
+ else if (global_abi == actual_abi)
+ printf_filtered (
+ "The MIPS ABI is assumed to be \"%s\" (due to user setting).\n",
+ actual_abi_str);
+ else
+ {
+ /* Probably shouldn't happen... */
+ printf_filtered (
+ "The (auto detected) MIPS ABI \"%s\" is in use even though the user setting was \"%s\".\n",
+ actual_abi_str,
+ mips_abi_strings[global_abi]);
+ }
+ }
+}
+
static void
mips_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
{
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: CAUSE_REGNUM = %d\n",
CAUSE_REGNUM);
- 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: DWARF_REG_TO_REGNUM # %s\n",
XSTRING (DWARF_REG_TO_REGNUM (REGNUM)));
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: GDB_TARGET_IS_MIPS64 = %d\n",
GDB_TARGET_IS_MIPS64);
- fprintf_unfiltered (file,
- "mips_dump_tdep: GDB_TARGET_MASK_DISAS_PC # %s\n",
- XSTRING (GDB_TARGET_MASK_DISAS_PC (PC)));
- fprintf_unfiltered (file,
- "mips_dump_tdep: GDB_TARGET_UNMASK_DISAS_PC # %s\n",
- XSTRING (GDB_TARGET_UNMASK_DISAS_PC (PC)));
fprintf_unfiltered (file,
"mips_dump_tdep: GEN_REG_SAVE_MASK = %d\n",
GEN_REG_SAVE_MASK);
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,
fprintf_unfiltered (file,
"mips_dump_tdep: _PROC_MAGIC_ = %d\n",
_PROC_MAGIC_);
-
- fprintf_unfiltered (file,
- "mips_dump_tdep: OS ABI = %s\n",
- gdbarch_osabi_name (tdep->osabi));
}
void
" eabi32\n"
" eabi64",
&setmipscmdlist);
- add_show_from_set (c, &showmipscmdlist);
set_cmd_sfunc (c, mips_abi_update);
+ add_cmd ("abi", class_obscure, show_mips_abi,
+ "Show ABI in use by MIPS target", &showmipscmdlist);
/* Let the user turn off floating point and set the fence post for
heuristic_proc_start. */