/* * NumberElement.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.explicit; import java.util.Collections; import java.util.Set; import org.jakstab.analysis.AbstractValue; import org.jakstab.analysis.LatticeElement; import org.jakstab.rtl.BitVectorType; import org.jakstab.rtl.expressions.ExpressionFactory; import org.jakstab.rtl.expressions.RTLNumber; import org.jakstab.util.*; /** * @author Johannes Kinder */ public class NumberElement implements AbstractValue, BitVectorType { @SuppressWarnings("unused") private static final Logger logger = Logger.getLogger(NumberElement.class); public static final NumberElement TRUE = new NumberElement(ExpressionFactory.TRUE); public static final NumberElement FALSE = new NumberElement(ExpressionFactory.FALSE); private static NumberElement[] TOPS = new NumberElement[128]; static { for (int bitWidth = 1; bitWidth <= 128; bitWidth++) { TOPS[bitWidth - 1] = new NumberElement(ExpressionFactory.createNumber(bitWidth - 1, bitWidth)); } } public static NumberElement getTop(int bitWidth) { return TOPS[bitWidth - 1]; } private final RTLNumber value; public NumberElement(RTLNumber v) { this.value = v; assert value != null : "Null number passed into NumberElement constructor"; assert v.getBitWidth() > 0 : "Cannot create number element for " + v + " with unknown bitwidth!"; } public RTLNumber getNumber() { assert !isTop() : "Attempting to get value of a TOP NumberElement!"; return value; } @Override public Set<RTLNumber> concretize() { if (isTop()) { // Enumerate small bitwidths if (getBitWidth() == 1) { Set<RTLNumber> result = new FastSet<RTLNumber>(); result.add(ExpressionFactory.TRUE); result.add(ExpressionFactory.FALSE); return result; } else { return RTLNumber.ALL_NUMBERS; } } return Collections.singleton(value); } @Override public boolean isBot() { return false; } @Override public boolean isTop() { return this == getTop(getBitWidth()); } @Override public int getBitWidth() { return value.getBitWidth(); } @Override public NumberElement join(LatticeElement l) { NumberElement other = (NumberElement)l; // Can happen for memory cells at same offset but of different size //assert other.getBitWidth() == this.getBitWidth() : "Trying to join numberelements of different bitwidth: " + other + " and " + this; if (other.getBitWidth() > this.getBitWidth()) return getTop(other.getBitWidth()); if (this.getBitWidth() > other.getBitWidth()) return getTop(this.getBitWidth()); if (l.isTop() || isTop()) return getTop(getBitWidth()); RTLNumber c = other.value; if (c.equals(value)) return this; else return getTop(getBitWidth()); } @Override public boolean lessOrEqual(LatticeElement l) { return l.isTop() || equals(l); } @Override public boolean equals(Object obj) { if (obj == this) return true; if (!(obj instanceof NumberElement)) return false; NumberElement other = (NumberElement)obj; if (getBitWidth() != other.getBitWidth()) return false; if (isTop()) return other.isTop(); return other.value.equals(this.value); } @Override public int hashCode() { return value.intValue(); // intValue is slightly faster than hashCode - and this is a hotspot //return value.hashCode(); } @Override public String toString() { if (isTop()) return Characters.TOP + "<" + getBitWidth() + ">"; else return value.toString(); } @Override public boolean hasUniqueConcretization() { return !isTop() && !isBot(); } }