138 lines · python
1import lldb2 3 4class StepWithChild:5 def __init__(self, thread_plan):6 self.thread_plan = thread_plan7 self.child_thread_plan = self.queue_child_thread_plan()8 9 def explains_stop(self, event):10 return False11 12 def should_stop(self, event):13 if not self.child_thread_plan.IsPlanComplete():14 return False15 16 self.thread_plan.SetPlanComplete(True)17 18 return True19 20 def should_step(self):21 return False22 23 def stop_description(self, stream):24 if self.child_thread_plan.IsPlanComplete():25 return self.child_thread_plan.GetDescription(stream)26 return True27 28 def queue_child_thread_plan(self):29 return None30 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 48class StepSingleInstruction(StepWithChild):49 def __init__(self, thread_plan, dict):50 super().__init__(thread_plan)51 52 def queue_child_thread_plan(self):53 return self.thread_plan.QueueThreadPlanForStepSingleInstruction(54 False, lldb.SBError()55 )56 57 58class StepSingleInstructionWithStepOver(StepWithChild):59 def __init__(self, thread_plan, dict):60 super().__init__(thread_plan)61 62 def queue_child_thread_plan(self):63 return self.thread_plan.QueueThreadPlanForStepSingleInstruction(64 True, lldb.SBError()65 )66 67 68# This plan does a step-over until a variable changes value.69class StepUntil(StepWithChild):70 def __init__(self, thread_plan, args_data):71 self.thread_plan = thread_plan72 self.frame = thread_plan.GetThread().frames[0]73 self.target = thread_plan.GetThread().GetProcess().GetTarget()74 var_entry = args_data.GetValueForKey("variable_name")75 76 if not var_entry.IsValid():77 print("Did not get a valid entry for variable_name")78 self.var_name = var_entry.GetStringValue(100)79 80 self.value = self.frame.FindVariable(self.var_name)81 if self.value.GetError().Fail():82 print("Failed to get foo value: %s" % (self.value.GetError().GetCString()))83 84 StepWithChild.__init__(self, thread_plan)85 86 def queue_child_thread_plan(self):87 le = self.frame.GetLineEntry()88 start_addr = le.GetStartAddress()89 start = start_addr.GetLoadAddress(self.target)90 end = le.GetEndAddress().GetLoadAddress(self.target)91 return self.thread_plan.QueueThreadPlanForStepOverRange(start_addr, end - start)92 93 def should_stop(self, event):94 if not self.child_thread_plan.IsPlanComplete():95 return False96 97 # If we've stepped out of this frame, stop.98 if not self.frame.IsValid():99 self.thread_plan.SetPlanComplete(True)100 return True101 102 if not self.value.IsValid():103 self.thread_plan.SetPlanComplete(True)104 return True105 106 if not self.value.GetValueDidChange():107 self.child_thread_plan = self.queue_child_thread_plan()108 return False109 else:110 self.thread_plan.SetPlanComplete(True)111 return True112 113 def stop_description(self, stream):114 stream.Print(f"Stepped until {self.var_name} changed.")115 116 117# This plan does nothing, but sets stop_mode to the118# value of GetStopOthers for this plan.119class StepReportsStopOthers:120 stop_mode_dict = {}121 122 def __init__(self, thread_plan, args_data):123 self.thread_plan = thread_plan124 self.key = str(args_data.GetValueForKey("token").GetUnsignedIntegerValue(1000))125 126 def should_stop(self, event):127 self.thread_plan.SetPlanComplete(True)128 StepReportsStopOthers.stop_mode_dict[129 self.key130 ] = self.thread_plan.GetStopOthers()131 return True132 133 def should_step(self):134 return True135 136 def explains_stop(self, event):137 return True138