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
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
57
58
59
60 inst.addTransformer(getInstance());
61
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
71
72
73
74
75
76
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
130
131
132
133
134
135
136
137
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
151 return transform(className, classBytes);
152 } else {
153
154 return classBytes;
155 }
156 }
157
158 private static boolean isForbiddenClass(String className) {
159
160
161
162 if (className != null) {
163 return className.startsWith("java/lang/") || className.startsWith("sun/awt/X11") ||
164 className.startsWith("org/softevo") ||
165
166 className.startsWith("java/io");
167 } else {
168 return true;
169 }
170
171 }
172
173
174
175
176
177
178
179
180
181
182
183
184
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 }