xref: /llvm-project/lldb/test/API/functionalities/step_scripted/Steps.py (revision 37fe152e0c9f47b0a9ef9663df1ddecffef6f338)
1import lldb
2
3
4class StepWithChild:
5    def __init__(self, thread_plan):
6        self.thread_plan = thread_plan
7        self.child_thread_plan = self.queue_child_thread_plan()
8
9    def explains_stop(self, event):
10        return False
11
12    def should_stop(self, event):
13        if not self.child_thread_plan.IsPlanComplete():
14            return False
15
16        self.thread_plan.SetPlanComplete(True)
17
18        return True
19
20    def should_step(self):
21        return False
22
23    def stop_description(self, stream):
24        if self.child_thread_plan.IsPlanComplete():
25            return self.child_thread_plan.GetDescription(stream)
26        return True
27
28    def queue_child_thread_plan(self):
29        return None
30
31
32class StepOut(StepWithChild):
33    def __init__(self, thread_plan, dict):
34        StepWithChild.__init__(self, thread_plan)
35
36    def queue_child_thread_plan(self):
37        return self.thread_plan.QueueThreadPlanForStepOut(0)
38
39
40class StepScripted(StepWithChild):
41    def __init__(self, thread_plan, dict):
42        StepWithChild.__init__(self, thread_plan)
43
44    def queue_child_thread_plan(self):
45        return self.thread_plan.QueueThreadPlanForStepScripted("Steps.StepOut")
46
47
48# This plan does a step-over until a variable changes value.
49class StepUntil(StepWithChild):
50    def __init__(self, thread_plan, args_data):
51        self.thread_plan = thread_plan
52        self.frame = thread_plan.GetThread().frames[0]
53        self.target = thread_plan.GetThread().GetProcess().GetTarget()
54        var_entry = args_data.GetValueForKey("variable_name")
55
56        if not var_entry.IsValid():
57            print("Did not get a valid entry for variable_name")
58        self.var_name = var_entry.GetStringValue(100)
59
60        self.value = self.frame.FindVariable(self.var_name)
61        if self.value.GetError().Fail():
62            print("Failed to get foo value: %s" % (self.value.GetError().GetCString()))
63
64        StepWithChild.__init__(self, thread_plan)
65
66    def queue_child_thread_plan(self):
67        le = self.frame.GetLineEntry()
68        start_addr = le.GetStartAddress()
69        start = start_addr.GetLoadAddress(self.target)
70        end = le.GetEndAddress().GetLoadAddress(self.target)
71        return self.thread_plan.QueueThreadPlanForStepOverRange(start_addr, end - start)
72
73    def should_stop(self, event):
74        if not self.child_thread_plan.IsPlanComplete():
75            return False
76
77        # If we've stepped out of this frame, stop.
78        if not self.frame.IsValid():
79            self.thread_plan.SetPlanComplete(True)
80            return True
81
82        if not self.value.IsValid():
83            self.thread_plan.SetPlanComplete(True)
84            return True
85
86        if not self.value.GetValueDidChange():
87            self.child_thread_plan = self.queue_child_thread_plan()
88            return False
89        else:
90            self.thread_plan.SetPlanComplete(True)
91            return True
92
93    def stop_description(self, stream):
94        stream.Print(f"Stepped until {self.var_name} changed.")
95
96
97# This plan does nothing, but sets stop_mode to the
98# value of GetStopOthers for this plan.
99class StepReportsStopOthers:
100    stop_mode_dict = {}
101
102    def __init__(self, thread_plan, args_data):
103        self.thread_plan = thread_plan
104        self.key = str(args_data.GetValueForKey("token").GetUnsignedIntegerValue(1000))
105
106    def should_stop(self, event):
107        self.thread_plan.SetPlanComplete(True)
108        StepReportsStopOthers.stop_mode_dict[
109            self.key
110        ] = self.thread_plan.GetStopOthers()
111        return True
112
113    def should_step(self):
114        return True
115
116    def explains_stop(self, event):
117        return True
118