/*
* Copyright 2002-2003 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
/*
* Original code for this class taken from the Java HotSpot VM.
* Modified for use with the Jakstab project. All modifications
* Copyright 2007-2015 Johannes Kinder <jk@jakstab.org>
*/
package org.jakstab.asm.x86;
import org.jakstab.asm.*;
import org.jakstab.rtl.Context;
public class X86Instruction extends AbstractInstruction
implements Instruction, X86Opcodes, MemoryInstruction, Cloneable {
final private int size;
final private int prefixes;
final private DataType dataType; //RTL dataType
private Operand[] operands;
final private int operandCount;
private String description;
public String getPrefixString() {
StringBuffer buf = new StringBuffer();
if ((prefixes & PREFIX_REPZ) != 0)
buf.append("repz ");
if ((prefixes & PREFIX_REPNZ) != 0)
buf.append("repnz ");
if ((prefixes & PREFIX_LOCK) != 0)
buf.append("lock ");
return buf.toString();
}
public boolean hasPrefixREPZ() {
return (prefixes & PREFIX_REPZ) != 0;
}
public boolean hasPrefixREPNZ() {
return (prefixes & PREFIX_REPNZ) != 0;
}
public boolean hasPrefixLOCK() {
return (prefixes & PREFIX_LOCK) != 0;
}
public int getSize() {
return size;
}
public String toString(long currentPc, SymbolFinder symFinder) {
if (description == null)
description = initDescription(currentPc, symFinder);
return description;
}
@Override
public int getOperandCount() {
return operandCount;
}
@Override
public Operand getOperand(int i) {
return operands[i];
}
public Operand getOperand1() {
return operands[0];
}
public Operand getOperand2() {
return operands[1];
}
public Operand getOperand3() {
return operands[2];
}
public DataType getDataType() {
return dataType;
}
public boolean hasEsiBasedMemorySource() {
return (getOperand2() instanceof X86MemoryOperand &&
((X86MemoryOperand)getOperand2()).getBase().equals(X86Registers.ESI));
}
public boolean hasEdiBasedMemoryTarget() {
return (getOperand1() instanceof X86MemoryOperand &&
((X86MemoryOperand)getOperand1()).getBase().equals(X86Registers.EDI));
}
public X86Instruction(String name, Operand op1, Operand op2, Operand op3, DataType dataType, int size, int prefixes) {
super(name);
this.size = size;
this.prefixes = prefixes;
this.operands = new Operand[]{op1, op2, op3};
// Count non-null operands
int operandCount = 3;
for (int i=0; i < operands.length; i++) {
if (operands[i] == null) {
operandCount = i;
break;
}
}
this.operandCount = operandCount;
this.dataType = dataType;
// initialized when needed for the first time
description = null;
}
public X86Instruction(String name, Operand op1, Operand op2, Operand op3, int size, int prefixes) {
this(name, op1, op2, op3, DataType.UNKNOWN, size, prefixes);
}
public X86Instruction(String name, Operand op1, Operand op2, DataType dataType, int size, int prefixes) {
this(name, op1, op2, (Operand)null, dataType, size, prefixes);
}
public X86Instruction(String name, Operand op1, Operand op2, int size, int prefixes) {
this(name, op1, op2, (Operand)null, size, prefixes);
}
public X86Instruction(String name, Operand op1, int size, int prefixes) {
this(name, op1, (Operand)null, (Operand)null, size, prefixes);
}
public X86Instruction(String name, int size, int prefixes) {
this(name, (Operand)null, (Operand)null, (Operand)null, size, prefixes);
}
protected String initDescription(long currentPc, SymbolFinder symFinder) {
StringBuffer buf = new StringBuffer();
buf.append(getPrefixString());
buf.append(getName());
buf.append(spaces);
if (operands[2] != null) {
//buf.append("(");
//buf.append(operands[2].getClass().getSimpleName());
//buf.append(")");
buf.append(operands[2].toString(currentPc, symFinder));
buf.append(comma);
}
if (operands[1] != null) {
//buf.append("(");
//buf.append(operands[1].getClass().getSimpleName());
//buf.append(")");
buf.append(operands[1].toString(currentPc, symFinder));
buf.append(comma);
}
if(operands[0] != null) {
//buf.append("(");
//buf.append(operands[0].getClass().getSimpleName());
//buf.append(")");
buf.append(operands[0].toString(currentPc, symFinder));
}
return buf.toString();
}
protected static String comma = ", ";
protected static String spaces = "\t";
@Override
public Instruction evaluate(Context ctx) {
boolean changed = false;
Operand[] evaledOperands = new Operand[operands.length];
for (int i = 0; i < getOperandCount(); i++) {
evaledOperands[i] = operands[i].evaluate(ctx);
changed |= evaledOperands[i] != operands[i];
}
if (!changed)
return this;
else {
X86Instruction inst = null;
try {
inst = (X86Instruction) super.clone();
inst.operands = new Operand[inst.operands.length];
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
System.arraycopy(evaledOperands, 0, inst.operands, 0, inst.operands.length);
return inst;
//return new X86Instruction(name, evaledOperands[0], evaledOperands[1], evaledOperands[2], size, prefixes);
}
}
}