[gdb/f14/master] - Fix lost siginfo_t in linux-nat (BZ 592031).
Jan Kratochvil
jkratoch at fedoraproject.org
Sat Sep 25 14:00:15 UTC 2010
commit a0db7fa0a1336ed756ad3fb94916aa0c90876671
Author: Jan Kratochvil <jan.kratochvil at redhat.com>
Date: Sat Sep 25 16:00:11 2010 +0200
- Fix lost siginfo_t in linux-nat (BZ 592031).
gdb-bz592031-siginfo-lost-1of5.patch | 87 +++
gdb-bz592031-siginfo-lost-2of5.patch | 139 +++++
gdb-bz592031-siginfo-lost-3of5.patch | 259 +++++++++
gdb-bz592031-siginfo-lost-4of5.patch | 992 ++++++++++++++++++++++++++++++++++
gdb-bz592031-siginfo-lost-5of5.patch | 141 +++++
gdb.spec | 17 +-
6 files changed, 1634 insertions(+), 1 deletions(-)
---
diff --git a/gdb-bz592031-siginfo-lost-1of5.patch b/gdb-bz592031-siginfo-lost-1of5.patch
new file mode 100644
index 0000000..16c789f
--- /dev/null
+++ b/gdb-bz592031-siginfo-lost-1of5.patch
@@ -0,0 +1,87 @@
+http://sourceware.org/ml/gdb-patches/2010-08/msg00559.html
+http://sourceware.org/ml/gdb-cvs/2010-08/msg00199.html
+
+### src/gdb/ChangeLog 2010/08/31 18:08:42 1.12129
+### src/gdb/ChangeLog 2010/08/31 18:11:48 1.12130
+## -1,5 +1,14 @@
+ 2010-08-31 Jan Kratochvil <jan.kratochvil at redhat.com>
+
++ Make linux_get_siginfo_type `type *' unique.
++ * linux-tdep.c (linux_gdbarch_data_handle, struct linux_gdbarch_data)
++ (init_linux_gdbarch_data, get_linux_gdbarch_data): New.
++ (linux_get_siginfo_type): New variable linux_gdbarch_data. Initialize
++ it. Use linux_gdbarch_data->siginfo_type as a persistent storage.
++ (_initialize_linux_tdep): New.
++
++2010-08-31 Jan Kratochvil <jan.kratochvil at redhat.com>
++
+ Code cleanup.
+ * defs.h (find_memory_region_ftype): New typedef.
+ (exec_set_find_memory_regions): Use it.
+Index: gdb-7.2/gdb/linux-tdep.c
+===================================================================
+--- gdb-7.2.orig/gdb/linux-tdep.c 2010-09-25 15:30:50.000000000 +0200
++++ gdb-7.2/gdb/linux-tdep.c 2010-09-25 15:31:54.000000000 +0200
+@@ -26,18 +26,42 @@
+ #include "value.h"
+ #include "infcall.h"
+
++static struct gdbarch_data *linux_gdbarch_data_handle;
++
++struct linux_gdbarch_data
++ {
++ struct type *siginfo_type;
++ };
++
++static void *
++init_linux_gdbarch_data (struct gdbarch *gdbarch)
++{
++ return GDBARCH_OBSTACK_ZALLOC (gdbarch, struct linux_gdbarch_data);
++}
++
++static struct linux_gdbarch_data *
++get_linux_gdbarch_data (struct gdbarch *gdbarch)
++{
++ return gdbarch_data (gdbarch, linux_gdbarch_data_handle);
++}
++
+ /* This function is suitable for architectures that don't
+ extend/override the standard siginfo structure. */
+
+ struct type *
+ linux_get_siginfo_type (struct gdbarch *gdbarch)
+ {
++ struct linux_gdbarch_data *linux_gdbarch_data;
+ struct type *int_type, *uint_type, *long_type, *void_ptr_type;
+ struct type *uid_type, *pid_type;
+ struct type *sigval_type, *clock_type;
+ struct type *siginfo_type, *sifields_type;
+ struct type *type;
+
++ linux_gdbarch_data = get_linux_gdbarch_data (gdbarch);
++ if (linux_gdbarch_data->siginfo_type != NULL)
++ return linux_gdbarch_data->siginfo_type;
++
+ int_type = arch_integer_type (gdbarch, gdbarch_int_bit (gdbarch),
+ 0, "int");
+ uint_type = arch_integer_type (gdbarch, gdbarch_int_bit (gdbarch),
+@@ -137,6 +161,8 @@ linux_get_siginfo_type (struct gdbarch *
+ "_sifields", sifields_type,
+ TYPE_LENGTH (long_type));
+
++ linux_gdbarch_data->siginfo_type = siginfo_type;
++
+ return siginfo_type;
+ }
+
+@@ -154,3 +180,10 @@ linux_has_shared_address_space (void)
+
+ return target_is_uclinux;
+ }
++
++void
++_initialize_linux_tdep (void)
++{
++ linux_gdbarch_data_handle =
++ gdbarch_data_register_post_init (init_linux_gdbarch_data);
++}
diff --git a/gdb-bz592031-siginfo-lost-2of5.patch b/gdb-bz592031-siginfo-lost-2of5.patch
new file mode 100644
index 0000000..c5184e0
--- /dev/null
+++ b/gdb-bz592031-siginfo-lost-2of5.patch
@@ -0,0 +1,139 @@
+http://sourceware.org/ml/gdb-patches/2010-09/msg00430.html
+http://sourceware.org/ml/gdb-cvs/2010-09/msg00152.html
+
+### src/gdb/ChangeLog 2010/09/24 11:15:51 1.12199
+### src/gdb/ChangeLog 2010/09/24 13:41:42 1.12200
+## -1,5 +1,12 @@
+ 2010-09-24 Pedro Alves <pedro at codesourcery.com>
+
++ * amd64-linux-nat.c (compat_siginfo_from_siginfo)
++ (siginfo_from_compat_siginfo): Also copy si_pid and si_uid when
++ si_code is < 0. Check for si_code == SI_TIMER before checking for
++ si_code < 0.
++
++2010-09-24 Pedro Alves <pedro at codesourcery.com>
++
+ * objfiles.h (ALL_OBJSECTIONS): Handle breaks in the inner loop.
+
+ 2010-09-22 Joel Brobecker <brobecker at adacore.com>
+--- src/gdb/amd64-linux-nat.c 2010/04/22 20:02:55 1.32
++++ src/gdb/amd64-linux-nat.c 2010/09/24 13:41:43 1.33
+@@ -574,8 +574,10 @@
+ to->si_errno = from->si_errno;
+ to->si_code = from->si_code;
+
+- if (to->si_code < 0)
++ if (to->si_code == SI_TIMER)
+ {
++ to->cpt_si_timerid = from->si_timerid;
++ to->cpt_si_overrun = from->si_overrun;
+ to->cpt_si_ptr = (intptr_t) from->si_ptr;
+ }
+ else if (to->si_code == SI_USER)
+@@ -583,10 +585,10 @@
+ to->cpt_si_pid = from->si_pid;
+ to->cpt_si_uid = from->si_uid;
+ }
+- else if (to->si_code == SI_TIMER)
++ else if (to->si_code < 0)
+ {
+- to->cpt_si_timerid = from->si_timerid;
+- to->cpt_si_overrun = from->si_overrun;
++ to->cpt_si_pid = from->si_pid;
++ to->cpt_si_uid = from->si_uid;
+ to->cpt_si_ptr = (intptr_t) from->si_ptr;
+ }
+ else
+@@ -628,8 +630,10 @@
+ to->si_errno = from->si_errno;
+ to->si_code = from->si_code;
+
+- if (to->si_code < 0)
++ if (to->si_code == SI_TIMER)
+ {
++ to->si_timerid = from->cpt_si_timerid;
++ to->si_overrun = from->cpt_si_overrun;
+ to->si_ptr = (void *) (intptr_t) from->cpt_si_ptr;
+ }
+ else if (to->si_code == SI_USER)
+@@ -637,10 +641,10 @@
+ to->si_pid = from->cpt_si_pid;
+ to->si_uid = from->cpt_si_uid;
+ }
+- else if (to->si_code == SI_TIMER)
++ if (to->si_code < 0)
+ {
+- to->si_timerid = from->cpt_si_timerid;
+- to->si_overrun = from->cpt_si_overrun;
++ to->si_pid = from->cpt_si_pid;
++ to->si_uid = from->cpt_si_uid;
+ to->si_ptr = (void *) (intptr_t) from->cpt_si_ptr;
+ }
+ else
+### src/gdb/gdbserver/ChangeLog 2010/09/13 19:11:03 1.431
+### src/gdb/gdbserver/ChangeLog 2010/09/24 13:41:43 1.432
+## -1,3 +1,10 @@
++2010-09-24 Pedro Alves <pedro at codesourcery.com>
++
++ * linux-x86-low.c (compat_siginfo_from_siginfo)
++ (siginfo_from_compat_siginfo): Also copy si_pid and si_uid when
++ si_code is < 0. Check for si_code == SI_TIMER before checking for
++ si_code < 0.
++
+ 2010-09-13 Joel Brobecker <brobecker at adacore.com>
+
+ * lynx-i386-low.c: New file.
+--- src/gdb/gdbserver/linux-x86-low.c 2010/08/27 00:16:48 1.23
++++ src/gdb/gdbserver/linux-x86-low.c 2010/09/24 13:41:43 1.24
+@@ -792,8 +792,10 @@
+ to->si_errno = from->si_errno;
+ to->si_code = from->si_code;
+
+- if (to->si_code < 0)
++ if (to->si_code == SI_TIMER)
+ {
++ to->cpt_si_timerid = from->si_timerid;
++ to->cpt_si_overrun = from->si_overrun;
+ to->cpt_si_ptr = (intptr_t) from->si_ptr;
+ }
+ else if (to->si_code == SI_USER)
+@@ -801,10 +803,10 @@
+ to->cpt_si_pid = from->si_pid;
+ to->cpt_si_uid = from->si_uid;
+ }
+- else if (to->si_code == SI_TIMER)
++ else if (to->si_code < 0)
+ {
+- to->cpt_si_timerid = from->si_timerid;
+- to->cpt_si_overrun = from->si_overrun;
++ to->cpt_si_pid = from->si_pid;
++ to->cpt_si_uid = from->si_uid;
+ to->cpt_si_ptr = (intptr_t) from->si_ptr;
+ }
+ else
+@@ -846,8 +848,10 @@
+ to->si_errno = from->si_errno;
+ to->si_code = from->si_code;
+
+- if (to->si_code < 0)
++ if (to->si_code == SI_TIMER)
+ {
++ to->si_timerid = from->cpt_si_timerid;
++ to->si_overrun = from->cpt_si_overrun;
+ to->si_ptr = (void *) (intptr_t) from->cpt_si_ptr;
+ }
+ else if (to->si_code == SI_USER)
+@@ -855,10 +859,10 @@
+ to->si_pid = from->cpt_si_pid;
+ to->si_uid = from->cpt_si_uid;
+ }
+- else if (to->si_code == SI_TIMER)
++ else if (to->si_code < 0)
+ {
+- to->si_timerid = from->cpt_si_timerid;
+- to->si_overrun = from->cpt_si_overrun;
++ to->si_pid = from->cpt_si_pid;
++ to->si_uid = from->cpt_si_uid;
+ to->si_ptr = (void *) (intptr_t) from->cpt_si_ptr;
+ }
+ else
diff --git a/gdb-bz592031-siginfo-lost-3of5.patch b/gdb-bz592031-siginfo-lost-3of5.patch
new file mode 100644
index 0000000..e45c83d
--- /dev/null
+++ b/gdb-bz592031-siginfo-lost-3of5.patch
@@ -0,0 +1,259 @@
+http://sourceware.org/ml/gdb-patches/2010-09/msg00438.html
+http://sourceware.org/ml/gdb-cvs/2010-09/msg00156.html
+
+### src/gdb/ChangeLog 2010/09/24 16:11:44 1.12203
+### src/gdb/ChangeLog 2010/09/24 18:35:20 1.12204
+## -1,3 +1,16 @@
++2010-09-24 Jan Kratochvil <jan.kratochvil at redhat.com>
++
++ Fix lost siginfo_t for inferior calls.
++ * infrun.c
++ (struct inferior_thread_state) <siginfo_gdbarch, siginfo_data>: New.
++ (save_inferior_thread_state): New variables regcache, gdbarch and
++ siginfo_data. Initialize SIGINFO_DATA if gdbarch_get_siginfo_type_p.
++ Move INF_STATE allocation later, pre-clear it. Initialize REGISTERS
++ using REGCACHE.
++ (restore_inferior_thread_state): New variables regcache and gdbarch.
++ Restore SIGINFO_DATA for matching GDBARCH. Restore REGISTERS using
++ REGCACHE. Free also SIGINFO_DATA.
++
+ 2010-09-24 Tom Tromey <tromey at redhat.com>
+
+ * dwarf2read.c (dw2_expand_symtabs_matching): Add missing
+--- src/gdb/infrun.c 2010/09/06 14:22:07 1.450
++++ src/gdb/infrun.c 2010/09/24 18:35:27 1.451
+@@ -6037,18 +6037,57 @@
+ enum target_signal stop_signal;
+ CORE_ADDR stop_pc;
+ struct regcache *registers;
++
++ /* Format of SIGINFO or NULL if it is not present. */
++ struct gdbarch *siginfo_gdbarch;
++
++ /* The inferior format depends on SIGINFO_GDBARCH and it has a length of
++ TYPE_LENGTH (gdbarch_get_siginfo_type ()). For different gdbarch the
++ content would be invalid. */
++ gdb_byte *siginfo_data;
+ };
+
+ struct inferior_thread_state *
+ save_inferior_thread_state (void)
+ {
+- struct inferior_thread_state *inf_state = XMALLOC (struct inferior_thread_state);
++ struct inferior_thread_state *inf_state;
+ struct thread_info *tp = inferior_thread ();
++ struct regcache *regcache = get_current_regcache ();
++ struct gdbarch *gdbarch = get_regcache_arch (regcache);
++ gdb_byte *siginfo_data = NULL;
++
++ if (gdbarch_get_siginfo_type_p (gdbarch))
++ {
++ struct type *type = gdbarch_get_siginfo_type (gdbarch);
++ size_t len = TYPE_LENGTH (type);
++ struct cleanup *back_to;
++
++ siginfo_data = xmalloc (len);
++ back_to = make_cleanup (xfree, siginfo_data);
++
++ if (target_read (¤t_target, TARGET_OBJECT_SIGNAL_INFO, NULL,
++ siginfo_data, 0, len) == len)
++ discard_cleanups (back_to);
++ else
++ {
++ /* Errors ignored. */
++ do_cleanups (back_to);
++ siginfo_data = NULL;
++ }
++ }
++
++ inf_state = XZALLOC (struct inferior_thread_state);
++
++ if (siginfo_data)
++ {
++ inf_state->siginfo_gdbarch = gdbarch;
++ inf_state->siginfo_data = siginfo_data;
++ }
+
+ inf_state->stop_signal = tp->stop_signal;
+ inf_state->stop_pc = stop_pc;
+
+- inf_state->registers = regcache_dup (get_current_regcache ());
++ inf_state->registers = regcache_dup (regcache);
+
+ return inf_state;
+ }
+@@ -6059,16 +6098,29 @@
+ restore_inferior_thread_state (struct inferior_thread_state *inf_state)
+ {
+ struct thread_info *tp = inferior_thread ();
++ struct regcache *regcache = get_current_regcache ();
++ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+
+ tp->stop_signal = inf_state->stop_signal;
+ stop_pc = inf_state->stop_pc;
+
++ if (inf_state->siginfo_gdbarch == gdbarch)
++ {
++ struct type *type = gdbarch_get_siginfo_type (gdbarch);
++ size_t len = TYPE_LENGTH (type);
++
++ /* Errors ignored. */
++ target_write (¤t_target, TARGET_OBJECT_SIGNAL_INFO, NULL,
++ inf_state->siginfo_data, 0, len);
++ }
++
+ /* The inferior can be gone if the user types "print exit(0)"
+ (and perhaps other times). */
+ if (target_has_execution)
+ /* NB: The register write goes through to the target. */
+- regcache_cpy (get_current_regcache (), inf_state->registers);
++ regcache_cpy (regcache, inf_state->registers);
+ regcache_xfree (inf_state->registers);
++ xfree (inf_state->siginfo_data);
+ xfree (inf_state);
+ }
+
+### src/gdb/testsuite/ChangeLog 2010/09/22 20:08:04 1.2456
+### src/gdb/testsuite/ChangeLog 2010/09/24 18:35:28 1.2457
+## -1,3 +1,9 @@
++2010-09-24 Jan Kratochvil <jan.kratochvil at redhat.com>
++
++ Fix lost siginfo_t for inferior calls.
++ * gdb.base/siginfo-infcall.exp: New file.
++ * gdb.base/siginfo-infcall.c: New file.
++
+ 2010-09-22 Joel Brobecker <brobecker at adacore.com>
+
+ * gdb.dwarf2/dw2-const.S: Minor (space) reformatting.
+--- src/gdb/testsuite/gdb.base/siginfo-infcall.c
++++ src/gdb/testsuite/gdb.base/siginfo-infcall.c 2010-09-25 13:25:25.007169000 +0000
+@@ -0,0 +1,79 @@
++/* 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/>. */
++
++#include <signal.h>
++#include <assert.h>
++#include <string.h>
++#include <unistd.h>
++
++#ifndef SA_SIGINFO
++# error "SA_SIGINFO is required for this test"
++#endif
++
++static int
++callme (void)
++{
++ return 42;
++}
++
++static int
++pass (void)
++{
++ return 1;
++}
++
++static int
++fail (void)
++{
++ return 1;
++}
++
++static void
++handler (int sig, siginfo_t *siginfo, void *context)
++{
++ assert (sig == SIGUSR1);
++ assert (siginfo->si_signo == SIGUSR1);
++ if (siginfo->si_pid == getpid ())
++ pass ();
++ else
++ fail ();
++}
++
++int
++main (void)
++{
++ struct sigaction sa;
++ int i;
++
++ callme ();
++
++ memset (&sa, 0, sizeof (sa));
++ sa.sa_sigaction = handler;
++ sa.sa_flags = SA_SIGINFO;
++
++ i = sigemptyset (&sa.sa_mask);
++ assert (i == 0);
++
++ i = sigaction (SIGUSR1, &sa, NULL);
++ assert (i == 0);
++
++ i = raise (SIGUSR1);
++ assert (i == 0);
++
++ sleep (600);
++ return 0;
++}
+--- src/gdb/testsuite/gdb.base/siginfo-infcall.exp
++++ src/gdb/testsuite/gdb.base/siginfo-infcall.exp 2010-09-25 13:25:25.357724000 +0000
+@@ -0,0 +1,47 @@
++# 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/>.
++
++if [target_info exists gdb,nosignals] {
++ verbose "Skipping siginfo-infcall.exp because of nosignals."
++ continue
++}
++
++set testfile siginfo-infcall
++set srcfile ${testfile}.c
++set executable ${testfile}
++if { [prepare_for_testing ${testfile}.exp $executable] } {
++ return -1
++}
++
++if ![runto_main] {
++ return -1
++}
++
++gdb_breakpoint "pass"
++gdb_breakpoint "fail"
++
++gdb_test "continue" "Program received signal SIGUSR1, .*" "continue to SIGUSR1"
++
++gdb_test "p callme ()" " = 42"
++
++set test "continue to the handler"
++gdb_test_multiple "continue" $test {
++ -re "Breakpoint \[0-9\]+,\[^\r\n\]* pass .*\r\n$gdb_prompt $" {
++ pass $test
++ }
++ -re "Breakpoint \[0-9\]+,\[^\r\n\]* fail .*\r\n$gdb_prompt $" {
++ fail $test
++ }
++}
diff --git a/gdb-bz592031-siginfo-lost-4of5.patch b/gdb-bz592031-siginfo-lost-4of5.patch
new file mode 100644
index 0000000..a73ab33
--- /dev/null
+++ b/gdb-bz592031-siginfo-lost-4of5.patch
@@ -0,0 +1,992 @@
+http://sourceware.org/ml/gdb-patches/2010-09/msg00360.html
+Subject: [patch 3/4]#3 linux-nat: Do not respawn signals
+
+Hi,
+
+linux-nat.c is fixed to never respawn signals; possibly keeping SIGSTOP
+pending, as is done in current in FSF gdbserver and as suggested by Pedro:
+ http://sourceware.org/ml/gdb-patches/2010-08/msg00544.html
+
+The last linux-nat.c removed patch chunk comes from the initial implementation
+by Mark Kettenis:
+ [PATCH] New Linux threads support
+ http://sourceware.org/ml/gdb-patches/2000-09/msg00020.html
+ 92280a75e017683bf8e4f339f4f85640b0700509
+It gets in part reimplemented into the new stop_wait_callback <if (lp->step)>
+part and partially just not needed as currently GDB never drops the signals as
+it does not PTRACE_CONT the thread; signal is kept for processing:
+ "RC: Not resuming sibling %s (has pending)\n"
+
+In stop_wait_callback I believe breakpoints cancellation is not needed here,
+it would be done later.
+
+
+The testcase sigstep-threads.exp was written to catch a regression-like
+appearance then the new <if (lp->step)> part of stop_wait_callback gets
+removed. Still the tecase fails even with FSF HEAD:
+
+32 var++; /* step-1 */
+(gdb) step
+Program received signal SIGUSR1, User defined signal 1.
+Program received signal SIGUSR1, User defined signal 1.
+31 { /* step-0 */
+
+There is no reason why it shouldn't stop on line 33, between line 32 and line
+33 no signal would occur. Stepping of the current thread should not be
+affected by whatever happens in the other threads as select_event_lwp has:
+ /* Give preference to any LWP that is being single-stepped. */
+
+There is a problem that with FSF HEAD GDB does PTRACE_SINGLESTEP for thread A,
+PTRACE_CONT for thread B (because of set scheduler-locking off), thread B hits
+SIGUSR1, so GDB tkills thread A with SIGSTOP and it can receive SIGSTOP for
+thread A before the SIGTRAP for completed PTRACE_SINGLESTEP. At that moment
+select_event_lwp. forgets it was stepping thread A because there is no pending
+SIGTRAP event. currently_stepping still remembers thread A was stepping so it
+will later stop but as thread A was PTRACE_CONT-ed in the meantime it is too
+late.
+
+There is the new <if (lp->step)> part of stop_wait_callback to always track
+thread A is stepping. Due to different scheduling without this part the
+changed GDB would very rarely stop in this testcase otherwise, making it look
+as a regression.
+
+I have some another patch I may post separately as if multiple signals happen
+besides SIGTRAP GDB still may switch from thread A away (as not considering it
+stepping) to thread B for SIGUSR and accidentally PTRACE_CONT thread A.
+But I do not find this as a prerequisite for this patchset.
+
+
+
+Thanks,
+Jan
+
+
+gdb/
+2010-09-20 Jan Kratochvil <jan.kratochvil at redhat.com>
+
+ * linux-nat.c (stop_wait_callback): New gdb_assert. Remove signals
+ respawning; keep TP with SIGNALLED. New debugging message "SWC:
+ Delayed SIGSTOP caught for %s.". Catch next signal if SIGSTOP has
+ been caught and LP->STEP is set.
+ (linux_nat_wait_1) <lp && lp->signalled>: Remove.
+
+gdb/testsuite/
+2010-09-20 Jan Kratochvil <jan.kratochvil at redhat.com>
+
+ * gdb.threads/siginfo-threads.exp: New file.
+ * gdb.threads/siginfo-threads.c: New file.
+ * gdb.threads/sigstep-threads.exp: New file.
+ * gdb.threads/sigstep-threads.c: New file.
+
+Index: gdb-7.2/gdb/linux-nat.c
+===================================================================
+--- gdb-7.2.orig/gdb/linux-nat.c 2010-09-25 15:30:54.000000000 +0200
++++ gdb-7.2/gdb/linux-nat.c 2010-09-25 15:37:23.000000000 +0200
+@@ -2702,6 +2702,8 @@ stop_wait_callback (struct lwp_info *lp,
+ {
+ int status;
+
++ gdb_assert (lp->resumed);
++
+ status = wait_lwp (lp);
+ if (status == 0)
+ return 0;
+@@ -2726,110 +2728,61 @@ stop_wait_callback (struct lwp_info *lp,
+
+ if (WSTOPSIG (status) != SIGSTOP)
+ {
+- if (WSTOPSIG (status) == SIGTRAP)
+- {
+- /* If a LWP other than the LWP that we're reporting an
+- event for has hit a GDB breakpoint (as opposed to
+- some random trap signal), then just arrange for it to
+- hit it again later. We don't keep the SIGTRAP status
+- and don't forward the SIGTRAP signal to the LWP. We
+- will handle the current event, eventually we will
+- resume all LWPs, and this one will get its breakpoint
+- trap again.
+-
+- If we do not do this, then we run the risk that the
+- 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);
+-
+- save_sigtrap (lp);
+-
+- /* Now resume this LWP and get the SIGSTOP event. */
+- errno = 0;
+- ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
+- if (debug_linux_nat)
+- {
+- fprintf_unfiltered (gdb_stdlog,
+- "PTRACE_CONT %s, 0, 0 (%s)\n",
+- target_pid_to_str (lp->ptid),
+- errno ? safe_strerror (errno) : "OK");
+-
+- fprintf_unfiltered (gdb_stdlog,
+- "SWC: Candidate SIGTRAP event in %s\n",
+- target_pid_to_str (lp->ptid));
+- }
+- /* Hold this event/waitstatus while we check to see if
+- there are any more (we still want to get that SIGSTOP). */
+- stop_wait_callback (lp, NULL);
++ /* The thread was stopped with a signal other than SIGSTOP. */
+
+- /* Hold the SIGTRAP for handling by linux_nat_wait. If
+- there's another event, throw it back into the
+- queue. */
+- if (lp->status)
+- {
+- if (debug_linux_nat)
+- fprintf_unfiltered (gdb_stdlog,
+- "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));
+- }
++ /* Save the trap's siginfo in case we need it later. */
++ save_siginfo (lp);
+
+- /* Save the sigtrap event. */
+- lp->status = status;
+- return 0;
+- }
+- else
+- {
+- /* The thread was stopped with a signal other than
+- SIGSTOP, and didn't accidentally trip a breakpoint. */
++ save_sigtrap (lp);
+
+- if (debug_linux_nat)
+- {
+- fprintf_unfiltered (gdb_stdlog,
+- "SWC: Pending event %s in %s\n",
+- status_to_str ((int) status),
+- target_pid_to_str (lp->ptid));
+- }
+- /* Now resume this LWP and get the SIGSTOP event. */
+- errno = 0;
+- ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
+- if (debug_linux_nat)
+- fprintf_unfiltered (gdb_stdlog,
+- "SWC: PTRACE_CONT %s, 0, 0 (%s)\n",
+- target_pid_to_str (lp->ptid),
+- errno ? safe_strerror (errno) : "OK");
+-
+- /* Hold this event/waitstatus while we check to see if
+- there are any more (we still want to get that SIGSTOP). */
+- stop_wait_callback (lp, NULL);
++ if (debug_linux_nat)
++ fprintf_unfiltered (gdb_stdlog,
++ "SWC: Pending event %s in %s\n",
++ status_to_str ((int) status),
++ target_pid_to_str (lp->ptid));
+
+- /* If the lp->status field is still empty, use it to
+- hold this event. If not, then this event must be
+- returned to the event queue of the LWP. */
+- if (lp->status)
+- {
+- if (debug_linux_nat)
+- {
+- fprintf_unfiltered (gdb_stdlog,
+- "SWC: kill %s, %s\n",
+- target_pid_to_str (lp->ptid),
+- status_to_str ((int) status));
+- }
+- kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (status));
+- }
+- else
+- lp->status = status;
+- return 0;
+- }
++ /* Save the sigtrap event. */
++ lp->status = status;
++ gdb_assert (! lp->stopped);
++ gdb_assert (lp->signalled);
++ lp->stopped = 1;
+ }
+ else
+ {
+ /* We caught the SIGSTOP that we intended to catch, so
+ there's no SIGSTOP pending. */
+- lp->stopped = 1;
++
++ if (debug_linux_nat)
++ fprintf_unfiltered (gdb_stdlog,
++ "SWC: Delayed SIGSTOP caught for %s.\n",
++ target_pid_to_str (lp->ptid));
++
++ if (lp->step)
++ {
++ /* LP->STATUS is 0 here. That means SIGTRAP from
++ PTRACE_SINGLESTEP still has to be delivered for this inferior
++ stop. Catching the SIGTRAP event is important to prevent
++ starvation in select_event_lwp. */
++
++ registers_changed ();
++ linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
++ 1, TARGET_SIGNAL_0);
++ if (debug_linux_nat)
++ fprintf_unfiltered (gdb_stdlog,
++ "SWC: %s %s, 0, 0 (discard SIGSTOP)\n",
++ "PTRACE_SINGLESTEP",
++ target_pid_to_str (lp->ptid));
++
++ lp->stopped = 0;
++ gdb_assert (lp->resumed);
++ stop_wait_callback (lp, NULL);
++ gdb_assert (lp->stopped);
++ }
++ else
++ lp->stopped = 1;
++
++ /* Reset SIGNALLED only after the stop_wait_callback call above as
++ it does gdb_assert on SIGNALLED. */
+ lp->signalled = 0;
+ }
+ }
+@@ -3416,52 +3369,6 @@ retry:
+ lp = NULL;
+ }
+
+- if (lp && lp->signalled)
+- {
+- /* A pending SIGSTOP may interfere with the normal stream of
+- events. In a typical case where interference is a problem,
+- we have a SIGSTOP signal pending for LWP A while
+- single-stepping it, encounter an event in LWP B, and take the
+- pending SIGSTOP while trying to stop LWP A. After processing
+- the event in LWP B, LWP A is continued, and we'll never see
+- the SIGTRAP associated with the last time we were
+- single-stepping LWP A. */
+-
+- /* Resume the thread. It should halt immediately returning the
+- pending SIGSTOP. */
+- registers_changed ();
+- linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
+- lp->step, TARGET_SIGNAL_0);
+- if (debug_linux_nat)
+- fprintf_unfiltered (gdb_stdlog,
+- "LLW: %s %s, 0, 0 (expect SIGSTOP)\n",
+- lp->step ? "PTRACE_SINGLESTEP" : "PTRACE_CONT",
+- target_pid_to_str (lp->ptid));
+- lp->stopped = 0;
+- gdb_assert (lp->resumed);
+-
+- /* Catch the pending SIGSTOP. */
+- status = lp->status;
+- lp->status = 0;
+-
+- stop_wait_callback (lp, NULL);
+-
+- /* If the lp->status field isn't empty, we caught another signal
+- while flushing the SIGSTOP. Return it back to the event
+- queue of the LWP, as we already have an event to handle. */
+- if (lp->status)
+- {
+- if (debug_linux_nat)
+- fprintf_unfiltered (gdb_stdlog,
+- "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));
+- }
+-
+- lp->status = status;
+- }
+-
+ if (!target_can_async_p ())
+ {
+ /* Causes SIGINT to be passed on to the attached process. */
+Index: gdb-7.2/gdb/testsuite/gdb.threads/siginfo-threads.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ gdb-7.2/gdb/testsuite/gdb.threads/siginfo-threads.c 2010-09-25 15:32:32.000000000 +0200
+@@ -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;
++}
+Index: gdb-7.2/gdb/testsuite/gdb.threads/siginfo-threads.exp
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ gdb-7.2/gdb/testsuite/gdb.threads/siginfo-threads.exp 2010-09-25 15:32:32.000000000 +0200
+@@ -0,0 +1,94 @@
++# 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 stop print pass" "Signal\[ \t\]+Stop\[ \t\]+Print\[ \t\]+Pass to program\[ \t\]+Description\r\nSIGUSR1\[ \t\]+Yes\[ \t\]+Yes\[ \t\]+Yes\[ \t\].*"
++gdb_test "handle SIGUSR2 stop print pass" "Signal\[ \t\]+Stop\[ \t\]+Print\[ \t\]+Pass to program\[ \t\]+Description\r\nSIGUSR2\[ \t\]+Yes\[ \t\]+Yes\[ \t\]+Yes\[ \t\].*"
++
++gdb_breakpoint [gdb_get_line_number "break-at-exit"]
++
++set test "get pid"
++gdb_test_multiple "p getpid ()" $test {
++ -re " = (\[0-9\]+)\r\n$gdb_prompt $" {
++ set pid $expect_out(1,string)
++ pass $test
++ }
++}
++
++for {set sigcount 0} {$sigcount < 4} {incr sigcount} {
++ set test "catch signal $sigcount"
++ set sigusr ""
++ gdb_test_multiple "continue" $test {
++ -re "Program received signal SIGUSR(\[12\]), User defined signal \[12\]\\.\r\n.*\r\n$gdb_prompt $" {
++ set sigusr $expect_out(1,string)
++ pass $test
++ }
++ }
++ if {$sigusr == ""} {
++ return -1
++ }
++
++ set test "signal $sigcount si_signo"
++ if {$sigusr == 1} {
++ set signo 10
++ } else {
++ set signo 12
++ }
++ gdb_test_multiple {p $_siginfo.si_signo} $test {
++ -re " = $signo\r\n$gdb_prompt $" {
++ pass $test
++ }
++ -re "Attempt to extract a component of a value that is not a structure\\.\r\n$gdb_prompt $" {
++ unsupported $test
++ }
++ }
++
++ set test "signal $sigcount si_code is SI_TKILL"
++ gdb_test_multiple {p $_siginfo.si_code} $test {
++ -re " = -6\r\n$gdb_prompt $" {
++ pass $test
++ }
++ -re "Attempt to extract a component of a value that is not a structure\\.\r\n$gdb_prompt $" {
++ unsupported $test
++ }
++ }
++
++ set test "signal $sigcount si_pid"
++ gdb_test_multiple {p $_siginfo._sifields._kill.si_pid} $test {
++ -re " = $pid\r\n$gdb_prompt $" {
++ pass $test
++ }
++ -re "Attempt to extract a component of a value that is not a structure\\.\r\n$gdb_prompt $" {
++ unsupported $test
++ }
++ }
++}
++
++gdb_continue_to_breakpoint break-at-exit ".*break-at-exit.*"
+Index: gdb-7.2/gdb/testsuite/gdb.threads/sigstep-threads.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ gdb-7.2/gdb/testsuite/gdb.threads/sigstep-threads.c 2010-09-25 15:32:32.000000000 +0200
+@@ -0,0 +1,54 @@
++/* 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/>. */
++
++#include <pthread.h>
++#include <assert.h>
++#include <signal.h>
++
++#include <asm/unistd.h>
++#include <unistd.h>
++#define tgkill(tgid, tid, sig) syscall (__NR_tgkill, (tgid), (tid), (sig))
++#define gettid() syscall (__NR_gettid)
++
++static volatile int var;
++
++static void
++handler (int signo) /* step-0 */
++{ /* step-0 */
++ var++; /* step-1 */
++ tgkill (getpid (), gettid (), SIGUSR1); /* step-2 */
++}
++
++static void *
++start (void *arg)
++{
++ signal (SIGUSR1, handler);
++ tgkill (getpid (), gettid (), SIGUSR1);
++ assert (0);
++
++ return NULL;
++}
++
++int
++main (void)
++{
++ pthread_t thread;
++
++ pthread_create (&thread, NULL, start, NULL);
++ start (NULL); /* main-start */
++ return 0;
++}
+Index: gdb-7.2/gdb/testsuite/gdb.threads/sigstep-threads.exp
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ gdb-7.2/gdb/testsuite/gdb.threads/sigstep-threads.exp 2010-09-25 15:32:32.000000000 +0200
+@@ -0,0 +1,74 @@
++# 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 sigstep-threads
++set srcfile ${testfile}.c
++set executable ${testfile}
++set binfile ${objdir}/${subdir}/${executable}
++
++if { [gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
++ untested ${testfile}.exp
++ return -1
++}
++
++clean_restart $executable
++
++if ![runto_main] {
++ return -1;
++}
++
++# `noprint' would not test the full logic of GDB.
++gdb_test "handle SIGUSR1 nostop print pass" "\r\nSIGUSR1\[ \t\]+No\[ \t\]+Yes\[ \t\]+Yes\[ \t\].*"
++
++gdb_test_no_output "set scheduler-locking off"
++
++gdb_breakpoint [gdb_get_line_number "step-1"]
++gdb_test_no_output {set $step1=$bpnum}
++gdb_continue_to_breakpoint "step-1" ".* step-1 .*"
++gdb_test_no_output {disable $step1}
++
++# 1 as we are now stopped at the `step-1' label.
++set step_at 1
++for {set i 0} {$i < 100} {incr i} {
++ set test "step $i"
++ # Presume this step failed - as in the case of a timeout.
++ set failed 1
++ gdb_test_multiple "step" $test {
++ -re "\r\nProgram received signal SIGUSR1, User defined signal 1.\r\n" {
++ exp_continue -continue_timer
++ }
++ -re "step-(\[012\]).*\r\n$gdb_prompt $" {
++ set now $expect_out(1,string)
++ if {$step_at == 2 && $now == 1} {
++ set failed 0
++ } elseif {$step_at == 1 && $now == 2} {
++ set failed 0
++ # Continue over the re-signalling back to the handle entry.
++ gdb_test_no_output {enable $step1} ""
++ gdb_test "continue" " step-1 .*" ""
++ set now 1
++ gdb_test_no_output {disable $step1} ""
++ } else {
++ fail $test
++ }
++ set step_at $now
++ }
++ }
++ if $failed {
++ return
++ }
++}
++# We can never reliably say the racy problematic case has been tested.
++pass "step"
diff --git a/gdb-bz592031-siginfo-lost-5of5.patch b/gdb-bz592031-siginfo-lost-5of5.patch
new file mode 100644
index 0000000..6bf93ef
--- /dev/null
+++ b/gdb-bz592031-siginfo-lost-5of5.patch
@@ -0,0 +1,141 @@
+http://sourceware.org/ml/gdb-patches/2010-09/msg00361.html
+Subject: [patch 4/4]#3 Remove redundant lp->siginfo
+
+Hi,
+
+this is a simplification which should not affect GDB behavior. As linux-nat
+now stops on each received signal without any reordering of them then
+PTRACE_GETSIGINFO is enough to access siginfo, without any need to copy it in
+advance.
+
+
+Thanks,
+Jan
+
+
+gdb/
+2010-09-20 Jan Kratochvil <jan.kratochvil at redhat.com>
+
+ * linux-nat.c (resume_callback) <lp->stopped && lp->status == 0>
+ (linux_nat_resume): Remove LP->SIGINFO clearing.
+ (save_siginfo): Remove.
+ (stop_wait_callback) <WSTOPSIG (status) != SIGSTOP>
+ (linux_nat_filter_event) <linux_nat_status_is_event (status)>: Remove
+ the save_siginfo call.
+ (resume_stopped_resumed_lwps): Remove LP->SIGINFO clearing.
+ (linux_nat_set_siginfo_fixup): Use PTRACE_GETSIGINFO.
+ * linux-nat.h (struct lwp_info) <siginfo>: Remove.
+
+Index: gdb-7.2/gdb/linux-nat.c
+===================================================================
+--- gdb-7.2.orig/gdb/linux-nat.c 2010-09-25 15:37:23.000000000 +0200
++++ gdb-7.2/gdb/linux-nat.c 2010-09-25 15:38:18.000000000 +0200
+@@ -1851,7 +1851,6 @@ resume_callback (struct lwp_info *lp, vo
+ target_pid_to_str (lp->ptid));
+ lp->stopped = 0;
+ lp->step = 0;
+- memset (&lp->siginfo, 0, sizeof (lp->siginfo));
+ lp->stopped_by_watchpoint = 0;
+ }
+ else if (lp->stopped && debug_linux_nat)
+@@ -1993,7 +1992,6 @@ 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->stopped_by_watchpoint = 0;
+
+ if (debug_linux_nat)
+@@ -2483,22 +2481,6 @@ wait_lwp (struct lwp_info *lp)
+ 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
+@@ -2730,9 +2712,6 @@ stop_wait_callback (struct lwp_info *lp,
+ {
+ /* The thread was stopped with a signal other than SIGSTOP. */
+
+- /* Save the trap's siginfo in case we need it later. */
+- save_siginfo (lp);
+-
+ save_sigtrap (lp);
+
+ if (debug_linux_nat)
+@@ -3102,12 +3081,7 @@ linux_nat_filter_event (int lwpid, int s
+ }
+
+ if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP)
+- {
+- /* Save the trap's siginfo in case we need it later. */
+- save_siginfo (lp);
+-
+- save_sigtrap (lp);
+- }
++ save_sigtrap (lp);
+
+ /* Check if the thread has exited. */
+ if ((WIFEXITED (status) || WIFSIGNALED (status))
+@@ -3706,7 +3680,6 @@ resume_stopped_resumed_lwps (struct lwp_
+ 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->stopped_by_watchpoint = 0;
+ }
+
+@@ -5878,11 +5851,19 @@ linux_nat_set_siginfo_fixup (struct targ
+ struct siginfo *
+ linux_nat_get_siginfo (ptid_t ptid)
+ {
+- struct lwp_info *lp = find_lwp_pid (ptid);
++ static struct siginfo siginfo;
++ int pid;
+
+- gdb_assert (lp != NULL);
++ pid = GET_LWP (ptid);
++ if (pid == 0)
++ pid = GET_PID (ptid);
++
++ errno = 0;
++ ptrace (PTRACE_GETSIGINFO, pid, (PTRACE_TYPE_ARG3) 0, &siginfo);
++ if (errno != 0)
++ memset (&siginfo, 0, sizeof (siginfo));
+
+- return &lp->siginfo;
++ return &siginfo;
+ }
+
+ /* Provide a prototype to silence -Wmissing-prototypes. */
+Index: gdb-7.2/gdb/linux-nat.h
+===================================================================
+--- gdb-7.2.orig/gdb/linux-nat.h 2010-09-25 15:30:50.000000000 +0200
++++ gdb-7.2/gdb/linux-nat.h 2010-09-25 15:37:57.000000000 +0200
+@@ -58,10 +58,6 @@ struct lwp_info
+ /* The kind of stepping of this LWP. */
+ enum resume_step 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;
diff --git a/gdb.spec b/gdb.spec
index 40436da..59ad980 100644
--- a/gdb.spec
+++ b/gdb.spec
@@ -27,7 +27,7 @@ Version: 7.2
# The release always contains a leading reserved number, start it at 1.
# `upstream' is not a part of `name' to stay fully rpm dependencies compatible for the testing.
-Release: 11%{?_with_upstream:.upstream}%{dist}
+Release: 12%{?_with_upstream:.upstream}%{dist}
License: GPLv3+ and GPLv3+ with exceptions and GPLv2+ and GPLv2+ with exceptions and GPL+ and LGPLv2+ and GFDL and BSD and Public Domain
Group: Development/Debuggers
@@ -441,6 +441,13 @@ Patch504: gdb-bz623749-gcore-relro.patch
# Fix infinite loop crash on self-referencing class (BZ 627432).
Patch506: gdb-bz627432-loop-static-self-class.patch
+# Fix lost siginfo_t in linux-nat (BZ 592031).
+Patch507: gdb-bz592031-siginfo-lost-1of5.patch
+Patch508: gdb-bz592031-siginfo-lost-2of5.patch
+Patch509: gdb-bz592031-siginfo-lost-3of5.patch
+Patch510: gdb-bz592031-siginfo-lost-4of5.patch
+Patch511: gdb-bz592031-siginfo-lost-5of5.patch
+
BuildRequires: ncurses-devel%{?_isa} texinfo gettext flex bison expat-devel%{?_isa}
Requires: readline%{?_isa}
BuildRequires: readline-devel%{?_isa}
@@ -704,6 +711,11 @@ rm -f gdb/jv-exp.c gdb/m2-exp.c gdb/objc-exp.c gdb/p-exp.c
%patch503 -p1
%patch504 -p1
%patch506 -p1
+%patch507 -p1
+%patch508 -p1
+%patch509 -p1
+%patch510 -p1
+%patch511 -p1
%patch393 -p1
%patch335 -p1
@@ -1088,6 +1100,9 @@ fi
%endif
%changelog
+* Sat Sep 25 2010 Jan Kratochvil <jan.kratochvil at redhat.com> - 7.2-12.fc14
+- Fix lost siginfo_t in linux-nat (BZ 592031).
+
* Sat Sep 25 2010 Jan Kratochvil <jan.kratochvil at redhat.com> - 7.2-11.fc14
- Fix infinite loop crash on self-referencing class (BZ 627432).
More information about the scm-commits
mailing list