why doesn't strace use test syscalls to find out their indices in the system call table?
Because there is no concept of a syscall name at that low of a level. There is no way strace
could say "Hey, let's make an fcntl()
call and see what the number is!". It can only make calls based on the syscall numbers themselves. This is because a syscall is made when the the syscall number is saved to the eax
or rax
register, and the process calls int 0x80
or syscall
.
Although it could call the wrapper function from the C library, there's no guarantee that the syscall would have the same name as the wrapper. For example, if it tried to figure out the syscall number of open()
by calling the libc wrapper of the same name and checking the syscall number used, it would incorrectly conclude that it is syscall 257, when it is in fact syscall 2. This is because that wrapper function actually calls openat()
, not open()
. A trivial demonstration shell log:
$ cat open.c
#include <fcntl.h>
int main(void)
{
open("/dev/null", O_RDONLY);
}
$ gcc open.c
$ strace -e trace=%file -P "/dev/null" ./a.out
openat(AT_FDCWD, "/dev/null", O_RDONLY) = 3
+++ exited with 0 +++
Now, you can do this using syscall(SYS_open, "/dev/null", O_RDONLY)
instead, but then you're relying on a constant defined in a header again, so why not just cut the middle-man and have strace
built with the syscall list from the C headers in the first place? That's what strace
does.