/*
* RTLMemoryLocation.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.Collections;
import java.util.Set;
import org.jakstab.rtl.*;
import org.jakstab.ssl.Architecture;
import org.jakstab.util.FastSet;
import org.jakstab.util.Logger;
/**
* A memory location with a specified data type/bit width and an address defined by another
* expression. IA-32 addresses can also contain a segment register, but the implementation
* is not yet complete.
*
* @author Johannes Kinder
*/
public class RTLMemoryLocation extends AbstractRTLExpression implements RTLExpression, Writable {
@SuppressWarnings("unused")
private final static Logger logger = Logger.getLogger(RTLMemoryLocation.class);
private Set<RTLMemoryLocation> usedMemoryLocations = null;
private SetOfVariables usedVariablesOnWrite;
private final RTLExpression segmentRegister;
private final RTLExpression address;
private final int bitWidth;
private final int size;
private final int memoryState;
protected RTLMemoryLocation(int memoryState, RTLExpression segmentRegister, RTLExpression address, int bitWidth) {
super();
this.memoryState = memoryState;
this.address = address;
this.segmentRegister = segmentRegister;
this.bitWidth = bitWidth;
this.size = 1 + (address != null ? address.size() : 0 )
+ (segmentRegister != null ? segmentRegister.size() : 0 );
}
/**
* @return the address
*/
public RTLExpression getAddress() {
return address;
}
public int getBitWidth() {
return bitWidth;
}
/**
* @return the segment register for this memory access, if specified,
* otherwise null.
*/
public RTLExpression getSegmentRegister() {
return segmentRegister;
}
/**
* Return the logical state this memory location refers to. Usually 0, but can
* be higher to allow expressions to refer to different memory states, e.g. as in
* mem32'[10] = mem32[10] + 5;
*
* @return the memory state (number of 'primes')
*/
public int getMemoryState() {
return memoryState;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
//if (getUsedVariables().contains(ExpressionFactory.getInstance().stackPointer))
// sb.append("stack");
//else
sb.append("mem");
if (bitWidth > 0) sb.append(bitWidth);
for (int i = 0; i < memoryState; i++)
sb.append('\'');
sb.append("[");
if (segmentRegister != null) {
sb.append(segmentRegister.toString());
sb.append(":");
}
sb.append(address.toHexString());
sb.append("]");
return sb.toString();
}
@Override
public RTLExpression evaluate(Context context) {
RTLExpression subst = context.getSubstitution(this);
// We also need to whether this location has been assigned a value (needed in VPC constant propagation, 31.1.13)
subst = context.getAssignment(this);
if (subst instanceof RTLMemoryLocation) {
RTLMemoryLocation m = (RTLMemoryLocation)subst;
RTLExpression evaldAddress = m.address.evaluate(context);
RTLMemoryLocation evaldMemLoc = evaldAddress == m.address ?
m : ExpressionFactory.createMemoryLocation(m.segmentRegister, evaldAddress, m.bitWidth);
RTLExpression value = context.getAssignment(evaldMemLoc);
if (value != null)
return value;
else
return evaldMemLoc;
} else {
return subst.evaluate(context);
}
}
@Override
public SetOfVariables getUsedVariables() {
if (usedVariables == null) {
usedVariables = new SetOfVariables();
if (segmentRegister != null)
usedVariables.addAll(segmentRegister.getUsedVariables());
if (address != null)
usedVariables.addAll(address.getUsedVariables());
//usedVariables.add(this);
}
return usedVariables;
}
@Override
public SetOfVariables getUsedVariablesOnWrite() {
if (usedVariablesOnWrite == null) {
usedVariablesOnWrite = new SetOfVariables();
if (segmentRegister != null)
usedVariablesOnWrite.addAll(segmentRegister.getUsedVariables());
if (address != null)
usedVariablesOnWrite.addAll(address.getUsedVariables());
}
return usedVariablesOnWrite;
}
@Override
public Set<RTLMemoryLocation> getUsedMemoryLocations() {
if (usedMemoryLocations == null) {
usedMemoryLocations = new FastSet<RTLMemoryLocation>();
usedMemoryLocations.addAll(address.getUsedMemoryLocations());
usedMemoryLocations.add(this);
}
return usedMemoryLocations;
}
@Override
public Set<RTLMemoryLocation> getDefinedMemoryLocationsOnWrite() {
return Collections.singleton(this);
}
@Override
public Set<RTLMemoryLocation> getUsedMemoryLocationsOnWrite() {
return address.getUsedMemoryLocations();
}
@Override
public SetOfVariables getDefinedVariablesOnWrite() {
//return setOfThis;
return SetOfVariables.EMPTY_SET;
}
@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;
RTLMemoryLocation other = (RTLMemoryLocation)obj;
return other.address.equals(address) &&
other.bitWidth == bitWidth &&
other.memoryState == memoryState &&
(other.segmentRegister == segmentRegister ||
(segmentRegister != null && segmentRegister.equals(other.segmentRegister)));
}
/*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return 59 + address.hashCode() + bitWidth;
}
@Override
public RTLExpression inferBitWidth(Architecture arch, int expectedBitWidth)
throws TypeInferenceException {
if (bitWidth != expectedBitWidth)
throw new TypeInferenceException("Expected bitwidth of " + expectedBitWidth + ", but memory reference is " + bitWidth + " bit.");
//return this;
// Inferring address bitwidth currently does not work b/c of multiplication.
// For MUL instructions, bitwidth gets doubled, in index-scale addressing, there is an implicit truncation
RTLExpression typedAddress = address.inferBitWidth(arch, arch.getAddressBitWidth());
if (typedAddress != address)
return ExpressionFactory.createMemoryLocation(
this.segmentRegister, typedAddress, bitWidth);
else return this;
}
@Override
public <T> T accept(ExpressionVisitor<T> visitor) {
return visitor.visit(this);
}
}