示例#1
0
    def do_step(self, step_type, destination_line_entry, test_stack_depth):
        expected_stack_depth = self.thread.GetNumFrames()
        if step_type == "into":
            expected_stack_depth += 1
            self.thread.StepInto()
        elif step_type == "out":
            expected_stack_depth -= 1
            self.thread.StepOut()
        elif step_type == "over":
            self.thread.StepOver()
        else:
            self.fail("Unrecognized step type: " + step_type)

        threads = lldbutil.get_stopped_threads(self.process, lldb.eStopReasonPlanComplete)
        if len(threads) != 1:
            destination_description = lldb.SBStream()
            destination_line_entry.GetDescription(destination_description)
            self.fail(
                "Failed to stop due to step "
                + step_type
                + " operation stepping to: "
                + destination_description.GetData()
            )

        self.thread = threads[0]

        stop_line_entry = self.thread.GetFrameAtIndex(0).GetLineEntry()
        self.assertTrue(stop_line_entry.IsValid(), "Stop line entry was not valid.")

        # Don't use the line entry equal operator because we don't care about the column number.
        stop_at_right_place = (
            stop_line_entry.GetFileSpec() == destination_line_entry.GetFileSpec()
            and stop_line_entry.GetLine() == destination_line_entry.GetLine()
        )
        if stop_at_right_place == False:
            destination_description = lldb.SBStream()
            destination_line_entry.GetDescription(destination_description)

            actual_description = lldb.SBStream()
            stop_line_entry.GetDescription(actual_description)

            self.fail(
                "Step "
                + step_type
                + " stopped at wrong place: expected: "
                + destination_description.GetData()
                + " got: "
                + actual_description.GetData()
                + "."
            )

        real_stack_depth = self.thread.GetNumFrames()

        if test_stack_depth and real_stack_depth != expected_stack_depth:
            destination_description = lldb.SBStream()
            destination_line_entry.GetDescription(destination_description)
            self.fail(
                "Step %s to %s got wrong number of frames, should be: %d was: %d."
                % (step_type, destination_description.GetData(), expected_stack_depth, real_stack_depth)
            )
示例#2
0
    def do_step(self, step_type, destination_line_entry):
        expected_stack_depth = self.thread.GetNumFrames()
        if step_type == "into":
            expected_stack_depth += 1
            self.thread.StepInto()
        elif step_type == "out":
            expected_stack_depth -= 1
            self.thread.StepOut()
        elif step_type == "over":
            self.thread.StepOver()
        else:
            self.fail("Unrecognized step type: " + step_type)

        threads = lldbutil.get_stopped_threads(self.process,
                                               lldb.eStopReasonPlanComplete)
        if len(threads) != 1:
            destination_description = lldb.SBStream()
            destination_line_entry.GetDescription(destination_description)
            self.fail("Failed to stop due to step " + step_type +
                      " operation stepping to: " +
                      destination_description.GetData())

        self.thread = threads[0]

        stop_line_entry = self.thread.GetFrameAtIndex(0).GetLineEntry()
        self.assertTrue(stop_line_entry.IsValid(),
                        "Stop line entry was not valid.")

        # Don't use the line entry equal operator because we don't care about the column number.
        stop_at_right_place = (stop_line_entry.GetFileSpec()
                               == destination_line_entry.GetFileSpec()
                               and stop_line_entry.GetLine()
                               == destination_line_entry.GetLine())
        if stop_at_right_place == False:
            destination_description = lldb.SBStream()
            destination_line_entry.GetDescription(destination_description)

            actual_description = lldb.SBStream()
            stop_line_entry.GetDescription(actual_description)

            self.fail("Step " + step_type +
                      " stopped at wrong place: expected: " +
                      destination_description.GetData() + " got: " +
                      actual_description.GetData() + ".")

        real_stack_depth = self.thread.GetNumFrames()

        if real_stack_depth != expected_stack_depth:
            destination_description = lldb.SBStream()
            destination_line_entry.GetDescription(destination_description)
            self.fail(
                "Step %s to %s got wrong number of frames, should be: %d was: %d."
                % (step_type, destination_description.GetData(),
                   expected_stack_depth, real_stack_depth))
示例#3
0
    def step_over_stepping(self):
        """Use Python APIs to test stepping over and hitting breakpoints."""
        exe = os.path.join(os.getcwd(), "a.out")

        target = self.dbg.CreateTarget(exe)
        self.assertTrue(target, VALID_TARGET)

        self.main_source_spec = lldb.SBFileSpec (self.main_source)

        breakpoints_to_disable = []

        break_1_in_main = target.BreakpointCreateBySourceRegex ('// frame select 2, thread step-out while stopped at .c.1..', self.main_source_spec)
        self.assertTrue(break_1_in_main, VALID_BREAKPOINT)
        breakpoints_to_disable.append (break_1_in_main)

        break_in_a = target.BreakpointCreateBySourceRegex ('// break here to stop in a before calling b', self.main_source_spec)
        self.assertTrue(break_in_a, VALID_BREAKPOINT)
        breakpoints_to_disable.append (break_in_a)

        break_in_b = target.BreakpointCreateBySourceRegex ('// thread step-out while stopped at .c.2..', self.main_source_spec)
        self.assertTrue(break_in_b, VALID_BREAKPOINT)
        breakpoints_to_disable.append (break_in_b)

        break_in_c = target.BreakpointCreateBySourceRegex ('// Find the line number of function .c. here.', self.main_source_spec)
        self.assertTrue(break_in_c, VALID_BREAKPOINT)
        breakpoints_to_disable.append (break_in_c)

        # Now launch the process, and do not stop at entry point.
        process = target.LaunchSimple (None, None, os.getcwd())

        self.assertTrue(process, PROCESS_IS_VALID)

        # The stop reason of the thread should be breakpoint.
        threads = lldbutil.get_threads_stopped_at_breakpoint (process, break_1_in_main)

        if len(threads) != 1:
            self.fail ("Failed to stop at first breakpoint in main.")

        thread = threads[0]

        # Get the stop id and for fun make sure it increases:
        old_stop_id = process.GetStopID()

        # Now step over, which should cause us to hit the breakpoint in "a"
        thread.StepOver()

        # The stop reason of the thread should be breakpoint.
        threads = lldbutil.get_threads_stopped_at_breakpoint (process, break_in_a)
        if len(threads) != 1:
            self.fail ("Failed to stop at breakpoint in a.")

        # Check that the stop ID increases:
        new_stop_id = process.GetStopID()
        self.assertTrue(new_stop_id > old_stop_id, "Stop ID increases monotonically.")

        thread = threads[0]

        # Step over, and we should hit the breakpoint in b:
        thread.StepOver()

        threads = lldbutil.get_threads_stopped_at_breakpoint (process, break_in_b)
        if len(threads) != 1:
            self.fail ("Failed to stop at breakpoint in b.")
        thread = threads[0]

        # Now try running some function, and make sure that we still end up in the same place
        # and with the same stop reason.
        frame = thread.GetFrameAtIndex(0)
        current_line = frame.GetLineEntry().GetLine()
        current_file = frame.GetLineEntry().GetFileSpec()
        current_bp = []
        current_bp.append(thread.GetStopReasonDataAtIndex(0))
        current_bp.append(thread.GetStopReasonDataAtIndex(1))

        stop_id_before_expression = process.GetStopID()
        stop_id_before_including_expressions = process.GetStopID(True)

        frame.EvaluateExpression ("(int) printf (print_string)")

        frame = thread.GetFrameAtIndex(0)
        self.assertTrue (current_line == frame.GetLineEntry().GetLine(), "The line stayed the same after expression.")
        self.assertTrue (current_file == frame.GetLineEntry().GetFileSpec(), "The file stayed the same after expression.")
        self.assertTrue (thread.GetStopReason() == lldb.eStopReasonBreakpoint, "We still say we stopped for a breakpoint.")
        self.assertTrue (thread.GetStopReasonDataAtIndex(0) == current_bp[0] and thread.GetStopReasonDataAtIndex(1) == current_bp[1], "And it is the same breakpoint.")
        
        # Also make sure running the expression didn't change the public stop id
        # but did change if we are asking for expression stops as well.
        stop_id_after_expression = process.GetStopID()
        stop_id_after_including_expressions = process.GetStopID(True)

        self.assertTrue (stop_id_before_expression == stop_id_after_expression, "Expression calling doesn't change stop ID")

        self.assertTrue (stop_id_after_including_expressions > stop_id_before_including_expressions, "Stop ID including expressions increments over expression call.")

        # Do the same thing with an expression that's going to crash, and make sure we are still unchanged.

        frame.EvaluateExpression ("((char *) 0)[0] = 'a'")

        frame = thread.GetFrameAtIndex(0)
        self.assertTrue (current_line == frame.GetLineEntry().GetLine(), "The line stayed the same after expression.")
        self.assertTrue (current_file == frame.GetLineEntry().GetFileSpec(), "The file stayed the same after expression.")
        self.assertTrue (thread.GetStopReason() == lldb.eStopReasonBreakpoint, "We still say we stopped for a breakpoint.")
        self.assertTrue (thread.GetStopReasonDataAtIndex(0) == current_bp[0] and thread.GetStopReasonDataAtIndex(1) == current_bp[1], "And it is the same breakpoint.")

        # Now continue and make sure we just complete the step:
        # Disable all our breakpoints first - sometimes the compiler puts two line table entries in for the
        # breakpoint a "b" and we don't want to hit that.
        for bkpt in breakpoints_to_disable:
            bkpt.SetEnabled(False)

        process.Continue()

        self.assertTrue (thread.GetFrameAtIndex(0).GetFunctionName() == "a")
        self.assertTrue (thread.GetStopReason() == lldb.eStopReasonPlanComplete)

        # And one more time should get us back to main:
        process.Continue()

        self.assertTrue (thread.GetFrameAtIndex(0).GetFunctionName() == "main")
        self.assertTrue (thread.GetStopReason() == lldb.eStopReasonPlanComplete)

        # Now make sure we can call a function, break in the called function, then have "continue" get us back out again:
        frame = thread.GetFrameAtIndex(0)
        frame = thread.GetFrameAtIndex(0)
        current_line = frame.GetLineEntry().GetLine()
        current_file = frame.GetLineEntry().GetFileSpec()

        break_in_b.SetEnabled(True)
        frame.EvaluateExpression ("b (4)", lldb.eNoDynamicValues, False)

        threads = lldbutil.get_threads_stopped_at_breakpoint (process, break_in_b)
        if len(threads) != 1:
            self.fail ("Failed to stop at breakpoint in b when calling b.")
        thread = threads[0]

        # So do a step over here to make sure we can still do that:

        thread.StepOver()

        # See that we are still in b:
        self.assertTrue (thread.GetFrameAtIndex(0).GetFunctionName() == "b")

        # Okay, now if we continue, we will finish off our function call and we should end up back in "a" as if nothing had happened:
        process.Continue ()

        self.assertTrue (thread.GetFrameAtIndex(0).GetLineEntry().GetLine() == current_line)
        self.assertTrue (thread.GetFrameAtIndex(0).GetLineEntry().GetFileSpec() == current_file)

        # Now we are going to test step in targetting a function:

        break_in_b.SetEnabled (False)

        break_before_complex_1 = target.BreakpointCreateBySourceRegex ('// Stop here to try step in targetting b.', self.main_source_spec)
        self.assertTrue(break_before_complex_1, VALID_BREAKPOINT)

        break_before_complex_2 = target.BreakpointCreateBySourceRegex ('// Stop here to try step in targetting complex.', self.main_source_spec)
        self.assertTrue(break_before_complex_2, VALID_BREAKPOINT)

        break_before_complex_3 = target.BreakpointCreateBySourceRegex ('// Stop here to step targetting b and hitting breakpoint.', self.main_source_spec)
        self.assertTrue(break_before_complex_3, VALID_BREAKPOINT)

        break_before_complex_4 = target.BreakpointCreateBySourceRegex ('// Stop here to make sure bogus target steps over.', self.main_source_spec)
        self.assertTrue(break_before_complex_4, VALID_BREAKPOINT)

        threads = lldbutil.continue_to_breakpoint(process, break_before_complex_1)
        self.assertTrue (len(threads) == 1)
        thread = threads[0]
        break_before_complex_1.SetEnabled(False)

        thread.StepInto ("b")
        self.assertTrue (thread.GetFrameAtIndex(0).GetFunctionName() == "b")

        # Now continue out and stop at the next call to complex.  This time step all the way into complex:
        threads = lldbutil.continue_to_breakpoint (process, break_before_complex_2)
        self.assertTrue (len(threads) == 1)
        thread = threads[0]
        break_before_complex_2.SetEnabled(False)

        thread.StepInto ("complex")
        self.assertTrue (thread.GetFrameAtIndex(0).GetFunctionName() == "complex")
        
        # Now continue out and stop at the next call to complex.  This time enable breakpoints in a and c and then step targetting b:
        threads = lldbutil.continue_to_breakpoint (process, break_before_complex_3)
        self.assertTrue (len(threads) == 1)
        thread = threads[0]
        break_before_complex_3.SetEnabled(False)

        break_at_start_of_a = target.BreakpointCreateByName ('a')
        break_at_start_of_c = target.BreakpointCreateByName ('c')

        thread.StepInto ("b")
        threads = lldbutil.get_stopped_threads(process, lldb.eStopReasonBreakpoint);

        self.assertTrue (len(threads) == 1)
        thread = threads[0]
        stop_break_id = thread.GetStopReasonDataAtIndex(0)
        self.assertTrue(stop_break_id == break_at_start_of_a.GetID() or stop_break_id == break_at_start_of_c.GetID())

        break_at_start_of_a.SetEnabled(False)
        break_at_start_of_c.SetEnabled(False)

        process.Continue()
        self.assertTrue (thread.GetFrameAtIndex(0).GetFunctionName() == "b")
        
        # Now continue out and stop at the next call to complex.  This time enable breakpoints in a and c and then step targetting b:
        threads = lldbutil.continue_to_breakpoint (process, break_before_complex_4)
        self.assertTrue (len(threads) == 1)
        thread = threads[0]
        break_before_complex_4.SetEnabled(False)

        thread.StepInto("NoSuchFunction")
        self.assertTrue (thread.GetFrameAtIndex(0).GetFunctionName() == "main")
示例#4
0
    def send_signal(self):
        """Test that lldb command 'process signal SIGUSR1' sends a signal to the inferior process."""

        exe = os.path.join(os.getcwd(), "a.out")

        # Create a target by the debugger.
        target = self.dbg.CreateTarget(exe)
        self.assertTrue(target, VALID_TARGET)

        # Now create a breakpoint on main.c by name 'c'.
        breakpoint = target.BreakpointCreateByLocation('main.c', self.line)
        self.assertTrue(breakpoint and breakpoint.GetNumLocations() == 1,
                        VALID_BREAKPOINT)

        # Get the breakpoint location from breakpoint after we verified that,
        # indeed, it has one location.
        location = breakpoint.GetLocationAtIndex(0)
        self.assertTrue(location and location.IsEnabled(),
                        VALID_BREAKPOINT_LOCATION)

        # Now launch the process, no arguments & do not stop at entry point.
        launch_info = lldb.SBLaunchInfo([exe])
        launch_info.SetWorkingDirectory(self.get_process_working_directory())

        process_listener = lldb.SBListener("signal_test_listener")
        launch_info.SetListener(process_listener)
        error = lldb.SBError()
        process = target.Launch(launch_info, error)
        self.assertTrue(process, PROCESS_IS_VALID)

        self.runCmd("process handle -n False -p True -s True SIGUSR1")

        thread = lldbutil.get_stopped_thread(process,
                                             lldb.eStopReasonBreakpoint)
        self.assertTrue(thread.IsValid(), "We hit the first breakpoint.")

        # After resuming the process, send it a SIGUSR1 signal.

        self.setAsync(True)

        self.assertTrue(process_listener.IsValid(),
                        "Got a good process listener")

        # Disable our breakpoint, we don't want to hit it anymore...
        breakpoint.SetEnabled(False)

        # Now continue:
        process.Continue()

        # If running remote test, there should be a connected event
        if lldb.remote_platform:
            self.match_state(process_listener, lldb.eStateConnected)

        self.match_state(process_listener, lldb.eStateRunning)

        # Now signal the process, and make sure it stops:
        process.Signal(lldbutil.get_signal_number('SIGUSR1'))

        self.match_state(process_listener, lldb.eStateStopped)

        # Now make sure the thread was stopped with a SIGUSR1:
        threads = lldbutil.get_stopped_threads(process, lldb.eStopReasonSignal)
        self.assertTrue(len(threads) == 1, "One thread stopped for a signal.")
        thread = threads[0]

        self.assertTrue(thread.GetStopReasonDataCount() >= 1,
                        "There was data in the event.")
        self.assertTrue(
            thread.GetStopReasonDataAtIndex(0) == lldbutil.get_signal_number(
                'SIGUSR1'), "The stop signal was SIGUSR1")
示例#5
0
    def do_thread_actions(self,
                          num_breakpoint_threads=0,
                          num_signal_threads=0,
                          num_watchpoint_threads=0,
                          num_crash_threads=0,
                          num_delay_breakpoint_threads=0,
                          num_delay_signal_threads=0,
                          num_delay_watchpoint_threads=0,
                          num_delay_crash_threads=0):
        """ Sets a breakpoint in the main thread where test parameters (numbers of threads) can be adjusted, runs the inferior
            to that point, and modifies the locals that control the event thread counts. Also sets a breakpoint in
            breakpoint_func (the function executed by each 'breakpoint' thread) and a watchpoint on a global modified in
            watchpoint_func. The inferior is continued until exit or a crash takes place, and the number of events seen by LLDB
            is verified to match the expected number of events.
        """
        exe = os.path.join(os.getcwd(), "a.out")
        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)

        # Get the target
        self.inferior_target = self.dbg.GetSelectedTarget()

        expected_bps = []

        # Initialize all the breakpoints (main thread/aux thread)
        self.setup_breakpoint = self.add_breakpoint(self.setup_breakpoint_line,
                                                    expected_bps)
        self.finish_breakpoint = self.add_breakpoint(
            self.finish_breakpoint_line, expected_bps)

        # Set the thread breakpoint
        if num_breakpoint_threads + num_delay_breakpoint_threads > 0:
            self.thread_breakpoint = self.add_breakpoint(
                self.thread_breakpoint_line, expected_bps)

        # Verify breakpoints
        self.expect("breakpoint list -f",
                    "Breakpoint locations shown correctly",
                    substrs=expected_bps)

        # Run the program.
        self.runCmd("run", RUN_SUCCEEDED)

        # Check we are at line self.setup_breakpoint
        self.expect("thread backtrace",
                    STOPPED_DUE_TO_BREAKPOINT,
                    substrs=["stop reason = breakpoint 1."])

        # Initialize the (single) watchpoint on the global variable (g_watchme)
        if num_watchpoint_threads + num_delay_watchpoint_threads > 0:
            self.runCmd("watchpoint set variable g_watchme")
            for w in self.inferior_target.watchpoint_iter():
                self.thread_watchpoint = w
                self.assertTrue("g_watchme" in str(self.thread_watchpoint),
                                "Watchpoint location not shown correctly")

        # Get the process
        self.inferior_process = self.inferior_target.GetProcess()

        # We should be stopped at the setup site where we can set the number of
        # threads doing each action (break/crash/signal/watch)
        self.assertEqual(
            self.inferior_process.GetNumThreads(), 1,
            'Expected to stop before any additional threads are spawned.')

        self.runCmd("expr num_breakpoint_threads=%d" % num_breakpoint_threads)
        self.runCmd("expr num_crash_threads=%d" % num_crash_threads)
        self.runCmd("expr num_signal_threads=%d" % num_signal_threads)
        self.runCmd("expr num_watchpoint_threads=%d" % num_watchpoint_threads)

        self.runCmd("expr num_delay_breakpoint_threads=%d" %
                    num_delay_breakpoint_threads)
        self.runCmd("expr num_delay_crash_threads=%d" %
                    num_delay_crash_threads)
        self.runCmd("expr num_delay_signal_threads=%d" %
                    num_delay_signal_threads)
        self.runCmd("expr num_delay_watchpoint_threads=%d" %
                    num_delay_watchpoint_threads)

        # Continue the inferior so threads are spawned
        self.runCmd("continue")

        # Make sure we see all the threads. The inferior program's threads all synchronize with a pseudo-barrier; that is,
        # the inferior program ensures all threads are started and running before any thread triggers its 'event'.
        num_threads = self.inferior_process.GetNumThreads()
        expected_num_threads = num_breakpoint_threads + num_delay_breakpoint_threads \
                             + num_signal_threads + num_delay_signal_threads \
                             + num_watchpoint_threads + num_delay_watchpoint_threads \
                             + num_crash_threads + num_delay_crash_threads + 1
        self.assertEqual(
            num_threads, expected_num_threads,
            'Expected to see %d threads, but seeing %d. Details:\n%s' %
            (expected_num_threads, num_threads, "\n\t".join(
                self.describe_threads())))

        self.signal_count = len(
            lldbutil.get_stopped_threads(self.inferior_process,
                                         lldb.eStopReasonSignal))
        self.crash_count = len(
            lldbutil.get_stopped_threads(self.inferior_process,
                                         lldb.eStopReasonException))

        # Run to completion (or crash)
        while not self.inferior_done():
            if self.TraceOn():
                self.runCmd("thread backtrace all")
            self.runCmd("continue")
            self.signal_count += len(
                lldbutil.get_stopped_threads(self.inferior_process,
                                             lldb.eStopReasonSignal))
            self.crash_count += len(
                lldbutil.get_stopped_threads(self.inferior_process,
                                             lldb.eStopReasonException))

        if num_crash_threads > 0 or num_delay_crash_threads > 0:
            # Expecting a crash
            self.assertTrue(
                self.crash_count > 0,
                "Expecting at least one thread to crash. Details: %s" %
                "\t\n".join(self.describe_threads()))

            # Ensure the zombie process is reaped
            self.runCmd("process kill")

        elif num_crash_threads == 0 and num_delay_crash_threads == 0:
            # There should be a single active thread (the main one) which hit the breakpoint after joining
            self.assertEqual(
                1, self.finish_breakpoint.GetHitCount(),
                "Expected main thread (finish) breakpoint to be hit once")

            num_threads = self.inferior_process.GetNumThreads()
            self.assertEqual(
                1, num_threads,
                "Expecting 1 thread but seeing %d. Details:%s" %
                (num_threads, "\n\t".join(self.describe_threads())))
            self.runCmd("continue")

            # The inferior process should have exited without crashing
            self.assertEqual(0, self.crash_count,
                             "Unexpected thread(s) in crashed state")
            self.assertTrue(
                self.inferior_process.GetState() == lldb.eStateExited,
                PROCESS_EXITED)

            # Verify the number of actions took place matches expected numbers
            expected_breakpoint_threads = num_delay_breakpoint_threads + num_breakpoint_threads
            breakpoint_hit_count = self.thread_breakpoint.GetHitCount(
            ) if expected_breakpoint_threads > 0 else 0
            self.assertEqual(
                expected_breakpoint_threads, breakpoint_hit_count,
                "Expected %d breakpoint hits, but got %d" %
                (expected_breakpoint_threads, breakpoint_hit_count))

            expected_signal_threads = num_delay_signal_threads + num_signal_threads
            self.assertEqual(
                expected_signal_threads, self.signal_count,
                "Expected %d stops due to signal delivery, but got %d" %
                (expected_signal_threads, self.signal_count))

            expected_watchpoint_threads = num_delay_watchpoint_threads + num_watchpoint_threads
            watchpoint_hit_count = self.thread_watchpoint.GetHitCount(
            ) if expected_watchpoint_threads > 0 else 0
            self.assertEqual(
                expected_watchpoint_threads, watchpoint_hit_count,
                "Expected %d watchpoint hits, got %d" %
                (expected_watchpoint_threads, watchpoint_hit_count))
示例#6
0
    def send_signal(self):
        """Test that lldb command 'process signal SIGUSR1' sends a signal to the inferior process."""

        exe = os.path.join(os.getcwd(), "a.out")

        # Create a target by the debugger.
        target = self.dbg.CreateTarget(exe)
        self.assertTrue(target, VALID_TARGET)

        # Now create a breakpoint on main.c by name 'c'.
        breakpoint = target.BreakpointCreateByLocation('main.c', self.line)
        self.assertTrue(breakpoint and
                        breakpoint.GetNumLocations() == 1,
                        VALID_BREAKPOINT)

        # Get the breakpoint location from breakpoint after we verified that,
        # indeed, it has one location.
        location = breakpoint.GetLocationAtIndex(0)
        self.assertTrue(location and
                        location.IsEnabled(),
                        VALID_BREAKPOINT_LOCATION)

        # Now launch the process, no arguments & do not stop at entry point.
        launch_info = lldb.SBLaunchInfo([exe])
        launch_info.SetWorkingDirectory(self.get_process_working_directory())

        process_listener = lldb.SBListener("signal_test_listener")
        launch_info.SetListener(process_listener)
        error = lldb.SBError()
        process = target.Launch(launch_info, error)
        self.assertTrue(process, PROCESS_IS_VALID)

        self.runCmd("process handle -n False -p True -s True SIGUSR1")

        thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint)
        self.assertTrue(thread.IsValid(), "We hit the first breakpoint.")

        # After resuming the process, send it a SIGUSR1 signal.

        self.setAsync(True)

        self.assertTrue(process_listener.IsValid(), "Got a good process listener")

        # Disable our breakpoint, we don't want to hit it anymore...
        breakpoint.SetEnabled(False)

        # Now continue:
        process.Continue()

        # If running remote test, there should be a connected event
        if lldb.remote_platform:
            self.match_state(process_listener, lldb.eStateConnected)

        self.match_state(process_listener, lldb.eStateRunning)

        # Now signal the process, and make sure it stops:
        process.Signal(signal.SIGUSR1)

        self.match_state(process_listener, lldb.eStateStopped)

        # Now make sure the thread was stopped with a SIGUSR1:
        threads = lldbutil.get_stopped_threads(process, lldb.eStopReasonSignal)
        self.assertTrue(len(threads) == 1, "One thread stopped for a signal.")
        thread = threads[0]

        self.assertTrue(thread.GetStopReasonDataCount() >= 1, "There was data in the event.")
        self.assertTrue(thread.GetStopReasonDataAtIndex(0) == signal.SIGUSR1, "The stop signal was SIGUSR1")
示例#7
0
    def step_over_stepping(self):
        """Use Python APIs to test stepping over and hitting breakpoints."""
        exe = os.path.join(os.getcwd(), "a.out")

        target = self.dbg.CreateTarget(exe)
        self.assertTrue(target, VALID_TARGET)

        self.main_source_spec = lldb.SBFileSpec(self.main_source)

        breakpoints_to_disable = []

        break_1_in_main = target.BreakpointCreateBySourceRegex(
            '// frame select 2, thread step-out while stopped at .c.1..',
            self.main_source_spec)
        self.assertTrue(break_1_in_main, VALID_BREAKPOINT)
        breakpoints_to_disable.append(break_1_in_main)

        break_in_a = target.BreakpointCreateBySourceRegex(
            '// break here to stop in a before calling b',
            self.main_source_spec)
        self.assertTrue(break_in_a, VALID_BREAKPOINT)
        breakpoints_to_disable.append(break_in_a)

        break_in_b = target.BreakpointCreateBySourceRegex(
            '// thread step-out while stopped at .c.2..',
            self.main_source_spec)
        self.assertTrue(break_in_b, VALID_BREAKPOINT)
        breakpoints_to_disable.append(break_in_b)

        break_in_c = target.BreakpointCreateBySourceRegex(
            '// Find the line number of function .c. here.',
            self.main_source_spec)
        self.assertTrue(break_in_c, VALID_BREAKPOINT)
        breakpoints_to_disable.append(break_in_c)

        # Now launch the process, and do not stop at entry point.
        process = target.LaunchSimple(None, None, os.getcwd())

        self.assertTrue(process, PROCESS_IS_VALID)

        # The stop reason of the thread should be breakpoint.
        threads = lldbutil.get_threads_stopped_at_breakpoint(
            process, break_1_in_main)

        if len(threads) != 1:
            self.fail("Failed to stop at first breakpoint in main.")

        thread = threads[0]

        # Get the stop id and for fun make sure it increases:
        old_stop_id = process.GetStopID()

        # Now step over, which should cause us to hit the breakpoint in "a"
        thread.StepOver()

        # The stop reason of the thread should be breakpoint.
        threads = lldbutil.get_threads_stopped_at_breakpoint(
            process, break_in_a)
        if len(threads) != 1:
            self.fail("Failed to stop at breakpoint in a.")

        # Check that the stop ID increases:
        new_stop_id = process.GetStopID()
        self.assertTrue(new_stop_id > old_stop_id,
                        "Stop ID increases monotonically.")

        thread = threads[0]

        # Step over, and we should hit the breakpoint in b:
        thread.StepOver()

        threads = lldbutil.get_threads_stopped_at_breakpoint(
            process, break_in_b)
        if len(threads) != 1:
            self.fail("Failed to stop at breakpoint in b.")
        thread = threads[0]

        # Now try running some function, and make sure that we still end up in the same place
        # and with the same stop reason.
        frame = thread.GetFrameAtIndex(0)
        current_line = frame.GetLineEntry().GetLine()
        current_file = frame.GetLineEntry().GetFileSpec()
        current_bp = []
        current_bp.append(thread.GetStopReasonDataAtIndex(0))
        current_bp.append(thread.GetStopReasonDataAtIndex(1))

        stop_id_before_expression = process.GetStopID()
        stop_id_before_including_expressions = process.GetStopID(True)

        frame.EvaluateExpression("(int) printf (print_string)")

        frame = thread.GetFrameAtIndex(0)
        self.assertTrue(current_line == frame.GetLineEntry().GetLine(),
                        "The line stayed the same after expression.")
        self.assertTrue(current_file == frame.GetLineEntry().GetFileSpec(),
                        "The file stayed the same after expression.")
        self.assertTrue(thread.GetStopReason() == lldb.eStopReasonBreakpoint,
                        "We still say we stopped for a breakpoint.")
        self.assertTrue(
            thread.GetStopReasonDataAtIndex(0) == current_bp[0]
            and thread.GetStopReasonDataAtIndex(1) == current_bp[1],
            "And it is the same breakpoint.")

        # Also make sure running the expression didn't change the public stop id
        # but did change if we are asking for expression stops as well.
        stop_id_after_expression = process.GetStopID()
        stop_id_after_including_expressions = process.GetStopID(True)

        self.assertTrue(stop_id_before_expression == stop_id_after_expression,
                        "Expression calling doesn't change stop ID")

        self.assertTrue(
            stop_id_after_including_expressions >
            stop_id_before_including_expressions,
            "Stop ID including expressions increments over expression call.")

        # Do the same thing with an expression that's going to crash, and make sure we are still unchanged.

        frame.EvaluateExpression("((char *) 0)[0] = 'a'")

        frame = thread.GetFrameAtIndex(0)
        self.assertTrue(current_line == frame.GetLineEntry().GetLine(),
                        "The line stayed the same after expression.")
        self.assertTrue(current_file == frame.GetLineEntry().GetFileSpec(),
                        "The file stayed the same after expression.")
        self.assertTrue(thread.GetStopReason() == lldb.eStopReasonBreakpoint,
                        "We still say we stopped for a breakpoint.")
        self.assertTrue(
            thread.GetStopReasonDataAtIndex(0) == current_bp[0]
            and thread.GetStopReasonDataAtIndex(1) == current_bp[1],
            "And it is the same breakpoint.")

        # Now continue and make sure we just complete the step:
        # Disable all our breakpoints first - sometimes the compiler puts two line table entries in for the
        # breakpoint a "b" and we don't want to hit that.
        for bkpt in breakpoints_to_disable:
            bkpt.SetEnabled(False)

        process.Continue()

        self.assertTrue(thread.GetFrameAtIndex(0).GetFunctionName() == "a")
        self.assertTrue(thread.GetStopReason() == lldb.eStopReasonPlanComplete)

        # And one more time should get us back to main:
        process.Continue()

        self.assertTrue(thread.GetFrameAtIndex(0).GetFunctionName() == "main")
        self.assertTrue(thread.GetStopReason() == lldb.eStopReasonPlanComplete)

        # Now make sure we can call a function, break in the called function, then have "continue" get us back out again:
        frame = thread.GetFrameAtIndex(0)
        frame = thread.GetFrameAtIndex(0)
        current_line = frame.GetLineEntry().GetLine()
        current_file = frame.GetLineEntry().GetFileSpec()

        break_in_b.SetEnabled(True)
        frame.EvaluateExpression("b (4)", lldb.eNoDynamicValues, False)

        threads = lldbutil.get_threads_stopped_at_breakpoint(
            process, break_in_b)
        if len(threads) != 1:
            self.fail("Failed to stop at breakpoint in b when calling b.")
        thread = threads[0]

        # So do a step over here to make sure we can still do that:

        thread.StepOver()

        # See that we are still in b:
        self.assertTrue(thread.GetFrameAtIndex(0).GetFunctionName() == "b")

        # Okay, now if we continue, we will finish off our function call and we should end up back in "a" as if nothing had happened:
        process.Continue()

        self.assertTrue(
            thread.GetFrameAtIndex(0).GetLineEntry().GetLine() == current_line)
        self.assertTrue(
            thread.GetFrameAtIndex(0).GetLineEntry().GetFileSpec() ==
            current_file)

        # Now we are going to test step in targetting a function:

        break_in_b.SetEnabled(False)

        break_before_complex_1 = target.BreakpointCreateBySourceRegex(
            '// Stop here to try step in targetting b.', self.main_source_spec)
        self.assertTrue(break_before_complex_1, VALID_BREAKPOINT)

        break_before_complex_2 = target.BreakpointCreateBySourceRegex(
            '// Stop here to try step in targetting complex.',
            self.main_source_spec)
        self.assertTrue(break_before_complex_2, VALID_BREAKPOINT)

        break_before_complex_3 = target.BreakpointCreateBySourceRegex(
            '// Stop here to step targetting b and hitting breakpoint.',
            self.main_source_spec)
        self.assertTrue(break_before_complex_3, VALID_BREAKPOINT)

        break_before_complex_4 = target.BreakpointCreateBySourceRegex(
            '// Stop here to make sure bogus target steps over.',
            self.main_source_spec)
        self.assertTrue(break_before_complex_4, VALID_BREAKPOINT)

        threads = lldbutil.continue_to_breakpoint(process,
                                                  break_before_complex_1)
        self.assertTrue(len(threads) == 1)
        thread = threads[0]
        break_before_complex_1.SetEnabled(False)

        thread.StepInto("b")
        self.assertTrue(thread.GetFrameAtIndex(0).GetFunctionName() == "b")

        # Now continue out and stop at the next call to complex.  This time step all the way into complex:
        threads = lldbutil.continue_to_breakpoint(process,
                                                  break_before_complex_2)
        self.assertTrue(len(threads) == 1)
        thread = threads[0]
        break_before_complex_2.SetEnabled(False)

        thread.StepInto("complex")
        self.assertTrue(
            thread.GetFrameAtIndex(0).GetFunctionName() == "complex")

        # Now continue out and stop at the next call to complex.  This time enable breakpoints in a and c and then step targetting b:
        threads = lldbutil.continue_to_breakpoint(process,
                                                  break_before_complex_3)
        self.assertTrue(len(threads) == 1)
        thread = threads[0]
        break_before_complex_3.SetEnabled(False)

        break_at_start_of_a = target.BreakpointCreateByName('a')
        break_at_start_of_c = target.BreakpointCreateByName('c')

        thread.StepInto("b")
        threads = lldbutil.get_stopped_threads(process,
                                               lldb.eStopReasonBreakpoint)

        self.assertTrue(len(threads) == 1)
        thread = threads[0]
        stop_break_id = thread.GetStopReasonDataAtIndex(0)
        self.assertTrue(stop_break_id == break_at_start_of_a.GetID()
                        or stop_break_id == break_at_start_of_c.GetID())

        break_at_start_of_a.SetEnabled(False)
        break_at_start_of_c.SetEnabled(False)

        process.Continue()
        self.assertTrue(thread.GetFrameAtIndex(0).GetFunctionName() == "b")

        # Now continue out and stop at the next call to complex.  This time enable breakpoints in a and c and then step targetting b:
        threads = lldbutil.continue_to_breakpoint(process,
                                                  break_before_complex_4)
        self.assertTrue(len(threads) == 1)
        thread = threads[0]
        break_before_complex_4.SetEnabled(False)

        thread.StepInto("NoSuchFunction")
        self.assertTrue(thread.GetFrameAtIndex(0).GetFunctionName() == "main")
示例#8
0
    def do_get_dynamic_vals(self):
        """Make sure we get dynamic values correctly both for compiled in classes and dynamic ones"""
        exe = os.path.join(os.getcwd(), "a.out")

        # Create a target from the debugger.

        target = self.dbg.CreateTarget(exe)
        self.assertTrue(target, VALID_TARGET)

        # Set up our breakpoints:

        handle_SourceBase_bkpt = target.BreakpointCreateByLocation(
            self.source_name, self.handle_SourceBase)
        self.assertTrue(
            handle_SourceBase_bkpt
            and handle_SourceBase_bkpt.GetNumLocations() == 1,
            VALID_BREAKPOINT)

        main_before_setProperty_bkpt = target.BreakpointCreateByLocation(
            self.source_name, self.main_before_setProperty_line)
        self.assertTrue(
            main_before_setProperty_bkpt
            and main_before_setProperty_bkpt.GetNumLocations() == 1,
            VALID_BREAKPOINT)

        # Now launch the process, and do not stop at the entry point.
        process = target.LaunchSimple(None, None,
                                      self.get_process_working_directory())

        self.assertTrue(process.GetState() == lldb.eStateStopped,
                        PROCESS_STOPPED)

        threads = lldbutil.get_threads_stopped_at_breakpoint(
            process, main_before_setProperty_bkpt)
        self.assertTrue(len(threads) == 1)
        thread = threads[0]

        #
        #  At this point, myObserver has a Source pointer that is actually a KVO swizzled SourceDerived
        #  make sure we can get that properly:

        frame = thread.GetFrameAtIndex(0)
        myObserver = frame.FindVariable('myObserver',
                                        lldb.eDynamicCanRunTarget)
        self.assertTrue(myObserver)
        myObserver_source = myObserver.GetChildMemberWithName(
            '_source', lldb.eDynamicCanRunTarget)
        self.examine_SourceDerived_ptr(myObserver_source)

        #
        #  Make sure a static value can be correctly turned into a dynamic value.

        frame = thread.GetFrameAtIndex(0)
        myObserver_static = frame.FindVariable('myObserver',
                                               lldb.eNoDynamicValues)
        self.assertTrue(myObserver_static)
        myObserver = myObserver_static.GetDynamicValue(
            lldb.eDynamicCanRunTarget)
        myObserver_source = myObserver.GetChildMemberWithName(
            '_source', lldb.eDynamicCanRunTarget)
        self.examine_SourceDerived_ptr(myObserver_source)

        # The "frame var" code uses another path to get into children, so let's
        # make sure that works as well:

        result = lldb.SBCommandReturnObject()

        self.expect('frame var -d run-target myObserver->_source',
                    'frame var finds its way into a child member',
                    patterns=['\(SourceDerived \*\)'])

        # check that our ObjC GetISA() does a good job at hiding KVO swizzled classes

        self.expect('frame var -d run-target myObserver->_source -T',
                    'the KVO-ed class is hidden',
                    substrs=['SourceDerived'])

        self.expect('frame var -d run-target myObserver->_source -T',
                    'the KVO-ed class is hidden',
                    matching=False,
                    substrs=['NSKVONotify'])

        # This test is not entirely related to the main thrust of this test case, but since we're here,
        # try stepping into setProperty, and make sure we get into the version in Source:

        thread.StepInto()

        threads = lldbutil.get_stopped_threads(process,
                                               lldb.eStopReasonPlanComplete)
        self.assertTrue(len(threads) == 1)
        line_entry = threads[0].GetFrameAtIndex(0).GetLineEntry()

        self.assertTrue(line_entry.GetLine() == self.set_property_line)
        self.assertTrue(
            line_entry.GetFileSpec().GetFilename() == self.source_name)

        # Okay, back to the main business.  Continue to the handle_SourceBase and make sure we get the correct dynamic value.

        threads = lldbutil.continue_to_breakpoint(process,
                                                  handle_SourceBase_bkpt)
        self.assertTrue(len(threads) == 1)
        thread = threads[0]

        frame = thread.GetFrameAtIndex(0)

        # Get "object" using FindVariable:

        noDynamic = lldb.eNoDynamicValues
        useDynamic = lldb.eDynamicCanRunTarget

        object_static = frame.FindVariable('object', noDynamic)
        object_dynamic = frame.FindVariable('object', useDynamic)

        # Delete this object to make sure that this doesn't cause havoc with the dynamic object that depends on it.
        del (object_static)

        self.examine_SourceDerived_ptr(object_dynamic)

        # Get "this" using FindValue, make sure that works too:
        object_static = frame.FindValue('object',
                                        lldb.eValueTypeVariableArgument,
                                        noDynamic)
        object_dynamic = frame.FindValue('object',
                                         lldb.eValueTypeVariableArgument,
                                         useDynamic)
        del (object_static)
        self.examine_SourceDerived_ptr(object_dynamic)

        # Get "this" using the EvaluateExpression:
        object_static = frame.EvaluateExpression('object', noDynamic)
        object_dynamic = frame.EvaluateExpression('object', useDynamic)
        del (object_static)
        self.examine_SourceDerived_ptr(object_dynamic)

        # Continue again to the handle_SourceBase and make sure we get the correct dynamic value.
        # This one looks exactly the same, but in fact this is an "un-KVO'ed" version of SourceBase, so
        # its isa pointer points to SourceBase not NSKVOSourceBase or whatever...

        threads = lldbutil.continue_to_breakpoint(process,
                                                  handle_SourceBase_bkpt)
        self.assertTrue(len(threads) == 1)
        thread = threads[0]

        frame = thread.GetFrameAtIndex(0)

        # Get "object" using FindVariable:

        object_static = frame.FindVariable('object', noDynamic)
        object_dynamic = frame.FindVariable('object', useDynamic)

        # Delete this object to make sure that this doesn't cause havoc with the dynamic object that depends on it.
        del (object_static)

        self.examine_SourceDerived_ptr(object_dynamic)
示例#9
0
    def do_get_dynamic_vals(self):
        """Make sure we get dynamic values correctly both for compiled in classes and dynamic ones"""
        exe = os.path.join(os.getcwd(), "a.out")

        # Create a target from the debugger.

        target = self.dbg.CreateTarget(exe)
        self.assertTrue(target, VALID_TARGET)

        # Set up our breakpoints:

        handle_SourceBase_bkpt = target.BreakpointCreateByLocation(self.source_name, self.handle_SourceBase)
        self.assertTrue(handle_SourceBase_bkpt and handle_SourceBase_bkpt.GetNumLocations() == 1, VALID_BREAKPOINT)

        main_before_setProperty_bkpt = target.BreakpointCreateByLocation(
            self.source_name, self.main_before_setProperty_line
        )
        self.assertTrue(
            main_before_setProperty_bkpt and main_before_setProperty_bkpt.GetNumLocations() == 1, VALID_BREAKPOINT
        )

        # Now launch the process, and do not stop at the entry point.
        process = target.LaunchSimple(None, None, os.getcwd())

        self.assertTrue(process.GetState() == lldb.eStateStopped, PROCESS_STOPPED)

        threads = lldbutil.get_threads_stopped_at_breakpoint(process, main_before_setProperty_bkpt)
        self.assertTrue(len(threads) == 1)
        thread = threads[0]

        #
        #  At this point, myObserver has a Source pointer that is actually a KVO swizzled SourceDerived
        #  make sure we can get that properly:

        frame = thread.GetFrameAtIndex(0)
        myObserver = frame.FindVariable("myObserver", lldb.eDynamicCanRunTarget)
        self.assertTrue(myObserver)
        myObserver_source = myObserver.GetChildMemberWithName("_source", lldb.eDynamicCanRunTarget)
        self.examine_SourceDerived_ptr(myObserver_source)

        #
        #  Make sure a static value can be correctly turned into a dynamic value.

        frame = thread.GetFrameAtIndex(0)
        myObserver_static = frame.FindVariable("myObserver", lldb.eNoDynamicValues)
        self.assertTrue(myObserver_static)
        myObserver = myObserver_static.GetDynamicValue(lldb.eDynamicCanRunTarget)
        myObserver_source = myObserver.GetChildMemberWithName("_source", lldb.eDynamicCanRunTarget)
        self.examine_SourceDerived_ptr(myObserver_source)

        # The "frame var" code uses another path to get into children, so let's
        # make sure that works as well:

        result = lldb.SBCommandReturnObject()

        self.expect(
            "frame var -d run-target myObserver->_source",
            "frame var finds its way into a child member",
            patterns=["\(SourceDerived \*\)"],
        )

        # check that our ObjC GetISA() does a good job at hiding KVO swizzled classes

        self.expect(
            "frame var -d run-target myObserver->_source -T",
            "the KVO-ed class is hidden",
            substrs=["dynamic type: SourceDerived"],
        )

        self.expect(
            "frame var -d run-target myObserver->_source -T",
            "the KVO-ed class is hidden",
            matching=False,
            substrs=["dynamic type: NSKVONotify"],
        )

        # This test is not entirely related to the main thrust of this test case, but since we're here,
        # try stepping into setProperty, and make sure we get into the version in Source:

        thread.StepInto()

        threads = lldbutil.get_stopped_threads(process, lldb.eStopReasonPlanComplete)
        self.assertTrue(len(threads) == 1)
        line_entry = threads[0].GetFrameAtIndex(0).GetLineEntry()
        self.assertTrue(line_entry.GetLine() == self.set_property_line)
        self.assertTrue(line_entry.GetFileSpec().GetFilename() == self.source_name)

        # Okay, back to the main business.  Continue to the handle_SourceBase and make sure we get the correct dynamic value.

        threads = lldbutil.continue_to_breakpoint(process, handle_SourceBase_bkpt)
        self.assertTrue(len(threads) == 1)
        thread = threads[0]

        frame = thread.GetFrameAtIndex(0)

        # Get "object" using FindVariable:

        noDynamic = lldb.eNoDynamicValues
        useDynamic = lldb.eDynamicCanRunTarget

        object_static = frame.FindVariable("object", noDynamic)
        object_dynamic = frame.FindVariable("object", useDynamic)

        # Delete this object to make sure that this doesn't cause havoc with the dynamic object that depends on it.
        del (object_static)

        self.examine_SourceDerived_ptr(object_dynamic)

        # Get "this" using FindValue, make sure that works too:
        object_static = frame.FindValue("object", lldb.eValueTypeVariableArgument, noDynamic)
        object_dynamic = frame.FindValue("object", lldb.eValueTypeVariableArgument, useDynamic)
        del (object_static)
        self.examine_SourceDerived_ptr(object_dynamic)

        # Get "this" using the EvaluateExpression:
        object_static = frame.EvaluateExpression("object", noDynamic)
        object_dynamic = frame.EvaluateExpression("object", useDynamic)
        del (object_static)
        self.examine_SourceDerived_ptr(object_dynamic)

        # Continue again to the handle_SourceBase and make sure we get the correct dynamic value.
        # This one looks exactly the same, but in fact this is an "un-KVO'ed" version of SourceBase, so
        # its isa pointer points to SourceBase not NSKVOSourceBase or whatever...

        threads = lldbutil.continue_to_breakpoint(process, handle_SourceBase_bkpt)
        self.assertTrue(len(threads) == 1)
        thread = threads[0]

        frame = thread.GetFrameAtIndex(0)

        # Get "object" using FindVariable:

        object_static = frame.FindVariable("object", noDynamic)
        object_dynamic = frame.FindVariable("object", useDynamic)

        # Delete this object to make sure that this doesn't cause havoc with the dynamic object that depends on it.
        del (object_static)

        self.examine_SourceDerived_ptr(object_dynamic)
示例#10
0
    def do_thread_actions(self,
                          num_breakpoint_threads = 0,
                          num_signal_threads = 0,
                          num_watchpoint_threads = 0,
                          num_crash_threads = 0,
                          num_delay_breakpoint_threads = 0,
                          num_delay_signal_threads = 0,
                          num_delay_watchpoint_threads = 0,
                          num_delay_crash_threads = 0):
        """ Sets a breakpoint in the main thread where test parameters (numbers of threads) can be adjusted, runs the inferior
            to that point, and modifies the locals that control the event thread counts. Also sets a breakpoint in
            breakpoint_func (the function executed by each 'breakpoint' thread) and a watchpoint on a global modified in
            watchpoint_func. The inferior is continued until exit or a crash takes place, and the number of events seen by LLDB
            is verified to match the expected number of events.
        """
        exe = os.path.join(os.getcwd(), "a.out")
        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)

        # Get the target
        self.inferior_target = self.dbg.GetSelectedTarget()

        expected_bps = []

        # Initialize all the breakpoints (main thread/aux thread)
        self.setup_breakpoint = self.add_breakpoint(self.setup_breakpoint_line, expected_bps)
        self.finish_breakpoint = self.add_breakpoint(self.finish_breakpoint_line, expected_bps)

        # Set the thread breakpoint
        if num_breakpoint_threads + num_delay_breakpoint_threads > 0:
            self.thread_breakpoint = self.add_breakpoint(self.thread_breakpoint_line, expected_bps)

        # Verify breakpoints
        self.expect("breakpoint list -f", "Breakpoint locations shown correctly", substrs = expected_bps)

        # Run the program.
        self.runCmd("run", RUN_SUCCEEDED)

        # Check we are at line self.setup_breakpoint
        self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT,
            substrs = ["stop reason = breakpoint 1."])

        # Initialize the (single) watchpoint on the global variable (g_watchme)
        if num_watchpoint_threads + num_delay_watchpoint_threads > 0:
            self.runCmd("watchpoint set variable g_watchme")
            for w in self.inferior_target.watchpoint_iter():
                self.thread_watchpoint = w
                self.assertTrue("g_watchme" in str(self.thread_watchpoint), "Watchpoint location not shown correctly")

        # Get the process
        self.inferior_process = self.inferior_target.GetProcess()

        # We should be stopped at the setup site where we can set the number of
        # threads doing each action (break/crash/signal/watch)
        self.assertEqual(self.inferior_process.GetNumThreads(), 1, 'Expected to stop before any additional threads are spawned.')

        self.runCmd("expr num_breakpoint_threads=%d" % num_breakpoint_threads)
        self.runCmd("expr num_crash_threads=%d" % num_crash_threads)
        self.runCmd("expr num_signal_threads=%d" % num_signal_threads)
        self.runCmd("expr num_watchpoint_threads=%d" % num_watchpoint_threads)

        self.runCmd("expr num_delay_breakpoint_threads=%d" % num_delay_breakpoint_threads)
        self.runCmd("expr num_delay_crash_threads=%d" % num_delay_crash_threads)
        self.runCmd("expr num_delay_signal_threads=%d" % num_delay_signal_threads)
        self.runCmd("expr num_delay_watchpoint_threads=%d" % num_delay_watchpoint_threads)

        # Continue the inferior so threads are spawned
        self.runCmd("continue")

        # Make sure we see all the threads. The inferior program's threads all synchronize with a pseudo-barrier; that is,
        # the inferior program ensures all threads are started and running before any thread triggers its 'event'.
        num_threads = self.inferior_process.GetNumThreads()
        expected_num_threads = num_breakpoint_threads + num_delay_breakpoint_threads \
                             + num_signal_threads + num_delay_signal_threads \
                             + num_watchpoint_threads + num_delay_watchpoint_threads \
                             + num_crash_threads + num_delay_crash_threads + 1
        self.assertEqual(num_threads, expected_num_threads,
            'Expected to see %d threads, but seeing %d. Details:\n%s' % (expected_num_threads,
                                                                         num_threads,
                                                                         "\n\t".join(self.describe_threads())))

        self.signal_count = len(lldbutil.get_stopped_threads(self.inferior_process, lldb.eStopReasonSignal))
        self.crash_count = len(lldbutil.get_stopped_threads(self.inferior_process, lldb.eStopReasonException))

        # Run to completion (or crash)
        while not self.inferior_done(): 
            if self.TraceOn():
                self.runCmd("thread backtrace all")
            self.runCmd("continue")
            self.signal_count += len(lldbutil.get_stopped_threads(self.inferior_process, lldb.eStopReasonSignal))
            self.crash_count += len(lldbutil.get_stopped_threads(self.inferior_process, lldb.eStopReasonException))

        if num_crash_threads > 0 or num_delay_crash_threads > 0:
            # Expecting a crash
            self.assertTrue(self.crash_count > 0,
                "Expecting at least one thread to crash. Details: %s" % "\t\n".join(self.describe_threads()))

            # Ensure the zombie process is reaped
            self.runCmd("process kill")

        elif num_crash_threads == 0 and num_delay_crash_threads == 0:
            # There should be a single active thread (the main one) which hit the breakpoint after joining
            self.assertEqual(1, self.finish_breakpoint.GetHitCount(), "Expected main thread (finish) breakpoint to be hit once")

            num_threads = self.inferior_process.GetNumThreads()
            self.assertEqual(1, num_threads, "Expecting 1 thread but seeing %d. Details:%s" % (num_threads,
                                                                                             "\n\t".join(self.describe_threads())))
            self.runCmd("continue")

            # The inferior process should have exited without crashing
            self.assertEqual(0, self.crash_count, "Unexpected thread(s) in crashed state")
            self.assertTrue(self.inferior_process.GetState() == lldb.eStateExited, PROCESS_EXITED)

            # Verify the number of actions took place matches expected numbers
            expected_breakpoint_threads = num_delay_breakpoint_threads + num_breakpoint_threads
            breakpoint_hit_count = self.thread_breakpoint.GetHitCount() if expected_breakpoint_threads > 0 else 0
            self.assertEqual(expected_breakpoint_threads, breakpoint_hit_count,
                "Expected %d breakpoint hits, but got %d" % (expected_breakpoint_threads, breakpoint_hit_count))

            expected_signal_threads = num_delay_signal_threads + num_signal_threads
            self.assertEqual(expected_signal_threads, self.signal_count,
                "Expected %d stops due to signal delivery, but got %d" % (expected_signal_threads, self.signal_count))

            expected_watchpoint_threads = num_delay_watchpoint_threads + num_watchpoint_threads
            watchpoint_hit_count = self.thread_watchpoint.GetHitCount() if expected_watchpoint_threads > 0 else 0
            self.assertEqual(expected_watchpoint_threads, watchpoint_hit_count,
                "Expected %d watchpoint hits, got %d" % (expected_watchpoint_threads, watchpoint_hit_count))