1 18 19 package alt.jiapi.instrumentor; 20 21 import java.lang.reflect.Method ; 22 import java.lang.reflect.Modifier ; 23 import java.util.HashMap ; 24 25 import org.apache.log4j.Category; 27 28 import alt.jiapi.Runtime; 29 import alt.jiapi.reflect.InstructionFactory; 30 import alt.jiapi.reflect.InstructionList; 31 import alt.jiapi.reflect.JiapiClass; 32 import alt.jiapi.reflect.JiapiField; 33 import alt.jiapi.reflect.JiapiMethod; 34 import alt.jiapi.reflect.JiapiRuntimeException; 35 import alt.jiapi.reflect.Loader; 36 import alt.jiapi.reflect.SignatureUtil; 37 38 57 public class MethodCallInstrumentor extends AbstractInstrumentor { 58 private static Category log = Category.getInstance(MethodCallInstrumentor.class); 59 60 protected Hook hook; 61 protected Class hookClass; 62 protected Method hookMethod; 63 protected boolean isDynamic; 64 65 private String jiapiFieldName; 66 67 { 69 jiapiFieldName = "__jiapi_field"; 72 } 73 74 78 protected InstrumentorChain preChain; 79 80 85 protected InstrumentorChain postChain; 86 87 92 public MethodCallInstrumentor() { 93 } 94 95 102 public MethodCallInstrumentor(Hook hook) { 103 setHook(hook); 104 } 105 106 115 public MethodCallInstrumentor(Class hookClass, 116 java.lang.reflect.Method hookMethod) { 117 this.hookClass = hookClass; 121 this.hookMethod = hookMethod; 122 this.isDynamic = !Modifier.isStatic(hookMethod.getModifiers()); 123 } 124 125 126 135 public void instrument(InstructionList il) { 136 log.info("Instrumenting " + getCurrentClass().getName() + "." + 137 il.getDeclaringMethod().getName()); 138 139 JiapiMethod jm = il.getDeclaringMethod(); 140 int modifiers = jm.getModifiers(); 142 if (Modifier.isNative(modifiers) || Modifier.isAbstract(modifiers)) { 143 log.info("skipping abstract or native method: " + 144 getCurrentClass().getName() + "." + jm.getName()); 145 146 forward(il); 147 return; 148 } 149 150 if (Modifier.isInterface(modifiers)) { 151 log.info("Will not instrument interface " + 152 getCurrentClass().getName()); 153 forward(il); 154 return; 155 } 156 157 164 165 patchInstructionList(il, getInstrumentation()); 166 167 forward(il); 168 } 169 170 171 174 private void patchInstructionList(InstructionList il, 175 Instrumentation instrumentation) { 176 InstructionFactory factory = il.getInstructionFactory(); 178 if (factory == null) { 179 throw new NullPointerException ("Got null factory"); 180 } 181 182 int currentMethodModifiers = il.getDeclaringMethod().getModifiers(); 183 184 JiapiClass clazz = getCurrentClass(); 185 Class [] hookParams = hookMethod.getParameterTypes(); 186 187 if (isDynamic) { 188 log.debug("Hook is dynamic"); 189 JiapiField field = null; 192 try { 193 field = clazz.getDeclaredField(jiapiFieldName); 194 } 195 catch (NoSuchFieldException nsfe) { 196 throw new JiapiRuntimeException("No such field: " + nsfe.getMessage()); 197 } 198 199 il.add(factory.getField(field)); 200 201 if (Modifier.isStatic(currentMethodModifiers)) { 202 il.add(factory.pushConstant(clazz.getName())); 203 } 204 else { 205 il.add(factory.pushThis()); } 207 } 208 else { 209 log.debug("Hook is static"); 210 il.add(factory.pushConstant(clazz.getName())); 215 } 216 217 for (int i = 1; i < hookParams.length; i++) { 219 if (hookParams[i].equals(String .class)) { 220 String targetName = instrumentation.getTargetName(); 222 if (targetName == null) { 223 targetName = "???"; 224 } 225 226 il.add(factory.pushConstant(targetName)); 227 } 228 else if (hookParams[i].equals(Object .class)) { 229 InstructionList targetCode = instrumentation.getTargetCode(); 231 if (targetCode != null) { 232 log.debug("Got target code: " + targetCode); 233 il.add(targetCode); 234 } 235 else { 236 log.debug("No target code"); 237 il.add(factory.pushNull()); 238 } 239 } 240 else if (hookParams[i].equals(Object [].class)) { 241 log.warn("target arguments are not supported"); 243 il.add(factory.pushNull()); 244 } 245 else { 246 log.error("Invalid Hook method: " + hookMethod); 247 } 248 } 249 250 Loader l = new Loader(); 251 try { 252 JiapiClass hClass = l.loadClass(hookClass.getName()); 253 Class [] hpTypes = hookMethod.getParameterTypes(); 254 String [] pTypes = new String [hpTypes.length]; 255 256 for (int i = 0; i < pTypes.length; i++) { 257 pTypes[i] = hpTypes[i].getName(); 258 } 259 260 JiapiMethod hMethod =hClass.getDeclaredMethod(hookMethod.getName(), 261 pTypes); 262 il.add(factory.invoke(hMethod)); 263 } 264 catch(Exception e) { 265 log.error("Failed to add invoke instruction: " + e); 266 } 267 } 268 269 private HashMap preInstrumentations = new HashMap (); 271 private HashMap postInstrumentations = new HashMap (); 272 273 281 public InstrumentorChain preInstrument() { 282 if (!isDynamic) { 283 log.info("Will not pre instrument for static calls"); 284 return null; 286 } 287 288 JiapiClass c = getCurrentClass(); 289 290 if (preInstrumentations.containsKey(c)) { 292 return null; 293 } 294 else { 295 preInstrumentations.put(c, null); 296 } 297 298 int modifiers = c.getModifiers(); 299 if (Modifier.isInterface(modifiers)) { 300 log.info("Will not pre instrument interface " + c.getName()); 301 return null; 302 } 303 304 preChain = new InstrumentorChain(); 305 306 preChain.add(new CreateFieldInstrumentor(Modifier.PUBLIC + 309 Modifier.STATIC, 310 hookClass.getName(), 311 jiapiFieldName)); 312 313 316 318 323 return preChain; 324 } 325 326 327 331 public InstrumentorChain postInstrument() { 332 if (!isDynamic) { 334 return null; 336 } 337 338 JiapiClass c = getCurrentClass(); 339 if (postInstrumentations.containsKey(c)) { 341 return null; 342 } 343 else { 344 postInstrumentations.put(c, null); 345 } 346 347 int modifiers = c.getModifiers(); 348 if (Modifier.isInterface(modifiers)) { 349 log.info("Will not post instrument interface " + c.getName()); 350 return null; 351 } 352 353 postChain = new InstrumentorChain(); 354 355 postChain.add(new CreateMethodInstrumentor(Modifier.STATIC, 359 "<clinit>")); 360 361 postChain.add(new HeadInstrumentor()); 362 363 postChain.add(new FieldAssignInstrumentor(jiapiFieldName, 366 hook.getInstance())); 367 368 return postChain; 369 } 370 371 372 376 public void setHook(Hook hook) { 377 this.hook = hook; 378 this.hookMethod = hook.getHookMethod(); 379 this.hookClass = hookMethod.getDeclaringClass(); 380 381 this.jiapiFieldName = hookClass.getName().replace('.', '_') + 382 "_" + hook.getInstance().hashCode(); 383 log.debug("Jiapi field name is '" + jiapiFieldName + "'"); 384 385 this.isDynamic = !Modifier.isStatic(hookMethod.getModifiers()); 386 } 387 388 392 public Hook getHook() { 393 return hook; 394 } 395 396 397 398 public String toString() { 399 return getClass().getName() + "#" + hook.getInstance().toString(); } 401 } 402 | Popular Tags |