Complete SH port.
diff --git a/backends/ChangeLog b/backends/ChangeLog
index 99d01ce..9fd9745 100644
--- a/backends/ChangeLog
+++ b/backends/ChangeLog
@@ -1,3 +1,12 @@
+2010-04-10  Matt Fleming  <matt@console-pimps.org>
+
+	* sh_corenote.c: New file.
+	* sh_regs.c: New file.
+	* sh_retval.c: New file.
+	* sh_symbol.c (sh_machine_flag_check): New function.
+	* Makefile.am (sh_SRCS): Add new files.
+	* sh_init.c (sh_init): Add initializers.
+
 2010-04-07  Roland McGrath  <roland@redhat.com>
 
 	* arm_reloc.def: Accept PC24 and ABS32 in EXEC|DYN too.
diff --git a/backends/Makefile.am b/backends/Makefile.am
index a18454d..3ce448a 100644
--- a/backends/Makefile.am
+++ b/backends/Makefile.am
@@ -52,7 +52,7 @@
 libebl_i386_pic_a_SOURCES = $(i386_SRCS)
 am_libebl_i386_pic_a_OBJECTS = $(i386_SRCS:.c=.os)
 
-sh_SRCS = sh_init.c sh_symbol.c
+sh_SRCS = sh_init.c sh_symbol.c sh_corenote.c sh_regs.c sh_retval.c
 libebl_sh_pic_a_SOURCES = $(sh_SRCS)
 am_libebl_sh_pic_a_OBJECTS = $(sh_SRCS:.c=.os)
 
diff --git a/backends/sh_corenote.c b/backends/sh_corenote.c
new file mode 100644
index 0000000..6887120
--- /dev/null
+++ b/backends/sh_corenote.c
@@ -0,0 +1,84 @@
+/* SH specific core note handling.
+   Copyright (C) 2010 Matt Fleming <matt@console-pimps.org>
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <elf.h>
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <sys/time.h>
+
+#define BACKEND		sh_
+#include "libebl_CPU.h"
+
+static const Ebl_Register_Location prstatus_regs[] =
+  {
+#define GR(at, n, dwreg)						\
+    { .offset = at * 4, .regno = dwreg, .count = n, .bits = 32 }
+    GR (0, 16, 0),		/* r0-r15 */
+    GR (16, 1, 16),		/* pc */
+    GR (17, 1, 17),		/* pr */
+    GR (18, 1, 22),		/* sr */
+    GR (19, 1, 18),		/* gbr */
+    GR (20, 1, 20),		/* mach */
+    GR (21, 1, 21),		/* macl */
+    /*  22, 1,			   tra */
+#undef GR
+  };
+#define PRSTATUS_REGS_SIZE	(23 * 4)
+
+#define	ULONG			uint32_t
+#define PID_T			int32_t
+#define	UID_T			uint16_t
+#define	GID_T			uint16_t
+#define ALIGN_ULONG		4
+#define ALIGN_PID_T		4
+#define ALIGN_UID_T		2
+#define ALIGN_GID_T		2
+#define TYPE_ULONG		ELF_T_WORD
+#define TYPE_PID_T		ELF_T_SWORD
+#define TYPE_UID_T		ELF_T_HALF
+#define TYPE_GID_T		ELF_T_HALF
+
+#define PRSTATUS_REGSET_ITEMS						      \
+  {									      \
+    .name = "tra", .type = ELF_T_ADDR, .format = 'x',			      \
+    .offset = offsetof (struct EBLHOOK(prstatus), pr_reg[22]),		      \
+    .group = "register"	       			  	       	 	      \
+  }
+
+static const Ebl_Register_Location fpregset_regs[] =
+  {
+    { .offset = 0, .regno = 25, .count = 16, .bits = 32 }, /* fr0-fr15 */
+    { .offset = 16, .regno = 87, .count = 16, .bits = 32 }, /* xf0-xf15 */
+    { .offset = 32, .regno = 24, .count = 1, .bits = 32 }, /* fpscr */
+    { .offset = 33, .regno = 23, .count = 1, .bits = 32 }  /* fpul */
+  };
+#define FPREGSET_SIZE		(50 * 4)
+
+#include "linux-core-note.c"
diff --git a/backends/sh_init.c b/backends/sh_init.c
index 02502ab..7b36e7a 100644
--- a/backends/sh_init.c
+++ b/backends/sh_init.c
@@ -51,6 +51,11 @@
   eh->name = "Hitachi SH";
   sh_init_reloc (eh);
   HOOK (eh, reloc_simple_type);
+  HOOK (eh, gotpc_reloc_check);
+  HOOK (eh, machine_flag_check);
+  HOOK (eh, core_note);
+  HOOK (eh, register_info);
+  HOOK (eh, return_value_location);
 
   return MODVERSION;
 }
diff --git a/backends/sh_regs.c b/backends/sh_regs.c
new file mode 100644
index 0000000..dbf4acc
--- /dev/null
+++ b/backends/sh_regs.c
@@ -0,0 +1,187 @@
+/* Register names and numbers for SH DWARF.
+   Copyright (C) 2010 Matt Fleming <matt@console-pimps.org>
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <dwarf.h>
+#include <string.h>
+
+#define BACKEND sh_
+#include "libebl_CPU.h"
+
+ssize_t
+sh_register_info (Ebl *ebl __attribute__ ((unused)),
+		  int regno, char *name, size_t namelen,
+		  const char **prefix, const char **setname,
+		  int *bits, int *type)
+{
+  if (name == NULL)
+    return 104;
+
+  if (regno < 0 || regno > 103 || namelen < 6)
+    return -1;
+
+  *prefix = NULL;
+  *bits = 32;
+  *type = DW_ATE_signed;
+
+  switch (regno)
+    {
+    case 0 ... 9:
+      *setname = "integer";
+      name[0] = 'r';
+      name[1] = regno + '0';
+      namelen = 2;
+      break;
+
+    case 10 ... 15:
+      *setname = "integer";
+      name[0] = 'r';
+      name[1] = '1';
+      name[2] = regno - 10 + '0';
+      namelen = 3;
+      break;
+
+    case 16:
+      *setname = "system";
+      *type = DW_ATE_address;
+      name[0] = 'p';
+      name[1] = 'c';
+      namelen = 2;
+      break;
+
+    case 17:
+      *setname = "system";
+      *type = DW_ATE_address;
+      name[0] = 'p';
+      name[1] = 'r';
+      namelen = 2;
+      break;
+
+    case 18:
+      *setname = "control";
+      *type = DW_ATE_unsigned;
+      name[0] = 's';
+      name[1] = 'r';
+      namelen = 2;
+      break;
+
+    case 19:
+      *setname = "control";
+      *type = DW_ATE_unsigned;
+      name[0] = 'g';
+      name[1] = 'b';
+      name[2] = 'r';
+      namelen = 3;
+      break;
+
+    case 20:
+      *setname = "system";
+      name[0] = 'm';
+      name[1] = 'a';
+      name[2] = 'c';
+      name[3] = 'h';
+      namelen = 4;
+      break;
+
+    case 21:
+      *setname = "system";
+      name[0] = 'm';
+      name[1] = 'a';
+      name[2] = 'c';
+      name[3] = 'l';
+      namelen = 4;
+
+      break;
+
+    case 23:
+      *setname = "system";
+      *type = DW_ATE_unsigned;
+      name[0] = 'f';
+      name[1] = 'p';
+      name[2] = 'u';
+      name[3] = 'l';
+      namelen = 4;
+      break;
+
+    case 24:
+      *setname = "system";
+      *type = DW_ATE_unsigned;
+      name[0] = 'f';
+      name[1] = 'p';
+      name[2] = 's';
+      name[3] = 'c';
+      name[4] = 'r';
+      namelen = 5;
+      break;
+
+    case 25 ... 34:
+      *setname = "fpu";
+      *type = DW_ATE_float;
+      name[0] = 'f';
+      name[1] = 'r';
+      name[2] = regno - 25 + '0';
+      namelen = 3;
+      break;
+
+    case 35 ... 40:
+      *setname = "fpu";
+      *type = DW_ATE_float;
+      name[0] = 'f';
+      name[1] = 'r';
+      name[2] = '1';
+      name[3] = regno - 35 + '0';
+      namelen = 4;
+      break;
+
+    case 87 ... 96:
+      *type = DW_ATE_float;
+      *setname = "fpu";
+      name[0] = 'x';
+      name[1] = 'f';
+      name[2] = regno - 87 + '0';
+      namelen = 3;
+      break;
+
+    case 97 ... 103:
+      *type = DW_ATE_float;
+      *setname = "fpu";
+      name[0] = 'x';
+      name[1] = 'f';
+      name[2] = '1';
+      name[3] = regno - 97 + '0';
+      namelen = 4;
+      break;
+
+    default:
+      return 0;
+    }
+
+  name[namelen++] = '\0';
+  return namelen;
+}
diff --git a/backends/sh_retval.c b/backends/sh_retval.c
new file mode 100644
index 0000000..07769a3
--- /dev/null
+++ b/backends/sh_retval.c
@@ -0,0 +1,138 @@
+/* Function return value location for Linux/SH ABI.
+   Copyright (C) 2010 Matt Fleming <matt@console-pimps.org>
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <dwarf.h>
+
+#define BACKEND sh_
+#include "libebl_CPU.h"
+
+
+/* This is the SVR4 ELF ABI convention, but AIX and Linux do not use it.  */
+#define SVR4_STRUCT_RETURN 0
+
+
+/* r0, or pair r0, r1.  */
+static const Dwarf_Op loc_intreg[] =
+  {
+    { .atom = DW_OP_reg0 }, { .atom = DW_OP_piece, .number = 4 },
+    { .atom = DW_OP_reg1 }, { .atom = DW_OP_piece, .number = 4 },
+  };
+#define nloc_intreg	1
+#define nloc_intregpair	4
+
+/* fr0 or fr1.  */
+static const Dwarf_Op loc_fpreg[] =
+  {
+    { .atom = DW_OP_reg25 }, { .atom = DW_OP_piece, .number = 4 },
+    { .atom = DW_OP_reg26 }, { .atom = DW_OP_piece, .number = 4 },
+  };
+#define nloc_fpreg	1
+#define nloc_fpregpair	2
+
+int
+sh_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp)
+{
+  /* Start with the function's type, and get the DW_AT_type attribute,
+     which is the type of the return value.  */
+
+  Dwarf_Attribute attr_mem;
+  Dwarf_Attribute *attr = dwarf_attr_integrate (functypedie, DW_AT_type,
+						&attr_mem);
+  if (attr == NULL)
+    /* The function has no return value, like a `void' function in C.  */
+    return 0;
+
+  Dwarf_Die die_mem;
+  Dwarf_Die *typedie = dwarf_formref_die (attr, &die_mem);
+  int tag = dwarf_tag (typedie);
+
+  /* Follow typedefs and qualifiers to get to the actual type.  */
+  while (tag == DW_TAG_typedef
+	 || tag == DW_TAG_const_type || tag == DW_TAG_volatile_type
+	 || tag == DW_TAG_restrict_type || tag == DW_TAG_mutable_type)
+    {
+      attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem);
+      typedie = dwarf_formref_die (attr, &die_mem);
+      tag = dwarf_tag (typedie);
+    }
+
+  Dwarf_Word size;
+  switch (tag)
+    {
+    case -1:
+      return -1;
+
+    case DW_TAG_subrange_type:
+      if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size))
+	{
+	  attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem);
+	  typedie = dwarf_formref_die (attr, &die_mem);
+	  tag = dwarf_tag (typedie);
+	}
+      /* Fall through.  */
+
+    case DW_TAG_base_type:
+    case DW_TAG_enumeration_type:
+    case DW_TAG_pointer_type:
+    case DW_TAG_ptr_to_member_type:
+      if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size,
+						 &attr_mem), &size) != 0)
+	{
+	  if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type)
+	    size = 4;
+	  else
+	    return -1;
+	}
+      if (size <= 8)
+	{
+	  if (tag == DW_TAG_base_type)
+	    {
+	      Dwarf_Word encoding;
+	      if (dwarf_formudata (dwarf_attr_integrate (typedie,
+							 DW_AT_encoding,
+							 &attr_mem),
+				   &encoding) != 0)
+		return -1;
+	      if (encoding == DW_ATE_float)
+		{
+		  *locp = loc_fpreg;
+		  return size <= 4 ? nloc_fpreg : nloc_fpregpair;
+		}
+	    }
+	  *locp = loc_intreg;
+	  return size <= 4 ? nloc_intreg : nloc_intregpair;
+	}
+    }
+
+  /* XXX We don't have a good way to return specific errors from ebl calls.
+     This value means we do not understand the type, but it is well-formed
+     DWARF and might be valid.  */
+  return -2;
+}
diff --git a/backends/sh_symbol.c b/backends/sh_symbol.c
index 26000cc..9fb5db4 100644
--- a/backends/sh_symbol.c
+++ b/backends/sh_symbol.c
@@ -54,3 +54,38 @@
       return ELF_T_NUM;
     }
 }
+
+/* Check whether machine flags are valid.  */
+bool
+sh_machine_flag_check (GElf_Word flags)
+{
+  switch (flags & EF_SH_MACH_MASK)
+    {
+    case EF_SH_UNKNOWN:
+    case EF_SH1:
+    case EF_SH2:
+    case EF_SH3:
+    case EF_SH_DSP:
+    case EF_SH3_DSP:
+    case EF_SH4AL_DSP:
+    case EF_SH3E:
+    case EF_SH4:
+    case EF_SH2E:
+    case EF_SH4A:
+    case EF_SH2A:
+    case EF_SH4_NOFPU:
+    case EF_SH4A_NOFPU:
+    case EF_SH4_NOMMU_NOFPU:
+    case EF_SH2A_NOFPU:
+    case EF_SH3_NOMMU:
+    case EF_SH2A_SH4_NOFPU:
+    case EF_SH2A_SH3_NOFPU:
+    case EF_SH2A_SH4:
+    case EF_SH2A_SH3E:
+      break;
+    default:
+      return false;
+    }
+
+  return ((flags &~ (EF_SH_MACH_MASK)) == 0);
+}