* gas/mips/mips.exp (run_dump_test_arch): Check for the presence
[deliverable/binutils-gdb.git] / gdb / arm-tdep.c
index 353bc487f373e826e0d9ba8909eed72a658a4c80..2df96cd0e62ff766a87e307a966ad44b12a4e11b 100644 (file)
@@ -53,6 +53,8 @@
 #include "gdb_assert.h"
 #include "vec.h"
 
+#include "features/arm-with-m.c"
+
 static int arm_debug;
 
 /* Macros for setting and testing a bit in a minimal symbol that marks
@@ -122,7 +124,8 @@ static const char *arm_mode_strings[] =
   {
     "auto",
     "arm",
-    "thumb"
+    "thumb",
+    NULL
   };
 
 static const char *arm_fallback_mode_string = "auto";
@@ -235,6 +238,11 @@ struct arm_prologue_cache
   struct trad_frame_saved_reg *saved_regs;
 };
 
+static CORE_ADDR arm_analyze_prologue (struct gdbarch *gdbarch,
+                                      CORE_ADDR prologue_start,
+                                      CORE_ADDR prologue_end,
+                                      struct arm_prologue_cache *cache);
+
 /* Architecture version for displaced stepping.  This effects the behaviour of
    certain instructions, and really should not be hard-wired.  */
 
@@ -250,12 +258,24 @@ struct arm_prologue_cache
 
 int arm_apcs_32 = 1;
 
-/* Determine if FRAME is executing in Thumb mode.  */
+/* Return the bit mask in ARM_PS_REGNUM that indicates Thumb mode.  */
 
 static int
+arm_psr_thumb_bit (struct gdbarch *gdbarch)
+{
+  if (gdbarch_tdep (gdbarch)->is_m)
+    return XPSR_T;
+  else
+    return CPSR_T;
+}
+
+/* Determine if FRAME is executing in Thumb mode.  */
+
+int
 arm_frame_is_thumb (struct frame_info *frame)
 {
   CORE_ADDR cpsr;
+  ULONGEST t_bit = arm_psr_thumb_bit (get_frame_arch (frame));
 
   /* Every ARM frame unwinder can unwind the T bit of the CPSR, either
      directly (from a signal frame or dummy frame) or by interpreting
@@ -263,7 +283,7 @@ arm_frame_is_thumb (struct frame_info *frame)
      trust the unwinders.  */
   cpsr = get_frame_register_unsigned (frame, ARM_PS_REGNUM);
 
-  return (cpsr & CPSR_T) != 0;
+  return (cpsr & t_bit) != 0;
 }
 
 /* Callback for VEC_lower_bound.  */
@@ -342,7 +362,7 @@ static CORE_ADDR arm_get_next_pc_raw (struct frame_info *frame,
    any executing frame; otherwise, prefer arm_frame_is_thumb.  */
 
 static int
-arm_pc_is_thumb (CORE_ADDR memaddr)
+arm_pc_is_thumb (struct gdbarch *gdbarch, CORE_ADDR memaddr)
 {
   struct obj_section *sec;
   struct minimal_symbol *sym;
@@ -358,6 +378,10 @@ arm_pc_is_thumb (CORE_ADDR memaddr)
   if (strcmp (arm_force_mode_string, "thumb") == 0)
     return 1;
 
+  /* ARM v6-M and v7-M are always in Thumb mode.  */
+  if (gdbarch_tdep (gdbarch)->is_m)
+    return 1;
+
   /* If there are mapping symbols, consult them.  */
   type = arm_find_mapping_symbol (memaddr, NULL);
   if (type)
@@ -424,21 +448,218 @@ arm_smash_text_address (struct gdbarch *gdbarch, CORE_ADDR val)
   return val & ~1;
 }
 
+/* Return 1 if PC is the start of a compiler helper function which
+   can be safely ignored during prologue skipping.  */
+static int
+skip_prologue_function (CORE_ADDR pc)
+{
+  struct minimal_symbol *msym;
+  const char *name;
+
+  msym = lookup_minimal_symbol_by_pc (pc);
+  if (msym == NULL || SYMBOL_VALUE_ADDRESS (msym) != pc)
+    return 0;
+
+  name = SYMBOL_LINKAGE_NAME (msym);
+  if (name == NULL)
+    return 0;
+
+  /* The GNU linker's Thumb call stub to foo is named
+     __foo_from_thumb.  */
+  if (strstr (name, "_from_thumb") != NULL)
+    name += 2;
+
+  /* On soft-float targets, __truncdfsf2 is called to convert promoted
+     arguments to their argument types in non-prototyped
+     functions.  */
+  if (strncmp (name, "__truncdfsf2", strlen ("__truncdfsf2")) == 0)
+    return 1;
+  if (strncmp (name, "__aeabi_d2f", strlen ("__aeabi_d2f")) == 0)
+    return 1;
+
+  /* Internal functions related to thread-local storage.  */
+  if (strncmp (name, "__tls_get_addr", strlen ("__tls_get_addr")) == 0)
+    return 1;
+  if (strncmp (name, "__aeabi_read_tp", strlen ("__aeabi_read_tp")) == 0)
+    return 1;
+
+  return 0;
+}
+
+/* Support routines for instruction parsing.  */
+#define submask(x) ((1L << ((x) + 1)) - 1)
+#define bit(obj,st) (((obj) >> (st)) & 1)
+#define bits(obj,st,fn) (((obj) >> (st)) & submask ((fn) - (st)))
+#define sbits(obj,st,fn) \
+  ((long) (bits(obj,st,fn) | ((long) bit(obj,fn) * ~ submask (fn - st))))
+#define BranchDest(addr,instr) \
+  ((CORE_ADDR) (((long) (addr)) + 8 + (sbits (instr, 0, 23) << 2)))
+
+/* Decode immediate value; implements ThumbExpandImmediate pseudo-op.  */
+
+static unsigned int
+thumb_expand_immediate (unsigned int imm)
+{
+  unsigned int count = imm >> 7;
+
+  if (count < 8)
+    switch (count / 2)
+      {
+      case 0:
+       return imm & 0xff;
+      case 1:
+       return (imm & 0xff) | ((imm & 0xff) << 16);
+      case 2:
+       return ((imm & 0xff) << 8) | ((imm & 0xff) << 24);
+      case 3:
+       return (imm & 0xff) | ((imm & 0xff) << 8)
+               | ((imm & 0xff) << 16) | ((imm & 0xff) << 24);
+      }
+
+  return (0x80 | (imm & 0x7f)) << (32 - count);
+}
+
+/* Return 1 if the 16-bit Thumb instruction INST might change
+   control flow, 0 otherwise.  */
+
+static int
+thumb_instruction_changes_pc (unsigned short inst)
+{
+  if ((inst & 0xff00) == 0xbd00)       /* pop {rlist, pc} */
+    return 1;
+
+  if ((inst & 0xf000) == 0xd000)       /* conditional branch */
+    return 1;
+
+  if ((inst & 0xf800) == 0xe000)       /* unconditional branch */
+    return 1;
+
+  if ((inst & 0xff00) == 0x4700)       /* bx REG, blx REG */
+    return 1;
+
+  if ((inst & 0xff87) == 0x4687)       /* mov pc, REG */
+    return 1;
+
+  if ((inst & 0xf500) == 0xb100)       /* CBNZ or CBZ.  */
+    return 1;
+
+  return 0;
+}
+
+/* Return 1 if the 32-bit Thumb instruction in INST1 and INST2
+   might change control flow, 0 otherwise.  */
+
+static int
+thumb2_instruction_changes_pc (unsigned short inst1, unsigned short inst2)
+{
+  if ((inst1 & 0xf800) == 0xf000 && (inst2 & 0x8000) == 0x8000)
+    {
+      /* Branches and miscellaneous control instructions.  */
+
+      if ((inst2 & 0x1000) != 0 || (inst2 & 0xd001) == 0xc000)
+       {
+         /* B, BL, BLX.  */
+         return 1;
+       }
+      else if (inst1 == 0xf3de && (inst2 & 0xff00) == 0x3f00)
+       {
+         /* SUBS PC, LR, #imm8.  */
+         return 1;
+       }
+      else if ((inst2 & 0xd000) == 0x8000 && (inst1 & 0x0380) != 0x0380)
+       {
+         /* Conditional branch.  */
+         return 1;
+       }
+
+      return 0;
+    }
+
+  if ((inst1 & 0xfe50) == 0xe810)
+    {
+      /* Load multiple or RFE.  */
+
+      if (bit (inst1, 7) && !bit (inst1, 8))
+       {
+         /* LDMIA or POP */
+         if (bit (inst2, 15))
+           return 1;
+       }
+      else if (!bit (inst1, 7) && bit (inst1, 8))
+       {
+         /* LDMDB */
+         if (bit (inst2, 15))
+           return 1;
+       }
+      else if (bit (inst1, 7) && bit (inst1, 8))
+       {
+         /* RFEIA */
+         return 1;
+       }
+      else if (!bit (inst1, 7) && !bit (inst1, 8))
+       {
+         /* RFEDB */
+         return 1;
+       }
+
+      return 0;
+    }
+
+  if ((inst1 & 0xffef) == 0xea4f && (inst2 & 0xfff0) == 0x0f00)
+    {
+      /* MOV PC or MOVS PC.  */
+      return 1;
+    }
+
+  if ((inst1 & 0xff70) == 0xf850 && (inst2 & 0xf000) == 0xf000)
+    {
+      /* LDR PC.  */
+      if (bits (inst1, 0, 3) == 15)
+       return 1;
+      if (bit (inst1, 7))
+       return 1;
+      if (bit (inst2, 11))
+       return 1;
+      if ((inst2 & 0x0fc0) == 0x0000)
+       return 1;       
+
+      return 0;
+    }
+
+  if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf000)
+    {
+      /* TBB.  */
+      return 1;
+    }
+
+  if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf010)
+    {
+      /* TBH.  */
+      return 1;
+    }
+
+  return 0;
+}
+
 /* Analyze a Thumb prologue, looking for a recognizable stack frame
    and frame pointer.  Scan until we encounter a store that could
-   clobber the stack frame unexpectedly, or an unknown instruction.  */
+   clobber the stack frame unexpectedly, or an unknown instruction.
+   Return the last address which is definitely safe to skip for an
+   initial breakpoint.  */
 
 static CORE_ADDR
 thumb_analyze_prologue (struct gdbarch *gdbarch,
                        CORE_ADDR start, CORE_ADDR limit,
                        struct arm_prologue_cache *cache)
 {
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
   int i;
   pv_t regs[16];
   struct pv_area *stack;
   struct cleanup *back_to;
   CORE_ADDR offset;
+  CORE_ADDR unrecognized_pc = 0;
 
   for (i = 0; i < 16; i++)
     regs[i] = pv_register (i, 0);
@@ -483,9 +704,29 @@ thumb_analyze_prologue (struct gdbarch *gdbarch,
            regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
                                                   offset);
        }
-      else if ((insn & 0xff00) == 0xaf00)      /* add r7, sp, #imm */
-       regs[THUMB_FP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
-                                                (insn & 0xff) << 2);
+      else if ((insn & 0xf800) == 0xa800)      /* add Rd, sp, #imm */
+       regs[bits (insn, 8, 10)] = pv_add_constant (regs[ARM_SP_REGNUM],
+                                                   (insn & 0xff) << 2);
+      else if ((insn & 0xfe00) == 0x1c00       /* add Rd, Rn, #imm */
+              && pv_is_register (regs[bits (insn, 3, 5)], ARM_SP_REGNUM))
+       regs[bits (insn, 0, 2)] = pv_add_constant (regs[bits (insn, 3, 5)],
+                                                  bits (insn, 6, 8));
+      else if ((insn & 0xf800) == 0x3000       /* add Rd, #imm */
+              && pv_is_register (regs[bits (insn, 8, 10)], ARM_SP_REGNUM))
+       regs[bits (insn, 8, 10)] = pv_add_constant (regs[bits (insn, 8, 10)],
+                                                   bits (insn, 0, 7));
+      else if ((insn & 0xfe00) == 0x1800       /* add Rd, Rn, Rm */
+              && pv_is_register (regs[bits (insn, 6, 8)], ARM_SP_REGNUM)
+              && pv_is_constant (regs[bits (insn, 3, 5)]))
+       regs[bits (insn, 0, 2)] = pv_add (regs[bits (insn, 3, 5)],
+                                         regs[bits (insn, 6, 8)]);
+      else if ((insn & 0xff00) == 0x4400       /* add Rd, Rm */
+              && pv_is_constant (regs[bits (insn, 3, 6)]))
+       {
+         int rd = (bit (insn, 7) << 3) + bits (insn, 0, 2);
+         int rm = bits (insn, 3, 6);
+         regs[rd] = pv_add (regs[rd], regs[rm]);
+       }
       else if ((insn & 0xff00) == 0x4600)      /* mov hi, lo or mov lo, hi */
        {
          int dst_reg = (insn & 0x7) + ((insn & 0x80) >> 4);
@@ -508,22 +749,351 @@ thumb_analyze_prologue (struct gdbarch *gdbarch,
 
          pv_area_store (stack, addr, 4, regs[regno]);
        }
-      else
+      else if ((insn & 0xf800) == 0x6000)      /* str rd, [rn, #off] */
+       {
+         int rd = bits (insn, 0, 2);
+         int rn = bits (insn, 3, 5);
+         pv_t addr;
+
+         offset = bits (insn, 6, 10) << 2;
+         addr = pv_add_constant (regs[rn], offset);
+
+         if (pv_area_store_would_trash (stack, addr))
+           break;
+
+         pv_area_store (stack, addr, 4, regs[rd]);
+       }
+      else if (((insn & 0xf800) == 0x7000      /* strb Rd, [Rn, #off] */
+               || (insn & 0xf800) == 0x8000)   /* strh Rd, [Rn, #off] */
+              && pv_is_register (regs[bits (insn, 3, 5)], ARM_SP_REGNUM))
+       /* Ignore stores of argument registers to the stack.  */
+       ;
+      else if ((insn & 0xf800) == 0xc800       /* ldmia Rn!, { registers } */
+              && pv_is_register (regs[bits (insn, 8, 10)], ARM_SP_REGNUM))
+       /* Ignore block loads from the stack, potentially copying
+          parameters from memory.  */
+       ;
+      else if ((insn & 0xf800) == 0x9800       /* ldr Rd, [Rn, #immed] */
+              || ((insn & 0xf800) == 0x6800    /* ldr Rd, [sp, #immed] */
+                  && pv_is_register (regs[bits (insn, 3, 5)], ARM_SP_REGNUM)))
+       /* Similarly ignore single loads from the stack.  */
+       ;
+      else if ((insn & 0xffc0) == 0x0000       /* lsls Rd, Rm, #0 */
+              || (insn & 0xffc0) == 0x1c00)    /* add Rd, Rn, #0 */
+       /* Skip register copies, i.e. saves to another register
+          instead of the stack.  */
+       ;
+      else if ((insn & 0xf800) == 0x2000)      /* movs Rd, #imm */
+       /* Recognize constant loads; even with small stacks these are necessary
+          on Thumb.  */
+       regs[bits (insn, 8, 10)] = pv_constant (bits (insn, 0, 7));
+      else if ((insn & 0xf800) == 0x4800)      /* ldr Rd, [pc, #imm] */
+       {
+         /* Constant pool loads, for the same reason.  */
+         unsigned int constant;
+         CORE_ADDR loc;
+
+         loc = start + 4 + bits (insn, 0, 7) * 4;
+         constant = read_memory_unsigned_integer (loc, 4, byte_order);
+         regs[bits (insn, 8, 10)] = pv_constant (constant);
+       }
+      else if ((insn & 0xe000) == 0xe000)
+       {
+         unsigned short inst2;
+
+         inst2 = read_memory_unsigned_integer (start + 2, 2,
+                                               byte_order_for_code);
+
+         if ((insn & 0xf800) == 0xf000 && (inst2 & 0xe800) == 0xe800)
+           {
+             /* BL, BLX.  Allow some special function calls when
+                skipping the prologue; GCC generates these before
+                storing arguments to the stack.  */
+             CORE_ADDR nextpc;
+             int j1, j2, imm1, imm2;
+
+             imm1 = sbits (insn, 0, 10);
+             imm2 = bits (inst2, 0, 10);
+             j1 = bit (inst2, 13);
+             j2 = bit (inst2, 11);
+
+             offset = ((imm1 << 12) + (imm2 << 1));
+             offset ^= ((!j2) << 22) | ((!j1) << 23);
+
+             nextpc = start + 4 + offset;
+             /* For BLX make sure to clear the low bits.  */
+             if (bit (inst2, 12) == 0)
+               nextpc = nextpc & 0xfffffffc;
+
+             if (!skip_prologue_function (nextpc))
+               break;
+           }
+
+         else if ((insn & 0xffd0) == 0xe900    /* stmdb Rn{!}, { registers } */
+                  && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
+           {
+             pv_t addr = regs[bits (insn, 0, 3)];
+             int regno;
+
+             if (pv_area_store_would_trash (stack, addr))
+               break;
+
+             /* Calculate offsets of saved registers.  */
+             for (regno = ARM_LR_REGNUM; regno >= 0; regno--)
+               if (inst2 & (1 << regno))
+                 {
+                   addr = pv_add_constant (addr, -4);
+                   pv_area_store (stack, addr, 4, regs[regno]);
+                 }
+
+             if (insn & 0x0020)
+               regs[bits (insn, 0, 3)] = addr;
+           }
+
+         else if ((insn & 0xff50) == 0xe940    /* strd Rt, Rt2, [Rn, #+/-imm]{!} */
+                  && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
+           {
+             int regno1 = bits (inst2, 12, 15);
+             int regno2 = bits (inst2, 8, 11);
+             pv_t addr = regs[bits (insn, 0, 3)];
+
+             offset = inst2 & 0xff;
+             if (insn & 0x0080)
+               addr = pv_add_constant (addr, offset);
+             else
+               addr = pv_add_constant (addr, -offset);
+
+             if (pv_area_store_would_trash (stack, addr))
+               break;
+
+             pv_area_store (stack, addr, 4, regs[regno1]);
+             pv_area_store (stack, pv_add_constant (addr, 4),
+                            4, regs[regno2]);
+
+             if (insn & 0x0020)
+               regs[bits (insn, 0, 3)] = addr;
+           }
+
+         else if ((insn & 0xfff0) == 0xf8c0    /* str Rt,[Rn,+/-#imm]{!} */
+                  && (inst2 & 0x0c00) == 0x0c00
+                  && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
+           {
+             int regno = bits (inst2, 12, 15);
+             pv_t addr = regs[bits (insn, 0, 3)];
+
+             offset = inst2 & 0xff;
+             if (inst2 & 0x0200)
+               addr = pv_add_constant (addr, offset);
+             else
+               addr = pv_add_constant (addr, -offset);
+
+             if (pv_area_store_would_trash (stack, addr))
+               break;
+
+             pv_area_store (stack, addr, 4, regs[regno]);
+
+             if (inst2 & 0x0100)
+               regs[bits (insn, 0, 3)] = addr;
+           }
+
+         else if ((insn & 0xfff0) == 0xf8c0    /* str.w Rt,[Rn,#imm] */
+                  && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
+           {
+             int regno = bits (inst2, 12, 15);
+             pv_t addr;
+
+             offset = inst2 & 0xfff;
+             addr = pv_add_constant (regs[bits (insn, 0, 3)], offset);
+
+             if (pv_area_store_would_trash (stack, addr))
+               break;
+
+             pv_area_store (stack, addr, 4, regs[regno]);
+           }
+
+         else if ((insn & 0xffd0) == 0xf880    /* str{bh}.w Rt,[Rn,#imm] */
+                  && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
+           /* Ignore stores of argument registers to the stack.  */
+           ;
+
+         else if ((insn & 0xffd0) == 0xf800    /* str{bh} Rt,[Rn,#+/-imm] */
+                  && (inst2 & 0x0d00) == 0x0c00
+                  && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
+           /* Ignore stores of argument registers to the stack.  */
+           ;
+
+         else if ((insn & 0xffd0) == 0xe890    /* ldmia Rn[!], { registers } */
+                  && (inst2 & 0x8000) == 0x0000
+                  && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
+           /* Ignore block loads from the stack, potentially copying
+              parameters from memory.  */
+           ;
+
+         else if ((insn & 0xffb0) == 0xe950    /* ldrd Rt, Rt2, [Rn, #+/-imm] */
+                  && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
+           /* Similarly ignore dual loads from the stack.  */
+           ;
+
+         else if ((insn & 0xfff0) == 0xf850    /* ldr Rt,[Rn,#+/-imm] */
+                  && (inst2 & 0x0d00) == 0x0c00
+                  && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
+           /* Similarly ignore single loads from the stack.  */
+           ;
+
+         else if ((insn & 0xfff0) == 0xf8d0    /* ldr.w Rt,[Rn,#imm] */
+                  && pv_is_register (regs[bits (insn, 0, 3)], ARM_SP_REGNUM))
+           /* Similarly ignore single loads from the stack.  */
+           ;
+
+         else if ((insn & 0xfbf0) == 0xf100    /* add.w Rd, Rn, #imm */
+                  && (inst2 & 0x8000) == 0x0000)
+           {
+             unsigned int imm = ((bits (insn, 10, 10) << 11)
+                                 | (bits (inst2, 12, 14) << 8)
+                                 | bits (inst2, 0, 7));
+
+             regs[bits (inst2, 8, 11)]
+               = pv_add_constant (regs[bits (insn, 0, 3)],
+                                  thumb_expand_immediate (imm));
+           }
+
+         else if ((insn & 0xfbf0) == 0xf200    /* addw Rd, Rn, #imm */
+                  && (inst2 & 0x8000) == 0x0000)
+           {
+             unsigned int imm = ((bits (insn, 10, 10) << 11)
+                                 | (bits (inst2, 12, 14) << 8)
+                                 | bits (inst2, 0, 7));
+
+             regs[bits (inst2, 8, 11)]
+               = pv_add_constant (regs[bits (insn, 0, 3)], imm);
+           }
+
+         else if ((insn & 0xfbf0) == 0xf1a0    /* sub.w Rd, Rn, #imm */
+                  && (inst2 & 0x8000) == 0x0000)
+           {
+             unsigned int imm = ((bits (insn, 10, 10) << 11)
+                                 | (bits (inst2, 12, 14) << 8)
+                                 | bits (inst2, 0, 7));
+
+             regs[bits (inst2, 8, 11)]
+               = pv_add_constant (regs[bits (insn, 0, 3)],
+                                  - (CORE_ADDR) thumb_expand_immediate (imm));
+           }
+
+         else if ((insn & 0xfbf0) == 0xf2a0    /* subw Rd, Rn, #imm */
+                  && (inst2 & 0x8000) == 0x0000)
+           {
+             unsigned int imm = ((bits (insn, 10, 10) << 11)
+                                 | (bits (inst2, 12, 14) << 8)
+                                 | bits (inst2, 0, 7));
+
+             regs[bits (inst2, 8, 11)]
+               = pv_add_constant (regs[bits (insn, 0, 3)], - (CORE_ADDR) imm);
+           }
+
+         else if ((insn & 0xfbff) == 0xf04f)   /* mov.w Rd, #const */
+           {
+             unsigned int imm = ((bits (insn, 10, 10) << 11)
+                                 | (bits (inst2, 12, 14) << 8)
+                                 | bits (inst2, 0, 7));
+
+             regs[bits (inst2, 8, 11)]
+               = pv_constant (thumb_expand_immediate (imm));
+           }
+
+         else if ((insn & 0xfbf0) == 0xf240)   /* movw Rd, #const */
+           {
+             unsigned int imm = ((bits (insn, 0, 3) << 12)
+                                 | (bits (insn, 10, 10) << 11)
+                                 | (bits (inst2, 12, 14) << 8)
+                                 | bits (inst2, 0, 7));
+
+             regs[bits (inst2, 8, 11)] = pv_constant (imm);
+           }
+
+         else if (insn == 0xea5f               /* mov.w Rd,Rm */
+                  && (inst2 & 0xf0f0) == 0)
+           {
+             int dst_reg = (inst2 & 0x0f00) >> 8;
+             int src_reg = inst2 & 0xf;
+             regs[dst_reg] = regs[src_reg];
+           }
+
+         else if ((insn & 0xff7f) == 0xf85f)   /* ldr.w Rt,<label> */
+           {
+             /* Constant pool loads.  */
+             unsigned int constant;
+             CORE_ADDR loc;
+
+             offset = bits (insn, 0, 11);
+             if (insn & 0x0080)
+               loc = start + 4 + offset;
+             else
+               loc = start + 4 - offset;
+
+             constant = read_memory_unsigned_integer (loc, 4, byte_order);
+             regs[bits (inst2, 12, 15)] = pv_constant (constant);
+           }
+
+         else if ((insn & 0xff7f) == 0xe95f)   /* ldrd Rt,Rt2,<label> */
+           {
+             /* Constant pool loads.  */
+             unsigned int constant;
+             CORE_ADDR loc;
+
+             offset = bits (insn, 0, 7) << 2;
+             if (insn & 0x0080)
+               loc = start + 4 + offset;
+             else
+               loc = start + 4 - offset;
+
+             constant = read_memory_unsigned_integer (loc, 4, byte_order);
+             regs[bits (inst2, 12, 15)] = pv_constant (constant);
+
+             constant = read_memory_unsigned_integer (loc + 4, 4, byte_order);
+             regs[bits (inst2, 8, 11)] = pv_constant (constant);
+           }
+
+         else if (thumb2_instruction_changes_pc (insn, inst2))
+           {
+             /* Don't scan past anything that might change control flow.  */
+             break;
+           }
+         else
+           {
+             /* The optimizer might shove anything into the prologue,
+                so we just skip what we don't recognize.  */
+             unrecognized_pc = start;
+           }
+
+         start += 2;
+       }
+      else if (thumb_instruction_changes_pc (insn))
        {
-         /* We don't know what this instruction is.  We're finished
-            scanning.  NOTE: Recognizing more safe-to-ignore
-            instructions here will improve support for optimized
-            code.  */
+         /* Don't scan past anything that might change control flow.  */
          break;
        }
+      else
+       {
+         /* The optimizer might shove anything into the prologue,
+            so we just skip what we don't recognize.  */
+         unrecognized_pc = start;
+       }
 
       start += 2;
     }
 
+  if (arm_debug)
+    fprintf_unfiltered (gdb_stdlog, "Prologue scan stopped at %s\n",
+                       paddress (gdbarch, start));
+
+  if (unrecognized_pc == 0)
+    unrecognized_pc = start;
+
   if (cache == NULL)
     {
       do_cleanups (back_to);
-      return start;
+      return unrecognized_pc;
     }
 
   if (pv_is_register (regs[ARM_FP_REGNUM], ARM_SP_REGNUM))
@@ -556,7 +1126,7 @@ thumb_analyze_prologue (struct gdbarch *gdbarch,
       cache->saved_regs[i].addr = offset;
 
   do_cleanups (back_to);
-  return start;
+  return unrecognized_pc;
 }
 
 /* Advance the PC across any function entry prologue instructions to
@@ -583,10 +1153,6 @@ arm_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
   CORE_ADDR func_addr, limit_pc;
   struct symtab_and_line sal;
 
-  /* If we're in a dummy frame, don't even try to skip the prologue.  */
-  if (deprecated_pc_in_call_dummy (gdbarch, pc))
-    return pc;
-
   /* See if we can determine the end of the prologue via the symbol table.
      If so, then return either PC, or the PC after the prologue, whichever
      is greater.  */
@@ -594,8 +1160,45 @@ arm_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
     {
       CORE_ADDR post_prologue_pc
        = skip_prologue_using_sal (gdbarch, func_addr);
+      struct symtab *s = find_pc_symtab (func_addr);
+
+      /* GCC always emits a line note before the prologue and another
+        one after, even if the two are at the same address or on the
+        same line.  Take advantage of this so that we do not need to
+        know every instruction that might appear in the prologue.  We
+        will have producer information for most binaries; if it is
+        missing (e.g. for -gstabs), assuming the GNU tools.  */
+      if (post_prologue_pc
+         && (s == NULL
+             || s->producer == NULL
+             || strncmp (s->producer, "GNU ", sizeof ("GNU ") - 1) == 0))
+       return post_prologue_pc;
+
       if (post_prologue_pc != 0)
-       return max (pc, post_prologue_pc);
+       {
+         CORE_ADDR analyzed_limit;
+
+         /* For non-GCC compilers, make sure the entire line is an
+            acceptable prologue; GDB will round this function's
+            return value up to the end of the following line so we
+            can not skip just part of a line (and we do not want to).
+
+            RealView does not treat the prologue specially, but does
+            associate prologue code with the opening brace; so this
+            lets us skip the first line if we think it is the opening
+            brace.  */
+         if (arm_pc_is_thumb (gdbarch, func_addr))
+           analyzed_limit = thumb_analyze_prologue (gdbarch, func_addr,
+                                                    post_prologue_pc, NULL);
+         else
+           analyzed_limit = arm_analyze_prologue (gdbarch, func_addr,
+                                                  post_prologue_pc, NULL);
+
+         if (analyzed_limit != post_prologue_pc)
+           return func_addr;
+
+         return post_prologue_pc;
+       }
     }
 
   /* Can't determine prologue from the symbol table, need to examine
@@ -611,7 +1214,7 @@ arm_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
 
 
   /* Check if this is Thumb code.  */
-  if (arm_pc_is_thumb (pc))
+  if (arm_pc_is_thumb (gdbarch, pc))
     return thumb_analyze_prologue (gdbarch, pc, limit_pc, NULL);
 
   for (skip_pc = pc; skip_pc < limit_pc; skip_pc += 4)
@@ -707,12 +1310,12 @@ thumb_scan_prologue (struct gdbarch *gdbarch, CORE_ADDR prev_pc,
   if (find_pc_partial_function (block_addr, NULL, &prologue_start,
                                &prologue_end))
     {
-      struct symtab_and_line sal = find_pc_line (prologue_start, 0);
-
-      if (sal.line == 0)               /* no line info, use current PC  */
-       prologue_end = prev_pc;
-      else if (sal.end < prologue_end) /* next line begins after fn end */
-       prologue_end = sal.end;         /* (probably means no prologue)  */
+      /* See comment in arm_scan_prologue for an explanation of
+        this heuristics.  */
+      if (prologue_end > prologue_start + 64)
+       {
+         prologue_end = prologue_start + 64;
+       }
     }
   else
     /* We're in the boondocks: we have no idea where the start of the
@@ -724,167 +1327,124 @@ thumb_scan_prologue (struct gdbarch *gdbarch, CORE_ADDR prev_pc,
   thumb_analyze_prologue (gdbarch, prologue_start, prologue_end, cache);
 }
 
-/* This function decodes an ARM function prologue to determine:
-   1) the size of the stack frame
-   2) which registers are saved on it
-   3) the offsets of saved regs
-   4) the offset from the stack pointer to the frame pointer
-   This information is stored in the "extra" fields of the frame_info.
-
-   There are two basic forms for the ARM prologue.  The fixed argument
-   function call will look like:
-
-   mov    ip, sp
-   stmfd  sp!, {fp, ip, lr, pc}
-   sub    fp, ip, #4
-   [sub sp, sp, #4]
-
-   Which would create this stack frame (offsets relative to FP):
-   IP ->   4    (caller's stack)
-   FP ->   0    PC (points to address of stmfd instruction + 8 in callee)
-   -4   LR (return address in caller)
-   -8   IP (copy of caller's SP)
-   -12  FP (caller's FP)
-   SP -> -28    Local variables
-
-   The frame size would thus be 32 bytes, and the frame offset would be
-   28 bytes.  The stmfd call can also save any of the vN registers it
-   plans to use, which increases the frame size accordingly.
-
-   Note: The stored PC is 8 off of the STMFD instruction that stored it
-   because the ARM Store instructions always store PC + 8 when you read
-   the PC register.
-
-   A variable argument function call will look like:
-
-   mov    ip, sp
-   stmfd  sp!, {a1, a2, a3, a4}
-   stmfd  sp!, {fp, ip, lr, pc}
-   sub    fp, ip, #20
-
-   Which would create this stack frame (offsets relative to FP):
-   IP ->  20    (caller's stack)
-   16  A4
-   12  A3
-   8  A2
-   4  A1
-   FP ->   0    PC (points to address of stmfd instruction + 8 in callee)
-   -4   LR (return address in caller)
-   -8   IP (copy of caller's SP)
-   -12  FP (caller's FP)
-   SP -> -28    Local variables
-
-   The frame size would thus be 48 bytes, and the frame offset would be
-   28 bytes.
-
-   There is another potential complication, which is that the optimizer
-   will try to separate the store of fp in the "stmfd" instruction from
-   the "sub fp, ip, #NN" instruction.  Almost anything can be there, so
-   we just key on the stmfd, and then scan for the "sub fp, ip, #NN"...
-
-   Also, note, the original version of the ARM toolchain claimed that there
-   should be an
-
-   instruction at the end of the prologue.  I have never seen GCC produce
-   this, and the ARM docs don't mention it.  We still test for it below in
-   case it happens...
-
- */
+/* Return 1 if THIS_INSTR might change control flow, 0 otherwise.  */
 
-static void
-arm_scan_prologue (struct frame_info *this_frame,
-                  struct arm_prologue_cache *cache)
+static int
+arm_instruction_changes_pc (uint32_t this_instr)
 {
-  struct gdbarch *gdbarch = get_frame_arch (this_frame);
-  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
-  enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
-  int regno;
-  CORE_ADDR prologue_start, prologue_end, current_pc;
-  CORE_ADDR prev_pc = get_frame_pc (this_frame);
-  CORE_ADDR block_addr = get_frame_address_in_block (this_frame);
-  pv_t regs[ARM_FPS_REGNUM];
-  struct pv_area *stack;
-  struct cleanup *back_to;
-  CORE_ADDR offset;
+  if (bits (this_instr, 28, 31) == INST_NV)
+    /* Unconditional instructions.  */
+    switch (bits (this_instr, 24, 27))
+      {
+      case 0xa:
+      case 0xb:
+       /* Branch with Link and change to Thumb.  */
+       return 1;
+      case 0xc:
+      case 0xd:
+      case 0xe:
+       /* Coprocessor register transfer.  */
+        if (bits (this_instr, 12, 15) == 15)
+         error (_("Invalid update to pc in instruction"));
+       return 0;
+      default:
+       return 0;
+      }
+  else
+    switch (bits (this_instr, 25, 27))
+      {
+      case 0x0:
+       if (bits (this_instr, 23, 24) == 2 && bit (this_instr, 20) == 0)
+         {
+           /* Multiplies and extra load/stores.  */
+           if (bit (this_instr, 4) == 1 && bit (this_instr, 7) == 1)
+             /* Neither multiplies nor extension load/stores are allowed
+                to modify PC.  */
+             return 0;
 
-  /* Assume there is no frame until proven otherwise.  */
-  cache->framereg = ARM_SP_REGNUM;
-  cache->framesize = 0;
+           /* Otherwise, miscellaneous instructions.  */
 
-  /* Check for Thumb prologue.  */
-  if (arm_frame_is_thumb (this_frame))
-    {
-      thumb_scan_prologue (gdbarch, prev_pc, block_addr, cache);
-      return;
-    }
+           /* BX <reg>, BXJ <reg>, BLX <reg> */
+           if (bits (this_instr, 4, 27) == 0x12fff1
+               || bits (this_instr, 4, 27) == 0x12fff2
+               || bits (this_instr, 4, 27) == 0x12fff3)
+             return 1;
 
-  /* Find the function prologue.  If we can't find the function in
-     the symbol table, peek in the stack frame to find the PC.  */
-  if (find_pc_partial_function (block_addr, NULL, &prologue_start,
-                               &prologue_end))
-    {
-      /* One way to find the end of the prologue (which works well
-         for unoptimized code) is to do the following:
+           /* Other miscellaneous instructions are unpredictable if they
+              modify PC.  */
+           return 0;
+         }
+       /* Data processing instruction.  Fall through.  */
 
-           struct symtab_and_line sal = find_pc_line (prologue_start, 0);
+      case 0x1:
+       if (bits (this_instr, 12, 15) == 15)
+         return 1;
+       else
+         return 0;
 
-           if (sal.line == 0)
-             prologue_end = prev_pc;
-           else if (sal.end < prologue_end)
-             prologue_end = sal.end;
+      case 0x2:
+      case 0x3:
+       /* Media instructions and architecturally undefined instructions.  */
+       if (bits (this_instr, 25, 27) == 3 && bit (this_instr, 4) == 1)
+         return 0;
 
-        This mechanism is very accurate so long as the optimizer
-        doesn't move any instructions from the function body into the
-        prologue.  If this happens, sal.end will be the last
-        instruction in the first hunk of prologue code just before
-        the first instruction that the scheduler has moved from
-        the body to the prologue.
+       /* Stores.  */
+       if (bit (this_instr, 20) == 0)
+         return 0;
 
-        In order to make sure that we scan all of the prologue
-        instructions, we use a slightly less accurate mechanism which
-        may scan more than necessary.  To help compensate for this
-        lack of accuracy, the prologue scanning loop below contains
-        several clauses which'll cause the loop to terminate early if
-        an implausible prologue instruction is encountered.  
-        
-        The expression
-        
-             prologue_start + 64
-           
-        is a suitable endpoint since it accounts for the largest
-        possible prologue plus up to five instructions inserted by
-        the scheduler.  */
-         
-      if (prologue_end > prologue_start + 64)
-       {
-         prologue_end = prologue_start + 64;   /* See above.  */
-       }
-    }
-  else
-    {
-      /* We have no symbol information.  Our only option is to assume this
-        function has a standard stack frame and the normal frame register.
-        Then, we can find the value of our frame pointer on entrance to
-        the callee (or at the present moment if this is the innermost frame).
-        The value stored there should be the address of the stmfd + 8.  */
-      CORE_ADDR frame_loc;
-      LONGEST return_value;
+       /* Loads.  */
+       if (bits (this_instr, 12, 15) == ARM_PC_REGNUM)
+         return 1;
+       else
+         return 0;
 
-      frame_loc = get_frame_register_unsigned (this_frame, ARM_FP_REGNUM);
-      if (!safe_read_memory_integer (frame_loc, 4, byte_order, &return_value))
-        return;
-      else
-        {
-          prologue_start = gdbarch_addr_bits_remove 
-                            (gdbarch, return_value) - 8;
-          prologue_end = prologue_start + 64;  /* See above.  */
-        }
-    }
+      case 0x4:
+       /* Load/store multiple.  */
+       if (bit (this_instr, 20) == 1 && bit (this_instr, 15) == 1)
+         return 1;
+       else
+         return 0;
 
-  if (prev_pc < prologue_end)
-    prologue_end = prev_pc;
+      case 0x5:
+       /* Branch and branch with link.  */
+       return 1;
+
+      case 0x6:
+      case 0x7:
+       /* Coprocessor transfers or SWIs can not affect PC.  */
+       return 0;
+
+      default:
+       internal_error (__FILE__, __LINE__, "bad value in switch");
+      }
+}
+
+/* Analyze an ARM mode prologue starting at PROLOGUE_START and
+   continuing no further than PROLOGUE_END.  If CACHE is non-NULL,
+   fill it in.  Return the first address not recognized as a prologue
+   instruction.
+
+   We recognize all the instructions typically found in ARM prologues,
+   plus harmless instructions which can be skipped (either for analysis
+   purposes, or a more restrictive set that can be skipped when finding
+   the end of the prologue).  */
+
+static CORE_ADDR
+arm_analyze_prologue (struct gdbarch *gdbarch,
+                     CORE_ADDR prologue_start, CORE_ADDR prologue_end,
+                     struct arm_prologue_cache *cache)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
+  int regno;
+  CORE_ADDR offset, current_pc;
+  pv_t regs[ARM_FPS_REGNUM];
+  struct pv_area *stack;
+  struct cleanup *back_to;
+  int framereg, framesize;
+  CORE_ADDR unrecognized_pc = 0;
 
-  /* Now search the prologue looking for instructions that set up the
+  /* Search the prologue looking for instructions that set up the
      frame pointer, adjust the stack pointer, and save registers.
 
      Be careful, however, and if it doesn't look like a prologue,
@@ -892,18 +1452,7 @@ arm_scan_prologue (struct frame_info *this_frame,
      begins with stmfd sp!, then we will tell ourselves there is
      a frame, which will confuse stack traceback, as well as "finish" 
      and other operations that rely on a knowledge of the stack
-     traceback.
-
-     In the APCS, the prologue should start with  "mov ip, sp" so
-     if we don't see this as the first insn, we will stop.  
-
-     [Note: This doesn't seem to be true any longer, so it's now an
-     optional part of the prologue.  - Kevin Buettner, 2001-11-20]
-
-     [Note further: The "mov ip,sp" only seems to be missing in
-     frameless functions at optimization level "-O2" or above,
-     in which case it is often (but not always) replaced by
-     "str lr, [sp, #-4]!".  - Michael Snyder, 2002-04-23]  */
+     traceback.  */
 
   for (regno = 0; regno < ARM_FPS_REGNUM; regno++)
     regs[regno] = pv_register (regno, 0);
@@ -922,28 +1471,33 @@ arm_scan_prologue (struct frame_info *this_frame,
          regs[ARM_IP_REGNUM] = regs[ARM_SP_REGNUM];
          continue;
        }
-      else if ((insn & 0xfffff000) == 0xe28dc000) /* add ip, sp #n */
+      else if ((insn & 0xfff00000) == 0xe2800000       /* add Rd, Rn, #n */
+              && pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM))
        {
          unsigned imm = insn & 0xff;                   /* immediate value */
          unsigned rot = (insn & 0xf00) >> 7;           /* rotate amount */
+         int rd = bits (insn, 12, 15);
          imm = (imm >> rot) | (imm << (32 - rot));
-         regs[ARM_IP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], imm);
+         regs[rd] = pv_add_constant (regs[bits (insn, 16, 19)], imm);
          continue;
        }
-      else if ((insn & 0xfffff000) == 0xe24dc000) /* sub ip, sp #n */
+      else if ((insn & 0xfff00000) == 0xe2400000       /* sub Rd, Rn, #n */
+              && pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM))
        {
          unsigned imm = insn & 0xff;                   /* immediate value */
          unsigned rot = (insn & 0xf00) >> 7;           /* rotate amount */
+         int rd = bits (insn, 12, 15);
          imm = (imm >> rot) | (imm << (32 - rot));
-         regs[ARM_IP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -imm);
+         regs[rd] = pv_add_constant (regs[bits (insn, 16, 19)], -imm);
          continue;
        }
-      else if (insn == 0xe52de004)     /* str lr, [sp, #-4]! */
+      else if ((insn & 0xffff0fff) == 0xe52d0004)      /* str Rd, [sp, #-4]! */
        {
          if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM]))
            break;
          regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -4);
-         pv_area_store (stack, regs[ARM_SP_REGNUM], 4, regs[ARM_LR_REGNUM]);
+         pv_area_store (stack, regs[ARM_SP_REGNUM], 4,
+                        regs[bits (insn, 12, 15)]);
          continue;
        }
       else if ((insn & 0xffff0000) == 0xe92d0000)
@@ -964,20 +1518,26 @@ arm_scan_prologue (struct frame_info *this_frame,
                pv_area_store (stack, regs[ARM_SP_REGNUM], 4, regs[regno]);
              }
        }
-      else if ((insn & 0xffffc000) == 0xe54b0000       /* strb rx,[r11,#-n] */
-              || (insn & 0xffffc0f0) == 0xe14b00b0     /* strh rx,[r11,#-n] */
+      else if ((insn & 0xffff0000) == 0xe54b0000       /* strb rx,[r11,#-n] */
+              || (insn & 0xffff00f0) == 0xe14b00b0     /* strh rx,[r11,#-n] */
               || (insn & 0xffffc000) == 0xe50b0000)    /* str  rx,[r11,#-n] */
        {
          /* No need to add this to saved_regs -- it's just an arg reg.  */
          continue;
        }
-      else if ((insn & 0xffffc000) == 0xe5cd0000       /* strb rx,[sp,#n] */
-              || (insn & 0xffffc0f0) == 0xe1cd00b0     /* strh rx,[sp,#n] */
+      else if ((insn & 0xffff0000) == 0xe5cd0000       /* strb rx,[sp,#n] */
+              || (insn & 0xffff00f0) == 0xe1cd00b0     /* strh rx,[sp,#n] */
               || (insn & 0xffffc000) == 0xe58d0000)    /* str  rx,[sp,#n] */
        {
          /* No need to add this to saved_regs -- it's just an arg reg.  */
          continue;
        }
+      else if ((insn & 0xfff00000) == 0xe8800000       /* stm Rn, { registers } */
+              && pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM))
+       {
+         /* No need to add this to saved_regs -- it's just arg regs.  */
+         continue;
+       }
       else if ((insn & 0xfffff000) == 0xe24cb000)      /* sub fp, ip #n */
        {
          unsigned imm = insn & 0xff;                   /* immediate value */
@@ -1035,42 +1595,188 @@ arm_scan_prologue (struct frame_info *this_frame,
                             regs[fp_start_reg++]);
            }
        }
+      else if ((insn & 0xff000000) == 0xeb000000 && cache == NULL) /* bl */
+       {
+         /* Allow some special function calls when skipping the
+            prologue; GCC generates these before storing arguments to
+            the stack.  */
+         CORE_ADDR dest = BranchDest (current_pc, insn);
+
+         if (skip_prologue_function (dest))
+           continue;
+         else
+           break;
+       }
       else if ((insn & 0xf0000000) != 0xe0000000)
        break;                  /* Condition not true, exit early */
-      else if ((insn & 0xfe200000) == 0xe8200000)      /* ldm? */
-       break;                  /* Don't scan past a block load */
-      else
-       /* The optimizer might shove anything into the prologue,
-          so we just skip what we don't recognize.  */
+      else if (arm_instruction_changes_pc (insn))
+       /* Don't scan past anything that might change control flow.  */
+       break;
+      else if ((insn & 0xfe500000) == 0xe8100000)      /* ldm */
+       {
+         /* Ignore block loads from the stack, potentially copying
+            parameters from memory.  */
+         if (pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM))
+           continue;
+         else
+           break;
+       }
+      else if ((insn & 0xfc500000) == 0xe4100000)
+       {
+         /* Similarly ignore single loads from the stack.  */
+         if (pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM))
+           continue;
+         else
+           break;
+       }
+      else if ((insn & 0xffff0ff0) == 0xe1a00000)
+       /* MOV Rd, Rm.  Skip register copies, i.e. saves to another
+          register instead of the stack.  */
        continue;
+      else
+       {
+         /* The optimizer might shove anything into the prologue,
+            so we just skip what we don't recognize.  */
+         unrecognized_pc = current_pc;
+         continue;
+       }
     }
 
+  if (unrecognized_pc == 0)
+    unrecognized_pc = current_pc;
+
   /* The frame size is just the distance from the frame register
      to the original stack pointer.  */
   if (pv_is_register (regs[ARM_FP_REGNUM], ARM_SP_REGNUM))
     {
       /* Frame pointer is fp.  */
-      cache->framereg = ARM_FP_REGNUM;
-      cache->framesize = -regs[ARM_FP_REGNUM].k;
+      framereg = ARM_FP_REGNUM;
+      framesize = -regs[ARM_FP_REGNUM].k;
     }
   else if (pv_is_register (regs[ARM_SP_REGNUM], ARM_SP_REGNUM))
     {
       /* Try the stack pointer... this is a bit desperate.  */
-      cache->framereg = ARM_SP_REGNUM;
-      cache->framesize = -regs[ARM_SP_REGNUM].k;
+      framereg = ARM_SP_REGNUM;
+      framesize = -regs[ARM_SP_REGNUM].k;
     }
   else
     {
       /* We're just out of luck.  We don't know where the frame is.  */
-      cache->framereg = -1;
-      cache->framesize = 0;
+      framereg = -1;
+      framesize = 0;
     }
 
-  for (regno = 0; regno < ARM_FPS_REGNUM; regno++)
-    if (pv_area_find_reg (stack, gdbarch, regno, &offset))
-      cache->saved_regs[regno].addr = offset;
+  if (cache)
+    {
+      cache->framereg = framereg;
+      cache->framesize = framesize;
+
+      for (regno = 0; regno < ARM_FPS_REGNUM; regno++)
+       if (pv_area_find_reg (stack, gdbarch, regno, &offset))
+         cache->saved_regs[regno].addr = offset;
+    }
+
+  if (arm_debug)
+    fprintf_unfiltered (gdb_stdlog, "Prologue scan stopped at %s\n",
+                       paddress (gdbarch, unrecognized_pc));
 
   do_cleanups (back_to);
+  return unrecognized_pc;
+}
+
+static void
+arm_scan_prologue (struct frame_info *this_frame,
+                  struct arm_prologue_cache *cache)
+{
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int regno;
+  CORE_ADDR prologue_start, prologue_end, current_pc;
+  CORE_ADDR prev_pc = get_frame_pc (this_frame);
+  CORE_ADDR block_addr = get_frame_address_in_block (this_frame);
+  pv_t regs[ARM_FPS_REGNUM];
+  struct pv_area *stack;
+  struct cleanup *back_to;
+  CORE_ADDR offset;
+
+  /* Assume there is no frame until proven otherwise.  */
+  cache->framereg = ARM_SP_REGNUM;
+  cache->framesize = 0;
+
+  /* Check for Thumb prologue.  */
+  if (arm_frame_is_thumb (this_frame))
+    {
+      thumb_scan_prologue (gdbarch, prev_pc, block_addr, cache);
+      return;
+    }
+
+  /* Find the function prologue.  If we can't find the function in
+     the symbol table, peek in the stack frame to find the PC.  */
+  if (find_pc_partial_function (block_addr, NULL, &prologue_start,
+                               &prologue_end))
+    {
+      /* One way to find the end of the prologue (which works well
+         for unoptimized code) is to do the following:
+
+           struct symtab_and_line sal = find_pc_line (prologue_start, 0);
+
+           if (sal.line == 0)
+             prologue_end = prev_pc;
+           else if (sal.end < prologue_end)
+             prologue_end = sal.end;
+
+        This mechanism is very accurate so long as the optimizer
+        doesn't move any instructions from the function body into the
+        prologue.  If this happens, sal.end will be the last
+        instruction in the first hunk of prologue code just before
+        the first instruction that the scheduler has moved from
+        the body to the prologue.
+
+        In order to make sure that we scan all of the prologue
+        instructions, we use a slightly less accurate mechanism which
+        may scan more than necessary.  To help compensate for this
+        lack of accuracy, the prologue scanning loop below contains
+        several clauses which'll cause the loop to terminate early if
+        an implausible prologue instruction is encountered.
+
+        The expression
+
+             prologue_start + 64
+
+        is a suitable endpoint since it accounts for the largest
+        possible prologue plus up to five instructions inserted by
+        the scheduler.  */
+
+      if (prologue_end > prologue_start + 64)
+       {
+         prologue_end = prologue_start + 64;   /* See above.  */
+       }
+    }
+  else
+    {
+      /* We have no symbol information.  Our only option is to assume this
+        function has a standard stack frame and the normal frame register.
+        Then, we can find the value of our frame pointer on entrance to
+        the callee (or at the present moment if this is the innermost frame).
+        The value stored there should be the address of the stmfd + 8.  */
+      CORE_ADDR frame_loc;
+      LONGEST return_value;
+
+      frame_loc = get_frame_register_unsigned (this_frame, ARM_FP_REGNUM);
+      if (!safe_read_memory_integer (frame_loc, 4, byte_order, &return_value))
+        return;
+      else
+        {
+          prologue_start = gdbarch_addr_bits_remove
+                            (gdbarch, return_value) - 8;
+          prologue_end = prologue_start + 64;  /* See above.  */
+        }
+    }
+
+  if (prev_pc < prologue_end)
+    prologue_end = prev_pc;
+
+  arm_analyze_prologue (gdbarch, prologue_start, prologue_end, cache);
 }
 
 static struct arm_prologue_cache *
@@ -1173,13 +1879,14 @@ arm_prologue_prev_register (struct frame_info *this_frame,
   if (prev_regnum == ARM_PS_REGNUM)
     {
       CORE_ADDR lr, cpsr;
+      ULONGEST t_bit = arm_psr_thumb_bit (gdbarch);
 
       cpsr = get_frame_register_unsigned (this_frame, prev_regnum);
       lr = frame_unwind_register_unsigned (this_frame, ARM_LR_REGNUM);
       if (IS_THUMB_ADDR (lr))
-       cpsr |= CPSR_T;
+       cpsr |= t_bit;
       else
-       cpsr &= ~CPSR_T;
+       cpsr &= ~t_bit;
       return frame_unwind_got_constant (this_frame, prev_regnum, cpsr);
     }
 
@@ -1198,9 +1905,7 @@ struct frame_unwind arm_prologue_unwind = {
 static struct arm_prologue_cache *
 arm_make_stub_cache (struct frame_info *this_frame)
 {
-  int reg;
   struct arm_prologue_cache *cache;
-  CORE_ADDR unwound_fp;
 
   cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache);
   cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
@@ -1308,6 +2013,7 @@ arm_dwarf2_prev_register (struct frame_info *this_frame, void **this_cache,
 {
   struct gdbarch * gdbarch = get_frame_arch (this_frame);
   CORE_ADDR lr, cpsr;
+  ULONGEST t_bit = arm_psr_thumb_bit (gdbarch);
 
   switch (regnum)
     {
@@ -1325,9 +2031,9 @@ arm_dwarf2_prev_register (struct frame_info *this_frame, void **this_cache,
       cpsr = get_frame_register_unsigned (this_frame, regnum);
       lr = frame_unwind_register_unsigned (this_frame, ARM_LR_REGNUM);
       if (IS_THUMB_ADDR (lr))
-       cpsr |= CPSR_T;
+       cpsr |= t_bit;
       else
-       cpsr &= ~CPSR_T;
+       cpsr &= ~t_bit;
       return frame_unwind_got_constant (this_frame, regnum, cpsr);
 
     default:
@@ -1354,18 +2060,215 @@ arm_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
     }
 }
 
-/* When arguments must be pushed onto the stack, they go on in reverse
-   order.  The code below implements a FILO (stack) to do this.  */
+/* Return true if we are in the function's epilogue, i.e. after the
+   instruction that destroyed the function's stack frame.  */
 
-struct stack_item
+static int
+thumb_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
 {
-  int len;
+  enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
+  unsigned int insn, insn2;
+  int found_return = 0, found_stack_adjust = 0;
+  CORE_ADDR func_start, func_end;
+  CORE_ADDR scan_pc;
+  gdb_byte buf[4];
+
+  if (!find_pc_partial_function (pc, NULL, &func_start, &func_end))
+    return 0;
+
+  /* The epilogue is a sequence of instructions along the following lines:
+
+    - add stack frame size to SP or FP
+    - [if frame pointer used] restore SP from FP
+    - restore registers from SP [may include PC]
+    - a return-type instruction [if PC wasn't already restored]
+
+    In a first pass, we scan forward from the current PC and verify the
+    instructions we find as compatible with this sequence, ending in a
+    return instruction.
+
+    However, this is not sufficient to distinguish indirect function calls
+    within a function from indirect tail calls in the epilogue in some cases.
+    Therefore, if we didn't already find any SP-changing instruction during
+    forward scan, we add a backward scanning heuristic to ensure we actually
+    are in the epilogue.  */
+
+  scan_pc = pc;
+  while (scan_pc < func_end && !found_return)
+    {
+      if (target_read_memory (scan_pc, buf, 2))
+       break;
+
+      scan_pc += 2;
+      insn = extract_unsigned_integer (buf, 2, byte_order_for_code);
+
+      if ((insn & 0xff80) == 0x4700)  /* bx <Rm> */
+       found_return = 1;
+      else if (insn == 0x46f7)  /* mov pc, lr */
+       found_return = 1;
+      else if (insn == 0x46bd)  /* mov sp, r7 */
+       found_stack_adjust = 1;
+      else if ((insn & 0xff00) == 0xb000)  /* add sp, imm or sub sp, imm  */
+       found_stack_adjust = 1;
+      else if ((insn & 0xfe00) == 0xbc00)  /* pop <registers> */
+       {
+         found_stack_adjust = 1;
+         if (insn & 0x0100)  /* <registers> include PC.  */
+           found_return = 1;
+       }
+      else if ((insn & 0xe000) == 0xe000)  /* 32-bit Thumb-2 instruction */
+       {
+         if (target_read_memory (scan_pc, buf, 2))
+           break;
+
+         scan_pc += 2;
+         insn2 = extract_unsigned_integer (buf, 2, byte_order_for_code);
+
+         if (insn == 0xe8bd)  /* ldm.w sp!, <registers> */
+           {
+             found_stack_adjust = 1;
+             if (insn2 & 0x8000)  /* <registers> include PC.  */
+               found_return = 1;
+           }
+         else if (insn == 0xf85d  /* ldr.w <Rt>, [sp], #4 */
+                  && (insn2 & 0x0fff) == 0x0b04)
+           {
+             found_stack_adjust = 1;
+             if ((insn2 & 0xf000) == 0xf000) /* <Rt> is PC.  */
+               found_return = 1;
+           }
+         else if ((insn & 0xffbf) == 0xecbd  /* vldm sp!, <list> */
+                  && (insn2 & 0x0e00) == 0x0a00)
+           found_stack_adjust = 1;
+         else
+           break;
+       }
+      else
+       break;
+    }
+
+  if (!found_return)
+    return 0;
+
+  /* Since any instruction in the epilogue sequence, with the possible
+     exception of return itself, updates the stack pointer, we need to
+     scan backwards for at most one instruction.  Try either a 16-bit or
+     a 32-bit instruction.  This is just a heuristic, so we do not worry
+     too much about false positives.*/
+
+  if (!found_stack_adjust)
+    {
+      if (pc - 4 < func_start)
+       return 0;
+      if (target_read_memory (pc - 4, buf, 4))
+       return 0;
+
+      insn = extract_unsigned_integer (buf, 2, byte_order_for_code);
+      insn2 = extract_unsigned_integer (buf + 2, 2, byte_order_for_code);
+
+      if (insn2 == 0x46bd)  /* mov sp, r7 */
+       found_stack_adjust = 1;
+      else if ((insn2 & 0xff00) == 0xb000)  /* add sp, imm or sub sp, imm  */
+       found_stack_adjust = 1;
+      else if ((insn2 & 0xff00) == 0xbc00)  /* pop <registers> without PC */
+       found_stack_adjust = 1;
+      else if (insn == 0xe8bd)  /* ldm.w sp!, <registers> */
+       found_stack_adjust = 1;
+      else if (insn == 0xf85d  /* ldr.w <Rt>, [sp], #4 */
+              && (insn2 & 0x0fff) == 0x0b04)
+       found_stack_adjust = 1;
+      else if ((insn & 0xffbf) == 0xecbd  /* vldm sp!, <list> */
+              && (insn2 & 0x0e00) == 0x0a00)
+       found_stack_adjust = 1;
+    }
+
+  return found_stack_adjust;
+}
+
+/* Return true if we are in the function's epilogue, i.e. after the
+   instruction that destroyed the function's stack frame.  */
+
+static int
+arm_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
+  unsigned int insn;
+  int found_return, found_stack_adjust;
+  CORE_ADDR func_start, func_end;
+
+  if (arm_pc_is_thumb (gdbarch, pc))
+    return thumb_in_function_epilogue_p (gdbarch, pc);
+
+  if (!find_pc_partial_function (pc, NULL, &func_start, &func_end))
+    return 0;
+
+  /* We are in the epilogue if the previous instruction was a stack
+     adjustment and the next instruction is a possible return (bx, mov
+     pc, or pop).  We could have to scan backwards to find the stack
+     adjustment, or forwards to find the return, but this is a decent
+     approximation.  First scan forwards.  */
+
+  found_return = 0;
+  insn = read_memory_unsigned_integer (pc, 4, byte_order_for_code);
+  if (bits (insn, 28, 31) != INST_NV)
+    {
+      if ((insn & 0x0ffffff0) == 0x012fff10)
+       /* BX.  */
+       found_return = 1;
+      else if ((insn & 0x0ffffff0) == 0x01a0f000)
+       /* MOV PC.  */
+       found_return = 1;
+      else if ((insn & 0x0fff0000) == 0x08bd0000
+         && (insn & 0x0000c000) != 0)
+       /* POP (LDMIA), including PC or LR.  */
+       found_return = 1;
+    }
+
+  if (!found_return)
+    return 0;
+
+  /* Scan backwards.  This is just a heuristic, so do not worry about
+     false positives from mode changes.  */
+
+  if (pc < func_start + 4)
+    return 0;
+
+  insn = read_memory_unsigned_integer (pc - 4, 4, byte_order_for_code);
+  if (bits (insn, 28, 31) != INST_NV)
+    {
+      if ((insn & 0x0df0f000) == 0x0080d000)
+       /* ADD SP (register or immediate).  */
+       found_stack_adjust = 1;
+      else if ((insn & 0x0df0f000) == 0x0040d000)
+       /* SUB SP (register or immediate).  */
+       found_stack_adjust = 1;
+      else if ((insn & 0x0ffffff0) == 0x01a0d000)
+       /* MOV SP.  */
+       found_return = 1;
+      else if ((insn & 0x0fff0000) == 0x08bd0000)
+       /* POP (LDMIA).  */
+       found_stack_adjust = 1;
+    }
+
+  if (found_stack_adjust)
+    return 1;
+
+  return 0;
+}
+
+
+/* When arguments must be pushed onto the stack, they go on in reverse
+   order.  The code below implements a FILO (stack) to do this.  */
+
+struct stack_item
+{
+  int len;
   struct stack_item *prev;
   void *data;
 };
 
 static struct stack_item *
-push_stack_item (struct stack_item *prev, void *contents, int len)
+push_stack_item (struct stack_item *prev, const void *contents, int len)
 {
   struct stack_item *si;
   si = xmalloc (sizeof (struct stack_item));
@@ -1676,7 +2579,7 @@ arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 
   /* Set the return address.  For the ARM, the return breakpoint is
      always at BP_ADDR.  */
-  if (arm_pc_is_thumb (bp_addr))
+  if (arm_pc_is_thumb (gdbarch, bp_addr))
     bp_addr |= 1;
   regcache_cooked_write_unsigned (regcache, ARM_LR_REGNUM, bp_addr);
 
@@ -1706,7 +2609,7 @@ arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
       struct type *arg_type;
       struct type *target_type;
       enum type_code typecode;
-      bfd_byte *val;
+      const bfd_byte *val;
       int align;
       enum arm_vfp_cprc_base_type vfp_base_type;
       int vfp_base_count;
@@ -1716,7 +2619,7 @@ arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
       len = TYPE_LENGTH (arg_type);
       target_type = TYPE_TARGET_TYPE (arg_type);
       typecode = TYPE_CODE (arg_type);
-      val = value_contents_writeable (args[argnum]);
+      val = value_contents (args[argnum]);
 
       align = arm_type_align (arg_type);
       /* Round alignment up to a whole number of words.  */
@@ -1812,14 +2715,15 @@ arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
         the THUMB bit in it.  */
       if (TYPE_CODE_PTR == typecode
          && target_type != NULL
-         && TYPE_CODE_FUNC == TYPE_CODE (target_type))
+         && TYPE_CODE_FUNC == TYPE_CODE (check_typedef (target_type)))
        {
          CORE_ADDR regval = extract_unsigned_integer (val, len, byte_order);
-         if (arm_pc_is_thumb (regval))
+         if (arm_pc_is_thumb (gdbarch, regval))
            {
-             val = alloca (len);
-             store_unsigned_integer (val, len, byte_order,
+             bfd_byte *copy = alloca (len);
+             store_unsigned_integer (copy, len, byte_order,
                                      MAKE_THUMB_ADDR (regval));
+             val = copy;
            }
        }
 
@@ -2233,16 +3137,6 @@ condition_true (unsigned long cond, unsigned long status_reg)
   return 1;
 }
 
-/* Support routines for single stepping.  Calculate the next PC value.  */
-#define submask(x) ((1L << ((x) + 1)) - 1)
-#define bit(obj,st) (((obj) >> (st)) & 1)
-#define bits(obj,st,fn) (((obj) >> (st)) & submask ((fn) - (st)))
-#define sbits(obj,st,fn) \
-  ((long) (bits(obj,st,fn) | ((long) bit(obj,fn) * ~ submask (fn - st))))
-#define BranchDest(addr,instr) \
-  ((CORE_ADDR) (((long) (addr)) + 8 + (sbits (instr, 0, 23) << 2)))
-#define ARM_PC_32 1
-
 static unsigned long
 shifted_reg_val (struct frame_info *frame, unsigned long inst, int carry,
                 unsigned long pc_val, unsigned long status_reg)
@@ -2261,8 +3155,7 @@ shifted_reg_val (struct frame_info *frame, unsigned long inst, int carry,
     shift = bits (inst, 7, 11);
 
   res = (rm == 15
-        ? ((pc_val | (ARM_PC_32 ? 0 : status_reg))
-           + (bit (inst, 4) ? 12 : 8))
+        ? (pc_val + (bit (inst, 4) ? 12 : 8))
         : get_frame_register_unsigned (frame, rm));
 
   switch (shifttype)
@@ -2486,7 +3379,16 @@ thumb_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc, int insert_bkpt)
   else if ((inst1 & 0xf000) == 0xd000) /* conditional branch */
     {
       unsigned long cond = bits (inst1, 8, 11);
-      if (cond != 0x0f && condition_true (cond, status))    /* 0x0f = SWI */
+      if (cond == 0x0f)  /* 0x0f = SWI */
+       {
+         struct gdbarch_tdep *tdep;
+         tdep = gdbarch_tdep (gdbarch);
+
+         if (tdep->syscall_next_pc != NULL)
+           nextpc = tdep->syscall_next_pc (frame);
+
+       }
+      else if (cond != 0x0f && condition_true (cond, status))
        nextpc = pc_val + (sbits (inst1, 0, 7) << 1);
     }
   else if ((inst1 & 0xf800) == 0xe000) /* unconditional branch */
@@ -2638,19 +3540,29 @@ thumb_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc, int insert_bkpt)
       else if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf000)
        {
          /* TBB.  */
-         CORE_ADDR table, offset, length;
+         CORE_ADDR tbl_reg, table, offset, length;
+
+         tbl_reg = bits (inst1, 0, 3);
+         if (tbl_reg == 0x0f)
+           table = pc + 4;  /* Regcache copy of PC isn't right yet.  */
+         else
+           table = get_frame_register_unsigned (frame, tbl_reg);
 
-         table = get_frame_register_unsigned (frame, bits (inst1, 0, 3));
          offset = get_frame_register_unsigned (frame, bits (inst2, 0, 3));
          length = 2 * get_frame_memory_unsigned (frame, table + offset, 1);
          nextpc = pc_val + length;
        }
-      else if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf000)
+      else if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf010)
        {
          /* TBH.  */
-         CORE_ADDR table, offset, length;
+         CORE_ADDR tbl_reg, table, offset, length;
+
+         tbl_reg = bits (inst1, 0, 3);
+         if (tbl_reg == 0x0f)
+           table = pc + 4;  /* Regcache copy of PC isn't right yet.  */
+         else
+           table = get_frame_register_unsigned (frame, tbl_reg);
 
-         table = get_frame_register_unsigned (frame, bits (inst1, 0, 3));
          offset = 2 * get_frame_register_unsigned (frame, bits (inst2, 0, 3));
          length = 2 * get_frame_memory_unsigned (frame, table + offset, 2);
          nextpc = pc_val + length;
@@ -2663,6 +3575,15 @@ thumb_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc, int insert_bkpt)
       else
        nextpc = get_frame_register_unsigned (frame, bits (inst1, 3, 6));
     }
+  else if ((inst1 & 0xff87) == 0x4687) /* mov pc, REG */
+    {
+      if (bits (inst1, 3, 6) == 0x0f)
+       nextpc = pc_val;
+      else
+       nextpc = get_frame_register_unsigned (frame, bits (inst1, 3, 6));
+
+      nextpc = MAKE_THUMB_ADDR (nextpc);
+    }
   else if ((inst1 & 0xf500) == 0xb100)
     {
       /* CBNZ or CBZ.  */
@@ -2925,7 +3846,16 @@ arm_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc, int insert_bkpt)
        case 0xc:
        case 0xd:
        case 0xe:               /* coproc ops */
+         break;
        case 0xf:               /* SWI */
+         {
+           struct gdbarch_tdep *tdep;
+           tdep = gdbarch_tdep (gdbarch);
+
+           if (tdep->syscall_next_pc != NULL)
+             nextpc = tdep->syscall_next_pc (frame);
+
+         }
          break;
 
        default:
@@ -3020,7 +3950,7 @@ arm_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr)
     return bpaddr;
 
   /* ARM mode does not have this problem.  */
-  if (!arm_pc_is_thumb (bpaddr))
+  if (!arm_pc_is_thumb (gdbarch, bpaddr))
     return bpaddr;
 
   /* We are setting a breakpoint in Thumb code that could potentially
@@ -3211,10 +4141,11 @@ static int
 displaced_in_arm_mode (struct regcache *regs)
 {
   ULONGEST ps;
+  ULONGEST t_bit = arm_psr_thumb_bit (get_regcache_arch (regs));
 
   regcache_cooked_read_unsigned (regs, ARM_PS_REGNUM, &ps);
 
-  return (ps & CPSR_T) == 0;
+  return (ps & t_bit) == 0;
 }
 
 /* Write to the PC as from a branch instruction.  */
@@ -3236,18 +4167,18 @@ static void
 bx_write_pc (struct regcache *regs, ULONGEST val)
 {
   ULONGEST ps;
+  ULONGEST t_bit = arm_psr_thumb_bit (get_regcache_arch (regs));
 
   regcache_cooked_read_unsigned (regs, ARM_PS_REGNUM, &ps);
 
   if ((val & 1) == 1)
     {
-      regcache_cooked_write_unsigned (regs, ARM_PS_REGNUM, ps | CPSR_T);
+      regcache_cooked_write_unsigned (regs, ARM_PS_REGNUM, ps | t_bit);
       regcache_cooked_write_unsigned (regs, ARM_PC_REGNUM, val & 0xfffffffe);
     }
   else if ((val & 2) == 0)
     {
-      regcache_cooked_write_unsigned (regs, ARM_PS_REGNUM,
-                                     ps & ~(ULONGEST) CPSR_T);
+      regcache_cooked_write_unsigned (regs, ARM_PS_REGNUM, ps & ~t_bit);
       regcache_cooked_write_unsigned (regs, ARM_PC_REGNUM, val);
     }
   else
@@ -3255,8 +4186,7 @@ bx_write_pc (struct regcache *regs, ULONGEST val)
       /* Unpredictable behaviour.  Try to do something sensible (switch to ARM
          mode, align dest to 4 bytes).  */
       warning (_("Single-stepping BX to non-word-aligned ARM instruction."));
-      regcache_cooked_write_unsigned (regs, ARM_PS_REGNUM,
-                                     ps & ~(ULONGEST) CPSR_T);
+      regcache_cooked_write_unsigned (regs, ARM_PS_REGNUM, ps & ~t_bit);
       regcache_cooked_write_unsigned (regs, ARM_PC_REGNUM, val & 0xfffffffc);
     }
 }
@@ -3371,7 +4301,7 @@ insn_references_pc (uint32_t insn, uint32_t bitmask)
    matter what address they are executed at: in those cases, use this.  */
 
 static int
-copy_unmodified (struct gdbarch *gdbarch ATTRIBUTE_UNUSED, uint32_t insn,
+copy_unmodified (struct gdbarch *gdbarch, uint32_t insn,
                 const char *iname, struct displaced_step_closure *dsc)
 {
   if (debug_displaced)
@@ -3387,7 +4317,7 @@ copy_unmodified (struct gdbarch *gdbarch ATTRIBUTE_UNUSED, uint32_t insn,
 /* Preload instructions with immediate offset.  */
 
 static void
-cleanup_preload (struct gdbarch *gdbarch ATTRIBUTE_UNUSED,
+cleanup_preload (struct gdbarch *gdbarch,
                 struct regcache *regs, struct displaced_step_closure *dsc)
 {
   displaced_write_reg (regs, dsc, 0, dsc->tmp[0], CANNOT_WRITE_PC);
@@ -3472,7 +4402,7 @@ copy_preload_reg (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
 /* Copy/cleanup coprocessor load and store instructions.  */
 
 static void
-cleanup_copro_load_store (struct gdbarch *gdbarch ATTRIBUTE_UNUSED,
+cleanup_copro_load_store (struct gdbarch *gdbarch,
                          struct regcache *regs,
                          struct displaced_step_closure *dsc)
 {
@@ -3526,7 +4456,7 @@ copy_copro_load_store (struct gdbarch *gdbarch, uint32_t insn,
    PC).  */
 
 static void
-cleanup_branch (struct gdbarch *gdbarch ATTRIBUTE_UNUSED, struct regcache *regs,
+cleanup_branch (struct gdbarch *gdbarch, struct regcache *regs,
                struct displaced_step_closure *dsc)
 {
   ULONGEST from = dsc->insn_addr;
@@ -3550,7 +4480,7 @@ cleanup_branch (struct gdbarch *gdbarch ATTRIBUTE_UNUSED, struct regcache *regs,
 /* Copy B/BL/BLX instructions with immediate destinations.  */
 
 static int
-copy_b_bl_blx (struct gdbarch *gdbarch ATTRIBUTE_UNUSED, uint32_t insn,
+copy_b_bl_blx (struct gdbarch *gdbarch, uint32_t insn,
               struct regcache *regs, struct displaced_step_closure *dsc)
 {
   unsigned int cond = bits (insn, 28, 31);
@@ -3597,7 +4527,7 @@ copy_b_bl_blx (struct gdbarch *gdbarch ATTRIBUTE_UNUSED, uint32_t insn,
 /* Copy BX/BLX with register-specified destinations.  */
 
 static int
-copy_bx_blx_reg (struct gdbarch *gdbarch ATTRIBUTE_UNUSED, uint32_t insn,
+copy_bx_blx_reg (struct gdbarch *gdbarch, uint32_t insn,
                 struct regcache *regs, struct displaced_step_closure *dsc)
 {
   unsigned int cond = bits (insn, 28, 31);
@@ -3635,7 +4565,7 @@ copy_bx_blx_reg (struct gdbarch *gdbarch ATTRIBUTE_UNUSED, uint32_t insn,
 /* Copy/cleanup arithmetic/logic instruction with immediate RHS. */
 
 static void
-cleanup_alu_imm (struct gdbarch *gdbarch ATTRIBUTE_UNUSED,
+cleanup_alu_imm (struct gdbarch *gdbarch,
                 struct regcache *regs, struct displaced_step_closure *dsc)
 {
   ULONGEST rd_val = displaced_read_reg (regs, dsc->insn_addr, 0);
@@ -3696,7 +4626,7 @@ copy_alu_imm (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
 /* Copy/cleanup arithmetic/logic insns with register RHS.  */
 
 static void
-cleanup_alu_reg (struct gdbarch *gdbarch ATTRIBUTE_UNUSED,
+cleanup_alu_reg (struct gdbarch *gdbarch,
                 struct regcache *regs, struct displaced_step_closure *dsc)
 {
   ULONGEST rd_val;
@@ -3765,7 +4695,7 @@ copy_alu_reg (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
 /* Cleanup/copy arithmetic/logic insns with shifted register RHS.  */
 
 static void
-cleanup_alu_shifted_reg (struct gdbarch *gdbarch ATTRIBUTE_UNUSED,
+cleanup_alu_shifted_reg (struct gdbarch *gdbarch,
                         struct regcache *regs,
                         struct displaced_step_closure *dsc)
 {
@@ -3839,7 +4769,7 @@ copy_alu_shifted_reg (struct gdbarch *gdbarch, uint32_t insn,
 /* Clean up load instructions.  */
 
 static void
-cleanup_load (struct gdbarch *gdbarch ATTRIBUTE_UNUSED, struct regcache *regs,
+cleanup_load (struct gdbarch *gdbarch, struct regcache *regs,
              struct displaced_step_closure *dsc)
 {
   ULONGEST rt_val, rt_val2 = 0, rn_val;
@@ -3869,7 +4799,7 @@ cleanup_load (struct gdbarch *gdbarch ATTRIBUTE_UNUSED, struct regcache *regs,
 /* Clean up store instructions.  */
 
 static void
-cleanup_store (struct gdbarch *gdbarch ATTRIBUTE_UNUSED, struct regcache *regs,
+cleanup_store (struct gdbarch *gdbarch, struct regcache *regs,
               struct displaced_step_closure *dsc)
 {
   CORE_ADDR from = dsc->insn_addr;
@@ -4202,7 +5132,7 @@ cleanup_block_store_pc (struct gdbarch *gdbarch, struct regcache *regs,
    must undo that here.  */
 
 static void
-cleanup_block_load_pc (struct gdbarch *gdbarch ATTRIBUTE_UNUSED,
+cleanup_block_load_pc (struct gdbarch *gdbarch,
                       struct regcache *regs,
                       struct displaced_step_closure *dsc)
 {
@@ -4398,7 +5328,7 @@ copy_block_xfer (struct gdbarch *gdbarch, uint32_t insn, struct regcache *regs,
    for Linux, where some SVC instructions must be treated specially.  */
 
 static void
-cleanup_svc (struct gdbarch *gdbarch ATTRIBUTE_UNUSED, struct regcache *regs,
+cleanup_svc (struct gdbarch *gdbarch, struct regcache *regs,
             struct displaced_step_closure *dsc)
 {
   CORE_ADDR from = dsc->insn_addr;
@@ -4442,7 +5372,7 @@ copy_svc (struct gdbarch *gdbarch, uint32_t insn, CORE_ADDR to,
 /* Copy undefined instructions.  */
 
 static int
-copy_undef (struct gdbarch *gdbarch ATTRIBUTE_UNUSED, uint32_t insn,
+copy_undef (struct gdbarch *gdbarch, uint32_t insn,
            struct displaced_step_closure *dsc)
 {
   if (debug_displaced)
@@ -4457,7 +5387,7 @@ copy_undef (struct gdbarch *gdbarch ATTRIBUTE_UNUSED, uint32_t insn,
 /* Copy unpredictable instructions.  */
 
 static int
-copy_unpred (struct gdbarch *gdbarch ATTRIBUTE_UNUSED, uint32_t insn,
+copy_unpred (struct gdbarch *gdbarch, uint32_t insn,
             struct displaced_step_closure *dsc)
 {
   if (debug_displaced)
@@ -5013,7 +5943,9 @@ arm_displaced_step_fixup (struct gdbarch *gdbarch,
 static int
 gdb_print_insn_arm (bfd_vma memaddr, disassemble_info *info)
 {
-  if (arm_pc_is_thumb (memaddr))
+  struct gdbarch *gdbarch = info->application_data;
+
+  if (arm_pc_is_thumb (gdbarch, memaddr))
     {
       static asymbol *asym;
       static combined_entry_type ce;
@@ -5103,7 +6035,7 @@ arm_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *lenptr)
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
 
-  if (arm_pc_is_thumb (*pcptr))
+  if (arm_pc_is_thumb (gdbarch, *pcptr))
     {
       *pcptr = UNMAKE_THUMB_ADDR (*pcptr);
 
@@ -5142,7 +6074,7 @@ arm_remote_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr,
 
   arm_breakpoint_from_pc (gdbarch, pcptr, kindptr);
 
-  if (arm_pc_is_thumb (*pcptr) && *kindptr == 4)
+  if (arm_pc_is_thumb (gdbarch, *pcptr) && *kindptr == 4)
     /* The documented magic value for a 32-bit Thumb-2 breakpoint, so
        that this is not confused with a 32-bit ARM breakpoint.  */
     *kindptr = 3;
@@ -5887,18 +6819,21 @@ arm_record_special_symbol (struct gdbarch *gdbarch, struct objfile *objfile,
 static void
 arm_write_pc (struct regcache *regcache, CORE_ADDR pc)
 {
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
   regcache_cooked_write_unsigned (regcache, ARM_PC_REGNUM, pc);
 
   /* If necessary, set the T bit.  */
   if (arm_apcs_32)
     {
-      ULONGEST val;
+      ULONGEST val, t_bit;
       regcache_cooked_read_unsigned (regcache, ARM_PS_REGNUM, &val);
-      if (arm_pc_is_thumb (pc))
-       regcache_cooked_write_unsigned (regcache, ARM_PS_REGNUM, val | CPSR_T);
+      t_bit = arm_psr_thumb_bit (gdbarch);
+      if (arm_pc_is_thumb (gdbarch, pc))
+       regcache_cooked_write_unsigned (regcache, ARM_PS_REGNUM,
+                                       val | t_bit);
       else
        regcache_cooked_write_unsigned (regcache, ARM_PS_REGNUM,
-                                       val & ~(ULONGEST) CPSR_T);
+                                       val & ~t_bit);
     }
 }
 
@@ -6079,13 +7014,163 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   enum arm_abi_kind arm_abi = arm_abi_global;
   enum arm_float_model fp_model = arm_fp_model;
   struct tdesc_arch_data *tdesc_data = NULL;
-  int i;
+  int i, is_m = 0;
   int have_vfp_registers = 0, have_vfp_pseudos = 0, have_neon_pseudos = 0;
   int have_neon = 0;
   int have_fpa_registers = 1;
+  const struct target_desc *tdesc = info.target_desc;
+
+  /* If we have an object to base this architecture on, try to determine
+     its ABI.  */
+
+  if (arm_abi == ARM_ABI_AUTO && info.abfd != NULL)
+    {
+      int ei_osabi, e_flags;
+
+      switch (bfd_get_flavour (info.abfd))
+       {
+       case bfd_target_aout_flavour:
+         /* Assume it's an old APCS-style ABI.  */
+         arm_abi = ARM_ABI_APCS;
+         break;
+
+       case bfd_target_coff_flavour:
+         /* Assume it's an old APCS-style ABI.  */
+         /* XXX WinCE?  */
+         arm_abi = ARM_ABI_APCS;
+         break;
+
+       case bfd_target_elf_flavour:
+         ei_osabi = elf_elfheader (info.abfd)->e_ident[EI_OSABI];
+         e_flags = elf_elfheader (info.abfd)->e_flags;
+
+         if (ei_osabi == ELFOSABI_ARM)
+           {
+             /* GNU tools used to use this value, but do not for EABI
+                objects.  There's nowhere to tag an EABI version
+                anyway, so assume APCS.  */
+             arm_abi = ARM_ABI_APCS;
+           }
+         else if (ei_osabi == ELFOSABI_NONE)
+           {
+             int eabi_ver = EF_ARM_EABI_VERSION (e_flags);
+             int attr_arch, attr_profile;
+
+             switch (eabi_ver)
+               {
+               case EF_ARM_EABI_UNKNOWN:
+                 /* Assume GNU tools.  */
+                 arm_abi = ARM_ABI_APCS;
+                 break;
+
+               case EF_ARM_EABI_VER4:
+               case EF_ARM_EABI_VER5:
+                 arm_abi = ARM_ABI_AAPCS;
+                 /* EABI binaries default to VFP float ordering.
+                    They may also contain build attributes that can
+                    be used to identify if the VFP argument-passing
+                    ABI is in use.  */
+                 if (fp_model == ARM_FLOAT_AUTO)
+                   {
+#ifdef HAVE_ELF
+                     switch (bfd_elf_get_obj_attr_int (info.abfd,
+                                                       OBJ_ATTR_PROC,
+                                                       Tag_ABI_VFP_args))
+                       {
+                       case 0:
+                         /* "The user intended FP parameter/result
+                            passing to conform to AAPCS, base
+                            variant".  */
+                         fp_model = ARM_FLOAT_SOFT_VFP;
+                         break;
+                       case 1:
+                         /* "The user intended FP parameter/result
+                            passing to conform to AAPCS, VFP
+                            variant".  */
+                         fp_model = ARM_FLOAT_VFP;
+                         break;
+                       case 2:
+                         /* "The user intended FP parameter/result
+                            passing to conform to tool chain-specific
+                            conventions" - we don't know any such
+                            conventions, so leave it as "auto".  */
+                         break;
+                       default:
+                         /* Attribute value not mentioned in the
+                            October 2008 ABI, so leave it as
+                            "auto".  */
+                         break;
+                       }
+#else
+                     fp_model = ARM_FLOAT_SOFT_VFP;
+#endif
+                   }
+                 break;
+
+               default:
+                 /* Leave it as "auto".  */
+                 warning (_("unknown ARM EABI version 0x%x"), eabi_ver);
+                 break;
+               }
+
+#ifdef HAVE_ELF
+             /* Detect M-profile programs.  This only works if the
+                executable file includes build attributes; GCC does
+                copy them to the executable, but e.g. RealView does
+                not.  */
+             attr_arch = bfd_elf_get_obj_attr_int (info.abfd, OBJ_ATTR_PROC,
+                                                   Tag_CPU_arch);
+             attr_profile = bfd_elf_get_obj_attr_int (info.abfd, OBJ_ATTR_PROC,
+                                                      Tag_CPU_arch_profile);
+             /* GCC specifies the profile for v6-M; RealView only
+                specifies the profile for architectures starting with
+                V7 (as opposed to architectures with a tag
+                numerically greater than TAG_CPU_ARCH_V7).  */
+             if (!tdesc_has_registers (tdesc)
+                 && (attr_arch == TAG_CPU_ARCH_V6_M
+                     || attr_arch == TAG_CPU_ARCH_V6S_M
+                     || attr_profile == 'M'))
+               tdesc = tdesc_arm_with_m;
+#endif
+           }
+
+         if (fp_model == ARM_FLOAT_AUTO)
+           {
+             int e_flags = elf_elfheader (info.abfd)->e_flags;
+
+             switch (e_flags & (EF_ARM_SOFT_FLOAT | EF_ARM_VFP_FLOAT))
+               {
+               case 0:
+                 /* Leave it as "auto".  Strictly speaking this case
+                    means FPA, but almost nobody uses that now, and
+                    many toolchains fail to set the appropriate bits
+                    for the floating-point model they use.  */
+                 break;
+               case EF_ARM_SOFT_FLOAT:
+                 fp_model = ARM_FLOAT_SOFT_FPA;
+                 break;
+               case EF_ARM_VFP_FLOAT:
+                 fp_model = ARM_FLOAT_VFP;
+                 break;
+               case EF_ARM_SOFT_FLOAT | EF_ARM_VFP_FLOAT:
+                 fp_model = ARM_FLOAT_SOFT_VFP;
+                 break;
+               }
+           }
+
+         if (e_flags & EF_ARM_BE8)
+           info.byte_order_for_code = BFD_ENDIAN_LITTLE;
+
+         break;
+
+       default:
+         /* Leave it as "auto".  */
+         break;
+       }
+    }
 
   /* Check any target description for validity.  */
-  if (tdesc_has_registers (info.target_desc))
+  if (tdesc_has_registers (tdesc))
     {
       /* For most registers we require GDB's default names; but also allow
         the numeric names for sp / lr / pc, as a convenience.  */
@@ -6096,10 +7181,17 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       const struct tdesc_feature *feature;
       int valid_p;
 
-      feature = tdesc_find_feature (info.target_desc,
+      feature = tdesc_find_feature (tdesc,
                                    "org.gnu.gdb.arm.core");
       if (feature == NULL)
-       return NULL;
+       {
+         feature = tdesc_find_feature (tdesc,
+                                       "org.gnu.gdb.arm.m-profile");
+         if (feature == NULL)
+           return NULL;
+         else
+           is_m = 1;
+       }
 
       tdesc_data = tdesc_data_alloc ();
 
@@ -6116,8 +7208,12 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       valid_p &= tdesc_numbered_register_choices (feature, tdesc_data,
                                                  ARM_PC_REGNUM,
                                                  arm_pc_names);
-      valid_p &= tdesc_numbered_register (feature, tdesc_data,
-                                         ARM_PS_REGNUM, "cpsr");
+      if (is_m)
+       valid_p &= tdesc_numbered_register (feature, tdesc_data,
+                                           ARM_PS_REGNUM, "xpsr");
+      else
+       valid_p &= tdesc_numbered_register (feature, tdesc_data,
+                                           ARM_PS_REGNUM, "cpsr");
 
       if (!valid_p)
        {
@@ -6125,7 +7221,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
          return NULL;
        }
 
-      feature = tdesc_find_feature (info.target_desc,
+      feature = tdesc_find_feature (tdesc,
                                    "org.gnu.gdb.arm.fpa");
       if (feature != NULL)
        {
@@ -6142,7 +7238,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       else
        have_fpa_registers = 0;
 
-      feature = tdesc_find_feature (info.target_desc,
+      feature = tdesc_find_feature (tdesc,
                                    "org.gnu.gdb.xscale.iwmmxt");
       if (feature != NULL)
        {
@@ -6180,7 +7276,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       /* If we have a VFP unit, check whether the single precision registers
         are present.  If not, then we will synthesize them as pseudo
         registers.  */
-      feature = tdesc_find_feature (info.target_desc,
+      feature = tdesc_find_feature (tdesc,
                                    "org.gnu.gdb.arm.vfp");
       if (feature != NULL)
        {
@@ -6217,7 +7313,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
          /* If we have VFP, also check for NEON.  The architecture allows
             NEON without VFP (integer vector operations only), but GDB
             does not support that.  */
-         feature = tdesc_find_feature (info.target_desc,
+         feature = tdesc_find_feature (tdesc,
                                        "org.gnu.gdb.arm.neon");
          if (feature != NULL)
            {
@@ -6239,134 +7335,6 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
        }
     }
 
-  /* If we have an object to base this architecture on, try to determine
-     its ABI.  */
-
-  if (arm_abi == ARM_ABI_AUTO && info.abfd != NULL)
-    {
-      int ei_osabi, e_flags;
-
-      switch (bfd_get_flavour (info.abfd))
-       {
-       case bfd_target_aout_flavour:
-         /* Assume it's an old APCS-style ABI.  */
-         arm_abi = ARM_ABI_APCS;
-         break;
-
-       case bfd_target_coff_flavour:
-         /* Assume it's an old APCS-style ABI.  */
-         /* XXX WinCE?  */
-         arm_abi = ARM_ABI_APCS;
-         break;
-
-       case bfd_target_elf_flavour:
-         ei_osabi = elf_elfheader (info.abfd)->e_ident[EI_OSABI];
-         e_flags = elf_elfheader (info.abfd)->e_flags;
-
-         if (ei_osabi == ELFOSABI_ARM)
-           {
-             /* GNU tools used to use this value, but do not for EABI
-                objects.  There's nowhere to tag an EABI version
-                anyway, so assume APCS.  */
-             arm_abi = ARM_ABI_APCS;
-           }
-         else if (ei_osabi == ELFOSABI_NONE)
-           {
-             int eabi_ver = EF_ARM_EABI_VERSION (e_flags);
-
-             switch (eabi_ver)
-               {
-               case EF_ARM_EABI_UNKNOWN:
-                 /* Assume GNU tools.  */
-                 arm_abi = ARM_ABI_APCS;
-                 break;
-
-               case EF_ARM_EABI_VER4:
-               case EF_ARM_EABI_VER5:
-                 arm_abi = ARM_ABI_AAPCS;
-                 /* EABI binaries default to VFP float ordering.
-                    They may also contain build attributes that can
-                    be used to identify if the VFP argument-passing
-                    ABI is in use.  */
-                 if (fp_model == ARM_FLOAT_AUTO)
-                   {
-#ifdef HAVE_ELF
-                     switch (bfd_elf_get_obj_attr_int (info.abfd,
-                                                       OBJ_ATTR_PROC,
-                                                       Tag_ABI_VFP_args))
-                       {
-                       case 0:
-                         /* "The user intended FP parameter/result
-                            passing to conform to AAPCS, base
-                            variant".  */
-                         fp_model = ARM_FLOAT_SOFT_VFP;
-                         break;
-                       case 1:
-                         /* "The user intended FP parameter/result
-                            passing to conform to AAPCS, VFP
-                            variant".  */
-                         fp_model = ARM_FLOAT_VFP;
-                         break;
-                       case 2:
-                         /* "The user intended FP parameter/result
-                            passing to conform to tool chain-specific
-                            conventions" - we don't know any such
-                            conventions, so leave it as "auto".  */
-                         break;
-                       default:
-                         /* Attribute value not mentioned in the
-                            October 2008 ABI, so leave it as
-                            "auto".  */
-                         break;
-                       }
-#else
-                     fp_model = ARM_FLOAT_SOFT_VFP;
-#endif
-                   }
-                 break;
-
-               default:
-                 /* Leave it as "auto".  */
-                 warning (_("unknown ARM EABI version 0x%x"), eabi_ver);
-                 break;
-               }
-           }
-
-         if (fp_model == ARM_FLOAT_AUTO)
-           {
-             int e_flags = elf_elfheader (info.abfd)->e_flags;
-
-             switch (e_flags & (EF_ARM_SOFT_FLOAT | EF_ARM_VFP_FLOAT))
-               {
-               case 0:
-                 /* Leave it as "auto".  Strictly speaking this case
-                    means FPA, but almost nobody uses that now, and
-                    many toolchains fail to set the appropriate bits
-                    for the floating-point model they use.  */
-                 break;
-               case EF_ARM_SOFT_FLOAT:
-                 fp_model = ARM_FLOAT_SOFT_FPA;
-                 break;
-               case EF_ARM_VFP_FLOAT:
-                 fp_model = ARM_FLOAT_VFP;
-                 break;
-               case EF_ARM_SOFT_FLOAT | EF_ARM_VFP_FLOAT:
-                 fp_model = ARM_FLOAT_SOFT_VFP;
-                 break;
-               }
-           }
-
-         if (e_flags & EF_ARM_BE8)
-           info.byte_order_for_code = BFD_ENDIAN_LITTLE;
-
-         break;
-
-       default:
-         /* Leave it as "auto".  */
-         break;
-       }
-    }
-
   /* If there is already a candidate, use it.  */
   for (best_arch = gdbarch_list_lookup_by_info (arches, &info);
        best_arch != NULL;
@@ -6385,6 +7353,10 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
         since gdbarches with a different target description are
         automatically disqualified.  */
 
+      /* Do check is_m, though, since it might come from the binary.  */
+      if (is_m != gdbarch_tdep (best_arch->gdbarch)->is_m)
+       continue;
+
       /* Found a match.  */
       break;
     }
@@ -6403,6 +7375,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
      These are gdbarch discriminators, like the OSABI.  */
   tdep->arm_abi = arm_abi;
   tdep->fp_model = fp_model;
+  tdep->is_m = is_m;
   tdep->have_fpa_registers = have_fpa_registers;
   tdep->have_vfp_registers = have_vfp_registers;
   tdep->have_vfp_pseudos = have_vfp_pseudos;
@@ -6468,6 +7441,9 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   /* Advance PC across function entry code.  */
   set_gdbarch_skip_prologue (gdbarch, arm_skip_prologue);
 
+  /* Detect whether PC is in function epilogue.  */
+  set_gdbarch_in_function_epilogue_p (gdbarch, arm_in_function_epilogue_p);
+
   /* Skip trampolines.  */
   set_gdbarch_skip_trampoline_code (gdbarch, arm_skip_stub);
 
@@ -6576,7 +7552,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
     {
       set_tdesc_pseudo_register_name (gdbarch, arm_register_name);
 
-      tdesc_use_registers (gdbarch, info.target_desc, tdesc_data);
+      tdesc_use_registers (gdbarch, tdesc, tdesc_data);
 
       /* Override tdesc_register_type to adjust the types of VFP
         registers for NEON.  */
@@ -6631,6 +7607,9 @@ _initialize_arm_tdep (void)
                                  bfd_target_elf_flavour,
                                  arm_elf_osabi_sniffer);
 
+  /* Initialize the standard target descriptions.  */
+  initialize_tdesc_arm_with_m ();
+
   /* Get the number of possible sets of register names defined in opcodes.  */
   num_disassembly_options = get_arm_regname_num_options ();
 
This page took 0.050311 seconds and 4 git commands to generate.