Skip to content

Commit

Permalink
Add StreamDecoder, integrate it into qemu-run.
Browse files Browse the repository at this point in the history
  • Loading branch information
Dirbaio committed Jul 18, 2021
1 parent 4c493a3 commit e5717d4
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 24 deletions.
11 changes: 11 additions & 0 deletions decoder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ mod decoder;
mod elf2table;
mod frame;
pub mod log;
mod stream;

use std::{
collections::{BTreeMap, HashMap},
Expand All @@ -31,6 +32,7 @@ use elf2table::parse_impl;

pub use elf2table::{Location, Locations};
pub use frame::Frame;
pub use stream::StreamDecoder;

/// Specifies the origin of a format string
#[derive(PartialEq, Eq, Debug)]
Expand Down Expand Up @@ -232,6 +234,15 @@ impl Table {
let consumed = len - decoder.bytes.len();
Ok((frame, consumed))
}

pub fn new_stream_decoder(&self) -> Box<dyn StreamDecoder + '_> {
Box::new(stream::Rzcobs::new(self))
}

// temporary, will remove
pub fn new_stream_decoder_raw(&self) -> Box<dyn StreamDecoder + '_> {
Box::new(stream::Raw::new(self))
}
}

// NOTE follows `parser::Type`
Expand Down
15 changes: 15 additions & 0 deletions decoder/src/stream/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
mod raw;
mod rzcobs;

pub use raw::Raw;
pub use rzcobs::Rzcobs;

use crate::{DecodeError, Frame};

pub trait StreamDecoder {
/// Push received data to the decoder. The decoder stores it
/// internally, and makes decoded frames available through [`decode`].
fn received(&mut self, data: &[u8]);

fn decode(&mut self) -> Result<Frame<'_>, DecodeError>;
}
32 changes: 32 additions & 0 deletions decoder/src/stream/raw.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use super::StreamDecoder;
use crate::{DecodeError, Frame, Table};

pub struct Raw<'a> {
table: &'a Table,
data: Vec<u8>,
}

impl<'a> Raw<'a> {
pub fn new(table: &'a Table) -> Self {
Self {
table,
data: Vec::new(),
}
}
}

impl<'a> StreamDecoder for Raw<'a> {
fn received(&mut self, data: &[u8]) {
self.data.extend_from_slice(data);
}

fn decode(&mut self) -> Result<Frame<'_>, DecodeError> {
match self.table.decode(&self.data) {
Ok((frame, consumed)) => {
self.data.drain(0..consumed);
Ok(frame)
}
Err(e) => Err(e),
}
}
}
95 changes: 95 additions & 0 deletions decoder/src/stream/rzcobs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
use super::StreamDecoder;
use crate::{DecodeError, Frame, Table};

/// Decode a full message.
///
/// `data` must be a full rzCOBS encoded message. Decoding partial
/// messages is not possible. `data` must NOT include any `0x00` separator byte.
fn rzcobs_decode(data: &[u8]) -> Result<Vec<u8>, DecodeError> {
let mut res = vec![];
let mut data = data.iter().rev().cloned();
while let Some(x) = data.next() {
match x {
0 => return Err(DecodeError::Malformed),
0x01..=0x7f => {
for i in 0..7 {
if x & (1 << (6 - i)) == 0 {
res.push(data.next().ok_or(DecodeError::Malformed)?);
} else {
res.push(0);
}
}
}
0x80..=0xfe => {
let n = (x & 0x7f) + 7;
res.push(0);
for _ in 0..n {
res.push(data.next().ok_or(DecodeError::Malformed)?);
}
}
0xff => {
for _ in 0..134 {
res.push(data.next().ok_or(DecodeError::Malformed)?);
}
}
}
}

res.reverse();
Ok(res)
}

pub struct Rzcobs<'a> {
table: &'a Table,
raw: Vec<u8>,
}

impl<'a> Rzcobs<'a> {
pub fn new(table: &'a Table) -> Self {
Self {
table,
raw: Vec::new(),
}
}
}

impl<'a> StreamDecoder for Rzcobs<'a> {
fn received(&mut self, mut data: &[u8]) {
// Trim zeros from the left, start storing at first non-zero byte.
if self.raw.is_empty() {
while data.get(0) == Some(&0) {
data = &data[1..]
}
}

self.raw.extend_from_slice(data);
}

fn decode(&mut self) -> Result<Frame<'_>, DecodeError> {
// Find frame separator. If not found, we don't have enough data yet.
let zero = self
.raw
.iter()
.position(|&x| x == 0)
.ok_or(DecodeError::UnexpectedEof)?;

let frame = rzcobs_decode(&self.raw[..zero]);

// Even if it failed, pop the data off so we don't get stuck.
// Pop off the frame + 1 or more separator zero-bytes
if let Some(nonzero) = self.raw[zero..].iter().position(|&x| x != 0) {
self.raw.drain(0..zero + nonzero);
} else {
self.raw.clear();
}

assert!(self.raw.is_empty() || self.raw[0] != 0);

let frame: Vec<u8> = frame?;
match self.table.decode(&frame) {
Ok((frame, _consumed)) => Ok(frame),
Err(DecodeError::UnexpectedEof) => Err(DecodeError::Malformed),
Err(DecodeError::Malformed) => Err(DecodeError::Malformed),
}
}
}
38 changes: 14 additions & 24 deletions qemu-run/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use std::{
};

use anyhow::{anyhow, bail};
use defmt_decoder::{DecodeError, Table};
use defmt_decoder::{DecodeError, StreamDecoder, Table};
use process::Child;

fn main() -> Result<(), anyhow::Error> {
Expand Down Expand Up @@ -64,29 +64,22 @@ fn notmain() -> Result<Option<i32>, anyhow::Error> {
.take()
.ok_or_else(|| anyhow!("failed to acquire child's stdout handle"))?;

let mut frames = vec![];
let mut decoder = table.new_stream_decoder();

let mut readbuf = [0; 256];
let exit_code;
loop {
let n = stdout.read(&mut readbuf)?;

if n != 0 {
frames.extend_from_slice(&readbuf[..n]);

decode(&mut frames, &table)?;
}
decoder.received(&readbuf[..n]);
decode(&mut *decoder)?;

if let Some(status) = child.0.try_wait()? {
exit_code = status.code();

stdout.read_to_end(&mut frames)?;
decode(&mut frames, &table)?;
if !frames.is_empty() {
return Err(anyhow!(
"couldn't decode all data (remaining: {:x?})",
frames
));
}
let mut data = Vec::new();
stdout.read_to_end(&mut data)?;
decoder.received(&data);
decode(&mut *decoder)?;

break;
}
Expand All @@ -95,18 +88,15 @@ fn notmain() -> Result<Option<i32>, anyhow::Error> {
Ok(exit_code)
}

fn decode(frames: &mut Vec<u8>, table: &Table) -> Result<(), DecodeError> {
fn decode(decoder: &mut dyn StreamDecoder) -> Result<(), DecodeError> {
loop {
match table.decode(&frames) {
Ok((frame, consumed)) => {
println!("{}", frame.display(true));
let n = frames.len();
frames.rotate_left(consumed);
frames.truncate(n - consumed);
match decoder.decode() {
Ok(frame) => {
println!("{}", frame.display(true))
}
Err(DecodeError::UnexpectedEof) => return Ok(()),
Err(DecodeError::Malformed) => {
eprintln!("failed to decode defmt data: {:x?}", frames);
eprintln!("failed to decode defmt data");
return Err(DecodeError::Malformed);
}
}
Expand Down

0 comments on commit e5717d4

Please sign in to comment.