diff -ruN gdb-6.8.orig/gdb/Makefile.in gdb-6.8/gdb/Makefile.in
--- gdb-6.8.orig/gdb/Makefile.in	2008-06-30 13:55:27.000000000 +0900
+++ gdb-6.8/gdb/Makefile.in	2008-06-30 14:00:19.000000000 +0900
@@ -1618,6 +1618,7 @@
 	score-tdep.c \
 	ser-go32.c ser-pipe.c ser-tcp.c ser-mingw.c \
 	sh-tdep.c sh64-tdep.c shnbsd-tdep.c shnbsd-nat.c \
+	sh-linux-tdep.c sh-linux-nat.c \
 	sol2-tdep.c \
 	solib-irix.c solib-svr4.c solib-sunos.c \
 	sparc-linux-nat.c \
@@ -2735,6 +2736,12 @@
 	$(gdbcmd_h) $(gdbcore_h) $(value_h) $(dis_asm_h) $(inferior_h) \
 	$(gdb_string_h) $(gdb_assert_h) $(arch_utils_h) $(regcache_h) \
 	$(osabi_h) $(elf_bfd_h) $(elf_sh_h) $(gdb_sim_sh_h)
+sh-linux-tdep.o: sh-linux-tdep.c $(defs_h) $(gdbcore_h) $(frame_h) $(value_h) \
+	$(regcache_h) $(inferior_h) $(osabi_h) $(reggroups_h) $(arch_utils_h) \
+	$(floatformat_h) $(solib_svr4_h) $(gdb_string_h) $(gregset_h) \
+	$(regset_h) $(sh_tdep_h) $(glibc_tdep_h)
+sh-linux-nat.o: sh-linux-nat.c $(defs_h) $(frame_h) $(inferior_h) $(gdbcore_h) \
+	$(regcache_h) $(gregset_h) $(sh_tdep_h)
 shnbsd-nat.o: shnbsd-nat.c $(defs_h) $(inferior_h) $(sh_tdep_h) \
 	$(shnbsd_tdep_h) $(inf_ptrace_h) $(regcache_h)
 shnbsd-tdep.o: shnbsd-tdep.c $(defs_h) $(gdbcore_h) $(regcache_h) $(regset_h) \
diff -ruN gdb-6.8.orig/gdb/config/sh/linux.mh gdb-6.8/gdb/config/sh/linux.mh
--- gdb-6.8.orig/gdb/config/sh/linux.mh	1970-01-01 09:00:00.000000000 +0900
+++ gdb-6.8/gdb/config/sh/linux.mh	2008-06-30 14:01:34.000000000 +0900
@@ -0,0 +1,8 @@
+# Host: Renesas Super-H running GNU/Linux
+NAT_FILE= nm-linux.h
+NATDEPFILES= inf-ptrace.o fork-child.o corelow.o \
+	sh-linux-nat.o \
+	proc-service.o linux-thread-db.o gcore.o \
+	linux-nat.o linux-fork.o
+
+LOADLIBES= -ldl -rdynamic
diff -ruN gdb-6.8.orig/gdb/config/sh/nm-linux.h gdb-6.8/gdb/config/sh/nm-linux.h
--- gdb-6.8.orig/gdb/config/sh/nm-linux.h	1970-01-01 09:00:00.000000000 +0900
+++ gdb-6.8/gdb/config/sh/nm-linux.h	2008-06-30 14:10:17.000000000 +0900
@@ -0,0 +1,54 @@
+/* Native-dependent definitions for SuperH running Linux, for GDB.
+   Copyright 2004 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program 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; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program 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 this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef NM_LINUX_H
+#define NM_LINUX_H
+
+/* Get generic Linux native definitions.  */
+#include "config/nm-linux.h"
+/* Support for the user area.  */
+
+/* Return the size of the user struct.  */
+extern int kernel_u_size (void);
+#define KERNEL_U_SIZE kernel_u_size()
+
+/* This is the amount to substract from u.u_ar0 to get the offset in
+   the core file of the register values.  */
+#define KERNEL_U_ADDR 0
+
+#define U_REGS_OFFSET 0
+
+extern CORE_ADDR register_u_addr (CORE_ADDR blockend, int regnum);
+#define REGISTER_U_ADDR(addr, blockend, regnum) \
+  (addr) = register_u_addr (blockend, regnum)
+
+/* Override copies of {fetch,store}_inferior_registers in `infptrace.c'.  */
+#define FETCH_INFERIOR_REGISTERS
+
+/* Nevertheless, define CANNOT_{FETCH,STORE}_REGISTER, because we
+   might fall back on the code `infptrace.c' (well a copy of that code
+   in `sh-linux-nat.c' for now) and we can access only the
+   general-purpose registers in that way.  */
+extern int cannot_fetch_register (int regno);
+extern int cannot_store_register (int regno);
+#define CANNOT_FETCH_REGISTER(regno) cannot_fetch_register (regno)
+#define CANNOT_STORE_REGISTER(regno) cannot_store_register (regno)
+
+#endif /* NM_LINUX_H */
diff -ruN gdb-6.8.orig/gdb/config/sh/xm-linux.h gdb-6.8/gdb/config/sh/xm-linux.h
--- gdb-6.8.orig/gdb/config/sh/xm-linux.h	1970-01-01 09:00:00.000000000 +0900
+++ gdb-6.8/gdb/config/sh/xm-linux.h	2008-06-30 14:12:33.000000000 +0900
@@ -0,0 +1,32 @@
+/* Native support for GNU/Linux, for GDB, the GNU debugger.
+   Copyright (C) 2000 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program 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; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifndef XM_LINUX_H
+#define XM_LINUX_H
+
+#define HOST_BYTE_ORDER LITTLE_ENDIAN
+
+#define HAVE_TERMIOS
+
+#define NEED_POSIX_SETPGID
+
+/* Need R_OK etc, but USG isn't defined.  */
+#include <unistd.h>
+
+#endif	/* #ifndef XM_LINUX_H */
diff -ruN gdb-6.8.orig/gdb/configure.host gdb-6.8/gdb/configure.host
--- gdb-6.8.orig/gdb/configure.host	2008-01-20 00:03:50.000000000 +0900
+++ gdb-6.8/gdb/configure.host	2008-06-30 14:14:37.000000000 +0900
@@ -136,6 +136,7 @@
 
 s390*-*-*)		gdb_host=s390 ;;
 
+sh*-*-linux*)		gdb_host=linux ;;
 sh*-*-netbsdelf* | sh*-*-knetbsd*-gnu)
 			gdb_host=nbsd ;;
 sh*-*-openbsd*)		gdb_host=nbsd ;;
diff -ruN gdb-6.8.orig/gdb/configure.tgt gdb-6.8/gdb/configure.tgt
--- gdb-6.8.orig/gdb/configure.tgt	2008-02-12 06:58:41.000000000 +0900
+++ gdb-6.8/gdb/configure.tgt	2008-06-30 14:19:24.000000000 +0900
@@ -368,11 +368,11 @@
 	;;
 
 # FIXME should that be sh*-*-linux*, perhaps?
-sh-*-linux*)
+sh*-*-linux*)
 	# Target: GNU/Linux Super-H
 	gdb_target_obs="sh-tdep.o sh64-tdep.o sh-linux-tdep.o monitor.o \
-			dsrec.o solib.o solib-svr4.o symfile-mem.o"
-	gdb_sim=../sim/sh/libsim.a
+			dsrec.o solib.o solib-svr4.o symfile-mem.o glibc-tdep.o"
+	# gdb_sim=../sim/sh/libsim.a
 	build_gdbserver=yes
 	;;
 sh*-*-netbsdelf* | sh*-*-knetbsd*-gnu)
diff -ruN gdb-6.8.orig/gdb/sh-tdep.c gdb-6.8/gdb/sh-tdep.c
--- gdb-6.8.orig/gdb/sh-tdep.c	2008-01-11 22:20:02.000000000 +0900
+++ gdb-6.8/gdb/sh-tdep.c	2008-06-30 14:39:06.000000000 +0900
@@ -24,6 +24,9 @@
  */
 
 #include "defs.h"
+#include "arch-utils.h"
+#include "command.h"
+#include "dummy-frame.h"
 #include "frame.h"
 #include "frame-base.h"
 #include "frame-unwind.h"
@@ -40,6 +43,7 @@
 #include "arch-utils.h"
 #include "floatformat.h"
 #include "regcache.h"
+#include "regset.h"
 #include "doublest.h"
 #include "osabi.h"
 #include "reggroups.h"
@@ -56,23 +60,6 @@
 
 static void (*sh_show_regs) (struct frame_info *);
 
-#define SH_NUM_REGS 67
-
-struct sh_frame_cache
-{
-  /* Base address.  */
-  CORE_ADDR base;
-  LONGEST sp_offset;
-  CORE_ADDR pc;
-
-  /* Flag showing that a frame has been created in the prologue code. */
-  int uses_fp;
-
-  /* Saved registers.  */
-  CORE_ADDR saved_regs[SH_NUM_REGS];
-  CORE_ADDR saved_sp;
-};
-
 static const char *
 sh_sh_register_name (struct gdbarch *gdbarch, int reg_nr)
 {
@@ -1007,7 +994,7 @@
     return 0;
   /* Otherwise if the type of that member is float, the whole type is
      treated as float.  */
-  if (TYPE_CODE (TYPE_FIELD_TYPE (type, 0)) == TYPE_CODE_FLT)
+  if (TYPE_CODE (check_typedef (TYPE_FIELD_TYPE (type, 0))) == TYPE_CODE_FLT)
     return 1;
   /* Otherwise it's not treated as float.  */
   return 0;
@@ -1051,7 +1038,7 @@
      in four registers available.  Loop thru args from first to last.  */
   for (argnum = 0; argnum < nargs; argnum++)
     {
-      type = value_type (args[argnum]);
+      type = check_typedef (value_type (args[argnum]));
       len = TYPE_LENGTH (type);
       val = sh_justify_value_in_reg (gdbarch, args[argnum], len);
 
@@ -2384,7 +2371,7 @@
     reg->how = DWARF2_FRAME_REG_UNDEFINED;
 }
 
-static struct sh_frame_cache *
+struct sh_frame_cache *
 sh_alloc_frame_cache (void)
 {
   struct sh_frame_cache *cache;
@@ -2411,7 +2398,7 @@
   return cache;
 }
 
-static struct sh_frame_cache *
+struct sh_frame_cache *
 sh_frame_cache (struct frame_info *next_frame, void **this_cache)
 {
   struct sh_frame_cache *cache;
@@ -2671,6 +2658,7 @@
 static struct gdbarch *
 sh_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 {
+  struct gdbarch_tdep *tdep;
   struct gdbarch *gdbarch;
 
   sh_show_regs = sh_generic_show_regs;
@@ -2725,7 +2713,20 @@
 
   /* None found, create a new architecture from the information
      provided. */
-  gdbarch = gdbarch_alloc (&info, NULL);
+  tdep = XMALLOC (struct gdbarch_tdep);
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  /* General-purpose registers.  */
+  tdep->gregset = NULL;
+  tdep->gregset_reg_offset = NULL;
+  tdep->gregset_num_regs = 23;
+  tdep->sizeof_gregset = 0;
+
+  /* Floating-point registers.  */
+  tdep->fpregset = NULL;
+  tdep->sizeof_fpregset = 34*4;
+
+  tdep->jb_pc_offset = -1;
 
   set_gdbarch_short_bit (gdbarch, 2 * TARGET_CHAR_BIT);
   set_gdbarch_int_bit (gdbarch, 4 * TARGET_CHAR_BIT);
diff -ruN gdb-6.8.orig/gdb/testsuite/gdb.asm/asm-source.exp gdb-6.8/gdb/testsuite/gdb.asm/asm-source.exp
--- gdb-6.8.orig/gdb/testsuite/gdb.asm/asm-source.exp	2008-01-02 07:53:18.000000000 +0900
+++ gdb-6.8/gdb/testsuite/gdb.asm/asm-source.exp	2008-06-30 14:42:49.000000000 +0900
@@ -105,6 +105,11 @@
     "powerpc*-*" {
         set asm-arch powerpc
     }
+    "sh*-linux*" {
+        set asm-arch sh-linux
+        set asm-flags "-I${srcdir}/${subdir} -I${objdir}/${subdir}"
+	set debug-flags "-gdwarf-2"
+    }
     "sh*-*-*" {
         set asm-arch sh
 	set debug-flags "-gdwarf-2"
diff -ruN gdb-6.8.orig/gdb/testsuite/gdb.asm/sh-linux.inc gdb-6.8/gdb/testsuite/gdb.asm/sh-linux.inc
--- gdb-6.8.orig/gdb/testsuite/gdb.asm/sh-linux.inc	1970-01-01 09:00:00.000000000 +0900
+++ gdb-6.8/gdb/testsuite/gdb.asm/sh-linux.inc	2008-06-30 14:43:35.000000000 +0900
@@ -0,0 +1,78 @@
+# You'll find a bunch of nop opcodes in the below macros.  They are
+# there to keep the code correctly aligned.  Be careful to maintain
+# them when changing the code.
+
+	comment "subroutine declare"
+	.purgem gdbasm_declare
+	.macro gdbasm_declare name
+	.align	1
+	.global	\name
+\name:
+	.endm
+
+	comment "subroutine prologue"
+	.macro gdbasm_enter
+	mov.l   r14,@-r15
+	sts.l   pr,@-r15
+	mov     r15,r14
+	nop
+	.endm
+
+	comment "subroutine epilogue"
+	.macro gdbasm_leave
+	mov     r14,r15
+	lds.l   @r15+,pr
+	mov.l   @r15+,r14
+	rts
+	nop
+	nop
+	.endm
+
+	comment "subroutine end"
+	.purgem gdbasm_end
+	.macro gdbasm_end name
+	.size   \name, .-_foo1
+	.align	1
+	.endm
+
+	comment "subroutine call"
+	.macro gdbasm_call subr
+	mov.l   .Lconst\@,r1
+	bra	.Lafterconst\@
+	nop
+	.align	2
+.Lconst\@:
+	.long	\subr
+.Lafterconst\@:
+	jsr	@r1
+	nop
+	.endm
+
+	.macro gdbasm_several_nops
+	nop
+	nop
+	nop
+	nop
+	.endm
+
+	comment "exit (0)"
+	.macro gdbasm_exit0
+	sleep
+	nop
+	.endm
+
+	comment "crt0 startup"
+	.macro gdbasm_startup
+	mov	#0,r14
+	.endm
+
+	comment "Declare a data variable"
+	.purgem gdbasm_datavar
+	.macro gdbasm_datavar name value
+	.data
+	.align 2
+	.type	\name, @object
+	.size	\name, 4
+\name:
+	.long	\value
+	.endm
diff -ruN gdb-6.8.orig/gdb/testsuite/gdb.asm/sh.inc gdb-6.8/gdb/testsuite/gdb.asm/sh.inc
--- gdb-6.8.orig/gdb/testsuite/gdb.asm/sh.inc	2005-03-08 06:16:50.000000000 +0900
+++ gdb-6.8/gdb/testsuite/gdb.asm/sh.inc	2008-06-30 14:44:55.000000000 +0900
@@ -40,9 +40,8 @@
 	mov.l   .Lconst\@,r1
 	bra	.Lafterconst\@
 	nop
-	nop
-.Lconst\@:
 	.align	2
+.Lconst\@:
 	.long	\subr
 	.align	1
 .Lafterconst\@:
diff -ruN gdb-6.8.orig/gdb/testsuite/gdb.base/annota1.c gdb-6.8/gdb/testsuite/gdb.base/annota1.c
--- gdb-6.8.orig/gdb/testsuite/gdb.base/annota1.c	1999-11-02 13:44:26.000000000 +0900
+++ gdb-6.8/gdb/testsuite/gdb.base/annota1.c	2008-06-30 14:46:10.000000000 +0900
@@ -1,9 +1,9 @@
 #include <stdio.h>
 #include <signal.h>
 
-#ifdef __sh__
-#define signal(a,b)	/* Signals not supported on this target - make them go away */
-#endif
+
+
+
 
 
 #ifdef PROTOTYPES
diff -ruN gdb-6.8.orig/gdb/testsuite/gdb.base/annota3.c gdb-6.8/gdb/testsuite/gdb.base/annota3.c
--- gdb-6.8.orig/gdb/testsuite/gdb.base/annota3.c	2003-08-03 10:57:13.000000000 +0900
+++ gdb-6.8/gdb/testsuite/gdb.base/annota3.c	2008-06-30 14:46:39.000000000 +0900
@@ -1,9 +1,9 @@
 #include <stdio.h>
 #include <signal.h>
 
-#ifdef __sh__
-#define signal(a,b)	/* Signals not supported on this target - make them go away */
-#endif
+
+
+
 
 
 #ifdef PROTOTYPES
diff -ruN gdb-6.8.orig/gdb/testsuite/gdb.base/sigall.c gdb-6.8/gdb/testsuite/gdb.base/sigall.c
--- gdb-6.8.orig/gdb/testsuite/gdb.base/sigall.c	2008-02-03 09:42:55.000000000 +0900
+++ gdb-6.8/gdb/testsuite/gdb.base/sigall.c	2008-06-30 14:47:16.000000000 +0900
@@ -1,9 +1,9 @@
 #include <signal.h>
 #include <unistd.h>
 
-#ifdef __sh__
-#define signal(a,b)	/* Signals not supported on this target - make them go away */
-#endif
+
+
+
 
 /* Signal handlers, we set breakpoints in them to make sure that the
    signals really get delivered.  */
diff -ruN gdb-6.8.orig/gdb/testsuite/gdb.base/signals.c gdb-6.8/gdb/testsuite/gdb.base/signals.c
--- gdb-6.8.orig/gdb/testsuite/gdb.base/signals.c	1999-06-29 01:04:03.000000000 +0900
+++ gdb-6.8/gdb/testsuite/gdb.base/signals.c	2008-06-30 14:47:40.000000000 +0900
@@ -3,10 +3,10 @@
 #include <signal.h>
 #include <unistd.h>
 
-#ifdef __sh__
-#define signal(a,b)	/* Signals not supported on this target - make them go away */
-#define alarm(a)	/* Ditto for alarm() */
-#endif
+
+
+
+
 
 static int count = 0;
 
--- gdb-6.8.orig/gdb/sh-linux-tdep.c	2008-01-02 07:53:12.000000000 +0900
+++ gdb-6.8/gdb/sh-linux-tdep.c	2008-06-30 16:03:21.000000000 +0900
@@ -18,18 +18,571 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
+#include "gdbcore.h"
+#include "frame.h"
+#include "frame-base.h"
+#include "frame-unwind.h"
+#include "dwarf2-frame.h"
+#include "value.h"
+#include "regcache.h"
+#include "inferior.h"
 #include "osabi.h"
-
+#include "reggroups.h"
+#include "arch-utils.h"
+#include "floatformat.h"
 #include "solib-svr4.h"
 #include "symtab.h"
+#include "gdb_string.h"
+#include "command.h"
+#include "gdb_assert.h"
+
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/user.h>
+#include <sys/syscall.h>
+
+#include "sh-tdep.h"
+#include "regset.h"
+#include "glibc-tdep.h"
+
+#define REG_PC		16
+#define REG_PR		17
+#define REG_SR		18
+#define REG_GBR      	19
+#define REG_MACH	20
+#define REG_MACL	21
+
+/* Recognizing signal handler frames.  */
+
+/* GNU/Linux has two flavors of signals.  Normal signal handlers, and
+   "realtime" (RT) signals.  The RT signals can provide additional
+   information to the signal handler if the SA_SIGINFO flag is set
+   when establishing a signal handler using `sigaction'.  It is not
+   unlikely that future versions of GNU/Linux will support SA_SIGINFO
+   for normal signals too.  */
+
+/* When the SH Linux kernel calls a signal handler and the
+   SA_RESTORER flag isn't set, the return address points to a bit of
+   code on the stack.  This function returns whether the PC appears to
+   be within this bit of code.
+
+   The instruction sequence for normal signals is
+       mov.w  1f,r3
+       trapa  #16
+       or     r0, r0
+       or     r0, r0
+       or     r0, r0
+       or     r0, r0
+       or     r0, r0
+    1: .word  __NR_sigreturn
+   or 0x9305 0xc310 0x200b 0x200b 0x200b 0x200b 0x200b 0x0077.
+
+   Checking for the code sequence should be somewhat reliable, because
+   the effect is to call the system call sigreturn.  This is unlikely
+   to occur anywhere other than a signal trampoline.
+
+   It kind of sucks that we have to read memory from the process in
+   order to identify a signal trampoline, but there doesn't seem to be
+   any other way.  The PC_IN_SIGTRAMP macro in tm-linux.h arranges to
+   only call us if no function name could be identified, which should
+   be the case since the code is on the stack.
+
+   Detection of signal trampolines for handlers that set the
+   SA_RESTORER flag is in general not possible.  Unfortunately this is
+   what the GNU C Library has been doing for quite some time now.
+   However, as of version 2.1.2, the GNU C Library uses signal
+   trampolines (named __restore and __restore_rt) that are identical
+   to the ones used by the kernel.  Therefore, these trampolines are
+   supported too.  */
+
+#define MOVW(n)	 (0x9300|((n)-2))	/* Move mem word at PC+n to R3 */
+#define TRAP16	 0xc310			/* Syscall w/no args (NR in R3) */
+#define OR_R0_R0 0x200b			/* or r0,r0 (insert to avoid hardware bug) */
+
+#define LINUX_SIGTRAMP_INSN0	MOVW(7)		/* Move mem word at PC+7 to R3 */
+#define LINUX_SIGTRAMP_INSN1	TRAP16		/* Syscall w/no args (NR in R3) */
+#define LINUX_SIGTRAMP_INSN2	OR_R0_R0	/* or r0,r0 (insert to avoid hardware bug) */
+
+static const unsigned short linux_sigtramp_code[] =
+{
+  LINUX_SIGTRAMP_INSN0,
+  LINUX_SIGTRAMP_INSN1,
+  LINUX_SIGTRAMP_INSN2,
+  LINUX_SIGTRAMP_INSN2,
+  LINUX_SIGTRAMP_INSN2,
+  LINUX_SIGTRAMP_INSN2,
+  LINUX_SIGTRAMP_INSN2,
+  __NR_sigreturn
+};
+
+#define LINUX_SIGTRAMP_LEN (sizeof linux_sigtramp_code)
+
+/* If PC is in a sigtramp routine, return the address of the start of
+   the routine.  Otherwise, return 0.  */
+
+static CORE_ADDR
+sh_linux_sigtramp_start (struct frame_info *next_frame)
+{
+  CORE_ADDR pc = frame_pc_unwind (next_frame);
+  gdb_byte buf[LINUX_SIGTRAMP_LEN];
+
+  /* We only recognize a signal trampoline if PC is at the start of
+     one of the three instructions.  We optimize for finding the PC at
+     the start, as will be the case when the trampoline is not the
+     first frame on the stack.  We assume that in the case where the
+     PC is not at the start of the instruction sequence, there will be
+     a few trailing readable bytes on the stack.  */
+
+  if (!safe_frame_unwind_memory (next_frame, pc, buf, LINUX_SIGTRAMP_LEN))
+    return 0;
+
+  if (buf[0] != LINUX_SIGTRAMP_INSN0)
+    {
+      if (buf[0] != LINUX_SIGTRAMP_INSN1)
+        return 0;
+
+      pc -= 2;
+
+      if (!safe_frame_unwind_memory (next_frame, pc, buf, LINUX_SIGTRAMP_LEN))
+	return 0;
+    }
+
+  if (memcmp (buf, linux_sigtramp_code, LINUX_SIGTRAMP_LEN) != 0)
+    return 0;
+
+  return pc;
+}
+
+/* This function does the same for RT signals.  Here the instruction
+   sequence is
+       mov.w  1f,r3
+       trapa  #16
+       or     r0, r0
+       or     r0, r0
+       or     r0, r0
+       or     r0, r0
+       or     r0, r0
+    1: .word  __NR_rt_sigreturn
+   or 0x9305 0xc310 0x200b 0x200b 0x200b 0x200b 0x200b 0x00ad.
+
+   The effect is to call the system call rt_sigreturn.  */
+
+#define LINUX_RT_SIGTRAMP_INSN0		MOVW(7)		/* Move mem word at PC+7 to R3 */
+#define LINUX_RT_SIGTRAMP_INSN1		TRAP16		/* Syscall w/no args (NR in R3) */
+#define LINUX_RT_SIGTRAMP_INSN2		OR_R0_R0	/* or r0,r0 (insert to avoid hardware bug) */
+
+static const unsigned short linux_rt_sigtramp_code[] =
+{
+  LINUX_RT_SIGTRAMP_INSN0,
+  LINUX_RT_SIGTRAMP_INSN1,
+  LINUX_RT_SIGTRAMP_INSN2,
+  LINUX_RT_SIGTRAMP_INSN2,
+  LINUX_RT_SIGTRAMP_INSN2,
+  LINUX_RT_SIGTRAMP_INSN2,
+  LINUX_RT_SIGTRAMP_INSN2,
+  __NR_rt_sigreturn
+};
+
+#define LINUX_RT_SIGTRAMP_LEN (sizeof linux_rt_sigtramp_code)
+
+/* If PC is in a RT sigtramp routine, return the address of the start
+   of the routine.  Otherwise, return 0.  */
+
+static CORE_ADDR
+sh_linux_rt_sigtramp_start (struct frame_info *next_frame)
+{
+  CORE_ADDR pc = frame_pc_unwind (next_frame);
+  gdb_byte buf[LINUX_RT_SIGTRAMP_LEN];
+
+  /* We only recognize a signal trampoline if PC is at the start of
+     one of the two instructions.  We optimize for finding the PC at
+     the start, as will be the case when the trampoline is not the
+     first frame on the stack.  We assume that in the case where the
+     PC is not at the start of the instruction sequence, there will be
+     a few trailing readable bytes on the stack.  */
+
+  if (!safe_frame_unwind_memory (next_frame, pc, buf, LINUX_RT_SIGTRAMP_LEN))
+    return 0;
+
+  if (buf[0] != LINUX_RT_SIGTRAMP_INSN0)
+    {
+      if (buf[0] != LINUX_RT_SIGTRAMP_INSN1)
+	return 0;
+
+      pc -= 2;
+
+      if (!safe_frame_unwind_memory (next_frame, pc, buf,
+				     LINUX_RT_SIGTRAMP_LEN))
+	return 0;
+    }
+
+  if (memcmp (buf, linux_rt_sigtramp_code, LINUX_RT_SIGTRAMP_LEN) != 0)
+    return 0;
+
+  return pc;
+}
+
+/* Return whether PC is in a GNU/Linux sigtramp routine.  */
+
+static int
+sh_linux_sigtramp_p (struct frame_info *next_frame)
+{
+  CORE_ADDR pc = frame_pc_unwind (next_frame);
+  char *name;
+
+  find_pc_partial_function (pc, &name, NULL, NULL);
+
+  /* If we have NAME, we can optimize the search.  The trampolines are
+     named __restore and __restore_rt.  However, they aren't dynamically
+     exported from the shared C library, so the trampoline may appear to
+     be part of the preceding function.  This should always be sigaction,
+     __sigaction, or __libc_sigaction (all aliases to the same function).  */
+  if (name == NULL || strstr (name, "sigaction") != NULL)
+    return (sh_linux_sigtramp_start (next_frame) != 0
+	    || sh_linux_rt_sigtramp_start (next_frame) != 0);
+
+  return (strcmp ("__restore", name) == 0
+	  || strcmp ("__restore_rt", name) == 0);
+}
+
+/* Offset to struct sigcontext in ucontext, from <asm/ucontext.h>.  */
+#define SH_LINUX_UCONTEXT_SIGCONTEXT_OFFSET 12
+
+
+/* Assuming NEXT_FRAME is a frame following a GNU/Linux sigtramp
+   routine, return the address of the associated sigcontext structure.  */
+
+static CORE_ADDR
+sh_linux_sigcontext_addr (struct frame_info *next_frame)
+{
+  CORE_ADDR pc;
+  CORE_ADDR sp;
+
+  sp = frame_unwind_register_unsigned (next_frame, SP_REGNUM);
+
+  pc = sh_linux_sigtramp_start (next_frame);
+  if (pc)
+    {
+      return sp;
+    }
+
+  pc = sh_linux_rt_sigtramp_start (next_frame);
+  if (pc)
+    {
+      CORE_ADDR ucontext_addr;
+
+      /* The sigcontext structure is part of the user context.  A
+	 pointer to the user context is passed as the third argument
+	 to the signal handler.  */
+      ucontext_addr = frame_unwind_register_unsigned (next_frame, ARG0_REGNUM+2);
+      return ucontext_addr + SH_LINUX_UCONTEXT_SIGCONTEXT_OFFSET;
+    }
+
+  error ("Couldn't recognize signal trampoline.");
+  return 0;
+}
+
+/* Signal trampolines.  */
+extern struct sh_frame_cache *sh_alloc_frame_cache (void);
+
+static struct sh_frame_cache *
+sh_linux_sigtramp_frame_cache (struct frame_info *next_frame, void **this_cache)
+{
+  struct sh_frame_cache *cache;
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  CORE_ADDR sigcontext_addr;
+
+  if (*this_cache)
+    return *this_cache;
+
+  cache = sh_alloc_frame_cache ();
+
+  cache->base = frame_unwind_register_unsigned (next_frame, SP_REGNUM);
+  sigcontext_addr = tdep->sigcontext_addr (next_frame);
+  if (tdep->sc_reg_offset)
+    {
+      int i;
+
+      gdb_assert (tdep->sc_num_regs <= SH_NUM_REGS);
+
+      for (i = 0; i < tdep->sc_num_regs; i++)
+	if (tdep->sc_reg_offset[i] != -1)
+	  cache->saved_regs[i] = sigcontext_addr + tdep->sc_reg_offset[i];
+    }
+
+  *this_cache = cache;
+  return cache;
+}
+
+static void
+sh_linux_sigtramp_frame_this_id (struct frame_info *next_frame, void **this_cache,
+			     struct frame_id *this_id)
+{
+  struct sh_frame_cache *cache =
+    sh_linux_sigtramp_frame_cache (next_frame, this_cache);
+
+  (*this_id) = frame_id_build (cache->base + 64, cache->pc);
+}
+
+static void
+sh_linux_sigtramp_frame_prev_register (struct frame_info *next_frame,
+				   void **this_cache,
+				   int regnum, int *optimizedp,
+				   enum lval_type *lvalp, CORE_ADDR *addrp,
+				   int *realnump, gdb_byte *valuep)
+{
+  struct sh_frame_cache *cache = sh_linux_sigtramp_frame_cache (next_frame, this_cache);
+
+  gdb_assert (regnum >= 0);
+
+  if (regnum < SH_NUM_REGS && cache->saved_regs[regnum] != -1)
+    {
+      *optimizedp = 0;
+      *lvalp = lval_memory;
+      *addrp = cache->saved_regs[regnum];
+      *realnump = -1;
+      if (valuep)
+	{
+	  /* Read the value in from memory.  */
+	  read_memory (*addrp, valuep,
+		       register_size (current_gdbarch, regnum));
+	}
+      return;
+    }
+
+  *optimizedp = 0;
+  *lvalp = lval_register;
+  *addrp = 0;
+  *realnump = regnum;
+  if (valuep)
+    frame_unwind_register (next_frame, (*realnump), valuep);
+}
+
+static const struct frame_unwind sh_linux_sigtramp_frame_unwind =
+{
+  SIGTRAMP_FRAME,
+  sh_linux_sigtramp_frame_this_id,
+  sh_linux_sigtramp_frame_prev_register
+};
+
+static const struct frame_unwind *
+sh_linux_sigtramp_frame_sniffer (struct frame_info *next_frame)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (next_frame));
+
+  /* We shouldn't even bother if we don't have a sigcontext_addr
+     handler.  */
+  if (tdep->sigcontext_addr == NULL)
+    return NULL;
+
+  if (tdep->sigtramp_p != NULL)
+    {
+      if (tdep->sigtramp_p (next_frame))
+	return &sh_linux_sigtramp_frame_unwind;
+    }
+
+  return NULL;
+}
+
+/* Supply register REGNUM from the buffer specified by GREGS and LEN
+   in the general-purpose register set REGSET to register cache
+   REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */
+
+void
+sh_supply_gregset (const struct regset *regset, struct regcache *regcache,
+		     int regnum, const void *gregs, size_t len)
+{
+  const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch);
+  const char *regs = gregs;
+  int i;
+
+  gdb_assert (len == tdep->sizeof_gregset);
+
+  for (i = 0; i < tdep->gregset_num_regs; i++)
+    {
+      if ((regnum == i || regnum == -1)
+	  && tdep->gregset_reg_offset[i] != -1)
+	regcache_raw_supply (regcache, i, regs + tdep->gregset_reg_offset[i]);
+    }
+}
+
+/* Collect register REGNUM from the register cache REGCACHE and store
+   it in the buffer specified by GREGS and LEN as described by the
+   general-purpose register set REGSET.  If REGNUM is -1, do this for
+   all registers in REGSET.  */
+
+void
+sh_collect_gregset (const struct regset *regset,
+		      const struct regcache *regcache,
+		      int regnum, void *gregs, size_t len)
+{
+  const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch);
+  char *regs = gregs;
+  int i;
+
+  gdb_assert (len == tdep->sizeof_gregset);
+
+  for (i = 0; i < tdep->gregset_num_regs; i++)
+    {
+      if ((regnum == i || regnum == -1)
+	  && tdep->gregset_reg_offset[i] != -1)
+	regcache_raw_collect (regcache, i, regs + tdep->gregset_reg_offset[i]);
+    }
+}
+
+/* Supply register REGNUM from the buffer specified by FPREGS and LEN
+   in the floating-point register set REGSET to register cache
+   REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */
+
+static void
+sh_supply_fpregset (const struct regset *regset, struct regcache *regcache,
+		      int regnum, const void *fpregs, size_t len)
+{
+  const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch);
+  const char *regs = fpregs;
+  int i;
+
+  gdb_assert (len == tdep->sizeof_fpregset);
+  for (i = 0; i < 16; i++)
+    {
+      if (regnum == i+25 || regnum == -1)
+	regcache_raw_supply (regcache, i+25, regs + i*4);
+    }
+  if (regnum == FPSCR_REGNUM || regnum == -1)
+    regcache_raw_supply (regcache, FPSCR_REGNUM, regs + 32*4);
+  if (regnum == FPUL_REGNUM || regnum == -1)
+    regcache_raw_supply (regcache, FPUL_REGNUM, regs + 33*4);
+}
+
+/* Collect register REGNUM from the register cache REGCACHE and store
+   it in the buffer specified by FPREGS and LEN as described by the
+   floating-point register set REGSET.  If REGNUM is -1, do this for
+   all registers in REGSET.  */
+
+static void
+sh_collect_fpregset (const struct regset *regset,
+		       const struct regcache *regcache,
+		       int regnum, void *fpregs, size_t len)
+{
+  const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch);
+  char *regs = fpregs;
+  int i;
+
+  gdb_assert (len == tdep->sizeof_fpregset);
+  for (i = 0; i < 16; i++)
+    {
+      if (regnum == i+25 || regnum == -1)
+	regcache_raw_collect (regcache, i+25, regs + i*4);
+    }
+  if (regnum == FPSCR_REGNUM || regnum == -1)
+    regcache_raw_collect (regcache, FPSCR_REGNUM, regs + 32*4);
+  if (regnum == FPUL_REGNUM || regnum == -1)
+    regcache_raw_collect (regcache, FPUL_REGNUM, regs + 33*4);
+}
+
+/* Return the appropriate register set for the core section identified
+   by SECT_NAME and SECT_SIZE.  */
+
+const struct regset *
+sh_linux_regset_from_core_section (struct gdbarch *gdbarch,
+			       const char *sect_name, size_t sect_size)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  if (strcmp (sect_name, ".reg") == 0 && sect_size == tdep->sizeof_gregset)
+    {
+      if (tdep->gregset == NULL)
+	tdep->gregset = regset_alloc (gdbarch, sh_supply_gregset,
+				      sh_collect_gregset);
+      return tdep->gregset;
+    }
+
+  if ((strcmp (sect_name, ".reg2") == 0 && sect_size == tdep->sizeof_fpregset))
+    {
+      if (tdep->fpregset == NULL)
+	tdep->fpregset = regset_alloc (gdbarch, sh_supply_fpregset,
+				       sh_collect_fpregset);
+      return tdep->fpregset;
+    }
+
+  return NULL;
+}
+
+/* The register sets used in GNU/Linux ELF core-dumps are identical to
+   the register sets in `struct user' that are used for a.out
+   core-dumps.  These are also used by ptrace(2).  The corresponding
+   types are `elf_gregset_t' for the general-purpose registers (with
+   `elf_greg_t' the type of a single GP register) and `elf_fpregset_t'
+   for the floating-point registers.
+
+   Those types used to be available under the names `gregset_t' and
+   `fpregset_t' too, and GDB used those names in the past.  But those
+   names are now used for the register sets used in the `mcontext_t'
+   type, which have a different size and layout.  */
+
+/* Mapping between the general-purpose registers in `struct user'
+   format and GDB's register cache layout.  */
+
+/* From <sys/reg.h>.  */
+static int sh_linux_gregset_reg_offset[] =
+{
+ 0,	4,	8,	12,	16,	20,	24,	28,
+ 32,	36,	40,	44,	48,	52,	56,	60,
+
+ REG_PC*4,   REG_PR*4,   REG_GBR*4,  -1,
+ REG_MACH*4, REG_MACL*4, REG_SR*4,
+};
+
+/* Mapping between the general-purpose registers in `struct
+   sigcontext' format and GDB's register cache layout.  */
+
+/* From <asm/sigcontext.h>.  */
+static int sh_linux_sc_reg_offset[] =
+{
+ 4,	8,	12,	16,	20,	24,	28,	32,
+ 36,	40,	44,	48,	52,	56,	60,	64,
+ 68,	72,	80,	-1,
+ 84,	88,	76
+};
 
 static void
 sh_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  bfd abfd;
+
+  tdep->gregset_reg_offset = sh_linux_gregset_reg_offset;
+  tdep->gregset_num_regs = ARRAY_SIZE (sh_linux_gregset_reg_offset);
+  tdep->sizeof_gregset = 23 * 4;
+
+  tdep->jb_pc_offset = 32;	/* From <bits/setjmp.h>.  */
+
+  tdep->sigtramp_p = sh_linux_sigtramp_p;
+  tdep->sigcontext_addr = sh_linux_sigcontext_addr;
+  tdep->sc_reg_offset = sh_linux_sc_reg_offset;
+  tdep->sc_num_regs = ARRAY_SIZE (sh_linux_sc_reg_offset);
+
+  frame_unwind_append_sniffer (gdbarch, sh_linux_sigtramp_frame_sniffer);
+
+  /* If we have a register mapping, enable the generic core file
+     support, unless it has already been enabled.  */
+  if (tdep->gregset_reg_offset
+      && !gdbarch_regset_from_core_section_p (gdbarch))
+    set_gdbarch_regset_from_core_section (gdbarch,
+					  sh_linux_regset_from_core_section);
+
   /* GNU/Linux uses SVR4-style shared libraries.  */
   set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
   set_solib_svr4_fetch_link_map_offsets
     (gdbarch, svr4_ilp32_fetch_link_map_offsets);
+
+  /* GNU/Linux uses the dynamic linker included in the GNU C Library.  */
+  set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
+
+  /* Enable TLS support.  */
+  set_gdbarch_fetch_tls_load_module_address (gdbarch,
+                                             svr4_fetch_objfile_link_map);
 }
 
 /* Provide a prototype to silence -Wmissing-prototypes.  */
--- gdb-6.8.orig/gdb/sh-linux-nat.c	1970-01-01 09:00:00.000000000 +0900
+++ gdb-6.8/gdb/sh-linux-nat.c	2008-06-30 16:38:17.000000000 +0900
@@ -0,0 +1,275 @@
+/* Low level SH interface to ptrace, for GDB when running native.
+   Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program 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; either version 2 of the License, or
+(at your option) any later version.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "inferior.h"
+#include "gdbcore.h"
+#include "regcache.h"
+#include "linux-nat.h"
+#include "target.h"
+#include "arch-utils.h"
+
+#include "gdb_assert.h"
+#include "gdb_string.h"
+#include <sys/ptrace.h>
+#include <sys/user.h>
+#include <sys/procfs.h>
+
+/* Prototypes for supply_gregset etc. */
+#include "gregset.h"
+#include "sh-tdep.h"
+
+/* Defines ps_err_e, struct ps_prochandle.  */
+#include "gdb_proc_service.h"
+
+#include <asm/elf.h>
+
+#define SH_LINUX_NUM_REGS	40
+/* This table must line up with REGISTER_NAME in "sh-tdep.c".  */
+static const int regmap[] =
+{
+  /* general registers 0-15 */
+  REG_REG0   , REG_REG0+1 , REG_REG0+2 , REG_REG0+3,
+  REG_REG0+4 , REG_REG0+5 , REG_REG0+6 , REG_REG0+7,
+  REG_REG0+8 , REG_REG0+9 , REG_REG0+10, REG_REG0+11,
+  REG_REG0+12, REG_REG0+13, REG_REG0+14, REG_REG0+15,
+  /* 16 - 22 */
+  REG_PC, REG_PR, REG_GBR, -1, REG_MACH, REG_MACL, REG_SR,
+  /* 23, 24 */
+  REG_FPUL, REG_FPSCR,
+  /* floating point registers 25 - 40 */
+  REG_FPREG0   , REG_FPREG0+1 , REG_FPREG0+2 , REG_FPREG0+3 ,
+  REG_FPREG0+4 , REG_FPREG0+5 , REG_FPREG0+6 , REG_FPREG0+7 ,
+  REG_FPREG0+8 , REG_FPREG0+9 , REG_FPREG0+10, REG_FPREG0+11,
+  REG_FPREG0+12, REG_FPREG0+13, REG_FPREG0+14, REG_FPREG0+15,
+};
+
+CORE_ADDR
+register_u_addr (CORE_ADDR blockend, int regnum)
+{
+  if (regnum < 0 || regnum >= sizeof regmap/sizeof regmap[0])
+    return (CORE_ADDR)-1;
+  return (blockend + 4 * regmap[regnum]);
+}
+
+/* Return the size of the user struct.  */
+
+int
+kernel_u_size (void)
+{
+  return (sizeof (struct user));
+}
+
+/* Return the address in the core dump or inferior of register REGNO.
+   BLOCKEND is the address of the end of the user structure.  */
+
+CORE_ADDR
+register_addr (int regno, CORE_ADDR blockend)
+{
+  CORE_ADDR addr;
+
+  if (regno < 0 || regno >= SH_LINUX_NUM_REGS) {
+    internal_error (__FILE__, __LINE__,
+		  _("Got request for bad register number %d."), regno);
+  }
+
+  REGISTER_U_ADDR (addr, blockend, regno);
+
+  return addr;
+}
+
+/* Fetch one register.  */
+
+static void
+fetch_register (struct regcache *regcache, int tid, int regno)
+{
+  int val;
+
+  if (cannot_fetch_register (regno))
+    {
+      regcache_raw_supply (regcache, regno, NULL);
+      return;
+    }
+
+  errno = 0;
+  val = ptrace (PTRACE_PEEKUSER, tid, register_addr (regno, 0), 0);
+  if (errno != 0)
+    perror_with_name (_("Couldn't get registers"));
+
+  regcache_raw_supply (regcache, regno, &val);
+}
+
+/* Store one register. */
+
+static void
+store_register (struct regcache *regcache, int tid, int regno)
+{
+  int val;
+
+  if (cannot_store_register (regno))
+    return;
+
+  errno = 0;
+  regcache_raw_collect (regcache, regno, &val);
+  ptrace (PTRACE_POKEUSER, tid, register_addr (regno, 0), val);
+  if (errno != 0)
+    perror_with_name (_("Couldn't write registers"));
+}
+
+/* Transfering the general-purpose registers between GDB, inferiors
+   and core files.  */
+
+/* Fill GDB's register array with the general-purpose register values
+   in *GREGSETP.  */
+
+void
+supply_gregset (struct regcache *regcache, const elf_gregset_t *gregsetp)
+{
+  elf_greg_t *regp = (elf_greg_t *) gregsetp;
+  int i;
+
+  for (i = 0; i < 23; i++)
+    if (regmap[i] == -1)
+      regcache_raw_supply (regcache, i, NULL);
+    else
+      regcache_raw_supply (regcache, i, (char *) (regp + regmap[i]));
+}
+
+/* Fill register REGNO (if it is a general-purpose register) in
+   *GREGSETPS with the value in GDB's register array.  If REGNO is -1,
+   do this for all registers.  */
+
+void
+fill_gregset (const struct regcache *regcache, elf_gregset_t *gregsetp, int regno)
+{
+  elf_greg_t *regp = (elf_greg_t *) gregsetp;
+  int i;
+
+  for (i = 0; i < 23; i++)
+    if (regmap[i] != -1 && (regno == -1 || regno == i))
+      regcache_raw_collect (regcache, i, (char *) (regp + regmap[i]));
+}
+
+/* Transfering floating-point registers between GDB, inferiors and cores.  */
+
+/* Fill GDB's register array with the floating-point register values in
+   *FPREGSETP.  */
+
+void
+supply_fpregset (struct regcache *regcache, const elf_fpregset_t *fpregsetp)
+{
+  int i;
+  long *regp = (long *)fpregsetp;
+
+  for (i = 0; i < 16; i++)
+    regcache_raw_supply (regcache, 25 + i, (char *) (regp + i));
+  regcache_raw_supply (regcache, FPUL_REGNUM, (char *) (regp + REG_FPUL - REG_FPREG0));
+  regcache_raw_supply (regcache, FPSCR_REGNUM, (char *) (regp + REG_FPSCR - REG_FPREG0));
+}
+
+/* Fill register REGNO (if it is a floating-point register) in
+   *FPREGSETP with the value in GDB's register array.  If REGNO is -1,
+   do this for all registers.  */
+
+void
+fill_fpregset (const struct regcache *regcache, elf_fpregset_t *fpregsetp, int regno)
+{
+  int i;
+  long *regp = (long *)fpregsetp;
+
+  for (i = 0; i < 16; i++)
+    if ((regno == -1) || (regno == i))
+      regcache_raw_collect (regcache, 25 + i, (char *) (regp + i));
+  if ((regno == -1) || regno == FPSCR_REGNUM)
+    regcache_raw_collect (regcache, FPSCR_REGNUM, (char *) (regp + REG_FPSCR - REG_FPREG0));
+  if ((regno == -1) || regno == FPUL_REGNUM)
+    regcache_raw_collect (regcache, FPUL_REGNUM, (char *) (regp + REG_FPUL - REG_FPREG0));
+}
+
+/* Transferring arbitrary registers between GDB and inferior.  */
+
+/* Check if register REGNO in the child process is accessible.
+   If we are accessing registers directly via the U area, only the
+   general-purpose registers are available.
+   All registers should be accessible if we have GETREGS support.  */
+   
+int
+cannot_fetch_register (int regno)
+{
+  return (regno < 0 || regno >= sizeof regmap / sizeof regmap[0] || regmap[regno] == -1);
+}
+
+int
+cannot_store_register (int regno)
+{
+  return (regno < 0 || regno >= sizeof regmap / sizeof regmap[0] || regmap[regno] == -1);
+}
+
+/* Fetch register values from the inferior.
+   If REGNO is negative, do this for all registers.
+   Otherwise, REGNO specifies which register (so we can save time). */
+
+static void
+sh_linux_fetch_inferior_registers (struct regcache *regcache, int regno)
+{
+  int i;
+  int tid;
+
+  /* GNU/Linux LWP ID's are process ID's.  */
+  if ((tid = TIDGET (inferior_ptid)) == 0)
+    tid = PIDGET (inferior_ptid);	/* Not a threaded program.  */
+
+  for (i = 0; i < SH_LINUX_NUM_REGS; i++)
+    if (regno == -1 || regno == i)
+      fetch_register (regcache, tid, i);
+}
+/* Store our register values back into the inferior.
+   If REGNO is negative, do this for all registers.
+   Otherwise, REGNO specifies which register (so we can save time).  */
+
+static void
+sh_linux_store_inferior_registers (struct regcache *regcache, int regno)
+{
+  int i;
+  int tid;
+
+  /* GNU/Linux LWP ID's are process ID's.  */
+  if ((tid = TIDGET (inferior_ptid)) == 0)
+    tid = PIDGET (inferior_ptid);	/* Not a threaded program.  */
+
+  for (i = 0; i < SH_LINUX_NUM_REGS; i++)
+    if (regno == -1 || regno == i)
+      store_register (regcache, tid, i);
+}
+
+void
+_initialize_sh_linux_nat (void)
+{
+  struct target_ops *t;
+
+  /* Fill in the generic GNU/Linux methods.  */
+  t = linux_target ();
+
+  /* Add our register access methods.  */
+  t->to_fetch_registers = sh_linux_fetch_inferior_registers;
+  t->to_store_registers = sh_linux_store_inferior_registers;
+
+  /* Register the target.  */
+  linux_nat_add_target (t);
+}
--- gdb-6.8.orig/gdb/sh-tdep.h	2008-01-02 07:53:13.000000000 +0900
+++ gdb-6.8/gdb/sh-tdep.h	2008-06-30 16:03:46.000000000 +0900
@@ -22,6 +22,39 @@
 
 /* Contributed by Steve Chamberlain sac@cygnus.com */
 
+struct frame_info;
+struct gdbarch;
+struct reggroup;
+struct regset;
+struct regcache;
+
+/* sh architecture specific information.  */
+struct gdbarch_tdep
+{
+  /* General-purpose registers.  */
+  struct regset *gregset;
+  int *gregset_reg_offset;
+  int gregset_num_regs;
+  size_t sizeof_gregset;
+
+  /* Floating-point registers.  */
+  struct regset *fpregset;
+  size_t sizeof_fpregset;
+
+  /* Offset of saved PC in jmp_buf.  */
+  int jb_pc_offset;
+
+  /* Detect sigtramp.  */
+  int (*sigtramp_p) (struct frame_info *);
+
+  /* Get address of sigcontext for sigtramp.  */
+  CORE_ADDR (*sigcontext_addr) (struct frame_info *);
+
+  /* Offset of registers in `struct sigcontext'.  */
+  int *sc_reg_offset;
+  int sc_num_regs;
+};
+
 /* Registers for all SH variants.  Used also by sh3-rom.c. */
 enum
   {
@@ -30,6 +63,7 @@
     ARG0_REGNUM = 4,
     ARGLAST_REGNUM = 7,
     FP_REGNUM = 14,
+    SP_REGNUM = 15,
     PR_REGNUM = 17,
     GBR_REGNUM = 18,
     VBR_REGNUM = 19,
@@ -82,7 +116,25 @@
     FV_LAST_REGNUM = 79
   };
 
+#define SH_NUM_REGS 67
+
+struct sh_frame_cache
+{
+  /* Base address.  */
+  CORE_ADDR base;
+  LONGEST sp_offset;
+  CORE_ADDR pc;
+
+  /* Flag showing that a frame has been created in the prologue code. */
+  int uses_fp;
+
+  /* Saved registers.  */
+  CORE_ADDR saved_regs[SH_NUM_REGS];
+  CORE_ADDR saved_sp;
+};
+
 extern gdbarch_init_ftype sh64_gdbarch_init;
 extern void sh64_show_regs (struct frame_info *);
+extern struct sh_frame_cache *sh_frame_cache (struct frame_info *next_frame, void **this_cache);
 
 #endif /* SH_TDEP_H */
