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