[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