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

jreversepro.revengine.JBranchTable Maven / Gradle / Ivy

/*
  @(#)JBranchTable.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.JJvmOpcodes; import jreversepro.reflect.JException; import jreversepro.reflect.JInstruction; import jreversepro.reflect.JMethod; import java.util.*; //import jreversepro.common.KeyWords; /** * JBranchTable manages the objects of JGotoEntry and JBranchEntry. * * @author Karthik Kumar */ public class JBranchTable implements BranchConstants, JJvmOpcodes { /** * It is a Vector of 'Integer's. * The integers are the target of the jump sub routine instruction. */ final Vector mJSRTarget; /** * Map of monitor instructions. */ final Map mMonitor; /** * Method reference * */ final JMethod method; /** * List of switch instructions. Individual members are * JInstruction. */ final List switches; /** * Branches is a list, with the individual elemens containing * 'JBranchEntry'. */ List branches; /** * gotos * Key - StartPc ( java.lang.Integer ) * Value - TargetPc ( Absolute target -java.lang.Integer). */ Map gotos; /** * @param method Method reference. */ public JBranchTable(JMethod method) { mJSRTarget = new Vector<>(); mMonitor = new HashMap<>(); branches = new Vector<>(); switches = new Vector(); gotos = new HashMap<>(); this.method = method; } /** * Adds a new branch entry to the list of branches. * * @param ent branch entry to be added. */ public void add(JBranchEntry ent) { branches.add(ent); } /** * Adds a Goto entry to the internal data structure. * * @param startPc StartPc of the goto statement. * @param targetPc TargetPc of the goto statement. */ public void addGotoEntry(int startPc, int targetPc) { gotos.put(startPc, targetPc); } /** * This adds the pc given as input as a JSR target. * * @param targetPc TargetPc for a JSR instruction that is to be * added to the internal data structure ( list ). */ public void addJSRPc(int targetPc) { Integer intPc = targetPc; if (!mJSRTarget.contains(intPc)) { mJSRTarget.add(intPc); } } /** * Adds a monitor Pc. * * @param aMonitorPc Pc that is monitorenter. * @param aMonObject Object that is 'monitored'. In the sense * object for which lock is obtained before entering a * 'synchronized' object. */ public void addMonitorPc(int aMonitorPc, String aMonObject) { mMonitor.put(aMonitorPc, aMonObject); } /** * When a RET instruction is encountered we add a branch with the * last element of the JSR target lists. * JSR instructions signify 'synchronized' and catch..all blocks. * * @param retPc PC of the instruction which is a RET. */ public void addRetPc(int retPc) { int startPc = mJSRTarget.lastElement(); branches.add(new JBranchEntry(method, startPc, startPc, retPc, TYPE_JSR, "", "", "")); } /** * Adds the switch entries and the case entries under the same to the * branch table. * * @param switchEntry switch table containing entries about switch * statements. */ public void addSwitch(JSwitchTable switchEntry) { List enumCases = switchEntry.getCases(); Helper.log("No: Case Entries " + enumCases.size()); for (JCaseEntry enumCase : enumCases) { int caseTarget = enumCase.getTarget(); int endCase = enumCase.getEndTarget(); List caseValues = enumCase.getValues(); StringBuilder sb = new StringBuilder(); for (String caseValue : caseValues) { sb.append(caseValue).append(","); } JBranchEntry ent = new JBranchEntry(method, caseTarget, caseTarget, endCase, TYPE_CASE, sb.toString(), "", ""); branches.add(ent); } branches.add(switchEntry.getBranchEntry()); } /** * List of JException entries. * * @param excTryTable Individual entries being JException. */ public void addTryBlocks(List excTryTable) { Helper.log("Number of Try..blocks " + excTryTable.size()); for (JException anExcTryTable : excTryTable) { int insIndex = anExcTryTable.getStartPc(); if (insIndex == -1) { continue; } int endPc = anExcTryTable.getEffectiveEndPc(method.getInstructions()); String syncLock = doesMonitorBegin(insIndex - 1); if (syncLock != null) { branches.add(new JBranchEntry(method, insIndex, insIndex, endPc, TYPE_SYNC, syncLock, "", "")); } else { branches.add(new JBranchEntry(method, insIndex, insIndex, endPc, (anExcTryTable.isAny()) ? TYPE_TRY_ANY : TYPE_TRY, "", "", "")); } } } /** * Returns the monitor type for the monitor that begins with * Pc. * * @param monitorBeginPc Pc that begins with the monitor. * @return monitor object associated with this branch. */ public String doesMonitorBegin(int monitorBeginPc) { return mMonitor.get(monitorBeginPc); } /** * Delete the branch that corresponds to a else .. * branch starting with the given Pc * * @param startElse PC for which the else statement * is to be deleted. */ public void deleteElse(int startElse) { for (int i = 0; i < branches.size(); i++) { JBranchEntry jbe = (JBranchEntry) branches.get(i); if (jbe.getType() == TYPE_ELSE && jbe.getStartPc() == startElse) { branches.remove(i); } } } /** * Finalizer method. */ protected void finalize() { branches = null; gotos = null; } /** * @param byteIns BytecodeInstruction List. * @param start StartPc. * @param end EndPc. * @return Returns a JInstruction reference. */ public JInstruction findGotoIns(List byteIns, int start, int end) { int i; for (i = 0; i < byteIns.size(); i++) { if ((byteIns.get(i)).index == start) { break; } } JInstruction curIns = byteIns.get(i); while (curIns != null && curIns.opcode != OPCODE_GOTO && curIns.opcode != OPCODE_GOTOW) { if (curIns.index == end) { curIns = null; break; } else if (curIns.opcode == OPCODE_RETURN) { curIns = curIns.next(); break; } curIns = curIns.next(); } return curIns; } /** * For the given pc return the target of the instruction. * The instruction is a goto statement. * * @param startPc Start Pc. * @return the TargetPc for the goto instruction at the * startPc */ public int findGotoTarget(int startPc) { Integer obj = gotos.get(startPc); if (obj == null) { return -1; } else { return obj; } } /** * Getter method for goto tables. * * @return Map of goto table entries. * key - goto pc. * value - target of that goto table. */ public Map getGotoTable() { return gotos; } /** * Identifies the else..if and else branches. * Identifies catch.. branches. * * @throws RevEngineException Thrown in case of any error. */ public void identifyMoreBranches() throws RevEngineException { for (int i = 0; i < branches.size(); i++) { JBranchEntry jbe = (JBranchEntry) branches.get(i); int gotoStartPc = jbe.getEndBlockPc() - 3; int gotoNextPc = gotoStartPc + 3; Integer obj = gotos.get(gotoStartPc); switch (jbe.getType()) { case TYPE_IF: case TYPE_ELSE_IF: if (obj != null) { //Before adding else, check for else if. int gotoTargetPc = obj; if (gotoTargetPc - gotoStartPc == 3) { break; } JBranchEntry elsif = contains(startsWith(gotoNextPc), TYPE_IF); if (elsif == null) { JBranchEntry caseEntry = contains(startsWith(gotoNextPc), TYPE_CASE); if (caseEntry == null) { JBranchEntry elseEntry = new JBranchEntry(method, gotoNextPc, gotoNextPc, gotoTargetPc, TYPE_ELSE, jbe.opr1, jbe.opr2, jbe.operator); branches.add(elseEntry); } } else { elsif.setType(TYPE_ELSE_IF); } } break; case TYPE_DO_WHILE: if (gotos.containsValue(jbe.startPc)) { jbe.setType(TYPE_WHILE); } break; } } } /** * Returns the first branch in the mentioned branchlist * that matches the particular type. * * @param listBranchEntries list of branch entries. * @param type Type that is to be searched for. * @return first branch entry that matches the type mentioned * in the list given. */ public static JBranchEntry contains(List listBranchEntries, int type) { if (listBranchEntries.size() == 0) { return null; } for (JBranchEntry listBranchEntry : listBranchEntries) { if (listBranchEntry.getType() == type) { return listBranchEntry; } } return null; } /** * Returns the list of branches that starts with the * mentioned aInsIndex. * * @param aInsIndex Instruction index. * @return List of JBranchEntry - * list of branches that starts with the mentioned * instruction index. * @throws RevEngineException thrown in case of an error. */ public List startsWith(int aInsIndex) throws RevEngineException { List branchEntries = new Vector<>(); for (Object branche : branches) { JBranchEntry jbe = (JBranchEntry) branche; if (jbe.doesStartWith(aInsIndex)) { branchEntries.add(jbe); } } return branchEntries; } /** * Checks if the Pc passed as argument is the target for * any JSR instructions. * * @param currPc Pc for which it is to be checked if it is the * target for any JSR instruction. * @return true, if there exists a JSR instruction with its target * currPc. false, otherwise. */ public boolean isJSRTarget(int currPc) { return mJSRTarget.contains(currPc); } /** * Setter method for the branch tables. * * @param aBranches Branches to be added. */ public void setTables(List aBranches) { branches.addAll(aBranches); } /** * This sorts the list containing branches such that no * branch overlaps with the one previously existing. * See JBranchComparator for more details. */ public void sort() { branches.sort(new JBranchComparator<>()); } /** * @return Stringified form of the class */ public String toString() { StringBuilder sb = new StringBuilder(); sb.append(branchesToString()); int size = gotos.size(); if (size > 0) { sb.append("Gotos:\n"); Iterator> it = gotos.entrySet().iterator(); for (int i = 0; i < size; i++) { sb.append(it.next()).append("\n"); } } size = mJSRTarget.size(); if (size > 0) { sb.append("JSRTargets:\n"); for (int i = 0; i < size; i++) { sb.append(mJSRTarget.get(i)).append("\n"); } } return sb.toString(); } /** * Stringifies the braches alone. * * @return Returns a Stringifed version of the branches alone. */ public String branchesToString() { StringBuilder sb = new StringBuilder(); int size = branches.size(); if (size > 0) { sb.append("Branches:\n"); for (Object branche : branches) { sb.append(branche).append("\n"); } } return sb.toString(); } }