/* Target-dependent code for the MIPS architecture, for GDB, the GNU Debugger.
- Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
- 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
- 2010, 2011 Free Software Foundation, Inc.
+ Copyright (C) 1988-2012 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.
static const char *mips_abi_string;
-static const char *mips_abi_strings[] = {
+static const char *const mips_abi_strings[] = {
"auto",
"n32",
"o32",
return mips_regnum (gdbarch)->fp0 + 12;
}
+/* Return 1 if REGNUM refers to a floating-point general register, raw
+ or cooked. Otherwise return 0. */
+
+static int
+mips_float_register_p (struct gdbarch *gdbarch, int regnum)
+{
+ int rawnum = regnum % gdbarch_num_regs (gdbarch);
+
+ return (rawnum >= mips_regnum (gdbarch)->fp0
+ && rawnum < mips_regnum (gdbarch)->fp0 + 32);
+}
+
#define MIPS_EABI(gdbarch) (gdbarch_tdep (gdbarch)->mips_abi \
== MIPS_ABI_EABI32 \
|| gdbarch_tdep (gdbarch)->mips_abi == MIPS_ABI_EABI64)
#define MIPS_FPU_TYPE(gdbarch) (gdbarch_tdep (gdbarch)->mips_fpu_type)
-/* MIPS16 function addresses are odd (bit 0 is set). Here are some
- functions to test, set, or clear bit 0 of addresses. */
-
-static CORE_ADDR
-is_mips16_addr (CORE_ADDR addr)
-{
- return ((addr) & 1);
-}
-
-static CORE_ADDR
-unmake_mips16_addr (CORE_ADDR addr)
-{
- return ((addr) & ~(CORE_ADDR) 1);
-}
-
-static CORE_ADDR
-make_mips16_addr (CORE_ADDR addr)
-{
- return ((addr) | (CORE_ADDR) 1);
-}
-
/* Return the MIPS ABI associated with GDBARCH. */
enum mips_abi
mips_abi (struct gdbarch *gdbarch)
}
}
+/* MIPS16 function addresses are odd (bit 0 is set). Here are some
+ functions to test, set, or clear bit 0 of addresses. */
+
+static CORE_ADDR
+is_mips16_addr (CORE_ADDR addr)
+{
+ return ((addr) & 1);
+}
+
+static CORE_ADDR
+unmake_mips16_addr (CORE_ADDR addr)
+{
+ return ((addr) & ~(CORE_ADDR) 1);
+}
+
+static CORE_ADDR
+make_mips16_addr (CORE_ADDR addr)
+{
+ return ((addr) | (CORE_ADDR) 1);
+}
+
/* 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.
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)
+ if (ELF_ST_IS_MIPS16 (((elf_symbol_type *)
+ (sym))->internal_elf_sym.st_other))
{
MSYMBOL_TARGET_FLAG_1 (msym) = 1;
}
"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",
};
/* Names of IDT R3041 registers. */
"", "", "", "", "", "", "", "",
"", "", "", "",
"", "", "", "", "", "", "", "",
- "", "", "config", "cache", "debug", "depc", "epc", ""
+ "", "", "config", "cache", "debug", "depc", "epc",
};
/* Names of IRIX registers. */
"pc", "cause", "bad", "hi", "lo", "fsr", "fir"
};
+/* Names of registers with Linux kernels. */
+static const char *mips_linux_reg_names[NUM_MIPS_PROCESSOR_REGS] = {
+ "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"
+};
+
/* Return the name of the register corresponding to REGNO. */
static const char *
else if (32 <= rawnum && rawnum < gdbarch_num_regs (gdbarch))
{
gdb_assert (rawnum - 32 < NUM_MIPS_PROCESSOR_REGS);
- return tdep->mips_processor_reg_names[rawnum - 32];
+ if (tdep->mips_processor_reg_names[rawnum - 32])
+ return tdep->mips_processor_reg_names[rawnum - 32];
+ return "";
}
else
internal_error (__FILE__, __LINE__,
gdbarch_num_regs .. 2 * gdbarch_num_regs) back onto the corresponding raw
registers. Take care of alignment and size problems. */
-static void
+static enum register_status
mips_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
int cookednum, gdb_byte *buf)
{
gdb_assert (cookednum >= gdbarch_num_regs (gdbarch)
&& cookednum < 2 * gdbarch_num_regs (gdbarch));
if (register_size (gdbarch, rawnum) == register_size (gdbarch, cookednum))
- regcache_raw_read (regcache, rawnum, buf);
+ return regcache_raw_read (regcache, rawnum, buf);
else if (register_size (gdbarch, rawnum) >
register_size (gdbarch, cookednum))
{
if (gdbarch_tdep (gdbarch)->mips64_transfers_32bit_regs_p)
- regcache_raw_read_part (regcache, rawnum, 0, 4, buf);
+ return regcache_raw_read_part (regcache, rawnum, 0, 4, buf);
else
{
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
LONGEST regval;
- regcache_raw_read_signed (regcache, rawnum, ®val);
- store_signed_integer (buf, 4, byte_order, regval);
+ enum register_status status;
+
+ status = regcache_raw_read_signed (regcache, rawnum, ®val);
+ if (status == REG_VALID)
+ store_signed_integer (buf, 4, byte_order, regval);
+ return status;
}
}
else
{
return (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG
&& register_size (gdbarch, regnum) == 4
- && (regnum % gdbarch_num_regs (gdbarch))
- >= mips_regnum (gdbarch)->fp0
- && (regnum % gdbarch_num_regs (gdbarch))
- < mips_regnum (gdbarch)->fp0 + 32
+ && mips_float_register_p (gdbarch, regnum)
&& TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) == 8);
}
|| mips_convert_register_gpreg_case_p (gdbarch, regnum, type);
}
-static void
+static int
mips_register_to_value (struct frame_info *frame, int regnum,
- struct type *type, gdb_byte *to)
+ struct type *type, gdb_byte *to,
+ int *optimizedp, int *unavailablep)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
{
get_frame_register (frame, regnum + 0, to + 4);
get_frame_register (frame, regnum + 1, to + 0);
+
+ if (!get_frame_register_bytes (frame, regnum + 0, 0, 4, to + 4,
+ optimizedp, unavailablep))
+ return 0;
+
+ if (!get_frame_register_bytes (frame, regnum + 1, 0, 4, to + 0,
+ optimizedp, unavailablep))
+ return 0;
+ *optimizedp = *unavailablep = 0;
+ return 1;
}
else if (mips_convert_register_gpreg_case_p (gdbarch, regnum, type))
{
int len = TYPE_LENGTH (type);
- if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
- get_frame_register_bytes (frame, regnum, 8 - len, len, to);
- else
- get_frame_register_bytes (frame, regnum, 0, len, to);
+ CORE_ADDR offset;
+
+ offset = gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG ? 8 - len : 0;
+ if (!get_frame_register_bytes (frame, regnum, offset, len, to,
+ optimizedp, unavailablep))
+ return 0;
+
+ *optimizedp = *unavailablep = 0;
+ return 1;
}
else
{
mips_register_type (struct gdbarch *gdbarch, int regnum)
{
gdb_assert (regnum >= 0 && regnum < 2 * gdbarch_num_regs (gdbarch));
- if ((regnum % gdbarch_num_regs (gdbarch)) >= mips_regnum (gdbarch)->fp0
- && (regnum % gdbarch_num_regs (gdbarch))
- < mips_regnum (gdbarch)->fp0 + 32)
+ if (mips_float_register_p (gdbarch, regnum))
{
/* The floating-point registers raw, or cooked, always match
mips_isa_regsize(), and also map 1:1, byte for byte. */
}
else
{
+ int rawnum = regnum - gdbarch_num_regs (gdbarch);
+
/* The cooked or ABI registers. These are sized according to
the ABI (with a few complications). */
- if (regnum >= (gdbarch_num_regs (gdbarch)
- + mips_regnum (gdbarch)->fp_control_status)
- && regnum <= gdbarch_num_regs (gdbarch) + MIPS_LAST_EMBED_REGNUM)
+ if (rawnum == mips_regnum (gdbarch)->fp_control_status
+ || rawnum == mips_regnum (gdbarch)->fp_implementation_revision)
+ return builtin_type (gdbarch)->builtin_int32;
+ else if (gdbarch_osabi (gdbarch) != GDB_OSABI_IRIX
+ && gdbarch_osabi (gdbarch) != GDB_OSABI_LINUX
+ && rawnum >= MIPS_FIRST_EMBED_REGNUM
+ && rawnum <= MIPS_LAST_EMBED_REGNUM)
/* The pseudo/cooked view of the embedded registers is always
32-bit. The raw view is handled below. */
return builtin_type (gdbarch)->builtin_int32;
if (TYPE_LENGTH (rawtype) == 0)
return rawtype;
- if (rawnum >= MIPS_EMBED_FP0_REGNUM && rawnum < MIPS_EMBED_FP0_REGNUM + 32)
+ if (rawnum >= mips_regnum (gdbarch)->fp0
+ && rawnum < mips_regnum (gdbarch)->fp0 + 32)
/* Present the floating point registers however the hardware did;
do not try to convert between FPU layouts. */
return rawtype;
- if (rawnum >= MIPS_EMBED_FP0_REGNUM + 32 && rawnum <= MIPS_LAST_EMBED_REGNUM)
- {
- /* The pseudo/cooked view of embedded registers is always
- 32-bit, even if the target transfers 64-bit values for them.
- New targets relying on XML descriptions should only transfer
- the necessary 32 bits, but older versions of GDB expected 64,
- so allow the target to provide 64 bits without interfering
- with the displayed type. */
- return builtin_type (gdbarch)->builtin_int32;
- }
-
/* Use pointer types for registers if we can. For n32 we can not,
since we do not have a 64-bit pointer type. */
if (mips_abi_regsize (gdbarch)
== TYPE_LENGTH (builtin_type (gdbarch)->builtin_data_ptr))
{
- if (rawnum == MIPS_SP_REGNUM || rawnum == MIPS_EMBED_BADVADDR_REGNUM)
+ if (rawnum == MIPS_SP_REGNUM
+ || rawnum == mips_regnum (gdbarch)->badvaddr)
return builtin_type (gdbarch)->builtin_data_ptr;
- else if (rawnum == MIPS_EMBED_PC_REGNUM)
+ else if (rawnum == mips_regnum (gdbarch)->pc)
return builtin_type (gdbarch)->builtin_func_ptr;
}
if (mips_abi_regsize (gdbarch) == 4 && TYPE_LENGTH (rawtype) == 8
- && rawnum >= MIPS_ZERO_REGNUM && rawnum <= MIPS_EMBED_PC_REGNUM)
+ && ((rawnum >= MIPS_ZERO_REGNUM && rawnum <= MIPS_PS_REGNUM)
+ || rawnum == mips_regnum (gdbarch)->lo
+ || rawnum == mips_regnum (gdbarch)->hi
+ || rawnum == mips_regnum (gdbarch)->badvaddr
+ || rawnum == mips_regnum (gdbarch)->cause
+ || rawnum == mips_regnum (gdbarch)->pc
+ || (mips_regnum (gdbarch)->dspacc != -1
+ && rawnum >= mips_regnum (gdbarch)->dspacc
+ && rawnum < mips_regnum (gdbarch)->dspacc + 6)))
return builtin_type (gdbarch)->builtin_int32;
+ if (gdbarch_osabi (gdbarch) != GDB_OSABI_IRIX
+ && gdbarch_osabi (gdbarch) != GDB_OSABI_LINUX
+ && rawnum >= MIPS_EMBED_FP0_REGNUM + 32
+ && rawnum <= MIPS_LAST_EMBED_REGNUM)
+ {
+ /* The pseudo/cooked view of embedded registers is always
+ 32-bit, even if the target transfers 64-bit values for them.
+ New targets relying on XML descriptions should only transfer
+ the necessary 32 bits, but older versions of GDB expected 64,
+ so allow the target to provide 64 bits without interfering
+ with the displayed type. */
+ return builtin_type (gdbarch)->builtin_int32;
+ }
+
/* For all other registers, pass through the hardware type. */
return rawtype;
}
{
struct minimal_symbol *sym;
- /* If bit 0 of the address is set, assume this is a MIPS16 address. */
- if (is_mips16_addr (memaddr))
- return 1;
-
- /* A flag indicating that this is a MIPS16 function is stored by elfread.c in
- the high bit of the info field. Use this to decide if the function is
- MIPS16 or normal MIPS. */
+ /* A flag indicating that this is a MIPS16 function is stored by
+ elfread.c in the high bit of the info field. Use this to decide
+ if the function is MIPS16 or normal MIPS. Otherwise if bit 0 of
+ the address is set, assume this is a MIPS16 address. */
sym = lookup_minimal_symbol_by_pc (memaddr);
if (sym)
return msymbol_is_special (sym);
else
- return 0;
+ return is_mips16_addr (memaddr);
}
/* MIPS believes that the PC has a sign extended value. Perhaps the
return ((itype_immediate (inst) ^ 0x8000) - 0x8000) << 2;
}
+/* Determine the address of the next instruction executed after the INST
+ floating condition branch instruction at PC. COUNT specifies the
+ number of the floating condition bits tested by the branch. */
+
+static CORE_ADDR
+mips32_bc1_pc (struct gdbarch *gdbarch, struct frame_info *frame,
+ ULONGEST inst, CORE_ADDR pc, int count)
+{
+ int fcsr = mips_regnum (gdbarch)->fp_control_status;
+ int cnum = (itype_rt (inst) >> 2) & (count - 1);
+ int tf = itype_rt (inst) & 1;
+ int mask = (1 << count) - 1;
+ ULONGEST fcs;
+ int cond;
+
+ if (fcsr == -1)
+ /* No way to handle; it'll most likely trap anyway. */
+ return pc;
+
+ fcs = get_frame_register_unsigned (frame, fcsr);
+ cond = ((fcs >> 24) & 0xfe) | ((fcs >> 23) & 0x01);
+
+ if (((cond >> cnum) & mask) != mask * !tf)
+ pc += mips32_relative_offset (inst);
+ else
+ pc += 4;
+
+ return pc;
+}
+
/* Determine where to set a single step breakpoint while considering
branch prediction. */
static CORE_ADDR
}
else if (itype_op (inst) == 17 && itype_rs (inst) == 8)
/* BC1F, BC1FL, BC1T, BC1TL: 010001 01000 */
+ pc = mips32_bc1_pc (gdbarch, frame, inst, pc + 4, 1);
+ else if (itype_op (inst) == 17 && itype_rs (inst) == 9
+ && (itype_rt (inst) & 2) == 0)
+ /* BC1ANY2F, BC1ANY2T: 010001 01001 xxx0x */
+ pc = mips32_bc1_pc (gdbarch, frame, inst, pc + 4, 2);
+ else if (itype_op (inst) == 17 && itype_rs (inst) == 10
+ && (itype_rt (inst) & 2) == 0)
+ /* BC1ANY4F, BC1ANY4T: 010001 01010 xxx0x */
+ pc = mips32_bc1_pc (gdbarch, frame, inst, pc + 4, 4);
+ else if (itype_op (inst) == 29)
+ /* JALX: 011101 */
+ /* The new PC will be alternate mode. */
{
- int tf = itype_rt (inst) & 0x01;
- int cnum = itype_rt (inst) >> 2;
- int fcrcs =
- get_frame_register_signed (frame,
- mips_regnum (get_frame_arch (frame))->
- fp_control_status);
- int cond = ((fcrcs >> 24) & 0x0e) | ((fcrcs >> 23) & 0x01);
-
- if (((cond >> cnum) & 0x01) == tf)
- pc += mips32_relative_offset (inst) + 4;
- else
- pc += 8;
+ unsigned long reg;
+
+ reg = jtype_target (inst) << 2;
+ /* Add 1 to indicate 16-bit mode -- invert ISA mode. */
+ pc = ((pc + 4) & ~(CORE_ADDR) 0x0fffffff) + reg + 1;
}
else
pc += 4; /* Not a branch, next instruction is easy. */
else
pc += 8; /* after the delay slot */
break;
+ case 0x1c: /* BPOSGE32 */
+ case 0x1e: /* BPOSGE64 */
+ pc += 4;
+ if (itype_rs (inst) == 0)
+ {
+ unsigned int pos = (op & 2) ? 64 : 32;
+ int dspctl = mips_regnum (gdbarch)->dspctl;
+
+ if (dspctl == -1)
+ /* No way to handle; it'll most likely trap anyway. */
+ break;
+
+ if ((get_frame_register_unsigned (frame,
+ dspctl) & 0x7f) >= pos)
+ pc += mips32_relative_offset (inst);
+ else
+ pc += 4;
+ }
+ break;
/* All of the other instructions in the REGIMM category */
default:
pc += 4;
pc = reg + ((pc + 4) & ~(CORE_ADDR) 0x0fffffff);
}
break;
- /* FIXME case JALX : */
- {
- unsigned long reg;
- reg = jtype_target (inst) << 2;
- pc = reg + ((pc + 4) & ~(CORE_ADDR) 0x0fffffff) + 1; /* yes, +1 */
- /* Add 1 to indicate 16 bit mode - Invert ISA mode */
- }
- break; /* The new PC will be alternate mode */
case 4: /* BEQ, BEQL */
equal_branch:
if (get_frame_register_signed (frame, itype_rs (inst)) ==
extended_offset (unsigned int extension)
{
CORE_ADDR value;
- value = (extension >> 21) & 0x3f; /* * extract 15:11 */
+
+ value = (extension >> 16) & 0x1f; /* Extract 15:11. */
value = value << 6;
- value |= (extension >> 16) & 0x1f; /* extract 10:5 */
+ value |= (extension >> 21) & 0x3f; /* Extract 10:5. */
value = value << 5;
- value |= extension & 0x01f; /* extract 4:0 */
+ value |= extension & 0x1f; /* Extract 4:0. */
+
return value;
}
CORE_ADDR value;
if (extension)
{
- value = extended_offset (extension);
- value = value << 11; /* rom for the original value */
- value |= inst & 0x7ff; /* eleven bits from instruction */
+ value = extended_offset ((extension << 16) | inst);
+ value = (value ^ 0x8000) - 0x8000; /* Sign-extend. */
}
else
{
value = inst & 0x7ff;
- /* FIXME : Consider sign extension. */
+ value = (value ^ 0x400) - 0x400; /* Sign-extend. */
}
offset = value;
regx = -1;
CORE_ADDR value;
if (extension)
{
- value = extended_offset (extension);
- value = value << 8; /* from the original instruction */
- value |= inst & 0xff; /* eleven bits from instruction */
- regx = (extension >> 8) & 0x07; /* or i8 funct */
- if (value & 0x4000) /* Test the sign bit, bit 26. */
- {
- value &= ~0x3fff; /* Remove the sign bit. */
- value = -value;
- }
+ value = extended_offset ((extension << 16) | inst);
+ value = (value ^ 0x8000) - 0x8000; /* Sign-extend. */
}
else
{
- value = inst & 0xff; /* 8 bits */
- regx = (inst >> 8) & 0x07; /* or i8 funct */
- /* FIXME: Do sign extension, this format needs it. */
- if (value & 0x80) /* THIS CONFUSES ME. */
- {
- value &= 0xef; /* Remove the sign bit. */
- value = -value;
- }
+ value = inst & 0xff; /* 8 bits */
+ value = (value ^ 0x80) - 0x80; /* Sign-extend. */
}
offset = value;
+ regx = (inst >> 8) & 0x07; /* i8 funct */
regy = -1;
break;
}
CORE_ADDR offset;
struct upk_mips16 upk;
unpack_mips16 (gdbarch, pc, extension, insn, itype, &upk);
- offset = upk.offset;
- if (offset & 0x800)
- {
- offset &= 0xeff;
- offset = -offset;
- }
- pc += (offset << 1) + 2;
+ pc += (upk.offset << 1) + 2;
break;
}
case 3: /* JAL , JALX - Watch out, these are 32 bit
struct upk_mips16 upk;
int reg;
unpack_mips16 (gdbarch, pc, extension, insn, ritype, &upk);
- reg = get_frame_register_signed (frame, upk.regx);
+ reg = get_frame_register_signed (frame, mips16_to_32_reg[upk.regx]);
if (reg == 0)
pc += (upk.offset << 1) + 2;
else
struct upk_mips16 upk;
int reg;
unpack_mips16 (gdbarch, pc, extension, insn, ritype, &upk);
- reg = get_frame_register_signed (frame, upk.regx);
+ reg = get_frame_register_signed (frame, mips16_to_32_reg[upk.regx]);
if (reg != 0)
pc += (upk.offset << 1) + 2;
else
int reg;
upk.regx = (insn >> 8) & 0x07;
upk.regy = (insn >> 5) & 0x07;
- switch (upk.regy)
- {
- case 0:
- reg = upk.regx;
- break;
- case 1:
- reg = 31;
- break; /* Function return instruction. */
- case 2:
- reg = upk.regx;
- break;
- default:
- reg = 31;
- break; /* BOGUS Guess */
- }
+ if ((upk.regy & 1) == 0)
+ reg = mips16_to_32_reg[upk.regx];
+ else
+ reg = 31; /* Function return instruction. */
pc = get_frame_register_signed (frame, reg);
}
else
static CORE_ADDR
mips_next_pc (struct frame_info *frame, CORE_ADDR pc)
{
- if (is_mips16_addr (pc))
+ if (mips_pc_is_mips16 (pc))
return mips16_next_pc (frame, pc);
else
return mips32_next_pc (frame, pc);
static const struct frame_unwind mips_insn16_frame_unwind =
{
NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
mips_insn16_frame_this_id,
mips_insn16_frame_prev_register,
NULL,
|| inst == 0x0399e021 /* addu $gp,$gp,$t9 */
|| inst == 0x033ce021 /* addu $gp,$t9,$gp */
)
- {
- /* These instructions are part of the prologue, but we don't
- need to do anything special to handle them. */
- }
+ {
+ /* These instructions are part of the prologue, but we don't
+ need to do anything special to handle them. */
+ }
/* The instructions below 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
- && (high_word == 0x3c01 /* lui $at,n */
- || high_word == 0x3c08 /* lui $t0,n */
- || high_word == 0x3421 /* ori $at,$at,n */
- || high_word == 0x3508 /* ori $t0,$t0,n */
- || high_word == 0x3401 /* ori $at,$zero,n */
- || high_word == 0x3408 /* ori $t0,$zero,n */
- ))
- {
- load_immediate_bytes += MIPS_INSN32_SIZE; /* FIXME! */
- }
+ && (high_word == 0x3c01 /* lui $at,n */
+ || high_word == 0x3c08 /* lui $t0,n */
+ || high_word == 0x3421 /* ori $at,$at,n */
+ || high_word == 0x3508 /* ori $t0,$t0,n */
+ || high_word == 0x3401 /* ori $at,$zero,n */
+ || high_word == 0x3408 /* ori $t0,$zero,n */
+ ))
+ {
+ if (end_prologue_addr == 0)
+ load_immediate_bytes += MIPS_INSN32_SIZE; /* FIXME! */
+ }
else
- {
- /* This instruction is not an instruction typically found
- in a prologue, so we must have reached the end of the
- prologue. */
- /* FIXME: brobecker/2004-10-10: Can't we just break out of this
- loop now? Why would we need to continue scanning the function
- instructions? */
- if (end_prologue_addr == 0)
- end_prologue_addr = cur_pc;
-
- /* Check for branches and jumps. For now, only jump to
- register are caught (i.e. returns). */
- if ((itype_op (inst) & 0x07) == 0 && rtype_funct (inst) == 8)
- in_delay_slot = 1;
- }
+ {
+ /* This instruction is not an instruction typically found
+ in a prologue, so we must have reached the end of the
+ prologue. */
+ /* FIXME: brobecker/2004-10-10: Can't we just break out of this
+ loop now? Why would we need to continue scanning the function
+ instructions? */
+ if (end_prologue_addr == 0)
+ end_prologue_addr = cur_pc;
+
+ /* Check for branches and jumps. For now, only jump to
+ register are caught (i.e. returns). */
+ if ((itype_op (inst) & 0x07) == 0 && rtype_funct (inst) == 8)
+ in_delay_slot = 1;
+ }
/* If the previous instruction was a jump, we must have reached
the end of the prologue by now. Stop scanning so that we do
static const struct frame_unwind mips_insn32_frame_unwind =
{
NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
mips_insn32_frame_this_id,
mips_insn32_frame_prev_register,
NULL,
static const struct frame_unwind mips_stub_frame_unwind =
{
NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
mips_stub_frame_this_id,
mips_stub_frame_prev_register,
NULL,
return 0; /* fallback to the standard single-step code. */
break;
case 1: /* REGIMM */
- is_branch = ((itype_rt (insn) & 0xc0) == 0); /* B{LT,GE}Z* */
+ is_branch = ((itype_rt (insn) & 0xc) == 0 /* B{LT,GE}Z* */
+ || ((itype_rt (insn) & 0x1e) == 0
+ && itype_rs (insn) == 0)); /* BPOSGE* */
break;
case 2: /* J */
case 3: /* JAL */
is_branch = 1;
break;
case 17: /* COP1 */
+ is_branch = ((itype_rs (insn) == 9 || itype_rs (insn) == 10)
+ && (itype_rt (insn) & 0x2) == 0);
+ if (is_branch) /* BC1ANY2F, BC1ANY2T, BC1ANY4F, BC1ANY4T */
+ break;
+ /* Fall through. */
case 18: /* COP2 */
case 19: /* COP3 */
is_branch = (itype_rs (insn) == 8); /* BCzF, BCzFL, BCzT, BCzTL */
static int
mips_about_to_return (struct gdbarch *gdbarch, CORE_ADDR pc)
{
- if (mips_pc_is_mips16 (pc))
- /* This mips16 case isn't necessarily reliable. Sometimes the compiler
- generates a "jr $ra"; other times it generates code to load
- the return address from the stack to an accessible register (such
- as $a3), then a "jr" using that register. This second case
- is almost impossible to distinguish from an indirect jump
- used for switch statements, so we don't even try. */
- return mips_fetch_instruction (gdbarch, pc) == 0xe820; /* jr $ra */
- else
- return mips_fetch_instruction (gdbarch, pc) == 0x3e00008; /* jr $ra */
+ ULONGEST insn;
+ ULONGEST hint;
+
+ /* This used to check for MIPS16, but this piece of code is never
+ called for MIPS16 functions. */
+ gdb_assert (!mips_pc_is_mips16 (pc));
+
+ insn = mips_fetch_instruction (gdbarch, pc);
+ hint = 0x7c0;
+ return (insn & ~hint) == 0x3e00008; /* jr(.hb) $ra */
}
len -= partial_len;
val += partial_len;
- /* Compute the the offset into the stack at which we
- will copy the next parameter.
+ /* Compute the offset into the stack at which we will
+ copy the next parameter.
In the new EABI (and the NABI32), the stack_offset
only needs to be adjusted when it has been used. */
len -= partial_len;
val += partial_len;
- /* Compute the the offset into the stack at which we
- will copy the next parameter.
+ /* Compute the offset into the stack at which we will
+ copy the next parameter.
In N32 (N64?), the stack_offset only needs to be
adjusted when it has been used. */
if (mips_debug)
fprintf_unfiltered (gdb_stderr, "Return float in $f0 and $f2\n");
mips_xfer_register (gdbarch, regcache,
- gdbarch_num_regs (gdbarch)
- + mips_regnum (gdbarch)->fp0,
+ (gdbarch_num_regs (gdbarch)
+ + mips_regnum (gdbarch)->fp0),
8, gdbarch_byte_order (gdbarch),
readbuf, writebuf, 0);
mips_xfer_register (gdbarch, regcache,
- gdbarch_num_regs (gdbarch)
- + mips_regnum (gdbarch)->fp0 + 2,
+ (gdbarch_num_regs (gdbarch)
+ + mips_regnum (gdbarch)->fp0 + 2),
8, gdbarch_byte_order (gdbarch),
readbuf ? readbuf + 8 : readbuf,
writebuf ? writebuf + 8 : writebuf, 0);
if (mips_debug)
fprintf_unfiltered (gdb_stderr, "Return float in $fp0\n");
mips_xfer_register (gdbarch, regcache,
- gdbarch_num_regs (gdbarch)
- + mips_regnum (gdbarch)->fp0,
+ (gdbarch_num_regs (gdbarch)
+ + mips_regnum (gdbarch)->fp0),
TYPE_LENGTH (type),
gdbarch_byte_order (gdbarch),
readbuf, writebuf, 0);
len -= partial_len;
val += partial_len;
- /* Compute the the offset into the stack at which we
- will copy the next parameter.
+ /* Compute 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
if (mips_debug)
fprintf_unfiltered (gdb_stderr, "Return float in $fp0\n");
mips_xfer_register (gdbarch, regcache,
- gdbarch_num_regs (gdbarch)
- + mips_regnum (gdbarch)->fp0,
+ (gdbarch_num_regs (gdbarch)
+ + mips_regnum (gdbarch)->fp0),
TYPE_LENGTH (type),
gdbarch_byte_order (gdbarch),
readbuf, writebuf, 0);
{
case BFD_ENDIAN_LITTLE:
mips_xfer_register (gdbarch, regcache,
- gdbarch_num_regs (gdbarch)
- + mips_regnum (gdbarch)->fp0 +
- 0, 4, gdbarch_byte_order (gdbarch),
+ (gdbarch_num_regs (gdbarch)
+ + mips_regnum (gdbarch)->fp0 + 0),
+ 4, gdbarch_byte_order (gdbarch),
readbuf, writebuf, 0);
mips_xfer_register (gdbarch, regcache,
- gdbarch_num_regs (gdbarch)
- + mips_regnum (gdbarch)->fp0 + 1,
+ (gdbarch_num_regs (gdbarch)
+ + mips_regnum (gdbarch)->fp0 + 1),
4, gdbarch_byte_order (gdbarch),
readbuf, writebuf, 4);
break;
case BFD_ENDIAN_BIG:
mips_xfer_register (gdbarch, regcache,
- gdbarch_num_regs (gdbarch)
- + mips_regnum (gdbarch)->fp0 + 1,
+ (gdbarch_num_regs (gdbarch)
+ + mips_regnum (gdbarch)->fp0 + 1),
4, gdbarch_byte_order (gdbarch),
readbuf, writebuf, 0);
mips_xfer_register (gdbarch, regcache,
- gdbarch_num_regs (gdbarch)
- + mips_regnum (gdbarch)->fp0 + 0,
+ (gdbarch_num_regs (gdbarch)
+ + mips_regnum (gdbarch)->fp0 + 0),
4, gdbarch_byte_order (gdbarch),
readbuf, writebuf, 4);
break;
len -= partial_len;
val += partial_len;
- /* Compute the the offset into the stack at which we
- will copy the next parameter.
+ /* Compute 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
if (mips_debug)
fprintf_unfiltered (gdb_stderr, "Return float in $fp0\n");
mips_xfer_register (gdbarch, regcache,
- gdbarch_num_regs (gdbarch)
- + mips_regnum (gdbarch)->fp0,
+ (gdbarch_num_regs (gdbarch)
+ + mips_regnum (gdbarch)->fp0),
TYPE_LENGTH (type),
gdbarch_byte_order (gdbarch),
readbuf, writebuf, 0);
struct value_print_options opts;
struct value *val;
- if (TYPE_CODE (register_type (gdbarch, regnum)) == TYPE_CODE_FLT)
+ if (mips_float_register_p (gdbarch, regnum))
{
mips_print_fp_register (file, frame, regnum);
return;
{
if (*gdbarch_register_name (gdbarch, regnum) == '\0')
continue; /* unused register */
- if (TYPE_CODE (register_type (gdbarch, regnum)) ==
- TYPE_CODE_FLT)
+ if (mips_float_register_p (gdbarch, regnum))
break; /* End the row: reached FP register. */
/* Large registers are handled separately. */
if (register_size (gdbarch, regnum) > mips_abi_regsize (gdbarch))
{
if (*gdbarch_register_name (gdbarch, regnum) == '\0')
continue; /* unused register */
- if (TYPE_CODE (register_type (gdbarch, regnum)) ==
- TYPE_CODE_FLT)
+ if (mips_float_register_p (gdbarch, regnum))
break; /* End row: reached FP register. */
if (register_size (gdbarch, regnum) > mips_abi_regsize (gdbarch))
break; /* End row: large register. */
while (regnum < gdbarch_num_regs (gdbarch)
+ gdbarch_num_pseudo_regs (gdbarch))
{
- if (TYPE_CODE (register_type (gdbarch, regnum)) ==
- TYPE_CODE_FLT)
+ if (mips_float_register_p (gdbarch, regnum))
{
if (all) /* True for "INFO ALL-REGISTERS" command. */
regnum = print_fp_register_row (file, frame, regnum);
}
}
+/* Return non-zero if the ADDR instruction has a branch delay slot
+ (i.e. it is a jump or branch instruction). This function is based
+ on mips32_next_pc. */
+
+static int
+mips32_instruction_has_delay_slot (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ gdb_byte buf[MIPS_INSN32_SIZE];
+ unsigned long inst;
+ int status;
+ int op;
+ int rs;
+ int rt;
+
+ status = target_read_memory (addr, buf, MIPS_INSN32_SIZE);
+ if (status)
+ return 0;
+
+ inst = mips_fetch_instruction (gdbarch, addr);
+ op = itype_op (inst);
+ if ((inst & 0xe0000000) != 0)
+ {
+ rs = itype_rs (inst);
+ rt = itype_rt (inst);
+ return (op >> 2 == 5 /* BEQL, BNEL, BLEZL, BGTZL: bits 0101xx */
+ || op == 29 /* JALX: bits 011101 */
+ || (op == 17
+ && (rs == 8
+ /* BC1F, BC1FL, BC1T, BC1TL: 010001 01000 */
+ || (rs == 9 && (rt & 0x2) == 0)
+ /* BC1ANY2F, BC1ANY2T: bits 010001 01001 */
+ || (rs == 10 && (rt & 0x2) == 0))));
+ /* BC1ANY4F, BC1ANY4T: bits 010001 01010 */
+ }
+ else
+ switch (op & 0x07) /* extract bits 28,27,26 */
+ {
+ case 0: /* SPECIAL */
+ op = rtype_funct (inst);
+ return (op == 8 /* JR */
+ || op == 9); /* JALR */
+ break; /* end SPECIAL */
+ case 1: /* REGIMM */
+ rs = itype_rs (inst);
+ rt = itype_rt (inst); /* branch condition */
+ return ((rt & 0xc) == 0
+ /* BLTZ, BLTZL, BGEZ, BGEZL: bits 000xx */
+ /* BLTZAL, BLTZALL, BGEZAL, BGEZALL: 100xx */
+ || ((rt & 0x1e) == 0x1c && rs == 0));
+ /* BPOSGE32, BPOSGE64: bits 1110x */
+ break; /* end REGIMM */
+ default: /* J, JAL, BEQ, BNE, BLEZ, BGTZ */
+ return 1;
+ break;
+ }
+}
+
+/* Return non-zero if the ADDR instruction, which must be a 32-bit
+ instruction if MUSTBE32 is set or can be any instruction otherwise,
+ has a branch delay slot (i.e. it is a non-compact jump instruction). */
+
+static int
+mips16_instruction_has_delay_slot (struct gdbarch *gdbarch, CORE_ADDR addr,
+ int mustbe32)
+{
+ gdb_byte buf[MIPS_INSN16_SIZE];
+ unsigned short inst;
+ int status;
+
+ status = target_read_memory (addr, buf, MIPS_INSN16_SIZE);
+ if (status)
+ return 0;
+
+ inst = mips_fetch_instruction (gdbarch, addr);
+ if (!mustbe32)
+ return (inst & 0xf89f) == 0xe800; /* JR/JALR (16-bit instruction) */
+ return (inst & 0xf800) == 0x1800; /* JAL/JALX (32-bit instruction) */
+}
+
+/* Calculate the starting address of the MIPS memory segment BPADDR is in.
+ This assumes KSSEG exists. */
+
+static CORE_ADDR
+mips_segment_boundary (CORE_ADDR bpaddr)
+{
+ CORE_ADDR mask = CORE_ADDR_MAX;
+ int segsize;
+
+ if (sizeof (CORE_ADDR) == 8)
+ /* Get the topmost two bits of bpaddr in a 32-bit safe manner (avoid
+ a compiler warning produced where CORE_ADDR is a 32-bit type even
+ though in that case this is dead code). */
+ switch (bpaddr >> ((sizeof (CORE_ADDR) << 3) - 2) & 3)
+ {
+ case 3:
+ if (bpaddr == (bfd_signed_vma) (int32_t) bpaddr)
+ segsize = 29; /* 32-bit compatibility segment */
+ else
+ segsize = 62; /* xkseg */
+ break;
+ case 2: /* xkphys */
+ segsize = 59;
+ break;
+ default: /* xksseg (1), xkuseg/kuseg (0) */
+ segsize = 62;
+ break;
+ }
+ else if (bpaddr & 0x80000000) /* kernel segment */
+ segsize = 29;
+ else
+ segsize = 31; /* user segment */
+ mask <<= segsize;
+ return bpaddr & mask;
+}
+
+/* Move the breakpoint at BPADDR out of any branch delay slot by shifting
+ it backwards if necessary. Return the address of the new location. */
+
+static CORE_ADDR
+mips_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr)
+{
+ CORE_ADDR prev_addr, next_addr;
+ CORE_ADDR boundary;
+ CORE_ADDR func_addr;
+
+ /* If a breakpoint is set on the instruction in a branch delay slot,
+ GDB gets confused. When the breakpoint is hit, the PC isn't on
+ the instruction in the branch delay slot, the PC will point to
+ the branch instruction. Since the PC doesn't match any known
+ breakpoints, GDB reports a trap exception.
+
+ There are two possible fixes for this problem.
+
+ 1) When the breakpoint gets hit, see if the BD bit is set in the
+ Cause register (which indicates the last exception occurred in a
+ branch delay slot). If the BD bit is set, fix the PC to point to
+ the instruction in the branch delay slot.
+
+ 2) When the user sets the breakpoint, don't allow him to set the
+ breakpoint on the instruction in the branch delay slot. Instead
+ move the breakpoint to the branch instruction (which will have
+ the same result).
+
+ The problem with the first solution is that if the user then
+ single-steps the processor, the branch instruction will get
+ skipped (since GDB thinks the PC is on the instruction in the
+ branch delay slot).
+
+ So, we'll use the second solution. To do this we need to know if
+ the instruction we're trying to set the breakpoint on is in the
+ branch delay slot. */
+
+ boundary = mips_segment_boundary (bpaddr);
+
+ /* Make sure we don't scan back before the beginning of the current
+ function, since we may fetch constant data or insns that look like
+ a jump. Of course we might do that anyway if the compiler has
+ moved constants inline. :-( */
+ if (find_pc_partial_function (bpaddr, NULL, &func_addr, NULL)
+ && func_addr > boundary && func_addr <= bpaddr)
+ boundary = func_addr;
+
+ if (!mips_pc_is_mips16 (bpaddr))
+ {
+ if (bpaddr == boundary)
+ return bpaddr;
+
+ /* If the previous instruction has a branch delay slot, we have
+ to move the breakpoint to the branch instruction. */
+ prev_addr = bpaddr - 4;
+ if (mips32_instruction_has_delay_slot (gdbarch, prev_addr))
+ bpaddr = prev_addr;
+ }
+ else
+ {
+ struct minimal_symbol *sym;
+ CORE_ADDR addr, jmpaddr;
+ int i;
+
+ boundary = unmake_mips16_addr (boundary);
+
+ /* The only MIPS16 instructions with delay slots are JAL, JALX,
+ JALR and JR. An absolute JAL/JALX is always 4 bytes long,
+ so try for that first, then try the 2 byte JALR/JR.
+ FIXME: We have to assume that bpaddr is not the second half
+ of an extended instruction. */
+
+ jmpaddr = 0;
+ addr = bpaddr;
+ for (i = 1; i < 4; i++)
+ {
+ if (unmake_mips16_addr (addr) == boundary)
+ break;
+ addr -= 2;
+ if (i == 1 && mips16_instruction_has_delay_slot (gdbarch, addr, 0))
+ /* Looks like a JR/JALR at [target-1], but it could be
+ the second word of a previous JAL/JALX, so record it
+ and check back one more. */
+ jmpaddr = addr;
+ else if (i > 1
+ && mips16_instruction_has_delay_slot (gdbarch, addr, 1))
+ {
+ if (i == 2)
+ /* Looks like a JAL/JALX at [target-2], but it could also
+ be the second word of a previous JAL/JALX, record it,
+ and check back one more. */
+ jmpaddr = addr;
+ else
+ /* Looks like a JAL/JALX at [target-3], so any previously
+ recorded JAL/JALX or JR/JALR must be wrong, because:
+
+ >-3: JAL
+ -2: JAL-ext (can't be JAL/JALX)
+ -1: bdslot (can't be JR/JALR)
+ 0: target insn
+
+ Of course it could be another JAL-ext which looks
+ like a JAL, but in that case we'd have broken out
+ of this loop at [target-2]:
+
+ -4: JAL
+ >-3: JAL-ext
+ -2: bdslot (can't be jmp)
+ -1: JR/JALR
+ 0: target insn */
+ jmpaddr = 0;
+ }
+ else
+ {
+ /* Not a jump instruction: if we're at [target-1] this
+ could be the second word of a JAL/JALX, so continue;
+ otherwise we're done. */
+ if (i > 1)
+ break;
+ }
+ }
+
+ if (jmpaddr)
+ bpaddr = jmpaddr;
+ }
+
+ return bpaddr;
+}
+
/* If PC is in a mips16 call or return stub, return the address of the target
PC, which is either the callee or the caller. There are several
cases which must be handled:
and the target PC is in $2.
* If the PC at the start of __mips16_call_stub_{s,d}f_{0..10}, i.e.
before the jal instruction, this is effectively a call stub
- and the the target PC is in $2. Otherwise this is effectively
+ and the target PC is in $2. Otherwise this is effectively
a return stub and the target PC is in $18.
See the source code for the stubs in gcc/config/mips/mips16.S for
mips_skip_mips16_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
- char *name;
+ const char *name;
CORE_ADDR start_addr;
/* Find the starting address and name of the function containing the PC. */
/* If the PC at the start of __mips16_call_stub_{s,d}f_{0..10}, i.e.
before the jal instruction, this is effectively a call stub
- and the the target PC is in $2. Otherwise this is effectively
+ and the target PC is in $2. Otherwise this is effectively
a return stub and the target PC is in $18. */
else if (name[19] == 's' || name[19] == 'd')
{
address from those two instructions. */
CORE_ADDR target_pc = get_frame_register_signed (frame, 2);
- ULONGEST inst;
int i;
/* See if the name of the target function is __fn_stub_*. */
instructions. FIXME. */
for (i = 0, pc = 0; i < 20; i++, target_pc += MIPS_INSN32_SIZE)
{
- inst = mips_fetch_instruction (gdbarch, target_pc);
+ ULONGEST inst = mips_fetch_instruction (gdbarch, target_pc);
+ CORE_ADDR addr = inst;
+
if ((inst & 0xffff0000) == 0x3c010000) /* lui $at */
- pc = (inst << 16) & 0xffff0000; /* high word */
+ pc = (((addr & 0xffff) ^ 0x8000) - 0x8000) << 16;
+ /* high word */
else if ((inst & 0xffff0000) == 0x24210000) /* addiu $at */
- return pc | (inst & 0xffff); /* low word */
+ return pc + ((addr & 0xffff) ^ 0x8000) - 0x8000;
+ /* low word */
}
/* Couldn't find the lui/addui pair, so return stub address. */
&& (stub_words[1] & 0xfc000000U) == 0x08000000
&& (stub_words[2] & 0xffff0000U) == 0x27390000
&& stub_words[3] == 0x00000000)
- return (((stub_words[0] & 0x0000ffff) << 16)
- + (stub_words[2] & 0x0000ffff));
+ return ((((stub_words[0] & 0x0000ffff) << 16)
+ + (stub_words[2] & 0x0000ffff)) ^ 0x8000) - 0x8000;
}
/* Not a recognized stub. */
regnum = mips_regnum (gdbarch)->hi;
else if (num == 71)
regnum = mips_regnum (gdbarch)->lo;
+ else if (mips_regnum (gdbarch)->dspacc != -1 && num >= 72 && num < 78)
+ regnum = num + mips_regnum (gdbarch)->dspacc - 72;
else
/* This will hopefully (eventually) provoke a warning. Should
we be calling complaint() here? */
regnum = mips_regnum (gdbarch)->hi;
else if (num == 65)
regnum = mips_regnum (gdbarch)->lo;
+ else if (mips_regnum (gdbarch)->dspacc != -1 && num >= 66 && num < 72)
+ regnum = num + mips_regnum (gdbarch)->dspacc - 66;
else
/* This will hopefully (eventually) provoke a warning. Should we
be calling complaint() here? */
enum mips_fpu_type fpu_type;
struct tdesc_arch_data *tdesc_data = NULL;
int elf_fpu_type = 0;
+ const char **reg_names;
+ struct mips_regnum mips_regnum, *regnum;
+ int dspacc;
+ int dspctl;
+
+ /* Fill in the OS dependent register numbers and names. */
+ if (info.osabi == GDB_OSABI_IRIX)
+ {
+ mips_regnum.fp0 = 32;
+ mips_regnum.pc = 64;
+ mips_regnum.cause = 65;
+ mips_regnum.badvaddr = 66;
+ mips_regnum.hi = 67;
+ mips_regnum.lo = 68;
+ mips_regnum.fp_control_status = 69;
+ mips_regnum.fp_implementation_revision = 70;
+ mips_regnum.dspacc = dspacc = -1;
+ mips_regnum.dspctl = dspctl = -1;
+ num_regs = 71;
+ reg_names = mips_irix_reg_names;
+ }
+ else if (info.osabi == GDB_OSABI_LINUX)
+ {
+ mips_regnum.fp0 = 38;
+ mips_regnum.pc = 37;
+ mips_regnum.cause = 36;
+ mips_regnum.badvaddr = 35;
+ mips_regnum.hi = 34;
+ mips_regnum.lo = 33;
+ mips_regnum.fp_control_status = 70;
+ mips_regnum.fp_implementation_revision = 71;
+ mips_regnum.dspacc = -1;
+ mips_regnum.dspctl = -1;
+ dspacc = 72;
+ dspctl = 78;
+ num_regs = 79;
+ reg_names = mips_linux_reg_names;
+ }
+ else
+ {
+ mips_regnum.lo = MIPS_EMBED_LO_REGNUM;
+ mips_regnum.hi = MIPS_EMBED_HI_REGNUM;
+ mips_regnum.badvaddr = MIPS_EMBED_BADVADDR_REGNUM;
+ mips_regnum.cause = MIPS_EMBED_CAUSE_REGNUM;
+ mips_regnum.pc = MIPS_EMBED_PC_REGNUM;
+ mips_regnum.fp0 = MIPS_EMBED_FP0_REGNUM;
+ mips_regnum.fp_control_status = 70;
+ mips_regnum.fp_implementation_revision = 71;
+ mips_regnum.dspacc = dspacc = -1;
+ mips_regnum.dspctl = dspctl = -1;
+ num_regs = MIPS_LAST_EMBED_REGNUM + 1;
+ if (info.bfd_arch_info != NULL
+ && info.bfd_arch_info->mach == bfd_mach_mips3900)
+ reg_names = mips_tx39_reg_names;
+ else
+ reg_names = mips_generic_reg_names;
+ }
/* Check any target description for validity. */
if (tdesc_has_registers (info.target_desc))
valid_p &= tdesc_numbered_register (feature, tdesc_data,
- MIPS_EMBED_LO_REGNUM, "lo");
+ mips_regnum.lo, "lo");
valid_p &= tdesc_numbered_register (feature, tdesc_data,
- MIPS_EMBED_HI_REGNUM, "hi");
+ mips_regnum.hi, "hi");
valid_p &= tdesc_numbered_register (feature, tdesc_data,
- MIPS_EMBED_PC_REGNUM, "pc");
+ mips_regnum.pc, "pc");
if (!valid_p)
{
valid_p = 1;
valid_p &= tdesc_numbered_register (feature, tdesc_data,
- MIPS_EMBED_BADVADDR_REGNUM,
- "badvaddr");
+ mips_regnum.badvaddr, "badvaddr");
valid_p &= tdesc_numbered_register (feature, tdesc_data,
MIPS_PS_REGNUM, "status");
valid_p &= tdesc_numbered_register (feature, tdesc_data,
- MIPS_EMBED_CAUSE_REGNUM, "cause");
+ mips_regnum.cause, "cause");
if (!valid_p)
{
valid_p = 1;
for (i = 0; i < 32; i++)
valid_p &= tdesc_numbered_register (feature, tdesc_data,
- i + MIPS_EMBED_FP0_REGNUM,
- mips_fprs[i]);
+ i + mips_regnum.fp0, mips_fprs[i]);
valid_p &= tdesc_numbered_register (feature, tdesc_data,
- MIPS_EMBED_FP0_REGNUM + 32, "fcsr");
- valid_p &= tdesc_numbered_register (feature, tdesc_data,
- MIPS_EMBED_FP0_REGNUM + 33, "fir");
+ mips_regnum.fp_control_status,
+ "fcsr");
+ valid_p
+ &= tdesc_numbered_register (feature, tdesc_data,
+ mips_regnum.fp_implementation_revision,
+ "fir");
if (!valid_p)
{
return NULL;
}
+ if (dspacc >= 0)
+ {
+ feature = tdesc_find_feature (info.target_desc,
+ "org.gnu.gdb.mips.dsp");
+ /* The DSP registers are optional; it's OK if they are absent. */
+ if (feature != NULL)
+ {
+ i = 0;
+ valid_p = 1;
+ valid_p &= tdesc_numbered_register (feature, tdesc_data,
+ dspacc + i++, "hi1");
+ valid_p &= tdesc_numbered_register (feature, tdesc_data,
+ dspacc + i++, "lo1");
+ valid_p &= tdesc_numbered_register (feature, tdesc_data,
+ dspacc + i++, "hi2");
+ valid_p &= tdesc_numbered_register (feature, tdesc_data,
+ dspacc + i++, "lo2");
+ valid_p &= tdesc_numbered_register (feature, tdesc_data,
+ dspacc + i++, "hi3");
+ valid_p &= tdesc_numbered_register (feature, tdesc_data,
+ dspacc + i++, "lo3");
+
+ valid_p &= tdesc_numbered_register (feature, tdesc_data,
+ dspctl, "dspctl");
+
+ if (!valid_p)
+ {
+ tdesc_data_cleanup (tdesc_data);
+ return NULL;
+ }
+
+ mips_regnum.dspacc = dspacc;
+ mips_regnum.dspctl = dspctl;
+ }
+ }
+
/* It would be nice to detect an attempt to use a 64-bit ABI
when only 32-bit registers are provided. */
+ reg_names = NULL;
}
/* First of all, extract the elf_flags, if available. */
set_gdbarch_elf_make_msymbol_special (gdbarch,
mips_elf_make_msymbol_special);
- /* Fill in the OS dependant register numbers and names. */
- {
- const char **reg_names;
- struct mips_regnum *regnum = GDBARCH_OBSTACK_ZALLOC (gdbarch,
- struct mips_regnum);
- if (tdesc_has_registers (info.target_desc))
- {
- regnum->lo = MIPS_EMBED_LO_REGNUM;
- regnum->hi = MIPS_EMBED_HI_REGNUM;
- regnum->badvaddr = MIPS_EMBED_BADVADDR_REGNUM;
- regnum->cause = MIPS_EMBED_CAUSE_REGNUM;
- regnum->pc = MIPS_EMBED_PC_REGNUM;
- regnum->fp0 = MIPS_EMBED_FP0_REGNUM;
- regnum->fp_control_status = 70;
- regnum->fp_implementation_revision = 71;
- num_regs = MIPS_LAST_EMBED_REGNUM + 1;
- reg_names = NULL;
- }
- else if (info.osabi == GDB_OSABI_IRIX)
- {
- regnum->fp0 = 32;
- regnum->pc = 64;
- regnum->cause = 65;
- regnum->badvaddr = 66;
- regnum->hi = 67;
- regnum->lo = 68;
- regnum->fp_control_status = 69;
- regnum->fp_implementation_revision = 70;
- num_regs = 71;
- reg_names = mips_irix_reg_names;
- }
- else
- {
- regnum->lo = MIPS_EMBED_LO_REGNUM;
- regnum->hi = MIPS_EMBED_HI_REGNUM;
- regnum->badvaddr = MIPS_EMBED_BADVADDR_REGNUM;
- regnum->cause = MIPS_EMBED_CAUSE_REGNUM;
- regnum->pc = MIPS_EMBED_PC_REGNUM;
- regnum->fp0 = MIPS_EMBED_FP0_REGNUM;
- regnum->fp_control_status = 70;
- regnum->fp_implementation_revision = 71;
- num_regs = 90;
- if (info.bfd_arch_info != NULL
- && info.bfd_arch_info->mach == bfd_mach_mips3900)
- reg_names = mips_tx39_reg_names;
- else
- reg_names = mips_generic_reg_names;
- }
- /* FIXME: cagney/2003-11-15: For MIPS, hasn't gdbarch_pc_regnum been
- replaced by gdbarch_read_pc? */
- set_gdbarch_pc_regnum (gdbarch, regnum->pc + num_regs);
- set_gdbarch_sp_regnum (gdbarch, MIPS_SP_REGNUM + num_regs);
- set_gdbarch_fp0_regnum (gdbarch, regnum->fp0);
- set_gdbarch_num_regs (gdbarch, num_regs);
- set_gdbarch_num_pseudo_regs (gdbarch, num_regs);
- set_gdbarch_register_name (gdbarch, mips_register_name);
- set_gdbarch_virtual_frame_pointer (gdbarch, mips_virtual_frame_pointer);
- tdep->mips_processor_reg_names = reg_names;
- tdep->regnum = regnum;
- }
+ regnum = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct mips_regnum);
+ *regnum = mips_regnum;
+ set_gdbarch_fp0_regnum (gdbarch, regnum->fp0);
+ set_gdbarch_num_regs (gdbarch, num_regs);
+ set_gdbarch_num_pseudo_regs (gdbarch, num_regs);
+ set_gdbarch_register_name (gdbarch, mips_register_name);
+ set_gdbarch_virtual_frame_pointer (gdbarch, mips_virtual_frame_pointer);
+ tdep->mips_processor_reg_names = reg_names;
+ tdep->regnum = regnum;
switch (mips_abi)
{
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
set_gdbarch_breakpoint_from_pc (gdbarch, mips_breakpoint_from_pc);
+ set_gdbarch_adjust_breakpoint_address (gdbarch,
+ mips_adjust_breakpoint_address);
set_gdbarch_skip_prologue (gdbarch, mips_skip_prologue);
info.tdep_info = (void *) tdesc_data;
gdbarch_init_osabi (info, gdbarch);
+ /* The hook may have adjusted num_regs, fetch the final value and
+ set pc_regnum and sp_regnum now that it has been fixed. */
+ /* FIXME: cagney/2003-11-15: For MIPS, hasn't gdbarch_pc_regnum been
+ replaced by gdbarch_read_pc? */
+ num_regs = gdbarch_num_regs (gdbarch);
+ set_gdbarch_pc_regnum (gdbarch, regnum->pc + num_regs);
+ set_gdbarch_sp_regnum (gdbarch, MIPS_SP_REGNUM + num_regs);
+
/* Unwind the frame. */
dwarf2_append_unwinders (gdbarch);
frame_unwind_append_unwinder (gdbarch, &mips_stub_frame_unwind);