2004-07-26 Andrew Cagney <cagney@gnu.org>
[deliverable/binutils-gdb.git] / gdb / arm-tdep.c
index 411d7d6a185f7a6670e9e13f73192b002fbe614f..b44768cdaad1425427223a486b372c1b71c1e016 100644 (file)
@@ -1,6 +1,6 @@
 /* Common target dependent code for GDB on ARM systems.
    Copyright 1988, 1989, 1991, 1992, 1993, 1995, 1996, 1998, 1999, 2000,
-   2001, 2002, 2003 Free Software Foundation, Inc.
+   2001, 2002, 2003, 2004 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -26,7 +26,6 @@
 #include "inferior.h"
 #include "gdbcmd.h"
 #include "gdbcore.h"
-#include "symfile.h"
 #include "gdb_string.h"
 #include "dis-asm.h"           /* For register styles. */
 #include "regcache.h"
@@ -34,6 +33,9 @@
 #include "value.h"
 #include "arch-utils.h"
 #include "osabi.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "trad-frame.h"
 
 #include "arm-tdep.h"
 #include "gdb/sim-arm.h"
@@ -78,15 +80,10 @@ static int arm_debug;
 
 /* Macros for setting and testing a bit in a minimal symbol that marks
    it as Thumb function.  The MSB of the minimal symbol's "info" field
-   is used for this purpose. This field is already being used to store
-   the symbol size, so the assumption is that the symbol size cannot
-   exceed 2^31.
+   is used for this purpose.
 
    MSYMBOL_SET_SPECIAL Actually sets the "special" bit.
-   MSYMBOL_IS_SPECIAL   Tests the "special" bit in a minimal symbol.
-   MSYMBOL_SIZE         Returns the size of the minimal symbol,
-                       i.e. the "info" field with the "special" bit
-                       masked out.  */
+   MSYMBOL_IS_SPECIAL   Tests the "special" bit in a minimal symbol.  */
 
 #define MSYMBOL_SET_SPECIAL(msym)                                      \
        MSYMBOL_INFO (msym) = (char *) (((long) MSYMBOL_INFO (msym))    \
@@ -95,9 +92,6 @@ static int arm_debug;
 #define MSYMBOL_IS_SPECIAL(msym)                               \
        (((long) MSYMBOL_INFO (msym) & 0x80000000) != 0)
 
-#define MSYMBOL_SIZE(msym)                             \
-       ((long) MSYMBOL_INFO (msym) & 0x7fffffff)
-
 /* The list of available "set arm ..." and "show arm ..." commands.  */
 static struct cmd_list_element *setarmcmdlist = NULL;
 static struct cmd_list_element *showarmcmdlist = NULL;
@@ -155,21 +149,26 @@ static void convert_from_extended (const struct floatformat *, const void *,
 static void convert_to_extended (const struct floatformat *, void *,
                                 const void *);
 
-/* Define other aspects of the stack frame.  We keep the offsets of
-   all saved registers, 'cause we need 'em a lot!  We also keep the
-   current size of the stack frame, and the offset of the frame
-   pointer from the stack pointer (for frameless functions, and when
-   we're still in the prologue of a function with a frame).  */
-
-#define arm_get_cache(fi) ((struct arm_prologue_cache *) get_frame_extra_info (fi))
-
 struct arm_prologue_cache
 {
-  CORE_ADDR unwound_sp, unwound_pc;
+  /* The stack pointer at the time this frame was created; i.e. the
+     caller's stack pointer when this function was called.  It is used
+     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.  */
+
   int framesize;
   int frameoffset;
+
+  /* The register used to hold the frame pointer for this frame.  */
   int framereg;
-  CORE_ADDR saved_regs[1];
+
+  /* Saved register offsets.  */
+  struct trad_frame_saved_reg *saved_regs;
 };
 
 /* Addresses for calling Thumb functions have the bit 0 set.
@@ -178,12 +177,6 @@ struct arm_prologue_cache
 #define MAKE_THUMB_ADDR(addr)  ((addr) | 1)
 #define UNMAKE_THUMB_ADDR(addr) ((addr) & ~1)
 
-static int
-arm_frame_chain_valid (CORE_ADDR chain, struct frame_info *thisframe)
-{
-  return (DEPRECATED_FRAME_SAVED_PC (thisframe) >= LOWEST_PC);
-}
-
 /* Set to true if the 32-bit mode is in use.  */
 
 int arm_apcs_32 = 1;
@@ -198,7 +191,7 @@ static int target_is_thumb;
 
 /* Flag set by arm_fix_call_dummy that tells whether the calling
    function is a Thumb function.  This flag is checked by
-   arm_pc_is_thumb and arm_call_dummy_breakpoint_offset.  */
+   arm_pc_is_thumb.  */
 
 static int caller_is_thumb;
 
@@ -241,7 +234,7 @@ arm_pc_is_thumb_dummy (CORE_ADDR memaddr)
      frame location (true if we have not pushed large data structures or
      gone too many levels deep) and that our 1024 is not enough to consider
      code regions as part of the stack (true for most practical purposes).  */
-  if (DEPRECATED_PC_IN_CALL_DUMMY (memaddr, sp, sp + 1024))
+  if (deprecated_pc_in_call_dummy (memaddr))
     return caller_is_thumb;
   else
     return 0;
@@ -298,7 +291,7 @@ arm_frameless_function_invocation (struct frame_info *fi)
        stmdb sp!, {}
        sub sp, ip, #4.  */
 
-  func_start = (get_frame_func (fi) + FUNCTION_START_OFFSET);
+  func_start = (get_frame_func (fi) + DEPRECATED_FUNCTION_START_OFFSET);
   after_prologue = SKIP_PROLOGUE (func_start);
 
   /* There are some frameless functions whose first two instructions
@@ -414,7 +407,7 @@ arm_skip_prologue (CORE_ADDR 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, 0, 0))
+  if (deprecated_pc_in_call_dummy (pc))
     return pc;
 
   /* See what the symbol table says.  */
@@ -453,6 +446,12 @@ arm_skip_prologue (CORE_ADDR pc)
       if (inst == 0xe1a0c00d)                  /* mov ip, sp */
        continue;
 
+      if ((inst & 0xfffff000) == 0xe28dc000)    /* add ip, sp #n */
+       continue;
+
+      if ((inst & 0xfffff000) == 0xe24dc000)    /* sub ip, sp #n */
+       continue;
+
       /* Some prologues begin with "str lr, [sp, #-4]!".  */
       if (inst == 0xe52de004)                  /* str lr, [sp, #-4]! */
        continue;
@@ -506,7 +505,6 @@ arm_skip_prologue (CORE_ADDR pc)
      2) which registers are saved on it
      3) the offsets of saved regs
      4) the offset from the stack pointer to the frame pointer
-   This information is stored in the "extra" fields of the frame_info.
 
    A typical Thumb function prologue would create this stack frame
    (offsets relative to FP)
@@ -523,7 +521,7 @@ arm_skip_prologue (CORE_ADDR pc)
 /* *INDENT-ON* */
 
 static void
-thumb_scan_prologue (struct arm_prologue_cache *cache)
+thumb_scan_prologue (CORE_ADDR prev_pc, struct arm_prologue_cache *cache)
 {
   CORE_ADDR prologue_start;
   CORE_ADDR prologue_end;
@@ -538,16 +536,12 @@ thumb_scan_prologue (struct arm_prologue_cache *cache)
   int findmask = 0;
   int i;
 
-  /* Don't try to scan dummy frames.  */
-  if (DEPRECATED_PC_IN_CALL_DUMMY (cache->unwound_pc, 0, 0))
-    return;
-
-  if (find_pc_partial_function (cache->unwound_pc, NULL, &prologue_start, &prologue_end))
+  if (find_pc_partial_function (prev_pc, NULL, &prologue_start, &prologue_end))
     {
       struct symtab_and_line sal = find_pc_line (prologue_start, 0);
 
       if (sal.line == 0)               /* no line info, use current PC  */
-       prologue_end = cache->unwound_pc;
+       prologue_end = prev_pc;
       else if (sal.end < prologue_end) /* next line begins after fn end */
        prologue_end = sal.end;         /* (probably means no prologue)  */
     }
@@ -556,7 +550,7 @@ thumb_scan_prologue (struct arm_prologue_cache *cache)
        16 pushes, an add, and "mv fp,sp".  */
     prologue_end = prologue_start + 40;
 
-  prologue_end = min (prologue_end, cache->unwound_pc);
+  prologue_end = min (prologue_end, prev_pc);
 
   /* Initialize the saved register map.  When register H is copied to
      register L, we will put H in saved_reg[L].  */
@@ -591,7 +585,7 @@ thumb_scan_prologue (struct arm_prologue_cache *cache)
            if (mask & (1 << regno))
              {
                cache->framesize += 4;
-               cache->saved_regs[saved_reg[regno]] = -cache->framesize;
+               cache->saved_regs[saved_reg[regno]].addr = -cache->framesize;
                /* Reset saved register map.  */
                saved_reg[regno] = regno;
              }
@@ -708,11 +702,11 @@ thumb_scan_prologue (struct arm_prologue_cache *cache)
  */
 
 static void
-arm_scan_prologue (struct arm_prologue_cache *cache)
+arm_scan_prologue (struct frame_info *next_frame, struct arm_prologue_cache *cache)
 {
-  int regno, sp_offset, fp_offset;
-  LONGEST return_value;
+  int regno, sp_offset, fp_offset, ip_offset;
   CORE_ADDR prologue_start, prologue_end, current_pc;
+  CORE_ADDR prev_pc = frame_pc_unwind (next_frame);
 
   /* Assume there is no frame until proven otherwise.  */
   cache->framereg = ARM_SP_REGNUM;
@@ -720,15 +714,15 @@ arm_scan_prologue (struct arm_prologue_cache *cache)
   cache->frameoffset = 0;
 
   /* Check for Thumb prologue.  */
-  if (arm_pc_is_thumb (cache->unwound_pc))
+  if (arm_pc_is_thumb (prev_pc))
     {
-      thumb_scan_prologue (cache);
+      thumb_scan_prologue (prev_pc, 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 (cache->unwound_pc, NULL, &prologue_start, &prologue_end))
+  if (find_pc_partial_function (prev_pc, 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:
@@ -736,7 +730,7 @@ arm_scan_prologue (struct arm_prologue_cache *cache)
            struct symtab_and_line sal = find_pc_line (prologue_start, 0);
 
            if (sal.line == 0)
-             prologue_end = cache->unwound_pc;
+             prologue_end = prev_pc;
            else if (sal.end < prologue_end)
              prologue_end = sal.end;
 
@@ -769,9 +763,16 @@ arm_scan_prologue (struct arm_prologue_cache *cache)
     }
   else
     {
-      /* Get address of the stmfd in the prologue of the callee; 
-         the saved PC is the address of the stmfd + 8.  */
-      if (!safe_read_memory_integer (cache->unwound_sp, 4,  &return_value))
+      /* We have no symbol information.  Our only option is to assume this
+        function has a standard stack frame and the normal frame register.
+        Then, we can find the value of our frame pointer on entrance to
+        the callee (or at the present moment if this is the innermost frame).
+        The value stored there should be the address of the stmfd + 8.  */
+      CORE_ADDR frame_loc;
+      LONGEST return_value;
+
+      frame_loc = frame_unwind_register_unsigned (next_frame, ARM_FP_REGNUM);
+      if (!safe_read_memory_integer (frame_loc, 4, &return_value))
         return;
       else
         {
@@ -780,6 +781,9 @@ arm_scan_prologue (struct arm_prologue_cache *cache)
         }
     }
 
+  if (prev_pc < prologue_end)
+    prologue_end = prev_pc;
+
   /* Now search the prologue looking for instructions that set up the
      frame pointer, adjust the stack pointer, and save registers.
 
@@ -801,7 +805,7 @@ arm_scan_prologue (struct arm_prologue_cache *cache)
      in which case it is often (but not always) replaced by
      "str lr, [sp, #-4]!".  - Michael Snyder, 2002-04-23]  */
 
-  sp_offset = fp_offset = 0;
+  sp_offset = fp_offset = ip_offset = 0;
 
   for (current_pc = prologue_start;
        current_pc < prologue_end;
@@ -811,11 +815,29 @@ arm_scan_prologue (struct arm_prologue_cache *cache)
 
       if (insn == 0xe1a0c00d)          /* mov ip, sp */
        {
+         ip_offset = 0;
+         continue;
+       }
+      else if ((insn & 0xfffff000) == 0xe28dc000) /* add ip, sp #n */
+       {
+         unsigned imm = insn & 0xff;                   /* immediate value */
+         unsigned rot = (insn & 0xf00) >> 7;           /* rotate amount */
+         imm = (imm >> rot) | (imm << (32 - rot));
+         ip_offset = imm;
+         continue;
+       }
+      else if ((insn & 0xfffff000) == 0xe24dc000) /* sub ip, sp #n */
+       {
+         unsigned imm = insn & 0xff;                   /* immediate value */
+         unsigned rot = (insn & 0xf00) >> 7;           /* rotate amount */
+         imm = (imm >> rot) | (imm << (32 - rot));
+         ip_offset = -imm;
          continue;
        }
       else if (insn == 0xe52de004)     /* str lr, [sp, #-4]! */
        {
-         /* Function is frameless: extra_info defaults OK?  */
+         sp_offset -= 4;
+         cache->saved_regs[ARM_LR_REGNUM].addr = sp_offset;
          continue;
        }
       else if ((insn & 0xffff0000) == 0xe92d0000)
@@ -830,7 +852,7 @@ arm_scan_prologue (struct arm_prologue_cache *cache)
            if (mask & (1 << regno))
              {
                sp_offset -= 4;
-               cache->saved_regs[regno] = sp_offset;
+               cache->saved_regs[regno].addr = sp_offset;
              }
        }
       else if ((insn & 0xffffc000) == 0xe54b0000 ||    /* strb rx,[r11,#-n] */
@@ -852,7 +874,7 @@ arm_scan_prologue (struct arm_prologue_cache *cache)
          unsigned imm = insn & 0xff;                   /* immediate value */
          unsigned rot = (insn & 0xf00) >> 7;           /* rotate amount */
          imm = (imm >> rot) | (imm << (32 - rot));
-         fp_offset = -imm;
+         fp_offset = -imm + ip_offset;
          cache->framereg = ARM_FP_REGNUM;
        }
       else if ((insn & 0xfffff000) == 0xe24dd000)      /* sub sp, sp #n */
@@ -866,7 +888,7 @@ arm_scan_prologue (struct arm_prologue_cache *cache)
        {
          sp_offset -= 12;
          regno = ARM_F0_REGNUM + ((insn >> 12) & 0x07);
-         cache->saved_regs[regno] = sp_offset;
+         cache->saved_regs[regno].addr = sp_offset;
        }
       else if ((insn & 0xffbf0fff) == 0xec2d0200)      /* sfmfd f0, 4, [sp!] */
        {
@@ -893,7 +915,7 @@ arm_scan_prologue (struct arm_prologue_cache *cache)
          for (; fp_start_reg < fp_bound_reg; fp_start_reg++)
            {
              sp_offset -= 12;
-             cache->saved_regs[fp_start_reg++] = sp_offset;
+             cache->saved_regs[fp_start_reg++].addr = sp_offset;
            }
        }
       else if ((insn & 0xf0000000) != 0xe0000000)
@@ -916,481 +938,239 @@ arm_scan_prologue (struct arm_prologue_cache *cache)
     cache->frameoffset = 0;
 }
 
-/* Find REGNUM on the stack.  Otherwise, it's in an active register.
-   One thing we might want to do here is to check REGNUM against the
-   clobber mask, and somehow flag it as invalid if it isn't saved on
-   the stack somewhere.  This would provide a graceful failure mode
-   when trying to get the value of caller-saves registers for an inner
-   frame.  */
-
-static CORE_ADDR
-arm_find_callers_reg (struct frame_info *fi, int regnum)
-{
-  /* NOTE: cagney/2002-05-03: This function really shouldn't be
-     needed.  Instead the (still being written) register unwind
-     function could be called directly.  */
-  for (; fi; fi = get_next_frame (fi))
-    {
-      if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (fi), 0, 0))
-       {
-         return deprecated_read_register_dummy (get_frame_pc (fi),
-                                                get_frame_base (fi), regnum);
-       }
-      else if (get_frame_saved_regs (fi)[regnum] != 0)
-       {
-         /* NOTE: cagney/2002-05-03: This would normally need to
-             handle ARM_SP_REGNUM as a special case as, according to
-             the frame.h comments, saved_regs[SP_REGNUM] contains the
-             SP value not its address.  It appears that the ARM isn't
-             doing this though.  */
-         return read_memory_integer (get_frame_saved_regs (fi)[regnum],
-                                     REGISTER_RAW_SIZE (regnum));
-       }
-    }
-  return read_register (regnum);
-}
-/* Function: frame_chain Given a GDB frame, determine the address of
-   the calling function's frame.  This will be used to create a new
-   GDB frame struct, and then DEPRECATED_INIT_EXTRA_FRAME_INFO and
-   DEPRECATED_INIT_FRAME_PC will be called for the new frame.  For
-   ARM, we save the frame size when we initialize the frame_info.  */
-
-CORE_ADDR
-arm_minimal_frame_chain (struct frame_info *next_frame, struct arm_prologue_cache *cache)
-{
-  CORE_ADDR caller_pc;
-  int framereg = arm_get_cache (next_frame)->framereg;
-
-  if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (next_frame), 0, 0))
-    return get_frame_base (next_frame);
-
-  if (get_frame_pc (next_frame) < LOWEST_PC)
-    return 0;
-
-  caller_pc = cache->unwound_pc;
-
-  /* If the caller is Thumb and the caller is ARM, or vice versa,
-     the frame register of the caller is different from ours.
-     So we must scan the prologue of the caller to determine its
-     frame register number.  */
-  /* XXX Fixme, we should try to do this without creating a temporary
-     cache!  */
-  /* NOTE drow/2003-06-26: I'm quite suspicious of this code... what is it
-     really doing?  I have the feeling that it's trying to handle the case
-     where my framereg is ARM_FP_REGNUM, and my (Thumb) caller's framereg is
-     THUMB_FP_REGNUM, and switching between the two.  But the unwinder should
-     be taking care of that.  */
-  if (arm_pc_is_thumb (caller_pc) != arm_pc_is_thumb (get_frame_pc (next_frame)))
-    {
-      struct arm_prologue_cache *cache
-       = xcalloc (1, sizeof (struct arm_prologue_cache)
-                  + (NUM_REGS + NUM_PSEUDO_REGS - 1) * sizeof (CORE_ADDR));
-      struct cleanup *old_chain = make_cleanup (xfree, cache);
-
-      /* Now, scan the prologue and obtain the frame register.  */
-      cache->unwound_pc = caller_pc;
-      arm_scan_prologue (cache);
-      framereg = cache->framereg;
-
-      /* Deallocate the storage associated with the temporary frame
-        created above.  */
-      do_cleanups (old_chain);
-    }
-
-  /* If the caller used a frame register, return its value.
-     Otherwise, return the caller's stack pointer.  */
-  if (framereg == ARM_FP_REGNUM || framereg == THUMB_FP_REGNUM)
-    return arm_find_callers_reg (next_frame, framereg);
-  else
-    /* FIXME drow/2003-06-26: The next frame is an opaque thing at this point,
-       we should only be using frame methods on it.  What if it's a dummy
-       frame, calling a frameless function (framereg == ARM_SP_REGNUM)?  Test
-       it.  */
-    return get_frame_base (next_frame) + arm_get_cache (next_frame)->framesize;
-}
-
-/* This function actually figures out the frame address for a given pc
-   and sp.  This is tricky because we sometimes don't use an explicit
-   frame pointer, and the previous stack pointer isn't necessarily
-   recorded on the stack.  The only reliable way to get this info is
-   to examine the prologue.  */
-
-static void
-arm_minimal_frame_info (struct frame_info *next_frame,
-                       struct arm_prologue_cache *cache)
+static struct arm_prologue_cache *
+arm_make_prologue_cache (struct frame_info *next_frame)
 {
   int reg;
-  CORE_ADDR sp;
-
-  memset (cache->saved_regs, '\000', sizeof (CORE_ADDR) * (NUM_REGS + NUM_PSEUDO_REGS));
-
-  /* Compute stack pointer for this frame.  We use this value for both
-     the sigtramp and call dummy cases.  */
-
-  if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (next_frame), 0, 0))
-    /* For generic dummy frames, pull the value direct from the frame.
-       Having an unwind function to do this would be nice.  */
-    sp = deprecated_read_register_dummy (get_frame_pc (next_frame),
-                                        get_frame_base (next_frame),
-                                        ARM_SP_REGNUM);
-  else if (arm_get_cache (next_frame))
-    sp = (get_frame_base (next_frame)
-         - arm_get_cache (next_frame)->frameoffset
-         + arm_get_cache (next_frame)->framesize);
-  else
-    sp = read_sp ();  /* FIXME remove case */
+  struct arm_prologue_cache *cache;
+  CORE_ADDR unwound_fp;
 
-  /* Determine whether or not we're in a sigtramp frame.
-     Unfortunately, it isn't sufficient to test (get_frame_type (fi)
-     == SIGTRAMP_FRAME) because this value is sometimes set after
-     invoking DEPRECATED_INIT_EXTRA_FRAME_INFO.  So we test *both*
-     (get_frame_type (fi) == SIGTRAMP_FRAME) and PC_IN_SIGTRAMP to
-     determine if we need to use the sigcontext addresses for the
-     saved registers.
+  cache = frame_obstack_zalloc (sizeof (struct arm_prologue_cache));
+  cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
 
-     Note: If an ARM PC_IN_SIGTRAMP method ever needs to compare
-     against the name of the function, the code below will have to be
-     changed to first fetch the name of the function and then pass
-     this name to PC_IN_SIGTRAMP.  */
+  arm_scan_prologue (next_frame, cache);
 
-  /* FIXME: cagney/2002-11-18: This problem will go away once
-     frame.c:get_prev_frame() is modified to set the frame's type
-     before calling functions like this.  */
+  unwound_fp = frame_unwind_register_unsigned (next_frame, cache->framereg);
+  if (unwound_fp == 0)
+    return cache;
 
-  /* NOTE drow/2003-06-26: This will move to a predicate for a different unwinder shortly.  */
+  cache->prev_sp = unwound_fp + cache->framesize - cache->frameoffset;
 
-  if (SIGCONTEXT_REGISTER_ADDRESS_P () 
-      && PC_IN_SIGTRAMP (cache->unwound_pc, (char *)0))
-    {
-      for (reg = 0; reg < NUM_REGS; reg++)
-       cache->saved_regs[reg] = SIGCONTEXT_REGISTER_ADDRESS (sp, cache->unwound_pc, reg);
-
-      /* FIXME: What about thumb mode?  */
-      cache->framereg = ARM_SP_REGNUM;
-      cache->unwound_sp = read_memory_integer (cache->saved_regs[cache->framereg], REGISTER_RAW_SIZE (cache->framereg));
-      cache->framesize = 0;
-      cache->frameoffset = 0;
-    }
-  else
-    {
-      /* At this point, the unwound sp is just the result of frame_chain.
-        Then it gets changed below.  */
-
-      arm_scan_prologue (cache);
-
-      if (!next_frame)
-       /* This is the innermost frame?  */
-       cache->unwound_sp = read_register (cache->framereg);
-      else if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (next_frame), 0, 0))
-       /* Next inner most frame is a dummy, just grab its frame.
-           Dummy frames always have the same FP as their caller.  */
-       cache->unwound_sp = get_frame_base (next_frame);
-      else if (cache->framereg == ARM_FP_REGNUM
-              || cache->framereg == THUMB_FP_REGNUM)
-       {
-         /* not the innermost frame */
-         /* If we have an FP, the callee saved it.  */
-         if (get_frame_saved_regs (next_frame) /**/ && get_frame_saved_regs (next_frame)[cache->framereg] != 0)
-           cache->unwound_sp = read_memory_integer (get_frame_saved_regs (next_frame)[cache->framereg], 4);
-         else if (frame_relative_level (next_frame) == 0
-                  && FRAMELESS_FUNCTION_INVOCATION (next_frame))
-           /* If we were called by a frameless fn.  then our frame is
-              still in the frame pointer register on the board...  */
-           cache->unwound_sp = deprecated_read_fp ();
-       }
+  /* Calculate actual addresses of saved registers using offsets
+     determined by arm_scan_prologue.  */
+  for (reg = 0; reg < NUM_REGS; reg++)
+    if (trad_frame_addr_p (cache->saved_regs, reg))
+      cache->saved_regs[reg].addr += cache->prev_sp;
 
-      /* Calculate actual addresses of saved registers using offsets
-         determined by arm_scan_prologue.  */
-      for (reg = 0; reg < NUM_REGS; reg++)
-       if (cache->saved_regs[reg] != 0)
-         cache->saved_regs[reg] = (cache->saved_regs[reg]
-                                   + cache->unwound_sp
-                                   + cache->framesize
-                                   - cache->frameoffset);
-    }
+  return cache;
 }
 
-static struct arm_prologue_cache *
-arm_make_prologue_cache (struct frame_info *next_frame)
+/* Our frame ID for a normal frame is the current function's starting PC
+   and the caller's SP when we were called.  */
+
+static void
+arm_prologue_this_id (struct frame_info *next_frame,
+                     void **this_cache,
+                     struct frame_id *this_id)
 {
   struct arm_prologue_cache *cache;
+  struct frame_id id;
+  CORE_ADDR func;
 
-  cache = frame_obstack_zalloc (sizeof (struct arm_prologue_cache)
-                               + sizeof (CORE_ADDR) * (NUM_REGS + NUM_PSEUDO_REGS - 1));
+  if (*this_cache == NULL)
+    *this_cache = arm_make_prologue_cache (next_frame);
+  cache = *this_cache;
 
-  cache->unwound_pc = frame_pc_unwind (next_frame);
-  if (frame_relative_level (next_frame) < 0)
-    cache->unwound_sp = deprecated_read_fp ();
-  else
-    cache->unwound_sp = arm_minimal_frame_chain (next_frame, cache);
-  arm_minimal_frame_info (next_frame, cache);
+  func = frame_func_unwind (next_frame);
 
-  return cache;
-}
+  /* 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)
+    return;
 
-static CORE_ADDR
-arm_frame_chain (struct frame_info *next_frame)
-{
-  struct arm_prologue_cache *cache;
+  /* If we've hit a wall, stop.  */
+  if (cache->prev_sp == 0)
+    return;
 
-  cache = arm_make_prologue_cache (next_frame);
-  return cache->unwound_sp;
+  id = frame_id_build (cache->prev_sp, func);
+  *this_id = id;
 }
 
 static void
-arm_init_extra_frame_info (int fromleaf, struct frame_info *fi)
+arm_prologue_prev_register (struct frame_info *next_frame,
+                           void **this_cache,
+                           int prev_regnum,
+                           int *optimized,
+                           enum lval_type *lvalp,
+                           CORE_ADDR *addrp,
+                           int *realnump,
+                           void *valuep)
 {
   struct arm_prologue_cache *cache;
 
-  cache = arm_make_prologue_cache (deprecated_get_next_frame_hack (fi));
+  if (*this_cache == NULL)
+    *this_cache = arm_make_prologue_cache (next_frame);
+  cache = *this_cache;
 
-  if (get_frame_saved_regs (fi) == NULL)
-    frame_saved_regs_zalloc (fi);
+  /* 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.  */
+  if (prev_regnum == ARM_PC_REGNUM)
+    prev_regnum = ARM_LR_REGNUM;
 
-  frame_extra_info_zalloc (fi, (sizeof (struct arm_prologue_cache)
-                               + ((NUM_REGS + NUM_PSEUDO_REGS - 1)
-                                  * sizeof (CORE_ADDR))));
+  /* 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.
+     The value was already reconstructed into PREV_SP.  */
+  if (prev_regnum == ARM_SP_REGNUM)
+    {
+      *lvalp = not_lval;
+      if (valuep)
+       store_unsigned_integer (valuep, 4, cache->prev_sp);
+      return;
+    }
 
-  memcpy (get_frame_extra_info (fi), cache,  (sizeof (struct arm_prologue_cache)
-                                             + ((NUM_REGS + NUM_PSEUDO_REGS - 1)
-                                                * sizeof (CORE_ADDR))));
-  memcpy (get_frame_saved_regs (fi), cache->saved_regs,
-         (NUM_REGS + NUM_PSEUDO_REGS - 1) * sizeof (CORE_ADDR));
+  trad_frame_prev_register (next_frame, cache->saved_regs, prev_regnum,
+                           optimized, lvalp, addrp, realnump, valuep);
 }
 
-/* Find the caller of this frame.  We do this by seeing if ARM_LR_REGNUM
-   is saved in the stack anywhere, otherwise we get it from the
-   registers.
+struct frame_unwind arm_prologue_unwind = {
+  NORMAL_FRAME,
+  arm_prologue_this_id,
+  arm_prologue_prev_register
+};
 
-   The old definition of this function was a macro:
-   #define FRAME_SAVED_PC(FRAME) \
-   ADDR_BITS_REMOVE (read_memory_integer ((FRAME)->frame - 4, 4)) */
+static const struct frame_unwind *
+arm_prologue_unwind_sniffer (struct frame_info *next_frame)
+{
+  return &arm_prologue_unwind;
+}
 
 static CORE_ADDR
-arm_frame_saved_pc (struct frame_info *fi)
+arm_normal_frame_base (struct frame_info *next_frame, void **this_cache)
 {
-  /* If a dummy frame, pull the PC out of the frame's register buffer.  */
-  if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (fi), 0, 0))
-    return deprecated_read_register_dummy (get_frame_pc (fi),
-                                          get_frame_base (fi), ARM_PC_REGNUM);
+  struct arm_prologue_cache *cache;
 
-  if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (fi),
-                                  (get_frame_base (fi)
-                                   - arm_get_cache (fi)->frameoffset),
-                                  get_frame_base (fi)))
-    {
-      return read_memory_integer (get_frame_saved_regs (fi)[ARM_PC_REGNUM],
-                                 REGISTER_RAW_SIZE (ARM_PC_REGNUM));
-    }
-  else
-    {
-      CORE_ADDR pc = arm_find_callers_reg (fi, ARM_LR_REGNUM);
-      return IS_THUMB_ADDR (pc) ? UNMAKE_THUMB_ADDR (pc) : pc;
-    }
+  if (*this_cache == NULL)
+    *this_cache = arm_make_prologue_cache (next_frame);
+  cache = *this_cache;
+
+  return cache->prev_sp + cache->frameoffset - cache->framesize;
 }
 
-/* Return the frame address.  On ARM, it is R11; on Thumb it is R7.
-   Examine the Program Status Register to decide which state we're in.  */
+struct frame_base arm_normal_base = {
+  &arm_prologue_unwind,
+  arm_normal_frame_base,
+  arm_normal_frame_base,
+  arm_normal_frame_base
+};
 
-static CORE_ADDR
-arm_read_fp (void)
+static struct arm_prologue_cache *
+arm_make_sigtramp_cache (struct frame_info *next_frame)
 {
-  if (read_register (ARM_PS_REGNUM) & 0x20)    /* Bit 5 is Thumb state bit */
-    return read_register (THUMB_FP_REGNUM);    /* R7 if Thumb */
-  else
-    return read_register (ARM_FP_REGNUM);      /* R11 if ARM */
-}
+  struct arm_prologue_cache *cache;
+  int reg;
 
-/* Store into a struct frame_saved_regs the addresses of the saved
-   registers of frame described by FRAME_INFO.  This includes special
-   registers such as PC and FP saved in special ways in the stack
-   frame.  SP is even more special: the address we return for it IS
-   the sp for the next frame.  */
+  cache = frame_obstack_zalloc (sizeof (struct arm_prologue_cache));
 
-static void
-arm_frame_init_saved_regs (struct frame_info *fip)
-{
+  cache->prev_sp = frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM);
 
-  if (get_frame_saved_regs (fip))
-    return;
+  cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
 
-  arm_init_extra_frame_info (0, fip);
-}
+  for (reg = 0; reg < NUM_REGS; reg++)
+    cache->saved_regs[reg].addr
+      = SIGCONTEXT_REGISTER_ADDRESS (cache->prev_sp,
+                                    frame_pc_unwind (next_frame), reg);
 
-/* Set the return address for a generic dummy frame.  ARM uses the
-   entry point.  */
+  /* FIXME: What about thumb mode?  */
+  cache->framereg = ARM_SP_REGNUM;
+  cache->prev_sp
+    = read_memory_integer (cache->saved_regs[cache->framereg].addr,
+                          register_size (current_gdbarch, cache->framereg));
 
-static CORE_ADDR
-arm_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
-{
-  write_register (ARM_LR_REGNUM, CALL_DUMMY_ADDRESS ());
-  return sp;
+  return cache;
 }
 
-/* Push an empty stack frame, to record the current PC, etc.  */
-
 static void
-arm_push_dummy_frame (void)
+arm_sigtramp_this_id (struct frame_info *next_frame,
+                     void **this_cache,
+                     struct frame_id *this_id)
 {
-  CORE_ADDR old_sp = read_register (ARM_SP_REGNUM);
-  CORE_ADDR sp = old_sp;
-  CORE_ADDR fp, prologue_start;
-  int regnum;
-
-  /* Push the two dummy prologue instructions in reverse order,
-     so that they'll be in the correct low-to-high order in memory.  */
-  /* sub     fp, ip, #4 */
-  sp = push_word (sp, 0xe24cb004);
-  /*  stmdb   sp!, {r0-r10, fp, ip, lr, pc} */
-  prologue_start = sp = push_word (sp, 0xe92ddfff);
-
-  /* Push a pointer to the dummy prologue + 12, because when stm
-     instruction stores the PC, it stores the address of the stm
-     instruction itself plus 12.  */
-  fp = sp = push_word (sp, prologue_start + 12);
-
-  /* Push the processor status.  */
-  sp = push_word (sp, read_register (ARM_PS_REGNUM));
+  struct arm_prologue_cache *cache;
 
-  /* Push all 16 registers starting with r15.  */
-  for (regnum = ARM_PC_REGNUM; regnum >= 0; regnum--)
-    sp = push_word (sp, read_register (regnum));
+  if (*this_cache == NULL)
+    *this_cache = arm_make_sigtramp_cache (next_frame);
+  cache = *this_cache;
 
-  /* Update fp (for both Thumb and ARM) and sp.  */
-  write_register (ARM_FP_REGNUM, fp);
-  write_register (THUMB_FP_REGNUM, fp);
-  write_register (ARM_SP_REGNUM, sp);
+  /* FIXME drow/2003-07-07: This isn't right if we single-step within
+     the sigtramp frame; the PC should be the beginning of the trampoline.  */
+  *this_id = frame_id_build (cache->prev_sp, frame_pc_unwind (next_frame));
 }
 
-/* DEPRECATED_CALL_DUMMY_WORDS:
-   This sequence of words is the instructions
+static void
+arm_sigtramp_prev_register (struct frame_info *next_frame,
+                           void **this_cache,
+                           int prev_regnum,
+                           int *optimized,
+                           enum lval_type *lvalp,
+                           CORE_ADDR *addrp,
+                           int *realnump,
+                           void *valuep)
+{
+  struct arm_prologue_cache *cache;
 
-   mov  lr,pc
-   mov  pc,r4
-   illegal
+  if (*this_cache == NULL)
+    *this_cache = arm_make_sigtramp_cache (next_frame);
+  cache = *this_cache;
 
-   Note this is 12 bytes.  */
+  trad_frame_prev_register (next_frame, cache->saved_regs, prev_regnum,
+                           optimized, lvalp, addrp, realnump, valuep);
+}
 
-static LONGEST arm_call_dummy_words[] =
-{
-  0xe1a0e00f, 0xe1a0f004, 0xe7ffdefe
+struct frame_unwind arm_sigtramp_unwind = {
+  SIGTRAMP_FRAME,
+  arm_sigtramp_this_id,
+  arm_sigtramp_prev_register
 };
 
-/* Adjust the call_dummy_breakpoint_offset for the bp_call_dummy
-   breakpoint to the proper address in the call dummy, so that
-   `finish' after a stop in a call dummy works.
+static const struct frame_unwind *
+arm_sigtramp_unwind_sniffer (struct frame_info *next_frame)
+{
+  if (SIGCONTEXT_REGISTER_ADDRESS_P ()
+      && legacy_pc_in_sigtramp (frame_pc_unwind (next_frame), (char *) 0))
+    return &arm_sigtramp_unwind;
 
-   FIXME rearnsha 2002-02018: Tweeking current_gdbarch is not an
-   optimal solution, but the call to arm_fix_call_dummy is immediately
-   followed by a call to call_function_by_hand, which is the only
-   function where call_dummy_breakpoint_offset is actually used.  */
+  return NULL;
+}
 
+/* Assuming NEXT_FRAME->prev 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 void
-arm_set_call_dummy_breakpoint_offset (void)
+static struct frame_id
+arm_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
 {
-  if (caller_is_thumb)
-    set_gdbarch_deprecated_call_dummy_breakpoint_offset (current_gdbarch, 4);
-  else
-    set_gdbarch_deprecated_call_dummy_breakpoint_offset (current_gdbarch, 8);
+  return frame_id_build (frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM),
+                        frame_pc_unwind (next_frame));
 }
 
-/* Fix up the call dummy, based on whether the processor is currently
-   in Thumb or ARM mode, and whether the target function is Thumb or
-   ARM.  There are three different situations requiring three
-   different dummies:
-
-   * ARM calling ARM: uses the call dummy in tm-arm.h, which has already
-   been copied into the dummy parameter to this function.
-   * ARM calling Thumb: uses the call dummy in tm-arm.h, but with the
-   "mov pc,r4" instruction patched to be a "bx r4" instead.
-   * Thumb calling anything: uses the Thumb dummy defined below, which
-   works for calling both ARM and Thumb functions.
-
-   All three call dummies expect to receive the target function
-   address in R4, with the low bit set if it's a Thumb function.  */
-
-static void
-arm_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
-                   struct value **args, struct type *type, int gcc_p)
-{
-  static short thumb_dummy[4] =
-  {
-    0xf000, 0xf801,            /*        bl      label */
-    0xdf18,                    /*        swi     24 */
-    0x4720,                    /* label: bx      r4 */
-  };
-  static unsigned long arm_bx_r4 = 0xe12fff14; /* bx r4 instruction */
-
-  /* Set flag indicating whether the current PC is in a Thumb function.  */
-  caller_is_thumb = arm_pc_is_thumb (read_pc ());
-  arm_set_call_dummy_breakpoint_offset ();
-
-  /* If the target function is Thumb, set the low bit of the function
-     address.  And if the CPU is currently in ARM mode, patch the
-     second instruction of call dummy to use a BX instruction to
-     switch to Thumb mode.  */
-  target_is_thumb = arm_pc_is_thumb (fun);
-  if (target_is_thumb)
-    {
-      fun |= 1;
-      if (!caller_is_thumb)
-       store_unsigned_integer (dummy + 4, sizeof (arm_bx_r4), arm_bx_r4);
-    }
-
-  /* If the CPU is currently in Thumb mode, use the Thumb call dummy
-     instead of the ARM one that's already been copied.  This will
-     work for both Thumb and ARM target functions.  */
-  if (caller_is_thumb)
-    {
-      int i;
-      char *p = dummy;
-      int len = sizeof (thumb_dummy) / sizeof (thumb_dummy[0]);
+/* Given THIS_FRAME, find the previous frame's resume PC (which will
+   be used to construct the previous frame's ID, after looking up the
+   containing function).  */
 
-      for (i = 0; i < len; i++)
-       {
-         store_unsigned_integer (p, sizeof (thumb_dummy[0]), thumb_dummy[i]);
-         p += sizeof (thumb_dummy[0]);
-       }
-    }
-
-  /* Put the target address in r4; the call dummy will copy this to
-     the PC.  */
-  write_register (4, fun);
+static CORE_ADDR
+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 IS_THUMB_ADDR (pc) ? UNMAKE_THUMB_ADDR (pc) : pc;
 }
 
-/* Pop the current frame.  So long as the frame info has been
-   initialized properly (see arm_init_extra_frame_info), this code
-   works for dummy frames as well as regular frames.  I.e, there's no
-   need to have a special case for dummy frames.  */
-static void
-arm_pop_frame (void)
+static CORE_ADDR
+arm_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
 {
-  int regnum;
-  struct frame_info *frame = get_current_frame ();
-  CORE_ADDR old_SP = (get_frame_base (frame)
-                     - arm_get_cache (frame)->frameoffset
-                     + arm_get_cache (frame)->framesize);
-
-  if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (frame),
-                                  get_frame_base (frame),
-                                  get_frame_base (frame)))
-    {
-      generic_pop_dummy_frame ();
-      flush_cached_frames ();
-      return;
-    }
-
-  for (regnum = 0; regnum < NUM_REGS; regnum++)
-    if (get_frame_saved_regs (frame)[regnum] != 0)
-      write_register (regnum,
-                 read_memory_integer (get_frame_saved_regs (frame)[regnum],
-                                      REGISTER_RAW_SIZE (regnum)));
-
-  write_register (ARM_PC_REGNUM, DEPRECATED_FRAME_SAVED_PC (frame));
-  write_register (ARM_SP_REGNUM, old_SP);
-
-  flush_cached_frames ();
+  return frame_unwind_register_unsigned (this_frame, ARM_SP_REGNUM);
 }
 
 /* When arguments must be pushed onto the stack, they go on in reverse
@@ -1430,7 +1210,7 @@ pop_stack_item (struct stack_item *si)
    we should probably support some of them based on the selected ABI.  */
 
 static CORE_ADDR
-arm_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                     struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
                     struct value **args, CORE_ADDR sp, int struct_return,
                     CORE_ADDR struct_addr)
@@ -1571,7 +1351,7 @@ static void
 arm_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
                      struct frame_info *frame, const char *args)
 {
-  register unsigned long status = read_register (ARM_FPS_REGNUM);
+  unsigned long status = read_register (ARM_FPS_REGNUM);
   int type;
 
   type = (status >> 24) & 127;
@@ -1588,7 +1368,7 @@ arm_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
    register N.  */
 
 static struct type *
-arm_register_type (int regnum)
+arm_register_type (struct gdbarch *gdbarch, int regnum)
 {
   if (regnum >= ARM_F0_REGNUM && regnum < ARM_F0_REGNUM + NUM_FREGS)
     {
@@ -1608,44 +1388,16 @@ static int
 arm_register_byte (int regnum)
 {
   if (regnum < ARM_F0_REGNUM)
-    return regnum * INT_REGISTER_RAW_SIZE;
+    return regnum * INT_REGISTER_SIZE;
   else if (regnum < ARM_PS_REGNUM)
-    return (NUM_GREGS * INT_REGISTER_RAW_SIZE
-           + (regnum - ARM_F0_REGNUM) * FP_REGISTER_RAW_SIZE);
+    return (NUM_GREGS * INT_REGISTER_SIZE
+           + (regnum - ARM_F0_REGNUM) * FP_REGISTER_SIZE);
   else
-    return (NUM_GREGS * INT_REGISTER_RAW_SIZE
-           + NUM_FREGS * FP_REGISTER_RAW_SIZE
+    return (NUM_GREGS * INT_REGISTER_SIZE
+           + NUM_FREGS * FP_REGISTER_SIZE
            + (regnum - ARM_FPS_REGNUM) * STATUS_REGISTER_SIZE);
 }
 
-/* Number of bytes of storage in the actual machine representation for
-   register N.  All registers are 4 bytes, except fp0 - fp7, which are
-   12 bytes in length.  */
-
-static int
-arm_register_raw_size (int regnum)
-{
-  if (regnum < ARM_F0_REGNUM)
-    return INT_REGISTER_RAW_SIZE;
-  else if (regnum < ARM_FPS_REGNUM)
-    return FP_REGISTER_RAW_SIZE;
-  else
-    return STATUS_REGISTER_SIZE;
-}
-
-/* Number of bytes of storage in a program's representation
-   for register N.  */
-static int
-arm_register_virtual_size (int regnum)
-{
-  if (regnum < ARM_F0_REGNUM)
-    return INT_REGISTER_VIRTUAL_SIZE;
-  else if (regnum < ARM_FPS_REGNUM)
-    return FP_REGISTER_VIRTUAL_SIZE;
-  else
-    return STATUS_REGISTER_SIZE;
-}
-
 /* Map GDB internal REGNUM onto the Arm simulator register numbers.  */
 static int
 arm_register_sim_regno (int regnum)
@@ -1843,11 +1595,25 @@ thumb_get_next_pc (CORE_ADDR pc)
     {
       nextpc = pc_val + (sbits (inst1, 0, 10) << 1);
     }
-  else if ((inst1 & 0xf800) == 0xf000) /* long branch with link */
+  else if ((inst1 & 0xf800) == 0xf000) /* long branch with link, and blx */
     {
       unsigned short inst2 = read_memory_integer (pc + 2, 2);
       offset = (sbits (inst1, 0, 10) << 12) + (bits (inst2, 0, 10) << 1);
       nextpc = pc_val + offset;
+      /* For BLX make sure to clear the low bits.  */
+      if (bits (inst2, 11, 12) == 1)
+       nextpc = nextpc & 0xfffffffc;
+    }
+  else if ((inst1 & 0xff00) == 0x4700) /* bx REG, blx REG */
+    {
+      if (bits (inst1, 3, 6) == 0x0f)
+       nextpc = pc_val;
+      else
+       nextpc = read_register (bits (inst1, 3, 6));
+
+      nextpc = ADDR_BITS_REMOVE (nextpc);
+      if (nextpc == pc)
+       error ("Infinite loop detected");
     }
 
   return nextpc;
@@ -1889,6 +1655,20 @@ arm_get_next_pc (CORE_ADDR pc)
                && bits (this_instr, 4, 7) == 9)        /* multiply */
              error ("Illegal update to pc in instruction");
 
+           /* BX <reg>, BLX <reg> */
+           if (bits (this_instr, 4, 28) == 0x12fff1
+               || bits (this_instr, 4, 28) == 0x12fff3)
+             {
+               rn = bits (this_instr, 0, 3);
+               result = (rn == 15) ? pc_val + 8 : read_register (rn);
+               nextpc = (CORE_ADDR) ADDR_BITS_REMOVE (result);
+
+               if (nextpc == pc)
+                 error ("Infinite loop detected");
+
+               return nextpc;
+             }
+
            /* Multiply into PC */
            c = (status & FLAG_C) ? 1 : 0;
            rn = bits (this_instr, 16, 19);
@@ -2054,6 +1834,10 @@ 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);
            if (nextpc == pc)
              error ("Infinite loop detected");
@@ -2242,7 +2026,7 @@ arm_extract_return_value (struct type *type,
            /* The value is in register F0 in internal format.  We need to
               extract the raw value and then convert it to the desired
               internal type.  */
-           bfd_byte tmpbuf[FP_REGISTER_RAW_SIZE];
+           bfd_byte tmpbuf[FP_REGISTER_SIZE];
 
            regcache_cooked_read (regs, ARM_F0_REGNUM, tmpbuf);
            convert_from_extended (floatformat_from_type (type), tmpbuf,
@@ -2255,7 +2039,7 @@ arm_extract_return_value (struct type *type,
          regcache_cooked_read (regs, ARM_A1_REGNUM, valbuf);
          if (TYPE_LENGTH (type) > 4)
            regcache_cooked_read (regs, ARM_A1_REGNUM + 1,
-                                 valbuf + INT_REGISTER_RAW_SIZE);
+                                 valbuf + INT_REGISTER_SIZE);
          break;
 
        default:
@@ -2284,11 +2068,11 @@ arm_extract_return_value (struct type *type,
             anything special for small big-endian values.  */
          regcache_cooked_read_unsigned (regs, regno++, &tmp);
          store_unsigned_integer (valbuf, 
-                                 (len > INT_REGISTER_RAW_SIZE
-                                  ? INT_REGISTER_RAW_SIZE : len),
+                                 (len > INT_REGISTER_SIZE
+                                  ? INT_REGISTER_SIZE : len),
                                  tmp);
-         len -= INT_REGISTER_RAW_SIZE;
-         valbuf += INT_REGISTER_RAW_SIZE;
+         len -= INT_REGISTER_SIZE;
+         valbuf += INT_REGISTER_SIZE;
        }
     }
   else
@@ -2298,15 +2082,15 @@ arm_extract_return_value (struct type *type,
          registers with 32-bit load instruction(s).  */
       int len = TYPE_LENGTH (type);
       int regno = ARM_A1_REGNUM;
-      bfd_byte tmpbuf[INT_REGISTER_RAW_SIZE];
+      bfd_byte tmpbuf[INT_REGISTER_SIZE];
 
       while (len > 0)
        {
          regcache_cooked_read (regs, regno++, tmpbuf);
          memcpy (valbuf, tmpbuf,
-                 len > INT_REGISTER_RAW_SIZE ? INT_REGISTER_RAW_SIZE : len);
-         len -= INT_REGISTER_RAW_SIZE;
-         valbuf += INT_REGISTER_RAW_SIZE;
+                 len > INT_REGISTER_SIZE ? INT_REGISTER_SIZE : len);
+         len -= INT_REGISTER_SIZE;
+         valbuf += INT_REGISTER_SIZE;
        }
     }
 }
@@ -2331,7 +2115,9 @@ static int
 arm_use_struct_convention (int gcc_p, struct type *type)
 {
   int nRc;
-  register enum type_code code;
+  enum type_code code;
+
+  CHECK_TYPEDEF (type);
 
   /* In the ARM ABI, "integer" like aggregate types are returned in
      registers.  For an aggregate type to be integer like, its size
@@ -2390,7 +2176,7 @@ arm_use_struct_convention (int gcc_p, struct type *type)
       for (i = 0; i < TYPE_NFIELDS (type); i++)
        {
          enum type_code field_type_code;
-         field_type_code = TYPE_CODE (TYPE_FIELD_TYPE (type, i));
+         field_type_code = TYPE_CODE (check_typedef (TYPE_FIELD_TYPE (type, i)));
 
          /* Is it a floating point type field?  */
          if (field_type_code == TYPE_CODE_FLT)
@@ -2428,7 +2214,7 @@ arm_store_return_value (struct type *type, struct regcache *regs,
 
   if (TYPE_CODE (type) == TYPE_CODE_FLT)
     {
-      char buf[ARM_MAX_REGISTER_RAW_SIZE];
+      char buf[MAX_REGISTER_SIZE];
 
       switch (arm_get_fp_model (current_gdbarch))
        {
@@ -2443,7 +2229,7 @@ arm_store_return_value (struct type *type, struct regcache *regs,
          regcache_cooked_write (regs, ARM_A1_REGNUM, valbuf);
          if (TYPE_LENGTH (type) > 4)
            regcache_cooked_write (regs, ARM_A1_REGNUM + 1, 
-                                  valbuf + INT_REGISTER_RAW_SIZE);
+                                  valbuf + INT_REGISTER_SIZE);
          break;
 
        default:
@@ -2464,10 +2250,10 @@ arm_store_return_value (struct type *type, struct regcache *regs,
        {
          /* Values of one word or less are zero/sign-extended and
             returned in r0.  */
-         bfd_byte tmpbuf[INT_REGISTER_RAW_SIZE];
+         bfd_byte tmpbuf[INT_REGISTER_SIZE];
          LONGEST val = unpack_long (type, valbuf);
 
-         store_signed_integer (tmpbuf, INT_REGISTER_RAW_SIZE, val);
+         store_signed_integer (tmpbuf, INT_REGISTER_SIZE, val);
          regcache_cooked_write (regs, ARM_A1_REGNUM, tmpbuf);
        }
       else
@@ -2481,8 +2267,8 @@ arm_store_return_value (struct type *type, struct regcache *regs,
          while (len > 0)
            {
              regcache_cooked_write (regs, regno++, valbuf);
-             len -= INT_REGISTER_RAW_SIZE;
-             valbuf += INT_REGISTER_RAW_SIZE;
+             len -= INT_REGISTER_SIZE;
+             valbuf += INT_REGISTER_SIZE;
            }
        }
     }
@@ -2493,15 +2279,15 @@ arm_store_return_value (struct type *type, struct regcache *regs,
          registers with 32-bit load instruction(s).  */
       int len = TYPE_LENGTH (type);
       int regno = ARM_A1_REGNUM;
-      bfd_byte tmpbuf[INT_REGISTER_RAW_SIZE];
+      bfd_byte tmpbuf[INT_REGISTER_SIZE];
 
       while (len > 0)
        {
          memcpy (tmpbuf, valbuf,
-                 len > INT_REGISTER_RAW_SIZE ? INT_REGISTER_RAW_SIZE : len);
+                 len > INT_REGISTER_SIZE ? INT_REGISTER_SIZE : len);
          regcache_cooked_write (regs, regno++, tmpbuf);
-         len -= INT_REGISTER_RAW_SIZE;
-         valbuf += INT_REGISTER_RAW_SIZE;
+         len -= INT_REGISTER_SIZE;
+         valbuf += INT_REGISTER_SIZE;
        }
     }
 }
@@ -2510,16 +2296,16 @@ static int
 arm_get_longjmp_target (CORE_ADDR *pc)
 {
   CORE_ADDR jb_addr;
-  char buf[INT_REGISTER_RAW_SIZE];
+  char buf[INT_REGISTER_SIZE];
   struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
   
   jb_addr = read_register (ARM_A1_REGNUM);
 
   if (target_read_memory (jb_addr + tdep->jb_pc * tdep->jb_elt_size, buf,
-                         INT_REGISTER_RAW_SIZE))
+                         INT_REGISTER_SIZE))
     return 0;
 
-  *pc = extract_unsigned_integer (buf, INT_REGISTER_RAW_SIZE);
+  *pc = extract_unsigned_integer (buf, INT_REGISTER_SIZE);
   return 1;
 }
 
@@ -2752,6 +2538,21 @@ arm_coff_make_msymbol_special(int val, struct minimal_symbol *msym)
     MSYMBOL_SET_SPECIAL (msym);
 }
 
+static void
+arm_write_pc (CORE_ADDR pc, ptid_t ptid)
+{
+  write_register_pid (ARM_PC_REGNUM, pc, ptid);
+
+  /* If necessary, set the T bit.  */
+  if (arm_apcs_32)
+    {
+      CORE_ADDR val = read_register_pid (ARM_PS_REGNUM, ptid);
+      if (arm_pc_is_thumb (pc))
+       write_register_pid (ARM_PS_REGNUM, val | 0x20, ptid);
+      else
+       write_register_pid (ARM_PS_REGNUM, val & ~(CORE_ADDR) 0x20, ptid);
+    }
+}
 \f
 static enum gdb_osabi
 arm_elf_osabi_sniffer (bfd *abfd)
@@ -2873,10 +2674,6 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   tdep = xmalloc (sizeof (struct gdbarch_tdep));
   gdbarch = gdbarch_alloc (&info, tdep);
 
-  /* NOTE: cagney/2002-12-06: This can be deleted when this arch is
-     ready to unwind the PC first (see frame.c:get_prev_frame()).  */
-  set_gdbarch_deprecated_init_frame_pc (gdbarch, init_frame_pc_default);
-
   /* 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.  */
@@ -2913,30 +2710,23 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   tdep->lowest_pc = 0x20;
   tdep->jb_pc = -1;    /* Longjump support not enabled by default.  */
 
-  set_gdbarch_deprecated_call_dummy_words (gdbarch, arm_call_dummy_words);
-  set_gdbarch_deprecated_sizeof_call_dummy_words (gdbarch, 0);
-
   set_gdbarch_push_dummy_call (gdbarch, arm_push_dummy_call);
 
+  set_gdbarch_write_pc (gdbarch, arm_write_pc);
+
   /* Frame handling.  */
-  set_gdbarch_deprecated_frame_chain_valid (gdbarch, arm_frame_chain_valid);
-  set_gdbarch_deprecated_init_extra_frame_info (gdbarch, arm_init_extra_frame_info);
-  set_gdbarch_deprecated_target_read_fp (gdbarch, arm_read_fp);
-  set_gdbarch_deprecated_frame_chain (gdbarch, arm_frame_chain);
-  set_gdbarch_frameless_function_invocation
-    (gdbarch, arm_frameless_function_invocation);
-  set_gdbarch_deprecated_frame_saved_pc (gdbarch, arm_frame_saved_pc);
-  set_gdbarch_frame_args_skip (gdbarch, 0);
-  set_gdbarch_deprecated_frame_init_saved_regs (gdbarch, arm_frame_init_saved_regs);
-  set_gdbarch_deprecated_pop_frame (gdbarch, arm_pop_frame);
+  set_gdbarch_unwind_dummy_id (gdbarch, arm_unwind_dummy_id);
+  set_gdbarch_unwind_pc (gdbarch, arm_unwind_pc);
+  set_gdbarch_unwind_sp (gdbarch, arm_unwind_sp);
+
+  set_gdbarch_deprecated_frameless_function_invocation (gdbarch, arm_frameless_function_invocation);
+
+  frame_base_set_default (gdbarch, &arm_normal_base);
 
   /* Address manipulation.  */
   set_gdbarch_smash_text_address (gdbarch, arm_smash_text_address);
   set_gdbarch_addr_bits_remove (gdbarch, arm_addr_bits_remove);
 
-  /* Offset from address of function to start of its code.  */
-  set_gdbarch_function_start_offset (gdbarch, 0);
-
   /* Advance PC across function entry code.  */
   set_gdbarch_skip_prologue (gdbarch, arm_skip_prologue);
 
@@ -2948,7 +2738,6 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
   /* Breakpoint manipulation.  */
   set_gdbarch_breakpoint_from_pc (gdbarch, arm_breakpoint_from_pc);
-  set_gdbarch_decr_pc_after_break (gdbarch, 0);
 
   /* Information about registers, etc.  */
   set_gdbarch_print_float_info (gdbarch, arm_print_float_info);
@@ -2957,15 +2746,11 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_pc_regnum (gdbarch, ARM_PC_REGNUM);
   set_gdbarch_deprecated_register_byte (gdbarch, arm_register_byte);
   set_gdbarch_deprecated_register_bytes (gdbarch,
-                                        (NUM_GREGS * INT_REGISTER_RAW_SIZE
-                                         + NUM_FREGS * FP_REGISTER_RAW_SIZE
+                                        (NUM_GREGS * INT_REGISTER_SIZE
+                                         + NUM_FREGS * FP_REGISTER_SIZE
                                          + NUM_SREGS * STATUS_REGISTER_SIZE));
   set_gdbarch_num_regs (gdbarch, NUM_GREGS + NUM_FREGS + NUM_SREGS);
-  set_gdbarch_deprecated_register_raw_size (gdbarch, arm_register_raw_size);
-  set_gdbarch_deprecated_register_virtual_size (gdbarch, arm_register_virtual_size);
-  set_gdbarch_deprecated_max_register_raw_size (gdbarch, FP_REGISTER_RAW_SIZE);
-  set_gdbarch_deprecated_max_register_virtual_size (gdbarch, FP_REGISTER_VIRTUAL_SIZE);
-  set_gdbarch_deprecated_register_virtual_type (gdbarch, arm_register_type);
+  set_gdbarch_register_type (gdbarch, arm_register_type);
 
   /* Internal <-> external register number maps.  */
   set_gdbarch_register_sim_regno (gdbarch, arm_register_sim_regno);
@@ -2977,9 +2762,8 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   /* Returning results.  */
   set_gdbarch_extract_return_value (gdbarch, arm_extract_return_value);
   set_gdbarch_store_return_value (gdbarch, arm_store_return_value);
-  set_gdbarch_use_struct_convention (gdbarch, arm_use_struct_convention);
-  set_gdbarch_extract_struct_value_address (gdbarch,
-                                           arm_extract_struct_value_address);
+  set_gdbarch_deprecated_use_struct_convention (gdbarch, arm_use_struct_convention);
+  set_gdbarch_deprecated_extract_struct_value_address (gdbarch, arm_extract_struct_value_address);
 
   /* Single stepping.  */
   /* XXX For an RDI target we should ask the target if it can single-step.  */
@@ -2996,6 +2780,10 @@ 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);
 
+  /* Add some default predicates.  */
+  frame_unwind_append_sniffer (gdbarch, arm_sigtramp_unwind_sniffer);
+  frame_unwind_append_sniffer (gdbarch, arm_prologue_unwind_sniffer);
+
   /* Now we have tuned the configuration, set a few final things,
      based on what the OS ABI has told us.  */
 
@@ -3142,7 +2930,7 @@ _initialize_arm_tdep (void)
                              &setlist);
   set_cmd_sfunc (new_set, set_disassembly_style_sfunc);
   deprecate_cmd (new_set, "set arm disassembly");
-  deprecate_cmd (add_show_from_set (new_set, &showlist),
+  deprecate_cmd (deprecated_add_show_from_set (new_set, &showlist),
                 "show arm disassembly");
 
   /* And now add the new interface.  */
@@ -3151,7 +2939,7 @@ _initialize_arm_tdep (void)
                              helptext, &setarmcmdlist);
 
   set_cmd_sfunc (new_set, set_disassembly_style_sfunc);
-  add_show_from_set (new_set, &showarmcmdlist);
+  deprecated_add_show_from_set (new_set, &showarmcmdlist);
 
   add_setshow_cmd_full ("apcs32", no_class,
                        var_boolean, (char *) &arm_apcs_32,
@@ -3181,7 +2969,8 @@ _initialize_arm_tdep (void)
      "vfp - VFP co-processor.",
      &setarmcmdlist);
   set_cmd_sfunc (new_set, set_fp_model_sfunc);
-  set_cmd_sfunc (add_show_from_set (new_set, &showarmcmdlist), show_fp_model);
+  set_cmd_sfunc (deprecated_add_show_from_set (new_set, &showarmcmdlist),
+                show_fp_model);
 
   /* Add the deprecated "othernames" command.  */
   deprecate_cmd (add_com ("othernames", class_obscure, arm_othernames,
This page took 0.152308 seconds and 4 git commands to generate.