/* * RTLNumber.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.rtl.expressions; import java.util.Collection; import java.util.Collections; import java.util.Set; import org.jakstab.analysis.*; import org.jakstab.rtl.*; import org.jakstab.ssl.Architecture; import org.jakstab.util.Logger; /** * Wrapper class for representing integer numbers with a defined number of bits. * * @author Johannes Kinder */ public class RTLNumber extends AbstractRTLExpression implements RTLExpression, AbstractDomainElement { public static final RTLNumber WILDCARD = null; public static final Set<RTLNumber> ALL_NUMBERS = Collections.singleton(WILDCARD); @SuppressWarnings("unused") private static final Logger logger = Logger.getLogger(RTLNumber.class); private final int bitWidth; private final long value; protected RTLNumber(long value, int bitWidth) { super(); this.bitWidth = bitWidth; // Implements bitvector semantics by wrapping all created numbers // according to bitwidth if (bitWidth < 64 && bitWidth > 1) { value = value % (1L << bitWidth); if (value >= (1L << (bitWidth - 1))) { value = value - (1L << bitWidth); } else if (value < -(1L << (bitWidth - 1))) { value = value + (1L << bitWidth); } } this.value = value; assert this.bitWidth != 1 || this.value == 0L || this.value == -1L; } /** * @return the represented number cast to an integer. */ public int intValue() { return (int)value; } /** * * @return the represented number as long integer. */ public long longValue() { return value; } /* * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (obj == null || obj.getClass() != this.getClass()) return false; RTLNumber other = ((RTLNumber)obj); // If one is weakly typed, only check values /*if (bitWidth == RTLVariable.UNKNOWN_BITWIDTH || other.bitWidth == RTLVariable.UNKNOWN_BITWIDTH) return other.value == value;*/ return other.value == value && other.bitWidth == bitWidth; } /* * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return 83 + (int)value + bitWidth; } /* * @see java.lang.Object#toString() */ @Override public String toString() { if (bitWidth == 1) { return (value == 0L) ? "false" : "true"; } //String bw = "<" + (bitWidth==RTLVariable.UNKNOWN_BITWIDTH ? "?" : bitWidth) + ">"; return Long.toString(value); //+ bw; } @Override public String toHexString() { String bw = "<" + (bitWidth==RTLVariable.UNKNOWN_BITWIDTH ? "?" : bitWidth) + ">"; String hex = Integer.toHexString((int)value); if (value < 0 && bitWidth > 0) { hex = hex.substring(Math.max(0, hex.length() - (bitWidth / 4))); } return "0x" + hex + bw; } @Override public RTLExpression evaluate(Context context) { return this; } @Override public SetOfVariables getUsedVariables() { return SetOfVariables.EMPTY_SET; } @Override public Set<RTLMemoryLocation> getUsedMemoryLocations() { return Collections.emptySet(); } /* * @see org.jakstab.rtl.RTLExpression#size() */ @Override public int size() { return 1; } @Override public int getBitWidth() { return bitWidth; } @Override public RTLExpression inferBitWidth(Architecture arch, int expectedBitWidth) throws TypeInferenceException { if (bitWidth == expectedBitWidth) return this; else if (bitWidth <= 0) { // Does the value (signed) fit into the bits? if (Math.log(Math.abs(value)) / Math.log(2) <= (expectedBitWidth - 1)) return ExpressionFactory.createNumber(this.value, expectedBitWidth); else throw new TypeInferenceException("Expected bit width of " + expectedBitWidth + " too small to hold numeric value of " + value + "!"); } else if (bitWidth < expectedBitWidth) { // TODO: Check if sign extension is correct return ExpressionFactory.createNumber(value, expectedBitWidth); } else { // Expected bitwidth less than our bitwidth throw new TypeInferenceException(this.toString() + " expected to be of bitwidth " + expectedBitWidth); } } @Override public <T> T accept(ExpressionVisitor<T> visitor) { return visitor.visit(this); } @Override public RTLNumber bitExtract(int first, int last) { return RTLBitRange.calculate(first, last, this); } @Override public RTLNumber join(LatticeElement l) { return null; } @Override public RTLNumber multiply(AbstractDomainElement op) { RTLNumber other = (RTLNumber)op; return ExpressionFactory.createNumber( value * other.value, Math.max(bitWidth, other.bitWidth)); } @Override public RTLNumber negate() { return ExpressionFactory.createNumber(-value, bitWidth); } @Override public RTLNumber plus(AbstractDomainElement op) { RTLNumber other = (RTLNumber)op; return ExpressionFactory.createNumber( value + other.value, Math.max(bitWidth, other.bitWidth)); } @Override public RTLNumber readStore(int bitWidth, PartitionedMemory<? extends AbstractDomainElement> store) { return (RTLNumber)store.get(MemoryRegion.GLOBAL, value, bitWidth); } @Override public Collection<RTLNumber> 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 valueToWrite) { store.set(MemoryRegion.GLOBAL, value, bitWidth, valueToWrite); } @Override public RTLNumber signExtend(int first, int last) { int targetWidth = Math.max(bitWidth, last + 1); long extension = value; if ((value & RTLBitRange.bitMask(bitWidth - 1, bitWidth - 1)) > 0) { extension = value | RTLBitRange.bitMask(first, last); } return ExpressionFactory.createNumber(extension, targetWidth); } @Override public RTLNumber zeroFill(int first, int last) { int targetWidth = Math.max(bitWidth, last + 1); long filled = value & ( RTLBitRange.bitMask(0, first - 1) | RTLBitRange.bitMask(last + 1, targetWidth - 1)); return ExpressionFactory.createNumber(filled, targetWidth); } @Override public Set<RTLNumber> concretize() { return Collections.singleton(this); } @Override public boolean hasUniqueConcretization() { return true; } @Override public boolean isBot() { return false; } @Override public boolean isTop() { return false; } @Override public boolean lessOrEqual(LatticeElement l) { return equals(l); } }