/*
* ValuationState.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 org.jakstab.cfa.Location;
import org.jakstab.rtl.expressions.*;
import org.jakstab.util.*;
import org.jakstab.util.MapMap.EntryIterator;
/**
* A generic class for abstract states that map each variable and memory location
* to some abstract value. It provides functions for abstract expression evaluation
* via power set expansion or subexpression joining, getters and setters for variables
* and memory, as well as Cartesian lattice operators. For this to work, you need to
* supply it with an AbstractValueFactory that creates abstract elements of the
* specific abstract domain that should be implemented.
*
* The abstract post remains to be implemented by the main analysis class.
*
* @author Johannes Kinder
*/
public class ValuationState implements AbstractState {
@SuppressWarnings("unused")
private static final Logger logger = Logger.getLogger(ValuationState.class);
private static long maxStateId = 0;
private final long id;
private final AbstractValueFactory<AbstractDomainElement> valueFactory;
private VariableValuation<AbstractDomainElement> varVal;
private PartitionedMemory<AbstractDomainElement> store;
public ValuationState(ValuationState proto) {
this(proto.valueFactory,
new VariableValuation<AbstractDomainElement>(proto.varVal),
new PartitionedMemory<AbstractDomainElement>(proto.store));
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public ValuationState(AbstractValueFactory valueFactory) {
this(valueFactory,
new VariableValuation<AbstractDomainElement>(valueFactory),
new PartitionedMemory<AbstractDomainElement>(valueFactory));
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private ValuationState(AbstractValueFactory valueFactory, VariableValuation<AbstractDomainElement> varVal, PartitionedMemory<AbstractDomainElement> store) {
this.valueFactory = valueFactory;
this.varVal = varVal;
this.store = store;
this.id = maxStateId++;
}
public AbstractDomainElement abstractEval(RTLExpression e) {
// TODO: Create a fast, specific implementation for this
Set<AbstractDomainElement> result = abstractEvalPowerSet(e);
return Lattices.joinAll(result);
}
public Set<AbstractDomainElement> abstractEvalPowerSet(RTLExpression e) {
return e.accept(new ExpressionVisitor<Set<AbstractDomainElement>>() {
@Override
public Set<AbstractDomainElement> visit(RTLBitRange e) {
AbstractDomainElement first = Lattices.joinAll(e.getFirstBitIndex().accept(this));
AbstractDomainElement last = Lattices.joinAll(e.getLastBitIndex().accept(this));
if (first.hasUniqueConcretization() && last.hasUniqueConcretization()) {
Set<AbstractDomainElement> res = new FastSet<AbstractDomainElement>();
for (AbstractDomainElement aOp : e.getOperand().accept(this)) {
res.add(aOp.bitExtract(first.concretize().iterator().next().intValue(),
last.concretize().iterator().next().intValue()));
}
return res;
} else {
return Collections.singleton(valueFactory.createTop(e.getBitWidth()));
}
}
@Override
public Set<AbstractDomainElement> visit(RTLMemoryLocation e) {
Set<AbstractDomainElement> res = new FastSet<AbstractDomainElement>();
for (AbstractDomainElement aAddress : e.getAddress().accept(this)) {
res.addAll(aAddress.readStorePowerSet(e.getBitWidth(), store));
}
return res;
}
@Override
public Set<AbstractDomainElement> visit(RTLOperation e) {
Tuple<Set<AbstractDomainElement>> aOperandSets =
new Tuple<Set<AbstractDomainElement>>(e.getOperandCount());
for (int i=0; i<e.getOperandCount(); i++) {
aOperandSets.set(i, e.getOperands()[i].accept(this));
}
int bitWidth = e.getBitWidth();
Set<AbstractDomainElement> res = new FastSet<AbstractDomainElement>();
for (Tuple<AbstractDomainElement> aOperands : Sets.crossProduct(aOperandSets)) {
AbstractDomainElement result;
switch (e.getOperator()) {
case PLUS:
result = aOperands.get(0);
for (int i=1; i<aOperands.size(); i++) {
AbstractDomainElement aOp = aOperands.get(i);
result = aOp.plus(result);
}
break;
case MUL:
result = aOperands.get(0);
for (int i=1; i<aOperands.size(); i++) {
AbstractDomainElement aOp = aOperands.get(i);
result = aOp.multiply(result);
}
break;
case EQUAL:
// If both sides can only have AbstractDomainElement single value, just
// see if they are equal.
if (aOperands.get(0).hasUniqueConcretization() &&
aOperands.get(1).hasUniqueConcretization()) {
if(aOperands.get(0).concretize().equals(
aOperands.get(1).concretize())) {
result = valueFactory.createTrue();
} else {
result = valueFactory.createFalse();
}
} else {
result = valueFactory.createTop(bitWidth);
}
break;
case SIGN_EXTEND: {
int from = ((RTLNumber)e.getOperands()[0]).intValue();
int to = ((RTLNumber)e.getOperands()[1]).intValue();
result = aOperands.get(2).signExtend(from, to);
break;
}
case ZERO_FILL: {
int from = ((RTLNumber)e.getOperands()[0]).intValue();
int to = ((RTLNumber)e.getOperands()[1]).intValue();
result = aOperands.get(2).zeroFill(from, to);
break;
}
default:
result = valueFactory.createTop(bitWidth);
}
res.add(result);
}
return res;
}
@Override
public Set<AbstractDomainElement> visit(RTLVariable e) {
return Collections.singleton(varVal.get(e));
}
@Override
public Set<AbstractDomainElement> visit(RTLConditionalExpression e) {
Set<AbstractDomainElement> res = new FastSet<AbstractDomainElement>();
res.addAll(e.getTrueExpression().accept(this));
res.addAll(e.getFalseExpression().accept(this));
return res;
}
@Override
public Set<AbstractDomainElement> visit(RTLNondet e) {
return Collections.singleton(valueFactory.createTop(e.getBitWidth()));
}
@Override
public Set<AbstractDomainElement> visit(RTLNumber e) {
return Collections.singleton(valueFactory.createAbstractValue(e));
}
@Override
public Set<AbstractDomainElement> visit(RTLSpecialExpression e) {
return Collections.singleton(valueFactory.createTop(e.getBitWidth()));
}
});
}
public void setMemoryValue(AbstractDomainElement address,
int bitWidth, AbstractDomainElement value) {
address.writeStore(bitWidth, store, value);
}
public void setMemoryValue(MemoryRegion region, long offset, int bitWidth, AbstractDomainElement value) {
store.set(region, offset, bitWidth, value);
}
public void setVariableValue(RTLVariable var, AbstractDomainElement value) {
varVal.set(var, value);
}
public AbstractDomainElement getMemoryValue(AbstractDomainElement address, int bitWidth) {
return address.readStore(bitWidth, store);
}
public AbstractDomainElement getMemoryValue(MemoryRegion region, long offset, int bitWidth) {
return store.get(region, offset, bitWidth);
}
public AbstractDomainElement getVariableValue(RTLVariable var) {
return varVal.get(var);
}
public Iterator<Map.Entry<RTLVariable, AbstractDomainElement>> variableIterator() {
return varVal.iterator();
}
public EntryIterator<MemoryRegion, Long, AbstractDomainElement> storeIterator() {
return store.entryIterator();
}
@Override
public String getIdentifier() {
return Long.toString(id);
}
@Override
public Location getLocation() {
throw new UnsupportedOperationException(this.getClass().getSimpleName() + " does not contain location information.");
}
@Override
public ValuationState join(LatticeElement l) {
ValuationState other = (ValuationState)l;
if (isTop() || other.isBot()) return this;
if (isBot() || other.isTop()) return other;
// Join variable valuations
VariableValuation<AbstractDomainElement> jVarVal = varVal.join(other.varVal);
PartitionedMemory<AbstractDomainElement> jStore = store.join(other.store);
return new ValuationState(valueFactory, jVarVal, jStore);
}
@Override
public Set<Tuple<RTLNumber>> projectionFromConcretization(
RTLExpression... expressions) {
Tuple<Set<RTLNumber>> tupleOfSets = new Tuple<Set<RTLNumber>>(expressions.length);
for (int i=0; i<expressions.length; i++) {
Set<RTLNumber> concreteValues = new FastSet<RTLNumber>();
for (AbstractDomainElement el : abstractEvalPowerSet(expressions[i])) {
Set<RTLNumber> c = el.concretize();
if (c == RTLNumber.ALL_NUMBERS) {
if (expressions[i].getBitWidth() == 1) {
// bitWidth is 1, we can just force 1 and 0 here
concreteValues.add(ExpressionFactory.TRUE);
concreteValues.add(ExpressionFactory.FALSE);
} else {
concreteValues = RTLNumber.ALL_NUMBERS;
break;
}
} else {
concreteValues.addAll(c);
}
}
tupleOfSets.set(i, concreteValues);
}
return Sets.crossProduct(tupleOfSets);
}
@Override
public boolean isBot() {
return varVal.isBot() && store.isBot();
}
@Override
public boolean isTop() {
return varVal.isTop() && store.isTop();
}
@Override
public boolean lessOrEqual(LatticeElement l) {
if (this == l) return true;
ValuationState other = (ValuationState)l;
if (isBot() || other.isTop()) return true;
if (isTop() || other.isBot()) return false;
if (!varVal.lessOrEqual(other.varVal))
return false;
if (!store.lessOrEqual(other.store))
return false;
return true;
}
@Override
public String toString() {
return "I: " + varVal.toString() + " Mem:" + store.toString();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((store == null) ? 0 : store.hashCode());
result = prime * result + ((varVal == null) ? 0 : varVal.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ValuationState other = (ValuationState) obj;
if (store == null) {
if (other.store != null)
return false;
} else if (!store.equals(other.store))
return false;
if (varVal == null) {
if (other.varVal != null)
return false;
} else if (!varVal.equals(other.varVal))
return false;
return true;
}
}