use std::io::{Write,Cursor,Read};
use std::ops::{Range};
use leb128;
use ron_uuid::UUID;
use {
Statement,
Endianess,
Operation,
MemoryOperation,
FlowOperation,
Constant,
Variable,
Value,
StrRef,
Result,
RewriteControl,
NameRef,
Names,
Strings,
Segment,
SegmentRef,
Segments,
Constraint
};
#[derive(Clone,Debug)]
pub struct Bitcode {
data: Vec<u8>,
}
macro_rules! encoding_rule {
( $val:tt [ c , c ] => $a:expr, $b:expr, $res:expr, $data:expr ) => {{
let val = $val;
let a = $a;
let b = $b;
let res = $res;
let data = $data;
data.write(&[val])?;
Self::encode_constant(a,data)?;
Self::encode_constant(b,data)?;
Self::encode_variable(res,data)?;
}};
( $val:tt [ c , v ] => $a:expr, $b:expr, $res:expr, $data:expr ) => {{
let val = $val;
let a = $a;
let b = $b;
let res = $res;
let data = $data;
data.write(&[val])?;
Self::encode_constant(a,data)?;
Self::encode_variable(b,data)?;
Self::encode_variable(res,data)?;
}};
( $val:tt [ c , u ] => $a:expr, $res:expr, $data:expr ) => {{
let val = $val;
let a = $a;
let res = $res;
let data = $data;
data.write(&[val])?;
Self::encode_constant(a,data)?;
Self::encode_variable(res,data)?;
}};
( $val:tt [ v , c ] => $a:expr, $b:expr, $res:expr, $data:expr ) => {{
let val = $val;
let a = $a;
let b = $b;
let res = $res;
let data = $data;
data.write(&[val])?;
Self::encode_variable(a,data)?;
Self::encode_constant(b,data)?;
Self::encode_variable(res,data)?;
}};
( $val:tt [ v , v ] => $a:expr, $b:expr, $res:expr, $data:expr ) => {{
let val = $val;
let a = $a;
let b = $b;
let res = $res;
let data = $data;
data.write(&[val])?;
Self::encode_variable(a,data)?;
Self::encode_variable(b,data)?;
Self::encode_variable(res,data)?;
}};
( $val:tt [ v , u ] => $a:expr, $res:expr, $data:expr ) => {{
let val = $val;
let a = $a;
let res = $res;
let data = $data;
data.write(&[val])?;
Self::encode_variable(a,data)?;
Self::encode_variable(res,data)?;
}};
( $val:tt [ u , c ] => $b:expr, $res:expr, $data:expr ) => {{
let val = $val;
let b = $b;
let res = $res;
let data = $data;
data.write(&[val])?;
Self::encode_constant(b,data)?;
Self::encode_variable(res,data)?;
}};
( $val:tt [ u , v ] => $b:expr, $res:expr, $data:expr ) => {{
let val = $val;
let b = $b;
let res = $res;
let data = $data;
data.write(&[val])?;
Self::encode_variable(b,data)?;
Self::encode_variable(res,data)?;
}};
}
impl Default for Bitcode {
fn default() -> Bitcode {
Bitcode{
data: Vec::new(),
}
}
}
impl Bitcode {
pub fn append<I: IntoIterator<Item=Statement> + Sized>(&mut self, i: I) -> Result<Range<usize>> {
let mut buf = Cursor::new(Vec::new());
let start = self.data.len();
for stmt in i {
Self::encode_statement(stmt,&mut buf)?;
}
self.data.extend(buf.into_inner().into_iter());
Ok(start..self.data.len())
}
pub fn new(v: Vec<Statement>) -> Result<Bitcode> {
let mut buf = Cursor::new(Vec::new());
for stmt in v {
Self::encode_statement(stmt,&mut buf)?;
}
Ok(Bitcode{ data: buf.into_inner() })
}
pub fn with_capacity(cap: usize) -> Bitcode {
Bitcode{
data: Vec::with_capacity(cap),
}
}
pub fn rewrite<F: FnMut(&mut Statement,&mut Names,&mut Strings,&mut Segments) -> Result<RewriteControl> + Sized>(&mut self, range: Range<usize>, names: &mut Names, strings: &mut Strings, segments: &mut Segments, mut func: F) -> Result<Range<usize>> {
if range.start == range.end { return Ok(range); }
debug!("rewrite bitcode in {:?}",range);
let mut read_pos = range.start;
let mut bytes_left = range.end - range.start;
let mut write_pos = range.start;
let mut tmp = Vec::with_capacity(10);
while bytes_left > 0 {
let mut stmt = {
debug!("read from {:?}",read_pos);
let mut read = Cursor::new(&self.data[read_pos..]);
let stmt = self.decode_statement(&mut read)?;
read_pos += read.position() as usize;
debug!("left: {:?}",bytes_left);
debug!("read {:?}",read.position());
debug!("read to {:?}",read_pos);
bytes_left -= read.position() as usize;
stmt
};
debug!("map {:?}",stmt);
match func(&mut stmt,names,strings,segments)? {
RewriteControl::Continue => { }
RewriteControl::Break => { return Ok(range.start..(read_pos + bytes_left)); }
}
debug!(" to {:?}",stmt);
{
let mut write = Cursor::new(tmp);
Self::encode_statement(stmt, &mut write)?;
tmp = write.into_inner();
if read_pos - write_pos < tmp.len() {
let diff = tmp.len() - (read_pos - write_pos);
debug!("make space for {} more bytes",diff);
self.data.reserve(diff);
for _ in 0..diff { self.data.insert(write_pos,42); }
read_pos += diff;
}
}
debug!("write {:?} at {}",tmp,write_pos);
{
let mut write = Cursor::new(&mut self.data[write_pos..]);
write_pos += write.write(&tmp)?;
tmp.clear();
}
if read_pos > write_pos {
debug!("remove {:?}",write_pos..read_pos);
self.data.drain(write_pos..read_pos);
read_pos = write_pos;
}
assert_eq!(read_pos, write_pos);
}
Ok(range.start..write_pos)
}
pub fn remove(&mut self, range: Range<usize>) {
self.data.drain(range);
}
pub fn insert(&mut self, pos: usize, stmts: Vec<Statement>) -> Result<Range<usize>> {
let data = Vec::with_capacity(stmts.len() * 10);
let mut cur = Cursor::new(data);
for stmt in stmts {
Self::encode_statement(stmt, &mut cur)?;
}
let buf = cur.into_inner();
let len = buf.len();
for b in buf.into_iter().rev() {
self.data.insert(pos,b);
}
Ok(pos..(pos + len))
}
fn encode_statement<W: Write>(stmt: Statement, data: &mut W) -> Result<()> {
use il::Operation::*;
use value::Value::*;
match stmt {
Statement::Expression{ op: Add(Constant(a),Constant(b)), result } => encoding_rule!( 0b00000_000 [c,c] => a, b, result, data ),
Statement::Expression{ op: Add(Constant(a),Variable(b)), result } => encoding_rule!( 0b00000_001 [c,v] => a, b, result, data ),
Statement::Expression{ op: Add(Constant(a),Undefined), result } => encoding_rule!( 0b00000_010 [c,u] => a, result, data ),
Statement::Expression{ op: Add(Variable(a),Constant(b)), result } => encoding_rule!( 0b00000_011 [v,c] => a, b, result, data ),
Statement::Expression{ op: Add(Variable(a),Variable(b)), result } => encoding_rule!( 0b00000_100 [v,v] => a, b, result, data ),
Statement::Expression{ op: Add(Variable(a),Undefined), result } => encoding_rule!( 0b00000_101 [v,u] => a, result, data ),
Statement::Expression{ op: Add(Undefined,Constant(b)), result } => encoding_rule!( 0b00000_110 [u,c] => b, result, data ),
Statement::Expression{ op: Add(Undefined,Variable(b)), result } => encoding_rule!( 0b00000_111 [u,v] => b, result, data ),
Statement::Expression{ op: Add(Undefined,Undefined), result } => {
Self::encode_statement(Statement::Expression{ op: Move(Undefined), result: result },data)?;
}
Statement::Expression{ op: Subtract(Constant(a),Constant(b)), result } => encoding_rule!( 0b00001_000 [c,c] => a, b, result, data ),
Statement::Expression{ op: Subtract(Constant(a),Variable(b)), result } => encoding_rule!( 0b00001_001 [c,v] => a, b, result, data ),
Statement::Expression{ op: Subtract(Constant(a),Undefined), result } => encoding_rule!( 0b00001_010 [c,u] => a, result, data ),
Statement::Expression{ op: Subtract(Variable(a),Constant(b)), result } => encoding_rule!( 0b00001_011 [v,c] => a, b, result, data ),
Statement::Expression{ op: Subtract(Variable(a),Variable(b)), result } => encoding_rule!( 0b00001_100 [v,v] => a, b, result, data ),
Statement::Expression{ op: Subtract(Variable(a),Undefined), result } => encoding_rule!( 0b00001_101 [v,u] => a, result, data ),
Statement::Expression{ op: Subtract(Undefined,Constant(b)), result } => encoding_rule!( 0b00001_110 [u,c] => b, result, data ),
Statement::Expression{ op: Subtract(Undefined,Variable(b)), result } => encoding_rule!( 0b00001_111 [u,v] => b, result, data ),
Statement::Expression{ op: Subtract(Undefined,Undefined), result } => {
Self::encode_statement(Statement::Expression{ op: Move(Undefined), result: result },data)?;
}
Statement::Expression{ op: Multiply(Constant(a),Constant(b)), result } => encoding_rule!( 0b00010_000 [c,c] => a, b, result, data ),
Statement::Expression{ op: Multiply(Constant(a),Variable(b)), result } => encoding_rule!( 0b00010_001 [c,v] => a, b, result, data ),
Statement::Expression{ op: Multiply(Constant(a),Undefined), result } => encoding_rule!( 0b00010_010 [c,u] => a, result, data ),
Statement::Expression{ op: Multiply(Variable(a),Constant(b)), result } => encoding_rule!( 0b00010_011 [v,c] => a, b, result, data ),
Statement::Expression{ op: Multiply(Variable(a),Variable(b)), result } => encoding_rule!( 0b00010_100 [v,v] => a, b, result, data ),
Statement::Expression{ op: Multiply(Variable(a),Undefined), result } => encoding_rule!( 0b00010_101 [v,u] => a, result, data ),
Statement::Expression{ op: Multiply(Undefined,Constant(b)), result } => encoding_rule!( 0b00010_110 [u,c] => b, result, data ),
Statement::Expression{ op: Multiply(Undefined,Variable(b)), result } => encoding_rule!( 0b00010_111 [u,v] => b, result, data ),
Statement::Expression{ op: Multiply(Undefined,Undefined), result } => {
Self::encode_statement(Statement::Expression{ op: Move(Undefined), result: result },data)?;
}
Statement::Expression{ op: DivideUnsigned(Constant(a),Constant(b)), result } => encoding_rule!( 0b00011_000 [c,c] => a, b, result, data ),
Statement::Expression{ op: DivideUnsigned(Constant(a),Variable(b)), result } => encoding_rule!( 0b00011_001 [c,v] => a, b, result, data ),
Statement::Expression{ op: DivideUnsigned(Constant(a),Undefined), result } => encoding_rule!( 0b00011_010 [c,u] => a, result, data ),
Statement::Expression{ op: DivideUnsigned(Variable(a),Constant(b)), result } => encoding_rule!( 0b00011_011 [v,c] => a, b, result, data ),
Statement::Expression{ op: DivideUnsigned(Variable(a),Variable(b)), result } => encoding_rule!( 0b00011_100 [v,v] => a, b, result, data ),
Statement::Expression{ op: DivideUnsigned(Variable(a),Undefined), result } => encoding_rule!( 0b00011_101 [v,u] => a, result, data ),
Statement::Expression{ op: DivideUnsigned(Undefined,Constant(b)), result } => encoding_rule!( 0b00011_110 [u,c] => b, result, data ),
Statement::Expression{ op: DivideUnsigned(Undefined,Variable(b)), result } => encoding_rule!( 0b00011_111 [u,v] => b, result, data ),
Statement::Expression{ op: DivideUnsigned(Undefined,Undefined), result } => {
Self::encode_statement(Statement::Expression{ op: Move(Undefined), result: result },data)?;
}
Statement::Expression{ op: DivideSigned(Constant(a),Constant(b)), result } => encoding_rule!( 0b00100_000 [c,c] => a, b, result, data ),
Statement::Expression{ op: DivideSigned(Constant(a),Variable(b)), result } => encoding_rule!( 0b00100_001 [c,v] => a, b, result, data ),
Statement::Expression{ op: DivideSigned(Constant(a),Undefined), result } => encoding_rule!( 0b00100_010 [c,u] => a, result, data ),
Statement::Expression{ op: DivideSigned(Variable(a),Constant(b)), result } => encoding_rule!( 0b00100_011 [v,c] => a, b, result, data ),
Statement::Expression{ op: DivideSigned(Variable(a),Variable(b)), result } => encoding_rule!( 0b00100_100 [v,v] => a, b, result, data ),
Statement::Expression{ op: DivideSigned(Variable(a),Undefined), result } => encoding_rule!( 0b00100_101 [v,u] => a, result, data ),
Statement::Expression{ op: DivideSigned(Undefined,Constant(b)), result } => encoding_rule!( 0b00100_110 [u,c] => b, result, data ),
Statement::Expression{ op: DivideSigned(Undefined,Variable(b)), result } => encoding_rule!( 0b00100_111 [u,v] => b, result, data ),
Statement::Expression{ op: DivideSigned(Undefined,Undefined), result } => {
Self::encode_statement(Statement::Expression{ op: Move(Undefined), result: result },data)?;
}
Statement::Expression{ op: ShiftLeft(Constant(a),Constant(b)), result } => encoding_rule!( 0b00101_000 [c,c] => a, b, result, data ),
Statement::Expression{ op: ShiftLeft(Constant(a),Variable(b)), result } => encoding_rule!( 0b00101_001 [c,v] => a, b, result, data ),
Statement::Expression{ op: ShiftLeft(Constant(a),Undefined), result } => encoding_rule!( 0b00101_010 [c,u] => a, result, data ),
Statement::Expression{ op: ShiftLeft(Variable(a),Constant(b)), result } => encoding_rule!( 0b00101_011 [v,c] => a, b, result, data ),
Statement::Expression{ op: ShiftLeft(Variable(a),Variable(b)), result } => encoding_rule!( 0b00101_100 [v,v] => a, b, result, data ),
Statement::Expression{ op: ShiftLeft(Variable(a),Undefined), result } => encoding_rule!( 0b00101_101 [v,u] => a, result, data ),
Statement::Expression{ op: ShiftLeft(Undefined,Constant(b)), result } => encoding_rule!( 0b00101_110 [u,c] => b, result, data ),
Statement::Expression{ op: ShiftLeft(Undefined,Variable(b)), result } => encoding_rule!( 0b00101_111 [u,v] => b, result, data ),
Statement::Expression{ op: ShiftLeft(Undefined,Undefined), result } => {
Self::encode_statement(Statement::Expression{ op: Move(Undefined), result: result },data)?;
}
Statement::Expression{ op: ShiftRightUnsigned(Constant(a),Constant(b)), result } => encoding_rule!( 0b00110_000 [c,c] => a, b, result, data ),
Statement::Expression{ op: ShiftRightUnsigned(Constant(a),Variable(b)), result } => encoding_rule!( 0b00110_001 [c,v] => a, b, result, data ),
Statement::Expression{ op: ShiftRightUnsigned(Constant(a),Undefined), result } => encoding_rule!( 0b00110_010 [c,u] => a, result, data ),
Statement::Expression{ op: ShiftRightUnsigned(Variable(a),Constant(b)), result } => encoding_rule!( 0b00110_011 [v,c] => a, b, result, data ),
Statement::Expression{ op: ShiftRightUnsigned(Variable(a),Variable(b)), result } => encoding_rule!( 0b00110_100 [v,v] => a, b, result, data ),
Statement::Expression{ op: ShiftRightUnsigned(Variable(a),Undefined), result } => encoding_rule!( 0b00110_101 [v,u] => a, result, data ),
Statement::Expression{ op: ShiftRightUnsigned(Undefined,Constant(b)), result } => encoding_rule!( 0b00110_110 [u,c] => b, result, data ),
Statement::Expression{ op: ShiftRightUnsigned(Undefined,Variable(b)), result } => encoding_rule!( 0b00110_111 [u,v] => b, result, data ),
Statement::Expression{ op: ShiftRightUnsigned(Undefined,Undefined), result } => {
Self::encode_statement(Statement::Expression{ op: Move(Undefined), result: result },data)?;
}
Statement::Expression{ op: ShiftRightSigned(Constant(a),Constant(b)), result } => encoding_rule!( 0b00111_000 [c,c] => a, b, result, data ),
Statement::Expression{ op: ShiftRightSigned(Constant(a),Variable(b)), result } => encoding_rule!( 0b00111_001 [c,v] => a, b, result, data ),
Statement::Expression{ op: ShiftRightSigned(Constant(a),Undefined), result } => encoding_rule!( 0b00111_010 [c,u] => a, result, data ),
Statement::Expression{ op: ShiftRightSigned(Variable(a),Constant(b)), result } => encoding_rule!( 0b00111_011 [v,c] => a, b, result, data ),
Statement::Expression{ op: ShiftRightSigned(Variable(a),Variable(b)), result } => encoding_rule!( 0b00111_100 [v,v] => a, b, result, data ),
Statement::Expression{ op: ShiftRightSigned(Variable(a),Undefined), result } => encoding_rule!( 0b00111_101 [v,u] => a, result, data ),
Statement::Expression{ op: ShiftRightSigned(Undefined,Constant(b)), result } => encoding_rule!( 0b00111_110 [u,c] => b, result, data ),
Statement::Expression{ op: ShiftRightSigned(Undefined,Variable(b)), result } => encoding_rule!( 0b00111_111 [u,v] => b, result, data ),
Statement::Expression{ op: ShiftRightSigned(Undefined,Undefined), result } => {
Self::encode_statement(Statement::Expression{ op: Move(Undefined), result: result },data)?;
}
Statement::Expression{ op: Modulo(Constant(a),Constant(b)), result } => encoding_rule!( 0b01000_000 [c,c] => a, b, result, data ),
Statement::Expression{ op: Modulo(Constant(a),Variable(b)), result } => encoding_rule!( 0b01000_001 [c,v] => a, b, result, data ),
Statement::Expression{ op: Modulo(Constant(a),Undefined), result } => encoding_rule!( 0b01000_010 [c,u] => a, result, data ),
Statement::Expression{ op: Modulo(Variable(a),Constant(b)), result } => encoding_rule!( 0b01000_011 [v,c] => a, b, result, data ),
Statement::Expression{ op: Modulo(Variable(a),Variable(b)), result } => encoding_rule!( 0b01000_100 [v,v] => a, b, result, data ),
Statement::Expression{ op: Modulo(Variable(a),Undefined), result } => encoding_rule!( 0b01000_101 [v,u] => a, result, data ),
Statement::Expression{ op: Modulo(Undefined,Constant(b)), result } => encoding_rule!( 0b01000_110 [u,c] => b, result, data ),
Statement::Expression{ op: Modulo(Undefined,Variable(b)), result } => encoding_rule!( 0b01000_111 [u,v] => b, result, data ),
Statement::Expression{ op: Modulo(Undefined,Undefined), result } => {
Self::encode_statement(Statement::Expression{ op: Move(Undefined), result: result },data)?;
}
Statement::Expression{ op: And(Constant(a),Constant(b)), result } => encoding_rule!( 0b01001_000 [c,c] => a, b, result, data ),
Statement::Expression{ op: And(Constant(a),Variable(b)), result } => encoding_rule!( 0b01001_001 [c,v] => a, b, result, data ),
Statement::Expression{ op: And(Constant(a),Undefined), result } => encoding_rule!( 0b01001_010 [c,u] => a, result, data ),
Statement::Expression{ op: And(Variable(a),Constant(b)), result } => encoding_rule!( 0b01001_011 [v,c] => a, b, result, data ),
Statement::Expression{ op: And(Variable(a),Variable(b)), result } => encoding_rule!( 0b01001_100 [v,v] => a, b, result, data ),
Statement::Expression{ op: And(Variable(a),Undefined), result } => encoding_rule!( 0b01001_101 [v,u] => a, result, data ),
Statement::Expression{ op: And(Undefined,Constant(b)), result } => encoding_rule!( 0b01001_110 [u,c] => b, result, data ),
Statement::Expression{ op: And(Undefined,Variable(b)), result } => encoding_rule!( 0b01001_111 [u,v] => b, result, data ),
Statement::Expression{ op: And(Undefined,Undefined), result } => {
Self::encode_statement(Statement::Expression{ op: Move(Undefined), result: result },data)?;
}
Statement::Expression{ op: InclusiveOr(Constant(a),Constant(b)), result } => encoding_rule!( 0b01010_000 [c,c] => a, b, result, data ),
Statement::Expression{ op: InclusiveOr(Constant(a),Variable(b)), result } => encoding_rule!( 0b01010_001 [c,v] => a, b, result, data ),
Statement::Expression{ op: InclusiveOr(Constant(a),Undefined), result } => encoding_rule!( 0b01010_010 [c,u] => a, result, data ),
Statement::Expression{ op: InclusiveOr(Variable(a),Constant(b)), result } => encoding_rule!( 0b01010_011 [v,c] => a, b, result, data ),
Statement::Expression{ op: InclusiveOr(Variable(a),Variable(b)), result } => encoding_rule!( 0b01010_100 [v,v] => a, b, result, data ),
Statement::Expression{ op: InclusiveOr(Variable(a),Undefined), result } => encoding_rule!( 0b01010_101 [v,u] => a, result, data ),
Statement::Expression{ op: InclusiveOr(Undefined,Constant(b)), result } => encoding_rule!( 0b01010_110 [u,c] => b, result, data ),
Statement::Expression{ op: InclusiveOr(Undefined,Variable(b)), result } => encoding_rule!( 0b01010_111 [u,v] => b, result, data ),
Statement::Expression{ op: InclusiveOr(Undefined,Undefined), result } => {
Self::encode_statement(Statement::Expression{ op: Move(Undefined), result: result },data)?;
}
Statement::Expression{ op: ExclusiveOr(Constant(a),Constant(b)), result } => encoding_rule!( 0b01011_000 [c,c] => a, b, result, data ),
Statement::Expression{ op: ExclusiveOr(Constant(a),Variable(b)), result } => encoding_rule!( 0b01011_001 [c,v] => a, b, result, data ),
Statement::Expression{ op: ExclusiveOr(Constant(a),Undefined), result } => encoding_rule!( 0b01011_010 [c,u] => a, result, data ),
Statement::Expression{ op: ExclusiveOr(Variable(a),Constant(b)), result } => encoding_rule!( 0b01011_011 [v,c] => a, b, result, data ),
Statement::Expression{ op: ExclusiveOr(Variable(a),Variable(b)), result } => encoding_rule!( 0b01011_100 [v,v] => a, b, result, data ),
Statement::Expression{ op: ExclusiveOr(Variable(a),Undefined), result } => encoding_rule!( 0b01011_101 [v,u] => a, result, data ),
Statement::Expression{ op: ExclusiveOr(Undefined,Constant(b)), result } => encoding_rule!( 0b01011_110 [u,c] => b, result, data ),
Statement::Expression{ op: ExclusiveOr(Undefined,Variable(b)), result } => encoding_rule!( 0b01011_111 [u,v] => b, result, data ),
Statement::Expression{ op: ExclusiveOr(Undefined,Undefined), result } => {
Self::encode_statement(Statement::Expression{ op: Move(Undefined), result: result },data)?;
}
Statement::Expression{ op: Equal(Constant(a),Constant(b)), result } => encoding_rule!( 0b01100_000 [c,c] => a, b, result, data ),
Statement::Expression{ op: Equal(Constant(a),Variable(b)), result } => encoding_rule!( 0b01100_001 [c,v] => a, b, result, data ),
Statement::Expression{ op: Equal(Constant(a),Undefined), result } => encoding_rule!( 0b01100_010 [c,u] => a, result, data ),
Statement::Expression{ op: Equal(Variable(a),Constant(b)), result } => encoding_rule!( 0b01100_011 [v,c] => a, b, result, data ),
Statement::Expression{ op: Equal(Variable(a),Variable(b)), result } => encoding_rule!( 0b01100_100 [v,v] => a, b, result, data ),
Statement::Expression{ op: Equal(Variable(a),Undefined), result } => encoding_rule!( 0b01100_101 [v,u] => a, result, data ),
Statement::Expression{ op: Equal(Undefined,Constant(b)), result } => encoding_rule!( 0b01100_110 [u,c] => b, result, data ),
Statement::Expression{ op: Equal(Undefined,Variable(b)), result } => encoding_rule!( 0b01100_111 [u,v] => b, result, data ),
Statement::Expression{ op: Equal(Undefined,Undefined), result } => {
Self::encode_statement(Statement::Expression{ op: Move(Undefined), result: result },data)?;
}
Statement::Expression{ op: LessOrEqualUnsigned(Constant(a),Constant(b)), result } => encoding_rule!( 0b01101_000 [c,c] => a, b, result, data ),
Statement::Expression{ op: LessOrEqualUnsigned(Constant(a),Variable(b)), result } => encoding_rule!( 0b01101_001 [c,v] => a, b, result, data ),
Statement::Expression{ op: LessOrEqualUnsigned(Constant(a),Undefined), result } => encoding_rule!( 0b01101_010 [c,u] => a, result, data ),
Statement::Expression{ op: LessOrEqualUnsigned(Variable(a),Constant(b)), result } => encoding_rule!( 0b01101_011 [v,c] => a, b, result, data ),
Statement::Expression{ op: LessOrEqualUnsigned(Variable(a),Variable(b)), result } => encoding_rule!( 0b01101_100 [v,v] => a, b, result, data ),
Statement::Expression{ op: LessOrEqualUnsigned(Variable(a),Undefined), result } => encoding_rule!( 0b01101_101 [v,u] => a, result, data ),
Statement::Expression{ op: LessOrEqualUnsigned(Undefined,Constant(b)), result } => encoding_rule!( 0b01101_110 [u,c] => b, result, data ),
Statement::Expression{ op: LessOrEqualUnsigned(Undefined,Variable(b)), result } => encoding_rule!( 0b01101_111 [u,v] => b, result, data ),
Statement::Expression{ op: LessOrEqualUnsigned(Undefined,Undefined), result } => {
Self::encode_statement(Statement::Expression{ op: Move(Undefined), result: result },data)?;
}
Statement::Expression{ op: LessOrEqualSigned(Constant(a),Constant(b)), result } => encoding_rule!( 0b01110_000 [c,c] => a, b, result, data ),
Statement::Expression{ op: LessOrEqualSigned(Constant(a),Variable(b)), result } => encoding_rule!( 0b01110_001 [c,v] => a, b, result, data ),
Statement::Expression{ op: LessOrEqualSigned(Constant(a),Undefined), result } => encoding_rule!( 0b01110_010 [c,u] => a, result, data ),
Statement::Expression{ op: LessOrEqualSigned(Variable(a),Constant(b)), result } => encoding_rule!( 0b01110_011 [v,c] => a, b, result, data ),
Statement::Expression{ op: LessOrEqualSigned(Variable(a),Variable(b)), result } => encoding_rule!( 0b01110_100 [v,v] => a, b, result, data ),
Statement::Expression{ op: LessOrEqualSigned(Variable(a),Undefined), result } => encoding_rule!( 0b01110_101 [v,u] => a, result, data ),
Statement::Expression{ op: LessOrEqualSigned(Undefined,Constant(b)), result } => encoding_rule!( 0b01110_110 [u,c] => b, result, data ),
Statement::Expression{ op: LessOrEqualSigned(Undefined,Variable(b)), result } => encoding_rule!( 0b01110_111 [u,v] => b, result, data ),
Statement::Expression{ op: LessOrEqualSigned(Undefined,Undefined), result } => {
Self::encode_statement(Statement::Expression{ op: Move(Undefined), result: result },data)?;
}
Statement::Expression{ op: LessUnsigned(Constant(a),Constant(b)), result } => encoding_rule!( 0b01111_000 [c,c] => a, b, result, data ),
Statement::Expression{ op: LessUnsigned(Constant(a),Variable(b)), result } => encoding_rule!( 0b01111_001 [c,v] => a, b, result, data ),
Statement::Expression{ op: LessUnsigned(Constant(a),Undefined), result } => encoding_rule!( 0b01111_010 [c,u] => a, result, data ),
Statement::Expression{ op: LessUnsigned(Variable(a),Constant(b)), result } => encoding_rule!( 0b01111_011 [v,c] => a, b, result, data ),
Statement::Expression{ op: LessUnsigned(Variable(a),Variable(b)), result } => encoding_rule!( 0b01111_100 [v,v] => a, b, result, data ),
Statement::Expression{ op: LessUnsigned(Variable(a),Undefined), result } => encoding_rule!( 0b01111_101 [v,u] => a, result, data ),
Statement::Expression{ op: LessUnsigned(Undefined,Constant(b)), result } => encoding_rule!( 0b01111_110 [u,c] => b, result, data ),
Statement::Expression{ op: LessUnsigned(Undefined,Variable(b)), result } => encoding_rule!( 0b01111_111 [u,v] => b, result, data ),
Statement::Expression{ op: LessUnsigned(Undefined,Undefined), result } => {
Self::encode_statement(Statement::Expression{ op: Move(Undefined), result: result },data)?;
}
Statement::Expression{ op: LessSigned(Constant(a),Constant(b)), result } => encoding_rule!( 0b10000_000 [c,c] => a, b, result, data ),
Statement::Expression{ op: LessSigned(Constant(a),Variable(b)), result } => encoding_rule!( 0b10000_001 [c,v] => a, b, result, data ),
Statement::Expression{ op: LessSigned(Constant(a),Undefined), result } => encoding_rule!( 0b10000_010 [c,u] => a, result, data ),
Statement::Expression{ op: LessSigned(Variable(a),Constant(b)), result } => encoding_rule!( 0b10000_011 [v,c] => a, b, result, data ),
Statement::Expression{ op: LessSigned(Variable(a),Variable(b)), result } => encoding_rule!( 0b10000_100 [v,v] => a, b, result, data ),
Statement::Expression{ op: LessSigned(Variable(a),Undefined), result } => encoding_rule!( 0b10000_101 [v,u] => a, result, data ),
Statement::Expression{ op: LessSigned(Undefined,Constant(b)), result } => encoding_rule!( 0b10000_110 [u,c] => b, result, data ),
Statement::Expression{ op: LessSigned(Undefined,Variable(b)), result } => encoding_rule!( 0b10000_111 [u,v] => b, result, data ),
Statement::Expression{ op: LessSigned(Undefined,Undefined), result } => {
Self::encode_statement(Statement::Expression{ op: Move(Undefined), result: result },data)?;
}
Statement::Expression{ op: ZeroExtend(sz,Constant(a)), result } => {
data.write(&[0b10001000])?;
leb128::write::unsigned(data,sz as u64)?;
Self::encode_constant(a,data)?;
Self::encode_variable(result,data)?;
}
Statement::Expression{ op: ZeroExtend(sz,Variable(a)), result } => {
data.write(&[0b10001001])?;
leb128::write::unsigned(data,sz as u64)?;
Self::encode_variable(a,data)?;
Self::encode_variable(result,data)?;
}
Statement::Expression{ op: ZeroExtend(_,Undefined), result } => {
Self::encode_statement(Statement::Expression{ op: Move(Undefined), result: result },data)?;
}
Statement::Expression{ op: SignExtend(sz,Constant(a)), result } => {
data.write(&[0b10001010])?;
leb128::write::unsigned(data,sz as u64)?;
Self::encode_constant(a,data)?;
Self::encode_variable(result,data)?;
}
Statement::Expression{ op: SignExtend(sz,Variable(a)), result } => {
data.write(&[0b10001011])?;
leb128::write::unsigned(data,sz as u64)?;
Self::encode_variable(a,data)?;
Self::encode_variable(result,data)?;
}
Statement::Expression{ op: SignExtend(_,Undefined), result } => {
Self::encode_statement(Statement::Expression{ op: Move(Undefined), result: result },data)?;
}
Statement::Expression{ op: Move(Constant(a)), result } => {
data.write(&[0b10001100])?;
Self::encode_constant(a,data)?;
Self::encode_variable(result,data)?;
}
Statement::Expression{ op: Move(Variable(a)), result } => {
data.write(&[0b10001101])?;
Self::encode_variable(a,data)?;
Self::encode_variable(result,data)?;
}
Statement::Expression{ op: Move(Undefined), result } => {
data.write(&[0b10001110])?;
Self::encode_variable(result,data)?;
}
Statement::Expression{ op: Initialize(name,sz), result } => {
data.write(&[0b10001111])?;
leb128::write::unsigned(data,name.index() as u64)?;
leb128::write::unsigned(data,sz as u64)?;
Self::encode_variable(result,data)?;
}
Statement::Expression{ op: Select(off,sz,Constant(src)), result } => {
data.write(&[0b10010000])?;
leb128::write::unsigned(data,off as u64)?;
leb128::write::unsigned(data,sz as u64)?;
Self::encode_constant(src,data)?;
Self::encode_variable(result,data)?;
}
Statement::Expression{ op: Select(off,sz,Variable(src)), result } => {
data.write(&[0b10010001])?;
leb128::write::unsigned(data,off as u64)?;
leb128::write::unsigned(data,sz as u64)?;
Self::encode_variable(src,data)?;
Self::encode_variable(result,data)?;
}
Statement::Expression{ op: Select(_,_,Undefined), result } => {
Self::encode_statement(Statement::Expression{ op: Move(Undefined), result: result },data)?;
}
Statement::Expression{ op: Load(segment,Endianess::Little,bytes,Constant(addr)), result } => {
data.write(&[0b10010100])?;
Self::encode_segment(segment,data)?;
leb128::write::unsigned(data,bytes as u64)?;
Self::encode_constant(addr,data)?;
Self::encode_variable(result,data)?;
}
Statement::Expression{ op: Load(segment,Endianess::Big,bytes,Constant(addr)), result } => {
data.write(&[0b10010110])?;
Self::encode_segment(segment,data)?;
leb128::write::unsigned(data,bytes as u64)?;
Self::encode_constant(addr,data)?;
Self::encode_variable(result,data)?;
}
Statement::Expression{ op: Load(segment,Endianess::Little,bytes,Variable(addr)), result } => {
data.write(&[0b10010101])?;
Self::encode_segment(segment,data)?;
leb128::write::unsigned(data,bytes as u64)?;
Self::encode_variable(addr,data)?;
Self::encode_variable(result,data)?;
}
Statement::Expression{ op: Load(segment,Endianess::Big,bytes,Variable(addr)), result } => {
data.write(&[0b10010111])?;
Self::encode_segment(segment,data)?;
leb128::write::unsigned(data,bytes as u64)?;
Self::encode_variable(addr,data)?;
Self::encode_variable(result,data)?;
}
Statement::Expression{ op: Phi(Variable(a),Variable(b),Undefined), result } |
Statement::Expression{ op: Phi(Variable(a),Undefined,Variable(b)), result } |
Statement::Expression{ op: Phi(Undefined,Variable(a),Variable(b)), result } => {
data.write(&[0b10011000])?;
Self::encode_variable(a,data)?;
Self::encode_variable(b,data)?;
Self::encode_variable(result,data)?;
}
Statement::Expression{ op: Phi(Variable(a),Variable(b),Variable(c)), result } => {
data.write(&[0b10011001])?;
Self::encode_variable(a,data)?;
Self::encode_variable(b,data)?;
Self::encode_variable(c,data)?;
Self::encode_variable(result,data)?;
}
Statement::Flow{ op: FlowOperation::ExternalCall{ external: name } } => {
data.write(&[0b10011010])?;
leb128::write::unsigned(data,name.index() as u64)?;
}
Statement::Flow{ op: FlowOperation::Call{ function: uuid } } => {
data.write(&[0b10011011])?;
Self::encode_uuid(uuid,data)?;
}
Statement::Flow{ op: FlowOperation::IndirectCall{ target: tgt } } => {
data.write(&[0b10011101])?;
Self::encode_variable(tgt,data)?;
}
Statement::Expression{ op: Phi(Undefined,Undefined,Undefined), result } => {
data.write(&[0b10011111])?;
Self::encode_variable(result,data)?;
}
Statement::Memory{ op: MemoryOperation::Store{ segment, bytes, endianess, address: Constant(addr), value: Constant(value) }, result } => {
data.write(&[0b10100000 | if endianess == Endianess::Little { 0 } else { 0b1000 }])?;
Self::encode_segment(segment,data)?;
leb128::write::unsigned(data,bytes as u64)?;
Self::encode_constant(addr,data)?;
Self::encode_constant(value,data)?;
Self::encode_segment(result,data)?;
}
Statement::Memory{ op: MemoryOperation::Store{ segment, bytes, endianess, address: Constant(addr), value: Variable(value) }, result } => {
data.write(&[0b10100001 | if endianess == Endianess::Little { 0 } else { 0b1000 }])?;
Self::encode_segment(segment,data)?;
leb128::write::unsigned(data,bytes as u64)?;
Self::encode_constant(addr,data)?;
Self::encode_variable(value,data)?;
Self::encode_segment(result,data)?;
}
Statement::Memory{ op: MemoryOperation::Store{ segment, bytes, endianess, address: Constant(addr), value: Undefined }, result } => {
data.write(&[0b10100010 | if endianess == Endianess::Little { 0 } else { 0b1000 }])?;
Self::encode_segment(segment,data)?;
leb128::write::unsigned(data,bytes as u64)?;
Self::encode_constant(addr,data)?;
Self::encode_segment(result,data)?;
}
Statement::Memory{ op: MemoryOperation::Store{ segment, bytes, endianess, address: Variable(addr), value: Constant(value) }, result } => {
data.write(&[0b10100011 | if endianess == Endianess::Little { 0 } else { 0b1000 }])?;
Self::encode_segment(segment,data)?;
leb128::write::unsigned(data,bytes as u64)?;
Self::encode_variable(addr,data)?;
Self::encode_constant(value,data)?;
Self::encode_segment(result,data)?;
}
Statement::Memory{ op: MemoryOperation::Store{ segment, bytes, endianess, address: Variable(addr), value: Variable(value) }, result } => {
data.write(&[0b10100100 | if endianess == Endianess::Little { 0 } else { 0b1000 }])?;
Self::encode_segment(segment,data)?;
leb128::write::unsigned(data,bytes as u64)?;
Self::encode_variable(addr,data)?;
Self::encode_variable(value,data)?;
Self::encode_segment(result,data)?;
}
Statement::Memory{ op: MemoryOperation::Store{ segment, bytes, endianess, address: Variable(addr), value: Undefined }, result } => {
data.write(&[0b10100101 | if endianess == Endianess::Little { 0 } else { 0b1000 }])?;
Self::encode_segment(segment,data)?;
leb128::write::unsigned(data,bytes as u64)?;
Self::encode_variable(addr,data)?;
Self::encode_segment(result,data)?;
}
Statement::Memory{ op: MemoryOperation::Store{ segment, bytes, endianess, address: Undefined, value: Constant(value) }, result } => {
data.write(&[0b10100110 | if endianess == Endianess::Little { 0 } else { 0b1000 }])?;
Self::encode_segment(segment,data)?;
leb128::write::unsigned(data,bytes as u64)?;
Self::encode_constant(value,data)?;
Self::encode_segment(result,data)?;
}
Statement::Memory{ op: MemoryOperation::Store{ segment, bytes, endianess, address: Undefined, value: Variable(value) }, result } => {
data.write(&[0b10100111 | if endianess == Endianess::Little { 0 } else { 0b1000 }])?;
Self::encode_segment(segment,data)?;
leb128::write::unsigned(data,bytes as u64)?;
Self::encode_variable(value,data)?;
Self::encode_segment(result,data)?;
}
Statement::Memory{ op: MemoryOperation::Store{ address: Undefined, value: Undefined,.. },.. } => { }
Statement::Flow{ op: FlowOperation::Return } => {
data.write(&[0b10110000])?;
}
Statement::Expression{ op: Load(segment,endianess,bytes,Undefined), result } => {
data.write(&[0b1011_0010 | if endianess == Endianess::Little { 0 } else { 0b1 }])?;
Self::encode_segment(segment,data)?;
leb128::write::unsigned(data,bytes as u64)?;
Self::encode_variable(result,data)?;
}
Statement::Expression{ op: Phi(Variable(a),Undefined,Undefined), result } => {
data.write(&[0b10110100])?;
Self::encode_variable(a,data)?;
Self::encode_variable(result,data)?;
}
Statement::Expression{ op: Phi(_,_,_),.. } => {
return Err(format!("Internal error: invalid Phi expression {:?}",stmt).into());
}
Statement::Memory{ op: MemoryOperation::MemoryPhi(None,None,None), result } => {
data.write(&[0b10110101])?;
Self::encode_segment(result,data)?;
data.write(&[0,0,0])?;
}
Statement::Memory{ op: MemoryOperation::MemoryPhi(Some(a),None,None), result } |
Statement::Memory{ op: MemoryOperation::MemoryPhi(None,Some(a),None), result } |
Statement::Memory{ op: MemoryOperation::MemoryPhi(None,None,Some(a)), result } => {
data.write(&[0b10110110])?;
Self::encode_segment(a,data)?;
Self::encode_segment(result,data)?;
data.write(&[0,0])?;
}
Statement::Memory{ op: MemoryOperation::MemoryPhi(Some(a),Some(b),None), result } |
Statement::Memory{ op: MemoryOperation::MemoryPhi(Some(a),None,Some(b)), result } |
Statement::Memory{ op: MemoryOperation::MemoryPhi(None,Some(a),Some(b)), result } => {
data.write(&[0b10110111])?;
Self::encode_segment(a,data)?;
Self::encode_segment(b,data)?;
Self::encode_segment(result,data)?;
data.write(&[0])?;
}
Statement::Memory{ op: MemoryOperation::MemoryPhi(Some(a),Some(b),Some(c)), result } => {
data.write(&[0b10111000])?;
Self::encode_segment(a,data)?;
Self::encode_segment(b,data)?;
Self::encode_segment(c,data)?;
Self::encode_segment(result,data)?;
}
Statement::Memory{ op: MemoryOperation::Allocate{ base }, result } => {
data.write(&[0b10111001])?;
leb128::write::unsigned(data,base.index() as u64)?;
Self::encode_segment(result,data)?;
}
Statement::Expression{ op: Assume(constr,a), result } => {
let code = match (&constr,&a) {
(&Constraint::Empty{ .. },&Value::Variable(..)) => 0b000,
(&Constraint::Unsigned{ .. },&Value::Variable(..)) => 0b001,
(&Constraint::Signed{ .. },&Value::Variable(..)) => 0b010,
(&Constraint::Full{ .. },&Value::Variable(..)) => 0b011,
(&Constraint::Empty{ .. },_) => 0b100,
(&Constraint::Unsigned{ .. },_) => 0b101,
(&Constraint::Signed{ .. },_) => 0b110,
(&Constraint::Full{ .. },_) => 0b111,
};
data.write(&[0b1100_0000 | code])?;
Self::encode_constraint(constr,data)?;
if let Value::Variable(var) = a {
Self::encode_variable(var,data)?;
}
Self::encode_variable(result,data)?;
}
}
Ok(())
}
fn encode_constant<W: Write>(c: Constant, data: &mut W) -> Result<()> {
let Constant{ value, bits } = c;
leb128::write::unsigned(data,bits as u64)?;
leb128::write::unsigned(data,value)?;
Ok(())
}
fn encode_variable<W: Write>(c: Variable, data: &mut W) -> Result<()> {
let Variable{ name, bits } = c;
leb128::write::unsigned(data,name.index() as u64)?;
leb128::write::unsigned(data,bits as u64)?;
Ok(())
}
fn encode_segment<W: Write>(c: Segment, data: &mut W) -> Result<()> {
let Segment{ name } = c;
leb128::write::unsigned(data,name.index() as u64)?;
Ok(())
}
fn encode_constraint<W: Write>(c: Constraint, data: &mut W) -> Result<()> {
match c {
Constraint::Empty{ bits } => {
leb128::write::unsigned(data,bits as u64)?;
}
Constraint::Unsigned{ from, to, bits } => {
leb128::write::unsigned(data,bits as u64)?;
leb128::write::unsigned(data,from)?;
leb128::write::unsigned(data,to)?;
}
Constraint::Signed{ from, to, bits } => {
leb128::write::unsigned(data,bits as u64)?;
leb128::write::signed(data,from)?;
leb128::write::signed(data,to)?;
}
Constraint::Full{ bits } => {
leb128::write::unsigned(data,bits as u64)?;
}
}
Ok(())
}
fn encode_uuid<W: Write>(uu: UUID, data: &mut W) -> Result<()> {
let (sch, hi, lo) = match uu {
UUID::Name{ name, scope } => (0, name, scope),
UUID::Number{ value1, value2 } => (1, value1, value2),
UUID::Derived{ timestamp, origin } => (2, timestamp, origin),
UUID::Event{ timestamp, origin } => (3, timestamp, origin),
};
data.write(&[sch])?;
leb128::write::unsigned(data,hi)?;
leb128::write::unsigned(data,lo)?;
Ok(())
}
fn decode_statement<R: Read>(&self, data: &mut R) -> Result<Statement> {
let mut opcode = [0u8; 1];
data.read_exact(&mut opcode)?;
match opcode[0] {
0b00000_000...0b00001_000 => {
let (a,b) = self.decode_arguments(opcode[0] & 0b111,data)?;
let res = self.decode_variable(data)?;
let stmt = Statement::Expression{ op: Operation::Add(a,b), result: res };
Ok(stmt)
}
0b00001_000...0b00010_000 => {
let (a,b) = self.decode_arguments(opcode[0] & 0b111,data)?;
let res = self.decode_variable(data)?;
let stmt = Statement::Expression{ op: Operation::Subtract(a,b), result: res };
Ok(stmt)
}
0b00010_000...0b00011_000 => {
let (a,b) = self.decode_arguments(opcode[0] & 0b111,data)?;
let res = self.decode_variable(data)?;
let stmt = Statement::Expression{ op: Operation::Multiply(a,b), result: res };
Ok(stmt)
}
0b00011_000...0b00100_000 => {
let (a,b) = self.decode_arguments(opcode[0] & 0b111,data)?;
let res = self.decode_variable(data)?;
let stmt = Statement::Expression{ op: Operation::DivideUnsigned(a,b), result: res };
Ok(stmt)
}
0b00100_000...0b00101_000 => {
let (a,b) = self.decode_arguments(opcode[0] & 0b111,data)?;
let res = self.decode_variable(data)?;
let stmt = Statement::Expression{ op: Operation::DivideSigned(a,b), result: res };
Ok(stmt)
}
0b00101_000...0b00110_000 => {
let (a,b) = self.decode_arguments(opcode[0] & 0b111,data)?;
let res = self.decode_variable(data)?;
let stmt = Statement::Expression{ op: Operation::ShiftLeft(a,b), result: res };
Ok(stmt)
}
0b00110_000...0b00111_000 => {
let (a,b) = self.decode_arguments(opcode[0] & 0b111,data)?;
let res = self.decode_variable(data)?;
let stmt = Statement::Expression{ op: Operation::ShiftRightUnsigned(a,b), result: res };
Ok(stmt)
}
0b00111_000...0b01000_000 => {
let (a,b) = self.decode_arguments(opcode[0] & 0b111,data)?;
let res = self.decode_variable(data)?;
let stmt = Statement::Expression{ op: Operation::ShiftRightSigned(a,b), result: res };
Ok(stmt)
}
0b01000_000...0b01001_000 => {
let (a,b) = self.decode_arguments(opcode[0] & 0b111,data)?;
let res = self.decode_variable(data)?;
let stmt = Statement::Expression{ op: Operation::Modulo(a,b), result: res };
Ok(stmt)
}
0b01001_000...0b01010_000 => {
let (a,b) = self.decode_arguments(opcode[0] & 0b111,data)?;
let res = self.decode_variable(data)?;
let stmt = Statement::Expression{ op: Operation::And(a,b), result: res };
Ok(stmt)
}
0b01010_000...0b01011_000 => {
let (a,b) = self.decode_arguments(opcode[0] & 0b111,data)?;
let res = self.decode_variable(data)?;
let stmt = Statement::Expression{ op: Operation::InclusiveOr(a,b), result: res };
Ok(stmt)
}
0b01011_000...0b01100_000 => {
let (a,b) = self.decode_arguments(opcode[0] & 0b111,data)?;
let res = self.decode_variable(data)?;
let stmt = Statement::Expression{ op: Operation::ExclusiveOr(a,b), result: res };
Ok(stmt)
}
0b01100_000...0b01101_000 => {
let (a,b) = self.decode_arguments(opcode[0] & 0b111,data)?;
let res = self.decode_variable(data)?;
let stmt = Statement::Expression{ op: Operation::Equal(a,b), result: res };
Ok(stmt)
}
0b01101_000...0b01110_000 => {
let (a,b) = self.decode_arguments(opcode[0] & 0b111,data)?;
let res = self.decode_variable(data)?;
let stmt = Statement::Expression{ op: Operation::LessOrEqualUnsigned(a,b), result: res };
Ok(stmt)
}
0b01110_000...0b01111_000 => {
let (a,b) = self.decode_arguments(opcode[0] & 0b111,data)?;
let res = self.decode_variable(data)?;
let stmt = Statement::Expression{ op: Operation::LessOrEqualSigned(a,b), result: res };
Ok(stmt)
}
0b01111_000...0b10000_000 => {
let (a,b) = self.decode_arguments(opcode[0] & 0b111,data)?;
let res = self.decode_variable(data)?;
let stmt = Statement::Expression{ op: Operation::LessUnsigned(a,b), result: res };
Ok(stmt)
}
0b10000_000...0b10000_111 => {
let (a,b) = self.decode_arguments(opcode[0] & 0b111,data)?;
let res = self.decode_variable(data)?;
let stmt = Statement::Expression{ op: Operation::LessSigned(a,b), result: res };
Ok(stmt)
}
0b1000_1000 | 0b1000_1001 => {
let sz = leb128::read::unsigned(data)? as usize;
let a = if opcode[0] & 1 == 0 {
Value::Constant(self.decode_constant(data)?)
} else {
Value::Variable(self.decode_variable(data)?)
};
let res = self.decode_variable(data)?;
let stmt = Statement::Expression{ op: Operation::ZeroExtend(sz,a), result: res };
Ok(stmt)
}
0b1000_1010 | 0b1000_1011 => {
let sz = leb128::read::unsigned(data)? as usize;
let a = if opcode[0] & 1 == 0 {
Value::Constant(self.decode_constant(data)?)
} else {
Value::Variable(self.decode_variable(data)?)
};
let res = self.decode_variable(data)?;
let stmt = Statement::Expression{ op: Operation::SignExtend(sz,a), result: res };
Ok(stmt)
}
0b1000_1100 | 0b1000_1101 => {
let a = if opcode[0] & 1 == 0 {
Value::Constant(self.decode_constant(data)?)
} else {
Value::Variable(self.decode_variable(data)?)
};
let res = self.decode_variable(data)?;
let stmt = Statement::Expression{ op: Operation::Move(a), result: res };
Ok(stmt)
}
0b1000_1110 => {
let res = self.decode_variable(data)?;
let stmt = Statement::Expression{ op: Operation::Move(Value::Undefined), result: res };
Ok(stmt)
}
0b1000_1111 => {
let name = leb128::read::unsigned(data)? as usize;
let sz = leb128::read::unsigned(data)? as usize;
let res = self.decode_variable(data)?;
let stmt = Statement::Expression{
op: Operation::Initialize(StrRef::new(name),sz),
result: res
};
Ok(stmt)
}
0b1001_0000...0b1001_0011 => {
let off = leb128::read::unsigned(data)? as usize;
let sz = leb128::read::unsigned(data)? as usize;
let val = if opcode[0] & 0b1 == 0 {
Value::Constant(self.decode_constant(data)?)
} else {
Value::Variable(self.decode_variable(data)?)
};
let res = self.decode_variable(data)?;
let stmt = Statement::Expression{
op: Operation::Select(off,sz,val),
result: res
};
Ok(stmt)
}
0b1001_0100...0b1001_0111 => {
let seg = self.decode_segment(data)?;
let sz = leb128::read::unsigned(data)? as usize;
let val = if opcode[0] & 0b1 == 0 {
Value::Constant(self.decode_constant(data)?)
} else {
Value::Variable(self.decode_variable(data)?)
};
let endianess = if opcode[0] & 0b10 == 0 {
Endianess::Little
} else {
Endianess::Big
};
let res = self.decode_variable(data)?;
let stmt = Statement::Expression{
op: Operation::Load(seg,endianess,sz,val),
result: res
};
Ok(stmt)
}
0b1001_1000 => {
let a = Value::Variable(self.decode_variable(data)?);
let b = Value::Variable(self.decode_variable(data)?);
let res = self.decode_variable(data)?;
let stmt = Statement::Expression{
op: Operation::Phi(a,b,Value::Undefined),
result: res
};
Ok(stmt)
}
0b1001_1001 => {
let a = Value::Variable(self.decode_variable(data)?);
let b = Value::Variable(self.decode_variable(data)?);
let c = Value::Variable(self.decode_variable(data)?);
let res = self.decode_variable(data)?;
let stmt = Statement::Expression{
op: Operation::Phi(a,b,c),
result: res
};
Ok(stmt)
}
0b1001_1010 => {
let s = leb128::read::unsigned(data)? as usize;
let stmt = Statement::Flow{
op: FlowOperation::ExternalCall{
external: StrRef::new(s)
}
};
Ok(stmt)
}
0b1001_1011 => {
let stmt = Statement::Flow{
op: FlowOperation::Call{
function: self.decode_uuid(data)?
}
};
Ok(stmt)
}
0b1001_1101 => {
let stmt = Statement::Flow{ op:
FlowOperation::IndirectCall{
target: self.decode_variable(data)?
},
};
Ok(stmt)
}
0b1001_1111 => {
let res = self.decode_variable(data)?;
let stmt = Statement::Expression{
op: Operation::Phi(
Value::undef(),
Value::undef(),
Value::undef()),
result: res
};
Ok(stmt)
}
0b1010_0000...0b1010_1111 => {
let seg = self.decode_segment(data)?;
let sz = leb128::read::unsigned(data)? as usize;
let (addr,val) = self.decode_arguments(opcode[0] & 0b111,data)?;
let res = self.decode_segment(data)?;
let endianess = if opcode[0] & 0b1000 == 0 {
Endianess::Little
} else {
Endianess::Big
};
let stmt = Statement::Memory{
op: MemoryOperation::Store{
segment: seg,
bytes: sz,
endianess: endianess,
address: addr,
value: val,
},
result: res,
};
Ok(stmt)
}
0b1011_0000 => {
let stmt = Statement::Flow{ op: FlowOperation::Return };
Ok(stmt)
}
0b1011_0010 | 0b1011_0011 => {
let seg = self.decode_segment(data)?;
let sz = leb128::read::unsigned(data)? as usize;
let endianess = if opcode[0] & 1 == 0 {
Endianess::Little
} else {
Endianess::Big
};
let res = self.decode_variable(data)?;
let stmt = Statement::Expression{
op: Operation::Load(seg,endianess,sz,Value::Undefined),
result: res
};
Ok(stmt)
}
0b10110100 => {
let a = Value::Variable(self.decode_variable(data)?);
let res = self.decode_variable(data)?;
let stmt = Statement::Expression{
op: Operation::Phi(a,Value::undef(),Value::undef()),
result: res
};
Ok(stmt)
}
0b10110101 => {
let res = self.decode_segment(data)?;
let stmt = Statement::Memory{
op: MemoryOperation::MemoryPhi(None,None,None),
result: res
};
data.read(&mut [0;3])?;
Ok(stmt)
}
0b10110110 => {
let a = self.decode_segment(data)?;
let res = self.decode_segment(data)?;
let stmt = Statement::Memory{
op: MemoryOperation::MemoryPhi(Some(a),None,None),
result: res
};
data.read(&mut [0;2])?;
Ok(stmt)
}
0b10110111 => {
let a = self.decode_segment(data)?;
let b = self.decode_segment(data)?;
let res = self.decode_segment(data)?;
let stmt = Statement::Memory{
op: MemoryOperation::MemoryPhi(Some(a),Some(b),None),
result: res
};
data.read(&mut [0;1])?;
Ok(stmt)
}
0b10111000 => {
let a = self.decode_segment(data)?;
let b = self.decode_segment(data)?;
let c = self.decode_segment(data)?;
let res = self.decode_segment(data)?;
let stmt = Statement::Memory{
op: MemoryOperation::MemoryPhi(Some(a),Some(b),Some(c)),
result: res
};
Ok(stmt)
}
0b1011_1001 => {
let name = leb128::read::unsigned(data)? as usize;
let res = self.decode_segment(data)?;
let stmt = Statement::Memory{
op: MemoryOperation::Allocate{ base: StrRef::new(name) },
result: res
};
Ok(stmt)
}
0b1100_0000...0b1100_0111 => {
let constr = self.decode_constraint(opcode[0] & 0b11,data)?;
let a = if opcode[0] & 0b100 == 0 {
Value::Variable(self.decode_variable(data)?)
} else {
Value::Undefined
};
let res = self.decode_variable(data)?;
let stmt = Statement::Expression{ op: Operation::Assume(constr,a), result: res };
Ok(stmt)
}
_ => Err(format!("Internal error: invalid bitcode {:b}",opcode[0]).into()),
}
}
fn decode_arguments<R: Read>(&self, code: u8, data: &mut R) -> Result<(Value,Value)> {
match code {
0b000 => {
let a = self.decode_constant(data)?;
let b = self.decode_constant(data)?;
Ok((Value::Constant(a),Value::Constant(b)))
}
0b001 => {
let a = self.decode_constant(data)?;
let b = self.decode_variable(data)?;
Ok((Value::Constant(a),Value::Variable(b)))
}
0b010 => {
let a = self.decode_constant(data)?;
Ok((Value::Constant(a),Value::Undefined))
}
0b011 => {
let a = self.decode_variable(data)?;
let b = self.decode_constant(data)?;
Ok((Value::Variable(a),Value::Constant(b)))
}
0b100 => {
let a = self.decode_variable(data)?;
let b = self.decode_variable(data)?;
Ok((Value::Variable(a),Value::Variable(b)))
}
0b101 => {
let a = self.decode_variable(data)?;
Ok((Value::Variable(a),Value::Undefined))
}
0b110 => {
let a = self.decode_constant(data)?;
Ok((Value::Undefined,Value::Constant(a)))
}
0b111 => {
let a = self.decode_variable(data)?;
Ok((Value::Undefined,Value::Variable(a)))
}
_ => Err(format!("internal error: impossible argument code {:b}",code).into())
}
}
fn decode_uuid<R: Read>(&self, data: &mut R) -> Result<UUID> {
let mut buf = [0u8; 1];
data.read_exact(&mut buf)?;
let hi = leb128::read::unsigned(data)?;
let lo = leb128::read::unsigned(data)?;
match buf[0] {
0 => Ok(UUID::Name{ name: hi, scope: lo }),
1 => Ok(UUID::Number{ value1: hi, value2: lo }),
2 => Ok(UUID::Derived{ timestamp: hi, origin: lo }),
3 => Ok(UUID::Event{ timestamp: hi, origin: lo }),
_ => Err("unknown UUID scheme".into()),
}
}
fn decode_constant<R: Read>(&self, data: &mut R) -> Result<Constant> {
let bits = leb128::read::unsigned(data)?;
let value = leb128::read::unsigned(data)?;
Ok(Constant{ bits: bits as usize, value: value })
}
fn decode_segment<R: Read>(&self, data: &mut R) -> Result<Segment> {
let name = leb128::read::unsigned(data)?;
let seg = Segment{
name: SegmentRef::new(name as usize),
};
Ok(seg)
}
fn decode_variable<R: Read>(&self, data: &mut R) -> Result<Variable> {
let name = leb128::read::unsigned(data)?;
let bits = leb128::read::unsigned(data)?;
let var = Variable{
name: NameRef::new(name as usize),
bits: bits as usize,
};
Ok(var)
}
fn decode_constraint<R: Read>(&self, code: u8, data: &mut R) -> Result<Constraint> {
let bits = leb128::read::unsigned(data)? as usize;
match code {
0b00 => {
Ok(Constraint::Empty{ bits: bits })
}
0b01 => {
let from = leb128::read::unsigned(data)?;
let to = leb128::read::unsigned(data)?;
let ret = Constraint::Unsigned{
bits: bits,
from: from,
to: to,
};
Ok(ret)
}
0b10 => {
let from = leb128::read::signed(data)?;
let to = leb128::read::signed(data)?;
let ret = Constraint::Signed{
bits: bits,
from: from,
to: to,
};
Ok(ret)
}
0b11 => {
Ok(Constraint::Full{ bits: bits })
}
_ => Err(format!("internal error: impossible constraint code {:b}",code).into())
}
}
pub fn iter<'a>(&'a self) -> BitcodeIter<'a> {
BitcodeIter{
cursor: Cursor::new(&self.data),
bitcode: self,
}
}
pub fn iter_range<'a>(&'a self, rgn: Range<usize>) -> BitcodeIter<'a> {
BitcodeIter{
cursor: Cursor::new(&self.data[rgn]),
bitcode: self,
}
}
pub fn num_bytes(&self) -> usize {
self.data.len()
}
}
pub struct BitcodeIter<'a> {
cursor: Cursor<&'a [u8]>,
bitcode: &'a Bitcode,
}
impl<'a> Iterator for BitcodeIter<'a> {
type Item = Statement;
fn next(&mut self) -> Option<Self::Item> {
self.bitcode.decode_statement(&mut self.cursor).ok()
}
}
#[cfg(test)]
mod tests {
use super::*;
use simple_logger;
quickcheck! {
fn round_trip(v: Vec<Statement>) -> bool {
let _ = simple_logger::init();
debug!("in: {:?}",v);
match Bitcode::new(v.clone()) {
Ok(bt) => {
debug!("{:?}",bt);
let w = bt.iter().collect::<Vec<_>>();
debug!("decoded: {:?}",w);
v == w
}
Err(s) => {
debug!("err: {}",s);
false
}
}
}
}
#[test]
fn rewrite_equal_size() {
use Operation::Add;
let s1 = Statement::Expression{
op: Add(Value::val(42,32).unwrap(),Value::var(NameRef::new(0),32).unwrap()),
result: Variable::new(NameRef::new(0),32).unwrap()
};
let s2 = Statement::Expression{
op: Add(Value::val(42,32).unwrap(),Value::var(NameRef::new(0),32).unwrap()),
result: Variable::new(NameRef::new(0),32).unwrap()
};
let s3 = Statement::Expression{
op: Add(Value::val(42,32).unwrap(),Value::var(NameRef::new(0),32).unwrap()),
result: Variable::new(NameRef::new(0),32).unwrap()
};
let mut bitcode = Bitcode::default();
let _ = bitcode.append(vec![s1]).unwrap();
let rgn = bitcode.append(vec![s2]).unwrap();
let _ = bitcode.append(vec![s3]).unwrap();
let mut names = Names::default();
let mut strings = Strings::default();
let mut segments = Segments::default();
let new_rgn = bitcode.rewrite(rgn.clone(),&mut names,&mut strings,&mut segments, |stmt,_,_,_| {
match stmt {
&mut Statement::Expression{ op: Add(Value::Constant(ref mut a),Value::Variable(ref mut b)), ref mut result } => {
*a = Constant::new(43,32).unwrap();
*b = Variable::new(NameRef::new(1),32).unwrap();
*result = Variable::new(NameRef::new(2),32).unwrap();
}
_ => { unreachable!() }
}
Ok(RewriteControl::Continue)
}).unwrap();
assert_eq!(rgn, new_rgn);
for (idx,stmt) in bitcode.iter().enumerate() {
match stmt {
Statement::Expression{ op: Add(Value::Constant(a),Value::Variable(b)), result } => {
if idx == 0 || idx == 2 {
assert_eq!(a, Constant::new(42,32).unwrap());
assert_eq!(b, Variable::new(NameRef::new(0),32).unwrap());
assert_eq!(result, Variable::new(NameRef::new(0),32).unwrap());
} else if idx == 1 {
assert_eq!(a, Constant::new(43,32).unwrap());
assert_eq!(b, Variable::new(NameRef::new(1),32).unwrap());
assert_eq!(result, Variable::new(NameRef::new(2),32).unwrap());
} else {
unreachable!()
}
}
_ => { unreachable!() }
}
}
}
#[test]
fn rewrite_smaller_size() {
use Operation::Add;
let s1 = Statement::Expression{
op: Add(Value::val(42,32).unwrap(),Value::var(NameRef::new(0),32).unwrap()),
result: Variable::new(NameRef::new(0),32).unwrap()
};
let s2 = Statement::Expression{
op: Add(Value::val(42,32).unwrap(),Value::var(NameRef::new(0),32).unwrap()),
result: Variable::new(NameRef::new(0),32).unwrap()
};
let s3 = Statement::Expression{
op: Add(Value::val(42,32).unwrap(),Value::var(NameRef::new(0),32).unwrap()),
result: Variable::new(NameRef::new(0),32).unwrap()
};
let mut bitcode = Bitcode::default();
let _ = bitcode.append(vec![s1]).unwrap();
let rgn = bitcode.append(vec![s2]).unwrap();
let _ = bitcode.append(vec![s3]).unwrap();
let mut names = Names::default();
let mut strings = Strings::default();
let mut segments = Segments::default();
let new_rgn = bitcode.rewrite(rgn.clone(),&mut names, &mut strings,&mut segments, |stmt,_,_,_| {
*stmt = Statement::Flow{ op: FlowOperation::Return };
Ok(RewriteControl::Continue)
}).unwrap();
assert_eq!(rgn.start, new_rgn.start);
for (idx,stmt) in bitcode.iter().enumerate() {
match stmt {
Statement::Expression{ op: Add(Value::Constant(a),Value::Variable(b)), result } => {
assert_eq!(a, Constant::new(42,32).unwrap());
assert_eq!(b, Variable::new(NameRef::new(0),32).unwrap());
assert_eq!(result, Variable::new(NameRef::new(0),32).unwrap());
assert!(idx == 0 || idx == 2);
}
Statement::Flow{ op: FlowOperation::Return } => {
assert_eq!(idx, 1);
}
_ => { unreachable!() }
}
}
}
#[test]
fn rewrite_larger_size() {
use Operation::Add;
let s1 = Statement::Expression{
op: Add(Value::val(42,32).unwrap(),Value::var(NameRef::new(0),32).unwrap()),
result: Variable::new(NameRef::new(0),32).unwrap()
};
let s2 = Statement::Flow{ op: FlowOperation::Return };
let s3 = Statement::Expression{
op: Add(Value::val(42,32).unwrap(),Value::var(NameRef::new(0),32).unwrap()),
result: Variable::new(NameRef::new(0),32).unwrap()
};
let mut bitcode = Bitcode::default();
let _ = bitcode.append(vec![s1]).unwrap();
let rgn = bitcode.append(vec![s2]).unwrap();
let _ = bitcode.append(vec![s3]).unwrap();
let mut names = Names::default();
let mut strings = Strings::default();
let mut segments = Segments::default();
let new_rgn = bitcode.rewrite(rgn.clone(),&mut names,&mut strings,&mut segments, |stmt,_,_,_| {
*stmt = Statement::Expression{
op: Add(Value::val(42,32).unwrap(),Value::var(NameRef::new(0),32).unwrap()),
result: Variable::new(NameRef::new(0),32).unwrap()
};
Ok(RewriteControl::Continue)
}).unwrap();
assert_eq!(rgn.start, new_rgn.start);
assert!(rgn.end < new_rgn.end);
for stmt in bitcode.iter() {
match stmt {
Statement::Expression{ op: Add(Value::Constant(a),Value::Variable(b)), result } => {
assert_eq!(a, Constant::new(42,32).unwrap());
assert_eq!(b, Variable::new(NameRef::new(0),32).unwrap());
assert_eq!(result, Variable::new(NameRef::new(0),32).unwrap());
}
_ => { unreachable!() }
}
}
}
#[test]
fn insert_mid() {
use Operation::Add;
let s1 = Statement::Expression{
op: Add(Value::val(42,32).unwrap(),Value::var(NameRef::new(0),32).unwrap()),
result: Variable::new(NameRef::new(0),32).unwrap()
};
let s2 = Statement::Expression{
op: Add(Value::val(42,32).unwrap(),Value::var(NameRef::new(0),32).unwrap()),
result: Variable::new(NameRef::new(0),32).unwrap()
};
let mut bitcode = Bitcode::default();
let _ = bitcode.append(vec![s1]).unwrap();
let rgn = bitcode.append(vec![s2]).unwrap();
let new_rgn = bitcode.insert(rgn.start,vec![Statement::Flow{ op: FlowOperation::Return }]).unwrap();
assert_eq!(rgn.start, new_rgn.start);
for (idx,stmt) in bitcode.iter().enumerate() {
match stmt {
Statement::Expression{ op: Add(Value::Constant(a),Value::Variable(b)), result } => {
assert_eq!(a, Constant::new(42,32).unwrap());
assert_eq!(b, Variable::new(NameRef::new(0),32).unwrap());
assert_eq!(result, Variable::new(NameRef::new(0),32).unwrap());
assert!(idx == 0 || idx == 2);
}
Statement::Flow{ op: FlowOperation::Return } => {
assert_eq!(idx, 1);
}
_ => { unreachable!() }
}
}
}
#[test]
fn insert_start() {
use Operation::Add;
let s1 = Statement::Expression{
op: Add(Value::val(42,32).unwrap(),Value::var(NameRef::new(0),32).unwrap()),
result: Variable::new(NameRef::new(0),32).unwrap()
};
let mut bitcode = Bitcode::default();
let rgn = bitcode.append(vec![s1]).unwrap();
let new_rgn = bitcode.insert(rgn.start,vec![Statement::Flow{ op: FlowOperation::Return }]).unwrap();
assert_eq!(rgn.start, new_rgn.start);
for (idx,stmt) in bitcode.iter().enumerate() {
match stmt {
Statement::Expression{ op: Add(Value::Constant(a),Value::Variable(b)), result } => {
assert_eq!(a, Constant::new(42,32).unwrap());
assert_eq!(b, Variable::new(NameRef::new(0),32).unwrap());
assert_eq!(result, Variable::new(NameRef::new(0),32).unwrap());
assert_eq!(idx, 1);
}
Statement::Flow{ op: FlowOperation::Return }=> {
assert_eq!(idx, 0);
}
_ => { unreachable!() }
}
}
}
#[test]
fn insert_end() {
use Operation::Add;
let s1 = Statement::Expression{
op: Add(Value::val(42,32).unwrap(),Value::var(NameRef::new(0),32).unwrap()),
result: Variable::new(NameRef::new(0),32).unwrap()
};
let mut bitcode = Bitcode::default();
let rgn = bitcode.append(vec![s1]).unwrap();
let new_rgn = bitcode.insert(rgn.end,vec![Statement::Flow{ op: FlowOperation::Return }]).unwrap();
assert_eq!(rgn.end, new_rgn.start);
for (idx,stmt) in bitcode.iter().enumerate() {
match stmt {
Statement::Expression{ op: Add(Value::Constant(a),Value::Variable(b)), result } => {
assert_eq!(a, Constant::new(42,32).unwrap());
assert_eq!(b, Variable::new(NameRef::new(0),32).unwrap());
assert_eq!(result, Variable::new(NameRef::new(0),32).unwrap());
assert_eq!(idx, 0);
}
Statement::Flow{ op: FlowOperation::Return } => {
assert_eq!(idx, 1);
}
_ => { unreachable!() }
}
}
}
}