ckb_debugger/
syscall_file_operation.rs1#[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;