cargo_drone/
itm.rs

1//! ITM parser.
2
3use colored::*;
4use failure::{err_msg, Error};
5use libc;
6use std::ffi::CString;
7use std::fs::{self, File};
8use std::io::{self, Read, Write};
9use std::os::unix::ffi::OsStringExt;
10use std::path::PathBuf;
11use std::thread;
12use std::time::Duration;
13
14/// ITM overflow error.
15#[derive(Fail, Debug)]
16#[fail(display = "ITM Overflow")]
17pub struct Overflow;
18
19/// Creates a new named pipe with given `name`.
20pub fn create_pipe(name: &str) -> Result<(), Error> {
21  let pipe = PathBuf::from(name);
22  if pipe.exists() {
23    fs::remove_file(&pipe)?;
24  }
25  let pipe = pipe.clone().into_os_string().into_vec();
26  let result = unsafe { libc::mkfifo(CString::new(pipe)?.as_ptr(), 0o644) };
27  if result != 0 {
28    Err(err_msg("Failed to create a FIFO"))?;
29  }
30  Ok(())
31}
32
33/// Opens a pipe, and runs a read loop.
34pub fn run_loop(pipe: &str, port: u8, debug: bool) -> Result<(), Error> {
35  let mut stream = io::BufReader::new(File::open(pipe)?);
36  let mut buffer = [0; 4];
37  loop {
38    match read(&mut stream, &mut buffer, port, debug) {
39      Ok(Some(payload)) => {
40        if debug {
41          for byte in payload {
42            print!("{:?} ", *byte as char);
43          }
44          println!();
45        } else {
46          io::stdout().write_all(payload)?;
47          io::stdout().flush()?;
48        }
49      }
50      Ok(None) => {
51        if debug {
52          println!("{}", "[IGN]".yellow());
53        }
54      }
55      Err(err) => {
56        if err.downcast_ref::<Overflow>().is_some() {
57          writeln!(io::stderr(), "{}", "[OFLW]".bold().white().on_red())?;
58        } else if let Some(err) = err.downcast_ref::<io::Error>() {
59          match err.kind() {
60            io::ErrorKind::UnexpectedEof => {
61              writeln!(io::stderr(), "{}", "[EOF]".red())?;
62              thread::sleep(Duration::from_millis(100));
63            }
64            kind => {
65              let message = format!("[IO: {:?}]", kind);
66              writeln!(io::stderr(), "{}", message.red())?;
67            }
68          }
69        }
70      }
71    }
72  }
73}
74
75/// Reads a packet from ITM stream.
76fn read<'a, 'b>(
77  stream: &'a mut io::BufReader<File>,
78  buffer: &'b mut [u8],
79  _selected_port: u8,
80  debug: bool,
81) -> Result<Option<&'b [u8]>, Error> {
82  stream.read_exact(&mut buffer[0..1])?;
83  let header = buffer[0];
84  if debug {
85    debug_print_byte(header)?;
86  }
87  if header == 0 {
88    // Synchronization
89    return Ok(None);
90  }
91  let size = header & 0b11;
92  if size == 0 {
93    if header == 0b0111_0000 {
94      // Protocol overflow
95      Err(Overflow)?
96    } else {
97      // Protocol other
98      Ok(None)
99    }
100  } else if header & 0b100 == 0 {
101    // Instrumentation source
102    let _port = header >> 3;
103    // if port != selected_port {
104    //   return Ok(None);
105    // }
106    let payload = match size {
107      0b01 => &mut buffer[0..1],
108      0b10 => &mut buffer[0..2],
109      0b11 => &mut buffer[0..4],
110      _ => unreachable!(),
111    };
112    if debug {
113      for byte in payload.chunks_mut(1) {
114        stream.read_exact(byte)?;
115        debug_print_byte(byte[0])?;
116      }
117    } else {
118      stream.read_exact(payload)?;
119    }
120    Ok(Some(payload))
121  } else {
122    // Hardware source
123    Ok(None)
124  }
125}
126
127fn debug_print_byte(byte: u8) -> Result<(), Error> {
128  print!("{:08b} ", byte);
129  io::stdout().flush()?;
130  Ok(())
131}