All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jreversepro.reflect.JInstruction Maven / Gradle / Ivy

/*
  @(#)JInstruction.java JReversePro - Java Decompiler / Disassembler.
 * Copyright (C) 2000 2001 Karthik Kumar.
 * EMail: [email protected]
 * 

* This program is free software; you can redistribute it and/or modify * it , under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2 of the License, * or (at your option) any later version. *

* This program 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 for more details. * You should have received a copy of the GNU General Public License * along with this program.If not, write to * The Free Software Foundation, Inc., * 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ package jreversepro.reflect; import jreversepro.common.Helper; import jreversepro.common.JJvmOpcodes; import jreversepro.common.JJvmSet; import jreversepro.common.KeyWords; /** * Abstraction of a JVM Opcode instruction. * * @author Karthik Kumar */ public class JInstruction implements JJvmOpcodes, KeyWords { /** * Invalid variable index. */ public static final int INVALID_VAR_INDEX = -2; /** * Arguments to the current opcode instruction. */ public final byte[] args; /** * Index of this instruction onto the byte array of the * method to be decompiled. zero-based index. */ public final int index; /** * opcode name of the instruction. */ public final String insName; /** * Length of the instruction in bytes. */ public final int length; /** * opcode of the JVM instruction. */ public final int opcode; /** * If this is a wide instruction. */ public final boolean wide; /** * Position of the method into the method pool * */ public int position; /** * Next instruction in the method pool * */ private JInstruction next; /** * Previous instruction in the method pool * */ private JInstruction prev; /** * @param rhsIndex Index of the instruction into the * method bytecode array. * @param rhsOpcode Opcode of the JVM instruction. * @param rhsArgs Arguments to the JVM opcodes. * @param rhsWide If the previous instruction was a wide * instruction. */ public JInstruction(int rhsIndex, int rhsOpcode, byte[] rhsArgs, boolean rhsWide) { prev = null; next = null; position = 1; index = rhsIndex; opcode = rhsOpcode; args = rhsArgs; insName = JJvmSet.getIns(rhsOpcode); length = (rhsArgs == null) ? 1 : rhsArgs.length + 1; wide = rhsWide; } /** * Appends a instruction to this * * @param rhsNext Next Instruction to be appended to this. */ public void append(JInstruction rhsNext) { this.next = rhsNext; rhsNext.prev = this; rhsNext.position = this.position + 1; } /** * @param obj Object to be compared. * @return true if index is there. * false, otherwise. */ public boolean equals(Object obj) { return obj instanceof JInstruction && ((JInstruction) obj).index == this.index; } public int getArgByte() { return getArgByte(0); } public int getArgByte(int pos) { return args[pos]; } /** * @return unsigned byte. */ public int getArgUnsignedByte() { return getArgUnsignedByte(0); } /** * @param pos Position from which bytes are to be taken from stream * and the value to be written. * @return unsigned byte. */ public int getArgUnsignedByte(int pos) { return Helper.signedToUnsigned(args[pos]); } public int getArgUnsignedInt() { return getArgUnsignedInt(0); } public int getArgUnsignedInt(int pos) { int byte1 = Helper.signedToUnsigned(args[pos]); int byte2 = Helper.signedToUnsigned(args[pos + 1]); int byte3 = Helper.signedToUnsigned(args[pos + 2]); int byte4 = Helper.signedToUnsigned(args[pos + 3]); return (byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4; } public int getArgUnsignedShort() { return getArgUnsignedShort(0); } public final int getArgUnsignedShort(int pos) { int byte1 = Helper.signedToUnsigned(args[pos]); int byte2 = Helper.signedToUnsigned(args[pos + 1]); return (byte1 << 8) | byte2; } public int getArgWide() { return getArgWide(0); } public int getArgWide(int pos) { if (wide) { if (pos != 0) { return getArgShort(pos * 2); } else { return getArgShort(0); } } else { return getArgByte(pos); } } public int getArgShort(int pos) { int byte1 = args[pos]; int byte2 = Helper.signedToUnsigned(args[pos + 1]); return (byte1 << 8) | byte2; } /** * In case this instruction is a branch instruction * on some condition then the operator corresponding to the * operator is returned. * For eg, for OPCODE_IFEQ , = is returned. * * @return Returns conditional operator for the condition * mentioned in the opcode. * Empty string, if the opcode is not of branch-on-condition type. */ public String getConditionalOperator() { switch (opcode) { case OPCODE_IFEQ: case OPCODE_IF_ICMPEQ: case OPCODE_IF_ACMPEQ: case OPCODE_IFNULL: return OPR_EQ; case OPCODE_IFNE: case OPCODE_IF_ICMPNE: case OPCODE_IF_ACMPNE: case OPCODE_IFNONNULL: return OPR_NE; case OPCODE_IFLT: case OPCODE_IF_ICMPLT: return OPR_LT; case OPCODE_IFGE: case OPCODE_IF_ICMPGE: return OPR_GE; case OPCODE_IFGT: case OPCODE_IF_ICMPGT: return OPR_GT; case OPCODE_IFLE: case OPCODE_IF_ICMPLE: return OPR_LE; default: return ""; } } /** * @return Returns the opcode name */ public String getInsName() { return insName; } /** * @return Returns the length of the instruction. * */ public int getLength() { return length; } /** * @return Returns the next instruction index. */ public int getNextIndex() { if (next != null) { return next.index; } else { //Last Index. return index + length; } } /** * In case this instruction is a jump/branch instruction, this * instruction returns the offset mentioned in the two * bytes in the argument array. Works whether wide target or not. * * @return Returns the offset. */ public int getTargetPc2() { if (!wide) { return getTargetPc(); } else { return getTargetPcW(); } } /** * In case this instruction is a jump/branch instruction, this * instruction returns the offset + index mentioned in the two * bytes in the argument array. * * @return Returns the offset + index. */ public int getTargetPc() { return (getOffset() + index) & 0xffff; } /** * In case this instruction is a jump/branch instruction, this * instruction returns the offset mentioned in the two * bytes in the argument array. Also important to note is the * fact this is a 'wide' variant of the conventional jump * instructions. * * @return Returns the offset. */ public int getTargetPcW() { return (getArgInt() + index) & 0xffff; } /** * In case this instruction is a jump/branch instruction, this * instruction returns the offset mentioned in the two * bytes in the argument array. * * @return Returns the offset. */ public int getOffset() { return getArgShort() & 0xffff; } public int getArgInt() { return getArgInt(0); } public int getArgShort() { return getArgShort(0); } public int getArgInt(int pos) { int byte1 = args[pos]; int byte2 = Helper.signedToUnsigned(args[pos + 1]); int byte3 = Helper.signedToUnsigned(args[pos + 2]); int byte4 = Helper.signedToUnsigned(args[pos + 3]); return (byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4; } /** * Returns if this instruction is a switch instruction or not. * * @return true, if switch instruction. false. otherwise */ public boolean isASwitchIns() { return opcode == OPCODE_TABLESWITCH || opcode == OPCODE_LOOKUPSWITCH; } /** * Returns if this instruction is an if instruction or not. * * @return true, if this is an 'if' instruction. * false, otherwise. */ public boolean isAnIfIns() { return (opcode >= OPCODE_IFEQ && opcode <= OPCODE_IF_ACMPNE) || opcode == OPCODE_IFNULL || opcode == OPCODE_IFNONNULL; } public final boolean isEndOfCatch() { return opcode == OPCODE_ARETURN || opcode == OPCODE_IRETURN || opcode == OPCODE_LRETURN || opcode == OPCODE_FRETURN || opcode == OPCODE_DRETURN || opcode == OPCODE_RETURN || opcode == OPCODE_POP || // opcode == OPCODE_GOTO || // opcode == OPCODE_GOTOW || opcode == OPCODE_ATHROW || opcode == OPCODE_JSR || opcode == OPCODE_JSRW; } /** * To check if this instruction denotes the corresponding * end-of-line in the source code. * * @return Returns true, if this denoted end-of-line. * false, otherwise. */ public boolean isEndOfLine() { return (opcode >= OPCODE_ISTORE && opcode <= OPCODE_SASTORE) || opcode == OPCODE_IINC || opcode == OPCODE_RETURN || opcode == OPCODE_IRETURN || opcode == OPCODE_LRETURN || opcode == OPCODE_FRETURN || opcode == OPCODE_DRETURN || opcode == OPCODE_ARETURN || opcode == OPCODE_ATHROW || opcode == OPCODE_PUTSTATIC || opcode == OPCODE_PUTFIELD || opcode == OPCODE_POP || opcode == OPCODE_POP2; } /** * Denotes if this instruction invokes some other * method or interface or a constructor. * * @return Returns true, if this invokes any one mentioned above, * false, otherwise */ public boolean isInvokeIns() { return opcode == OPCODE_INVOKESPECIAL || opcode == OPCODE_INVOKEVIRTUAL || opcode == OPCODE_INVOKESTATIC || opcode == OPCODE_INVOKEINTERFACE; } /** * In case this instruction is a store instruction, * ( that is popping a local variable from the JVM stack ) , * then that variable index is returned. If no * variable is referenced then INVALID_VAR_INDEX * is returned. * * @return index of the variable referred to. * INVALID_VAR_INDEX, otherwise. */ public int isStoreInstruction() { switch (opcode) { case OPCODE_ISTORE_0: case OPCODE_FSTORE_0: case OPCODE_LSTORE_0: case OPCODE_DSTORE_0: case OPCODE_ASTORE_0: return 0; case OPCODE_ISTORE_1: case OPCODE_FSTORE_1: case OPCODE_LSTORE_1: case OPCODE_DSTORE_1: case OPCODE_ASTORE_1: return 1; case OPCODE_ISTORE_2: case OPCODE_FSTORE_2: case OPCODE_LSTORE_2: case OPCODE_DSTORE_2: case OPCODE_ASTORE_2: return 2; case OPCODE_ISTORE_3: case OPCODE_FSTORE_3: case OPCODE_LSTORE_3: case OPCODE_DSTORE_3: case OPCODE_ASTORE_3: return 3; case OPCODE_ISTORE: case OPCODE_FSTORE: case OPCODE_LSTORE: case OPCODE_DSTORE: case OPCODE_ASTORE: return getArgUnsignedWide(); default: return INVALID_VAR_INDEX; } } /** * @return unsigned Arg Wide. */ public int getArgUnsignedWide() { return getArgUnsignedWide(0); } /** * @param pos Position from which bytes are to be taken from stream * and the value to be written. * @return unsigned arg wide. */ public int getArgUnsignedWide(int pos) { if (wide) { if (pos != 0) { return getArgUnsignedShort(pos * 2); } else { return getArgUnsignedShort(0); } } else { return getArgUnsignedByte(pos); } } /** * @return Returns next instruction * */ public JInstruction next() { return next; } /** * @return Returns previous instruction * */ public JInstruction prev() { return prev; } /** * In case this instruction is a load instruction, * ( that is loading a datatype onto the JVM stack ) , * then that variable index is returned. If no * variable is referenced then INVALID_VAR_INDEX * is returned. * * @return index of the variable referred to. * INVALID_VAR_INDEX, otherwise. */ public int referredVariable() { switch (opcode) { case OPCODE_ILOAD_0: case OPCODE_FLOAD_0: case OPCODE_LLOAD_0: case OPCODE_DLOAD_0: case OPCODE_ALOAD_0: return 0; case OPCODE_ILOAD_1: case OPCODE_FLOAD_1: case OPCODE_LLOAD_1: case OPCODE_DLOAD_1: case OPCODE_ALOAD_1: return 1; case OPCODE_ILOAD_2: case OPCODE_FLOAD_2: case OPCODE_LLOAD_2: case OPCODE_DLOAD_2: case OPCODE_ALOAD_2: return 2; case OPCODE_ILOAD_3: case OPCODE_FLOAD_3: case OPCODE_LLOAD_3: case OPCODE_DLOAD_3: case OPCODE_ALOAD_3: return 3; case OPCODE_ILOAD: case OPCODE_FLOAD: case OPCODE_LLOAD: case OPCODE_DLOAD: case OPCODE_ALOAD: return getArgUnsignedWide(); default: return INVALID_VAR_INDEX; } } /** * Stringified form of JInstruction * * @return String representation of JInstruction. */ public String toString() { StringBuilder sb = new StringBuilder(); sb.append(" ").append(index).append(": ").append(insName); if (args == null) { return sb.toString(); } sb.append("["); for (int i = 0; i < args.length; i++) { sb.append(" ").append(getArgUnsignedByte(i)); } sb.append("]"); return sb.toString(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy