1 /* 2 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_FINAL; 27 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PRIVATE; 28 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC; 29 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC; 30 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_SUPER; 31 import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD; 32 import static jdk.internal.org.objectweb.asm.Opcodes.ARETURN; 33 import static jdk.internal.org.objectweb.asm.Opcodes.ILOAD; 34 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC; 35 import static jdk.internal.org.objectweb.asm.Opcodes.LLOAD; 36 import static jdk.internal.org.objectweb.asm.Opcodes.RETURN; 37 import static jdk.internal.org.objectweb.asm.Opcodes.V1_6; 38 39 import java.lang.instrument.ClassDefinition; 40 import java.lang.instrument.Instrumentation; 41 import java.lang.reflect.Method; 42 import java.lang.reflect.Modifier; 43 import java.net.InetAddress; 44 45 import jdk.internal.org.objectweb.asm.ClassWriter; 46 import jdk.internal.org.objectweb.asm.MethodVisitor; 47 import jdk.internal.org.objectweb.asm.Type; 48 import sun.misc.IoTrace; 49 import sun.misc.IoTraceContext; 50 51 public class IoTraceAgent { 52 53 private static IoTraceListener listener; 54 55 public static void setListener(IoTraceListener l) { 56 listener = l; 57 } 58 59 public static IoTraceContext socketReadBegin(InetAddress address, int port, 60 int timeout) { 61 IoTraceListener l = listener; 62 if (l != null) { 63 return l.socketReadBegin(address, port, timeout); 64 } 65 return null; 66 } 67 68 public static void socketReadEnd(IoTraceContext context, long bytesRead) { 69 IoTraceListener l = listener; 70 if (l != null) { 71 l.socketReadEnd(context, bytesRead); 72 } 73 } 74 75 public static IoTraceContext socketWriteBegin(InetAddress address, int port) { 76 IoTraceListener l = listener; 77 if (l != null) { 78 return l.socketWriteBegin(address, port); 79 } 80 return null; 81 } 82 83 public static void socketWriteEnd(IoTraceContext context, long bytesWritten) { 84 IoTraceListener l = listener; 85 if (l != null) { 86 l.socketWriteEnd(context, bytesWritten); 87 } 88 } 89 90 public static IoTraceContext fileReadBegin(String path) { 91 IoTraceListener l = listener; 92 if (l != null) { 93 return l.fileReadBegin(path); 94 } 95 return null; 96 } 97 98 public static void fileReadEnd(IoTraceContext context, long bytesRead) { 99 IoTraceListener l = listener; 100 if (l != null) { 101 l.fileReadEnd(context, bytesRead); 102 } 103 } 104 105 public static IoTraceContext fileWriteBegin(String path) { 106 IoTraceListener l = listener; 107 if (l != null) { 108 return l.fileWriteBegin(path); 109 } 110 return null; 111 } 112 113 public static void fileWriteEnd(IoTraceContext context, long bytesWritten) { 114 IoTraceListener l = listener; 115 if (l != null) { 116 l.fileWriteEnd(context, bytesWritten); 117 } 118 } 119 120 public static void premain(String agentArgs, Instrumentation inst) 121 throws Exception { 122 ClassDefinition cd = new ClassDefinition(IoTrace.class, 123 generateClassAsm()); 124 inst.redefineClasses(cd); 125 } 126 127 private static byte[] generateClassAsm() { 128 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES 129 | ClassWriter.COMPUTE_MAXS); 130 cw.visit(V1_6, ACC_PUBLIC | ACC_SUPER | ACC_FINAL, "sun/misc/IoTrace", 131 null, "java/lang/Object", null); 132 133 // for all methods in the existing IoTrace class 134 // we want to create a method in the new version of it which call 135 // IoTraceAgent 136 // 137 // 0: aload_0 138 // 1: iload_1 139 // 2: iload_2 140 // 3: invokestatic #16 // Method 141 // IoTraceAgent.socketReadBegin:(Ljava/net/InetAddress;II)Lsun/misc/IoTraceContext; 142 // 6: areturn 143 144 for (Method om : IoTrace.class.getDeclaredMethods()) { 145 if (!Modifier.isStatic(om.getModifiers())) { 146 continue; 147 } 148 149 // create a method with the same signature as the 150 // original method 151 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, 152 om.getName(), Type.getMethodDescriptor(om), null, null); 153 mv.visitCode(); 154 155 // get the return type and argument list types 156 Type[] argTypes = Type.getArgumentTypes(om); 157 Type retType = Type.getReturnType(om); 158 159 // load all the arguments 160 int i = 0; 161 for (Type t : argTypes) { 162 int instr; 163 switch (t.getSort()) { 164 case Type.INT: 165 instr = ILOAD; 166 break; 167 case Type.LONG: 168 instr = LLOAD; 169 break; 170 case Type.OBJECT: 171 instr = ALOAD; 172 break; 173 default: 174 throw new IllegalArgumentException( 175 "Unhandled argument type when generating code: " 176 + t); 177 } 178 mv.visitVarInsn(instr, i++); 179 } 180 181 // call a method with the same signature (but in a different class) 182 // with all the arguments 183 mv.visitMethodInsn(INVOKESTATIC, "IoTraceAgent", om.getName(), 184 Type.getMethodDescriptor(om)); 185 186 // return the value from the called method 187 if (retType.getSort() == Type.VOID) { 188 mv.visitInsn(RETURN); 189 } else if (retType.getSort() == Type.OBJECT) { 190 mv.visitInsn(ARETURN); 191 } else { 192 throw new IllegalArgumentException( 193 "Unhandled return type when generating code: " 194 + retType); 195 } 196 mv.visitEnd(); 197 } 198 199 // empty private constructor 200 MethodVisitor mv = cw.visitMethod(ACC_PRIVATE, "<init>", "()V", null, 201 null); 202 mv.visitCode(); 203 mv.visitInsn(RETURN); 204 mv.visitEnd(); 205 206 cw.visitEnd(); 207 return cw.toByteArray(); 208 } 209 }