/* * RTLBitrange.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.Set; import org.jakstab.rtl.Context; import org.jakstab.rtl.TypeInferenceException; import org.jakstab.ssl.Architecture; import org.jakstab.util.Logger; /** * A bitrange over another expression. Both start and endbits can be expressions, but the * bitwidth can only be determined if start and end position are numbers. * * @author Johannes Kinder */ public class RTLBitRange extends AbstractRTLExpression implements RTLExpression, Writable { /** * Creates a Bitmask in which all bits from startbit to and including * endbit are set. * * @param startBit The positive index of the first bit to set * @param endBit The positive index of the last bit to set * @return The bitmask */ public final static long bitMask(int startBit, int endBit) { return ((1L << (endBit - startBit + 1) ) - 1) << startBit; } public static final RTLNumber calculate(RTLNumber firstIndex, RTLNumber lastIndex, RTLNumber operand) { int firstBit = firstIndex.intValue(); int lastBit = lastIndex.intValue(); return calculate(firstBit, lastBit, operand); } public static final RTLNumber calculate(int firstBit, int lastBit, RTLNumber operand) { long value = operand.longValue(); return ExpressionFactory.createNumber((bitMask(firstBit, lastBit) & value) >> firstBit, lastBit - firstBit + 1); } private final static Logger logger = Logger.getLogger(RTLBitRange.class); private final RTLExpression firstBit; private final RTLExpression lastBit; private final RTLExpression operand; private final int size; private SetOfVariables usedVariablesOnWrite = null; protected RTLBitRange(RTLExpression variable, RTLExpression firstBit, RTLExpression lastBit) { super(); this.operand = variable; this.firstBit = firstBit; this.lastBit = lastBit; this.size = 1 + operand.size() + firstBit.size() + lastBit.size(); } @Override public RTLExpression evaluate(Context context) { RTLExpression evaldOperand = operand.evaluate(context); RTLExpression evaldFirstBit = firstBit.evaluate(context); RTLExpression evaldLastBit = lastBit.evaluate(context); if (evaldFirstBit instanceof RTLNumber && evaldLastBit instanceof RTLNumber) { int firstBit = ((RTLNumber)evaldFirstBit).intValue(); int lastBit = ((RTLNumber)evaldLastBit).intValue(); // Check for unnecessary index if (firstBit == 0 && evaldOperand instanceof RTLVariable && ((RTLVariable)evaldOperand).getBitWidth() == lastBit + 1) { logger.debug("Removing unnecessary Bitrange from " + this.toString()); return evaldOperand; } if (evaldOperand instanceof RTLNumber) { //long value = ((RTLNumber)evaldOperand).longValue(); //return ExpressionFactory.createNumber((bitMask(firstBit, lastBit) & value) >> firstBit, // lastBit - firstBit + 1); return calculate((RTLNumber)evaldFirstBit, (RTLNumber)evaldLastBit, (RTLNumber)evaldOperand); } } return ExpressionFactory.createBitRange(evaldOperand, evaldFirstBit, evaldLastBit); } @Override public SetOfVariables getDefinedVariablesOnWrite() { if (operand instanceof Writable) return ((Writable)operand).getDefinedVariablesOnWrite(); else throw new RuntimeException("Non-writable operand in bitrange!"); //return operand.getUsedVariables(); } /** * @return the firstBit */ public RTLExpression getFirstBitIndex() { return firstBit; } /** * @return the lastBit */ public RTLExpression getLastBitIndex() { return lastBit; } /** * @return the operand */ public RTLExpression getOperand() { return operand; } /** * Creates a bitmasking expression over the supplied parameter that is the * inverse of this bitrange. Can be used for simplifying assignments such as * x[0:7] = y; to x := (x & bitmask) | (size of x)y; * x[8:15] = y; to x := (x & bitmask) | ((size of x)y << 8) * * @param rhs the expression that the inverse should be applied to * @return The inverse of this bitrange applied to the parameter */ public RTLExpression applyInverse(RTLExpression rhs) { int firstBit = ((RTLNumber)getFirstBitIndex()).intValue(); int lastBit = ((RTLNumber)getLastBitIndex()).intValue(); long bitMask = RTLBitRange.bitMask(0, firstBit - 1) | RTLBitRange.bitMask(lastBit + 1, operand.getBitWidth()); // Bring rhs up to the size of the operand RTLExpression castToOpSize = ExpressionFactory.createZeroFill( ExpressionFactory.createNumber(rhs.getBitWidth(), 8), ExpressionFactory.createNumber(getOperand().getBitWidth() - 1, 8), rhs ); // Shift rhs if necessary RTLExpression maskedRhs; if (firstBit == 0) { maskedRhs = castToOpSize; } else { maskedRhs = ExpressionFactory.createShiftLeft( castToOpSize, getFirstBitIndex() ); } // Create the mask RTLExpression ret = ExpressionFactory.createOr( ExpressionFactory.createAnd( getOperand(), ExpressionFactory.createNumber(bitMask, getOperand().getBitWidth()) ), maskedRhs ); //logger.debug("Created " + ret); return ret; } @Override public SetOfVariables getUsedVariables() { if (usedVariables == null) { usedVariables = new SetOfVariables(); if (firstBit != null) usedVariables.addAll(firstBit.getUsedVariables()); if (lastBit != null) usedVariables.addAll(lastBit.getUsedVariables()); if (operand != null) usedVariables.addAll(operand.getUsedVariables()); } return usedVariables; } @Override public SetOfVariables getUsedVariablesOnWrite() { if (usedVariablesOnWrite == null) { usedVariablesOnWrite = new SetOfVariables(); if (firstBit != null) usedVariablesOnWrite.addAll(firstBit.getUsedVariables()); if (lastBit != null) usedVariablesOnWrite.addAll(lastBit.getUsedVariables()); // This was a temp fix for AH, AL etc. // usedVariablesOnWrite.addAll(operand.getUsedVariables()); } return usedVariablesOnWrite; } @Override public Set<RTLMemoryLocation> getUsedMemoryLocations() { return operand.getUsedMemoryLocations(); } @Override public Set<RTLMemoryLocation> getUsedMemoryLocationsOnWrite() { if (operand instanceof Writable) return ((Writable)operand).getUsedMemoryLocationsOnWrite(); else throw new RuntimeException("Non-writable operand in bitrange!"); //return operand.getUsedVariables(); } @Override public Set<RTLMemoryLocation> getDefinedMemoryLocationsOnWrite() { if (operand instanceof Writable) return ((Writable)operand).getDefinedMemoryLocationsOnWrite(); else throw new RuntimeException("Non-writable operand in bitrange!"); //return operand.getUsedVariables(); } @Override public String toString() { String bitRange; if (firstBit instanceof RTLNumber && lastBit instanceof RTLNumber) { int first = ((RTLNumber)firstBit).intValue(); int last = ((RTLNumber)lastBit).intValue(); if (first == last) bitRange = Integer.toString(first); else bitRange = first + ":" + last; } else { bitRange = firstBit.toString() + ":" + lastBit.toString(); } return operand.toString() + "@[" + bitRange + "]"; } @Override public int getBitWidth() { if (firstBit instanceof RTLNumber && lastBit instanceof RTLNumber) { int result = ((RTLNumber)lastBit).intValue() - ((RTLNumber)firstBit).intValue() + 1; return result; } else { if (firstBit.equals(lastBit)) return 1; assert false : "Cannot determine bitwidth for bitrange from " + firstBit + " to " + lastBit; return -1; } } @Override public int size() { return size; } /* * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (obj == null || obj.getClass() != this.getClass()) return false; RTLBitRange other = (RTLBitRange)obj; return other.operand.equals(this.operand) && other.firstBit.equals(this.firstBit) && other.lastBit.equals(this.lastBit); } /* * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return 3 + firstBit.hashCode() + lastBit.hashCode() + operand.hashCode(); } @Override public <T> T accept(ExpressionVisitor<T> visitor) { return visitor.visit(this); } /* * @see org.jakstab.rtl.expressions.AbstractRTLExpression#inferBitWidth(org.jakstab.ssl.Architecture, int) */ @Override public RTLExpression inferBitWidth(Architecture arch, int expectedBitWidth) throws TypeInferenceException { super.inferBitWidth(arch, expectedBitWidth); // Try to make bit indices 8 bit, if it fails, leave them the way they are RTLExpression typedFirstBit; try { typedFirstBit = firstBit.inferBitWidth(arch, 8); } catch (TypeInferenceException e) { logger.warn("Exception on inferring type of first bit index " + firstBit); typedFirstBit = firstBit; } RTLExpression typedLastBit; try { typedLastBit = lastBit.inferBitWidth(arch, 8); } catch (TypeInferenceException e) { logger.warn("Exception on inferring type of last bit index " + lastBit); typedLastBit = lastBit; } return ExpressionFactory.createBitRange(operand, typedFirstBit, typedLastBit); } }