Browse Source
* infcall.c (show_unwind_on_terminating_exception_p): New function. (call_function_by_hand): Create breakpoint and clean-up call for std::terminate.breakpoint. Add unwind_on_terminating_exception_p gate. Pop frame on breakpoint hit. (_initialize_infcall): Add add_setshow_boolean_cmd for unwind-on-terminating-exception. testsuite/ 2009-06-15 Phil Muldoon <pmuldoon@redhat.com> * gdb.cp/gdb2495.cc: New file. * gdb.cp/gdb2495.exp: New file. doc/ 2009-06-15 Phil Muldoon <pmuldoon@redhat.com> * doc/gdb.texinfo (Calling): Document set-unwind-on-terminating-exception usage.cgen-1_1-branch
8 changed files with 392 additions and 1 deletions
@ -0,0 +1,89 @@ |
|||
/* This testcase is part of GDB, the GNU debugger.
|
|||
|
|||
Copyright 2009 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 <iostream> |
|||
#include <signal.h> |
|||
|
|||
using namespace std; |
|||
|
|||
class SimpleException |
|||
{ |
|||
|
|||
public: |
|||
|
|||
void raise_signal (int dummy) |
|||
{ |
|||
if (dummy > 0) |
|||
raise(SIGABRT); |
|||
} |
|||
|
|||
int no_throw_function () |
|||
{ |
|||
return 1; |
|||
} |
|||
|
|||
void throw_function () |
|||
{ |
|||
throw 1; |
|||
} |
|||
|
|||
int throw_function_with_handler () |
|||
{ |
|||
try |
|||
{ |
|||
throw 1; |
|||
} |
|||
catch (...) |
|||
{ |
|||
cout << "Handled" << endl; |
|||
} |
|||
|
|||
return 2; |
|||
} |
|||
|
|||
void call_throw_function_no_handler () |
|||
{ |
|||
throw_function (); |
|||
} |
|||
|
|||
void call_throw_function_handler () |
|||
{ |
|||
throw_function_with_handler (); |
|||
} |
|||
}; |
|||
SimpleException exceptions; |
|||
|
|||
int |
|||
main() |
|||
{ |
|||
/* Have to call these functions so GCC does not optimize them
|
|||
away. */ |
|||
exceptions.raise_signal (-1); |
|||
exceptions.no_throw_function (); |
|||
exceptions.throw_function_with_handler (); |
|||
exceptions.call_throw_function_handler (); |
|||
try |
|||
{ |
|||
exceptions.throw_function (); |
|||
exceptions.call_throw_function_no_handler (); |
|||
} |
|||
catch (...) |
|||
{ |
|||
} |
|||
return 0; |
|||
} |
|||
@ -0,0 +1,157 @@ |
|||
# Copyright 2009 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/>. |
|||
|
|||
|
|||
# In gdb inferior function calls, if a C++ exception is raised in the |
|||
# dummy-frame, and the exception handler is (normally, and expected to |
|||
# be) out-of-frame, the default C++ handler will (wrongly) be called |
|||
# in an inferior function call. |
|||
# This is incorrect as an exception can normally and legally be handled |
|||
# out-of-frame. The confines of the dummy frame prevent the unwinder |
|||
# from finding the correct handler (or any handler, unless it is |
|||
# in-frame). The default handler calls std::terminate. This will kill |
|||
# the inferior. Assert that terminate should never be called in an |
|||
# inferior function call. These tests test the functionality around |
|||
# unwinding that sequence and also tests the flag behaviour gating this |
|||
# functionality. |
|||
|
|||
# This test is largely based of gdb.base/callfuncs.exp. |
|||
|
|||
if $tracelevel then { |
|||
strace $tracelevel |
|||
} |
|||
|
|||
if { [skip_cplus_tests] } { continue } |
|||
|
|||
set prms_id 2495 |
|||
set bug_id 0 |
|||
|
|||
set testfile "gdb2495" |
|||
set srcfile ${testfile}.cc |
|||
set binfile $objdir/$subdir/$testfile |
|||
|
|||
# Create and source the file that provides information about the compiler |
|||
# used to compile the test case. |
|||
if [get_compiler_info ${binfile} "c++"] { |
|||
return -1 |
|||
} |
|||
|
|||
if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } { |
|||
untested gdb2495.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 |
|||
} |
|||
|
|||
gdb_exit |
|||
gdb_start |
|||
gdb_reinitialize_dir $srcdir/$subdir |
|||
gdb_load ${binfile} |
|||
|
|||
if ![runto_main] then { |
|||
perror "couldn't run to main" |
|||
continue |
|||
} |
|||
|
|||
# See http://sourceware.org/gdb/bugs/2495 |
|||
|
|||
# Test normal baseline behaviour. Call a function that |
|||
# does not raise an exception. |
|||
gdb_test "p exceptions.no_throw_function()" " = 1" |
|||
# And one that does but handles it in-frame. |
|||
gdb_test "p exceptions.throw_function_with_handler()" " = 2" |
|||
# Both should return normally. |
|||
|
|||
# Test basic unwind. Call a function that raises an exception but |
|||
# does not handle it. It should be rewound. |
|||
gdb_test "p exceptions.throw_function()" \ |
|||
"The program being debugged entered a std::terminate call, .*" \ |
|||
"Call a function that raises an exception without a handler." |
|||
|
|||
# Make sure that after rewinding we are back at the call parent. |
|||
gdb_test "bt" \ |
|||
"#0 main.*" \ |
|||
"bt after returning from a popped frame" |
|||
|
|||
# Make sure the only breakpoint is the one set via the runto_main |
|||
# call and that the std::terminate breakpoint has evaporated and |
|||
# cleaned-up. |
|||
gdb_test "info breakpoints" \ |
|||
"gdb.cp/gdb2495\.cc.*" |
|||
|
|||
# Turn off this new behaviour. |
|||
gdb_test_multiple "set unwind-on-terminating-exception off" \ |
|||
"Turn unwind-on-terminating-exception off" { |
|||
-re "$gdb_prompt $" {pass "set unwinn-on-terminating-exception off"} |
|||
timeout {fail "(timeout) set unwind-on-terminating-exception off"} |
|||
} |
|||
|
|||
# Check that it is turned off. |
|||
gdb_test "show unwind-on-terminating-exception" \ |
|||
"exception is unhandled while in a call dummy is off.*" \ |
|||
"Turn off unwind on terminating exception flag" |
|||
|
|||
# Check that the old behaviour is restored. |
|||
gdb_test "p exceptions.throw_function()" \ |
|||
"The program being debugged was signaled while in a function called .*" \ |
|||
"Call a function that raises an exception with unwinding off.." |
|||
|
|||
# Restart the inferior back at main. |
|||
if ![runto_main] then { |
|||
perror "couldn't run to main" |
|||
continue |
|||
} |
|||
|
|||
|
|||
# Check to see if the new behaviour alters the unwind signal |
|||
# behaviour; it should not. Test both on and off states. |
|||
|
|||
# Turn on unwind on signal behaviour. |
|||
gdb_test_multiple "set unwindonsignal on" "Turn unwindonsignal on" { |
|||
-re "$gdb_prompt $" {pass "set unwindonsignal on"} |
|||
timeout {fail "(timeout) set unwindonsignal on"} |
|||
} |
|||
|
|||
# Check that it is turned on. |
|||
gdb_test "show unwindonsignal" \ |
|||
"signal is received while in a call dummy is on.*" \ |
|||
"Turn on unwind on signal" |
|||
|
|||
# Check to see if new behaviour interferes with |
|||
# normal signal handling in inferior function calls. |
|||
gdb_test "p exceptions.raise_signal(1)" \ |
|||
"To change this behavior use \"set unwindonsignal off\".*" |
|||
|
|||
# And reverse - turn off again. |
|||
gdb_test_multiple "set unwindonsignal off" "Turn unwindonsignal off" { |
|||
-re "$gdb_prompt $" {pass "set unwindonsignal off"} |
|||
timeout {fail "(timeout) set unwindonsignal off"} |
|||
} |
|||
|
|||
# Check that it is actually turned off. |
|||
gdb_test "show unwindonsignal" \ |
|||
"signal is received while in a call dummy is off.*" \ |
|||
"Turn off unwind on signal" |
|||
|
|||
# Check to see if new behaviour interferes with |
|||
# normal signal handling in inferior function calls. |
|||
gdb_test "p exceptions.raise_signal(1)" \ |
|||
"To change this behavior use \"set unwindonsignal on\".*" |
|||
Loading…
Reference in new issue