ckb_debugger/
syscall_stdio.rs

1#[cfg(target_family = "unix")]
2mod arch {
3    use ckb_vm::{
4        Error, Memory, Register, SupportMachine, Syscalls,
5        registers::{A0, A1, A2, A7},
6    };
7    use std::os::fd::BorrowedFd;
8
9    #[derive(Clone, Debug, Default)]
10    #[repr(C)]
11    struct AbiStat {
12        dev: u64,
13        ino: u64,
14        mode: u32,
15        nlink: i32,
16        uid: u32,
17        gid: u32,
18        rdev: u64,
19        __pad1: u64,
20        size: i64,
21        blksize: i32,
22        __pad2: i32,
23        blocks: i64,
24        atime: i64,
25        atime_nsec: i64,
26        mtime: i64,
27        mtime_nsec: i64,
28        ctime: i64,
29        ctime_nsec: i64,
30        __unused4: i32,
31        __unused5: i32,
32    }
33
34    #[derive(Default)]
35    pub struct Stdio {
36        keep_stdios: bool,
37    }
38
39    impl Stdio {
40        pub fn new(keep_stdios: bool) -> Self {
41            Stdio { keep_stdios }
42        }
43
44        fn close<Mac: SupportMachine>(&mut self, machine: &mut Mac) -> Result<(), Error> {
45            let fd = machine.registers()[A0].to_i32();
46            if (fd >= 0 && fd <= 2) && self.keep_stdios {
47                machine.set_register(A0, Mac::REG::zero());
48                return Ok(());
49            }
50            let ret = match nix::unistd::close(fd) {
51                Ok(()) => 0,
52                Err(e) => {
53                    println!("Error: {:?}", e);
54                    (-1i64) as u64
55                }
56            };
57            machine.set_register(A0, Mac::REG::from_u64(ret));
58            Ok(())
59        }
60
61        fn fstat<Mac: SupportMachine>(&mut self, machine: &mut Mac) -> Result<(), Error> {
62            let stat = match nix::sys::stat::fstat(unsafe { BorrowedFd::borrow_raw(machine.registers()[A0].to_i32()) })
63            {
64                Ok(stat) => stat,
65                Err(e) => {
66                    println!("Error: {:?}", e);
67                    machine.set_register(A0, Mac::REG::from_i8(-1));
68                    return Ok(());
69                }
70            };
71            let mut abi_stat = AbiStat::default();
72            abi_stat.dev = stat.st_dev as u64;
73            abi_stat.ino = stat.st_ino;
74            abi_stat.mode = stat.st_mode as u32;
75            abi_stat.nlink = stat.st_nlink as i32;
76            abi_stat.uid = stat.st_uid;
77            abi_stat.gid = stat.st_gid;
78            abi_stat.rdev = stat.st_rdev as u64;
79            abi_stat.size = stat.st_size;
80            abi_stat.blksize = stat.st_blksize as i32;
81            abi_stat.blocks = stat.st_blocks;
82            abi_stat.atime = stat.st_atime;
83            abi_stat.atime_nsec = stat.st_atime_nsec;
84            abi_stat.mtime = stat.st_mtime;
85            abi_stat.mtime_nsec = stat.st_mtime_nsec;
86            abi_stat.ctime = stat.st_ctime;
87            abi_stat.ctime_nsec = stat.st_ctime_nsec;
88            let len = std::mem::size_of::<AbiStat>();
89            let b: &[u8] = unsafe { std::slice::from_raw_parts(&abi_stat as *const AbiStat as *const u8, len) };
90            let addr = machine.registers()[A1].to_u64();
91            machine.memory_mut().store_bytes(addr, b)?;
92            machine.set_register(A0, Mac::REG::zero());
93            Ok(())
94        }
95
96        fn lseek<Mac: SupportMachine>(&mut self, machine: &mut Mac) -> Result<(), Error> {
97            let fd = machine.registers()[A0].to_i32();
98            let offset = machine.registers()[A1].to_i64();
99            let whence = match machine.registers()[A2].to_i32() {
100                libc::SEEK_SET => nix::unistd::Whence::SeekSet,
101                libc::SEEK_CUR => nix::unistd::Whence::SeekCur,
102                libc::SEEK_END => nix::unistd::Whence::SeekEnd,
103                _ => return Err(Error::Unexpected("Unexpected whence".into())),
104            };
105            let ret = nix::unistd::lseek(unsafe { BorrowedFd::borrow_raw(fd) }, offset, whence).unwrap_or_else(|e| {
106                println!("Error: {:?}", e);
107                -1
108            });
109            machine.set_register(A0, Mac::REG::from_i64(ret));
110            Ok(())
111        }
112
113        fn read<Mac: SupportMachine>(&mut self, machine: &mut Mac) -> Result<(), Error> {
114            let fd = machine.registers()[A0].to_i32();
115            let addr = machine.registers()[A1].to_u64();
116            let size = machine.registers()[A2].to_u64() as usize;
117            let mut buf = vec![0u8; size];
118
119            match nix::unistd::read(unsafe { BorrowedFd::borrow_raw(fd) }, &mut buf) {
120                Ok(read_size) => {
121                    machine.memory_mut().store_bytes(addr, &buf[0..read_size])?;
122                    machine.set_register(A0, Mac::REG::from_u64(read_size as u64));
123                }
124                Err(e) => {
125                    println!("Error: {:?}", e);
126                    machine.set_register(A0, Mac::REG::from_i64(-1i64));
127                }
128            };
129            Ok(())
130        }
131
132        fn write<Mac: SupportMachine>(&mut self, machine: &mut Mac) -> Result<(), Error> {
133            let fd = machine.registers()[A0].to_i32();
134            let addr = machine.registers()[A1].to_u64();
135            let size = machine.registers()[A2].to_u64() as usize;
136            let mut buf = vec![0u8; size];
137            for i in 0..size {
138                buf[i] = machine.memory_mut().load8(&Mac::REG::from_u64(addr + i as u64))?.to_u8();
139            }
140            let ret = nix::unistd::write(unsafe { BorrowedFd::borrow_raw(fd) }, &buf).unwrap_or_else(|e| {
141                println!("Error: {:?}", e);
142                (-1isize) as usize
143            });
144            machine.set_register(A0, Mac::REG::from_u64(ret as u64));
145            Ok(())
146        }
147
148        fn writev<Mac: SupportMachine>(&mut self, machine: &mut Mac) -> Result<(), Error> {
149            let fd = machine.registers()[A0].to_i32();
150            let iov = machine.registers()[A1].to_u64();
151            let iovcnt = machine.registers()[A2].to_u64();
152
153            let mut written = 0;
154            for i in 0..iovcnt {
155                let base = machine.memory_mut().load64(&Mac::REG::from_u64(iov + i * 16))?.to_u64();
156                let len = machine.memory_mut().load64(&Mac::REG::from_u64(iov + i * 16 + 8))?.to_u64();
157
158                let buf = machine.memory_mut().load_bytes(base, len)?;
159
160                written += match nix::unistd::write(unsafe { BorrowedFd::borrow_raw(fd) }, &buf) {
161                    Ok(w) => w as u64,
162                    Err(e) => {
163                        println!("Error: {:?}", e);
164                        machine.set_register(A0, Mac::REG::from_i64(-1));
165                        return Ok(());
166                    }
167                };
168            }
169            machine.set_register(A0, Mac::REG::from_u64(written));
170            Ok(())
171        }
172    }
173
174    impl<Mac: SupportMachine> Syscalls<Mac> for Stdio {
175        fn initialize(&mut self, _machine: &mut Mac) -> Result<(), Error> {
176            Ok(())
177        }
178
179        fn ecall(&mut self, machine: &mut Mac) -> Result<bool, Error> {
180            match machine.registers()[A7].to_u64() {
181                57 => self.close(machine)?,
182                62 => self.lseek(machine)?,
183                63 => self.read(machine)?,
184                64 => self.write(machine)?,
185                66 => self.writev(machine)?,
186                80 => self.fstat(machine)?,
187                _ => return Ok(false),
188            };
189            Ok(true)
190        }
191    }
192}
193
194#[cfg(any(target_family = "wasm", target_family = "windows"))]
195mod arch {
196    use ckb_vm::{Error, SupportMachine, Syscalls};
197
198    #[derive(Default)]
199    pub struct Stdio {}
200
201    impl Stdio {
202        pub fn new(_: bool) -> Self {
203            Stdio {}
204        }
205    }
206
207    impl<Mac: SupportMachine> Syscalls<Mac> for Stdio {
208        fn initialize(&mut self, _machine: &mut Mac) -> Result<(), Error> {
209            Ok(())
210        }
211
212        fn ecall(&mut self, _machine: &mut Mac) -> Result<bool, Error> {
213            Ok(false)
214        }
215    }
216}
217
218pub use arch::Stdio;