TestThreadPlanCommands.py
7.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
"""
Test that thread plan listing, and deleting works.
"""
import lldb
from lldbsuite.test.decorators import *
import lldbsuite.test.lldbutil as lldbutil
from lldbsuite.test.lldbtest import *
class TestThreadPlanCommands(TestBase):
mydir = TestBase.compute_mydir(__file__)
NO_DEBUG_INFO_TESTCASE = True
@skipIfWindows
def test_thread_plan_actions(self):
self.build()
self.main_source_file = lldb.SBFileSpec("main.c")
self.thread_plan_test()
def check_list_output(self, command, active_plans = [], completed_plans = [], discarded_plans = []):
# Check the "thread plan list" output against a list of active & completed and discarded plans.
# If all three check arrays are empty, that means the command is expected to fail.
interp = self.dbg.GetCommandInterpreter()
result = lldb.SBCommandReturnObject()
num_active = len(active_plans)
num_completed = len(completed_plans)
num_discarded = len(discarded_plans)
interp.HandleCommand(command, result)
print("Command: %s"%(command))
print(result.GetOutput())
if num_active == 0 and num_completed == 0 and num_discarded == 0:
self.assertFalse(result.Succeeded(), "command: '%s' succeeded when it should have failed: '%s'"%
(command, result.GetError()))
return
self.assertTrue(result.Succeeded(), "command: '%s' failed: '%s'"%(command, result.GetError()))
result_arr = result.GetOutput().splitlines()
num_results = len(result_arr)
# Now iterate through the results array and pick out the results.
result_idx = 0
self.assertIn("thread #", result_arr[result_idx], "Found thread header") ; result_idx += 1
self.assertIn("Active plan stack", result_arr[result_idx], "Found active header") ; result_idx += 1
self.assertIn("Element 0: Base thread plan", result_arr[result_idx], "Found base plan") ; result_idx += 1
for text in active_plans:
self.assertIn(text, result_arr[result_idx], "Didn't find active plan: %s"%(text)) ; result_idx += 1
if len(completed_plans) > 0:
# First consume any remaining active plans:
while not "Completed plan stack:" in result_arr[result_idx]:
result_idx += 1
if result_idx == num_results:
self.fail("There should have been completed plans, but I never saw the completed stack header")
# We are at the Completed header, skip it:
result_idx += 1
for text in completed_plans:
self.assertIn(text, result_arr[result_idx], "Didn't find completed plan: %s"%(text)) ; result_idx += 1
if len(discarded_plans) > 0:
# First consume any remaining completed plans:
while not "Discarded plan stack:" in result_arr[result_idx]:
result_idx += 1
if result_idx == num_results:
self.fail("There should have been discarded plans, but I never saw the discarded stack header")
# We are at the Discarded header, skip it:
result_idx += 1
for text in discarded_plans:
self.assertIn(text, result_arr[result_idx], "Didn't find discarded plan: %s"%(text)) ; result_idx += 1
def thread_plan_test(self):
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self,
"Set a breakpoint here", self.main_source_file)
# We need to have an internal plan so we can test listing one.
# The most consistent way to do that is to use a scripted thread plan
# that uses a sub-plan. Source that in now.
source_path = os.path.join(self.getSourceDir(), "wrap_step_over.py")
self.runCmd("command script import '%s'"%(source_path))
# Now set a breakpoint that we will hit by running our scripted step.
call_me_bkpt = target.BreakpointCreateBySourceRegex("Set another here", self.main_source_file)
self.assertTrue(call_me_bkpt.GetNumLocations() > 0, "Set the breakpoint successfully")
thread.StepUsingScriptedThreadPlan("wrap_step_over.WrapStepOver")
threads = lldbutil.get_threads_stopped_at_breakpoint(process, call_me_bkpt)
self.assertEqual(len(threads), 1, "Hit my breakpoint while stepping over")
current_id = threads[0].GetIndexID()
current_tid = threads[0].GetThreadID()
# Run thread plan list without the -i flag:
command = "thread plan list %d"%(current_id)
self.check_list_output (command, ["wrap_step_over.WrapStepOver"], [])
# Run thread plan list with the -i flag:
command = "thread plan list -i %d"%(current_id)
self.check_list_output(command, ["WrapStepOver", "Stepping over line main.c"])
# Run thread plan list providing TID, output should be the same:
command = "thread plan list -t %d"%(current_tid)
self.check_list_output(command, ["wrap_step_over.WrapStepOver"])
# Provide both index & tid, and make sure we only print once:
command = "thread plan list -t %d %d"%(current_tid, current_id)
self.check_list_output(command, ["wrap_step_over.WrapStepOver"])
# Try a fake TID, and make sure that fails:
fake_tid = 0
for i in range(100, 10000, 100):
fake_tid = current_tid + i
thread = process.GetThreadByID(fake_tid)
if not thread:
break
command = "thread plan list -t %d"%(fake_tid)
self.check_list_output(command)
# Now continue, and make sure we printed the completed plan:
process.Continue()
threads = lldbutil.get_stopped_threads(process, lldb.eStopReasonPlanComplete)
self.assertEqual(len(threads), 1, "One thread completed a step")
# Run thread plan list - there aren't any private plans at this point:
command = "thread plan list %d"%(current_id)
self.check_list_output(command, [], ["wrap_step_over.WrapStepOver"])
# Set another breakpoint that we can run to, to try deleting thread plans.
second_step_bkpt = target.BreakpointCreateBySourceRegex("Run here to step over again",
self.main_source_file)
self.assertTrue(second_step_bkpt.GetNumLocations() > 0, "Set the breakpoint successfully")
final_bkpt = target.BreakpointCreateBySourceRegex("Make sure we get here on last continue",
self.main_source_file)
self.assertTrue(final_bkpt.GetNumLocations() > 0, "Set the breakpoint successfully")
threads = lldbutil.continue_to_breakpoint(process, second_step_bkpt)
self.assertEqual(len(threads), 1, "Hit the second step breakpoint")
threads[0].StepOver()
threads = lldbutil.get_threads_stopped_at_breakpoint(process, call_me_bkpt)
result = lldb.SBCommandReturnObject()
interp = self.dbg.GetCommandInterpreter()
interp.HandleCommand("thread plan discard 1", result)
self.assertTrue(result.Succeeded(), "Deleted the step over plan: %s"%(result.GetOutput()))
# Make sure the plan gets listed in the discarded plans:
command = "thread plan list %d"%(current_id)
self.check_list_output(command, [], [], ["Stepping over line main.c:"])
process.Continue()
threads = lldbutil.get_threads_stopped_at_breakpoint(process, final_bkpt)
self.assertEqual(len(threads), 1, "Ran to final breakpoint")
threads = lldbutil.get_stopped_threads(process, lldb.eStopReasonPlanComplete)
self.assertEqual(len(threads), 0, "Did NOT complete the step over plan")