Looks like as of writing (2019-02-08), this is impossible.
strace gets it wrong.
Edit: Linus Torvalds talks about it here, also analysing possible (but commented-out) workarounds in the
strace code that directly look at the instructions made in the binary. This code was removed here as part of the patchset I mention below. It says
It works, but is too complicated, and strictly speaking, unreliable, but it is unclear to me in which cases the "strictly speaking, unreliably" applies, if that is only in the case of a multi-threaded executable rewriting itself at runtime (thus not suitable for forbidding certain syscalls for security use cases), or also in other cases.
Edit: The "unreliable" part was added in this commit.
Edit: I have now tried out strace's opcode-peeking implementation (version
v4.25), and suspect that it was bugged: When activating that code path by changing this line to
#if 0 and this line to
#elif 1, no syscalls are printed because
scno is not set at all. I added
scno = x86_64_regs.orig_rax; after this line to make it work.
See the presentation How to make strace happy, slide 2, problem 2:
There is no reliable way to distinguish between x86_64 and x86 syscalls.
Details shown on slides 4-6. There is a proposed solution to be added to the kernel:
Extend the ptrace API with PTRACE_GET_SYSCALL_INFO request
But this solution isn't merged to the kernel.
The patchset is called
ptrace: add PTRACE_GET_SYSCALL_INFO request and it's still being worked on in January 2019. Hopefully it will soon be merged.
strace already has support for it since release 4.26 (but it shouldn't work unless you apply the kernel patch manually):
Implemented obtainment of system call information using
PTRACE_GET_SYSCALL_INFO ptrace API.