5503N/A/*
5503N/A * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
5503N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5503N/A *
5503N/A * This code is free software; you can redistribute it and/or modify it
5503N/A * under the terms of the GNU General Public License version 2 only, as
5503N/A * published by the Free Software Foundation.
5503N/A *
5503N/A * This code is distributed in the hope that it will be useful, but WITHOUT
5503N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
5503N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
5503N/A * version 2 for more details (a copy is included in the LICENSE file that
5503N/A * accompanied this code).
5503N/A *
5503N/A * You should have received a copy of the GNU General Public License version
5503N/A * 2 along with this work; if not, write to the Free Software Foundation,
5503N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
5503N/A *
5503N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
5503N/A * or visit www.oracle.com if you need additional information or have any
5503N/A * questions.
5503N/A */
5503N/A
5503N/Aimport static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ACC_FINAL;
5503N/Aimport static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ACC_PRIVATE;
5503N/Aimport static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ACC_PUBLIC;
5503N/Aimport static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ACC_STATIC;
5503N/Aimport static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ACC_SUPER;
5503N/Aimport static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ILOAD;
5503N/Aimport static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.INVOKESPECIAL;
5503N/Aimport static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.INVOKESTATIC;
5503N/Aimport static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.IRETURN;
5503N/Aimport static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.RETURN;
5503N/Aimport static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.V1_6;
5503N/A
5503N/Aimport java.lang.instrument.ClassDefinition;
5503N/Aimport java.lang.instrument.Instrumentation;
5503N/Aimport java.lang.reflect.Method;
5503N/Aimport java.lang.reflect.Modifier;
5503N/Aimport java.net.InetAddress;
5503N/A
5503N/Aimport com.sun.xml.internal.ws.org.objectweb.asm.ClassWriter;
5503N/Aimport com.sun.xml.internal.ws.org.objectweb.asm.MethodVisitor;
5503N/Aimport com.sun.xml.internal.ws.org.objectweb.asm.Type;
5503N/Aimport sun.misc.IoTrace;
5503N/A
5503N/Apublic class IoTraceAgent {
5503N/A
5503N/A private static IoTraceListener listener;
5503N/A
5503N/A public static void setListener(IoTraceListener l) {
5503N/A listener = l;
5503N/A }
5503N/A
5766N/A public static Object socketReadBegin() {
5503N/A IoTraceListener l = listener;
5503N/A if (l != null) {
5766N/A return l.socketReadBegin();
5503N/A }
5503N/A return null;
5503N/A }
5503N/A
5766N/A public static void socketReadEnd(Object context, InetAddress address, int port,
5766N/A int timeout, long bytesRead) {
5503N/A IoTraceListener l = listener;
5503N/A if (l != null) {
5766N/A l.socketReadEnd(context, address, port, timeout, bytesRead);
5503N/A }
5503N/A }
5503N/A
5766N/A public static Object socketWriteBegin() {
5503N/A IoTraceListener l = listener;
5503N/A if (l != null) {
5766N/A return l.socketWriteBegin();
5503N/A }
5503N/A return null;
5503N/A }
5503N/A
5766N/A public static void socketWriteEnd(Object context, InetAddress address, int port,
5766N/A long bytesWritten) {
5503N/A IoTraceListener l = listener;
5503N/A if (l != null) {
5766N/A l.socketWriteEnd(context, address, port, bytesWritten);
5503N/A }
5503N/A }
5503N/A
5503N/A public static Object fileReadBegin(String path) {
5503N/A IoTraceListener l = listener;
5503N/A if (l != null) {
5503N/A return l.fileReadBegin(path);
5503N/A }
5503N/A return null;
5503N/A }
5503N/A
5503N/A public static void fileReadEnd(Object context, long bytesRead) {
5503N/A IoTraceListener l = listener;
5503N/A if (l != null) {
5503N/A l.fileReadEnd(context, bytesRead);
5503N/A }
5503N/A }
5503N/A
5503N/A public static Object fileWriteBegin(String path) {
5503N/A IoTraceListener l = listener;
5503N/A if (l != null) {
5503N/A return l.fileWriteBegin(path);
5503N/A }
5503N/A return null;
5503N/A }
5503N/A
5503N/A public static void fileWriteEnd(Object context, long bytesWritten) {
5503N/A IoTraceListener l = listener;
5503N/A if (l != null) {
5503N/A l.fileWriteEnd(context, bytesWritten);
5503N/A }
5503N/A }
5503N/A
5503N/A public static void premain(String agentArgs, Instrumentation inst)
5503N/A throws Exception {
5503N/A ClassDefinition cd = new ClassDefinition(IoTrace.class,
5503N/A generateClassAsm());
5503N/A inst.redefineClasses(cd);
5503N/A }
5503N/A
5503N/A private static byte[] generateClassAsm() {
5503N/A ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
5503N/A cw.visit(V1_6, ACC_PUBLIC | ACC_SUPER | ACC_FINAL, "sun/misc/IoTrace",
5503N/A null, "java/lang/Object", null);
5503N/A
5503N/A // for all methods in the existing IoTrace class
5503N/A // we want to create a method in the new version of it which call
5503N/A // IoTraceAgent
5503N/A //
5503N/A // 0: aload_0
5503N/A // 1: iload_1
5503N/A // 2: iload_2
5503N/A // 3: invokestatic #16 // Method
5766N/A // IoTraceAgent.socketReadBegin:(II)Ljava/lang/Object;
5503N/A // 6: areturn
5503N/A
5503N/A for (Method om : IoTrace.class.getDeclaredMethods()) {
5503N/A if (!Modifier.isStatic(om.getModifiers())) {
5503N/A continue;
5503N/A }
5503N/A
5503N/A // create a method with the same signature as the
5503N/A // original method
5503N/A MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC,
5503N/A om.getName(), Type.getMethodDescriptor(om), null, null);
5503N/A mv.visitCode();
5503N/A
5503N/A // get the return type and argument list types
5503N/A Type[] argTypes = Type.getArgumentTypes(om);
5503N/A Type retType = Type.getReturnType(om);
5503N/A
5503N/A // load all the arguments
5503N/A int i = 0;
5503N/A for (Type t : argTypes) {
5503N/A mv.visitVarInsn(t.getOpcode(ILOAD), i++);
5503N/A }
5503N/A
5503N/A // call a method with the same signature (but in a different class)
5503N/A // with all the arguments
5503N/A mv.visitMethodInsn(INVOKESTATIC, "IoTraceAgent", om.getName(),
5503N/A Type.getMethodDescriptor(om));
5503N/A
5503N/A // return the value from the called method
5503N/A mv.visitInsn(retType.getOpcode(IRETURN));
5503N/A mv.visitEnd();
5503N/A }
5503N/A
5503N/A // empty private constructor
5503N/A MethodVisitor mv = cw.visitMethod(ACC_PRIVATE, "<init>", "()V", null,
5503N/A null);
5503N/A mv.visitCode();
5503N/A mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
5503N/A mv.visitInsn(RETURN);
5503N/A mv.visitEnd();
5503N/A
5503N/A cw.visitEnd();
5503N/A return cw.toByteArray();
5503N/A }
5503N/A}