Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/instrument/InstrumentationImpl.java
38829 views
/*1* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/242526package sun.instrument;2728import java.lang.reflect.Method;29import java.lang.reflect.AccessibleObject;3031import java.lang.instrument.ClassFileTransformer;32import java.lang.instrument.ClassDefinition;33import java.lang.instrument.Instrumentation;3435import java.security.AccessController;36import java.security.PrivilegedAction;37import java.security.ProtectionDomain;3839import java.util.jar.JarFile;4041/*42* Copyright 2003 Wily Technology, Inc.43*/4445/**46* The Java side of the JPLIS implementation. Works in concert with a native JVMTI agent47* to implement the JPLIS API set. Provides both the Java API implementation of48* the Instrumentation interface and utility Java routines to support the native code.49* Keeps a pointer to the native data structure in a scalar field to allow native50* processing behind native methods.51*/52public class InstrumentationImpl implements Instrumentation {53private final TransformerManager mTransformerManager;54private TransformerManager mRetransfomableTransformerManager;55// needs to store a native pointer, so use 64 bits56private final long mNativeAgent;57private final boolean mEnvironmentSupportsRedefineClasses;58private volatile boolean mEnvironmentSupportsRetransformClassesKnown;59private volatile boolean mEnvironmentSupportsRetransformClasses;60private final boolean mEnvironmentSupportsNativeMethodPrefix;6162private63InstrumentationImpl(long nativeAgent,64boolean environmentSupportsRedefineClasses,65boolean environmentSupportsNativeMethodPrefix) {66mTransformerManager = new TransformerManager(false);67mRetransfomableTransformerManager = null;68mNativeAgent = nativeAgent;69mEnvironmentSupportsRedefineClasses = environmentSupportsRedefineClasses;70mEnvironmentSupportsRetransformClassesKnown = false; // false = need to ask71mEnvironmentSupportsRetransformClasses = false; // don't know yet72mEnvironmentSupportsNativeMethodPrefix = environmentSupportsNativeMethodPrefix;73}7475public void76addTransformer(ClassFileTransformer transformer) {77addTransformer(transformer, false);78}7980public synchronized void81addTransformer(ClassFileTransformer transformer, boolean canRetransform) {82if (transformer == null) {83throw new NullPointerException("null passed as 'transformer' in addTransformer");84}85if (canRetransform) {86if (!isRetransformClassesSupported()) {87throw new UnsupportedOperationException(88"adding retransformable transformers is not supported in this environment");89}90if (mRetransfomableTransformerManager == null) {91mRetransfomableTransformerManager = new TransformerManager(true);92}93mRetransfomableTransformerManager.addTransformer(transformer);94if (mRetransfomableTransformerManager.getTransformerCount() == 1) {95setHasRetransformableTransformers(mNativeAgent, true);96}97} else {98mTransformerManager.addTransformer(transformer);99}100}101102public synchronized boolean103removeTransformer(ClassFileTransformer transformer) {104if (transformer == null) {105throw new NullPointerException("null passed as 'transformer' in removeTransformer");106}107TransformerManager mgr = findTransformerManager(transformer);108if (mgr != null) {109mgr.removeTransformer(transformer);110if (mgr.isRetransformable() && mgr.getTransformerCount() == 0) {111setHasRetransformableTransformers(mNativeAgent, false);112}113return true;114}115return false;116}117118public boolean119isModifiableClass(Class<?> theClass) {120if (theClass == null) {121throw new NullPointerException(122"null passed as 'theClass' in isModifiableClass");123}124return isModifiableClass0(mNativeAgent, theClass);125}126127public boolean128isRetransformClassesSupported() {129// ask lazily since there is some overhead130if (!mEnvironmentSupportsRetransformClassesKnown) {131mEnvironmentSupportsRetransformClasses = isRetransformClassesSupported0(mNativeAgent);132mEnvironmentSupportsRetransformClassesKnown = true;133}134return mEnvironmentSupportsRetransformClasses;135}136137public void138retransformClasses(Class<?>... classes) {139if (!isRetransformClassesSupported()) {140throw new UnsupportedOperationException(141"retransformClasses is not supported in this environment");142}143retransformClasses0(mNativeAgent, classes);144}145146public boolean147isRedefineClassesSupported() {148return mEnvironmentSupportsRedefineClasses;149}150151public void152redefineClasses(ClassDefinition... definitions)153throws ClassNotFoundException {154if (!isRedefineClassesSupported()) {155throw new UnsupportedOperationException("redefineClasses is not supported in this environment");156}157if (definitions == null) {158throw new NullPointerException("null passed as 'definitions' in redefineClasses");159}160for (int i = 0; i < definitions.length; ++i) {161if (definitions[i] == null) {162throw new NullPointerException("element of 'definitions' is null in redefineClasses");163}164}165if (definitions.length == 0) {166return; // short-circuit if there are no changes requested167}168169redefineClasses0(mNativeAgent, definitions);170}171172@SuppressWarnings("rawtypes")173public Class[]174getAllLoadedClasses() {175return getAllLoadedClasses0(mNativeAgent);176}177178@SuppressWarnings("rawtypes")179public Class[]180getInitiatedClasses(ClassLoader loader) {181return getInitiatedClasses0(mNativeAgent, loader);182}183184public long185getObjectSize(Object objectToSize) {186if (objectToSize == null) {187throw new NullPointerException("null passed as 'objectToSize' in getObjectSize");188}189return getObjectSize0(mNativeAgent, objectToSize);190}191192public void193appendToBootstrapClassLoaderSearch(JarFile jarfile) {194appendToClassLoaderSearch0(mNativeAgent, jarfile.getName(), true);195}196197public void198appendToSystemClassLoaderSearch(JarFile jarfile) {199appendToClassLoaderSearch0(mNativeAgent, jarfile.getName(), false);200}201202public boolean203isNativeMethodPrefixSupported() {204return mEnvironmentSupportsNativeMethodPrefix;205}206207public synchronized void208setNativeMethodPrefix(ClassFileTransformer transformer, String prefix) {209if (!isNativeMethodPrefixSupported()) {210throw new UnsupportedOperationException(211"setNativeMethodPrefix is not supported in this environment");212}213if (transformer == null) {214throw new NullPointerException(215"null passed as 'transformer' in setNativeMethodPrefix");216}217TransformerManager mgr = findTransformerManager(transformer);218if (mgr == null) {219throw new IllegalArgumentException(220"transformer not registered in setNativeMethodPrefix");221}222mgr.setNativeMethodPrefix(transformer, prefix);223String[] prefixes = mgr.getNativeMethodPrefixes();224setNativeMethodPrefixes(mNativeAgent, prefixes, mgr.isRetransformable());225}226227private TransformerManager228findTransformerManager(ClassFileTransformer transformer) {229if (mTransformerManager.includesTransformer(transformer)) {230return mTransformerManager;231}232if (mRetransfomableTransformerManager != null &&233mRetransfomableTransformerManager.includesTransformer(transformer)) {234return mRetransfomableTransformerManager;235}236return null;237}238239240/*241* Natives242*/243private native boolean244isModifiableClass0(long nativeAgent, Class<?> theClass);245246private native boolean247isRetransformClassesSupported0(long nativeAgent);248249private native void250setHasRetransformableTransformers(long nativeAgent, boolean has);251252private native void253retransformClasses0(long nativeAgent, Class<?>[] classes);254255private native void256redefineClasses0(long nativeAgent, ClassDefinition[] definitions)257throws ClassNotFoundException;258259@SuppressWarnings("rawtypes")260private native Class[]261getAllLoadedClasses0(long nativeAgent);262263@SuppressWarnings("rawtypes")264private native Class[]265getInitiatedClasses0(long nativeAgent, ClassLoader loader);266267private native long268getObjectSize0(long nativeAgent, Object objectToSize);269270private native void271appendToClassLoaderSearch0(long nativeAgent, String jarfile, boolean bootLoader);272273private native void274setNativeMethodPrefixes(long nativeAgent, String[] prefixes, boolean isRetransformable);275276static {277System.loadLibrary("instrument");278}279280/*281* Internals282*/283284285// Enable or disable Java programming language access checks on a286// reflected object (for example, a method)287private static void setAccessible(final AccessibleObject ao, final boolean accessible) {288AccessController.doPrivileged(new PrivilegedAction<Object>() {289public Object run() {290ao.setAccessible(accessible);291return null;292}});293}294295// Attempt to load and start an agent296private void297loadClassAndStartAgent( String classname,298String methodname,299String optionsString)300throws Throwable {301302ClassLoader mainAppLoader = ClassLoader.getSystemClassLoader();303Class<?> javaAgentClass = mainAppLoader.loadClass(classname);304305Method m = null;306NoSuchMethodException firstExc = null;307boolean twoArgAgent = false;308309// The agent class must have a premain or agentmain method that310// has 1 or 2 arguments. We check in the following order:311//312// 1) declared with a signature of (String, Instrumentation)313// 2) declared with a signature of (String)314// 3) inherited with a signature of (String, Instrumentation)315// 4) inherited with a signature of (String)316//317// So the declared version of either 1-arg or 2-arg always takes318// primary precedence over an inherited version. After that, the319// 2-arg version takes precedence over the 1-arg version.320//321// If no method is found then we throw the NoSuchMethodException322// from the first attempt so that the exception text indicates323// the lookup failed for the 2-arg method (same as JDK5.0).324325try {326m = javaAgentClass.getDeclaredMethod( methodname,327new Class<?>[] {328String.class,329java.lang.instrument.Instrumentation.class330}331);332twoArgAgent = true;333} catch (NoSuchMethodException x) {334// remember the NoSuchMethodException335firstExc = x;336}337338if (m == null) {339// now try the declared 1-arg method340try {341m = javaAgentClass.getDeclaredMethod(methodname,342new Class<?>[] { String.class });343} catch (NoSuchMethodException x) {344// ignore this exception because we'll try345// two arg inheritance next346}347}348349if (m == null) {350// now try the inherited 2-arg method351try {352m = javaAgentClass.getMethod( methodname,353new Class<?>[] {354String.class,355java.lang.instrument.Instrumentation.class356}357);358twoArgAgent = true;359} catch (NoSuchMethodException x) {360// ignore this exception because we'll try361// one arg inheritance next362}363}364365if (m == null) {366// finally try the inherited 1-arg method367try {368m = javaAgentClass.getMethod(methodname,369new Class<?>[] { String.class });370} catch (NoSuchMethodException x) {371// none of the methods exists so we throw the372// first NoSuchMethodException as per 5.0373throw firstExc;374}375}376377// the premain method should not be required to be public,378// make it accessible so we can call it379// Note: The spec says the following:380// The agent class must implement a public static premain method...381setAccessible(m, true);382383// invoke the 1 or 2-arg method384if (twoArgAgent) {385m.invoke(null, new Object[] { optionsString, this });386} else {387m.invoke(null, new Object[] { optionsString });388}389390// don't let others access a non-public premain method391setAccessible(m, false);392}393394// WARNING: the native code knows the name & signature of this method395private void396loadClassAndCallPremain( String classname,397String optionsString)398throws Throwable {399400loadClassAndStartAgent( classname, "premain", optionsString );401}402403404// WARNING: the native code knows the name & signature of this method405private void406loadClassAndCallAgentmain( String classname,407String optionsString)408throws Throwable {409410loadClassAndStartAgent( classname, "agentmain", optionsString );411}412413// WARNING: the native code knows the name & signature of this method414private byte[]415transform( ClassLoader loader,416String classname,417Class<?> classBeingRedefined,418ProtectionDomain protectionDomain,419byte[] classfileBuffer,420boolean isRetransformer) {421TransformerManager mgr = isRetransformer?422mRetransfomableTransformerManager :423mTransformerManager;424if (mgr == null) {425return null; // no manager, no transform426} else {427return mgr.transform( loader,428classname,429classBeingRedefined,430protectionDomain,431classfileBuffer);432}433}434}435436437