Package org.codehaus.aspectwerkz.hook.impl

Source Code of org.codehaus.aspectwerkz.hook.impl.ClassLoaderPreProcessorImpl

/**************************************************************************************
* Copyright (c) The AspectWerkz Team. All rights reserved.                           *
* http://aspectwerkz.codehaus.org                                                    *
* ---------------------------------------------------------------------------------- *
* The software in this package is published under the terms of the BSD style license *
* a copy of which has been included with this distribution in the license.txt file.  *
**************************************************************************************/
package org.codehaus.aspectwerkz.hook.impl;

import org.codehaus.aspectwerkz.hook.ClassLoaderPreProcessor;
import org.codehaus.aspectwerkz.hook.ClassLoaderPatcher;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.Constants;
import org.apache.bcel.generic.*;

import java.io.InputStream;
import java.io.ByteArrayInputStream;
import java.io.OutputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;

/**
* Instruments the java.lang.ClassLoader to plug in the Class PreProcessor
* mechanism using BCEL.
*
* We are using a lazy initialization of the class preprocessor to allow all class
* pre processor logic to be in system classpath and not in bootclasspath.
*
* This implementation should support IBM custom JRE
*
* @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur</a>
*/
public class ClassLoaderPreProcessorImpl implements ClassLoaderPreProcessor {

    public ClassLoaderPreProcessorImpl() {
    }

    public byte[] preProcess(byte[] b) {
        try {
            // Implementation note: add modified ClassLoader in bcel/lib/ and add wished class in bootclasspath
            // then turn on BCELifier to learn more about BCEL
            //org.apache.bcel.util.BCELifier bc = new org.apache.bcel.util.BCELifier(repository.loadClass("java.lang.ClassLoader"), System.out);
            //bc.start();

            final ClassGen cg = new ClassGen(
                    (new ClassParser(new ByteArrayInputStream(b), "<generated>")).parse());
            final String className = cg.getClassName();
            final Method[] methods = cg.getMethods();
            final ConstantPoolGen cpg = cg.getConstantPool();
            final InstructionFactory factory = new InstructionFactory(cg);

            // for all methods, look for caller side "this.define0" calls
            for (int i = 0; i < methods.length; i++) {
                final MethodGen mg = new MethodGen(methods[i], className, cpg);
                final InstructionList il = mg.getInstructionList();
                if (il == null) continue;

                InstructionHandle ih = il.getStart();
                while (ih != null) {
                    final Instruction ins = ih.getInstruction();
                    //System.out.println(ins.getName() + ins.getOpcode());
                    if (ins instanceof INVOKESPECIAL
                        || ins instanceof INVOKESTATIC
                        || ins instanceof INVOKEVIRTUAL) {

                        final InvokeInstruction invokeInst = (InvokeInstruction) ins;
                        final String callerSideMethodClassName = invokeInst.getClassName(cpg);
                        final String callerSideMethodName = invokeInst.getMethodName(cpg);

                        //System.out.println(callerSideMethodClassName + "." + callerSideMethodName);
                        if ("java.lang.ClassLoader".equals(callerSideMethodClassName)
                            && "defineClass0".equals(callerSideMethodName)) {

                            //assert compliant JRE
                            Type args[] = invokeInst.getArgumentTypes(cpg);
                            assertSupported(args);

                            // store former method args in local vars
                            InstructionHandle ihc = null;
                            if (args.length > 5) {
                                // IBM like JRE with extra args
                                ihc = il.append(ih.getPrev(), factory.createStore(args[args.length-1], 2100+args.length-1));
                                for (int index = args.length-2; index >= 5; index--) {
                                    ihc = il.append(ihc, factory.createStore(args[index], 2100+index));
                                }
                                ihc = il.append(ihc, factory.createStore(Type.OBJECT, 2016));//protection domain
                            } else {
                                // SUN regular JRE
                                ihc = il.append(ih.getPrev(), factory.createStore(Type.OBJECT, 2016));//protection domain
                            }

                            ihc = il.append(ihc, factory.createStore(Type.INT, 2015));//length
                            ihc = il.append(ihc, factory.createStore(Type.INT, 2014));//index
                            ihc = il.append(ihc, factory.createStore(Type.OBJECT, 2013));//bytes
                            ihc = il.append(ihc, factory.createStore(Type.OBJECT, 2012));//name

                            // prepare method call stack
                            ihc = il.append(ihc, factory.createLoad(Type.OBJECT, 0));//this
                            ihc = il.append(ihc, factory.createLoad(Type.OBJECT, 2012));
                            ihc = il.append(ihc, factory.createLoad(Type.OBJECT, 2013));
                            ihc = il.append(ihc, factory.createLoad(Type.INT, 2014));
                            ihc = il.append(ihc, factory.createLoad(Type.INT, 2015));
                            ihc = il.append(ihc, factory.createLoad(Type.OBJECT, 2016));

                            // call weaver helper
                            ihc = il.append(ihc, factory.createInvoke(
                                "org.codehaus.aspectwerkz.hook.impl.ClassPreProcessorHelper",
                                "defineClass0Pre",
                                new ArrayType(Type.BYTE, 1),
                                new Type[] {
                                    new ObjectType("java.lang.ClassLoader"),
                                    Type.STRING,
                                    new ArrayType(Type.BYTE, 1),
                                    Type.INT,
                                    Type.INT,
                                    new ObjectType("java.security.ProtectionDomain") },
                                Constants.INVOKESTATIC));
                            ihc = il.append(ihc, factory.createStore(Type.OBJECT, 3018));//result bytes

                            // rebuild former method call stack
                            ihc = il.append(ihc, factory.createLoad(Type.OBJECT, 2012));//name
                            ihc = il.append(ihc, factory.createLoad(Type.OBJECT, 3018));//bytes
                            ihc = il.append(ihc, new PUSH(cpg, 0));
                            ihc = il.append(ihc, factory.createLoad(Type.OBJECT, 3018));//bytes
                            ihc = il.append(ihc, InstructionConstants.ARRAYLENGTH);//.length
                            ihc = il.append(ihc, factory.createLoad(Type.OBJECT, 2016));//protection domain

                            // extra args for IBM like JRE
                            if (args.length > 5) {
                                for (int index = 5; index < args.length; index++) {
                                    ihc = il.append(ihc, factory.createLoad(args[index], 2100+index));
                                }
                            }

                            // call to define0 occurs here ...

                            // substitute result
                            ihc = il.append(ihc.getNext(), factory.createStore(Type.OBJECT, 3020));//result Class
                            ihc = il.append(ihc, factory.createLoad(Type.OBJECT, 3020));
                        }
                    }
                    ih = ih.getNext();
                }
                mg.setInstructionList(il);
                mg.setMaxLocals();
                mg.setMaxStack();
                methods[i] = mg.getMethod();
            }
            cg.setMethods(methods);

            // dump generated BCEL stuff thru BCELifier
            //org.apache.bcel.util.BCELifier bc = new org.apache.bcel.util.BCELifier(cg.getJavaClass(), System.out);
            //bc.start();

            // dump class file
            //cg.getJavaClass().dump("ClassLoader.class");

            return cg.getJavaClass().getBytes();
        } catch (Exception e) {
            System.err.println("failed to patch ClassLoader:");
            e.printStackTrace();
            return b;
        }
    }


















    public byte[] preProcessCOPY(byte[] b) {
        try {
            // Implementation note: add modified ClassLoader in bcel/lib/ and add wished class in bootclasspath
            // then turn on BCELifier to learn more about BCEL
            //org.apache.bcel.util.BCELifier bc = new org.apache.bcel.util.BCELifier(repository.loadClass("java.lang.ClassLoader"), System.out);
            //bc.start();

            final ClassGen cg = new ClassGen(
                    (new ClassParser(new ByteArrayInputStream(b), "<generated>")).parse());
            final String className = cg.getClassName();
            final Method[] methods = cg.getMethods();
            final ConstantPoolGen cpg = cg.getConstantPool();
            final InstructionFactory factory = new InstructionFactory(cg);

            // for all methods, look for caller side "this.define0" calls
            for (int i = 0; i < methods.length; i++) {
                final MethodGen mg = new MethodGen(methods[i], className, cpg);
                final InstructionList il = mg.getInstructionList();
                if (il == null) continue;

                InstructionHandle ih = il.getStart();
                while (ih != null) {
                    final Instruction ins = ih.getInstruction();
                    if (ins instanceof INVOKESPECIAL
                        || ins instanceof INVOKESTATIC
                        || ins instanceof INVOKEVIRTUAL) {

                        final InvokeInstruction invokeInst = (InvokeInstruction) ins;
                        final String callerSideMethodClassName = invokeInst.getClassName(cpg);
                        final String callerSideMethodName = invokeInst.getMethodName(cpg);

                        //System.out.println(callerSideMethodClassName + "." + callerSideMethodName);
                        if ("java.lang.ClassLoader".equals(callerSideMethodClassName)
                            && "defineClass0".equals(callerSideMethodName)) {
                            //assert compliant JRE
                            Type args[] = invokeInst.getArgumentTypes(cpg);
                            assertSupported(args);

                            System.out.println(invokeInst.consumeStack(cpg));
                            System.out.println(invokeInst.produceStack(cpg));
                            System.out.println(invokeInst.getIndex());


                            InstructionHandle ihc = null;
                            /*if (args.length > 5) {
                                // IBM like JRE with extra args
                                ihc = il.insert(ih, factory.createStore(args[args.length-1], 160+args.length-1));
                                System.out.println(160+args.length-1);
                                for (int index = args.length-2; index >= 5; index--) {
                                    ihc = il.append(ihc, factory.createStore(args[index], 160+index));
                                    System.out.println(160+index);
                                }
                                ihc = il.append(ihc, factory.createStore(Type.OBJECT, 16));//bytes
                            } else {
                                // SUN regular JRE
                                ihc = il.insert(ih, factory.createStore(Type.OBJECT, 16));//bytes
                            }*/

                            //ihc = il.insert(ih, factory.createStore(Type.OBJECT, 19));//bytes
                            //ihc = il.append(ihc, factory.createStore(Type.OBJECT, 18));//bytes
                            //ihc = il.append(ihc, factory.createStore(Type.OBJECT, 16));//bytes


                            ihc = il.insert(ih, factory.createStore(Type.OBJECT, 16));//bytes

                            ihc = il.append(ihc, factory.createStore(Type.INT, 15));//length
                            ihc = il.append(ihc, factory.createStore(Type.INT, 14));//index
                            ihc = il.append(ihc, factory.createStore(Type.OBJECT, 13));//bytes
                            ihc = il.append(ihc, factory.createStore(Type.OBJECT, 12));//name
                            ihc = il.append(ihc, factory.createStore(Type.OBJECT, 11));//this
                            ihc = il.append(ihc, factory.createLoad(Type.OBJECT, 0));
                            //ihc = il.append(ihc, InstructionConstants.THIS);

                            ihc = il.append(ihc, factory.createLoad(Type.OBJECT, 12));
                            ihc = il.append(ihc, factory.createLoad(Type.OBJECT, 13));
                            ihc = il.append(ihc, factory.createLoad(Type.INT, 14));
                            ihc = il.append(ihc, factory.createLoad(Type.INT, 15));
                            ihc = il.append(ihc, factory.createLoad(Type.OBJECT, 16));



                            ihc = il.append(ihc, factory.createInvoke(
                                "org.codehaus.aspectwerkz.hook.impl.ClassPreProcessorHelper",
                                "defineClass0Pre",
                                new ArrayType(Type.BYTE, 1),
                                new Type[] {
                                    new ObjectType("java.lang.ClassLoader"),
                                    Type.STRING,
                                    new ArrayType(Type.BYTE, 1),
                                    Type.INT,
                                    Type.INT,
                                    new ObjectType("java.security.ProtectionDomain") },
                                Constants.INVOKESTATIC));
                            ihc = il.append(ihc, factory.createStore(Type.OBJECT, 18+2/*18*/));//result bytes


                            ihc = il.append(ihc, factory.createLoad(Type.OBJECT, 11));//this
                            ihc = il.append(ihc, factory.createLoad(Type.OBJECT, 12));//name
                            ihc = il.append(ihc, factory.createLoad(Type.OBJECT, 18+2/*18*/));//bytes
                            ihc = il.append(ihc, new PUSH(cpg, 0));
                            ihc = il.append(ihc, factory.createLoad(Type.OBJECT, 18+2/*18*/));//bytes
                            ihc = il.append(ihc, InstructionConstants.ARRAYLENGTH);//.length
                            ihc = il.append(ihc, factory.createLoad(Type.OBJECT, 16));//protection domain

                            //ihc = il.append(ihc, factory.createLoad(Type.OBJECT, 18));//bytes
                            //ihc = il.append(ihc, factory.createLoad(Type.OBJECT, 19));//bytes

                            /*
                            // extra args for IBM like JRE
                            if (args.length > 5) {
                                for (int index = 5; index < args.length; index++) {
                                    ihc = il.append(ihc, factory.createLoad(Type.OBJECT, 160+index));
                                    System.out.println(" " + 160+index);
                                }
                            }
                            */

                            // call to define0 occurs here ...

                            ihc = il.append(ihc.getNext(), factory.createStore(Type.OBJECT, 19+2/*19*/));//result Class
                            ihc = il.append(ihc, factory.createLoad(Type.OBJECT, 19+2/*19*/));
                        }
                    }
                    ih = ih.getNext();
                }
                mg.setInstructionList(il);
                mg.setMaxLocals();
                mg.setMaxStack();
                methods[i] = mg.getMethod();
            }
            cg.setMethods(methods);

            // dump generated BCEL stuff thru BCELifier
            //org.apache.bcel.util.BCELifier bc = new org.apache.bcel.util.BCELifier(cg.getJavaClass(), System.out);
            //bc.start();

            // dump class file
            //cg.getJavaClass().dump("ClassLoader.class");

            return cg.getJavaClass().getBytes();
        } catch (Exception e) {
            System.err.println("failed to patch ClassLoader:");
            e.printStackTrace();
            return b;
        }
    }

    /**
     * Check the signature of defineClass0
     * @param args
     */
    private static void assertSupported(Type[] args) {
        if (args.length >= 5 &&
            (
            args[0].getSignature().equals("Ljava/lang/String;")
            && args[1].getSignature().equals("[B")
            && args[2].getSignature().equals("I")
            && args[3].getSignature().equals("I")
            && args[4].getSignature().equals("Ljava/security/ProtectionDomain;")
            ))
            ;
        else {
            StringBuffer sign = new StringBuffer("(");
            for (int i = 0; i < args.length; i++) {
                sign.append(args[i].toString());
                if (i < args.length -1)
                    sign.append(", ");
            }
            sign.append(")");
            throw new Error("non standard JDK, native call not supported "+sign.toString());
        }
    }

    /**
     * main test
     */
    public static void main(String args[]) throws Exception {
        ClassLoaderPreProcessor me = new ClassLoaderPreProcessorImpl();
        InputStream is = ClassLoader.getSystemClassLoader().getParent().getResourceAsStream("java/lang/ClassLoader.class");
        byte[] out = me.preProcess(ClassLoaderPatcher.inputStreamToByteArray(is));
        is.close();
        OutputStream os = new FileOutputStream("_boot/java/lang/ClassLoader.class");
        os.write(out);
        os.close();
    }

}
TOP

Related Classes of org.codehaus.aspectwerkz.hook.impl.ClassLoaderPreProcessorImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.