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