Example #1
0
 /*  94:    */
 /*  95:    */ protected int match(
     int c, int pos, CodeIterator iterator, int typedesc, ConstPool cp)
     /*  96:    */ throws BadBytecode
       /*  97:    */ {
   /*  98:110 */ if (this.newIndex == 0)
   /*  99:    */ {
     /* 100:111 */ int nt = cp.addNameAndTypeInfo(cp.addUtf8Info(this.newMethodname), typedesc);
     /* 101:    */
     /* 102:113 */ int ci = cp.addClassInfo(this.newClassname);
     /* 103:114 */ if (c == 185)
     /* 104:    */ {
       /* 105:115 */ this.newIndex = cp.addInterfaceMethodrefInfo(ci, nt);
       /* 106:    */ }
     /* 107:    */ else
     /* 108:    */ {
       /* 109:117 */ if ((this.newMethodIsPrivate) && (c == 182)) {
         /* 110:118 */ iterator.writeByte(183, pos);
         /* 111:    */ }
       /* 112:120 */ this.newIndex = cp.addMethodrefInfo(ci, nt);
       /* 113:    */ }
     /* 114:123 */ this.constPool = cp;
     /* 115:    */ }
   /* 116:126 */ iterator.write16bit(this.newIndex, pos + 1);
   /* 117:127 */ return pos;
   /* 118:    */ }
    public static void rewriteFakeMethod(CodeIterator methodBody, String methodDescriptor) {
      String ret = DescriptorUtils.getReturnType(methodDescriptor);
      // if the return type is larger than one then it is not a primitive
      // so it does not need to be boxed
      if (ret.length() != 1) {
        return;
      }
      byte ar = (byte) Opcode.ARETURN;
      byte[] areturn = {ar};
      // void methods are special
      if (ret.equals("V")) {

        while (methodBody.hasNext()) {
          try {
            int index = methodBody.next();
            int opcode = methodBody.byteAt(index);
            // replace a RETURN opcode with
            // ACONST_NULL
            // ARETURN
            // to return a null value
            if (opcode == Opcode.RETURN) {
              Bytecode code = new Bytecode(methodBody.get().getConstPool());
              code.add(Opcode.ACONST_NULL);
              code.add(Opcode.ARETURN);
              methodBody.insertAt(index, code.get());
            }
          } catch (BadBytecode e) {
            throw new RuntimeException(e);
          }
        }
      } else {
        while (methodBody.hasNext()) {
          try {
            int index = methodBody.next();
            int opcode = methodBody.byteAt(index);

            switch (opcode) {
              case Opcode.IRETURN:
              case Opcode.LRETURN:
              case Opcode.DRETURN:
              case Opcode.FRETURN:
                // write a NOP over the old return instruction
                // insert the boxing code to get an object on the stack
                Bytecode b = new Bytecode(methodBody.get().getConstPool());
                Boxing.box(b, ret.charAt(0));
                b.addOpcode(Opcode.ARETURN);
                methodBody.insertAt(index, b.get());
            }
          } catch (BadBytecode e) {
            throw new RuntimeException(e);
          }
        }
      }
    }
  @Override
  protected void onApply(CtBehavior behavior, Bytecode bytecode) throws BadBytecode {

    bytecode = BytecodeTools.prepareMethodForBytecode(behavior, bytecode);

    // loop through the opcodes and change any GT/GE opcodes to ICMPGT/ICMPGE
    CodeIterator iterator = behavior.getMethodInfo().getCodeAttribute().iterator();
    while (iterator.hasNext()) {
      int index = iterator.next();
      int opcode = iterator.byteAt(index);
      switch (opcode) {
        case Opcode.IFGT:

          // overwrite the opcode
          iterator.writeByte(Opcode.IF_ICMPGT, index);

          // insert the method call
          iterator.insertAt(index, bytecode.get());
          behavior.getMethodInfo().getCodeAttribute().computeMaxStack();

          break;

        case Opcode.IFGE:

          // overwrite the opcode
          iterator.writeByte(Opcode.IF_ICMPGE, index);

          // insert the method call
          iterator.insertAt(index, bytecode.get());
          behavior.getMethodInfo().getCodeAttribute().computeMaxStack();

          break;
      }
    }
  }
  protected void enhanceAttributesAccess(
      CtClass managedCtClass,
      IdentityHashMap<String, PersistentAttributeAccessMethods> attributeDescriptorMap) {
    final ConstPool constPool = managedCtClass.getClassFile().getConstPool();

    for (Object oMethod : managedCtClass.getClassFile().getMethods()) {
      final MethodInfo methodInfo = (MethodInfo) oMethod;
      final String methodName = methodInfo.getName();

      // skip methods added by enhancement and abstract methods (methods without any code)
      if (methodName.startsWith("$$_hibernate_") || methodInfo.getCodeAttribute() == null) {
        continue;
      }

      try {
        final CodeIterator itr = methodInfo.getCodeAttribute().iterator();
        while (itr.hasNext()) {
          final int index = itr.next();
          final int op = itr.byteAt(index);
          if (op != Opcode.PUTFIELD && op != Opcode.GETFIELD) {
            continue;
          }
          final String fieldName = constPool.getFieldrefName(itr.u16bitAt(index + 1));
          final PersistentAttributeAccessMethods attributeMethods =
              attributeDescriptorMap.get(fieldName);

          // its not a field we have enhanced for interception, so skip it
          if (attributeMethods == null) {
            continue;
          }
          // System.out.printf( "Transforming access to field [%s] from method [%s]%n", fieldName,
          // methodName );
          log.debugf("Transforming access to field [%s] from method [%s]", fieldName, methodName);

          if (op == Opcode.GETFIELD) {
            final int methodIndex = MethodWriter.addMethod(constPool, attributeMethods.getReader());
            itr.writeByte(Opcode.INVOKESPECIAL, index);
            itr.write16bit(methodIndex, index + 1);
          } else {
            final int methodIndex = MethodWriter.addMethod(constPool, attributeMethods.getWriter());
            itr.writeByte(Opcode.INVOKESPECIAL, index);
            itr.write16bit(methodIndex, index + 1);
          }
        }
        methodInfo.getCodeAttribute().setAttribute(MapMaker.make(classPool, methodInfo));
      } catch (BadBytecode bb) {
        final String msg =
            String.format(
                "Unable to perform field access transformation in method [%s]", methodName);
        throw new EnhancementException(msg, bb);
      }
    }
  }
Example #5
0
  /**
   * Changes a super constructor called by this constructor.
   *
   * <p>This method modifies a call to <code>super()</code>, which should be at the head of a
   * constructor body, so that a constructor in a different super class is called. This method does
   * not change actural parameters. Hence the new super class must have a constructor with the same
   * signature as the original one.
   *
   * <p>This method should be called when the super class of the class declaring this method is
   * changed.
   *
   * <p>This method does not perform anything unless this <code>MethodInfo</code> represents a
   * constructor.
   *
   * @param superclass the new super class
   */
  public void setSuperclass(String superclass) throws BadBytecode {
    if (!isConstructor()) return;

    CodeAttribute ca = getCodeAttribute();
    byte[] code = ca.getCode();
    CodeIterator iterator = ca.iterator();
    int pos = iterator.skipSuperConstructor();
    if (pos >= 0) { // not this()
      ConstPool cp = constPool;
      int mref = ByteArray.readU16bit(code, pos + 1);
      int nt = cp.getMethodrefNameAndType(mref);
      int sc = cp.addClassInfo(superclass);
      int mref2 = cp.addMethodrefInfo(sc, nt);
      ByteArray.write16bit(mref2, code, pos + 1);
    }
  }
Example #6
0
 /*  49:    */
 /*  50:    */ public int transform(CtClass clazz, int pos, CodeIterator iterator, ConstPool cp)
     /*  51:    */ throws BadBytecode
       /*  52:    */ {
   /*  53: 68 */ int c = iterator.byteAt(pos);
   /*  54: 69 */ if ((c == 185) || (c == 183) || (c == 184) || (c == 182))
   /*  55:    */ {
     /*  56: 71 */ int index = iterator.u16bitAt(pos + 1);
     /*  57: 72 */ String cname = cp.eqMember(this.methodname, this.methodDescriptor, index);
     /*  58: 73 */ if ((cname != null) && (matchClass(cname, clazz.getClassPool())))
     /*  59:    */ {
       /*  60: 74 */ int ntinfo = cp.getMemberNameAndType(index);
       /*  61: 75 */ pos = match(c, pos, iterator, cp.getNameAndTypeDescriptor(ntinfo), cp);
       /*  62:    */ }
     /*  63:    */ }
   /*  64: 80 */ return pos;
   /*  65:    */ }
  private static String lookupSwitch(CodeIterator iter, int pos) {
    StringBuffer buffer = new StringBuffer("lookupswitch {\n");
    int index = (pos & ~3) + 4;
    // default
    buffer.append("\t\tdefault: ").append(pos + iter.s32bitAt(index)).append("\n");
    int npairs = iter.s32bitAt(index += 4);
    int end = npairs * 8 + (index += 4);

    for (; index < end; index += 8) {
      int match = iter.s32bitAt(index);
      int target = iter.s32bitAt(index + 4) + pos;
      buffer.append("\t\t").append(match).append(": ").append(target).append("\n");
    }

    buffer.setCharAt(buffer.length() - 1, '}');
    return buffer.toString();
  }
  /** Prints the bytecode instructions of a given method. */
  public void print(CtMethod method) {
    MethodInfo info = method.getMethodInfo2();
    ConstPool pool = info.getConstPool();
    CodeAttribute code = info.getCodeAttribute();
    if (code == null) return;

    CodeIterator iterator = code.iterator();
    while (iterator.hasNext()) {
      int pos;
      try {
        pos = iterator.next();
      } catch (BadBytecode e) {
        throw new RuntimeException(e);
      }

      stream.println(pos + ": " + instructionString(iterator, pos, pool));
    }
  }
  private static String tableSwitch(CodeIterator iter, int pos) {
    StringBuffer buffer = new StringBuffer("tableswitch {\n");
    int index = (pos & ~3) + 4;
    // default
    buffer.append("\t\tdefault: ").append(pos + iter.s32bitAt(index)).append("\n");
    int low = iter.s32bitAt(index += 4);
    int high = iter.s32bitAt(index += 4);
    int end = (high - low + 1) * 4 + (index += 4);

    // Offset table
    for (int key = low; index < end; index += 4, key++) {
      int target = iter.s32bitAt(index) + pos;
      buffer.append("\t\t").append(key).append(": ").append(target).append("\n");
    }

    buffer.setCharAt(buffer.length() - 1, '}');
    return buffer.toString();
  }
 private static String wide(CodeIterator iter, int pos) {
   int opcode = iter.byteAt(pos + 1);
   int index = iter.u16bitAt(pos + 2);
   switch (opcode) {
     case ILOAD:
     case LLOAD:
     case FLOAD:
     case DLOAD:
     case ALOAD:
     case ISTORE:
     case LSTORE:
     case FSTORE:
     case DSTORE:
     case ASTORE:
     case IINC:
     case RET:
       return opcodes[opcode] + " " + index;
     default:
       throw new RuntimeException("Invalid WIDE operand");
   }
 }
  private void initExtraHarvest() {
    try {
      CtClass terraForming =
          HookManager.getInstance()
              .getClassPool()
              .get("com.wurmonline.server.behaviours.Terraforming");

      CtClass[] paramTypes = {
        HookManager.getInstance().getClassPool().get("com.wurmonline.server.creatures.Creature"),
        CtPrimitiveType.intType,
        CtPrimitiveType.intType,
        CtPrimitiveType.booleanType,
        CtPrimitiveType.intType,
        CtPrimitiveType.floatType,
        HookManager.getInstance().getClassPool().get("com.wurmonline.server.items.Item")
      };

      CtMethod method =
          terraForming.getMethod(
              "harvest", Descriptor.ofMethod(CtPrimitiveType.booleanType, paramTypes));
      MethodInfo methodInfo = method.getMethodInfo();
      CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
      CodeIterator codeIterator = codeAttribute.iterator();

      LocalVariableAttribute attr =
          (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
      int quantityIndex = -1;
      for (int i = 0; i < attr.tableLength(); i++) {
        if ("quantity".equals(attr.variableName(i))) {
          quantityIndex = attr.index(i);
        }
      }

      if (quantityIndex == -1) {
        throw new HookException("Quantity variable can not be resolved");
      }

      while (codeIterator.hasNext()) {
        int pos = codeIterator.next();
        int op = codeIterator.byteAt(pos);
        if (op == CodeIterator.ISTORE) {
          int fieldRefIdx = codeIterator.byteAt(pos + 1);
          if (quantityIndex == fieldRefIdx) {
            Bytecode bytecode = new Bytecode(codeIterator.get().getConstPool());
            bytecode.addIconst(extraHarvest);
            bytecode.add(Bytecode.IADD);
            codeIterator.insertAt(pos, bytecode.get());
            break;
          }
        }
      }
    } catch (NotFoundException | BadBytecode e) {
      throw new HookException(e);
    }
  }
  protected void enhanceAttributesAccess(Map<String, CtField> fieldsMap, CtClass managedCtClass)
      throws Exception {
    final ConstPool constPool = managedCtClass.getClassFile().getConstPool();
    final ClassPool classPool = managedCtClass.getClassPool();

    for (Object oMethod : managedCtClass.getClassFile().getMethods()) {
      final MethodInfo methodInfo = (MethodInfo) oMethod;
      final String methodName = methodInfo.getName();

      // skip methods added by enhancement, and abstract methods (methods without any code)
      if (methodName.startsWith(DROOLS_PREFIX) || methodInfo.getCodeAttribute() == null) {
        continue;
      }

      try {
        final CodeIterator itr = methodInfo.getCodeAttribute().iterator();
        while (itr.hasNext()) {
          final int index = itr.next();
          final int op = itr.byteAt(index);
          if (op != Opcode.PUTFIELD && op != Opcode.GETFIELD) {
            continue;
          }

          final String fieldName = constPool.getFieldrefName(itr.u16bitAt(index + 1));
          CtField ctField = fieldsMap.get(fieldName);
          if (ctField == null) {
            continue;
          }

          // if we are in constructors, only need to intercept assignment statement for Reactive
          // Collection/List/... (regardless they may be final)
          if (methodInfo.isConstructor() && !(isCtFieldACollection(ctField))) {
            continue;
          }

          if (op == Opcode.PUTFIELD) {
            // addMethod is a safe add, if constant already present it return the existing value
            // without adding.
            final int methodIndex = addMethod(constPool, writeMethods.get(fieldName));
            itr.writeByte(Opcode.INVOKEVIRTUAL, index);
            itr.write16bit(methodIndex, index + 1);
          }
        }
        methodInfo.getCodeAttribute().setAttribute(MapMaker.make(classPool, methodInfo));
      } catch (BadBytecode bb) {
        final String msg =
            String.format(
                "Unable to perform field access transformation in method [%s]", methodName);
        throw new Exception(msg, bb);
      }
    }
  }
Example #13
0
    static byte[] doit(byte[] code, LdcEntry ldc, ExceptionTable etable, CodeAttribute ca)
        throws BadBytecode {
      if (ldc != null) code = CodeIterator.changeLdcToLdcW(code, etable, ca, ldc);

      /* The original code was the following:

         while (ldc != null) {
           int where = ldc.where;
           code = CodeIterator.insertGapCore0(code, where, 1, false, etable, ca);
           code[where] = (byte)Opcode.LDC_W;
           ByteArray.write16bit(ldc.index, code, where + 1);
           ldc = ldc.next;
         }

         But this code does not support a large method > 32KB.
      */

      return code;
    }
Example #14
0
  private static void shiftIndex8(CodeIterator ci, int index, int opcode, int lessThan, int delta)
      throws BadBytecode {
    int var = ci.byteAt(index + 1);
    if (var < lessThan) return;

    var += delta;
    if (var < 0x100) ci.writeByte(var, index + 1);
    else {
      int pos = ci.insertExGap(2);
      ci.writeByte(WIDE, pos - 2);
      ci.writeByte(opcode, pos - 1);
      ci.write16bit(var, pos);
    }
  }
Example #15
0
  private static void shiftIndex0(
      CodeIterator ci, int index, int opcode, int lessThan, int delta, int opcode_i_0, int opcode_i)
      throws BadBytecode {
    int var = (opcode - opcode_i_0) % 4;
    if (var < lessThan) return;

    var += delta;
    if (var < 4) ci.writeByte(opcode + delta, index);
    else {
      opcode = (opcode - opcode_i_0) / 4 + opcode_i;
      if (var < 0x100) {
        int pos = ci.insertExGap(1);
        ci.writeByte(opcode, pos - 1);
        ci.writeByte(var, pos);
      } else {
        int pos = ci.insertExGap(3);
        ci.writeByte(WIDE, pos - 1);
        ci.writeByte(opcode, pos);
        ci.write16bit(var, pos + 1);
      }
    }
  }
  @Override
  public boolean transform(
      ClassLoader loader,
      String className,
      Class<?> classBeingRedefined,
      ProtectionDomain protectionDomain,
      ClassFile file)
      throws IllegalClassFormatException, BadBytecode {

    /**
     * Hack up the proxy factory so it stores the proxy ClassFile. We need this to regenerate
     * proxies.
     */
    if (file.getName().equals("org.jboss.weld.bean.proxy.ProxyFactory")) {
      for (final MethodInfo method : (List<MethodInfo>) file.getMethods()) {
        if (method.getName().equals("createProxyClass")) {
          final MethodInvokationManipulator methodInvokationManipulator =
              new MethodInvokationManipulator();
          methodInvokationManipulator.replaceVirtualMethodInvokationWithStatic(
              ClassLoader.class.getName(),
              WeldProxyClassLoadingDelegate.class.getName(),
              "loadClass",
              "(Ljava/lang/String;)Ljava/lang/Class;",
              "(Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/lang/Class;",
              loader);
          methodInvokationManipulator.replaceVirtualMethodInvokationWithStatic(
              "org.jboss.weld.util.bytecode.ClassFileUtils",
              WeldProxyClassLoadingDelegate.class.getName(),
              "toClass",
              "(Ljavassist/bytecode/ClassFile;Ljava/lang/ClassLoader;Ljava/security/ProtectionDomain;)Ljava/lang/Class;",
              "(Ljavassist/bytecode/ClassFile;Ljava/lang/ClassLoader;Ljava/security/ProtectionDomain;)Ljava/lang/Class;",
              loader);
          HashSet<MethodInfo> modifiedMethods = new HashSet<MethodInfo>();
          methodInvokationManipulator.transformClass(file, loader, true, modifiedMethods);
          for (MethodInfo m : modifiedMethods) {
            m.rebuildStackMap(ClassPool.getDefault());
          }
          return true;
        } else if (method.getName().equals("<init>")) {

          Integer beanArgument = null;
          int count = 0;
          for (final String paramType :
              DescriptorUtils.descriptorStringToParameterArray(method.getDescriptor())) {
            if (paramType.equals("javax/enterprise/inject/spi/Bean")) {
              beanArgument = count;
              break;
            } else if (paramType.equals("D") || paramType.equals("J")) {
              count += 2;
            } else {
              count++;
            }
          }
          if (beanArgument == null) {
            log.error(
                "Constructor org.jboss.weld.bean.proxy.ProxyFactory.<init>"
                    + method.getDescriptor()
                    + " does not have a bean parameter, proxies produced by this factory will not be reloadable");
            continue;
          }

          // similar to other tracked instances
          // but we need a strong ref
          Bytecode code = new Bytecode(file.getConstPool());
          code.addAload(0);
          code.addAload(beanArgument);
          code.addInvokestatic(
              WeldClassChangeAware.class.getName(),
              "addProxyFactory",
              "(Lorg/jboss/weld/bean/proxy/ProxyFactory;)V");
          CodeIterator it = method.getCodeAttribute().iterator();
          it.skipConstructor();
          it.insert(code.get());
        }
      }
    }
    return false;
  }
Example #17
0
  /**
   * @param lessThan If the index of the local variable is less than this value, it does not change.
   *     Otherwise, the index is increased.
   * @param delta the indexes of the local variables are increased by this value.
   */
  private static void shiftIndex(CodeIterator ci, int lessThan, int delta) throws BadBytecode {
    int index = ci.next();
    int opcode = ci.byteAt(index);
    if (opcode < ILOAD) return;
    else if (opcode < IASTORE) {
      if (opcode < ILOAD_0) {
        // iload, lload, fload, dload, aload
        shiftIndex8(ci, index, opcode, lessThan, delta);
      } else if (opcode < IALOAD) {
        // iload_0, ..., aload_3
        shiftIndex0(ci, index, opcode, lessThan, delta, ILOAD_0, ILOAD);
      } else if (opcode < ISTORE) return;
      else if (opcode < ISTORE_0) {
        // istore, lstore, ...
        shiftIndex8(ci, index, opcode, lessThan, delta);
      } else {
        // istore_0, ..., astore_3
        shiftIndex0(ci, index, opcode, lessThan, delta, ISTORE_0, ISTORE);
      }
    } else if (opcode == IINC) {
      int var = ci.byteAt(index + 1);
      if (var < lessThan) return;

      var += delta;
      if (var < 0x100) ci.writeByte(var, index + 1);
      else {
        int plus = (byte) ci.byteAt(index + 2);
        int pos = ci.insertExGap(3);
        ci.writeByte(WIDE, pos - 3);
        ci.writeByte(IINC, pos - 2);
        ci.write16bit(var, pos - 1);
        ci.write16bit(plus, pos + 1);
      }
    } else if (opcode == RET) shiftIndex8(ci, index, opcode, lessThan, delta);
    else if (opcode == WIDE) {
      int var = ci.u16bitAt(index + 2);
      if (var < lessThan) return;

      var += delta;
      ci.write16bit(var, index + 2);
    }
  }
Example #18
0
  /**
   * Changes the index numbers of the local variables to append a new parameter. This method does
   * not update <code>LocalVariableAttribute</code>, <code>LocalVariableTypeAttribute</code>, <code>
   * StackMapTable</code>, or <code>StackMap</code>. These attributes must be explicitly updated.
   *
   * @param where the index of the new parameter.
   * @param size the type size of the new parameter (1 or 2).
   * @see LocalVariableAttribute#shiftIndex(int, int)
   * @see LocalVariableTypeAttribute#shiftIndex(int, int)
   * @see StackMapTable#insertLocal(int, int, int)
   * @see StackMap#insertLocal(int, int, int)
   */
  public void insertLocalVar(int where, int size) throws BadBytecode {
    CodeIterator ci = iterator();
    while (ci.hasNext()) shiftIndex(ci, where, size);

    setMaxLocals(getMaxLocals() + size);
  }
Example #19
0
  private static LdcEntry copyCode(
      byte[] code,
      int beginPos,
      int endPos,
      ConstPool srcCp,
      byte[] newcode,
      ConstPool destCp,
      Map classnameMap)
      throws BadBytecode {
    int i2, index;
    LdcEntry ldcEntry = null;

    for (int i = beginPos; i < endPos; i = i2) {
      i2 = CodeIterator.nextOpcode(code, i);
      byte c = code[i];
      newcode[i] = c;
      switch (c & 0xff) {
        case LDC_W:
        case LDC2_W:
        case GETSTATIC:
        case PUTSTATIC:
        case GETFIELD:
        case PUTFIELD:
        case INVOKEVIRTUAL:
        case INVOKESPECIAL:
        case INVOKESTATIC:
        case NEW:
        case ANEWARRAY:
        case CHECKCAST:
        case INSTANCEOF:
          copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp, classnameMap);
          break;
        case LDC:
          index = code[i + 1] & 0xff;
          index = srcCp.copy(index, destCp, classnameMap);
          if (index < 0x100) newcode[i + 1] = (byte) index;
          else {
            newcode[i] = NOP;
            newcode[i + 1] = NOP;
            LdcEntry ldc = new LdcEntry();
            ldc.where = i;
            ldc.index = index;
            ldc.next = ldcEntry;
            ldcEntry = ldc;
          }
          break;
        case INVOKEINTERFACE:
          copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp, classnameMap);
          newcode[i + 3] = code[i + 3];
          newcode[i + 4] = code[i + 4];
          break;
        case INVOKEDYNAMIC:
          copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp, classnameMap);
          newcode[i + 3] = 0;
          newcode[i + 4] = 0;
          break;
        case MULTIANEWARRAY:
          copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp, classnameMap);
          newcode[i + 3] = code[i + 3];
          break;
        default:
          while (++i < i2) newcode[i] = code[i];

          break;
      }
    }

    return ldcEntry;
  }
  /** Gets a string representation of the bytecode instruction at the specified position. */
  public static String instructionString(CodeIterator iter, int pos, ConstPool pool) {
    int opcode = iter.byteAt(pos);

    if (opcode > opcodes.length || opcode < 0)
      throw new IllegalArgumentException("Invalid opcode, opcode: " + opcode + " pos: " + pos);

    String opstring = opcodes[opcode];
    switch (opcode) {
      case BIPUSH:
        return opstring + " " + iter.byteAt(pos + 1);
      case SIPUSH:
        return opstring + " " + iter.s16bitAt(pos + 1);
      case LDC:
        return opstring + " " + ldc(pool, iter.byteAt(pos + 1));
      case LDC_W:
      case LDC2_W:
        return opstring + " " + ldc(pool, iter.u16bitAt(pos + 1));
      case ILOAD:
      case LLOAD:
      case FLOAD:
      case DLOAD:
      case ALOAD:
      case ISTORE:
      case LSTORE:
      case FSTORE:
      case DSTORE:
      case ASTORE:
        return opstring + " " + iter.byteAt(pos + 1);
      case IFEQ:
      case IFGE:
      case IFGT:
      case IFLE:
      case IFLT:
      case IFNE:
      case IFNONNULL:
      case IFNULL:
      case IF_ACMPEQ:
      case IF_ACMPNE:
      case IF_ICMPEQ:
      case IF_ICMPGE:
      case IF_ICMPGT:
      case IF_ICMPLE:
      case IF_ICMPLT:
      case IF_ICMPNE:
        return opstring + " " + (iter.s16bitAt(pos + 1) + pos);
      case IINC:
        return opstring + " " + iter.byteAt(pos + 1);
      case GOTO:
      case JSR:
        return opstring + " " + (iter.s16bitAt(pos + 1) + pos);
      case RET:
        return opstring + " " + iter.byteAt(pos + 1);
      case TABLESWITCH:
        return tableSwitch(iter, pos);
      case LOOKUPSWITCH:
        return lookupSwitch(iter, pos);
      case GETSTATIC:
      case PUTSTATIC:
      case GETFIELD:
      case PUTFIELD:
        return opstring + " " + fieldInfo(pool, iter.u16bitAt(pos + 1));
      case INVOKEVIRTUAL:
      case INVOKESPECIAL:
      case INVOKESTATIC:
        return opstring + " " + methodInfo(pool, iter.u16bitAt(pos + 1));
      case INVOKEINTERFACE:
        return opstring + " " + interfaceMethodInfo(pool, iter.u16bitAt(pos + 1));
      case INVOKEDYNAMIC:
        return opstring + " " + iter.u16bitAt(pos + 1);
      case NEW:
        return opstring + " " + classInfo(pool, iter.u16bitAt(pos + 1));
      case NEWARRAY:
        return opstring + " " + arrayInfo(iter.byteAt(pos + 1));
      case ANEWARRAY:
      case CHECKCAST:
        return opstring + " " + classInfo(pool, iter.u16bitAt(pos + 1));
      case WIDE:
        return wide(iter, pos);
      case MULTIANEWARRAY:
        return opstring + " " + classInfo(pool, iter.u16bitAt(pos + 1));
      case GOTO_W:
      case JSR_W:
        return opstring + " " + (iter.s32bitAt(pos + 1) + pos);
      default:
        return opstring;
    }
  }
  protected void checkClassFile(ClassFile file) throws Exception {
    Map<Integer, Triple> calls = new HashMap<>();

    ConstPool pool = file.getConstPool();
    for (int i = 1; i < pool.getSize(); ++i) {
      // we have a method call
      BytecodeUtils.Ref ref = BytecodeUtils.getRef(pool, i);
      String className = ref.getClassName(pool, i);
      if (className != null) {
        String methodName = ref.getName(pool, i);
        String methodDesc = ref.getDesc(pool, i);
        fillCalls(i, className, methodName, methodDesc, calls);
      }
    }

    if (calls.isEmpty() && annotations.isEmpty()) {
      return;
    }

    String className = file.getName();

    AnnotationsAttribute faa =
        (AnnotationsAttribute) file.getAttribute(AnnotationsAttribute.visibleTag);
    checkAnnotations(className, TYPE_USAGE.getMethodName(), faa, -1);

    List<MethodInfo> methods = file.getMethods();
    for (MethodInfo m : methods) {
      try {
        // ignore abstract methods
        if (m.getCodeAttribute() == null) {
          continue;
        }

        AnnotationsAttribute maa =
            (AnnotationsAttribute) m.getAttribute(AnnotationsAttribute.visibleTag);
        boolean annotationsChecked = false;
        int firstLine = -1;

        CodeIterator it = m.getCodeAttribute().iterator();
        while (it.hasNext()) {
          // loop through the bytecode
          final int index = it.next();
          final int line = m.getLineNumber(index);

          if (annotationsChecked == false) {
            annotationsChecked = true;
            firstLine = line;
            checkAnnotations(
                className, m.getName(), maa, line - 2); // -2 to get the line above the method
          }

          int op = it.byteAt(index);
          // if the bytecode is a method invocation
          if (op == CodeIterator.INVOKEVIRTUAL
              || op == CodeIterator.INVOKESTATIC
              || op == CodeIterator.INVOKEINTERFACE
              || op == CodeIterator.INVOKESPECIAL) {
            int val = it.s16bitAt(index + 1);
            Triple triple = calls.get(val);
            if (triple != null) {
              Map<Tuple, Set<CodeLine>> map = report.get(triple.className);
              Set<CodeLine> set = map.get(triple.tuple);
              CodeLine cl = new CodeLine(className, m.getName(), line);
              set.add(cl.modify()); // check for .jsp, etc
            }
          }
        }

        if (BaseMethodExclusion.isBridge(m) == false) {
          SignatureAttribute.MethodSignature signature =
              SignatureAttribute.toMethodSignature(m.getDescriptor());
          handleMethodSignature(className, m.getName(), firstLine - 1, signature.getReturnType());
          handleMethodSignature(
              className, m.getName(), firstLine - 1, signature.getParameterTypes());
          handleMethodSignature(
              className, m.getName(), firstLine - 1, signature.getExceptionTypes());
        }

        ParameterAnnotationsAttribute paa =
            (ParameterAnnotationsAttribute)
                m.getAttribute(ParameterAnnotationsAttribute.visibleTag);
        if (paa != null) {
          Annotation[][] paas = paa.getAnnotations();
          if (paas != null) {
            for (Annotation[] params : paas) {
              for (Annotation a : params) {
                for (Map.Entry<String, Boolean> entry : annotations.entrySet()) {
                  if (entry.getKey().equals(a.getTypeName())) {
                    checkAnnotation(
                        className, m.getName(), firstLine - 1, entry.getValue(), entry.getKey(), a);
                  }
                }
              }
            }
          }
        }

        m.getCodeAttribute().computeMaxStack();
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
Example #22
0
 public boolean match(String filename, ClassFile classFile, ClassMap tempClassMap) {
   for (Object o : classFile.getMethods()) {
     MethodInfo methodInfo = (MethodInfo) o;
     classMod.methodInfo = methodInfo;
     CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
     if (codeAttribute == null) {
       continue;
     }
     if (getClassMap().hasMap(deobfMethod)) {
       MethodRef obfTarget = (MethodRef) getClassMap().map(deobfMethod);
       if (!methodInfo.getName().equals(obfTarget.getName())) {
         continue;
       }
     }
     ArrayList<String> deobfTypes = null;
     ArrayList<String> obfTypes = null;
     if (deobfMethod != null && deobfMethod.getType() != null) {
       deobfTypes = ConstPoolUtils.parseDescriptor(deobfMethod.getType());
       obfTypes = ConstPoolUtils.parseDescriptor(methodInfo.getDescriptor());
       if (!isPotentialTypeMatch(deobfTypes, obfTypes)) {
         continue;
       }
     }
     ConstPool constPool = methodInfo.getConstPool();
     CodeIterator codeIterator = codeAttribute.iterator();
     initMatcher();
     ArrayList<JavaRef> tempMappings = new ArrayList<JavaRef>();
     try {
       match:
       for (int offset = 0;
           offset < codeIterator.getCodeLength() && matcher.match(methodInfo, offset);
           offset = codeIterator.next()) {
         tempMappings.clear();
         for (Map.Entry<Integer, JavaRef> entry : xrefs.entrySet()) {
           int captureGroup = entry.getKey();
           JavaRef xref = entry.getValue();
           byte[] code = matcher.getCaptureGroup(captureGroup);
           int index = Util.demarshal(code, 1, 2);
           ConstPoolUtils.matchOpcodeToRefType(code[0], xref);
           ConstPoolUtils.matchConstPoolTagToRefType(constPool.getTag(index), xref);
           JavaRef newRef = ConstPoolUtils.getRefForIndex(constPool, index);
           if (!isPotentialTypeMatch(xref.getType(), newRef.getType())) {
             if (deobfMethod != null) {
               Logger.log(
                   Logger.LOG_METHOD,
                   "method %s %s matches %s %s, but",
                   methodInfo.getName(),
                   methodInfo.getDescriptor(),
                   deobfMethod.getName(),
                   deobfMethod.getType());
             }
             Logger.log(
                 Logger.LOG_METHOD,
                 "method %s %s failed xref #%d %s %s -> %s %s",
                 methodInfo.getName(),
                 methodInfo.getDescriptor(),
                 captureGroup,
                 xref.getName(),
                 xref.getType(),
                 newRef.getName(),
                 newRef.getType());
             continue match;
           }
           tempMappings.add(xref);
           tempMappings.add(newRef);
         }
         for (int i = 0; i + 1 < tempMappings.size(); i += 2) {
           tempClassMap.addMap(tempMappings.get(i), tempMappings.get(i + 1));
         }
         if (deobfMethod != null) {
           String deobfName = classMod.getDeobfClass();
           tempClassMap.addClassMap(deobfName, ClassMap.filenameToClassName(filename));
           tempClassMap.addMethodMap(
               deobfName, deobfMethod.getName(), methodInfo.getName(), methodInfo.getDescriptor());
           if (deobfTypes != null && obfTypes != null) {
             for (int i = 0; i < deobfTypes.size(); i++) {
               String desc = ClassMap.descriptorToClassName(deobfTypes.get(i));
               String obf = ClassMap.descriptorToClassName(obfTypes.get(i));
               if (!obf.equals(desc)) {
                 tempClassMap.addClassMap(desc, obf);
               }
             }
           }
         }
         afterMatch(classFile, methodInfo);
         classMod.methodInfo = null;
         return true;
       }
     } catch (BadBytecode e) {
       Logger.log(e);
     }
   }
   classMod.methodInfo = null;
   return false;
 }
  /**
   * Replace access to fields of entities (for example, entity.field) with a call to the enhanced
   * getter / setter (in this example, entity.$$_hibernate_read_field()). It's assumed that the
   * target entity is enhanced as well.
   *
   * @param managedCtClass Class to enhance
   */
  public void enhanceFieldAccess(CtClass managedCtClass) {
    final ConstPool constPool = managedCtClass.getClassFile().getConstPool();

    for (Object oMethod : managedCtClass.getClassFile().getMethods()) {
      final MethodInfo methodInfo = (MethodInfo) oMethod;
      final String methodName = methodInfo.getName();

      // skip methods added by enhancement and abstract methods (methods without any code)
      if (methodName.startsWith("$$_hibernate_") || methodInfo.getCodeAttribute() == null) {
        continue;
      }

      try {
        final CodeIterator itr = methodInfo.getCodeAttribute().iterator();
        while (itr.hasNext()) {
          int index = itr.next();
          int op = itr.byteAt(index);
          if (op != Opcode.PUTFIELD && op != Opcode.GETFIELD) {
            continue;
          }
          String fieldName = constPool.getFieldrefName(itr.u16bitAt(index + 1));
          String fieldClassName =
              constPool.getClassInfo(constPool.getFieldrefClass(itr.u16bitAt(index + 1)));
          CtClass targetCtClass = this.classPool.getCtClass(fieldClassName);

          if (!enhancementContext.isEntityClass(targetCtClass)
              && !enhancementContext.isCompositeClass(targetCtClass)) {
            continue;
          }
          if (targetCtClass == managedCtClass
              || !enhancementContext.isPersistentField(targetCtClass.getField(fieldName))
              || "this$0".equals(fieldName)) {
            continue;
          }

          log.debugf("Transforming access to field [%s] from method [%s]", fieldName, methodName);

          if (op == Opcode.GETFIELD) {
            int fieldReaderMethodIndex =
                constPool.addMethodrefInfo(
                    constPool.addClassInfo(fieldClassName),
                    EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX + fieldName,
                    "()" + constPool.getFieldrefType(itr.u16bitAt(index + 1)));
            itr.writeByte(Opcode.INVOKEVIRTUAL, index);
            itr.write16bit(fieldReaderMethodIndex, index + 1);
          } else {
            int fieldWriterMethodIndex =
                constPool.addMethodrefInfo(
                    constPool.addClassInfo(fieldClassName),
                    EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX + fieldName,
                    "(" + constPool.getFieldrefType(itr.u16bitAt(index + 1)) + ")V");
            itr.writeByte(Opcode.INVOKEVIRTUAL, index);
            itr.write16bit(fieldWriterMethodIndex, index + 1);
          }
        }
        methodInfo.getCodeAttribute().setAttribute(MapMaker.make(classPool, methodInfo));
      } catch (BadBytecode bb) {
        final String msg =
            String.format(
                "Unable to perform field access transformation in method [%s]", methodName);
        throw new EnhancementException(msg, bb);
      } catch (NotFoundException nfe) {
        final String msg =
            String.format(
                "Unable to perform field access transformation in method [%s]", methodName);
        throw new EnhancementException(msg, nfe);
      }
    }
  }
  public boolean transformClass(ClassFile file, ClassLoader loader, boolean modifiableClass) {
    Set<Integer> methodCallLocations = new HashSet<Integer>();
    Integer newCallLocation = null;
    Integer methodReflectionLocation = null;
    Integer fakeCallRequiredLocation = null;
    // first we need to scan the constant pool looking for
    // CONSTANT_method_info_ref structures
    ConstPool pool = file.getConstPool();
    for (int i = 1; i < pool.getSize(); ++i) {
      // we have a method call
      if (pool.getTag(i) == ConstPool.CONST_Methodref) {
        String className = pool.getMethodrefClassName(i);
        String methodName = pool.getMethodrefName(i);

        if (className.equals(Method.class.getName())) {
          if (methodName.equals("invoke")) {
            // store the location in the const pool of the method ref
            methodCallLocations.add(i);
            // we have found a method call

            // if we have not already stored a reference to our new
            // method in the const pool
            if (newCallLocation == null) {
              methodReflectionLocation =
                  pool.addClassInfo("org.fakereplace.reflection.MethodReflection");
              int nt = pool.addNameAndTypeInfo("fakeCallRequired", "(Ljava/lang/reflect/Method;)Z");
              fakeCallRequiredLocation = pool.addMethodrefInfo(methodReflectionLocation, nt);
              newCallLocation = pool.addNameAndTypeInfo(METHOD_NAME, REPLACED_METHOD_DESCRIPTOR);
            }
          }
        }
      }
    }

    // this means we found an instance of the call, now we have to iterate
    // through the methods and replace instances of the call
    if (newCallLocation != null) {
      List<MethodInfo> methods = file.getMethods();
      for (MethodInfo m : methods) {
        try {
          // ignore abstract methods
          if (m.getCodeAttribute() == null) {
            continue;
          }
          CodeIterator it = m.getCodeAttribute().iterator();
          while (it.hasNext()) {
            // loop through the bytecode
            int index = it.next();
            int op = it.byteAt(index);
            // if the bytecode is a method invocation
            if (op == CodeIterator.INVOKEVIRTUAL) {
              int val = it.s16bitAt(index + 1);
              // if the method call is one of the methods we are
              // replacing
              if (methodCallLocations.contains(val)) {
                Bytecode b = new Bytecode(file.getConstPool());
                // our stack looks like Method, instance,params
                // we need Method, instance, params , Method
                b.add(Opcode.DUP_X2);
                b.add(Opcode.POP);
                b.add(Opcode.DUP_X2);
                b.add(Opcode.POP);
                b.add(Opcode.DUP_X2);
                b.addInvokestatic(
                    methodReflectionLocation, "fakeCallRequired", "(Ljava/lang/reflect/Method;)Z");
                b.add(Opcode.IFEQ);
                JumpMarker performRealCall = JumpUtils.addJumpInstruction(b);
                // now perform the fake call
                b.addInvokestatic(methodReflectionLocation, "invoke", REPLACED_METHOD_DESCRIPTOR);
                b.add(Opcode.GOTO);
                JumpMarker finish = JumpUtils.addJumpInstruction(b);
                performRealCall.mark();
                b.addInvokevirtual(Method.class.getName(), METHOD_NAME, METHOD_DESCRIPTOR);
                finish.mark();
                it.writeByte(CodeIterator.NOP, index);
                it.writeByte(CodeIterator.NOP, index + 1);
                it.writeByte(CodeIterator.NOP, index + 2);
                it.insert(b.get());
              }
            }
          }
          m.getCodeAttribute().computeMaxStack();
        } catch (Exception e) {
          log.error("Bad byte code transforming " + file.getName());
          e.printStackTrace();
        }
      }
      return true;
    } else {
      return false;
    }
  }