ckb_vm_debug_utils/
elf_dumper.rs1use byteorder::{ByteOrder, LittleEndian};
2use bytes::{BufMut, Bytes, BytesMut};
3use ckb_vm::{
4 Error, Memory, RISCV_PAGES, RISCV_PAGESIZE, Register, SupportMachine, Syscalls,
5 memory::{FLAG_EXECUTABLE, FLAG_WXORX_BIT},
6 registers::A7,
7};
8use std::fs::File;
9use std::io::Write;
10
11pub struct ElfDumper {
12 dump_file_name: String,
13 syscall_number: u64,
14 maximum_zero_gap: u64,
15}
16
17impl Default for ElfDumper {
18 fn default() -> ElfDumper {
19 ElfDumper { dump_file_name: "dump.bin".to_string(), syscall_number: 4097, maximum_zero_gap: 64 }
20 }
21}
22
23impl ElfDumper {
24 pub fn new(dump_file_name: String, syscall_number: u64, maximum_zero_gap: u64) -> Self {
25 ElfDumper { dump_file_name, syscall_number, maximum_zero_gap }
26 }
27}
28
29#[derive(Clone)]
30struct Segment {
31 start: u64,
32 data: Bytes,
33 executable: bool,
34}
35
36impl Segment {
37 fn first_page(&self) -> u64 {
38 self.start / RISCV_PAGESIZE as u64
39 }
40
41 fn first_page_address(&self) -> u64 {
42 self.first_page() * RISCV_PAGESIZE as u64
43 }
44
45 fn last_page(&self) -> u64 {
46 (self.start + self.data.len() as u64 - 1) / RISCV_PAGESIZE as u64
47 }
48}
49
50impl<Mac: SupportMachine> Syscalls<Mac> for ElfDumper {
51 fn initialize(&mut self, _machine: &mut Mac) -> Result<(), Error> {
52 Ok(())
53 }
54
55 fn ecall(&mut self, machine: &mut Mac) -> Result<bool, Error> {
56 if machine.registers()[A7].to_u64() != self.syscall_number {
57 return Ok(false);
58 }
59 let mut segments: Vec<Segment> = vec![];
60 let mut page = 0;
61 while page < RISCV_PAGES as u64 {
63 let mut start = page * RISCV_PAGESIZE as u64;
64 let end = (page + 1) * RISCV_PAGESIZE as u64;
65
66 while start < end {
67 while start < end {
69 if machine.memory_mut().load64(&Mac::REG::from_u64(start))?.to_u64() != 0 {
70 break;
71 }
72 start += 8;
73 }
74
75 if start < end {
76 let executable = machine.memory_mut().fetch_flag(page)? & FLAG_WXORX_BIT == FLAG_EXECUTABLE;
78 let (bytes_start, mut bytes_mut) = if segments.is_empty() {
79 (start, BytesMut::new())
80 } else {
81 let last_segment = &segments[segments.len() - 1];
82 let same_page = page == last_segment.last_page();
83 let gap = start - (last_segment.start + last_segment.data.len() as u64);
84 if last_segment.executable == executable && ((gap <= self.maximum_zero_gap) || same_page) {
85 let Segment { start: segment_start, data: segment_data, .. } =
86 segments.remove(segments.len() - 1);
87 let mut segment_data = BytesMut::from(segment_data.as_ref());
88 let mut zeros = vec![];
90 zeros.resize(gap as usize, 0);
91 segment_data.extend_from_slice(&zeros);
92 (segment_start, segment_data)
93 } else {
94 (start, BytesMut::new())
95 }
96 };
97
98 while start < end {
100 let value = machine.memory_mut().load64(&Mac::REG::from_u64(start))?.to_u64();
101 if value == 0 {
102 break;
103 }
104
105 bytes_mut.put_u64_le(value);
106 start += 8;
107 }
108
109 segments.push(Segment { start: bytes_start, data: bytes_mut.freeze(), executable });
110 }
111 }
112 page += 1;
113 }
114 if segments.is_empty() || segments[0].start <= RISCV_PAGESIZE as u64 {
117 return Err(Error::Unexpected("Unexpected segments".into()));
118 }
119
120 let mut register_buffer = BytesMut::new();
122 for register_value in &machine.registers()[1..] {
123 register_buffer.put_u64_le(register_value.to_u64());
124 }
125 let register_entrypoint = register_buffer.len() as u64;
126 register_buffer.put_u32_le(0x00000517); register_buffer.put_u32_le(0xf0050513); register_buffer.put_u32_le(0x00853083); register_buffer.put_u32_le(0x01053103); register_buffer.put_u32_le(0x01853183); register_buffer.put_u32_le(0x02053203); register_buffer.put_u32_le(0x02853283); register_buffer.put_u32_le(0x03053303); register_buffer.put_u32_le(0x03853383); register_buffer.put_u32_le(0x04053403); register_buffer.put_u32_le(0x04853483); register_buffer.put_u32_le(0x05853583); register_buffer.put_u32_le(0x06053603); register_buffer.put_u32_le(0x06853683); register_buffer.put_u32_le(0x07053703); register_buffer.put_u32_le(0x07853783); register_buffer.put_u32_le(0x08053803); register_buffer.put_u32_le(0x08853883); register_buffer.put_u32_le(0x09053903); register_buffer.put_u32_le(0x09853983); register_buffer.put_u32_le(0x0a053a03); register_buffer.put_u32_le(0x0a853a83); register_buffer.put_u32_le(0x0b053b03); register_buffer.put_u32_le(0x0b853b83); register_buffer.put_u32_le(0x0c053c03); register_buffer.put_u32_le(0x0c853c83); register_buffer.put_u32_le(0x0d053d03); register_buffer.put_u32_le(0x0d853d83); register_buffer.put_u32_le(0x0e053e03); register_buffer.put_u32_le(0x0e853e83); register_buffer.put_u32_le(0x0f053f03); register_buffer.put_u32_le(0x0f853f83); register_buffer.put_u32_le(0x05053503); let register_buffer_start = segments[0].first_page_address() - RISCV_PAGESIZE as u64;
161 let jump_instruction_pc = register_buffer_start + register_buffer.len() as u64;
162 let jump_offset = machine.pc().to_u64() - jump_instruction_pc;
163 let masked = jump_offset & 0xFFFFFFFFFFE00001;
164 if masked != 0 && masked != 0xFFFFFFFFFFE00000 {
165 return Err(Error::Unexpected("Unexpected masked".into()));
166 }
167 let jump_instruction = 0b1101111
168 | ((((jump_offset >> 12) & 0b_1111_1111) as u32) << 12)
169 | ((((jump_offset >> 11) & 1) as u32) << 20)
170 | ((((jump_offset >> 1) & 0b_1111_1111_11) as u32) << 21)
171 | ((((jump_offset >> 20) & 1) as u32) << 31);
172 register_buffer.put_u32_le(jump_instruction);
173 assert!(register_buffer.len() < RISCV_PAGESIZE);
174
175 segments.push(Segment { start: register_buffer_start, data: register_buffer.freeze(), executable: true });
176
177 let mut elf = BytesMut::new();
179 elf.extend_from_slice(&[
181 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
182 ]);
183 elf.put_u16_le(2);
185 elf.put_u16_le(243);
187 elf.put_u32_le(1);
189 elf.put_u64_le(register_buffer_start + register_entrypoint);
191 let program_header_offset = elf.len();
192 elf.put_u64_le(0);
194 let section_header_offset = elf.len();
195 elf.put_u64_le(0);
197 elf.put_u32_le(1);
199 elf.put_u16_le(64);
201 elf.put_u16_le(56);
203 let program_header_number_offset = elf.len();
204 elf.put_u16_le(0);
206 elf.put_u16_le(64);
208 let section_header_number_offset = elf.len();
209 elf.put_u16_le(0);
211 elf.put_u16_le(0);
213 assert!(elf.len() == 64);
214
215 let string_table_offset = elf.len() as u64;
216 elf.put_u32_le(0);
217
218 let mut section_headers = vec![];
219 let mut string_table_section_header = BytesMut::new();
220 string_table_section_header.put_u32_le(0);
222 string_table_section_header.put_u32_le(3);
224 string_table_section_header.put_u64_le(0);
226 string_table_section_header.put_u64_le(0);
228 string_table_section_header.put_u64_le(string_table_offset);
230 string_table_section_header.put_u64_le(4);
232 string_table_section_header.put_u32_le(0);
234 string_table_section_header.put_u32_le(0);
236 string_table_section_header.put_u64_le(1);
238 string_table_section_header.put_u64_le(0);
240 assert!(string_table_section_header.len() == 64);
241 section_headers.push(string_table_section_header.freeze());
242
243 let mut program_headers = vec![];
244
245 for segment in segments {
246 let current_offset = elf.len() as u64;
247 elf.extend_from_slice(segment.data.as_ref());
248
249 let mut program_header = BytesMut::new();
250 program_header.put_u32_le(1);
252 program_header.put_u32_le(if segment.executable { 5 } else { 6 });
254 program_header.put_u64_le(current_offset);
256 program_header.put_u64_le(segment.start);
258 program_header.put_u64_le(segment.start);
260 program_header.put_u64_le(segment.data.len() as u64);
262 program_header.put_u64_le(segment.data.len() as u64);
264 program_header.put_u64_le(0x1000);
266 assert!(program_header.len() == 56);
267 program_headers.push(program_header.freeze());
268
269 if segment.executable {
273 let mut section_header = BytesMut::new();
274 section_header.put_u32_le(0);
276 section_header.put_u32_le(1);
278 section_header.put_u64_le(6);
280 section_header.put_u64_le(segment.start);
282 section_header.put_u64_le(current_offset);
284 section_header.put_u64_le(segment.data.len() as u64);
286 section_header.put_u32_le(0);
288 section_header.put_u32_le(0);
290 section_header.put_u64_le(2);
292 section_header.put_u64_le(0);
294 assert!(section_header.len() == 64);
295 section_headers.push(section_header.freeze());
296 }
297 }
298
299 while elf.len() % 4 != 0 {
300 elf.put_u8(0);
301 }
302 let current_offset = elf.len() as u64;
303 LittleEndian::write_u64(&mut elf[program_header_offset..program_header_offset + 8], current_offset);
304 LittleEndian::write_u16(
305 &mut elf[program_header_number_offset..program_header_number_offset + 8],
306 program_headers.len() as u16,
307 );
308 for program_header in program_headers {
309 elf.extend_from_slice(program_header.as_ref());
310 }
311
312 while elf.len() % 4 != 0 {
313 elf.put_u8(0);
314 }
315 let current_offset = elf.len() as u64;
316 LittleEndian::write_u64(&mut elf[section_header_offset..section_header_offset + 8], current_offset);
317 LittleEndian::write_u16(
318 &mut elf[section_header_number_offset..section_header_number_offset + 8],
319 section_headers.len() as u16,
320 );
321 for section_header in section_headers {
322 elf.extend_from_slice(section_header.as_ref());
323 }
324
325 let mut file = File::create(&self.dump_file_name)?;
326 file.write_all(&elf)?;
327
328 Ok(true)
329 }
330}