Commit c11a21e9 by Enkelmann Committed by Enkelmann

implement conversion functions for jumps and defs.

parent 263c1498
use crate::intermediate_representation::BinOpType as IrBinOpType;
use crate::intermediate_representation::ByteSize;
use crate::intermediate_representation::CastOpType as IrCastOpType;
use crate::intermediate_representation::Expression as IrExpression;
use crate::intermediate_representation::UnOpType as IrUnOpType;
use apint::Width;
use serde::{Deserialize, Serialize};
pub mod variable;
......@@ -7,6 +13,13 @@ pub type Bitvector = apint::ApInt;
pub type BitSize = u16;
impl From<BitSize> for ByteSize {
/// Convert to `ByteSize`, while always rounding up to the nearest full byte.
fn from(bitsize: BitSize) -> ByteSize {
((bitsize as u64 + 7) / 8).into()
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub enum Expression {
Var(Variable),
......@@ -189,6 +202,100 @@ impl Expression {
}
}
}
pub fn bitsize(&self) -> BitSize {
use Expression::*;
match self {
Var(var) => var.bitsize().unwrap(),
Const(bitvector) => bitvector.width().to_usize() as u16,
Load { size, .. } => *size,
Store { .. } => 0,
BinOp { op, lhs, rhs: _ } => {
use BinOpType::*;
match op {
EQ | NEQ | LT | LE | SLT | SLE => 1,
_ => lhs.bitsize(),
}
}
UnOp { arg, .. } => arg.bitsize(),
Cast { width, .. } => *width,
Let { .. } => panic!(),
Unknown {
description: _,
type_,
} => type_.bitsize().unwrap(),
IfThenElse { true_exp, .. } => true_exp.bitsize(),
Extract {
low_bit, high_bit, ..
} => high_bit - low_bit,
Concat { left, right } => left.bitsize() + right.bitsize(),
}
}
}
impl From<Expression> for IrExpression {
fn from(expr: Expression) -> IrExpression {
use Expression::*;
match expr {
Var(var) => IrExpression::Var(var.into()),
Const(bitvector) => IrExpression::Const(bitvector),
Load { .. } | Store { .. } | Let { .. } | Unknown { .. } | IfThenElse { .. } => {
panic!()
}
BinOp { op, lhs, rhs } => IrExpression::BinOp {
op: op.into(),
lhs: Box::new(IrExpression::from(*lhs)),
rhs: Box::new(IrExpression::from(*rhs)),
},
UnOp { op, arg } => IrExpression::UnOp {
op: op.into(),
arg: Box::new(IrExpression::from(*arg)),
},
Cast { kind, width, arg } => {
use CastType::*;
match kind {
UNSIGNED => IrExpression::Cast {
arg: Box::new(IrExpression::from(*arg)),
op: IrCastOpType::IntZExt,
size: width.into(),
},
SIGNED => IrExpression::Cast {
arg: Box::new(IrExpression::from(*arg)),
op: IrCastOpType::IntSExt,
size: width.into(),
},
HIGH => {
assert!(width % 8 == 0);
let low_byte = (arg.bitsize() - BitSize::from(width)).into();
IrExpression::Subpiece {
arg: Box::new(IrExpression::from(*arg)),
low_byte,
size: width.into(),
}
}
LOW => IrExpression::Subpiece {
arg: Box::new(IrExpression::from(*arg)),
low_byte: (0 as u64).into(),
size: width.into(),
},
}
}
Extract {
low_bit,
high_bit,
arg,
} => IrExpression::Subpiece {
size: (high_bit - low_bit + 1).into(),
low_byte: low_bit.into(),
arg: Box::new(IrExpression::from(*arg)),
},
Concat { left, right } => IrExpression::BinOp {
op: IrBinOpType::Piece,
lhs: Box::new(IrExpression::from(*left)),
rhs: Box::new(IrExpression::from(*right)),
},
}
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone, Copy)]
......@@ -222,12 +329,50 @@ pub enum BinOpType {
SLE,
}
impl From<BinOpType> for IrBinOpType {
fn from(op: BinOpType) -> IrBinOpType {
use BinOpType::*;
use IrBinOpType::*;
match op {
PLUS => IntAdd,
MINUS => IntSub,
TIMES => IntMult,
DIVIDE => IntDiv,
SDIVIDE => IntSDiv,
MOD => IntRem,
SMOD => IntSRem,
LSHIFT => IntLeft,
RSHIFT => IntRight,
ARSHIFT => IntSRight,
AND => IntAnd,
OR => IntOr,
XOR => IntXOr,
EQ => IntEqual,
NEQ => IntNotEqual,
LT => IntLess,
LE => IntLessEqual,
SLT => IntSLess,
SLE => IntSLessEqual,
}
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum UnOpType {
NEG,
NOT,
}
impl From<UnOpType> for IrUnOpType {
fn from(op: UnOpType) -> IrUnOpType {
use UnOpType::*;
match op {
NEG => IrUnOpType::Int2Comp,
NOT => IrUnOpType::IntNegate,
}
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum Endianness {
LittleEndian,
......
use super::BitSize;
use crate::intermediate_representation::Variable as IrVariable;
use crate::prelude::*;
use serde::{Deserialize, Serialize};
......@@ -19,12 +20,33 @@ pub enum Type {
Unknown,
}
impl Type {
pub fn bitsize(&self) -> Result<BitSize, Error> {
if let Type::Immediate(bitsize) = self {
Ok(*bitsize)
} else {
Err(anyhow!("Not a register type"))
}
}
}
impl Variable {
pub fn bitsize(&self) -> Result<BitSize, Error> {
if let Type::Immediate(bitsize) = self.type_ {
Ok(bitsize)
self.type_.bitsize()
}
}
impl From<Variable> for IrVariable {
fn from(var: Variable) -> IrVariable {
let size = if let Type::Immediate(bitsize) = var.type_ {
bitsize.into()
} else {
Err(anyhow!("Not a register variable"))
panic!()
};
IrVariable {
name: var.name,
size,
is_temp: var.is_temp,
}
}
}
......
......@@ -38,6 +38,8 @@ pub enum BinOpType {
IntNotEqual,
IntLess,
IntSLess,
IntLessEqual,
IntSLessEqual,
IntAdd,
IntSub,
IntCarry,
......@@ -74,7 +76,6 @@ pub enum CastOpType {
Int2Float,
Float2Float,
Trunc,
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone, Copy)]
......
......@@ -12,51 +12,51 @@ pub use term::*;
// TODO: move ByteSize and BitSize into their own module
#[derive(
Serialize,
Deserialize,
Debug,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Clone,
Copy,
Display,
Binary,
Octal,
LowerHex,
UpperHex,
From,
Into,
Not,
Add,
Sub,
Mul,
Div,
Rem,
Shr,
Shl,
AddAssign,
SubAssign,
MulAssign,
DivAssign,
RemAssign,
ShrAssign,
ShlAssign,
Sum,
Serialize,
Deserialize,
Debug,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Clone,
Copy,
Display,
Binary,
Octal,
LowerHex,
UpperHex,
From,
Into,
Not,
Add,
Sub,
Mul,
Div,
Rem,
Shr,
Shl,
AddAssign,
SubAssign,
MulAssign,
DivAssign,
RemAssign,
ShrAssign,
ShlAssign,
Sum,
)]
#[serde(transparent)]
pub struct ByteSize(u64);
impl From<ByteSize> for BitSize {
fn from(bytesize: ByteSize) -> BitSize {
u16::try_from(u64::from(bytesize) * 8).unwrap()
}
fn from(bytesize: ByteSize) -> BitSize {
u16::try_from(u64::from(bytesize) * 8).unwrap()
}
}
impl From<ByteSize> for apint::BitWidth {
fn from(bytesize: ByteSize) -> apint::BitWidth {
apint::BitWidth::from((u64::from(bytesize) * 8) as usize)
}
}
\ No newline at end of file
fn from(bytesize: ByteSize) -> apint::BitWidth {
apint::BitWidth::from((u64::from(bytesize) * 8) as usize)
}
}
use super::{ByteSize, Expression, Variable};
use crate::prelude::*;
use crate::term::{Term, Tid};
use super::{Variable, Expression, ByteSize};
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub enum Def {
......@@ -18,4 +16,33 @@ pub enum Def {
var: Variable,
value: Expression,
},
}
\ No newline at end of file
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub enum Jmp {
Branch(Tid),
BranchInd(Expression),
CBranch {
target: Tid,
condition: Expression,
},
Call {
target: Tid,
return_: Option<Tid>,
},
CallInd {
target: Expression,
return_: Option<Tid>,
},
Return(Expression),
CallOther {
description: String,
return_: Option<Tid>,
},
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub struct Blk {
pub defs: Vec<Term<Def>>,
pub jmps: Vec<Term<Jmp>>,
}
use crate::prelude::*;
use super::ByteSize;
use crate::prelude::*;
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub struct Variable {
pub name: String,
pub size: ByteSize,
pub is_temp: bool,
}
\ No newline at end of file
pub name: String,
pub size: ByteSize,
pub is_temp: bool,
}
......@@ -11,10 +11,10 @@ pub mod abstract_domain;
pub mod analysis;
pub mod bil;
pub mod ffi;
pub mod intermediate_representation;
pub mod pcode;
pub mod term;
pub mod utils;
pub mod pcode;
pub mod intermediate_representation;
mod prelude {
pub use apint::Width;
......
use crate::prelude::*;
use crate::term::{Term, Tid};
use crate::intermediate_representation::BinOpType as IrBinOpType;
use crate::intermediate_representation::ByteSize;
use crate::intermediate_representation::Variable as IrVariable;
use crate::intermediate_representation::CastOpType as IrCastOpType;
use crate::intermediate_representation::Expression as IrExpression;
use crate::intermediate_representation::BinOpType as IrBinOpType;
use crate::intermediate_representation::UnOpType as IrUnOpType;
use crate::intermediate_representation::CastOpType as IrCastOpType;
use crate::intermediate_representation::Variable as IrVariable;
use crate::prelude::*;
use crate::term::{Term, Tid};
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub struct Variable {
pub name: Option<String>,
pub value: Option<String>,
pub size: ByteSize,
pub is_virtual: bool,
pub name: Option<String>,
pub value: Option<String>,
pub size: ByteSize,
pub is_virtual: bool,
}
impl From<Variable> for IrVariable {
fn from(pcode_var: Variable) -> IrVariable {
IrVariable {
name: pcode_var.name.unwrap(),
size: pcode_var.size,
is_temp: pcode_var.is_virtual, // TODO: rename `pcode_var.is_virtual` to `is_temp`
fn from(pcode_var: Variable) -> IrVariable {
IrVariable {
name: pcode_var.name.unwrap(),
size: pcode_var.size,
is_temp: pcode_var.is_virtual, // TODO: rename `pcode_var.is_virtual` to `is_temp`
}
}
}
}
impl From<Variable> for IrExpression {
fn from(pcode_var: Variable) -> IrExpression {
match (&pcode_var.name, &pcode_var.value) {
(Some(_name), None) => IrExpression::Var(pcode_var.into()),
(None, Some(hex_value)) => {
// TODO: Implement parsing for large hex values.
if pcode_var.size > 8.into() {
panic!("Parsing of immediates greater than 8 bytes not yet implemented: {}", hex_value);
fn from(pcode_var: Variable) -> IrExpression {
match (&pcode_var.name, &pcode_var.value) {
(Some(_name), None) => IrExpression::Var(pcode_var.into()),
(None, Some(hex_value)) => {
// TODO: Implement parsing for large hex values.
if u64::from(pcode_var.size) > 8 {
panic!(
"Parsing of immediates greater than 8 bytes not yet implemented: {}",
hex_value
);
}
let val: u64 = u64::from_str_radix(&hex_value, 16).unwrap();
let mut bitvector: Bitvector = Bitvector::from_u64(val);
bitvector.truncate(pcode_var.size).unwrap();
IrExpression::Const(bitvector)
}
_ => panic!(),
}
let val: u64 = u64::from_str_radix(&hex_value, 16).unwrap();
let mut bitvector: Bitvector = Bitvector::from_u64(val);
bitvector.truncate(pcode_var.size).unwrap();
IrExpression::Const(bitvector)
},
_ => panic!(),
}
}
}
impl From<Variable> for ByteSize {
fn from(pcode_var: Variable) -> ByteSize {
match (&pcode_var.name, &pcode_var.value) {
(None, Some(hex_value)) => {
// TODO: Implement parsing for large hex values.
if pcode_var.size > 8.into() {
panic!("Parsing of immediates greater than 8 bytes not yet implemented: {}", hex_value);
fn from(pcode_var: Variable) -> ByteSize {
match (&pcode_var.name, &pcode_var.value) {
(None, Some(hex_value)) => {
// TODO: Implement parsing for large hex values.
if u64::from(pcode_var.size) > 8 {
panic!(
"Parsing of immediates greater than 8 bytes not yet implemented: {}",
hex_value
);
}
let val: u64 = u64::from_str_radix(&hex_value, 16).unwrap();
val.into()
}
_ => panic!(),
}
let val: u64 = u64::from_str_radix(&hex_value, 16).unwrap();
val.into()
},
_ => panic!(),
}
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub struct Expression {
pub mnemonic: ExpressionType,
pub input0: Option<Variable>,
pub input1: Option<Variable>,
pub input2: Option<Variable>,
}
impl From<Expression> for IrExpression {
fn from(expr: Expression) -> IrExpression {
match expr.mnemonic {
_ => todo!(),
}
}
pub mnemonic: ExpressionType,
pub input0: Option<Variable>,
pub input1: Option<Variable>,
pub input2: Option<Variable>,
}
#[allow(non_camel_case_types)]
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum ExpressionType {
COPY,
LOAD,
STORE,
PIECE,
SUBPIECE,
COPY,
LOAD,
STORE,
PIECE,
SUBPIECE,
INT_EQUAL,
INT_NOTEQUAL,
INT_LESS,
INT_SLESS,
INT_LESSEQUAL,
INT_SLESSEQUAL,
INT_ADD,
INT_SUB,
INT_CARRY,
INT_SCARRY,
INT_SBORROW,
INT_XOR,
INT_AND,
INT_OR,
INT_LEFT,
INT_RIGHT,
INT_SRIGHT,
INT_MULT,
INT_DIV,
INT_REM,
INT_SDIV,
INT_SREM,
INT_EQUAL,
INT_NOTEQUAL,
INT_LESS,
INT_SLESS,
INT_ADD,
INT_SUB,
BOOL_XOR,
BOOL_AND,
BOOL_OR,
INT_CARRY,
INT_SCARRY,
INT_SBORROW,
INT_XOR,
INT_AND,
INT_OR,
FLOAT_EQUAL,
FLOAT_NOTEQUAL,
FLOAT_LESS,
FLOAT_LESSEQUAL,
INT_LEFT,
INT_RIGHT,
INT_SRIGHT,
INT_MULT,
INT_DIV,
FLOAT_ADD,
FLOAT_SUB,
FLOAT_MULT,
FLOAT_DIV,
INT_REM,
INT_SDIV,
INT_SREM,
BOOL_XOR,
BOOL_AND,
BOOL_OR,
FLOAT_EQUAL,
FLOAT_NOTEQUAL,
FLOAT_LESS,
FLOAT_LESSEQUAL,
FLOAT_ADD,
FLOAT_SUB,
FLOAT_MULT,
FLOAT_DIV,
INT_NEGATE,
INT_2COMP,
BOOL_NEGATE,
INT_NEGATE,
INT_2COMP,
BOOL_NEGATE,
FLOAT_NEGATE,
FLOAT_ABS,
FLOAT_SQRT,
FLOAT_CEIL,
FLOAT_FLOOR,
FLOAT_ROUND,
FLOAT_NAN,
FLOAT_NEGATE,
FLOAT_ABS,
FLOAT_SQRT,
FLOAT_CEIL,
FLOAT_FLOOR,
FLOAT_ROUND,
FLOAT_NAN,
INT_ZEXT,
INT_SEXT,
INT2FLOAT,
FLOAT2FLOAT,
TRUNC,
INT_ZEXT,
INT_SEXT,
INT2FLOAT,
FLOAT2FLOAT,
TRUNC,
}
impl From<ExpressionType> for IrBinOpType {
fn from(expr_type: ExpressionType) -> IrBinOpType {
use ExpressionType::*;
match expr_type {
PIECE => IrBinOpType::Piece,
INT_EQUAL => IrBinOpType::IntEqual,
INT_NOTEQUAL => IrBinOpType::IntNotEqual,
INT_LESS => IrBinOpType::IntLess,
INT_SLESS => IrBinOpType::IntSLess,
INT_ADD => IrBinOpType::IntAdd,
INT_SUB => IrBinOpType::IntSub,
fn from(expr_type: ExpressionType) -> IrBinOpType {
use ExpressionType::*;
use IrBinOpType::*;
match expr_type {
PIECE => IrBinOpType::Piece,
INT_EQUAL => IrBinOpType::IntEqual,
INT_NOTEQUAL => IrBinOpType::IntNotEqual,
INT_LESS => IrBinOpType::IntLess,
INT_SLESS => IrBinOpType::IntSLess,
INT_LESSEQUAL => IntLessEqual,
INT_SLESSEQUAL => IntSLessEqual,
INT_CARRY => IrBinOpType::IntCarry,
INT_SCARRY => IrBinOpType::IntSCarry,
INT_SBORROW => IrBinOpType::IntSBorrow,
INT_XOR => IrBinOpType::IntXOr,
INT_AND => IrBinOpType::IntAnd,
INT_OR => IrBinOpType::IntOr,
INT_ADD => IrBinOpType::IntAdd,
INT_SUB => IrBinOpType::IntSub,
INT_LEFT => IrBinOpType::IntLeft,
INT_RIGHT => IrBinOpType::IntRight,
INT_SRIGHT => IrBinOpType::IntSRight,
INT_MULT => IrBinOpType::IntMult,
INT_DIV => IrBinOpType::IntDiv,
INT_CARRY => IrBinOpType::IntCarry,
INT_SCARRY => IrBinOpType::IntSCarry,
INT_SBORROW => IrBinOpType::IntSBorrow,
INT_XOR => IrBinOpType::IntXOr,
INT_AND => IrBinOpType::IntAnd,
INT_OR => IrBinOpType::IntOr,
INT_REM => IrBinOpType::IntRem,
INT_SDIV => IrBinOpType::IntSDiv,
INT_SREM => IrBinOpType::IntSRem,
BOOL_XOR => IrBinOpType::BoolXOr,
BOOL_AND => IrBinOpType::BoolAnd,
INT_LEFT => IrBinOpType::IntLeft,
INT_RIGHT => IrBinOpType::IntRight,
INT_SRIGHT => IrBinOpType::IntSRight,
INT_MULT => IrBinOpType::IntMult,
INT_DIV => IrBinOpType::IntDiv,
BOOL_OR => IrBinOpType::BoolOr,
FLOAT_EQUAL => IrBinOpType::FloatEqual,
FLOAT_NOTEQUAL => IrBinOpType::FloatNotEqual,
FLOAT_LESS => IrBinOpType::FloatLess,
FLOAT_LESSEQUAL => IrBinOpType::FloatLessEqual,
INT_REM => IrBinOpType::IntRem,
INT_SDIV => IrBinOpType::IntSDiv,
INT_SREM => IrBinOpType::IntSRem,
BOOL_XOR => IrBinOpType::BoolXOr,
BOOL_AND => IrBinOpType::BoolAnd,
FLOAT_ADD => IrBinOpType::FloatAdd,
FLOAT_SUB => IrBinOpType::FloatSub,
FLOAT_MULT => IrBinOpType::FloatMult,
FLOAT_DIV => IrBinOpType::FloatDiv,
BOOL_OR => IrBinOpType::BoolOr,
FLOAT_EQUAL => IrBinOpType::FloatEqual,
FLOAT_NOTEQUAL => IrBinOpType::FloatNotEqual,
FLOAT_LESS => IrBinOpType::FloatLess,
FLOAT_LESSEQUAL => IrBinOpType::FloatLessEqual,
_ => panic!(),
FLOAT_ADD => IrBinOpType::FloatAdd,
FLOAT_SUB => IrBinOpType::FloatSub,
FLOAT_MULT => IrBinOpType::FloatMult,
FLOAT_DIV => IrBinOpType::FloatDiv,
_ => panic!(),
}
}
}
}
impl From<ExpressionType> for IrUnOpType {
fn from(expr_type: ExpressionType) -> IrUnOpType {
use ExpressionType::*;
match expr_type {
INT_NEGATE => IrUnOpType::IntNegate,
INT_2COMP => IrUnOpType::Int2Comp,
BOOL_NEGATE => IrUnOpType::BoolNegate,
FLOAT_NEGATE => IrUnOpType::FloatNegate,
FLOAT_ABS => IrUnOpType::FloatAbs,
FLOAT_SQRT => IrUnOpType::FloatSqrt,
FLOAT_CEIL => IrUnOpType::FloatCeil,
FLOAT_FLOOR => IrUnOpType::FloatFloor,
FLOAT_ROUND => IrUnOpType::FloatRound,
FLOAT_NAN => IrUnOpType::FloatNaN,
_ => panic!(),
fn from(expr_type: ExpressionType) -> IrUnOpType {
use ExpressionType::*;
match expr_type {
INT_NEGATE => IrUnOpType::IntNegate,
INT_2COMP => IrUnOpType::Int2Comp,
BOOL_NEGATE => IrUnOpType::BoolNegate,
FLOAT_NEGATE => IrUnOpType::FloatNegate,
FLOAT_ABS => IrUnOpType::FloatAbs,
FLOAT_SQRT => IrUnOpType::FloatSqrt,
FLOAT_CEIL => IrUnOpType::FloatCeil,
FLOAT_FLOOR => IrUnOpType::FloatFloor,
FLOAT_ROUND => IrUnOpType::FloatRound,
FLOAT_NAN => IrUnOpType::FloatNaN,
_ => panic!(),
}
}
}
}
impl From<ExpressionType> for IrCastOpType {
fn from(expr_type: ExpressionType) -> IrCastOpType {
use ExpressionType::*;
match expr_type {
INT_ZEXT => IrCastOpType::IntZExt,
INT_SEXT => IrCastOpType::IntSExt,
INT2FLOAT => IrCastOpType::Int2Float,
FLOAT2FLOAT => IrCastOpType::Float2Float,
TRUNC => IrCastOpType::Trunc,
_ => panic!(),
fn from(expr_type: ExpressionType) -> IrCastOpType {
use ExpressionType::*;
match expr_type {
INT_ZEXT => IrCastOpType::IntZExt,
INT_SEXT => IrCastOpType::IntSExt,
INT2FLOAT => IrCastOpType::Int2Float,
FLOAT2FLOAT => IrCastOpType::Float2Float,
TRUNC => IrCastOpType::Trunc,
_ => panic!(),
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use super::*;
#[test]
fn variable_deserialization() {
let _: Variable = serde_json::from_str(
r#"
#[test]
fn variable_deserialization() {
let _: Variable = serde_json::from_str(
r#"
{
"name": "RSP",
"size": 8,
"is_virtual": false
}
"#,
)
.unwrap();
}
)
.unwrap();
}
#[test]
fn expression_deserialization() {
let _: Expression = serde_json::from_str(
r#"
#[test]
fn expression_deserialization() {
let _: Expression = serde_json::from_str(
r#"
{
"mnemonic": "INT_SUB",
"input0": {
......@@ -257,7 +263,7 @@ mod tests {
}
}
"#,
)
.unwrap();
}
}
\ No newline at end of file
)
.unwrap();
}
}
......@@ -7,4 +7,3 @@ mod expressions;
pub use expressions::*;
mod term;
pub use term::*;
use super::{Expression, Variable};
use crate::intermediate_representation::Def as IrDef;
use crate::intermediate_representation::Expression as IrExpression;
use crate::intermediate_representation::Jmp as IrJmp;
use crate::prelude::*;
use crate::term::{Term, Tid};
// TODO: Handle the case where an indirect tail call is represented by CALLIND plus RETURN
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub struct Call {
pub target: Label,
pub return_: Option<Label>,
pub target: Label,
pub return_: Option<Label>,
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub struct Jmp {
pub mnemonic: JmpType,
pub goto: Option<Label>,
pub call: Option<Call>,
pub condition: Option<Expression>,
pub mnemonic: JmpType,
pub goto: Option<Label>,
pub call: Option<Call>,
pub condition: Option<Variable>,
}
// TODO: CALLOTHER is still missing!
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum JmpType {
BRANCH,
CBRANCH,
BRANCHIND,
CALL,
CALLIND,
RETURN,
BRANCH,
CBRANCH,
BRANCHIND,
CALL,
CALLIND,
RETURN,
}
impl From<Jmp> for IrJmp {
fn from(jmp: Jmp) -> IrJmp {
use JmpType::*;
let unwrap_label_direct = |label| {
if let Label::Direct(tid) = label {
tid
} else {
panic!()
}
};
let unwrap_label_indirect = |label| {
if let Label::Indirect(expr) = label {
expr
} else {
panic!()
}
};
match jmp.mnemonic {
BRANCH => IrJmp::Branch(unwrap_label_direct(jmp.goto.unwrap())),
CBRANCH => IrJmp::CBranch {
target: unwrap_label_direct(jmp.goto.unwrap()),
condition: jmp.condition.unwrap().into(),
},
BRANCHIND => IrJmp::BranchInd(unwrap_label_indirect(jmp.goto.unwrap()).into()),
CALL => {
let call = jmp.call.unwrap();
IrJmp::Call {
target: unwrap_label_direct(call.target),
return_: call.return_.map(unwrap_label_direct),
}
}
CALLIND => {
let call = jmp.call.unwrap();
IrJmp::CallInd {
target: unwrap_label_indirect(call.target).into(),
return_: call.return_.map(unwrap_label_direct),
}
}
RETURN => IrJmp::Return(unwrap_label_indirect(jmp.goto.unwrap()).into()),
}
}
}
// TODO: Remove since code duplication?
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub enum Label {
Direct(Tid),
Indirect(Variable),
Direct(Tid),
Indirect(Variable),
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub struct Def {
pub lhs: Variable,
pub rhs: Expression,
pub lhs: Variable,
pub rhs: Expression,
}
impl From<Def> for IrDef {
fn from(def: Def) -> IrDef {
use super::ExpressionType::*;
match def.rhs.mnemonic {
COPY => IrDef::Assign {
var: def.lhs.into(),
value: IrExpression::from(def.rhs),
},
LOAD => IrDef::Load {
var: def.lhs.into(),
address: def.rhs.input1.unwrap().into(),
},
STORE => IrDef::Store {
address: def.rhs.input1.unwrap().into(),
value: def.rhs.input2.unwrap().into(),
},
PIECE | INT_EQUAL | INT_NOTEQUAL | INT_LESS | INT_SLESS | INT_ADD | INT_SUB | INT_CARRY
| INT_SCARRY | INT_SBORROW | INT_XOR | INT_AND | INT_OR | INT_LEFT | INT_RIGHT
| INT_SRIGHT | INT_MULT | INT_DIV | INT_REM | INT_SDIV | INT_SREM | BOOL_XOR | BOOL_AND
| BOOL_OR | FLOAT_EQUAL | FLOAT_NOTEQUAL | FLOAT_LESS | FLOAT_LESSEQUAL | FLOAT_ADD
| FLOAT_SUB | FLOAT_MULT | FLOAT_DIV => IrDef::Assign {
var: def.lhs.into(),
value: IrExpression::BinOp {
op: def.rhs.mnemonic.into(),
lhs: Box::new(def.rhs.input0.unwrap().into()),
rhs: Box::new(def.rhs.input1.unwrap().into()),
},
},
SUBPIECE => IrDef::Assign {
var: def.lhs.clone().into(),
value: IrExpression::Subpiece {
low_byte: def.rhs.input1.unwrap().into(),
size: def.lhs.size,
arg: Box::new(def.rhs.input0.unwrap().into()),
},
},
INT_NEGATE | INT_2COMP | BOOL_NEGATE | FLOAT_NEGATE | FLOAT_ABS | FLOAT_SQRT | FLOAT_CEIL
| FLOAT_FLOOR | FLOAT_ROUND | FLOAT_NAN => IrDef::Assign {
var: def.lhs.into(),
value: IrExpression::UnOp {
op: def.rhs.mnemonic.into(),
arg: Box::new(def.rhs.input0.unwrap().into()),
},
},
INT_ZEXT | INT_SEXT | INT2FLOAT | FLOAT2FLOAT | TRUNC => IrDef::Assign {
var: def.lhs.clone().into(),
value: IrExpression::Cast {
op: def.rhs.mnemonic.into(),
size: def.lhs.size,
arg: Box::new(def.rhs.input0.unwrap().into()),
},
},
fn from(def: Def) -> IrDef {
use super::ExpressionType::*;
match def.rhs.mnemonic {
COPY => IrDef::Assign {
var: def.lhs.into(),
value: def.rhs.input0.unwrap().into(),
},
LOAD => IrDef::Load {
var: def.lhs.into(),
address: def.rhs.input1.unwrap().into(),
},
STORE => IrDef::Store {
address: def.rhs.input1.unwrap().into(),
value: def.rhs.input2.unwrap().into(),
},
PIECE | INT_EQUAL | INT_NOTEQUAL | INT_LESS | INT_SLESS | INT_LESSEQUAL
| INT_SLESSEQUAL | INT_ADD | INT_SUB | INT_CARRY | INT_SCARRY | INT_SBORROW
| INT_XOR | INT_AND | INT_OR | INT_LEFT | INT_RIGHT | INT_SRIGHT | INT_MULT
| INT_DIV | INT_REM | INT_SDIV | INT_SREM | BOOL_XOR | BOOL_AND | BOOL_OR
| FLOAT_EQUAL | FLOAT_NOTEQUAL | FLOAT_LESS | FLOAT_LESSEQUAL | FLOAT_ADD
| FLOAT_SUB | FLOAT_MULT | FLOAT_DIV => IrDef::Assign {
var: def.lhs.into(),
value: IrExpression::BinOp {
op: def.rhs.mnemonic.into(),
lhs: Box::new(def.rhs.input0.unwrap().into()),
rhs: Box::new(def.rhs.input1.unwrap().into()),
},
},
SUBPIECE => IrDef::Assign {
var: def.lhs.clone().into(),
value: IrExpression::Subpiece {
low_byte: def.rhs.input1.unwrap().into(),
size: def.lhs.size,
arg: Box::new(def.rhs.input0.unwrap().into()),
},
},
INT_NEGATE | INT_2COMP | BOOL_NEGATE | FLOAT_NEGATE | FLOAT_ABS | FLOAT_SQRT
| FLOAT_CEIL | FLOAT_FLOOR | FLOAT_ROUND | FLOAT_NAN => IrDef::Assign {
var: def.lhs.into(),
value: IrExpression::UnOp {
op: def.rhs.mnemonic.into(),
arg: Box::new(def.rhs.input0.unwrap().into()),
},
},
INT_ZEXT | INT_SEXT | INT2FLOAT | FLOAT2FLOAT | TRUNC => IrDef::Assign {
var: def.lhs.clone().into(),
value: IrExpression::Cast {
op: def.rhs.mnemonic.into(),
size: def.lhs.size,
arg: Box::new(def.rhs.input0.unwrap().into()),
},
},
}
}
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub struct Blk {
pub defs: Vec<Term<Def>>,
pub jmps: Vec<Term<Jmp>>,
pub defs: Vec<Term<Def>>,
pub jmps: Vec<Term<Jmp>>,
}
// TODO: We need a unit test for stack parameter (that use location instead of var)!
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub struct Arg {
pub var: Option<Variable>,
pub location: Option<Expression>,
pub intent: ArgIntent,
pub var: Option<Variable>,
pub location: Option<Expression>,
pub intent: ArgIntent,
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub enum ArgIntent {
INPUT,
OUTPUT,
BOTH,
INPUT,
OUTPUT,
BOTH,
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub struct Sub {
pub name: String,
pub blocks: Vec<Term<Blk>>,
pub name: String,
pub blocks: Vec<Term<Blk>>,
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub struct ExternSymbol {
pub tid: Tid,
pub address: String,
pub name: String,
pub calling_convention: Option<String>,
pub arguments: Vec<Arg>,
pub tid: Tid,
pub address: String,
pub name: String,
pub calling_convention: Option<String>,
pub arguments: Vec<Arg>,
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub struct Program {
pub subs: Vec<Term<Sub>>,
pub extern_symbols: Vec<ExternSymbol>,
pub entry_points: Vec<Tid>,
pub subs: Vec<Term<Sub>>,
pub extern_symbols: Vec<ExternSymbol>,
pub entry_points: Vec<Tid>,
}
#[cfg(test)]
mod tests {
use super::*;
use super::*;
#[test]
fn def_deserialization() {
let def: Def = serde_json::from_str(
r#"
#[test]
fn def_deserialization() {
let def: Def = serde_json::from_str(
r#"
{
"lhs": {
"name": "CF",
......@@ -169,15 +217,15 @@ mod tests {
}
}
"#,
)
.unwrap();
let _ : IrDef = def.into();
}
)
.unwrap();
let _: IrDef = def.into();
}
#[test]
fn label_deserialization() {
let _: Label = serde_json::from_str(
r#"
#[test]
fn label_deserialization() {
let _: Label = serde_json::from_str(
r#"
{
"Direct": {
"id": "blk_00103901",
......@@ -185,10 +233,10 @@ mod tests {
}
}
"#,
)
.unwrap();
let _: Label = serde_json::from_str(
r#"
)
.unwrap();
let _: Label = serde_json::from_str(
r#"
{
"Indirect": {
"name": "00109ef0",
......@@ -197,14 +245,14 @@ mod tests {
}
}
"#,
)
.unwrap();
}
)
.unwrap();
}
#[test]
fn jmp_deserialization() {
let _: Term<Jmp> = serde_json::from_str(
r#"
#[test]
fn jmp_deserialization() {
let _: Term<Jmp> = serde_json::from_str(
r#"
{
"tid": {
"id": "instr_00102014_2",
......@@ -231,14 +279,14 @@ mod tests {
}
}
"#,
)
.unwrap();
}
)
.unwrap();
}
#[test]
fn blk_deserialization() {
let _: Term<Blk> = serde_json::from_str(
r#"
#[test]
fn blk_deserialization() {
let _: Term<Blk> = serde_json::from_str(
r#"
{
"tid": {
"id": "blk_00101000",
......@@ -250,14 +298,14 @@ mod tests {
}
}
"#,
)
.unwrap();
}
)
.unwrap();
}
#[test]
fn arg_deserialization() {
let _: Arg = serde_json::from_str(
r#"
#[test]
fn arg_deserialization() {
let _: Arg = serde_json::from_str(
r#"
{
"var": {
"name": "RDI",
......@@ -267,14 +315,14 @@ mod tests {
"intent": "INPUT"
}
"#,
)
.unwrap();
}
)
.unwrap();
}
#[test]
fn sub_deserialization() {
let _: Term<Sub> = serde_json::from_str(
r#"
#[test]
fn sub_deserialization() {
let _: Term<Sub> = serde_json::from_str(
r#"
{
"tid": {
"id": "sub_00101000",
......@@ -286,14 +334,14 @@ mod tests {
}
}
"#,
)
.unwrap();
}
)
.unwrap();
}
#[test]
fn extern_symbol_deserialization() {
let _: ExternSymbol = serde_json::from_str(
r#"
#[test]
fn extern_symbol_deserialization() {
let _: ExternSymbol = serde_json::from_str(
r#"
{
"tid": {
"id": "sub_0010b020",
......@@ -338,14 +386,14 @@ mod tests {
]
}
"#,
)
.unwrap();
}
)
.unwrap();
}
#[test]
fn program_deserialization() {
let _: Term<Program> = serde_json::from_str(
r#"
#[test]
fn program_deserialization() {
let _: Term<Program> = serde_json::from_str(
r#"
{
"tid": {
"id": "prog_00101000",
......@@ -358,7 +406,7 @@ mod tests {
}
}
"#,
)
.unwrap();
}
)
.unwrap();
}
}
use crate::bil::*;
use crate::intermediate_representation::Def as IrDef;
use crate::intermediate_representation::Expression as IrExpression;
use crate::intermediate_representation::Jmp as IrJmp;
use serde::{Deserialize, Serialize};
pub mod symbol;
......@@ -37,6 +40,80 @@ pub struct Def {
pub rhs: Expression,
}
impl Def {
fn to_ir_defs(self) -> Vec<IrDef> {
match self.rhs {
Expression::Load { address, .. } => {
let (defs, cleaned_address, _) = extract_loads_from_expression(*address, 0);
let mut ir_defs: Vec<IrDef> =
defs.into_iter().map(|def| def.to_ir_assignment()).collect();
ir_defs.push(IrDef::Load {
address: cleaned_address.into(),
var: self.lhs.into(),
});
ir_defs
}
Expression::Store { address, value, .. } => {
let (mut defs, cleaned_address, counter) =
extract_loads_from_expression(*address, 0);
let (mut more_defs, cleaned_value, _) =
extract_loads_from_expression(*value, counter);
defs.append(&mut more_defs);
let mut ir_defs: Vec<IrDef> =
defs.into_iter().map(|def| def.to_ir_assignment()).collect();
ir_defs.push(IrDef::Store {
address: cleaned_address.into(),
value: cleaned_value.into(),
});
ir_defs
}
Expression::IfThenElse {
condition,
true_exp,
false_exp,
} => {
// We only match for conditional stores.
// Other usages of the `IfThenElse`-expression will result in panics.
let (address, value) = match (*true_exp, *false_exp) {
(Expression::Store { address, value, .. }, Expression::Var(var))
| (Expression::Var(var), Expression::Store { address, value, .. })
if var == self.lhs =>
{
(address, value)
}
_ => panic!(),
};
let (mut defs, _cleaned_condition, counter) =
extract_loads_from_expression(*condition, 0);
let (mut more_defs, cleaned_adress, counter) =
extract_loads_from_expression(*address, counter);
let (mut even_more_defs, cleaned_value, _) =
extract_loads_from_expression(*value, counter);
defs.append(&mut more_defs);
defs.append(&mut even_more_defs);
let mut ir_defs: Vec<IrDef> =
defs.into_iter().map(|def| def.to_ir_assignment()).collect();
ir_defs.push(IrDef::Store {
address: cleaned_adress.into(),
value: IrExpression::Unknown {
description: "BAP conditional store".into(),
size: cleaned_value.bitsize().into(),
},
});
ir_defs
}
_ => vec![self.to_ir_assignment()],
}
}
fn to_ir_assignment(self) -> IrDef {
IrDef::Assign {
var: self.lhs.into(),
value: self.rhs.into(),
}
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub struct Jmp {
pub condition: Option<Expression>,
......@@ -51,6 +128,38 @@ pub enum JmpKind {
Interrupt { value: isize, return_addr: Tid },
}
impl From<Jmp> for IrJmp {
fn from(jmp: Jmp) -> IrJmp {
match jmp.kind {
JmpKind::Goto(Label::Direct(tid)) => IrJmp::Branch(tid),
JmpKind::Goto(Label::Indirect(expr)) => IrJmp::BranchInd(expr.into()),
JmpKind::Return(Label::Indirect(expr)) => IrJmp::Return(expr.into()),
JmpKind::Return(Label::Direct(_)) => panic!(),
JmpKind::Call(call) => {
let return_ = match call.return_ {
Some(Label::Direct(tid)) => Some(tid),
None => None,
_ => panic!(),
};
match call.target {
Label::Direct(tid) => IrJmp::Call {
target: tid,
return_,
},
Label::Indirect(expr) => IrJmp::CallInd {
target: expr.into(),
return_,
},
}
}
JmpKind::Interrupt { value, return_addr } => IrJmp::CallOther {
description: format!("Interrupt {}", value),
return_: Some(return_addr),
},
}
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub struct Call {
pub target: Label,
......@@ -168,6 +277,106 @@ impl ArgIntent {
}
}
fn extract_loads_from_expression(expr: Expression, counter: u64) -> (Vec<Def>, Expression, u64) {
use Expression::*;
match expr {
Load {
memory,
address,
endian,
size,
} => {
let (mut defs, cleaned_address, mut counter) =
extract_loads_from_expression(*address, counter);
counter += 1;
let temp_var = Variable {
name: format!("temp_{}", counter),
type_: Type::Immediate(size),
is_temp: true,
};
defs.push(Def {
lhs: temp_var.clone(),
rhs: Load {
memory,
address: Box::new(cleaned_address),
endian,
size,
},
});
(defs, Var(temp_var), counter)
}
Var(_) | Const(_) | Unknown { .. } => (Vec::new(), expr, counter),
Store { .. } | Let { .. } | IfThenElse { .. } => panic!(),
BinOp { op, lhs, rhs } => {
let (mut defs, cleaned_lhs, counter) = extract_loads_from_expression(*lhs, counter);
let (mut defs_rhs, cleaned_rhs, counter) = extract_loads_from_expression(*rhs, counter);
defs.append(&mut defs_rhs);
(
defs,
BinOp {
op,
lhs: Box::new(cleaned_lhs),
rhs: Box::new(cleaned_rhs),
},
counter,
)
}
UnOp { op, arg } => {
let (defs, cleaned_arg, counter) = extract_loads_from_expression(*arg, counter);
(
defs,
UnOp {
op,
arg: Box::new(cleaned_arg),
},
counter,
)
}
Cast { kind, width, arg } => {
let (defs, cleaned_arg, counter) = extract_loads_from_expression(*arg, counter);
(
defs,
Cast {
kind,
width,
arg: Box::new(cleaned_arg),
},
counter,
)
}
Extract {
low_bit,
high_bit,
arg,
} => {
let (defs, cleaned_arg, counter) = extract_loads_from_expression(*arg, counter);
(
defs,
Extract {
low_bit,
high_bit,
arg: Box::new(cleaned_arg),
},
counter,
)
}
Concat { left, right } => {
let (mut defs, cleaned_left, counter) = extract_loads_from_expression(*left, counter);
let (mut defs_right, cleaned_right, counter) =
extract_loads_from_expression(*right, counter);
defs.append(&mut defs_right);
(
defs,
Concat {
left: Box::new(cleaned_left),
right: Box::new(cleaned_right),
},
counter,
)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment