This test is currently flaky on a local Windows amd64 build. The reason is that it relies on the order of `process.threads` but this order is nondeterministic: If we print lldb's inputs and outputs while running, we can see that the breakpoints are always being set correctly, and always being hit: ```sh runCmd: breakpoint set -f "main.c" -l 2 output: Breakpoint 1: where = a.out`func_inner + 1 at main.c:2:9, address = 0x0000000140001001 runCmd: breakpoint set -f "main.c" -l 7 output: Breakpoint 2: where = a.out`main + 17 at main.c:7:5, address = 0x0000000140001021 runCmd: run output: Process 52328 launched: 'C:\workspace\llvm-project\llvm\build\lldb-test-build.noindex\functionalities\unwind\zeroth_frame\TestZerothFrame.test_dwarf\a.out' (x86_64) Process 52328 stopped * thread #1, stop reason = breakpoint 1.1 frame #0: 0x00007ff68f6b1001 a.out`func_inner at main.c:2:9 1 void func_inner() { -> 2 int a = 1; // Set breakpoint 1 here ^ 3 } 4 5 int main() { 6 func_inner(); 7 return 0; // Set breakpoint 2 here ``` However, sometimes the backtrace printed in this test shows that the process is stopped inside NtWaitForWorkViaWorkerFactory from `ntdll.dll`: ```sh Backtrace at the first breakpoint: frame #0: 0x00007ffecc7b3bf4 ntdll.dll`NtWaitForWorkViaWorkerFactory + 20 frame #1: 0x00007ffecc74585e ntdll.dll`RtlClearThreadWorkOnBehalfTicket + 862 frame #2: 0x00007ffecc3e257d kernel32.dll`BaseThreadInitThunk + 29 frame #3: 0x00007ffecc76af28 ntdll.dll`RtlUserThreadStart + 40 ``` When this happens, the test fails with an assertion error that the stopped thread's zeroth frame's current line number does not match the expected line number. This is because the test is looking at the wrong thread: `process.threads[0]`. If we print the list of threads each time the test is run, we notice that threads are sometimes in a different order, within `process.threads`: ```sh Thread 0: thread #4: tid = 0x9c38, 0x00007ffecc7b3bf4 ntdll.dll`NtWaitForWorkViaWorkerFactory + 20 Thread 1: thread #2: tid = 0xa950, 0x00007ffecc7b3bf4 ntdll.dll`NtWaitForWorkViaWorkerFactory + 20 Thread 2: thread #1: tid = 0xab18, 0x00007ff64bc81001 a.out`func_inner at main.c:2:9, stop reason = breakpoint 1.1 Thread 3: thread #3: tid = 0xc514, 0x00007ffecc7b3bf4 ntdll.dll`NtWaitForWorkViaWorkerFactory + 20 Thread 0: thread #3: tid = 0x018c, 0x00007ffecc7b3bf4 ntdll.dll`NtWaitForWorkViaWorkerFactory + 20 Thread 1: thread #1: tid = 0x85c8, 0x00007ff7130c1001 a.out`func_inner at main.c:2:9, stop reason = breakpoint 1.1 Thread 2: thread #2: tid = 0xf344, 0x00007ffecc7b3bf4 ntdll.dll`NtWaitForWorkViaWorkerFactory + 20 Thread 3: thread #4: tid = 0x6a50, 0x00007ffecc7b3bf4 ntdll.dll`NtWaitForWorkViaWorkerFactory + 20 ``` Use `self.thread()` to consistently select the correct thread, instead. Co-authored-by: kendal <kendal@thebrowser.company>
89 lines
3.5 KiB
Python
89 lines
3.5 KiB
Python
"""
|
|
Test that line information is recalculated properly for a frame when it moves
|
|
from the middle of the backtrace to a zero index.
|
|
|
|
This is a regression test for a StackFrame bug, where whether frame is zero or
|
|
not depends on an internal field. When LLDB was updating its frame list value
|
|
of the field wasn't copied into existing StackFrame instances, so those
|
|
StackFrame instances, would use an incorrect line entry evaluation logic in
|
|
situations if it was in the middle of the stack frame list (not zeroth), and
|
|
then moved to the top position. The difference in logic is that for zeroth
|
|
frames line entry is returned for program counter, while for other frame
|
|
(except for those that "behave like zeroth") it is for the instruction
|
|
preceding PC, as PC points to the next instruction after function call. When
|
|
the bug is present, when execution stops at the second breakpoint
|
|
SBFrame.GetLineEntry() returns line entry for the previous line, rather than
|
|
the one with a breakpoint. Note that this is specific to
|
|
SBFrame.GetLineEntry(), SBFrame.GetPCAddress().GetLineEntry() would return
|
|
correct entry.
|
|
|
|
This bug doesn't reproduce through an LLDB interpretator, however it happens
|
|
when using API directly, for example in LLDB-MI.
|
|
"""
|
|
|
|
import lldb
|
|
from lldbsuite.test.decorators import *
|
|
from lldbsuite.test.lldbtest import *
|
|
from lldbsuite.test import lldbutil
|
|
|
|
|
|
class ZerothFrame(TestBase):
|
|
def test(self):
|
|
"""
|
|
Test that line information is recalculated properly for a frame when it moves
|
|
from the middle of the backtrace to a zero index.
|
|
"""
|
|
self.build()
|
|
self.setTearDownCleanup()
|
|
|
|
exe = self.getBuildArtifact("a.out")
|
|
target = self.dbg.CreateTarget(exe)
|
|
self.assertTrue(target, VALID_TARGET)
|
|
|
|
main_dot_c = lldb.SBFileSpec("main.c")
|
|
bp1 = target.BreakpointCreateBySourceRegex(
|
|
"// Set breakpoint 1 here", main_dot_c
|
|
)
|
|
bp2 = target.BreakpointCreateBySourceRegex(
|
|
"// Set breakpoint 2 here", main_dot_c
|
|
)
|
|
|
|
process = target.LaunchSimple(None, None, self.get_process_working_directory())
|
|
self.assertTrue(process, VALID_PROCESS)
|
|
|
|
thread = self.thread()
|
|
|
|
if self.TraceOn():
|
|
print("Backtrace at the first breakpoint:")
|
|
for f in thread.frames:
|
|
print(f)
|
|
|
|
# Check that we have stopped at correct breakpoint.
|
|
self.assertEqual(
|
|
thread.frame[0].GetLineEntry().GetLine(),
|
|
bp1.GetLocationAtIndex(0).GetAddress().GetLineEntry().GetLine(),
|
|
"LLDB reported incorrect line number.",
|
|
)
|
|
|
|
# Important to use SBProcess::Continue() instead of
|
|
# self.runCmd('continue'), because the problem doesn't reproduce with
|
|
# 'continue' command.
|
|
process.Continue()
|
|
|
|
if self.TraceOn():
|
|
print("Backtrace at the second breakpoint:")
|
|
for f in thread.frames:
|
|
print(f)
|
|
# Check that we have stopped at the breakpoint
|
|
self.assertEqual(
|
|
thread.frame[0].GetLineEntry().GetLine(),
|
|
bp2.GetLocationAtIndex(0).GetAddress().GetLineEntry().GetLine(),
|
|
"LLDB reported incorrect line number.",
|
|
)
|
|
# Double-check with GetPCAddress()
|
|
self.assertEqual(
|
|
thread.frame[0].GetLineEntry().GetLine(),
|
|
thread.frame[0].GetPCAddress().GetLineEntry().GetLine(),
|
|
"LLDB reported incorrect line number.",
|
|
)
|