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 24import lldb 25from lldbsuite.test.decorators import * 26from lldbsuite.test.lldbtest import * 27from lldbsuite.test import lldbutil 28 29 30class ZerothFrame(TestBase): 31 def test(self): 32 """ 33 Test that line information is recalculated properly for a frame when it moves 34 from the middle of the backtrace to a zero index. 35 """ 36 self.build() 37 self.setTearDownCleanup() 38 39 exe = self.getBuildArtifact("a.out") 40 target = self.dbg.CreateTarget(exe) 41 self.assertTrue(target, VALID_TARGET) 42 43 main_dot_c = lldb.SBFileSpec("main.c") 44 bp1 = target.BreakpointCreateBySourceRegex( 45 "// Set breakpoint 1 here", main_dot_c 46 ) 47 bp2 = target.BreakpointCreateBySourceRegex( 48 "// Set breakpoint 2 here", main_dot_c 49 ) 50 51 process = target.LaunchSimple(None, None, self.get_process_working_directory()) 52 self.assertTrue(process, VALID_PROCESS) 53 54 thread = self.thread() 55 56 if self.TraceOn(): 57 print("Backtrace at the first breakpoint:") 58 for f in thread.frames: 59 print(f) 60 61 # Check that we have stopped at correct breakpoint. 62 self.assertEqual( 63 thread.frame[0].GetLineEntry().GetLine(), 64 bp1.GetLocationAtIndex(0).GetAddress().GetLineEntry().GetLine(), 65 "LLDB reported incorrect line number.", 66 ) 67 68 # Important to use SBProcess::Continue() instead of 69 # self.runCmd('continue'), because the problem doesn't reproduce with 70 # 'continue' command. 71 process.Continue() 72 73 if self.TraceOn(): 74 print("Backtrace at the second breakpoint:") 75 for f in thread.frames: 76 print(f) 77 # Check that we have stopped at the breakpoint 78 self.assertEqual( 79 thread.frame[0].GetLineEntry().GetLine(), 80 bp2.GetLocationAtIndex(0).GetAddress().GetLineEntry().GetLine(), 81 "LLDB reported incorrect line number.", 82 ) 83 # Double-check with GetPCAddress() 84 self.assertEqual( 85 thread.frame[0].GetLineEntry().GetLine(), 86 thread.frame[0].GetPCAddress().GetLineEntry().GetLine(), 87 "LLDB reported incorrect line number.", 88 ) 89