This is the mail archive of the gdb-patches@sourceware.org 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]

[rfc 7/9]#2 Associate siginfo_t with any signal


series #2 of: http://sourceware.org/ml/gdb-patches/2010-07/msg00409.html

Hi,

this patch brings the primary fix of this patchset.  siginfo_t gets associated
with every signal (both target_signal_t and int host_signal).

It is RFC only as I expect there some changes of code for gdb/remote.c .

Also some code may need to be moved to gdb/common/ to be reused from
gdb/gdbserver/ (but which I have not planned to implement so far).


Thanks,
Jan


include/gdb/
2010-08-30  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* signals.h (target_signal_t): Remove the comment about limitations.
	New fields siginfo_gdbarch and siginfo.
	(TARGET_SIGNAL_STRUCT): New define.
	(TARGET_SIGNAL_INITIALIZER, target_signal_from_number): Adjust it.

gdb/
2010-08-30  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* configure.ac (HAVE_SIGINFO_T, gdb_cv_sizeof_siginfo_t)
	(MAX_SIGINFO_SIZE, HAVE_RT_TGSIGQUEUEINFO_SYSCALL): New checks.
	* configure.tgt (gdb_target_siginfo_size, gdb_all_max_siginfo_size):
	New constants.
	(arm*-*-linux*, i[34567]86-*-linux*, x86_64-*-linux*): Set
	gdb_target_siginfo_size.
	($gdb_target_siginfo_size -gt $gdb_all_max_siginfo_size): New test.
	* config.in: Regenerated.
	* configure: Regenerated.
	* amd64-linux-nat.c (amd64_linux_siginfo_fixup): New parameter
	gdbarch.  Follow it.  New variable arch.  New gdb_asserts on known
	gdbarch.
	* i386-linux-nat.c: Include inf-ptrace.h.
	(PTRACE_SETSIGINFO)
	(i386_linux_resume) <target_signal_siginfo_p (&signal)>: New.
	* inf-ptrace.c (PTRACE_GETSIGINFO, PTRACE_SETSIGINFO): New.
	(inf_ptrace_resume) <target_signal_siginfo_p (&signal)>
	(inf_ptrace_wait) <TARGET_WAITKIND_USES_SIG (ourstatus->kind)>: New.
	(inf_ptrace_siginfo_fixup): Conditionalize it by HAVE_SIGINFO_T.  New
	`gdbarch *' parameter.
	(inf_ptrace_set_siginfo_fixup): Conditionalize it by HAVE_SIGINFO_T.
	New `gdbarch *' parameter of the siginfo_fixup parameter.
	(siginfo_fixup): Conditionalize it by HAVE_SIGINFO_T.  Extend the
	comment.  New MAX_SIGINFO_SIZE gdb_assert.  New gdbarch parameter,
	pass it along.
	* inf-ptrace.h (siginfo_fixup, inf_ptrace_set_siginfo_fixup):
	Conditionalize the declarations by HAVE_SIGINFO_T.
	* linux-nat.c: Include unistd.h and sys/syscall.h also for
	HAVE_RT_TGSIGQUEUEINFO_SYSCALL.
	(struct simple_pid_list) <siginfo>: New field.
	(add_to_pid_list) <siginfop>: New parameter.  Store it.
	(pull_pid_from_list) <siginfop>: New parameter.  Retrieve it.
	(linux_record_stopped_pid) <siginfop: New parameter.  Pass it.
	(my_waitpid) <siginfop>: New parameter.  Fill it in.  Extend the
	function comment.
	(linux_test_for_tracefork): Pass NULL to my_waitpid.
	(linux_child_follow_fork): Clear lp->siginfo.
	(linux_nat_post_attach_wait) <siginfop>: New parameter.  Pass it.
	(lin_lwp_attach_lwp) <siginfo>: New variable.  Use it, store it to
	lp->siginfo.
	(linux_nat_attach) <siginfo>: New variable.  use it, store it to
	lp->siginfo.
	(get_pending_status): New comment about SIGNO.siginfo.
	(resume_callback) <lp->siginfo>: Replace memset by just si_signo = 0.
	(linux_nat_resume): Set saved_signo siginfo from lp->siginfo.  Clear
	lp->siginfo when clearing lp->status.  Replace memset by si_signo = 0.
	(kill_lwp) <debug_linux_nat>: New message.
	(kill_lwp_siginfo): New function.
	(linux_handle_extended_wait): New parameter siginfop.  New variable
	siginfo, initialize it.  Pass siginfo around.  Clear siginfo when
	clearing status.  Set signo.siginfo when setting signo.
	(wait_lwp): New parameter siginfop.  New variable siginfo_local.  Pass
	siginfop around.  Clear siginfop on thread_dead.  Clear siginfop on
	setting status.
	(save_siginfo): Remove the function.
	(set_ignore_sigint): Clear lp->siginfo when clearing lp->status.
	(stop_wait_callback): New variable siginfo.  Use it to set
	lp->siginfo.  Call kill_lwp_siginfo instead of kill_lwp.  Set
	lp->siginfo when setting lp->status.
	(cancel_breakpoints_callback): Clear lp->siginfo when clearing
	lp->status.
	(select_event_lwp): New parameter siginfop.  Store it into
	(*orig_lp)->siginfo and *siginfop.  
	(linux_nat_filter_event): New parameter siginfop.  New variable
	siginfo.  Pass it along.  Clear siginfo when setting status.  Replace
	called save_siginfo by using siginfo.  Store siginfo to lp->siginfo.
	(linux_nat_wait_1): Remove unused status initialization.  New variable
	siginfo.  Initialize it.  Set siginfo when setting status.  Set
	lp->siginfo when setting lp->status.  Call kill_lwp_siginfo instead of
	kill_lwp.  Pass siginfo along.  Store lp->siginfo into lp->waitstatus,
	signo and ourstatus.
	(resume_stopped_resumed_lwps): Replace memset by si_signo = 0.
	(kill_wait_callback): Pass NULL to siginfop of my_waitpid.
	(linux_xfer_siginfo): Use MAX_SIGINFO_SIZE size for inf_siginfo.
	Create gdbarch for siginfo_fixup.
	(linux_nat_stop_lwp): Set also lwp->siginfo when setting lwp->status.
	(linux_nat_get_siginfo): Extend the function comment.
	* linux-nat.h (struct lwp_info) <siginfo>: Move it to status.
	Describe it more.
	(linux_nat_get_siginfo): Extend the function comment.
	* rs6000-nat.c (PTRACE_GETSIGINFO): New define.
	(rs6000_wait): Set also ourstatus->value.sig.
	* spu-linux-nat.c (PTRACE_GETSIGINFO): New define.
	(spu_child_wait): New variable siginfo.  Set also
	ourstatus->value.sig.
	* target.c (target_signal_siginfo_p, target_signal_siginfo_len)
	(target_signal_siginfo_get, target_signal_siginfo_set): New functions.
	* target.h (TARGET_WAITKIND_USES_SIG): New define.
	(target_signal_siginfo_p, target_signal_siginfo_len)
	(target_signal_siginfo_get, target_signal_siginfo_set): New
	declarations.

gdb/testsuite/
2010-08-30  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* gdb.threads/siginfo-threads.exp: New file.
	* gdb.threads/siginfo-threads.c: New file.

--- a/gdb/amd64-linux-nat.c
+++ b/gdb/amd64-linux-nat.c
@@ -685,12 +685,21 @@ siginfo_from_compat_siginfo (siginfo_t *to, compat_siginfo_t *from)
    INF.  */
 
 static int
-amd64_linux_siginfo_fixup (struct siginfo *native, gdb_byte *inf, int direction)
+amd64_linux_siginfo_fixup (struct siginfo *native, gdb_byte *inf,
+                           int direction, struct gdbarch *gdbarch)
 {
-  /* Is the inferior 32-bit?  If so, then do fixup the siginfo
-     object.  */
-  if (gdbarch_addr_bit (get_frame_arch (get_current_frame ())) == 32)
-    {
+  const bfd_arch_info_type *arch = gdbarch_bfd_arch_info (gdbarch);
+
+  gdb_assert (gdbarch_osabi (gdbarch) == GDB_OSABI_LINUX);
+  gdb_assert (arch->arch == bfd_arch_i386);
+
+  switch (arch->mach)
+  {
+    /* Is the inferior 32-bit?  If so, then do fixup the siginfo
+       object.  */
+    case bfd_mach_i386_i386:
+    case bfd_mach_i386_i386_intel_syntax:
+      gdb_assert (gdbarch_addr_bit (gdbarch) == 32);
       gdb_assert (sizeof (struct siginfo) == sizeof (compat_siginfo_t));
 
       if (direction == 0)
@@ -699,9 +708,16 @@ amd64_linux_siginfo_fixup (struct siginfo *native, gdb_byte *inf, int direction)
 	siginfo_from_compat_siginfo (native, (struct compat_siginfo *) inf);
 
       return 1;
-    }
-  else
-    return 0;
+
+    case bfd_mach_x86_64:
+    case bfd_mach_x86_64_intel_syntax:
+      gdb_assert (gdbarch_addr_bit (gdbarch) == 64);
+
+      return 0;
+
+    default:
+      gdb_assert_not_reached ("Unsupported architecture");
+  }
 }
 
 /* Get Linux/x86 target description from running target.
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -464,6 +464,9 @@
 /* Define to 1 if you have the `resize_term' function. */
 #undef HAVE_RESIZE_TERM
 
+/* Define if you support the rt_tgsigqueueinfo syscall. */
+#undef HAVE_RT_TGSIGQUEUEINFO_SYSCALL
+
 /* Define to 1 if you have the `sbrk' function. */
 #undef HAVE_SBRK
 
@@ -488,6 +491,9 @@
 /* Define to 1 if you have the `sigaction' function. */
 #undef HAVE_SIGACTION
 
+/* Define to 1 if the system has the type `siginfo_t'. */
+#undef HAVE_SIGINFO_T
+
 /* Define to 1 if you have the <signal.h> header file. */
 #undef HAVE_SIGNAL_H
 
@@ -718,6 +724,9 @@
 /* Define to a substitute value for mmap()'s MAP_ANONYMOUS flag. */
 #undef MAP_ANONYMOUS
 
+/* Maximum size of siginfo_t across any supported target. */
+#undef MAX_SIGINFO_SIZE
+
 /* Define if you want to use new multi-fd /proc interface (replaces
    HAVE_MULTIPLE_PROC_FDS as well as other macros). */
 #undef NEW_PROC_API
--- a/gdb/configure
+++ b/gdb/configure
@@ -2339,116 +2339,116 @@ rm -f conftest.val
 
 } # ac_fn_c_compute_int
 
-# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES
-# ----------------------------------------------------
-# Tries to find if the field MEMBER exists in type AGGR, after including
-# INCLUDES, setting cache variable VAR accordingly.
-ac_fn_c_check_member ()
+# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
+# -------------------------------------------
+# Tests whether TYPE exists after having included INCLUDES, setting cache
+# variable VAR accordingly.
+ac_fn_c_check_type ()
 {
   as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5
-$as_echo_n "checking for $2.$3... " >&6; }
-if { as_var=$4; eval "test \"\${$as_var+set}\" = set"; }; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
   $as_echo_n "(cached) " >&6
 else
+  eval "$3=no"
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-$5
+$4
 int
 main ()
 {
-static $2 ac_aggr;
-if (ac_aggr.$3)
-return 0;
+if (sizeof ($2))
+	 return 0;
   ;
   return 0;
 }
 _ACEOF
 if ac_fn_c_try_compile "$LINENO"; then :
-  eval "$4=yes"
-else
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-$5
+$4
 int
 main ()
 {
-static $2 ac_aggr;
-if (sizeof ac_aggr.$3)
-return 0;
+if (sizeof (($2)))
+	    return 0;
   ;
   return 0;
 }
 _ACEOF
 if ac_fn_c_try_compile "$LINENO"; then :
-  eval "$4=yes"
+
 else
-  eval "$4=no"
+  eval "$3=yes"
 fi
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
-eval ac_res=\$$4
+eval ac_res=\$$3
 	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
 $as_echo "$ac_res" >&6; }
   eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
 
-} # ac_fn_c_check_member
+} # ac_fn_c_check_type
 
-# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
-# -------------------------------------------
-# Tests whether TYPE exists after having included INCLUDES, setting cache
-# variable VAR accordingly.
-ac_fn_c_check_type ()
+# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES
+# ----------------------------------------------------
+# Tries to find if the field MEMBER exists in type AGGR, after including
+# INCLUDES, setting cache variable VAR accordingly.
+ac_fn_c_check_member ()
 {
   as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-$as_echo_n "checking for $2... " >&6; }
-if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5
+$as_echo_n "checking for $2.$3... " >&6; }
+if { as_var=$4; eval "test \"\${$as_var+set}\" = set"; }; then :
   $as_echo_n "(cached) " >&6
 else
-  eval "$3=no"
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-$4
+$5
 int
 main ()
 {
-if (sizeof ($2))
-	 return 0;
+static $2 ac_aggr;
+if (ac_aggr.$3)
+return 0;
   ;
   return 0;
 }
 _ACEOF
 if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$4=yes"
+else
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-$4
+$5
 int
 main ()
 {
-if (sizeof (($2)))
-	    return 0;
+static $2 ac_aggr;
+if (sizeof ac_aggr.$3)
+return 0;
   ;
   return 0;
 }
 _ACEOF
 if ac_fn_c_try_compile "$LINENO"; then :
-
+  eval "$4=yes"
 else
-  eval "$3=yes"
+  eval "$4=no"
 fi
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
-eval ac_res=\$$3
+eval ac_res=\$$4
 	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
 $as_echo "$ac_res" >&6; }
   eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
 
-} # ac_fn_c_check_type
+} # ac_fn_c_check_member
 cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
@@ -7919,10 +7919,44 @@ fi
 
 . $srcdir/configure.host
 
+if test "${gdb_native}" = yes; then
+  ac_fn_c_check_type "$LINENO" "siginfo_t" "ac_cv_type_siginfo_t" "#include <signal.h>
+"
+if test "x$ac_cv_type_siginfo_t" = x""yes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_SIGINFO_T 1
+_ACEOF
+
+
+fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sizeof (siginfo_t)" >&5
+$as_echo_n "checking for sizeof (siginfo_t)... " >&6; }
+  if test "${gdb_cv_sizeof_siginfo_t+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "sizeof (siginfo_t)" "gdb_cv_sizeof_siginfo_t"        "#include <signal.h>"; then :
+
+else
+  gdb_cv_sizeof_siginfo_t=0
+fi
+
+fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdb_cv_sizeof_siginfo_t" >&5
+$as_echo "$gdb_cv_sizeof_siginfo_t" >&6; }
+fi
+
 # Accumulate some settings from configure.tgt over all enabled targets
 
 TARGET_OBS=
 all_targets=
+if test "${gdb_native}" = yes; then
+  MAX_SIGINFO_SIZE=$gdb_cv_sizeof_siginfo_t
+else
+  MAX_SIGINFO_SIZE=0
+fi
 
 for targ_alias in `echo $target_alias $enable_targets | sed 's/,/ /g'`
 do
@@ -7953,6 +7987,10 @@ fi
         esac
     done
 
+    if test $MAX_SIGINFO_SIZE -lt $gdb_target_siginfo_size; then
+      MAX_SIGINFO_SIZE=$gdb_target_siginfo_size
+    fi
+
     # Check whether this target needs 64-bit CORE_ADDR
     if test x${want64} = xfalse; then
       . ${srcdir}/../bfd/config.bfd
@@ -8025,6 +8063,17 @@ gdb_osabi=
 build_gdbserver=
 targ=$target; . ${srcdir}/configure.tgt
 
+if test x${all_targets} = xtrue; then
+  if test $MAX_SIGINFO_SIZE -lt $gdb_all_max_siginfo_size; then
+    MAX_SIGINFO_SIZE=$gdb_all_max_siginfo_size
+  fi
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define MAX_SIGINFO_SIZE $MAX_SIGINFO_SIZE
+_ACEOF
+
+
 # Fetch the default architecture and default target vector from BFD.
 targ=$target; . $srcdir/../bfd/config.bfd
 
@@ -14605,6 +14654,41 @@ $as_echo "#define HAVE_TKILL_SYSCALL 1" >>confdefs.h
 
 fi
 
+if test "x$ac_cv_header_sys_syscall_h" = "xyes"; then
+   { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether <sys/syscall.h> has __NR_rt_tgsigqueueinfo" >&5
+$as_echo_n "checking whether <sys/syscall.h> has __NR_rt_tgsigqueueinfo... " >&6; }
+if test "${gdb_cv_sys_syscall_h_has_rt_tgsigqueueinfo+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/syscall.h>
+int
+main ()
+{
+int i = __NR_rt_tgsigqueueinfo;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  gdb_cv_sys_syscall_h_has_rt_tgsigqueueinfo=yes
+else
+  gdb_cv_sys_syscall_h_has_rt_tgsigqueueinfo=no
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdb_cv_sys_syscall_h_has_rt_tgsigqueueinfo" >&5
+$as_echo "$gdb_cv_sys_syscall_h_has_rt_tgsigqueueinfo" >&6; }
+fi
+if test "x$gdb_cv_sys_syscall_h_has_rt_tgsigqueueinfo" = "xyes" && test "x$ac_cv_func_syscall" = "xyes"; then
+
+$as_echo "#define HAVE_RT_TGSIGQUEUEINFO_SYSCALL 1" >>confdefs.h
+
+fi
+
 ac_fn_c_check_decl "$LINENO" "ADDR_NO_RANDOMIZE" "ac_cv_have_decl_ADDR_NO_RANDOMIZE" "#include <sys/personality.h>
 "
 if test "x$ac_cv_have_decl_ADDR_NO_RANDOMIZE" = x""yes; then :
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -141,10 +141,24 @@ fi
 
 . $srcdir/configure.host
 
+if test "${gdb_native}" = yes; then
+  AC_CHECK_TYPES([siginfo_t],,, [[#include <signal.h>]])
+  AC_MSG_CHECKING([for sizeof (siginfo_t)])
+  AC_CACHE_VAL(gdb_cv_sizeof_siginfo_t,
+    [AC_COMPUTE_INT([gdb_cv_sizeof_siginfo_t], [sizeof (siginfo_t)],
+		    [[#include <signal.h>]], [gdb_cv_sizeof_siginfo_t=0])])
+  AC_MSG_RESULT($gdb_cv_sizeof_siginfo_t)
+fi
+
 # Accumulate some settings from configure.tgt over all enabled targets
 
 TARGET_OBS=
 all_targets=
+if test "${gdb_native}" = yes; then
+  MAX_SIGINFO_SIZE=$gdb_cv_sizeof_siginfo_t
+else
+  MAX_SIGINFO_SIZE=0
+fi
 
 for targ_alias in `echo $target_alias $enable_targets | sed 's/,/ /g'`
 do
@@ -174,6 +188,10 @@ do
         esac
     done
 
+    if test $MAX_SIGINFO_SIZE -lt $gdb_target_siginfo_size; then
+      MAX_SIGINFO_SIZE=$gdb_target_siginfo_size
+    fi
+
     # Check whether this target needs 64-bit CORE_ADDR
     if test x${want64} = xfalse; then
       . ${srcdir}/../bfd/config.bfd
@@ -213,6 +231,14 @@ gdb_osabi=
 build_gdbserver=
 targ=$target; . ${srcdir}/configure.tgt
 
+if test x${all_targets} = xtrue; then
+  if test $MAX_SIGINFO_SIZE -lt $gdb_all_max_siginfo_size; then
+    MAX_SIGINFO_SIZE=$gdb_all_max_siginfo_size
+  fi
+fi
+AC_DEFINE_UNQUOTED(MAX_SIGINFO_SIZE, $MAX_SIGINFO_SIZE,
+		   [Maximum size of siginfo_t across any supported target.])
+
 # Fetch the default architecture and default target vector from BFD.
 targ=$target; . $srcdir/../bfd/config.bfd
 
@@ -1642,6 +1668,23 @@ if test "x$gdb_cv_sys_syscall_h_has_tkill" = "xyes" && test "x$ac_cv_func_syscal
   AC_DEFINE(HAVE_TKILL_SYSCALL, 1, [Define if you support the tkill syscall.])
 fi
 
+dnl See if we have a sys/syscall header file that has __NR_rt_tgsigqueueinfo.
+if test "x$ac_cv_header_sys_syscall_h" = "xyes"; then
+   AC_CACHE_CHECK([whether <sys/syscall.h> has __NR_rt_tgsigqueueinfo],
+                  gdb_cv_sys_syscall_h_has_rt_tgsigqueueinfo,
+     AC_TRY_COMPILE(
+       [#include <sys/syscall.h>],
+       [int i = __NR_rt_tgsigqueueinfo;],
+       gdb_cv_sys_syscall_h_has_rt_tgsigqueueinfo=yes,
+       gdb_cv_sys_syscall_h_has_rt_tgsigqueueinfo=no
+     )
+   )
+fi
+dnl See if we can issue rt_tgsigqueueinfo syscall.
+if test "x$gdb_cv_sys_syscall_h_has_rt_tgsigqueueinfo" = "xyes" && test "x$ac_cv_func_syscall" = "xyes"; then
+  AC_DEFINE(HAVE_RT_TGSIGQUEUEINFO_SYSCALL, 1, [Define if you support the rt_tgsigqueueinfo syscall.])
+fi
+
 dnl Check if we can disable the virtual address space randomization.
 dnl The functionality of setarch -R.
 AC_CHECK_DECLS([ADDR_NO_RANDOMIZE],,, [#include <sys/personality.h>])
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -30,6 +30,10 @@ esac
 
 # map target info into gdb names.
 
+gdb_target_siginfo_size=0
+# Maximum size of $gdb_target_siginfo_size set by any of the targets.
+gdb_all_max_siginfo_size=128
+
 case "${targ}" in
 
 alpha*-*-osf*)
@@ -79,6 +83,7 @@ arm*-*-linux*)
 	# Target: ARM based machine running GNU/Linux
 	gdb_target_obs="arm-tdep.o arm-linux-tdep.o glibc-tdep.o \
 			solib.o solib-svr4.o symfile-mem.o corelow.o linux-tdep.o"
+	gdb_target_siginfo_size=128
 	build_gdbserver=yes
 	;;
 arm*-*-netbsd* | arm*-*-knetbsd*-gnu)
@@ -206,9 +211,11 @@ i[34567]86-*-linux*)
 	gdb_target_obs="i386-tdep.o i386-linux-tdep.o glibc-tdep.o i387-tdep.o \
 			solib.o solib-svr4.o symfile-mem.o corelow.o \
 			linux-tdep.o linux-record.o"
+	gdb_target_siginfo_size=128
 	if test "x$enable_64_bit_bfd" = "xyes"; then
 	    # Target: GNU/Linux x86-64
 	    gdb_target_obs="amd64-tdep.o amd64-linux-tdep.o ${gdb_target_obs}"
+	    # gdb_target_siginfo_size has the same size.
 	fi
 	build_gdbserver=yes
 	;;
@@ -579,6 +586,7 @@ x86_64-*-linux*)
 			i387-tdep.o i386-linux-tdep.o glibc-tdep.o \
 			solib.o solib-svr4.o corelow.o symfile-mem.o linux-tdep.o \
 			linux-record.o"
+	gdb_target_siginfo_size=128
 	build_gdbserver=yes
 	;;
 x86_64-*-freebsd* | x86_64-*-kfreebsd*-gnu)
@@ -619,6 +627,11 @@ xtensa*)
 
 esac
 
+if [ $gdb_target_siginfo_size -gt $gdb_all_max_siginfo_size ]; then
+  echo "*** Configuration $targ exceeds gdb_all_max_siginfo_size." >&2
+  exit 1
+fi
+
 # map target onto default OS ABI
 
 case "${targ}" in
--- a/gdb/i386-linux-nat.c
+++ b/gdb/i386-linux-nat.c
@@ -26,6 +26,7 @@
 #include "regset.h"
 #include "target.h"
 #include "linux-nat.h"
+#include "inf-ptrace.h"
 
 #include "gdb_assert.h"
 #include "gdb_string.h"
@@ -83,6 +84,10 @@
 #define PTRACE_SETREGSET	0x4205
 #endif
 
+#ifndef PTRACE_SETSIGINFO
+# define PTRACE_SETSIGINFO	0x4203
+#endif
+
 /* Does the current host support PTRACE_GETREGSET?  */
 static int have_ptrace_getregset = -1;
 
@@ -891,6 +896,22 @@ i386_linux_resume (struct target_ops *ops,
 	}
     }
 
+  if (target_signal_siginfo_p (&signal))
+    {
+      struct gdbarch *gdbarch;
+      siginfo_t host_siginfo;
+      /* INF_SIGINFO should be `const *'.  */
+      gdb_byte *inf_siginfo;
+
+      gdbarch = target_thread_architecture (ptid);
+      inf_siginfo = target_signal_siginfo_get (&signal, gdbarch);
+      siginfo_fixup (&host_siginfo, inf_siginfo, 1, gdbarch);
+
+      if (ptrace (PTRACE_SETSIGINFO, pid, (PTRACE_TYPE_ARG3) 0, &host_siginfo)
+	  != 0)
+	perror_with_name (("ptrace (PTRACE_SETSIGINFO)"));
+    }
+
   if (ptrace (request, pid, 0, target_signal_to_host (signal)) == -1)
     perror_with_name (("ptrace"));
 }
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -39,6 +39,11 @@
 
 
 
+#ifndef PTRACE_GETSIGINFO
+# define PTRACE_GETSIGINFO	0x4202
+# define PTRACE_SETSIGINFO	0x4203
+#endif
+
 #ifdef PT_GET_PROCESS_STATE
 
 static int
@@ -375,6 +380,24 @@ inf_ptrace_resume (struct target_ops *ops,
       request = PT_STEP;
     }
 
+#ifdef HAVE_SIGINFO_T
+  if (target_signal_siginfo_p (&signal))
+    {
+      struct gdbarch *gdbarch;
+      siginfo_t host_siginfo;
+      /* INF_SIGINFO should be `const *'.  */
+      gdb_byte *inf_siginfo;
+
+      gdbarch = target_thread_architecture (ptid);
+      inf_siginfo = target_signal_siginfo_get (&signal, gdbarch);
+      siginfo_fixup (&host_siginfo, inf_siginfo, 1, gdbarch);
+
+      if (ptrace (PTRACE_SETSIGINFO, pid, (PTRACE_TYPE_ARG3) 0, &host_siginfo)
+	  != 0)
+	perror_with_name (("ptrace (PTRACE_SETSIGINFO)"));
+    }
+#endif /* HAVE_SIGINFO_T */
+
   /* An address of (PTRACE_TYPE_ARG3)1 tells ptrace to continue from
      where it was.  If GDB wanted it to start some other way, we have
      already written a new program counter value to the child.  */
@@ -465,6 +488,28 @@ inf_ptrace_wait (struct target_ops *ops,
 #endif
 
   store_waitstatus (ourstatus, status);
+
+#ifdef HAVE_SIGINFO_T
+  if (TARGET_WAITKIND_USES_SIG (ourstatus->kind))
+    {
+      struct gdbarch *pid_gdbarch;
+      siginfo_t siginfo;
+
+      /* We could also use waitid.  */
+
+      pid_gdbarch = target_thread_architecture (pid_to_ptid (pid));
+      if (ptrace (PTRACE_GETSIGINFO, pid, (PTRACE_TYPE_ARG3) 0, &siginfo)
+	  == 0)
+	{
+	  gdb_byte inf_siginfo[MAX_SIGINFO_SIZE];
+
+	  siginfo_fixup (&siginfo, inf_siginfo, 0, pid_gdbarch);
+	  target_signal_siginfo_set (&ourstatus->value.sig, pid_gdbarch,
+				     inf_siginfo);
+	}
+    }
+#endif /* HAVE_SIGINFO_T */
+
   return pid_to_ptid (pid);
 }
 
@@ -797,10 +842,13 @@ inf_ptrace_trad_target (CORE_ADDR (*register_u_offset)
   return t;
 }
 
+#ifdef HAVE_SIGINFO_T
+
 /* The method to call, if any, when the siginfo object needs to be
    converted between the layout returned by ptrace, and the layout in
    the architecture of the inferior.  */
-static int (*inf_ptrace_siginfo_fixup) (struct siginfo *, gdb_byte *, int);
+static int (*inf_ptrace_siginfo_fixup) (struct siginfo *, gdb_byte *, int,
+					struct gdbarch *);
 
 /* Register a method that converts a siginfo object between the layout
    that ptrace returns, and the layout in the architecture of the
@@ -808,22 +856,29 @@ static int (*inf_ptrace_siginfo_fixup) (struct siginfo *, gdb_byte *, int);
 void
 inf_ptrace_set_siginfo_fixup (struct target_ops *t,
 			      int (*siginfo_fixup) (struct siginfo *,
-						    gdb_byte *, int))
+						    gdb_byte *, int,
+						    struct gdbarch *))
 {
   /* Save the pointer.  */
   inf_ptrace_siginfo_fixup = siginfo_fixup;
 }
 
 /* Convert a native/host siginfo object, into/from the siginfo in the
-   layout of the inferiors' architecture.  */
+   layout of the inferiors' architecture.
+   DIRECTION 1 transfers SIGINFO <- INF_SIGINFO.
+   DIRECTION 0 transfers SIGINFO -> INF_SIGINFO.
+   INF_SIGINFO must have size of at least MAX_SIGINFO_SIZE.  */
 
 void
-siginfo_fixup (struct siginfo *siginfo, gdb_byte *inf_siginfo, int direction)
+siginfo_fixup (struct siginfo *siginfo, gdb_byte *inf_siginfo, int direction,
+	       struct gdbarch *gdbarch)
 {
   int done = 0;
 
+  gdb_assert (MAX_SIGINFO_SIZE >= sizeof (struct siginfo));
+
   if (inf_ptrace_siginfo_fixup != NULL)
-    done = inf_ptrace_siginfo_fixup (siginfo, inf_siginfo, direction);
+    done = inf_ptrace_siginfo_fixup (siginfo, inf_siginfo, direction, gdbarch);
 
   /* If there was no callback, or the callback didn't do anything,
      then just do a straight memcpy.  */
@@ -835,3 +890,5 @@ siginfo_fixup (struct siginfo *siginfo, gdb_byte *inf_siginfo, int direction)
 	memcpy (inf_siginfo, siginfo, sizeof (struct siginfo));
     }
 }
+
+#endif /* HAVE_SIGINFO_T */
--- a/gdb/inf-ptrace.h
+++ b/gdb/inf-ptrace.h
@@ -34,14 +34,19 @@ extern struct target_ops *
   inf_ptrace_trad_target (CORE_ADDR (*register_u_offset)
 					(struct gdbarch *, int, int));
 
+#ifdef HAVE_SIGINFO_T
+
 struct siginfo;
 extern void siginfo_fixup (struct siginfo *siginfo, gdb_byte *inf_siginfo,
-			   int direction);
+			   int direction, struct gdbarch *gdbarch);
 
 extern
   void inf_ptrace_set_siginfo_fixup (struct target_ops *t,
 				     int (*siginfo_fixup) (struct siginfo *,
 							   gdb_byte *,
-							   int));
+							   int,
+							   struct gdbarch *));
+
+#endif /* HAVE_SIGINFO_T */
 
 #endif
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -24,7 +24,7 @@
 #include "gdb_string.h"
 #include "gdb_wait.h"
 #include "gdb_assert.h"
-#ifdef HAVE_TKILL_SYSCALL
+#if defined HAVE_TKILL_SYSCALL || defined HAVE_RT_TGSIGQUEUEINFO_SYSCALL
 #include <unistd.h>
 #include <sys/syscall.h>
 #endif
@@ -267,6 +267,7 @@ struct simple_pid_list
 {
   int pid;
   int status;
+  siginfo_t siginfo;
   struct simple_pid_list *next;
 };
 struct simple_pid_list *stopped_pids;
@@ -358,18 +359,21 @@ static struct lwp_info *find_lwp_pid (ptid_t ptid);
 /* Trivial list manipulation functions to keep track of a list of
    new stopped processes.  */
 static void
-add_to_pid_list (struct simple_pid_list **listp, int pid, int status)
+add_to_pid_list (struct simple_pid_list **listp, int pid, int status,
+		 const siginfo_t *siginfop)
 {
   struct simple_pid_list *new_pid = xmalloc (sizeof (struct simple_pid_list));
 
   new_pid->pid = pid;
   new_pid->status = status;
+  new_pid->siginfo = *siginfop;
   new_pid->next = *listp;
   *listp = new_pid;
 }
 
 static int
-pull_pid_from_list (struct simple_pid_list **listp, int pid, int *statusp)
+pull_pid_from_list (struct simple_pid_list **listp, int pid, int *statusp,
+		    siginfo_t *siginfop)
 {
   struct simple_pid_list **p;
 
@@ -379,6 +383,8 @@ pull_pid_from_list (struct simple_pid_list **listp, int pid, int *statusp)
 	struct simple_pid_list *next = (*p)->next;
 
 	*statusp = (*p)->status;
+	if (siginfop)
+	  *siginfop = (*p)->siginfo;
 	xfree (*p);
 	*p = next;
 	return 1;
@@ -387,9 +393,9 @@ pull_pid_from_list (struct simple_pid_list **listp, int pid, int *statusp)
 }
 
 static void
-linux_record_stopped_pid (int pid, int status)
+linux_record_stopped_pid (int pid, int status, const siginfo_t *siginfop)
 {
-  add_to_pid_list (&stopped_pids, pid, status);
+  add_to_pid_list (&stopped_pids, pid, status, siginfop);
 }
 
 
@@ -404,10 +410,13 @@ linux_tracefork_child (void)
   _exit (0);
 }
 
-/* Wrapper function for waitpid which handles EINTR.  */
+/* Wrapper function for waitpid which handles EINTR.  If SIGINFOP is not NULL
+   it may be filled-in with extended information about the returned signal if
+   it is available.  It will be cleared otherwise.  If SIGINFOP is not NULL
+   then STATUSP must be also not NULL.  */
 
 static int
-my_waitpid (int pid, int *statusp, int flags)
+my_waitpid (int pid, int *statusp, struct siginfo *siginfop, int flags)
 {
   int ret;
 
@@ -417,6 +426,18 @@ my_waitpid (int pid, int *statusp, int flags)
     }
   while (ret == -1 && errno == EINTR);
 
+  if (siginfop != NULL)
+    {
+      gdb_assert (statusp != NULL);
+
+      /* We could also use waitid.  */
+
+      if (! (ret > 0 && (WIFSIGNALED (*statusp) || WIFSTOPPED (*statusp)))
+	  || (ptrace (PTRACE_GETSIGINFO, ret, (PTRACE_TYPE_ARG3) 0, siginfop)
+	      == -1))
+	siginfop->si_signo = 0;
+    }
+
   return ret;
 }
 
@@ -460,7 +481,7 @@ linux_test_for_tracefork (int original_pid)
   if (child_pid == 0)
     linux_tracefork_child ();
 
-  ret = my_waitpid (child_pid, &status, 0);
+  ret = my_waitpid (child_pid, &status, NULL, 0);
   if (ret == -1)
     perror_with_name (("waitpid"));
   else if (ret != child_pid)
@@ -479,7 +500,7 @@ linux_test_for_tracefork (int original_pid)
 	  return;
 	}
 
-      ret = my_waitpid (child_pid, &status, 0);
+      ret = my_waitpid (child_pid, &status, NULL, 0);
       if (ret != child_pid)
 	warning (_("linux_test_for_tracefork: failed to wait for killed child"));
       else if (!WIFSIGNALED (status))
@@ -499,7 +520,7 @@ linux_test_for_tracefork (int original_pid)
   if (ret != 0)
     warning (_("linux_test_for_tracefork: failed to resume child"));
 
-  ret = my_waitpid (child_pid, &status, 0);
+  ret = my_waitpid (child_pid, &status, NULL, 0);
 
   if (ret == child_pid && WIFSTOPPED (status)
       && status >> 16 == PTRACE_EVENT_FORK)
@@ -511,11 +532,11 @@ linux_test_for_tracefork (int original_pid)
 	  int second_status;
 
 	  linux_supports_tracefork_flag = 1;
-	  my_waitpid (second_pid, &second_status, 0);
+	  my_waitpid (second_pid, &second_status, NULL, 0);
 	  ret = ptrace (PTRACE_KILL, second_pid, 0, 0);
 	  if (ret != 0)
 	    warning (_("linux_test_for_tracefork: failed to kill second child"));
-	  my_waitpid (second_pid, &status, 0);
+	  my_waitpid (second_pid, &status, NULL, 0);
 	}
     }
   else
@@ -525,7 +546,7 @@ linux_test_for_tracefork (int original_pid)
   ret = ptrace (PTRACE_KILL, child_pid, 0, 0);
   if (ret != 0)
     warning (_("linux_test_for_tracefork: failed to kill child"));
-  my_waitpid (child_pid, &status, 0);
+  my_waitpid (child_pid, &status, NULL, 0);
 
   restore_child_signals_mask (&prev_mask);
 }
@@ -845,6 +866,7 @@ holding the child stopped.  Try \"set detach-on-fork\" or \
 		 will notice a pending event, and bypasses actually
 		 resuming the inferior.  */
 	      lp->status = 0;
+	      lp->siginfo.si_signo = 0;
 	      lp->waitstatus.kind = TARGET_WAITKIND_VFORK_DONE;
 	      lp->stopped = 0;
 	      lp->resumed = 1;
@@ -1344,7 +1366,7 @@ pid_is_stopped (pid_t pid)
 
 static int
 linux_nat_post_attach_wait (ptid_t ptid, int first, int *cloned,
-			    int *signalled)
+			    int *signalled, struct siginfo *siginfop)
 {
   pid_t new_pid, pid = GET_LWP (ptid);
   int status;
@@ -1378,14 +1400,14 @@ linux_nat_post_attach_wait (ptid_t ptid, int first, int *cloned,
   /* Make sure the initial process is stopped.  The user-level threads
      layer might want to poke around in the inferior, and that won't
      work if things haven't stabilized yet.  */
-  new_pid = my_waitpid (pid, &status, 0);
+  new_pid = my_waitpid (pid, &status, siginfop, 0);
   if (new_pid == -1 && errno == ECHILD)
     {
       if (first)
 	warning (_("%s is a cloned process"), target_pid_to_str (ptid));
 
       /* Try again with __WCLONE to check cloned processes.  */
-      new_pid = my_waitpid (pid, &status, __WCLONE);
+      new_pid = my_waitpid (pid, &status, siginfop, __WCLONE);
       *cloned = 1;
     }
 
@@ -1420,6 +1442,7 @@ lin_lwp_attach_lwp (ptid_t ptid)
 {
   struct lwp_info *lp;
   sigset_t prev_mask;
+  siginfo_t siginfo;
 
   gdb_assert (is_lwp (ptid));
 
@@ -1455,7 +1478,8 @@ lin_lwp_attach_lwp (ptid_t ptid)
 			    "LLAL: PTRACE_ATTACH %s, 0, 0 (OK)\n",
 			    target_pid_to_str (ptid));
 
-      status = linux_nat_post_attach_wait (ptid, 0, &cloned, &signalled);
+      status = linux_nat_post_attach_wait (ptid, 0, &cloned, &signalled,
+					   &siginfo);
       if (!WIFSTOPPED (status))
 	return -1;
 
@@ -1467,6 +1491,7 @@ lin_lwp_attach_lwp (ptid_t ptid)
 	{
 	  lp->resumed = 1;
 	  lp->status = status;
+	  lp->siginfo = siginfo;
 	}
 
       target_post_attach (GET_LWP (lp->ptid));
@@ -1544,6 +1569,7 @@ linux_nat_attach (struct target_ops *ops, char *args, int from_tty)
 {
   struct lwp_info *lp;
   int status;
+  siginfo_t siginfo;
   ptid_t ptid;
 
   linux_ops->to_attach (ops, args, from_tty);
@@ -1557,7 +1583,7 @@ linux_nat_attach (struct target_ops *ops, char *args, int from_tty)
   lp = add_lwp (ptid);
 
   status = linux_nat_post_attach_wait (lp->ptid, 1, &lp->cloned,
-				       &lp->signalled);
+				       &lp->signalled, &siginfo);
   if (!WIFSTOPPED (status))
     {
       if (WIFEXITED (status))
@@ -1601,6 +1627,7 @@ linux_nat_attach (struct target_ops *ops, char *args, int from_tty)
 			(long) GET_PID (lp->ptid), status_to_str (status));
 
   lp->status = status;
+  lp->siginfo = siginfo;
 
   if (target_can_async_p ())
     target_async (inferior_event_handler, 0);
@@ -1636,7 +1663,10 @@ get_pending_status (struct lwp_info *lp, int *status)
   if (lp->waitstatus.kind != TARGET_WAITKIND_IGNORE)
     signo = TARGET_SIGNAL_0; /* a pending ptrace event, not a real signal.  */
   else if (lp->status)
-    signo = target_signal_from_host (WSTOPSIG (lp->status));
+    {
+      signo = target_signal_from_host (WSTOPSIG (lp->status));
+      /* SIGNO.siginfo is not used below.  */
+    }
   else if (non_stop && !is_executing (lp->ptid))
     {
       struct thread_info *tp = find_thread_ptid (lp->ptid);
@@ -1827,7 +1857,7 @@ resume_callback (struct lwp_info *lp, void *data)
 			    target_pid_to_str (lp->ptid));
       lp->stopped = 0;
       lp->step = 0;
-      memset (&lp->siginfo, 0, sizeof (lp->siginfo));
+      lp->siginfo.si_signo = 0;
       lp->stopped_by_watchpoint = 0;
     }
   else if (lp->stopped && debug_linux_nat)
@@ -1906,6 +1936,15 @@ linux_nat_resume (struct target_ops *ops,
       inf = find_inferior_pid (ptid_get_pid (lp->ptid));
       gdb_assert (inf);
       saved_signo = target_signal_from_host (WSTOPSIG (lp->status));
+      if (lp->siginfo.si_signo != 0)
+	{
+	  struct gdbarch *gdbarch;
+	  gdb_byte inf_siginfo[MAX_SIGINFO_SIZE];
+
+	  gdbarch = target_thread_architecture (lp->ptid);
+	  siginfo_fixup (&lp->siginfo, inf_siginfo, 0, gdbarch);
+	  target_signal_siginfo_set (&saved_signo, gdbarch, inf_siginfo);
+	}
 
       /* Defer to common code if we're gaining control of the
 	 inferior.  */
@@ -1924,6 +1963,7 @@ linux_nat_resume (struct target_ops *ops,
 	  gdb_assert (TARGET_SIGNAL_EQ (signo, TARGET_SIGNAL_0));
 	  signo = saved_signo;
 	  lp->status = 0;
+	  lp->siginfo.si_signo = 0;
 	}
     }
 
@@ -1959,7 +1999,7 @@ linux_nat_resume (struct target_ops *ops,
   ptid = pid_to_ptid (GET_LWP (lp->ptid));
 
   linux_ops->to_resume (linux_ops, ptid, step, signo);
-  memset (&lp->siginfo, 0, sizeof (lp->siginfo));
+  lp->siginfo.si_signo = 0;
   lp->stopped_by_watchpoint = 0;
 
   if (debug_linux_nat)
@@ -1995,6 +2035,10 @@ kill_lwp (int lwpid, int signo)
 	if (errno != ENOSYS)
 	  return ret;
 	tkill_failed = 1;
+	if (debug_linux_nat)
+	  fprintf_unfiltered (gdb_stdlog,
+			      "KL: syscall tkill is not supported, "
+			      "giving up\n");
       }
   }
 #endif
@@ -2002,6 +2046,57 @@ kill_lwp (int lwpid, int signo)
   return kill (lwpid, signo);
 }
 
+/* Send an extended signal information to an LWP.  */
+
+static void
+kill_lwp_siginfo (struct lwp_info *lp, int signo, const siginfo_t *siginfop)
+{
+#ifdef HAVE_RT_TGSIGQUEUEINFO_SYSCALL
+  {
+    static int rt_tgsigqueueinfo_failed;
+
+    if (! rt_tgsigqueueinfo_failed)
+      {
+	int ret;
+
+	errno = 0;
+	ret = syscall (__NR_rt_tgsigqueueinfo, GET_PID (lp->ptid),
+		       GET_LWP (lp->ptid), signo, siginfop);
+	if (ret == 0)
+	  return;
+	if (errno == ENOSYS)
+	  {
+	    rt_tgsigqueueinfo_failed = 1;
+	    if (debug_linux_nat)
+	      fprintf_unfiltered (gdb_stdlog,
+				  "KLS: syscall rt_tgsigqueueinfo is not "
+				  "supported, giving up\n");
+	  }
+	else
+	  {
+	    if (debug_linux_nat)
+	      fprintf_unfiltered (gdb_stdlog,
+				  "KLS: rt_tgsigqueueinfo failed: %s\n",
+				  safe_strerror (errno));
+	  }
+
+	/* We may also fail with EPERM when tkill still can be used.  It will
+	   drop some associated siginfo_t information, though.  As this
+	   siginfo_t information is commonly ignored by the inferior so we
+	   should not stop.  */
+      }
+  }
+#else /* ! HAVE_RT_TGSIGQUEUEINFO_SYSCALL */
+  if (debug_linux_nat)
+    fprintf_unfiltered (gdb_stdlog,
+			"KLS: No rt_tgsigqueueinfo support compiled in\n");
+#endif /* ! HAVE_RT_TGSIGQUEUEINFO_SYSCALL */
+
+  /* SIGINFOP has to be dropped - give a warning?  */
+
+  kill_lwp (GET_LWP (lp->ptid), signo);
+}
+
 /* Handle a GNU/Linux syscall trap wait response.  If we see a syscall
    event, check if the core is interested in it: if not, ignore the
    event, and keep waiting; otherwise, we need to toggle the LWP's
@@ -2137,11 +2232,17 @@ linux_handle_syscall_trap (struct lwp_info *lp, int stopping)
 
 static int
 linux_handle_extended_wait (struct lwp_info *lp, int status,
-			    int stopping)
+			    const siginfo_t *siginfop, int stopping)
 {
   int pid = GET_LWP (lp->ptid);
   struct target_waitstatus *ourstatus = &lp->waitstatus;
   int event = status >> 16;
+  siginfo_t siginfo;
+
+  if (siginfop == NULL)
+    siginfo.si_signo = 0;
+  else
+    siginfo = *siginfop;
 
   if (event == PTRACE_EVENT_FORK || event == PTRACE_EVENT_VFORK
       || event == PTRACE_EVENT_CLONE)
@@ -2152,11 +2253,11 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
       ptrace (PTRACE_GETEVENTMSG, pid, 0, &new_pid);
 
       /* If we haven't already seen the new PID stop, wait for it now.  */
-      if (! pull_pid_from_list (&stopped_pids, new_pid, &status))
+      if (! pull_pid_from_list (&stopped_pids, new_pid, &status, &siginfo))
 	{
 	  /* The new child has a pending SIGSTOP.  We can't affect it until it
 	     hits the SIGSTOP, but we're already attached.  */
-	  ret = my_waitpid (new_pid, &status,
+	  ret = my_waitpid (new_pid, &status, &siginfo,
 			    (event == PTRACE_EVENT_CLONE) ? __WCLONE : 0);
 	  if (ret == -1)
 	    perror_with_name (_("waiting for new child"));
@@ -2225,7 +2326,10 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
 	      new_lp->signalled = 1;
 	    }
 	  else
-	    status = 0;
+	    {
+	      status = 0;
+	      siginfo.si_signo = 0;
+	    }
 
 	  if (non_stop)
 	    {
@@ -2264,9 +2368,22 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
 	      new_lp->stopped = 0;
 	      new_lp->resumed = 1;
 
-	      signo = (status
-		       ? target_signal_from_host (WSTOPSIG (status))
-		       : TARGET_SIGNAL_0);
+	      if (status == 0)
+		signo = TARGET_SIGNAL_0;
+	      else
+		{
+		  signo = target_signal_from_host (WSTOPSIG (status));
+		  if (siginfo.si_signo != 0)
+		    {
+		      struct gdbarch *gdbarch;
+		      gdb_byte inf_siginfo[MAX_SIGINFO_SIZE];
+
+		      gdbarch = target_thread_architecture (new_lp->ptid);
+		      siginfo_fixup (&siginfo, inf_siginfo, 0, gdbarch);
+		      target_signal_siginfo_set (&signo, gdbarch,
+						 inf_siginfo);
+		    }
+		}
 
 	      linux_ops->to_resume (linux_ops, pid_to_ptid (new_pid),
 				    0, signo);
@@ -2342,22 +2459,28 @@ LHEW: Got PTRACE_EVENT_VFORK_DONE from LWP %ld: resuming\n",
 }
 
 /* Wait for LP to stop.  Returns the wait status, or 0 if the LWP has
-   exited.  */
+   exited.  If SIGINFOP is not NULL it may be filled-in with extended
+   information about the returned signal if it is available.  It will be
+   cleared otherwise.  */
 
 static int
-wait_lwp (struct lwp_info *lp)
+wait_lwp (struct lwp_info *lp, struct siginfo *siginfop)
 {
   pid_t pid;
   int status;
   int thread_dead = 0;
+  siginfo_t siginfo_local;
 
   gdb_assert (!lp->stopped);
   gdb_assert (lp->status == 0);
+  
+  if (siginfop == NULL)
+    siginfop = &siginfo_local;
 
-  pid = my_waitpid (GET_LWP (lp->ptid), &status, 0);
+  pid = my_waitpid (GET_LWP (lp->ptid), &status, siginfop, 0);
   if (pid == -1 && errno == ECHILD)
     {
-      pid = my_waitpid (GET_LWP (lp->ptid), &status, __WCLONE);
+      pid = my_waitpid (GET_LWP (lp->ptid), &status, siginfop, __WCLONE);
       if (pid == -1 && errno == ECHILD)
 	{
 	  /* The thread has previously exited.  We need to delete it
@@ -2397,6 +2520,7 @@ wait_lwp (struct lwp_info *lp)
   if (thread_dead)
     {
       exit_lwp (lp);
+      siginfop->si_signo = 0;
       return 0;
     }
 
@@ -2410,8 +2534,9 @@ wait_lwp (struct lwp_info *lp)
 	 on handling the event like a regular SIGTRAP from here
 	 on.  */
       status = W_STOPCODE (SIGTRAP);
+      siginfop->si_signo = 0;
       if (linux_handle_syscall_trap (lp, 1))
-	return wait_lwp (lp);
+	return wait_lwp (lp, siginfop);
     }
 
   /* Handle GNU/Linux's extended waitstatus for trace events.  */
@@ -2421,29 +2546,13 @@ wait_lwp (struct lwp_info *lp)
 	fprintf_unfiltered (gdb_stdlog,
 			    "WL: Handling extended status 0x%06x\n",
 			    status);
-      if (linux_handle_extended_wait (lp, status, 1))
-	return wait_lwp (lp);
+      if (linux_handle_extended_wait (lp, status, siginfop, 1))
+	return wait_lwp (lp, siginfop);
     }
 
   return status;
 }
 
-/* Save the most recent siginfo for LP.  This is currently only called
-   for SIGTRAP; some ports use the si_addr field for
-   target_stopped_data_address.  In the future, it may also be used to
-   restore the siginfo of requeued signals.  */
-
-static void
-save_siginfo (struct lwp_info *lp)
-{
-  errno = 0;
-  ptrace (PTRACE_GETSIGINFO, GET_LWP (lp->ptid),
-	  (PTRACE_TYPE_ARG3) 0, &lp->siginfo);
-
-  if (errno != 0)
-    memset (&lp->siginfo, 0, sizeof (lp->siginfo));
-}
-
 /* Send a SIGSTOP to LP.  */
 
 static int
@@ -2501,7 +2610,10 @@ set_ignore_sigint (struct lwp_info *lp, void *data)
      flag to consume the next one.  */
   if (lp->stopped && lp->status != 0 && WIFSTOPPED (lp->status)
       && WSTOPSIG (lp->status) == SIGINT)
-    lp->status = 0;
+    {
+      lp->status = 0;
+      lp->siginfo.si_signo = 0;
+    }
   else
     lp->ignore_sigint = 1;
 
@@ -2650,8 +2762,9 @@ stop_wait_callback (struct lwp_info *lp, void *data)
   if (!lp->stopped)
     {
       int status;
+      siginfo_t siginfo;
 
-      status = wait_lwp (lp);
+      status = wait_lwp (lp, &siginfo);
       if (status == 0)
 	return 0;
 
@@ -2690,9 +2803,7 @@ stop_wait_callback (struct lwp_info *lp, void *data)
 	         user will delete or disable the breakpoint, but the
 	         thread will have already tripped on it.  */
 
-	      /* Save the trap's siginfo in case we need it later.  */
-	      save_siginfo (lp);
-
+	      lp->siginfo = siginfo;
 	      save_sigtrap (lp);
 
 	      /* Now resume this LWP and get the SIGSTOP event. */
@@ -2723,11 +2834,12 @@ stop_wait_callback (struct lwp_info *lp, void *data)
 					"SWC: kill %s, %s\n",
 					target_pid_to_str (lp->ptid),
 					status_to_str ((int) status));
-		  kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (lp->status));
+		  kill_lwp_siginfo (lp, WSTOPSIG (lp->status), &lp->siginfo);
 		}
 
 	      /* Save the sigtrap event. */
 	      lp->status = status;
+	      lp->siginfo = siginfo;
 	      return 0;
 	    }
 	  else
@@ -2767,10 +2879,13 @@ stop_wait_callback (struct lwp_info *lp, void *data)
 					  target_pid_to_str (lp->ptid),
 					  status_to_str ((int) status));
 		    }
-		  kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (status));
+		  kill_lwp_siginfo (lp, WSTOPSIG (status), &siginfo);
 		}
 	      else
-		lp->status = status;
+		{
+		  lp->status = status;
+		  lp->siginfo = siginfo;
+		}
 	      return 0;
 	    }
 	}
@@ -2919,8 +3034,11 @@ cancel_breakpoints_callback (struct lwp_info *lp, void *data)
 
   if (linux_nat_lp_status_is_event (lp)
       && cancel_breakpoint (lp))
-    /* Throw away the SIGTRAP.  */
-    lp->status = 0;
+    {
+      /* Throw away the SIGTRAP.  */
+      lp->status = 0;
+      lp->siginfo.si_signo = 0;
+    }
 
   return 0;
 }
@@ -2928,7 +3046,8 @@ cancel_breakpoints_callback (struct lwp_info *lp, void *data)
 /* Select one LWP out of those that have events pending.  */
 
 static void
-select_event_lwp (ptid_t filter, struct lwp_info **orig_lp, int *status)
+select_event_lwp (ptid_t filter, struct lwp_info **orig_lp, int *status,
+		  siginfo_t *siginfop)
 {
   int num_events = 0;
   int random_selector;
@@ -2936,6 +3055,7 @@ select_event_lwp (ptid_t filter, struct lwp_info **orig_lp, int *status)
 
   /* Record the wait status for the original LWP.  */
   (*orig_lp)->status = *status;
+  (*orig_lp)->siginfo = *siginfop;
 
   /* Give preference to any LWP that is being single-stepped.  */
   event_lp = iterate_over_lwps (filter,
@@ -2974,10 +3094,12 @@ select_event_lwp (ptid_t filter, struct lwp_info **orig_lp, int *status)
       /* Switch the event LWP.  */
       *orig_lp = event_lp;
       *status = event_lp->status;
+      *siginfop = event_lp->siginfo;
     }
 
   /* Flush the wait status for the event LWP.  */
   (*orig_lp)->status = 0;
+  (*orig_lp)->siginfo.si_signo = 0;
 }
 
 /* Return non-zero if LP has been resumed.  */
@@ -3013,9 +3135,16 @@ stop_and_resume_callback (struct lwp_info *lp, void *data)
 /* Check if we should go on and pass this event to common code.
    Return the affected lwp if we are, or NULL otherwise.  */
 static struct lwp_info *
-linux_nat_filter_event (int lwpid, int status, int options)
+linux_nat_filter_event (int lwpid, int status, const siginfo_t *siginfop,
+			int options)
 {
   struct lwp_info *lp;
+  siginfo_t siginfo;
+
+  if (siginfop)
+    siginfo = *siginfop;
+  else
+    siginfo.si_signo = 0;
 
   lp = find_lwp_pid (pid_to_ptid (lwpid));
 
@@ -3029,7 +3158,7 @@ linux_nat_filter_event (int lwpid, int status, int options)
      from waitpid before or after the event is.  */
   if (WIFSTOPPED (status) && !lp)
     {
-      linux_record_stopped_pid (lwpid, status);
+      linux_record_stopped_pid (lwpid, status, &siginfo);
       return NULL;
     }
 
@@ -3075,6 +3204,7 @@ linux_nat_filter_event (int lwpid, int status, int options)
 	 on handling the event like a regular SIGTRAP from here
 	 on.  */
       status = W_STOPCODE (SIGTRAP);
+      siginfo.si_signo = 0;
       if (linux_handle_syscall_trap (lp, 0))
 	return NULL;
     }
@@ -3086,15 +3216,13 @@ linux_nat_filter_event (int lwpid, int status, int options)
 	fprintf_unfiltered (gdb_stdlog,
 			    "LLW: Handling extended status 0x%06x\n",
 			    status);
-      if (linux_handle_extended_wait (lp, status, 0))
+      if (linux_handle_extended_wait (lp, status, &siginfo, 0))
 	return NULL;
     }
 
   if (linux_nat_status_is_event (status))
     {
-      /* Save the trap's siginfo in case we need it later.  */
-      save_siginfo (lp);
-
+      lp->siginfo = siginfo;
       save_sigtrap (lp);
     }
 
@@ -3220,6 +3348,7 @@ linux_nat_filter_event (int lwpid, int status, int options)
   /* An interesting event.  */
   gdb_assert (lp);
   lp->status = status;
+  lp->siginfo = siginfo;
   return lp;
 }
 
@@ -3231,7 +3360,8 @@ linux_nat_wait_1 (struct target_ops *ops,
   static sigset_t prev_mask;
   struct lwp_info *lp = NULL;
   int options = 0;
-  int status = 0;
+  int status;
+  siginfo_t siginfo;
   pid_t pid;
 
   if (debug_linux_nat_async)
@@ -3268,6 +3398,7 @@ linux_nat_wait_1 (struct target_ops *ops,
 retry:
   lp = NULL;
   status = 0;
+  siginfo.si_signo = 0;
 
   /* Make sure that of those LWPs we want to get an event from, there
      is at least one LWP that has been resumed.  If there's none, just
@@ -3360,7 +3491,9 @@ retry:
 
       /* Catch the pending SIGSTOP.  */
       status = lp->status;
+      siginfo = lp->siginfo;
       lp->status = 0;
+      lp->siginfo.si_signo = 0;
 
       stop_wait_callback (lp, NULL);
 
@@ -3374,10 +3507,11 @@ retry:
 				"LLW: kill %s, %s\n",
 				target_pid_to_str (lp->ptid),
 				status_to_str (lp->status));
-	  kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (lp->status));
+	  kill_lwp_siginfo (lp, WSTOPSIG (lp->status), &lp->siginfo);
 	}
 
       lp->status = status;
+      lp->siginfo = siginfo;
     }
 
   if (!target_can_async_p ())
@@ -3394,7 +3528,7 @@ retry:
     {
       pid_t lwpid;
 
-      lwpid = my_waitpid (pid, &status, options);
+      lwpid = my_waitpid (pid, &status, &siginfo, options);
 
       if (lwpid > 0)
 	{
@@ -3407,7 +3541,7 @@ retry:
 				  (long) lwpid, status_to_str (status));
 	    }
 
-	  lp = linux_nat_filter_event (lwpid, status, options);
+	  lp = linux_nat_filter_event (lwpid, status, &siginfo, options);
 
 	  /* STATUS is now no longer valid, use LP->STATUS instead.  */
 	  status = 0;
@@ -3441,6 +3575,7 @@ retry:
 			{
 			  /* Throw away the SIGTRAP.  */
 			  lp->status = 0;
+			  lp->siginfo.si_signo = 0;
 
 			  if (debug_linux_nat)
 			    fprintf (stderr,
@@ -3482,6 +3617,18 @@ retry:
 		  /* Store the pending event in the waitstatus as
 		     well, because W_EXITCODE(0,0) == 0.  */
 		  store_waitstatus (&lp->waitstatus, lp->status);
+		  if (lp->siginfo.si_signo != 0
+		      && TARGET_WAITKIND_USES_SIG (lp->waitstatus.kind))
+		    {
+		      struct gdbarch *gdbarch;
+		      gdb_byte inf_siginfo[MAX_SIGINFO_SIZE];
+
+		      gdbarch = target_thread_architecture (lp->ptid);
+
+		      siginfo_fixup (&lp->siginfo, inf_siginfo, 0, gdbarch);
+		      target_signal_siginfo_set (&lp->waitstatus.value.sig,
+						 gdbarch, inf_siginfo);
+		    }
 		}
 
 	      /* Keep looking.  */
@@ -3549,7 +3696,9 @@ retry:
   gdb_assert (lp);
 
   status = lp->status;
+  siginfo = lp->siginfo;
   lp->status = 0;
+  lp->siginfo.si_signo = 0;
 
   /* Don't report signals that GDB isn't interested in, such as
      signals that are neither printed nor stopped upon.  Stopping all
@@ -3560,9 +3709,20 @@ retry:
 
   if (WIFSTOPPED (status))
     {
-      target_signal_t signo = target_signal_from_host (WSTOPSIG (status));
+      target_signal_t signo;
       struct inferior *inf;
 
+      signo = target_signal_from_host (WSTOPSIG (status));
+      if (siginfo.si_signo != 0)
+	{
+	  struct gdbarch *gdbarch;
+	  gdb_byte inf_siginfo[MAX_SIGINFO_SIZE];
+
+	  gdbarch = target_thread_architecture (lp->ptid);
+	  siginfo_fixup (&siginfo, inf_siginfo, 0, gdbarch);
+	  target_signal_siginfo_set (&signo, gdbarch, inf_siginfo);
+	}
+
       inf = find_inferior_pid (ptid_get_pid (lp->ptid));
       gdb_assert (inf);
 
@@ -3638,7 +3798,7 @@ retry:
 	 to all LWPs that have had events helps prevent
 	 starvation.  */
       if (pid == -1)
-	select_event_lwp (ptid, &lp, &status);
+	select_event_lwp (ptid, &lp, &status, &siginfo);
 
       /* Now that we've selected our final event LWP, cancel any
 	 breakpoints in other LWPs that have hit a GDB breakpoint.
@@ -3667,7 +3827,19 @@ retry:
       lp->waitstatus.kind = TARGET_WAITKIND_IGNORE;
     }
   else
-    store_waitstatus (ourstatus, status);
+    {
+      store_waitstatus (ourstatus, status);
+      if (siginfo.si_signo != 0 && TARGET_WAITKIND_USES_SIG (ourstatus->kind))
+	{
+	  struct gdbarch *gdbarch;
+	  gdb_byte inf_siginfo[MAX_SIGINFO_SIZE];
+
+	  gdbarch = target_thread_architecture (lp->ptid);
+	  siginfo_fixup (&siginfo, inf_siginfo, 0, gdbarch);
+	  target_signal_siginfo_set (&ourstatus->value.sig, gdbarch,
+				     inf_siginfo);
+	}
+    }
 
   if (debug_linux_nat_async)
     fprintf_unfiltered (gdb_stdlog, "LLW: exit\n");
@@ -3717,7 +3889,7 @@ resume_stopped_resumed_lwps (struct lwp_info *lp, void *data)
       linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
 			    lp->step, TARGET_SIGNAL_0);
       lp->stopped = 0;
-      memset (&lp->siginfo, 0, sizeof (lp->siginfo));
+      lp->siginfo.si_signo = 0;
       lp->stopped_by_watchpoint = 0;
     }
 
@@ -3795,7 +3967,7 @@ kill_wait_callback (struct lwp_info *lp, void *data)
     {
       do
 	{
-	  pid = my_waitpid (GET_LWP (lp->ptid), NULL, __WCLONE);
+	  pid = my_waitpid (GET_LWP (lp->ptid), NULL, NULL, __WCLONE);
 	  if (pid != (pid_t) -1)
 	    {
 	      if (debug_linux_nat)
@@ -3817,7 +3989,7 @@ kill_wait_callback (struct lwp_info *lp, void *data)
 
   do
     {
-      pid = my_waitpid (GET_LWP (lp->ptid), NULL, 0);
+      pid = my_waitpid (GET_LWP (lp->ptid), NULL, NULL, 0);
       if (pid != (pid_t) -1)
 	{
 	  if (debug_linux_nat)
@@ -3899,7 +4071,7 @@ linux_xfer_siginfo (struct target_ops *ops, enum target_object object,
 {
   int pid;
   struct siginfo siginfo;
-  gdb_byte inf_siginfo[sizeof (struct siginfo)];
+  gdb_byte inf_siginfo[MAX_SIGINFO_SIZE];
 
   gdb_assert (object == TARGET_OBJECT_SIGNAL_INFO);
   gdb_assert (readbuf || writebuf);
@@ -3922,7 +4094,8 @@ linux_xfer_siginfo (struct target_ops *ops, enum target_object object,
      with a 32-bit GDB, we need to convert it.  GDB core always sees
      the converted layout, so any read/write will have to be done
      post-conversion.  */
-  siginfo_fixup (&siginfo, inf_siginfo, 0);
+  siginfo_fixup (&siginfo, inf_siginfo, 0,
+		 get_frame_arch (get_current_frame ()));
 
   if (offset + len > sizeof (siginfo))
     len = sizeof (siginfo) - offset;
@@ -3934,7 +4107,8 @@ linux_xfer_siginfo (struct target_ops *ops, enum target_object object,
       memcpy (inf_siginfo + offset, writebuf, len);
 
       /* Convert back to ptrace layout before flushing it out.  */
-      siginfo_fixup (&siginfo, inf_siginfo, 1);
+      siginfo_fixup (&siginfo, inf_siginfo, 1,
+		     get_frame_arch (get_current_frame ()));
 
       errno = 0;
       ptrace (PTRACE_SETSIGINFO, pid, (PTRACE_TYPE_ARG3) 0, &siginfo);
@@ -5450,7 +5624,10 @@ linux_nat_stop_lwp (struct lwp_info *lwp, void *data)
 	 event-loop will end up calling target_wait which will collect
 	 these.  */
       if (lwp->status == 0)
-	lwp->status = W_STOPCODE (0);
+	{
+	  lwp->status = W_STOPCODE (0);
+	  lwp->siginfo.si_signo = 0;
+	}
       async_file_mark ();
     }
   else
@@ -5666,8 +5843,13 @@ linux_nat_set_new_thread (struct target_ops *t, void (*new_thread) (ptid_t))
   linux_nat_new_thread = new_thread;
 }
 
+/* Return the saved siginfo associated with PTID.  Returned data are in the
+   host native format (which may be different from the target thread format
+   during biarch operation).
+
+   This siginfo is for the currently detected stop, before it gets presented
+   to the user.  Signal gets moved into thread_info->stop_signal later.  */
 
-/* Return the saved siginfo associated with PTID.  */
 struct siginfo *
 linux_nat_get_siginfo (ptid_t ptid)
 {
--- a/gdb/linux-nat.h
+++ b/gdb/linux-nat.h
@@ -52,16 +52,16 @@ struct lwp_info
      didn't try to let the LWP run.  */
   int resumed;
 
-  /* If non-zero, a pending wait status.  */
+  /* If non-zero, a pending wait status.  SIGINFO contains extended
+     information for WIFSTOPPED and WIFSIGNALLED cases of STATUS.  SIGINFO
+     data have the host native format (which may be different from the target
+     thread format during biarch operation).  */
   int status;
+  struct siginfo siginfo;
 
   /* Non-zero if we were stepping this LWP.  */
   int step;
 
-  /* Non-zero si_signo if this LWP stopped with a trap.  si_addr may
-     be the address of a hardware watchpoint.  */
-  struct siginfo siginfo;
-
   /* STOPPED_BY_WATCHPOINT is non-zero if this LWP stopped with a data
      watchpoint trap.  */
   int stopped_by_watchpoint;
@@ -159,7 +159,12 @@ void linux_nat_set_new_thread (struct target_ops *, void (*) (ptid_t));
    to another.  */
 void linux_nat_switch_fork (ptid_t new_ptid);
 
-/* Return the saved siginfo associated with PTID.  */
+/* Return the saved siginfo associated with PTID.  Returned data are in the
+   host native format (which may be different from the target thread format
+   during biarch operation).
+
+   This siginfo is for the currently detected stop, before it gets presented
+   to the user.  Signal gets moved into thread_info->stop_signal later.  */
 struct siginfo *linux_nat_get_siginfo (ptid_t ptid);
 
 /* Compute and return the processor core of a given thread.  */
--- a/gdb/rs6000-nat.c
+++ b/gdb/rs6000-nat.c
@@ -118,6 +118,10 @@ typedef union {
 #define LDI_FD(ldi, arch64)		LDI_FIELD(ldi, arch64, fd)
 #define LDI_FILENAME(ldi, arch64)	LDI_FIELD(ldi, arch64, filename)
 
+#ifndef PTRACE_GETSIGINFO
+# define PTRACE_GETSIGINFO	0x4202
+#endif
+
 extern struct vmap *map_vmap (bfd * bf, bfd * arch);
 
 static void vmap_exec (void);
@@ -567,7 +571,25 @@ rs6000_wait (struct target_ops *ops,
     ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
   /* A normal waitstatus.  Let the usual macros deal with it.  */
   else
-    store_waitstatus (ourstatus, status);
+    {
+      siginfo_t siginfo;
+
+      store_waitstatus (ourstatus, status);
+
+      /* We could also use waitid.  */
+      if (TARGET_WAITKIND_USES_SIG (ourstatus->kind)
+	  && (ptrace (PTRACE_GETSIGINFO, pid, (PTRACE_TYPE_ARG3) 0, &siginfo)
+	      == 0))
+	{
+	  struct gdbarch *gdbarch;
+	  gdb_byte inf_siginfo[MAX_SIGINFO_SIZE];
+
+	  gdbarch = target_thread_architecture (pid_to_ptid (pid));
+	  siginfo_fixup (&siginfo, inf_siginfo, 0, gdbarch);
+	  target_signal_siginfo_set (&ourstatus->value.sig, gdbarch,
+				     inf_siginfo);
+	}
+    }
 
   return pid_to_ptid (pid);
 }
--- a/gdb/spu-linux-nat.c
+++ b/gdb/spu-linux-nat.c
@@ -40,6 +40,9 @@
 #define INSTR_SC	0x44000002
 #define NR_spu_run	0x0116
 
+#ifndef PTRACE_GETSIGINFO
+# define PTRACE_GETSIGINFO	0x4202
+#endif
 
 /* Fetch PPU register REGNO.  */
 static ULONGEST
@@ -429,6 +432,7 @@ spu_child_wait (struct target_ops *ops,
   int save_errno;
   int status;
   pid_t pid;
+  siginfo_t siginfo;
 
   do
     {
@@ -466,6 +470,19 @@ spu_child_wait (struct target_ops *ops,
     }
 
   store_waitstatus (ourstatus, status);
+
+  /* We could also use waitid.  */
+  if (TARGET_WAITKIND_USES_SIG (ourstatus->kind)
+      && ptrace (PTRACE_GETSIGINFO, ret, (PTRACE_TYPE_ARG3) 0, &siginfo) == 0)
+    {
+      struct gdbarch *gdbarch;
+      gdb_byte inf_siginfo[MAX_SIGINFO_SIZE];
+
+      gdbarch = target_thread_architecture (pid_to_ptid (pid));
+      siginfo_fixup (&siginfo, inf_siginfo, 0, gdbarch);
+      target_signal_siginfo_set (&ourstatus->value.sig, gdbarch, inf_siginfo);
+    }
+
   return pid_to_ptid (pid);
 }
 
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -2984,7 +2984,96 @@ store_waitstatus (struct target_waitstatus *ourstatus, int hoststatus)
       ourstatus->value.sig = target_signal_from_host (WSTOPSIG (hoststatus));
     }
 }
-
+
+int
+target_signal_siginfo_p (const target_signal_t *sigp)
+{
+#if MAX_SIGINFO_SIZE == 0
+  return 0;
+#else /* MAX_SIGINFO_SIZE > 0 */
+  return sigp->siginfo_gdbarch != NULL;
+#endif /* MAX_SIGINFO_SIZE > 0 */
+}
+
+size_t
+target_signal_siginfo_len (struct gdbarch *siginfo_gdbarch)
+{
+#if MAX_SIGINFO_SIZE == 0
+  gdb_assert_not_reached ("no siginfo target is configured");
+#else /* MAX_SIGINFO_SIZE > 0 */
+
+  gdb_assert (siginfo_gdbarch != NULL);
+  
+  if (gdbarch_get_siginfo_type_p (siginfo_gdbarch))
+    {
+      struct type *type;
+      size_t len;
+
+      type = gdbarch_get_siginfo_type (siginfo_gdbarch);
+      len = TYPE_LENGTH (type);
+
+      return len;
+    }
+
+#ifdef HAVE_SIGINFO_T
+
+  /* This case is used only for native targets with their tdep missing
+     gdbarch_get_siginfo_type.  */
+  return sizeof (siginfo_t);
+
+#else /* ! HAVE_SIGINFO_T */
+
+  /* remote.c will need to provide the length as received from the remote even
+     if the tdep is missing gdbarch_get_siginfo_type.  */
+  internal_error (__FILE__, __LINE__,
+		  _("arch %s is missing gdbarch_get_siginfo_type"),
+		  gdbarch_bfd_arch_info (siginfo_gdbarch)->printable_name);
+
+#endif /* ! HAVE_SIGINFO_T */
+
+#endif /* MAX_SIGINFO_SIZE > 0 */
+}
+
+void *
+target_signal_siginfo_get (target_signal_t *sigp,
+			   struct gdbarch *siginfo_gdbarch)
+{
+#if MAX_SIGINFO_SIZE == 0
+  gdb_assert_not_reached ("no siginfo target is configured");
+#else /* MAX_SIGINFO_SIZE > 0 */
+  gdb_assert (sigp->siginfo_gdbarch != NULL);
+  gdb_assert (siginfo_gdbarch != NULL);
+  gdb_assert (siginfo_gdbarch == sigp->siginfo_gdbarch);
+
+  return sigp->siginfo;
+#endif /* MAX_SIGINFO_SIZE > 0 */
+}
+
+void
+target_signal_siginfo_set (target_signal_t *sig,
+			   struct gdbarch *siginfo_gdbarch,
+			   const void *siginfo)
+{
+#if MAX_SIGINFO_SIZE > 0
+  size_t len;
+
+  gdb_assert (siginfo != NULL);
+  gdb_assert (sig->siginfo_gdbarch == NULL);
+
+  len = target_signal_siginfo_len (siginfo_gdbarch);
+
+  if (MAX_SIGINFO_SIZE < len)
+    internal_error (__FILE__, __LINE__,
+		    _("MAX_SIGINFO_SIZE (%lu) is smaller than "
+		      "siginfo_t size (%lu) of arch %s"),
+		    (unsigned long) MAX_SIGINFO_SIZE, (unsigned long) len,
+		    gdbarch_bfd_arch_info (siginfo_gdbarch)->printable_name);
+
+  sig->siginfo_gdbarch = siginfo_gdbarch;
+  memcpy (sig->siginfo, siginfo, len);
+#endif /* MAX_SIGINFO_SIZE > 0 */
+}
+
 /* Convert a normal process ID to a string.  Returns the string in a
    static buffer.  */
 
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -170,6 +170,10 @@ struct target_waitstatus
     value;
   };
 
+/* Is target_waitstatus.value.sig used for this target_waitstatus.KIND?  */
+#define TARGET_WAITKIND_USES_SIG(kind) ((kind) == TARGET_WAITKIND_SIGNALLED \
+					|| (kind) == TARGET_WAITKIND_STOPPED)
+
 /* Options that can be passed to target_wait.  */
 
 /* Return immediately if there's no event already queued.  If this
@@ -1588,6 +1592,14 @@ extern int remote_timeout;
 /* This is for native targets which use a unix/POSIX-style waitstatus.  */
 extern void store_waitstatus (struct target_waitstatus *, int);
 
+extern int target_signal_siginfo_p (const target_signal_t *sigp);
+extern size_t target_signal_siginfo_len (struct gdbarch *siginfo_gdbarch);
+extern void *target_signal_siginfo_get (target_signal_t *sigp,
+					struct gdbarch *siginfo_gdbarch);
+extern void target_signal_siginfo_set (target_signal_t *sigp,
+				       struct gdbarch *siginfo_gdbarch,
+				       const void *siginfo);
+
 /* These are in common/signals.c, but they're only used by gdb.  */
 extern target_signal_t default_target_signal_from_host (struct gdbarch *,
 							   int);
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/siginfo-threads.c
@@ -0,0 +1,447 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2010 Free Software Foundation, Inc.
+
+   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 3 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, see <http://www.gnu.org/licenses/>.  */
+
+#define _GNU_SOURCE
+#include <pthread.h>
+#include <stdio.h>
+#include <limits.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <unistd.h>
+#include <asm/unistd.h>
+
+#define gettid() syscall (__NR_gettid)
+#define tgkill(tgid, tid, sig) syscall (__NR_tgkill, tgid, tid, sig)
+
+/* Terminate always in the main task, it can lock up with SIGSTOPped GDB
+   otherwise.  */
+#define TIMEOUT (gettid () == getpid() ? 10 : 15)
+
+static pid_t thread1_tid;
+static pthread_cond_t thread1_tid_cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t thread1_tid_mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
+static int thread1_sigusr1_hit;
+static int thread1_sigusr2_hit;
+
+static pid_t thread2_tid;
+static pthread_cond_t thread2_tid_cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t thread2_tid_mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
+static int thread2_sigusr1_hit;
+static int thread2_sigusr2_hit;
+
+static pthread_mutex_t terminate_mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
+
+/* Do not use alarm as it would create a ptrace event which would hang up us if
+   we are being traced by GDB which we stopped ourselves.  */
+
+static void timed_mutex_lock (pthread_mutex_t *mutex)
+{
+  int i;
+  struct timespec start, now;
+
+  i = clock_gettime (CLOCK_MONOTONIC, &start);
+  assert (i == 0);
+
+  do
+    {
+      i = pthread_mutex_trylock (mutex);
+      if (i == 0)
+	return;
+      assert (i == EBUSY);
+
+      i = clock_gettime (CLOCK_MONOTONIC, &now);
+      assert (i == 0);
+      assert (now.tv_sec >= start.tv_sec);
+    }
+  while (now.tv_sec - start.tv_sec < TIMEOUT);
+
+  fprintf (stderr, "Timed out waiting for internal lock!\n");
+  exit (EXIT_FAILURE);
+}
+
+static void
+handler (int signo, siginfo_t *siginfo, void *exception)
+{
+  int *varp;
+
+  assert (siginfo->si_signo == signo);
+  assert (siginfo->si_code == SI_TKILL);
+  assert (siginfo->si_pid == getpid ());
+
+  if (gettid () == thread1_tid)
+    {
+      if (signo == SIGUSR1)
+	varp = &thread1_sigusr1_hit;
+      else if (signo == SIGUSR2)
+	varp = &thread1_sigusr2_hit;
+      else
+	assert (0);
+    }
+  else if (gettid () == thread2_tid)
+    {
+      if (signo == SIGUSR1)
+	varp = &thread2_sigusr1_hit;
+      else if (signo == SIGUSR2)
+	varp = &thread2_sigusr2_hit;
+      else
+	assert (0);
+    }
+  else
+    assert (0);
+
+  if (*varp)
+    {
+      fprintf (stderr, "Signal %d for TID %lu has been already hit!\n", signo,
+	       (unsigned long) gettid ());
+      exit (EXIT_FAILURE);
+    }
+  *varp = 1;
+}
+
+static void *
+thread1_func (void *unused)
+{
+  int i;
+
+  timed_mutex_lock (&thread1_tid_mutex);
+
+  /* THREAD1_TID_MUTEX must be already locked to avoid race.  */
+  thread1_tid = gettid ();
+
+  i = pthread_cond_signal (&thread1_tid_cond);
+  assert (i == 0);
+  i = pthread_mutex_unlock (&thread1_tid_mutex);
+  assert (i == 0);
+
+  /* Be sure the "t (tracing stop)" test can proceed for both threads.  */
+  timed_mutex_lock (&terminate_mutex);
+  i = pthread_mutex_unlock (&terminate_mutex);
+  assert (i == 0);
+
+  if (! thread1_sigusr1_hit)
+    {
+      fprintf (stderr, "Thread 1 signal SIGUSR1 not hit!\n");
+      exit (EXIT_FAILURE);
+    }
+  if (! thread1_sigusr2_hit)
+    {
+      fprintf (stderr, "Thread 1 signal SIGUSR2 not hit!\n");
+      exit (EXIT_FAILURE);
+    }
+
+  return NULL;
+}
+
+static void *
+thread2_func (void *unused)
+{
+  int i;
+
+  timed_mutex_lock (&thread2_tid_mutex);
+
+  /* THREAD2_TID_MUTEX must be already locked to avoid race.  */
+  thread2_tid = gettid ();
+
+  i = pthread_cond_signal (&thread2_tid_cond);
+  assert (i == 0);
+  i = pthread_mutex_unlock (&thread2_tid_mutex);
+  assert (i == 0);
+
+  /* Be sure the "t (tracing stop)" test can proceed for both threads.  */
+  timed_mutex_lock (&terminate_mutex);
+  i = pthread_mutex_unlock (&terminate_mutex);
+  assert (i == 0);
+
+  if (! thread2_sigusr1_hit)
+    {
+      fprintf (stderr, "Thread 2 signal SIGUSR1 not hit!\n");
+      exit (EXIT_FAILURE);
+    }
+  if (! thread2_sigusr2_hit)
+    {
+      fprintf (stderr, "Thread 2 signal SIGUSR2 not hit!\n");
+      exit (EXIT_FAILURE);
+    }
+
+  return NULL;
+}
+
+static const char *
+proc_string (const char *filename, const char *line)
+{
+  FILE *f;
+  static char buf[LINE_MAX];
+  size_t line_len = strlen (line);
+
+  f = fopen (filename, "r");
+  if (f == NULL)
+    {
+      fprintf (stderr, "fopen (\"%s\") for \"%s\": %s\n", filename, line,
+	       strerror (errno));
+      exit (EXIT_FAILURE);
+    }
+  while (errno = 0, fgets (buf, sizeof (buf), f))
+    {
+      char *s;
+
+      s = strchr (buf, '\n');
+      assert (s != NULL);
+      *s = 0;
+
+      if (strncmp (buf, line, line_len) != 0)
+	continue;
+
+      if (fclose (f))
+	{
+	  fprintf (stderr, "fclose (\"%s\") for \"%s\": %s\n", filename, line,
+		   strerror (errno));
+	  exit (EXIT_FAILURE);
+	}
+
+      return &buf[line_len];
+    }
+  if (errno != 0)
+    {
+      fprintf (stderr, "fgets (\"%s\": %s\n", filename, strerror (errno));
+      exit (EXIT_FAILURE);
+    }
+  fprintf (stderr, "\"%s\": No line \"%s\" found.\n", filename, line);
+  exit (EXIT_FAILURE);
+}
+
+static unsigned long
+proc_ulong (const char *filename, const char *line)
+{
+  const char *s = proc_string (filename, line);
+  long retval;
+  char *end;
+
+  errno = 0;
+  retval = strtol (s, &end, 10);
+  if (retval < 0 || retval >= LONG_MAX || (end && *end))
+    {
+      fprintf (stderr, "\"%s\":\"%s\": %ld, %s\n", filename, line, retval,
+	       strerror (errno));
+      exit (EXIT_FAILURE);
+    }
+  return retval;
+}
+
+static void
+state_wait (pid_t process, const char *wanted)
+{
+  char *filename;
+  int i;
+  struct timespec start, now;
+  const char *state;
+
+  i = asprintf (&filename, "/proc/%lu/status", (unsigned long) process);
+  assert (i > 0);
+
+  i = clock_gettime (CLOCK_MONOTONIC, &start);
+  assert (i == 0);
+
+  do
+    {
+      state = proc_string (filename, "State:\t");
+
+      /* torvalds/linux-2.6.git 464763cf1c6df632dccc8f2f4c7e50163154a2c0
+	 has changed "T (tracing stop)" to "t (tracing stop)".  Make the GDB
+	 testcase backward compatible with older Linux kernels.  */
+      if (strcmp (state, "T (tracing stop)") == 0)
+	state = "t (tracing stop)";
+
+      if (strcmp (state, wanted) == 0)
+	{
+	  free (filename);
+	  return;
+	}
+
+      if (sched_yield ())
+	{
+	  perror ("sched_yield()");
+	  exit (EXIT_FAILURE);
+	}
+
+      i = clock_gettime (CLOCK_MONOTONIC, &now);
+      assert (i == 0);
+      assert (now.tv_sec >= start.tv_sec);
+    }
+  while (now.tv_sec - start.tv_sec < TIMEOUT);
+
+  fprintf (stderr, "Timed out waiting for PID %lu \"%s\" (now it is \"%s\")!\n",
+	   (unsigned long) process, wanted, state);
+  exit (EXIT_FAILURE);
+}
+
+static volatile pid_t tracer = 0;
+static pthread_t thread1, thread2;
+
+static void
+cleanup (void)
+{
+  printf ("Resuming GDB PID %lu.\n", (unsigned long) tracer);
+
+  if (tracer)
+    {
+      int i;
+      int tracer_save = tracer;
+
+      tracer = 0;
+
+      i = kill (tracer_save, SIGCONT);
+      assert (i == 0);
+    }
+}
+
+int
+main (int argc, char **argv)
+{
+  int i;
+  int standalone = 0;
+  struct sigaction act;
+
+  if (argc == 2 && strcmp (argv[1], "-s") == 0)
+    standalone = 1;
+  else
+    assert (argc == 1);
+
+  setbuf (stdout, NULL);
+
+  timed_mutex_lock (&thread1_tid_mutex);
+  timed_mutex_lock (&thread2_tid_mutex);
+
+  timed_mutex_lock (&terminate_mutex);
+
+  errno = 0;
+  memset (&act, 0, sizeof (act));
+  act.sa_sigaction = handler;
+  act.sa_flags = SA_RESTART | SA_SIGINFO;
+  i = sigemptyset (&act.sa_mask);
+  assert_perror (errno);
+  assert (i == 0);
+  i = sigaction (SIGUSR1, &act, NULL);
+  assert_perror (errno);
+  assert (i == 0);
+  i = sigaction (SIGUSR2, &act, NULL);
+  assert_perror (errno);
+  assert (i == 0);
+
+  i = pthread_create (&thread1, NULL, thread1_func, NULL);
+  assert (i == 0);
+
+  i = pthread_create (&thread2, NULL, thread2_func, NULL);
+  assert (i == 0);
+
+  if (!standalone)
+    {
+      tracer = proc_ulong ("/proc/self/status", "TracerPid:\t");
+      if (tracer == 0)
+	{
+	  fprintf (stderr, "The testcase must be run by GDB!\n");
+	  exit (EXIT_FAILURE);
+	}
+      if (tracer != getppid ())
+	{
+	  fprintf (stderr, "The testcase parent must be our GDB tracer!\n");
+	  exit (EXIT_FAILURE);
+	}
+    }
+
+  /* SIGCONT our debugger in the case of our crash as we would deadlock
+     otherwise.  */
+
+  atexit (cleanup);
+
+  printf ("Stopping GDB PID %lu.\n", (unsigned long) tracer);
+
+  if (tracer)
+    {
+      i = kill (tracer, SIGSTOP);
+      assert (i == 0);
+      state_wait (tracer, "T (stopped)");
+    }
+
+  /* Threads are now waiting at timed_mutex_lock (thread1_tid_mutex) and so
+     they could not trigger the signals before GDB gets unstopped later.
+     Threads get resumed at pthread_cond_wait below.  Use `while' loops for
+     protection against spurious pthread_cond_wait wakeups.  */
+
+  printf ("Waiting till the threads initialize their TIDs.\n");
+
+  while (thread1_tid == 0)
+    {
+      i = pthread_cond_wait (&thread1_tid_cond, &thread1_tid_mutex);
+      assert (i == 0);
+    }
+
+  while (thread2_tid == 0)
+    {
+      i = pthread_cond_wait (&thread2_tid_cond, &thread2_tid_mutex);
+      assert (i == 0);
+    }
+
+  printf ("Thread 1 TID = %lu, thread 2 TID = %lu, PID = %lu.\n",
+	  (unsigned long) thread1_tid, (unsigned long) thread2_tid,
+	  (unsigned long) getpid ());
+
+  errno = 0;
+  i = tgkill (getpid (), thread1_tid, SIGUSR1);
+  assert_perror (errno);
+  assert (i == 0);
+  i = tgkill (getpid (), thread1_tid, SIGUSR2);
+  assert_perror (errno);
+  assert (i == 0);
+  i = tgkill (getpid (), thread2_tid, SIGUSR1);
+  assert_perror (errno);
+  assert (i == 0);
+  i = tgkill (getpid (), thread2_tid, SIGUSR2);
+  assert_perror (errno);
+  assert (i == 0);
+
+  printf ("Waiting till the threads get trapped by the signals.\n");
+
+  if (tracer)
+    {
+      /* s390x-unknown-linux-gnu will fail with "R (running)".  */
+
+      state_wait (thread1_tid, "t (tracing stop)");
+
+      state_wait (thread2_tid, "t (tracing stop)");
+    }
+
+  cleanup ();
+
+  printf ("Joining the threads.\n");
+
+  i = pthread_mutex_unlock (&terminate_mutex);
+  assert (i == 0);
+
+  i = pthread_join (thread1, NULL);
+  assert (i == 0);
+
+  i = pthread_join (thread2, NULL);
+  assert (i == 0);
+
+  printf ("Exiting.\n");	/* break-at-exit */
+
+  return EXIT_SUCCESS;
+}
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/siginfo-threads.exp
@@ -0,0 +1,49 @@
+# Copyright 2010 Free Software Foundation, Inc.
+
+# 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 3 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, see <http://www.gnu.org/licenses/>.
+
+set testfile "siginfo-threads"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" ${binfile} executable [list debug additional_flags=-lrt]] != "" } {
+    return -1
+}
+
+clean_restart $testfile
+
+if ![runto_main] {
+    return -1
+}
+
+# `nostop noprint pass' could in some cases report false PASS due to the
+# (preempt 'handle') code path.
+
+gdb_test "handle SIGUSR1 nostop print pass" "Signal\[ \t\]+Stop\[ \t\]+Print\[ \t\]+Pass to program\[ \t\]+Description\r\nSIGUSR1\[ \t\]+No\[ \t\]+Yes\[ \t\]+Yes\[ \t\]+User defined signal 1"
+gdb_test "handle SIGUSR2 nostop print pass" "Signal\[ \t\]+Stop\[ \t\]+Print\[ \t\]+Pass to program\[ \t\]+Description\r\nSIGUSR2\[ \t\]+No\[ \t\]+Yes\[ \t\]+Yes\[ \t\]+User defined signal 2"
+
+gdb_breakpoint [gdb_get_line_number "break-at-exit"]
+
+# Catch any KLS: .*rt_tgsigqueueinfo messages.
+# Ignore possible: Undefined set debug command: "lin-lwp 1" ...
+gdb_test "set debug lin-lwp 1" ".*"
+
+set test "continue to break-at-exit"
+gdb_test_multiple "continue" $test {
+    -re "KLS: \[^\r\n\]*rt_tgsigqueueinfo" {
+	unsupported "Missing rt_tgsigqueueinfo kernel support"
+    }
+    -re "Breakpoint .*break-at-exit.*\r\n$gdb_prompt $" {
+	pass $test
+    }
+}
--- a/include/gdb/signals.h
+++ b/include/gdb/signals.h
@@ -39,14 +39,7 @@
    (1) This set of signals represents a widely-accepted attempt to
    represent events of this sort in a portable fashion, (2) we want a
    signal to make it from wait to child_wait to the user intact, (3) many
-   remote protocols use a similar encoding.  However, it is
-   recognized that this set of signals has limitations (such as not
-   distinguishing between various kinds of SIGSEGV, or not
-   distinguishing hitting a breakpoint from finishing a single step).
-   So in the future we may get around this either by adding additional
-   signals for breakpoint, single-step, etc., or by adding signal
-   codes; the latter seems more in the spirit of what BSD, System V,
-   etc. are doing to address these issues.  */
+   remote protocols use a similar encoding.  */
 
 /* For an explanation of what each signal means, see
    target_signal_to_string.  */
@@ -66,11 +59,35 @@ enum target_signal_number
 typedef struct
   {
     enum target_signal_number number;
+
+#if MAX_SIGINFO_SIZE > 0
+
+    /* Target architecture of the current frame of the associated thread.  */
+    struct gdbarch *siginfo_gdbarch;
+
+    /* Valid iff SIGINFO_GDBARCH is not NULL.  Content has the target
+       siginfo_t format, even despite the native PTRACE_GETSIGINFO format may
+       be different during biarch operation.  */
+    unsigned char siginfo[MAX_SIGINFO_SIZE];
+
+#endif /* MAX_SIGINFO_SIZE > 0 */
   }
 target_signal_t;
 
-#define TARGET_SIGNAL_INITIALIZER(target_signal) \
-  { TARGET_SIGNAL_NUMBER_CONST (target_signal) }
+#if MAX_SIGINFO_SIZE > 0
+
+# define TARGET_SIGNAL_STRUCT(target_signal_number) \
+  { (target_signal_number), NULL }
+
+#else /* MAX_SIGINFO_SIZE == 0 */
+
+# define TARGET_SIGNAL_STRUCT(target_signal_number) \
+  { (target_signal_number) }
+
+#endif /* MAX_SIGINFO_SIZE == 0 */
+
+# define TARGET_SIGNAL_INITIALIZER(target_signal) \
+  TARGET_SIGNAL_STRUCT (TARGET_SIGNAL_NUMBER_CONST (target_signal))
 
 #define SET(symbol, constant, name, string) ANY (symbol, name, string)
 #define ANY(symbol, name, string)			\
@@ -85,7 +102,7 @@ target_signal_t;
 static inline target_signal_t
 target_signal_from_number (enum target_signal_number number)
 {
-  target_signal_t retval = { number } ;
+  target_signal_t retval = TARGET_SIGNAL_STRUCT (number);
 
   return retval;
 }


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