use std::convert::TryFrom;
use crate::Errno;
use crate::{SyscallError, VarType};
mod transformer;
pub(crate) use transformer::*;
mod helpers;
pub mod kind;
mod value_impl;
pub use value_impl::*;
use crate::call::CStructAV;
pub use crate::ptrace::MockPtrace;
use crate::syscall::Direction;
#[allow(non_camel_case_types)]
pub(crate) enum AV {
Int(Direction),
#[allow(dead_code)]
UnsignedLong(Direction),
SizeT(Direction),
SSizeT(Direction),
OffT(Direction),
CString(Direction),
BufferFromArgPosition(Direction, usize),
BufferFromReturn(Direction),
MemoryAddress(Direction),
CStruct(Direction, CStructAV),
Void(Direction),
AddressFamily(Direction),
SocketType(Direction),
Prot(Direction),
OpenatMode(Direction),
AccessMode(Direction),
SockAddr(Direction, usize),
#[allow(dead_code)]
DynType(Direction, Box<dyn VarType>),
}
pub(crate) fn map_output(out: &AV, is_error: u8, rval: i64) -> Result<Value, SyscallError> {
if is_error > 0 {
match i32::try_from(
rval.checked_mul(-1)
.ok_or_else(|| SyscallError::from_errno(Errno::UnknownErrno))?,
) {
Ok(val) => Err(SyscallError::from_i32(val)),
Err(_) => return Err(SyscallError::from_errno(Errno::UnknownErrno)),
}
} else {
Ok(match out {
AV::Int(_) => Value::Int(rval as isize),
AV::MemoryAddress(_) => Value::MemoryAddress(kind::MemoryAddress(rval as usize)),
AV::SSizeT(_) => Value::SSizeT(rval as isize),
AV::OffT(_) => Value::OffT(rval as usize),
AV::Void(_) => Value::Void,
_ => Value::Failure,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
pub fn test_map_output_overflow() {
assert_eq!(
map_output(&AV::Int(Direction::Out), 23, -9223372036854775808)
.unwrap_err()
.to_errno(),
Errno::UnknownErrno
);
}
#[test]
pub fn test_map_output() {
assert_eq!(
map_output(&AV::Int(Direction::Out), 23, -1)
.unwrap_err()
.to_errno(),
Errno::EPERM
);
match map_output(&AV::Int(Direction::Out), 0, 50).unwrap() {
Value::Int(val) => assert_eq!(val, 50),
_ => panic!("map_output expected value::int"),
}
}
}