1#![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
21const 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 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 reader: BufReader<TcpStream>,
105 writer: BufWriter<TcpStream>,
106 command_tx: Sender<Command>,
107 response_rx: Receiver<Output>,
108 response_tx: Sender<Output>,
109 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 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 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 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}