xref: /aosp_15_r20/external/apache-commons-bcel/src/examples/helloify.java (revision 0c56280ab0842982c46a149f7b9eaa497e31e292)
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