From: Jim Ingham Date: Thu, 14 Feb 2013 03:05:42 +0000 (+0000) Subject: Add a test for handling a function call that throws an exception, and make it work. X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=0ac5709027bd71230053115af79f7a426d4862ee;p=platform%2Fupstream%2Fllvm.git Add a test for handling a function call that throws an exception, and make it work. llvm-svn: 175127 --- diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp index b54eb32..e8bdfad 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp @@ -418,7 +418,8 @@ ItaniumABILanguageRuntime::SetExceptionBreakpoints () SearchFilterSP filter_sp = target.GetSearchFilterForModule(NULL); m_cxx_exception_bp_sp = target.CreateBreakpoint (filter_sp, exception_resolver_sp, is_internal); - m_cxx_exception_bp_sp->SetBreakpointKind("c++ exception"); + if (m_cxx_exception_bp_sp) + m_cxx_exception_bp_sp->SetBreakpointKind("c++ exception"); } else m_cxx_exception_bp_sp->SetEnabled (true); diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp index cacdfdb..1f20f44 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp @@ -333,11 +333,15 @@ AppleObjCRuntime::SetExceptionBreakpoints () const bool is_internal = true; if (!m_objc_exception_bp_sp) + { m_objc_exception_bp_sp = LanguageRuntime::CreateExceptionBreakpoint (m_process->GetTarget(), GetLanguageType(), catch_bp, throw_bp, is_internal); + if (m_objc_exception_bp_sp) + m_objc_exception_bp_sp->SetBreakpointKind("ObjC exception"); + } else m_objc_exception_bp_sp->SetEnabled(true); } diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp index e0a0046..3500a88 100644 --- a/lldb/source/Target/StopInfo.cpp +++ b/lldb/source/Target/StopInfo.cpp @@ -233,10 +233,29 @@ public: StreamString strm; if (m_break_id != LLDB_INVALID_BREAK_ID) { - if (m_was_one_shot) - strm.Printf ("one-shot breakpoint %d", m_break_id); + BreakpointSP break_sp = m_thread.GetProcess()->GetTarget().GetBreakpointByID(m_break_id); + if (break_sp) + { + if (break_sp->IsInternal()) + { + const char *kind = break_sp->GetBreakpointKind(); + if (kind) + strm.Printf ("internal %s breakpoint(%d).", kind, m_break_id); + else + strm.Printf ("internal breakpoint(%d).", m_break_id); + } + else + { + strm.Printf ("breakpoint %d.", m_break_id); + } + } else - strm.Printf ("breakpoint %d which has been deleted.", m_break_id); + { + if (m_was_one_shot) + strm.Printf ("one-shot breakpoint %d", m_break_id); + else + strm.Printf ("breakpoint %d which has been deleted.", m_break_id); + } } else if (m_address == LLDB_INVALID_ADDRESS) strm.Printf("breakpoint site %" PRIi64 " which has been deleted - unknown address", m_value); diff --git a/lldb/source/Target/ThreadPlanCallFunction.cpp b/lldb/source/Target/ThreadPlanCallFunction.cpp index 70a3455..c48f4fb 100644 --- a/lldb/source/Target/ThreadPlanCallFunction.cpp +++ b/lldb/source/Target/ThreadPlanCallFunction.cpp @@ -579,12 +579,6 @@ ThreadPlanCallFunction::BreakpointsExplainStop() return true; } - // Finally, if the process is set to ignore breakpoints in function calls, - // then we explain all breakpoint stops. - - if (m_ignore_breakpoints) - return true; - return false; } diff --git a/lldb/test/expression_command/call-throws/Makefile b/lldb/test/expression_command/call-throws/Makefile new file mode 100644 index 0000000..ac07b31 --- /dev/null +++ b/lldb/test/expression_command/call-throws/Makefile @@ -0,0 +1,6 @@ +LEVEL = ../../make + +OBJC_SOURCES := call-throws.m + +include $(LEVEL)/Makefile.rules +LDFLAGS += -framework Foundation diff --git a/lldb/test/expression_command/call-throws/TestCallThatThrows.py b/lldb/test/expression_command/call-throws/TestCallThatThrows.py new file mode 100644 index 0000000..5e04a67 --- /dev/null +++ b/lldb/test/expression_command/call-throws/TestCallThatThrows.py @@ -0,0 +1,100 @@ +""" +Test calling a function that hits a signal set to auto-restart, make sure the call completes. +""" + +import unittest2 +import lldb +import lldbutil +from lldbtest import * + +class ExprCommandWithTimeoutsTestCase(TestBase): + + mydir = os.path.join("expression_command", "call-throws") + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + + self.main_source = "call-throws.m" + self.main_source_spec = lldb.SBFileSpec (self.main_source) + + + @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") + @dsym_test + def test_with_dsym(self): + """Test calling std::String member function.""" + self.buildDsym() + self.call_function() + + @dwarf_test + def test_with_dwarf(self): + """Test calling std::String member function.""" + self.buildDwarf() + self.call_function() + + def check_after_call (self): + # Check that we are back where we were before: + frame = self.thread.GetFrameAtIndex(0) + self.assertTrue (self.orig_frame_pc == frame.GetPC(), "Restored the zeroth frame correctly") + + + def call_function(self): + """Test calling function with timeout.""" + exe_name = "a.out" + exe = os.path.join(os.getcwd(), exe_name) + + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + + breakpoint = target.BreakpointCreateBySourceRegex('I am about to throw.',self.main_source_spec) + self.assertTrue(breakpoint.GetNumLocations() > 0, VALID_BREAKPOINT) + + # Launch the process, and do not stop at the entry point. + process = target.LaunchSimple(None, None, os.getcwd()) + + self.assertTrue(process, PROCESS_IS_VALID) + + # Frame #0 should be at our breakpoint. + threads = lldbutil.get_threads_stopped_at_breakpoint (process, breakpoint) + + self.assertTrue(len(threads) == 1) + self.thread = threads[0] + + options = lldb.SBExpressionOptions() + options.SetUnwindOnError(True) + + frame = self.thread.GetFrameAtIndex(0) + # Store away the PC to check that the functions unwind to the right place after calls + self.orig_frame_pc = frame.GetPC() + + value = frame.EvaluateExpression ("[my_class callMeIThrow]", options) + self.assertTrue (value.IsValid()) + self.assertTrue (value.GetError().Success() == False) + + self.check_after_call() + + # Okay, now try with a breakpoint in the called code in the case where + # we are ignoring breakpoint hits. + handler_bkpt = target.BreakpointCreateBySourceRegex("I felt like it", self.main_source_spec) + self.assertTrue (handler_bkpt.GetNumLocations() > 0) + options.SetIgnoreBreakpoints(True) + options.SetUnwindOnError(True) + + value = frame.EvaluateExpression ("[my_class callMeIThrow]", options) + + self.assertTrue (value.IsValid() and value.GetError().Success() == False) + self.check_after_call() + + # Now set this unwind on error to false, and make sure that we stop where the exception was thrown + options.SetUnwindOnError(False) + value = frame.EvaluateExpression ("[my_class callMeIThrow]", options) + + + self.assertTrue (value.IsValid() and value.GetError().Success() == False) + self.check_after_call() + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() diff --git a/lldb/test/expression_command/call-throws/call-throws.m b/lldb/test/expression_command/call-throws/call-throws.m new file mode 100644 index 0000000..c199022 --- /dev/null +++ b/lldb/test/expression_command/call-throws/call-throws.m @@ -0,0 +1,32 @@ +#import + +@interface MyClass : NSObject +{ +} +- (int) callMeIThrow; +@end + +@implementation MyClass +- (int) callMeIThrow +{ + NSException *e = [NSException + exceptionWithName:@"JustForTheHeckOfItException" + reason:@"I felt like it" + userInfo:nil]; + @throw e; + return 56; +} +@end + +int +main () +{ + int return_value; + MyClass *my_class = [[MyClass alloc] init]; + + NSLog (@"I am about to throw."); + + return_value = [my_class callMeIThrow]; + + return return_value; +}