示例#1
0
 /**
  * Sets the leaving RET instruction. Must be invoked after all instructions are added. Must not
  * be invoked for top-level 'subroutine'.
  */
 void setLeavingRET() {
   if (localVariable == UNSET) {
     throw new AssertionViolatedException(
         "setLeavingRET() called for top-level 'subroutine' or forgot to set local variable first.");
   }
   Iterator iter = instructions.iterator();
   InstructionHandle ret = null;
   while (iter.hasNext()) {
     InstructionHandle actual = (InstructionHandle) iter.next();
     if (actual.getInstruction() instanceof RET) {
       if (ret != null) {
         throw new StructuralCodeConstraintException(
             "Subroutine with more then one RET detected: '" + ret + "' and '" + actual + "'.");
       } else {
         ret = actual;
       }
     }
   }
   if (ret == null) {
     throw new StructuralCodeConstraintException("Subroutine without a RET detected.");
   }
   if (((RET) ret.getInstruction()).getIndex() != localVariable) {
     throw new StructuralCodeConstraintException(
         "Subroutine uses '"
             + ret
             + "' which does not match the correct local variable '"
             + localVariable
             + "'.");
   }
   theRET = ret;
 }
示例#2
0
  /** Instrument the specified method to replace mapped calls. */
  public void instrument_method(Method m, MethodGen mg) {

    // Loop through each instruction, making substitutions
    InstructionList il = mg.getInstructionList();
    for (InstructionHandle ih = il.getStart(); ih != null; ) {
      if (debug_instrument_inst.enabled()) {
        debug_instrument_inst.log("instrumenting instruction %s%n", ih);
        // ih.getInstruction().toString(pool.getConstantPool()));
      }
      InstructionList new_il = null;

      // Remember the next instruction to process
      InstructionHandle next_ih = ih.getNext();

      // Get the translation for this instruction (if any)
      new_il = xform_inst(mg, ih.getInstruction());
      if (debug_instrument_inst.enabled()) debug_instrument_inst.log("  new inst: %s%n", new_il);

      // If this instruction was modified, replace it with the new
      // instruction list. If this instruction was the target of any
      // jumps or line numbers , replace them with the first
      // instruction in the new list
      replace_instructions(il, ih, new_il);

      ih = next_ih;
    }
  }
 /**
  * Get CodeException object.<br>
  * This relies on that the instruction list has already been dumped to byte code or or that the
  * `setPositions' methods has been called for the instruction list.
  *
  * @param cp constant pool
  */
 public CodeException getCodeException(ConstantPoolGen cp) {
   return new CodeException(
       start_pc.getPosition(),
       end_pc.getPosition() + end_pc.getInstruction().getLength(),
       handler_pc.getPosition(),
       (catch_type == null) ? 0 : cp.addClass(catch_type));
 }
示例#4
0
  CFG createCFG(String className) throws ClassNotFoundException {
    CFG cfg = new CFG();
    JavaClass jc = Repository.lookupClass(className);
    ClassGen cg = new ClassGen(jc);
    ConstantPoolGen cpg = cg.getConstantPool();
    for (Method m : cg.getMethods()) {
      MethodGen mg = new MethodGen(m, cg.getClassName(), cpg);
      InstructionList il = mg.getInstructionList();
      InstructionHandle[] handles = il.getInstructionHandles();
      int prev = 0;
      for (InstructionHandle ih : handles) {
        int position = ih.getPosition();
        cfg.addNode(position, m, jc);
        Instruction inst = ih.getInstruction();

        boolean br = inst.getName().contains("if") || inst.getName().contains("goto");
        boolean ret = inst.getName().contains("return");
        boolean stat = inst.getName().contains("invokestatic");
        int len = inst.getLength();

        if (stat) {
          int index = inst.toString(true).indexOf(" ");
          String name = inst.toString(true).substring(index + 1);
          int tar = Integer.valueOf(name);
          INVOKESTATIC inv = new INVOKESTATIC(tar);
          name = inv.getMethodName(cpg);

          Method m2 = null;
          Method[] tm = cg.getMethods();
          for (int i = 0; i < tm.length; i++) {
            if (tm[i].getName().equals(name)) {
              m2 = tm[i];
            }
          }
          cfg.addEdge(position, m, jc, 0, m2, jc);
          cfg.addEdge(-1, m2, jc, position + len, m, jc);
        }

        if (!ret && !stat) {
          cfg.addEdge(position, position + len, m, jc);
        }
        if (br) {
          cfg.addEdge(position, position + len, m, jc);
          IF_ICMPGE comp = new IF_ICMPGE(ih);
          String name = comp.getTarget().toString(false);
          int index = name.indexOf(">");
          name = name.substring(index + 2);
          int tar = Integer.valueOf(name);
          cfg.addEdge(position, tar, m, jc);
        }
        if (ret) {
          cfg.addEdge(position, -1, m, jc);
        }

        prev = position;
      }
      System.out.println(cfg.toString());
    }
    return cfg;
  }
 private void dumpCode() {
   int i = 0;
   for (InstructionHandle handle = this.codeStart; handle != null; handle = handle.getNext()) {
     System.err.println(
         i++
             + ":\t"
             + org.caesarj.classfile.OpcodeNames.getName(handle.getInstruction().getOpcode()));
   }
   System.err.flush();
 }
示例#6
0
 /** Adds a new JSR or JSR_W that has this subroutine as its target. */
 public void addEnteringJsrInstruction(InstructionHandle jsrInst) {
   if ((jsrInst == null) || (!(jsrInst.getInstruction() instanceof JsrInstruction))) {
     throw new AssertionViolatedException("Expecting JsrInstruction InstructionHandle.");
   }
   if (localVariable == UNSET) {
     throw new AssertionViolatedException("Set the localVariable first!");
   } else {
     // Something is wrong when an ASTORE is targeted that does not operate on the same local
     // variable than the rest of the
     // JsrInstruction-targets and the RET.
     // (We don't know out leader here so we cannot check if we're really targeted!)
     if (localVariable
         != ((ASTORE) (((JsrInstruction) jsrInst.getInstruction()).getTarget().getInstruction()))
             .getIndex()) {
       throw new AssertionViolatedException("Setting a wrong JsrInstruction.");
     }
   }
   theJSRs.add(jsrInst);
 }
  /**
   * Long output format:
   *
   * <p>&lt;position in byte code&gt; &lt;name of opcode&gt; "["&lt;opcode number&gt;"]"
   * "("&lt;length of instruction&gt;")" "&lt;"&lt;target instruction&gt;"&gt;" "@"&lt;branch target
   * offset&gt;
   *
   * @param verbose long/short format switch
   * @return mnemonic for instruction
   */
  public String toString(boolean verbose) {
    String s = super.toString(verbose);
    String t = "null";

    if (verbose) {
      if (target != null) {
        if (target.getInstruction() == this) t = "<points to itself>";
        else if (target.getInstruction() == null) t = "<null instruction!!!?>";
        else t = target.getInstruction().toString(false); // Avoid circles
      }
    } else {
      if (target != null) {
        index = getTargetOffset();
        t = "" + (index + position);
      }
    }

    return s + " -> " + t;
  }
示例#8
0
  /**
   * A utility method that calculates the successors of a given InstructionHandle <B>in the same
   * subroutine</B>. That means, a RET does not have any successors as defined here. A
   * JsrInstruction has its physical successor as its successor (opposed to its target) as defined
   * here.
   */
  private static InstructionHandle[] getSuccessors(InstructionHandle instruction) {
    final InstructionHandle[] empty = new InstructionHandle[0];
    final InstructionHandle[] single = new InstructionHandle[1];
    final InstructionHandle[] pair = new InstructionHandle[2];

    Instruction inst = instruction.getInstruction();

    if (inst instanceof RET) {
      return empty;
    }

    // Terminates method normally.
    if (inst instanceof ReturnInstruction) {
      return empty;
    }

    // Terminates method abnormally, because JustIce mandates
    // subroutines not to be protected by exception handlers.
    if (inst instanceof ATHROW) {
      return empty;
    }

    // See method comment.
    if (inst instanceof JsrInstruction) {
      single[0] = instruction.getNext();
      return single;
    }

    if (inst instanceof GotoInstruction) {
      single[0] = ((GotoInstruction) inst).getTarget();
      return single;
    }

    if (inst instanceof BranchInstruction) {
      if (inst instanceof Select) {
        // BCEL's getTargets() returns only the non-default targets,
        // thanks to Eli Tilevich for reporting.
        InstructionHandle[] matchTargets = ((Select) inst).getTargets();
        InstructionHandle[] ret = new InstructionHandle[matchTargets.length + 1];
        ret[0] = ((Select) inst).getTarget();
        System.arraycopy(matchTargets, 0, ret, 1, matchTargets.length);
        return ret;
      } else {
        pair[0] = instruction.getNext();
        pair[1] = ((BranchInstruction) inst).getTarget();
        return pair;
      }
    }

    // default case: Fall through.
    single[0] = instruction.getNext();
    return single;
  }
  /**
   * Get LocalVariable object.
   *
   * <p>This relies on that the instruction list has already been dumped to byte code or or that the
   * `setPositions' methods has been called for the instruction list.
   *
   * <p>Note that for local variables whose scope end at the last instruction of the method's code,
   * the JVM specification is ambiguous: both a start_pc+length ending at the last instruction and
   * start_pc+length ending at first index beyond the end of the code are valid.
   *
   * @param il instruction list (byte code) which this variable belongs to
   * @param cp constant pool
   */
  public LocalVariable getLocalVariable(ConstantPoolGen cp) {
    int start_pc = start.getPosition();
    int length = end.getPosition() - start_pc;

    if (length > 0) length += end.getInstruction().getLength();

    int name_index = cp.addUtf8(name);
    int signature_index = cp.addUtf8(type.getSignature());

    return new LocalVariable(
        start_pc, length, name_index, signature_index, index, cp.getConstantPool());
  }
示例#10
0
  /** Start the method's visit. */
  public void start() {
    if (!mg.isAbstract() && !mg.isNative()) {
      for (InstructionHandle ih = mg.getInstructionList().getStart();
          ih != null;
          ih = ih.getNext()) {
        Instruction i = ih.getInstruction();

        if (!visitInstruction(i)) i.accept(this);
      }
      updateExceptionHandlers();
    }
  }
示例#11
0
    /*
     * Satisfies Subroutine.getAccessedLocalIndices().
     */
    public int[] getAccessedLocalsIndices() {
      // TODO: Implement caching.
      HashSet<Integer> acc = new HashSet<Integer>();
      if (theRET == null && this != TOPLEVEL) {
        throw new AssertionViolatedException(
            "This subroutine object must be built up completely before calculating accessed locals.");
      }
      Iterator i = instructions.iterator();
      while (i.hasNext()) {
        InstructionHandle ih = (InstructionHandle) i.next();
        // RET is not a LocalVariableInstruction in the current version of BCEL.
        if (ih.getInstruction() instanceof LocalVariableInstruction
            || ih.getInstruction() instanceof RET) {
          int idx = ((IndexedInstruction) (ih.getInstruction())).getIndex();
          acc.add(new Integer(idx));
          // LONG? DOUBLE?.
          try {
            // LocalVariableInstruction instances are typed without the need to look into
            // the constant pool.
            if (ih.getInstruction() instanceof LocalVariableInstruction) {
              int s = ((LocalVariableInstruction) ih.getInstruction()).getType(null).getSize();
              if (s == 2) acc.add(new Integer(idx + 1));
            }
          } catch (RuntimeException re) {
            throw new AssertionViolatedException(
                "Oops. BCEL did not like NULL as a ConstantPoolGen object.");
          }
        }
      }

      int[] ret = new int[acc.size()];
      i = acc.iterator();
      int j = -1;
      while (i.hasNext()) {
        j++;
        ret[j] = ((Integer) i.next()).intValue();
      }
      return ret;
    }
示例#12
0
 /**
  * Remove from instruction `prev' to instruction `next' both contained in this list. Throws
  * TargetLostException when one of the removed instruction handles is still being targeted.
  *
  * @param prev where to start deleting (predecessor, exclusive)
  * @param next where to end deleting (successor, exclusive)
  */
 private void remove(InstructionHandle prev, InstructionHandle next) throws TargetLostException {
   InstructionHandle first, last; // First and last deleted instruction
   if ((prev == null) && (next == null)) {
     first = start;
     last = end;
     start = end = null;
   } else {
     if (prev == null) { // At start of list
       first = start;
       start = next;
     } else {
       first = prev.next;
       prev.next = next;
     }
     if (next == null) { // At end of list
       last = end;
       end = prev;
     } else {
       last = next.prev;
       next.prev = prev;
     }
   }
   first.prev = null; // Completely separated from rest of list
   last.next = null;
   List<InstructionHandle> target_vec = new ArrayList<InstructionHandle>();
   for (InstructionHandle ih = first; ih != null; ih = ih.next) {
     ih.getInstruction().dispose(); // e.g. BranchInstructions release their targets
   }
   StringBuilder buf = new StringBuilder("{ ");
   for (InstructionHandle ih = first; ih != null; ih = next) {
     next = ih.next;
     length--;
     if (ih.hasTargeters()) { // Still got targeters?
       target_vec.add(ih);
       buf.append(ih.toString(true) + " ");
       ih.next = ih.prev = null;
     } else {
       ih.dispose();
     }
   }
   buf.append("}");
   if (!target_vec.isEmpty()) {
     InstructionHandle[] targeted = new InstructionHandle[target_vec.size()];
     target_vec.toArray(targeted);
     throw new TargetLostException(targeted, buf.toString());
   }
 }
示例#13
0
  /**
   * Build the array of the instructions resulting from the optimization process.
   *
   * @return the array of instructions
   */
  private Instruction[] buildInstructionArray() {
    int length;

    // count size of instruction array
    length = 0;
    for (InstructionHandle handle = this.codeStart; handle != null; handle = handle.getNext()) {
      length += 1;
    }

    Instruction[] insns = new Instruction[length];

    length = 0;
    for (InstructionHandle handle = this.codeStart; handle != null; handle = handle.getNext()) {
      insns[length] = handle.getInstruction();
      length += 1;
    }

    return insns;
  }
示例#14
0
 /**
  * Redirect all references from old_target to new_target, i.e., update targets of branch
  * instructions.
  *
  * @param old_target the old target instruction handle
  * @param new_target the new target instruction handle
  */
 public void redirectBranches(InstructionHandle old_target, InstructionHandle new_target) {
   for (InstructionHandle ih = start; ih != null; ih = ih.next) {
     Instruction i = ih.getInstruction();
     if (i instanceof BranchInstruction) {
       BranchInstruction b = (BranchInstruction) i;
       InstructionHandle target = b.getTarget();
       if (target == old_target) {
         b.setTarget(new_target);
       }
       if (b instanceof Select) { // Either LOOKUPSWITCH or TABLESWITCH
         InstructionHandle[] targets = ((Select) b).getTargets();
         for (int j = 0; j < targets.length; j++) {
           if (targets[j] == old_target) {
             ((Select) b).setTarget(j, new_target);
           }
         }
       }
     }
   }
 }
示例#15
0
  /**
   * Constructor.
   *
   * @param il A MethodGen object representing method to create the Subroutine objects of.
   */
  public Subroutines(MethodGen mg) {

    InstructionHandle[] all = mg.getInstructionList().getInstructionHandles();
    CodeExceptionGen[] handlers = mg.getExceptionHandlers();

    // Define our "Toplevel" fake subroutine.
    TOPLEVEL = new SubroutineImpl();

    // Calculate "real" subroutines.
    HashSet<InstructionHandle> sub_leaders =
        new HashSet<InstructionHandle>(); // Elements: InstructionHandle
    for (int i = 0; i < all.length; i++) {
      Instruction inst = all[i].getInstruction();
      if (inst instanceof JsrInstruction) {
        sub_leaders.add(((JsrInstruction) inst).getTarget());
      }
    }

    // Build up the database.
    Iterator iter = sub_leaders.iterator();
    while (iter.hasNext()) {
      SubroutineImpl sr = new SubroutineImpl();
      InstructionHandle astore = (InstructionHandle) (iter.next());
      sr.setLocalVariable(((ASTORE) (astore.getInstruction())).getIndex());
      subroutines.put(astore, sr);
    }

    // Fake it a bit. We want a virtual "TopLevel" subroutine.
    subroutines.put(all[0], TOPLEVEL);
    sub_leaders.add(all[0]);

    // Tell the subroutines about their JsrInstructions.
    // Note that there cannot be a JSR targeting the top-level
    // since "Jsr 0" is disallowed in Pass 3a.
    // Instructions shared by a subroutine and the toplevel are
    // disallowed and checked below, after the BFS.
    for (int i = 0; i < all.length; i++) {
      Instruction inst = all[i].getInstruction();
      if (inst instanceof JsrInstruction) {
        InstructionHandle leader = ((JsrInstruction) inst).getTarget();
        ((SubroutineImpl) getSubroutine(leader)).addEnteringJsrInstruction(all[i]);
      }
    }

    // Now do a BFS from every subroutine leader to find all the
    // instructions that belong to a subroutine.
    HashSet<InstructionHandle> instructions_assigned =
        new HashSet<InstructionHandle>(); // we don't want to assign an instruction to two or more
    // Subroutine objects.

    Hashtable<InstructionHandle, Color> colors =
        new Hashtable<
            InstructionHandle,
            Color>(); // Graph colouring. Key: InstructionHandle, Value: java.awt.Color .

    iter = sub_leaders.iterator();
    while (iter.hasNext()) {
      // Do some BFS with "actual" as the root of the graph.
      InstructionHandle actual = (InstructionHandle) (iter.next());
      // Init colors
      for (int i = 0; i < all.length; i++) {
        colors.put(all[i], Color.white);
      }
      colors.put(actual, Color.gray);
      // Init Queue
      ArrayList<InstructionHandle> Q = new ArrayList<InstructionHandle>();
      Q.add(actual); // add(Obj) adds to the end, remove(0) removes from the start.

      /* BFS ALGORITHM MODIFICATION: Start out with multiple "root" nodes, as exception handlers are starting points of top-level code, too. [why top-level? TODO: Refer to the special JustIce notion of subroutines.]*/
      if (actual == all[0]) {
        for (int j = 0; j < handlers.length; j++) {
          colors.put(handlers[j].getHandlerPC(), Color.gray);
          Q.add(handlers[j].getHandlerPC());
        }
      }
      /* CONTINUE NORMAL BFS ALGORITHM */

      // Loop until Queue is empty
      while (Q.size() != 0) {
        InstructionHandle u = (InstructionHandle) Q.remove(0);
        InstructionHandle[] successors = getSuccessors(u);
        for (int i = 0; i < successors.length; i++) {
          if (((Color) colors.get(successors[i])) == Color.white) {
            colors.put(successors[i], Color.gray);
            Q.add(successors[i]);
          }
        }
        colors.put(u, Color.black);
      }
      // BFS ended above.
      for (int i = 0; i < all.length; i++) {
        if (colors.get(all[i]) == Color.black) {
          ((SubroutineImpl) (actual == all[0] ? getTopLevel() : getSubroutine(actual)))
              .addInstruction(all[i]);
          if (instructions_assigned.contains(all[i])) {
            throw new StructuralCodeConstraintException(
                "Instruction '"
                    + all[i]
                    + "' is part of more than one subroutine (or of the top level and a subroutine).");
          } else {
            instructions_assigned.add(all[i]);
          }
        }
      }
      if (actual != all[0]) { // If we don't deal with the top-level 'subroutine'
        ((SubroutineImpl) getSubroutine(actual)).setLeavingRET();
      }
    }

    // Now make sure no instruction of a Subroutine is protected by exception handling code
    // as is mandated by JustIces notion of subroutines.
    for (int i = 0; i < handlers.length; i++) {
      InstructionHandle _protected = handlers[i].getStartPC();
      while (_protected
          != handlers[i]
              .getEndPC()
              .getNext()) { // Note the inclusive/inclusive notation of "generic API" exception
        // handlers!
        Enumeration subs = subroutines.elements();
        while (subs.hasMoreElements()) {
          Subroutine sub = (Subroutine) subs.nextElement();
          if (sub
              != subroutines.get(all[0])) { // We don't want to forbid top-level exception handlers.
            if (sub.contains(_protected)) {
              throw new StructuralCodeConstraintException(
                  "Subroutine instruction '"
                      + _protected
                      + "' is protected by an exception handler, '"
                      + handlers[i]
                      + "'. This is forbidden by the JustIce verifier due to its clear definition of subroutines.");
            }
          }
        }
        _protected = _protected.getNext();
      }
    }

    // Now make sure no subroutine is calling a subroutine
    // that uses the same local variable for the RET as themselves
    // (recursively).
    // This includes that subroutines may not call themselves
    // recursively, even not through intermediate calls to other
    // subroutines.
    noRecursiveCalls(getTopLevel(), new HashSet<Integer>());
  }