def redo(self, dryrun): dbg.syscall("%d: %s" % (self.ob.ticket, self.ob)) if not dryrun: if self.ob.ret != -1: p = self.ob.args["path"].path dbg.syscall("unlinking fd:%s" % p) os.unlink(p)
def redo(self, dryrun): cur_pn = kutil.iget("/mnt/retro/trunk", self.ob.ret.inode.ino) if not dryrun: if self.ob.args["flags"] & os.O_TRUNC: dbg.syscall("%d: %s" % (self.ob.ticket, self.ob)) dbg.syscall("creating empty file, %s" % cur_pn) open(cur_pn, "w").close()
def flatten(self): """Set tic[0] to tac[0]. Used for wait4 rescheduling.""" assert self.retnode assert len(self.retnode.readers) == 1 procSysRet = list(self.retnode.readers)[0] newtic = procSysRet.tic newtac = procSysRet.tac dbg.syscall('setting tic,tac %s %s -> %s %s' % (self.tic, self.tac, newtic, newtac)) self.tic, self.tac = newtic, newtac
def redo(self, dryrun): cur_pn = kutil.iget("/mnt/retro/trunk", self.ob.args["fd"].inode.ino) dbg.syscall("%d: %s" % (self.ob.ticket, self.ob)) dbg.syscall("re-writing to fd:%s" % cur_pn) if not dryrun: offset = self.ob.args["fd"].offset f = open(cur_pn, "r+") # append if offset == -1: f.seek(0, os.SEEK_END) else: f.seek(offset) f.write(self.ob.args["buf"]) f.close()
def redo(self): if self.argsnode.data is None: dbg.syscall("no argsnode data for %s, returning prematurely" % self) return if (hasattr(self.argsnode, "rerun") and self.argsnode.rerun.is_active()): rerun = self.argsnode.rerun pid = self.argsnode.data.pid expanding = not hasattr( self, 'parent_retnode') or not self.parent_retnode if expanding: child_pid = None else: child_pid = self.parent_retnode.origdata.ret (r, p) = rerun.clone(pid, child_pid) r.sid = self.argsnode.data.sid # TODO(ipopov): refactor into __fix_sid() if expanding: # This creates parent_retnode and child_retnode self.osloader.parse_record(r) else: self.child_retnode.data = deepcopy(self.child_retnode.origdata) self.parent_retnode.data = deepcopy( self.parent_retnode.origdata) # TODO(ipopov): should we change the retvalue here? (probably # not) # find child actor and setup for rerun r = self.parent_retnode.data child = ProcessActor.get(r.ret, r) child.rerun = rerun rerun.add(child) else: # This should not happen. dbg.error('no redo performed for clonesyscall action!')
def redo(self): dbg.syscall("redoing ProcSysRet") if not self.actor.rerun and getattr(self.retnode, 'rerun', None): self.actor.rerun = self.retnode.rerun if self.retnode.data is None: # This probably means that the retnode has been rolled back to # its (-Inf, -Inf, None) checkpoint and has not been updated # (rolled forward), probably because the syscall that was to # fill it never got executed. dbg.syscall("no argsnode data for %s, returning prematurely" % self) return # start shepherded re-execution if self.retnode.data.name == "execve" and not self.actor.rerun: dbg.rerun('actor %s (%s) has no rerun object' % (self.actor, id(self.actor))) # create rerun process (arg, ret) = self.actor.get_execve() if hasattr(self, "uids"): rerun = Rerun(arg, ret, self.uids) else: rerun = Rerun(arg, ret) rerun.execve(self.actor.pid) # process actor has a reference to the rerun module self.actor.rerun = rerun rerun.add(self.actor) return if self.actor.rerun and self.actor.rerun.is_expanding(): pid = self.retnode.data.pid (r, p) = self.actor.rerun.next(True, pid) if r == None: return assert r.usage & ENTER # pass rerun object to the bumped process if r.pid != self.retnode.data.pid: assert r.pid == pid actor = ProcessActor.get(r.pid, r) actor.rerun = self.actor.rerun actor.rerun.add(actor) # create pcall action self.osloader.parse_record(r) return # It's not undesirable that we fall through to here. ProcSysRets should # only be reexecuted if there is some information to be handed back to the # process (which there never should be, because in such a circumstance, the # rerun module would already be active, and receiving "sysret nodes" # directly from the kernel, as it were). dbg.syscall('ignoring Procsysret redo request')
def redo(self, dryrun): dbg.syscall("re-executing %s", self.ob) if not dryrun: print self.ob.ret [ret, root, pwd, fds] = self.ob.ret pass
def redo(self): dbg.syscall("redoing") if self.argsnode.data is None: dbg.syscall("no argsnode data for %s, returning prematurely" % self) return # share expanding & following if (hasattr(self.argsnode, "rerun") and self.argsnode.rerun.is_active()): rerun = self.argsnode.rerun pid = self.argsnode.data.pid # wait syscalls: make it non-blocking if self.argsnode.data.name == "wait4": result = rerun.wait4(pid) if not result: self.flatten() raise mgrapi.ReschedulePendingException else: (r, p) = result elif self.argsnode.data.name == "exit_group": (r, p) = rerun.exit_group(pid) # from Taesoo: # while expanding (after canceling all nodes), you should # create new node (pcall) to dynamically create new nodes of # parents # # The current process is exiting. But, perhaps its reexecution # has spawned new children that must persist. if rerun.is_expanding() and len(rerun.pids) >= 1: for childpid in rerun.pids: dbg.info("reviewing: %s" % childpid) (childr, childp) = rerun.next(True, childpid) assert childr.usage & ENTER self.osloader.parse_record(childr) return else: (r, p) = rerun.next(False, pid) r.sid = self.argsnode.data.sid # Is this actually true?: # Vestigial, from Taesoo: r is None with exit_group()-like # syscalls assert not r or (r and r.usage & EXIT) if r: # self.retnode exists iff the exit record has already been # parsed for the syscall in question, i.e. iff this syscall # has already been carried out, i.e. iff we are retracing it. if self.retnode: # following self.retnode.data = deepcopy(self.retnode.origdata) self.retnode.data.ret = r.ret else: # exploring new nodes/edges self.osloader.parse_record(r) self.retnode.rerun = rerun return else: r = self.argsnode.data func = getattr(self, "syscall_%s" % r.name, None) if func: # exit_group() has no retnode if self.retnode: self.retnode.data = func(self.argsnode, self.retnode) return # raise Exception('not impl') dbg.error("Not implemented:", r.name)
def redo(self): """Execute another action of this action's actor. If the greedy heuristic matches the current action to the action just executed, we're fine. Otherwise, call parse_record() to create a new node in the action history graph. """ dbg.syscall("redoing") rerun = self.actor.rerun if not rerun: dbg.syscall("no rerun instance bound to ProcSyscall %s;" "returning prematurely" % self) return # following history while rerunning if rerun.is_following(): (r, p) = rerun.next(True, self.actor.pid) if r == None: dbg.syscall('Aborting syscall; rerun returned no record') return assert r.usage & ENTER # special treatment of wait4 # (see note in wait4.doc) # The following if statement seems pretty impenetrable. What I think it # does is the following. If a process under rerun tries to execute a # wait4, but that doesn't match up with the expected syscall from the # previous execution, call code.interact() and handle it manually. if (r.nr == syscall.NR_wait4 and self.argsnode.origdata.nr != syscall.NR_wait4): dbg.rerun('entering interactive') code.interact(local=locals()) # wait4() again, at this time we should be able # to fetch child exit status (r, p) = rerun.next(False, self.actor.pid) assert r.usage & ENTER and r.nr == syscall.NR_wait4 # this is a real system call we should execute # on this action node (r, p) = rerun.next(True, self.actor.pid) assert r.usage & ENTER # match up if (self.argsnode.origdata.nr == r.nr and check_args(r, self.argsnode.origdata)): # update arguments self.argsnode.data = deepcopy(self.argsnode.origdata) self.argsnode.data.args = r.args self.argsnode.rerun = rerun # failed: need to explore/create new nodes/edges else: dbg.infom( "!", "#R<mismatched#> syscalls: %s vs %s" % (self.argsnode.origdata, r)) assert self.argsnode.data == None ts = 0 for a in rerun.actors: t = max(a.actions) if ts < t.tac: ts = t.tac rerun.detach(r, ts) # Actually create a new node to correspond to what was just # executed. self.osloader.parse_record(r) # rerunning but creating new nodes/edges elif rerun.is_state("detached"): # if detached node if rerun.wait_r == self.argsnode.origdata: rerun.resume() #rerun.activate() # ipopov: ???? if rerun.is_expanding(): self.argsnode.data = self.argsnode.origdata self.argsnode.rerun = rerun
def parse_record(self, r): argsnode = None retnode = None retnode_child = None retnode_parent = None is_clone = r.nr in [NR_clone, NR_fork, NR_vfork] # enter if r.usage & ENTER: actor_call = procmgr.ProcessActor.get(r.pid, r) argsname = actor_call.name + ('sysarg', r.sid) if mgrapi.RegisteredObject.by_name(argsname) is None: argsnode = mgrutil.BufferNode(argsname, r.ts + (2, ), r) pc = procmgr.ProcSysCall(actor_call, argsnode, self) pc.tic = r.ts + (0 + r.pid.gen, ) pc.tac = r.ts + (1 + r.pid.gen, ) pc.connect() # exit if r.usage & EXIT: if not is_clone: actor_ret = procmgr.ProcessActor.get(r.pid, r) retname = actor_ret.name + ('sysret', r.sid) if mgrapi.RegisteredObject.by_name(retname) is None: retnode = mgrutil.BufferNode(retname, r.ts + (1, ), r) pr = procmgr.ProcSysRet(actor_ret, retnode, self) pr.tic = r.ts + (2 + r.pid.gen, ) pr.tac = r.ts + (3 + r.pid.gen, ) if r.nr == NR_execve: assert hasattr(r, "uids") setattr(pr, "uids", r.uids) pr.connect() else: actor_child = procmgr.ProcessActor.get(r.ret, r) actor_parent = procmgr.ProcessActor.get(r.pid, r) retname_parent = actor_parent.name + ('sysret', r.sid) retname_child = actor_child.name + ('sysret', r.sid) dbg.syscall('parentnode %s' % mgrapi.RegisteredObject.by_name(retname_parent)) if mgrapi.RegisteredObject.by_name(retname_parent) is None: retnode_parent = mgrutil.BufferNode( retname_parent, r.ts + (1, ), r) pr = procmgr.ProcSysRet(actor_parent, retnode_parent, self) pr.tic = r.ts + (4 + r.pid.gen, ) pr.tac = r.ts + (5 + r.pid.gen, ) pr.connect() dbg.syscall('childnode %s' % mgrapi.RegisteredObject.by_name(retname_child)) if mgrapi.RegisteredObject.by_name(retname_child) is None: retnode_child = mgrutil.BufferNode(retname_child, r.ts + (1, ), r) pr = procmgr.ProcSysRet(actor_child, retnode_child, self) pr.tic = r.ts + (2 + r.pid.gen, ) pr.tac = r.ts + (3 + r.pid.gen, ) pr.connect() if is_clone: sc = procmgr.CloneSyscallAction.get(r, self) dbg.syscall( 'populating sc %s with parent_retnode %s and child_retnode %s' % (sc, retnode_parent, retnode_child)) if retnode_parent: sc.parent_retnode = retnode_parent if retnode_child: sc.child_retnode = retnode_child else: sc = procmgr.SyscallAction.get(r, self) if retnode: sc.retnode = retnode if argsnode: sc.argsnode = argsnode if r.usage & ENTER: sc.tic = r.ts + (3, ) if r.usage & EXIT: sc.tac = r.ts + (0, ) ## Some system calls do not have return records ## (or return value objects, but that's OK for now.) if r.nr in [NR_exit, NR_exit_group]: sc.tac = r.ts + (4, ) sc.connect() return sc