View Javadoc

1   /*
2    *
3    */
4   package org.softevo.jdynpur.runtime;
5   
6   import java.io.ByteArrayOutputStream;
7   import java.io.File;
8   import java.io.IOException;
9   import java.io.InputStream;
10  import java.lang.instrument.ClassDefinition;
11  import java.lang.instrument.ClassFileTransformer;
12  import java.lang.instrument.IllegalClassFormatException;
13  import java.lang.instrument.Instrumentation;
14  import java.lang.jdynpur.Tracer;
15  import java.security.ProtectionDomain;
16  import java.util.Vector;
17  
18  import org.objectweb.asm.ClassReader;
19  import org.objectweb.asm.ClassWriter;
20  import org.softevo.util.ObjectIdMapper;
21  import org.softevo.util.asm.FieldIdentifier;
22  import org.softevo.util.asm.MethodIdentifierMapGenerator;
23  
24  public class OnTheFlyInstrumenter implements ClassFileTransformer {
25  
26  
27  	private static OnTheFlyInstrumenter singletonInstance = null;
28  
29  	private ObjectIdMapper<FieldIdentifier> fieldIdentiferMap;
30  	
31  	private MethodIdentifierMapGenerator identifierMapGenerator = null;
32  
33  	private String suffix = "";
34  
35  	private boolean isShuttingDown = false;
36  
37  //	private static final boolean useOnTheFlyCalculation = false;
38  	
39  	public static String TRACECLASSNAME = "java/lang/jdynpur/Tracer";
40  
41  
42  	public static OnTheFlyInstrumenter getInstance() {
43  		return singletonInstance;
44  	}
45  
46  	private OnTheFlyInstrumenter() {
47  		identifierMapGenerator = new MethodIdentifierMapGenerator();
48  		fieldIdentiferMap = new ObjectIdMapper<FieldIdentifier>();
49  		readSuffix();
50  	}
51  
52  	public static void premain(String agentArgs, Instrumentation inst) {
53  		singletonInstance = new OnTheFlyInstrumenter();
54  		Tracer.methodIdentifierMap = singletonInstance.identifierMapGenerator;
55  		Tracer.fieldIdentfierMap = singletonInstance.fieldIdentiferMap;
56  //		if (useOnTheFlyCalculation) {
57  //			System.out.println("Initializing on the fly calculator");
58  //			OnTheFlyAnalyser.init(singletonInstance.identifierMapGenerator);
59  //		}
60  		inst.addTransformer(getInstance());
61  //		redefineClasses(inst);
62  	}
63  
64  	public static void redefineClasses(Instrumentation inst) {
65  		Class[] loadedClasses;
66  		ClassDefinition classDefinition;
67  		byte[] classBytes, transformedBytes;
68  		Vector<ClassDefinition> redefinitions;
69  
70  		/*System.out.println("Loaded classes:");
71  		loadedClasses = inst.getAllLoadedClasses();
72  		for (int counter = 0; counter < loadedClasses.length; counter++) {
73  			System.out.println(loadedClasses[counter].getName());
74  		}
75  		System.out.println("End of loaded classes list. Exiting.");
76  		System.exit(0);*/
77  		loadedClasses = inst.getAllLoadedClasses();
78  		redefinitions = new Vector<ClassDefinition>();
79  		for (int counter = 0; counter < loadedClasses.length; counter++) {
80  			if (loadedClasses[counter].getName().startsWith("java.util")) {
81  				classBytes = loadClass(loadedClasses[counter].getName());
82  				transformedBytes = singletonInstance.transform(loadedClasses[counter].getName(), classBytes);
83  				classDefinition = new ClassDefinition(loadedClasses[counter], transformedBytes);
84  				redefinitions.add(classDefinition);
85  			}
86  		}
87  		try {
88  			System.out.println("Redefining classes");
89  			System.out.println("Redefine supported " + inst.isRedefineClassesSupported());
90  			inst.redefineClasses(redefinitions.toArray(new ClassDefinition[redefinitions.size()]));
91  			System.out.println("Redefine finished successfully.");
92  		} catch (Exception redefineException) {
93  			System.out.println(redefineException);
94  			redefineException.printStackTrace();
95  		}
96  	}
97  
98  	private static byte[] loadClass(String className) {
99  		InputStream inputStream;
100 		ByteArrayOutputStream byteBuffer;
101 
102 		try {
103 			inputStream = OnTheFlyInstrumenter.class.getClassLoader().getResourceAsStream(className.replace('.', '/').concat(".class"));
104 			byteBuffer = new ByteArrayOutputStream();
105 			while (inputStream.available() > 0) {
106 				byteBuffer.write(inputStream.read());
107 			}
108 			return byteBuffer.toByteArray();
109 		} catch (Exception loadException) {
110 			System.out.println(loadException);
111 			loadException.printStackTrace(System.out);
112 		}
113 		return null;
114 	}
115 
116 	private byte[] transform(String className, byte[] classBytes ) {
117 		ClassReader classReader;
118 		ClassWriter classWriter;
119 		InstrumentingClassFileTransformer transformer;
120 		byte[] bytes;
121 
122 		try {
123 			classReader = new ClassReader(classBytes);
124 			classWriter = new ClassWriter(true);
125 			boolean traceParameterMutability = System.getProperty("jdynpur.traceparametermutability", "false").equalsIgnoreCase("true");
126 			transformer = new InstrumentingClassFileTransformer(classWriter, className, identifierMapGenerator, fieldIdentiferMap, traceParameterMutability);
127 			classReader.accept(transformer, false);
128 			bytes = classWriter.toByteArray();
129 			/*if (className.equals("org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding") || className.equals("sun/awt/X11/XToolkit")) {
130 				classReader = new ClassReader(bytes);
131 				System.out.println(className);
132 				classReader.accept(new TraceClassVisitor(new PrintWriter(System.out)), false);
133 				System.out.println("Uninstrumented:");
134 				classReader = new ClassReader(classBytes);
135 				classReader.accept(new TraceClassVisitor(new PrintWriter(System.out)), false);
136 			}*/
137 			// System.out.println("Successfully instrumented " + className);
138 			return bytes;
139 		} catch (Throwable instrumentationError) {
140 			System.out.println("An error occured instrumenting class " + className);
141 			instrumentationError.printStackTrace();
142 		}
143 		return classBytes;
144 	}
145 
146 	public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
147 	                        ProtectionDomain protectionDomain, byte[] classBytes) throws IllegalClassFormatException {
148 
149 		if (!isForbiddenClass(className) && !isShuttingDown) {
150 //			System.out.println("Transforming class " + className);
151 			return transform(className, classBytes);
152 		} else {
153 //			System.out.println("Skipping class " + className);
154 			return classBytes;
155 		}
156 	}
157 
158 	private static boolean isForbiddenClass(String className) {
159 //		if (useOnTheFlyCalculation) {
160 //			return isOnTheFlyCalculationForbiddenClass(className);
161 //		} else {
162 			if (className != null) {
163 				return className.startsWith("java/lang/") || className.startsWith("sun/awt/X11") || 
164 				className.startsWith("org/softevo") ||
165 //				className.startsWith("java/util/TreeMap") || className.startsWith("java/util/logging") ||
166 				className.startsWith("java/io");
167 			} else {
168 				return true;
169 			}
170 //		}
171 	}
172 
173 	/*private static boolean isOnTheFlyCalculationForbiddenClass(String className) {
174 		if (className != null) {
175 			return className.startsWith("java/lang/") || className.startsWith("sun/awt/X11") || 
176 			className.startsWith("org/softevo") || className.startsWith("java/security") ||
177 			className.startsWith("java/io") || className.startsWith("java/util/AbstractList$ListItr") ||
178 			className.startsWith("java/util/Arrays") || className.startsWith("java/util/concurrent") ||
179 			className.startsWith("java/util/HashMap") || className.startsWith("java/util/LinkedHashMap") ||
180 			className.startsWith("java/util/ListIterator") || className.startsWith("java/util/Properties") ||
181 			className.startsWith("java/util/regex/") || className.startsWith("sun/security") ||
182 			className.startsWith("sun/misc/FloatingDecimal") || className.startsWith("sun/reflect");
183 		} else {
184 			return true;
185 		}
186 	}*/
187 	
188 	private void readSuffix() {
189 		File[] children;
190 		String suffixFileName;
191 
192 		children = new File("./").listFiles();
193 		for (int counter = 0; counter < children.length; counter++) {
194 			if (children[counter].getName().startsWith("suffix_")) {
195 				suffixFileName = children[counter].getName();
196 				suffix = suffixFileName.substring(7, suffixFileName.length());
197 			}
198 		}
199 	}
200 
201 }