Linux Syscall Table Generator
This weekend, I worked on a script that scans through the Linux source tree and generates syscall tables for both x86 and x64 architectures. If you are interested, you can check it out in this repo. I’d like to share some notes about it.
The generated tables are here:
In Linux, syscalls are identified by numbers, and their parameters are in machine word size, either 32-bit or 64-bit. Each system call can have up to 6 parameters, and both the syscall number and the parameters are stored in specific registers. On the x64 architecture, the syscall number is stored in the %rax
register, while parameters are stored in %rdi
, %rsi
, %rdx
, %r10
, %r8
, %r9
registers, in that order. On the x86 architecture, the sycall number is stored in the %eax
register, while parameters are stored in %ebx
, %ecx
, %edx
, %esi
, %edi
, %ebp
registers, in that order.
In the Linux source tree, the syscalls are defined using one of the SYSCALL_DEFINE
macros. Let’s take the getpid
syscall defined in kernel/sys.c
as an example:
|
The number at the end of the macro name indicates the number of parameters for the syscall. In this case, the getpid
syscall has zero parameters. The range for this number is from 0 to 6, as each syscall can have up to 6 parameters.
Now, let’s consider another example, the read
syscall defined in fs/read_write.c
:
|
The macro name indicates that this syscall has 3 parameters. Inside the parenthesis, the first symbol, read
, is the syscall name, the following symbols indicate the type and name of each parameter, alternating in that pattern.
This gives up the basic idea about how to search for all syscall definitions in the source tree. Let’s try using the following grep
command:
|
Unfortunately, many syscall definitions span multiple lines, such as the second and the third definitions in the above output. We want to capture the entire definition starting SYSCALL
to the closing parenthesis. I ended up with the following grep
pattern:
|
Some explanation on the grep
flags used above:
- The
-z
flag instructsgrep
to process the content of each input file as a whole, rather than line by line.grep
adds a trailing NUL character, instead of a newline. - The
-o
flag tells grep to only print the matching part of the input. Since the-z
flag is used, each input file is now treated like a single long line. - The
-P
flag enablesgrep
to use Perl-compatible regular expressions (PCREs). We need this because we utilize the(?s)
marker, which activates thePCRE_DOTALL
mode. This mode allows the dot symbol to match any character, including newlines.
We find all syscall definitions and store them in a temporary file named /tmp/all_defs
:
|
Note that most syscalls are architecture-independent. However, a few syscalls are defined in architecture-specific code files, as they entail specific machine characteristics. For instance, the rt_sigreturn
syscall is defined multiple times across different architectures:
|
For the scope of this syscall table generator, we only concentrate on the x86 and x64 architectures. We’ll eliminate definitions of other architectures by feeding the preceding result to another grep
command:
|
This certainly improves the result, but there are a couple of remaining issues:
- We need to discard definitions under
arch/x86/um/*.c
, since those definitions are exclusive for User-Mode Linux. - The source files
arch/x86/kernel/process_32.c
andarch/x86/kernel/process_64.c
are mutual exclusive. We should retain only one of these. We’ll keep the 32-bit.
Here’s the modified command:
|
Another issue arises with the syscalls clone
and sigsuspend
, each having multiple definitions sitting within conditional macros.
Here’s clone
in file kernel/fork.c
:
|
And sigsuspend
in file kernel/signal.c
:
|
As these two syscalls are dependant on the kernel configuration at the build time, we can’t predict which definitions will be compiled into the kernel binary. The best we can do is to arbitrarily select one. We’ll pick the first one.
|
Having isolated all the syscall definitions for x64 or x86, our remaining task is to present them in a table format and apply final polishing.