/* Target-dependent code for the MIPS architecture, for GDB, the GNU Debugger.
- Copyright 1988, 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995
+ 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 "gdbcore.h"
#include "symfile.h"
#include "objfiles.h"
+#include "gdbtypes.h"
#include "opcode/mips.h"
#define VM_MIN_ADDRESS (unsigned)0x400000
+
+/* FIXME: Put this declaration in frame.h. */
+extern struct obstack frame_cache_obstack;
\f
+#if 0
static int mips_in_lenient_prologue PARAMS ((CORE_ADDR, CORE_ADDR));
+#endif
+
+void mips_set_processor_type_command PARAMS ((char *, int));
+
+int mips_set_processor_type PARAMS ((char *));
+
+static void mips_show_processor_type_command PARAMS ((char *, int));
+
+static void reinit_frame_cache_sfunc PARAMS ((char *, int,
+ struct cmd_list_element *));
+
+/* This value is the model of MIPS in use. It is derived from the value
+ of the PrID register. */
+
+char *mips_processor_type;
+
+char *tmp_mips_processor_type;
/* Some MIPS boards don't support floating point, so we permit the
user to turn it off. */
+
int mips_fpu = 1;
+/* A set of original names, to be used when restoring back to generic
+ registers from a specific set. */
+
+char *mips_generic_reg_names[] = REGISTER_NAMES;
+
+/* 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", "",
+ "", "", "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", "",
+ "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", "",
+ "inx", "rand", "elo", "cfg", "ctxt", "", "", "",
+ "", "", "ehi", "", "", "", "epc", "prid",
+};
+
+struct {
+ char *name;
+ char **regnames;
+} mips_processor_type_table[] = {
+ { "generic", mips_generic_reg_names },
+ { "r3041", mips_r3041_reg_names },
+ { "r3051", mips_r3051_reg_names },
+ { "r3071", mips_r3081_reg_names },
+ { "r3081", mips_r3081_reg_names },
+ { NULL, NULL }
+};
+
/* Heuristic_proc_start may hunt through the text section for a long
time across a 2400 baud serial line. Allows the user to limit this
search. */
+
static unsigned int heuristic_fence_post = 0;
#define PROC_LOW_ADDR(proc) ((proc)->pdr.adr) /* least address */
} *linked_proc_desc_table = NULL;
\f
-#define READ_FRAME_REG(fi, regno) read_next_frame_reg((fi)->next, regno)
+/* Guaranteed to set fci->saved_regs to some values (it never leaves it
+ NULL). */
+
+void
+mips_find_saved_regs (fci)
+ struct frame_info *fci;
+{
+ int ireg;
+ CORE_ADDR reg_position;
+ /* r0 bit means kernel trap */
+ int kernel_trap;
+ /* What registers have been saved? Bitmasks. */
+ unsigned long gen_mask, float_mask;
+ mips_extra_func_info_t proc_desc;
+
+ fci->saved_regs = (struct frame_saved_regs *)
+ obstack_alloc (&frame_cache_obstack, sizeof(struct frame_saved_regs));
+ memset (fci->saved_regs, 0, sizeof (struct frame_saved_regs));
+
+ proc_desc = 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
+ and set the saved_regs right away. */
+ return;
+
+ kernel_trap = PROC_REG_MASK(proc_desc) & 1;
+ gen_mask = kernel_trap ? 0xFFFFFFFF : PROC_REG_MASK(proc_desc);
+ float_mask = kernel_trap ? 0xFFFFFFFF : PROC_FREG_MASK(proc_desc);
+
+ if (/* In any frame other than the innermost, 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
+
+ /* In a dummy frame we know exactly where things are saved. */
+ && !PROC_DESC_IS_DUMMY (proc_desc)
+
+ /* Not sure exactly what kernel_trap means, but if it means
+ the kernel saves the registers without a prologue doing it,
+ we better not examine the prologue to see whether registers
+ have been saved yet. */
+ && !kernel_trap)
+ {
+ /* We need to figure out whether the registers that the proc_desc
+ claims are saved have been saved yet. */
+
+ CORE_ADDR addr;
+ int status;
+ char buf[4];
+ unsigned long inst;
+
+ /* Bitmasks; set if we have found a save for the register. */
+ unsigned long gen_save_found = 0;
+ unsigned long float_save_found = 0;
+
+ for (addr = PROC_LOW_ADDR (proc_desc);
+ addr < fci->pc /*&& (gen_mask != gen_save_found
+ || float_mask != float_save_found)*/;
+ addr += 4)
+ {
+ status = read_memory_nobpt (addr, buf, 4);
+ if (status)
+ memory_error (status, addr);
+ inst = extract_unsigned_integer (buf, 4);
+ if (/* sw reg,n($sp) */
+ (inst & 0xffe00000) == 0xafa00000
+
+ /* sw reg,n($r30) */
+ || (inst & 0xffe00000) == 0xafc00000
+
+ /* sd reg,n($sp) */
+ || (inst & 0xffe00000) == 0xffa00000)
+ {
+ /* It might be possible to use the instruction to
+ find the offset, rather than the code below which
+ is based on things being in a certain order in the
+ frame, but figuring out what the instruction's offset
+ is relative to might be a little tricky. */
+ int reg = (inst & 0x001f0000) >> 16;
+ gen_save_found |= (1 << reg);
+ }
+ else if (/* swc1 freg,n($sp) */
+ (inst & 0xffe00000) == 0xe7a00000
+
+ /* swc1 freg,n($r30) */
+ || (inst & 0xffe00000) == 0xe7c00000
+
+ /* sdc1 freg,n($sp) */
+ || (inst & 0xffe00000) == 0xf7a00000)
+
+ {
+ int reg = ((inst & 0x001f0000) >> 16);
+ float_save_found |= (1 << reg);
+ }
+ }
+ gen_mask = gen_save_found;
+ float_mask = float_save_found;
+ }
+
+ /* Fill in the offsets for the registers which gen_mask says
+ were saved. */
+ reg_position = fci->frame + PROC_REG_OFFSET (proc_desc);
+ for (ireg= 31; gen_mask; --ireg, gen_mask <<= 1)
+ if (gen_mask & 0x80000000)
+ {
+ fci->saved_regs->regs[ireg] = reg_position;
+ reg_position -= MIPS_REGSIZE;
+ }
+ /* Fill in the offsets for the registers which float_mask says
+ were saved. */
+ reg_position = fci->frame + PROC_FREG_OFFSET (proc_desc);
+
+ /* The freg_offset points to where the first *double* register
+ is saved. So skip to the high-order word. */
+ reg_position += 4;
+ for (ireg = 31; float_mask; --ireg, float_mask <<= 1)
+ if (float_mask & 0x80000000)
+ {
+ fci->saved_regs->regs[FP0_REGNUM+ireg] = reg_position;
+ reg_position -= MIPS_REGSIZE;
+ }
+
+ fci->saved_regs->regs[PC_REGNUM] = fci->saved_regs->regs[RA_REGNUM];
+}
static int
read_next_frame_reg(fi, regno)
- FRAME fi;
+ struct frame_info *fi;
int regno;
{
/* If it is the frame for sigtramp we have a complete sigcontext
- immediately below the frame and we get the saved registers from there.
+ somewhere above the frame and we get the saved registers from there.
If the stack layout for sigtramp changes we might have to change these
- constants and the companion fixup_sigtramp in mipsread.c */
+ constants and the companion fixup_sigtramp in mdebugread.c */
#ifndef SIGFRAME_BASE
-#define SIGFRAME_BASE 0x12c /* sizeof(sigcontext) */
-#define SIGFRAME_PC_OFF (-SIGFRAME_BASE + 2 * 4)
-#define SIGFRAME_REGSAVE_OFF (-SIGFRAME_BASE + 3 * 4)
+/* To satisfy alignment restrictions the sigcontext is located 4 bytes
+ above the sigtramp frame. */
+#define SIGFRAME_BASE 4
+#define SIGFRAME_PC_OFF (SIGFRAME_BASE + 2 * 4)
+#define SIGFRAME_REGSAVE_OFF (SIGFRAME_BASE + 3 * 4)
+#endif
+#ifndef SIGFRAME_REG_SIZE
+#define SIGFRAME_REG_SIZE 4
#endif
for (; fi; fi = fi->next)
- if (in_sigtramp(fi->pc, 0)) {
+ {
+ if (fi->signal_handler_caller)
+ {
int offset;
if (regno == PC_REGNUM) offset = SIGFRAME_PC_OFF;
- else if (regno < 32) offset = SIGFRAME_REGSAVE_OFF + regno * 4;
+ else if (regno < 32) offset = (SIGFRAME_REGSAVE_OFF
+ + regno * SIGFRAME_REG_SIZE);
else return 0;
- return read_memory_integer(fi->frame + offset, 4);
- }
+ return read_memory_integer(fi->frame + offset, MIPS_REGSIZE);
+ }
else if (regno == SP_REGNUM) return fi->frame;
- else if (fi->saved_regs->regs[regno])
- return read_memory_integer(fi->saved_regs->regs[regno], 4);
- return read_register(regno);
+ else
+ {
+ if (fi->saved_regs == NULL)
+ mips_find_saved_regs (fi);
+ if (fi->saved_regs->regs[regno])
+ return read_memory_integer(fi->saved_regs->regs[regno], MIPS_REGSIZE);
+ }
+ }
+ return read_register (regno);
}
int
mips_frame_saved_pc(frame)
- FRAME frame;
+ struct frame_info *frame;
{
mips_extra_func_info_t proc_desc = frame->proc_desc;
- int pcreg = proc_desc ? PROC_PC_REG(proc_desc) : RA_REGNUM;
+ /* 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
+ : (proc_desc ? PROC_PC_REG(proc_desc) : RA_REGNUM);
if (proc_desc && PROC_DESC_IS_DUMMY(proc_desc))
return read_memory_integer(frame->frame - 4, 4);
static mips_extra_func_info_t
heuristic_proc_desc(start_pc, limit_pc, next_frame)
CORE_ADDR start_pc, limit_pc;
- FRAME next_frame;
+ struct frame_info *next_frame;
{
- CORE_ADDR sp = next_frame ? next_frame->frame : read_register (SP_REGNUM);
+ CORE_ADDR sp = read_next_frame_reg (next_frame, SP_REGNUM);
CORE_ADDR cur_pc;
int frame_size;
int has_frame_reg = 0;
- int reg30; /* Value of $r30. Used by gcc for frame-pointer */
+ int reg30 = 0; /* Value of $r30. Used by gcc for frame-pointer */
unsigned long reg_mask = 0;
if (start_pc == 0) return NULL;
- bzero(&temp_proc_desc, sizeof(temp_proc_desc));
- bzero(&temp_saved_regs, sizeof(struct frame_saved_regs));
- PROC_LOW_ADDR(&temp_proc_desc) = start_pc;
+ memset (&temp_proc_desc, '\0', sizeof(temp_proc_desc));
+ memset (&temp_saved_regs, '\0', sizeof(struct frame_saved_regs));
+ PROC_LOW_ADDR (&temp_proc_desc) = start_pc;
- if (start_pc + 200 < limit_pc) limit_pc = start_pc + 200;
+ if (start_pc + 200 < limit_pc)
+ limit_pc = start_pc + 200;
restart:
frame_size = 0;
for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += 4) {
else if ((word & 0xFFE00000) == 0xafa00000) { /* sw reg,offset($sp) */
int reg = (word & 0x001F0000) >> 16;
reg_mask |= 1 << reg;
- temp_saved_regs.regs[reg] = sp + (short)word;
+ temp_saved_regs.regs[reg] = sp + (word & 0xffff);
}
else if ((word & 0xFFFF0000) == 0x27be0000) { /* addiu $30,$sp,size */
- if ((unsigned short)word != frame_size)
- reg30 = sp + (unsigned short)word;
+ if ((word & 0xffff) != frame_size)
+ reg30 = sp + (word & 0xffff);
else if (!has_frame_reg) {
int alloca_adjust;
has_frame_reg = 1;
reg30 = read_next_frame_reg(next_frame, 30);
- alloca_adjust = reg30 - (sp + (unsigned short)word);
+ alloca_adjust = reg30 - (sp + (word & 0xffff));
if (alloca_adjust > 0) {
/* FP > SP + frame_size. This may be because
- /* of an alloca or somethings similar.
+ * of an alloca or somethings similar.
* Fix sp to "pre-alloca" value, and try again.
*/
sp += alloca_adjust;
else if ((word & 0xFFE00000) == 0xafc00000) { /* sw reg,offset($30) */
int reg = (word & 0x001F0000) >> 16;
reg_mask |= 1 << reg;
- temp_saved_regs.regs[reg] = reg30 + (short)word;
+ temp_saved_regs.regs[reg] = reg30 + (word & 0xffff);
}
}
if (has_frame_reg) {
}
static mips_extra_func_info_t
-find_proc_desc(pc, next_frame)
- CORE_ADDR pc;
- FRAME next_frame;
+find_proc_desc (pc, next_frame)
+ CORE_ADDR pc;
+ struct frame_info *next_frame;
{
mips_extra_func_info_t proc_desc;
struct block *b = block_for_pc(pc);
* THEN create a "heuristic" proc_desc (by analyzing
* the actual code) to replace the "official" proc_desc.
*/
- proc_desc = (mips_extra_func_info_t)SYMBOL_VALUE(sym);
+ proc_desc = (mips_extra_func_info_t) SYMBOL_VALUE (sym);
if (next_frame == NULL) {
struct symtab_and_line val;
struct symbol *proc_symbol =
}
if (!proc_symbol || pc < val.pc) {
mips_extra_func_info_t found_heuristic =
- heuristic_proc_desc(PROC_LOW_ADDR(proc_desc),
- pc, next_frame);
- if (found_heuristic) proc_desc = found_heuristic;
+ heuristic_proc_desc (PROC_LOW_ADDR (proc_desc),
+ pc, next_frame);
+ if (found_heuristic)
+ proc_desc = found_heuristic;
}
}
}
heuristic_proc_desc knows how to create them! */
register struct linked_proc_info *link;
+
for (link = linked_proc_desc_table; link; link = link->next)
- if (PROC_LOW_ADDR(&link->info) <= pc
- && PROC_HIGH_ADDR(&link->info) > pc)
- return &link->info;
+ if (PROC_LOW_ADDR(&link->info) <= pc
+ && PROC_HIGH_ADDR(&link->info) > pc)
+ return &link->info;
if (startaddr == 0)
startaddr = heuristic_proc_start (pc);
mips_extra_func_info_t cached_proc_desc;
-FRAME_ADDR
+CORE_ADDR
mips_frame_chain(frame)
- FRAME frame;
+ struct frame_info *frame;
{
mips_extra_func_info_t proc_desc;
CORE_ADDR saved_pc = FRAME_SAVED_PC(frame);
return 0;
cached_proc_desc = proc_desc;
- return read_next_frame_reg(frame, PROC_FRAME_REG(proc_desc))
- + PROC_FRAME_OFFSET(proc_desc);
+
+ /* If no frame pointer and frame size is zero, we must be at end
+ of stack (or otherwise hosed). If we don't check frame size,
+ 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)
+ return 0;
+ else
+ return read_next_frame_reg(frame, PROC_FRAME_REG(proc_desc))
+ + PROC_FRAME_OFFSET(proc_desc);
}
void
init_extra_frame_info(fci)
struct frame_info *fci;
{
- extern struct obstack frame_cache_obstack;
/* 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);
- fci->saved_regs = (struct frame_saved_regs*)
- obstack_alloc (&frame_cache_obstack, sizeof(struct frame_saved_regs));
- memset (fci->saved_regs, 0, sizeof (struct frame_saved_regs));
+ fci->saved_regs = NULL;
fci->proc_desc =
proc_desc == &temp_proc_desc ? 0 : proc_desc;
if (proc_desc)
{
- int ireg;
- CORE_ADDR reg_position;
- unsigned long mask;
- /* r0 bit means kernel trap */
- int kernel_trap = PROC_REG_MASK(proc_desc) & 1;
-
/* Fixup frame-pointer - only needed for top frame */
- /* This may not be quite right, if proc has a real frame register */
- if (fci->pc == PROC_LOW_ADDR(proc_desc) && !PROC_DESC_IS_DUMMY(proc_desc))
- fci->frame = read_register (SP_REGNUM);
+ /* 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)
+ && !PROC_DESC_IS_DUMMY (proc_desc))
+ fci->frame = read_next_frame_reg (fci->next, SP_REGNUM);
else
- fci->frame = READ_FRAME_REG(fci, PROC_FRAME_REG(proc_desc))
- + PROC_FRAME_OFFSET(proc_desc);
-
- /* If this is the innermost frame, and we are still in the
- prologue (loosely defined), then the registers may not have
- been saved yet. */
- if (fci->next == NULL
- && !PROC_DESC_IS_DUMMY(proc_desc)
- && mips_in_lenient_prologue (PROC_LOW_ADDR (proc_desc), fci->pc))
- {
- /* Can't just say that the registers are not saved, because they
- might get clobbered halfway through the prologue.
- heuristic_proc_desc already has the right code to figure out
- exactly what has been saved, so use it. As far as I know we
- could be doing this (as we do on the 68k, for example)
- regardless of whether we are in the prologue; I'm leaving in
- the check for being in the prologue only out of conservatism
- (I'm not sure whether heuristic_proc_desc handles all cases,
- for example).
-
- This stuff is ugly (and getting uglier by the minute). Probably
- the best way to clean it up is to ignore the proc_desc's from
- the symbols altogher, and get all the information we need by
- examining the prologue (provided we can make the prologue
- examining code good enough to get all the cases...). */
- proc_desc =
- heuristic_proc_desc (PROC_LOW_ADDR (proc_desc),
- fci->pc,
- fci->next);
- }
+ fci->frame =
+ read_next_frame_reg (fci->next, PROC_FRAME_REG (proc_desc))
+ + PROC_FRAME_OFFSET (proc_desc);
if (proc_desc == &temp_proc_desc)
- *fci->saved_regs = temp_saved_regs;
- else
{
- /* find which general-purpose registers were saved */
- reg_position = fci->frame + PROC_REG_OFFSET(proc_desc);
- mask = kernel_trap ? 0xFFFFFFFF : PROC_REG_MASK(proc_desc);
- for (ireg= 31; mask; --ireg, mask <<= 1)
- if (mask & 0x80000000)
- {
- fci->saved_regs->regs[ireg] = reg_position;
- reg_position -= 4;
- }
- /* find which floating-point registers were saved */
- reg_position = fci->frame + PROC_FREG_OFFSET(proc_desc);
-
- /* The freg_offset points to where the first *double* register
- is saved. So skip to the high-order word. */
- reg_position += 4;
- mask = kernel_trap ? 0xFFFFFFFF : PROC_FREG_MASK(proc_desc);
- for (ireg = 31; mask; --ireg, mask <<= 1)
- if (mask & 0x80000000)
- {
- fci->saved_regs->regs[FP0_REGNUM+ireg] = reg_position;
- reg_position -= 4;
- }
+ fci->saved_regs = (struct frame_saved_regs*)
+ obstack_alloc (&frame_cache_obstack,
+ sizeof (struct frame_saved_regs));
+ *fci->saved_regs = temp_saved_regs;
+ fci->saved_regs->regs[PC_REGNUM] = fci->saved_regs->regs[RA_REGNUM];
}
/* hack: if argument regs are saved, guess these contain args */
else if ((PROC_REG_MASK(proc_desc) & 0x40) == 0) fci->num_args = 3;
else if ((PROC_REG_MASK(proc_desc) & 0x20) == 0) fci->num_args = 2;
else if ((PROC_REG_MASK(proc_desc) & 0x10) == 0) fci->num_args = 1;
-
- fci->saved_regs->regs[PC_REGNUM] = fci->saved_regs->regs[RA_REGNUM];
}
}
cache. This allows the rest of info frame to extract the important
arguments without difficulty. */
-FRAME
+struct frame_info *
setup_arbitrary_frame (argc, argv)
int argc;
- FRAME_ADDR *argv;
+ CORE_ADDR *argv;
{
if (argc != 2)
error ("MIPS frame specifications require two arguments: sp and pc");
CORE_ADDR
mips_push_arguments(nargs, args, sp, struct_return, struct_addr)
int nargs;
- value *args;
+ value_ptr *args;
CORE_ADDR sp;
int struct_return;
CORE_ADDR struct_addr;
{
- CORE_ADDR buf;
register i;
- int accumulate_size = struct_return ? 4 : 0;
+ int accumulate_size = struct_return ? MIPS_REGSIZE : 0;
struct mips_arg { char *contents; int len; int offset; };
struct mips_arg *mips_args =
- (struct mips_arg*)alloca(nargs * sizeof(struct mips_arg));
+ (struct mips_arg*)alloca((nargs + 4) * sizeof(struct mips_arg));
register struct mips_arg *m_arg;
+ int fake_args = 0;
+
for (i = 0, m_arg = mips_args; i < nargs; i++, m_arg++) {
- extern value value_arg_coerce();
- value arg = value_arg_coerce (args[i]);
+ value_ptr arg = value_arg_coerce (args[i]);
m_arg->len = TYPE_LENGTH (VALUE_TYPE (arg));
/* This entire mips-specific routine is because doubles must be aligned
* on 8-byte boundaries. It still isn't quite right, because MIPS decided
* breaks their varargs implementation...). A correct solution
* requires an simulation of gcc's 'alignof' (and use of 'alignof'
* in stdarg.h/varargs.h).
+ * On the 64 bit r4000 we always pass the first four arguments
+ * using eight bytes each, so that we can load them up correctly
+ * in CALL_DUMMY.
*/
- if (m_arg->len > 4) accumulate_size = (accumulate_size + 7) & -8;
+ if (m_arg->len > 4)
+ accumulate_size = (accumulate_size + 7) & -8;
m_arg->offset = accumulate_size;
- accumulate_size = (accumulate_size + m_arg->len + 3) & -4;
m_arg->contents = VALUE_CONTENTS(arg);
+ if (! GDB_TARGET_IS_MIPS64)
+ accumulate_size = (accumulate_size + m_arg->len + 3) & -4;
+ else
+ {
+ if (accumulate_size >= 4 * MIPS_REGSIZE)
+ accumulate_size = (accumulate_size + m_arg->len + 3) &~ 4;
+ else
+ {
+ static char zeroes[8] = { 0 };
+ int len = m_arg->len;
+
+ if (len < 8)
+ {
+ if (TARGET_BYTE_ORDER == BIG_ENDIAN)
+ m_arg->offset += 8 - len;
+ ++m_arg;
+ m_arg->len = 8 - len;
+ m_arg->contents = zeroes;
+ if (TARGET_BYTE_ORDER == BIG_ENDIAN)
+ m_arg->offset = accumulate_size;
+ else
+ m_arg->offset = accumulate_size + len;
+ ++fake_args;
+ }
+ accumulate_size = (accumulate_size + len + 7) & ~8;
+ }
+ }
}
accumulate_size = (accumulate_size + 7) & (-8);
- if (accumulate_size < 16) accumulate_size = 16;
+ if (accumulate_size < 4 * MIPS_REGSIZE)
+ accumulate_size = 4 * MIPS_REGSIZE;
sp -= accumulate_size;
- for (i = nargs; m_arg--, --i >= 0; )
+ for (i = nargs + fake_args; m_arg--, --i >= 0; )
write_memory(sp + m_arg->offset, m_arg->contents, m_arg->len);
- if (struct_return) {
- buf = struct_addr;
- write_memory(sp, (char *)&buf, sizeof(CORE_ADDR));
- }
+ if (struct_return)
+ {
+ char buf[TARGET_PTR_BIT / HOST_CHAR_BIT];
+
+ store_address (buf, sizeof buf, struct_addr);
+ write_memory (sp, buf, sizeof buf);
+ }
return sp;
}
/* MASK(i,j) == (1<<i) + (1<<(i+1)) + ... + (1<<j)). Assume i<=j<31. */
-#define MASK(i,j) ((1 << (j)+1)-1 ^ (1 << (i))-1)
+#define MASK(i,j) (((1 << ((j)+1))-1) ^ ((1 << (i))-1))
void
mips_push_dummy_frame()
{
+ char buffer[MAX_REGISTER_RAW_SIZE];
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 = read_register (SP_REGNUM);
CORE_ADDR save_address;
- REGISTER_TYPE buffer;
link->next = linked_proc_desc_table;
linked_proc_desc_table = link;
#define PUSH_FP_REGNUM 16 /* must be a register preserved across calls */
for (ireg = 32; --ireg >= 0; )
if (PROC_REG_MASK(proc_desc) & (1 << ireg))
{
- buffer = read_register (ireg);
- write_memory (save_address, (char *)&buffer, sizeof(REGISTER_TYPE));
+ read_register_gen (ireg, buffer);
+
+ /* Need to fix the save_address decrement below, and also make sure
+ that we don't run into problems with the size of the dummy frame
+ or any of the offsets within it. */
+ if (REGISTER_RAW_SIZE (ireg) > 4)
+ error ("Cannot call functions on mips64");
+
+ write_memory (save_address, buffer, REGISTER_RAW_SIZE (ireg));
save_address -= 4;
}
/* save floating-points registers starting with high order word */
for (ireg = 32; --ireg >= 0; )
if (PROC_FREG_MASK(proc_desc) & (1 << ireg))
{
- buffer = read_register (ireg + FP0_REGNUM);
- write_memory (save_address, (char *)&buffer, 4);
+ read_register_gen (ireg + FP0_REGNUM, buffer);
+
+ if (REGISTER_RAW_SIZE (ireg + FP0_REGNUM) > 4)
+ error ("Cannot call functions on mips64");
+
+ write_memory (save_address, buffer,
+ REGISTER_RAW_SIZE (ireg + FP0_REGNUM));
save_address -= 4;
}
write_register (PUSH_FP_REGNUM, sp);
PROC_FRAME_REG(proc_desc) = PUSH_FP_REGNUM;
PROC_FRAME_OFFSET(proc_desc) = 0;
- buffer = read_register (PC_REGNUM);
- write_memory (sp - 4, (char *)&buffer, sizeof(REGISTER_TYPE));
- buffer = read_register (HI_REGNUM);
- write_memory (sp - 8, (char *)&buffer, sizeof(REGISTER_TYPE));
- buffer = read_register (LO_REGNUM);
- write_memory (sp - 12, (char *)&buffer, sizeof(REGISTER_TYPE));
- buffer = read_register (mips_fpu ? FCRCS_REGNUM : ZERO_REGNUM);
- write_memory (sp - 16, (char *)&buffer, sizeof(REGISTER_TYPE));
+ read_register_gen (PC_REGNUM, buffer);
+ write_memory (sp - 4, buffer, REGISTER_RAW_SIZE (PC_REGNUM));
+ read_register_gen (HI_REGNUM, buffer);
+ write_memory (sp - 8, buffer, REGISTER_RAW_SIZE (HI_REGNUM));
+ read_register_gen (LO_REGNUM, buffer);
+ write_memory (sp - 12, buffer, REGISTER_RAW_SIZE (LO_REGNUM));
+ if (mips_fpu)
+ read_register_gen (FCRCS_REGNUM, buffer);
+ else
+ memset (buffer, 0, REGISTER_RAW_SIZE (FCRCS_REGNUM));
+ write_memory (sp - 16, buffer, REGISTER_RAW_SIZE (FCRCS_REGNUM));
sp -= 4 * (GEN_REG_SAVE_COUNT
+ (mips_fpu ? FLOAT_REG_SAVE_COUNT : 0)
+ SPECIAL_REG_SAVE_COUNT);
mips_pop_frame()
{
register int regnum;
- FRAME frame = get_current_frame ();
- CORE_ADDR new_sp = frame->frame;
+ struct frame_info *frame = get_current_frame ();
+ CORE_ADDR new_sp = FRAME_FP (frame);
mips_extra_func_info_t proc_desc = frame->proc_desc;
write_register (PC_REGNUM, FRAME_SAVED_PC(frame));
+ if (frame->saved_regs == NULL)
+ mips_find_saved_regs (frame);
if (proc_desc)
{
for (regnum = 32; --regnum >= 0; )
}
write_register (SP_REGNUM, new_sp);
flush_cached_frames ();
- /* We let mips_init_extra_frame_info figure out the frame pointer */
- set_current_frame (create_new_frame (0, read_pc ()));
- if (PROC_DESC_IS_DUMMY(proc_desc))
+ if (proc_desc && PROC_DESC_IS_DUMMY(proc_desc))
{
struct linked_proc_info *pi_ptr, *prev_ptr;
int regnum, all;
{
unsigned char raw_buffer[MAX_REGISTER_RAW_SIZE];
- REGISTER_TYPE val;
+ struct type *our_type =
+ init_type (TYPE_CODE_INT,
+ /* We will fill in the length for each register. */
+ 0,
+ TYPE_FLAG_UNSIGNED,
+ NULL,
+ NULL);
/* Get the data in raw format. */
if (read_relative_register_raw_bytes (regnum, raw_buffer))
#endif
printf_filtered ("(d%d: ", regnum-FP0_REGNUM);
val_print (builtin_type_double, dbuffer, 0,
- stdout, 0, 1, 0, Val_pretty_default);
+ gdb_stdout, 0, 1, 0, Val_pretty_default);
printf_filtered ("); ");
}
- fputs_filtered (reg_names[regnum], stdout);
+ fputs_filtered (reg_names[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
printf_filtered (": ");
/* If virtual format is floating, print it that way. */
- if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT
- && ! INVALID_FLOAT (raw_buffer, REGISTER_VIRTUAL_SIZE(regnum))) {
+ if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT)
val_print (REGISTER_VIRTUAL_TYPE (regnum), raw_buffer, 0,
- stdout, 0, 1, 0, Val_pretty_default);
- }
+ gdb_stdout, 0, 1, 0, Val_pretty_default);
/* Else print as integer in hex. */
else
- {
- long val;
-
- val = extract_signed_integer (raw_buffer,
- REGISTER_RAW_SIZE (regnum));
-
- if (val == 0)
- printf_filtered ("0");
- else if (all)
- /* FIXME: We should be printing this in a fixed field width, so that
- registers line up. */
- printf_filtered (local_hex_format(), val);
- else
- printf_filtered ("%s=%d", local_hex_string(val), val);
- }
+ print_scalar_formatted (raw_buffer, REGISTER_VIRTUAL_TYPE (regnum),
+ 'x', 0, gdb_stdout);
}
/* Replacement for generic do_registers_info. */
+
void
mips_do_registers_info (regnum, fpregs)
int regnum;
int fpregs;
{
- if (regnum != -1) {
+ if (regnum != -1)
+ {
+ if (*(reg_names[regnum]) == '\0')
+ error ("Not a valid register for the current processor type");
+
mips_print_register (regnum, 0);
printf_filtered ("\n");
- }
- else {
- for (regnum = 0; regnum < NUM_REGS; ) {
- if ((!fpregs) && regnum >= FP0_REGNUM && regnum <= FCRIR_REGNUM) {
- regnum++;
- continue;
- }
+ }
+ else
+ {
+ int did_newline;
+
+ for (regnum = 0; regnum < NUM_REGS; )
+ {
+ if (((!fpregs) && regnum >= FP0_REGNUM && regnum <= FCRIR_REGNUM)
+ || *(reg_names[regnum]) == '\0')
+ {
+ regnum++;
+ continue;
+ }
mips_print_register (regnum, 1);
regnum++;
- if ((regnum & 3) == 0 || regnum == NUM_REGS)
- printf_filtered (";\n");
- else
- printf_filtered ("; ");
- }
- }
+ printf_filtered ("; ");
+ did_newline = 0;
+ if ((regnum & 3) == 0)
+ {
+ printf_filtered ("\n");
+ did_newline = 1;
+ }
+ }
+ if (!did_newline)
+ printf_filtered ("\n");
+ }
}
+
/* Return number of args passed to a frame. described by FIP.
Can return -1, meaning no way to tell. */
int
-mips_frame_num_args(fip)
- FRAME fip;
+mips_frame_num_args (frame)
+ struct frame_info *frame;
{
-#if 0
- struct chain_info_t *p;
+#if 0 /* FIXME Use or lose this! */
+ struct chain_info_t *p;
- p = mips_find_cached_frame(FRAME_FP(fip));
- if (p->valid)
- return p->the_info.numargs;
+ p = mips_find_cached_frame (FRAME_FP (frame));
+ if (p->valid)
+ return p->the_info.numargs;
#endif
- return -1;
+ return -1;
}
\f
/* Is this a branch with a delay slot? */
+
+static int is_delayed PARAMS ((unsigned long));
+
static int
is_delayed (insn)
unsigned long insn;
| INSN_COND_BRANCH_LIKELY)));
}
+int
+mips_step_skips_delay (pc)
+ CORE_ADDR pc;
+{
+ char buf[4];
+
+ if (target_read_memory (pc, buf, 4) != 0)
+ /* If error reading memory, guess that it is not a delayed branch. */
+ return 0;
+ return is_delayed (extract_unsigned_integer (buf, 4));
+}
+
/* To skip prologues, I use this predicate. Returns either PC itself
if the code at PC does not look like a function prologue; otherwise
returns an address that (if we're lucky) follows the prologue. If
CORE_ADDR pc;
int lenient;
{
- struct symbol *f;
- struct block *b;
unsigned long inst;
int offset;
int seen_sp_adjust = 0;
+ int load_immediate_bytes = 0;
/* Skip the typical prologue instructions. These are the stack adjustment
instruction and the instructions that save registers on the stack
memory_error (status, pc + offset);
inst = extract_unsigned_integer (buf, 4);
+#if 0
if (lenient && is_delayed (inst))
continue;
+#endif
if ((inst & 0xffff0000) == 0x27bd0000) /* addiu $sp,$sp,offset */
seen_sp_adjust = 1;
+ else if (inst == 0x03a1e823 || /* subu $sp,$sp,$at */
+ inst == 0x03a8e823) /* subu $sp,$sp,$t0 */
+ seen_sp_adjust = 1;
else if ((inst & 0xFFE00000) == 0xAFA00000 && (inst & 0x001F0000))
continue; /* sw reg,n($sp) */
/* reg != $zero */
else if ((inst & 0xF3E00000) == 0xA3C00000 && (inst & 0x001F0000))
/* sx reg,n($s8) */
continue; /* reg != $zero */
- else if (inst == 0x03A0F021) /* move $s8,$sp */
+
+ /* move $s8,$sp. With different versions of gas this will be either
+ `addu $s8,$sp,$zero' or `or $s8,$sp,$zero'. Accept either. */
+ else if (inst == 0x03A0F021 || inst == 0x03a0f025)
continue;
+
else if ((inst & 0xFF9F07FF) == 0x00800021) /* move reg,$a0-$a3 */
continue;
+ else if ((inst & 0xffff0000) == 0x3c1c0000) /* lui $gp,n */
+ continue;
+ else if ((inst & 0xffff0000) == 0x279c0000) /* addiu $gp,$gp,n */
+ continue;
+ else if (inst == 0x0399e021 /* addu $gp,$gp,$t9 */
+ || inst == 0x033ce021) /* addu $gp,$t9,$gp */
+ continue;
+ /* The following instructions load $at or $t0 with an immediate
+ value in preparation for a stack adjustment via
+ subu $sp,$sp,[$at,$t0]. These instructions could also initialize
+ a local variable, so we accept them only before a stack adjustment
+ instruction was seen. */
+ else if (!seen_sp_adjust)
+ {
+ if ((inst & 0xffff0000) == 0x3c010000 || /* lui $at,n */
+ (inst & 0xffff0000) == 0x3c080000) /* lui $t0,n */
+ {
+ load_immediate_bytes += 4;
+ continue;
+ }
+ else if ((inst & 0xffff0000) == 0x34210000 || /* ori $at,$at,n */
+ (inst & 0xffff0000) == 0x35080000 || /* ori $t0,$t0,n */
+ (inst & 0xffff0000) == 0x34010000 || /* ori $at,$zero,n */
+ (inst & 0xffff0000) == 0x34080000) /* ori $t0,$zero,n */
+ {
+ load_immediate_bytes += 4;
+ continue;
+ }
+ else
+ break;
+ }
else
- break;
+ break;
}
- return pc + offset;
-/* FIXME schauer. The following code seems no longer necessary if we
- always skip the typical prologue instructions. */
+ /* In a frameless function, we might have incorrectly
+ skipped some load immediate instructions. Undo the skipping
+ if the load immediate was not followed by a stack adjustment. */
+ if (load_immediate_bytes && !seen_sp_adjust)
+ offset -= load_immediate_bytes;
+ return pc + offset;
+}
#if 0
- if (seen_sp_adjust)
- return pc + offset;
-
- /* Well, it looks like a frameless. Let's make sure.
- Note that we are not called on the current PC,
- but on the function`s start PC, and I have definitely
- seen optimized code that adjusts the SP quite later */
- b = block_for_pc(pc);
- if (!b) return pc;
-
- f = lookup_symbol(MIPS_EFI_SYMBOL_NAME, b, LABEL_NAMESPACE, 0, NULL);
- if (!f) return pc;
- /* Ideally, I would like to use the adjusted info
- from mips_frame_info(), but for all practical
- purposes it will not matter (and it would require
- a different definition of SKIP_PROLOGUE())
-
- Actually, it would not hurt to skip the storing
- of arguments on the stack as well. */
- if (((mips_extra_func_info_t)SYMBOL_VALUE(f))->pdr.frameoffset)
- return pc + 4;
-
- return pc;
-#endif
-}
+/* The lenient prologue stuff should be superceded by the code in
+ init_extra_frame_info which looks to see whether the stores mentioned
+ in the proc_desc have actually taken place. */
/* Is address PC in the prologue (loosely defined) for function at
STARTADDR? */
CORE_ADDR end_prologue = mips_skip_prologue (startaddr, 1);
return pc >= startaddr && pc < end_prologue;
}
+#endif
/* Given a return value in `regbuf' with a type `valtype',
extract and copy its value into `valbuf'. */
write_register_bytes(REGISTER_BYTE (regnum), raw_buffer, TYPE_LENGTH (valtype));
}
-static void reinit_frame_cache_sfunc PARAMS ((char *, int
- struct cmd_list_element *));
+/* These exist in mdebugread.c. */
+extern CORE_ADDR sigtramp_address, sigtramp_end;
+extern void fixup_sigtramp PARAMS ((void));
+
+/* Exported procedure: Is PC in the signal trampoline code */
+
+int
+in_sigtramp (pc, ignore)
+ CORE_ADDR pc;
+ char *ignore; /* function name */
+{
+ if (sigtramp_address == 0)
+ fixup_sigtramp ();
+ return (pc >= sigtramp_address && pc < sigtramp_end);
+}
+
+/* Command to set the processor type. */
+
+void
+mips_set_processor_type_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+ int i;
+
+ if (tmp_mips_processor_type == NULL || *tmp_mips_processor_type == '\0')
+ {
+ printf_unfiltered ("The known MIPS processor types are as follows:\n\n");
+ for (i = 0; mips_processor_type_table[i].name != NULL; ++i)
+ printf_unfiltered ("%s\n", mips_processor_type_table[i].name);
+
+ /* Restore the value. */
+ tmp_mips_processor_type = strsave (mips_processor_type);
+
+ return;
+ }
+
+ if (!mips_set_processor_type (tmp_mips_processor_type))
+ {
+ error ("Unknown processor type `%s'.", tmp_mips_processor_type);
+ /* Restore its value. */
+ tmp_mips_processor_type = strsave (mips_processor_type);
+ }
+}
+
+static void
+mips_show_processor_type_command (args, from_tty)
+ char *args;
+ int from_tty;
+{
+}
+
+/* Modify the actual processor type. */
+
+int
+mips_set_processor_type (str)
+ char *str;
+{
+ int i, j;
+
+ if (str == NULL)
+ return 0;
+
+ for (i = 0; mips_processor_type_table[i].name != NULL; ++i)
+ {
+ if (strcasecmp (str, mips_processor_type_table[i].name) == 0)
+ {
+ mips_processor_type = str;
+
+ for (j = 0; j < NUM_REGS; ++j)
+ reg_names[j] = mips_processor_type_table[i].regnames[j];
+
+ return 1;
+
+ /* FIXME tweak fpu flag too */
+ }
+ }
+
+ return 0;
+}
+
+/* Attempt to identify the particular processor model by reading the
+ processor id. */
+
+char *
+mips_read_processor_type ()
+{
+ int prid;
+
+ prid = read_register (PRID_REGNUM);
+
+ if (prid & ~0xf == 0x700)
+ return savestring ("r3041", strlen("r3041"));
+
+ return NULL;
+}
/* Just like reinit_frame_cache, but with the right arguments to be
callable as an sfunc. */
+
static void
reinit_frame_cache_sfunc (args, from_tty, c)
char *args;
reinit_frame_cache ();
}
+int
+gdb_print_insn_mips (memaddr, info)
+ bfd_vma memaddr;
+ disassemble_info *info;
+{
+ if (TARGET_BYTE_ORDER == BIG_ENDIAN)
+ return print_insn_big_mips (memaddr, info);
+ else
+ return print_insn_little_mips (memaddr, info);
+}
+
void
_initialize_mips_tdep ()
{
struct cmd_list_element *c;
+ tm_print_insn = gdb_print_insn_mips;
+
/* Let the user turn off floating point and set the fence post for
heuristic_proc_start. */
or dealing with return values.", &setlist),
&showlist);
- c = add_set_cmd ("heuristic-fence-post", class_support, var_uinteger,
+ c = add_set_cmd ("processor", class_support, var_string_noescape,
+ (char *) &tmp_mips_processor_type,
+ "Set the type of MIPS processor in use.\n\
+Set this to be able to access processor-type-specific registers.\n\
+",
+ &setlist);
+ c->function.cfunc = mips_set_processor_type_command;
+ c = add_show_from_set (c, &showlist);
+ c->function.cfunc = mips_show_processor_type_command;
+
+ tmp_mips_processor_type = strsave (DEFAULT_MIPS_TYPE);
+ mips_set_processor_type_command (strsave (DEFAULT_MIPS_TYPE), 0);
+
+ /* We really would like to have both "0" and "unlimited" work, but
+ command.c doesn't deal with that. So make it a var_zinteger
+ because the user can always use "999999" or some such for unlimited. */
+ c = add_set_cmd ("heuristic-fence-post", class_support, var_zinteger,
(char *) &heuristic_fence_post,
"\
Set the distance searched for the start of a function.\n\