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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits