sim/
[deliverable/binutils-gdb.git] / gdb / arm-tdep.c
index 2cfb5c0281b477a981a92667324810db7c5a2871..3cc8d016a5fbb2c1f85c1740479c4e54b3b0cb90 100644 (file)
@@ -1,13 +1,14 @@
 /* Common target dependent code for GDB on ARM systems.
 
    Copyright (C) 1988, 1989, 1991, 1992, 1993, 1995, 1996, 1998, 1999, 2000,
-   2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   Free Software Foundation, Inc.
 
    This file is part of GDB.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
@@ -16,9 +17,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include <ctype.h>             /* XXX for isupper () */
 
@@ -52,6 +51,7 @@
 #include "elf/arm.h"
 
 #include "gdb_assert.h"
+#include "vec.h"
 
 static int arm_debug;
 
@@ -63,11 +63,26 @@ static int arm_debug;
    MSYMBOL_IS_SPECIAL   Tests the "special" bit in a minimal symbol.  */
 
 #define MSYMBOL_SET_SPECIAL(msym)                                      \
-       MSYMBOL_INFO (msym) = (char *) (((long) MSYMBOL_INFO (msym))    \
-                                       | 0x80000000)
+       MSYMBOL_TARGET_FLAG_1 (msym) = 1
 
 #define MSYMBOL_IS_SPECIAL(msym)                               \
-       (((long) MSYMBOL_INFO (msym) & 0x80000000) != 0)
+       MSYMBOL_TARGET_FLAG_1 (msym)
+
+/* Per-objfile data used for mapping symbols.  */
+static const struct objfile_data *arm_objfile_data_key;
+
+struct arm_mapping_symbol
+{
+  bfd_vma value;
+  char type;
+};
+typedef struct arm_mapping_symbol arm_mapping_symbol_s;
+DEF_VEC_O(arm_mapping_symbol_s);
+
+struct arm_per_objfile
+{
+  VEC(arm_mapping_symbol_s) **section_maps;
+};
 
 /* The list of available "set arm ..." and "show arm ..." commands.  */
 static struct cmd_list_element *setarmcmdlist = NULL;
@@ -102,6 +117,17 @@ static const char *arm_abi_strings[] =
 static enum arm_abi_kind arm_abi_global = ARM_ABI_AUTO;
 static const char *arm_abi_string = "auto";
 
+/* The execution mode to assume.  */
+static const char *arm_mode_strings[] =
+  {
+    "auto",
+    "arm",
+    "thumb"
+  };
+
+static const char *arm_fallback_mode_string = "auto";
+static const char *arm_force_mode_string = "auto";
+
 /* Number of different reg name sets (options).  */
 static int num_disassembly_options;
 
@@ -178,9 +204,16 @@ static void set_disassembly_style_sfunc(char *, int,
 static void set_disassembly_style (void);
 
 static void convert_from_extended (const struct floatformat *, const void *,
-                                  void *);
+                                  void *, int);
 static void convert_to_extended (const struct floatformat *, void *,
-                                const void *);
+                                const void *, int);
+
+static void arm_neon_quad_read (struct gdbarch *gdbarch,
+                               struct regcache *regcache,
+                               int regnum, gdb_byte *buf);
+static void arm_neon_quad_write (struct gdbarch *gdbarch,
+                                struct regcache *regcache,
+                                int regnum, const gdb_byte *buf);
 
 struct arm_prologue_cache
 {
@@ -189,13 +222,11 @@ struct arm_prologue_cache
      to identify this frame.  */
   CORE_ADDR prev_sp;
 
-  /* The frame base for this frame is just prev_sp + frame offset -
-     frame size.  FRAMESIZE is the size of this stack frame, and
-     FRAMEOFFSET if the initial offset from the stack pointer (this
-     frame's stack pointer, not PREV_SP) to the frame base.  */
+  /* The frame base for this frame is just prev_sp - frame size.
+     FRAMESIZE is the distance from the frame pointer to the
+     initial stack pointer.  */
 
   int framesize;
-  int frameoffset;
 
   /* The register used to hold the frame pointer for this frame.  */
   int framereg;
@@ -214,36 +245,121 @@ struct arm_prologue_cache
 
 int arm_apcs_32 = 1;
 
+/* Determine if FRAME is executing in Thumb mode.  */
+
+static int
+arm_frame_is_thumb (struct frame_info *frame)
+{
+  CORE_ADDR cpsr;
+
+  /* Every ARM frame unwinder can unwind the T bit of the CPSR, either
+     directly (from a signal frame or dummy frame) or by interpreting
+     the saved LR (from a prologue or DWARF frame).  So consult it and
+     trust the unwinders.  */
+  cpsr = get_frame_register_unsigned (frame, ARM_PS_REGNUM);
+
+  return (cpsr & CPSR_T) != 0;
+}
+
+/* Callback for VEC_lower_bound.  */
+
+static inline int
+arm_compare_mapping_symbols (const struct arm_mapping_symbol *lhs,
+                            const struct arm_mapping_symbol *rhs)
+{
+  return lhs->value < rhs->value;
+}
+
 /* Determine if the program counter specified in MEMADDR is in a Thumb
-   function.  */
+   function.  This function should be called for addresses unrelated to
+   any executing frame; otherwise, prefer arm_frame_is_thumb.  */
 
 static int
 arm_pc_is_thumb (CORE_ADDR memaddr)
 {
+  struct obj_section *sec;
   struct minimal_symbol *sym;
 
   /* If bit 0 of the address is set, assume this is a Thumb address.  */
   if (IS_THUMB_ADDR (memaddr))
     return 1;
 
+  /* If the user wants to override the symbol table, let him.  */
+  if (strcmp (arm_force_mode_string, "arm") == 0)
+    return 0;
+  if (strcmp (arm_force_mode_string, "thumb") == 0)
+    return 1;
+
+  /* If there are mapping symbols, consult them.  */
+  sec = find_pc_section (memaddr);
+  if (sec != NULL)
+    {
+      struct arm_per_objfile *data;
+      VEC(arm_mapping_symbol_s) *map;
+      struct arm_mapping_symbol map_key = { memaddr - obj_section_addr (sec),
+                                           0 };
+      unsigned int idx;
+
+      data = objfile_data (sec->objfile, arm_objfile_data_key);
+      if (data != NULL)
+       {
+         map = data->section_maps[sec->the_bfd_section->index];
+         if (!VEC_empty (arm_mapping_symbol_s, map))
+           {
+             struct arm_mapping_symbol *map_sym;
+
+             idx = VEC_lower_bound (arm_mapping_symbol_s, map, &map_key,
+                                    arm_compare_mapping_symbols);
+
+             /* VEC_lower_bound finds the earliest ordered insertion
+                point.  If the following symbol starts at this exact
+                address, we use that; otherwise, the preceding
+                mapping symbol covers this address.  */
+             if (idx < VEC_length (arm_mapping_symbol_s, map))
+               {
+                 map_sym = VEC_index (arm_mapping_symbol_s, map, idx);
+                 if (map_sym->value == map_key.value)
+                   return map_sym->type == 't';
+               }
+
+             if (idx > 0)
+               {
+                 map_sym = VEC_index (arm_mapping_symbol_s, map, idx - 1);
+                 return map_sym->type == 't';
+               }
+           }
+       }
+    }
+
   /* Thumb functions have a "special" bit set in minimal symbols.  */
   sym = lookup_minimal_symbol_by_pc (memaddr);
   if (sym)
-    {
-      return (MSYMBOL_IS_SPECIAL (sym));
-    }
-  else
-    {
-      return 0;
-    }
+    return (MSYMBOL_IS_SPECIAL (sym));
+
+  /* If the user wants to override the fallback mode, let them.  */
+  if (strcmp (arm_fallback_mode_string, "arm") == 0)
+    return 0;
+  if (strcmp (arm_fallback_mode_string, "thumb") == 0)
+    return 1;
+
+  /* If we couldn't find any symbol, but we're talking to a running
+     target, then trust the current value of $cpsr.  This lets
+     "display/i $pc" always show the correct mode (though if there is
+     a symbol table we will not reach here, so it still may not be
+     displayed in the mode it will be executed).  */
+  if (target_has_registers)
+    return arm_frame_is_thumb (get_current_frame ());
+
+  /* Otherwise we're out of luck; we assume ARM.  */
+  return 0;
 }
 
 /* Remove useless bits from addresses in a running program.  */
 static CORE_ADDR
-arm_addr_bits_remove (CORE_ADDR val)
+arm_addr_bits_remove (struct gdbarch *gdbarch, CORE_ADDR val)
 {
   if (arm_apcs_32)
-    return (val & (arm_pc_is_thumb (val) ? 0xfffffffe : 0xfffffffc));
+    return UNMAKE_THUMB_ADDR (val);
   else
     return (val & 0x03fffffc);
 }
@@ -251,7 +367,7 @@ arm_addr_bits_remove (CORE_ADDR val)
 /* When reading symbols, we need to zap the low bit of the address,
    which may be set to 1 for Thumb functions.  */
 static CORE_ADDR
-arm_smash_text_address (CORE_ADDR val)
+arm_smash_text_address (struct gdbarch *gdbarch, CORE_ADDR val)
 {
   return val & ~1;
 }
@@ -265,6 +381,7 @@ thumb_analyze_prologue (struct gdbarch *gdbarch,
                        CORE_ADDR start, CORE_ADDR limit,
                        struct arm_prologue_cache *cache)
 {
+  enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
   int i;
   pv_t regs[16];
   struct pv_area *stack;
@@ -273,28 +390,22 @@ thumb_analyze_prologue (struct gdbarch *gdbarch,
 
   for (i = 0; i < 16; i++)
     regs[i] = pv_register (i, 0);
-  stack = make_pv_area (ARM_SP_REGNUM);
+  stack = make_pv_area (ARM_SP_REGNUM, gdbarch_addr_bit (gdbarch));
   back_to = make_cleanup_free_pv_area (stack);
 
-  /* The call instruction saved PC in LR, and the current PC is not
-     interesting.  Due to this file's conventions, we want the value
-     of LR at this function's entry, not at the call site, so we do
-     not record the save of the PC - when the ARM prologue analyzer
-     has also been converted to the pv mechanism, we could record the
-     save here and remove the hack in prev_register.  */
-  regs[ARM_PC_REGNUM] = pv_unknown ();
-
   while (start < limit)
     {
       unsigned short insn;
 
-      insn = read_memory_unsigned_integer (start, 2);
+      insn = read_memory_unsigned_integer (start, 2, byte_order_for_code);
 
       if ((insn & 0xfe00) == 0xb400)           /* push { rlist } */
        {
          int regno;
          int mask;
-         int stop = 0;
+
+         if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM]))
+           break;
 
          /* Bits 0-7 contain a mask for registers R0-R7.  Bit 8 says
             whether to save LR (R14).  */
@@ -304,19 +415,10 @@ thumb_analyze_prologue (struct gdbarch *gdbarch,
          for (regno = ARM_LR_REGNUM; regno >= 0; regno--)
            if (mask & (1 << regno))
              {
-               if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM]))
-                 {
-                   stop = 1;
-                   break;
-                 }
-
                regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
                                                       -4);
                pv_area_store (stack, regs[ARM_SP_REGNUM], 4, regs[regno]);
              }
-
-         if (stop)
-           break;
        }
       else if ((insn & 0xff00) == 0xb000)      /* add sp, #simm  OR  
                                                   sub sp, #simm */
@@ -372,9 +474,6 @@ thumb_analyze_prologue (struct gdbarch *gdbarch,
       return start;
     }
 
-  /* frameoffset is unused for this unwinder.  */
-  cache->frameoffset = 0;
-
   if (pv_is_register (regs[ARM_FP_REGNUM], ARM_SP_REGNUM))
     {
       /* Frame pointer is fp.  Frame size is constant.  */
@@ -424,49 +523,48 @@ thumb_analyze_prologue (struct gdbarch *gdbarch,
    sub fp, ip, #nn @@ nn == 20 or 4 depending on second insn */
 
 static CORE_ADDR
-arm_skip_prologue (CORE_ADDR pc)
+arm_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
 {
+  enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
   unsigned long inst;
   CORE_ADDR skip_pc;
-  CORE_ADDR func_addr, func_end = 0;
-  char *func_name;
+  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 (pc))
+  if (deprecated_pc_in_call_dummy (gdbarch, pc))
     return pc;
 
-  /* See what the symbol table says.  */
-
-  if (find_pc_partial_function (pc, &func_name, &func_addr, &func_end))
+  /* 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.  */
+  if (find_pc_partial_function (pc, NULL, &func_addr, NULL))
     {
-      struct symbol *sym;
-
-      /* Found a function.  */
-      sym = lookup_symbol (func_name, NULL, VAR_DOMAIN, NULL, NULL);
-      if (sym && SYMBOL_LANGUAGE (sym) != language_asm)
-        {
-         /* Don't use this trick for assembly source files.  */
-         sal = find_pc_line (func_addr, 0);
-         if ((sal.line != 0) && (sal.end < func_end))
-           return sal.end;
-        }
+      CORE_ADDR post_prologue_pc
+       = skip_prologue_using_sal (gdbarch, func_addr);
+      if (post_prologue_pc != 0)
+       return max (pc, post_prologue_pc);
     }
 
-  /* Can't find the prologue end in the symbol table, try it the hard way
-     by disassembling the instructions.  */
+  /* Can't determine prologue from the symbol table, need to examine
+     instructions.  */
 
+  /* Find an upper limit on the function prologue using the debug
+     information.  If the debug information could not be used to provide
+     that bound, then use an arbitrary large number as the upper bound.  */
   /* Like arm_scan_prologue, stop no later than pc + 64. */
-  if (func_end == 0 || func_end > pc + 64)
-    func_end = pc + 64;
+  limit_pc = skip_prologue_using_sal (gdbarch, pc);
+  if (limit_pc == 0)
+    limit_pc = pc + 64;          /* Magic.  */
+
 
   /* Check if this is Thumb code.  */
   if (arm_pc_is_thumb (pc))
-    return thumb_analyze_prologue (current_gdbarch, pc, func_end, NULL);
+    return thumb_analyze_prologue (gdbarch, pc, limit_pc, NULL);
 
-  for (skip_pc = pc; skip_pc < func_end; skip_pc += 4)
+  for (skip_pc = pc; skip_pc < limit_pc; skip_pc += 4)
     {
-      inst = read_memory_unsigned_integer (skip_pc, 4);
+      inst = read_memory_unsigned_integer (skip_pc, 4, byte_order_for_code);
 
       /* "mov ip, sp" is no longer a required part of the prologue.  */
       if (inst == 0xe1a0c00d)                  /* mov ip, sp */
@@ -547,22 +645,15 @@ arm_skip_prologue (CORE_ADDR pc)
 /* *INDENT-ON* */
 
 static void
-thumb_scan_prologue (CORE_ADDR prev_pc, struct arm_prologue_cache *cache)
+thumb_scan_prologue (struct gdbarch *gdbarch, CORE_ADDR prev_pc,
+                    CORE_ADDR block_addr, struct arm_prologue_cache *cache)
 {
   CORE_ADDR prologue_start;
   CORE_ADDR prologue_end;
   CORE_ADDR current_pc;
-  /* Which register has been copied to register n?  */
-  int saved_reg[16];
-  /* findmask:
-     bit 0 - push { rlist }
-     bit 1 - mov r7, sp  OR  add r7, sp, #imm  (setting of r7)
-     bit 2 - sub sp, #simm  OR  add sp, #simm  (adjusting of sp)
-  */
-  int findmask = 0;
-  int i;
 
-  if (find_pc_partial_function (prev_pc, NULL, &prologue_start, &prologue_end))
+  if (find_pc_partial_function (block_addr, NULL, &prologue_start,
+                               &prologue_end))
     {
       struct symtab_and_line sal = find_pc_line (prologue_start, 0);
 
@@ -578,8 +669,7 @@ thumb_scan_prologue (CORE_ADDR prev_pc, struct arm_prologue_cache *cache)
 
   prologue_end = min (prologue_end, prev_pc);
 
-  thumb_analyze_prologue (current_gdbarch, prologue_start, prologue_end,
-                         cache);
+  thumb_analyze_prologue (gdbarch, prologue_start, prologue_end, cache);
 }
 
 /* This function decodes an ARM function prologue to determine:
@@ -650,27 +740,36 @@ thumb_scan_prologue (CORE_ADDR prev_pc, struct arm_prologue_cache *cache)
  */
 
 static void
-arm_scan_prologue (struct frame_info *next_frame, struct arm_prologue_cache *cache)
+arm_scan_prologue (struct frame_info *this_frame,
+                  struct arm_prologue_cache *cache)
 {
-  int regno, sp_offset, fp_offset, ip_offset;
+  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 = frame_pc_unwind (next_frame);
+  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;
-  cache->frameoffset = 0;
 
   /* Check for Thumb prologue.  */
-  if (arm_pc_is_thumb (prev_pc))
+  if (arm_frame_is_thumb (this_frame))
     {
-      thumb_scan_prologue (prev_pc, cache);
+      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 (prev_pc, NULL, &prologue_start, &prologue_end))
+  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:
@@ -719,12 +818,13 @@ arm_scan_prologue (struct frame_info *next_frame, struct arm_prologue_cache *cac
       CORE_ADDR frame_loc;
       LONGEST return_value;
 
-      frame_loc = frame_unwind_register_unsigned (next_frame, ARM_FP_REGNUM);
-      if (!safe_read_memory_integer (frame_loc, 4, &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 = ADDR_BITS_REMOVE (return_value) - 8;
+          prologue_start = gdbarch_addr_bits_remove 
+                            (gdbarch, return_value) - 8;
           prologue_end = prologue_start + 64;  /* See above.  */
         }
     }
@@ -753,17 +853,21 @@ arm_scan_prologue (struct frame_info *next_frame, struct arm_prologue_cache *cac
      in which case it is often (but not always) replaced by
      "str lr, [sp, #-4]!".  - Michael Snyder, 2002-04-23]  */
 
-  sp_offset = fp_offset = ip_offset = 0;
+  for (regno = 0; regno < ARM_FPS_REGNUM; regno++)
+    regs[regno] = pv_register (regno, 0);
+  stack = make_pv_area (ARM_SP_REGNUM, gdbarch_addr_bit (gdbarch));
+  back_to = make_cleanup_free_pv_area (stack);
 
   for (current_pc = prologue_start;
        current_pc < prologue_end;
        current_pc += 4)
     {
-      unsigned int insn = read_memory_unsigned_integer (current_pc, 4);
+      unsigned int insn
+       = read_memory_unsigned_integer (current_pc, 4, byte_order_for_code);
 
       if (insn == 0xe1a0c00d)          /* mov ip, sp */
        {
-         ip_offset = 0;
+         regs[ARM_IP_REGNUM] = regs[ARM_SP_REGNUM];
          continue;
        }
       else if ((insn & 0xfffff000) == 0xe28dc000) /* add ip, sp #n */
@@ -771,7 +875,7 @@ arm_scan_prologue (struct frame_info *next_frame, struct arm_prologue_cache *cac
          unsigned imm = insn & 0xff;                   /* immediate value */
          unsigned rot = (insn & 0xf00) >> 7;           /* rotate amount */
          imm = (imm >> rot) | (imm << (32 - rot));
-         ip_offset = imm;
+         regs[ARM_IP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], imm);
          continue;
        }
       else if ((insn & 0xfffff000) == 0xe24dc000) /* sub ip, sp #n */
@@ -779,13 +883,15 @@ arm_scan_prologue (struct frame_info *next_frame, struct arm_prologue_cache *cac
          unsigned imm = insn & 0xff;                   /* immediate value */
          unsigned rot = (insn & 0xf00) >> 7;           /* rotate amount */
          imm = (imm >> rot) | (imm << (32 - rot));
-         ip_offset = -imm;
+         regs[ARM_IP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -imm);
          continue;
        }
       else if (insn == 0xe52de004)     /* str lr, [sp, #-4]! */
        {
-         sp_offset -= 4;
-         cache->saved_regs[ARM_LR_REGNUM].addr = sp_offset;
+         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]);
          continue;
        }
       else if ((insn & 0xffff0000) == 0xe92d0000)
@@ -795,12 +901,15 @@ arm_scan_prologue (struct frame_info *next_frame, struct arm_prologue_cache *cac
        {
          int mask = insn & 0xffff;
 
+         if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM]))
+           break;
+
          /* Calculate offsets of saved registers.  */
          for (regno = ARM_PC_REGNUM; regno >= 0; regno--)
            if (mask & (1 << regno))
              {
-               sp_offset -= 4;
-               cache->saved_regs[regno].addr = sp_offset;
+               regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -4);
+               pv_area_store (stack, regs[ARM_SP_REGNUM], 4, regs[regno]);
              }
        }
       else if ((insn & 0xffffc000) == 0xe54b0000 ||    /* strb rx,[r11,#-n] */
@@ -822,29 +931,34 @@ arm_scan_prologue (struct frame_info *next_frame, struct arm_prologue_cache *cac
          unsigned imm = insn & 0xff;                   /* immediate value */
          unsigned rot = (insn & 0xf00) >> 7;           /* rotate amount */
          imm = (imm >> rot) | (imm << (32 - rot));
-         fp_offset = -imm + ip_offset;
-         cache->framereg = ARM_FP_REGNUM;
+         regs[ARM_FP_REGNUM] = pv_add_constant (regs[ARM_IP_REGNUM], -imm);
        }
       else if ((insn & 0xfffff000) == 0xe24dd000)      /* sub sp, sp #n */
        {
          unsigned imm = insn & 0xff;                   /* immediate value */
          unsigned rot = (insn & 0xf00) >> 7;           /* rotate amount */
          imm = (imm >> rot) | (imm << (32 - rot));
-         sp_offset -= imm;
+         regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -imm);
        }
       else if ((insn & 0xffff7fff) == 0xed6d0103       /* stfe f?, [sp, -#c]! */
-              && gdbarch_tdep (current_gdbarch)->have_fpa_registers)
+              && gdbarch_tdep (gdbarch)->have_fpa_registers)
        {
-         sp_offset -= 12;
+         if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM]))
+           break;
+
+         regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -12);
          regno = ARM_F0_REGNUM + ((insn >> 12) & 0x07);
-         cache->saved_regs[regno].addr = sp_offset;
+         pv_area_store (stack, regs[ARM_SP_REGNUM], 12, regs[regno]);
        }
       else if ((insn & 0xffbf0fff) == 0xec2d0200       /* sfmfd f0, 4, [sp!] */
-              && gdbarch_tdep (current_gdbarch)->have_fpa_registers)
+              && gdbarch_tdep (gdbarch)->have_fpa_registers)
        {
          int n_saved_fp_regs;
          unsigned int fp_start_reg, fp_bound_reg;
 
+         if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM]))
+           break;
+
          if ((insn & 0x800) == 0x800)          /* N0 is set */
            {
              if ((insn & 0x40000) == 0x40000)  /* N1 is set */
@@ -864,8 +978,9 @@ arm_scan_prologue (struct frame_info *next_frame, struct arm_prologue_cache *cac
          fp_bound_reg = fp_start_reg + n_saved_fp_regs;
          for (; fp_start_reg < fp_bound_reg; fp_start_reg++)
            {
-             sp_offset -= 12;
-             cache->saved_regs[fp_start_reg++].addr = sp_offset;
+             regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -12);
+             pv_area_store (stack, regs[ARM_SP_REGNUM], 12,
+                            regs[fp_start_reg++]);
            }
        }
       else if ((insn & 0xf0000000) != 0xe0000000)
@@ -878,37 +993,55 @@ arm_scan_prologue (struct frame_info *next_frame, struct arm_prologue_cache *cac
        continue;
     }
 
-  /* The frame size is just the negative of the offset (from the
-     original SP) of the last thing thing we pushed on the stack. 
-     The frame offset is [new FP] - [new SP].  */
-  cache->framesize = -sp_offset;
-  if (cache->framereg == ARM_FP_REGNUM)
-    cache->frameoffset = fp_offset - sp_offset;
+  /* 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;
+    }
+  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;
+    }
   else
-    cache->frameoffset = 0;
+    {
+      /* We're just out of luck.  We don't know where the frame is.  */
+      cache->framereg = -1;
+      cache->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;
+
+  do_cleanups (back_to);
 }
 
 static struct arm_prologue_cache *
-arm_make_prologue_cache (struct frame_info *next_frame)
+arm_make_prologue_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 (next_frame);
+  cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
 
-  arm_scan_prologue (next_frame, cache);
+  arm_scan_prologue (this_frame, cache);
 
-  unwound_fp = frame_unwind_register_unsigned (next_frame, cache->framereg);
+  unwound_fp = get_frame_register_unsigned (this_frame, cache->framereg);
   if (unwound_fp == 0)
     return cache;
 
-  cache->prev_sp = unwound_fp + cache->framesize - cache->frameoffset;
+  cache->prev_sp = unwound_fp + cache->framesize;
 
   /* Calculate actual addresses of saved registers using offsets
      determined by arm_scan_prologue.  */
-  for (reg = 0; reg < NUM_REGS; reg++)
+  for (reg = 0; reg < gdbarch_num_regs (get_frame_arch (this_frame)); reg++)
     if (trad_frame_addr_p (cache->saved_regs, reg))
       cache->saved_regs[reg].addr += cache->prev_sp;
 
@@ -919,93 +1052,108 @@ arm_make_prologue_cache (struct frame_info *next_frame)
    and the caller's SP when we were called.  */
 
 static void
-arm_prologue_this_id (struct frame_info *next_frame,
+arm_prologue_this_id (struct frame_info *this_frame,
                      void **this_cache,
                      struct frame_id *this_id)
 {
   struct arm_prologue_cache *cache;
   struct frame_id id;
-  CORE_ADDR func;
+  CORE_ADDR pc, func;
 
   if (*this_cache == NULL)
-    *this_cache = arm_make_prologue_cache (next_frame);
+    *this_cache = arm_make_prologue_cache (this_frame);
   cache = *this_cache;
 
-  func = frame_func_unwind (next_frame, NORMAL_FRAME);
-
-  /* This is meant to halt the backtrace at "_start".  Make sure we
-     don't halt it at a generic dummy frame. */
-  if (func <= LOWEST_PC)
+  /* This is meant to halt the backtrace at "_start".  */
+  pc = get_frame_pc (this_frame);
+  if (pc <= gdbarch_tdep (get_frame_arch (this_frame))->lowest_pc)
     return;
 
   /* If we've hit a wall, stop.  */
   if (cache->prev_sp == 0)
     return;
 
+  func = get_frame_func (this_frame);
   id = frame_id_build (cache->prev_sp, func);
   *this_id = id;
 }
 
-static void
-arm_prologue_prev_register (struct frame_info *next_frame,
+static struct value *
+arm_prologue_prev_register (struct frame_info *this_frame,
                            void **this_cache,
-                           int prev_regnum,
-                           int *optimized,
-                           enum lval_type *lvalp,
-                           CORE_ADDR *addrp,
-                           int *realnump,
-                           gdb_byte *valuep)
+                           int prev_regnum)
 {
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
   struct arm_prologue_cache *cache;
 
   if (*this_cache == NULL)
-    *this_cache = arm_make_prologue_cache (next_frame);
+    *this_cache = arm_make_prologue_cache (this_frame);
   cache = *this_cache;
 
   /* If we are asked to unwind the PC, then we need to return the LR
-     instead.  The saved value of PC points into this frame's
-     prologue, not the next frame's resume location.  */
+     instead.  The prologue may save PC, but it will point into this
+     frame's prologue, not the next frame's resume location.  Also
+     strip the saved T bit.  A valid LR may have the low bit set, but
+     a valid PC never does.  */
   if (prev_regnum == ARM_PC_REGNUM)
-    prev_regnum = ARM_LR_REGNUM;
+    {
+      CORE_ADDR lr;
+
+      lr = frame_unwind_register_unsigned (this_frame, ARM_LR_REGNUM);
+      return frame_unwind_got_constant (this_frame, prev_regnum,
+                                       arm_addr_bits_remove (gdbarch, lr));
+    }
 
   /* SP is generally not saved to the stack, but this frame is
-     identified by NEXT_FRAME's stack pointer at the time of the call.
+     identified by the next frame's stack pointer at the time of the call.
      The value was already reconstructed into PREV_SP.  */
   if (prev_regnum == ARM_SP_REGNUM)
+    return frame_unwind_got_constant (this_frame, prev_regnum, cache->prev_sp);
+
+  /* The CPSR may have been changed by the call instruction and by the
+     called function.  The only bit we can reconstruct is the T bit,
+     by checking the low bit of LR as of the call.  This is a reliable
+     indicator of Thumb-ness except for some ARM v4T pre-interworking
+     Thumb code, which could get away with a clear low bit as long as
+     the called function did not use bx.  Guess that all other
+     bits are unchanged; the condition flags are presumably lost,
+     but the processor status is likely valid.  */
+  if (prev_regnum == ARM_PS_REGNUM)
     {
-      *lvalp = not_lval;
-      if (valuep)
-       store_unsigned_integer (valuep, 4, cache->prev_sp);
-      return;
+      CORE_ADDR lr, cpsr;
+
+      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;
+      else
+       cpsr &= ~CPSR_T;
+      return frame_unwind_got_constant (this_frame, prev_regnum, cpsr);
     }
 
-  trad_frame_get_prev_register (next_frame, cache->saved_regs, prev_regnum,
-                               optimized, lvalp, addrp, realnump, valuep);
+  return trad_frame_get_prev_register (this_frame, cache->saved_regs,
+                                      prev_regnum);
 }
 
 struct frame_unwind arm_prologue_unwind = {
   NORMAL_FRAME,
   arm_prologue_this_id,
-  arm_prologue_prev_register
+  arm_prologue_prev_register,
+  NULL,
+  default_frame_sniffer
 };
 
-static const struct frame_unwind *
-arm_prologue_unwind_sniffer (struct frame_info *next_frame)
-{
-  return &arm_prologue_unwind;
-}
-
 static struct arm_prologue_cache *
-arm_make_stub_cache (struct frame_info *next_frame)
+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 (next_frame);
+  cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
 
-  cache->prev_sp = frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM);
+  cache->prev_sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM);
 
   return cache;
 }
@@ -1013,50 +1161,53 @@ arm_make_stub_cache (struct frame_info *next_frame)
 /* Our frame ID for a stub frame is the current SP and LR.  */
 
 static void
-arm_stub_this_id (struct frame_info *next_frame,
+arm_stub_this_id (struct frame_info *this_frame,
                  void **this_cache,
                  struct frame_id *this_id)
 {
   struct arm_prologue_cache *cache;
 
   if (*this_cache == NULL)
-    *this_cache = arm_make_stub_cache (next_frame);
+    *this_cache = arm_make_stub_cache (this_frame);
   cache = *this_cache;
 
-  *this_id = frame_id_build (cache->prev_sp,
-                            frame_pc_unwind (next_frame));
+  *this_id = frame_id_build (cache->prev_sp, get_frame_pc (this_frame));
 }
 
-struct frame_unwind arm_stub_unwind = {
-  NORMAL_FRAME,
-  arm_stub_this_id,
-  arm_prologue_prev_register
-};
-
-static const struct frame_unwind *
-arm_stub_unwind_sniffer (struct frame_info *next_frame)
+static int
+arm_stub_unwind_sniffer (const struct frame_unwind *self,
+                        struct frame_info *this_frame,
+                        void **this_prologue_cache)
 {
   CORE_ADDR addr_in_block;
   char dummy[4];
 
-  addr_in_block = frame_unwind_address_in_block (next_frame, NORMAL_FRAME);
+  addr_in_block = get_frame_address_in_block (this_frame);
   if (in_plt_section (addr_in_block, NULL)
-      || target_read_memory (frame_pc_unwind (next_frame), dummy, 4) != 0)
-    return &arm_stub_unwind;
+      || target_read_memory (get_frame_pc (this_frame), dummy, 4) != 0)
+    return 1;
 
-  return NULL;
+  return 0;
 }
 
+struct frame_unwind arm_stub_unwind = {
+  NORMAL_FRAME,
+  arm_stub_this_id,
+  arm_prologue_prev_register,
+  NULL,
+  arm_stub_unwind_sniffer
+};
+
 static CORE_ADDR
-arm_normal_frame_base (struct frame_info *next_frame, void **this_cache)
+arm_normal_frame_base (struct frame_info *this_frame, void **this_cache)
 {
   struct arm_prologue_cache *cache;
 
   if (*this_cache == NULL)
-    *this_cache = arm_make_prologue_cache (next_frame);
+    *this_cache = arm_make_prologue_cache (this_frame);
   cache = *this_cache;
 
-  return cache->prev_sp + cache->frameoffset - cache->framesize;
+  return cache->prev_sp - cache->framesize;
 }
 
 struct frame_base arm_normal_base = {
@@ -1066,17 +1217,17 @@ struct frame_base arm_normal_base = {
   arm_normal_frame_base
 };
 
-/* Assuming NEXT_FRAME->prev is a dummy, return the frame ID of that
+/* Assuming THIS_FRAME is a dummy, return the frame ID of that
    dummy frame.  The frame ID's base needs to match the TOS value
    saved by save_dummy_frame_tos() and returned from
    arm_push_dummy_call, and the PC needs to match the dummy frame's
    breakpoint.  */
 
 static struct frame_id
-arm_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
+arm_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
 {
-  return frame_id_build (frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM),
-                        frame_pc_unwind (next_frame));
+  return frame_id_build (get_frame_register_unsigned (this_frame, ARM_SP_REGNUM),
+                        get_frame_pc (this_frame));
 }
 
 /* Given THIS_FRAME, find the previous frame's resume PC (which will
@@ -1088,7 +1239,7 @@ arm_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
 {
   CORE_ADDR pc;
   pc = frame_unwind_register_unsigned (this_frame, ARM_PC_REGNUM);
-  return arm_addr_bits_remove (pc);
+  return arm_addr_bits_remove (gdbarch, pc);
 }
 
 static CORE_ADDR
@@ -1097,6 +1248,58 @@ arm_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
   return frame_unwind_register_unsigned (this_frame, ARM_SP_REGNUM);
 }
 
+static struct value *
+arm_dwarf2_prev_register (struct frame_info *this_frame, void **this_cache,
+                         int regnum)
+{
+  struct gdbarch * gdbarch = get_frame_arch (this_frame);
+  CORE_ADDR lr, cpsr;
+
+  switch (regnum)
+    {
+    case ARM_PC_REGNUM:
+      /* The PC is normally copied from the return column, which
+        describes saves of LR.  However, that version may have an
+        extra bit set to indicate Thumb state.  The bit is not
+        part of the PC.  */
+      lr = frame_unwind_register_unsigned (this_frame, ARM_LR_REGNUM);
+      return frame_unwind_got_constant (this_frame, regnum,
+                                       arm_addr_bits_remove (gdbarch, lr));
+
+    case ARM_PS_REGNUM:
+      /* Reconstruct the T bit; see arm_prologue_prev_register for details.  */
+      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;
+      else
+       cpsr &= ~CPSR_T;
+      return frame_unwind_got_constant (this_frame, regnum, cpsr);
+
+    default:
+      internal_error (__FILE__, __LINE__,
+                     _("Unexpected register %d"), regnum);
+    }
+}
+
+static void
+arm_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
+                          struct dwarf2_frame_state_reg *reg,
+                          struct frame_info *this_frame)
+{
+  switch (regnum)
+    {
+    case ARM_PC_REGNUM:
+    case ARM_PS_REGNUM:
+      reg->how = DWARF2_FRAME_REG_FN;
+      reg->loc.fn = arm_dwarf2_prev_register;
+      break;
+    case ARM_SP_REGNUM:
+      reg->how = DWARF2_FRAME_REG_CFA;
+      break;
+    }
+}
+
 /* When arguments must be pushed onto the stack, they go on in reverse
    order.  The code below implements a FILO (stack) to do this.  */
 
@@ -1177,8 +1380,222 @@ arm_type_align (struct type *t)
     }
 }
 
-/* We currently only support passing parameters in integer registers.  This
-   conforms with GCC's default model.  Several other variants exist and
+/* Possible base types for a candidate for passing and returning in
+   VFP registers.  */
+
+enum arm_vfp_cprc_base_type
+{
+  VFP_CPRC_UNKNOWN,
+  VFP_CPRC_SINGLE,
+  VFP_CPRC_DOUBLE,
+  VFP_CPRC_VEC64,
+  VFP_CPRC_VEC128
+};
+
+/* The length of one element of base type B.  */
+
+static unsigned
+arm_vfp_cprc_unit_length (enum arm_vfp_cprc_base_type b)
+{
+  switch (b)
+    {
+    case VFP_CPRC_SINGLE:
+      return 4;
+    case VFP_CPRC_DOUBLE:
+      return 8;
+    case VFP_CPRC_VEC64:
+      return 8;
+    case VFP_CPRC_VEC128:
+      return 16;
+    default:
+      internal_error (__FILE__, __LINE__, _("Invalid VFP CPRC type: %d."),
+                     (int) b);
+    }
+}
+
+/* The character ('s', 'd' or 'q') for the type of VFP register used
+   for passing base type B.  */
+
+static int
+arm_vfp_cprc_reg_char (enum arm_vfp_cprc_base_type b)
+{
+  switch (b)
+    {
+    case VFP_CPRC_SINGLE:
+      return 's';
+    case VFP_CPRC_DOUBLE:
+      return 'd';
+    case VFP_CPRC_VEC64:
+      return 'd';
+    case VFP_CPRC_VEC128:
+      return 'q';
+    default:
+      internal_error (__FILE__, __LINE__, _("Invalid VFP CPRC type: %d."),
+                     (int) b);
+    }
+}
+
+/* Determine whether T may be part of a candidate for passing and
+   returning in VFP registers, ignoring the limit on the total number
+   of components.  If *BASE_TYPE is VFP_CPRC_UNKNOWN, set it to the
+   classification of the first valid component found; if it is not
+   VFP_CPRC_UNKNOWN, all components must have the same classification
+   as *BASE_TYPE.  If it is found that T contains a type not permitted
+   for passing and returning in VFP registers, a type differently
+   classified from *BASE_TYPE, or two types differently classified
+   from each other, return -1, otherwise return the total number of
+   base-type elements found (possibly 0 in an empty structure or
+   array).  Vectors and complex types are not currently supported,
+   matching the generic AAPCS support.  */
+
+static int
+arm_vfp_cprc_sub_candidate (struct type *t,
+                           enum arm_vfp_cprc_base_type *base_type)
+{
+  t = check_typedef (t);
+  switch (TYPE_CODE (t))
+    {
+    case TYPE_CODE_FLT:
+      switch (TYPE_LENGTH (t))
+       {
+       case 4:
+         if (*base_type == VFP_CPRC_UNKNOWN)
+           *base_type = VFP_CPRC_SINGLE;
+         else if (*base_type != VFP_CPRC_SINGLE)
+           return -1;
+         return 1;
+
+       case 8:
+         if (*base_type == VFP_CPRC_UNKNOWN)
+           *base_type = VFP_CPRC_DOUBLE;
+         else if (*base_type != VFP_CPRC_DOUBLE)
+           return -1;
+         return 1;
+
+       default:
+         return -1;
+       }
+      break;
+
+    case TYPE_CODE_ARRAY:
+      {
+       int count;
+       unsigned unitlen;
+       count = arm_vfp_cprc_sub_candidate (TYPE_TARGET_TYPE (t), base_type);
+       if (count == -1)
+         return -1;
+       if (TYPE_LENGTH (t) == 0)
+         {
+           gdb_assert (count == 0);
+           return 0;
+         }
+       else if (count == 0)
+         return -1;
+       unitlen = arm_vfp_cprc_unit_length (*base_type);
+       gdb_assert ((TYPE_LENGTH (t) % unitlen) == 0);
+       return TYPE_LENGTH (t) / unitlen;
+      }
+      break;
+
+    case TYPE_CODE_STRUCT:
+      {
+       int count = 0;
+       unsigned unitlen;
+       int i;
+       for (i = 0; i < TYPE_NFIELDS (t); i++)
+         {
+           int sub_count = arm_vfp_cprc_sub_candidate (TYPE_FIELD_TYPE (t, i),
+                                                       base_type);
+           if (sub_count == -1)
+             return -1;
+           count += sub_count;
+         }
+       if (TYPE_LENGTH (t) == 0)
+         {
+           gdb_assert (count == 0);
+           return 0;
+         }
+       else if (count == 0)
+         return -1;
+       unitlen = arm_vfp_cprc_unit_length (*base_type);
+       if (TYPE_LENGTH (t) != unitlen * count)
+         return -1;
+       return count;
+      }
+
+    case TYPE_CODE_UNION:
+      {
+       int count = 0;
+       unsigned unitlen;
+       int i;
+       for (i = 0; i < TYPE_NFIELDS (t); i++)
+         {
+           int sub_count = arm_vfp_cprc_sub_candidate (TYPE_FIELD_TYPE (t, i),
+                                                       base_type);
+           if (sub_count == -1)
+             return -1;
+           count = (count > sub_count ? count : sub_count);
+         }
+       if (TYPE_LENGTH (t) == 0)
+         {
+           gdb_assert (count == 0);
+           return 0;
+         }
+       else if (count == 0)
+         return -1;
+       unitlen = arm_vfp_cprc_unit_length (*base_type);
+       if (TYPE_LENGTH (t) != unitlen * count)
+         return -1;
+       return count;
+      }
+
+    default:
+      break;
+    }
+
+  return -1;
+}
+
+/* Determine whether T is a VFP co-processor register candidate (CPRC)
+   if passed to or returned from a non-variadic function with the VFP
+   ABI in effect.  Return 1 if it is, 0 otherwise.  If it is, set
+   *BASE_TYPE to the base type for T and *COUNT to the number of
+   elements of that base type before returning.  */
+
+static int
+arm_vfp_call_candidate (struct type *t, enum arm_vfp_cprc_base_type *base_type,
+                       int *count)
+{
+  enum arm_vfp_cprc_base_type b = VFP_CPRC_UNKNOWN;
+  int c = arm_vfp_cprc_sub_candidate (t, &b);
+  if (c <= 0 || c > 4)
+    return 0;
+  *base_type = b;
+  *count = c;
+  return 1;
+}
+
+/* Return 1 if the VFP ABI should be used for passing arguments to and
+   returning values from a function of type FUNC_TYPE, 0
+   otherwise.  */
+
+static int
+arm_vfp_abi_for_function (struct gdbarch *gdbarch, struct type *func_type)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  /* Variadic functions always use the base ABI.  Assume that functions
+     without debug info are not variadic.  */
+  if (func_type && TYPE_VARARGS (check_typedef (func_type)))
+    return 0;
+  /* The VFP ABI is only supported as a variant of AAPCS.  */
+  if (tdep->arm_abi != ARM_ABI_AAPCS)
+    return 0;
+  return gdbarch_tdep (gdbarch)->fp_model == ARM_FLOAT_VFP;
+}
+
+/* We currently only support passing parameters in integer registers, which
+   conforms with GCC's default model, and VFP argument passing following
+   the VFP variant of AAPCS.  Several other variants exist and
    we should probably support some of them based on the selected ABI.  */
 
 static CORE_ADDR
@@ -1187,10 +1604,21 @@ arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                     struct value **args, CORE_ADDR sp, int struct_return,
                     CORE_ADDR struct_addr)
 {
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   int argnum;
   int argreg;
   int nstack;
   struct stack_item *si = NULL;
+  int use_vfp_abi;
+  struct type *ftype;
+  unsigned vfp_regs_free = (1 << 16) - 1;
+
+  /* Determine the type of this function and whether the VFP ABI
+     applies.  */
+  ftype = check_typedef (value_type (function));
+  if (TYPE_CODE (ftype) == TYPE_CODE_PTR)
+    ftype = check_typedef (TYPE_TARGET_TYPE (ftype));
+  use_vfp_abi = arm_vfp_abi_for_function (gdbarch, ftype);
 
   /* Set the return address.  For the ARM, the return breakpoint is
      always at BP_ADDR.  */
@@ -1210,8 +1638,9 @@ arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   if (struct_return)
     {
       if (arm_debug)
-       fprintf_unfiltered (gdb_stdlog, "struct return in %s = 0x%s\n",
-                           REGISTER_NAME (argreg), paddr (struct_addr));
+       fprintf_unfiltered (gdb_stdlog, "struct return in %s = %s\n",
+                           gdbarch_register_name (gdbarch, argreg),
+                           paddress (gdbarch, struct_addr));
       regcache_cooked_write_unsigned (regcache, argreg, struct_addr);
       argreg++;
     }
@@ -1224,6 +1653,9 @@ arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
       enum type_code typecode;
       bfd_byte *val;
       int align;
+      enum arm_vfp_cprc_base_type vfp_base_type;
+      int vfp_base_count;
+      int may_use_core_reg = 1;
 
       arg_type = check_typedef (value_type (args[argnum]));
       len = TYPE_LENGTH (arg_type);
@@ -1247,6 +1679,65 @@ arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
            align = INT_REGISTER_SIZE * 2;
        }
 
+      if (use_vfp_abi
+         && arm_vfp_call_candidate (arg_type, &vfp_base_type,
+                                    &vfp_base_count))
+       {
+         int regno;
+         int unit_length;
+         int shift;
+         unsigned mask;
+
+         /* Because this is a CPRC it cannot go in a core register or
+            cause a core register to be skipped for alignment.
+            Either it goes in VFP registers and the rest of this loop
+            iteration is skipped for this argument, or it goes on the
+            stack (and the stack alignment code is correct for this
+            case).  */
+         may_use_core_reg = 0;
+
+         unit_length = arm_vfp_cprc_unit_length (vfp_base_type);
+         shift = unit_length / 4;
+         mask = (1 << (shift * vfp_base_count)) - 1;
+         for (regno = 0; regno < 16; regno += shift)
+           if (((vfp_regs_free >> regno) & mask) == mask)
+             break;
+
+         if (regno < 16)
+           {
+             int reg_char;
+             int reg_scaled;
+             int i;
+
+             vfp_regs_free &= ~(mask << regno);
+             reg_scaled = regno / shift;
+             reg_char = arm_vfp_cprc_reg_char (vfp_base_type);
+             for (i = 0; i < vfp_base_count; i++)
+               {
+                 char name_buf[4];
+                 int regnum;
+                 if (reg_char == 'q')
+                   arm_neon_quad_write (gdbarch, regcache, reg_scaled + i,
+                                        val + i * unit_length);
+                 else
+                   {
+                     sprintf (name_buf, "%c%d", reg_char, reg_scaled + i);
+                     regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
+                                                           strlen (name_buf));
+                     regcache_cooked_write (regcache, regnum,
+                                            val + i * unit_length);
+                   }
+               }
+             continue;
+           }
+         else
+           {
+             /* This CPRC could not go in VFP registers, so all VFP
+                registers are now marked as used.  */
+             vfp_regs_free = 0;
+           }
+       }
+
       /* Push stack padding for dowubleword alignment.  */
       if (nstack & (align - 1))
        {
@@ -1255,7 +1746,8 @@ arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
        }
       
       /* Doubleword aligned quantities must go in even register pairs.  */
-      if (argreg <= ARM_LAST_ARG_REGNUM
+      if (may_use_core_reg
+         && argreg <= ARM_LAST_ARG_REGNUM
          && align > INT_REGISTER_SIZE
          && argreg & 1)
        argreg++;
@@ -1267,11 +1759,12 @@ arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
          && target_type != NULL
          && TYPE_CODE_FUNC == TYPE_CODE (target_type))
        {
-         CORE_ADDR regval = extract_unsigned_integer (val, len);
+         CORE_ADDR regval = extract_unsigned_integer (val, len, byte_order);
          if (arm_pc_is_thumb (regval))
            {
              val = alloca (len);
-             store_unsigned_integer (val, len, MAKE_THUMB_ADDR (regval));
+             store_unsigned_integer (val, len, byte_order,
+                                     MAKE_THUMB_ADDR (regval));
            }
        }
 
@@ -1280,17 +1773,22 @@ arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
         registers and stack.  */
       while (len > 0)
        {
-         int partial_len = len < DEPRECATED_REGISTER_SIZE ? len : DEPRECATED_REGISTER_SIZE;
+         int partial_len = len < INT_REGISTER_SIZE ? len : INT_REGISTER_SIZE;
 
-         if (argreg <= ARM_LAST_ARG_REGNUM)
+         if (may_use_core_reg && argreg <= ARM_LAST_ARG_REGNUM)
            {
              /* The argument is being passed in a general purpose
                 register.  */
-             CORE_ADDR regval = extract_unsigned_integer (val, partial_len);
+             CORE_ADDR regval
+               = extract_unsigned_integer (val, partial_len, byte_order);
+             if (byte_order == BFD_ENDIAN_BIG)
+               regval <<= (INT_REGISTER_SIZE - partial_len) * 8;
              if (arm_debug)
                fprintf_unfiltered (gdb_stdlog, "arg %d in %s = 0x%s\n",
-                                   argnum, REGISTER_NAME (argreg),
-                                   phex (regval, DEPRECATED_REGISTER_SIZE));
+                                   argnum,
+                                   gdbarch_register_name
+                                     (gdbarch, argreg),
+                                   phex (regval, INT_REGISTER_SIZE));
              regcache_cooked_write_unsigned (regcache, argreg, regval);
              argreg++;
            }
@@ -1300,8 +1798,8 @@ arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
              if (arm_debug)
                fprintf_unfiltered (gdb_stdlog, "arg %d @ sp + %d\n",
                                    argnum, nstack);
-             si = push_stack_item (si, val, DEPRECATED_REGISTER_SIZE);
-             nstack += DEPRECATED_REGISTER_SIZE;
+             si = push_stack_item (si, val, INT_REGISTER_SIZE);
+             nstack += INT_REGISTER_SIZE;
            }
              
          len -= partial_len;
@@ -1359,7 +1857,7 @@ static void
 arm_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
                      struct frame_info *frame, const char *args)
 {
-  unsigned long status = read_register (ARM_FPS_REGNUM);
+  unsigned long status = get_frame_register_unsigned (frame, ARM_FPS_REGNUM);
   int type;
 
   type = (status >> 24) & 127;
@@ -1375,31 +1873,146 @@ arm_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
   print_fpu_flags (status);
 }
 
+/* Construct the ARM extended floating point type.  */
+static struct type *
+arm_ext_type (struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  if (!tdep->arm_ext_type)
+    tdep->arm_ext_type
+      = arch_float_type (gdbarch, -1, "builtin_type_arm_ext",
+                        floatformats_arm_ext);
+
+  return tdep->arm_ext_type;
+}
+
+static struct type *
+arm_neon_double_type (struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  if (tdep->neon_double_type == NULL)
+    {
+      struct type *t, *elem;
+
+      t = arch_composite_type (gdbarch, "__gdb_builtin_type_neon_d",
+                              TYPE_CODE_UNION);
+      elem = builtin_type (gdbarch)->builtin_uint8;
+      append_composite_type_field (t, "u8", init_vector_type (elem, 8));
+      elem = builtin_type (gdbarch)->builtin_uint16;
+      append_composite_type_field (t, "u16", init_vector_type (elem, 4));
+      elem = builtin_type (gdbarch)->builtin_uint32;
+      append_composite_type_field (t, "u32", init_vector_type (elem, 2));
+      elem = builtin_type (gdbarch)->builtin_uint64;
+      append_composite_type_field (t, "u64", elem);
+      elem = builtin_type (gdbarch)->builtin_float;
+      append_composite_type_field (t, "f32", init_vector_type (elem, 2));
+      elem = builtin_type (gdbarch)->builtin_double;
+      append_composite_type_field (t, "f64", elem);
+
+      TYPE_VECTOR (t) = 1;
+      TYPE_NAME (t) = "neon_d";
+      tdep->neon_double_type = t;
+    }
+
+  return tdep->neon_double_type;
+}
+
+/* FIXME: The vector types are not correctly ordered on big-endian
+   targets.  Just as s0 is the low bits of d0, d0[0] is also the low
+   bits of d0 - regardless of what unit size is being held in d0.  So
+   the offset of the first uint8 in d0 is 7, but the offset of the
+   first float is 4.  This code works as-is for little-endian
+   targets.  */
+
+static struct type *
+arm_neon_quad_type (struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  if (tdep->neon_quad_type == NULL)
+    {
+      struct type *t, *elem;
+
+      t = arch_composite_type (gdbarch, "__gdb_builtin_type_neon_q",
+                              TYPE_CODE_UNION);
+      elem = builtin_type (gdbarch)->builtin_uint8;
+      append_composite_type_field (t, "u8", init_vector_type (elem, 16));
+      elem = builtin_type (gdbarch)->builtin_uint16;
+      append_composite_type_field (t, "u16", init_vector_type (elem, 8));
+      elem = builtin_type (gdbarch)->builtin_uint32;
+      append_composite_type_field (t, "u32", init_vector_type (elem, 4));
+      elem = builtin_type (gdbarch)->builtin_uint64;
+      append_composite_type_field (t, "u64", init_vector_type (elem, 2));
+      elem = builtin_type (gdbarch)->builtin_float;
+      append_composite_type_field (t, "f32", init_vector_type (elem, 4));
+      elem = builtin_type (gdbarch)->builtin_double;
+      append_composite_type_field (t, "f64", init_vector_type (elem, 2));
+
+      TYPE_VECTOR (t) = 1;
+      TYPE_NAME (t) = "neon_q";
+      tdep->neon_quad_type = t;
+    }
+
+  return tdep->neon_quad_type;
+}
+
 /* Return the GDB type object for the "standard" data type of data in
    register N.  */
 
 static struct type *
 arm_register_type (struct gdbarch *gdbarch, int regnum)
 {
+  int num_regs = gdbarch_num_regs (gdbarch);
+
+  if (gdbarch_tdep (gdbarch)->have_vfp_pseudos
+      && regnum >= num_regs && regnum < num_regs + 32)
+    return builtin_type (gdbarch)->builtin_float;
+
+  if (gdbarch_tdep (gdbarch)->have_neon_pseudos
+      && regnum >= num_regs + 32 && regnum < num_regs + 32 + 16)
+    return arm_neon_quad_type (gdbarch);
+
+  /* If the target description has register information, we are only
+     in this function so that we can override the types of
+     double-precision registers for NEON.  */
+  if (tdesc_has_registers (gdbarch_target_desc (gdbarch)))
+    {
+      struct type *t = tdesc_register_type (gdbarch, regnum);
+
+      if (regnum >= ARM_D0_REGNUM && regnum < ARM_D0_REGNUM + 32
+         && TYPE_CODE (t) == TYPE_CODE_FLT
+         && gdbarch_tdep (gdbarch)->have_neon)
+       return arm_neon_double_type (gdbarch);
+      else
+       return t;
+    }
+
   if (regnum >= ARM_F0_REGNUM && regnum < ARM_F0_REGNUM + NUM_FREGS)
-    return builtin_type_arm_ext;
+    {
+      if (!gdbarch_tdep (gdbarch)->have_fpa_registers)
+       return builtin_type (gdbarch)->builtin_void;
+
+      return arm_ext_type (gdbarch);
+    }
   else if (regnum == ARM_SP_REGNUM)
-    return builtin_type_void_data_ptr;
+    return builtin_type (gdbarch)->builtin_data_ptr;
   else if (regnum == ARM_PC_REGNUM)
-    return builtin_type_void_func_ptr;
+    return builtin_type (gdbarch)->builtin_func_ptr;
   else if (regnum >= ARRAY_SIZE (arm_register_names))
     /* These registers are only supported on targets which supply
        an XML description.  */
-    return builtin_type_int0;
+    return builtin_type (gdbarch)->builtin_int0;
   else
-    return builtin_type_uint32;
+    return builtin_type (gdbarch)->builtin_uint32;
 }
 
 /* Map a DWARF register REGNUM onto the appropriate GDB register
    number.  */
 
 static int
-arm_dwarf_reg_to_regnum (int reg)
+arm_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg)
 {
   /* Core integer regs.  */
   if (reg >= 0 && reg <= 15)
@@ -1426,15 +2039,43 @@ arm_dwarf_reg_to_regnum (int reg)
   if (reg >= 192 && reg <= 199)
     return ARM_WC0_REGNUM + reg - 192;
 
+  /* VFP v2 registers.  A double precision value is actually
+     in d1 rather than s2, but the ABI only defines numbering
+     for the single precision registers.  This will "just work"
+     in GDB for little endian targets (we'll read eight bytes,
+     starting in s0 and then progressing to s1), but will be
+     reversed on big endian targets with VFP.  This won't
+     be a problem for the new Neon quad registers; you're supposed
+     to use DW_OP_piece for those.  */
+  if (reg >= 64 && reg <= 95)
+    {
+      char name_buf[4];
+
+      sprintf (name_buf, "s%d", reg - 64);
+      return user_reg_map_name_to_regnum (gdbarch, name_buf,
+                                         strlen (name_buf));
+    }
+
+  /* VFP v3 / Neon registers.  This range is also used for VFP v2
+     registers, except that it now describes d0 instead of s0.  */
+  if (reg >= 256 && reg <= 287)
+    {
+      char name_buf[4];
+
+      sprintf (name_buf, "d%d", reg - 256);
+      return user_reg_map_name_to_regnum (gdbarch, name_buf,
+                                         strlen (name_buf));
+    }
+
   return -1;
 }
 
 /* Map GDB internal REGNUM onto the Arm simulator register numbers.  */
 static int
-arm_register_sim_regno (int regnum)
+arm_register_sim_regno (struct gdbarch *gdbarch, int regnum)
 {
   int reg = regnum;
-  gdb_assert (reg >= 0 && reg < NUM_REGS);
+  gdb_assert (reg >= 0 && reg < gdbarch_num_regs (gdbarch));
 
   if (regnum >= ARM_WR0_REGNUM && regnum <= ARM_WR15_REGNUM)
     return regnum - ARM_WR0_REGNUM + SIM_ARM_IWMMXT_COP0R0_REGNUM;
@@ -1467,10 +2108,11 @@ arm_register_sim_regno (int regnum)
 
 static void
 convert_from_extended (const struct floatformat *fmt, const void *ptr,
-                      void *dbl)
+                      void *dbl, int endianess)
 {
   DOUBLEST d;
-  if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+
+  if (endianess == BFD_ENDIAN_BIG)
     floatformat_to_doublest (&floatformat_arm_ext_big, ptr, &d);
   else
     floatformat_to_doublest (&floatformat_arm_ext_littlebyte_bigword,
@@ -1479,11 +2121,13 @@ convert_from_extended (const struct floatformat *fmt, const void *ptr,
 }
 
 static void
-convert_to_extended (const struct floatformat *fmt, void *dbl, const void *ptr)
+convert_to_extended (const struct floatformat *fmt, void *dbl, const void *ptr,
+                    int endianess)
 {
   DOUBLEST d;
+
   floatformat_to_doublest (fmt, ptr, &d);
-  if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+  if (endianess == BFD_ENDIAN_BIG)
     floatformat_from_doublest (&floatformat_arm_ext_big, &d, dbl);
   else
     floatformat_from_doublest (&floatformat_arm_ext_littlebyte_bigword,
@@ -1543,8 +2187,8 @@ condition_true (unsigned long cond, unsigned long status_reg)
 #define ARM_PC_32 1
 
 static unsigned long
-shifted_reg_val (unsigned long inst, int carry, unsigned long pc_val,
-                unsigned long status_reg)
+shifted_reg_val (struct frame_info *frame, unsigned long inst, int carry,
+                unsigned long pc_val, unsigned long status_reg)
 {
   unsigned long res, shift;
   int rm = bits (inst, 0, 3);
@@ -1553,7 +2197,8 @@ shifted_reg_val (unsigned long inst, int carry, unsigned long pc_val,
   if (bit (inst, 4))
     {
       int rs = bits (inst, 8, 11);
-      shift = (rs == 15 ? pc_val + 8 : read_register (rs)) & 0xFF;
+      shift = (rs == 15 ? pc_val + 8
+                       : get_frame_register_unsigned (frame, rs)) & 0xFF;
     }
   else
     shift = bits (inst, 7, 11);
@@ -1561,7 +2206,7 @@ shifted_reg_val (unsigned long inst, int carry, unsigned long pc_val,
   res = (rm == 15
         ? ((pc_val | (ARM_PC_32 ? 0 : status_reg))
            + (bit (inst, 4) ? 12 : 8))
-        : read_register (rm));
+        : get_frame_register_unsigned (frame, rm));
 
   switch (shifttype)
     {
@@ -1604,29 +2249,34 @@ bitcount (unsigned long val)
 }
 
 static CORE_ADDR
-thumb_get_next_pc (CORE_ADDR pc)
+thumb_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
 {
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
   unsigned long pc_val = ((unsigned long) pc) + 4;     /* PC after prefetch */
-  unsigned short inst1 = read_memory_unsigned_integer (pc, 2);
+  unsigned short inst1;
   CORE_ADDR nextpc = pc + 2;           /* default is next instruction */
   unsigned long offset;
 
+  inst1 = read_memory_unsigned_integer (pc, 2, byte_order_for_code);
+
   if ((inst1 & 0xff00) == 0xbd00)      /* pop {rlist, pc} */
     {
       CORE_ADDR sp;
 
       /* Fetch the saved PC from the stack.  It's stored above
          all of the other registers.  */
-      offset = bitcount (bits (inst1, 0, 7)) * DEPRECATED_REGISTER_SIZE;
-      sp = read_register (ARM_SP_REGNUM);
-      nextpc = (CORE_ADDR) read_memory_unsigned_integer (sp + offset, 4);
-      nextpc = ADDR_BITS_REMOVE (nextpc);
+      offset = bitcount (bits (inst1, 0, 7)) * INT_REGISTER_SIZE;
+      sp = get_frame_register_unsigned (frame, ARM_SP_REGNUM);
+      nextpc = read_memory_unsigned_integer (sp + offset, 4, byte_order);
+      nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
       if (nextpc == pc)
        error (_("Infinite loop detected"));
     }
   else if ((inst1 & 0xf000) == 0xd000) /* conditional branch */
     {
-      unsigned long status = read_register (ARM_PS_REGNUM);
+      unsigned long status = get_frame_register_unsigned (frame, ARM_PS_REGNUM);
       unsigned long cond = bits (inst1, 8, 11);
       if (cond != 0x0f && condition_true (cond, status))    /* 0x0f = SWI */
        nextpc = pc_val + (sbits (inst1, 0, 7) << 1);
@@ -1637,7 +2287,8 @@ thumb_get_next_pc (CORE_ADDR pc)
     }
   else if ((inst1 & 0xf800) == 0xf000) /* long branch with link, and blx */
     {
-      unsigned short inst2 = read_memory_unsigned_integer (pc + 2, 2);
+      unsigned short inst2;
+      inst2 = read_memory_unsigned_integer (pc + 2, 2, byte_order_for_code);
       offset = (sbits (inst1, 0, 10) << 12) + (bits (inst2, 0, 10) << 1);
       nextpc = pc_val + offset;
       /* For BLX make sure to clear the low bits.  */
@@ -1649,9 +2300,9 @@ thumb_get_next_pc (CORE_ADDR pc)
       if (bits (inst1, 3, 6) == 0x0f)
        nextpc = pc_val;
       else
-       nextpc = read_register (bits (inst1, 3, 6));
+       nextpc = get_frame_register_unsigned (frame, bits (inst1, 3, 6));
 
-      nextpc = ADDR_BITS_REMOVE (nextpc);
+      nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
       if (nextpc == pc)
        error (_("Infinite loop detected"));
     }
@@ -1659,23 +2310,50 @@ thumb_get_next_pc (CORE_ADDR pc)
   return nextpc;
 }
 
-static CORE_ADDR
-arm_get_next_pc (CORE_ADDR pc)
+CORE_ADDR
+arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
 {
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
   unsigned long pc_val;
   unsigned long this_instr;
   unsigned long status;
   CORE_ADDR nextpc;
 
-  if (arm_pc_is_thumb (pc))
-    return thumb_get_next_pc (pc);
+  if (arm_frame_is_thumb (frame))
+    return thumb_get_next_pc (frame, pc);
 
   pc_val = (unsigned long) pc;
-  this_instr = read_memory_unsigned_integer (pc, 4);
-  status = read_register (ARM_PS_REGNUM);
+  this_instr = read_memory_unsigned_integer (pc, 4, byte_order_for_code);
+
+  status = get_frame_register_unsigned (frame, ARM_PS_REGNUM);
   nextpc = (CORE_ADDR) (pc_val + 4);   /* Default case */
 
-  if (condition_true (bits (this_instr, 28, 31), status))
+  if (bits (this_instr, 28, 31) == INST_NV)
+    switch (bits (this_instr, 24, 27))
+      {
+      case 0xa:
+      case 0xb:
+       {
+         /* Branch with Link and change to Thumb.  */
+         nextpc = BranchDest (pc, this_instr);
+         nextpc |= bit (this_instr, 24) << 1;
+
+         nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
+         if (nextpc == pc)
+           error (_("Infinite loop detected"));
+         break;
+       }
+      case 0xc:
+      case 0xd:
+      case 0xe:
+       /* Coprocessor register transfer.  */
+        if (bits (this_instr, 12, 15) == 15)
+         error (_("Invalid update to pc in instruction"));
+       break;
+      }
+  else if (condition_true (bits (this_instr, 28, 31), status))
     {
       switch (bits (this_instr, 24, 27))
        {
@@ -1700,8 +2378,10 @@ arm_get_next_pc (CORE_ADDR pc)
                || bits (this_instr, 4, 27) == 0x12fff3)
              {
                rn = bits (this_instr, 0, 3);
-               result = (rn == 15) ? pc_val + 8 : read_register (rn);
-               nextpc = (CORE_ADDR) ADDR_BITS_REMOVE (result);
+               result = (rn == 15) ? pc_val + 8
+                                   : get_frame_register_unsigned (frame, rn);
+               nextpc = (CORE_ADDR) gdbarch_addr_bits_remove
+                                      (gdbarch, result);
 
                if (nextpc == pc)
                  error (_("Infinite loop detected"));
@@ -1712,7 +2392,8 @@ arm_get_next_pc (CORE_ADDR pc)
            /* Multiply into PC */
            c = (status & FLAG_C) ? 1 : 0;
            rn = bits (this_instr, 16, 19);
-           operand1 = (rn == 15) ? pc_val + 8 : read_register (rn);
+           operand1 = (rn == 15) ? pc_val + 8
+                                 : get_frame_register_unsigned (frame, rn);
 
            if (bit (this_instr, 25))
              {
@@ -1722,7 +2403,7 @@ arm_get_next_pc (CORE_ADDR pc)
                  & 0xffffffff;
              }
            else                /* operand 2 is a shifted register */
-             operand2 = shifted_reg_val (this_instr, c, pc_val, status);
+             operand2 = shifted_reg_val (frame, this_instr, c, pc_val, status);
 
            switch (bits (this_instr, 21, 24))
              {
@@ -1782,7 +2463,8 @@ arm_get_next_pc (CORE_ADDR pc)
                result = ~operand2;
                break;
              }
-           nextpc = (CORE_ADDR) ADDR_BITS_REMOVE (result);
+           nextpc = (CORE_ADDR) gdbarch_addr_bits_remove
+                                  (gdbarch, result);
 
            if (nextpc == pc)
              error (_("Infinite loop detected"));
@@ -1807,14 +2489,15 @@ arm_get_next_pc (CORE_ADDR pc)
 
                  /* byte write to PC */
                  rn = bits (this_instr, 16, 19);
-                 base = (rn == 15) ? pc_val + 8 : read_register (rn);
+                 base = (rn == 15) ? pc_val + 8
+                                   : get_frame_register_unsigned (frame, rn);
                  if (bit (this_instr, 24))
                    {
                      /* pre-indexed */
                      int c = (status & FLAG_C) ? 1 : 0;
                      unsigned long offset =
                      (bit (this_instr, 25)
-                      ? shifted_reg_val (this_instr, c, pc_val, status)
+                      ? shifted_reg_val (frame, this_instr, c, pc_val, status)
                       : bits (this_instr, 0, 11));
 
                      if (bit (this_instr, 23))
@@ -1823,9 +2506,9 @@ arm_get_next_pc (CORE_ADDR pc)
                        base -= offset;
                    }
                  nextpc = (CORE_ADDR) read_memory_integer ((CORE_ADDR) base,
-                                                           4);
+                                                           4, byte_order);
 
-                 nextpc = ADDR_BITS_REMOVE (nextpc);
+                 nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
 
                  if (nextpc == pc)
                    error (_("Infinite loop detected"));
@@ -1856,13 +2539,15 @@ arm_get_next_pc (CORE_ADDR pc)
 
                  {
                    unsigned long rn_val =
-                   read_register (bits (this_instr, 16, 19));
+                   get_frame_register_unsigned (frame,
+                                                bits (this_instr, 16, 19));
                    nextpc =
                      (CORE_ADDR) read_memory_integer ((CORE_ADDR) (rn_val
                                                                  + offset),
-                                                      4);
+                                                      4, byte_order);
                  }
-                 nextpc = ADDR_BITS_REMOVE (nextpc);
+                 nextpc = gdbarch_addr_bits_remove
+                            (gdbarch, nextpc);
                  if (nextpc == pc)
                    error (_("Infinite loop detected"));
                }
@@ -1874,11 +2559,7 @@ arm_get_next_pc (CORE_ADDR pc)
          {
            nextpc = BranchDest (pc, this_instr);
 
-           /* BLX */
-           if (bits (this_instr, 28, 31) == INST_NV)
-             nextpc |= bit (this_instr, 24) << 1;
-
-           nextpc = ADDR_BITS_REMOVE (nextpc);
+           nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
            if (nextpc == pc)
              error (_("Infinite loop detected"));
            break;
@@ -1905,14 +2586,16 @@ arm_get_next_pc (CORE_ADDR pc)
    and breakpoint it.  */
 
 int
-arm_software_single_step (struct regcache *regcache)
+arm_software_single_step (struct frame_info *frame)
 {
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+
   /* NOTE: This may insert the wrong breakpoint instruction when
      single-stepping over a mode-changing instruction, if the
      CPSR heuristics are used.  */
 
-  CORE_ADDR next_pc = arm_get_next_pc (read_register (ARM_PC_REGNUM));
-  insert_single_step_breakpoint (next_pc);
+  CORE_ADDR next_pc = arm_get_next_pc (frame, get_frame_pc (frame));
+  insert_single_step_breakpoint (gdbarch, next_pc);
 
   return 1;
 }
@@ -1954,7 +2637,7 @@ gdb_print_insn_arm (bfd_vma memaddr, disassemble_info *info)
   else
     info->symbols = NULL;
 
-  if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+  if (info->endian == BFD_ENDIAN_BIG)
     return print_insn_big_arm (memaddr, info);
   else
     return print_insn_little_arm (memaddr, info);
@@ -2008,9 +2691,9 @@ static const char arm_default_thumb_be_breakpoint[] = THUMB_BE_BREAKPOINT;
    breakpoint should be inserted.  */
 
 static const unsigned char *
-arm_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
+arm_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *lenptr)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
   if (arm_pc_is_thumb (*pcptr))
     {
@@ -2033,9 +2716,12 @@ static void
 arm_extract_return_value (struct type *type, struct regcache *regs,
                          gdb_byte *valbuf)
 {
+  struct gdbarch *gdbarch = get_regcache_arch (regs);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
   if (TYPE_CODE_FLT == TYPE_CODE (type))
     {
-      switch (gdbarch_tdep (current_gdbarch)->fp_model)
+      switch (gdbarch_tdep (gdbarch)->fp_model)
        {
        case ARM_FLOAT_FPA:
          {
@@ -2046,12 +2732,15 @@ arm_extract_return_value (struct type *type, struct regcache *regs,
 
            regcache_cooked_read (regs, ARM_F0_REGNUM, tmpbuf);
            convert_from_extended (floatformat_from_type (type), tmpbuf,
-                                  valbuf);
+                                  valbuf, gdbarch_byte_order (gdbarch));
          }
          break;
 
        case ARM_FLOAT_SOFT_FPA:
        case ARM_FLOAT_SOFT_VFP:
+         /* ARM_FLOAT_VFP can arise if this is a variadic function so
+            not using the VFP ABI code.  */
+       case ARM_FLOAT_VFP:
          regcache_cooked_read (regs, ARM_A1_REGNUM, valbuf);
          if (TYPE_LENGTH (type) > 4)
            regcache_cooked_read (regs, ARM_A1_REGNUM + 1,
@@ -2086,7 +2775,7 @@ arm_extract_return_value (struct type *type, struct regcache *regs,
          store_unsigned_integer (valbuf, 
                                  (len > INT_REGISTER_SIZE
                                   ? INT_REGISTER_SIZE : len),
-                                 tmp);
+                                 byte_order, tmp);
          len -= INT_REGISTER_SIZE;
          valbuf += INT_REGISTER_SIZE;
        }
@@ -2126,7 +2815,7 @@ arm_return_in_memory (struct gdbarch *gdbarch, struct type *type)
 
   /* In the ARM ABI, "integer" like aggregate types are returned in
      registers.  For an aggregate type to be integer like, its size
-     must be less than or equal to DEPRECATED_REGISTER_SIZE and the
+     must be less than or equal to INT_REGISTER_SIZE and the
      offset of each addressable subfield must be zero.  Note that bit
      fields are not addressable, and all addressable subfields of
      unions always start at offset zero.
@@ -2143,7 +2832,7 @@ arm_return_in_memory (struct gdbarch *gdbarch, struct type *type)
 
   /* All aggregate types that won't fit in a register must be returned
      in memory.  */
-  if (TYPE_LENGTH (type) > DEPRECATED_REGISTER_SIZE)
+  if (TYPE_LENGTH (type) > INT_REGISTER_SIZE)
     {
       return 1;
     }
@@ -2170,7 +2859,7 @@ arm_return_in_memory (struct gdbarch *gdbarch, struct type *type)
       int i;
       /* Need to check if this struct/union is "integer" like.  For
          this to be true, its size must be less than or equal to
-         DEPRECATED_REGISTER_SIZE and the offset of each addressable
+         INT_REGISTER_SIZE and the offset of each addressable
          subfield must be zero.  Note that bit fields are not
          addressable, and unions always start at offset zero.  If any
          of the subfields is a floating point type, the struct/union
@@ -2220,20 +2909,27 @@ static void
 arm_store_return_value (struct type *type, struct regcache *regs,
                        const gdb_byte *valbuf)
 {
+  struct gdbarch *gdbarch = get_regcache_arch (regs);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
   if (TYPE_CODE (type) == TYPE_CODE_FLT)
     {
       char buf[MAX_REGISTER_SIZE];
 
-      switch (gdbarch_tdep (current_gdbarch)->fp_model)
+      switch (gdbarch_tdep (gdbarch)->fp_model)
        {
        case ARM_FLOAT_FPA:
 
-         convert_to_extended (floatformat_from_type (type), buf, valbuf);
+         convert_to_extended (floatformat_from_type (type), buf, valbuf,
+                              gdbarch_byte_order (gdbarch));
          regcache_cooked_write (regs, ARM_F0_REGNUM, buf);
          break;
 
        case ARM_FLOAT_SOFT_FPA:
        case ARM_FLOAT_SOFT_VFP:
+         /* ARM_FLOAT_VFP can arise if this is a variadic function so
+            not using the VFP ABI code.  */
+       case ARM_FLOAT_VFP:
          regcache_cooked_write (regs, ARM_A1_REGNUM, valbuf);
          if (TYPE_LENGTH (type) > 4)
            regcache_cooked_write (regs, ARM_A1_REGNUM + 1, 
@@ -2261,7 +2957,7 @@ arm_store_return_value (struct type *type, struct regcache *regs,
          bfd_byte tmpbuf[INT_REGISTER_SIZE];
          LONGEST val = unpack_long (type, valbuf);
 
-         store_signed_integer (tmpbuf, INT_REGISTER_SIZE, val);
+         store_signed_integer (tmpbuf, INT_REGISTER_SIZE, byte_order, val);
          regcache_cooked_write (regs, ARM_A1_REGNUM, tmpbuf);
        }
       else
@@ -2304,11 +3000,50 @@ arm_store_return_value (struct type *type, struct regcache *regs,
 /* Handle function return values.  */
 
 static enum return_value_convention
-arm_return_value (struct gdbarch *gdbarch, struct type *valtype,
-                 struct regcache *regcache, gdb_byte *readbuf,
-                 const gdb_byte *writebuf)
+arm_return_value (struct gdbarch *gdbarch, struct type *func_type,
+                 struct type *valtype, struct regcache *regcache,
+                 gdb_byte *readbuf, const gdb_byte *writebuf)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  enum arm_vfp_cprc_base_type vfp_base_type;
+  int vfp_base_count;
+
+  if (arm_vfp_abi_for_function (gdbarch, func_type)
+      && arm_vfp_call_candidate (valtype, &vfp_base_type, &vfp_base_count))
+    {
+      int reg_char = arm_vfp_cprc_reg_char (vfp_base_type);
+      int unit_length = arm_vfp_cprc_unit_length (vfp_base_type);
+      int i;
+      for (i = 0; i < vfp_base_count; i++)
+       {
+         if (reg_char == 'q')
+           {
+             if (writebuf)
+               arm_neon_quad_write (gdbarch, regcache, i,
+                                    writebuf + i * unit_length);
+
+             if (readbuf)
+               arm_neon_quad_read (gdbarch, regcache, i,
+                                   readbuf + i * unit_length);
+           }
+         else
+           {
+             char name_buf[4];
+             int regnum;
+
+             sprintf (name_buf, "%c%d", reg_char, i);
+             regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
+                                                   strlen (name_buf));
+             if (writebuf)
+               regcache_cooked_write (regcache, regnum,
+                                      writebuf + i * unit_length);
+             if (readbuf)
+               regcache_cooked_read (regcache, regnum,
+                                     readbuf + i * unit_length);
+           }
+       }
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
 
   if (TYPE_CODE (valtype) == TYPE_CODE_STRUCT
       || TYPE_CODE (valtype) == TYPE_CODE_UNION
@@ -2330,54 +3065,42 @@ arm_return_value (struct gdbarch *gdbarch, struct type *valtype,
 
 
 static int
-arm_get_longjmp_target (CORE_ADDR *pc)
+arm_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
 {
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   CORE_ADDR jb_addr;
   char buf[INT_REGISTER_SIZE];
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
   
-  jb_addr = read_register (ARM_A1_REGNUM);
+  jb_addr = get_frame_register_unsigned (frame, ARM_A1_REGNUM);
 
   if (target_read_memory (jb_addr + tdep->jb_pc * tdep->jb_elt_size, buf,
                          INT_REGISTER_SIZE))
     return 0;
 
-  *pc = extract_unsigned_integer (buf, INT_REGISTER_SIZE);
+  *pc = extract_unsigned_integer (buf, INT_REGISTER_SIZE, byte_order);
   return 1;
 }
 
-/* Return non-zero if the PC is inside a thumb call thunk.  */
-
-int
-arm_in_call_stub (CORE_ADDR pc, char *name)
-{
-  CORE_ADDR start_addr;
-
-  /* Find the starting address of the function containing the PC.  If
-     the caller didn't give us a name, look it up at the same time.  */
-  if (0 == find_pc_partial_function (pc, name ? NULL : &name, 
-                                    &start_addr, NULL))
-    return 0;
-
-  return strncmp (name, "_call_via_r", 11) == 0;
-}
-
-/* If PC is in a Thumb call or return stub, return the address of the
-   target PC, which is in a register.  The thunk functions are called
-   _called_via_xx, where x is the register name.  The possible names
-   are r0-r9, sl, fp, ip, sp, and lr.  */
+/* Recognize GCC and GNU ld's trampolines.  If we are in a trampoline,
+   return the target PC.  Otherwise return 0.  */
 
 CORE_ADDR
-arm_skip_stub (CORE_ADDR pc)
+arm_skip_stub (struct frame_info *frame, CORE_ADDR pc)
 {
   char *name;
+  int namelen;
   CORE_ADDR start_addr;
 
   /* Find the starting address and name of the function containing the PC.  */
   if (find_pc_partial_function (pc, &name, &start_addr, NULL) == 0)
     return 0;
 
-  /* Call thunks always start with "_call_via_".  */
+  /* If PC is in a Thumb call or return stub, return the address of the
+     target PC, which is in a register.  The thunk functions are called
+     _call_via_xx, where x is the register name.  The possible names
+     are r0-r9, sl, fp, ip, sp, and lr.  */
   if (strncmp (name, "_call_via_", 10) == 0)
     {
       /* Use the name suffix to determine which register contains the
@@ -2387,10 +3110,47 @@ arm_skip_stub (CORE_ADDR pc)
        "r8", "r9", "sl", "fp", "ip", "sp", "lr"
       };
       int regno;
+      int offset = strlen (name) - 2;
 
       for (regno = 0; regno <= 14; regno++)
-       if (strcmp (&name[10], table[regno]) == 0)
-         return read_register (regno);
+       if (strcmp (&name[offset], table[regno]) == 0)
+         return get_frame_register_unsigned (frame, regno);
+    }
+
+  /* GNU ld generates __foo_from_arm or __foo_from_thumb for
+     non-interworking calls to foo.  We could decode the stubs
+     to find the target but it's easier to use the symbol table.  */
+  namelen = strlen (name);
+  if (name[0] == '_' && name[1] == '_'
+      && ((namelen > 2 + strlen ("_from_thumb")
+          && strncmp (name + namelen - strlen ("_from_thumb"), "_from_thumb",
+                      strlen ("_from_thumb")) == 0)
+         || (namelen > 2 + strlen ("_from_arm")
+             && strncmp (name + namelen - strlen ("_from_arm"), "_from_arm",
+                         strlen ("_from_arm")) == 0)))
+    {
+      char *target_name;
+      int target_len = namelen - 2;
+      struct minimal_symbol *minsym;
+      struct objfile *objfile;
+      struct obj_section *sec;
+
+      if (name[namelen - 1] == 'b')
+       target_len -= strlen ("_from_thumb");
+      else
+       target_len -= strlen ("_from_arm");
+
+      target_name = alloca (target_len + 1);
+      memcpy (target_name, name + 2, target_len);
+      target_name[target_len] = '\0';
+
+      sec = find_pc_section (pc);
+      objfile = (sec == NULL) ? NULL : sec->objfile;
+      minsym = lookup_minimal_symbol (target_name, NULL, objfile);
+      if (minsym != NULL)
+       return SYMBOL_VALUE_ADDRESS (minsym);
+      else
+       return 0;
     }
 
   return 0;                    /* not a stub */
@@ -2416,7 +3176,7 @@ arm_update_current_architecture (void)
   struct gdbarch_info info;
 
   /* If the current architecture is not ARM, we have nothing to do.  */
-  if (gdbarch_bfd_arch_info (current_gdbarch)->arch != bfd_arch_arm)
+  if (gdbarch_bfd_arch_info (target_gdbarch)->arch != bfd_arch_arm)
     return;
 
   /* Update the architecture.  */
@@ -2450,10 +3210,10 @@ static void
 show_fp_model (struct ui_file *file, int from_tty,
               struct cmd_list_element *c, const char *value)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (target_gdbarch);
 
   if (arm_fp_model == ARM_FLOAT_AUTO
-      && gdbarch_bfd_arch_info (current_gdbarch)->arch == bfd_arch_arm)
+      && gdbarch_bfd_arch_info (target_gdbarch)->arch == bfd_arch_arm)
     fprintf_filtered (file, _("\
 The current ARM floating point model is \"auto\" (currently \"%s\").\n"),
                      fp_model_strings[tdep->fp_model]);
@@ -2487,10 +3247,10 @@ static void
 arm_show_abi (struct ui_file *file, int from_tty,
             struct cmd_list_element *c, const char *value)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (target_gdbarch);
 
   if (arm_abi_global == ARM_ABI_AUTO
-      && gdbarch_bfd_arch_info (current_gdbarch)->arch == bfd_arch_arm)
+      && gdbarch_bfd_arch_info (target_gdbarch)->arch == bfd_arch_arm)
     fprintf_filtered (file, _("\
 The current ARM ABI is \"auto\" (currently \"%s\").\n"),
                      arm_abi_strings[tdep->arm_abi]);
@@ -2499,6 +3259,28 @@ The current ARM ABI is \"auto\" (currently \"%s\").\n"),
                      arm_abi_string);
 }
 
+static void
+arm_show_fallback_mode (struct ui_file *file, int from_tty,
+                       struct cmd_list_element *c, const char *value)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (target_gdbarch);
+
+  fprintf_filtered (file, _("\
+The current execution mode assumed (when symbols are unavailable) is \"%s\".\n"),
+                   arm_fallback_mode_string);
+}
+
+static void
+arm_show_force_mode (struct ui_file *file, int from_tty,
+                    struct cmd_list_element *c, const char *value)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (target_gdbarch);
+
+  fprintf_filtered (file, _("\
+The current execution mode assumed (even when symbols are available) is \"%s\".\n"),
+                   arm_force_mode_string);
+}
+
 /* If the user changes the register disassembly style used for info
    register and other commands, we have to also switch the style used
    in opcodes for disassembly output.  This function is run in the "set
@@ -2513,8 +3295,34 @@ set_disassembly_style_sfunc (char *args, int from_tty,
 \f
 /* Return the ARM register name corresponding to register I.  */
 static const char *
-arm_register_name (int i)
+arm_register_name (struct gdbarch *gdbarch, int i)
 {
+  const int num_regs = gdbarch_num_regs (gdbarch);
+
+  if (gdbarch_tdep (gdbarch)->have_vfp_pseudos
+      && i >= num_regs && i < num_regs + 32)
+    {
+      static const char *const vfp_pseudo_names[] = {
+       "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
+       "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15",
+       "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
+       "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31",
+      };
+
+      return vfp_pseudo_names[i - num_regs];
+    }
+
+  if (gdbarch_tdep (gdbarch)->have_neon_pseudos
+      && i >= num_regs + 32 && i < num_regs + 32 + 16)
+    {
+      static const char *const neon_pseudo_names[] = {
+       "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
+       "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15",
+      };
+
+      return neon_pseudo_names[i - num_regs - 32];
+    }
+
   if (i >= ARRAY_SIZE (arm_register_names))
     /* These registers are only supported on targets which supply
        an XML description.  */
@@ -2576,18 +3384,213 @@ arm_coff_make_msymbol_special(int val, struct minimal_symbol *msym)
 }
 
 static void
-arm_write_pc (CORE_ADDR pc, ptid_t ptid)
+arm_objfile_data_cleanup (struct objfile *objfile, void *arg)
+{
+  struct arm_per_objfile *data = arg;
+  unsigned int i;
+
+  for (i = 0; i < objfile->obfd->section_count; i++)
+    VEC_free (arm_mapping_symbol_s, data->section_maps[i]);
+}
+
+static void
+arm_record_special_symbol (struct gdbarch *gdbarch, struct objfile *objfile,
+                          asymbol *sym)
 {
-  write_register_pid (ARM_PC_REGNUM, pc, ptid);
+  const char *name = bfd_asymbol_name (sym);
+  struct arm_per_objfile *data;
+  VEC(arm_mapping_symbol_s) **map_p;
+  struct arm_mapping_symbol new_map_sym;
+
+  gdb_assert (name[0] == '$');
+  if (name[1] != 'a' && name[1] != 't' && name[1] != 'd')
+    return;
+
+  data = objfile_data (objfile, arm_objfile_data_key);
+  if (data == NULL)
+    {
+      data = OBSTACK_ZALLOC (&objfile->objfile_obstack,
+                            struct arm_per_objfile);
+      set_objfile_data (objfile, arm_objfile_data_key, data);
+      data->section_maps = OBSTACK_CALLOC (&objfile->objfile_obstack,
+                                          objfile->obfd->section_count,
+                                          VEC(arm_mapping_symbol_s) *);
+    }
+  map_p = &data->section_maps[bfd_get_section (sym)->index];
+
+  new_map_sym.value = sym->value;
+  new_map_sym.type = name[1];
+
+  /* Assume that most mapping symbols appear in order of increasing
+     value.  If they were randomly distributed, it would be faster to
+     always push here and then sort at first use.  */
+  if (!VEC_empty (arm_mapping_symbol_s, *map_p))
+    {
+      struct arm_mapping_symbol *prev_map_sym;
+
+      prev_map_sym = VEC_last (arm_mapping_symbol_s, *map_p);
+      if (prev_map_sym->value >= sym->value)
+       {
+         unsigned int idx;
+         idx = VEC_lower_bound (arm_mapping_symbol_s, *map_p, &new_map_sym,
+                                arm_compare_mapping_symbols);
+         VEC_safe_insert (arm_mapping_symbol_s, *map_p, idx, &new_map_sym);
+         return;
+       }
+    }
+
+  VEC_safe_push (arm_mapping_symbol_s, *map_p, &new_map_sym);
+}
+
+static void
+arm_write_pc (struct regcache *regcache, CORE_ADDR pc)
+{
+  regcache_cooked_write_unsigned (regcache, ARM_PC_REGNUM, pc);
 
   /* If necessary, set the T bit.  */
   if (arm_apcs_32)
     {
-      CORE_ADDR val = read_register_pid (ARM_PS_REGNUM, ptid);
+      ULONGEST val;
+      regcache_cooked_read_unsigned (regcache, ARM_PS_REGNUM, &val);
       if (arm_pc_is_thumb (pc))
-       write_register_pid (ARM_PS_REGNUM, val | 0x20, ptid);
+       regcache_cooked_write_unsigned (regcache, ARM_PS_REGNUM, val | CPSR_T);
+      else
+       regcache_cooked_write_unsigned (regcache, ARM_PS_REGNUM,
+                                       val & ~(ULONGEST) CPSR_T);
+    }
+}
+
+/* Read the contents of a NEON quad register, by reading from two
+   double registers.  This is used to implement the quad pseudo
+   registers, and for argument passing in case the quad registers are
+   missing; vectors are passed in quad registers when using the VFP
+   ABI, even if a NEON unit is not present.  REGNUM is the index of
+   the quad register, in [0, 15].  */
+
+static void
+arm_neon_quad_read (struct gdbarch *gdbarch, struct regcache *regcache,
+                   int regnum, gdb_byte *buf)
+{
+  char name_buf[4];
+  gdb_byte reg_buf[8];
+  int offset, double_regnum;
+
+  sprintf (name_buf, "d%d", regnum << 1);
+  double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
+                                              strlen (name_buf));
+
+  /* d0 is always the least significant half of q0.  */
+  if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+    offset = 8;
+  else
+    offset = 0;
+
+  regcache_raw_read (regcache, double_regnum, reg_buf);
+  memcpy (buf + offset, reg_buf, 8);
+
+  offset = 8 - offset;
+  regcache_raw_read (regcache, double_regnum + 1, reg_buf);
+  memcpy (buf + offset, reg_buf, 8);
+}
+
+static void
+arm_pseudo_read (struct gdbarch *gdbarch, struct regcache *regcache,
+                int regnum, gdb_byte *buf)
+{
+  const int num_regs = gdbarch_num_regs (gdbarch);
+  char name_buf[4];
+  gdb_byte reg_buf[8];
+  int offset, double_regnum;
+
+  gdb_assert (regnum >= num_regs);
+  regnum -= num_regs;
+
+  if (gdbarch_tdep (gdbarch)->have_neon_pseudos && regnum >= 32 && regnum < 48)
+    /* Quad-precision register.  */
+    arm_neon_quad_read (gdbarch, regcache, regnum - 32, buf);
+  else
+    {
+      /* Single-precision register.  */
+      gdb_assert (regnum < 32);
+
+      /* s0 is always the least significant half of d0.  */
+      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+       offset = (regnum & 1) ? 0 : 4;
+      else
+       offset = (regnum & 1) ? 4 : 0;
+
+      sprintf (name_buf, "d%d", regnum >> 1);
+      double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
+                                                  strlen (name_buf));
+
+      regcache_raw_read (regcache, double_regnum, reg_buf);
+      memcpy (buf, reg_buf + offset, 4);
+    }
+}
+
+/* Store the contents of BUF to a NEON quad register, by writing to
+   two double registers.  This is used to implement the quad pseudo
+   registers, and for argument passing in case the quad registers are
+   missing; vectors are passed in quad registers when using the VFP
+   ABI, even if a NEON unit is not present.  REGNUM is the index
+   of the quad register, in [0, 15].  */
+
+static void
+arm_neon_quad_write (struct gdbarch *gdbarch, struct regcache *regcache,
+                    int regnum, const gdb_byte *buf)
+{
+  char name_buf[4];
+  gdb_byte reg_buf[8];
+  int offset, double_regnum;
+
+  sprintf (name_buf, "d%d", regnum << 1);
+  double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
+                                              strlen (name_buf));
+
+  /* d0 is always the least significant half of q0.  */
+  if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+    offset = 8;
+  else
+    offset = 0;
+
+  regcache_raw_write (regcache, double_regnum, buf + offset);
+  offset = 8 - offset;
+  regcache_raw_write (regcache, double_regnum + 1, buf + offset);
+}
+
+static void
+arm_pseudo_write (struct gdbarch *gdbarch, struct regcache *regcache,
+                 int regnum, const gdb_byte *buf)
+{
+  const int num_regs = gdbarch_num_regs (gdbarch);
+  char name_buf[4];
+  gdb_byte reg_buf[8];
+  int offset, double_regnum;
+
+  gdb_assert (regnum >= num_regs);
+  regnum -= num_regs;
+
+  if (gdbarch_tdep (gdbarch)->have_neon_pseudos && regnum >= 32 && regnum < 48)
+    /* Quad-precision register.  */
+    arm_neon_quad_write (gdbarch, regcache, regnum - 32, buf);
+  else
+    {
+      /* Single-precision register.  */
+      gdb_assert (regnum < 32);
+
+      /* s0 is always the least significant half of d0.  */
+      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+       offset = (regnum & 1) ? 0 : 4;
       else
-       write_register_pid (ARM_PS_REGNUM, val & ~(CORE_ADDR) 0x20, ptid);
+       offset = (regnum & 1) ? 4 : 0;
+
+      sprintf (name_buf, "d%d", regnum >> 1);
+      double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
+                                                  strlen (name_buf));
+
+      regcache_raw_read (regcache, double_regnum, reg_buf);
+      memcpy (reg_buf + offset, buf, 4);
+      regcache_raw_write (regcache, double_regnum, reg_buf);
     }
 }
 
@@ -2635,6 +3638,8 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   enum arm_float_model fp_model = arm_fp_model;
   struct tdesc_arch_data *tdesc_data = NULL;
   int i;
+  int have_vfp_registers = 0, have_vfp_pseudos = 0, have_neon_pseudos = 0;
+  int have_neon = 0;
   int have_fpa_registers = 1;
 
   /* Check any target description for validity.  */
@@ -2647,7 +3652,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       static const char *const arm_pc_names[] = { "r15", "pc", NULL };
 
       const struct tdesc_feature *feature;
-      int i, valid_p;
+      int valid_p;
 
       feature = tdesc_find_feature (info.target_desc,
                                    "org.gnu.gdb.arm.core");
@@ -2729,6 +3734,67 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
              return NULL;
            }
        }
+
+      /* 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,
+                                   "org.gnu.gdb.arm.vfp");
+      if (feature != NULL)
+       {
+         static const char *const vfp_double_names[] = {
+           "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
+           "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15",
+           "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
+           "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31",
+         };
+
+         /* Require the double precision registers.  There must be either
+            16 or 32.  */
+         valid_p = 1;
+         for (i = 0; i < 32; i++)
+           {
+             valid_p &= tdesc_numbered_register (feature, tdesc_data,
+                                                 ARM_D0_REGNUM + i,
+                                                 vfp_double_names[i]);
+             if (!valid_p)
+               break;
+           }
+
+         if (!valid_p && i != 16)
+           {
+             tdesc_data_cleanup (tdesc_data);
+             return NULL;
+           }
+
+         if (tdesc_unnumbered_register (feature, "s0") == 0)
+           have_vfp_pseudos = 1;
+
+         have_vfp_registers = 1;
+
+         /* 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,
+                                       "org.gnu.gdb.arm.neon");
+         if (feature != NULL)
+           {
+             /* NEON requires 32 double-precision registers.  */
+             if (i != 32)
+               {
+                 tdesc_data_cleanup (tdesc_data);
+                 return NULL;
+               }
+
+             /* If there are quad registers defined by the stub, use
+                their type; otherwise (normally) provide them with
+                the default type.  */
+             if (tdesc_unnumbered_register (feature, "q0") == 0)
+               have_neon_pseudos = 1;
+
+             have_neon = 1;
+           }
+       }
     }
 
   /* If we have an object to base this architecture on, try to determine
@@ -2776,9 +3842,45 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
                case EF_ARM_EABI_VER4:
                case EF_ARM_EABI_VER5:
                  arm_abi = ARM_ABI_AAPCS;
-                 /* EABI binaries default to VFP float ordering.  */
+                 /* 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)
-                   fp_model = ARM_FLOAT_SOFT_VFP;
+                   {
+#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:
@@ -2811,6 +3913,10 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
                  break;
                }
            }
+
+         if (e_flags & EF_ARM_BE8)
+           info.byte_order_for_code = BFD_ENDIAN_LITTLE;
+
          break;
 
        default:
@@ -2819,41 +3925,24 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
        }
     }
 
-  /* Now that we have inferred any architecture settings that we
-     can, try to inherit from the last ARM ABI.  */
-  if (arches != NULL)
-    {
-      if (arm_abi == ARM_ABI_AUTO)
-       arm_abi = gdbarch_tdep (arches->gdbarch)->arm_abi;
-
-      if (fp_model == ARM_FLOAT_AUTO)
-       fp_model = gdbarch_tdep (arches->gdbarch)->fp_model;
-    }
-  else
-    {
-      /* There was no prior ARM architecture; fill in default values.  */
-
-      if (arm_abi == ARM_ABI_AUTO)
-       arm_abi = ARM_ABI_APCS;
-
-      /* We used to default to FPA for generic ARM, but almost nobody
-        uses that now, and we now provide a way for the user to force
-        the model.  So default to the most useful variant.  */
-      if (fp_model == ARM_FLOAT_AUTO)
-       fp_model = ARM_FLOAT_SOFT_FPA;
-    }
-
   /* If there is already a candidate, use it.  */
   for (best_arch = gdbarch_list_lookup_by_info (arches, &info);
        best_arch != NULL;
        best_arch = gdbarch_list_lookup_by_info (best_arch->next, &info))
     {
-      if (arm_abi != gdbarch_tdep (best_arch->gdbarch)->arm_abi)
+      if (arm_abi != ARM_ABI_AUTO
+         && arm_abi != gdbarch_tdep (best_arch->gdbarch)->arm_abi)
        continue;
 
-      if (fp_model != gdbarch_tdep (best_arch->gdbarch)->fp_model)
+      if (fp_model != ARM_FLOAT_AUTO
+         && fp_model != gdbarch_tdep (best_arch->gdbarch)->fp_model)
        continue;
 
+      /* There are various other properties in tdep that we do not
+        need to check here: those derived from a target description,
+        since gdbarches with a different target description are
+        automatically disqualified.  */
+
       /* Found a match.  */
       break;
     }
@@ -2873,9 +3962,13 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   tdep->arm_abi = arm_abi;
   tdep->fp_model = fp_model;
   tdep->have_fpa_registers = have_fpa_registers;
+  tdep->have_vfp_registers = have_vfp_registers;
+  tdep->have_vfp_pseudos = have_vfp_pseudos;
+  tdep->have_neon_pseudos = have_neon_pseudos;
+  tdep->have_neon = have_neon;
 
   /* Breakpoints.  */
-  switch (info.byte_order)
+  switch (info.byte_order_for_code)
     {
     case BFD_ENDIAN_BIG:
       tdep->arm_breakpoint = arm_default_arm_be_breakpoint;
@@ -2915,7 +4008,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_write_pc (gdbarch, arm_write_pc);
 
   /* Frame handling.  */
-  set_gdbarch_unwind_dummy_id (gdbarch, arm_unwind_dummy_id);
+  set_gdbarch_dummy_id (gdbarch, arm_dummy_id);
   set_gdbarch_unwind_pc (gdbarch, arm_unwind_pc);
   set_gdbarch_unwind_sp (gdbarch, arm_unwind_sp);
 
@@ -2950,12 +4043,9 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
     set_gdbarch_print_float_info (gdbarch, arm_print_float_info);
 
   /* Internal <-> external register number maps.  */
-  set_gdbarch_dwarf_reg_to_regnum (gdbarch, arm_dwarf_reg_to_regnum);
   set_gdbarch_dwarf2_reg_to_regnum (gdbarch, arm_dwarf_reg_to_regnum);
   set_gdbarch_register_sim_regno (gdbarch, arm_register_sim_regno);
 
-  /* Integer registers are 4 bytes.  */
-  set_gdbarch_deprecated_register_size (gdbarch, 4);
   set_gdbarch_register_name (gdbarch, arm_register_name);
 
   /* Returning results.  */
@@ -2968,6 +4058,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_elf_make_msymbol_special (gdbarch, arm_elf_make_msymbol_special);
   set_gdbarch_coff_make_msymbol_special (gdbarch,
                                         arm_coff_make_msymbol_special);
+  set_gdbarch_record_special_symbol (gdbarch, arm_record_special_symbol);
 
   /* Virtual tables.  */
   set_gdbarch_vbit_in_delta (gdbarch, 1);
@@ -2975,20 +4066,33 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   /* Hook in the ABI-specific overrides, if they have been registered.  */
   gdbarch_init_osabi (info, gdbarch);
 
+  dwarf2_frame_set_init_reg (gdbarch, arm_dwarf2_frame_init_reg);
+
   /* Add some default predicates.  */
-  frame_unwind_append_sniffer (gdbarch, arm_stub_unwind_sniffer);
-  frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
-  frame_unwind_append_sniffer (gdbarch, arm_prologue_unwind_sniffer);
+  frame_unwind_append_unwinder (gdbarch, &arm_stub_unwind);
+  dwarf2_append_unwinders (gdbarch);
+  frame_unwind_append_unwinder (gdbarch, &arm_prologue_unwind);
 
   /* Now we have tuned the configuration, set a few final things,
      based on what the OS ABI has told us.  */
 
+  /* If the ABI is not otherwise marked, assume the old GNU APCS.  EABI
+     binaries are always marked.  */
+  if (tdep->arm_abi == ARM_ABI_AUTO)
+    tdep->arm_abi = ARM_ABI_APCS;
+
+  /* We used to default to FPA for generic ARM, but almost nobody
+     uses that now, and we now provide a way for the user to force
+     the model.  So default to the most useful variant.  */
+  if (tdep->fp_model == ARM_FLOAT_AUTO)
+    tdep->fp_model = ARM_FLOAT_SOFT_FPA;
+
   if (tdep->jb_pc >= 0)
     set_gdbarch_get_longjmp_target (gdbarch, arm_get_longjmp_target);
 
   /* Floating point sizes and format.  */
   set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
-  if (fp_model == ARM_FLOAT_SOFT_FPA || fp_model == ARM_FLOAT_FPA)
+  if (tdep->fp_model == ARM_FLOAT_SOFT_FPA || tdep->fp_model == ARM_FLOAT_FPA)
     {
       set_gdbarch_double_format
        (gdbarch, floatformats_ieee_double_littlebyte_bigword);
@@ -3001,8 +4105,30 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
     }
 
+  if (have_vfp_pseudos)
+    {
+      /* NOTE: These are the only pseudo registers used by
+        the ARM target at the moment.  If more are added, a
+        little more care in numbering will be needed.  */
+
+      int num_pseudos = 32;
+      if (have_neon_pseudos)
+       num_pseudos += 16;
+      set_gdbarch_num_pseudo_regs (gdbarch, num_pseudos);
+      set_gdbarch_pseudo_register_read (gdbarch, arm_pseudo_read);
+      set_gdbarch_pseudo_register_write (gdbarch, arm_pseudo_write);
+    }
+
   if (tdesc_data)
-    tdesc_use_registers (gdbarch, tdesc_data);
+    {
+      set_tdesc_pseudo_register_name (gdbarch, arm_register_name);
+
+      tdesc_use_registers (gdbarch, info.target_desc, tdesc_data);
+
+      /* Override tdesc_register_type to adjust the types of VFP
+        registers for NEON.  */
+      set_gdbarch_register_type (gdbarch, arm_register_type);
+    }
 
   /* Add standard register aliases.  We add aliases even for those
      nanes which are used by the current architecture - it's simpler,
@@ -3015,9 +4141,9 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 }
 
 static void
-arm_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
+arm_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
   if (tdep == NULL)
     return;
@@ -3044,6 +4170,9 @@ _initialize_arm_tdep (void)
 
   gdbarch_register (bfd_arch_arm, arm_gdbarch_init, arm_dump_tdep);
 
+  arm_objfile_data_key
+    = register_objfile_data_with_cleanup (arm_objfile_data_cleanup);
+
   /* Register an ELF OS ABI sniffer for ARM binaries.  */
   gdbarch_register_osabi_sniffer (bfd_arch_arm,
                                  bfd_target_elf_flavour,
@@ -3131,6 +4260,21 @@ vfp - VFP co-processor."),
                        NULL, arm_set_abi, arm_show_abi,
                        &setarmcmdlist, &showarmcmdlist);
 
+  /* Add two commands to allow the user to force the assumed
+     execution mode.  */
+  add_setshow_enum_cmd ("fallback-mode", class_support,
+                       arm_mode_strings, &arm_fallback_mode_string,
+                       _("Set the mode assumed when symbols are unavailable."),
+                       _("Show the mode assumed when symbols are unavailable."),
+                       NULL, NULL, arm_show_fallback_mode,
+                       &setarmcmdlist, &showarmcmdlist);
+  add_setshow_enum_cmd ("force-mode", class_support,
+                       arm_mode_strings, &arm_force_mode_string,
+                       _("Set the mode assumed even when symbols are available."),
+                       _("Show the mode assumed even when symbols are available."),
+                       NULL, NULL, arm_show_force_mode,
+                       &setarmcmdlist, &showarmcmdlist);
+
   /* Debugging flag.  */
   add_setshow_boolean_cmd ("arm", class_maintenance, &arm_debug,
                           _("Set ARM debugging."),
This page took 0.069564 seconds and 4 git commands to generate.