zinc64_debug/
rap_server.rs

1// This file is part of zinc64.
2// Copyright (c) 2016-2019 Sebastian Jastrzebski. All rights reserved.
3// Licensed under the GPLv3. See LICENSE file in the project root for full license text.
4
5#![cfg_attr(feature = "cargo-clippy", allow(clippy::cast_lossless))]
6
7use std::ffi::CStr;
8use std::io;
9use std::io::{BufReader, BufWriter, Error, ErrorKind, Read, Write};
10use std::net::{SocketAddr, TcpListener, TcpStream};
11use std::str;
12use std::sync::mpsc;
13use std::sync::mpsc::{Receiver, Sender};
14use std::u16;
15use std::u8;
16
17use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
18
19use super::{Command, Output};
20
21// SPEC: https://github.com/radare/radare2/blob/master/doc/rap
22// SPEC: https://github.com/radare/radare2/blob/master/libr/io/p/io_rap.c
23// SPEC: https://github.com/radare/radare2/blob/master/libr/socket/rap_server.c
24
25const RAP_RMT_MAX: u32 = 4096;
26
27const REG_PROFILE: &str = "
28=PC	pc
29=SP	sp
30gpr	a	.8	0	0
31gpr	x	.8	1	0
32gpr	y	.8	2	0
33gpr	p	.8	3	0
34gpr	C	.1	.24	0
35gpr	Z	.1	.25	0
36gpr	I	.1	.26	0
37gpr	D	.1	.27	0
38gpr	V	.1	.30	0
39gpr	N	.1	.31	0
40gpr	sp	.8	4	0
41gpr	pc	.16	5	0
42";
43
44#[derive(Clone, Copy)]
45enum RapCmd {
46    Registers,
47    RegisterProfile,
48}
49
50enum RapOp {
51    Open = 1,
52    Read = 2,
53    Write = 3,
54    Seek = 4,
55    Close = 5,
56    // System = 6,
57    Cmd = 7,
58    Reply = 0x80,
59}
60
61impl RapOp {
62    pub fn from(op: u8) -> Result<RapOp, String> {
63        match op {
64            1 => Ok(RapOp::Open),
65            2 => Ok(RapOp::Read),
66            3 => Ok(RapOp::Write),
67            4 => Ok(RapOp::Seek),
68            5 => Ok(RapOp::Close),
69            7 => Ok(RapOp::Cmd),
70            _ => Err(format!("Invalid op {}", op)),
71        }
72    }
73}
74
75pub struct RapServer {
76    command_tx: Sender<Command>,
77}
78
79impl RapServer {
80    pub fn new(command_tx: Sender<Command>) -> Self {
81        Self { command_tx }
82    }
83
84    pub fn start(&self, addr: SocketAddr) -> io::Result<()> {
85        let listener = TcpListener::bind(addr)?;
86        for stream in listener.incoming() {
87            if let Ok(stream) = stream {
88                let mut conn = Connection::build(self.command_tx.clone(), &stream).unwrap();
89                match conn.handle() {
90                    Ok(_) => info!(target: "debugger", "Connection closed"),
91                    Err(error) => {
92                        error!(target: "debugger", "Connection failed, error - {}", error)
93                    }
94                }
95            }
96        }
97        Ok(())
98    }
99}
100
101struct Connection {
102    command_parser: CommandParser,
103    // I/O
104    reader: BufReader<TcpStream>,
105    writer: BufWriter<TcpStream>,
106    command_tx: Sender<Command>,
107    response_rx: Receiver<Output>,
108    response_tx: Sender<Output>,
109    // Runtime State
110    offset: u16,
111    running: bool,
112}
113
114impl Connection {
115    pub fn build(command_tx: Sender<Command>, stream: &TcpStream) -> io::Result<Self> {
116        let reader = BufReader::new(stream.try_clone()?);
117        let writer = BufWriter::new(stream.try_clone()?);
118        let (response_tx, response_rx) = mpsc::channel::<Output>();
119        let conn = Self {
120            command_parser: CommandParser::new(),
121            reader,
122            writer,
123            command_tx,
124            response_rx,
125            response_tx,
126            offset: 0,
127            running: true,
128        };
129        Ok(conn)
130    }
131
132    pub fn handle(&mut self) -> io::Result<()> {
133        while self.running {
134            let opcode = self.reader.read_u8()?;
135            let op = RapOp::from(opcode).map_err(|e| Error::new(ErrorKind::Other, e))?;
136            match op {
137                RapOp::Open => self.handle_open(),
138                RapOp::Read => self.handle_read(),
139                RapOp::Write => self.handle_write(),
140                RapOp::Seek => self.handle_seek(),
141                RapOp::Close => self.handle_close(),
142                RapOp::Cmd => self.handle_cmd(),
143                _ => Ok(()),
144            }?;
145        }
146        Ok(())
147    }
148
149    fn handle_cmd(&mut self) -> io::Result<()> {
150        let len = self.reader.read_u32::<BigEndian>()?;
151        let mut data = vec![0; len as usize];
152        self.reader.read_exact(&mut data)?;
153        let c_str = CStr::from_bytes_with_nul(&data).unwrap();
154        let input = str::from_utf8(c_str.to_bytes())
155            .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?;
156        let input = input.to_string();
157        info!(target: "rap", "Cmd '{}'", input);
158        let result = match self.command_parser.parse(&input) {
159            Ok(command) => self.execute_cmd(command),
160            Err(error) => Ok(error),
161        }?;
162        info!(target: "rap", "Cmd result len {}", result.len());
163        self.writer
164            .write_u8(RapOp::Cmd as u8 | RapOp::Reply as u8)?;
165        self.writer
166            .write_u32::<BigEndian>((result.len() + 1) as u32)?;
167        if !result.is_empty() {
168            self.writer.write_all(&result.as_bytes())?;
169            self.writer.write_u8(0)?;
170        }
171        self.writer.flush()
172    }
173
174    fn handle_close(&mut self) -> io::Result<()> {
175        let _fd = self.reader.read_u32::<BigEndian>()?;
176        match self.execute_emu(Command::Detach)? {
177            Output::Unit => Ok(()),
178            result => Err(self.invalid_response(&result)),
179        }?;
180        self.running = false;
181        self.writer
182            .write_u8(RapOp::Close as u8 | RapOp::Reply as u8)?;
183        self.writer.write_u32::<BigEndian>(0)?;
184        self.writer.flush()
185    }
186
187    fn handle_open(&mut self) -> io::Result<()> {
188        let _rw_flag = self.reader.read_u8()?;
189        let len = self.reader.read_u8()?;
190        let mut data = vec![0; len as usize];
191        self.reader.read_exact(&mut data)?;
192        let tx = self.response_tx.clone();
193        match self.execute_emu(Command::Attach(tx))? {
194            Output::Unit => Ok(()),
195            result => Err(self.invalid_response(&result)),
196        }?;
197        self.writer
198            .write_u8(RapOp::Open as u8 | RapOp::Reply as u8)?;
199        self.writer.write_u32::<BigEndian>(1000)?;
200        self.writer.flush()
201    }
202
203    fn handle_read(&mut self) -> io::Result<()> {
204        let mut len = self.reader.read_u32::<BigEndian>()?;
205        if len > RAP_RMT_MAX {
206            len = RAP_RMT_MAX;
207        }
208        info!(target: "rap", "Read 0x{:04x} {}", self.offset, len);
209        let start = self.offset;
210        let end = self.offset.wrapping_add(len as u16);
211        let command = Command::MemRead(start, end);
212        let data = match self.execute_emu(command)? {
213            Output::Buffer(data) => Ok(data),
214            result => Err(self.invalid_response(&result)),
215        }?;
216        self.writer
217            .write_u8(RapOp::Read as u8 | RapOp::Reply as u8)?;
218        self.writer.write_u32::<BigEndian>(data.len() as u32)?;
219        self.writer.write_all(&data)?;
220        self.writer.flush()
221    }
222
223    fn handle_seek(&mut self) -> io::Result<()> {
224        let whence = self.reader.read_u8()?;
225        let offset = self.reader.read_u64::<BigEndian>()? as u16;
226        info!(target: "rap", "Seek {} 0x{:04x}", whence, offset);
227        self.offset = match whence {
228            0 => offset,
229            1 => self.offset.wrapping_add(offset),
230            2 => (0xffff_u16).wrapping_add(offset),
231            _ => self.offset,
232        };
233        self.writer
234            .write_u8(RapOp::Seek as u8 | RapOp::Reply as u8)?;
235        self.writer.write_u64::<BigEndian>(self.offset as u64)?;
236        self.writer.flush()
237    }
238
239    fn handle_write(&mut self) -> io::Result<()> {
240        let mut len = self.reader.read_u32::<BigEndian>()?;
241        if len > RAP_RMT_MAX {
242            len = RAP_RMT_MAX;
243        }
244        info!(target: "rap", "Write 0x{:04x} {}", self.offset, len);
245        let mut data = vec![0; len as usize];
246        self.reader.read_exact(&mut data)?;
247        let command = Command::MemWrite(self.offset, data);
248        match self.execute_emu(command)? {
249            Output::Unit => Ok(()),
250            result => Err(self.invalid_response(&result)),
251        }?;
252        self.writer
253            .write_u8(RapOp::Write as u8 | RapOp::Reply as u8)?;
254        self.writer.write_u32::<BigEndian>(len)?;
255        self.writer.flush()
256    }
257
258    fn invalid_response(&self, _result: &Output) -> Error {
259        Error::new(ErrorKind::Other, "Invalid debugger result")
260    }
261
262    // -- Commands
263
264    fn cmd_registers(&mut self) -> io::Result<String> {
265        match self.execute_emu(Command::RegRead)? {
266            Output::Registers(regs) => {
267                let mut buffer = String::new();
268                buffer.push_str(format!("a = 0x{:02x}\n", regs.a).as_str());
269                buffer.push_str(format!("x = 0x{:02x}\n", regs.x).as_str());
270                buffer.push_str(format!("y = 0x{:02x}\n", regs.y).as_str());
271                buffer.push_str(format!("p = 0x{:02x}\n", regs.p).as_str());
272                buffer.push_str(format!("sp = 0x{:02x}\n", regs.sp).as_str());
273                buffer.push_str(format!("pc = 0x{:04x}\n", regs.pc).as_str());
274                Ok(buffer)
275            }
276            other => Err(self.invalid_response(&other)),
277        }
278    }
279
280    fn cmd_register_profile(&mut self) -> io::Result<String> {
281        Ok(REG_PROFILE.to_string())
282    }
283
284    // -- Execution
285
286    fn execute_cmd(&mut self, command: RapCmd) -> io::Result<String> {
287        match command {
288            RapCmd::Registers => self.cmd_registers(),
289            RapCmd::RegisterProfile => self.cmd_register_profile(),
290        }
291    }
292
293    fn execute_emu(&mut self, command: Command) -> io::Result<Output> {
294        self.command_tx.send(command).unwrap();
295        match self.response_rx.recv() {
296            Ok(Output::Error(error)) => Err(Error::new(ErrorKind::Other, error)),
297            Ok(result) => Ok(result),
298            Err(error) => Err(Error::new(ErrorKind::Other, error)),
299        }
300    }
301}
302
303struct CommandParser {
304    radix: u32,
305}
306
307impl CommandParser {
308    pub fn new() -> Self {
309        Self { radix: 16 }
310    }
311
312    pub fn parse(&self, input: &str) -> Result<RapCmd, String> {
313        let mut tokens = input.split_whitespace();
314        if let Some(command) = tokens.next() {
315            match command.to_lowercase().as_str() {
316                "dr" => self.parse_registers(&mut tokens),
317                "drp" => self.parse_register_profile(&mut tokens),
318                _ => Err(format!("Invalid command {}", input)),
319            }
320        } else {
321            Err(format!("Invalid command {}", input))
322        }
323    }
324
325    fn parse_registers(&self, tokens: &mut dyn Iterator<Item = &str>) -> Result<RapCmd, String> {
326        self.ensure_eos(tokens)?;
327        Ok(RapCmd::Registers)
328    }
329
330    fn parse_register_profile(
331        &self,
332        tokens: &mut dyn Iterator<Item = &str>,
333    ) -> Result<RapCmd, String> {
334        self.ensure_eos(tokens)?;
335        Ok(RapCmd::RegisterProfile)
336    }
337
338    // Helpers
339
340    fn ensure_eos(&self, tokens: &mut dyn Iterator<Item = &str>) -> Result<(), String> {
341        match tokens.next() {
342            Some(token) => Err(format!("Invalid token {}", token)),
343            None => Ok(()),
344        }
345    }
346
347    #[allow(dead_code)]
348    fn parse_num(&self, input: Option<&str>) -> Result<u16, String> {
349        if let Some(value) = input {
350            u16::from_str_radix(value, self.radix).map_err(|_| format!("invalid number {}", value))
351        } else {
352            Err("missing argument".to_string())
353        }
354    }
355
356    #[allow(dead_code)]
357    fn parse_num_maybe(&self, input: Option<&str>) -> Result<Option<u16>, String> {
358        if let Some(value) = input {
359            let result = u16::from_str_radix(value, self.radix)
360                .map_err(|_| format!("invalid number {}", value))?;
361            Ok(Some(result))
362        } else {
363            Ok(None)
364        }
365    }
366}