use super::guest::GuestCpu;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Sysno {
Read,
Write,
Readv,
Writev,
Open,
Openat,
Close,
Lseek,
Brk,
Mmap,
Munmap,
Mremap,
Mprotect,
Exit,
ExitGroup,
Fstat,
Stat,
Lstat,
Newfstatat,
Statx,
Fcntl,
Dup,
Dup2,
Dup3,
Chdir,
Fchdir,
Faccessat,
Umask,
Fchmod,
Fchmodat,
Utimensat,
Nanosleep,
Poll,
Ppoll,
Select,
Pselect6,
Rename,
Renameat,
Renameat2,
Chown,
Pread64,
Pwrite64,
CopyFileRange,
Fallocate,
Uname,
Getpid,
Getppid,
Gettid,
Getuid,
Geteuid,
Getgid,
Getegid,
Access,
Getcwd,
Ioctl,
ArchPrctl,
SetTidAddress,
SetRobustList,
RtSigaction,
RtSigprocmask,
RtSigreturn,
Time,
ClockGettime,
Gettimeofday,
Futex,
Getrandom,
Readlink,
Readlinkat,
Getdents64,
Mkdir,
Mkdirat,
Unlink,
Unlinkat,
Rmdir,
Symlink,
Symlinkat,
Link,
Linkat,
Truncate,
Ftruncate,
Clone,
Fork,
Vfork,
Execve,
Wait4,
Pipe,
Pipe2,
Flock,
Statfs,
Fstatfs,
Socket,
Connect,
Bind,
Listen,
Accept,
Sendto,
Recvfrom,
Sendmsg,
Recvmsg,
Shutdown,
Getsockname,
Getpeername,
Setsockopt,
Getsockopt,
SchedYield,
Ignored,
}
#[derive(Debug, Clone, Copy)]
pub struct StatLayout {
pub size: usize,
pub mode_off: usize,
pub nlink_off: usize,
pub size_off: usize,
pub blksize_off: usize,
pub blocks_off: usize,
pub dev_off: usize,
pub ino_off: usize,
}
pub trait LinuxAbi {
fn syscall_nr(&self, cpu: &dyn GuestCpu) -> u64;
fn syscall_args(&self, cpu: &dyn GuestCpu) -> [u64; 6];
fn set_return(&self, cpu: &mut dyn GuestCpu, ret: i64);
fn map_syscall(&self, nr: u64) -> Option<Sysno>;
fn ptr_bits(&self) -> u8;
fn stat_layout(&self) -> StatLayout;
}
#[derive(Debug, Default, Clone, Copy)]
pub struct I386Abi;
impl LinuxAbi for I386Abi {
fn syscall_nr(&self, cpu: &dyn GuestCpu) -> u64 {
cpu.reg(0)
}
fn syscall_args(&self, cpu: &dyn GuestCpu) -> [u64; 6] {
[
cpu.reg(3),
cpu.reg(1),
cpu.reg(2),
cpu.reg(6),
cpu.reg(7),
cpu.reg(5),
]
}
fn set_return(&self, cpu: &mut dyn GuestCpu, ret: i64) {
cpu.set_reg(0, ret as u64);
}
fn map_syscall(&self, nr: u64) -> Option<Sysno> {
Some(match nr {
1 => Sysno::Exit,
3 => Sysno::Read,
4 => Sysno::Write,
5 => Sysno::Open,
6 => Sysno::Close,
13 => Sysno::Time,
19 => Sysno::Lseek,
20 => Sysno::Getpid,
24 => Sysno::Getuid,
33 => Sysno::Access,
45 => Sysno::Brk,
49 => Sysno::Geteuid,
47 => Sysno::Getgid,
50 => Sysno::Getegid,
54 => Sysno::Ioctl,
64 => Sysno::Getppid,
2 => Sysno::Fork,
7 => Sysno::Wait4, 10 => Sysno::Unlink,
11 => Sysno::Execve,
12 => Sysno::Chdir,
42 => Sysno::Pipe,
114 => Sysno::Wait4,
190 => Sysno::Vfork,
331 => Sysno::Pipe2,
143 => Sysno::Flock,
99 => Sysno::Statfs,
100 => Sysno::Fstatfs,
268 => Sysno::Statfs, 269 => Sysno::Fstatfs, 39 => Sysno::Mkdir,
40 => Sysno::Rmdir,
41 => Sysno::Dup,
55 => Sysno::Fcntl,
60 => Sysno::Umask,
63 => Sysno::Dup2,
94 => Sysno::Fchmod,
133 => Sysno::Fchdir,
142 => Sysno::Select, 162 => Sysno::Nanosleep,
168 => Sysno::Poll,
180 => Sysno::Pread64,
181 => Sysno::Pwrite64,
377 => Sysno::CopyFileRange,
324 => Sysno::Fallocate,
196 => Sysno::Lstat, 221 => Sysno::Fcntl, 267 => Sysno::Nanosleep, 306 => Sysno::Fchmodat,
307 => Sysno::Faccessat,
309 => Sysno::Ppoll,
308 => Sysno::Pselect6,
320 => Sysno::Utimensat,
330 => Sysno::Dup3,
383 => Sysno::Statx,
439 => Sysno::Faccessat, 38 => Sysno::Rename,
302 => Sysno::Renameat,
353 => Sysno::Renameat2,
182 => Sysno::Chown,
212 => Sysno::Chown, 198 => Sysno::Chown, 207 => Sysno::Chown, 298 => Sysno::Chown, 83 => Sysno::Symlink,
85 => Sysno::Readlink,
92 => Sysno::Truncate,
93 => Sysno::Ftruncate,
193 => Sysno::Truncate, 194 => Sysno::Ftruncate, 220 => Sysno::Getdents64,
296 => Sysno::Mkdirat,
301 => Sysno::Unlinkat,
304 => Sysno::Symlinkat,
9 => Sysno::Link,
303 => Sysno::Linkat,
91 => Sysno::Munmap,
163 => Sysno::Mremap,
122 => Sysno::Uname,
125 => Sysno::Mprotect,
145 => Sysno::Readv,
146 => Sysno::Writev,
174 => Sysno::RtSigaction,
175 => Sysno::RtSigprocmask,
173 => Sysno::RtSigreturn,
183 => Sysno::Getcwd,
192 => Sysno::Mmap, 195 => Sysno::Stat, 197 => Sysno::Fstat, 224 => Sysno::Gettid,
243 => Sysno::Ignored, 258 => Sysno::SetTidAddress,
295 => Sysno::Openat,
300 => Sysno::Newfstatat, 311 => Sysno::SetRobustList,
252 => Sysno::ExitGroup,
265 => Sysno::ClockGettime,
78 => Sysno::Gettimeofday,
240 => Sysno::Futex,
355 => Sysno::Getrandom,
340 => Sysno::Ignored, 305 => Sysno::Readlinkat,
_ => return None,
})
}
fn ptr_bits(&self) -> u8 {
32
}
fn stat_layout(&self) -> StatLayout {
StatLayout {
size: 96,
mode_off: 16,
nlink_off: 20,
size_off: 44,
blksize_off: 52,
blocks_off: 56,
dev_off: 0,
ino_off: 88,
}
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct Amd64Abi;
impl Amd64Abi {
#[must_use]
pub fn map(nr: u64) -> Option<Sysno> {
Some(match nr {
0 => Sysno::Read,
1 => Sysno::Write,
2 => Sysno::Open,
3 => Sysno::Close,
4 => Sysno::Stat,
5 => Sysno::Fstat,
6 => Sysno::Lstat,
7 => Sysno::Poll,
8 => Sysno::Lseek,
23 => Sysno::Select,
17 => Sysno::Pread64,
18 => Sysno::Pwrite64,
326 => Sysno::CopyFileRange,
285 => Sysno::Fallocate,
32 => Sysno::Dup,
33 => Sysno::Dup2,
35 => Sysno::Nanosleep,
72 => Sysno::Fcntl,
80 => Sysno::Chdir,
81 => Sysno::Fchdir,
91 => Sysno::Fchmod,
95 => Sysno::Umask,
230 => Sysno::Nanosleep, 268 => Sysno::Fchmodat,
269 => Sysno::Faccessat,
270 => Sysno::Pselect6,
82 => Sysno::Rename,
264 => Sysno::Renameat,
316 => Sysno::Renameat2,
92 => Sysno::Chown,
93 => Sysno::Chown, 94 => Sysno::Chown, 260 => Sysno::Chown, 271 => Sysno::Ppoll,
280 => Sysno::Utimensat,
292 => Sysno::Dup3,
332 => Sysno::Statx,
439 => Sysno::Faccessat, 9 => Sysno::Mmap,
10 => Sysno::Mprotect,
11 => Sysno::Munmap,
25 => Sysno::Mremap,
12 => Sysno::Brk,
13 => Sysno::RtSigaction,
14 => Sysno::RtSigprocmask,
15 => Sysno::RtSigreturn,
16 => Sysno::Ioctl,
19 => Sysno::Readv,
20 => Sysno::Writev,
21 => Sysno::Access,
39 => Sysno::Getpid,
60 => Sysno::Exit,
63 => Sysno::Uname,
79 => Sysno::Getcwd,
102 => Sysno::Getuid,
104 => Sysno::Getgid,
107 => Sysno::Geteuid,
108 => Sysno::Getegid,
110 => Sysno::Getppid,
158 => Sysno::ArchPrctl,
186 => Sysno::Gettid,
218 => Sysno::SetTidAddress,
231 => Sysno::ExitGroup,
257 => Sysno::Openat,
262 => Sysno::Newfstatat,
273 => Sysno::SetRobustList,
228 => Sysno::ClockGettime,
96 => Sysno::Gettimeofday,
202 => Sysno::Futex,
204 => Sysno::Ignored, 302 => Sysno::Ignored, 318 => Sysno::Getrandom,
334 => Sysno::Ignored, 267 => Sysno::Readlinkat,
76 => Sysno::Truncate,
77 => Sysno::Ftruncate,
83 => Sysno::Mkdir,
84 => Sysno::Rmdir,
87 => Sysno::Unlink,
88 => Sysno::Symlink,
89 => Sysno::Readlink,
217 => Sysno::Getdents64,
258 => Sysno::Mkdirat,
263 => Sysno::Unlinkat,
266 => Sysno::Symlinkat,
86 => Sysno::Link,
265 => Sysno::Linkat,
56 => Sysno::Clone,
57 => Sysno::Fork,
58 => Sysno::Vfork,
59 => Sysno::Execve,
61 => Sysno::Wait4,
22 => Sysno::Pipe,
293 => Sysno::Pipe2,
73 => Sysno::Flock,
137 => Sysno::Statfs,
138 => Sysno::Fstatfs,
41 => Sysno::Socket,
42 => Sysno::Connect,
43 => Sysno::Accept,
44 => Sysno::Sendto,
45 => Sysno::Recvfrom,
46 => Sysno::Sendmsg,
47 => Sysno::Recvmsg,
48 => Sysno::Shutdown,
49 => Sysno::Bind,
50 => Sysno::Listen,
51 => Sysno::Getsockname,
52 => Sysno::Getpeername,
54 => Sysno::Setsockopt,
55 => Sysno::Getsockopt,
288 => Sysno::Accept, 165 => Sysno::Ignored, 166 => Sysno::Ignored, 24 => Sysno::SchedYield,
28 => Sysno::Ignored, _ => return None,
})
}
}
impl LinuxAbi for Amd64Abi {
fn syscall_nr(&self, cpu: &dyn GuestCpu) -> u64 {
cpu.reg(0)
}
fn syscall_args(&self, cpu: &dyn GuestCpu) -> [u64; 6] {
[
cpu.reg(7),
cpu.reg(6),
cpu.reg(2),
cpu.reg(10),
cpu.reg(8),
cpu.reg(9),
]
}
fn set_return(&self, cpu: &mut dyn GuestCpu, ret: i64) {
cpu.set_reg(0, ret as u64);
}
fn map_syscall(&self, nr: u64) -> Option<Sysno> {
Self::map(nr)
}
fn ptr_bits(&self) -> u8 {
64
}
fn stat_layout(&self) -> StatLayout {
StatLayout {
size: 144,
mode_off: 24,
nlink_off: 16,
size_off: 48,
blksize_off: 56,
blocks_off: 64,
dev_off: 0,
ino_off: 8,
}
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct Aarch64Abi;
#[cfg(test)]
mod tests {
use super::*;
use crate::emulator::emulator::Cpu;
use crate::emulator::emulator::regs::Reg32;
#[test]
fn i386_reads_nr_args_and_writes_return() {
let mut cpu = Cpu::new();
cpu.regs.set32(Reg32::Eax, 4); cpu.regs.set32(Reg32::Ebx, 1); cpu.regs.set32(Reg32::Ecx, 0x1234); cpu.regs.set32(Reg32::Edx, 3); let abi = I386Abi;
assert_eq!(abi.syscall_nr(&cpu), 4);
assert_eq!(abi.syscall_args(&cpu)[..4], [1, 0x1234, 3, 0][..4]);
assert_eq!(abi.map_syscall(4), Some(Sysno::Write));
assert_eq!(abi.map_syscall(1), Some(Sysno::Exit));
assert_eq!(abi.map_syscall(45), Some(Sysno::Brk));
assert_eq!(abi.map_syscall(9999), None);
abi.set_return(&mut cpu, -38);
assert_eq!(cpu.regs.get32(Reg32::Eax), (-38i32) as u32);
}
#[test]
fn stat_layouts_match_known_struct_sizes() {
let i386 = I386Abi.stat_layout();
assert_eq!((i386.size, i386.mode_off, i386.size_off), (96, 16, 44));
let amd64 = Amd64Abi.stat_layout();
assert_eq!((amd64.size, amd64.mode_off, amd64.size_off), (144, 24, 48));
let a64 = Aarch64Abi.stat_layout();
assert_eq!((a64.size, a64.mode_off, a64.size_off), (128, 16, 48));
for l in [i386, amd64, a64] {
assert!(l.size_off + 8 <= l.size && l.blocks_off + 8 <= l.size);
assert!(l.mode_off + 4 <= l.size && l.nlink_off + 4 <= l.size);
}
}
#[test]
fn new_dir_syscall_numbers_map() {
assert_eq!(I386Abi.map_syscall(220), Some(Sysno::Getdents64));
assert_eq!(I386Abi.map_syscall(85), Some(Sysno::Readlink));
assert_eq!(Amd64Abi::map(217), Some(Sysno::Getdents64));
assert_eq!(Amd64Abi::map(83), Some(Sysno::Mkdir));
assert_eq!(Aarch64Abi::map(61), Some(Sysno::Getdents64));
assert_eq!(Aarch64Abi::map(35), Some(Sysno::Unlinkat));
}
#[test]
fn arch_tables_agree_on_common_calls() {
assert_eq!(Amd64Abi::map(1), Some(Sysno::Write));
assert_eq!(Amd64Abi::map(60), Some(Sysno::Exit));
assert_eq!(Aarch64Abi::map(64), Some(Sysno::Write));
assert_eq!(Aarch64Abi::map(93), Some(Sysno::Exit));
}
}
impl Aarch64Abi {
#[must_use]
pub fn map(nr: u64) -> Option<Sysno> {
Some(match nr {
17 => Sysno::Getcwd,
23 => Sysno::Dup,
24 => Sysno::Dup3,
25 => Sysno::Fcntl,
29 => Sysno::Ioctl,
48 => Sysno::Faccessat,
49 => Sysno::Chdir,
50 => Sysno::Fchdir,
52 => Sysno::Fchmod,
53 => Sysno::Fchmodat,
56 => Sysno::Openat,
67 => Sysno::Pread64,
68 => Sysno::Pwrite64,
47 => Sysno::Fallocate,
285 => Sysno::CopyFileRange,
72 => Sysno::Pselect6,
38 => Sysno::Renameat,
276 => Sysno::Renameat2,
54 => Sysno::Chown, 55 => Sysno::Chown, 73 => Sysno::Ppoll,
88 => Sysno::Utimensat,
101 => Sysno::Nanosleep,
115 => Sysno::Nanosleep, 166 => Sysno::Umask,
221 => Sysno::Execve,
260 => Sysno::Wait4,
59 => Sysno::Pipe2,
32 => Sysno::Flock,
43 => Sysno::Statfs,
44 => Sysno::Fstatfs,
198 => Sysno::Socket,
200 => Sysno::Bind,
201 => Sysno::Listen,
202 => Sysno::Accept,
203 => Sysno::Connect,
204 => Sysno::Getsockname,
205 => Sysno::Getpeername,
206 => Sysno::Sendto,
207 => Sysno::Recvfrom,
208 => Sysno::Setsockopt,
209 => Sysno::Getsockopt,
210 => Sysno::Shutdown,
211 => Sysno::Sendmsg,
212 => Sysno::Recvmsg,
242 => Sysno::Accept, 291 => Sysno::Statx,
57 => Sysno::Close,
63 => Sysno::Read,
64 => Sysno::Write,
65 => Sysno::Readv,
66 => Sysno::Writev,
79 => Sysno::Newfstatat,
80 => Sysno::Fstat,
93 => Sysno::Exit,
94 => Sysno::ExitGroup,
96 => Sysno::SetTidAddress,
99 => Sysno::SetRobustList,
134 => Sysno::RtSigaction,
135 => Sysno::RtSigprocmask,
139 => Sysno::RtSigreturn,
160 => Sysno::Uname,
172 => Sysno::Getpid,
173 => Sysno::Getppid,
174 => Sysno::Getuid,
175 => Sysno::Geteuid,
176 => Sysno::Getgid,
177 => Sysno::Getegid,
178 => Sysno::Gettid,
214 => Sysno::Brk,
215 => Sysno::Munmap,
216 => Sysno::Mremap,
222 => Sysno::Mmap,
226 => Sysno::Mprotect,
113 => Sysno::ClockGettime,
169 => Sysno::Gettimeofday,
98 => Sysno::Futex,
278 => Sysno::Getrandom,
261 => Sysno::Ignored, 78 => Sysno::Readlinkat,
45 => Sysno::Truncate,
46 => Sysno::Ftruncate,
61 => Sysno::Getdents64,
34 => Sysno::Mkdirat,
35 => Sysno::Unlinkat,
36 => Sysno::Symlinkat,
37 => Sysno::Linkat,
_ => return None,
})
}
}
impl LinuxAbi for Aarch64Abi {
fn syscall_nr(&self, cpu: &dyn GuestCpu) -> u64 {
cpu.reg(8)
}
fn syscall_args(&self, cpu: &dyn GuestCpu) -> [u64; 6] {
[
cpu.reg(0),
cpu.reg(1),
cpu.reg(2),
cpu.reg(3),
cpu.reg(4),
cpu.reg(5),
]
}
fn set_return(&self, cpu: &mut dyn GuestCpu, ret: i64) {
cpu.set_reg(0, ret as u64);
}
fn map_syscall(&self, nr: u64) -> Option<Sysno> {
Self::map(nr)
}
fn ptr_bits(&self) -> u8 {
64
}
fn stat_layout(&self) -> StatLayout {
StatLayout {
size: 128,
mode_off: 16,
nlink_off: 20,
size_off: 48,
blksize_off: 56,
blocks_off: 64,
dev_off: 0,
ino_off: 8,
}
}
}