+2009-01-17 Denys Vlasenko <dvlasenk@redhat.com>
+
+ * defs.h: Update a comment. No code changes.
+ * strace.c (handle_stopped_tcbs): Discard all execve stops
+ and clear TCB_WAITEXECVE bit.
+ * syscall.c (get_scno): Add the code to not mistakenly
+ treat ptrace stop as execve stop (execve stops can be blocked
+ by traced program).
+ Fixes RH#477775 "strace hangs if the target process blocks SIGTRAP".
+
2009-01-17 Denys Vlasenko <dvlasenk@redhat.com>
* process.c: Add a comment. No code changes.
#define TCB_FOLLOWFORK 00400 /* Process should have forks followed */
#define TCB_REPRINT 01000 /* We should reprint this syscall on exit */
#ifdef LINUX
-/* x86 does not need TCB_WAITEXECVE.
+/* TCB_WAITEXECVE bit means "ignore next SIGTRAP, it's execve exit stop".
+ * it is not reliable if traced program masks SIGTRAP.
+ *
+ * x86 does not need TCB_WAITEXECVE.
* It can detect execve's SIGTRAP by looking at eax/rax.
* See "stray syscall exit: eax = " message in syscall_fixup().
+ *
+ * Note that on newer kernels, we use ptrace options and therefore
+ * can filter out execve stops reliably on any architecture,
+ * without using TCB_WAITEXECVE flag.
+ * I guess we can remove it from the source somewhere around year 2010 :)
*/
# if defined(ALPHA) || defined(SPARC) || defined(SPARC64) || defined(POWERPC) || defined(IA64) || defined(HPPA) || defined(SH) || defined(SH64) || defined(S390) || defined(S390X) || defined(ARM) || defined(MIPS) || defined(BFIN)
# define TCB_WAITEXECVE 02000 /* ignore SIGTRAP after exceve */
* but be paranoid about it.
*/
if (((unsigned)status >> 16) == PTRACE_EVENT_EXEC) {
- /* It's post-exec ptrace stop. */
- /* Set WSTOPSIG(status) = (SIGTRAP | 0x80). */
- status |= 0x8000;
+ /* It's post-exec ptrace stop. Ignore it,
+ * we will get syscall exit ptrace stop later.
+ */
+#ifdef TCB_WAITEXECVE
+ tcp->flags &= ~TCB_WAITEXECVE;
+#endif
+ goto tracing;
} else {
/* Take a better look... */
siginfo_t si;
+ si.si_signo = 0;
ptrace(PTRACE_GETSIGINFO, pid, (void*) 0, (void*) &si);
/*
* Check some fields to make sure we see
}
#elif defined(IA64)
# define IA64_PSR_IS ((long)1 << 34)
- if (upeek (tcp, PT_CR_IPSR, &psr) >= 0)
+ if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
ia32 = (psr & IA64_PSR_IS) != 0;
if (!(tcp->flags & TCB_INSYSCALL)) {
if (ia32) {
if (upeek(tcp, PT_R1, &scno) < 0) /* orig eax */
return -1;
} else {
- if (upeek (tcp, PT_R15, &scno) < 0)
+ if (upeek(tcp, PT_R15, &scno) < 0)
return -1;
}
/* Check if we return from execve. */
if (tcp->flags & TCB_WAITEXECVE) {
+#if defined PTRACE_GETSIGINFO
+ siginfo_t si;
+
+ tcp->flags &= ~TCB_WAITEXECVE;
+ /* If SIGTRAP is masked, execve's magic SIGTRAP
+ * is not delivered. We end up here on a subsequent
+ * ptrace stop instead. Luckily, we can check
+ * for the type of this SIGTRAP. execve's magic one
+ * has 0 (SI_USER) in si.si_code, ptrace stop has 5.
+ * (I don't know why 5).
+ */
+ si.si_code = SI_USER;
+ /* If PTRACE_GETSIGINFO fails, we assume it's
+ * magic SIGTRAP. Moot anyway, PTRACE_GETSIGINFO
+ * doesn't fail.
+ */
+ ptrace(PTRACE_GETSIGINFO, pid, (void*) 0, (void*) &si);
+ if (si.si_code == SI_USER)
+ return 0;
+#else
tcp->flags &= ~TCB_WAITEXECVE;
return 0;
+#endif
}
} else {
/* syscall in progress */
- if (upeek (tcp, PT_R8, &r8) < 0)
+ if (upeek(tcp, PT_R8, &r8) < 0)
return -1;
- if (upeek (tcp, PT_R10, &r10) < 0)
+ if (upeek(tcp, PT_R10, &r10) < 0)
return -1;
}
#elif defined (ARM)