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

jreversepro.revengine.JBranchEntry Maven / Gradle / Ivy

/*
  @(#)JBranchEntry.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.revengine; import jreversepro.common.Helper; import jreversepro.common.KeyWords; import jreversepro.reflect.JInstruction; import jreversepro.reflect.JMethod; import jreversepro.reflect.method.*; import jreversepro.runtime.JOperandStack; import jreversepro.runtime.Operand; import jreversepro.runtime.OperandConstants; /** * JBranchEntry refers to a single conditional BranchEntry only. * * @author Karthik Kumar */ public class JBranchEntry implements KeyWords, BranchConstants, OperandConstants { /** * The method corresponding to the code being processed */ final JMethod method; /** * The JBlockObject associated with this JBranchEntry */ JBlockObject block = null; /** * nextPc is the NextPc of the branch entry. */ int nextPc; /** * Operator */ String operator; //Possible values. TYPE_WHILE || TYPE_IF. /** * Operand 1 */ String opr1; /** * Operand 2. */ String opr2; /** * startPc is the start of the branch entry */ int startPc; /** * targetPc is the targetPc of the branch entry */ int targetPc; /** * type of the branch type */ int type; /** * Written flag - to signify if the branch has been written on the source * code. */ boolean written; /** * @param method Method to which this branch entry belongs to. * @param startPc StartPc * @param targetPc TargetPc * @param type Type of the branch */ public JBranchEntry(JMethod method, int startPc, int targetPc, int type) { this(method, startPc, startPc, targetPc, type, "", "", ""); written = false; } /** * @param method Method to which this branch entry belongs to. * @param startPc StartPc * @param nextPc NextPc * @param targetPc TargetPc * @param type Type of the branch * @param opr1 Operand 1 * @param opr2 Operand 2 * @param operator Operator Comparison of the branch. */ public JBranchEntry(JMethod method, int startPc, int nextPc, int targetPc, int type, String opr1, String opr2, String operator) { this.method = method; this.startPc = startPc; this.nextPc = nextPc; this.targetPc = targetPc; this.type = type; this.opr1 = opr1; this.opr2 = opr2; this.operator = operator; } /** * Appends end block statement for a branch entry. * * @param decomp Decompiler reference. * @param jos Java Operand Stack reference. * @return Returns boolean. */ public final boolean appendEndBlockStmt(JDecompiler decomp, JOperandStack jos) { boolean mergeStack = false; if (!(type == TYPE_CATCH_ANY || type == TYPE_TRY_ANY)) { Helper.log("Branch Ends " + this); switch (type) { case TYPE_IF: if (written) { method.closeBlock(); decomp.setLastIns(nextPc); //Set the index ptr to the ins after the end of //this block //JInstruction sIns = // method.getInstruction(TargetPc); //decomp.setLastIns(sIns.getTargetPc2()); //decomp.setLastInsPos( // method.getInstruction( // sIns.getTargetPc2()).position); // //log.info( // "End sync - setting end to: "+sIns.getTargetPc()); //decomp.setLastInsPos(?); } else if (!jos.empty()) { //Rollback (remove current IF block) method.removeCurrentBlock(); Operand op1 = jos.pop(); String expr = getExpression(); jos.push(new Operand("(" + expr + ") ? " + op1.getValueEx(L_TERN) + " : ", op1.getDatatype(), L_TERN)); } else { method.closeBlock(); //Set the index ptr to the ins after the end of this //block //JInstruction sIns = method.getInstruction(TargetPc); //decomp.setLastIns(sIns.getTargetPc2()); //decomp.setLastInsPos( // method.getInstruction( // sIns.getTargetPc2()).position); //log.info("End sync - setting end to: " // + sIns.getTargetPc()); // log.info(method.getName()+":if2 // StartPC="+StartPc+" NextPc="+NextPc+" TargetPc=" // +TargetPc); // decomp.setLastIns(NextPc); // decomp.setLastInsPos(?); } break; case TYPE_ELSE: if (written) { method.closeBlock(); //Set the index ptr to the ins after the end of this //block //JInstruction sIns = method.getInstruction(TargetPc); //decomp.setLastIns(sIns.getTargetPc2()); //decomp.setLastInsPos( // method.getInstruction( // sIns.getTargetPc2()).position); //log.info("End sync - setting end to: " // + sIns.getTargetPc()); // log.info(method.getName()+":else // StartPC="+StartPc+" NextPc="+NextPc+" TargetPc=" // +TargetPc); //decomp.setLastIns(NextPc); //decomp.setLastInsPos(?); } else { if (!jos.empty()) { //Rollback (remove current else block) method.removeCurrentBlock(); } mergeStack = true; } break; case TYPE_TRY: case TYPE_ELSE_IF: case TYPE_WHILE: case TYPE_JSR: case TYPE_SWITCH: case TYPE_CASE: //Blocks that use "goto i" at targetPc to identify next //instruction case TYPE_CATCH: case TYPE_SYNC: method.closeBlock(); //Set the index ptr to the ins after the end of this block //JInstruction sIns = method.getInstruction(TargetPc); //decomp.setLastIns(sIns.getTargetPc2()); //decomp.setLastInsPos(method.getInstruction( // sIns.getTargetPc2()).position); //log.info("End sync - setting end to: " // + sIns.getTargetPc()); ///log.info(method.getName() // + ":try/elseif... StartPC=" // + StartPc+" NextPc="+NextPc+" TargetPc=" // + TargetPc); //decomp.setLastIns(NextPc); //decomp.setLastInsPos(?); break; //Set the index ptr to the ins after the end of this //block, IF no other catch follows /* JInstruction sIns = method.getInstruction(targetPc); if (targetPc > 0) { // Verified that this works for catch stmts decomp.setLastIns(sIns.index); decomp.setLastInsPos(sIns.position); //decomp.setLastIns(sIns.getTargetPc2()); //decomp.setLastInsPos(method.getInstruction( // sIns.getTargetPc2()).position); // } */ case TYPE_DO_WHILE: method.closeBlock(); decomp.setLastIns(nextPc); //decomp.setLastInsPos(?); ((JDoWhileBlock) block).setVar1(opr1); ((JDoWhileBlock) block).setOper(operator); ((JDoWhileBlock) block).setVar2(opr2); //Set the index ptr to the ins after the end of this block //JInstruction sIns = method.getInstruction(TargetPc); //decomp.setLastIns(sIns.getTargetPc2()); //decomp.setLastInsPos(method.getInstruction( // sIns.getTargetPc2()).position); //log.info("End sync - setting end to: " // +sIns.getTargetPc()); // log.info("do_while"); // log.info("do_while StartPC=" // +StartPc+" NextPc=" // +NextPc+" TargetPc="+TargetPc); break; default: } } return mergeStack; } /** * Trims the expression for a condition here. * For eg, an expression of the form - * if ( a == true ) is converted to 'a' ( just 'a' ). * These small modifications improve the readability of the code. * * @return Returns the new code. */ public String getExpression() { operator = operator.trim(); opr2 = opr2.trim(); switch (opr2) { case FALSE: if (operator.equals(OPR_EQ)) { return OPR_NOT + opr1; } return opr1; case TRUE: if (operator.equals(OPR_EQ)) { return opr1; } return OPR_NOT + opr1; default: return opr1 + " " + operator + " " + opr2; } } /** * Append the code for the beginning of a block * * @param decomp Reference to decempiler. */ public final void appendStartBlockStmtX(JDecompiler decomp) { JInstruction sIns; Helper.log("Branch Begins " + this); if (!(type == TYPE_CATCH_ANY || type == TYPE_TRY_ANY)) { switch (type) { case TYPE_IF: String expr = getExpression(); decomp.setLastIns(nextPc); decomp.setLastInsPos(method.getInstruction(nextPc).position); method.addBlock(new JIfBlock(this, expr)); break; case TYPE_ELSE_IF: decomp.setLastIns(nextPc); decomp.setLastInsPos(method.getInstruction(nextPc).position); method.addBlock(new JElseIfBlock(this, getExpression())); break; case TYPE_ELSE: decomp.setLastIns(nextPc); decomp.setLastInsPos(method.getInstruction(nextPc).position); method.addBlock(new JElseBlock(this)); break; case TYPE_WHILE: //This is a For loop //Create a reference so we can add the missing init //& loop values later block = new JForBlock(this, getExpression()); method.addBlock(block); //Set next pc to be after the end of the for loop decomp.setLastIns(this.nextPc); //decomp.setLastInsPos(this.?); break; case TYPE_DO_WHILE: //Create a reference so we can add the operators later block = new JDoWhileBlock(this); method.addBlock(block); break; case TYPE_TRY: method.addBlock(new JTryBlock(this)); break; case TYPE_CATCH: //Adjust start PC for executable instruction //Set to next instruction sIns = method.getNextInstruction(startPc); decomp.setLastIns(sIns.index); decomp.setLastInsPos(sIns.position); method.addBlock(new JCatchBlock(this, opr1, opr2)); break; case TYPE_JSR: method.addBlock(new JFinallyBlock(this)); break; case TYPE_SYNC: method.addBlock(new JSynchBlock(this, opr1)); break; case TYPE_CASE: Helper.log("CASE BLOCK : " + opr1); method.addBlock(new JCaseBlock(this, opr1)); break; case TYPE_SWITCH: method.addBlock(new JSwitchBlock(this, opr1)); break; default: } } } /** * Collates a single statement , depending on if it is * a IF / WHILE statement. *
* * @return true , if the entry is a 'if' branch . * false , otherwise. */ boolean collate() { if (type == TYPE_JSR) { return true; } if (startPc < targetPc) { complementOperator(); return true; } else { if (type != TYPE_WHILE) { type = TYPE_DO_WHILE; } return false; } } /** * Complements the conditional operator of the branch */ public void complementOperator() { operator = getComplementOperator(operator); } /** * Returns the complementary operator of the given operator. *
* * @param rhs Operator for which complement is to be returned. * @return the complementary operator of Rhs */ private String getComplementOperator(String rhs) { if (rhs.compareTo(OPR_GT) == 0) { return OPR_LE; } else if (rhs.compareTo(OPR_GE) == 0) { return OPR_LT; } else if (rhs.compareTo(OPR_LT) == 0) { return OPR_GE; } else if (rhs.compareTo(OPR_LE) == 0) { return OPR_GT; } else if (rhs.compareTo(OPR_EQ) == 0) { return OPR_NE; } else if (rhs.compareTo(OPR_NE) == 0) { return OPR_EQ; } else { return rhs; } } /** * This is invoked under the following circumstances. First this * is recognized as a 'if' branch. Then afterwards recognized as * 'while' branch. */ public void convertToWhile() { this.type = TYPE_WHILE; //Swap targetPc and NextPc. int temp = targetPc; targetPc = nextPc; nextPc = temp; } /** * Returns if the given Pc is enclosed in the mentioned block * * @param aPc the Pc for which the location is to be mentioned. * @return true, if the block mentioned contains this Pc. * false, otherwise. * @throws RevEngineException Thrown in case any error occurs while * performing this operation. */ public boolean doesContain(int aPc) throws RevEngineException { return (getStartBlockPc() <= aPc && getEndBlockPc() >= aPc); } /** * @return Returns the start pc of this block. * @throws RevEngineException Thrown in case of any error while geting * start block Pc. */ public int getStartBlockPc() throws RevEngineException { switch (type) { case TYPE_IF: case TYPE_ELSE: case TYPE_ELSE_IF: case TYPE_TRY: case TYPE_TRY_ANY: case TYPE_CATCH: case TYPE_CATCH_ANY: case TYPE_JSR: case TYPE_SYNC: case TYPE_SWITCH: case TYPE_CASE: return startPc; case TYPE_WHILE: case TYPE_DO_WHILE: return targetPc; default: throw new RevEngineException("Invalid Branch Entry"); } } /** * @return Returns the endpc of the block under consideration. * @throws RevEngineException Thrown in case there of any * problem getting End block pc. */ public int getEndBlockPc() throws RevEngineException { switch (type) { case TYPE_IF: case TYPE_ELSE: case TYPE_ELSE_IF: case TYPE_TRY: case TYPE_TRY_ANY: case TYPE_CATCH: case TYPE_CATCH_ANY: case TYPE_JSR: case TYPE_SYNC: case TYPE_CASE: case TYPE_SWITCH: return targetPc; case TYPE_WHILE: case TYPE_DO_WHILE: return nextPc; default: throw new RevEngineException("Invalid Branch Entry "); } } /** * Sets the end pc of this block. * * @param aNewPc New Pc that is to be set as the * end of the block */ public void setEndBlockPc(int aNewPc) { switch (type) { case TYPE_IF: case TYPE_ELSE: case TYPE_ELSE_IF: case TYPE_TRY: case TYPE_TRY_ANY: case TYPE_CATCH: case TYPE_CATCH_ANY: case TYPE_JSR: case TYPE_SYNC: case TYPE_CASE: case TYPE_SWITCH: targetPc = aNewPc; break; case TYPE_WHILE: case TYPE_DO_WHILE: nextPc = aNewPc; break; } } /** * This method checks if this particular branch block starts with * the given Pc. * * @param rhsStartPc StartPc that is to be checked if a block * starts there. * @return true, if this block starts with the mentioned startPc. * false, otherwise. * @throws RevEngineException Thrown when any error occurs. */ public boolean doesStartWith(int rhsStartPc) throws RevEngineException { return type != TYPE_INVALID && (getStartBlockPc() == rhsStartPc); } /** * @return Returns the NextPc. */ public int getNextPc() { return nextPc; } /** * Setter method for NextPc. * * @param nextPc Value for the nextPc. */ public void setNextPc(int nextPc) { this.nextPc = nextPc; } /** * @return Returns the operand 1. */ public String getOpr1() { return opr1; } /** * @param opr1 Operand 1. * Setter method for operand 1. */ public void setOpr1(String opr1) { this.opr1 = opr1; } /** * @return Returns the Pc from which the execution for the * block under consideration. * @throws RevEngineException Thrown in case any error occurs. */ public int getStartExecPc() throws RevEngineException { switch (type) { case TYPE_IF: case TYPE_ELSE: case TYPE_ELSE_IF: case TYPE_TRY: case TYPE_TRY_ANY: case TYPE_CATCH: case TYPE_CATCH_ANY: case TYPE_JSR: case TYPE_SYNC: case TYPE_CASE: case TYPE_SWITCH: return nextPc; case TYPE_WHILE: case TYPE_DO_WHILE: return targetPc; default: throw new RevEngineException("Invalid Branch Entry"); } } /** * @return Returns the startPc */ public int getStartPc() { return startPc; } /** * @param startPc StartPc of the branch. * Setter method for startPc. */ public void setStartPc(int startPc) { this.startPc = startPc; } /** * @return Returns the targetPc. */ public int getTargetPc() { return targetPc; } /** * @param targetPc TargetPC of the block. */ public void setTargetPc(int targetPc) { this.targetPc = targetPc; } /** * @return Returns the type of the Branch. */ public final int getType() { return type; } /** * Setter method for type. * * @param type Type of the branch. */ public void setType(int type) { this.type = type; } /** * Lets us know if the block is independent. * When we say independent, we refer to blocks that can start on its own, * Examples of the same - if, while, try, do..while. switch * Examples of dependent branch blocks are . * else_if , else, catch each dependent on one of the independent block * for is existence * * @return true, if the block is independent. * false, otherwise. */ public boolean independent() { return type == TYPE_IF || type == TYPE_WHILE || type == TYPE_TRY || type == TYPE_DO_WHILE || type == TYPE_SYNC || type == TYPE_SWITCH || type == TYPE_CASE || type == TYPE_TRY_ANY; } /** * Returns if the branch mentioned can be a TYPE_WHILE. * One indication of a while loop is that the startPc > targetPc. * * @return true, if it is a while loop. false, otherwise. */ public boolean isWhile() { return (startPc > targetPc); } /** * Resets the written flag */ public void resetWrittenFlag() { written = false; } /** * @param opr2 Operand 2. * Setter method for operand 2. */ public void setOpr2(String opr2) { this.opr2 = opr2; } /** * Sets the written flag. */ public void setWrittenFlag() { written = true; } /** * @return Returns the Stringified representation of the * class. */ public String toString() { StringBuilder sb = new StringBuilder(" "); sb.append(written).append(" "); sb.append(startPc).append(" ").append(nextPc).append(" ").append(targetPc).append(" "); switch (type) { case TYPE_IF: sb.append("TYPE_IF"); break; case TYPE_ELSE_IF: sb.append("TYPE_ELSE_IF"); break; case TYPE_ELSE: sb.append("TYPE_ELSE"); break; case TYPE_DO_WHILE: sb.append("TYPE_DO_WHILE"); break; case TYPE_TRY: sb.append("TYPE_TRY"); break; case TYPE_TRY_ANY: sb.append("TYPE_TRY_ANY"); break; case TYPE_CATCH: sb.append("TYPE_CATCH"); break; case TYPE_CATCH_ANY: sb.append("TYPE_CATCH_ANY"); break; case TYPE_WHILE: sb.append("TYPE_WHILE"); break; case TYPE_JSR: sb.append("TYPE_JSR"); break; case TYPE_SYNC: sb.append("TYPE_SYNCHRONIZED"); break; case TYPE_CASE: sb.append("TYPE_CASE"); break; case TYPE_SWITCH: sb.append("TYPE_SWITCH"); break; default: sb.append(type); } sb.append(" ").append(opr1).append(" ").append(operator).append(" ").append(opr2); return sb.toString(); } /** * Case 1: *

* a: x y z
* b: y p1 p2
* z:

* This means either a 'IF OR ' or and 'WHILE AND' between the * statements. *
* Now the row 'b' is invalidated , and contents of a become *
a: x p1 p2
* The Operands are also changed accordingly. *
* Case 2: *

* a: x y z
* b: y p1 z OR
*
* a: x y z
* z: .....
* b: y p1 p2

* This means either a 'IF AND' or 'WHILE OR' between the * statements.
+ * Now the row 'b' is invalidated , and contents of a become *
a: x p1 p2
* The Operands are also changed accordingly. *
*
*
* * @param case1 Merge case either case1 or case 2 * as mentioned above. * @param ifstat If we have to write a if statements. * @param entryB Other entry index for which we have to write the statement. */ void writeCase(boolean case1, boolean ifstat, JBranchEntry entryB) { this.type = entryB.type; entryB.type = TYPE_INVALID; //Invalidate entryB since that is irrelevant //after merging. this.nextPc = entryB.nextPc; this.targetPc = entryB.targetPc; this.rewriteCondition(entryB, (ifstat ^ case1) ? COND_AND : COND_OR, ifstat); } /** * This merges the current condition represented by the * current JBranchEntry. * * @param nextEntry Next Condition that is to be merged with * the current condition. * @param conditionType If OR or AND. * @param complement if the current expression needs to be * complemented. */ public void rewriteCondition(JBranchEntry nextEntry, String conditionType, boolean complement) { opr1 = this.getCondition(complement); operator = conditionType; opr2 = nextEntry.getCondition(true); } /** * Given the index to the entry in the BranchTable , this * returns the condition . *
* For example , if an entry has
* 4: i 3 != .
* Then getCondition(4,true) yields * i != 3 and
* getCondition(4,false) yields * i == 3 . * * @param complement If flag is set the operator is replaced by its * complement. For eg, complement of >= is replaced by '<''. * @return Returns the condition. */ private String getCondition(boolean complement) { if (!complement) { operator = getComplementOperator(operator); } return getExpression(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy