/* * BasedNumberElement.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.*; import org.jakstab.Program; import org.jakstab.analysis.*; import org.jakstab.rtl.BitVectorType; import org.jakstab.rtl.expressions.RTLNumber; import org.jakstab.util.Characters; import org.jakstab.util.Logger; /** * Represents symbolic constants of the form "region + offset". Used * for representing variable memory addresses of stack and heap structures. * Non-address values are identified with the "global" region. * * @author Johannes Kinder */ public class BasedNumberElement implements AbstractDomainElement, BitVectorType { private static final Logger logger = Logger.getLogger(BasedNumberElement.class); private static BasedNumberElement[] TOPS = new BasedNumberElement[128]; static { for (int bitWidth = 1; bitWidth <= 128; bitWidth++) { TOPS[bitWidth - 1] = new BasedNumberElement(MemoryRegion.TOP, NumberElement.getTop(bitWidth)); } } public static final BasedNumberElement TRUE = new BasedNumberElement(MemoryRegion.GLOBAL, NumberElement.TRUE); public static final BasedNumberElement FALSE = new BasedNumberElement(MemoryRegion.GLOBAL, NumberElement.FALSE); public static BasedNumberElement getTop(int bitWidth) { return TOPS[bitWidth - 1]; } private final MemoryRegion region; private final NumberElement value; public BasedNumberElement(MemoryRegion region, NumberElement value) { this.region = region; this.value = value; assert value != null; assert region != null; if (!region.isBot() && !region.isTop() && value.getBitWidth() != Program.getProgram().getArchitecture().getAddressBitWidth()) logger.verbose("Created based number element " + this + " with non-address-sized bitwidth!"); } public BasedNumberElement(MemoryRegion region, RTLNumber number) { this(region, new NumberElement(number)); } public BasedNumberElement(RTLNumber v) { this(MemoryRegion.GLOBAL, new NumberElement(v)); } /** * Checks whether the offset part of this based value is TOP. The caller has * to make sure that the region is valid (not TOP). * @return */ public boolean isNumberTop() { assert (!isTop()) : "TOP BasedNumberElement has no number!"; return value.isTop(); } public RTLNumber getNumber() { return value.getNumber(); } @Override public Set<RTLNumber> concretize() { // Just pass down to number elements - value in (TOP,TOPs) are // corresponding NumerElement TOPs if (!isUnbased() && !isTop()) { // Make sure to concretize regioned values to all numbers return getTop(getBitWidth()).concretize(); } return value.concretize(); } @Override public boolean isBot() { return false; } @Override public boolean isTop() { return region == MemoryRegion.TOP && value.isTop(); } @Override public int getBitWidth() { // Top and unbased values carry the bitwidth in their NumberElements //if (isTop() || isUnbased()) return value.getBitWidth(); // // All based numbers are addresses // FS is a 16bit register but stores a region-address (FS:0), so we cannot // just return 32 bit for all region-addresses. //return Program.getProgram().getArchitecture().getAddressBitWidth(); return value.getBitWidth(); } public boolean isUnbased() { return region == MemoryRegion.GLOBAL; } /** * Checks whether this element represents just a single concrete value. * * @return True if this abstract element's concretization has exactly one concrete element. */ public boolean hasUniqueConcretization() { return !isTop() && isUnbased() && !isNumberTop(); } @Override public BasedNumberElement join(LatticeElement l) { BasedNumberElement other = (BasedNumberElement)l; // Can happen for memory cells at same offset but of different size - no it shouldn't! assert other.getBitWidth() == this.getBitWidth() : "Different bitwidths: " + other + " with " + other.getBitWidth() + " and " + this + " with " + this.getBitWidth(); //if (other.getBitWidth() > this.getBitWidth()) return getTop(other.getBitWidth()); //if (this.getBitWidth() > other.getBitWidth()) return getTop(this.getBitWidth()); if (other.isTop()) return other; if (isTop()) return this; if (equals(other)) return this; if (region != other.region) return getTop(getBitWidth()); else return new BasedNumberElement(region, value.join(other.value)); } @Override public boolean lessOrEqual(LatticeElement l) { if (l.isTop() || equals(l)) return true; if (isTop()) return l.isTop(); BasedNumberElement other = (BasedNumberElement)l; return region == other.region && value.lessOrEqual(other.value); } @Override public int hashCode() { return region.hashCode() * 31 + value.hashCode(); } @Override public boolean equals(Object obj) { if (obj == null) return false; BasedNumberElement other = (BasedNumberElement) obj; return region.equals(other.region) && value.equals(other.value); } @Override public String toString() { if (isTop()) return Characters.TOP + "<" + getBitWidth() + ">"; else if (region == MemoryRegion.GLOBAL) return "$" + value.toString(); else return region.toString() + "+" + value.toString(); } public MemoryRegion getRegion() { return region; } @Override public BasedNumberElement bitExtract(int first, int last) { if (getRegion() != MemoryRegion.GLOBAL) return getTop(getBitWidth()); else return new BasedNumberElement(getRegion(), getNumber().bitExtract(first, last)); } @Override public BasedNumberElement multiply(AbstractDomainElement op) { BasedNumberElement other = (BasedNumberElement)op; if (other.getRegion() != MemoryRegion.GLOBAL || getRegion() != MemoryRegion.GLOBAL ) { return getTop(Math.max(getBitWidth(), other.getBitWidth())); } return new BasedNumberElement(getRegion(), getNumber().multiply(other.getNumber())); } @Override public BasedNumberElement negate() { if (region != MemoryRegion.GLOBAL) return getTop(getBitWidth()); else return new BasedNumberElement(getRegion(), getNumber().negate()); } @Override public BasedNumberElement plus(AbstractDomainElement op) { BasedNumberElement other = (BasedNumberElement)op; MemoryRegion resultRegion = region.join(other.getRegion()); if (resultRegion != MemoryRegion.TOP) { return new BasedNumberElement(resultRegion, getNumber().plus(other.getNumber())); } else { return getTop(Math.max(getBitWidth(), other.getBitWidth())); } } @Override public BasedNumberElement readStore(int bitWidth, PartitionedMemory<? extends AbstractDomainElement> store) { return (BasedNumberElement)store.get(getRegion(), getNumber().longValue(), bitWidth); } @Override public Collection<BasedNumberElement> readStorePowerSet( int bitWidth, PartitionedMemory<? extends AbstractDomainElement> store) { return Collections.singleton(readStore(bitWidth, store)); } @Override public <A extends AbstractDomainElement> void writeStore(int bitWidth, PartitionedMemory<A> store, A value) { if (isTop()) store.setTop(); else if (isNumberTop()) store.setTop(getRegion()); else store.set(getRegion(), getNumber().longValue(), bitWidth, value); } @Override public BasedNumberElement signExtend(int first, int last) { if (region != MemoryRegion.GLOBAL) return getTop(getBitWidth()); else return new BasedNumberElement(getRegion(), getNumber().signExtend(first, last)); } @Override public BasedNumberElement zeroFill(int first, int last) { if (region != MemoryRegion.GLOBAL) return getTop(getBitWidth()); else return new BasedNumberElement(getRegion(), getNumber().zeroFill(first, last)); } }