170 lines · python
1import lldb2import time3import unittest4from lldbsuite.test.lldbtest import *5from lldbsuite.test.decorators import *6from lldbsuite.test.gdbclientutils import *7from lldbsuite.test.lldbreverse import ReverseTestBase8from lldbsuite.test import lldbutil9 10 11class TestReverseContinueBreakpoints(ReverseTestBase):12 @skipIfRemote13 def test_reverse_continue(self):14 self.reverse_continue_internal(async_mode=False)15 16 @skipIfRemote17 def test_reverse_continue_async(self):18 self.reverse_continue_internal(async_mode=True)19 20 def reverse_continue_internal(self, async_mode):21 target, process, initial_threads = self.setup_recording(async_mode)22 23 # Reverse-continue. We'll stop at the point where we started recording.24 status = process.ContinueInDirection(lldb.eRunReverse)25 self.assertSuccess(status)26 self.expect_async_state_changes(27 async_mode, process, [lldb.eStateRunning, lldb.eStateStopped]28 )29 self.expect(30 "thread list",31 STOPPED_DUE_TO_HISTORY_BOUNDARY,32 substrs=["stopped", "stop reason = history boundary"],33 )34 35 # Continue forward normally until the target exits.36 status = process.ContinueInDirection(lldb.eRunForward)37 self.expect_async_state_changes(38 async_mode, process, [lldb.eStateRunning, lldb.eStateExited]39 )40 self.assertSuccess(status)41 self.assertState(process.GetState(), lldb.eStateExited)42 self.assertEqual(process.GetExitStatus(), 0)43 44 @skipIfRemote45 def test_reverse_continue_breakpoint(self):46 self.reverse_continue_breakpoint_internal(async_mode=False)47 48 @skipIfRemote49 def test_reverse_continue_breakpoint_async(self):50 self.reverse_continue_breakpoint_internal(async_mode=True)51 52 def reverse_continue_breakpoint_internal(self, async_mode):53 target, process, initial_threads = self.setup_recording(async_mode)54 55 # Reverse-continue to the function "trigger_breakpoint".56 trigger_bkpt = target.BreakpointCreateByName("trigger_breakpoint", None)57 status = process.ContinueInDirection(lldb.eRunReverse)58 self.assertSuccess(status)59 self.expect_async_state_changes(60 async_mode, process, [lldb.eStateRunning, lldb.eStateStopped]61 )62 threads_now = lldbutil.get_threads_stopped_at_breakpoint(process, trigger_bkpt)63 self.assertEqual(threads_now, initial_threads)64 65 @skipIfRemote66 @skipIf(67 oslist=["windows"],68 archs=["x86_64"],69 bugnumber="github.com/llvm/llvm-project/issues/138084",70 )71 def test_reverse_continue_skip_breakpoint(self):72 self.reverse_continue_skip_breakpoint_internal(async_mode=False)73 74 @skipIfRemote75 @skipIf(76 oslist=["windows"],77 archs=["x86_64"],78 bugnumber="github.com/llvm/llvm-project/issues/138084",79 )80 def test_reverse_continue_skip_breakpoint_async(self):81 self.reverse_continue_skip_breakpoint_internal(async_mode=True)82 83 def reverse_continue_skip_breakpoint_internal(self, async_mode):84 target, process, initial_threads = self.setup_recording(async_mode)85 86 # Reverse-continue over a breakpoint at "trigger_breakpoint" whose87 # condition is false (via function call).88 # This tests that we continue in the correct direction after hitting89 # the breakpoint.90 trigger_bkpt = target.BreakpointCreateByName("trigger_breakpoint", None)91 trigger_bkpt.SetCondition("false_condition()")92 status = process.ContinueInDirection(lldb.eRunReverse)93 self.expect_async_state_changes(94 async_mode, process, [lldb.eStateRunning, lldb.eStateStopped]95 )96 self.assertSuccess(status)97 self.expect(98 "thread list",99 STOPPED_DUE_TO_HISTORY_BOUNDARY,100 substrs=["stopped", "stop reason = history boundary"],101 )102 103 @skipIfRemote104 def test_continue_preserves_direction(self):105 self.continue_preserves_direction_internal(async_mode=False)106 107 @skipIfRemote108 def test_continue_preserves_direction_asyhc(self):109 self.continue_preserves_direction_internal(async_mode=True)110 111 def continue_preserves_direction_internal(self, async_mode):112 target, process, initial_threads = self.setup_recording(async_mode)113 114 # Reverse-continue to the function "trigger_breakpoint".115 trigger_bkpt = target.BreakpointCreateByName("trigger_breakpoint", None)116 status = process.ContinueInDirection(lldb.eRunReverse)117 self.assertSuccess(status)118 self.expect_async_state_changes(119 async_mode, process, [lldb.eStateRunning, lldb.eStateStopped]120 )121 # This should continue in reverse.122 status = process.Continue()123 self.expect_async_state_changes(124 async_mode, process, [lldb.eStateRunning, lldb.eStateStopped]125 )126 self.assertSuccess(status)127 self.expect(128 "thread list",129 STOPPED_DUE_TO_HISTORY_BOUNDARY,130 substrs=["stopped", "stop reason = history boundary"],131 )132 133 def setup_recording(self, async_mode):134 """135 Record execution of code between "start_recording" and "stop_recording" breakpoints.136 137 Returns with the target stopped at "stop_recording", with recording disabled,138 ready to reverse-execute.139 """140 self.build()141 target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))142 process = self.connect(target)143 144 # Record execution from the start of the function "start_recording"145 # to the start of the function "stop_recording". We want to keep the146 # interval that we record as small as possible to minimize the run-time147 # of our single-stepping recorder.148 start_recording_bkpt = target.BreakpointCreateByName("start_recording", None)149 self.assertTrue(start_recording_bkpt.GetNumLocations() > 0)150 initial_threads = lldbutil.continue_to_breakpoint(process, start_recording_bkpt)151 self.assertEqual(len(initial_threads), 1)152 target.BreakpointDelete(start_recording_bkpt.GetID())153 self.start_recording()154 stop_recording_bkpt = target.BreakpointCreateByName("stop_recording", None)155 self.assertTrue(stop_recording_bkpt.GetNumLocations() > 0)156 lldbutil.continue_to_breakpoint(process, stop_recording_bkpt)157 target.BreakpointDelete(stop_recording_bkpt.GetID())158 self.stop_recording()159 160 self.dbg.SetAsync(async_mode)161 self.expect_async_state_changes(async_mode, process, [lldb.eStateStopped])162 163 return target, process, initial_threads164 165 def expect_async_state_changes(self, async_mode, process, states):166 if not async_mode:167 return168 listener = self.dbg.GetListener()169 lldbutil.expect_state_changes(self, listener, process, states)170