Make strace correctly handle SIGTRAP produced by e.g.

Roland McGrath roland at redhat.com
Tue Nov 3 21:03:13 UTC 2009


> +	int sigtrap80;		/* What sig we consider to be ptrace stop */

This is a lousy name for the member.  "syscall_stopsig" or something fits.
But I'm not really sure it is worthwhile to have per-tcb state for this at
all.  If the ptrace features work they work on this kernel, period, that
never varies across different tasks.  You can determine once what the
ptrace feature support is, set every tracee the same way, and expect that
behavior.

> +#ifdef LINUX /* add more OSes after you verified it works for them */
> +			/*
> +			 * Ask kernel to set signo to SIGTRAP | 0x80
> +			 * on ptrace-generated SIGTRAPs, and mark
> +			 * execve's SIGTRAP with PTRACE_EVENT_EXEC.
> +			 */
> +			if (tcp->sigtrap80 == SIGTRAP
> +			 && ptrace(PTRACE_SETOPTIONS, pid, (char *) 0,
> +					(void *) (PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXEC)) == 0) {
> +				tcp->sigtrap80 = SIGTRAP | 0x80;
> +			}
> +#endif

There are a few kinds of older kernels you need to account for here.

Some kernels have no PTRACE_SETOPTIONS at all, so that's fine here except
that you make this failed call every time it stops.  You should cache the
result (globally).

Some kernels have PTRACE_SETOPTIONS that actually only supports
PTRACE_O_TRACESYSGOOD and no other option bits, but does not reject
any bits.  So those will return 0 here even though PTRACE_O_TRACEEXEC
was ignored.

Some kernels (I think) have PTRACE_SETOPTIONS that checks for unsupported
bits, and do not support PTRACE_O_TRACEEXEC.  So those fail here with
EINVAL, but you could back off to just PTRACE_O_TRACESYSGOOD and win.

Because of the second case above, you can't assume that exec stops use
PTRACE_EVENT_EXEC until you actually see one.  Before you've seen one, a
SIGTRAP stop could be an exec stop.  You should always know when an exec
stop is coming, because you just traced the execve syscall exit with
successful return.

> +				/* It's post-exec ptrace stop.  */
> +				/* Set WSTOPSIG(status) = (SIGTRAP | 0x80).  */
> +				status |= 0x8000;

This magic number needs comments at the very least.  What's it for?

> +				 * Check some fields to make sure we see
> +				 * real SIGTRAP.
> +				 * Otherwise interpret it as ptrace stop.
> +				 * Real SIGTRAPs (int3 insn on x86, kill() etc)
> +				 * have these values:
> +				 * int3:                   kill -TRAP $pid:
> +				 * si_signo:5 (SIGTRAP)    si_signo:5 (SIGTRAP)
> +				 * si_errno:0              si_errno:(?)
> +				 * si_code:128 (SI_KERNEL) si_code:0 (SI_USER)
> +				 * si_pid:0                si_pid:(>0?)
> +				 * si_band:0               si_band:(?)
> +				 * Ptrace stops have garbage there instead.

This is way too fiddly.  These assumptions about siginfo_t settings for
real signals are not really valid across all machines and kernel versions.


Thanks,
Roland




More information about the Strace-devel mailing list