summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2016-08-04 17:40:26 +0100
committerPedro Alves <palves@redhat.com>2016-08-04 17:40:26 +0100
commit4265c12fbbf4e7b181e3136ecbe1644121242abc (patch)
tree2070e80b92c6a683ad45f22d2647c0ceb9569155
parent6f67973b4280cfd045e632a3340becd16e43b4b1 (diff)
downloadbinutils-gdb-users/palves/restore-signal-dispositions.tar.gz
Fix PR gdb/18653: gdb disturbs inferior's inherited signal dispositionsusers/palves/restore-signal-dispositions
Today I was helping Phil debug something on the new C++ compile support, and we noticed that when debugging gdb under gdb, the inferior gdb behaved differently compared to when it was not being debugged. Turned out to be a manifestation of PR gdb/18653. Since the exec family of functions do not reset the signal disposition of signals that are set to SIG_IGN: http://pubs.opengroup.org/onlinepubs/7908799/xsh/execve.html Signals set to the default action (SIG_DFL) in the calling process image are set to the default action in the new process image. Signals set to be ignored (SIG_IGN) by the calling process image are set to be ignored by the new process image. Signals set to be caught by the calling process image are set to the default action in the new process image (see <signal.h>). gdb's (or gdbserver's) own signal handling should not interfere with the signal dispositions their spawned children inherit. However, it currently does. For example, some paths in gdb cause SIGPIPE to be set to SIG_IGN, and as consequence, the child starts with SIGPIPE to set to SIG_IGN too, even though gdb was started with SIGPIPE set to SIG_DFL. In order to be transparent, when spawning new child processes to debug (with "run", etc.), reset all signal dispositions back to what was originally inherited from gdb/gdbserver's parent, just before execing the target program to debug. gdb/ChangeLog: yyyy-mm-dd Pedro Alves <palves@redhat.com> PR gdb/18653 * Makefile.in (SFILES): Add common/signal-dispositions-save-restore.c. (HFILES_NO_SRCDIR): Add common/signal-dispositions-save-restore.h. (COMMON_OBS): Add signal-dispositions-save-restore.o. (signal-dispositions-save-restore.o): New rule. * configure: Regenerate. * fork-child.c: Include "signal-dispositions-save-restore.h". (fork_inferior): Call restore_original_signal_dispositions. * main.c: Include "signal-dispositions-save-restore.h". (captured_main): Call save_original_signal_dispositions. * common/common.m4: Add sigaction to AC_CHECK_FUNCS checks. * common/signal-dispositions-save-restore.c: New file. * common/signal-dispositions-save-restore.h: New file. gdb/gdbserver/ChangeLog: yyyy-mm-dd Pedro Alves <palves@redhat.com> PR gdb/18653 * Makefile.in (OBS): Add signal-dispositions-save-restore.o. (signal-dispositions-save-restore.o): New rule. * config.in: Regenerate. * configure: Regenerate. * linux-low.c: Include "signal-dispositions-save-restore.h". (linux_create_inferior): Call restore_original_signal_dispositions. * server.c: Include "signal-dispositions-save-restore.h". (captured_main): Call save_original_signal_dispositions. gdb/testsuite/ChangeLog: yyyy-mm-dd Pedro Alves <palves@redhat.com> PR gdb/18653 * gdb.base/signal-dispositions-child.c: New file. * gdb.base/signal-dispositions-child.exp: New file. * gdb.gdb/selftest.exp (do_steps_and_nexts): Add new pattern.
-rw-r--r--gdb/Makefile.in9
-rw-r--r--gdb/common/common.m42
-rw-r--r--gdb/common/signal-dispositions-save-restore.c65
-rw-r--r--gdb/common/signal-dispositions-save-restore.h40
-rwxr-xr-xgdb/configure2
-rw-r--r--gdb/fork-child.c4
-rw-r--r--gdb/gdbserver/Makefile.in4
-rw-r--r--gdb/gdbserver/config.in3
-rwxr-xr-xgdb/gdbserver/configure2
-rw-r--r--gdb/gdbserver/linux-low.c4
-rw-r--r--gdb/gdbserver/server.c4
-rw-r--r--gdb/main.c2
-rw-r--r--gdb/testsuite/gdb.base/signal-dispositions-child.c62
-rw-r--r--gdb/testsuite/gdb.base/signal-dispositions-child.exp80
-rw-r--r--gdb/testsuite/gdb.gdb/selftest.exp4
15 files changed, 280 insertions, 7 deletions
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 5af61036e8e..20549de1de7 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -897,6 +897,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
target/waitstatus.c common/print-utils.c common/rsp-low.c \
common/errors.c common/common-debug.c common/common-exceptions.c \
common/btrace-common.c common/fileio.c common/common-regcache.c \
+ common/signal-dispositions-save-restore.c \
$(SUBDIR_GCC_COMPILE_SRCS)
LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
@@ -989,7 +990,8 @@ common/common-exceptions.h target/target.h common/symbol.h \
common/common-regcache.h fbsd-tdep.h nat/linux-personality.h \
common/fileio.h nat/x86-linux.h nat/x86-linux-dregs.h nat/amd64-linux-siginfo.h\
nat/linux-namespaces.h arch/arm.h common/gdb_sys_time.h arch/aarch64-insn.h \
-tid-parse.h ser-event.h
+tid-parse.h ser-event.h \
+common/signal-dispositions-save-restore.h
# Header files that already have srcdir in them, or which are in objdir.
@@ -1049,6 +1051,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
build-id.o buildsym.o \
findcmd.o \
std-regs.o \
+ signal-dispositions-save-restore.o \
signals.o \
exec.o reverse.o \
bcache.o objfiles.o observer.o minsyms.o maint.o demangle.o \
@@ -2286,6 +2289,10 @@ common-regcache.o: ${srcdir}/common/common-regcache.c
$(COMPILE) $(srcdir)/common/common-regcache.c
$(POSTCOMPILE)
+signal-dispositions-save-restore.o: $(srcdir)/common/signal-dispositions-save-restore.c
+ $(COMPILE) $(srcdir)/common/signal-dispositions-save-restore.c
+ $(POSTCOMPILE)
+
#
# gdb/target/ dependencies
#
diff --git a/gdb/common/common.m4 b/gdb/common/common.m4
index 1342503aaf4..68afc65ba27 100644
--- a/gdb/common/common.m4
+++ b/gdb/common/common.m4
@@ -30,7 +30,7 @@ AC_DEFUN([GDB_AC_COMMON], [
sys/un.h sys/wait.h dnl
thread_db.h wait.h)
- AC_CHECK_FUNCS([fdwalk getrlimit pipe pipe2 socketpair])
+ AC_CHECK_FUNCS([fdwalk getrlimit pipe pipe2 socketpair sigaction])
AC_CHECK_DECLS([strerror, strstr])
diff --git a/gdb/common/signal-dispositions-save-restore.c b/gdb/common/signal-dispositions-save-restore.c
new file mode 100644
index 00000000000..422ebf22b87
--- /dev/null
+++ b/gdb/common/signal-dispositions-save-restore.c
@@ -0,0 +1,65 @@
+/* Copyright (C) 2016 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 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 "common-defs.h"
+#include "signal-dispositions-save-restore.h"
+
+#include <signal.h>
+
+/* The original signal handlers. */
+
+#ifdef HAVE_SIGACTION
+static sighandler_t original_signal_handlers[NSIG];
+#endif
+
+/* See signal-dispositions-save-restore.h. */
+
+void
+save_original_signal_dispositions (void)
+{
+#ifdef HAVE_SIGACTION
+ int i;
+
+ for (i = 1; i < NSIG; i++)
+ {
+ struct sigaction oldact;
+
+ sigaction (i, NULL, &oldact);
+
+ original_signal_handlers[i] = oldact.sa_handler;
+
+ /* If we find a signal handler already installed, then this
+ function was called too late. */
+ if (oldact.sa_handler != SIG_DFL
+ && oldact.sa_handler != SIG_IGN)
+ internal_error (__FILE__, __LINE__, _("unexpected signal handler"));
+ }
+#endif
+}
+
+/* See signal-dispositions-save-restore.h. */
+
+void
+restore_original_signal_dispositions (void)
+{
+#ifdef HAVE_SIGACTION
+ int i;
+
+ for (i = 1; i < NSIG; i++)
+ signal (i, original_signal_handlers[i]);
+#endif
+}
diff --git a/gdb/common/signal-dispositions-save-restore.h b/gdb/common/signal-dispositions-save-restore.h
new file mode 100644
index 00000000000..71c33655bf0
--- /dev/null
+++ b/gdb/common/signal-dispositions-save-restore.h
@@ -0,0 +1,40 @@
+/* Copyright (C) 2016 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 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/>. */
+
+#ifndef COMMON_SIGNAL_DISPOSITIONS_SAVE_RESTORE_H
+#define COMMON_SIGNAL_DISPOSITIONS_SAVE_RESTORE_H
+
+/* Save/restore the signal disposition of all signals.
+
+ Since the exec family of functions does not reset the signal
+ disposition of signals set to SIG_IGN, in order to be transparent,
+ when spawning new child processes to debug (with "run", etc.), we
+ must reset all signal dispositions back to what was originally
+ inherited from gdb/gdbserver's parent, just before execing the
+ target program to debug. */
+
+/* Save the signal disposition of all signals, to be restored by
+ restore_original_signal_dispositions. */
+
+extern void save_original_signal_dispositions (void);
+
+/* Restore the signal disposition of all signals, as saved by a call
+ to save_original_signals_disposition. */
+
+extern void restore_original_signal_dispositions (void);
+
+#endif /* COMMON_SIGNAL_DISPOSITIONS_SAVE_RESTORE_H */
diff --git a/gdb/configure b/gdb/configure
index 067f86e5e27..fde6503edf5 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -12243,7 +12243,7 @@ fi
done
- for ac_func in fdwalk getrlimit pipe pipe2 socketpair
+ for ac_func in fdwalk getrlimit pipe pipe2 socketpair sigaction
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
diff --git a/gdb/fork-child.c b/gdb/fork-child.c
index 8ac3befd78b..1c1a4bff010 100644
--- a/gdb/fork-child.c
+++ b/gdb/fork-child.c
@@ -32,7 +32,7 @@
#include "solib.h"
#include "filestuff.h"
#include "top.h"
-
+#include "signal-dispositions-save-restore.h"
#include <signal.h>
/* This just gets used as a default if we can't find SHELL. */
@@ -366,6 +366,8 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
saying "not parent". Sorry; you'll have to use print
statements! */
+ restore_original_signal_dispositions ();
+
/* There is no execlpe call, so we have to set the environment
for our child in the global variable. If we've vforked, this
clobbers the parent, but environ is restored a few lines down
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 2be61eff4af..4e4279a0da2 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -200,6 +200,7 @@ OBS = agent.o ax.o inferiors.o regcache.o remote-utils.o server.o signals.o \
common-utils.o ptid.o buffer.o format.o filestuff.o dll.o notif.o \
tdesc.o print-utils.o rsp-low.o errors.o common-debug.o cleanups.o \
common-exceptions.o symbol.o btrace-common.o fileio.o common-regcache.o \
+ signal-dispositions-save-restore.o \
$(XML_BUILTIN) $(DEPFILES) $(LIBOBJS)
GDBREPLAY_OBS = gdbreplay.o version.o
GDBSERVER_LIBS = @GDBSERVER_LIBS@
@@ -715,6 +716,9 @@ fileio.o: ../common/fileio.c
common-regcache.o: ../common/common-regcache.c
$(COMPILE) $<
$(POSTCOMPILE)
+signal-dispositions-save-restore.o: ../common/signal-dispositions-save-restore.c
+ $(COMPILE) $<
+ $(POSTCOMPILE)
# Arch object files rules form ../arch
diff --git a/gdb/gdbserver/config.in b/gdb/gdbserver/config.in
index 2c3a69a2c61..04072cf56b7 100644
--- a/gdb/gdbserver/config.in
+++ b/gdb/gdbserver/config.in
@@ -202,6 +202,9 @@
/* Define to 1 if you have the <sgtty.h> header file. */
#undef HAVE_SGTTY_H
+/* Define to 1 if you have the `sigaction' function. */
+#undef HAVE_SIGACTION
+
/* Define to 1 if you have the <signal.h> header file. */
#undef HAVE_SIGNAL_H
diff --git a/gdb/gdbserver/configure b/gdb/gdbserver/configure
index 2926deb51f6..0a3436e6aff 100755
--- a/gdb/gdbserver/configure
+++ b/gdb/gdbserver/configure
@@ -5912,7 +5912,7 @@ fi
done
- for ac_func in fdwalk getrlimit pipe pipe2 socketpair
+ for ac_func in fdwalk getrlimit pipe pipe2 socketpair sigaction
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 1839f998aff..6bc618993f5 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -22,7 +22,7 @@
#include "agent.h"
#include "tdesc.h"
#include "rsp-low.h"
-
+#include "signal-dispositions-save-restore.h"
#include "nat/linux-nat.h"
#include "nat/linux-waitpid.h"
#include "gdb_wait.h"
@@ -975,6 +975,8 @@ linux_create_inferior (char *program, char **allargs)
}
}
+ restore_original_signal_dispositions ();
+
execv (program, allargs);
if (errno == ENOENT)
execvp (program, allargs);
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 6d6cb0923e8..d5209472823 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -22,7 +22,7 @@
#include "notif.h"
#include "tdesc.h"
#include "rsp-low.h"
-
+#include "signal-dispositions-save-restore.h"
#include <ctype.h>
#include <unistd.h>
#if HAVE_SIGNAL_H
@@ -3611,6 +3611,8 @@ captured_main (int argc, char *argv[])
opened by remote_prepare. */
notice_open_fds ();
+ save_original_signal_dispositions ();
+
/* We need to know whether the remote connection is stdio before
starting the inferior. Inferiors created in this scenario have
stdin,stdout redirected. So do this here before we call
diff --git a/gdb/main.c b/gdb/main.c
index 5477379b249..a018d84ef10 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -44,6 +44,7 @@
#include <signal.h>
#include "event-top.h"
#include "infrun.h"
+#include "signal-dispositions-save-restore.h"
/* The selected interpreter. This will be used as a set command
variable, so it should always be malloc'ed - since
@@ -505,6 +506,7 @@ captured_main (void *data)
bfd_init ();
notice_open_fds ();
+ save_original_signal_dispositions ();
make_cleanup (VEC_cleanup (cmdarg_s), &cmdarg_vec);
dirsize = 1;
diff --git a/gdb/testsuite/gdb.base/signal-dispositions-child.c b/gdb/testsuite/gdb.base/signal-dispositions-child.c
new file mode 100644
index 00000000000..2e93d622b25
--- /dev/null
+++ b/gdb/testsuite/gdb.base/signal-dispositions-child.c
@@ -0,0 +1,62 @@
+/* Copyright 2016 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 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 <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+
+#ifndef OUTPUT_TXT
+# define OUTPUT_TXT "output.txt"
+#endif
+
+int
+main (int argc, char **argv)
+{
+ int i;
+ FILE *out;
+
+ if (argc > 1)
+ out = stdout;
+ else
+ {
+ out = fopen (OUTPUT_TXT, "w");
+ if (out == NULL)
+ {
+ fprintf (stderr, "File open failed\n");
+ exit (1);
+ }
+ }
+
+ for (i = 1; i < NSIG; i++)
+ {
+ struct sigaction oldact;
+
+ sigaction (i, NULL, &oldact);
+
+ if (oldact.sa_handler == SIG_DFL)
+ fprintf (out, "%d: SIG_DFL\n", i);
+ else if (oldact.sa_handler == SIG_IGN)
+ fprintf (out, "%d: SIG_IGN\n", i);
+ else
+ abort ();
+ }
+
+ if (out != stdout)
+ fclose (out);
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.base/signal-dispositions-child.exp b/gdb/testsuite/gdb.base/signal-dispositions-child.exp
new file mode 100644
index 00000000000..4a926b8f265
--- /dev/null
+++ b/gdb/testsuite/gdb.base/signal-dispositions-child.exp
@@ -0,0 +1,80 @@
+# Copyright 2016 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/>.
+
+# Test that gdb's (or gdbserver's) own signal handling does not
+# interfere with the signal dispositions their spawned children
+# inherit.
+#
+# - If gdb inherits some signal set to SIG_IGN, so should the
+# inferior, even if gdb itself chooses not to ignore the signal.
+#
+# - If gdb inherits some signal set to SIG_DFL, so should the inferior
+# even if gdb itself ignores that signal.
+#
+# This requires special support in gdb/gdbserver because the exec
+# family of functions do not reset the signal disposition of signals
+# that are set to SIG_IGN.
+
+standard_testfile
+
+set gdb_txt [standard_output_file gdb.txt]
+set standalone_txt [standard_output_file standalone.txt]
+remote_exec host "rm -f $gdb_txt"
+remote_exec host "rm -f $standalone_txt"
+
+set options [list debug "additional_flags=-DOUTPUT_TXT=\"$gdb_txt\""]
+if {[build_executable $testfile.exp $testfile $srcfile $options]} {
+ untested $testfile.exp
+ return -1
+}
+
+set options [list debug "additional_flags=-DOUTPUT_TXT=\"$standalone_txt\""]
+if {[build_executable $testfile.exp $testfile-standalone $srcfile $options]} {
+ untested $testfile.exp
+ return -1
+}
+
+# Run the program directly, and dump its initial signal dispositions
+# in "standalone.txt".
+
+# Use remote_spawn instead of remote_exec, like how we spawn gdb.
+# This is in order to take the same code code paths in dejagnu
+# compared to when running the program through gdb. E.g., because
+# local_exec uses -ignore SIGHUP, while remote_spawn does not, if we
+# used remote_exec, the test program would start with SIGHUP ignored
+# when run standalone, but not when run through gdb.
+set res [remote_spawn host "$binfile-standalone"]
+if { $res < 0 || $res == "" } {
+ perror "Spawning $binfile-standalone failed."
+ return 1
+}
+remote_close host
+
+# Now run the program through gdb, and dump its initial signal
+# dispositions in "gdb.txt".
+
+clean_restart $binfile
+
+if { ! [ runto_main ] } then {
+ untested $testfile.exp
+ return -1
+}
+
+gdb_continue_to_end
+
+# Diff the .txt files. They should be identical.
+gdb_test "shell diff -s $standalone_txt $gdb_txt" \
+ "Files .* are identical.*" \
+ "diff signal dispositions"
diff --git a/gdb/testsuite/gdb.gdb/selftest.exp b/gdb/testsuite/gdb.gdb/selftest.exp
index 2fdd9e3539f..236f4b79bec 100644
--- a/gdb/testsuite/gdb.gdb/selftest.exp
+++ b/gdb/testsuite/gdb.gdb/selftest.exp
@@ -162,6 +162,10 @@ proc do_steps_and_nexts {} {
set description "next over notice_open_fds"
set command "next"
}
+ -re ".*save_original_signal_dispositions ..;.*$gdb_prompt $" {
+ set description "next over save_original_signal_dispositions"
+ set command "next"
+ }
-re ".*VEC_cleanup .cmdarg_s.*$gdb_prompt $" {
set description "next over cmdarg_s VEC_cleanup"
set command "next"