Re: [RFA] dummy frame handling cleanup, plus inferior fun call signal handling improvement

Doug Evans
2008-11-26T02:03:49Z

[-- Attachment #1: Type: text/plain, Size: 893 bytes --]

ref: http://sourceware.org/ml/gdb-patches/2008-11/msg00454.html

On Tue, Nov 18, 2008 at 4:58 AM, Doug Evans <dje@google.com> wrote:
> [...]
> There are two things this patch does:
> 1) properly pop dummy frames more often
> 2) make the inferior resumable after an inferior function call gets a
> signal without having to remember to do "signal 0"
> [...]
> Restoring stop_signal also has the benefit that if an inferior function
> call is made after getting a signal, and the inferior function call
> doesn't complete (e.g. has a breakpoint and doesn't complete right away),
> the user can resume the program (after popping the inf fun call off the
> stack) with "continue" without having to remember what the signal was
> and remember to use "signal N".
> [...]

Hi. This patch is an update to the testcases for this patch,
call-signal-resume.exp now tests for the above case.

Comments?

[-- Attachment #2: gdb-081125-infcall-tests-1.patch.txt --]
[-- Type: text/plain, Size: 12547 bytes --]

2008-11-25 Doug Evans <dje@google.com>

* gdb.base/call-signal-resume.exp: New file.
* gdb.base/call-signals.c: New file.
* gdb.base/unwindonsignal.exp: New file.
* gdb.base/unwindonsignal.c: New file.

Index: call-signal-resume.exp
===================================================================
RCS file: call-signal-resume.exp
diff -N call-signal-resume.exp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ call-signal-resume.exp 26 Nov 2008 01:51:04 -0000
@@ -0,0 +1,157 @@
+# Copyright 2008 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 inferior resumption after discarding a hand-called function.
+# There are two things to test.
+# 1) Inferior stops normally. Upon resumption it should continue normally,
+# regardless of whatever signal the hand-called function got.
+# 2) Inferior is stopped at a signal. Upon resumption it should continue
+# with that signal, regardless of whatever the hand-called function did.
+
+if $tracelevel then {
+ strace $tracelevel
+}
+
+if [target_info exists gdb,noinferiorio] {
+ verbose "Skipping call-signal-resume.exp because of no fileio capabilities."
+ continue
+}
+
+set prms_id 0
+set bug_id 0
+
+set testfile "call-signals"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+ untested call-signal-resume.exp
+ return -1
+}
+
+# Some targets can't do function calls, so don't even bother with this
+# test.
+if [target_info exists gdb,cannot_call_functions] {
+ setup_xfail "*-*-*" 2416
+ fail "This target can not call functions"
+ continue
+}
+
+proc get_dummy_frame_number { } {
+ global gdb_prompt
+
+ send_gdb "bt\n"
+ gdb_expect {
+ -re "#(\[0-9\]*) *<function called from gdb>.*$gdb_prompt $"
+ {
+ return $expect_out(1,string)
+ }
+ -re "$gdb_prompt $"
+ {
+ return ""
+ }
+ timeout
+ {
+ return ""
+ }
+ }
+ return ""
+}
+
+# Start with a fresh gdb.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+if { ![runto_main] } {
+ fail "Can't run to main"
+ return 0
+}
+
+gdb_test "break stop_one" "Breakpoint \[0-9\]* at .*"
+gdb_test "continue" "Continuing.*Breakpoint \[0-9\]*, stop_one.*" \
+ "continue to breakpoint at stop_one"
+
+# Call function (causing the program to get a signal), and see if gdb handles
+# it properly.
+gdb_test_multiple "call gen_signal ()" \
+ "call-signal-resume, inferior function call signaled" {
+ -re "\[\r\n\]*no signal\[\r\n\]+$gdb_prompt $" {
+ unsupported "call-signal-resume, inferior function call signaled"
+ return 0
+ }
+ -re "\[\r\n\]*The program being debugged was signaled.*\[\r\n\]+$gdb_prompt $" {
+ pass "call-signal-resume, inferior function call signaled"
+ }
+}
+
+set frame_number [get_dummy_frame_number]
+if { "$frame_number" == "" } {
+ fail "call-signal-resume, dummy stack frame number"
+ setup_xfail "*-*-*"
+} else {
+ pass "call-signal-resume, dummy stack frame number"
+}
+
+# Pop the dummy frame.
+gdb_test "frame $frame_number" ""
+gdb_test "set confirm off" ""
+gdb_test "return" ""
+
+# Resume execution, the program should continue without any signal.
+
+gdb_test "break stop_two" "Breakpoint \[0-9\]* at .*"
+gdb_test "continue" "Breakpoint \[0-9\]*, stop_two.*" \
+ "continue to breakpoint at stop_two"
+
+# Continue again, we should get a signal.
+
+gdb_test "continue" "Program received signal .*" \
+ "continue to receipt of signal"
+
+# Hand call another function that prematurely stops,
+# then manually pop the dummy stack frame.
+
+gdb_test "break null_hand_call" "Breakpoint \[0-9\]* at .*"
+gdb_test "call null_hand_call ()" "Breakpoint \[0-9\]*, null_hand_call.*" \
+ "null_hand_call"
+
+set frame_number [get_dummy_frame_number]
+if { "$frame_number" == "" } {
+ fail "call-signal-resume, dummy stack frame number"
+ setup_xfail "*-*-*"
+} else {
+ pass "call-signal-resume, dummy stack frame number"
+}
+
+# Pop the dummy frame.
+gdb_test "frame $frame_number" ""
+gdb_test "set confirm off" ""
+gdb_test "return" ""
+
+# Continue again, this time we should get to the signal handler.
+
+gdb_test "break handle_signal" "Breakpoint \[0-9\]* at .*"
+gdb_test "continue" "Breakpoint \[0-9\]*, handle_signal.*" \
+ "continue to breakpoint at handle_signal"
+
+# Continue one last time, the program should exit normally.
+
+gdb_test "continue" "Program exited normally." \
+ "continue to program exit"
+
+return 0
Index: call-signals.c
===================================================================
RCS file: call-signals.c
diff -N call-signals.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ call-signals.c 26 Nov 2008 01:51:04 -0000
@@ -0,0 +1,89 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2008 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/>. */
+
+/* Support program for testing handling of inferior function calls
+ in the presence of signals. */
+
+#include <stdio.h>
+#include <signal.h>
+#include <unistd.h>
+
+void
+handle_signal (int sig)
+{
+}
+
+void
+gen_signal ()
+{
+ /* According to sigall.exp, SIGABRT is always supported. */
+#ifdef SIGABRT
+ kill (getpid (), SIGABRT);
+#endif
+ /* If we get here we couldn't generate a signal, tell dejagnu. */
+ printf ("no signal\n");
+}
+
+/* Easy place to set a breakpoint. */
+
+void
+stop_one ()
+{
+}
+
+void
+stop_two ()
+{
+}
+
+void
+null_hand_call ()
+{
+}
+
+int
+main ()
+{
+#ifdef usestubs
+ set_debug_traps ();
+ breakpoint ();
+#endif
+
+#ifdef SIG_SETMASK
+ /* Ensure all the signals aren't blocked.
+ The environment in which the testsuite is run may have blocked some
+ for whatever reason. */
+ {
+ sigset_t newset;
+ sigemptyset (&newset);
+ sigprocmask (SIG_SETMASK, &newset, NULL);
+ }
+#endif
+
+ signal (SIGABRT, handle_signal);
+
+ /* Stop here so we can hand-call gen_signal. */
+ stop_one ();
+
+ /* When we're resumed stop here. */
+ stop_two ();
+
+ /* When we're resumed we generate a signal ourselves. */
+ gen_signal ();
+
+ return 0;
+}
Index: unwindonsignal.c
===================================================================
RCS file: unwindonsignal.c
diff -N unwindonsignal.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ unwindonsignal.c 26 Nov 2008 01:51:04 -0000
@@ -0,0 +1,65 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2008 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/>. */
+
+/* Support program for testing unwindonsignal. */
+
+#include <stdio.h>
+#include <signal.h>
+#include <unistd.h>
+
+void
+gen_signal ()
+{
+ /* According to sigall.exp, SIGABRT is always supported. */
+#ifdef SIGABRT
+ kill (getpid (), SIGABRT);
+#endif
+ /* If we get here we couldn't generate a signal, tell dejagnu. */
+ printf ("no signal\n");
+}
+
+/* Easy place to set a breakpoint. */
+
+void
+stop_here ()
+{
+}
+
+int
+main ()
+{
+#ifdef usestubs
+ set_debug_traps ();
+ breakpoint ();
+#endif
+
+#ifdef SIG_SETMASK
+ /* Ensure all the signals aren't blocked.
+ The environment in which the testsuite is run may have blocked some
+ for whatever reason. */
+ {
+ sigset_t newset;
+ sigemptyset (&newset);
+ sigprocmask (SIG_SETMASK, &newset, NULL);
+ }
+#endif
+
+ /* Stop here so we can hand-call gen_signal. */
+ stop_here ();
+
+ return 0;
+}
Index: unwindonsignal.exp
===================================================================
RCS file: unwindonsignal.exp
diff -N unwindonsignal.exp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ unwindonsignal.exp 26 Nov 2008 01:51:04 -0000
@@ -0,0 +1,98 @@
+# Copyright 2008 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 $tracelevel then {
+ strace $tracelevel
+}
+
+if [target_info exists gdb,noinferiorio] {
+ verbose "Skipping unwindonsignal.exp because of no fileio capabilities."
+ continue
+}
+
+set prms_id 0
+set bug_id 0
+
+set testfile "unwindonsignal"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+ untested unwindonsignal.exp
+ return -1
+}
+
+# Some targets can't do function calls, so don't even bother with this
+# test.
+if [target_info exists gdb,cannot_call_functions] {
+ setup_xfail "*-*-*" 2416
+ fail "This target can not call functions"
+ continue
+}
+
+# Start with a fresh gdb.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+if { ![runto_main] } {
+ fail "Can't run to main"
+ return 0
+}
+
+gdb_test "break stop_here" "Breakpoint \[0-9\]* at .*"
+gdb_test "continue" "Continuing.*Breakpoint \[0-9\]*, stop_here.*" \
+ "continue to breakpoint at stop_here"
+
+# Turn on unwindonsignal.
+gdb_test "set unwindonsignal on" \
+ "" \
+ "setting unwindonsignal"
+gdb_test "show unwindonsignal" \
+ "Unwinding of stack .* is on." \
+ "showing unwindonsignal"
+
+# Call function (causing the program to get a signal), and see if gdb handles
+# it properly.
+gdb_test_multiple "call gen_signal ()" \
+ "unwindonsignal, inferior function call signaled" {
+ -re "\[\r\n\]*no signal\[\r\n\]+$gdb_prompt $" {
+ unsupported "unwindonsignal, inferior function call signaled"
+ return 0
+ }
+ -re "\[\r\n\]*The program being debugged was signaled.*\[\r\n\]+$gdb_prompt $" {
+ pass "unwindonsignal, inferior function call signaled"
+ }
+}
+
+# Verify the stack got unwound.
+gdb_test "bt" \
+ "#0 *\[x0-9a-f in\]*stop_here \\(.*\\) at .*#1 *\[x0-9a-f in\]*main \\(.*\\) at .*" \
+ "unwindonsignal, stack unwound"
+
+# Verify the dummy frame got removed from dummy_frame_stack.
+gdb_test_multiple "maint print dummy-frames" \
+ "unwindonsignal, dummy frame removed" {
+ -re "\[\r\n\]*.*stack=.*code=.*\[\r\n\]+$gdb_prompt $" {
+ fail "unwindonsignal, dummy frame removed"
+ }
+ -re "\[\r\n\]+$gdb_prompt $" {
+ pass "unwindonsignal, dummy frame removed"
+ }
+}
+
+return 0