* gdbarch.sh (stab_reg_to_regnum, dwarf_reg_to_regnum)
[deliverable/binutils-gdb.git] / gdb / arm-tdep.c
index 575c59a2a411bfc8d46a8df48e62f0fe20f7e821..db68a310bdbaa0ee7c3de62f425f238c00e2adad 100644 (file)
@@ -7,7 +7,7 @@
 
    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 +16,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 () */
 
@@ -189,13 +187,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;
@@ -294,7 +290,9 @@ thumb_analyze_prologue (struct gdbarch *gdbarch,
        {
          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 +302,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 +361,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.  */
@@ -650,16 +636,21 @@ 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 *next_frame,
+                  struct arm_prologue_cache *cache)
 {
-  int regno, sp_offset, fp_offset, ip_offset;
+  struct gdbarch *gdbarch = get_frame_arch (next_frame);
+  int regno;
   CORE_ADDR prologue_start, prologue_end, current_pc;
   CORE_ADDR prev_pc = frame_pc_unwind (next_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))
@@ -725,7 +716,7 @@ arm_scan_prologue (struct frame_info *next_frame, struct arm_prologue_cache *cac
       else
         {
           prologue_start = gdbarch_addr_bits_remove 
-                            (current_gdbarch, return_value) - 8;
+                            (gdbarch, return_value) - 8;
           prologue_end = prologue_start + 64;  /* See above.  */
         }
     }
@@ -754,7 +745,12 @@ 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);
+  back_to = make_cleanup_free_pv_area (stack);
+
+  regs[ARM_PC_REGNUM] = pv_unknown ();
 
   for (current_pc = prologue_start;
        current_pc < prologue_end;
@@ -764,7 +760,7 @@ arm_scan_prologue (struct frame_info *next_frame, struct arm_prologue_cache *cac
 
       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 */
@@ -772,7 +768,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 */
@@ -780,13 +776,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)
@@ -796,12 +794,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] */
@@ -823,29 +824,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 */
@@ -865,8 +871,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)
@@ -879,14 +886,32 @@ 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 *
@@ -905,11 +930,11 @@ arm_make_prologue_cache (struct frame_info *next_frame)
   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 < gdbarch_num_regs (current_gdbarch); reg++)
+  for (reg = 0; reg < gdbarch_num_regs (get_frame_arch (next_frame)); reg++)
     if (trad_frame_addr_p (cache->saved_regs, reg))
       cache->saved_regs[reg].addr += cache->prev_sp;
 
@@ -936,7 +961,7 @@ arm_prologue_this_id (struct frame_info *next_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)
+  if (func <= gdbarch_tdep (get_frame_arch (next_frame))->lowest_pc)
     return;
 
   /* If we've hit a wall, stop.  */
@@ -1057,7 +1082,7 @@ arm_normal_frame_base (struct frame_info *next_frame, void **this_cache)
     *this_cache = arm_make_prologue_cache (next_frame);
   cache = *this_cache;
 
-  return cache->prev_sp + cache->frameoffset - cache->framesize;
+  return cache->prev_sp - cache->framesize;
 }
 
 struct frame_base arm_normal_base = {
@@ -1212,7 +1237,7 @@ arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
     {
       if (arm_debug)
        fprintf_unfiltered (gdb_stdlog, "struct return in %s = 0x%s\n",
-                           gdbarch_register_name (current_gdbarch, argreg),
+                           gdbarch_register_name (gdbarch, argreg),
                            paddr (struct_addr));
       regcache_cooked_write_unsigned (regcache, argreg, struct_addr);
       argreg++;
@@ -1289,13 +1314,13 @@ arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
              /* The argument is being passed in a general purpose
                 register.  */
              CORE_ADDR regval = extract_unsigned_integer (val, partial_len);
-             if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+             if (gdbarch_byte_order (gdbarch) == 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,
                                    gdbarch_register_name
-                                     (current_gdbarch, argreg),
+                                     (gdbarch, argreg),
                                    phex (regval, INT_REGISTER_SIZE));
              regcache_cooked_write_unsigned (regcache, argreg, regval);
              argreg++;
@@ -1405,7 +1430,7 @@ arm_register_type (struct gdbarch *gdbarch, int regnum)
    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)
@@ -1437,10 +1462,10 @@ arm_dwarf_reg_to_regnum (int reg)
 
 /* 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 < gdbarch_num_regs (current_gdbarch));
+  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;
@@ -1613,6 +1638,7 @@ bitcount (unsigned long val)
 static CORE_ADDR
 thumb_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
 {
+  struct gdbarch *gdbarch = get_frame_arch (frame);
   unsigned long pc_val = ((unsigned long) pc) + 4;     /* PC after prefetch */
   unsigned short inst1 = read_memory_unsigned_integer (pc, 2);
   CORE_ADDR nextpc = pc + 2;           /* default is next instruction */
@@ -1627,7 +1653,7 @@ thumb_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
       offset = bitcount (bits (inst1, 0, 7)) * INT_REGISTER_SIZE;
       sp = get_frame_register_unsigned (frame, ARM_SP_REGNUM);
       nextpc = (CORE_ADDR) read_memory_unsigned_integer (sp + offset, 4);
-      nextpc = gdbarch_addr_bits_remove (current_gdbarch, nextpc);
+      nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
       if (nextpc == pc)
        error (_("Infinite loop detected"));
     }
@@ -1658,7 +1684,7 @@ thumb_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
       else
        nextpc = get_frame_register_unsigned (frame, bits (inst1, 3, 6));
 
-      nextpc = gdbarch_addr_bits_remove (current_gdbarch, nextpc);
+      nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
       if (nextpc == pc)
        error (_("Infinite loop detected"));
     }
@@ -1666,9 +1692,10 @@ thumb_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
   return nextpc;
 }
 
-static CORE_ADDR
+CORE_ADDR
 arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
 {
+  struct gdbarch *gdbarch = get_frame_arch (frame);
   unsigned long pc_val;
   unsigned long this_instr;
   unsigned long status;
@@ -1682,7 +1709,30 @@ arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
   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))
        {
@@ -1710,7 +1760,7 @@ arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
                result = (rn == 15) ? pc_val + 8
                                    : get_frame_register_unsigned (frame, rn);
                nextpc = (CORE_ADDR) gdbarch_addr_bits_remove
-                                      (current_gdbarch, result);
+                                      (gdbarch, result);
 
                if (nextpc == pc)
                  error (_("Infinite loop detected"));
@@ -1793,7 +1843,7 @@ arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
                break;
              }
            nextpc = (CORE_ADDR) gdbarch_addr_bits_remove
-                                  (current_gdbarch, result);
+                                  (gdbarch, result);
 
            if (nextpc == pc)
              error (_("Infinite loop detected"));
@@ -1837,7 +1887,7 @@ arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
                  nextpc = (CORE_ADDR) read_memory_integer ((CORE_ADDR) base,
                                                            4);
 
-                 nextpc = gdbarch_addr_bits_remove (current_gdbarch, nextpc);
+                 nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
 
                  if (nextpc == pc)
                    error (_("Infinite loop detected"));
@@ -1876,7 +1926,7 @@ arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
                                                       4);
                  }
                  nextpc = gdbarch_addr_bits_remove
-                            (current_gdbarch, nextpc);
+                            (gdbarch, nextpc);
                  if (nextpc == pc)
                    error (_("Infinite loop detected"));
                }
@@ -1888,11 +1938,7 @@ arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
          {
            nextpc = BranchDest (pc, this_instr);
 
-           /* BLX */
-           if (bits (this_instr, 28, 31) == INST_NV)
-             nextpc |= bit (this_instr, 24) << 1;
-
-           nextpc = gdbarch_addr_bits_remove (current_gdbarch, nextpc);
+           nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
            if (nextpc == pc)
              error (_("Infinite loop detected"));
            break;
@@ -2022,9 +2068,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))
     {
@@ -2049,7 +2095,7 @@ arm_extract_return_value (struct type *type, struct regcache *regs,
 {
   if (TYPE_CODE_FLT == TYPE_CODE (type))
     {
-      switch (gdbarch_tdep (current_gdbarch)->fp_model)
+      switch (gdbarch_tdep (get_regcache_arch (regs))->fp_model)
        {
        case ARM_FLOAT_FPA:
          {
@@ -2238,7 +2284,7 @@ arm_store_return_value (struct type *type, struct regcache *regs,
     {
       char buf[MAX_REGISTER_SIZE];
 
-      switch (gdbarch_tdep (current_gdbarch)->fp_model)
+      switch (gdbarch_tdep (get_regcache_arch (regs))->fp_model)
        {
        case ARM_FLOAT_FPA:
 
@@ -2360,38 +2406,24 @@ arm_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
   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 (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
@@ -2401,12 +2433,49 @@ arm_skip_stub (struct frame_info *frame, 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)
+       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 */
 }
 
@@ -2527,7 +2596,7 @@ 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)
 {
   if (i >= ARRAY_SIZE (arm_register_names))
     /* These registers are only supported on targets which supply
@@ -2835,39 +2904,17 @@ 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;
 
       /* Found a match.  */
@@ -2997,12 +3044,23 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   /* 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);
@@ -3016,7 +3074,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
     }
 
   if (tdesc_data)
-    tdesc_use_registers (gdbarch, tdesc_data);
+    tdesc_use_registers (gdbarch, info.target_desc, tdesc_data);
 
   /* Add standard register aliases.  We add aliases even for those
      nanes which are used by the current architecture - it's simpler,
@@ -3029,9 +3087,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;
This page took 0.044333 seconds and 4 git commands to generate.