Exemple #1
0
  private static byte[] insertGapCore1(
      byte[] code,
      int where,
      int gapLength,
      boolean exclusive,
      ExceptionTable etable,
      CodeAttribute ca)
      throws BadBytecode, AlignmentException {
    int codeLength = code.length;
    byte[] newcode = new byte[codeLength + gapLength];
    insertGap2(code, where, gapLength, codeLength, newcode, exclusive);
    etable.shiftPc(where, gapLength, exclusive);
    LineNumberAttribute na = (LineNumberAttribute) ca.getAttribute(LineNumberAttribute.tag);
    if (na != null) na.shiftPc(where, gapLength, exclusive);

    LocalVariableAttribute va =
        (LocalVariableAttribute) ca.getAttribute(LocalVariableAttribute.tag);
    if (va != null) va.shiftPc(where, gapLength, exclusive);

    LocalVariableAttribute vta =
        (LocalVariableAttribute) ca.getAttribute(LocalVariableAttribute.typeTag);
    if (vta != null) vta.shiftPc(where, gapLength, exclusive);

    StackMapTable smt = (StackMapTable) ca.getAttribute(StackMapTable.tag);
    if (smt != null) smt.shiftPc(where, gapLength, exclusive);

    StackMap sm = (StackMap) ca.getAttribute(StackMap.tag);
    if (sm != null) sm.shiftPc(where, gapLength, exclusive);

    return newcode;
  }
  @SuppressWarnings("unchecked")
  public void visit(ClassFile file) throws Exception {
    List<MethodInfo> methods = file.getMethods();
    for (MethodInfo mi : methods) {
      try {
        CodeAttribute codeAttribute = mi.getCodeAttribute();
        // ignore abstract methods
        if (codeAttribute == null) {
          continue;
        }

        final int maxStack = codeAttribute.getMaxStack();
        int modified = 0;

        for (MethodRewriter mr : rewriters) {
          modified += mr.visit(mi);
        }

        if (modified != 0) {
          codeAttribute.setMaxStack(maxStack + modified);
        }
      } catch (Exception e) {
        throw new IllegalStateException("Cannot rewrite method: " + mi, e);
      }
    }
  }
Exemple #3
0
  /* skipSuper        1: this(), 0: super(), -1: both.
   */
  private int skipSuperConstructor0(int skipThis) throws BadBytecode {
    begin();
    ConstPool cp = codeAttr.getConstPool();
    String thisClassName = codeAttr.getDeclaringClass();
    int nested = 0;
    while (hasNext()) {
      int index = next();
      int c = byteAt(index);
      if (c == NEW) ++nested;
      else if (c == INVOKESPECIAL) {
        int mref = ByteArray.readU16bit(bytecode, index + 1);
        if (cp.getMethodrefName(mref).equals(MethodInfo.nameInit))
          if (--nested < 0) {
            if (skipThis < 0) return index;

            String cname = cp.getMethodrefClassName(mref);
            if (cname.equals(thisClassName) == (skipThis > 0)) return index;
            else break;
          }
      }
    }

    begin();
    return -1;
  }
Exemple #4
0
 /**
  * Rebuilds a stack map table for J2ME (CLDC). If no stack map table is included, a new one is
  * created. If this <code>MethodInfo</code> does not include a code attribute, nothing happens.
  *
  * @param pool used for making type hierarchy.
  * @see StackMap
  * @since 3.12
  */
 public void rebuildStackMapForME(ClassPool pool) throws BadBytecode {
   CodeAttribute ca = getCodeAttribute();
   if (ca != null) {
     StackMap sm = MapMaker.make2(pool, this);
     ca.setAttribute(sm);
   }
 }
 /**
  * Rebuilds a stack map table. If no stack map table is included, a new one is created. If this
  * <code>MethodInfo</code> does not include a code attribute, nothing happens.
  *
  * @param pool used for making type hierarchy.
  * @see StackMapTable
  * @since 3.6
  */
 public void rebuildStackMap(ClassPool pool) throws BadBytecode {
   CodeAttribute ca = getCodeAttribute();
   if (ca != null) {
     StackMapTable smt = MapMaker.make(pool, this);
     ca.setAttribute(smt);
   }
 }
  /**
   * Returns the line number of the source line corresponding to the specified bytecode contained in
   * this method.
   *
   * @param pos the position of the bytecode (&gt;= 0). an index into the code array.
   * @return -1 if this information is not available.
   */
  public int getLineNumber(int pos) {
    CodeAttribute ca = getCodeAttribute();
    if (ca == null) return -1;

    LineNumberAttribute ainfo = (LineNumberAttribute) ca.getAttribute(LineNumberAttribute.tag);
    if (ainfo == null) return -1;

    return ainfo.toLineNumber(pos);
  }
  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);
    }
  }
Exemple #8
0
 Pointers(int cur, int m, int m0, ExceptionTable et, CodeAttribute ca) {
   cursor = cur;
   mark = m;
   mark0 = m0;
   etable = et; // non null
   line = (LineNumberAttribute) ca.getAttribute(LineNumberAttribute.tag);
   vars = (LocalVariableAttribute) ca.getAttribute(LocalVariableAttribute.tag);
   types = (LocalVariableAttribute) ca.getAttribute(LocalVariableAttribute.typeTag);
   stack = (StackMapTable) ca.getAttribute(StackMapTable.tag);
   stack2 = (StackMap) ca.getAttribute(StackMap.tag);
 }
Exemple #9
0
  /**
   * Return javaassist source snippet which lists all the parameters and their values. If available
   * the source names are extracted from the debug information and used, otherwise just a number is
   * shown.
   *
   * @param method
   * @return
   * @throws NotFoundException
   */
  public static String getSignature(CtBehavior method) throws NotFoundException {

    CtClass[] parameterTypes = method.getParameterTypes();

    CodeAttribute codeAttribute = method.getMethodInfo().getCodeAttribute();

    LocalVariableAttribute locals = null;

    if (codeAttribute != null) {
      AttributeInfo attribute;
      attribute = codeAttribute.getAttribute("LocalVariableTable");
      locals = (LocalVariableAttribute) attribute;
    }

    String methodName = method.getName();

    StringBuilder sb = new StringBuilder(methodName).append("(\" ");
    for (int i = 0; i < parameterTypes.length; i++) {
      if (i > 0) {
        // add a comma and a space between printed values
        sb.append(" + \", \" ");
      }

      CtClass parameterType = parameterTypes[i];
      boolean isArray = parameterType.isArray();
      CtClass arrayType = parameterType.getComponentType();
      if (isArray) {
        while (arrayType.isArray()) {
          arrayType = arrayType.getComponentType();
        }
      }

      sb.append(" + \"");
      try {
        sb.append(parameterNameFor(method, locals, i));
      } catch (Exception e) {
        sb.append(i + 1);
      }
      sb.append("\" + \"=");

      if (parameterType.isPrimitive()) {
        // let the compiler handle primitive -> string
        sb.append("\"+ $").append(i + 1);
      } else {
        String s = "org.slf4j.instrumentation.ToStringHelper.render";
        sb.append("\"+ ").append(s).append("($").append(i + 1).append(')');
      }
    }
    sb.append("+\")");

    String signature = sb.toString();
    return signature;
  }
  /**
   * 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);
    }
  }
Exemple #11
0
  /**
   * Constructs a copy of <code>Code_attribute</code>. Specified class names are replaced during the
   * copy.
   *
   * @param cp constant pool table.
   * @param src source Code attribute.
   * @param classnames pairs of replaced and substituted class names.
   */
  private CodeAttribute(ConstPool cp, CodeAttribute src, Map classnames) throws BadBytecode {
    super(cp, tag);

    maxStack = src.getMaxStack();
    maxLocals = src.getMaxLocals();
    exceptions = src.getExceptionTable().copy(cp, classnames);
    attributes = new ArrayList();
    List src_attr = src.getAttributes();
    int num = src_attr.size();
    for (int i = 0; i < num; ++i) {
      AttributeInfo ai = (AttributeInfo) src_attr.get(i);
      attributes.add(ai.copy(cp, classnames));
    }

    info = src.copyCode(cp, classnames, exceptions, this);
  }
  private void read(MethodInfo src, String methodname, Map classnames) throws BadBytecode {
    ConstPool destCp = constPool;
    accessFlags = src.accessFlags;
    name = destCp.addUtf8Info(methodname);
    cachedName = methodname;
    ConstPool srcCp = src.constPool;
    String desc = srcCp.getUtf8Info(src.descriptor);
    String desc2 = Descriptor.rename(desc, classnames);
    descriptor = destCp.addUtf8Info(desc2);

    attribute = new LinkedList();
    ExceptionsAttribute eattr = src.getExceptionsAttribute();
    if (eattr != null) attribute.add(eattr.copy(destCp, classnames));

    CodeAttribute cattr = src.getCodeAttribute();
    if (cattr != null) attribute.add(cattr.copy(destCp, classnames));
  }
  /** 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));
    }
  }
Exemple #14
0
 /** Copies code. */
 private byte[] copyCode(
     ConstPool destCp, Map classnames, ExceptionTable etable, CodeAttribute destCa)
     throws BadBytecode {
   int len = getCodeLength();
   byte[] newCode = new byte[len];
   destCa.info = newCode;
   LdcEntry ldc = copyCode(this.info, 0, len, this.getConstPool(), newCode, destCp, classnames);
   return LdcEntry.doit(newCode, ldc, etable, destCa);
 }
Exemple #15
0
  /**
   * Appends a gap at the end of the bytecode sequence.
   *
   * @param gapLength gap length
   */
  public void appendGap(int gapLength) {
    byte[] code = bytecode;
    int codeLength = code.length;
    byte[] newcode = new byte[codeLength + gapLength];

    int i;
    for (i = 0; i < codeLength; ++i) newcode[i] = code[i];

    for (i = codeLength; i < codeLength + gapLength; ++i) newcode[i] = NOP;

    codeAttr.setCode(newcode);
    bytecode = newcode;
    endPos = getCodeLength();
  }
Exemple #16
0
  /**
   * Inserts an inclusive or exclusive gap in front of the instruction at the given index <code>pos
   * </code>. Branch offsets and the exception table in the method body are also updated. The
   * inserted gap is filled with NOP. The gap length may be extended to a multiple of 4.
   *
   * <p>Suppose that the instruction at the given index is at the beginning of a block statement. If
   * the gap is inclusive, then it is included within that block. If the gap is exclusive, then it
   * is excluded from that block.
   *
   * <p>The index at which the gap is actually inserted might be different from pos since some other
   * bytes might be inserted at other positions (e.g. to change <code>GOTO</code> to <code>GOTO_W
   * </code>). The index is available from the <code>Gap</code> object returned by this method.
   *
   * <p>Suppose that the gap is inserted at the position of the next instruction that would be
   * returned by <code>next()</code> (not the last instruction returned by the last call to <code>
   * next()</code>). The next instruction returned by <code>next()</code> after the gap is inserted
   * is still the same instruction. It is not <code>NOP</code> at the first byte of the inserted
   * gap.
   *
   * @param pos the index at which a gap is inserted.
   * @param length gap length.
   * @param exclusive true if exclusive, otherwise false.
   * @return the position and the length of the inserted gap.
   * @since 3.11
   */
  public Gap insertGapAt(int pos, int length, boolean exclusive) throws BadBytecode {
    /** cursorPos indicates the next bytecode whichever exclusive is true or false. */
    Gap gap = new Gap();
    if (length <= 0) {
      gap.position = pos;
      gap.length = 0;
      return gap;
    }

    byte[] c;
    int length2;
    if (bytecode.length + length > Short.MAX_VALUE) {
      // currentPos might change after calling insertGapCore0w().
      c =
          insertGapCore0w(
              bytecode, pos, length, exclusive, get().getExceptionTable(), codeAttr, gap);
      pos = gap.position;
      length2 = length; // == gap.length
    } else {
      int cur = currentPos;
      c = insertGapCore0(bytecode, pos, length, exclusive, get().getExceptionTable(), codeAttr);
      // insertGapCore0() never changes pos.
      length2 = c.length - bytecode.length;
      gap.position = pos;
      gap.length = length2;
      if (cur >= pos) currentPos = cur + length2;

      if (mark > pos || (mark == pos && exclusive)) mark += length2;
    }

    codeAttr.setCode(c);
    bytecode = c;
    endPos = getCodeLength();
    updateCursors(pos, length2);
    return gap;
  }
 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;
 }
Exemple #18
0
 protected CodeIterator(CodeAttribute ca) {
   codeAttr = ca;
   bytecode = ca.getCode();
   begin();
 }
  /** Add a method to a class that simply delegates to the parent implementation of the method */
  public static void addDelegatingMethod(ClassFile file, MethodData mData)
      throws BadBytecode, DuplicateMemberException {
    MethodInfo m =
        new MethodInfo(file.getConstPool(), mData.getMethodName(), mData.getDescriptor());
    m.setAccessFlags(mData.getAccessFlags());
    Bytecode code = new Bytecode(file.getConstPool());

    String[] params = DescriptorUtils.descriptorStringToParameterArray(mData.getDescriptor());
    code.add(Opcode.ALOAD_0); // push this
    int count = 1; // zero is the this pointer
    int maxLocals = 1;
    for (String p : params) {
      // int char short boolean byte
      if (p.equals("I") || p.equals("C") || p.equals("S") || p.equals("Z") || p.equals("B")) {
        // push integer 0
        code.addIload(count);
        maxLocals++;
      }
      // long
      else if (p.equals("J")) {
        code.addLload(count);
        maxLocals += 2;
        count++;
      }
      // double
      else if (p.equals("D")) {
        code.addDload(count);
        maxLocals += 2;
        count++;
      }
      // float
      else if (p.equals("F")) {
        code.addFload(count);
        maxLocals++;
      }
      // arrays and reference types
      else {
        code.addAload(count);
        maxLocals++;
      }
      count++;
    }
    code.addInvokespecial(file.getSuperclass(), mData.getMethodName(), mData.getDescriptor());
    String p = DescriptorUtils.getReturnTypeInJvmFormat(mData.getDescriptor());
    // int char short boolean byte
    if (p.equals("I") || p.equals("C") || p.equals("S") || p.equals("Z") || p.equals("B")) {
      code.add(Opcode.IRETURN);
    }
    // long
    else if (p.equals("J")) {
      code.add(Opcode.LRETURN);
    }
    // double
    else if (p.equals("D")) {
      code.add(Opcode.DRETURN);
    }
    // float
    else if (p.equals("F")) {
      code.add(Opcode.FRETURN);
    }
    // void
    else if (p.equals("V")) {
      code.add(Opcode.RETURN);
    }
    // arrays and reference types
    else {
      code.add(Opcode.ARETURN);
    }
    CodeAttribute ca = code.toCodeAttribute();
    ca.computeMaxStack();
    ca.setMaxLocals(maxLocals);
    m.setCodeAttribute(ca);
    file.addMethod(m);
  }
Exemple #20
0
 /**
  * Copies and inserts the entries in the given exception table at the beginning of the exception
  * table in the code attribute edited by this object.
  *
  * @param offset the value added to the code positions included in the entries.
  */
 public void insert(ExceptionTable et, int offset) {
   codeAttr.getExceptionTable().add(0, et, offset);
 }
Exemple #21
0
 /**
  * Copies and appends the entries in the given exception table at the end of the exception table
  * in the code attribute edited by this object.
  *
  * @param offset the value added to the code positions included in the entries.
  */
 public void append(ExceptionTable et, int offset) {
   ExceptionTable table = codeAttr.getExceptionTable();
   table.add(table.size(), et, offset);
 }