use crate::{
analysis::{cpa::lattice::JoinSemiLattice, valuation::SimpleValuationState},
display::JingleDisplay,
};
use internment::Intern;
use jingle_sleigh::{SleighArchInfo, VarNode};
use std::ops::{BitXor, Deref};
use std::{
fmt::Formatter,
ops::{Add, Mul, Sub},
};
trait Simplify {
fn simplify(&self) -> SimpleValue;
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub struct Entry(VarNode);
impl Deref for Entry {
type Target = VarNode;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub struct Const(VarNode);
impl Deref for Const {
type Target = VarNode;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub struct Offset(Intern<Entry>, Intern<Const>);
impl Offset {
pub fn base_vn(&self) -> &Entry {
self.0.as_ref()
}
pub fn offset(&self) -> &Const {
self.1.as_ref()
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub struct MulExpr(pub Intern<SimpleValue>, pub Intern<SimpleValue>, pub usize);
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub struct AddExpr(pub Intern<SimpleValue>, pub Intern<SimpleValue>, pub usize);
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub struct SubExpr(pub Intern<SimpleValue>, pub Intern<SimpleValue>, pub usize);
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub struct Or(pub Intern<SimpleValue>, pub Intern<SimpleValue>, pub usize);
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub struct XorExpr(pub Intern<SimpleValue>, pub Intern<SimpleValue>, pub usize);
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub struct Load(pub Intern<SimpleValue>, pub usize);
impl AsRef<VarNode> for Const {
fn as_ref(&self) -> &VarNode {
&self.0
}
}
impl AsRef<VarNode> for Entry {
fn as_ref(&self) -> &VarNode {
&self.0
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub enum SimpleValue {
Entry(Entry),
Const(Const),
Offset(Offset),
Mul(MulExpr),
Add(AddExpr),
Sub(SubExpr),
Or(Or),
Xor(XorExpr),
Load(Load),
Top,
}
impl SimpleValue {
pub fn as_const(&self) -> Option<&VarNode> {
match self {
SimpleValue::Const(vn_intern) => Some(vn_intern.as_ref()),
_ => None,
}
}
pub fn as_const_value(&self) -> Option<i64> {
self.as_const().map(|vn| vn.offset() as i64)
}
pub fn as_entry(&self) -> Option<&Entry> {
match self {
SimpleValue::Entry(e) => Some(e),
_ => None,
}
}
pub fn as_offset(&self) -> Option<&Offset> {
match self {
SimpleValue::Offset(e) => Some(e),
_ => None,
}
}
fn is_compound(&self) -> bool {
matches!(
self,
SimpleValue::Mul(_)
| SimpleValue::Add(_)
| SimpleValue::Sub(_)
| SimpleValue::Or(_)
| SimpleValue::Xor(_)
)
}
pub fn as_mul(&self) -> Option<&MulExpr> {
match self {
SimpleValue::Mul(m) => Some(m),
_ => None,
}
}
pub fn as_add(&self) -> Option<&AddExpr> {
match self {
SimpleValue::Add(a) => Some(a),
_ => None,
}
}
pub fn as_sub(&self) -> Option<&SubExpr> {
match self {
SimpleValue::Sub(s) => Some(s),
_ => None,
}
}
pub fn as_or(&self) -> Option<&Or> {
match self {
SimpleValue::Or(o) => Some(o),
_ => None,
}
}
pub fn as_xor(&self) -> Option<&XorExpr> {
match self {
SimpleValue::Xor(x) => Some(x),
_ => None,
}
}
pub fn as_load(&self) -> Option<&Load> {
match self {
SimpleValue::Load(l) => Some(l),
_ => None,
}
}
pub fn size(&self) -> usize {
match self {
SimpleValue::Entry(Entry(vn)) => vn.size(),
SimpleValue::Const(vn) => vn.as_ref().size(),
SimpleValue::Offset(Offset(_, vn)) => vn.as_ref().0.size(),
SimpleValue::Mul(MulExpr(_, _, s))
| SimpleValue::Add(AddExpr(_, _, s))
| SimpleValue::Sub(SubExpr(_, _, s))
| SimpleValue::Or(Or(_, _, s))
| SimpleValue::Xor(XorExpr(_, _, s)) => *s,
SimpleValue::Load(Load(_, s)) => *s,
SimpleValue::Top => 8, }
}
pub fn entry(vn: VarNode) -> Self {
SimpleValue::Entry(Entry(vn))
}
pub fn offset(vn: VarNode, offset: VarNode) -> Self {
SimpleValue::Offset(Offset(Intern::new(Entry(vn)), Intern::new(Const(offset))))
}
pub fn const_(v: i64) -> Self {
let vn = VarNode::new_const(v as u64, 8u32);
SimpleValue::Const(Const(vn))
}
pub fn const_from_varnode(vn: VarNode) -> Self {
SimpleValue::Const(Const(vn))
}
pub fn or(left: SimpleValue, right: SimpleValue) -> Self {
let s = std::cmp::max(left.size(), right.size());
SimpleValue::Or(Or(Intern::new(left), Intern::new(right), s))
}
pub fn xor(left: SimpleValue, right: SimpleValue) -> Self {
let s = std::cmp::max(left.size(), right.size());
SimpleValue::Xor(XorExpr(Intern::new(left), Intern::new(right), s))
}
pub fn load(child: SimpleValue) -> Self {
let s = child.size();
SimpleValue::Load(Load(Intern::new(child), s))
}
fn make_const(value: i64, size: u32) -> Self {
let vn = VarNode::new_const(value as u64, size);
SimpleValue::Const(Const(vn))
}
fn derive_size_from(val: &SimpleValue) -> usize {
let s = val.size();
if s == 0 { 8 } else { s }
}
fn normalize_commutative(left: SimpleValue, right: SimpleValue) -> (SimpleValue, SimpleValue) {
let left_is_const = left.as_const().is_some();
let right_is_const = right.as_const().is_some();
if left_is_const && !right_is_const {
(right, left)
} else {
(left, right)
}
}
fn normalize_or(left: SimpleValue, right: SimpleValue) -> (SimpleValue, SimpleValue) {
let left_is_or = matches!(left, SimpleValue::Or(_));
let right_is_or = matches!(right, SimpleValue::Or(_));
if left_is_or && !right_is_or {
(right, left)
} else {
(left, right)
}
}
fn variant_rank(v: &SimpleValue) -> u8 {
match v {
SimpleValue::Const(_) => 0,
SimpleValue::Entry(_) => 1,
SimpleValue::Offset(_) => 2,
SimpleValue::Mul(_) => 3,
SimpleValue::Add(_) => 4,
SimpleValue::Sub(_) => 5,
SimpleValue::Or(_) => 6,
SimpleValue::Xor(_) => 7,
SimpleValue::Load(_) => 8,
SimpleValue::Top => 9,
}
}
}
impl Simplify for SimpleValue {
fn simplify(&self) -> SimpleValue {
match self {
SimpleValue::Mul(expr) => expr.simplify(),
SimpleValue::Add(expr) => expr.simplify(),
SimpleValue::Sub(expr) => expr.simplify(),
SimpleValue::Or(expr) => expr.simplify(),
SimpleValue::Xor(expr) => expr.simplify(),
SimpleValue::Load(expr) => expr.simplify(),
SimpleValue::Entry(_)
| SimpleValue::Offset(_)
| SimpleValue::Const(_)
| SimpleValue::Top => self.clone(),
}
}
}
impl Mul for SimpleValue {
type Output = SimpleValue;
fn mul(self, rhs: Self) -> Self::Output {
let s = std::cmp::max(self.size(), rhs.size());
SimpleValue::Mul(MulExpr(Intern::new(self), Intern::new(rhs), s))
}
}
impl Add for SimpleValue {
type Output = SimpleValue;
fn add(self, rhs: Self) -> Self::Output {
let s = std::cmp::max(self.size(), rhs.size());
SimpleValue::Add(AddExpr(Intern::new(self), Intern::new(rhs), s))
}
}
impl BitXor for SimpleValue {
type Output = SimpleValue;
fn bitxor(self, rhs: Self) -> Self::Output {
let s = std::cmp::max(self.size(), rhs.size());
SimpleValue::Xor(XorExpr(Intern::new(self), Intern::new(rhs), s))
}
}
impl Sub for SimpleValue {
type Output = SimpleValue;
fn sub(self, rhs: Self) -> Self::Output {
let s = std::cmp::max(self.size(), rhs.size());
SimpleValue::Sub(SubExpr(Intern::new(self), Intern::new(rhs), s))
}
}
impl SimpleValue {
pub fn simplify(&self) -> SimpleValue {
Simplify::simplify(self)
}
}
impl Simplify for AddExpr {
fn simplify(&self) -> SimpleValue {
let a_intern = self.0;
let b_intern = self.1;
let a_s = a_intern.as_ref().simplify();
let b_s = b_intern.as_ref().simplify();
if matches!(a_s, SimpleValue::Top) || matches!(b_s, SimpleValue::Top) {
return SimpleValue::Top;
}
if let (Some(a_vn), Some(b_vn)) = (a_s.as_const(), b_s.as_const()) {
let a = a_vn.offset() as i64;
let b = b_vn.offset() as i64;
let res = a.wrapping_add(b);
let size = SimpleValue::derive_size_from(&a_s).max(SimpleValue::derive_size_from(&b_s));
return SimpleValue::make_const(res, size as u32);
}
let (left, right) = SimpleValue::normalize_commutative(a_s, b_s);
if let Some(0) = right.as_const().map(|vn| vn.offset() as i64) {
return left;
}
if let SimpleValue::Add(AddExpr(left_inner_left, left_inner_right, _)) = &left {
if let Some(inner_right_vn) = left_inner_right.as_ref().as_const() {
if let Some(right_vn) = right.as_const() {
let inner_right_const = inner_right_vn.offset() as i64;
let right_const = right_vn.offset() as i64;
let res = inner_right_const.wrapping_add(right_const);
let size = std::cmp::max(
left_inner_left.as_ref().size(),
SimpleValue::derive_size_from(&SimpleValue::make_const(res, 8u32)),
);
let new_const = SimpleValue::make_const(res, size as u32);
return AddExpr(*left_inner_left, Intern::new(new_const), size).simplify();
}
}
}
if let SimpleValue::Sub(SubExpr(expr, a, _)) = &left {
if let Some(a_vn) = a.as_ref().as_const() {
if let Some(b_vn) = right.as_const() {
let a_const = a_vn.offset() as i64;
let b = b_vn.offset() as i64;
let res = a_const.wrapping_sub(b);
let size =
std::cmp::max(expr.as_ref().size(), SimpleValue::derive_size_from(&left));
if res < 0 {
let new_const = SimpleValue::make_const(-res, size as u32);
return AddExpr(*expr, Intern::new(new_const), size).simplify();
} else {
let new_const = SimpleValue::make_const(res, size as u32);
return SubExpr(*expr, Intern::new(new_const), size).simplify();
}
}
}
}
let s = std::cmp::max(left.size(), right.size());
SimpleValue::Add(AddExpr(Intern::new(left), Intern::new(right), s))
}
}
impl Simplify for SubExpr {
fn simplify(&self) -> SimpleValue {
let a_intern = self.0;
let b_intern = self.1;
let a_s = a_intern.as_ref().simplify();
let b_s = b_intern.as_ref().simplify();
if matches!(a_s, SimpleValue::Top) || matches!(b_s, SimpleValue::Top) {
return SimpleValue::Top;
}
if let (Some(left_vn), Some(right_vn)) = (a_s.as_const(), b_s.as_const()) {
let left = left_vn.offset() as i64;
let right = right_vn.offset() as i64;
let res = left.wrapping_sub(right);
let size = SimpleValue::derive_size_from(&a_s).max(SimpleValue::derive_size_from(&b_s));
return SimpleValue::make_const(res, size as u32);
}
let left = a_s;
let right = b_s;
match right.as_const().map(|vn| vn.offset() as i64) {
Some(0) => {
return left;
}
Some(a) => {
if a < 0 {
let new_const =
SimpleValue::make_const(-a, SimpleValue::derive_size_from(&left) as u32);
let add = AddExpr(
Intern::new(left.clone()),
Intern::new(new_const),
left.size(),
)
.simplify();
return add;
}
}
_ => {}
}
if left == right {
let size = SimpleValue::derive_size_from(&left);
return SimpleValue::make_const(0, size as u32);
}
if let SimpleValue::Add(AddExpr(expr, a, _)) = &left {
if let Some(a_vn) = a.as_ref().as_const() {
if let Some(b_vn) = right.as_const() {
let a_val = a_vn.offset() as i64;
let b_val = b_vn.offset() as i64;
let res = a_val.wrapping_sub(b_val);
let size =
std::cmp::max(expr.as_ref().size(), SimpleValue::derive_size_from(&left));
if res < 0 {
let new_const = SimpleValue::make_const(-res, size as u32);
return AddExpr(*expr, Intern::new(new_const), size).simplify();
} else {
let new_const = SimpleValue::make_const(res, size as u32);
return SubExpr(*expr, Intern::new(new_const), size).simplify();
}
}
}
}
if let SimpleValue::Sub(SubExpr(expr, a, _)) = &left {
if let Some(a_vn) = a.as_ref().as_const() {
if let Some(b_vn) = right.as_const() {
let a_val = a_vn.offset() as i64;
let b_val = b_vn.offset() as i64;
let res = a_val.wrapping_add(b_val);
let size =
std::cmp::max(expr.as_ref().size(), SimpleValue::derive_size_from(&left));
let new_const = SimpleValue::make_const(res, size as u32);
return SubExpr(*expr, Intern::new(new_const), size).simplify();
}
}
}
let s = std::cmp::max(left.size(), right.size());
SimpleValue::Sub(SubExpr(Intern::new(left), Intern::new(right), s))
}
}
impl Simplify for MulExpr {
fn simplify(&self) -> SimpleValue {
let a_intern = self.0;
let b_intern = self.1;
let a_s = a_intern.as_ref().simplify();
let b_s = b_intern.as_ref().simplify();
if matches!(a_s, SimpleValue::Top) || matches!(b_s, SimpleValue::Top) {
return SimpleValue::Top;
}
let (left, right) = SimpleValue::normalize_commutative(a_s, b_s);
if let (Some(a_vn), Some(b_vn)) = (left.as_const(), right.as_const()) {
let a_v = a_vn.offset() as i64;
let b_v = b_vn.offset() as i64;
let res = a_v.wrapping_mul(b_v);
let size =
SimpleValue::derive_size_from(&left).max(SimpleValue::derive_size_from(&right));
return SimpleValue::make_const(res, size as u32);
}
if right.as_const().map(|vn| vn.offset() as i64) == Some(1) {
return left;
}
if right.as_const().map(|vn| vn.offset() as i64) == Some(0) {
let size = SimpleValue::derive_size_from(&left);
return SimpleValue::make_const(0, size as u32);
}
let s = std::cmp::max(left.size(), right.size());
SimpleValue::Mul(MulExpr(Intern::new(left), Intern::new(right), s))
}
}
impl Simplify for Or {
fn simplify(&self) -> SimpleValue {
let a_intern = self.0;
let b_intern = self.1;
let a_s = a_intern.as_ref().simplify();
let b_s = b_intern.as_ref().simplify();
if matches!(a_s, SimpleValue::Top) || matches!(b_s, SimpleValue::Top) {
return SimpleValue::Top;
}
let (mut left, mut right) = SimpleValue::normalize_or(a_s, b_s);
if !matches!(left, SimpleValue::Or(_))
&& !matches!(right, SimpleValue::Or(_))
&& SimpleValue::variant_rank(&left) > SimpleValue::variant_rank(&right)
{
std::mem::swap(&mut left, &mut right);
}
if left == right {
return left;
}
if let SimpleValue::Or(Or(inner_a, inner_b, _)) = &right {
if inner_a.as_ref() == &left {
let inner = SimpleValue::Or(Or(Intern::new(left.clone()), *inner_b, right.size()))
.simplify();
return inner;
}
if inner_b.as_ref() == &left {
let inner = SimpleValue::Or(Or(Intern::new(left.clone()), *inner_a, right.size()))
.simplify();
return inner;
}
}
if let (SimpleValue::Or(Or(l1, l2, _)), SimpleValue::Or(Or(r1, r2, _))) = (&left, &right) {
if l1.as_ref() == r1.as_ref() {
let inner = SimpleValue::Or(Or(
*l2,
*r2,
std::cmp::max(l2.as_ref().size(), r2.as_ref().size()),
))
.simplify();
let s = std::cmp::max(l1.as_ref().size(), inner.size());
return SimpleValue::Or(Or(
Intern::new(l1.as_ref().clone()),
Intern::new(inner),
s,
))
.simplify();
}
if l1.as_ref() == r2.as_ref() {
let inner = SimpleValue::Or(Or(
*l2,
*r1,
std::cmp::max(l2.as_ref().size(), r1.as_ref().size()),
))
.simplify();
let s = std::cmp::max(l1.as_ref().size(), inner.size());
return SimpleValue::Or(Or(
Intern::new(l1.as_ref().clone()),
Intern::new(inner),
s,
))
.simplify();
}
if l2.as_ref() == r1.as_ref() {
let inner = SimpleValue::Or(Or(
*l1,
*r2,
std::cmp::max(l1.as_ref().size(), r2.as_ref().size()),
))
.simplify();
let s = std::cmp::max(l2.as_ref().size(), inner.size());
return SimpleValue::Or(Or(
Intern::new(l2.as_ref().clone()),
Intern::new(inner),
s,
))
.simplify();
}
if l2.as_ref() == r2.as_ref() {
let inner = SimpleValue::Or(Or(
*l1,
*r1,
std::cmp::max(l1.as_ref().size(), r1.as_ref().size()),
))
.simplify();
let s = std::cmp::max(l2.as_ref().size(), inner.size());
return SimpleValue::Or(Or(
Intern::new(l2.as_ref().clone()),
Intern::new(inner),
s,
))
.simplify();
}
}
let s = std::cmp::max(left.size(), right.size());
SimpleValue::Or(Or(Intern::new(left), Intern::new(right), s))
}
}
impl Simplify for XorExpr {
fn simplify(&self) -> SimpleValue {
let a_intern = self.0;
let b_intern = self.1;
let a_s = a_intern.as_ref().simplify();
let b_s = b_intern.as_ref().simplify();
if matches!(a_s, SimpleValue::Top) || matches!(b_s, SimpleValue::Top) {
return SimpleValue::Top;
}
let (left, right) = SimpleValue::normalize_commutative(a_s, b_s);
if let (Some(left_vn), Some(right_vn)) = (left.as_const(), right.as_const()) {
let left_val = left_vn.offset();
let right_val = right_vn.offset();
let res = (left_val ^ right_val) as i64;
let size =
SimpleValue::derive_size_from(&left).max(SimpleValue::derive_size_from(&right));
return SimpleValue::make_const(res, size as u32);
}
if left == right {
let size = SimpleValue::derive_size_from(&left);
return SimpleValue::make_const(0, size as u32);
}
if right.as_const().map(|vn| vn.offset()) == Some(0) {
return left;
}
let s = std::cmp::max(left.size(), right.size());
SimpleValue::Xor(XorExpr(Intern::new(left), Intern::new(right), s))
}
}
impl Simplify for Load {
fn simplify(&self) -> SimpleValue {
let a_intern = self.0;
let a_s = a_intern.as_ref().simplify();
if matches!(a_s, SimpleValue::Top) {
return SimpleValue::Top;
}
SimpleValue::Load(Load(Intern::new(a_s), self.1))
}
}
fn fmt_operand_jingle(
f: &mut Formatter<'_>,
v: &SimpleValue,
info: &SleighArchInfo,
) -> std::fmt::Result {
if v.is_compound() {
write!(f, "(")?;
v.fmt_jingle(f, info)?;
write!(f, ")")
} else {
v.fmt_jingle(f, info)
}
}
fn fmt_operand(f: &mut std::fmt::Formatter<'_>, v: &SimpleValue) -> std::fmt::Result {
if v.is_compound() {
write!(f, "({v})")
} else {
write!(f, "{v}")
}
}
fn fmt_operand_hex(f: &mut std::fmt::Formatter<'_>, v: &SimpleValue) -> std::fmt::Result {
if v.is_compound() {
write!(f, "({v:x})")
} else {
write!(f, "{v:x}")
}
}
impl JingleDisplay for SimpleValue {
fn fmt_jingle(&self, f: &mut Formatter<'_>, info: &SleighArchInfo) -> std::fmt::Result {
match self {
SimpleValue::Entry(Entry(vn)) => write!(f, "{}", vn.display(info)),
SimpleValue::Const(vn) => {
write!(f, "{:#x}", vn.as_ref().offset())
}
SimpleValue::Offset(Offset(vn, con)) => {
write!(
f,
"offset({},{})",
vn.as_ref().0.display(info),
con.as_ref().0.display(info)
)
}
SimpleValue::Mul(MulExpr(a, b, _)) => {
fmt_operand_jingle(f, a.as_ref(), info)?;
write!(f, "*")?;
fmt_operand_jingle(f, b.as_ref(), info)
}
SimpleValue::Add(AddExpr(a, b, _)) => {
fmt_operand_jingle(f, a.as_ref(), info)?;
write!(f, "+")?;
fmt_operand_jingle(f, b.as_ref(), info)
}
SimpleValue::Sub(SubExpr(a, b, _)) => {
fmt_operand_jingle(f, a.as_ref(), info)?;
write!(f, "-")?;
fmt_operand_jingle(f, b.as_ref(), info)
}
SimpleValue::Or(Or(a, b, _)) => {
fmt_operand_jingle(f, a.as_ref(), info)?;
write!(f, "||")?;
fmt_operand_jingle(f, b.as_ref(), info)
}
SimpleValue::Xor(XorExpr(a, b, _)) => {
fmt_operand_jingle(f, a.as_ref(), info)?;
write!(f, "^")?;
fmt_operand_jingle(f, b.as_ref(), info)
}
SimpleValue::Load(Load(a, _)) => write!(f, "Load({})", a.as_ref().display(info)),
SimpleValue::Top => write!(f, "⊤"),
}
}
}
impl std::fmt::Display for SimpleValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SimpleValue::Entry(Entry(vn)) => {
write!(f, "{}", vn)
}
SimpleValue::Const(vn) => {
write!(f, "{:#x}", vn.as_ref().offset())
}
SimpleValue::Offset(Offset(vn, off)) => {
write!(f, "offset({}, {})", vn.0, off.0)
}
SimpleValue::Mul(MulExpr(a, b, _)) => {
fmt_operand(f, a.as_ref())?;
write!(f, "*")?;
fmt_operand(f, b.as_ref())
}
SimpleValue::Add(AddExpr(a, b, _)) => {
fmt_operand(f, a.as_ref())?;
write!(f, "+")?;
fmt_operand(f, b.as_ref())
}
SimpleValue::Sub(SubExpr(a, b, _)) => {
fmt_operand(f, a.as_ref())?;
write!(f, "-")?;
fmt_operand(f, b.as_ref())
}
SimpleValue::Or(Or(a, b, _)) => {
fmt_operand(f, a.as_ref())?;
write!(f, "||")?;
fmt_operand(f, b.as_ref())
}
SimpleValue::Xor(XorExpr(a, b, _)) => {
fmt_operand(f, a.as_ref())?;
write!(f, "^")?;
fmt_operand(f, b.as_ref())
}
SimpleValue::Load(Load(a, _)) => {
write!(f, "Load({})", a.as_ref())
}
SimpleValue::Top => {
write!(f, "⊤")
}
}
}
}
impl std::fmt::LowerHex for SimpleValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SimpleValue::Entry(Entry(vn)) => {
write!(f, "{}", vn)
}
SimpleValue::Const(vn) => {
write!(f, "{:x}", vn.as_ref().offset())
}
SimpleValue::Offset(Offset(vn, off)) => {
write!(f, "offset({:x}, {:x})", vn.0, off.0)
}
SimpleValue::Mul(MulExpr(a, b, _)) => {
fmt_operand_hex(f, a.as_ref())?;
write!(f, "*")?;
fmt_operand_hex(f, b.as_ref())
}
SimpleValue::Add(AddExpr(a, b, _)) => {
fmt_operand_hex(f, a.as_ref())?;
write!(f, "+")?;
fmt_operand_hex(f, b.as_ref())
}
SimpleValue::Sub(SubExpr(a, b, _)) => {
fmt_operand_hex(f, a.as_ref())?;
write!(f, "-")?;
fmt_operand_hex(f, b.as_ref())
}
SimpleValue::Or(Or(a, b, _)) => {
fmt_operand_hex(f, a.as_ref())?;
write!(f, "||")?;
fmt_operand_hex(f, b.as_ref())
}
SimpleValue::Xor(XorExpr(a, b, _)) => {
fmt_operand_hex(f, a.as_ref())?;
write!(f, "^")?;
fmt_operand_hex(f, b.as_ref())
}
SimpleValue::Load(Load(a, _)) => {
write!(f, "Load({:x})", a.as_ref())
}
SimpleValue::Top => write!(f, "⊤"),
}
}
}
impl SimpleValue {
pub fn from_varnode_or_entry(state: &SimpleValuationState, vn: &VarNode) -> Self {
if vn.is_const() {
SimpleValue::const_from_varnode(vn.clone())
} else if let Some(v) = state.valuation.direct_writes.get(vn) {
v.clone()
} else {
SimpleValue::Entry(Entry(vn.clone()))
}
}
}
impl JoinSemiLattice for SimpleValue {
fn join(&mut self, _other: &Self) {}
}