1*0c56280aSSorin Basca /* 2*0c56280aSSorin Basca * Licensed to the Apache Software Foundation (ASF) under one or more 3*0c56280aSSorin Basca * contributor license agreements. See the NOTICE file distributed with 4*0c56280aSSorin Basca * this work for additional information regarding copyright ownership. 5*0c56280aSSorin Basca * The ASF licenses this file to You under the Apache License, Version 2.0 6*0c56280aSSorin Basca * (the "License"); you may not use this file except in compliance with 7*0c56280aSSorin Basca * the License. You may obtain a copy of the License at 8*0c56280aSSorin Basca * 9*0c56280aSSorin Basca * http://www.apache.org/licenses/LICENSE-2.0 10*0c56280aSSorin Basca * 11*0c56280aSSorin Basca * Unless required by applicable law or agreed to in writing, software 12*0c56280aSSorin Basca * distributed under the License is distributed on an "AS IS" BASIS, 13*0c56280aSSorin Basca * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*0c56280aSSorin Basca * See the License for the specific language governing permissions and 15*0c56280aSSorin Basca * limitations under the License. 16*0c56280aSSorin Basca * 17*0c56280aSSorin Basca */ 18*0c56280aSSorin Basca 19*0c56280aSSorin Basca import org.apache.bcel.Constants; 20*0c56280aSSorin Basca import org.apache.bcel.classfile.ClassParser; 21*0c56280aSSorin Basca import org.apache.bcel.classfile.Code; 22*0c56280aSSorin Basca import org.apache.bcel.classfile.ConstantClass; 23*0c56280aSSorin Basca import org.apache.bcel.classfile.ConstantPool; 24*0c56280aSSorin Basca import org.apache.bcel.classfile.ConstantUtf8; 25*0c56280aSSorin Basca import org.apache.bcel.classfile.JavaClass; 26*0c56280aSSorin Basca import org.apache.bcel.classfile.Method; 27*0c56280aSSorin Basca import org.apache.bcel.classfile.Utility; 28*0c56280aSSorin Basca import org.apache.bcel.generic.ConstantPoolGen; 29*0c56280aSSorin Basca import org.apache.bcel.generic.GETSTATIC; 30*0c56280aSSorin Basca import org.apache.bcel.generic.INVOKESPECIAL; 31*0c56280aSSorin Basca import org.apache.bcel.generic.INVOKEVIRTUAL; 32*0c56280aSSorin Basca import org.apache.bcel.generic.InstructionHandle; 33*0c56280aSSorin Basca import org.apache.bcel.generic.InstructionList; 34*0c56280aSSorin Basca import org.apache.bcel.generic.MethodGen; 35*0c56280aSSorin Basca import org.apache.bcel.generic.PUSH; 36*0c56280aSSorin Basca 37*0c56280aSSorin Basca /** 38*0c56280aSSorin Basca * Read class file(s) and patch all of its methods, so that they print 39*0c56280aSSorin Basca * "hello" and their name and signature before doing anything else. 40*0c56280aSSorin Basca * 41*0c56280aSSorin Basca * @version $Id$ 42*0c56280aSSorin Basca */ 43*0c56280aSSorin Basca public final class helloify implements Constants { 44*0c56280aSSorin Basca 45*0c56280aSSorin Basca private static String class_name; 46*0c56280aSSorin Basca private static ConstantPoolGen cp; 47*0c56280aSSorin Basca private static int out; // reference to System.out 48*0c56280aSSorin Basca private static int println; // reference to PrintStream.println 49*0c56280aSSorin Basca main(String[] argv)50*0c56280aSSorin Basca public static void main(String[] argv) throws Exception { 51*0c56280aSSorin Basca for (String arg : argv) { 52*0c56280aSSorin Basca if (arg.endsWith(".class")) { 53*0c56280aSSorin Basca JavaClass java_class = new ClassParser(arg).parse(); 54*0c56280aSSorin Basca ConstantPool constants = java_class.getConstantPool(); 55*0c56280aSSorin Basca String file_name = arg.substring(0, arg.length() - 6) + "_hello.class"; 56*0c56280aSSorin Basca cp = new ConstantPoolGen(constants); 57*0c56280aSSorin Basca 58*0c56280aSSorin Basca helloifyClassName(java_class); 59*0c56280aSSorin Basca 60*0c56280aSSorin Basca out = cp.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;"); 61*0c56280aSSorin Basca println = cp.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V"); 62*0c56280aSSorin Basca // Patch all methods. 63*0c56280aSSorin Basca Method[] methods = java_class.getMethods(); 64*0c56280aSSorin Basca 65*0c56280aSSorin Basca for (int j = 0; j < methods.length; j++) { 66*0c56280aSSorin Basca methods[j] = helloifyMethod(methods[j]); 67*0c56280aSSorin Basca } 68*0c56280aSSorin Basca 69*0c56280aSSorin Basca // Finally dump it back to a file. 70*0c56280aSSorin Basca java_class.setConstantPool(cp.getFinalConstantPool()); 71*0c56280aSSorin Basca java_class.dump(file_name); 72*0c56280aSSorin Basca } 73*0c56280aSSorin Basca } 74*0c56280aSSorin Basca } 75*0c56280aSSorin Basca 76*0c56280aSSorin Basca /** 77*0c56280aSSorin Basca * Change class name to <old_name>_hello 78*0c56280aSSorin Basca */ helloifyClassName(JavaClass java_class)79*0c56280aSSorin Basca private static void helloifyClassName(JavaClass java_class) { 80*0c56280aSSorin Basca class_name = java_class.getClassName() + "_hello"; 81*0c56280aSSorin Basca int index = java_class.getClassNameIndex(); 82*0c56280aSSorin Basca 83*0c56280aSSorin Basca index = ((ConstantClass) cp.getConstant(index)).getNameIndex(); 84*0c56280aSSorin Basca cp.setConstant(index, new ConstantUtf8(class_name.replace('.', '/'))); 85*0c56280aSSorin Basca } 86*0c56280aSSorin Basca 87*0c56280aSSorin Basca /** 88*0c56280aSSorin Basca * Patch a method. 89*0c56280aSSorin Basca */ helloifyMethod(Method m)90*0c56280aSSorin Basca private static Method helloifyMethod(Method m) { 91*0c56280aSSorin Basca Code code = m.getCode(); 92*0c56280aSSorin Basca int flags = m.getAccessFlags(); 93*0c56280aSSorin Basca String name = m.getName(); 94*0c56280aSSorin Basca 95*0c56280aSSorin Basca // Sanity check 96*0c56280aSSorin Basca if (m.isNative() || m.isAbstract() || (code == null)) { 97*0c56280aSSorin Basca return m; 98*0c56280aSSorin Basca } 99*0c56280aSSorin Basca 100*0c56280aSSorin Basca // Create instruction list to be inserted at method start. 101*0c56280aSSorin Basca String mesg = "Hello from " + Utility.methodSignatureToString(m.getSignature(), 102*0c56280aSSorin Basca name, 103*0c56280aSSorin Basca Utility.accessToString(flags)); 104*0c56280aSSorin Basca InstructionList patch = new InstructionList(); 105*0c56280aSSorin Basca patch.append(new GETSTATIC(out)); 106*0c56280aSSorin Basca patch.append(new PUSH(cp, mesg)); 107*0c56280aSSorin Basca patch.append(new INVOKEVIRTUAL(println)); 108*0c56280aSSorin Basca 109*0c56280aSSorin Basca MethodGen mg = new MethodGen(m, class_name, cp); 110*0c56280aSSorin Basca InstructionList il = mg.getInstructionList(); 111*0c56280aSSorin Basca InstructionHandle[] ihs = il.getInstructionHandles(); 112*0c56280aSSorin Basca 113*0c56280aSSorin Basca if (name.equals("<init>")) { // First let the super or other constructor be called 114*0c56280aSSorin Basca for (int j = 1; j < ihs.length; j++) { 115*0c56280aSSorin Basca if (ihs[j].getInstruction() instanceof INVOKESPECIAL) { 116*0c56280aSSorin Basca il.append(ihs[j], patch); // Should check: method name == "<init>" 117*0c56280aSSorin Basca break; 118*0c56280aSSorin Basca } 119*0c56280aSSorin Basca } 120*0c56280aSSorin Basca } else { 121*0c56280aSSorin Basca il.insert(ihs[0], patch); 122*0c56280aSSorin Basca } 123*0c56280aSSorin Basca 124*0c56280aSSorin Basca // Stack size must be at least 2, since the println method takes 2 argument. 125*0c56280aSSorin Basca if (code.getMaxStack() < 2) { 126*0c56280aSSorin Basca mg.setMaxStack(2); 127*0c56280aSSorin Basca } 128*0c56280aSSorin Basca 129*0c56280aSSorin Basca m = mg.getMethod(); 130*0c56280aSSorin Basca 131*0c56280aSSorin Basca il.dispose(); // Reuse instruction handles 132*0c56280aSSorin Basca 133*0c56280aSSorin Basca return m; 134*0c56280aSSorin Basca } 135*0c56280aSSorin Basca } 136