The last post about the Linuxulator where I explained the Linuxulator from an user point of view got some good amount of attention. Triggered by a recent explanation of the Linuxulator errno stuff to a fellow FreeBSD developer I decided so see if more developers are interested in some more info too…
The syscall vector
In sys/linux/linux_sysvec.c is all the basic setup to handle Linux “system stuff” in FreeBSD. The “system stuff” is about translating FreeBSD errnos to Linux errnos, about translating FreeBSD signals to Linux signales, about handling Linux traps, and about setting up the FreeBSD system vector (the kernel structure which contains all the data to identify when a Linux program is called and to be able to lookup the right kernel functions for e.g. syscalls and ioctls).
There is not only one syscall vector, there is one for a.out (struct sysentvec linux_sysvec) and one for ELF (struct sysentvec elf_linux_sysvec) binaries (at least on i386, for other architectures it may not make sense to have the a.out stuff, as they maybe never seen any a.out Linux binary).
The ELF AUX args
When an ELF image is executed, the Linuxulator adds some runtime information (like pagesize, uid, guid, …) so that the userland can query this information which is not static at build-time easily. This is handled in the elf_linux_fixup function(). If you see some error messages about missing ELF notes from e.g. glibc, this is the place to add this information to. It would not be bad from time to time to have a look what Linux is providing and missing pieces there. FreeBSD does not has an automated way of doing this, and I am not aware of someone who regularly checks this. There is a little bit more info about ELF notes available in a message to one of the FreeBSD mailing lists, it also has an example how to read out this data.
Linux and FreeBSD do not share the same point of view how a trap shall be handled (SIGBUS or SIGSEGV), the corresponding decision making is handled in translate_traps() and a translation table is available as _bsd_to_linux_trapcode.
The values for the signal names are not the same in FreeBSD and Linux. The translation tables are called linux_to_bsd_signal and bsd_to_linux_signal. The translation is a feature of the syscall vector (= automatic).
The values for the errno names are not the same in FreeBSD and Linux. The translation table is called bsd_to_linux_errno. Returning an errno in one of the Linux syscalls will trigger an automatic translation from the FreeBSD errno value to the Linux errno value. This means that FreeBSD errnos have to be returned (e.g. FreeBSD ENOSYS=78) and the Linux program will receive the Linux value (e.g. Linux ENOSYS=38, and as the Linux kernel returns negative errnos, the linux program will get ‑38).
If you see somewhere an “-ESOMETHING” in the Linuxulator code, this is either a bug, or some clever/tricky/dangerous use of the sign-bit to encode some info (e.g. in the futex code there is a function which returns ‑ENOSYS, but the sign-bit is used as an error indicator and the calling code is responsible to translate negative errnos into positive ones).
The Linux syscalls are defined similar to the FreeBSD ones. There is a mapping table (sys/linux/syscalls.master) between syscall numbers and the corresponding functions. This table is used to generate code (“make sysent” in sys//linux/) which does what is necessary.