Documentation ¶
Overview ¶
Package usertrap implements the library to replace syscall instructions with function calls.
The most often used pattern of performing a system call is a sequence of two instruction: mov sysno, %eax; syscall. The size of the mov instruction is 5 bytes and the size of the syscall instruction is 2 bytes. These two instruction can be replaced with a single jmp instruction with an absolute address below 2 gigabytes.
Here is a few tricks:
- The GS register is used to access a per-thread memory.
- The syscall instruction is replaced with the "jmp *%ds:offset" instruction. On x86_64, ds is always zero. offset is a 32-bit signed integer. This means that a service mapping for a table with syscall trampolines has to be mapped below 2GB.
- We can't touch a process stack, so we have to use the jmp instruction instead of callq and generate a new function call for each replaced instruction. Each trampoline contains a syscall number and an return address.
- The address for the syscall table is set so that the syscall instruction is replaced on an invalid instruction. This allows us to handle races when two threads are executing the same syscall concurrently. And this allows us to restart a syscall if it has been interrupted by a signal.
+checkalignedignore
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrFaultRestart indicates that the current stub thread has to be restarted. ErrFaultRestart = fmt.Errorf("need to restart stub thread") // ErrFaultSyscall indicates that the current fault has to be handled as a system call. ErrFaultSyscall = fmt.Errorf("need to handle as syscall") )
Functions ¶
This section is empty.
Types ¶
type State ¶
type State struct {
// contains filtered or unexported fields
}
State represents the current state of the trap table.
+stateify savable
func (*State) HandleFault ¶
HandleFault handles a fault on a patched syscall instruction.
When we replace a system call with a function call, we replace two instructions with one instruction. This means that here can be a thread which called the first instruction, then another thread applied a binary patch and the first thread calls the second instruction.
To handle this case, the function call (jmp) instruction is constructed so that the first byte of the syscall instruction is changed with the one-byte invalid instruction (0x6). And in case of the race, the first thread will fault on the invalid instruction and HandleFault will restart the function call.
func (*State) PatchSyscall ¶
PatchSyscall changes the syscall instruction into a function call.