1""" 2Test that line information is recalculated properly for a frame when it moves 3from the middle of the backtrace to a zero index. 4 5This is a regression test for a StackFrame bug, where whether frame is zero or 6not depends on an internal field. When LLDB was updating its frame list value 7of the field wasn't copied into existing StackFrame instances, so those 8StackFrame instances, would use an incorrect line entry evaluation logic in 9situations if it was in the middle of the stack frame list (not zeroth), and 10then moved to the top position. The difference in logic is that for zeroth 11frames line entry is returned for program counter, while for other frame 12(except for those that "behave like zeroth") it is for the instruction 13preceding PC, as PC points to the next instruction after function call. When 14the bug is present, when execution stops at the second breakpoint 15SBFrame.GetLineEntry() returns line entry for the previous line, rather than 16the one with a breakpoint. Note that this is specific to 17SBFrame.GetLineEntry(), SBFrame.GetPCAddress().GetLineEntry() would return 18correct entry. 19 20This bug doesn't reproduce through an LLDB interpretator, however it happens 21when using API directly, for example in LLDB-MI. 22""" 23 24from __future__ import print_function 25 26 27import lldb 28from lldbsuite.test.decorators import * 29from lldbsuite.test.lldbtest import * 30from lldbsuite.test import lldbutil 31 32 33class ZerothFrame(TestBase): 34 mydir = TestBase.compute_mydir(__file__) 35 36 def test(self): 37 """ 38 Test that line information is recalculated properly for a frame when it moves 39 from the middle of the backtrace to a zero index. 40 """ 41 self.build() 42 self.setTearDownCleanup() 43 44 exe = self.getBuildArtifact("a.out") 45 target = self.dbg.CreateTarget(exe) 46 self.assertTrue(target, VALID_TARGET) 47 48 bp1_line = line_number('main.c', '// Set breakpoint 1 here') 49 bp2_line = line_number('main.c', '// Set breakpoint 2 here') 50 51 lldbutil.run_break_set_by_file_and_line( 52 self, 53 'main.c', 54 bp1_line, 55 num_expected_locations=1) 56 lldbutil.run_break_set_by_file_and_line( 57 self, 58 'main.c', 59 bp2_line, 60 num_expected_locations=1) 61 62 process = target.LaunchSimple( 63 None, None, self.get_process_working_directory()) 64 self.assertTrue(process, VALID_PROCESS) 65 66 thread = process.GetThreadAtIndex(0) 67 if self.TraceOn(): 68 print("Backtrace at the first breakpoint:") 69 for f in thread.frames: 70 print(f) 71 # Check that we have stopped at correct breakpoint. 72 self.assertEqual( 73 process.GetThreadAtIndex(0).frame[0].GetLineEntry().GetLine(), 74 bp1_line, 75 "LLDB reported incorrect line number.") 76 77 # Important to use SBProcess::Continue() instead of 78 # self.runCmd('continue'), because the problem doesn't reproduce with 79 # 'continue' command. 80 process.Continue() 81 82 thread = process.GetThreadAtIndex(0) 83 if self.TraceOn(): 84 print("Backtrace at the second breakpoint:") 85 for f in thread.frames: 86 print(f) 87 # Check that we have stopped at the breakpoint 88 self.assertEqual( 89 thread.frame[0].GetLineEntry().GetLine(), 90 bp2_line, 91 "LLDB reported incorrect line number.") 92 # Double-check with GetPCAddress() 93 self.assertEqual( 94 thread.frame[0].GetLineEntry().GetLine(), 95 thread.frame[0].GetPCAddress().GetLineEntry().GetLine(), 96 "LLDB reported incorrect line number.") 97