def signal(self, pid, sig): flags = self.allflags[pid] if sig == 'SIGTRAP': if flags.has_key('exectrappending'): # assume first SIGTRAP following an exec is due to the # exec (FIX: not strictly true?) del flags['exectrappending'] return ('SIG_0',) # XXX: merge these? if flags.has_key('skiptrap'): del flags['skiptrap'] return ('SIG_0',) elif sig == 'SIGCHLD' and flags.has_key('deathnotice'): # FIX: This is somewhat bogus. For starters, don't do this if # parent or child has exec'ed since clone # FIX: this deathnotice queueing is probably bogus, too dpid, dsignal = flags['deathnotice'].pop(0) #if self.allflags.has_key(dpid): # ??? # del self.allflags[dpid] # ??? if not flags['deathnotice']: del flags['deathnotice'] return (signalmap.lookup_name(dsignal),) elif sig == 'SIGSTOP' and flags.has_key('skipstop'): # in 2.4, there's a gratuitous SIGSTOP right after fork/etc del flags['skipstop'] return ('SIG_0',)
def trace_signal(pid, flags, tricklist, sig): if not _signal_weedout_mask[sig]: return sig signalname = signalmap.lookup_name(sig) # innermost trick gets first shot at the signal tricklist = tricklist[:] tricklist.reverse() for trick, callmask, signalmask in tricklist: if (not signalmask or signalmask.has_key(signalname)) and trick.is_enabled(pid): r = trick.signal(pid, signalname) # r is None or (signal, ) if r != None: assert len(r) == 1, "signal must return None or a 1-tuple" signalname = r[0] assert isinstance(signalname, types.StringType) and ( 0 <= signalmap.lookup_number(signalname) < signal.NSIG ), ("bad signal %s; must use signal name" % signalname) if signalname == "SIG_0": break # XXX: perhaps we ought to also ignore signals that the # process is ignoring ?? return signalmap.lookup_number(signalname)
def callafter(self, pid, call, result, state): if call == 'rt_sigaction' or call == 'sigaction' or call == 'signal': if state != None and not (-1024 < result < 0): sig = state[0] f = self.allflags[pid] handler = state[1] if sig == signal.SIGCHLD: sa_flags = ptrace.peekdata(pid, handler + 4) f['SA_NOCLDSTOP'] = sa_flags & 0x1 # SA_NOCLDSTOP else: if call != 'signal': handler = ptrace.peekdata(pid, handler) f[signalmap.lookup_name(sig)] = handler elif call == 'wait4' or call == 'waitpid': f = self.allflags[pid] if f.has_key('waitresult'): wpid, statusptr, status = f['waitresult'] del f['waitresult'] del f['waiting'] if statusptr != 0: try: ptrace.pokedata(pid, statusptr, status) except OSError, e: if e.errno != errno.ESRCH: # FIX assert 0, "wait status pointer bad? (%s)" % e else: print 'waiter dead or not stopped' # XXX return wpid # XXX: is this actually correct and useful? if result == -errno_internal.ERESTARTNOHAND: # like pause return -errno_internal.ERESTARTSYS # like wait
def trace_exit(pid, flags, tricklist, exitstatus, termsig): signalname = None if termsig: signalname = signalmap.lookup_name(termsig) for trick, callmask, signalmask in tricklist: if trick.is_enabled(pid): trick.exit(pid, exitstatus, signalname)
def trace_signal(pid, flags, tricklist, sig): if not _signal_weedout_mask[sig]: return sig signalname = signalmap.lookup_name(sig) # innermost trick gets first shot at the signal tricklist = tricklist[:] tricklist.reverse() for trick, callmask, signalmask in tricklist: if (not signalmask or signalmask.has_key(signalname))\ and trick.is_enabled(pid): r = trick.signal(pid, signalname) # r is None or (signal, ) if r != None: assert len(r) == 1, "signal must return None or a 1-tuple" signalname = r[0] assert (isinstance(signalname, types.StringType) and (0 <= signalmap.lookup_number(signalname) < signal.NSIG)), \ "bad signal %s; must use signal name" % signalname if signalname == 'SIG_0': break # XXX: perhaps we ought to also ignore signals that the # process is ignoring ?? return signalmap.lookup_number(signalname)
def handle_sf_signal(signo, frame, tricks): """Send a signal received by sf itself to the interested tricks.""" # discard frame -- it's not part of the interface because this may be # reimplemented in another language signal = signalmap.lookup_name(signo) for trick in tricks: assert not trick.tricksignalmask \ or trick.tricksignalmask().has_key(signal) trick.tricksignal(signal)
if waitchannelhack: callstop = _subterfugue.atcallstop(wpid, stopsig) else: callstop = stopsig == signal.SIGTRAP | 0x80 if not callstop: sig = trace_signal(wpid, flags, tricklist, stopsig) if (sig == signal.SIGSTOP or sig == signal.SIGTSTP or sig == signal.SIGTTIN or sig == signal.SIGTTOU): # FIX: more needed for ~SIGSTOP case # ~SIGSTOP: if handler, pass like any other signal # ~SIGSTOP: if IGN or DEF & orphaned pgrp, ignore # all: stop # all: if parent's SIGCHLD has !SA_NOCLDSTOP, notify if sig != signal.SIGSTOP: signame = signalmap.lookup_name(sig) handler = flags.get(signame, signal.SIG_DFL) if handler == signal.SIG_DFL: pass # FIX: handle orphaned pgrp elif handler == signal.SIG_IGN: ptrace.syscall(wpid, 0) continue else: # XXX: it would seem that we could get a duplicate # signal here, since the kernel will report this # twice (?), but this doesn't seem to be happening # (maybe because the signals merge?) ptrace.syscall(wpid, sig) continue if flags.has_key('status'):