2005-10-17 Jim Blandy <jimb@redhat.com>
[deliverable/binutils-gdb.git] / gdb / arm-tdep.c
index a0892ea98e3d78b4ba491101f5e51b41e9347a14..ba713f21419cd5e4f2611fb111e701e6a120acad 100644 (file)
@@ -37,6 +37,8 @@
 #include "frame-unwind.h"
 #include "frame-base.h"
 #include "trad-frame.h"
+#include "objfiles.h"
+#include "dwarf2-frame.h"
 
 #include "arm-tdep.h"
 #include "gdb/sim-arm.h"
@@ -105,13 +107,27 @@ static const char *fp_model_strings[] =
   "softfpa",
   "fpa",
   "softvfp",
-  "vfp"
+  "vfp",
+  NULL
 };
 
 /* A variable that can be configured by the user.  */
 static enum arm_float_model arm_fp_model = ARM_FLOAT_AUTO;
 static const char *current_fp_model = "auto";
 
+/* The ABI to use.  Keep this in sync with arm_abi_kind.  */
+static const char *arm_abi_strings[] =
+{
+  "auto",
+  "APCS",
+  "AAPCS",
+  NULL
+};
+
+/* A variable that can be configured by the user.  */
+static enum arm_abi_kind arm_abi_global = ARM_ABI_AUTO;
+static const char *arm_abi_string = "auto";
+
 /* Number of different reg name sets (options).  */
 static int num_disassembly_options;
 
@@ -182,20 +198,6 @@ struct arm_prologue_cache
 
 int arm_apcs_32 = 1;
 
-/* Flag set by arm_fix_call_dummy that tells whether the target
-   function is a Thumb function.  This flag is checked by
-   arm_push_arguments.  FIXME: Change the PUSH_ARGUMENTS macro (and
-   its use in valops.c) to pass the function address as an additional
-   parameter.  */
-
-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.  */
-
-static int caller_is_thumb;
-
 /* Determine if the program counter specified in MEMADDR is in a Thumb
    function.  */
 
@@ -220,27 +222,6 @@ arm_pc_is_thumb (CORE_ADDR memaddr)
     }
 }
 
-/* Determine if the program counter specified in MEMADDR is in a call
-   dummy being called from a Thumb function.  */
-
-int
-arm_pc_is_thumb_dummy (CORE_ADDR memaddr)
-{
-  CORE_ADDR sp = read_sp ();
-
-  /* FIXME: Until we switch for the new call dummy macros, this heuristic
-     is the best we can do.  We are trying to determine if the pc is on
-     the stack, which (hopefully) will only happen in a call dummy.
-     We hope the current stack pointer is not so far alway from the dummy
-     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))
-    return caller_is_thumb;
-  else
-    return 0;
-}
-
 /* Remove useless bits from addresses in a running program.  */
 static CORE_ADDR
 arm_addr_bits_remove (CORE_ADDR val)
@@ -972,7 +953,7 @@ arm_prologue_prev_register (struct frame_info *next_frame,
                            enum lval_type *lvalp,
                            CORE_ADDR *addrp,
                            int *realnump,
-                           void *valuep)
+                           gdb_byte *valuep)
 {
   struct arm_prologue_cache *cache;
 
@@ -1013,6 +994,56 @@ arm_prologue_unwind_sniffer (struct frame_info *next_frame)
   return &arm_prologue_unwind;
 }
 
+static struct arm_prologue_cache *
+arm_make_stub_cache (struct frame_info *next_frame)
+{
+  int reg;
+  struct arm_prologue_cache *cache;
+  CORE_ADDR unwound_fp;
+
+  cache = frame_obstack_zalloc (sizeof (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);
+
+  return cache;
+}
+
+/* Our frame ID for a stub frame is the current SP and LR.  */
+
+static void
+arm_stub_this_id (struct frame_info *next_frame,
+                 void **this_cache,
+                 struct frame_id *this_id)
+{
+  struct arm_prologue_cache *cache;
+
+  if (*this_cache == NULL)
+    *this_cache = arm_make_stub_cache (next_frame);
+  cache = *this_cache;
+
+  *this_id = frame_id_build (cache->prev_sp,
+                            frame_pc_unwind (next_frame));
+}
+
+struct frame_unwind arm_stub_unwind = {
+  NORMAL_FRAME,
+  arm_stub_this_id,
+  arm_prologue_prev_register
+};
+
+static const struct frame_unwind *
+arm_stub_unwind_sniffer (struct frame_info *next_frame)
+{
+  char dummy[4];
+
+  if (in_plt_section (frame_unwind_address_in_block (next_frame), NULL)
+      || target_read_memory (frame_pc_unwind (next_frame), dummy, 4) != 0)
+    return &arm_stub_unwind;
+
+  return NULL;
+}
+
 static CORE_ADDR
 arm_normal_frame_base (struct frame_info *next_frame, void **this_cache)
 {
@@ -1082,7 +1113,7 @@ arm_sigtramp_prev_register (struct frame_info *next_frame,
                            enum lval_type *lvalp,
                            CORE_ADDR *addrp,
                            int *realnump,
-                           void *valuep)
+                           gdb_byte *valuep)
 {
   struct arm_prologue_cache *cache;
 
@@ -1173,6 +1204,54 @@ pop_stack_item (struct stack_item *si)
   return si;
 }
 
+
+/* Return the alignment (in bytes) of the given type.  */
+
+static int
+arm_type_align (struct type *t)
+{
+  int n;
+  int align;
+  int falign;
+
+  t = check_typedef (t);
+  switch (TYPE_CODE (t))
+    {
+    default:
+      /* Should never happen.  */
+      internal_error (__FILE__, __LINE__, _("unknown type alignment"));
+      return 4;
+
+    case TYPE_CODE_PTR:
+    case TYPE_CODE_ENUM:
+    case TYPE_CODE_INT:
+    case TYPE_CODE_FLT:
+    case TYPE_CODE_SET:
+    case TYPE_CODE_RANGE:
+    case TYPE_CODE_BITSTRING:
+    case TYPE_CODE_REF:
+    case TYPE_CODE_CHAR:
+    case TYPE_CODE_BOOL:
+      return TYPE_LENGTH (t);
+
+    case TYPE_CODE_ARRAY:
+    case TYPE_CODE_COMPLEX:
+      /* TODO: What about vector types?  */
+      return arm_type_align (TYPE_TARGET_TYPE (t));
+
+    case TYPE_CODE_STRUCT:
+    case TYPE_CODE_UNION:
+      align = 1;
+      for (n = 0; n < TYPE_NFIELDS (t); n++)
+       {
+         falign = arm_type_align (TYPE_FIELD_TYPE (t, n));
+         if (falign > align)
+           align = falign;
+       }
+      return align;
+    }
+}
+
 /* We currently only support passing parameters in integer registers.  This
    conforms with GCC's default model.  Several other variants exist and
    we should probably support some of them based on the selected ABI.  */
@@ -1224,6 +1303,7 @@ arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
       struct type *target_type;
       enum type_code typecode;
       bfd_byte *val;
+      int align;
 
       arg_type = check_typedef (value_type (args[argnum]));
       len = TYPE_LENGTH (arg_type);
@@ -1231,6 +1311,35 @@ arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
       typecode = TYPE_CODE (arg_type);
       val = value_contents_writeable (args[argnum]);
 
+      align = arm_type_align (arg_type);
+      /* Round alignment up to a whole number of words.  */
+      align = (align + INT_REGISTER_SIZE - 1) & ~(INT_REGISTER_SIZE - 1);
+      /* Different ABIs have different maximum alignments.  */
+      if (gdbarch_tdep (gdbarch)->arm_abi == ARM_ABI_APCS)
+       {
+         /* The APCS ABI only requires word alignment.  */
+         align = INT_REGISTER_SIZE;
+       }
+      else
+       {
+         /* The AAPCS requires at most doubleword alignment.  */
+         if (align > INT_REGISTER_SIZE * 2)
+           align = INT_REGISTER_SIZE * 2;
+       }
+
+      /* Push stack padding for dowubleword alignment.  */
+      if (nstack & (align - 1))
+       {
+         si = push_stack_item (si, val, INT_REGISTER_SIZE);
+         nstack += INT_REGISTER_SIZE;
+       }
+      
+      /* Doubleword aligned quantities must go in even register pairs.  */
+      if (argreg <= ARM_LAST_ARG_REGNUM
+         && align > INT_REGISTER_SIZE
+         && argreg & 1)
+       argreg++;
+
       /* If the argument is a pointer to a function, and it is a
         Thumb function, create a LOCAL copy of the value and set
         the THUMB bit in it.  */
@@ -1964,7 +2073,7 @@ arm_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
 
-  if (arm_pc_is_thumb (*pcptr) || arm_pc_is_thumb_dummy (*pcptr))
+  if (arm_pc_is_thumb (*pcptr))
     {
       *pcptr = UNMAKE_THUMB_ADDR (*pcptr);
       *lenptr = tdep->thumb_breakpoint_size;
@@ -1982,15 +2091,12 @@ arm_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
    format, into VALBUF.  */
 
 static void
-arm_extract_return_value (struct type *type,
-                         struct regcache *regs,
-                         void *dst)
+arm_extract_return_value (struct type *type, struct regcache *regs,
+                         gdb_byte *valbuf)
 {
-  bfd_byte *valbuf = dst;
-
   if (TYPE_CODE_FLT == TYPE_CODE (type))
     {
-      switch (arm_get_fp_model (current_gdbarch))
+      switch (gdbarch_tdep (current_gdbarch)->fp_model)
        {
        case ARM_FLOAT_FPA:
          {
@@ -2066,24 +2172,13 @@ arm_extract_return_value (struct type *type,
     }
 }
 
-/* Extract from an array REGBUF containing the (raw) register state
-   the address in which a function should return its structure value.  */
-
-static CORE_ADDR
-arm_extract_struct_value_address (struct regcache *regcache)
-{
-  ULONGEST ret;
-
-  regcache_cooked_read_unsigned (regcache, ARM_A1_REGNUM, &ret);
-  return ret;
-}
 
 /* Will a function return an aggregate type in memory or in a
    register?  Return 0 if an aggregate type can be returned in a
    register, 1 if it must be returned in memory.  */
 
 static int
-arm_use_struct_convention (int gcc_p, struct type *type)
+arm_return_in_memory (struct gdbarch *gdbarch, struct type *type)
 {
   int nRc;
   enum type_code code;
@@ -2114,6 +2209,11 @@ arm_use_struct_convention (int gcc_p, struct type *type)
       return 1;
     }
 
+  /* The AAPCS says all aggregates not larger than a word are returned
+     in a register.  */
+  if (gdbarch_tdep (gdbarch)->arm_abi != ARM_ABI_APCS)
+    return 0;
+
   /* The only aggregate types that can be returned in a register are
      structs and unions.  Arrays must be returned in memory.  */
   code = TYPE_CODE (type);
@@ -2179,15 +2279,13 @@ arm_use_struct_convention (int gcc_p, struct type *type)
 
 static void
 arm_store_return_value (struct type *type, struct regcache *regs,
-                       const void *src)
+                       const gdb_byte *valbuf)
 {
-  const bfd_byte *valbuf = src;
-
   if (TYPE_CODE (type) == TYPE_CODE_FLT)
     {
       char buf[MAX_REGISTER_SIZE];
 
-      switch (arm_get_fp_model (current_gdbarch))
+      switch (gdbarch_tdep (current_gdbarch)->fp_model)
        {
        case ARM_FLOAT_FPA:
 
@@ -2263,6 +2361,32 @@ arm_store_return_value (struct type *type, struct regcache *regs,
     }
 }
 
+
+/* Handle function return values.  */
+
+static enum return_value_convention
+arm_return_value (struct gdbarch *gdbarch, struct type *valtype,
+                 struct regcache *regcache, void *readbuf,
+                 const void *writebuf)
+{
+  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))
+       return RETURN_VALUE_STRUCT_CONVENTION;
+    }
+
+  if (writebuf)
+    arm_store_return_value (valtype, regcache, writebuf);
+
+  if (readbuf)
+    arm_extract_return_value (valtype, regcache, readbuf);
+
+  return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+
 static int
 arm_get_longjmp_target (CORE_ADDR *pc)
 {
@@ -2344,34 +2468,20 @@ show_arm_command (char *args, int from_tty)
   cmd_show_list (showarmcmdlist, from_tty, "");
 }
 
-enum arm_float_model
-arm_get_fp_model (struct gdbarch *gdbarch)
+static void
+arm_update_current_architecture (void)
 {
-  if (arm_fp_model == ARM_FLOAT_AUTO)
-    return gdbarch_tdep (gdbarch)->fp_model;
+  struct gdbarch_info info;
 
-  return arm_fp_model;
-}
+  /* If the current architecture is not ARM, we have nothing to do.  */
+  if (gdbarch_bfd_arch_info (current_gdbarch)->arch != bfd_arch_arm)
+    return;
 
-static void
-arm_set_fp (struct gdbarch *gdbarch)
-{
-  enum arm_float_model fp_model = arm_get_fp_model (gdbarch);
+  /* Update the architecture.  */
+  gdbarch_info_init (&info);
 
-  if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_LITTLE 
-      && (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);
-    }
+  if (!gdbarch_update_p (info))
+    internal_error (__FILE__, __LINE__, "could not update architecture");
 }
 
 static void
@@ -2391,8 +2501,7 @@ set_fp_model_sfunc (char *args, int from_tty,
     internal_error (__FILE__, __LINE__, _("Invalid fp model accepted: %s."),
                    current_fp_model);
 
-  if (gdbarch_bfd_arch_info (current_gdbarch)->arch == bfd_arch_arm)
-    arm_set_fp (current_gdbarch);
+  arm_update_current_architecture ();
 }
 
 static void
@@ -2401,12 +2510,51 @@ show_fp_model (struct ui_file *file, int from_tty,
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
 
-  deprecated_show_value_hack (file, from_tty, c, value);
-  if (arm_fp_model == ARM_FLOAT_AUTO 
+  if (arm_fp_model == ARM_FLOAT_AUTO
       && gdbarch_bfd_arch_info (current_gdbarch)->arch == bfd_arch_arm)
-    /* i18n: "the default [floating point model] for the current ABI..." */
-    printf_filtered (_("  - the default for the current ABI is \"%s\".\n"),
-                    fp_model_strings[tdep->fp_model]);
+    fprintf_filtered (file, _("\
+The current ARM floating point model is \"auto\" (currently \"%s\").\n"),
+                     fp_model_strings[tdep->fp_model]);
+  else
+    fprintf_filtered (file, _("\
+The current ARM floating point model is \"%s\".\n"),
+                     fp_model_strings[arm_fp_model]);
+}
+
+static void
+arm_set_abi (char *args, int from_tty,
+            struct cmd_list_element *c)
+{
+  enum arm_abi_kind arm_abi;
+
+  for (arm_abi = ARM_ABI_AUTO; arm_abi != ARM_ABI_LAST; arm_abi++)
+    if (strcmp (arm_abi_string, arm_abi_strings[arm_abi]) == 0)
+      {
+       arm_abi_global = arm_abi;
+       break;
+      }
+
+  if (arm_abi == ARM_ABI_LAST)
+    internal_error (__FILE__, __LINE__, _("Invalid ABI accepted: %s."),
+                   arm_abi_string);
+
+  arm_update_current_architecture ();
+}
+
+static void
+arm_show_abi (struct ui_file *file, int from_tty,
+            struct cmd_list_element *c, const char *value)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+  if (arm_abi_global == ARM_ABI_AUTO
+      && gdbarch_bfd_arch_info (current_gdbarch)->arch == bfd_arch_arm)
+    fprintf_filtered (file, _("\
+The current ARM ABI is \"auto\" (currently \"%s\").\n"),
+                     arm_abi_strings[tdep->arm_abi]);
+  else
+    fprintf_filtered (file, _("The current ARM ABI is \"%s\".\n"),
+                     arm_abi_string);
 }
 
 /* If the user changes the register disassembly style used for info
@@ -2431,7 +2579,7 @@ arm_register_name (int i)
 static void
 set_disassembly_style (void)
 {
-  const char *setname, *setdesc, **regnames;
+  const char *setname, *setdesc, *const *regnames;
   int numregs, j;
 
   /* Find the style that the user wants in the opcodes table.  */
@@ -2518,76 +2666,19 @@ arm_write_pc (CORE_ADDR pc, ptid_t ptid)
 static enum gdb_osabi
 arm_elf_osabi_sniffer (bfd *abfd)
 {
-  unsigned int elfosabi, eflags;
+  unsigned int elfosabi;
   enum gdb_osabi osabi = GDB_OSABI_UNKNOWN;
 
   elfosabi = elf_elfheader (abfd)->e_ident[EI_OSABI];
 
-  switch (elfosabi)
-    {
-    case ELFOSABI_NONE:  
-      /* When elfosabi is ELFOSABI_NONE (0), then the ELF structures in the
-        file are conforming to the base specification for that machine 
-        (there are no OS-specific extensions).  In order to determine the 
-        real OS in use we must look for OS notes that have been added.  */
-      bfd_map_over_sections (abfd,
-                            generic_elf_osabi_sniff_abi_tag_sections,  
-                            &osabi);
-      if (osabi == GDB_OSABI_UNKNOWN)
-       {
-         /* Existing ARM tools don't set this field, so look at the EI_FLAGS
-            field for more information.  */
-         eflags = EF_ARM_EABI_VERSION(elf_elfheader(abfd)->e_flags);
-         switch (eflags)
-           {
-           case EF_ARM_EABI_VER1:
-             osabi = GDB_OSABI_ARM_EABI_V1;
-             break;
-
-           case EF_ARM_EABI_VER2:
-             osabi = GDB_OSABI_ARM_EABI_V2;
-             break;
-
-           case EF_ARM_EABI_UNKNOWN:
-             /* Assume GNU tools.  */
-             osabi = GDB_OSABI_ARM_APCS;
-             break;
-
-           default:
-             internal_error (__FILE__, __LINE__,
-                             _("\
-arm_elf_osabi_sniffer: Unknown ARM EABI version 0x%x"),
-                             eflags);
-           }
-       }
-      break;
-
-    case ELFOSABI_ARM:
-      /* GNU tools use this value.  Check note sections in this case,
-        as well.  */
-      bfd_map_over_sections (abfd,
-                            generic_elf_osabi_sniff_abi_tag_sections, 
-                            &osabi);
-      if (osabi == GDB_OSABI_UNKNOWN)
-       {
-         /* Assume APCS ABI.  */
-         osabi = GDB_OSABI_ARM_APCS;
-       }
-      break;
-
-    case ELFOSABI_FREEBSD:
-      osabi = GDB_OSABI_FREEBSD_ELF;
-      break;
-
-    case ELFOSABI_NETBSD:
-      osabi = GDB_OSABI_NETBSD_ELF;
-      break;
-
-    case ELFOSABI_LINUX:
-      osabi = GDB_OSABI_LINUX;
-      break;
-    }
+  if (elfosabi == ELFOSABI_ARM)
+    /* GNU tools use this value.  Check note sections in this case,
+       as well.  */
+    bfd_map_over_sections (abfd,
+                          generic_elf_osabi_sniff_abi_tag_sections, 
+                          &osabi);
 
+  /* Anything else will be handled by the generic ELF sniffer.  */
   return osabi;
 }
 
@@ -2604,42 +2695,123 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 {
   struct gdbarch_tdep *tdep;
   struct gdbarch *gdbarch;
+  struct gdbarch_list *best_arch;
+  enum arm_abi_kind arm_abi = arm_abi_global;
+  enum arm_float_model fp_model = arm_fp_model;
 
-  /* Try to deterimine the ABI of the object we are loading.  */
+  /* If we have an object to base this architecture on, try to determine
+     its ABI.  */
 
-  if (info.abfd != NULL && info.osabi == GDB_OSABI_UNKNOWN)
+  if (arm_abi == ARM_ABI_AUTO && info.abfd != NULL)
     {
+      int ei_osabi;
+
       switch (bfd_get_flavour (info.abfd))
        {
        case bfd_target_aout_flavour:
          /* Assume it's an old APCS-style ABI.  */
-         info.osabi = GDB_OSABI_ARM_APCS;
+         arm_abi = ARM_ABI_APCS;
          break;
 
        case bfd_target_coff_flavour:
          /* Assume it's an old APCS-style ABI.  */
          /* XXX WinCE?  */
-         info.osabi = GDB_OSABI_ARM_APCS;
+         arm_abi = ARM_ABI_APCS;
+         break;
+
+       case bfd_target_elf_flavour:
+         ei_osabi = elf_elfheader (info.abfd)->e_ident[EI_OSABI];
+         if (ei_osabi == ELFOSABI_ARM)
+           {
+             /* GNU tools used to use this value, but do not for EABI
+                objects.  There's nowhere to tag an EABI version anyway,
+                so assume APCS.  */
+             arm_abi = ARM_ABI_APCS;
+           }
+         else if (ei_osabi == ELFOSABI_NONE)
+           {
+             int e_flags, eabi_ver;
+
+             e_flags = elf_elfheader (info.abfd)->e_flags;
+             eabi_ver = EF_ARM_EABI_VERSION (e_flags);
+
+             switch (eabi_ver)
+               {
+               case EF_ARM_EABI_UNKNOWN:
+                 /* Assume GNU tools.  */
+                 arm_abi = ARM_ABI_APCS;
+                 break;
+
+               case EF_ARM_EABI_VER4:
+                 arm_abi = ARM_ABI_AAPCS;
+                 /* EABI binaries default to VFP float ordering.  */
+                 if (fp_model == ARM_FLOAT_AUTO)
+                   fp_model = ARM_FLOAT_SOFT_VFP;
+                 break;
+
+               default:
+                 warning (_("unknown ARM EABI version 0x%x"), eabi_ver);
+                 arm_abi = ARM_ABI_APCS;
+                 break;
+               }
+           }
          break;
 
        default:
-         /* Leave it as "unknown".  */
+         /* Leave it as "auto".  */
          break;
        }
     }
 
-  /* If there is already a candidate, use it.  */
-  arches = gdbarch_list_lookup_by_info (arches, &info);
+  /* Now that we have inferred any architecture settings that we
+     can, try to inherit from the last ARM ABI.  */
   if (arches != NULL)
-    return arches->gdbarch;
+    {
+      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)
+       continue;
+
+      if (fp_model != gdbarch_tdep (best_arch->gdbarch)->fp_model)
+       continue;
 
-  tdep = xmalloc (sizeof (struct gdbarch_tdep));
+      /* Found a match.  */
+      break;
+    }
+
+  if (best_arch != NULL)
+    return best_arch->gdbarch;
+
+  tdep = xcalloc (1, sizeof (struct gdbarch_tdep));
   gdbarch = gdbarch_alloc (&info, tdep);
 
-  /* 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.  */
-  tdep->fp_model = ARM_FLOAT_SOFT_FPA;
+  /* Record additional information about the architecture we are defining.
+     These are gdbarch discriminators, like the OSABI.  */
+  tdep->arm_abi = arm_abi;
+  tdep->fp_model = fp_model;
 
   /* Breakpoints.  */
   switch (info.byte_order)
@@ -2716,10 +2888,7 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_register_name (gdbarch, arm_register_name);
 
   /* Returning results.  */
-  set_gdbarch_extract_return_value (gdbarch, arm_extract_return_value);
-  set_gdbarch_store_return_value (gdbarch, arm_store_return_value);
-  set_gdbarch_deprecated_use_struct_convention (gdbarch, arm_use_struct_convention);
-  set_gdbarch_deprecated_extract_struct_value_address (gdbarch, arm_extract_struct_value_address);
+  set_gdbarch_return_value (gdbarch, arm_return_value);
 
   /* Single stepping.  */
   /* XXX For an RDI target we should ask the target if it can single-step.  */
@@ -2737,7 +2906,9 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   gdbarch_init_osabi (info, gdbarch);
 
   /* Add some default predicates.  */
+  frame_unwind_append_sniffer (gdbarch, arm_stub_unwind_sniffer);
   frame_unwind_append_sniffer (gdbarch, arm_sigtramp_unwind_sniffer);
+  frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
   frame_unwind_append_sniffer (gdbarch, arm_prologue_unwind_sniffer);
 
   /* Now we have tuned the configuration, set a few final things,
@@ -2753,12 +2924,23 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       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;
 
     case BFD_ENDIAN_LITTLE:
       set_gdbarch_float_format (gdbarch, &floatformat_ieee_single_little);
-      arm_set_fp (gdbarch);
+      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;
 
     default:
@@ -2781,27 +2963,6 @@ arm_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
                      (unsigned long) tdep->lowest_pc);
 }
 
-static void
-arm_init_abi_eabi_v1 (struct gdbarch_info info,
-                     struct gdbarch *gdbarch)
-{
-  /* Place-holder.  */
-}
-
-static void
-arm_init_abi_eabi_v2 (struct gdbarch_info info,
-                     struct gdbarch *gdbarch)
-{
-  /* Place-holder.  */
-}
-
-static void
-arm_init_abi_apcs (struct gdbarch_info info,
-                  struct gdbarch *gdbarch)
-{
-  /* Place-holder.  */
-}
-
 extern initialize_file_ftype _initialize_arm_tdep; /* -Wmissing-prototypes */
 
 void
@@ -2812,7 +2973,7 @@ _initialize_arm_tdep (void)
   struct cmd_list_element *new_set, *new_show;
   const char *setname;
   const char *setdesc;
-  const char **regnames;
+  const char *const *regnames;
   int numregs, i, j;
   static char *helptext;
   char regdesc[1024], *rdptr = regdesc;
@@ -2825,14 +2986,6 @@ _initialize_arm_tdep (void)
                                  bfd_target_elf_flavour,
                                  arm_elf_osabi_sniffer);
 
-  /* Register some ABI variants for embedded systems.  */
-  gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_ARM_EABI_V1,
-                          arm_init_abi_eabi_v1);
-  gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_ARM_EABI_V2,
-                          arm_init_abi_eabi_v2);
-  gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_ARM_APCS,
-                          arm_init_abi_apcs);
-
   /* Get the number of possible sets of register names defined in opcodes.  */
   num_disassembly_options = get_arm_regname_num_options ();
 
@@ -2848,7 +3001,8 @@ _initialize_arm_tdep (void)
   /* Sync the opcode insn printer with our register viewer.  */
   parse_arm_disassembler_option ("reg-names-std");
 
-  /* Initialize the array that will be passed to add_set_enum_cmd().  */
+  /* Initialize the array that will be passed to
+     add_setshow_enum_cmd().  */
   valid_disassembly_styles
     = xmalloc ((num_disassembly_options + 1) * sizeof (char *));
   for (i = 0; i < num_disassembly_options; i++)
@@ -2885,16 +3039,16 @@ _initialize_arm_tdep (void)
                       _("Set the disassembly style."),
                       _("Show the disassembly style."),
                       helptext,
+                      set_disassembly_style_sfunc,
                       NULL, /* FIXME: i18n: The disassembly style is \"%s\".  */
-                      set_disassembly_style_sfunc, NULL,
                       &setarmcmdlist, &showarmcmdlist);
 
   add_setshow_boolean_cmd ("apcs32", no_class, &arm_apcs_32,
                           _("Set usage of ARM 32-bit mode."),
                           _("Show usage of ARM 32-bit mode."),
                           _("When off, a 26-bit PC will be used."),
+                          NULL,
                           NULL, /* FIXME: i18n: Usage of ARM 32-bit mode is %s.  */
-                          NULL, NULL,
                           &setarmcmdlist, &showarmcmdlist);
 
   /* Add a command to allow the user to force the FPU model.  */
@@ -2906,16 +3060,22 @@ softfpa - Software FP, mixed-endian doubles on little-endian ARMs.\n\
 fpa - FPA co-processor (GCC compiled).\n\
 softvfp - Software FP with pure-endian doubles.\n\
 vfp - VFP co-processor."),
-                       NULL, /* FIXME: i18n: "The floating point type is \"%s\".  */
                        set_fp_model_sfunc, show_fp_model,
                        &setarmcmdlist, &showarmcmdlist);
 
+  /* Add a command to allow the user to force the ABI.  */
+  add_setshow_enum_cmd ("abi", class_support, arm_abi_strings, &arm_abi_string,
+                       _("Set the ABI."),
+                       _("Show the ABI."),
+                       NULL, arm_set_abi, arm_show_abi,
+                       &setarmcmdlist, &showarmcmdlist);
+
   /* Debugging flag.  */
   add_setshow_boolean_cmd ("arm", class_maintenance, &arm_debug,
                           _("Set ARM debugging."),
                           _("Show ARM debugging."),
                           _("When on, arm-specific debugging is enabled."),
+                          NULL,
                           NULL, /* FIXME: i18n: "ARM debugging is %s.  */
-                          NULL, NULL,
                           &setdebuglist, &showdebuglist);
 }
This page took 0.051219 seconds and 4 git commands to generate.