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 "bt -u", 51 ordered=True, 52 patterns=["frame.*foo", "frame.*std::__[^:]*::__function", "frame.*main"], 53 ) 54 self.expect( 55 "thread backtrace -u", 56 ordered=True, 57 patterns=["frame.*foo", "frame.*std::__[^:]*::__function", "frame.*main"], 58 ) 59 self.expect( 60 "thread backtrace --unfiltered", 61 ordered=True, 62 patterns=["frame.*foo", "frame.*std::__[^:]*::__function", "frame.*main"], 63 ) 64 65 @add_test_categories(["libc++"]) 66 def test_up_down(self): 67 """Test that std::function implementation details are skipped""" 68 self.build() 69 (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( 70 self, "// break here", lldb.SBFileSpec("main.cpp") 71 ) 72 frame = thread.selected_frame 73 # up 74 self.assertIn("foo", frame.GetFunctionName()) 75 start_idx = frame.GetFrameID() 76 i = 0 77 while i < thread.GetNumFrames(): 78 self.expect("up") 79 frame = thread.selected_frame 80 if frame.GetFunctionName() == "main": 81 break 82 end_idx = frame.GetFrameID() 83 self.assertLess(i, end_idx - start_idx, "skipped frames") 84 85 # Back down again. 86 start_idx = frame.GetFrameID() 87 for i in range(1, thread.GetNumFrames()): 88 self.expect("down") 89 frame = thread.selected_frame 90 if "foo" in frame.GetFunctionName(): 91 break 92 end_idx = frame.GetFrameID() 93 self.assertLess(i, start_idx - end_idx, "skipped frames") 94 95 @add_test_categories(["libc++"]) 96 def test_api(self): 97 """Test that std::function implementation details are skipped""" 98 self.build() 99 (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( 100 self, "// break here", lldb.SBFileSpec("main.cpp") 101 ) 102 num_hidden = 0 103 for frame in thread.frames: 104 if frame.IsHidden(): 105 num_hidden += 1 106 107 self.assertGreater(num_hidden, 0) 108 self.assertLess(num_hidden, thread.GetNumFrames()) 109