[PATCH 0/5] get_scno is an unholy mess, make it less horrible
Denys Vlasenko
dvlasenk at redhat.com
Mon Aug 22 10:21:51 UTC 2011
Currently, get_scno does *much* more than "get syscall no".
It checks for post-execve SIGTRAP. It checks for changes
in personality. It retrieves params on entry and registers on exit.
Worse still, it is different in different architectures: for example,
for AVR32 regs are fetched in get_scno(), while for e.g. I386
it is done in syscall_enter().
Another problem is that get_scno() is called on both syscall entry and
syscall exit, which is stupid: we don't need to know scno on syscall
exit, it is already known from last syscall entry and stored in
tcp->scno! In essence, get_scno() does two completely different things
on syscall entry and on exit, they are just mixed into one bottle, like
shampoo and conditioner.
The following 5 patches try to improve this situation.
1. Duplicate get_scno into identical get_scno_on_sysenter,
get_scno_on_sysexit functions. Call them in syscall enter and syscall
exit, correspondingly.
2. Remove if (entering(tcp)) / if (exiting(tcp)) conditionals from both
functions, since now we know that they are always true or false there.
3. Remove scno retrieval code in get_scno_on_sysexit, since we don't
save it anyway. This is the first real logic change which should make
strace faster: for example, on x64 ORIG_EAX is no longer read in each
syscall exit.
4. Another speedup: on x86, EAX read on syscall entry is also not
necessary if we know that post-execve SIGTRAP is disabled by
PTRACE_O_TRACEEXEC ptrace option. This patch (a) moves EAX retrieval
from syscall_fixup to get_scno_on_sysexit, and (b) perform EAX retrieval
in syscall_fixup only if we are in syscall entry and PTRACE_O_TRACEEXEC
option is not on.
5. Move post-execve SIGTRAP from get_scno_on_sysenter (multitude of
places on many architectures) to a single location in
trace_syscall_entering. This loosens the logic for some arches, since
many of them had additional checks such as scno == 0. So maybe this last
patch is not 100% safe. (However, on non-ancient Linux kernels we should
never have post-execve SIGTRAP in the first place, by virtue of using
PTRACE_O_TRACEEXEC.)
Patches 3 and 4 have the following effects: patch 3 removes one ptrace
call on syscall exit:
ptrace(PTRACE_SYSCALL, PID, 0x1, SIG_0) = 0
--- {si_signo=SIGCHLD, si_code=CLD_TRAPPED, si_pid=PID, si_status=SIGTRAP, si_utime=0, si_stime=0} (Child exited) ---
wait4(-1, [{WIFSTOPPED(s) && WSTOPSIG(s) == 133}], __WALL, NULL) = PID
-ptrace(PTRACE_PEEKUSER, PID, 4*ORIG_EAX, [0xb]) = 0
ptrace(PTRACE_PEEKUSER, PID, 4*EAX, [0]) = 0
write(3, ") = 0\n", 6) = 6
and patch 4 drops another one on syscall entry:
write(3, ", {B38400 opost isig icanon echo ...}) = 0\n", 43) = 43
ptrace(PTRACE_SYSCALL, PID, 0x1, SIG_0) = 0
--- {si_signo=SIGCHLD, si_code=CLD_TRAPPED, si_pid=PID, si_status=SIGTRAP, si_utime=0, si_stime=0} (Child exited) ---
wait4(-1, [{WIFSTOPPED(s) && WSTOPSIG(s) == 133}], __WALL, NULL) = PID
ptrace(PTRACE_PEEKUSER, PID, 4*ORIG_EAX, [0x36]) = 0
-ptrace(PTRACE_PEEKUSER, PID, 4*EAX, [0xffffffda]) = 0
ptrace(PTRACE_PEEKUSER, PID, 4*EBX, [0x1]) = 0
ptrace(PTRACE_PEEKUSER, PID, 4*ECX, [0x5401]) = 0
ptrace(PTRACE_PEEKUSER, PID, 4*EDX, [0xbfda3f80]) = 0
write(3, "ioctl(1, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS", 71) = 71
Further progress can be achieved by moving some (most/all?) code from
syscall_enter to get_scno_on_sysenter, and renaming get_scno_on_sysenter/exit
to better reflect on their actual operations.
--
vda
More information about the Strace-devel
mailing list