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())