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
|
import lldb
class StepWithChild:
def __init__(self, thread_plan):
self.thread_plan = thread_plan
self.child_thread_plan = self.queue_child_thread_plan()
def explains_stop(self, event):
return False
def should_stop(self, event):
if not self.child_thread_plan.IsPlanComplete():
return False
self.thread_plan.SetPlanComplete(True)
return True
def should_step(self):
return False
def stop_description(self, stream):
if self.child_thread_plan.IsPlanComplete():
return self.child_thread_plan.GetDescription(stream)
return True
def queue_child_thread_plan(self):
return None
class StepOut(StepWithChild):
def __init__(self, thread_plan, dict):
StepWithChild.__init__(self, thread_plan)
def queue_child_thread_plan(self):
return self.thread_plan.QueueThreadPlanForStepOut(0)
class StepScripted(StepWithChild):
def __init__(self, thread_plan, dict):
StepWithChild.__init__(self, thread_plan)
def queue_child_thread_plan(self):
return self.thread_plan.QueueThreadPlanForStepScripted("Steps.StepOut")
class StepSingleInstruction(StepWithChild):
def __init__(self, thread_plan, dict):
super().__init__(thread_plan)
def queue_child_thread_plan(self):
return self.thread_plan.QueueThreadPlanForStepSingleInstruction(
False, lldb.SBError()
)
class StepSingleInstructionWithStepOver(StepWithChild):
def __init__(self, thread_plan, dict):
super().__init__(thread_plan)
def queue_child_thread_plan(self):
return self.thread_plan.QueueThreadPlanForStepSingleInstruction(
True, lldb.SBError()
)
# This plan does a step-over until a variable changes value.
class StepUntil(StepWithChild):
def __init__(self, thread_plan, args_data):
self.thread_plan = thread_plan
self.frame = thread_plan.GetThread().frames[0]
self.target = thread_plan.GetThread().GetProcess().GetTarget()
var_entry = args_data.GetValueForKey("variable_name")
if not var_entry.IsValid():
print("Did not get a valid entry for variable_name")
self.var_name = var_entry.GetStringValue(100)
self.value = self.frame.FindVariable(self.var_name)
if self.value.GetError().Fail():
print("Failed to get foo value: %s" % (self.value.GetError().GetCString()))
StepWithChild.__init__(self, thread_plan)
def queue_child_thread_plan(self):
le = self.frame.GetLineEntry()
start_addr = le.GetStartAddress()
start = start_addr.GetLoadAddress(self.target)
end = le.GetEndAddress().GetLoadAddress(self.target)
return self.thread_plan.QueueThreadPlanForStepOverRange(start_addr, end - start)
def should_stop(self, event):
if not self.child_thread_plan.IsPlanComplete():
return False
# If we've stepped out of this frame, stop.
if not self.frame.IsValid():
self.thread_plan.SetPlanComplete(True)
return True
if not self.value.IsValid():
self.thread_plan.SetPlanComplete(True)
return True
if not self.value.GetValueDidChange():
self.child_thread_plan = self.queue_child_thread_plan()
return False
else:
self.thread_plan.SetPlanComplete(True)
return True
def stop_description(self, stream):
stream.Print(f"Stepped until {self.var_name} changed.")
# This plan does nothing, but sets stop_mode to the
# value of GetStopOthers for this plan.
class StepReportsStopOthers:
stop_mode_dict = {}
def __init__(self, thread_plan, args_data):
self.thread_plan = thread_plan
self.key = str(args_data.GetValueForKey("token").GetUnsignedIntegerValue(1000))
def should_stop(self, event):
self.thread_plan.SetPlanComplete(True)
StepReportsStopOthers.stop_mode_dict[
self.key
] = self.thread_plan.GetStopOthers()
return True
def should_step(self):
return True
def explains_stop(self, event):
return True
|