/* * Copyright (c) 2013-2014, Pierre Laporte * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License * along with this work; if not, see <http://www.gnu.org/licenses/>. */ package fr.pingtimeout.tyrion.transformation; import fr.pingtimeout.tyrion.util.SimpleLogger; import lombok.NoArgsConstructor; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.util.TraceClassVisitor; import java.io.PrintWriter; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; import java.security.ProtectionDomain; public class CriticalSectionsInterceptor implements ClassFileTransformer { private final PrintWriter traceBytecodeWriter; public CriticalSectionsInterceptor() { traceBytecodeWriter = null; } public CriticalSectionsInterceptor(PrintWriter traceBytecodeWriter) { this.traceBytecodeWriter = traceBytecodeWriter; } @Override public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { try { SimpleLogger.debug("Trying to transform %s...", className); return transform(className, classfileBuffer); } catch (RuntimeException ignored) { SimpleLogger.warn("Unable to transform class %s, returning the class buffer unchanged. Cause : %s", className, ignored.getMessage()); SimpleLogger.debug(ignored); return classfileBuffer; } } byte[] transform(String className, byte[] classfileBuffer) { ClassReader reader = new ClassReader(classfileBuffer); ClassNode classNode = new ClassNode(); ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); SynchronizedBlockTransformer synchronizedBlockTransformer = new SynchronizedBlockTransformer(classNode); final ClassVisitor syncMethodsVisitor; if (traceBytecodeWriter != null) { ClassVisitor traceClassVisitor = new TraceClassVisitor(writer, traceBytecodeWriter); syncMethodsVisitor = new SynchronizedMethodTransformer(Opcodes.ASM4, traceClassVisitor, className); } else { syncMethodsVisitor = new SynchronizedMethodTransformer(Opcodes.ASM4, writer, className); } // Reader -> ClassNode -> SynchronizedMethodTransformer -> (TraceClassVisitor ->) Writer reader.accept(classNode, 0); synchronizedBlockTransformer.interceptAllSynchronizedBlocks(); classNode.accept(syncMethodsVisitor); return writer.toByteArray(); } }