def attach(self, pid): self.running = True self.pid = pid self.task = debug.task_for_pid(self.pid) self.is64 = debug.is_64_bit(self.pid) debug.ptrace_attach(pid) status = os.waitpid(self.pid, 0)[1] self.running = False
def start(self, args): assert self.pid is None, "already tracing a program." self.running = True self.pid = os.fork() if self.pid: status = os.waitpid(self.pid, 0)[1] self.task = debug.task_for_pid(self.pid) self.is64 = debug.is_64_bit(self.pid) self.running = False else: debug.ptrace_trace_me() os.execv(args[0], args)
def run(self): pc_register_name = self.general_register_prefix + 'ip' assert not self.running self.threads = debug.task_threads(self.task) status = self.run_and_wait() while os.WIFSTOPPED(status): if os.WSTOPSIG(status) != signal.SIGTRAP: # Send all non-trap signals to the child. status = self.run_and_wait(signal=os.WSTOPSIG(status)) continue try: state = self.general_register_state except OSError: # This condition occurs when a process performs an exec # call across bit-sizes. Everything is still a bit crazy, # though and maybe it should just crash until I find a # better way to detect "the program just changed". self.is64 = debug.is_64_bit(self.pid) pc_register_name = self.general_register_prefix + 'ip' state = self.general_register_state pc = getattr(state, pc_register_name) if pc - 1 in self.breakpoints: setattr(state, pc_register_name, pc - 1) address = pc - 1 breakpoint = self.breakpoints[address] breakpoint.callback(self) # step past the breakpoint, then reinsert it: debug.thread_set_state(self.threads[0], state) old_value = breakpoint.old_value debug.vm_write_wrapper(self.task, address, old_value) self.run_and_wait(step=True) if breakpoint.remove_once_hit(): del self.breakpoints[address] else: debug.vm_write_wrapper(self.task, address, '\xCC') status = self.run_and_wait()