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}; use serde::{Deserialize, Serialize};
pub mod variable; pub mod variable;
...@@ -7,6 +13,13 @@ pub type Bitvector = apint::ApInt; ...@@ -7,6 +13,13 @@ pub type Bitvector = apint::ApInt;
pub type BitSize = u16; 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)] #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub enum Expression { pub enum Expression {
Var(Variable), Var(Variable),
...@@ -189,6 +202,100 @@ impl Expression { ...@@ -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)] #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone, Copy)]
...@@ -222,12 +329,50 @@ pub enum BinOpType { ...@@ -222,12 +329,50 @@ pub enum BinOpType {
SLE, 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)] #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum UnOpType { pub enum UnOpType {
NEG, NEG,
NOT, 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)] #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum Endianness { pub enum Endianness {
LittleEndian, LittleEndian,
......
use super::BitSize; use super::BitSize;
use crate::intermediate_representation::Variable as IrVariable;
use crate::prelude::*; use crate::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
...@@ -19,12 +20,33 @@ pub enum Type { ...@@ -19,12 +20,33 @@ pub enum Type {
Unknown, 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 { impl Variable {
pub fn bitsize(&self) -> Result<BitSize, Error> { pub fn bitsize(&self) -> Result<BitSize, Error> {
if let Type::Immediate(bitsize) = self.type_ { self.type_.bitsize()
Ok(bitsize) }
}
impl From<Variable> for IrVariable {
fn from(var: Variable) -> IrVariable {
let size = if let Type::Immediate(bitsize) = var.type_ {
bitsize.into()
} else { } 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 { ...@@ -38,6 +38,8 @@ pub enum BinOpType {
IntNotEqual, IntNotEqual,
IntLess, IntLess,
IntSLess, IntSLess,
IntLessEqual,
IntSLessEqual,
IntAdd, IntAdd,
IntSub, IntSub,
IntCarry, IntCarry,
...@@ -74,7 +76,6 @@ pub enum CastOpType { ...@@ -74,7 +76,6 @@ pub enum CastOpType {
Int2Float, Int2Float,
Float2Float, Float2Float,
Trunc, Trunc,
} }
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone, Copy)] #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone, Copy)]
......
...@@ -12,51 +12,51 @@ pub use term::*; ...@@ -12,51 +12,51 @@ pub use term::*;
// TODO: move ByteSize and BitSize into their own module // TODO: move ByteSize and BitSize into their own module
#[derive( #[derive(
Serialize, Serialize,
Deserialize, Deserialize,
Debug, Debug,
PartialEq, PartialEq,
Eq, Eq,
PartialOrd, PartialOrd,
Ord, Ord,
Hash, Hash,
Clone, Clone,
Copy, Copy,
Display, Display,
Binary, Binary,
Octal, Octal,
LowerHex, LowerHex,
UpperHex, UpperHex,
From, From,
Into, Into,
Not, Not,
Add, Add,
Sub, Sub,
Mul, Mul,
Div, Div,
Rem, Rem,
Shr, Shr,
Shl, Shl,
AddAssign, AddAssign,
SubAssign, SubAssign,
MulAssign, MulAssign,
DivAssign, DivAssign,
RemAssign, RemAssign,
ShrAssign, ShrAssign,
ShlAssign, ShlAssign,
Sum, Sum,
)] )]
#[serde(transparent)] #[serde(transparent)]
pub struct ByteSize(u64); pub struct ByteSize(u64);
impl From<ByteSize> for BitSize { impl From<ByteSize> for BitSize {
fn from(bytesize: ByteSize) -> BitSize { fn from(bytesize: ByteSize) -> BitSize {
u16::try_from(u64::from(bytesize) * 8).unwrap() u16::try_from(u64::from(bytesize) * 8).unwrap()
} }
} }
impl From<ByteSize> for apint::BitWidth { impl From<ByteSize> for apint::BitWidth {
fn from(bytesize: ByteSize) -> apint::BitWidth { fn from(bytesize: ByteSize) -> apint::BitWidth {
apint::BitWidth::from((u64::from(bytesize) * 8) as usize) apint::BitWidth::from((u64::from(bytesize) * 8) as usize)
} }
} }
\ No newline at end of file
use super::{ByteSize, Expression, Variable};
use crate::prelude::*; use crate::prelude::*;
use crate::term::{Term, Tid}; use crate::term::{Term, Tid};
use super::{Variable, Expression, ByteSize};
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)] #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub enum Def { pub enum Def {
...@@ -18,4 +16,33 @@ pub enum Def { ...@@ -18,4 +16,33 @@ pub enum Def {
var: Variable, var: Variable,
value: Expression, 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 super::ByteSize;
use crate::prelude::*;
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)] #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub struct Variable { pub struct Variable {
pub name: String, pub name: String,
pub size: ByteSize, pub size: ByteSize,
pub is_temp: bool, pub is_temp: bool,
} }
\ No newline at end of file
...@@ -11,10 +11,10 @@ pub mod abstract_domain; ...@@ -11,10 +11,10 @@ pub mod abstract_domain;
pub mod analysis; pub mod analysis;
pub mod bil; pub mod bil;
pub mod ffi; pub mod ffi;
pub mod intermediate_representation;
pub mod pcode;
pub mod term; pub mod term;
pub mod utils; pub mod utils;
pub mod pcode;
pub mod intermediate_representation;
mod prelude { mod prelude {
pub use apint::Width; pub use apint::Width;
......
...@@ -7,4 +7,3 @@ mod expressions; ...@@ -7,4 +7,3 @@ mod expressions;
pub use expressions::*; pub use expressions::*;
mod term; mod term;
pub use term::*; pub use term::*;
use crate::bil::*; 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}; use serde::{Deserialize, Serialize};
pub mod symbol; pub mod symbol;
...@@ -37,6 +40,80 @@ pub struct Def { ...@@ -37,6 +40,80 @@ pub struct Def {
pub rhs: Expression, 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)] #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub struct Jmp { pub struct Jmp {
pub condition: Option<Expression>, pub condition: Option<Expression>,
...@@ -51,6 +128,38 @@ pub enum JmpKind { ...@@ -51,6 +128,38 @@ pub enum JmpKind {
Interrupt { value: isize, return_addr: Tid }, 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)] #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub struct Call { pub struct Call {
pub target: Label, pub target: Label,
...@@ -168,6 +277,106 @@ impl ArgIntent { ...@@ -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)] #[cfg(test)]
mod tests { mod tests {
use super::*; 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