/* Target-dependent code for the MIPS architecture, for GDB, the GNU Debugger.
- Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
- 1997, 1998, 1999, 2000, Free Software Foundation, Inc.
+ Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
+ 1998, 1999, 2000, 2001 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 "gdbtypes.h"
#include "target.h"
#include "arch-utils.h"
+#include "regcache.h"
#include "opcode/mips.h"
#include "elf/mips.h"
#define GDB_TARGET_IS_MIPS64 (gdbarch_tdep (current_gdbarch)->gdb_target_is_mips64 + 0)
#endif
+#if GDB_MULTI_ARCH
+#undef MIPS_DEFAULT_MASK_ADDRESS_P
+#define MIPS_DEFAULT_MASK_ADDRESS_P (gdbarch_tdep (current_gdbarch)->default_mask_address_p)
+#elif !defined (MIPS_DEFAULT_MASK_ADDRESS_P)
+#define MIPS_DEFAULT_MASK_ADDRESS_P (0)
+#endif
+
#define VM_MIN_ADDRESS (CORE_ADDR)0x400000
int gdb_print_insn_mips (bfd_vma, disassemble_info *);
{
if (mips64_transfers_32bit_regs_p)
return REGISTER_VIRTUAL_SIZE (reg_nr);
+ else if (reg_nr >= FP0_REGNUM && reg_nr < FP0_REGNUM + 32
+ && FP_REGISTER_DOUBLE)
+ /* For MIPS_ABI_N32 (for example) we need 8 byte floating point
+ registers. */
+ return 8;
else
return MIPS_REGSIZE;
}
return 0;
break;
case CMD_AUTO_BOOLEAN_AUTO:
- return gdbarch_tdep (current_gdbarch)->default_mask_address_p;
+ return MIPS_DEFAULT_MASK_ADDRESS_P;
default:
- internal_error ("mips_mask_address_p: bad switch");
+ internal_error (__FILE__, __LINE__,
+ "mips_mask_address_p: bad switch");
return -1;
}
}
mips_mask_address_p () ? "enabled" : "disabled");
break;
default:
- internal_error ("show_mask_address: bad switch");
+ internal_error (__FILE__, __LINE__,
+ "show_mask_address: bad switch");
break;
}
}
} /* mips32_next_pc */
/* Decoding the next place to set a breakpoint is irregular for the
- mips 16 variant, but fortunatly, there fewer instructions. We have to cope
+ mips 16 variant, but fortunately, there fewer instructions. We have to cope
ith extensions for 16 bit instructions and a pair of actual 32 bit instructions.
We dont want to set a single step instruction on the extend instruction
either.
extRi64type, /* 20 5,6,5,5,3,3,5 */
extshift64type /* 21 5,5,1,1,1,1,1,1,5,1,1,1,3,5 */
};
-/* I am heaping all the fields of the formats into one structure and then,
- only the fields which are involved in instruction extension */
+/* I am heaping all the fields of the formats into one structure and
+ then, only the fields which are involved in instruction extension */
struct upk_mips16
{
- unsigned short inst;
- enum mips16_inst_fmts fmt;
- unsigned long offset;
+ CORE_ADDR offset;
unsigned int regx; /* Function in i8 type */
unsigned int regy;
};
+/* The EXT-I, EXT-ri nad EXT-I8 instructions all have the same format
+ for the bits which make up the immediatate extension. */
-static void
-print_unpack (char *comment,
- struct upk_mips16 *u)
-{
- printf ("%s %04x ,f(%d) off(%s) (x(%x) y(%x)\n",
- comment, u->inst, u->fmt, paddr (u->offset), u->regx, u->regy);
-}
-
-/* The EXT-I, EXT-ri nad EXT-I8 instructions all have the same
- format for the bits which make up the immediatate extension.
- */
-static unsigned long
-extended_offset (unsigned long extension)
+static CORE_ADDR
+extended_offset (unsigned int extension)
{
- unsigned long value;
+ CORE_ADDR value;
value = (extension >> 21) & 0x3f; /* * extract 15:11 */
value = value << 6;
value |= (extension >> 16) & 0x1f; /* extrace 10:5 */
when the offset is to be used in relative addressing */
-static unsigned short
+static unsigned int
fetch_mips_16 (CORE_ADDR pc)
{
char buf[8];
static void
unpack_mips16 (CORE_ADDR pc,
+ unsigned int extension,
+ unsigned int inst,
+ enum mips16_inst_fmts insn_format,
struct upk_mips16 *upk)
{
- CORE_ADDR extpc;
- unsigned long extension;
- int extended;
- extpc = (pc - 4) & ~0x01; /* Extensions are 32 bit instructions */
- /* Decrement to previous address and loose the 16bit mode flag */
- /* return if the instruction was extendable, but not actually extended */
- extended = ((mips32_op (extension) == 30) ? 1 : 0);
- if (extended)
- {
- extension = mips_fetch_instruction (extpc);
- }
- switch (upk->fmt)
+ CORE_ADDR offset;
+ int regx;
+ int regy;
+ switch (insn_format)
{
case itype:
{
- unsigned long value;
- if (extended)
+ CORE_ADDR value;
+ if (extension)
{
value = extended_offset (extension);
value = value << 11; /* rom for the original value */
- value |= upk->inst & 0x7ff; /* eleven bits from instruction */
+ value |= inst & 0x7ff; /* eleven bits from instruction */
}
else
{
- value = upk->inst & 0x7ff;
+ value = inst & 0x7ff;
/* FIXME : Consider sign extension */
}
- upk->offset = value;
+ offset = value;
+ regx = -1;
+ regy = -1;
}
break;
case ritype:
{ /* A register identifier and an offset */
/* Most of the fields are the same as I type but the
immediate value is of a different length */
- unsigned long value;
- if (extended)
+ CORE_ADDR value;
+ if (extension)
{
value = extended_offset (extension);
value = value << 8; /* from the original instruction */
- value |= upk->inst & 0xff; /* eleven bits from instruction */
- upk->regx = (extension >> 8) & 0x07; /* or i8 funct */
+ 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 */
}
else
{
- value = upk->inst & 0xff; /* 8 bits */
- upk->regx = (upk->inst >> 8) & 0x07; /* or i8 funct */
+ 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;
}
-
}
- upk->offset = value;
+ offset = value;
+ regy = -1;
break;
}
case jalxtype:
{
unsigned long value;
- unsigned short nexthalf;
- value = ((upk->inst & 0x1f) << 5) | ((upk->inst >> 5) & 0x1f);
+ unsigned int nexthalf;
+ value = ((inst & 0x1f) << 5) | ((inst >> 5) & 0x1f);
value = value << 16;
nexthalf = mips_fetch_instruction (pc + 2); /* low bit still set */
value |= nexthalf;
- upk->offset = value;
+ offset = value;
+ regx = -1;
+ regy = -1;
break;
}
default:
- printf_filtered ("Decoding unimplemented instruction format type\n");
- break;
+ internal_error (__FILE__, __LINE__,
+ "bad switch");
}
- /* print_unpack("UPK",upk) ; */
+ upk->offset = offset;
+ upk->regx = regx;
+ upk->regy = regy;
}
-#define mips16_op(x) (x >> 11)
-
-/* This is a map of the opcodes which ae known to perform branches */
-static unsigned char map16[32] =
-{0, 0, 1, 1, 1, 1, 0, 0,
- 0, 0, 0, 0, 1, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 1, 1, 0
-};
-
static CORE_ADDR
add_offset_16 (CORE_ADDR pc, int offset)
{
}
-
-
-static struct upk_mips16 upk;
-
-CORE_ADDR
-mips16_next_pc (CORE_ADDR pc)
+static CORE_ADDR
+extended_mips16_next_pc (CORE_ADDR pc,
+ unsigned int extension,
+ unsigned int insn)
{
- int op;
- t_inst inst;
- /* inst = mips_fetch_instruction(pc) ; - This doesnt always work */
- inst = fetch_mips_16 (pc);
- upk.inst = inst;
- op = mips16_op (upk.inst);
- if (map16[op])
+ int op = (insn >> 11);
+ switch (op)
{
- int reg;
- switch (op)
- {
- case 2: /* Branch */
- upk.fmt = itype;
- unpack_mips16 (pc, &upk);
+ case 2: /* Branch */
+ {
+ CORE_ADDR offset;
+ struct upk_mips16 upk;
+ unpack_mips16 (pc, extension, insn, itype, &upk);
+ offset = upk.offset;
+ if (offset & 0x800)
{
- long offset;
- offset = upk.offset;
- if (offset & 0x800)
+ offset &= 0xeff;
+ offset = -offset;
+ }
+ pc += (offset << 1) + 2;
+ break;
+ }
+ case 3: /* JAL , JALX - Watch out, these are 32 bit instruction */
+ {
+ struct upk_mips16 upk;
+ unpack_mips16 (pc, extension, insn, jalxtype, &upk);
+ pc = add_offset_16 (pc, upk.offset);
+ if ((insn >> 10) & 0x01) /* Exchange mode */
+ pc = pc & ~0x01; /* Clear low bit, indicate 32 bit mode */
+ else
+ pc |= 0x01;
+ break;
+ }
+ case 4: /* beqz */
+ {
+ struct upk_mips16 upk;
+ int reg;
+ unpack_mips16 (pc, extension, insn, ritype, &upk);
+ reg = read_signed_register (upk.regx);
+ if (reg == 0)
+ pc += (upk.offset << 1) + 2;
+ else
+ pc += 2;
+ break;
+ }
+ case 5: /* bnez */
+ {
+ struct upk_mips16 upk;
+ int reg;
+ unpack_mips16 (pc, extension, insn, ritype, &upk);
+ reg = read_signed_register (upk.regx);
+ if (reg != 0)
+ pc += (upk.offset << 1) + 2;
+ else
+ pc += 2;
+ break;
+ }
+ case 12: /* I8 Formats btez btnez */
+ {
+ struct upk_mips16 upk;
+ int reg;
+ unpack_mips16 (pc, extension, insn, i8type, &upk);
+ /* upk.regx contains the opcode */
+ reg = read_signed_register (24); /* Test register is 24 */
+ if (((upk.regx == 0) && (reg == 0)) /* BTEZ */
+ || ((upk.regx == 1) && (reg != 0))) /* BTNEZ */
+ /* pc = add_offset_16(pc,upk.offset) ; */
+ pc += (upk.offset << 1) + 2;
+ else
+ pc += 2;
+ break;
+ }
+ case 29: /* RR Formats JR, JALR, JALR-RA */
+ {
+ struct upk_mips16 upk;
+ /* upk.fmt = rrtype; */
+ op = insn & 0x1f;
+ if (op == 0)
+ {
+ int reg;
+ upk.regx = (insn >> 8) & 0x07;
+ upk.regy = (insn >> 5) & 0x07;
+ switch (upk.regy)
{
- offset &= 0xeff;
- offset = -offset;
+ 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 */
}
- pc += (offset << 1) + 2;
+ pc = read_signed_register (reg);
}
- break;
- case 3: /* JAL , JALX - Watch out, these are 32 bit instruction */
- upk.fmt = jalxtype;
- unpack_mips16 (pc, &upk);
- pc = add_offset_16 (pc, upk.offset);
- if ((upk.inst >> 10) & 0x01) /* Exchange mode */
- pc = pc & ~0x01; /* Clear low bit, indicate 32 bit mode */
- else
- pc |= 0x01;
- break;
- case 4: /* beqz */
- upk.fmt = ritype;
- unpack_mips16 (pc, &upk);
- reg = read_signed_register (upk.regx);
- if (reg == 0)
- pc += (upk.offset << 1) + 2;
- else
- pc += 2;
- break;
- case 5: /* bnez */
- upk.fmt = ritype;
- unpack_mips16 (pc, &upk);
- reg = read_signed_register (upk.regx);
- if (reg != 0)
- pc += (upk.offset << 1) + 2;
- else
- pc += 2;
- break;
- case 12: /* I8 Formats btez btnez */
- upk.fmt = i8type;
- unpack_mips16 (pc, &upk);
- /* upk.regx contains the opcode */
- reg = read_signed_register (24); /* Test register is 24 */
- if (((upk.regx == 0) && (reg == 0)) /* BTEZ */
- || ((upk.regx == 1) && (reg != 0))) /* BTNEZ */
- /* pc = add_offset_16(pc,upk.offset) ; */
- pc += (upk.offset << 1) + 2;
- else
- pc += 2;
- break;
- case 29: /* RR Formats JR, JALR, JALR-RA */
- upk.fmt = rrtype;
- op = upk.inst & 0x1f;
- if (op == 0)
- {
- upk.regx = (upk.inst >> 8) & 0x07;
- upk.regy = (upk.inst >> 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 */
- }
- pc = read_signed_register (reg);
- }
- else
- pc += 2;
- break;
- case 30: /* This is an extend instruction */
- pc += 4; /* Dont be setting breakpints on the second half */
- break;
- default:
- printf ("Filtered - next PC probably incorrrect due to jump inst\n");
+ else
pc += 2;
- break;
- }
+ break;
+ }
+ case 30:
+ /* This is an instruction extension. Fetch the real instruction
+ (which follows the extension) and decode things based on
+ that. */
+ {
+ pc += 2;
+ pc = extended_mips16_next_pc (pc, insn, fetch_mips_16 (pc));
+ break;
+ }
+ default:
+ {
+ pc += 2;
+ break;
+ }
}
- else
- pc += 2; /* just a good old instruction */
- /* See if we CAN actually break on the next instruction */
- /* printf("NXTm16PC %08x\n",(unsigned long)pc) ; */
return pc;
-} /* mips16_next_pc */
+}
-/* The mips_next_pc function supports single_tep when the remote target monitor or
- stub is not developed enough to so a single_step.
- It works by decoding the current instruction and predicting where a branch
- will go. This isnt hard because all the data is available.
- The MIPS32 and MIPS16 variants are quite different
- */
+CORE_ADDR
+mips16_next_pc (CORE_ADDR pc)
+{
+ unsigned int insn = fetch_mips_16 (pc);
+ return extended_mips16_next_pc (pc, 0, insn);
+}
+
+/* The mips_next_pc function supports single_step when the remote
+ target monitor or stub is not developed enough to do a single_step.
+ It works by decoding the current instruction and predicting where a
+ branch will go. This isnt hard because all the data is available.
+ The MIPS32 and MIPS16 variants are quite different */
CORE_ADDR
mips_next_pc (CORE_ADDR pc)
{
- t_inst inst;
- /* inst = mips_fetch_instruction(pc) ; */
- /* if (pc_is_mips16) <----- This is failing */
if (pc & 0x01)
return mips16_next_pc (pc);
else
return mips32_next_pc (pc);
-} /* mips_next_pc */
+}
/* Guaranteed to set fci->saved_regs to some values (it never leaves it
NULL). */
else
linked_proc_desc_table = pi_ptr->next;
- free (pi_ptr);
+ xfree (pi_ptr);
write_register (HI_REGNUM,
read_memory_integer (new_sp - 2 * MIPS_SAVED_REGSIZE,
flt2 = unpack_double (builtin_type_float, raw_buffer[LO], &inv2);
doub = unpack_double (builtin_type_double, dbl_buffer, &inv3);
- printf_filtered (inv1 ? " %-5s: <invalid float>" :
- " %-5s%-17.9g", REGISTER_NAME (regnum), flt1);
- printf_filtered (inv2 ? " %-5s: <invalid float>" :
- " %-5s%-17.9g", REGISTER_NAME (regnum + 1), flt2);
- printf_filtered (inv3 ? " dbl: <invalid double>\n" :
- " dbl: %-24.17g\n", doub);
+ printf_filtered (" %-5s", REGISTER_NAME (regnum));
+ if (inv1)
+ printf_filtered (": <invalid float>");
+ else
+ printf_filtered ("%-17.9g", flt1);
+
+ printf_filtered (" %-5s", REGISTER_NAME (regnum + 1));
+ if (inv2)
+ printf_filtered (": <invalid float>");
+ else
+ printf_filtered ("%-17.9g", flt2);
+
+ printf_filtered (" dbl: ");
+ if (inv3)
+ printf_filtered ("<invalid double>");
+ else
+ printf_filtered ("%-24.17g", doub);
+ printf_filtered ("\n");
+
/* may want to do hex display here (future enhancement) */
regnum += 2;
}
&raw_buffer[HI][offset], &inv1);
doub = unpack_double (builtin_type_double, dbl_buffer, &inv3);
- printf_filtered (inv1 ? " %-5s: <invalid float>" :
- " %-5s flt: %-17.9g", REGISTER_NAME (regnum), flt1);
- printf_filtered (inv3 ? " dbl: <invalid double>\n" :
- " dbl: %-24.17g\n", doub);
+ printf_filtered (" %-5s: ", REGISTER_NAME (regnum));
+ if (inv1)
+ printf_filtered ("<invalid float>");
+ else
+ printf_filtered ("flt: %-17.9g", flt1);
+
+ printf_filtered (" dbl: ");
+ if (inv3)
+ printf_filtered ("<invalid double>");
+ else
+ printf_filtered ("%-24.17g", doub);
+
+ printf_filtered ("\n");
/* may want to do hex display here (future enhancement) */
regnum++;
}
printf_unfiltered ("%s\n", mips_processor_type_table[i].name);
/* Restore the value. */
- tmp_mips_processor_type = strsave (mips_processor_type);
+ tmp_mips_processor_type = xstrdup (mips_processor_type);
return;
}
{
error ("Unknown processor type `%s'.", tmp_mips_processor_type);
/* Restore its value. */
- tmp_mips_processor_type = strsave (mips_processor_type);
+ tmp_mips_processor_type = xstrdup (mips_processor_type);
}
}
}
-/* If the current gcc for for this target does not produce correct debugging
+/* If the current gcc for this target does not produce correct debugging
information for float parameters, both prototyped and unprototyped, then
define this macro. This forces gdb to always assume that floats are
passed as doubles and then converted in the callee.
}
+/* Convert a dbx stab register number (from `r' declaration) to a gdb
+ REGNUM */
+
+static int
+mips_stab_reg_to_regnum (int num)
+{
+ if (num < 32)
+ return num;
+ else
+ return num + FP0_REGNUM - 38;
+}
+
+/* Convert a ecoff register number to a gdb REGNUM */
+
+static int
+mips_ecoff_reg_to_regnum (int num)
+{
+ if (num < 32)
+ return num;
+ else
+ return num + FP0_REGNUM - 32;
+}
+
static struct gdbarch *
mips_gdbarch_init (struct gdbarch_info info,
struct gdbarch_list *arches)
set_gdbarch_read_sp (gdbarch, generic_target_read_sp);
set_gdbarch_write_sp (gdbarch, generic_target_write_sp);
+ /* Map debug register numbers onto internal register numbers. */
+ set_gdbarch_stab_reg_to_regnum (gdbarch, mips_stab_reg_to_regnum);
+ set_gdbarch_ecoff_reg_to_regnum (gdbarch, mips_ecoff_reg_to_regnum);
+
/* Initialize a frame */
set_gdbarch_init_extra_frame_info (gdbarch, mips_init_extra_frame_info);
"Select single-precision MIPS floating-point coprocessor.",
&mipsfpulist);
add_cmd ("double", class_support, set_mipsfpu_double_command,
- "Select double-precision MIPS floating-point coprocessor .",
+ "Select double-precision MIPS floating-point coprocessor.",
&mipsfpulist);
add_alias_cmd ("on", "double", class_support, 1, &mipsfpulist);
add_alias_cmd ("yes", "double", class_support, 1, &mipsfpulist);
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);
+ tmp_mips_processor_type = xstrdup (DEFAULT_MIPS_TYPE);
+ mips_set_processor_type_command (xstrdup (DEFAULT_MIPS_TYPE), 0);
#endif
/* We really would like to have both "0" and "unlimited" work, but