001 package railo.runtime.instrumentation; 002 003 import java.io.IOException; 004 import java.lang.instrument.ClassDefinition; 005 import java.lang.instrument.Instrumentation; 006 import java.lang.instrument.UnmodifiableClassException; 007 008 import org.objectweb.asm.ClassAdapter; 009 import org.objectweb.asm.ClassReader; 010 import org.objectweb.asm.ClassVisitor; 011 import org.objectweb.asm.ClassWriter; 012 import org.objectweb.asm.MethodVisitor; 013 import org.objectweb.asm.Opcodes; 014 015 import railo.commons.lang.ClassUtil; 016 import railo.runtime.type.List; 017 import railo.transformer.bytecode.util.ASMUtil; 018 019 public class InstrumentationUtil { 020 021 /** 022 * clear all method/constructor bodies of the given class 023 * @param clazz class to clear 024 * @param redefineClass if true change the class instance, if false just create the byte array 025 * @return 026 */ 027 public static byte[] clearAllBodies(Class<?> clazz,boolean redefineClass){ 028 byte[] barr = clean(clazz); 029 if(redefineClass)redefineClassEL(clazz, barr); 030 return barr; 031 } 032 033 private static byte[] clean(Class<?> clazz) { 034 try { 035 return clean(ClassUtil.toBytes(clazz)); 036 } catch (IOException e) { 037 e.printStackTrace(); 038 } 039 return null; 040 } 041 042 private static byte[] clean(byte[] org) { 043 ClassWriter cw = ASMUtil.getClassWriter(); 044 ChangeAdapter ca = new ChangeAdapter(cw); 045 ClassReader cr = new ClassReader(org); 046 cr.accept(ca, false); 047 return cw.toByteArray(); 048 } 049 050 /** 051 * redefine the class with the given byte array 052 * @param clazz 053 * @param barr 054 * @return 055 */ 056 public static boolean redefineClassEL(Class clazz, byte[] barr){ 057 Instrumentation inst = InstrumentationFactory.getInstance(); 058 if(inst!=null && inst.isRedefineClassesSupported()) { 059 try { 060 inst.redefineClasses(new ClassDefinition(clazz,barr)); 061 return true; 062 } 063 catch (Throwable t) {t.printStackTrace();} 064 } 065 return false; 066 } 067 public static void redefineClass(Class clazz, byte[] barr) throws ClassNotFoundException, UnmodifiableClassException{ 068 Instrumentation inst = InstrumentationFactory.getInstance(); 069 inst.redefineClasses(new ClassDefinition(clazz,barr)); 070 } 071 072 073 public static class ChangeAdapter extends ClassAdapter { 074 public ChangeAdapter(ClassVisitor cv) { 075 super(cv); 076 } 077 078 /** 079 * @see org.objectweb.asm.ClassAdapter#visitMethod(int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[]) 080 */ 081 public MethodVisitor visitMethod(int access, String name, String desc,String signature, String[] exceptions) { 082 MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); 083 if(name.startsWith("<")) return mv; 084 085 mv.visitCode(); 086 String ret = List.last(desc, ')').toLowerCase(); 087 // void 088 if(ret.equals("v")) { 089 mv.visitInsn(Opcodes.RETURN); 090 } 091 // boolean, short, int, char, 092 else if(ret.equals("z") || ret.equals("s") || ret.equals("i") || ret.equals("c") || ret.equals("b")) { 093 mv.visitInsn(Opcodes.ICONST_0); 094 mv.visitInsn(Opcodes.IRETURN); 095 } 096 else if(ret.equals("f")) { 097 mv.visitInsn(Opcodes.FCONST_0); 098 mv.visitInsn(Opcodes.FRETURN); 099 } 100 else if(ret.equals("j")) { 101 mv.visitInsn(Opcodes.LCONST_0); 102 mv.visitInsn(Opcodes.LRETURN); 103 } 104 else if(ret.equals("d")) { 105 mv.visitInsn(Opcodes.DCONST_0); 106 mv.visitInsn(Opcodes.DRETURN); 107 } 108 else { 109 mv.visitInsn(Opcodes.ACONST_NULL); 110 mv.visitInsn(Opcodes.ARETURN); 111 } 112 mv.visitEnd(); 113 return mv; 114 } 115 } 116 117 118 public static boolean isSupported() { 119 Instrumentation inst = InstrumentationFactory.getInstance(); 120 return (inst!=null && inst.isRedefineClassesSupported()); 121 } 122 }