* Makefile.in (arm-tdep.o, eval.o, target-descriptions.o)
[deliverable/binutils-gdb.git] / gdb / arm-tdep.c
index 6b574653f63a24830c6842f5ff8d6054263df7e0..ab7b2e99f3d2e3d74f35200e9d5835cca2767c21 100644 (file)
@@ -1,8 +1,7 @@
 /* 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
-   Free Software Foundation, Inc.
+   Copyright (C) 1988, 1989, 1991, 1992, 1993, 1995, 1996, 1998, 1999, 2000,
+   2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #include "trad-frame.h"
 #include "objfiles.h"
 #include "dwarf2-frame.h"
+#include "gdbtypes.h"
+#include "prologue-value.h"
+#include "target-descriptions.h"
+#include "user-regs.h"
 
 #include "arm-tdep.h"
 #include "gdb/sim-arm.h"
@@ -102,13 +105,58 @@ static const char *arm_abi_string = "auto";
 /* Number of different reg name sets (options).  */
 static int num_disassembly_options;
 
-/* We have more registers than the disassembler as gdb can print the value
-   of special registers as well.
-   The general register names are overwritten by whatever is being used by
-   the disassembler at the moment. We also adjust the case of cpsr and fps.  */
+/* The standard register names, and all the valid aliases for them.  */
+static const struct
+{
+  const char *name;
+  int regnum;
+} arm_register_aliases[] = {
+  /* Basic register numbers.  */
+  { "r0", 0 },
+  { "r1", 1 },
+  { "r2", 2 },
+  { "r3", 3 },
+  { "r4", 4 },
+  { "r5", 5 },
+  { "r6", 6 },
+  { "r7", 7 },
+  { "r8", 8 },
+  { "r9", 9 },
+  { "r10", 10 },
+  { "r11", 11 },
+  { "r12", 12 },
+  { "r13", 13 },
+  { "r14", 14 },
+  { "r15", 15 },
+  /* Synonyms (argument and variable registers).  */
+  { "a1", 0 },
+  { "a2", 1 },
+  { "a3", 2 },
+  { "a4", 3 },
+  { "v1", 4 },
+  { "v2", 5 },
+  { "v3", 6 },
+  { "v4", 7 },
+  { "v5", 8 },
+  { "v6", 9 },
+  { "v7", 10 },
+  { "v8", 11 },
+  /* Other platform-specific names for r9.  */
+  { "sb", 9 },
+  { "tr", 9 },
+  /* Special names.  */
+  { "ip", 12 },
+  { "sp", 13 },
+  { "lr", 14 },
+  { "pc", 15 },
+  /* Names used by GCC (not listed in the ARM EABI).  */
+  { "sl", 10 },
+  { "fp", 11 },
+  /* A special name from the older ATPCS.  */
+  { "wr", 7 },
+};
 
-/* Initial value: Register names used in ARM's ISA documentation.  */
-static char * arm_register_name_strings[] =
+static const char *const arm_register_names[] =
 {"r0",  "r1",  "r2",  "r3",    /*  0  1  2  3 */
  "r4",  "r5",  "r6",  "r7",    /*  4  5  6  7 */
  "r8",  "r9",  "r10", "r11",   /*  8  9 10 11 */
@@ -116,15 +164,12 @@ static char * arm_register_name_strings[] =
  "f0",  "f1",  "f2",  "f3",    /* 16 17 18 19 */
  "f4",  "f5",  "f6",  "f7",    /* 20 21 22 23 */
  "fps", "cpsr" };              /* 24 25       */
-static char **arm_register_names = arm_register_name_strings;
 
 /* Valid register name styles.  */
 static const char **valid_disassembly_styles;
 
 /* Disassembly style to use. Default to "std" register names.  */
 static const char *disassembly_style;
-/* Index to that option in the opcodes table.  */
-static int current_option;
 
 /* This is used to keep the bfd arch_info in sync with the disassembly
    style.  */
@@ -211,95 +256,156 @@ arm_smash_text_address (CORE_ADDR val)
   return val & ~1;
 }
 
-/* Immediately after a function call, return the saved pc.  Can't
-   always go through the frames for this because on some machines the
-   new frame is not set up until the new function executes some
-   instructions.  */
-
-static CORE_ADDR
-arm_saved_pc_after_call (struct frame_info *frame)
-{
-  return ADDR_BITS_REMOVE (read_register (ARM_LR_REGNUM));
-}
-
-/* A typical Thumb prologue looks like this:
-   push    {r7, lr}
-   add     sp, sp, #-28
-   add     r7, sp, #12
-   Sometimes the latter instruction may be replaced by:
-   mov     r7, sp
-   
-   or like this:
-   push    {r7, lr}
-   mov     r7, sp
-   sub    sp, #12
-   
-   or, on tpcs, like this:
-   sub     sp,#16
-   push    {r7, lr}
-   (many instructions)
-   mov     r7, sp
-   sub    sp, #12
-
-   There is always one instruction of three classes:
-   1 - push
-   2 - setting of r7
-   3 - adjusting of sp
-   
-   When we have found at least one of each class we are done with the prolog.
-   Note that the "sub sp, #NN" before the push does not count.
-   */
+/* Analyze a Thumb prologue, looking for a recognizable stack frame
+   and frame pointer.  Scan until we encounter a store that could
+   clobber the stack frame unexpectedly, or an unknown instruction.  */
 
 static CORE_ADDR
-thumb_skip_prologue (CORE_ADDR pc, CORE_ADDR func_end)
+thumb_analyze_prologue (struct gdbarch *gdbarch,
+                       CORE_ADDR start, CORE_ADDR limit,
+                       struct arm_prologue_cache *cache)
 {
-  CORE_ADDR current_pc;
-  /* 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;
+  pv_t regs[16];
+  struct pv_area *stack;
+  struct cleanup *back_to;
+  CORE_ADDR offset;
 
-  for (current_pc = pc;
-       current_pc + 2 < func_end && current_pc < pc + 40;
-       current_pc += 2)
+  for (i = 0; i < 16; i++)
+    regs[i] = pv_register (i, 0);
+  stack = make_pv_area (ARM_SP_REGNUM);
+  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 = read_memory_unsigned_integer (current_pc, 2);
+      unsigned short insn;
+
+      insn = read_memory_unsigned_integer (start, 2);
 
       if ((insn & 0xfe00) == 0xb400)           /* push { rlist } */
        {
-         findmask |= 1;                        /* push found */
+         int regno;
+         int mask;
+         int stop = 0;
+
+         /* Bits 0-7 contain a mask for registers R0-R7.  Bit 8 says
+            whether to save LR (R14).  */
+         mask = (insn & 0xff) | ((insn & 0x100) << 6);
+
+         /* Calculate offsets of saved R0-R7 and LR.  */
+         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 */
        {
-         if ((findmask & 1) == 0)              /* before push ? */
-           continue;
+         offset = (insn & 0x7f) << 2;          /* get scaled offset */
+         if (insn & 0x80)                      /* Check for SUB.  */
+           regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
+                                                  -offset);
          else
-           findmask |= 4;                      /* add/sub sp found */
+           regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
+                                                  offset);
        }
       else if ((insn & 0xff00) == 0xaf00)      /* add r7, sp, #imm */
+       regs[THUMB_FP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
+                                                (insn & 0xff) << 2);
+      else if ((insn & 0xff00) == 0x4600)      /* mov hi, lo or mov lo, hi */
        {
-         findmask |= 2;                        /* setting of r7 found */
+         int dst_reg = (insn & 0x7) + ((insn & 0x80) >> 4);
+         int src_reg = (insn & 0x78) >> 3;
+         regs[dst_reg] = regs[src_reg];
        }
-      else if (insn == 0x466f)                 /* mov r7, sp */
+      else if ((insn & 0xf800) == 0x9000)      /* str rd, [sp, #off] */
        {
-         findmask |= 2;                        /* setting of r7 found */
+         /* Handle stores to the stack.  Normally pushes are used,
+            but with GCC -mtpcs-frame, there may be other stores
+            in the prologue to create the frame.  */
+         int regno = (insn >> 8) & 0x7;
+         pv_t addr;
+
+         offset = (insn & 0xff) << 2;
+         addr = pv_add_constant (regs[ARM_SP_REGNUM], offset);
+
+         if (pv_area_store_would_trash (stack, addr))
+           break;
+
+         pv_area_store (stack, addr, 4, regs[regno]);
        }
-      else if (findmask == (4+2+1))
+      else
        {
-         /* We have found one of each type of prologue instruction */
+         /* We don't know what this instruction is.  We're finished
+            scanning.  NOTE: Recognizing more safe-to-ignore
+            instructions here will improve support for optimized
+            code.  */
          break;
        }
-      else
-       /* Something in the prolog that we don't care about or some
-          instruction from outside the prolog scheduled here for
-          optimization.  */
-       continue;
+
+      start += 2;
     }
 
-  return current_pc;
+  if (cache == NULL)
+    {
+      do_cleanups (back_to);
+      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.  */
+      cache->framereg = ARM_FP_REGNUM;
+      cache->framesize = -regs[ARM_FP_REGNUM].k;
+    }
+  else if (pv_is_register (regs[THUMB_FP_REGNUM], ARM_SP_REGNUM))
+    {
+      /* Frame pointer is r7.  Frame size is constant.  */
+      cache->framereg = THUMB_FP_REGNUM;
+      cache->framesize = -regs[THUMB_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
+    {
+      /* We're just out of luck.  We don't know where the frame is.  */
+      cache->framereg = -1;
+      cache->framesize = 0;
+    }
+
+  for (i = 0; i < 16; i++)
+    if (pv_area_find_reg (stack, gdbarch, i, &offset))
+      cache->saved_regs[i].addr = offset;
+
+  do_cleanups (back_to);
+  return start;
 }
 
 /* Advance the PC across any function entry prologue instructions to
@@ -347,10 +453,6 @@ arm_skip_prologue (CORE_ADDR pc)
         }
     }
 
-  /* Check if this is Thumb code.  */
-  if (arm_pc_is_thumb (pc))
-    return thumb_skip_prologue (pc, func_end);
-
   /* Can't find the prologue end in the symbol table, try it the hard way
      by disassembling the instructions.  */
 
@@ -358,6 +460,10 @@ arm_skip_prologue (CORE_ADDR pc)
   if (func_end == 0 || func_end > pc + 64)
     func_end = pc + 64;
 
+  /* Check if this is Thumb code.  */
+  if (arm_pc_is_thumb (pc))
+    return thumb_analyze_prologue (current_gdbarch, pc, func_end, NULL);
+
   for (skip_pc = pc; skip_pc < func_end; skip_pc += 4)
     {
       inst = read_memory_unsigned_integer (skip_pc, 4);
@@ -472,86 +578,8 @@ thumb_scan_prologue (CORE_ADDR prev_pc, struct arm_prologue_cache *cache)
 
   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].  */
-  for (i = 0; i < 16; i++)
-    saved_reg[i] = i;
-
-  /* Search the prologue looking for instructions that set up the
-     frame pointer, adjust the stack pointer, and save registers.
-     Do this until all basic prolog instructions are found.  */
-
-  cache->framesize = 0;
-  for (current_pc = prologue_start;
-       (current_pc < prologue_end) && ((findmask & 7) != 7);
-       current_pc += 2)
-    {
-      unsigned short insn;
-      int regno;
-      int offset;
-
-      insn = read_memory_unsigned_integer (current_pc, 2);
-
-      if ((insn & 0xfe00) == 0xb400)   /* push { rlist } */
-       {
-         int mask;
-         findmask |= 1;                /* push found */
-         /* Bits 0-7 contain a mask for registers R0-R7.  Bit 8 says
-            whether to save LR (R14).  */
-         mask = (insn & 0xff) | ((insn & 0x100) << 6);
-
-         /* Calculate offsets of saved R0-R7 and LR.  */
-         for (regno = ARM_LR_REGNUM; regno >= 0; regno--)
-           if (mask & (1 << regno))
-             {
-               cache->framesize += 4;
-               cache->saved_regs[saved_reg[regno]].addr = -cache->framesize;
-               /* Reset saved register map.  */
-               saved_reg[regno] = regno;
-             }
-       }
-      else if ((insn & 0xff00) == 0xb000)      /* add sp, #simm  OR  
-                                                  sub sp, #simm */
-       {
-         if ((findmask & 1) == 0)              /* before push?  */
-           continue;
-         else
-           findmask |= 4;                      /* add/sub sp found */
-         
-         offset = (insn & 0x7f) << 2;          /* get scaled offset */
-         if (insn & 0x80)              /* is it signed? (==subtracting) */
-           {
-             cache->frameoffset += offset;
-             offset = -offset;
-           }
-         cache->framesize -= offset;
-       }
-      else if ((insn & 0xff00) == 0xaf00)      /* add r7, sp, #imm */
-       {
-         findmask |= 2;                        /* setting of r7 found */
-         cache->framereg = THUMB_FP_REGNUM;
-         /* get scaled offset */
-         cache->frameoffset = (insn & 0xff) << 2;
-       }
-      else if (insn == 0x466f)                 /* mov r7, sp */
-       {
-         findmask |= 2;                        /* setting of r7 found */
-         cache->framereg = THUMB_FP_REGNUM;
-         cache->frameoffset = 0;
-         saved_reg[THUMB_FP_REGNUM] = ARM_SP_REGNUM;
-       }
-      else if ((insn & 0xffc0) == 0x4640)      /* mov r0-r7, r8-r15 */
-       {
-         int lo_reg = insn & 7;                /* dest.  register (r0-r7) */
-         int hi_reg = ((insn >> 3) & 7) + 8;   /* source register (r8-15) */
-         saved_reg[lo_reg] = hi_reg;           /* remember hi reg was saved */
-       }
-      else
-       /* Something in the prolog that we don't care about or some
-          instruction from outside the prolog scheduled here for
-          optimization.  */ 
-       continue;
-    }
+  thumb_analyze_prologue (current_gdbarch, prologue_start, prologue_end,
+                         cache);
 }
 
 /* This function decodes an ARM function prologue to determine:
@@ -865,7 +893,7 @@ arm_make_prologue_cache (struct frame_info *next_frame)
   struct arm_prologue_cache *cache;
   CORE_ADDR unwound_fp;
 
-  cache = frame_obstack_zalloc (sizeof (struct arm_prologue_cache));
+  cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache);
   cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
 
   arm_scan_prologue (next_frame, cache);
@@ -972,7 +1000,7 @@ arm_make_stub_cache (struct frame_info *next_frame)
   struct arm_prologue_cache *cache;
   CORE_ADDR unwound_fp;
 
-  cache = frame_obstack_zalloc (sizeof (struct arm_prologue_cache));
+  cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache);
   cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
 
   cache->prev_sp = frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM);
@@ -1056,7 +1084,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 IS_THUMB_ADDR (pc) ? UNMAKE_THUMB_ADDR (pc) : pc;
+  return arm_addr_bits_remove (pc);
 }
 
 static CORE_ADDR
@@ -1350,31 +1378,13 @@ static struct type *
 arm_register_type (struct gdbarch *gdbarch, int regnum)
 {
   if (regnum >= ARM_F0_REGNUM && regnum < ARM_F0_REGNUM + NUM_FREGS)
-    {
-      if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
-       return builtin_type_arm_ext_big;
-      else
-       return builtin_type_arm_ext_littlebyte_bigword;
-    }
+    return builtin_type_arm_ext;
+  else if (regnum == ARM_SP_REGNUM)
+    return builtin_type_void_data_ptr;
+  else if (regnum == ARM_PC_REGNUM)
+    return builtin_type_void_func_ptr;
   else
-    return builtin_type_int32;
-}
-
-/* Index within `registers' of the first byte of the space for
-   register N.  */
-
-static int
-arm_register_byte (int regnum)
-{
-  if (regnum < ARM_F0_REGNUM)
-    return regnum * INT_REGISTER_SIZE;
-  else if (regnum < ARM_PS_REGNUM)
-    return (NUM_GREGS * INT_REGISTER_SIZE
-           + (regnum - ARM_F0_REGNUM) * FP_REGISTER_SIZE);
-  else
-    return (NUM_GREGS * INT_REGISTER_SIZE
-           + NUM_FREGS * FP_REGISTER_SIZE
-           + (regnum - ARM_FPS_REGNUM) * STATUS_REGISTER_SIZE);
+    return builtin_type_uint32;
 }
 
 /* Map GDB internal REGNUM onto the Arm simulator register numbers.  */
@@ -1635,8 +1645,8 @@ arm_get_next_pc (CORE_ADDR pc)
              error (_("Invalid update to pc in instruction"));
 
            /* BX <reg>, BLX <reg> */
-           if (bits (this_instr, 4, 28) == 0x12fff1
-               || bits (this_instr, 4, 28) == 0x12fff3)
+           if (bits (this_instr, 4, 27) == 0x12fff1
+               || bits (this_instr, 4, 27) == 0x12fff3)
              {
                rn = bits (this_instr, 0, 3);
                result = (rn == 15) ? pc_val + 8 : read_register (rn);
@@ -1849,16 +1859,18 @@ arm_get_next_pc (CORE_ADDR pc)
 static void
 arm_software_single_step (enum target_signal sig, int insert_bpt)
 {
-  static int next_pc;           /* State between setting and unsetting.  */
-  static char break_mem[BREAKPOINT_MAX]; /* Temporary storage for mem@bpt */
+  /* NOTE: This may insert the wrong breakpoint instruction when
+     single-stepping over a mode-changing instruction, if the
+     CPSR heuristics are used.  */
 
   if (insert_bpt)
     {
-      next_pc = arm_get_next_pc (read_register (ARM_PC_REGNUM));
-      target_insert_breakpoint (next_pc, break_mem);
+      CORE_ADDR next_pc = arm_get_next_pc (read_register (ARM_PC_REGNUM));
+
+      insert_single_step_breakpoint (next_pc);
     }
   else
-    target_remove_breakpoint (next_pc, break_mem);
+    remove_single_step_breakpoints ();
 }
 
 #include "bfd-in2.h"
@@ -1962,11 +1974,6 @@ static const char arm_default_thumb_be_breakpoint[] = THUMB_BE_BREAKPOINT;
    necessary) to point to the actual memory location where the
    breakpoint should be inserted.  */
 
-/* XXX ??? from old tm-arm.h: if we're using RDP, then we're inserting
-   breakpoints and storing their handles instread of what was in
-   memory.  It is nice that this is the same size as a handle -
-   otherwise remote-rdp will have to change.  */
-
 static const unsigned char *
 arm_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
 {
@@ -2268,11 +2275,14 @@ arm_return_value (struct gdbarch *gdbarch, struct type *valtype,
                  struct regcache *regcache, gdb_byte *readbuf,
                  const gdb_byte *writebuf)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
   if (TYPE_CODE (valtype) == TYPE_CODE_STRUCT
       || TYPE_CODE (valtype) == TYPE_CODE_UNION
       || TYPE_CODE (valtype) == TYPE_CODE_ARRAY)
     {
-      if (arm_return_in_memory (gdbarch, valtype))
+      if (tdep->struct_return == pcc_struct_return
+         || arm_return_in_memory (gdbarch, valtype))
        return RETURN_VALUE_STRUCT_CONVENTION;
     }
 
@@ -2478,32 +2488,13 @@ arm_register_name (int i)
 static void
 set_disassembly_style (void)
 {
-  const char *setname, *setdesc, *const *regnames;
-  int numregs, j;
-
-  /* Find the style that the user wants in the opcodes table.  */
-  int current = 0;
-  numregs = get_arm_regnames (current, &setname, &setdesc, &regnames);
-  while ((disassembly_style != setname)
-        && (current < num_disassembly_options))
-    get_arm_regnames (++current, &setname, &setdesc, &regnames);
-  current_option = current;
-
-  /* Fill our copy.  */
-  for (j = 0; j < numregs; j++)
-    arm_register_names[j] = (char *) regnames[j];
+  int current;
 
-  /* Adjust case.  */
-  if (isupper (*regnames[ARM_PC_REGNUM]))
-    {
-      arm_register_names[ARM_FPS_REGNUM] = "FPS";
-      arm_register_names[ARM_PS_REGNUM] = "CPSR";
-    }
-  else
-    {
-      arm_register_names[ARM_FPS_REGNUM] = "fps";
-      arm_register_names[ARM_PS_REGNUM] = "cpsr";
-    }
+  /* Find the style that the user wants.  */
+  for (current = 0; current < num_disassembly_options; current++)
+    if (disassembly_style == valid_disassembly_styles[current])
+      break;
+  gdb_assert (current < num_disassembly_options);
 
   /* Synchronize the disassembler.  */
   set_arm_regname_option (current);
@@ -2561,6 +2552,13 @@ arm_write_pc (CORE_ADDR pc, ptid_t ptid)
        write_register_pid (ARM_PS_REGNUM, val & ~(CORE_ADDR) 0x20, ptid);
     }
 }
+
+static struct value *
+value_of_arm_user_reg (struct frame_info *frame, const void *baton)
+{
+  const int *reg_p = baton;
+  return value_of_register (*reg_p, frame);
+}
 \f
 static enum gdb_osabi
 arm_elf_osabi_sniffer (bfd *abfd)
@@ -2597,13 +2595,72 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   struct gdbarch_list *best_arch;
   enum arm_abi_kind arm_abi = arm_abi_global;
   enum arm_float_model fp_model = arm_fp_model;
+  struct tdesc_arch_data *tdesc_data = NULL;
+  int i;
+
+  /* Check any target description for validity.  */
+  if (tdesc_has_registers (info.target_desc))
+    {
+      /* For most registers we require GDB's default names; but also allow
+        the numeric names for sp / lr / pc, as a convenience.  */
+      static const char *const arm_sp_names[] = { "r13", "sp", NULL };
+      static const char *const arm_lr_names[] = { "r14", "lr", NULL };
+      static const char *const arm_pc_names[] = { "r15", "pc", NULL };
+
+      const struct tdesc_feature *feature;
+      int i, valid_p;
+
+      feature = tdesc_find_feature (info.target_desc,
+                                   "org.gnu.gdb.arm.core");
+      if (feature == NULL)
+       return NULL;
+
+      tdesc_data = tdesc_data_alloc ();
+
+      valid_p = 1;
+      for (i = 0; i < ARM_SP_REGNUM; i++)
+       valid_p &= tdesc_numbered_register (feature, tdesc_data, i,
+                                           arm_register_names[i]);
+      valid_p &= tdesc_numbered_register_choices (feature, tdesc_data,
+                                                 ARM_SP_REGNUM,
+                                                 arm_sp_names);
+      valid_p &= tdesc_numbered_register_choices (feature, tdesc_data,
+                                                 ARM_LR_REGNUM,
+                                                 arm_lr_names);
+      valid_p &= tdesc_numbered_register_choices (feature, tdesc_data,
+                                                 ARM_PC_REGNUM,
+                                                 arm_pc_names);
+      valid_p &= tdesc_numbered_register (feature, tdesc_data,
+                                         ARM_PS_REGNUM, "cpsr");
+
+      if (!valid_p)
+       {
+         tdesc_data_cleanup (tdesc_data);
+         return NULL;
+       }
+
+      feature = tdesc_find_feature (info.target_desc,
+                                   "org.gnu.gdb.arm.fpa");
+      if (feature != NULL)
+       {
+         valid_p = 1;
+         for (i = ARM_F0_REGNUM; i <= ARM_FPS_REGNUM; i++)
+           valid_p &= tdesc_numbered_register (feature, tdesc_data, i,
+                                               arm_register_names[i]);
+         if (!valid_p)
+           {
+             tdesc_data_cleanup (tdesc_data);
+             return NULL;
+           }
+       }
+    }
 
   /* If we have an object to base this architecture on, try to determine
      its ABI.  */
 
   if (arm_abi == ARM_ABI_AUTO && info.abfd != NULL)
     {
-      int ei_osabi;
+      int ei_osabi, e_flags;
 
       switch (bfd_get_flavour (info.abfd))
        {
@@ -2620,19 +2677,18 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
        case bfd_target_elf_flavour:
          ei_osabi = elf_elfheader (info.abfd)->e_ident[EI_OSABI];
+         e_flags = elf_elfheader (info.abfd)->e_flags;
+
          if (ei_osabi == ELFOSABI_ARM)
            {
              /* GNU tools used to use this value, but do not for EABI
-                objects.  There's nowhere to tag an EABI version anyway,
-                so assume APCS.  */
+                objects.  There's nowhere to tag an EABI version
+                anyway, so assume APCS.  */
              arm_abi = ARM_ABI_APCS;
            }
          else if (ei_osabi == ELFOSABI_NONE)
            {
-             int e_flags, eabi_ver;
-
-             e_flags = elf_elfheader (info.abfd)->e_flags;
-             eabi_ver = EF_ARM_EABI_VERSION (e_flags);
+             int eabi_ver = EF_ARM_EABI_VERSION (e_flags);
 
              switch (eabi_ver)
                {
@@ -2642,6 +2698,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
                  break;
 
                case EF_ARM_EABI_VER4:
+               case EF_ARM_EABI_VER5:
                  arm_abi = ARM_ABI_AAPCS;
                  /* EABI binaries default to VFP float ordering.  */
                  if (fp_model == ARM_FLOAT_AUTO)
@@ -2649,8 +2706,32 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
                  break;
 
                default:
+                 /* Leave it as "auto".  */
                  warning (_("unknown ARM EABI version 0x%x"), eabi_ver);
-                 arm_abi = ARM_ABI_APCS;
+                 break;
+               }
+           }
+
+         if (fp_model == ARM_FLOAT_AUTO)
+           {
+             int e_flags = elf_elfheader (info.abfd)->e_flags;
+
+             switch (e_flags & (EF_ARM_SOFT_FLOAT | EF_ARM_VFP_FLOAT))
+               {
+               case 0:
+                 /* Leave it as "auto".  Strictly speaking this case
+                    means FPA, but almost nobody uses that now, and
+                    many toolchains fail to set the appropriate bits
+                    for the floating-point model they use.  */
+                 break;
+               case EF_ARM_SOFT_FLOAT:
+                 fp_model = ARM_FLOAT_SOFT_FPA;
+                 break;
+               case EF_ARM_VFP_FLOAT:
+                 fp_model = ARM_FLOAT_VFP;
+                 break;
+               case EF_ARM_SOFT_FLOAT | EF_ARM_VFP_FLOAT:
+                 fp_model = ARM_FLOAT_SOFT_VFP;
                  break;
                }
            }
@@ -2702,7 +2783,11 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
     }
 
   if (best_arch != NULL)
-    return best_arch->gdbarch;
+    {
+      if (tdesc_data != NULL)
+       tdesc_data_cleanup (tdesc_data);
+      return best_arch->gdbarch;
+    }
 
   tdep = xcalloc (1, sizeof (struct gdbarch_tdep));
   gdbarch = gdbarch_alloc (&info, tdep);
@@ -2743,6 +2828,10 @@ 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.  */
 
+  /* The default, for both APCS and AAPCS, is to return small
+     structures in registers.  */
+  tdep->struct_return = reg_struct_return;
+
   set_gdbarch_push_dummy_call (gdbarch, arm_push_dummy_call);
   set_gdbarch_frame_align (gdbarch, arm_frame_align);
 
@@ -2762,9 +2851,6 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   /* Advance PC across function entry code.  */
   set_gdbarch_skip_prologue (gdbarch, arm_skip_prologue);
 
-  /* Get the PC when a frame might not be available.  */
-  set_gdbarch_deprecated_saved_pc_after_call (gdbarch, arm_saved_pc_after_call);
-
   /* The stack grows downward.  */
   set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
 
@@ -2776,7 +2862,6 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_deprecated_fp_regnum (gdbarch, ARM_FP_REGNUM);   /* ??? */
   set_gdbarch_sp_regnum (gdbarch, ARM_SP_REGNUM);
   set_gdbarch_pc_regnum (gdbarch, ARM_PC_REGNUM);
-  set_gdbarch_deprecated_register_byte (gdbarch, arm_register_byte);
   set_gdbarch_num_regs (gdbarch, NUM_GREGS + NUM_FREGS + NUM_SREGS);
   set_gdbarch_register_type (gdbarch, arm_register_type);
 
@@ -2802,6 +2887,9 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_coff_make_msymbol_special (gdbarch,
                                         arm_coff_make_msymbol_special);
 
+  /* Virtual tables.  */
+  set_gdbarch_vbit_in_delta (gdbarch, 1);
+
   /* Hook in the ABI-specific overrides, if they have been registered.  */
   gdbarch_init_osabi (info, gdbarch);
 
@@ -2817,35 +2905,29 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
     set_gdbarch_get_longjmp_target (gdbarch, arm_get_longjmp_target);
 
   /* Floating point sizes and format.  */
-  switch (info.byte_order)
+  set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
+  if (fp_model == ARM_FLOAT_SOFT_FPA || fp_model == ARM_FLOAT_FPA)
     {
-    case BFD_ENDIAN_BIG:
-      set_gdbarch_float_format (gdbarch, &floatformat_ieee_single_big);
-      set_gdbarch_double_format (gdbarch, &floatformat_ieee_double_big);
-      set_gdbarch_long_double_format (gdbarch, &floatformat_ieee_double_big);
-      break;
+      set_gdbarch_double_format
+       (gdbarch, floatformats_ieee_double_littlebyte_bigword);
+      set_gdbarch_long_double_format
+       (gdbarch, floatformats_ieee_double_littlebyte_bigword);
+    }
+  else
+    {
+      set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
+      set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
+    }
 
-    case BFD_ENDIAN_LITTLE:
-      set_gdbarch_float_format (gdbarch, &floatformat_ieee_single_little);
-      if (fp_model == ARM_FLOAT_SOFT_FPA || fp_model == ARM_FLOAT_FPA)
-       {
-         set_gdbarch_double_format
-           (gdbarch, &floatformat_ieee_double_littlebyte_bigword);
-         set_gdbarch_long_double_format
-           (gdbarch, &floatformat_ieee_double_littlebyte_bigword);
-       }
-      else
-       {
-         set_gdbarch_double_format (gdbarch, &floatformat_ieee_double_little);
-         set_gdbarch_long_double_format (gdbarch,
-                                         &floatformat_ieee_double_little);
-       }
-      break;
+  if (tdesc_data)
+    tdesc_use_registers (gdbarch, tdesc_data);
 
-    default:
-      internal_error (__FILE__, __LINE__,
-                     _("arm_gdbarch_init: bad byte order for float format"));
-    }
+  /* Add standard register aliases.  We add aliases even for those
+     nanes which are used by the current architecture - it's simpler,
+     and does no harm, since nothing ever lists user registers.  */
+  for (i = 0; i < ARRAY_SIZE (arm_register_aliases); i++)
+    user_reg_add (gdbarch, arm_register_aliases[i].name,
+                 value_of_arm_user_reg, &arm_register_aliases[i].regnum);
 
   return gdbarch;
 }
@@ -2911,13 +2993,11 @@ _initialize_arm_tdep (void)
       length = snprintf (rdptr, rest, "%s - %s\n", setname, setdesc);
       rdptr += length;
       rest -= length;
-      /* Copy the default names (if found) and synchronize disassembler.  */
+      /* When we find the default names, tell the disassembler to use
+        them.  */
       if (!strcmp (setname, "std"))
        {
           disassembly_style = setname;
-          current_option = i;
-         for (j = 0; j < numregs; j++)
-            arm_register_names[j] = (char *) regnames[j];
           set_arm_regname_option (i);
        }
     }
This page took 0.033237 seconds and 4 git commands to generate.