ckb_debugger/
syscall_file_operation.rs

1#[cfg(any(target_family = "unix", target_family = "windows"))]
2mod arch {
3    use ckb_vm::{Error, SupportMachine, Syscalls};
4    use ckb_vm::{
5        Memory, Register,
6        registers::{A0, A1, A2, A3, A7},
7    };
8    use libc::{
9        FILE, c_char, c_int, c_long, c_void, fclose, feof, ferror, fgetc, fopen, fread, freopen, fseek, ftell, fwrite,
10        size_t,
11    };
12    use std::ffi::CString;
13
14    const SYSCALL_NUMBER_FOPEN: u64 = 9003;
15    const SYSCALL_NUMBER_FREOPEN: u64 = 9004;
16    const SYSCALL_NUMBER_FREAD: u64 = 9005;
17    const SYSCALL_NUMBER_FEOF: u64 = 9006;
18    const SYSCALL_NUMBER_FERROR: u64 = 9007;
19    const SYSCALL_NUMBER_FGETC: u64 = 9008;
20    const SYSCALL_NUMBER_FCLOSE: u64 = 9009;
21    const SYSCALL_NUMBER_FTELL: u64 = 9010;
22    const SYSCALL_NUMBER_FSEEK: u64 = 9011;
23    const SYSCALL_NUMBER_FWRITE: u64 = 9012;
24
25    pub struct FileOperation {}
26
27    impl FileOperation {
28        pub fn new() -> Self {
29            Self {}
30        }
31    }
32
33    impl<Mac: SupportMachine> Syscalls<Mac> for FileOperation {
34        fn initialize(&mut self, _machine: &mut Mac) -> Result<(), Error> {
35            Ok(())
36        }
37
38        fn ecall(&mut self, machine: &mut Mac) -> Result<bool, Error> {
39            let id = machine.registers()[A7].to_u64();
40            let arg0 = machine.registers()[A0].to_u64();
41            let arg1 = machine.registers()[A1].to_u64();
42            let arg2 = machine.registers()[A2].to_u64();
43            let arg3 = machine.registers()[A3].to_u64();
44
45            match id {
46                SYSCALL_NUMBER_FOPEN => {
47                    let path = CString::new(ckb_vm::memory::load_c_string_byte_by_byte(
48                        machine.memory_mut(),
49                        &Mac::REG::from_u64(arg0),
50                    )?)
51                    .expect("Invalid C string");
52                    let mode = CString::new(ckb_vm::memory::load_c_string_byte_by_byte(
53                        machine.memory_mut(),
54                        &Mac::REG::from_u64(arg1),
55                    )?)
56                    .expect("Invalid C string");
57                    let handler = unsafe {
58                        fopen(
59                            path.as_bytes_with_nul().as_ptr() as *const c_char,
60                            mode.as_bytes_with_nul().as_ptr() as *const c_char,
61                        )
62                    };
63                    machine.set_register(A0, Mac::REG::from_u64(handler as u64));
64                }
65                SYSCALL_NUMBER_FREOPEN => {
66                    let path = CString::new(ckb_vm::memory::load_c_string_byte_by_byte(
67                        machine.memory_mut(),
68                        &Mac::REG::from_u64(arg0),
69                    )?)
70                    .expect("Invalid C string");
71                    let mode = CString::new(ckb_vm::memory::load_c_string_byte_by_byte(
72                        machine.memory_mut(),
73                        &Mac::REG::from_u64(arg1),
74                    )?)
75                    .expect("Invalid C string");
76                    let stream = arg2;
77                    let handler = unsafe {
78                        freopen(
79                            path.as_bytes_with_nul().as_ptr() as *const c_char,
80                            mode.as_bytes_with_nul().as_ptr() as *const c_char,
81                            stream as *mut FILE,
82                        )
83                    };
84                    machine.set_register(A0, Mac::REG::from_u64(handler as u64));
85                }
86                SYSCALL_NUMBER_FREAD => {
87                    let ptr = arg0;
88                    let size = arg1;
89                    let nitems = arg2;
90                    let stream = arg3;
91                    let total_size = nitems * size;
92                    if total_size > 3 * 1024 * 1024 {
93                        panic!("Too much memory to read");
94                    }
95                    let buf = vec![0u8; total_size as usize];
96                    let read_count = unsafe {
97                        fread(buf.as_ptr() as *mut c_void, size as size_t, nitems as size_t, stream as *mut FILE)
98                    };
99                    machine.memory_mut().store_bytes(ptr, &buf[0..read_count * size as usize])?;
100                    machine.set_register(A0, Mac::REG::from_u64(read_count as u64));
101                }
102                SYSCALL_NUMBER_FEOF => {
103                    let eof = unsafe { feof(arg0 as *mut FILE) };
104                    machine.set_register(A0, Mac::REG::from_i32(eof));
105                }
106                SYSCALL_NUMBER_FERROR => {
107                    let error = unsafe { ferror(arg0 as *mut FILE) };
108                    machine.set_register(A0, Mac::REG::from_i32(error));
109                }
110                SYSCALL_NUMBER_FGETC => {
111                    let ch = unsafe { fgetc(arg0 as *mut FILE) };
112                    machine.set_register(A0, Mac::REG::from_i32(ch));
113                }
114                SYSCALL_NUMBER_FCLOSE => {
115                    let ret = unsafe { fclose(arg0 as *mut FILE) };
116                    machine.set_register(A0, Mac::REG::from_i32(ret));
117                }
118                SYSCALL_NUMBER_FTELL => {
119                    let pos = unsafe { ftell(arg0 as *mut FILE) };
120                    machine.set_register(A0, Mac::REG::from_i64(pos.into()));
121                }
122                SYSCALL_NUMBER_FSEEK => {
123                    let ret = unsafe { fseek(arg0 as *mut FILE, arg1 as c_long, arg2 as c_int) };
124                    machine.set_register(A0, Mac::REG::from_i32(ret));
125                }
126                SYSCALL_NUMBER_FWRITE => {
127                    let ptr = arg0;
128                    let size = arg1;
129                    let nitems = arg2;
130                    let stream = arg3;
131                    let total_size = nitems * size;
132                    if total_size > 3 * 1024 * 1024 {
133                        panic!("Too much memory to write");
134                    }
135                    let buf = machine.memory_mut().load_bytes(ptr, total_size)?;
136                    let write_count = unsafe {
137                        fwrite(buf.as_ptr() as *mut c_void, size as size_t, nitems as size_t, stream as *mut FILE)
138                    };
139                    machine.set_register(A0, Mac::REG::from_u64(write_count as u64));
140                }
141                _ => {
142                    return Ok(false);
143                }
144            }
145            Ok(true)
146        }
147    }
148}
149
150#[cfg(target_family = "wasm")]
151mod arch {
152    use ckb_vm::{Error, SupportMachine, Syscalls};
153
154    #[derive(Default)]
155    pub struct FileOperation {}
156
157    impl FileOperation {
158        pub fn new() -> Self {
159            FileOperation {}
160        }
161    }
162
163    impl<Mac: SupportMachine> Syscalls<Mac> for FileOperation {
164        fn initialize(&mut self, _machine: &mut Mac) -> Result<(), Error> {
165            Ok(())
166        }
167
168        fn ecall(&mut self, _machine: &mut Mac) -> Result<bool, Error> {
169            Ok(false)
170        }
171    }
172}
173
174pub use arch::FileOperation;