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