1import lldb 2from lldbsuite.test.decorators import * 3from lldbsuite.test.lldbtest import * 4from lldbsuite.test import lldbutil 5 6 7class LibCxxStdFunctionRecognizerTestCase(TestBase): 8 NO_DEBUG_INFO_TESTCASE = True 9 10 @add_test_categories(["libc++"]) 11 def test_frame_recognizer(self): 12 """Test that std::function all implementation details are hidden in SBFrame""" 13 self.build() 14 (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( 15 self, "// break here", lldb.SBFileSpec("main.cpp") 16 ) 17 self.assertIn("foo", thread.GetFrameAtIndex(0).GetFunctionName()) 18 # Skip all hidden frames 19 frame_id = 1 20 while ( 21 frame_id < thread.GetNumFrames() 22 and thread.GetFrameAtIndex(frame_id).IsHidden() 23 ): 24 frame_id = frame_id + 1 25 # Expect `std::function<...>::operator()` to be the direct parent of `foo` 26 self.assertIn( 27 "::operator()", thread.GetFrameAtIndex(frame_id).GetFunctionName() 28 ) 29 # And right above that, there should be the `main` frame 30 self.assertIn("main", thread.GetFrameAtIndex(frame_id + 1).GetFunctionName()) 31 32 @add_test_categories(["libc++"]) 33 def test_backtrace(self): 34 """Test that std::function implementation details are hidden in bt""" 35 self.build() 36 (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( 37 self, "// break here", lldb.SBFileSpec("main.cpp") 38 ) 39 # Filtered. 40 self.expect( 41 "thread backtrace", 42 ordered=True, 43 substrs=["frame", "foo", "frame", "main"], 44 ) 45 self.expect( 46 "thread backtrace", matching=False, patterns=["frame.*std::__.*::__function"] 47 ) 48 # Unfiltered. 49 self.expect( 50 "thread backtrace -u", 51 ordered=True, 52 patterns=["frame.*foo", "frame.*std::__[^:]*::__function", "frame.*main"], 53 ) 54 self.expect( 55 "thread backtrace --unfiltered", 56 ordered=True, 57 patterns=["frame.*foo", "frame.*std::__[^:]*::__function", "frame.*main"], 58 ) 59 60 @add_test_categories(["libc++"]) 61 def test_up_down(self): 62 """Test that std::function implementation details are skipped""" 63 self.build() 64 (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( 65 self, "// break here", lldb.SBFileSpec("main.cpp") 66 ) 67 frame = thread.GetSelectedFrame() 68 # up 69 self.assertIn("foo", frame.GetFunctionName()) 70 start_idx = frame.GetFrameID() 71 i = 0 72 while i < thread.GetNumFrames(): 73 self.expect("up") 74 frame = thread.GetSelectedFrame() 75 if frame.GetFunctionName() == "main": 76 break 77 end_idx = frame.GetFrameID() 78 self.assertLess(i, end_idx - start_idx, "skipped frames") 79 80 # Back down again. 81 start_idx = frame.GetFrameID() 82 for i in range(1, thread.GetNumFrames()): 83 self.expect("down") 84 frame = thread.GetSelectedFrame() 85 if "foo" in frame.GetFunctionName(): 86 break 87 end_idx = frame.GetFrameID() 88 self.assertLess(i, start_idx - end_idx, "skipped frames") 89 90 @add_test_categories(["libc++"]) 91 def test_api(self): 92 """Test that std::function implementation details are skipped""" 93 self.build() 94 (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( 95 self, "// break here", lldb.SBFileSpec("main.cpp") 96 ) 97 frame = thread.GetSelectedFrame() 98 num_hidden = 0 99 for i in range(1, thread.GetNumFrames()): 100 thread.SetSelectedFrame(i) 101 frame = thread.GetSelectedFrame() 102 if frame.IsHidden(): 103 num_hidden += 1 104 105 self.assertGreater(num_hidden, 0) 106 self.assertLess(num_hidden, thread.GetNumFrames()) 107