@Test public void test() throws Throwable { Instrumentation instrumentation = ByteBuddyAgent.install(); TestHelper.appendSpyJar(instrumentation); ArthasBootstrap.getInstance(instrumentation, "ip=127.0.0.1"); AdviceListener listener = Mockito.mock(AdviceListener.class); EqualsMatcher<String> methodNameMatcher = new EqualsMatcher<String>("print"); EqualsMatcher<String> classNameMatcher = new EqualsMatcher<String>(MathGame.class.getName()); Enhancer enhancer = new Enhancer(listener, true, false, classNameMatcher, methodNameMatcher); ClassLoader inClassLoader = MathGame.class.getClassLoader(); String className = MathGame.class.getName(); Class<?> classBeingRedefined = MathGame.class; ClassNode classNode = AsmUtils.loadClass(MathGame.class); byte[] classfileBuffer = AsmUtils.toBytes(classNode); byte[] result = enhancer.transform(inClassLoader, className, classBeingRedefined, null, classfileBuffer); ClassNode resultClassNode1 = AsmUtils.toClassNode(result); result = enhancer.transform(inClassLoader, className, classBeingRedefined, null, result); ClassNode resultClassNode2 = AsmUtils.toClassNode(result); MethodNode resultMethodNode1 = AsmUtils.findMethods(resultClassNode1.methods, "print").get(0); MethodNode resultMethodNode2 = AsmUtils.findMethods(resultClassNode2.methods, "print").get(0); Assertions .assertThat(AsmUtils .findMethodInsnNode(resultMethodNode1, Type.getInternalName(SpyAPI.class), "atEnter").size()) .isEqualTo(AsmUtils.findMethodInsnNode(resultMethodNode2, Type.getInternalName(SpyAPI.class), "atEnter") .size()); Assertions.assertThat(AsmUtils .findMethodInsnNode(resultMethodNode1, Type.getInternalName(SpyAPI.class), "atExceptionExit").size()) .isEqualTo(AsmUtils .findMethodInsnNode(resultMethodNode2, Type.getInternalName(SpyAPI.class), "atExceptionExit") .size()); Assertions.assertThat(AsmUtils .findMethodInsnNode(resultMethodNode1, Type.getInternalName(SpyAPI.class), "atBeforeInvoke").size()) .isEqualTo(AsmUtils .findMethodInsnNode(resultMethodNode2, Type.getInternalName(SpyAPI.class), "atBeforeInvoke") .size()); Assertions.assertThat(AsmUtils .findMethodInsnNode(resultMethodNode1, Type.getInternalName(SpyAPI.class), "atInvokeException").size()) .isEqualTo(AsmUtils .findMethodInsnNode(resultMethodNode2, Type.getInternalName(SpyAPI.class), "atInvokeException") .size()); String string = Decompiler.decompile(result); System.err.println(string); }
@Override public byte[] transform(final ClassLoader inClassLoader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { try { try { if (inClassLoader != null) { inClassLoader.loadClass(SpyAPI.class.getName()); } } catch (Throwable e) { logger.error("the classloader can not load SpyAPI, ignore it. classloader: {}, className: {}", inClassLoader.getClass().getName(), className); return null; } if (matchingClasses != null && !matchingClasses.contains(classBeingRedefined)) { return null; } ClassNode classNode = new ClassNode(Opcodes.ASM9); ClassReader classReader = AsmUtils.toClassNode(classfileBuffer, classNode); classNode = AsmUtils.removeJSRInstructions(classNode); DefaultInterceptorClassParser defaultInterceptorClassParser = new DefaultInterceptorClassParser(); final List<InterceptorProcessor> interceptorProcessors = new ArrayList<InterceptorProcessor>(); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyInterceptor1.class)); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyInterceptor2.class)); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyInterceptor3.class)); if (this.isTracing) { if (this.skipJDKTrace == false) { interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceInterceptor1.class)); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceInterceptor2.class)); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceInterceptor3.class)); } else { interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceExcludeJDKInterceptor1.class)); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceExcludeJDKInterceptor2.class)); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceExcludeJDKInterceptor3.class)); } } List<MethodNode> matchedMethods = new ArrayList<MethodNode>(); for (MethodNode methodNode : classNode.methods) { if (!isIgnore(methodNode, methodNameMatcher)) { matchedMethods.add(methodNode); } } GroupLocationFilter groupLocationFilter = new GroupLocationFilter(); LocationFilter enterFilter = new InvokeContainLocationFilter(Type.getInternalName(SpyAPI.class), "atEnter", LocationType.ENTER); LocationFilter existFilter = new InvokeContainLocationFilter(Type.getInternalName(SpyAPI.class), "atExit", LocationType.EXIT); LocationFilter exceptionFilter = new InvokeContainLocationFilter(Type.getInternalName(SpyAPI.class), "atExceptionExit", LocationType.EXCEPTION_EXIT); groupLocationFilter.addFilter(enterFilter); groupLocationFilter.addFilter(existFilter); groupLocationFilter.addFilter(exceptionFilter); LocationFilter invokeBeforeFilter = new InvokeCheckLocationFilter(Type.getInternalName(SpyAPI.class), "atBeforeInvoke", LocationType.INVOKE); LocationFilter invokeAfterFilter = new InvokeCheckLocationFilter(Type.getInternalName(SpyAPI.class), "atInvokeException", LocationType.INVOKE_COMPLETED); LocationFilter invokeExceptionFilter = new InvokeCheckLocationFilter(Type.getInternalName(SpyAPI.class), "atInvokeException", LocationType.INVOKE_EXCEPTION_EXIT); groupLocationFilter.addFilter(invokeBeforeFilter); groupLocationFilter.addFilter(invokeAfterFilter); groupLocationFilter.addFilter(invokeExceptionFilter); for (MethodNode methodNode : matchedMethods) { if(AsmUtils.containsMethodInsnNode(methodNode, Type.getInternalName(SpyAPI.class), "atBeforeInvoke")) { for (AbstractInsnNode insnNode = methodNode.instructions.getFirst(); insnNode != null; insnNode = insnNode .getNext()) { if (insnNode instanceof MethodInsnNode) { final MethodInsnNode methodInsnNode = (MethodInsnNode) insnNode; if(this.skipJDKTrace) { if(methodInsnNode.owner.startsWith("java/")) { continue; } } if(AsmOpUtils.isBoxType(Type.getObjectType(methodInsnNode.owner))) { continue; } AdviceListenerManager.registerTraceAdviceListener(inClassLoader, className, methodInsnNode.owner, methodInsnNode.name, methodInsnNode.desc, listener); } } }else { MethodProcessor methodProcessor = new MethodProcessor(classNode, methodNode, groupLocationFilter); for (InterceptorProcessor interceptor : interceptorProcessors) { try { List<Location> locations = interceptor.process(methodProcessor); for (Location location : locations) { if (location instanceof MethodInsnNodeWare) { MethodInsnNodeWare methodInsnNodeWare = (MethodInsnNodeWare) location; MethodInsnNode methodInsnNode = methodInsnNodeWare.methodInsnNode(); AdviceListenerManager.registerTraceAdviceListener(inClassLoader, className, methodInsnNode.owner, methodInsnNode.name, methodInsnNode.desc, listener); } } } catch (Throwable e) { logger.error("enhancer error, class: {}, method: {}, interceptor: {}", classNode.name, methodNode.name, interceptor.getClass().getName(), e); } } } AdviceListenerManager.registerAdviceListener(inClassLoader, className, methodNode.name, methodNode.desc, listener); affect.addMethodAndCount(inClassLoader, className, methodNode.name, methodNode.desc); } if (AsmUtils.getMajorVersion(classNode.version) < 49) { classNode.version = AsmUtils.setMajorVersion(classNode.version, 49); } byte[] enhanceClassByteArray = AsmUtils.toBytes(classNode, inClassLoader, classReader); classBytesCache.put(classBeingRedefined, new Object()); dumpClassIfNecessary(className, enhanceClassByteArray, affect); affect.cCnt(1); return enhanceClassByteArray; } catch (Throwable t) { logger.warn("transform loader[{}]:class[{}] failed.", inClassLoader, className, t); affect.setThrowable(t); } return null; }
Enhancer implements ClassFileTransformer { @Override public byte[] transform(final ClassLoader inClassLoader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { try { try { if (inClassLoader != null) { inClassLoader.loadClass(SpyAPI.class.getName()); } } catch (Throwable e) { logger.error("the classloader can not load SpyAPI, ignore it. classloader: {}, className: {}", inClassLoader.getClass().getName(), className); return null; } if (matchingClasses != null && !matchingClasses.contains(classBeingRedefined)) { return null; } ClassNode classNode = new ClassNode(Opcodes.ASM9); ClassReader classReader = AsmUtils.toClassNode(classfileBuffer, classNode); classNode = AsmUtils.removeJSRInstructions(classNode); DefaultInterceptorClassParser defaultInterceptorClassParser = new DefaultInterceptorClassParser(); final List<InterceptorProcessor> interceptorProcessors = new ArrayList<InterceptorProcessor>(); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyInterceptor1.class)); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyInterceptor2.class)); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyInterceptor3.class)); if (this.isTracing) { if (this.skipJDKTrace == false) { interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceInterceptor1.class)); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceInterceptor2.class)); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceInterceptor3.class)); } else { interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceExcludeJDKInterceptor1.class)); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceExcludeJDKInterceptor2.class)); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceExcludeJDKInterceptor3.class)); } } List<MethodNode> matchedMethods = new ArrayList<MethodNode>(); for (MethodNode methodNode : classNode.methods) { if (!isIgnore(methodNode, methodNameMatcher)) { matchedMethods.add(methodNode); } } GroupLocationFilter groupLocationFilter = new GroupLocationFilter(); LocationFilter enterFilter = new InvokeContainLocationFilter(Type.getInternalName(SpyAPI.class), "atEnter", LocationType.ENTER); LocationFilter existFilter = new InvokeContainLocationFilter(Type.getInternalName(SpyAPI.class), "atExit", LocationType.EXIT); LocationFilter exceptionFilter = new InvokeContainLocationFilter(Type.getInternalName(SpyAPI.class), "atExceptionExit", LocationType.EXCEPTION_EXIT); groupLocationFilter.addFilter(enterFilter); groupLocationFilter.addFilter(existFilter); groupLocationFilter.addFilter(exceptionFilter); LocationFilter invokeBeforeFilter = new InvokeCheckLocationFilter(Type.getInternalName(SpyAPI.class), "atBeforeInvoke", LocationType.INVOKE); LocationFilter invokeAfterFilter = new InvokeCheckLocationFilter(Type.getInternalName(SpyAPI.class), "atInvokeException", LocationType.INVOKE_COMPLETED); LocationFilter invokeExceptionFilter = new InvokeCheckLocationFilter(Type.getInternalName(SpyAPI.class), "atInvokeException", LocationType.INVOKE_EXCEPTION_EXIT); groupLocationFilter.addFilter(invokeBeforeFilter); groupLocationFilter.addFilter(invokeAfterFilter); groupLocationFilter.addFilter(invokeExceptionFilter); for (MethodNode methodNode : matchedMethods) { if(AsmUtils.containsMethodInsnNode(methodNode, Type.getInternalName(SpyAPI.class), "atBeforeInvoke")) { for (AbstractInsnNode insnNode = methodNode.instructions.getFirst(); insnNode != null; insnNode = insnNode .getNext()) { if (insnNode instanceof MethodInsnNode) { final MethodInsnNode methodInsnNode = (MethodInsnNode) insnNode; if(this.skipJDKTrace) { if(methodInsnNode.owner.startsWith("java/")) { continue; } } if(AsmOpUtils.isBoxType(Type.getObjectType(methodInsnNode.owner))) { continue; } AdviceListenerManager.registerTraceAdviceListener(inClassLoader, className, methodInsnNode.owner, methodInsnNode.name, methodInsnNode.desc, listener); } } }else { MethodProcessor methodProcessor = new MethodProcessor(classNode, methodNode, groupLocationFilter); for (InterceptorProcessor interceptor : interceptorProcessors) { try { List<Location> locations = interceptor.process(methodProcessor); for (Location location : locations) { if (location instanceof MethodInsnNodeWare) { MethodInsnNodeWare methodInsnNodeWare = (MethodInsnNodeWare) location; MethodInsnNode methodInsnNode = methodInsnNodeWare.methodInsnNode(); AdviceListenerManager.registerTraceAdviceListener(inClassLoader, className, methodInsnNode.owner, methodInsnNode.name, methodInsnNode.desc, listener); } } } catch (Throwable e) { logger.error("enhancer error, class: {}, method: {}, interceptor: {}", classNode.name, methodNode.name, interceptor.getClass().getName(), e); } } } AdviceListenerManager.registerAdviceListener(inClassLoader, className, methodNode.name, methodNode.desc, listener); affect.addMethodAndCount(inClassLoader, className, methodNode.name, methodNode.desc); } if (AsmUtils.getMajorVersion(classNode.version) < 49) { classNode.version = AsmUtils.setMajorVersion(classNode.version, 49); } byte[] enhanceClassByteArray = AsmUtils.toBytes(classNode, inClassLoader, classReader); classBytesCache.put(classBeingRedefined, new Object()); dumpClassIfNecessary(className, enhanceClassByteArray, affect); affect.cCnt(1); return enhanceClassByteArray; } catch (Throwable t) { logger.warn("transform loader[{}]:class[{}] failed.", inClassLoader, className, t); affect.setThrowable(t); } return null; } }
Enhancer implements ClassFileTransformer { @Override public byte[] transform(final ClassLoader inClassLoader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { try { try { if (inClassLoader != null) { inClassLoader.loadClass(SpyAPI.class.getName()); } } catch (Throwable e) { logger.error("the classloader can not load SpyAPI, ignore it. classloader: {}, className: {}", inClassLoader.getClass().getName(), className); return null; } if (matchingClasses != null && !matchingClasses.contains(classBeingRedefined)) { return null; } ClassNode classNode = new ClassNode(Opcodes.ASM9); ClassReader classReader = AsmUtils.toClassNode(classfileBuffer, classNode); classNode = AsmUtils.removeJSRInstructions(classNode); DefaultInterceptorClassParser defaultInterceptorClassParser = new DefaultInterceptorClassParser(); final List<InterceptorProcessor> interceptorProcessors = new ArrayList<InterceptorProcessor>(); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyInterceptor1.class)); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyInterceptor2.class)); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyInterceptor3.class)); if (this.isTracing) { if (this.skipJDKTrace == false) { interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceInterceptor1.class)); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceInterceptor2.class)); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceInterceptor3.class)); } else { interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceExcludeJDKInterceptor1.class)); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceExcludeJDKInterceptor2.class)); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceExcludeJDKInterceptor3.class)); } } List<MethodNode> matchedMethods = new ArrayList<MethodNode>(); for (MethodNode methodNode : classNode.methods) { if (!isIgnore(methodNode, methodNameMatcher)) { matchedMethods.add(methodNode); } } GroupLocationFilter groupLocationFilter = new GroupLocationFilter(); LocationFilter enterFilter = new InvokeContainLocationFilter(Type.getInternalName(SpyAPI.class), "atEnter", LocationType.ENTER); LocationFilter existFilter = new InvokeContainLocationFilter(Type.getInternalName(SpyAPI.class), "atExit", LocationType.EXIT); LocationFilter exceptionFilter = new InvokeContainLocationFilter(Type.getInternalName(SpyAPI.class), "atExceptionExit", LocationType.EXCEPTION_EXIT); groupLocationFilter.addFilter(enterFilter); groupLocationFilter.addFilter(existFilter); groupLocationFilter.addFilter(exceptionFilter); LocationFilter invokeBeforeFilter = new InvokeCheckLocationFilter(Type.getInternalName(SpyAPI.class), "atBeforeInvoke", LocationType.INVOKE); LocationFilter invokeAfterFilter = new InvokeCheckLocationFilter(Type.getInternalName(SpyAPI.class), "atInvokeException", LocationType.INVOKE_COMPLETED); LocationFilter invokeExceptionFilter = new InvokeCheckLocationFilter(Type.getInternalName(SpyAPI.class), "atInvokeException", LocationType.INVOKE_EXCEPTION_EXIT); groupLocationFilter.addFilter(invokeBeforeFilter); groupLocationFilter.addFilter(invokeAfterFilter); groupLocationFilter.addFilter(invokeExceptionFilter); for (MethodNode methodNode : matchedMethods) { if(AsmUtils.containsMethodInsnNode(methodNode, Type.getInternalName(SpyAPI.class), "atBeforeInvoke")) { for (AbstractInsnNode insnNode = methodNode.instructions.getFirst(); insnNode != null; insnNode = insnNode .getNext()) { if (insnNode instanceof MethodInsnNode) { final MethodInsnNode methodInsnNode = (MethodInsnNode) insnNode; if(this.skipJDKTrace) { if(methodInsnNode.owner.startsWith("java/")) { continue; } } if(AsmOpUtils.isBoxType(Type.getObjectType(methodInsnNode.owner))) { continue; } AdviceListenerManager.registerTraceAdviceListener(inClassLoader, className, methodInsnNode.owner, methodInsnNode.name, methodInsnNode.desc, listener); } } }else { MethodProcessor methodProcessor = new MethodProcessor(classNode, methodNode, groupLocationFilter); for (InterceptorProcessor interceptor : interceptorProcessors) { try { List<Location> locations = interceptor.process(methodProcessor); for (Location location : locations) { if (location instanceof MethodInsnNodeWare) { MethodInsnNodeWare methodInsnNodeWare = (MethodInsnNodeWare) location; MethodInsnNode methodInsnNode = methodInsnNodeWare.methodInsnNode(); AdviceListenerManager.registerTraceAdviceListener(inClassLoader, className, methodInsnNode.owner, methodInsnNode.name, methodInsnNode.desc, listener); } } } catch (Throwable e) { logger.error("enhancer error, class: {}, method: {}, interceptor: {}", classNode.name, methodNode.name, interceptor.getClass().getName(), e); } } } AdviceListenerManager.registerAdviceListener(inClassLoader, className, methodNode.name, methodNode.desc, listener); affect.addMethodAndCount(inClassLoader, className, methodNode.name, methodNode.desc); } if (AsmUtils.getMajorVersion(classNode.version) < 49) { classNode.version = AsmUtils.setMajorVersion(classNode.version, 49); } byte[] enhanceClassByteArray = AsmUtils.toBytes(classNode, inClassLoader, classReader); classBytesCache.put(classBeingRedefined, new Object()); dumpClassIfNecessary(className, enhanceClassByteArray, affect); affect.cCnt(1); return enhanceClassByteArray; } catch (Throwable t) { logger.warn("transform loader[{}]:class[{}] failed.", inClassLoader, className, t); affect.setThrowable(t); } return null; } Enhancer(AdviceListener listener, boolean isTracing, boolean skipJDKTrace, Matcher classNameMatcher,
            Matcher methodNameMatcher); }
Enhancer implements ClassFileTransformer { @Override public byte[] transform(final ClassLoader inClassLoader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { try { try { if (inClassLoader != null) { inClassLoader.loadClass(SpyAPI.class.getName()); } } catch (Throwable e) { logger.error("the classloader can not load SpyAPI, ignore it. classloader: {}, className: {}", inClassLoader.getClass().getName(), className); return null; } if (matchingClasses != null && !matchingClasses.contains(classBeingRedefined)) { return null; } ClassNode classNode = new ClassNode(Opcodes.ASM9); ClassReader classReader = AsmUtils.toClassNode(classfileBuffer, classNode); classNode = AsmUtils.removeJSRInstructions(classNode); DefaultInterceptorClassParser defaultInterceptorClassParser = new DefaultInterceptorClassParser(); final List<InterceptorProcessor> interceptorProcessors = new ArrayList<InterceptorProcessor>(); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyInterceptor1.class)); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyInterceptor2.class)); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyInterceptor3.class)); if (this.isTracing) { if (this.skipJDKTrace == false) { interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceInterceptor1.class)); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceInterceptor2.class)); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceInterceptor3.class)); } else { interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceExcludeJDKInterceptor1.class)); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceExcludeJDKInterceptor2.class)); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceExcludeJDKInterceptor3.class)); } } List<MethodNode> matchedMethods = new ArrayList<MethodNode>(); for (MethodNode methodNode : classNode.methods) { if (!isIgnore(methodNode, methodNameMatcher)) { matchedMethods.add(methodNode); } } GroupLocationFilter groupLocationFilter = new GroupLocationFilter(); LocationFilter enterFilter = new InvokeContainLocationFilter(Type.getInternalName(SpyAPI.class), "atEnter", LocationType.ENTER); LocationFilter existFilter = new InvokeContainLocationFilter(Type.getInternalName(SpyAPI.class), "atExit", LocationType.EXIT); LocationFilter exceptionFilter = new InvokeContainLocationFilter(Type.getInternalName(SpyAPI.class), "atExceptionExit", LocationType.EXCEPTION_EXIT); groupLocationFilter.addFilter(enterFilter); groupLocationFilter.addFilter(existFilter); groupLocationFilter.addFilter(exceptionFilter); LocationFilter invokeBeforeFilter = new InvokeCheckLocationFilter(Type.getInternalName(SpyAPI.class), "atBeforeInvoke", LocationType.INVOKE); LocationFilter invokeAfterFilter = new InvokeCheckLocationFilter(Type.getInternalName(SpyAPI.class), "atInvokeException", LocationType.INVOKE_COMPLETED); LocationFilter invokeExceptionFilter = new InvokeCheckLocationFilter(Type.getInternalName(SpyAPI.class), "atInvokeException", LocationType.INVOKE_EXCEPTION_EXIT); groupLocationFilter.addFilter(invokeBeforeFilter); groupLocationFilter.addFilter(invokeAfterFilter); groupLocationFilter.addFilter(invokeExceptionFilter); for (MethodNode methodNode : matchedMethods) { if(AsmUtils.containsMethodInsnNode(methodNode, Type.getInternalName(SpyAPI.class), "atBeforeInvoke")) { for (AbstractInsnNode insnNode = methodNode.instructions.getFirst(); insnNode != null; insnNode = insnNode .getNext()) { if (insnNode instanceof MethodInsnNode) { final MethodInsnNode methodInsnNode = (MethodInsnNode) insnNode; if(this.skipJDKTrace) { if(methodInsnNode.owner.startsWith("java/")) { continue; } } if(AsmOpUtils.isBoxType(Type.getObjectType(methodInsnNode.owner))) { continue; } AdviceListenerManager.registerTraceAdviceListener(inClassLoader, className, methodInsnNode.owner, methodInsnNode.name, methodInsnNode.desc, listener); } } }else { MethodProcessor methodProcessor = new MethodProcessor(classNode, methodNode, groupLocationFilter); for (InterceptorProcessor interceptor : interceptorProcessors) { try { List<Location> locations = interceptor.process(methodProcessor); for (Location location : locations) { if (location instanceof MethodInsnNodeWare) { MethodInsnNodeWare methodInsnNodeWare = (MethodInsnNodeWare) location; MethodInsnNode methodInsnNode = methodInsnNodeWare.methodInsnNode(); AdviceListenerManager.registerTraceAdviceListener(inClassLoader, className, methodInsnNode.owner, methodInsnNode.name, methodInsnNode.desc, listener); } } } catch (Throwable e) { logger.error("enhancer error, class: {}, method: {}, interceptor: {}", classNode.name, methodNode.name, interceptor.getClass().getName(), e); } } } AdviceListenerManager.registerAdviceListener(inClassLoader, className, methodNode.name, methodNode.desc, listener); affect.addMethodAndCount(inClassLoader, className, methodNode.name, methodNode.desc); } if (AsmUtils.getMajorVersion(classNode.version) < 49) { classNode.version = AsmUtils.setMajorVersion(classNode.version, 49); } byte[] enhanceClassByteArray = AsmUtils.toBytes(classNode, inClassLoader, classReader); classBytesCache.put(classBeingRedefined, new Object()); dumpClassIfNecessary(className, enhanceClassByteArray, affect); affect.cCnt(1); return enhanceClassByteArray; } catch (Throwable t) { logger.warn("transform loader[{}]:class[{}] failed.", inClassLoader, className, t); affect.setThrowable(t); } return null; } Enhancer(AdviceListener listener, boolean isTracing, boolean skipJDKTrace, Matcher classNameMatcher,
            Matcher methodNameMatcher); @Override byte[] transform(final ClassLoader inClassLoader, String className, Class<?> classBeingRedefined,
            ProtectionDomain protectionDomain, byte[] classfileBuffer); synchronized EnhancerAffect enhance(final Instrumentation inst); static synchronized EnhancerAffect reset(final Instrumentation inst, final Matcher classNameMatcher); }
Enhancer implements ClassFileTransformer { @Override public byte[] transform(final ClassLoader inClassLoader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { try { try { if (inClassLoader != null) { inClassLoader.loadClass(SpyAPI.class.getName()); } } catch (Throwable e) { logger.error("the classloader can not load SpyAPI, ignore it. classloader: {}, className: {}", inClassLoader.getClass().getName(), className); return null; } if (matchingClasses != null && !matchingClasses.contains(classBeingRedefined)) { return null; } ClassNode classNode = new ClassNode(Opcodes.ASM9); ClassReader classReader = AsmUtils.toClassNode(classfileBuffer, classNode); classNode = AsmUtils.removeJSRInstructions(classNode); DefaultInterceptorClassParser defaultInterceptorClassParser = new DefaultInterceptorClassParser(); final List<InterceptorProcessor> interceptorProcessors = new ArrayList<InterceptorProcessor>(); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyInterceptor1.class)); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyInterceptor2.class)); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyInterceptor3.class)); if (this.isTracing) { if (this.skipJDKTrace == false) { interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceInterceptor1.class)); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceInterceptor2.class)); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceInterceptor3.class)); } else { interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceExcludeJDKInterceptor1.class)); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceExcludeJDKInterceptor2.class)); interceptorProcessors.addAll(defaultInterceptorClassParser.parse(SpyTraceExcludeJDKInterceptor3.class)); } } List<MethodNode> matchedMethods = new ArrayList<MethodNode>(); for (MethodNode methodNode : classNode.methods) { if (!isIgnore(methodNode, methodNameMatcher)) { matchedMethods.add(methodNode); } } GroupLocationFilter groupLocationFilter = new GroupLocationFilter(); LocationFilter enterFilter = new InvokeContainLocationFilter(Type.getInternalName(SpyAPI.class), "atEnter", LocationType.ENTER); LocationFilter existFilter = new InvokeContainLocationFilter(Type.getInternalName(SpyAPI.class), "atExit", LocationType.EXIT); LocationFilter exceptionFilter = new InvokeContainLocationFilter(Type.getInternalName(SpyAPI.class), "atExceptionExit", LocationType.EXCEPTION_EXIT); groupLocationFilter.addFilter(enterFilter); groupLocationFilter.addFilter(existFilter); groupLocationFilter.addFilter(exceptionFilter); LocationFilter invokeBeforeFilter = new InvokeCheckLocationFilter(Type.getInternalName(SpyAPI.class), "atBeforeInvoke", LocationType.INVOKE); LocationFilter invokeAfterFilter = new InvokeCheckLocationFilter(Type.getInternalName(SpyAPI.class), "atInvokeException", LocationType.INVOKE_COMPLETED); LocationFilter invokeExceptionFilter = new InvokeCheckLocationFilter(Type.getInternalName(SpyAPI.class), "atInvokeException", LocationType.INVOKE_EXCEPTION_EXIT); groupLocationFilter.addFilter(invokeBeforeFilter); groupLocationFilter.addFilter(invokeAfterFilter); groupLocationFilter.addFilter(invokeExceptionFilter); for (MethodNode methodNode : matchedMethods) { if(AsmUtils.containsMethodInsnNode(methodNode, Type.getInternalName(SpyAPI.class), "atBeforeInvoke")) { for (AbstractInsnNode insnNode = methodNode.instructions.getFirst(); insnNode != null; insnNode = insnNode .getNext()) { if (insnNode instanceof MethodInsnNode) { final MethodInsnNode methodInsnNode = (MethodInsnNode) insnNode; if(this.skipJDKTrace) { if(methodInsnNode.owner.startsWith("java/")) { continue; } } if(AsmOpUtils.isBoxType(Type.getObjectType(methodInsnNode.owner))) { continue; } AdviceListenerManager.registerTraceAdviceListener(inClassLoader, className, methodInsnNode.owner, methodInsnNode.name, methodInsnNode.desc, listener); } } }else { MethodProcessor methodProcessor = new MethodProcessor(classNode, methodNode, groupLocationFilter); for (InterceptorProcessor interceptor : interceptorProcessors) { try { List<Location> locations = interceptor.process(methodProcessor); for (Location location : locations) { if (location instanceof MethodInsnNodeWare) { MethodInsnNodeWare methodInsnNodeWare = (MethodInsnNodeWare) location; MethodInsnNode methodInsnNode = methodInsnNodeWare.methodInsnNode(); AdviceListenerManager.registerTraceAdviceListener(inClassLoader, className, methodInsnNode.owner, methodInsnNode.name, methodInsnNode.desc, listener); } } } catch (Throwable e) { logger.error("enhancer error, class: {}, method: {}, interceptor: {}", classNode.name, methodNode.name, interceptor.getClass().getName(), e); } } } AdviceListenerManager.registerAdviceListener(inClassLoader, className, methodNode.name, methodNode.desc, listener); affect.addMethodAndCount(inClassLoader, className, methodNode.name, methodNode.desc); } if (AsmUtils.getMajorVersion(classNode.version) < 49) { classNode.version = AsmUtils.setMajorVersion(classNode.version, 49); } byte[] enhanceClassByteArray = AsmUtils.toBytes(classNode, inClassLoader, classReader); classBytesCache.put(classBeingRedefined, new Object()); dumpClassIfNecessary(className, enhanceClassByteArray, affect); affect.cCnt(1); return enhanceClassByteArray; } catch (Throwable t) { logger.warn("transform loader[{}]:class[{}] failed.", inClassLoader, className, t); affect.setThrowable(t); } return null; } Enhancer(AdviceListener listener, boolean isTracing, boolean skipJDKTrace, Matcher classNameMatcher,
            Matcher methodNameMatcher); @Override byte[] transform(final ClassLoader inClassLoader, String className, Class<?> classBeingRedefined,
            ProtectionDomain protectionDomain, byte[] classfileBuffer); synchronized EnhancerAffect enhance(final Instrumentation inst); static synchronized EnhancerAffect reset(final Instrumentation inst, final Matcher classNameMatcher);  }