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]

[csl-arm] Add ARM EABI support


This patch, an updated version of a patch Paul posted in December, adds EABI
v4 support to the ARM architecture.  I've committed it to
csl-arm-20050325-branch only; I'm not going to submit it for HEAD quite yet. 

I don't like the proliferation of architecture-specific OSABI constants
here.  I see a way to avoid it, parallel to MIPS, by moving the ABI into a
separate place in the tdep structure; but it will take a little while to
implement and test properly.  Also, Richard had some comments on the
original patch that I haven't properly looked at yet :-)

-- 
Daniel Jacobowitz
CodeSourcery, LLC

2005-03-25  Paul Brook  <paul@codesourcery.com>
	    Daniel Jacobowitz  <dan@codesourcery.com>

	* configure.tgt: Add default OSABI setting for arm*-*-linux-gnueabi.
	* arm-tdep.c (arm_type_align): New function.
	(arm_push_dummy_call): Use it.  Ensure proper argument alignment.
	Don't try to align the stack.
	(arm_frame_align): New function.
	(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 case.  Handle
	GDB_OSABI_ARM_EABI_V4_LINUX.
	(arm_gdbarch_init): Set different FPU and ABI defaults for EABI
	objects.  Use set_gdbarch_return_value instead of obsolete functions.
	Call set_gdbarch_frame_align.
	(arm_init_abi_eabi_v4): New function.
	(_initialize_arm_tdep): Register GDB_OSABI_ARM_EABI_V4.
	* arm-linux-tdep.c (ARM_LINUX_EABI_JB_PC): Define.
	(arm_linux_eabi_init_abi): New function.
	(_initialize_arm_linux_tdep): Register GDB_OSABI_ARM_EABI_V4_LINUX.
	* arm-tdep.h (enum arm_abi_variant): New.
	(struct gdbarch_tdep): Add abi field.
	* defs.h (enum gdb_osabi): Add GDB_OSABI_ARM_EABI_V4 and
	GDB_OSABI_ARM_EABI_V4_LINUX.
	* osabi.c (gdb_osabi_name): Add "ARM EABI v4" and
	"ARM EABI v4 GNU/Linux".

2005-03-25  Paul Brook  <paul@codesourcery.com>

	* gdb.base/long_long.exp: Don't expect FPA format for ARM EABI targets.

Index: gdb/gdb/configure.tgt
===================================================================
--- gdb.orig/gdb/configure.tgt	2005-03-24 12:14:23.717288302 -0500
+++ gdb/gdb/configure.tgt	2005-03-24 12:16:55.168855743 -0500
@@ -208,6 +208,8 @@ esac
 # map target onto default OS ABI
 
 case "${target}" in
+arm*-*-linux-gnueabi)
+		gdb_osabi=GDB_OSABI_ARM_EABI_V4_LINUX ;;
 *-*-linux*)	gdb_osabi=GDB_OSABI_LINUX ;;
 *-*-nto*)	gdb_osabi=GDB_OSABI_QNXNTO ;;
 m68*-*-openbsd* | m88*-*-openbsd* | vax-*-openbsd*) ;;
Index: gdb/gdb/testsuite/gdb.base/long_long.exp
===================================================================
--- gdb.orig/gdb/testsuite/gdb.base/long_long.exp	2005-03-24 12:14:23.717288302 -0500
+++ gdb/gdb/testsuite/gdb.base/long_long.exp	2005-03-24 12:16:55.168855743 -0500
@@ -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: gdb/gdb/arm-tdep.c
===================================================================
--- gdb.orig/gdb/arm-tdep.c	2005-03-24 12:14:23.717288302 -0500
+++ gdb/gdb/arm-tdep.c	2005-03-24 12:16:55.170855378 -0500
@@ -1223,6 +1223,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 = 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.  */
@@ -1251,11 +1308,6 @@ arm_push_dummy_call (struct gdbarch *gdb
   argreg = ARM_A1_REGNUM;
   nstack = 0;
 
-  /* Some platforms require a double-word aligned stack.  Make sure sp
-     is correctly aligned before we start.  We always do this even if
-     it isn't really needed -- it can never hurt things.  */
-  sp &= ~(CORE_ADDR)(2 * DEPRECATED_REGISTER_SIZE - 1);
-
   /* The struct_return pointer occupies the first parameter
      passing register.  */
   if (struct_return)
@@ -1274,6 +1326,7 @@ arm_push_dummy_call (struct gdbarch *gdb
       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);
@@ -1281,6 +1334,35 @@ arm_push_dummy_call (struct gdbarch *gdb
       typecode = TYPE_CODE (arg_type);
       val = value_contents_writeable (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_assert (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.  */
@@ -1347,6 +1429,13 @@ arm_push_dummy_call (struct gdbarch *gdb
   return sp;
 }
 
+static CORE_ADDR
+arm_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
+{
+  /* Align the stack to eight bytes.  */
+  return sp & ~ (CORE_ADDR) 7;
+}
+
 static void
 print_fpu_flags (int flags)
 {
@@ -2116,24 +2205,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;
@@ -2164,6 +2242,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);
@@ -2313,6 +2396,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)
 {
@@ -2598,6 +2708,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;
@@ -2610,6 +2724,12 @@ arm_elf_osabi_sniffer: Unknown ARM EABI 
 			      eflags);
 	    }
 	}
+      else if (osabi == GDB_OSABI_LINUX)
+	{
+	  eflags = EF_ARM_EABI_VERSION (elf_elfheader (abfd)->e_flags);
+	  if (eflags == EF_ARM_EABI_VER4)
+	    osabi = GDB_OSABI_ARM_EABI_V4_LINUX;
+	}
       break;
 
     case ELFOSABI_ARM:
@@ -2686,10 +2806,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 || info.osabi == GDB_OSABI_ARM_EABI_V4_LINUX)
+    {
+      /* 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)
@@ -2723,6 +2853,7 @@ arm_gdbarch_init (struct gdbarch_info in
   tdep->jb_pc = -1;	/* Longjump support not enabled by default.  */
 
   set_gdbarch_push_dummy_call (gdbarch, arm_push_dummy_call);
+  set_gdbarch_frame_align (gdbarch, arm_frame_align);
 
   set_gdbarch_write_pc (gdbarch, arm_write_pc);
 
@@ -2766,10 +2897,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.  */
@@ -2847,6 +2975,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)
 {
@@ -2881,6 +3016,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/gdb/arm-linux-tdep.c
===================================================================
--- gdb.orig/gdb/arm-linux-tdep.c	2005-03-24 12:14:23.717288302 -0500
+++ gdb/gdb/arm-linux-tdep.c	2005-03-24 12:19:45.304229606 -0500
@@ -49,6 +49,7 @@ static const char arm_linux_arm_be_break
 /* Description of the longjmp buffer.  */
 #define ARM_LINUX_JB_ELEMENT_SIZE	INT_REGISTER_SIZE
 #define ARM_LINUX_JB_PC			21
+#define ARM_LINUX_EABI_JB_PC		27
 
 /* Extract from an array REGBUF containing the (raw) register state
    a function return value of type TYPE, and copy that, in virtual format,
@@ -487,9 +488,42 @@ arm_linux_init_abi (struct gdbarch_info 
   set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
 }
 
+static void
+arm_linux_eabi_init_abi (struct gdbarch_info info,
+			 struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  tdep->lowest_pc = 0x8000;
+  if (info.byte_order == BFD_ENDIAN_BIG)
+    {
+      tdep->arm_breakpoint = arm_linux_arm_be_breakpoint;
+      tdep->thumb_breakpoint = arm_linux_thumb_be_breakpoint;
+    }
+  else
+    {
+      tdep->arm_breakpoint = arm_linux_arm_le_breakpoint;
+      tdep->thumb_breakpoint = arm_linux_thumb_le_breakpoint;
+    }
+  tdep->arm_breakpoint_size = sizeof (arm_linux_arm_le_breakpoint);
+  tdep->thumb_breakpoint_size = sizeof (arm_linux_thumb_le_breakpoint);
+
+  tdep->jb_pc = ARM_LINUX_EABI_JB_PC;
+  tdep->jb_elt_size = ARM_LINUX_JB_ELEMENT_SIZE;
+
+  set_solib_svr4_fetch_link_map_offsets
+    (gdbarch, arm_linux_svr4_fetch_link_map_offsets);
+
+  /* Shared library handling.  */
+  set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
+  set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
+}
+
 void
 _initialize_arm_linux_tdep (void)
 {
   gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_LINUX,
 			  arm_linux_init_abi);
+  gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_ARM_EABI_V4_LINUX,
+			  arm_linux_eabi_init_abi);
 }
Index: gdb/gdb/osabi.c
===================================================================
--- gdb.orig/gdb/osabi.c	2005-03-24 12:14:23.717288302 -0500
+++ gdb/gdb/osabi.c	2005-03-24 12:16:55.171855196 -0500
@@ -73,6 +73,8 @@ static const char * const gdb_osabi_name
 
   "ARM EABI v1",
   "ARM EABI v2",
+  "ARM EABI v4",
+  "ARM EABI v4 GNU/Linux",
   "ARM APCS",
   "QNX Neutrino",
 
Index: gdb/gdb/arm-tdep.h
===================================================================
--- gdb.orig/gdb/arm-tdep.h	2005-03-24 12:14:23.717288302 -0500
+++ gdb/gdb/arm-tdep.h	2005-03-24 12:16:55.171855196 -0500
@@ -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/gdb/defs.h
===================================================================
--- gdb.orig/gdb/defs.h	2005-03-24 12:14:23.717288302 -0500
+++ gdb/gdb/defs.h	2005-03-24 12:16:55.172855013 -0500
@@ -950,6 +950,8 @@ enum gdb_osabi
 
   GDB_OSABI_ARM_EABI_V1,
   GDB_OSABI_ARM_EABI_V2,
+  GDB_OSABI_ARM_EABI_V4,
+  GDB_OSABI_ARM_EABI_V4_LINUX,
   GDB_OSABI_ARM_APCS,
   GDB_OSABI_QNXNTO,
 


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