Package org.jreversepro.decompile.simulate

Source Code of org.jreversepro.decompile.simulate.BranchTable

/**
* @(#)BranchTable.java
* JReversePro - Java Decompiler / Disassembler.
* Copyright (C) 2008 Karthik Kumar.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*    http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/

package org.jreversepro.decompile.simulate;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.logging.Logger;

import org.jreversepro.CustomLoggerFactory;
import org.jreversepro.jvm.Opcodes;
import org.jreversepro.reflect.Method;
import org.jreversepro.reflect.ExceptionThrown;
import org.jreversepro.reflect.instruction.Instruction;


/**
* BranchTable manages the objects of GotoEntry and BranchEntry.
*
* @author Karthik Kumar
*/
public class BranchTable implements BranchConstants, Opcodes {

  /**
   * @param method
   *          Method reference.
   */
  public BranchTable(Method method) {
    mJSRTarget = new Vector<Integer>();
    mMonitor = new HashMap<Integer, String>();
    branches = new Vector<BranchEntry>();
    switches = new Vector<Instruction>();
    gotos = new HashMap<Integer, Integer>();
    this.method = method;
  }

  /**
   * Setter method for the branch tables.
   *
   * @param aBranches
   *          Branches to be added.
   */
  public void setTables(List<BranchEntry> aBranches) {
    branches.addAll(aBranches);
  }

  /**
   * Getter method for goto tables.
   *
   * @return Map of goto table entries. key - goto pc. value - target of that
   *         goto table.
   */
  public Map<Integer, Integer> getGotoTable() {
    return gotos;
  }

  /**
   * 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(Integer.valueOf(startPc), Integer.valueOf(targetPc));
  }



  /**
   * Adds a new branch entry to the list of branches.
   *
   * @param ent
   *          branch entry to be added.
   */
  public void add(BranchEntry ent) {
    branches.add(ent);
  }

  /**
   * 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(Integer.valueOf(currPc));
  }

  /**
   * 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 = Integer.valueOf(targetPc);
    if (!mJSRTarget.contains(intPc)) {
      mJSRTarget.add(intPc);
    }
  }

  /**
   * 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().intValue();
    branches.add(new BranchEntry(method, startPc, startPc, retPc, TYPE_JSR, "",
        "", ""));
  }

  /**
   * This sorts the list containing branches such that no branch overlaps with
   * the one previously existing. See JBranchComparator for more details.
   */
  public void sort() {
    Collections.sort(branches, new BranchComparator());
  }

  /**
   * 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(Integer.valueOf(aMonitorPc), aMonObject);
  }

  /**
   * 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(Integer.valueOf(monitorBeginPc));
  }

  /**
   * Identifies the else..if and else branches. Identifies catch.. branches.
   *
   * @throws RevEngineException
   *           Thrown in case of any error.
   */
  public void identifyMoreBranches() {

    for (BranchEntry jbe : branches) {
      int gotoStartPc = jbe.getEndBlockPc() - 3;
      int gotoNextPc = gotoStartPc + 3;
      Integer obj = gotos.get( Integer.valueOf(gotoStartPc));
      switch (jbe.getType()) {
      case TYPE_IF:
      case TYPE_ELSE_IF:
        if (obj != null) {
          // Before adding else, check for else if.
          int gotoTargetPc = obj.intValue();
          if (gotoTargetPc - gotoStartPc == 3) {
            break;
          }
          BranchEntry elsif = contains(startsWith(gotoNextPc), TYPE_IF);

          if (elsif == null) {
            BranchEntry caseEntry = contains(startsWith(gotoNextPc), TYPE_CASE);
            if (caseEntry == null) {
              BranchEntry elseEntry = new BranchEntry(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( Integer.valueOf(jbe.getStartPc()))) {
          jbe.setType(TYPE_WHILE);
        }
        break;
      }
    }
  }

  /**
   * 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(SwitchTable switchEntry) {
    int defaultByte = switchEntry.getDefaultByte();
    int maxTarget = defaultByte;
    List<CaseEntry> enumCases = switchEntry.getCases();

    logger.fine("No: Case Entries " + enumCases.size());
    for (CaseEntry singleCase : enumCases) {
      int caseTarget = singleCase.getTarget();
      int endCase = singleCase.getEndTarget();

      List<String> caseValues = singleCase.getValues();
      StringBuilder sb = new StringBuilder();
      for (String singleCaseValue : caseValues) {
        sb.append(singleCaseValue + ",");
      }
      BranchEntry ent = new BranchEntry(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<ExceptionThrown> excTryTable) {
    for (ExceptionThrown exc : excTryTable) {
      int insIndex = exc.getStartPc();
      if (insIndex == -1) {
        continue;
      }

      int endPc = exc.getEndPc();
      String syncLock = doesMonitorBegin(insIndex - 1);
      if (syncLock != null) {
        branches.add(new BranchEntry(method, insIndex, insIndex, endPc,
            TYPE_SYNC, syncLock, "", ""));
      } else {
        branches.add(new BranchEntry(method, insIndex, insIndex, endPc, (exc
            .isAny()) ? TYPE_TRY_ANY : TYPE_TRY, "", "", ""));
      }
    }
  }

  /**
   * 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 gotoStartPc = Integer.valueOf(startPc);
    Integer obj = gotos.get(gotoStartPc);
    if (obj == null) {
      return -1;
    } else {
      return obj.intValue();
    }
  }

  /**
   * 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<BranchEntry> startsWith(int aInsIndex) {

    List<BranchEntry> branchEntries = new ArrayList<BranchEntry>();
    for (BranchEntry jbe : branches) {
      if (jbe.doesStartWith(aInsIndex)) {
        branchEntries.add(jbe);
      }
    }
    return branchEntries;
  }

  /**
   * 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++) {
      BranchEntry jbe = branches.get(i);
      if (jbe.getType() == TYPE_ELSE && jbe.getStartPc() == startElse) {
        branches.remove(i);
      }
    }
  }

  /**
   * 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 BranchEntry contains(List<BranchEntry> listBranchEntries,
      int type) {
    if (listBranchEntries.size() == 0) {
      return null;
    }
    for (final BranchEntry ent : listBranchEntries) {
      if (ent.getType() == type) {
        return ent;
      }
    }
    return null;
  }

  /**
   * @param byteIns
   *          List of Instructions.
   * @return null.
   */
  private Instruction getNextGoto(List<Instruction> byteIns) {
    return null;
  }

  /**
   * @param byteIns
   *          BytecodeInstruction List.
   * @param start
   *          StartPc.
   * @param end
   *          EndPc.
   * @return Returns a JInstruction reference.
   */
  public Instruction findGotoIns(List<Instruction> byteIns, int start, int end) {
    int i;
    for (i = 0; i < byteIns.size(); i++) {
      if (byteIns.get(i).currentPc == start) {
        break;
      }
    }
    Instruction ins = byteIns.get(i);
    while (ins != null && ins.opcode != OPCODE_GOTO
        && ins.opcode != OPCODE_GOTOW) {
      if (ins.currentPc == end) {
        ins = null;
        break;
      } else if (ins.opcode == OPCODE_RETURN) {
        // TODO: Revisit this code
        // ins = byteIns.get(ins.position + 1);
        break;
      }
      // TODO: Revisit this piece of code.
      // ins = byteIns.get(ins.position + 1);
    }
    return ins;
  }

  /**
   * 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 (int i = 0; i < size; i++) {
        sb.append(branches.get(i) + "\n");
      }
    }
    return sb.toString();
  }

  /**
   * @return Stringified form of the class
   */
  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder("");
    sb.append(branchesToString());
    int size = gotos.size();
    if (size > 0) {
      sb.append("Gotos:\n");
      for (Object obj : gotos.entrySet()) {
        sb.append(obj.toString() + "\n");
      }
    }
    size = mJSRTarget.size();
    if (size > 0) {
      sb.append("JSRTargets:\n");
      for (int i = 0; i < size; i++) {
        sb.append(mJSRTarget.get(i) + "\n");
      }
    }
    return sb.toString();
  }

  /**
   * List of branch representations.
   */
  List<BranchEntry> branches;

  /**
   * gotos Key - StartPc ( java.lang.Integer ) Value - TargetPc ( Absolute
   * target -java.lang.Integer).
   */
  Map<Integer, Integer> gotos;

  /**
   * List of switch instructions. Individual members are JInstruction.
   */
  List<Instruction> switches;

  /**
   * It is a Vector of 'Integer's. The integers are the target of the jump sub
   * routine instruction.
   */
  Vector<Integer> mJSRTarget;

  /**
   * Map of monitor instructions.
   */
  Map<Integer, String> mMonitor;

  /** Method reference * */
  Method method;

  private final Logger logger = CustomLoggerFactory.createLogger();
}
TOP

Related Classes of org.jreversepro.decompile.simulate.BranchTable

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.