Example #1
0
  /**
   * Processes the fields of the given class.
   *
   * @param cf {@code non-null;} class being translated
   * @param out {@code non-null;} output class
   */
  private static void processFields(DirectClassFile cf, ClassDefItem out) {
    CstType thisClass = cf.getThisClass();
    FieldList fields = cf.getFields();
    int sz = fields.size();

    for (int i = 0; i < sz; i++) {
      Field one = fields.get(i);
      try {
        CstFieldRef field = new CstFieldRef(thisClass, one.getNat());
        int accessFlags = one.getAccessFlags();

        if (AccessFlags.isStatic(accessFlags)) {
          TypedConstant constVal = one.getConstantValue();
          EncodedField fi = new EncodedField(field, accessFlags);
          if (constVal != null) {
            constVal = coerceConstant(constVal, field.getType());
          }
          out.addStaticField(fi, constVal);
        } else {
          EncodedField fi = new EncodedField(field, accessFlags);
          out.addInstanceField(fi);
        }

        Annotations annotations = AttributeTranslator.getAnnotations(one.getAttributes());
        if (annotations.size() != 0) {
          out.addFieldAnnotations(field, annotations);
        }
      } catch (RuntimeException ex) {
        String msg =
            "...while processing " + one.getName().toHuman() + " " + one.getDescriptor().toHuman();
        throw ExceptionWithContext.withContext(ex, msg);
      }
    }
  }
  /** Parses an {@code InnerClasses} attribute. */
  private Attribute innerClasses(
      DirectClassFile cf, int offset, int length, ParseObserver observer) {
    if (length < 2) {
      return throwSeverelyTruncated();
    }

    ByteArray bytes = cf.getBytes();
    ConstantPool pool = cf.getConstantPool();
    int count = bytes.getUnsignedShort(offset); // number_of_classes

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

    offset += 2;
    length -= 2;

    if (length != (count * 8)) {
      throwBadLength((count * 8) + 2);
    }

    InnerClassList list = new InnerClassList(count);

    for (int i = 0; i < count; i++) {
      int innerClassIdx = bytes.getUnsignedShort(offset);
      int outerClassIdx = bytes.getUnsignedShort(offset + 2);
      int nameIdx = bytes.getUnsignedShort(offset + 4);
      int accessFlags = bytes.getUnsignedShort(offset + 6);
      CstType innerClass = (CstType) pool.get(innerClassIdx);
      CstType outerClass = (CstType) pool.get0Ok(outerClassIdx);
      CstString name = (CstString) pool.get0Ok(nameIdx);
      list.set(i, innerClass, outerClass, name, accessFlags);
      if (observer != null) {
        observer.parsed(
            bytes, offset, 2, "inner_class: " + DirectClassFile.stringOrNone(innerClass));
        observer.parsed(
            bytes, offset + 2, 2, "  outer_class: " + DirectClassFile.stringOrNone(outerClass));
        observer.parsed(bytes, offset + 4, 2, "  name: " + DirectClassFile.stringOrNone(name));
        observer.parsed(
            bytes, offset + 6, 2, "  access_flags: " + AccessFlags.innerClassString(accessFlags));
      }
      offset += 8;
    }

    list.setImmutable();
    return new AttInnerClasses(list);
  }
Example #3
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;
  }
Example #4
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);
      }
    }
  }