aboutsummaryrefslogtreecommitdiff
path: root/lldb/test/API/functionalities/step_scripted/Steps.py
blob: e2a03c9988111303b1710959d3f650e22c16a620 (plain)
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