emrekultursay created this revision.
Herald added a project: All.
emrekultursay requested review of this revision.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.

The test is identical to API/lang/c/stepping/ except:

1. It uses C++ and thus needs demangling support
2. It uses dynamic library, and tries to step into a function that is defined 
in the library.

Test fails with:

    File 
"...llvm-project/lldb/test/API/lang/cpp/stepping/TestStepAndBreakpointsCpp.py", 
line 252, in test_and_python_api
      self.assertEqual(thread.GetFrameAtIndex(0).GetFunctionName(), "b(int)")
  AssertionError: 'main' != 'b(int)'

...because it fails to step into the `b(int)` method and hits the next
breakpoint inside the `main` method.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D131821

Files:
  lldb/test/API/lang/cpp/stepping/Makefile
  lldb/test/API/lang/cpp/stepping/TestStepAndBreakpointsCpp.py
  lldb/test/API/lang/cpp/stepping/helper.cpp
  lldb/test/API/lang/cpp/stepping/main.cpp

Index: lldb/test/API/lang/cpp/stepping/main.cpp
===================================================================
--- /dev/null
+++ lldb/test/API/lang/cpp/stepping/main.cpp
@@ -0,0 +1,24 @@
+int a(int);
+int b(int);
+int c(int);
+const char *print_string = "aaaaaaaaaa\n";
+int complex (int first, int second, int third);
+
+int main (int argc, char const *argv[])
+{
+    int A1 = a(1); // frame select 2, thread step-out while stopped at "c(1)"
+
+    int B2 = b(2); // assignment to B2
+
+    int A3 = a(3); // frame select 1, thread step-out while stopped at "c(3)"
+
+    int A4 = complex (a(1), b(2), c(3)); // Stop here to try step in targeting b.
+
+    int A5 = complex (a(2), b(3), c(4)); // Stop here to try step in targeting complex.
+
+    int A6 = complex (a(4), b(5), c(6)); // Stop here to step targeting b and hitting breakpoint.
+
+    int A7 = complex (a(5), b(6), c(7)); // Stop here to make sure bogus target steps over.
+
+    return A1 + B2 + A3 + A4 + A5 + A6 + A7 + *print_string;
+}
Index: lldb/test/API/lang/cpp/stepping/helper.cpp
===================================================================
--- /dev/null
+++ lldb/test/API/lang/cpp/stepping/helper.cpp
@@ -0,0 +1,35 @@
+int a(int);
+int b(int);
+int c(int);
+
+int a(int val)
+{
+    int return_value = val;  // basic break at the start of b
+
+    if (val <= 1)
+    {
+        return_value =  b(val); // break here to stop in a before calling b
+    }
+    else if (val >= 3)
+    {
+        return_value = c(val);
+    }
+
+    return return_value;
+}
+
+int b(int val)
+{
+    int rc = c(val); // thread step-out while stopped at "c(2)"
+    return rc;
+}
+
+int c(int val)
+{
+    return val + 3; // Find the line number of function "c" here.
+}
+
+int complex (int first, int second, int third)
+{
+    return first + second + third;  // Step in targeting complex should stop here
+}
Index: lldb/test/API/lang/cpp/stepping/TestStepAndBreakpointsCpp.py
===================================================================
--- /dev/null
+++ lldb/test/API/lang/cpp/stepping/TestStepAndBreakpointsCpp.py
@@ -0,0 +1,302 @@
+"""Test stepping over vrs. hitting breakpoints & subsequent stepping in various forms."""
+
+
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestCppStepping(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    def setUp(self):
+        # Call super's setUp().
+        TestBase.setUp(self)
+        # Find the line numbers that we will step to in main:
+        self.main_source = "main.cpp"
+        self.helper_source = "helper.cpp"
+
+    @add_test_categories(['pyapi', 'basic_process'])
+    @expectedFailureAll(oslist=['freebsd'], bugnumber='llvm.org/pr17932')
+    @expectedFailureAll(oslist=["linux"], archs=no_match(["i386", "x86_64"]))
+    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24777")
+    @expectedFailureNetBSD
+    @skipIfWindows
+    @skipIfDarwinEmbedded
+    def test_and_python_api(self):
+        """Test stepping over vrs. hitting breakpoints & subsequent stepping in various forms."""
+        self.build()
+        exe = self.getBuildArtifact("a.out")
+
+        target = self.dbg.CreateTarget(exe)
+        self.assertTrue(target, VALID_TARGET)
+
+        environment = self.registerSharedLibrariesWithTarget(target, ["helper"])
+
+        self.main_source_spec = lldb.SBFileSpec(self.main_source)
+        self.helper_source_spec = lldb.SBFileSpec(self.helper_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.helper_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.helper_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.helper_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, environment, self.get_process_working_directory())
+
+        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.assertEqual(
+            current_line, frame.GetLineEntry().GetLine(),
+            "The line stayed the same after expression.")
+        self.assertEqual(
+            current_file, frame.GetLineEntry().GetFileSpec(),
+            "The file stayed the same after expression.")
+        self.assertEqual(
+            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.assertEqual(
+            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.assertEqual(
+            current_line, frame.GetLineEntry().GetLine(),
+            "The line stayed the same after expression.")
+        self.assertEqual(
+            current_file, frame.GetLineEntry().GetFileSpec(),
+            "The file stayed the same after expression.")
+        self.assertEqual(
+            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.assertEqual(thread.GetFrameAtIndex(0).GetFunctionName(), "a(int)")
+        self.assertEqual(thread.GetStopReason(), lldb.eStopReasonPlanComplete)
+
+        # And one more time should get us back to main:
+        process.Continue()
+
+        self.assertEqual(thread.GetFrameAtIndex(0).GetFunctionName(), "main")
+        self.assertEqual(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)
+        options = lldb.SBExpressionOptions()
+        options.SetIgnoreBreakpoints(False)
+        options.SetFetchDynamicValue(False)
+        options.SetUnwindOnError(False)
+        frame.EvaluateExpression("b (4)", options)
+
+        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:
+        func_name = thread.GetFrameAtIndex(0).GetFunctionName()
+        self.assertEqual(
+            func_name, "b(int)",
+            "Should be in 'b', were in %s" %
+            (func_name))
+
+        # 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 targeting a function:
+
+        break_in_b.SetEnabled(False)
+
+        break_before_complex_1 = target.BreakpointCreateBySourceRegex(
+            '// Stop here to try step in targeting 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 targeting complex.', self.main_source_spec)
+        self.assertTrue(break_before_complex_2, VALID_BREAKPOINT)
+
+        break_before_complex_3 = target.BreakpointCreateBySourceRegex(
+            '// Stop here to step targeting 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.assertEqual(len(threads), 1)
+        thread = threads[0]
+        break_before_complex_1.SetEnabled(False)
+
+        thread.StepInto("b")
+        self.assertEqual(thread.GetFrameAtIndex(0).GetFunctionName(), "b(int)")
+
+        # 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.assertEqual(len(threads), 1)
+        thread = threads[0]
+        break_before_complex_2.SetEnabled(False)
+
+        thread.StepInto("complex")
+        self.assertEqual(thread.GetFrameAtIndex(
+            0).GetFunctionName(), "complex(int, int, int)")
+
+        # Now continue out and stop at the next call to complex.  This time
+        # enable breakpoints in a and c and then step targeting b:
+        threads = lldbutil.continue_to_breakpoint(
+            process, break_before_complex_3)
+        self.assertEqual(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.assertEqual(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.assertEqual(thread.GetFrameAtIndex(0).GetFunctionName(), "b(int)")
+
+        # Now continue out and stop at the next call to complex.  This time
+        # enable breakpoints in a and c and then step targeting b:
+        threads = lldbutil.continue_to_breakpoint(
+            process, break_before_complex_4)
+        self.assertEqual(len(threads), 1)
+        thread = threads[0]
+        break_before_complex_4.SetEnabled(False)
+
+        thread.StepInto("NoSuchFunction")
+        self.assertEqual(thread.GetFrameAtIndex(0).GetFunctionName(), "main")
Index: lldb/test/API/lang/cpp/stepping/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/lang/cpp/stepping/Makefile
@@ -0,0 +1,12 @@
+LD_EXTRAS := -L. -lhelper
+CXX_SOURCES := main.cpp
+USE_LIBDL := 1
+CFLAGS := -g -O0
+
+a.out: libhelper
+
+include Makefile.rules
+
+libhelper:
+	$(MAKE) -f $(MAKEFILE_RULES) \
+		DYLIB_ONLY=YES DYLIB_CXX_SOURCES=helper.cpp DYLIB_NAME=helper
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to