This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch] Arm EABI support


The attached patch adds gdb support for the new Arm EABI. This involves a new 
calling convention, slightly different elf header flags, and different 
default floating point format.

Tested with cross to arm-none-elf and arm-none-eabi.
Ok?

2004-12-13  Paul Brook  <paul@codesourcery.com>

 * arm-tdep.c (arm_type_align): New function.
 (arm_push_dummy_call): Use it.  Ensure proper argument alignment.
 (arm_extract_struct_value_address): Remove.
 (arm_use_struct_convention): Rename...
 (arm_return_in_memory): ... To this.  Return nonzero for all small
 aggregates under the EABI.
 (arm_return_value): New function.
 (arm_elf_osabi_sniffer): Add EF_ARM_EABI_VER4:.
 (arm_gdbarch_init): Set different fpu and abi defaults for EABI
 objects.  Use set_gdbarch_return_value instead of obsolete functions.
 (arm_init_abi_eabi_v4): New function.
 (_initialize_arm_tdep): Register GDB_OSABI_ARM_EABI_V4.
 * arm-tdep.h (enum arm_abi_variant): Add.
 (struct gdbarch_tdep): Add abi field.
 * defs.h (enum gdb_osabi): Add GDB_OSABI_ARM_EABI_V4.
 * osabi.c (gdb_osabi_name): Add "ARM EABI v4".
 * testsuite/long_long.exp: Exclude eabi targets from arm FPA float
 format test.
? bfd/doc/bfd.info
? sim/p
Index: gdb/arm-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/arm-tdep.c,v
retrieving revision 1.184
diff -u -p -r1.184 arm-tdep.c
--- gdb/arm-tdep.c	12 Nov 2004 21:45:05 -0000	1.184
+++ gdb/arm-tdep.c	13 Dec 2004 14:16:39 -0000
@@ -1172,6 +1172,63 @@ 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;
+
+  switch (TYPE_CODE (t))
+    {
+    case TYPE_CODE_UNDEF:
+    case TYPE_CODE_FUNC:
+    case TYPE_CODE_VOID:
+    case TYPE_CODE_STRING:
+    case TYPE_CODE_ERROR:
+    case TYPE_CODE_MEMBER:
+    case TYPE_CODE_METHOD:
+    case TYPE_CODE_TEMPLATE:
+    case TYPE_CODE_TEMPLATE_ARG:
+    case TYPE_CODE_NAMESPACE:
+    case TYPE_CODE_TYPEDEF:
+    default:
+      /* Should never happen, so make something up.  */
+      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 = 0;
+      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.  */
@@ -1223,6 +1280,7 @@ arm_push_dummy_call (struct gdbarch *gdb
       struct type *target_type;
       enum type_code typecode;
       char *val;
+      int align;
 
       arg_type = check_typedef (value_type (args[argnum]));
       len = TYPE_LENGTH (arg_type);
@@ -1230,6 +1288,35 @@ arm_push_dummy_call (struct gdbarch *gdb
       typecode = TYPE_CODE (arg_type);
       val = VALUE_CONTENTS (args[argnum]);
 
+      if (gdbarch_tdep (gdbarch)->abi == ARM_ABI_APCS_GNU)
+	{
+	  /* The old APCS ABI does not require doubleword alignment.  */
+	  align = INT_REGISTER_SIZE;
+	}
+      else
+	{
+	  align = arm_type_align (arg_type);
+
+	  /* Round alignment up to one or two words.  */
+	  align = (align + INT_REGISTER_SIZE - 1) & ~(INT_REGISTER_SIZE - 1);
+
+	  gdb_asset (align == INT_REGISTER_SIZE
+		     || 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.  */
@@ -2062,24 +2149,13 @@ arm_extract_return_value (struct type *t
     }
 }
 
-/* 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;
@@ -2110,6 +2186,11 @@ arm_use_struct_convention (int gcc_p, st
       return 1;
     }
 
+  /* The new EABI says all aggregates not larger than a word are returned
+     in a register.  */
+  if (gdbarch_tdep (gdbarch)->abi != ARM_ABI_APCS_GNU)
+    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);
@@ -2259,6 +2340,33 @@ arm_store_return_value (struct type *typ
     }
 }
 
+
+/* 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)
+{
+  /* TODO: Only call for aggreagates.  */
+  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)
 {
@@ -2554,6 +2662,10 @@ arm_elf_osabi_sniffer (bfd *abfd)
 	      osabi = GDB_OSABI_ARM_EABI_V2;
 	      break;
 
+	    case EF_ARM_EABI_VER4:
+	      osabi = GDB_OSABI_ARM_EABI_V4;
+	      break;
+
 	    case EF_ARM_EABI_UNKNOWN:
 	      /* Assume GNU tools.  */
 	      osabi = GDB_OSABI_ARM_APCS;
@@ -2641,10 +2753,20 @@ arm_gdbarch_init (struct gdbarch_info in
   tdep = xmalloc (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;
+  if (info.osabi == GDB_OSABI_ARM_EABI_V4)
+    {
+      /* Default EABI targets to soft-vfp.  */
+      tdep->fp_model = ARM_FLOAT_SOFT_VFP;
+      tdep->abi = ARM_ABI_AAPCS;
+    }
+  else
+    {
+      /* 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;
+      tdep->abi = ARM_ABI_APCS_GNU;
+    }
 
   /* Breakpoints.  */
   switch (info.byte_order)
@@ -2721,10 +2843,7 @@ arm_gdbarch_init (struct gdbarch_info in
   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.  */
@@ -2801,6 +2920,13 @@ arm_init_abi_eabi_v2 (struct gdbarch_inf
 }
 
 static void
+arm_init_abi_eabi_v4 (struct gdbarch_info info,
+		      struct gdbarch *gdbarch)
+{
+  /* Place-holder.  */
+}
+
+static void
 arm_init_abi_apcs (struct gdbarch_info info,
 		   struct gdbarch *gdbarch)
 {
@@ -2833,6 +2959,8 @@ _initialize_arm_tdep (void)
                           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_EABI_V4,
+                          arm_init_abi_eabi_v4);
   gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_ARM_APCS,
                           arm_init_abi_apcs);
 
Index: gdb/arm-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/arm-tdep.h,v
retrieving revision 1.12
diff -u -p -r1.12 arm-tdep.h
--- gdb/arm-tdep.h	25 Mar 2004 16:52:42 -0000	1.12
+++ gdb/arm-tdep.h	13 Dec 2004 14:16:39 -0000
@@ -116,6 +116,12 @@ enum arm_float_model
 /* A method to the setting based on user's choice and ABI setting.  */
 enum arm_float_model arm_get_fp_model (struct gdbarch *);
 
+enum arm_abi_variant
+{
+  ARM_ABI_APCS_GNU,
+  ARM_ABI_AAPCS
+};
+
 /* Target-dependent structure in gdbarch.  */
 struct gdbarch_tdep
 {
@@ -133,6 +139,8 @@ struct gdbarch_tdep
 				   If this is negative, longjmp support
 				   will be disabled.  */
   size_t jb_elt_size;		/* And the size of each entry in the buf.  */
+
+  enum arm_abi_variant abi;	/* Which abi variant is in use.  */
 };
 
 #ifndef LOWEST_PC
Index: gdb/defs.h
===================================================================
RCS file: /cvs/src/src/gdb/defs.h,v
retrieving revision 1.175
diff -u -p -r1.175 defs.h
--- gdb/defs.h	13 Nov 2004 17:00:04 -0000	1.175
+++ gdb/defs.h	13 Dec 2004 14:16:39 -0000
@@ -1043,6 +1043,7 @@ enum gdb_osabi
 
   GDB_OSABI_ARM_EABI_V1,
   GDB_OSABI_ARM_EABI_V2,
+  GDB_OSABI_ARM_EABI_V4,
   GDB_OSABI_ARM_APCS,
   GDB_OSABI_QNXNTO,
 
Index: gdb/osabi.c
===================================================================
RCS file: /cvs/src/src/gdb/osabi.c,v
retrieving revision 1.28
diff -u -p -r1.28 osabi.c
--- gdb/osabi.c	2 Jul 2004 21:27:17 -0000	1.28
+++ gdb/osabi.c	13 Dec 2004 14:16:41 -0000
@@ -73,6 +73,7 @@ static const char * const gdb_osabi_name
 
   "ARM EABI v1",
   "ARM EABI v2",
+  "ARM EABI v4",
   "ARM APCS",
   "QNX Neutrino",
 
Index: gdb/testsuite/gdb.base/long_long.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.base/long_long.exp,v
retrieving revision 1.15
diff -u -p -r1.15 long_long.exp
--- gdb/testsuite/gdb.base/long_long.exp	16 Jun 2004 15:19:41 -0000	1.15
+++ gdb/testsuite/gdb.base/long_long.exp	13 Dec 2004 14:16:41 -0000
@@ -201,13 +201,16 @@ gdb_test_ptr "p/a val.oct" "" "" "0x7705
 gdb_test "p/c val.oct" "'w'"
 
 if { $sizeof_double == 8 || $sizeof_long_double == 8 } {
-    # ARM floating point numbers are not strictly little endian or big endian,
-    # but a hybrid.  They are in little endian format with the two words
-    # swapped in big endian format.
+    # ARM FPA floating point numbers are not strictly little endian or big
+    # endian, but a hybrid.  They are in little endian format with the two
+    # words swapped in big endian format.
+    # EABI targets default to natural-endian VFP format
 
-    if { [istarget "arm*-*-*"] || \
+    if { ([istarget "arm*-*-*"] || \
 	    [istarget "xscale*-*-*"] || \
-	    [istarget "strongarm*-*-*"] } then {
+	    [istarget "strongarm*-*-*"]) \
+	  && !([istarget "*-*-*eabi"] || \
+		[istarget "*-*-symbianelf"]) } then {
 	# assume the long long represents a floating point double in ARM format
 	gdb_test "p/f val.oct" "2.1386676354387559e\\+265"
     } else {

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]