X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fmips-tdep.c;h=d708b6acabc7ec643592d6e09f46a7b4327e25ea;hb=41270571562fe1b32a38ba7a49dac8a9e416d1c8;hp=454ab73364d6dee10d96253e4cb0a53846522a38;hpb=e03c0cc67016bb6c50add63e0176a4c3cd0f011e;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c index 454ab73364..d708b6acab 100644 --- a/gdb/mips-tdep.c +++ b/gdb/mips-tdep.c @@ -1,5 +1,6 @@ /* 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. @@ -29,22 +30,112 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #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; #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 */ @@ -68,44 +159,184 @@ struct linked_proc_info } *linked_proc_desc_table = NULL; -#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 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 * 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); @@ -181,9 +412,9 @@ Otherwise, you told GDB there was a function where there isn't one, or\n\ 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; @@ -191,11 +422,12 @@ heuristic_proc_desc(start_pc, limit_pc, next_frame) unsigned long reg_mask = 0; if (start_pc == 0) return NULL; - 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; + 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) { @@ -254,9 +486,9 @@ heuristic_proc_desc(start_pc, limit_pc, next_frame) } 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); @@ -286,7 +518,7 @@ find_proc_desc(pc, next_frame) * 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 = @@ -300,9 +532,10 @@ find_proc_desc(pc, next_frame) } if (!proc_symbol || pc < val.pc) { mips_extra_func_info_t found_heuristic = - heuristic_proc_desc(PROC_LOW_ADDR(proc_desc), - pc, next_frame); - 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; } } } @@ -314,10 +547,11 @@ find_proc_desc(pc, next_frame) 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); @@ -330,9 +564,9 @@ find_proc_desc(pc, next_frame) 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); @@ -364,127 +598,34 @@ 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; - /* 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); + 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 { - /* What registers have been saved? Bitmasks. */ - unsigned long gen_mask, float_mask; - - 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) - { - /* 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) - { - 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 -= 4; - } - /* 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 -= 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 */ @@ -493,8 +634,6 @@ init_extra_frame_info(fci) 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]; } } @@ -513,10 +652,10 @@ init_extra_frame_info(fci) 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"); @@ -528,21 +667,21 @@ setup_arbitrary_frame (argc, argv) 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 @@ -550,21 +689,55 @@ mips_push_arguments(nargs, args, sp, struct_return, struct_addr) * 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; } @@ -574,13 +747,13 @@ mips_push_arguments(nargs, args, sp, struct_return, struct_addr) 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 */ @@ -621,8 +794,15 @@ mips_push_dummy_frame() 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 */ @@ -630,21 +810,29 @@ mips_push_dummy_frame() 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); @@ -659,12 +847,14 @@ void 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; ) @@ -679,8 +869,6 @@ mips_pop_frame() } 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 && PROC_DESC_IS_DUMMY(proc_desc)) { @@ -716,6 +904,13 @@ mips_print_register (regnum, all) int regnum, all; { unsigned char raw_buffer[MAX_REGISTER_RAW_SIZE]; + 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)) @@ -751,74 +946,78 @@ mips_print_register (regnum, all) 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, 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=%ld", 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; } -#if 0 /* Is this a branch with a delay slot? */ + +static int is_delayed PARAMS ((unsigned long)); + static int is_delayed (insn) unsigned long insn; @@ -833,7 +1032,18 @@ is_delayed (insn) | INSN_COND_BRANCH_DELAY | INSN_COND_BRANCH_LIKELY))); } -#endif + +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 @@ -852,6 +1062,7 @@ mips_skip_prologue (pc, lenient) 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 @@ -873,6 +1084,9 @@ mips_skip_prologue (pc, lenient) 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 */ @@ -881,8 +1095,12 @@ mips_skip_prologue (pc, lenient) 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 */ @@ -892,39 +1110,40 @@ mips_skip_prologue (pc, lenient) 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. */ - -#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 + /* 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 @@ -999,11 +1218,90 @@ in_sigtramp (pc, ignore) return (pc >= sigtramp_address && pc < sigtramp_end); } -static void reinit_frame_cache_sfunc PARAMS ((char *, int, - struct cmd_list_element *)); +/* 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; @@ -1013,11 +1311,24 @@ reinit_frame_cache_sfunc (args, from_tty, c) 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. */ @@ -1029,6 +1340,19 @@ Turn off to avoid using floating point instructions when calling functions\n\ or dealing with return values.", &setlist), &showlist); + 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. */