/** * 初始化类字节码的转换器 * * @param inst 用于管理字节码转换器 */ private static void initTransformer(Instrumentation inst) throws UnmodifiableClassException { LinkedList<Class> retransformClasses = new LinkedList<Class>(); CustomClassTransformer customClassTransformer = new CustomClassTransformer(); inst.addTransformer(customClassTransformer, true); Class[] loadedClasses = inst.getAllLoadedClasses(); for (Class clazz : loadedClasses) { for (final AbstractClassHook hook : customClassTransformer.getHooks()) { if (hook.isClassMatched(clazz.getName().replace(".", "/"))) { if (inst.isModifiableClass(clazz) && !clazz.getName().startsWith("java.lang.invoke.LambdaForm")) { retransformClasses.add(clazz); } } } } // hook已经加载的类 Class[] classes = new Class[retransformClasses.size()]; retransformClasses.toArray(classes); if (classes.length > 0) { inst.retransformClasses(classes); } }
public static void premain(String args, Instrumentation instrumentation) { if (!instrumentation.isRetransformClassesSupported()) { System.out.println("Class retransformation is not supported."); return; } System.out.println("Calling lambda to ensure that lambda forms were created"); Agent.lambda.run(); System.out.println("Registering class file transformer"); instrumentation.addTransformer(new Agent()); for (Class c : instrumentation.getAllLoadedClasses()) { if (c.getName().contains("LambdaForm") && instrumentation.isModifiableClass(c)) { System.out.format("We've found a modifiable lambda form: %s%n", c.getName()); try { instrumentation.retransformClasses(c); } catch (UnmodifiableClassException e) { throw new AssertionError("Modification of modifiable class " + "caused UnmodifiableClassException", e); } } } }
@Test public void testBadModification2() throws ClassNotFoundException, AgentLoadException, AgentInitializationException, IOException, AttachNotSupportedException, UnmodifiableClassException, IllegalConnectorArgumentsException { // Rewrite method DynamicModification badModification = new DynamicModification() { public Collection<String> affects() { return Lists.newArrayList(TestJDWPAgentDebug.class.getName()); } public void apply(ClassPool arg0) throws NotFoundException, CannotCompileException { CtClass cls = arg0.getCtClass(TestJDWPAgentDebug.class.getName()); cls.getMethods()[0].insertBefore("definitely not code..."); } }; JDWPAgent dynamic = JDWPAgent.get(); // Modification should just be ignored since it throws a notfoundexception try { dynamic.install(badModification); fail(); } catch (CannotCompileException e) { } }
@Test public void testBadModification2() throws ClassNotFoundException, AgentLoadException, AgentInitializationException, IOException, AttachNotSupportedException, UnmodifiableClassException { // Rewrite method DynamicModification badModification = new DynamicModification() { public Collection<String> affects() { return Lists.newArrayList(TestJVMAgent.class.getName()); } public void apply(ClassPool arg0) throws NotFoundException, CannotCompileException { CtClass cls = arg0.getCtClass(TestJVMAgent.class.getName()); cls.getMethods()[0].insertBefore("definitely not code..."); } }; JVMAgent dynamic = JVMAgent.get(); // Modification should just be ignored since it throws a notfoundexception try { dynamic.install(badModification); fail(); } catch (CannotCompileException e) { } }
@Test public void testBadTracepoint() throws ClassNotFoundException, UnmodifiableClassException, CannotCompileException { // Create and register dummy advice PTAgentForTest test = new PTAgentForTest(); AdviceImplForTest advice = new AdviceImplForTest(); int lookupId = test.agent.adviceManager.register(advice); // Method under test MethodTracepointSpec t1 = TracepointsTestUtils.getMethodSpec(getClass(), "method"); MethodTracepointSpec tbad = MethodTracepointSpec.newBuilder(t1).setMethodName("badmethod").build(); // Invoke method - should do nothing before rewrite method("hi"); advice.expectSize(0); // Rewrite method MethodRewriteModification mod = new MethodRewriteModification(tbad, lookupId); test.agent.dynamic.clear().add(mod).install(); advice.expectSize(0); method("hi"); advice.expectSize(0); }
public void reset() { Class<?>[] classesToReset = classes.toArray(new Class[0]); Class<?>[] classesToRelink = nativeClasses.toArray(new Class[0]); classes.clear(); methods.clear(); nativeClasses.clear(); if (classesToReset.length > 0) { try { inst.retransformClasses(classesToReset); } catch (UnmodifiableClassException e) { System.err.println("unexpected class transforming restriction: " + e.getMessage()); e.printStackTrace(System.err); } } for (Class<?> clazz : classesToRelink) { relinkNativeMethods(clazz); } }
private void setupTransformer() { try { System.out.println("setup"); Instrumented instrumented = getTestClass().getJavaClass().getAnnotation(Instrumented.class); TestRecorderAgentConfig config = fetchConfig(instrumented); Class<?>[] classes = fetchClasses(instrumented); agent = new TestRecorderAgent(inst); agent.prepareInstrumentations(config); if (classes.length > 0) { inst.retransformClasses(classes); } } catch (ReflectiveOperationException | UnmodifiableClassException | Error e) { throw new RuntimeException(e); } }
@Before public void instrument() throws ClassNotFoundException, UnmodifiableClassException, InstantiationException, IllegalAccessException{ Assert.assertTrue(methods.length == expectedResults.length); Args args = new Args(); args.specify(Arg.DOUBLE2FLOAT); args.specify(Arg.PRINT); CojacReferencesBuilder builder = new CojacReferencesBuilder(args); agent = new Agent(builder.build()); AgentTest.instrumentation.addTransformer(agent); classz = ClassLoader.getSystemClassLoader().loadClass("com.github.cojac.unit.behaviours.Double2FloatTests"); AgentTest.instrumentation.retransformClasses(classz); object = classz.newInstance(); }
private void setRounding(Arg a) throws ClassNotFoundException, UnmodifiableClassException, InstantiationException, IllegalAccessException{ Args args = new Args(); args.specify(a); args.specify(Arg.PRINT); CojacReferencesBuilder builder = new CojacReferencesBuilder(args); try{ agent = new Agent(builder.build()); isLibraryLoaded = true; AgentTest.instrumentation.addTransformer(agent); classz = ClassLoader.getSystemClassLoader().loadClass("com.github.cojac.unit.behaviours.NativeRoundingTests"); AgentTest.instrumentation.retransformClasses(classz); object = classz.newInstance(); }catch(RuntimeException e){ System.err.println("Library couldn't be charged. Abording Native rounding tests."); isLibraryLoaded = false; } }
@Test public void testCallBackMethodCalled() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException, UnmodifiableClassException { Args args = new Args(); args.specify(Arg.ALL); args.setValue(Arg.CALL_BACK, "com/github/cojac/unit/CallBacksAgent/log"); CojacReferencesBuilder builder = new CojacReferencesBuilder(args); Agent agent = new Agent(builder.build()); AgentTest.instrumentation.addTransformer(agent); Class<?> classz = ClassLoader.getSystemClassLoader().loadClass("com.github.cojac.unit.SimpleOverflows"); AgentTest.instrumentation.retransformClasses(classz); Object object = classz.newInstance(); Method m = classz.getMethod("test"); m.invoke(object); classz = ClassLoader.getSystemClassLoader().loadClass("com.github.cojac.unit.CallBacksAgent"); Field field = classz.getField("count"); Assert.assertEquals(1, field.get(null)); AgentTest.instrumentation.removeTransformer(agent); }
/** * Ensures that the given sampler will be invoked every time a constructor * for class c is invoked. * * @param c The class to be tracked * @param sampler the code to be invoked when an instance of c is constructed * @throws UnmodifiableClassException if c cannot be modified. */ public static void instrumentClass(Class<?> c, ConstructorCallback<?> sampler) throws UnmodifiableClassException { // IMPORTANT: Don't forget that other threads may be accessing this // class while this code is running. Specifically, the class may be // executed directly after the retransformClasses is called. Thus, we need // to be careful about what happens after the retransformClasses call. synchronized (samplerPutAtomicityLock) { List<ConstructorCallback<?>> list = samplerMap.get(c); if (list == null) { CopyOnWriteArrayList<ConstructorCallback<?>> samplerList = new CopyOnWriteArrayList<ConstructorCallback<?>>(); samplerList.add(sampler); samplerMap.put(c, samplerList); Instrumentation inst = AllocationRecorder.getInstrumentation(); Class<?>[] cs = new Class<?>[1]; cs[0] = c; inst.retransformClasses(c); } else { list.add(sampler); } } }
/** * Inserts the appropriate INVOKESTATIC call */ @Override public void visitInsn(int opcode) { if ((opcode == Opcodes.ARETURN) || (opcode == Opcodes.IRETURN) || (opcode == Opcodes.LRETURN) || (opcode == Opcodes.FRETURN) || (opcode == Opcodes.DRETURN)) { throw new RuntimeException(new UnmodifiableClassException( "Constructors are supposed to return void")); } if (opcode == Opcodes.RETURN) { super.visitVarInsn(Opcodes.ALOAD, 0); super.visitMethodInsn( Opcodes.INVOKESTATIC, "com/google/monitoring/runtime/instrumentation/ConstructorInstrumenter", "invokeSamplers", "(Ljava/lang/Object;)V", false); } super.visitInsn(opcode); }
private void reload(Entry e) throws IOException, ClassNotFoundException, UnmodifiableClassException { System.err.println(e.file); cdefs.clear(); if (e.loaderRef != null) { ClassLoader cl = e.loaderRef.get(); if (cl != null) { request(e, cl); if (e.children != null) { for (Entry ce : e.children) { request(ce, cl); } } // System.err.println(cdefs); Agent.inst.redefineClasses(cdefs.toArray(new ClassDefinition[0])); } else { e.loaderRef = null; } } }
/** * 自动热加载 Class * @param intervals 自动重读的时间间隔, 单位: 秒 * @throws UnmodifiableClassException 不可修改的 Class 异常 * @throws ClassNotFoundException Class未找到异常 */ public void autoReload(int intervals) throws UnmodifiableClassException, ClassNotFoundException { this.reloadIntervals = intervals; cancelAutoReload(); Logger.info("[HOTSWAP] Start auto reload and hotswap every " + intervals + " seconds"); reloadTask = new HashWheelTask() { @Override public void run() { try { List<ClassFileInfo> changedFiles = fileWatcher(); reloadClass(changedFiles); } catch (UnmodifiableClassException |ClassNotFoundException e) { e.printStackTrace(); } } }; Global.getHashWheelTimer().addTask(reloadTask, intervals, true); }
@Override public void visitInsn(int opcode) { if ((opcode == Opcodes.ARETURN) || (opcode == Opcodes.IRETURN) || (opcode == Opcodes.LRETURN) || (opcode == Opcodes.FRETURN) || (opcode == Opcodes.DRETURN)) { throw new RuntimeException(new UnmodifiableClassException("Constructors are supposed to return void")); } if (opcode == Opcodes.RETURN) { super.visitVarInsn(Opcodes.ALOAD, 0); super.visitTypeInsn(Opcodes.NEW, Type.getInternalName(ScottReportingRule.class)); super.visitInsn(Opcodes.DUP); super.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(ScottReportingRule.class), "<init>", "()V", false); super.visitFieldInsn(Opcodes.PUTFIELD, className, "scottReportingRule", Type.getDescriptor(ScottReportingRule.class)); } super.visitInsn(opcode); }
@Override public synchronized Class<?> loadClass(String name, byte[] barr) throws UnmodifiableClassException { Class<?> clazz=null; try { clazz = loadClass(name,false,false); // we do not load existing class from disk } catch (ClassNotFoundException cnf) {} // if class already exists if(clazz!=null) { try { InstrumentationFactory.getInstrumentation(config).redefineClasses(new ClassDefinition(clazz,barr)); } catch (ClassNotFoundException e) { // the documentation clearly sais that this exception only exists for backward compatibility and never happen } return clazz; } // class not exists yet return _loadClass(name, barr); }
@Override public synchronized Class<?> loadClass(String name, byte[] barr) throws UnmodifiableClassException { Class<?> clazz=null; try { clazz = loadClass(name); } catch (ClassNotFoundException cnf) {} // if class already exists if(clazz!=null) { try { InstrumentationFactory.getInstrumentation(config).redefineClasses(new ClassDefinition(clazz,barr)); } catch (ClassNotFoundException e) { // the documentation clearly sais that this exception only exists for backward compatibility and never happen } aprint.e("redefined:memory:"+clazz.getName()); return clazz; } // class not exists yet return _loadClass(name, barr); }
public static ASMClass getClass(ExtendableClassLoader pcl,Resource classRoot,Class clazz) throws IOException, InstantiationException, IllegalAccessException, IllegalArgumentException, SecurityException, InvocationTargetException, NoSuchMethodException, UnmodifiableClassException{ Type type = Type.getType(clazz); // Fields Field[] fields = clazz.getFields(); for(int i=0;i<fields.length;i++){ if(Modifier.isPrivate(fields[i].getModifiers())) continue; createField(type,fields[i]); } // Methods Method[] methods = clazz.getMethods(); Map<String,ASMMethod> amethods=new HashMap<String, ASMMethod>(); for(int i=0;i<methods.length;i++){ if(Modifier.isPrivate(methods[i].getModifiers())) continue; amethods.put(methods[i].getName(), getMethod(pcl,classRoot,type,clazz,methods[i])); } return new ASMClass(clazz.getName(),amethods); }
private static ASMMethod getMethod(ExtendableClassLoader pcl, Resource classRoot, Type type,Class clazz, Method method) throws IOException, InstantiationException, IllegalAccessException, IllegalArgumentException, SecurityException, InvocationTargetException, NoSuchMethodException, UnmodifiableClassException { String className = createMethodName(clazz,method.getName(),method.getParameterTypes()); // check if already in memory cache ASMMethod asmm = methods.get(className); if(asmm!=null)return asmm; // try to load existing ASM Class Class<?> asmClass; try { asmClass = pcl.loadClass(className); } catch (ClassNotFoundException cnfe) { byte[] barr = _createMethod(type, clazz, method, classRoot, className); asmClass=pcl.loadClass(className, barr); } asmm = newInstance(asmClass,clazz,method.getParameterTypes()); methods.put(className, asmm); return asmm; }
public void enableEntryPointCoverage(FilterEntryPath filter) throws ClassNotFoundException, UnmodifiableClassException { System.out.println("enabling entry point coverage "+filter.toString()); Instrumentation instrumentation = InstrumentationHolder.getInstance().getInst(); if (instrumentation != null) { TransformerService ts = new TransformerService(); Map<String, List<EntryPathData>> mapConvert = ts .transformDataFromLeechPluginForTransformation(leechPluginRegistry.values(), filter); if (!config.getPathSend()) { // if the initPath are not called initPathsRemote(); } instrumentation.addTransformer( new EntryPointTransformer(mapConvert, CoreEngine.getInstance().getConfig().getPerformance()), true); ts.transformAllClassScanByH2h(instrumentation, mapConvert.keySet()); } else { System.err.println("Instrumentation fail because internal inst is null"); } }
@Test() public void testRetransform_Fail_memoryleak_prevent() throws Exception { final Instrumentation instrumentation = mock(Instrumentation.class); when(instrumentation.isModifiableClass(any(Class.class))).thenReturn(true); doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { throw new UnmodifiableClassException(); } }).when(instrumentation).retransformClasses(any(Class.class)); DefaultDynamicTransformerRegistry listener = new DefaultDynamicTransformerRegistry(); final ClassFileTransformer classFileTransformer = mock(ClassFileTransformer.class); DynamicTransformService dynamicTransformService = new DynamicTransformService(instrumentation, listener); try { dynamicTransformService.retransform(String.class, classFileTransformer); Assert.fail("expected retransform fail"); } catch (Exception e) { } Assert.assertEquals(listener.size(), 0); }
public static void agentmain(String agentArgs, Instrumentation instrumentation) { main(agentArgs, instrumentation); LOG.info("Retransforming all classes"); for( Class<?> c : instrumentation.getAllLoadedClasses() ) { Transformer transformer = getInstance().transformer; if ( transformer.isTransformable(c) ) { try { instrumentation.retransformClasses(c); } catch ( UnmodifiableClassException e ) { LOG.log(Level.WARNING, "Cannot retransform " + c, e); } } } LOG.info("Retransformation done"); }
public void redefineClasses(Map<Class<?>, byte[]> classes) throws ClassNotFoundException, UnmodifiableClassException { if (PluginManager.getInstance().getInstrumentation() == null) { throw new IllegalStateException("Instrumentation agent is not properly installed!"); } ClassDefinition[] definitions = new ClassDefinition[classes.size()]; int i = 0; for (Map.Entry<Class<?>, byte[]> entry : classes.entrySet()) { definitions[i++] = new ClassDefinition(entry.getKey(), entry.getValue()); URL classResource = getClassResource(entry.getKey()); try (OutputStream fileWriter = new FileOutputStream(new File(classResource.toURI()))) { fileWriter.write(entry.getValue()); } catch (Exception e) { throw new RuntimeException(e); } } PluginManager.getInstance().getInstrumentation().redefineClasses(definitions); }
public void process(Class<?> ... transformerClasses) { List<AgentJob> agentJobs = new ArrayList<>(); for (Class<?> clazz : transformerClasses) agentJobs.add(new AgentJob(clazz)); ClassTransformer classTransformer = new ClassTransformer(agentJobs); instrumentation.addTransformer(classTransformer, true); try { instrumentation.retransformClasses(classTransformer.getClassesToTransform()); } catch (UnmodifiableClassException e) { e.printStackTrace(); } }
@Override public void redefine(ClassBytecodes[] cbcs) throws ClassInstallException, NotImplementedException, EngineTerminationException { int count = cbcs.length; boolean[] status = new boolean[cbcs.length]; int success = 0; NbRemoteLoader ldr = prepareClassLoader(); for (int i = 0; i < count; i++) { String name = cbcs[i].name(); byte[] replaceBytecode = cbcs[i].bytecodes(); Long id = ldr.getClassId(name); if (id != null) { Class defined = ldr.getClassOfId(id); try { agent.getInstrumentation().redefineClasses( new ClassDefinition(defined, replaceBytecode) ); status[i] = true; success++; } catch (ClassNotFoundException | UnmodifiableClassException ex) { Logger.getLogger(AgentWorker.class.getName()).log(Level.SEVERE, null, ex); } } if (success < count) { throw new ClassInstallException("Could not redefine classes", status); } } }
@Test public void testSingleton() throws IOException, UnmodifiableClassException { new GasketInjector().register(TestClass.class, SomeSingleton.class, SomeOtherSingleton.class); final TestClass testClass = new TestClass(5); Assert.assertEquals("Invalid data returned", 5, testClass.getSingletonData()); Assert.assertEquals("Invalid data returned", 9, testClass.getOtherSingletonData()); final TestClass testClass2 = new TestClass("kek"); Assert.assertEquals("Invalid data returned", 5, testClass2.getSingletonData()); Assert.assertEquals("Invalid data returned", 9, testClass2.getOtherSingletonData()); }
@Test public void testNamedSingleton() throws IOException, UnmodifiableClassException { new GasketInjector().register(TestNamed.class, TestImplementation1.class, TestImplementation2.class); final TestNamed testNamed = new TestNamed(); Assert.assertEquals("Implementation 1 returned wrong value", NAMED_VALUE1, testNamed.getValue1()); Assert.assertEquals("Implementation 2 returned wrong value", NAMED_VALUE2, testNamed.getValue2()); }
@Test public void testProviders() throws IOException, UnmodifiableClassException { final GasketInjector injector = new GasketInjector(); injector.register(Config.class, ProviderTest.class, TestClass.class); injector.getConfig().setProperty("provider_type", "test1"); Assert.assertEquals("Returned value is invalid", CONFIG_VALUE * SERVICE1_VALUE, new TestClass().getValue()); injector.getConfig().setProperty("provider_type", "test2"); Assert.assertEquals("Returned value is invalid", CONFIG_VALUE * SERVICE2_VALUE, new TestClass().getValue()); }
public static void agentmain(String agentArgs, Instrumentation instrumentation) throws ClassNotFoundException, UnmodifiableClassException, InterruptedException { inst = instrumentation; inst.addTransformer(new CodeTransformer(), true); }
public synchronized static void removeMetricsClass(String name) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, UnmodifiableClassException { Class seleClass = Class.forName(name.replace('/', '.')); needRecoverClasses.put(name, needMetricsClasses.remove(name)); Instrumentation inst = instrumentation(); inst.retransformClasses(seleClass); MetricsCollector.getCollector().removeClassMetrics(name); }
public static void restoreClass(ViewASMCodeReq req) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, UnmodifiableClassException, IllegalAccessException, NotFoundException { DebugInfo debugInfo = AgentTool.getDebugInfoByClassName(req.className); if(debugInfo != null){ AgentTool.removeDebugClassByTraceId(debugInfo.getTraceId(),true); }else { AgentTool.removeMetricsClass(req.className); } }
@Override public void rewriteIfPossible(Class<?> declaringClass) throws IllegalStateException { Instrumentation instrumentation = checkInstrumentation(); /* byte[] bytecode; ClassLoader loader = declaringClass.getClassLoader(); try(InputStream input = loader.getResourceAsStream(declaringClass.getName().replace('.', '/') + ".class")) { if (input == null) { throw new IllegalStateException("no input"); } Function<String, Optional<InputStream>> classFileFinder = internalName -> Optional.ofNullable(loader.getResourceAsStream(internalName + ".class")); bytecode = Rewriter.rewrite(input, classFileFinder); } catch (IOException e) { throw new IllegalStateException(e); } try { instrumentation.redefineClasses(new ClassDefinition(declaringClass, bytecode)); } catch (ClassNotFoundException | UnmodifiableClassException e) { throw new IllegalStateException(e); }*/ try { instrumentation.retransformClasses(declaringClass); } catch (UnmodifiableClassException e) { throw new IllegalStateException(e); } }
private void testTransformAndVerify() throws NoSuchFieldException, NoSuchMethodException { Class<TypeAnnotatedTestClass> c = TypeAnnotatedTestClass.class; Class<?> myClass = c; /* * Verify that the expected annotations are where they should be before transform. */ verifyClassTypeAnnotations(c); verifyFieldTypeAnnotations(c); verifyMethodTypeAnnotations(c); try { inst.addTransformer(new Transformer(), true); inst.retransformClasses(myClass); } catch (UnmodifiableClassException e) { throw new RuntimeException(e); } /* * Verify that the expected annotations are where they should be after transform. * Also verify that before and after are equal. */ verifyClassTypeAnnotations(c); verifyFieldTypeAnnotations(c); verifyMethodTypeAnnotations(c); }
/** Reload original class definition */ public void reset(Collection<String> classNames) throws UnmodifiableClassException, CannotCompileException { Map<String, Collection<DynamicModification>> modifications = Maps.newHashMap(); for (String className : classNames) { modifications.put(className, new HashSet<DynamicModification>()); } install(modifications); }
/** Install the provided modifications, deriving the affected classes from the modifications */ public void install(Collection<? extends DynamicModification> modifications) throws UnmodifiableClassException, CannotCompileException { Multimap<String, DynamicModification> modificationsByClass = HashMultimap.create(); for (DynamicModification modification : modifications) { for (String className : modification.affects()) { modificationsByClass.put(className, modification); } } install(modificationsByClass.asMap()); }
/** Install the provided modifications. If a class is unknown, its modification is ignored, but if the provided modifications * cannot compile then exceptions will be thrown */ public void install(Map<String, Collection<DynamicModification>> modifications, Collection<Throwable> problems) throws CannotCompileException, UnmodifiableClassException { Installation i = new Installation(); i.modifyAll(modifications, problems); if (!i.reloadMap.isEmpty()) { log.info("Reloading {} classes: {}", modifications.size(), modifications.keySet()); reload(i.reloadMap); } }
public void install() throws CannotCompileException, UnmodifiableClassException { if (agent != null) { problems.clear(); agent.install(pending.changes(), problems); pending.persist(); } }