use crate::{allocation, secret, AbstractData, StructDescriptions};
use either::Either;
use haybale::{Error, Project, Result, State};
use haybale::backend::*;
use llvm_ir::*;
pub fn fill_unconstrained_with_length<B: Backend>(
state: &mut State<B>,
out_buffer: Either<&Operand, B::BV>,
out_len_ptr: Either<&Operand, B::BV>,
max_buffer_len_bytes: u32,
buffer_name: String,
) -> Result<()> {
let out_len_bitwidth: u32 = 64;
let out_buffer: B::BV = match out_buffer {
Either::Left(op) => {
match op.get_type() {
Type::PointerType { .. } => {},
ty => return Err(Error::OtherError(format!("fill_unconstrained_with_length: expected out_buffer to be some pointer type, got {:?}", ty))),
};
state.operand_to_bv(op)?
},
Either::Right(bv) => bv,
};
let out_len_ptr: B::BV = match out_len_ptr {
Either::Left(op) => {
match op.get_type() {
Type::PointerType { pointee_type, .. } => match *pointee_type {
Type::IntegerType { bits } if bits == out_len_bitwidth => {},
_ => return Err(Error::OtherError(format!("fill_unconstrained_with_length: expected out_len_ptr to be pointer-to-64-bit-integer type, got pointer to {:?}", pointee_type))),
},
ty => return Err(Error::OtherError(format!("fill_unconstrained_with_length: expected out_len_ptr to be some pointer type, got {:?}", ty))),
};
state.operand_to_bv(op)?
},
Either::Right(bv) => bv,
};
let out_len = state.new_bv_with_name(Name::from(format!("{}_length", buffer_name)), out_len_bitwidth)?;
out_len.ulte(&state.bv_from_u32(max_buffer_len_bytes, out_len_bitwidth)).assert()?;
state.write(&out_len_ptr, out_len)?;
let unconstrained_bytes = state.new_bv_with_name(Name::from(buffer_name), max_buffer_len_bytes * 8)?;
state.write(&out_buffer, unconstrained_bytes)?;
Ok(())
}
pub fn fill_secret_with_length(
state: &mut State<secret::Backend>,
out_buffer: Either<&Operand, secret::BV>,
out_len_ptr: Either<&Operand, secret::BV>,
max_buffer_len_bytes: u32,
buffer_name: String,
) -> Result<()> {
let out_len_bitwidth: u32 = 64;
let out_buffer: secret::BV = match out_buffer {
Either::Left(op) => {
match op.get_type() {
Type::PointerType { .. } => {},
ty => return Err(Error::OtherError(format!("fill_secret_with_length: expected out_buffer to be some pointer type, got {:?}", ty))),
};
state.operand_to_bv(op)?
},
Either::Right(bv) => bv,
};
let out_len_ptr: secret::BV = match out_len_ptr {
Either::Left(op) => {
match op.get_type() {
Type::PointerType { pointee_type, .. } => match *pointee_type {
Type::IntegerType { bits } if bits == out_len_bitwidth => {},
_ => return Err(Error::OtherError(format!("fill_secret_with_length: expected out_len_ptr to be pointer-to-64-bit-integer type, got pointer to {:?}", pointee_type))),
},
ty => return Err(Error::OtherError(format!("fill_secret_with_length: expected out_len_ptr to be some pointer type, got {:?}", ty))),
};
state.operand_to_bv(op)?
},
Either::Right(bv) => bv,
};
let out_len = state.new_bv_with_name(Name::from(format!("{}_length", buffer_name)), out_len_bitwidth)?;
out_len.ulte(&state.bv_from_u32(max_buffer_len_bytes, out_len_bitwidth)).assert()?;
state.write(&out_len_ptr, out_len)?;
let secret_bytes = secret::BV::Secret { btor: state.solver.clone(), width: max_buffer_len_bytes * 8, symbol: Some(buffer_name) };
state.write(&out_buffer, secret_bytes)?;
Ok(())
}
pub fn allocate_and_init_abstractdata<'p>(
proj: &'p Project,
state: &mut State<'p, secret::Backend>,
ad: AbstractData,
ty: &Type,
sd: &'p StructDescriptions,
) -> Result<secret::BV> {
let ad = ad.to_complete(ty, proj, sd);
let ptr = state.allocate(ad.size_in_bits() as u64);
let mut allocationctx = allocation::Context::new(proj, state, sd);
allocation::InitializationContext::blank().initialize_cad_in_memory(&mut allocationctx, &ptr, &ad, Some(ty))?;
Ok(ptr)
}
pub fn reinitialize_pointee<'p>(
proj: &'p Project,
state: &mut State<'p, secret::Backend>,
pointer: &Operand,
ad: AbstractData,
sd: &'p StructDescriptions,
) -> Result<()> {
let ptr = state.operand_to_bv(pointer)?;
let pointee_ty = match pointer.get_type() {
Type::PointerType { pointee_type, .. } => pointee_type,
ty => return Err(Error::OtherError(format!("reinitialize_pointee: expected `pointer` to be a pointer, got {:?}", ty))),
};
let mut allocationctx = allocation::Context::new(proj, state, sd);
allocation::InitializationContext::blank().initialize_data_in_memory(&mut allocationctx, &ptr, ad, &pointee_ty)?;
Ok(())
}