/**
   * Parse the table part of either a {@code LocalVariableTable} or a {@code
   * LocalVariableTypeTable}.
   *
   * @param bytes {@code non-null;} bytes to parse, which should <i>only</i> contain the table data
   *     (no header)
   * @param pool {@code non-null;} constant pool to use
   * @param count {@code >= 0;} the number of entries
   * @param typeTable {@code true} iff this is for a type table
   * @return {@code non-null;} the constructed list
   */
  private LocalVariableList parseLocalVariables(
      ByteArray bytes, ConstantPool pool, ParseObserver observer, int count, boolean typeTable) {
    if (bytes.size() != (count * 10)) {
      // "+ 2" is for the count.
      throwBadLength((count * 10) + 2);
    }

    ByteArray.MyDataInputStream in = bytes.makeDataInputStream();
    LocalVariableList list = new LocalVariableList(count);

    try {
      for (int i = 0; i < count; i++) {
        int startPc = in.readUnsignedShort();
        int length = in.readUnsignedShort();
        int nameIdx = in.readUnsignedShort();
        int typeIdx = in.readUnsignedShort();
        int index = in.readUnsignedShort();
        CstString name = (CstString) pool.get(nameIdx);
        CstString type = (CstString) pool.get(typeIdx);
        CstString descriptor = null;
        CstString signature = null;

        if (typeTable) {
          signature = type;
        } else {
          descriptor = type;
        }

        list.set(i, startPc, length, name, descriptor, signature, index);

        if (observer != null) {
          observer.parsed(
              bytes,
              i * 10,
              10,
              Hex.u2(startPc)
                  + ".."
                  + Hex.u2(startPc + length)
                  + " "
                  + Hex.u2(index)
                  + " "
                  + name.toHuman()
                  + " "
                  + type.toHuman());
        }
      }
    } catch (IOException ex) {
      throw new RuntimeException("shouldn't happen", ex);
    }

    list.setImmutable();
    return list;
  }
예제 #2
0
  /**
   * Does a registerizing dump.
   *
   * @param meth {@code non-null;} method data to dump
   */
  private void ropDump(ConcreteMethod meth) {
    TranslationAdvice advice = DexTranslationAdvice.THE_ONE;
    BytecodeArray code = meth.getCode();
    ByteArray bytes = code.getBytes();
    RopMethod rmeth = Ropper.convert(meth, advice);
    StringBuffer sb = new StringBuffer(2000);

    if (optimize) {
      boolean isStatic = AccessFlags.isStatic(meth.getAccessFlags());
      int paramWidth = computeParamWidth(meth, isStatic);
      rmeth = new Optimizer().optimize(rmeth, paramWidth, isStatic, true, advice);
    }

    BasicBlockList blocks = rmeth.getBlocks();
    int[] order = blocks.getLabelsInOrder();

    sb.append("first " + Hex.u2(rmeth.getFirstLabel()) + "\n");

    for (int label : order) {
      BasicBlock bb = blocks.get(blocks.indexOfLabel(label));
      sb.append("block ");
      sb.append(Hex.u2(label));
      sb.append("\n");

      IntList preds = rmeth.labelToPredecessors(label);
      int psz = preds.size();
      for (int i = 0; i < psz; i++) {
        sb.append("  pred ");
        sb.append(Hex.u2(preds.get(i)));
        sb.append("\n");
      }

      InsnList il = bb.getInsns();
      int ilsz = il.size();
      for (int i = 0; i < ilsz; i++) {
        Insn one = il.get(i);
        sb.append("  ");
        sb.append(il.get(i).toHuman());
        sb.append("\n");
      }

      IntList successors = bb.getSuccessors();
      int ssz = successors.size();
      if (ssz == 0) {
        sb.append("  returns\n");
      } else {
        int primary = bb.getPrimarySuccessor();
        for (int i = 0; i < ssz; i++) {
          int succ = successors.get(i);
          sb.append("  next ");
          sb.append(Hex.u2(succ));

          if ((ssz != 1) && (succ == primary)) {
            sb.append(" *");
          }

          sb.append("\n");
        }
      }
    }

    suppressDump = false;
    setAt(bytes, 0);
    parsed(bytes, 0, bytes.size(), sb.toString());
    suppressDump = true;
  }
예제 #3
0
  /**
   * Does a regular basic block dump.
   *
   * @param meth {@code non-null;} method data to dump
   */
  private void regularDump(ConcreteMethod meth) {
    BytecodeArray code = meth.getCode();
    ByteArray bytes = code.getBytes();
    ByteBlockList list = BasicBlocker.identifyBlocks(meth);
    int sz = list.size();
    CodeObserver codeObserver = new CodeObserver(bytes, BlockDumper.this);

    // Reset the dump cursor to the start of the bytecode.
    setAt(bytes, 0);

    suppressDump = false;

    int byteAt = 0;
    for (int i = 0; i < sz; i++) {
      ByteBlock bb = list.get(i);
      int start = bb.getStart();
      int end = bb.getEnd();

      if (byteAt < start) {
        parsed(bytes, byteAt, start - byteAt, "dead code " + Hex.u2(byteAt) + ".." + Hex.u2(start));
      }

      parsed(
          bytes,
          start,
          0,
          "block " + Hex.u2(bb.getLabel()) + ": " + Hex.u2(start) + ".." + Hex.u2(end));
      changeIndent(1);

      int len;
      for (int j = start; j < end; j += len) {
        len = code.parseInstruction(j, codeObserver);
        codeObserver.setPreviousOffset(j);
      }

      IntList successors = bb.getSuccessors();
      int ssz = successors.size();
      if (ssz == 0) {
        parsed(bytes, end, 0, "returns");
      } else {
        for (int j = 0; j < ssz; j++) {
          int succ = successors.get(j);
          parsed(bytes, end, 0, "next " + Hex.u2(succ));
        }
      }

      ByteCatchList catches = bb.getCatches();
      int csz = catches.size();
      for (int j = 0; j < csz; j++) {
        ByteCatchList.Item one = catches.get(j);
        CstType exceptionClass = one.getExceptionClass();
        parsed(
            bytes,
            end,
            0,
            "catch "
                + ((exceptionClass == CstType.OBJECT) ? "<any>" : exceptionClass.toHuman())
                + " -> "
                + Hex.u2(one.getHandlerPc()));
      }

      changeIndent(-1);
      byteAt = end;
    }

    int end = bytes.size();
    if (byteAt < end) {
      parsed(bytes, byteAt, end - byteAt, "dead code " + Hex.u2(byteAt) + ".." + Hex.u2(end));
    }

    suppressDump = true;
  }