| import lldb |
| from lldbsuite.test.decorators import * |
| from lldbsuite.test.lldbtest import * |
| from lldbsuite.test import lldbutil |
| |
| |
| class LibCxxStdFunctionRecognizerTestCase(TestBase): |
| NO_DEBUG_INFO_TESTCASE = True |
| |
| @add_test_categories(["libc++"]) |
| def test_frame_recognizer(self): |
| """Test that std::function all implementation details are hidden in SBFrame""" |
| self.build() |
| (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( |
| self, "// break here", lldb.SBFileSpec("main.cpp") |
| ) |
| self.assertIn("foo", thread.GetFrameAtIndex(0).GetFunctionName()) |
| # Skip all hidden frames |
| frame_id = 1 |
| while ( |
| frame_id < thread.GetNumFrames() |
| and thread.GetFrameAtIndex(frame_id).IsHidden() |
| ): |
| frame_id = frame_id + 1 |
| # Expect `std::function<...>::operator()` to be the direct parent of `foo` |
| self.assertIn( |
| "::operator()", thread.GetFrameAtIndex(frame_id).GetFunctionName() |
| ) |
| # And right above that, there should be the `main` frame |
| self.assertIn("main", thread.GetFrameAtIndex(frame_id + 1).GetFunctionName()) |
| |
| @add_test_categories(["libc++"]) |
| def test_backtrace(self): |
| """Test that std::function implementation details are hidden in bt""" |
| self.build() |
| (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( |
| self, "// break here", lldb.SBFileSpec("main.cpp") |
| ) |
| # Filtered. |
| self.expect( |
| "thread backtrace", |
| ordered=True, |
| substrs=["frame", "foo", "frame", "main"], |
| ) |
| self.expect( |
| "thread backtrace", matching=False, patterns=["frame.*std::__.*::__function"] |
| ) |
| # Unfiltered. |
| self.expect( |
| "bt -u", |
| ordered=True, |
| patterns=["frame.*foo", "frame.*std::__[^:]*::__function", "frame.*main"], |
| ) |
| self.expect( |
| "thread backtrace -u", |
| ordered=True, |
| patterns=["frame.*foo", "frame.*std::__[^:]*::__function", "frame.*main"], |
| ) |
| self.expect( |
| "thread backtrace --unfiltered", |
| ordered=True, |
| patterns=["frame.*foo", "frame.*std::__[^:]*::__function", "frame.*main"], |
| ) |
| |
| @add_test_categories(["libc++"]) |
| def test_up_down(self): |
| """Test that std::function implementation details are skipped""" |
| self.build() |
| (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( |
| self, "// break here", lldb.SBFileSpec("main.cpp") |
| ) |
| frame = thread.selected_frame |
| # up |
| self.assertIn("foo", frame.GetFunctionName()) |
| start_idx = frame.GetFrameID() |
| i = 0 |
| while i < thread.GetNumFrames(): |
| self.expect("up") |
| frame = thread.selected_frame |
| if frame.GetFunctionName() == "main": |
| break |
| end_idx = frame.GetFrameID() |
| self.assertLess(i, end_idx - start_idx, "skipped frames") |
| |
| # Back down again. |
| start_idx = frame.GetFrameID() |
| for i in range(1, thread.GetNumFrames()): |
| self.expect("down") |
| frame = thread.selected_frame |
| if "foo" in frame.GetFunctionName(): |
| break |
| end_idx = frame.GetFrameID() |
| self.assertLess(i, start_idx - end_idx, "skipped frames") |
| |
| @add_test_categories(["libc++"]) |
| def test_api(self): |
| """Test that std::function implementation details are skipped""" |
| self.build() |
| (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( |
| self, "// break here", lldb.SBFileSpec("main.cpp") |
| ) |
| num_hidden = 0 |
| for frame in thread.frames: |
| if frame.IsHidden(): |
| num_hidden += 1 |
| |
| self.assertGreater(num_hidden, 0) |
| self.assertLess(num_hidden, thread.GetNumFrames()) |