Example #1
0
  /** {@inheritDoc} */
  public int compareTo(Annotation other) {
    int result = type.compareTo(other.type);

    if (result != 0) {
      return result;
    }

    result = visibility.compareTo(other.visibility);

    if (result != 0) {
      return result;
    }

    Iterator<NameValuePair> thisIter = elements.values().iterator();
    Iterator<NameValuePair> otherIter = other.elements.values().iterator();

    while (thisIter.hasNext() && otherIter.hasNext()) {
      NameValuePair thisOne = thisIter.next();
      NameValuePair otherOne = otherIter.next();

      result = thisOne.compareTo(otherOne);
      if (result != 0) {
        return result;
      }
    }

    if (thisIter.hasNext()) {
      return 1;
    } else if (otherIter.hasNext()) {
      return -1;
    }

    return 0;
  }
Example #2
0
  /** {@inheritDoc} */
  @Override
  public boolean equals(Object other) {
    if (!(other instanceof Annotation)) {
      return false;
    }

    Annotation otherAnnotation = (Annotation) other;

    if (!(type.equals(otherAnnotation.type) && (visibility == otherAnnotation.visibility))) {
      return false;
    }

    return elements.equals(otherAnnotation.elements);
  }
Example #3
0
  /** {@inheritDoc} */
  public String toHuman() {
    StringBuilder sb = new StringBuilder();

    sb.append(visibility.toHuman());
    sb.append("-annotation ");
    sb.append(type.toHuman());
    sb.append(" {");

    boolean first = true;
    for (NameValuePair pair : elements.values()) {
      if (first) {
        first = false;
      } else {
        sb.append(", ");
      }
      sb.append(pair.getName().toHuman());
      sb.append(": ");
      sb.append(pair.getValue().toHuman());
    }

    sb.append("}");
    return sb.toString();
  }
Example #4
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;
  }
Example #5
0
 /** {@inheritDoc} */
 public int hashCode() {
   int hash = type.hashCode();
   hash = (hash * 31) + elements.hashCode();
   hash = (hash * 31) + visibility.hashCode();
   return hash;
 }
Example #6
0
  /**
   * Processes the methods of the given class.
   *
   * @param cf {@code non-null;} class being translated
   * @param cfOptions {@code non-null;} options for class translation
   * @param dexOptions {@code non-null;} options for dex output
   * @param out {@code non-null;} output class
   */
  private static void processMethods(
      DirectClassFile cf, CfOptions cfOptions, DexOptions dexOptions, ClassDefItem out) {
    CstType thisClass = cf.getThisClass();
    MethodList methods = cf.getMethods();
    int sz = methods.size();

    for (int i = 0; i < sz; i++) {
      Method one = methods.get(i);
      try {
        CstMethodRef meth = new CstMethodRef(thisClass, one.getNat());
        int accessFlags = one.getAccessFlags();
        boolean isStatic = AccessFlags.isStatic(accessFlags);
        boolean isPrivate = AccessFlags.isPrivate(accessFlags);
        boolean isNative = AccessFlags.isNative(accessFlags);
        boolean isAbstract = AccessFlags.isAbstract(accessFlags);
        boolean isConstructor = meth.isInstanceInit() || meth.isClassInit();
        DalvCode code;

        if (isNative || isAbstract) {
          // There's no code for native or abstract methods.
          code = null;
        } else {
          ConcreteMethod concrete =
              new ConcreteMethod(
                  one, cf, (cfOptions.positionInfo != PositionList.NONE), cfOptions.localInfo);

          TranslationAdvice advice;

          advice = DexTranslationAdvice.THE_ONE;

          RopMethod rmeth = Ropper.convert(concrete, advice);
          RopMethod nonOptRmeth = null;
          int paramSize;

          paramSize = meth.getParameterWordCount(isStatic);

          String canonicalName =
              thisClass.getClassType().getDescriptor() + "." + one.getName().getString();

          if (cfOptions.optimize && OptimizerOptions.shouldOptimize(canonicalName)) {
            if (DEBUG) {
              System.err.println("Optimizing " + canonicalName);
            }

            nonOptRmeth = rmeth;
            rmeth = Optimizer.optimize(rmeth, paramSize, isStatic, cfOptions.localInfo, advice);

            if (DEBUG) {
              OptimizerOptions.compareOptimizerStep(
                  nonOptRmeth, paramSize, isStatic, cfOptions, advice, rmeth);
            }

            if (cfOptions.statistics) {
              CodeStatistics.updateRopStatistics(nonOptRmeth, rmeth);
            }
          }

          LocalVariableInfo locals = null;

          if (cfOptions.localInfo) {
            locals = LocalVariableExtractor.extract(rmeth);
          }

          code =
              RopTranslator.translate(rmeth, cfOptions.positionInfo, locals, paramSize, dexOptions);

          if (cfOptions.statistics && nonOptRmeth != null) {
            updateDexStatistics(
                cfOptions,
                dexOptions,
                rmeth,
                nonOptRmeth,
                locals,
                paramSize,
                concrete.getCode().size());
          }
        }

        // Preserve the synchronized flag as its "declared" variant...
        if (AccessFlags.isSynchronized(accessFlags)) {
          accessFlags |= AccessFlags.ACC_DECLARED_SYNCHRONIZED;

          /*
           * ...but only native methods are actually allowed to be
           * synchronized.
           */
          if (!isNative) {
            accessFlags &= ~AccessFlags.ACC_SYNCHRONIZED;
          }
        }

        if (isConstructor) {
          accessFlags |= AccessFlags.ACC_CONSTRUCTOR;
        }

        TypeList exceptions = AttributeTranslator.getExceptions(one);
        EncodedMethod mi = new EncodedMethod(meth, accessFlags, code, exceptions);

        if (meth.isInstanceInit() || meth.isClassInit() || isStatic || isPrivate) {
          out.addDirectMethod(mi);
        } else {
          out.addVirtualMethod(mi);
        }

        Annotations annotations = AttributeTranslator.getMethodAnnotations(one);
        if (annotations.size() != 0) {
          out.addMethodAnnotations(meth, annotations);
        }

        AnnotationsList list = AttributeTranslator.getParameterAnnotations(one);
        if (list.size() != 0) {
          out.addParameterAnnotations(meth, list);
        }
      } catch (RuntimeException ex) {
        String msg =
            "...while processing " + one.getName().toHuman() + " " + one.getDescriptor().toHuman();
        throw ExceptionWithContext.withContext(ex, msg);
      }
    }
  }
  /** Parses a {@code Code} attribute. */
  private Attribute code(DirectClassFile cf, int offset, int length, ParseObserver observer) {
    if (length < 12) {
      return throwSeverelyTruncated();
    }

    ByteArray bytes = cf.getBytes();
    ConstantPool pool = cf.getConstantPool();
    int maxStack = bytes.getUnsignedShort(offset); // u2 max_stack
    int maxLocals = bytes.getUnsignedShort(offset + 2); // u2 max_locals
    int codeLength = bytes.getInt(offset + 4); // u4 code_length
    int origOffset = offset;

    if (observer != null) {
      observer.parsed(bytes, offset, 2, "max_stack: " + Hex.u2(maxStack));
      observer.parsed(bytes, offset + 2, 2, "max_locals: " + Hex.u2(maxLocals));
      observer.parsed(bytes, offset + 4, 4, "code_length: " + Hex.u4(codeLength));
    }

    offset += 8;
    length -= 8;

    if (length < (codeLength + 4)) {
      return throwTruncated();
    }

    int codeOffset = offset;
    offset += codeLength;
    length -= codeLength;
    BytecodeArray code = new BytecodeArray(bytes.slice(codeOffset, codeOffset + codeLength), pool);
    if (observer != null) {
      code.forEach(new CodeObserver(code.getBytes(), observer));
    }

    // u2 exception_table_length
    int exceptionTableLength = bytes.getUnsignedShort(offset);
    ByteCatchList catches =
        (exceptionTableLength == 0) ? ByteCatchList.EMPTY : new ByteCatchList(exceptionTableLength);

    if (observer != null) {
      observer.parsed(bytes, offset, 2, "exception_table_length: " + Hex.u2(exceptionTableLength));
    }

    offset += 2;
    length -= 2;

    if (length < (exceptionTableLength * 8 + 2)) {
      return throwTruncated();
    }

    for (int i = 0; i < exceptionTableLength; i++) {
      if (observer != null) {
        observer.changeIndent(1);
      }

      int startPc = bytes.getUnsignedShort(offset);
      int endPc = bytes.getUnsignedShort(offset + 2);
      int handlerPc = bytes.getUnsignedShort(offset + 4);
      int catchTypeIdx = bytes.getUnsignedShort(offset + 6);
      CstType catchType = (CstType) pool.get0Ok(catchTypeIdx);
      catches.set(i, startPc, endPc, handlerPc, catchType);
      if (observer != null) {
        observer.parsed(
            bytes,
            offset,
            8,
            Hex.u2(startPc)
                + ".."
                + Hex.u2(endPc)
                + " -> "
                + Hex.u2(handlerPc)
                + " "
                + ((catchType == null) ? "<any>" : catchType.toHuman()));
      }
      offset += 8;
      length -= 8;

      if (observer != null) {
        observer.changeIndent(-1);
      }
    }

    catches.setImmutable();

    AttributeListParser parser = new AttributeListParser(cf, CTX_CODE, offset, this);
    parser.setObserver(observer);

    StdAttributeList attributes = parser.getList();
    attributes.setImmutable();

    int attributeByteCount = parser.getEndOffset() - offset;
    if (attributeByteCount != length) {
      return throwBadLength(attributeByteCount + (offset - origOffset));
    }

    return new AttCode(maxStack, maxLocals, code, catches, attributes);
  }