Split syscall_fixup into enter/exit pair of functions

* syscall.c: Create syscall_fixup_on_sysexit() which is a copy of
syscall_fixup().
(trace_syscall_exiting): Call syscall_fixup_on_sysexit() instead of
syscall_fixup().

Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
This commit is contained in:
Denys Vlasenko 2011-08-25 10:23:00 +02:00
parent 61526c6b1e
commit 20c41fd91d

183
syscall.c
View File

@ -1237,7 +1237,7 @@ known_scno(struct tcb *tcp)
return scno;
}
/* Called in trace_syscall() at each syscall entry and exit.
/* Called at each syscall entry.
* Returns:
* 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
* 1: ok, continue in trace_syscall().
@ -1987,6 +1987,185 @@ get_syscall_result(struct tcb *tcp)
return 1;
}
/* Called at each syscall exit.
* Returns:
* 0: "ignore this ptrace stop", bail out of trace_syscall() silently.
* 1: ok, continue in trace_syscall().
* other: error, trace_syscall() should print error indicator
* ("????" etc) and bail out.
*/
static int
syscall_fixup_on_sysexit(struct tcb *tcp)
{
#ifdef USE_PROCFS
int scno = known_scno(tcp);
if (entering(tcp)) {
if (tcp->status.PR_WHY != PR_SYSENTRY) {
if (
scno == SYS_fork
#ifdef SYS_vfork
|| scno == SYS_vfork
#endif /* SYS_vfork */
#ifdef SYS_fork1
|| scno == SYS_fork1
#endif /* SYS_fork1 */
#ifdef SYS_forkall
|| scno == SYS_forkall
#endif /* SYS_forkall */
#ifdef SYS_rfork1
|| scno == SYS_rfork1
#endif /* SYS_fork1 */
#ifdef SYS_rforkall
|| scno == SYS_rforkall
#endif /* SYS_rforkall */
) {
/* We are returning in the child, fake it. */
tcp->status.PR_WHY = PR_SYSENTRY;
trace_syscall(tcp);
tcp->status.PR_WHY = PR_SYSEXIT;
}
else {
fprintf(stderr, "syscall: missing entry\n");
tcp->flags |= TCB_INSYSCALL;
}
}
}
else {
if (tcp->status.PR_WHY != PR_SYSEXIT) {
fprintf(stderr, "syscall: missing exit\n");
tcp->flags &= ~TCB_INSYSCALL;
}
}
#endif /* USE_PROCFS */
#ifdef SUNOS4
if (entering(tcp)) {
if (scno == 0) {
fprintf(stderr, "syscall: missing entry\n");
tcp->flags |= TCB_INSYSCALL;
}
}
else {
if (scno != 0) {
if (debug) {
/*
* This happens when a signal handler
* for a signal which interrupted a
* a system call makes another system call.
*/
fprintf(stderr, "syscall: missing exit\n");
}
tcp->flags &= ~TCB_INSYSCALL;
}
}
#endif /* SUNOS4 */
#ifdef LINUX
/* A common case of "not a syscall entry" is post-execve SIGTRAP */
#if defined (I386)
/* With PTRACE_O_TRACEEXEC, post-execve SIGTRAP is disabled.
* Every extra ptrace call is expensive, so check EAX
* on syscall entry only if PTRACE_O_TRACEEXEC is not enabled:
*/
if (entering(tcp) && !(ptrace_setoptions & PTRACE_O_TRACEEXEC)) {
if (upeek(tcp, 4*EAX, &eax) < 0)
return -1;
if (eax != -ENOSYS) {
if (debug)
fprintf(stderr, "not a syscall entry (eax = %ld)\n", eax);
return 0;
}
}
#elif defined (X86_64)
if (entering(tcp) && !(ptrace_setoptions & PTRACE_O_TRACEEXEC)) {
if (upeek(tcp, 8*RAX, &rax) < 0)
return -1;
if (current_personality == 1)
rax = (long int)(int)rax; /* sign extend from 32 bits */
if (rax != -ENOSYS && entering(tcp)) {
if (debug)
fprintf(stderr, "not a syscall entry (rax = %ld)\n", rax);
return 0;
}
}
#elif defined (S390) || defined (S390X)
if (upeek(tcp, PT_GPR2, &gpr2) < 0)
return -1;
if (syscall_mode != -ENOSYS)
syscall_mode = tcp->scno;
if (gpr2 != syscall_mode && entering(tcp)) {
if (debug)
fprintf(stderr, "not a syscall entry (gpr2 = %ld)\n", gpr2);
return 0;
}
else if (((tcp->flags & (TCB_INSYSCALL|TCB_WAITEXECVE))
== (TCB_INSYSCALL|TCB_WAITEXECVE))
&& (gpr2 == -ENOSYS || gpr2 == tcp->scno)) {
/*
* Return from execve.
* Fake a return value of zero. We leave the TCB_WAITEXECVE
* flag set for the post-execve SIGTRAP to see and reset.
*/
gpr2 = 0;
}
#elif defined (POWERPC)
# define SO_MASK 0x10000000
if (upeek(tcp, sizeof(unsigned long)*PT_CCR, &flags) < 0)
return -1;
if (upeek(tcp, sizeof(unsigned long)*PT_R3, &result) < 0)
return -1;
if (flags & SO_MASK)
result = -result;
#elif defined (M68K)
if (upeek(tcp, 4*PT_D0, &d0) < 0)
return -1;
if (d0 != -ENOSYS && entering(tcp)) {
if (debug)
fprintf(stderr, "not a syscall entry (d0 = %ld)\n", d0);
return 0;
}
#elif defined (ARM)
/*
* Nothing required
*/
#elif defined(BFIN)
if (upeek(tcp, PT_R0, &r0) < 0)
return -1;
#elif defined (HPPA)
if (upeek(tcp, PT_GR28, &r28) < 0)
return -1;
#elif defined(IA64)
if (upeek(tcp, PT_R10, &r10) < 0)
return -1;
if (upeek(tcp, PT_R8, &r8) < 0)
return -1;
if (ia32 && r8 != -ENOSYS && entering(tcp)) {
if (debug)
fprintf(stderr, "not a syscall entry (r8 = %ld)\n", r8);
return 0;
}
#elif defined(CRISV10) || defined(CRISV32)
if (upeek(tcp, 4*PT_R10, &r10) < 0)
return -1;
if (r10 != -ENOSYS && entering(tcp)) {
if (debug)
fprintf(stderr, "not a syscall entry (r10 = %ld)\n", r10);
return 0;
}
#elif defined(MICROBLAZE)
if (upeek(tcp, 3 * 4, &r3) < 0)
return -1;
if (r3 != -ENOSYS && entering(tcp)) {
if (debug)
fprintf(stderr, "not a syscall entry (r3 = %ld)\n", r3);
return 0;
}
#endif
#endif /* LINUX */
return 1;
}
#ifdef LINUX
/*
* Check the syscall return value register value for whether it is
@ -2302,7 +2481,7 @@ trace_syscall_exiting(struct tcb *tcp)
if (res == 0)
return res;
if (res == 1)
res = syscall_fixup(tcp);
res = syscall_fixup_on_sysexit(tcp);
if (res == 0)
return res;
if (res == 1)