* arm-tdep.h (enum arm_abi): New enum.
[deliverable/binutils-gdb.git] / gdb / arm-tdep.c
index 169441e721c1257aa9befc15dd1611effb391123..9577f0a1e56b76548ab824bbf478d02745e78ae5 100644 (file)
@@ -39,6 +39,7 @@
 
 #include "elf-bfd.h"
 #include "coff/internal.h"
+#include "elf/arm.h"
 
 /* Each OS has a different mechanism for accessing the various
    registers stored in the sigcontext structure.
 #define MSYMBOL_SIZE(msym)                             \
        ((long) MSYMBOL_INFO (msym) & 0x7fffffff)
 
+/* This table matches the indicees assigned to enum arm_abi.  Keep
+   them in sync.  */
+
+static const char * const arm_abi_names[] =
+{
+  "<unknown>",
+  "ARM EABI (version 1)",
+  "ARM EABI (version 2)",
+  "GNU/Linux",
+  "NetBSD (a.out)",
+  "NetBSD (ELF)",
+  "APCS",
+  "FreeBSD",
+  "Windows CE",
+  NULL
+};
+
 /* Number of different reg name sets (options). */
 static int num_flavor_options;
 
@@ -145,100 +163,6 @@ struct frame_extra_info
 #define MAKE_THUMB_ADDR(addr)  ((addr) | 1)
 #define UNMAKE_THUMB_ADDR(addr) ((addr) & ~1)
 
-/* 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.  */
-
-int
-arm_use_struct_convention (int gcc_p, struct type *type)
-{
-  int nRc;
-  register enum type_code code;
-
-  /* In the ARM ABI, "integer" like aggregate types are returned in
-     registers.  For an aggregate type to be integer like, its size
-     must be less than or equal to REGISTER_SIZE and the offset of
-     each addressable subfield must be zero.  Note that bit fields are
-     not addressable, and all addressable subfields of unions always
-     start at offset zero.
-
-     This function is based on the behaviour of GCC 2.95.1.
-     See: gcc/arm.c: arm_return_in_memory() for details.
-
-     Note: All versions of GCC before GCC 2.95.2 do not set up the
-     parameters correctly for a function returning the following
-     structure: struct { float f;}; This should be returned in memory,
-     not a register.  Richard Earnshaw sent me a patch, but I do not
-     know of any way to detect if a function like the above has been
-     compiled with the correct calling convention.  */
-
-  /* All aggregate types that won't fit in a register must be returned
-     in memory.  */
-  if (TYPE_LENGTH (type) > REGISTER_SIZE)
-    {
-      return 1;
-    }
-
-  /* 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);
-  if ((TYPE_CODE_STRUCT != code) && (TYPE_CODE_UNION != code))
-    {
-      return 1;
-    }
-
-  /* Assume all other aggregate types can be returned in a register.
-     Run a check for structures, unions and arrays.  */
-  nRc = 0;
-
-  if ((TYPE_CODE_STRUCT == code) || (TYPE_CODE_UNION == code))
-    {
-      int i;
-      /* Need to check if this struct/union is "integer" like.  For
-         this to be true, its size must be less than or equal to
-         REGISTER_SIZE and the offset of each addressable subfield
-         must be zero.  Note that bit fields are not addressable, and
-         unions always start at offset zero.  If any of the subfields
-         is a floating point type, the struct/union cannot be an
-         integer type.  */
-
-      /* For each field in the object, check:
-         1) Is it FP? --> yes, nRc = 1;
-         2) Is it addressable (bitpos != 0) and
-         not packed (bitsize == 0)?
-         --> yes, nRc = 1  
-       */
-
-      for (i = 0; i < TYPE_NFIELDS (type); i++)
-       {
-         enum type_code field_type_code;
-         field_type_code = TYPE_CODE (TYPE_FIELD_TYPE (type, i));
-
-         /* Is it a floating point type field?  */
-         if (field_type_code == TYPE_CODE_FLT)
-           {
-             nRc = 1;
-             break;
-           }
-
-         /* If bitpos != 0, then we have to care about it.  */
-         if (TYPE_FIELD_BITPOS (type, i) != 0)
-           {
-             /* Bitfields are not addressable.  If the field bitsize is 
-                zero, then the field is not packed.  Hence it cannot be
-                a bitfield or any other packed type.  */
-             if (TYPE_FIELD_BITSIZE (type, i) == 0)
-               {
-                 nRc = 1;
-                 break;
-               }
-           }
-       }
-    }
-
-  return nRc;
-}
-
 static int
 arm_frame_chain_valid (CORE_ADDR chain, struct frame_info *thisframe)
 {
@@ -1447,12 +1371,7 @@ arm_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
       arg_type = check_typedef (VALUE_TYPE (args[argnum]));
       len = TYPE_LENGTH (arg_type);
 
-      /* ANSI C code passes float arguments as integers, K&R code
-         passes float arguments as doubles.  Correct for this here.  */
-      if (TYPE_CODE_FLT == TYPE_CODE (arg_type) && REGISTER_SIZE == len)
-       nstack_size += FP_REGISTER_VIRTUAL_SIZE;
-      else
-       nstack_size += len;
+      nstack_size += len;
     }
 
   /* Allocate room on the stack, and initialize our stack frame
@@ -1489,21 +1408,6 @@ arm_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
       typecode = TYPE_CODE (arg_type);
       val = (char *) VALUE_CONTENTS (args[argnum]);
 
-      /* ANSI C code passes float arguments as integers, K&R code
-         passes float arguments as doubles.  The .stabs record for 
-         for ANSI prototype floating point arguments records the
-         type as FP_INTEGER, while a K&R style (no prototype)
-         .stabs records the type as FP_FLOAT.  In this latter case
-         the compiler converts the float arguments to double before
-         calling the function.  */
-      if (TYPE_CODE_FLT == typecode && REGISTER_SIZE == len)
-       {
-         DOUBLEST dblval;
-         dblval = extract_floating (val, len);
-         len = TARGET_DOUBLE_BIT / TARGET_CHAR_BIT;
-         val = alloca (len);
-         store_floating (val, len, dblval);
-       }
 #if 1
       /* I don't know why this code was disable. The only logical use
          for a function pointer is to call that function, so setting
@@ -2067,7 +1971,7 @@ arm_get_next_pc (CORE_ADDR pc)
          break;
 
        default:
-         fprintf (stderr, "Bad bit-field extraction\n");
+         fprintf_filtered (gdb_stderr, "Bad bit-field extraction\n");
          return (pc);
        }
     }
@@ -2206,6 +2110,109 @@ arm_extract_return_value (struct type *type,
            TYPE_LENGTH (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 (char *regbuf)
+{
+  return extract_address (regbuf, REGISTER_RAW_SIZE(ARM_A1_REGNUM));
+}
+
+/* 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)
+{
+  int nRc;
+  register enum type_code code;
+
+  /* In the ARM ABI, "integer" like aggregate types are returned in
+     registers.  For an aggregate type to be integer like, its size
+     must be less than or equal to REGISTER_SIZE and the offset of
+     each addressable subfield must be zero.  Note that bit fields are
+     not addressable, and all addressable subfields of unions always
+     start at offset zero.
+
+     This function is based on the behaviour of GCC 2.95.1.
+     See: gcc/arm.c: arm_return_in_memory() for details.
+
+     Note: All versions of GCC before GCC 2.95.2 do not set up the
+     parameters correctly for a function returning the following
+     structure: struct { float f;}; This should be returned in memory,
+     not a register.  Richard Earnshaw sent me a patch, but I do not
+     know of any way to detect if a function like the above has been
+     compiled with the correct calling convention.  */
+
+  /* All aggregate types that won't fit in a register must be returned
+     in memory.  */
+  if (TYPE_LENGTH (type) > REGISTER_SIZE)
+    {
+      return 1;
+    }
+
+  /* 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);
+  if ((TYPE_CODE_STRUCT != code) && (TYPE_CODE_UNION != code))
+    {
+      return 1;
+    }
+
+  /* Assume all other aggregate types can be returned in a register.
+     Run a check for structures, unions and arrays.  */
+  nRc = 0;
+
+  if ((TYPE_CODE_STRUCT == code) || (TYPE_CODE_UNION == code))
+    {
+      int i;
+      /* Need to check if this struct/union is "integer" like.  For
+         this to be true, its size must be less than or equal to
+         REGISTER_SIZE and the offset of each addressable subfield
+         must be zero.  Note that bit fields are not addressable, and
+         unions always start at offset zero.  If any of the subfields
+         is a floating point type, the struct/union cannot be an
+         integer type.  */
+
+      /* For each field in the object, check:
+         1) Is it FP? --> yes, nRc = 1;
+         2) Is it addressable (bitpos != 0) and
+         not packed (bitsize == 0)?
+         --> yes, nRc = 1  
+       */
+
+      for (i = 0; i < TYPE_NFIELDS (type); i++)
+       {
+         enum type_code field_type_code;
+         field_type_code = TYPE_CODE (TYPE_FIELD_TYPE (type, i));
+
+         /* Is it a floating point type field?  */
+         if (field_type_code == TYPE_CODE_FLT)
+           {
+             nRc = 1;
+             break;
+           }
+
+         /* If bitpos != 0, then we have to care about it.  */
+         if (TYPE_FIELD_BITPOS (type, i) != 0)
+           {
+             /* Bitfields are not addressable.  If the field bitsize is 
+                zero, then the field is not packed.  Hence it cannot be
+                a bitfield or any other packed type.  */
+             if (TYPE_FIELD_BITSIZE (type, i) == 0)
+               {
+                 nRc = 1;
+                 break;
+               }
+           }
+       }
+    }
+
+  return nRc;
+}
+
 /* Write into appropriate registers a function return value of type
    TYPE, given in virtual format.  */
 
@@ -2431,16 +2438,301 @@ arm_coff_make_msymbol_special(int val, struct minimal_symbol *msym)
     MSYMBOL_SET_SPECIAL (msym);
 }
 
+\f
+static void
+process_note_abi_tag_sections (bfd *abfd, asection *sect, void *obj)
+{
+  enum arm_abi *os_ident_ptr = obj;
+  const char *name;
+  unsigned int sectsize;
+
+  name = bfd_get_section_name (abfd, sect);
+  sectsize = bfd_section_size (abfd, sect);
+
+  if (strcmp (name, ".note.ABI-tag") == 0 && sectsize > 0)
+    {
+      unsigned int name_length, data_length, note_type;
+      char *note;
+
+      /* If the section is larger than this, it's probably not what we are
+        looking for.  */
+      if (sectsize > 128)
+       sectsize = 128;
+
+      note = alloca (sectsize);
+
+      bfd_get_section_contents (abfd, sect, note,
+                                (file_ptr) 0, (bfd_size_type) sectsize);
+
+      name_length = bfd_h_get_32 (abfd, note);
+      data_length = bfd_h_get_32 (abfd, note + 4);
+      note_type   = bfd_h_get_32 (abfd, note + 8);
+
+      if (name_length == 4 && data_length == 16 && note_type == 1
+          && strcmp (note + 12, "GNU") == 0)
+       {
+         int os_number = bfd_h_get_32 (abfd, note + 16);
+
+         /* The case numbers are from abi-tags in glibc */
+         switch (os_number)
+           {
+           case 0 :
+             *os_ident_ptr = ARM_ABI_LINUX;
+             break;
+
+           case 1 :
+             internal_error
+               (__FILE__, __LINE__,
+                "process_note_abi_sections: Hurd objects not supported");
+             break;
+
+           case 2 :
+             internal_error
+               (__FILE__, __LINE__,
+                "process_note_abi_sections: Solaris objects not supported");
+             break;
+
+           default :
+             internal_error
+               (__FILE__, __LINE__,
+                "process_note_abi_sections: unknown OS number %d",
+                os_number);
+             break;
+           }
+       }
+    }
+  /* NetBSD uses a similar trick.  */
+  else if (strcmp (name, ".note.netbsd.ident") == 0 && sectsize > 0)
+    {
+      unsigned int name_length, desc_length, note_type;
+      char *note;
+
+      /* If the section is larger than this, it's probably not what we are
+        looking for.  */
+      if (sectsize > 128)
+       sectsize = 128;
+
+      note = alloca (sectsize);
+
+      bfd_get_section_contents (abfd, sect, note,
+                                (file_ptr) 0, (bfd_size_type) sectsize);
+
+      name_length = bfd_h_get_32 (abfd, note);
+      desc_length = bfd_h_get_32 (abfd, note + 4);
+      note_type   = bfd_h_get_32 (abfd, note + 8);
+
+      if (name_length == 7 && desc_length == 4 && note_type == 1
+          && strcmp (note + 12, "NetBSD") == 0)
+       /* XXX Should we check the version here?
+          Probably not necessary yet.  */
+       *os_ident_ptr = ARM_ABI_NETBSD_ELF;
+    }
+}
+
+/* Return one of the ELFOSABI_ constants for BFDs representing ELF
+   executables.  If it's not an ELF executable or if the OS/ABI couldn't
+   be determined, simply return -1. */
+
+static int
+get_elfosabi (bfd *abfd)
+{
+  int elfosabi;
+  enum arm_abi arm_abi = ARM_ABI_UNKNOWN;
+
+  elfosabi = elf_elfheader (abfd)->e_ident[EI_OSABI];
+
+  /* When elfosabi is 0 (ELFOSABI_NONE), this is supposed to indicate
+     that we're on a SYSV system.  However, GNU/Linux uses a note section
+     to record OS/ABI info, but leaves e_ident[EI_OSABI] zero.  So we
+     have to check the note sections too.
+
+     GNU/ARM tools set the EI_OSABI field to ELFOSABI_ARM, so handle that
+     as well.*/
+  if (elfosabi == 0 || elfosabi == ELFOSABI_ARM)
+    {
+      bfd_map_over_sections (abfd,
+                            process_note_abi_tag_sections,
+                            &arm_abi);
+    }
+
+  if (arm_abi != ARM_ABI_UNKNOWN)
+    return arm_abi;
+
+  switch (elfosabi)
+    {
+    case ELFOSABI_NONE:
+      /* Existing ARM Tools don't set this field, so look at the EI_FLAGS
+        field for more information.  */
+
+      switch (EF_ARM_EABI_VERSION(elf_elfheader(abfd)->e_flags))
+       {
+       case EF_ARM_EABI_VER1:
+         return ARM_ABI_EABI_V1;
+
+       case EF_ARM_EABI_VER2:
+         return ARM_ABI_EABI_V2;
+
+       case EF_ARM_EABI_UNKNOWN:
+         /* Assume GNU tools.  */
+         return ARM_ABI_APCS;
+
+       default:
+         internal_error (__FILE__, __LINE__,
+                         "get_elfosabi: Unknown ARM EABI version 0x%lx",
+                         EF_ARM_EABI_VERSION(elf_elfheader(abfd)->e_flags));
+
+       }
+      break;
+
+    case ELFOSABI_NETBSD:
+      return ARM_ABI_NETBSD_ELF;
+
+    case ELFOSABI_FREEBSD:
+      return ARM_ABI_FREEBSD;
+
+    case ELFOSABI_LINUX:
+      return ARM_ABI_LINUX;
+
+    case ELFOSABI_ARM:
+      /* Assume GNU tools with the old APCS abi.  */
+      return ARM_ABI_APCS;
+
+    default:
+    }
+
+  return ARM_ABI_UNKNOWN;
+}
+
+struct arm_abi_handler
+{
+  struct arm_abi_handler *next;
+  enum arm_abi abi;
+  void (*init_abi)(struct gdbarch_info, struct gdbarch *);
+};
+
+struct arm_abi_handler *arm_abi_handler_list = NULL;
+
+void
+arm_gdbarch_register_os_abi (enum arm_abi abi,
+                            void (*init_abi)(struct gdbarch_info,
+                                             struct gdbarch *))
+{
+  struct arm_abi_handler **handler_p;
+
+  for (handler_p = &arm_abi_handler_list; *handler_p != NULL;
+       handler_p = &(*handler_p)->next)
+    {
+      if ((*handler_p)->abi == abi)
+       {
+         internal_error
+           (__FILE__, __LINE__,
+            "arm_gdbarch_register_os_abi: A handler for this ABI variant (%d)"
+            " has already been registered", (int)abi);
+         /* If user wants to continue, override previous definition.  */
+         (*handler_p)->init_abi = init_abi;
+         return;
+       }
+    }
+
+  (*handler_p)
+    = (struct arm_abi_handler *) xmalloc (sizeof (struct arm_abi_handler));
+  (*handler_p)->next = NULL;
+  (*handler_p)->abi = abi;
+  (*handler_p)->init_abi = init_abi;
+}
+
+/* Initialize the current architecture based on INFO.  If possible, re-use an
+   architecture from ARCHES, which is a list of architectures already created
+   during this debugging session.
+
+   Called e.g. at program startup, when reading a core file, and when reading
+   a binary file. */
+
 static struct gdbarch *
 arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 {
+  struct gdbarch_tdep *tdep;
   struct gdbarch *gdbarch;
+  enum arm_abi arm_abi = ARM_ABI_UNKNOWN;
+  struct arm_abi_handler *abi_handler;
 
-  if (arches != NULL)
-    return arches->gdbarch;
+  /* Try to deterimine the ABI of the object we are loading.  */
 
-  /* XXX We'll probably need to set the tdep field soon.  */
-  gdbarch = gdbarch_alloc (&info, NULL);
+  if (info.abfd != NULL)
+    {
+      switch (bfd_get_flavour (info.abfd))
+       {
+       case bfd_target_elf_flavour:
+         arm_abi = get_elfosabi (info.abfd);
+         break;
+
+       case bfd_target_aout_flavour:
+         if (strcmp (bfd_get_target(info.abfd), "a.out-arm-netbsd") == 0)
+           arm_abi = ARM_ABI_NETBSD_AOUT;
+         else
+           /* Assume it's an old APCS-style ABI.  */
+           arm_abi = ARM_ABI_APCS;
+         break;
+
+       case bfd_target_coff_flavour:
+         /* Assume it's an old APCS-style ABI.  */
+         /* XXX WinCE?  */
+         arm_abi = ARM_ABI_APCS;
+         break;
+
+       default:
+         /* Not sure what to do here, leave the ABI as unknown.  */
+         break;
+       }
+    }
+
+  /* Find a candidate among extant architectures. */
+  for (arches = gdbarch_list_lookup_by_info (arches, &info);
+       arches != NULL;
+       arches = gdbarch_list_lookup_by_info (arches->next, &info))
+    {
+      /* Make sure the ABI selection matches.  */
+      tdep = gdbarch_tdep (arches->gdbarch);
+      if (tdep && tdep->arm_abi == arm_abi)
+       return arches->gdbarch;
+    }
+
+  tdep = xmalloc (sizeof (struct gdbarch_tdep));
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  tdep->arm_abi = arm_abi;
+  if (arm_abi < ARM_ABI_INVALID)
+    tdep->abi_name = arm_abi_names[arm_abi];
+  else
+    {
+      internal_error (__FILE__, __LINE__, "Invalid setting of arm_abi %d",
+                     (int) arm_abi);
+      tdep->abi_name = "<invalid>";
+    }
+
+  /* Floating point sizes and format.  */
+  switch (info.byte_order)
+    {
+    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;
+
+    case BFD_ENDIAN_LITTLE:
+      set_gdbarch_float_format (gdbarch, &floatformat_ieee_single_little);
+      set_gdbarch_double_format (gdbarch,
+                                &floatformat_ieee_double_littlebyte_bigword);
+      set_gdbarch_long_double_format (gdbarch,
+                                &floatformat_ieee_double_littlebyte_bigword);
+      break;
+
+    default:
+      internal_error (__FILE__, __LINE__,
+                     "arm_gdbarch_init: bad byte order for float format");
+    }
+
+  tdep->lowest_pc = 0x20;
 
   set_gdbarch_use_generic_dummy_frames (gdbarch, 0);
 
@@ -2522,6 +2814,9 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_extract_return_value (gdbarch, arm_extract_return_value);
   set_gdbarch_store_return_value (gdbarch, arm_store_return_value);
   set_gdbarch_store_struct_return (gdbarch, arm_store_struct_return);
+  set_gdbarch_use_struct_convention (gdbarch, arm_use_struct_convention);
+  set_gdbarch_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.  */
@@ -2532,8 +2827,41 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_coff_make_msymbol_special (gdbarch,
                                         arm_coff_make_msymbol_special);
 
-  /* XXX We can't do this until NUM_REGS is set for the architecture.
-     Even then, we can't use SIZEOF_FRAME_SAVED_REGS, since that still
+  /* Hook in the ABI-specific overrides, if they have been registered.  */
+  if (arm_abi == ARM_ABI_UNKNOWN)
+    {
+      fprintf_filtered
+       (gdb_stderr, "GDB doesn't recognize the ABI of the inferior.  "
+        "Attempting to continue with the default ARM settings");
+    }
+  else
+    {
+      for (abi_handler = arm_abi_handler_list; abi_handler != NULL;
+          abi_handler = abi_handler->next)
+       if (abi_handler->abi == arm_abi)
+         break;
+
+      if (abi_handler)
+       abi_handler->init_abi (info, gdbarch);
+      else
+       {
+         /* We assume that if GDB_MULTI_ARCH is less than 
+            GDB_MULTI_ARCH_TM that an ABI variant can be supported by
+            overriding definitions in this file.  */
+         if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL)
+           fprintf_filtered
+             (gdb_stderr,
+              "A handler for the ABI variant \"%s\" is not built into this "
+              "configuration of GDB.  "
+              "Attempting to continue with the default ARM settings",
+              arm_abi_names[arm_abi]);
+       }
+    }
+
+  /* Now we have tuned the configuration, set a few final things,
+     based on what the OS ABI has told us.  */
+
+  /* We can't use SIZEOF_FRAME_SAVED_REGS here, since that still
      references the old architecture vector, not the one we are
      building here.  */
   if (prologue_cache.saved_regs != NULL)
@@ -2541,11 +2869,51 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
   prologue_cache.saved_regs = (CORE_ADDR *)
     xcalloc (1, (sizeof (CORE_ADDR)
-                * (NUM_GREGS + NUM_FREGS + NUM_SREGS + NUM_PSEUDO_REGS)));
+                * (gdbarch_num_regs (gdbarch) + NUM_PSEUDO_REGS)));
 
   return gdbarch;
 }
 
+static void
+arm_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+  if (tdep == NULL)
+    return;
+
+  if (tdep->abi_name != NULL)
+    fprintf_unfiltered (file, "arm_dump_tdep: ABI = %s\n", tdep->abi_name);
+  else
+    internal_error (__FILE__, __LINE__,
+                   "arm_dump_tdep: illegal setting of tdep->arm_abi (%d)",
+                   (int) tdep->arm_abi);
+
+  fprintf_unfiltered (file, "arm_dump_tdep: Lowest pc = 0x%lx",
+                     (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.  */
+}
+
 void
 _initialize_arm_tdep (void)
 {
@@ -2559,7 +2927,12 @@ _initialize_arm_tdep (void)
   static char *helptext;
 
   if (GDB_MULTI_ARCH)
-    register_gdbarch_init (bfd_arch_arm, arm_gdbarch_init);
+    gdbarch_register (bfd_arch_arm, arm_gdbarch_init, arm_dump_tdep);
+
+  /* Register some ABI variants for embedded systems.  */
+  arm_gdbarch_register_os_abi (ARM_ABI_EABI_V1, arm_init_abi_eabi_v1);
+  arm_gdbarch_register_os_abi (ARM_ABI_EABI_V2, arm_init_abi_eabi_v2);
+  arm_gdbarch_register_os_abi (ARM_ABI_APCS, arm_init_abi_apcs);
 
   tm_print_insn = gdb_print_insn_arm;
 
This page took 0.030309 seconds and 4 git commands to generate.