/* * VariableValuation.java - This file is part of the Jakstab project. * Copyright 2007-2015 Johannes Kinder <jk@jakstab.org> * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, see <http://www.gnu.org/licenses/>. */ package org.jakstab.analysis; import java.util.*; import java.util.Map.Entry; import org.jakstab.rtl.Context; import org.jakstab.rtl.expressions.*; import org.jakstab.util.Logger; /** * @author Johannes Kinder */ public class VariableValuation<A extends AbstractValue> implements LatticeElement, Iterable<Map.Entry<RTLVariable, A>> { @SuppressWarnings("unused") private static final Logger logger = Logger.getLogger(VariableValuation.class); protected final TreeMap<RTLVariable,A> aVarVal; protected final AbstractValueFactory<A> valueFactory; protected VariableValuation(TreeMap<RTLVariable,A> aVarVal, AbstractValueFactory<A> valueFactory) { this.aVarVal = aVarVal; this.valueFactory = valueFactory; } public VariableValuation(VariableValuation<A> proto) { this(new TreeMap<RTLVariable, A>(proto.aVarVal), proto.valueFactory); } public VariableValuation(AbstractValueFactory<A> valueFactory) { this(new TreeMap<RTLVariable, A>(), valueFactory); } public A get(RTLVariable var) { A e = aVarVal.get(var); if (e != null) { return e; } else { // See if we can get the value from a covering register RTLBitRange asParent = ExpressionFactory.getRegisterAsParent(var); if (asParent != null && asParent.getOperand() instanceof RTLVariable) { RTLVariable parent = (RTLVariable)asParent.getOperand(); // Recursive call for al -> ax -> eax A parentVal = get(parent); assert parentVal != null; Collection<RTLNumber> cValues = new LinkedList<RTLNumber>(); for (RTLNumber cVal : parentVal.concretize()) { if (cVal == null) { cValues = null; break; } Context ctx = new Context(); ctx.addAssignment(parent, cVal); RTLExpression result = asParent.evaluate(ctx); cValues.add((RTLNumber)result); } if (cValues != null) { e = valueFactory.createAbstractValue(cValues); //logger.debug("Generated abstract value " + e + " for " + var + " from value " + parentVal + " of " + parent); return e; } } return valueFactory.createTop(var.getBitWidth()); } } private void clearCovering(RTLVariable var) { for (RTLVariable covering : ExpressionFactory.coveringRegisters(var)) { aVarVal.remove(covering); //clearCovering(covering); } } private void clearCovered(RTLVariable var) { for (RTLVariable covered : ExpressionFactory.coveredRegisters(var)) { aVarVal.remove(covered); //clearCovered(covered); } } public void set(RTLVariable var, A value) { RTLBitRange asParent = ExpressionFactory.getRegisterAsParent(var); // Set parent register - we only do this if the value to set represents // a single concrete value. If we want to generalize this, we have to // build the cartesian product of concretizations if (asParent != null && asParent.getOperand() instanceof RTLVariable && value.hasUniqueConcretization()) { RTLVariable parent = (RTLVariable)asParent.getOperand(); A parentVal = get(parent); RTLNumber cRhs = value.concretize().iterator().next(); Collection<RTLNumber> cValues = new LinkedList<RTLNumber>(); for (RTLNumber cVal : parentVal.concretize()) { if (cVal == null) { cValues = null; break; } Context ctx = new Context(); ctx.addAssignment(parent, cVal); RTLExpression result = asParent.applyInverse(cRhs).evaluate(ctx); cValues.add((RTLNumber)result); } if (cValues != null) { A e = valueFactory.createAbstractValue(cValues); //logger.debug("Setting parent " + parent + " of " + var + " to value " + e); set(parent, e); return; } } clearCovering(var); clearCovered(var); if (value.isTop()) { aVarVal.remove(var); } else { aVarVal.put(var, value); } } public void setTop(RTLVariable var) { clearCovering(var); clearCovered(var); aVarVal.remove(var); } @Override public boolean isBot() { return false; } @Override public boolean isTop() { return aVarVal.isEmpty(); } @SuppressWarnings("unchecked") @Override public VariableValuation<A> join(LatticeElement l) { VariableValuation<A> other = (VariableValuation<A>)l; if (isTop() || other.isBot()) return this; if (isBot() || other.isTop()) return other; VariableValuation<A> joinedValuation = new VariableValuation<A>(valueFactory); // Join variable valuations for (Map.Entry<RTLVariable,A> entry : aVarVal.entrySet()) { RTLVariable var = entry.getKey(); A value = entry.getValue(); joinedValuation.set(var, (A)value.join(other.get(var))); } return joinedValuation; } @SuppressWarnings("unchecked") @Override public boolean lessOrEqual(LatticeElement l) { if (this == l) return true; VariableValuation<A> other = (VariableValuation<A>)l; if (other.isTop()) return true; if (isTop()) return false; // For all variables in other valuation, check if their // value in this valuation is less. Other way round is not // possible, as their could be variables present in the other // valuation but not in this one. for (Map.Entry<RTLVariable,A> entry : other.aVarVal.entrySet()) { RTLVariable var = entry.getKey(); A value = entry.getValue(); if (!get(var).lessOrEqual(value)) { return false; } } return true; } @Override public String toString() { return aVarVal.toString(); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((aVarVal == null) ? 0 : aVarVal.hashCode()); return result; } @SuppressWarnings("unchecked") @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; VariableValuation<A> other = (VariableValuation<A>) obj; if (aVarVal == null) { return other.aVarVal == null; } else { return aVarVal.equals(other.aVarVal); } } @Override public Iterator<Entry<RTLVariable, A>> iterator() { return aVarVal.entrySet().iterator(); } }