Skip to main content

gdb_remote_protocol_debugger/
gdb_remote_protocol_debugger.rs

1#[macro_use]
2extern crate log;
3
4use bytes::Bytes;
5use ckb_vm::machine::VERSION2;
6use ckb_vm::{
7    DefaultCoreMachine, DefaultMachineBuilder, ISA_A, ISA_B, ISA_IMC, ISA_MOP, SparseMemory, SupportMachine,
8    WXorXMemory,
9};
10#[cfg(feature = "stdio")]
11use ckb_vm_debug_utils::Stdio;
12use ckb_vm_debug_utils::{GdbStubHandler, GdbStubHandlerEventLoop};
13use gdbstub::conn::ConnectionExt;
14use gdbstub::stub::{DisconnectReason, GdbStub};
15use gdbstub_arch::riscv::Riscv64;
16use std::env;
17use std::fs::File;
18use std::io::Read;
19use std::net::TcpListener;
20
21fn main() {
22    let _ = env_logger::init();
23    let args: Vec<String> = env::args().skip(1).collect();
24
25    let listener = TcpListener::bind(&args[0]).expect("listen");
26    debug!("Listening on {}", args[0]);
27
28    let mut file = File::open(&args[1]).expect("open program");
29    let mut buffer = Vec::new();
30    file.read_to_end(&mut buffer).unwrap();
31    let program: Bytes = buffer.into();
32    let program_args: Vec<Bytes> = args.into_iter().skip(1).map(|a| a.into()).collect();
33
34    for res in listener.incoming() {
35        debug!("Got connection");
36        if let Ok(stream) = res {
37            // TODO: vm version and isa should be configurable in the future.
38            let machine_core = DefaultCoreMachine::<u64, WXorXMemory<SparseMemory<u64>>>::new(
39                ISA_IMC | ISA_A | ISA_B | ISA_MOP,
40                VERSION2,
41                u64::max_value(),
42            );
43            let machine_builder = DefaultMachineBuilder::new(machine_core);
44            #[cfg(feature = "stdio")]
45            let mut machine = machine_builder.syscall(Box::new(Stdio::new(true))).build();
46            #[cfg(not(feature = "stdio"))]
47            let mut machine = machine_builder.build();
48            machine.load_program(&program, program_args.iter().cloned().map(Ok)).expect("load program");
49            machine.set_running(true);
50            let mut h = GdbStubHandler::<_, Riscv64>::new(machine);
51            let connection: Box<dyn ConnectionExt<Error = std::io::Error>> = Box::new(stream);
52            let gdb = GdbStub::new(connection);
53            match gdb.run_blocking::<GdbStubHandlerEventLoop<_, Riscv64>>(&mut h) {
54                Ok(DisconnectReason::Disconnect) => {
55                    debug!("GDB client disconnected, running to completion");
56                    let _ = h.run_till_exited();
57                }
58                Ok(DisconnectReason::TargetExited(_)) => {
59                    let _ = h.run_till_exited();
60                }
61                Ok(reason) => {
62                    debug!("GDB session ended: {:?}", reason);
63                }
64                Err(e) => {
65                    debug!("GDB stub error: {}", e);
66                }
67            }
68        }
69        debug!("Connection closed");
70    }
71}