gdb_curses.h: Undefine KEY_EVENT before including curses
[deliverable/binutils-gdb.git] / gdb / mips-tdep.c
index 7e74bc46a230c39eb84b907bdce268cf455e99bd..9a3c7fb0813ba07f687e6b9c9427f6f97cfe8d8e 100644 (file)
@@ -1,8 +1,6 @@
 /* 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.
@@ -84,7 +82,7 @@ enum
 
 static const char *mips_abi_string;
 
-static const char *mips_abi_strings[] = {
+static const char *const mips_abi_strings[] = {
   "auto",
   "n32",
   "o32",
@@ -181,6 +179,18 @@ mips_fpa0_regnum (struct gdbarch *gdbarch)
   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)
@@ -193,27 +203,6 @@ mips_fpa0_regnum (struct gdbarch *gdbarch)
 
 #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)
@@ -257,6 +246,27 @@ mips_abi_regsize (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.
@@ -270,7 +280,8 @@ mips_abi_regsize (struct gdbarch *gdbarch)
 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;
     }
@@ -392,9 +403,7 @@ static const char *mips_generic_reg_names[NUM_MIPS_PROCESSOR_REGS] = {
   "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.  */
@@ -420,7 +429,7 @@ static const char *mips_tx39_reg_names[NUM_MIPS_PROCESSOR_REGS] = {
   "", "", "", "", "", "", "", "",
   "", "", "", "",
   "", "", "", "", "", "", "", "",
-  "", "", "config", "cache", "debug", "depc", "epc", ""
+  "", "", "config", "cache", "debug", "depc", "epc",
 };
 
 /* Names of IRIX registers.  */
@@ -432,6 +441,16 @@ static const char *mips_irix_reg_names[NUM_MIPS_PROCESSOR_REGS] = {
   "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 *
@@ -486,7 +505,9 @@ mips_register_name (struct gdbarch *gdbarch, int regno)
   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__,
@@ -708,10 +729,7 @@ mips_convert_register_float_case_p (struct gdbarch *gdbarch, int regnum,
 {
   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);
 }
 
@@ -834,9 +852,7 @@ static struct type *
 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.  */
@@ -856,11 +872,17 @@ mips_register_type (struct gdbarch *gdbarch, int regnum)
     }
   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;
@@ -899,37 +921,50 @@ mips_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
   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;
 }
@@ -989,18 +1024,54 @@ mips_pc_is_mips16 (CORE_ADDR memaddr)
 {
   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 is_mips16_addr (memaddr);
+}
+
+/* Various MIPS16 thunk (aka stub or trampoline) names.  */
+
+static const char mips_str_mips16_call_stub[] = "__mips16_call_stub_";
+static const char mips_str_mips16_ret_stub[] = "__mips16_ret_";
+static const char mips_str_call_fp_stub[] = "__call_stub_fp_";
+static const char mips_str_call_stub[] = "__call_stub_";
+static const char mips_str_fn_stub[] = "__fn_stub_";
+
+/* This is used as a PIC thunk prefix.  */
+
+static const char mips_str_pic[] = ".pic.";
+
+/* Return non-zero if the PC is inside a call thunk (aka stub or
+   trampoline) that should be treated as a temporary frame.  */
+
+static int
+mips_in_frame_stub (CORE_ADDR pc)
+{
+  CORE_ADDR start_addr;
+  const char *name;
+
+  /* Find the starting address of the function containing the PC.  */
+  if (find_pc_partial_function (pc, &name, &start_addr, NULL) == 0)
     return 0;
+
+  /* If the PC is in __mips16_call_stub_*, this is a call/return stub.  */
+  if (strncmp (name, mips_str_mips16_call_stub,
+              strlen (mips_str_mips16_call_stub)) == 0)
+    return 1;
+  /* If the PC is in __call_stub_*, this is a call/return or a call stub.  */
+  if (strncmp (name, mips_str_call_stub, strlen (mips_str_call_stub)) == 0)
+    return 1;
+  /* If the PC is in __fn_stub_*, this is a call stub.  */
+  if (strncmp (name, mips_str_fn_stub, strlen (mips_str_fn_stub)) == 0)
+    return 1;
+
+  return 0;                    /* Not a stub.  */
 }
 
 /* MIPS believes that the PC has a sign extended value.  Perhaps the
@@ -1020,12 +1091,31 @@ mips_read_pc (struct regcache *regcache)
 static CORE_ADDR
 mips_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
 {
-  ULONGEST pc;
+  CORE_ADDR pc;
 
   pc = frame_unwind_register_signed
         (next_frame, gdbarch_num_regs (gdbarch) + mips_regnum (gdbarch)->pc);
   if (is_mips16_addr (pc))
     pc = unmake_mips16_addr (pc);
+  /* macro/2012-04-20: This hack skips over MIPS16 call thunks as
+     intermediate frames.  In this case we can get the caller's address
+     from $ra, or if $ra contains an address within a thunk as well, then
+     it must be in the return path of __mips16_call_stub_{s,d}{f,c}_{0..10}
+     and thus the caller's address is in $s2.  */
+  if (frame_relative_level (next_frame) >= 0 && mips_in_frame_stub (pc))
+    {
+      pc = frame_unwind_register_signed
+            (next_frame, gdbarch_num_regs (gdbarch) + MIPS_RA_REGNUM);
+      if (is_mips16_addr (pc))
+       pc = unmake_mips16_addr (pc);
+      if (mips_in_frame_stub (pc))
+       {
+         pc = frame_unwind_register_signed
+                (next_frame, gdbarch_num_regs (gdbarch) + MIPS_S2_REGNUM);
+         if (is_mips16_addr (pc))
+           pc = unmake_mips16_addr (pc);
+       }
+    }
   return pc;
 }
 
@@ -1108,6 +1198,36 @@ mips32_relative_offset (ULONGEST inst)
   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
@@ -1140,19 +1260,24 @@ mips32_next_pc (struct frame_info *frame, CORE_ADDR pc)
        }
       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.  */
@@ -1212,6 +1337,25 @@ mips32_next_pc (struct frame_info *frame, CORE_ADDR pc)
                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;
@@ -1227,14 +1371,6 @@ mips32_next_pc (struct frame_info *frame, CORE_ADDR pc)
            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)) ==
@@ -1322,9 +1458,9 @@ 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 & 0x1f;           /* Extract 4:0.  */
 
@@ -1364,14 +1500,13 @@ unpack_mips16 (struct gdbarch *gdbarch, CORE_ADDR pc,
        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;
@@ -1386,28 +1521,16 @@ unpack_mips16 (struct gdbarch *gdbarch, CORE_ADDR pc,
        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;
       }
@@ -1453,13 +1576,7 @@ extended_mips16_next_pc (struct frame_info *frame, CORE_ADDR pc,
        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
@@ -1479,7 +1596,7 @@ extended_mips16_next_pc (struct frame_info *frame, CORE_ADDR pc,
        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
@@ -1491,7 +1608,7 @@ extended_mips16_next_pc (struct frame_info *frame, CORE_ADDR pc,
        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
@@ -1523,21 +1640,10 @@ extended_mips16_next_pc (struct frame_info *frame, CORE_ADDR pc,
            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
@@ -1579,7 +1685,7 @@ mips16_next_pc (struct frame_info *frame, CORE_ADDR pc)
 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);
@@ -2231,42 +2337,43 @@ restart:
                || 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
@@ -2623,7 +2730,9 @@ deal_with_atomic_sequence (struct gdbarch *gdbarch,
            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 */
@@ -2639,6 +2748,11 @@ deal_with_atomic_sequence (struct gdbarch *gdbarch,
          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 */
@@ -2707,16 +2821,16 @@ mips_software_single_step (struct frame_info *frame)
 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 */
 }
 
 
@@ -3616,13 +3730,13 @@ mips_n32n64_return_value (struct gdbarch *gdbarch, struct type *func_type,
       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);
@@ -3635,8 +3749,8 @@ mips_n32n64_return_value (struct gdbarch *gdbarch, struct type *func_type,
       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);
@@ -4075,8 +4189,8 @@ mips_o32_return_value (struct gdbarch *gdbarch, struct type *func_type,
       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);
@@ -4094,25 +4208,25 @@ mips_o32_return_value (struct gdbarch *gdbarch, struct type *func_type,
        {
        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;
@@ -4482,8 +4596,8 @@ mips_o64_return_value (struct gdbarch *gdbarch, struct type *func_type,
       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);
@@ -4712,7 +4826,7 @@ mips_print_register (struct ui_file *file, struct frame_info *frame,
   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;
@@ -4781,8 +4895,7 @@ print_gp_register_row (struct ui_file *file, struct frame_info *frame,
     {
       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))
@@ -4821,8 +4934,7 @@ print_gp_register_row (struct ui_file *file, struct frame_info *frame,
     {
       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.  */
@@ -4877,8 +4989,7 @@ mips_print_registers_info (struct gdbarch *gdbarch, struct ui_file *file,
       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);
@@ -5327,101 +5438,579 @@ mips_breakpoint_from_pc (struct gdbarch *gdbarch,
     }
 }
 
-/* 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
+/* 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;
+}
+
+/* Return non-zero if SUFFIX is one of the numeric suffixes used for MIPS16
+   call stubs, one of 1, 2, 5, 6, 9, 10, or, if ZERO is non-zero, also 0.  */
+
+static int
+mips_is_stub_suffix (const char *suffix, int zero)
+{
+  switch (suffix[0])
+   {
+   case '0':
+     return zero && suffix[1] == '\0';
+   case '1':
+     return suffix[1] == '\0' || (suffix[1] == '0' && suffix[2] == '\0');
+   case '2':
+   case '5':
+   case '6':
+   case '9':
+     return suffix[1] == '\0';
+   default:
+     return 0;
+   }
+}
+
+/* Return non-zero if MODE is one of the mode infixes used for MIPS16
+   call stubs, one of sf, df, sc, or dc.  */
+
+static int
+mips_is_stub_mode (const char *mode)
+{
+  return ((mode[0] == 's' || mode[0] == 'd')
+         && (mode[1] == 'f' || mode[1] == 'c'));
+}
+
+/* Code at PC is a compiler-generated stub.  Such a stub for a function
+   bar might have a name like __fn_stub_bar, and might look like this:
+
+      mfc1    $4, $f13
+      mfc1    $5, $f12
+      mfc1    $6, $f15
+      mfc1    $7, $f14
+
+   followed by (or interspersed with):
+
+      j       bar
+
+   or:
+
+      lui     $25, %hi(bar)
+      addiu   $25, $25, %lo(bar)
+      jr      $25
+
+   ($1 may be used in old code; for robustness we accept any register)
+   or, in PIC code:
+
+      lui     $28, %hi(_gp_disp)
+      addiu   $28, $28, %lo(_gp_disp)
+      addu    $28, $28, $25
+      lw      $25, %got(bar)
+      addiu   $25, $25, %lo(bar)
+      jr      $25
+
+   In the case of a __call_stub_bar stub, the sequence to set up
+   arguments might look like this:
+
+      mtc1    $4, $f13
+      mtc1    $5, $f12
+      mtc1    $6, $f15
+      mtc1    $7, $f14
+
+   followed by (or interspersed with) one of the jump sequences above.
+
+   In the case of a __call_stub_fp_bar stub, JAL or JALR is used instead
+   of J or JR, respectively, followed by:
+
+      mfc1    $2, $f0
+      mfc1    $3, $f1
+      jr      $18
+
+   We are at the beginning of the stub here, and scan down and extract
+   the target address from the jump immediate instruction or, if a jump
+   register instruction is used, from the register referred.  Return
+   the value of PC calculated or 0 if inconclusive.
+
+   The limit on the search is arbitrarily set to 20 instructions.  FIXME.  */
+
+static CORE_ADDR
+mips_get_mips16_fn_stub_pc (struct frame_info *frame, CORE_ADDR pc)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int addrreg = MIPS_ZERO_REGNUM;
+  CORE_ADDR start_pc = pc;
+  CORE_ADDR target_pc = 0;
+  CORE_ADDR addr = 0;
+  CORE_ADDR gp = 0;
+  int status = 0;
+  int i;
+
+  for (i = 0;
+       status == 0 && target_pc == 0 && i < 20;
+       i++, pc += MIPS_INSN32_SIZE)
+    {
+      ULONGEST inst = mips_fetch_instruction (gdbarch, pc);
+      CORE_ADDR imm;
+      int rt;
+      int rs;
+      int rd;
+
+      switch (itype_op (inst))
+       {
+       case 0:         /* SPECIAL */
+         switch (rtype_funct (inst))
+           {
+           case 8:             /* JR */
+           case 9:             /* JALR */
+             rs = rtype_rs (inst);
+             if (rs == MIPS_GP_REGNUM)
+               target_pc = gp;                         /* Hmm...  */
+             else if (rs == addrreg)
+               target_pc = addr;
+             break;
+
+           case 0x21:          /* ADDU */
+             rt = rtype_rt (inst);
+             rs = rtype_rs (inst);
+             rd = rtype_rd (inst);
+             if (rd == MIPS_GP_REGNUM
+                 && ((rs == MIPS_GP_REGNUM && rt == MIPS_T9_REGNUM)
+                     || (rs == MIPS_T9_REGNUM && rt == MIPS_GP_REGNUM)))
+               gp += start_pc;
+             break;
+           }
+         break;
+
+       case 2:         /* J */
+       case 3:         /* JAL */
+         target_pc = jtype_target (inst) << 2;
+         target_pc += ((pc + 4) & ~(CORE_ADDR) 0x0fffffff);
+         break;
+
+       case 9:         /* ADDIU */
+         rt = itype_rt (inst);
+         rs = itype_rs (inst);
+         if (rt == rs)
+           {
+             imm = (itype_immediate (inst) ^ 0x8000) - 0x8000;
+             if (rt == MIPS_GP_REGNUM)
+               gp += imm;
+             else if (rt == addrreg)
+               addr += imm;
+           }
+         break;
+
+       case 0xf:       /* LUI */
+         rt = itype_rt (inst);
+         imm = ((itype_immediate (inst) ^ 0x8000) - 0x8000) << 16;
+         if (rt == MIPS_GP_REGNUM)
+           gp = imm;
+         else if (rt != MIPS_ZERO_REGNUM)
+           {
+             addrreg = rt;
+             addr = imm;
+           }
+         break;
+
+       case 0x23:      /* LW */
+         rt = itype_rt (inst);
+         rs = itype_rs (inst);
+         imm = (itype_immediate (inst) ^ 0x8000) - 0x8000;
+         if (gp != 0 && rs == MIPS_GP_REGNUM)
+           {
+             gdb_byte buf[4];
+
+             memset (buf, 0, sizeof (buf));
+             status = target_read_memory (gp + imm, buf, sizeof (buf));
+             addrreg = rt;
+             addr = extract_signed_integer (buf, sizeof (buf), byte_order);
+           }
+         break;
+       }
+    }
+
+  return target_pc;
+}
+
+/* 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:
 
-   * If the PC is in __mips16_ret_{d,s}f, this is a return stub and the
-   target PC is in $31 ($ra).
+   * If the PC is in __mips16_ret_{d,s}{f,c}, this is a return stub
+     and the target PC is in $31 ($ra).
    * If the PC is in __mips16_call_stub_{1..10}, this is a call stub
-   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 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
+     and the target PC is in $2.
+   * If the PC at the start of __mips16_call_stub_{s,d}{f,c}_{0..10},
+     i.e. before the JALR instruction, this is effectively a call stub
+     and the target PC is in $2.  Otherwise this is effectively
+     a return stub and the target PC is in $18.
+   * If the PC is at the start of __call_stub_fp_*, i.e. before the
+     JAL or JALR instruction, this is effectively a call stub and the
+     target PC is buried in the instruction stream.  Otherwise this
+     is effectively a return stub and the target PC is in $18.
+   * If the PC is in __call_stub_* or in __fn_stub_*, this is a call
+     stub and the target PC is buried in the instruction stream.
+
+   See the source code for the stubs in gcc/config/mips/mips16.S, or the
+   stub builder in gcc/config/mips/mips.c (mips16_build_call_stub) for the
    gory details.  */
 
 static CORE_ADDR
 mips_skip_mips16_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
 {
   struct gdbarch *gdbarch = get_frame_arch (frame);
-  char *name;
   CORE_ADDR start_addr;
+  const char *name;
+  size_t prefixlen;
 
   /* Find the starting address and name of the function containing the PC.  */
   if (find_pc_partial_function (pc, &name, &start_addr, NULL) == 0)
     return 0;
 
-  /* If the PC is in __mips16_ret_{d,s}f, this is a return stub and the
-     target PC is in $31 ($ra).  */
-  if (strcmp (name, "__mips16_ret_sf") == 0
-      || strcmp (name, "__mips16_ret_df") == 0)
-    return get_frame_register_signed (frame, MIPS_RA_REGNUM);
-
-  if (strncmp (name, "__mips16_call_stub_", 19) == 0)
+  /* If the PC is in __mips16_ret_{d,s}{f,c}, this is a return stub
+     and the target PC is in $31 ($ra).  */
+  prefixlen = strlen (mips_str_mips16_ret_stub);
+  if (strncmp (name, mips_str_mips16_ret_stub, prefixlen) == 0
+      && mips_is_stub_mode (name + prefixlen)
+      && name[prefixlen + 2] == '\0')
+    return get_frame_register_signed
+            (frame, gdbarch_num_regs (gdbarch) + MIPS_RA_REGNUM);
+
+  /* If the PC is in __mips16_call_stub_*, this is one of the call
+     call/return stubs.  */
+  prefixlen = strlen (mips_str_mips16_call_stub);
+  if (strncmp (name, mips_str_mips16_call_stub, prefixlen) == 0)
     {
       /* If the PC is in __mips16_call_stub_{1..10}, this is a call stub
          and the target PC is in $2.  */
-      if (name[19] >= '0' && name[19] <= '9')
-       return get_frame_register_signed (frame, 2);
+      if (mips_is_stub_suffix (name + prefixlen, 0))
+       return get_frame_register_signed
+                (frame, gdbarch_num_regs (gdbarch) + MIPS_V0_REGNUM);
 
-      /* 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
+      /* If the PC at the start of __mips16_call_stub_{s,d}{f,c}_{0..10},
+         i.e. before the JALR instruction, this is effectively a call stub
          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')
+      else if (mips_is_stub_mode (name + prefixlen)
+              && name[prefixlen + 2] == '_'
+              && mips_is_stub_suffix (name + prefixlen + 3, 0))
        {
          if (pc == start_addr)
-           {
-             /* Check if the target of the stub is a compiler-generated
-                stub.  Such a stub for a function bar might have a name
-                like __fn_stub_bar, and might look like this:
-                mfc1    $4,$f13
-                mfc1    $5,$f12
-                mfc1    $6,$f15
-                mfc1    $7,$f14
-                la      $1,bar   (becomes a lui/addiu pair)
-                jr      $1
-                So scan down to the lui/addi and extract the target
-                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_*.  */
-             if (find_pc_partial_function (target_pc, &name, NULL, NULL) ==
-                 0)
-               return target_pc;
-             if (strncmp (name, "__fn_stub_", 10) != 0
-                 && strcmp (name, "etext") != 0
-                 && strcmp (name, "_etext") != 0)
-               return target_pc;
-
-             /* Scan through this _fn_stub_ code for the lui/addiu pair.
-                The limit on the search is arbitrarily set to 20
-                instructions.  FIXME.  */
-             for (i = 0, pc = 0; i < 20; i++, target_pc += MIPS_INSN32_SIZE)
-               {
-                 inst = mips_fetch_instruction (gdbarch, target_pc);
-                 if ((inst & 0xffff0000) == 0x3c010000)        /* lui $at */
-                   pc = (inst << 16) & 0xffff0000;             /* high word */
-                 else if ((inst & 0xffff0000) == 0x24210000)   /* addiu $at */
-                   return pc | (inst & 0xffff);                /* low word */
-               }
-
-             /* Couldn't find the lui/addui pair, so return stub address.  */
-             return target_pc;
-           }
+           /* This is the 'call' part of a call stub.  The return
+              address is in $2.  */
+           return get_frame_register_signed
+                    (frame, gdbarch_num_regs (gdbarch) + MIPS_V0_REGNUM);
          else
            /* This is the 'return' part of a call stub.  The return
-              address is in $r18.  */
-           return get_frame_register_signed (frame, 18);
+              address is in $18.  */
+           return get_frame_register_signed
+                    (frame, gdbarch_num_regs (gdbarch) + MIPS_S2_REGNUM);
        }
+      else
+       return 0;               /* Not a stub.  */
+    }
+
+  /* If the PC is in __call_stub_* or __fn_stub*, this is one of the
+     compiler-generated call or call/return stubs.  */
+  if (strncmp (name, mips_str_fn_stub, strlen (mips_str_fn_stub)) == 0
+      || strncmp (name, mips_str_call_stub, strlen (mips_str_call_stub)) == 0)
+    {
+      if (pc == start_addr)
+       /* This is the 'call' part of a call stub.  Call this helper
+          to scan through this code for interesting instructions
+          and determine the final PC.  */
+       return mips_get_mips16_fn_stub_pc (frame, pc);
+      else
+       /* This is the 'return' part of a call stub.  The return address
+          is in $18.  */
+       return get_frame_register_signed
+                (frame, gdbarch_num_regs (gdbarch) + MIPS_S2_REGNUM);
     }
-  return 0;                    /* not a stub */
+
+  return 0;                    /* Not a stub.  */
+}
+
+/* Return non-zero if the PC is inside a return thunk (aka stub or trampoline).
+   This implements the IN_SOLIB_RETURN_TRAMPOLINE macro.  */
+
+static int
+mips_in_return_stub (struct gdbarch *gdbarch, CORE_ADDR pc, const char *name)
+{
+  CORE_ADDR start_addr;
+  size_t prefixlen;
+
+  /* Find the starting address of the function containing the PC.  */
+  if (find_pc_partial_function (pc, NULL, &start_addr, NULL) == 0)
+    return 0;
+
+  /* If the PC is in __mips16_call_stub_{s,d}{f,c}_{0..10} but not at
+     the start, i.e. after the JALR instruction, this is effectively
+     a return stub.  */
+  prefixlen = strlen (mips_str_mips16_call_stub);
+  if (pc != start_addr
+      && strncmp (name, mips_str_mips16_call_stub, prefixlen) == 0
+      && mips_is_stub_mode (name + prefixlen)
+      && name[prefixlen + 2] == '_'
+      && mips_is_stub_suffix (name + prefixlen + 3, 1))
+    return 1;
+
+  /* If the PC is in __call_stub_fp_* but not at the start, i.e. after
+     the JAL or JALR instruction, this is effectively a return stub.  */
+  prefixlen = strlen (mips_str_call_fp_stub);
+  if (pc != start_addr
+      && strncmp (name, mips_str_call_fp_stub, prefixlen) == 0)
+    return 1;
+
+  /* Consume the .pic. prefix of any PIC stub, this function must return
+     true when the PC is in a PIC stub of a __mips16_ret_{d,s}{f,c} stub
+     or the call stub path will trigger in handle_inferior_event causing
+     it to go astray.  */
+  prefixlen = strlen (mips_str_pic);
+  if (strncmp (name, mips_str_pic, prefixlen) == 0)
+    name += prefixlen;
+
+  /* If the PC is in __mips16_ret_{d,s}{f,c}, this is a return stub.  */
+  prefixlen = strlen (mips_str_mips16_ret_stub);
+  if (strncmp (name, mips_str_mips16_ret_stub, prefixlen) == 0
+      && mips_is_stub_mode (name + prefixlen)
+      && name[prefixlen + 2] == '\0')
+    return 1;
+
+  return 0;                    /* Not a stub.  */
 }
 
 /* If the current PC is the start of a non-PIC-to-PIC stub, return the
@@ -5473,8 +6062,8 @@ mips_skip_pic_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
          && (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.  */
@@ -5484,21 +6073,41 @@ mips_skip_pic_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
 static CORE_ADDR
 mips_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
 {
+  CORE_ADDR requested_pc = pc;
   CORE_ADDR target_pc;
+  CORE_ADDR new_pc;
 
-  target_pc = mips_skip_mips16_trampoline_code (frame, pc);
-  if (target_pc)
-    return target_pc;
+  do
+    {
+      target_pc = pc;
 
-  target_pc = find_solib_trampoline_target (frame, pc);
-  if (target_pc)
-    return target_pc;
+      new_pc = mips_skip_mips16_trampoline_code (frame, pc);
+      if (new_pc)
+       {
+         pc = new_pc;
+         if (is_mips16_addr (pc))
+           pc = unmake_mips16_addr (pc);
+       }
 
-  target_pc = mips_skip_pic_trampoline_code (frame, pc);
-  if (target_pc)
-    return target_pc;
+      new_pc = find_solib_trampoline_target (frame, pc);
+      if (new_pc)
+       {
+         pc = new_pc;
+         if (is_mips16_addr (pc))
+           pc = unmake_mips16_addr (pc);
+       }
 
-  return 0;
+      new_pc = mips_skip_pic_trampoline_code (frame, pc);
+      if (new_pc)
+       {
+         pc = new_pc;
+         if (is_mips16_addr (pc))
+           pc = unmake_mips16_addr (pc);
+       }
+    }
+  while (pc != target_pc);
+
+  return pc != requested_pc ? pc : 0;
 }
 
 /* Convert a dbx stab register number (from `r' declaration) to a GDB
@@ -5516,6 +6125,8 @@ mips_stab_reg_to_regnum (struct gdbarch *gdbarch, int num)
     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?  */
@@ -5539,6 +6150,8 @@ mips_dwarf_dwarf2_ecoff_reg_to_regnum (struct gdbarch *gdbarch, int num)
     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?  */
@@ -5678,6 +6291,63 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   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))
@@ -5712,11 +6382,11 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
 
       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)
        {
@@ -5734,12 +6404,11 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
       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)
        {
@@ -5760,13 +6429,15 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       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)
        {
@@ -5774,8 +6445,45 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
          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.  */
@@ -6024,66 +6732,15 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   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)
     {
@@ -6261,6 +6918,8 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
   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);
 
@@ -6291,6 +6950,16 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
   set_gdbarch_skip_trampoline_code (gdbarch, mips_skip_trampoline_code);
 
+  /* NOTE drow/2012-04-25: We overload the core solib trampoline code
+     to support MIPS16.  This is a bad thing.  Make sure not to do it
+     if we have an OS ABI that actually supports shared libraries, since
+     shared library support is more important.  If we have an OS someday
+     that supports both shared libraries and MIPS16, we'll have to find
+     a better place for these.
+     macro/2012-04-25: But that applies to return trampolines only and
+     currently no MIPS OS ABI uses shared libraries that have them.  */
+  set_gdbarch_in_solib_return_trampoline (gdbarch, mips_in_return_stub);
+
   set_gdbarch_single_step_through_delay (gdbarch,
                                         mips_single_step_through_delay);
 
@@ -6303,6 +6972,14 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   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);
This page took 0.045704 seconds and 4 git commands to generate.