mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 07:14:30 +02:00
8187443: Forest Consolidation: Move files to unified layout
Reviewed-by: darcy, ihse
This commit is contained in:
parent
270fe13182
commit
3789983e89
56923 changed files with 3 additions and 15727 deletions
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.lang.instrument;
|
||||
|
||||
/*
|
||||
* Copyright 2003 Wily Technology, Inc.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class serves as a parameter block to the <code>Instrumentation.redefineClasses</code> method.
|
||||
* Serves to bind the <code>Class</code> that needs redefining together with the new class file bytes.
|
||||
*
|
||||
* @see java.lang.instrument.Instrumentation#redefineClasses
|
||||
* @since 1.5
|
||||
*/
|
||||
public final class ClassDefinition {
|
||||
/**
|
||||
* The class to redefine
|
||||
*/
|
||||
private final Class<?> mClass;
|
||||
|
||||
/**
|
||||
* The replacement class file bytes
|
||||
*/
|
||||
private final byte[] mClassFile;
|
||||
|
||||
/**
|
||||
* Creates a new <code>ClassDefinition</code> binding using the supplied
|
||||
* class and class file bytes. Does not copy the supplied buffer, just captures a reference to it.
|
||||
*
|
||||
* @param theClass the <code>Class</code> that needs redefining
|
||||
* @param theClassFile the new class file bytes
|
||||
*
|
||||
* @throws java.lang.NullPointerException if the supplied class or array is <code>null</code>.
|
||||
*/
|
||||
public
|
||||
ClassDefinition( Class<?> theClass,
|
||||
byte[] theClassFile) {
|
||||
if (theClass == null || theClassFile == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
mClass = theClass;
|
||||
mClassFile = theClassFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the class.
|
||||
*
|
||||
* @return the <code>Class</code> object referred to.
|
||||
*/
|
||||
public Class<?>
|
||||
getDefinitionClass() {
|
||||
return mClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the array of bytes that contains the new class file.
|
||||
*
|
||||
* @return the class file bytes.
|
||||
*/
|
||||
public byte[]
|
||||
getDefinitionClassFile() {
|
||||
return mClassFile;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.lang.instrument;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.ProtectionDomain;
|
||||
|
||||
/*
|
||||
* Copyright 2003 Wily Technology, Inc.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A transformer of class files. An agent registers an implementation of this
|
||||
* interface using the {@link Instrumentation#addTransformer addTransformer}
|
||||
* method so that the transformer's {@link
|
||||
* ClassFileTransformer#transform(Module,ClassLoader,String,Class,ProtectionDomain,byte[])
|
||||
* transform} method is invoked when classes are loaded,
|
||||
* {@link Instrumentation#redefineClasses redefined}, or
|
||||
* {@link Instrumentation#retransformClasses retransformed}. The implementation
|
||||
* should override one of the {@code transform} methods defined here.
|
||||
* Transformers are invoked before the class is defined by the Java virtual
|
||||
* machine.
|
||||
*
|
||||
* <P>
|
||||
* There are two kinds of transformers, determined by the <code>canRetransform</code>
|
||||
* parameter of
|
||||
* {@link java.lang.instrument.Instrumentation#addTransformer(ClassFileTransformer,boolean)}:
|
||||
* <ul>
|
||||
* <li><i>retransformation capable</i> transformers that were added with
|
||||
* <code>canRetransform</code> as true
|
||||
* </li>
|
||||
* <li><i>retransformation incapable</i> transformers that were added with
|
||||
* <code>canRetransform</code> as false or where added with
|
||||
* {@link java.lang.instrument.Instrumentation#addTransformer(ClassFileTransformer)}
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* <P>
|
||||
* Once a transformer has been registered with
|
||||
* {@link java.lang.instrument.Instrumentation#addTransformer(ClassFileTransformer,boolean)
|
||||
* addTransformer},
|
||||
* the transformer will be called for every new class definition and every class redefinition.
|
||||
* Retransformation capable transformers will also be called on every class retransformation.
|
||||
* The request for a new class definition is made with
|
||||
* {@link java.lang.ClassLoader#defineClass ClassLoader.defineClass}
|
||||
* or its native equivalents.
|
||||
* The request for a class redefinition is made with
|
||||
* {@link java.lang.instrument.Instrumentation#redefineClasses Instrumentation.redefineClasses}
|
||||
* or its native equivalents.
|
||||
* The request for a class retransformation is made with
|
||||
* {@link java.lang.instrument.Instrumentation#retransformClasses Instrumentation.retransformClasses}
|
||||
* or its native equivalents.
|
||||
* The transformer is called during the processing of the request, before the class file bytes
|
||||
* have been verified or applied.
|
||||
* When there are multiple transformers, transformations are composed by chaining the
|
||||
* <code>transform</code> calls.
|
||||
* That is, the byte array returned by one call to <code>transform</code> becomes the input
|
||||
* (via the <code>classfileBuffer</code> parameter) to the next call.
|
||||
*
|
||||
* <P>
|
||||
* Transformations are applied in the following order:
|
||||
* <ul>
|
||||
* <li>Retransformation incapable transformers
|
||||
* </li>
|
||||
* <li>Retransformation incapable native transformers
|
||||
* </li>
|
||||
* <li>Retransformation capable transformers
|
||||
* </li>
|
||||
* <li>Retransformation capable native transformers
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* <P>
|
||||
* For retransformations, the retransformation incapable transformers are not
|
||||
* called, instead the result of the previous transformation is reused.
|
||||
* In all other cases, this method is called.
|
||||
* Within each of these groupings, transformers are called in the order registered.
|
||||
* Native transformers are provided by the <code>ClassFileLoadHook</code> event
|
||||
* in the Java Virtual Machine Tool Interface).
|
||||
*
|
||||
* <P>
|
||||
* The input (via the <code>classfileBuffer</code> parameter) to the first
|
||||
* transformer is:
|
||||
* <ul>
|
||||
* <li>for new class definition,
|
||||
* the bytes passed to <code>ClassLoader.defineClass</code>
|
||||
* </li>
|
||||
* <li>for class redefinition,
|
||||
* <code>definitions.getDefinitionClassFile()</code> where
|
||||
* <code>definitions</code> is the parameter to
|
||||
* {@link java.lang.instrument.Instrumentation#redefineClasses
|
||||
* Instrumentation.redefineClasses}
|
||||
* </li>
|
||||
* <li>for class retransformation,
|
||||
* the bytes passed to the new class definition or, if redefined,
|
||||
* the last redefinition, with all transformations made by retransformation
|
||||
* incapable transformers reapplied automatically and unaltered;
|
||||
* for details see
|
||||
* {@link java.lang.instrument.Instrumentation#retransformClasses
|
||||
* Instrumentation.retransformClasses}
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* <P>
|
||||
* If the implementing method determines that no transformations are needed,
|
||||
* it should return <code>null</code>.
|
||||
* Otherwise, it should create a new <code>byte[]</code> array,
|
||||
* copy the input <code>classfileBuffer</code> into it,
|
||||
* along with all desired transformations, and return the new array.
|
||||
* The input <code>classfileBuffer</code> must not be modified.
|
||||
*
|
||||
* <P>
|
||||
* In the retransform and redefine cases,
|
||||
* the transformer must support the redefinition semantics:
|
||||
* if a class that the transformer changed during initial definition is later
|
||||
* retransformed or redefined, the
|
||||
* transformer must insure that the second class output class file is a legal
|
||||
* redefinition of the first output class file.
|
||||
*
|
||||
* <P>
|
||||
* If the transformer throws an exception (which it doesn't catch),
|
||||
* subsequent transformers will still be called and the load, redefine
|
||||
* or retransform will still be attempted.
|
||||
* Thus, throwing an exception has the same effect as returning <code>null</code>.
|
||||
* To prevent unexpected behavior when unchecked exceptions are generated
|
||||
* in transformer code, a transformer can catch <code>Throwable</code>.
|
||||
* If the transformer believes the <code>classFileBuffer</code> does not
|
||||
* represent a validly formatted class file, it should throw
|
||||
* an <code>IllegalClassFormatException</code>;
|
||||
* while this has the same effect as returning null. it facilitates the
|
||||
* logging or debugging of format corruptions.
|
||||
*
|
||||
* <P>
|
||||
* Note the term <i>class file</i> is used as defined in section 3.1 of
|
||||
* <cite>The Java™ Virtual Machine Specification</cite>, to mean a
|
||||
* sequence of bytes in class file format, whether or not they reside in a
|
||||
* file.
|
||||
*
|
||||
* @see java.lang.instrument.Instrumentation
|
||||
* @since 1.5
|
||||
*/
|
||||
|
||||
public interface ClassFileTransformer {
|
||||
|
||||
/**
|
||||
* Transforms the given class file and returns a new replacement class file.
|
||||
* This method is invoked when the {@link Module Module} bearing {@link
|
||||
* ClassFileTransformer#transform(Module,ClassLoader,String,Class,ProtectionDomain,byte[])
|
||||
* transform} is not overridden.
|
||||
*
|
||||
* @implSpec The default implementation returns null.
|
||||
*
|
||||
* @param loader the defining loader of the class to be transformed,
|
||||
* may be {@code null} if the bootstrap loader
|
||||
* @param className the name of the class in the internal form of fully
|
||||
* qualified class and interface names as defined in
|
||||
* <i>The Java Virtual Machine Specification</i>.
|
||||
* For example, <code>"java/util/List"</code>.
|
||||
* @param classBeingRedefined if this is triggered by a redefine or retransform,
|
||||
* the class being redefined or retransformed;
|
||||
* if this is a class load, {@code null}
|
||||
* @param protectionDomain the protection domain of the class being defined or redefined
|
||||
* @param classfileBuffer the input byte buffer in class file format - must not be modified
|
||||
*
|
||||
* @throws IllegalClassFormatException
|
||||
* if the input does not represent a well-formed class file
|
||||
* @return a well-formed class file buffer (the result of the transform),
|
||||
* or {@code null} if no transform is performed
|
||||
*
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
default byte[]
|
||||
transform( ClassLoader loader,
|
||||
String className,
|
||||
Class<?> classBeingRedefined,
|
||||
ProtectionDomain protectionDomain,
|
||||
byte[] classfileBuffer)
|
||||
throws IllegalClassFormatException {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Transforms the given class file and returns a new replacement class file.
|
||||
*
|
||||
* @implSpec The default implementation of this method invokes the
|
||||
* {@link #transform(ClassLoader,String,Class,ProtectionDomain,byte[]) transform}
|
||||
* method.
|
||||
*
|
||||
* @param module the module of the class to be transformed
|
||||
* @param loader the defining loader of the class to be transformed,
|
||||
* may be {@code null} if the bootstrap loader
|
||||
* @param className the name of the class in the internal form of fully
|
||||
* qualified class and interface names as defined in
|
||||
* <i>The Java Virtual Machine Specification</i>.
|
||||
* For example, <code>"java/util/List"</code>.
|
||||
* @param classBeingRedefined if this is triggered by a redefine or retransform,
|
||||
* the class being redefined or retransformed;
|
||||
* if this is a class load, {@code null}
|
||||
* @param protectionDomain the protection domain of the class being defined or redefined
|
||||
* @param classfileBuffer the input byte buffer in class file format - must not be modified
|
||||
*
|
||||
* @throws IllegalClassFormatException
|
||||
* if the input does not represent a well-formed class file
|
||||
* @return a well-formed class file buffer (the result of the transform),
|
||||
* or {@code null} if no transform is performed
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
default byte[]
|
||||
transform( Module module,
|
||||
ClassLoader loader,
|
||||
String className,
|
||||
Class<?> classBeingRedefined,
|
||||
ProtectionDomain protectionDomain,
|
||||
byte[] classfileBuffer)
|
||||
throws IllegalClassFormatException {
|
||||
|
||||
// invoke the legacy transform method
|
||||
return transform(loader,
|
||||
className,
|
||||
classBeingRedefined,
|
||||
protectionDomain,
|
||||
classfileBuffer);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.lang.instrument;
|
||||
|
||||
/*
|
||||
* Copyright 2003 Wily Technology, Inc.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Thrown by an implementation of
|
||||
* {@link java.lang.instrument.ClassFileTransformer#transform ClassFileTransformer.transform}
|
||||
* when its input parameters are invalid.
|
||||
* This may occur either because the initial class file bytes were
|
||||
* invalid or a previously applied transform corrupted the bytes.
|
||||
*
|
||||
* @see java.lang.instrument.ClassFileTransformer#transform
|
||||
* @since 1.5
|
||||
*/
|
||||
public class IllegalClassFormatException extends Exception {
|
||||
private static final long serialVersionUID = -3841736710924794009L;
|
||||
|
||||
/**
|
||||
* Constructs an <code>IllegalClassFormatException</code> with no
|
||||
* detail message.
|
||||
*/
|
||||
public
|
||||
IllegalClassFormatException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an <code>IllegalClassFormatException</code> with the
|
||||
* specified detail message.
|
||||
*
|
||||
* @param s the detail message.
|
||||
*/
|
||||
public
|
||||
IllegalClassFormatException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,743 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.lang.instrument;
|
||||
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
/*
|
||||
* Copyright 2003 Wily Technology, Inc.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class provides services needed to instrument Java
|
||||
* programming language code.
|
||||
* Instrumentation is the addition of byte-codes to methods for the
|
||||
* purpose of gathering data to be utilized by tools.
|
||||
* Since the changes are purely additive, these tools do not modify
|
||||
* application state or behavior.
|
||||
* Examples of such benign tools include monitoring agents, profilers,
|
||||
* coverage analyzers, and event loggers.
|
||||
*
|
||||
* <P>
|
||||
* There are two ways to obtain an instance of the
|
||||
* <code>Instrumentation</code> interface:
|
||||
*
|
||||
* <ol>
|
||||
* <li><p> When a JVM is launched in a way that indicates an agent
|
||||
* class. In that case an <code>Instrumentation</code> instance
|
||||
* is passed to the <code>premain</code> method of the agent class.
|
||||
* </p></li>
|
||||
* <li><p> When a JVM provides a mechanism to start agents sometime
|
||||
* after the JVM is launched. In that case an <code>Instrumentation</code>
|
||||
* instance is passed to the <code>agentmain</code> method of the
|
||||
* agent code. </p> </li>
|
||||
* </ol>
|
||||
* <p>
|
||||
* These mechanisms are described in the
|
||||
* {@linkplain java.lang.instrument package specification}.
|
||||
* <p>
|
||||
* Once an agent acquires an <code>Instrumentation</code> instance,
|
||||
* the agent may call methods on the instance at any time.
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
public interface Instrumentation {
|
||||
/**
|
||||
* Registers the supplied transformer. All future class definitions
|
||||
* will be seen by the transformer, except definitions of classes upon which any
|
||||
* registered transformer is dependent.
|
||||
* The transformer is called when classes are loaded, when they are
|
||||
* {@linkplain #redefineClasses redefined}. and if <code>canRetransform</code> is true,
|
||||
* when they are {@linkplain #retransformClasses retransformed}.
|
||||
* {@link ClassFileTransformer} defines the order of transform calls.
|
||||
*
|
||||
* If a transformer throws
|
||||
* an exception during execution, the JVM will still call the other registered
|
||||
* transformers in order. The same transformer may be added more than once,
|
||||
* but it is strongly discouraged -- avoid this by creating a new instance of
|
||||
* transformer class.
|
||||
* <P>
|
||||
* This method is intended for use in instrumentation, as described in the
|
||||
* {@linkplain Instrumentation class specification}.
|
||||
*
|
||||
* @param transformer the transformer to register
|
||||
* @param canRetransform can this transformer's transformations be retransformed
|
||||
* @throws java.lang.NullPointerException if passed a <code>null</code> transformer
|
||||
* @throws java.lang.UnsupportedOperationException if <code>canRetransform</code>
|
||||
* is true and the current configuration of the JVM does not allow
|
||||
* retransformation ({@link #isRetransformClassesSupported} is false)
|
||||
* @since 1.6
|
||||
*/
|
||||
void
|
||||
addTransformer(ClassFileTransformer transformer, boolean canRetransform);
|
||||
|
||||
/**
|
||||
* Registers the supplied transformer.
|
||||
* <P>
|
||||
* Same as <code>addTransformer(transformer, false)</code>.
|
||||
*
|
||||
* @param transformer the transformer to register
|
||||
* @throws java.lang.NullPointerException if passed a <code>null</code> transformer
|
||||
* @see #addTransformer(ClassFileTransformer,boolean)
|
||||
*/
|
||||
void
|
||||
addTransformer(ClassFileTransformer transformer);
|
||||
|
||||
/**
|
||||
* Unregisters the supplied transformer. Future class definitions will
|
||||
* not be shown to the transformer. Removes the most-recently-added matching
|
||||
* instance of the transformer. Due to the multi-threaded nature of
|
||||
* class loading, it is possible for a transformer to receive calls
|
||||
* after it has been removed. Transformers should be written defensively
|
||||
* to expect this situation.
|
||||
*
|
||||
* @param transformer the transformer to unregister
|
||||
* @return true if the transformer was found and removed, false if the
|
||||
* transformer was not found
|
||||
* @throws java.lang.NullPointerException if passed a <code>null</code> transformer
|
||||
*/
|
||||
boolean
|
||||
removeTransformer(ClassFileTransformer transformer);
|
||||
|
||||
/**
|
||||
* Returns whether or not the current JVM configuration supports retransformation
|
||||
* of classes.
|
||||
* The ability to retransform an already loaded class is an optional capability
|
||||
* of a JVM.
|
||||
* Retransformation will only be supported if the
|
||||
* <code>Can-Retransform-Classes</code> manifest attribute is set to
|
||||
* <code>true</code> in the agent JAR file (as described in the
|
||||
* {@linkplain java.lang.instrument package specification}) and the JVM supports
|
||||
* this capability.
|
||||
* During a single instantiation of a single JVM, multiple calls to this
|
||||
* method will always return the same answer.
|
||||
* @return true if the current JVM configuration supports retransformation of
|
||||
* classes, false if not.
|
||||
* @see #retransformClasses
|
||||
* @since 1.6
|
||||
*/
|
||||
boolean
|
||||
isRetransformClassesSupported();
|
||||
|
||||
/**
|
||||
* Retransform the supplied set of classes.
|
||||
*
|
||||
* <P>
|
||||
* This function facilitates the instrumentation
|
||||
* of already loaded classes.
|
||||
* When classes are initially loaded or when they are
|
||||
* {@linkplain #redefineClasses redefined},
|
||||
* the initial class file bytes can be transformed with the
|
||||
* {@link java.lang.instrument.ClassFileTransformer ClassFileTransformer}.
|
||||
* This function reruns the transformation process
|
||||
* (whether or not a transformation has previously occurred).
|
||||
* This retransformation follows these steps:
|
||||
* <ul>
|
||||
* <li>starting from the initial class file bytes
|
||||
* </li>
|
||||
* <li>for each transformer that was added with <code>canRetransform</code>
|
||||
* false, the bytes returned by
|
||||
* {@link ClassFileTransformer#transform(Module,ClassLoader,String,Class,ProtectionDomain,byte[])
|
||||
* transform} during the last class load or redefine are
|
||||
* reused as the output of the transformation; note that this is
|
||||
* equivalent to reapplying the previous transformation, unaltered;
|
||||
* except that {@code transform} method is not called.
|
||||
* </li>
|
||||
* <li>for each transformer that was added with <code>canRetransform</code>
|
||||
* true, the
|
||||
* {@link ClassFileTransformer#transform(Module,ClassLoader,String,Class,ProtectionDomain,byte[])
|
||||
* transform} method is called in these transformers
|
||||
* </li>
|
||||
* <li>the transformed class file bytes are installed as the new
|
||||
* definition of the class
|
||||
* </li>
|
||||
* </ul>
|
||||
* <P>
|
||||
*
|
||||
* The order of transformation is described in {@link ClassFileTransformer}.
|
||||
* This same order is used in the automatic reapplication of
|
||||
* retransformation incapable transforms.
|
||||
* <P>
|
||||
*
|
||||
* The initial class file bytes represent the bytes passed to
|
||||
* {@link java.lang.ClassLoader#defineClass ClassLoader.defineClass} or
|
||||
* {@link #redefineClasses redefineClasses}
|
||||
* (before any transformations
|
||||
* were applied), however they might not exactly match them.
|
||||
* The constant pool might not have the same layout or contents.
|
||||
* The constant pool may have more or fewer entries.
|
||||
* Constant pool entries may be in a different order; however,
|
||||
* constant pool indices in the bytecodes of methods will correspond.
|
||||
* Some attributes may not be present.
|
||||
* Where order is not meaningful, for example the order of methods,
|
||||
* order might not be preserved.
|
||||
*
|
||||
* <P>
|
||||
* This method operates on
|
||||
* a set in order to allow interdependent changes to more than one class at the same time
|
||||
* (a retransformation of class A can require a retransformation of class B).
|
||||
*
|
||||
* <P>
|
||||
* If a retransformed method has active stack frames, those active frames continue to
|
||||
* run the bytecodes of the original method.
|
||||
* The retransformed method will be used on new invokes.
|
||||
*
|
||||
* <P>
|
||||
* This method does not cause any initialization except that which would occur
|
||||
* under the customary JVM semantics. In other words, redefining a class
|
||||
* does not cause its initializers to be run. The values of static variables
|
||||
* will remain as they were prior to the call.
|
||||
*
|
||||
* <P>
|
||||
* Instances of the retransformed class are not affected.
|
||||
*
|
||||
* <P>
|
||||
* The retransformation may change method bodies, the constant pool and attributes.
|
||||
* The retransformation must not add, remove or rename fields or methods, change the
|
||||
* signatures of methods, or change inheritance. These restrictions maybe be
|
||||
* lifted in future versions. The class file bytes are not checked, verified and installed
|
||||
* until after the transformations have been applied, if the resultant bytes are in
|
||||
* error this method will throw an exception.
|
||||
*
|
||||
* <P>
|
||||
* If this method throws an exception, no classes have been retransformed.
|
||||
* <P>
|
||||
* This method is intended for use in instrumentation, as described in the
|
||||
* {@linkplain Instrumentation class specification}.
|
||||
*
|
||||
* @param classes array of classes to retransform;
|
||||
* a zero-length array is allowed, in this case, this method does nothing
|
||||
* @throws java.lang.instrument.UnmodifiableClassException if a specified class cannot be modified
|
||||
* ({@link #isModifiableClass} would return <code>false</code>)
|
||||
* @throws java.lang.UnsupportedOperationException if the current configuration of the JVM does not allow
|
||||
* retransformation ({@link #isRetransformClassesSupported} is false) or the retransformation attempted
|
||||
* to make unsupported changes
|
||||
* @throws java.lang.ClassFormatError if the data did not contain a valid class
|
||||
* @throws java.lang.NoClassDefFoundError if the name in the class file is not equal to the name of the class
|
||||
* @throws java.lang.UnsupportedClassVersionError if the class file version numbers are not supported
|
||||
* @throws java.lang.ClassCircularityError if the new classes contain a circularity
|
||||
* @throws java.lang.LinkageError if a linkage error occurs
|
||||
* @throws java.lang.NullPointerException if the supplied classes array or any of its components
|
||||
* is <code>null</code>.
|
||||
*
|
||||
* @see #isRetransformClassesSupported
|
||||
* @see #addTransformer
|
||||
* @see java.lang.instrument.ClassFileTransformer
|
||||
* @since 1.6
|
||||
*/
|
||||
void
|
||||
retransformClasses(Class<?>... classes) throws UnmodifiableClassException;
|
||||
|
||||
/**
|
||||
* Returns whether or not the current JVM configuration supports redefinition
|
||||
* of classes.
|
||||
* The ability to redefine an already loaded class is an optional capability
|
||||
* of a JVM.
|
||||
* Redefinition will only be supported if the
|
||||
* <code>Can-Redefine-Classes</code> manifest attribute is set to
|
||||
* <code>true</code> in the agent JAR file (as described in the
|
||||
* {@linkplain java.lang.instrument package specification}) and the JVM supports
|
||||
* this capability.
|
||||
* During a single instantiation of a single JVM, multiple calls to this
|
||||
* method will always return the same answer.
|
||||
* @return true if the current JVM configuration supports redefinition of classes,
|
||||
* false if not.
|
||||
* @see #redefineClasses
|
||||
*/
|
||||
boolean
|
||||
isRedefineClassesSupported();
|
||||
|
||||
/**
|
||||
* Redefine the supplied set of classes using the supplied class files.
|
||||
*
|
||||
* <P>
|
||||
* This method is used to replace the definition of a class without reference
|
||||
* to the existing class file bytes, as one might do when recompiling from source
|
||||
* for fix-and-continue debugging.
|
||||
* Where the existing class file bytes are to be transformed (for
|
||||
* example in bytecode instrumentation)
|
||||
* {@link #retransformClasses retransformClasses}
|
||||
* should be used.
|
||||
*
|
||||
* <P>
|
||||
* This method operates on
|
||||
* a set in order to allow interdependent changes to more than one class at the same time
|
||||
* (a redefinition of class A can require a redefinition of class B).
|
||||
*
|
||||
* <P>
|
||||
* If a redefined method has active stack frames, those active frames continue to
|
||||
* run the bytecodes of the original method.
|
||||
* The redefined method will be used on new invokes.
|
||||
*
|
||||
* <P>
|
||||
* This method does not cause any initialization except that which would occur
|
||||
* under the customary JVM semantics. In other words, redefining a class
|
||||
* does not cause its initializers to be run. The values of static variables
|
||||
* will remain as they were prior to the call.
|
||||
*
|
||||
* <P>
|
||||
* Instances of the redefined class are not affected.
|
||||
*
|
||||
* <P>
|
||||
* The redefinition may change method bodies, the constant pool and attributes.
|
||||
* The redefinition must not add, remove or rename fields or methods, change the
|
||||
* signatures of methods, or change inheritance. These restrictions maybe be
|
||||
* lifted in future versions. The class file bytes are not checked, verified and installed
|
||||
* until after the transformations have been applied, if the resultant bytes are in
|
||||
* error this method will throw an exception.
|
||||
*
|
||||
* <P>
|
||||
* If this method throws an exception, no classes have been redefined.
|
||||
* <P>
|
||||
* This method is intended for use in instrumentation, as described in the
|
||||
* {@linkplain Instrumentation class specification}.
|
||||
*
|
||||
* @param definitions array of classes to redefine with corresponding definitions;
|
||||
* a zero-length array is allowed, in this case, this method does nothing
|
||||
* @throws java.lang.instrument.UnmodifiableClassException if a specified class cannot be modified
|
||||
* ({@link #isModifiableClass} would return <code>false</code>)
|
||||
* @throws java.lang.UnsupportedOperationException if the current configuration of the JVM does not allow
|
||||
* redefinition ({@link #isRedefineClassesSupported} is false) or the redefinition attempted
|
||||
* to make unsupported changes
|
||||
* @throws java.lang.ClassFormatError if the data did not contain a valid class
|
||||
* @throws java.lang.NoClassDefFoundError if the name in the class file is not equal to the name of the class
|
||||
* @throws java.lang.UnsupportedClassVersionError if the class file version numbers are not supported
|
||||
* @throws java.lang.ClassCircularityError if the new classes contain a circularity
|
||||
* @throws java.lang.LinkageError if a linkage error occurs
|
||||
* @throws java.lang.NullPointerException if the supplied definitions array or any of its components
|
||||
* is <code>null</code>
|
||||
* @throws java.lang.ClassNotFoundException Can never be thrown (present for compatibility reasons only)
|
||||
*
|
||||
* @see #isRedefineClassesSupported
|
||||
* @see #addTransformer
|
||||
* @see java.lang.instrument.ClassFileTransformer
|
||||
*/
|
||||
void
|
||||
redefineClasses(ClassDefinition... definitions)
|
||||
throws ClassNotFoundException, UnmodifiableClassException;
|
||||
|
||||
|
||||
/**
|
||||
* Tests whether a class is modifiable by
|
||||
* {@linkplain #retransformClasses retransformation}
|
||||
* or {@linkplain #redefineClasses redefinition}.
|
||||
* If a class is modifiable then this method returns <code>true</code>.
|
||||
* If a class is not modifiable then this method returns <code>false</code>.
|
||||
* <P>
|
||||
* For a class to be retransformed, {@link #isRetransformClassesSupported} must also be true.
|
||||
* But the value of <code>isRetransformClassesSupported()</code> does not influence the value
|
||||
* returned by this function.
|
||||
* For a class to be redefined, {@link #isRedefineClassesSupported} must also be true.
|
||||
* But the value of <code>isRedefineClassesSupported()</code> does not influence the value
|
||||
* returned by this function.
|
||||
* <P>
|
||||
* Primitive classes (for example, <code>java.lang.Integer.TYPE</code>)
|
||||
* and array classes are never modifiable.
|
||||
*
|
||||
* @param theClass the class to check for being modifiable
|
||||
* @return whether or not the argument class is modifiable
|
||||
* @throws java.lang.NullPointerException if the specified class is <code>null</code>.
|
||||
*
|
||||
* @see #retransformClasses
|
||||
* @see #isRetransformClassesSupported
|
||||
* @see #redefineClasses
|
||||
* @see #isRedefineClassesSupported
|
||||
* @since 1.6
|
||||
*/
|
||||
boolean
|
||||
isModifiableClass(Class<?> theClass);
|
||||
|
||||
/**
|
||||
* Returns an array of all classes currently loaded by the JVM.
|
||||
*
|
||||
* @return an array containing all the classes loaded by the JVM, zero-length if there are none
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
Class[]
|
||||
getAllLoadedClasses();
|
||||
|
||||
/**
|
||||
* Returns an array of all classes for which <code>loader</code> is an initiating loader.
|
||||
* If the supplied loader is <code>null</code>, classes initiated by the bootstrap class
|
||||
* loader are returned.
|
||||
*
|
||||
* @param loader the loader whose initiated class list will be returned
|
||||
* @return an array containing all the classes for which loader is an initiating loader,
|
||||
* zero-length if there are none
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
Class[]
|
||||
getInitiatedClasses(ClassLoader loader);
|
||||
|
||||
/**
|
||||
* Returns an implementation-specific approximation of the amount of storage consumed by
|
||||
* the specified object. The result may include some or all of the object's overhead,
|
||||
* and thus is useful for comparison within an implementation but not between implementations.
|
||||
*
|
||||
* The estimate may change during a single invocation of the JVM.
|
||||
*
|
||||
* @param objectToSize the object to size
|
||||
* @return an implementation-specific approximation of the amount of storage consumed by the specified object
|
||||
* @throws java.lang.NullPointerException if the supplied Object is <code>null</code>.
|
||||
*/
|
||||
long
|
||||
getObjectSize(Object objectToSize);
|
||||
|
||||
|
||||
/**
|
||||
* Specifies a JAR file with instrumentation classes to be defined by the
|
||||
* bootstrap class loader.
|
||||
*
|
||||
* <p> When the virtual machine's built-in class loader, known as the "bootstrap
|
||||
* class loader", unsuccessfully searches for a class, the entries in the {@link
|
||||
* java.util.jar.JarFile JAR file} will be searched as well.
|
||||
*
|
||||
* <p> This method may be used multiple times to add multiple JAR files to be
|
||||
* searched in the order that this method was invoked.
|
||||
*
|
||||
* <p> The agent should take care to ensure that the JAR does not contain any
|
||||
* classes or resources other than those to be defined by the bootstrap
|
||||
* class loader for the purpose of instrumentation.
|
||||
* Failure to observe this warning could result in unexpected
|
||||
* behavior that is difficult to diagnose. For example, suppose there is a
|
||||
* loader L, and L's parent for delegation is the bootstrap class loader.
|
||||
* Furthermore, a method in class C, a class defined by L, makes reference to
|
||||
* a non-public accessor class C$1. If the JAR file contains a class C$1 then
|
||||
* the delegation to the bootstrap class loader will cause C$1 to be defined
|
||||
* by the bootstrap class loader. In this example an <code>IllegalAccessError</code>
|
||||
* will be thrown that may cause the application to fail. One approach to
|
||||
* avoiding these types of issues, is to use a unique package name for the
|
||||
* instrumentation classes.
|
||||
*
|
||||
* <p>
|
||||
* <cite>The Java™ Virtual Machine Specification</cite>
|
||||
* specifies that a subsequent attempt to resolve a symbolic
|
||||
* reference that the Java virtual machine has previously unsuccessfully attempted
|
||||
* to resolve always fails with the same error that was thrown as a result of the
|
||||
* initial resolution attempt. Consequently, if the JAR file contains an entry
|
||||
* that corresponds to a class for which the Java virtual machine has
|
||||
* unsuccessfully attempted to resolve a reference, then subsequent attempts to
|
||||
* resolve that reference will fail with the same error as the initial attempt.
|
||||
*
|
||||
* @param jarfile
|
||||
* The JAR file to be searched when the bootstrap class loader
|
||||
* unsuccessfully searches for a class.
|
||||
*
|
||||
* @throws NullPointerException
|
||||
* If <code>jarfile</code> is <code>null</code>.
|
||||
*
|
||||
* @see #appendToSystemClassLoaderSearch
|
||||
* @see java.lang.ClassLoader
|
||||
* @see java.util.jar.JarFile
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
void
|
||||
appendToBootstrapClassLoaderSearch(JarFile jarfile);
|
||||
|
||||
/**
|
||||
* Specifies a JAR file with instrumentation classes to be defined by the
|
||||
* system class loader.
|
||||
*
|
||||
* When the system class loader for delegation (see
|
||||
* {@link java.lang.ClassLoader#getSystemClassLoader getSystemClassLoader()})
|
||||
* unsuccessfully searches for a class, the entries in the {@link
|
||||
* java.util.jar.JarFile JarFile} will be searched as well.
|
||||
*
|
||||
* <p> This method may be used multiple times to add multiple JAR files to be
|
||||
* searched in the order that this method was invoked.
|
||||
*
|
||||
* <p> The agent should take care to ensure that the JAR does not contain any
|
||||
* classes or resources other than those to be defined by the system class
|
||||
* loader for the purpose of instrumentation.
|
||||
* Failure to observe this warning could result in unexpected
|
||||
* behavior that is difficult to diagnose (see
|
||||
* {@link #appendToBootstrapClassLoaderSearch
|
||||
* appendToBootstrapClassLoaderSearch}).
|
||||
*
|
||||
* <p> The system class loader supports adding a JAR file to be searched if
|
||||
* it implements a method named <code>appendToClassPathForInstrumentation</code>
|
||||
* which takes a single parameter of type <code>java.lang.String</code>. The
|
||||
* method is not required to have <code>public</code> access. The name of
|
||||
* the JAR file is obtained by invoking the {@link java.util.zip.ZipFile#getName
|
||||
* getName()} method on the <code>jarfile</code> and this is provided as the
|
||||
* parameter to the <code>appendToClassPathForInstrumentation</code> method.
|
||||
*
|
||||
* <p>
|
||||
* <cite>The Java™ Virtual Machine Specification</cite>
|
||||
* specifies that a subsequent attempt to resolve a symbolic
|
||||
* reference that the Java virtual machine has previously unsuccessfully attempted
|
||||
* to resolve always fails with the same error that was thrown as a result of the
|
||||
* initial resolution attempt. Consequently, if the JAR file contains an entry
|
||||
* that corresponds to a class for which the Java virtual machine has
|
||||
* unsuccessfully attempted to resolve a reference, then subsequent attempts to
|
||||
* resolve that reference will fail with the same error as the initial attempt.
|
||||
*
|
||||
* <p> This method does not change the value of <code>java.class.path</code>
|
||||
* {@link java.lang.System#getProperties system property}.
|
||||
*
|
||||
* @param jarfile
|
||||
* The JAR file to be searched when the system class loader
|
||||
* unsuccessfully searches for a class.
|
||||
*
|
||||
* @throws UnsupportedOperationException
|
||||
* If the system class loader does not support appending a
|
||||
* a JAR file to be searched.
|
||||
*
|
||||
* @throws NullPointerException
|
||||
* If <code>jarfile</code> is <code>null</code>.
|
||||
*
|
||||
* @see #appendToBootstrapClassLoaderSearch
|
||||
* @see java.lang.ClassLoader#getSystemClassLoader
|
||||
* @see java.util.jar.JarFile
|
||||
* @since 1.6
|
||||
*/
|
||||
void
|
||||
appendToSystemClassLoaderSearch(JarFile jarfile);
|
||||
|
||||
/**
|
||||
* Returns whether the current JVM configuration supports
|
||||
* {@linkplain #setNativeMethodPrefix(ClassFileTransformer,String)
|
||||
* setting a native method prefix}.
|
||||
* The ability to set a native method prefix is an optional
|
||||
* capability of a JVM.
|
||||
* Setting a native method prefix will only be supported if the
|
||||
* <code>Can-Set-Native-Method-Prefix</code> manifest attribute is set to
|
||||
* <code>true</code> in the agent JAR file (as described in the
|
||||
* {@linkplain java.lang.instrument package specification}) and the JVM supports
|
||||
* this capability.
|
||||
* During a single instantiation of a single JVM, multiple
|
||||
* calls to this method will always return the same answer.
|
||||
* @return true if the current JVM configuration supports
|
||||
* setting a native method prefix, false if not.
|
||||
* @see #setNativeMethodPrefix
|
||||
* @since 1.6
|
||||
*/
|
||||
boolean
|
||||
isNativeMethodPrefixSupported();
|
||||
|
||||
/**
|
||||
* This method modifies the failure handling of
|
||||
* native method resolution by allowing retry
|
||||
* with a prefix applied to the name.
|
||||
* When used with the
|
||||
* {@link java.lang.instrument.ClassFileTransformer ClassFileTransformer},
|
||||
* it enables native methods to be
|
||||
* instrumented.
|
||||
* <p>
|
||||
* Since native methods cannot be directly instrumented
|
||||
* (they have no bytecodes), they must be wrapped with
|
||||
* a non-native method which can be instrumented.
|
||||
* For example, if we had:
|
||||
* <pre>
|
||||
* native boolean foo(int x);</pre>
|
||||
* <p>
|
||||
* We could transform the class file (with the
|
||||
* ClassFileTransformer during the initial definition
|
||||
* of the class) so that this becomes:
|
||||
* <pre>
|
||||
* boolean foo(int x) {
|
||||
* <i>... record entry to foo ...</i>
|
||||
* return wrapped_foo(x);
|
||||
* }
|
||||
*
|
||||
* native boolean wrapped_foo(int x);</pre>
|
||||
* <p>
|
||||
* Where <code>foo</code> becomes a wrapper for the actual native
|
||||
* method with the appended prefix "wrapped_". Note that
|
||||
* "wrapped_" would be a poor choice of prefix since it
|
||||
* might conceivably form the name of an existing method
|
||||
* thus something like "$$$MyAgentWrapped$$$_" would be
|
||||
* better but would make these examples less readable.
|
||||
* <p>
|
||||
* The wrapper will allow data to be collected on the native
|
||||
* method call, but now the problem becomes linking up the
|
||||
* wrapped method with the native implementation.
|
||||
* That is, the method <code>wrapped_foo</code> needs to be
|
||||
* resolved to the native implementation of <code>foo</code>,
|
||||
* which might be:
|
||||
* <pre>
|
||||
* Java_somePackage_someClass_foo(JNIEnv* env, jint x)</pre>
|
||||
* <p>
|
||||
* This function allows the prefix to be specified and the
|
||||
* proper resolution to occur.
|
||||
* Specifically, when the standard resolution fails, the
|
||||
* resolution is retried taking the prefix into consideration.
|
||||
* There are two ways that resolution occurs, explicit
|
||||
* resolution with the JNI function <code>RegisterNatives</code>
|
||||
* and the normal automatic resolution. For
|
||||
* <code>RegisterNatives</code>, the JVM will attempt this
|
||||
* association:
|
||||
* <pre>{@code
|
||||
* method(foo) -> nativeImplementation(foo)
|
||||
* }</pre>
|
||||
* <p>
|
||||
* When this fails, the resolution will be retried with
|
||||
* the specified prefix prepended to the method name,
|
||||
* yielding the correct resolution:
|
||||
* <pre>{@code
|
||||
* method(wrapped_foo) -> nativeImplementation(foo)
|
||||
* }</pre>
|
||||
* <p>
|
||||
* For automatic resolution, the JVM will attempt:
|
||||
* <pre>{@code
|
||||
* method(wrapped_foo) -> nativeImplementation(wrapped_foo)
|
||||
* }</pre>
|
||||
* <p>
|
||||
* When this fails, the resolution will be retried with
|
||||
* the specified prefix deleted from the implementation name,
|
||||
* yielding the correct resolution:
|
||||
* <pre>{@code
|
||||
* method(wrapped_foo) -> nativeImplementation(foo)
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Note that since the prefix is only used when standard
|
||||
* resolution fails, native methods can be wrapped selectively.
|
||||
* <p>
|
||||
* Since each <code>ClassFileTransformer</code>
|
||||
* can do its own transformation of the bytecodes, more
|
||||
* than one layer of wrappers may be applied. Thus each
|
||||
* transformer needs its own prefix. Since transformations
|
||||
* are applied in order, the prefixes, if applied, will
|
||||
* be applied in the same order
|
||||
* (see {@link #addTransformer(ClassFileTransformer,boolean) addTransformer}).
|
||||
* Thus if three transformers applied
|
||||
* wrappers, <code>foo</code> might become
|
||||
* <code>$trans3_$trans2_$trans1_foo</code>. But if, say,
|
||||
* the second transformer did not apply a wrapper to
|
||||
* <code>foo</code> it would be just
|
||||
* <code>$trans3_$trans1_foo</code>. To be able to
|
||||
* efficiently determine the sequence of prefixes,
|
||||
* an intermediate prefix is only applied if its non-native
|
||||
* wrapper exists. Thus, in the last example, even though
|
||||
* <code>$trans1_foo</code> is not a native method, the
|
||||
* <code>$trans1_</code> prefix is applied since
|
||||
* <code>$trans1_foo</code> exists.
|
||||
*
|
||||
* @param transformer
|
||||
* The ClassFileTransformer which wraps using this prefix.
|
||||
* @param prefix
|
||||
* The prefix to apply to wrapped native methods when
|
||||
* retrying a failed native method resolution. If prefix
|
||||
* is either <code>null</code> or the empty string, then
|
||||
* failed native method resolutions are not retried for
|
||||
* this transformer.
|
||||
* @throws java.lang.NullPointerException if passed a <code>null</code> transformer.
|
||||
* @throws java.lang.UnsupportedOperationException if the current configuration of
|
||||
* the JVM does not allow setting a native method prefix
|
||||
* ({@link #isNativeMethodPrefixSupported} is false).
|
||||
* @throws java.lang.IllegalArgumentException if the transformer is not registered
|
||||
* (see {@link #addTransformer(ClassFileTransformer,boolean) addTransformer}).
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
void
|
||||
setNativeMethodPrefix(ClassFileTransformer transformer, String prefix);
|
||||
|
||||
/**
|
||||
* Redefine a module to expand the set of modules that it reads, the set of
|
||||
* packages that it exports or opens, or the services that it uses or
|
||||
* provides. This method facilitates the instrumentation of code in named
|
||||
* modules where that instrumentation requires changes to the set of modules
|
||||
* that are read, the packages that are exported or open, or the services
|
||||
* that are used or provided.
|
||||
*
|
||||
* <p> This method cannot reduce the set of modules that a module reads, nor
|
||||
* reduce the set of packages that it exports or opens, nor reduce the set
|
||||
* of services that it uses or provides. This method is a no-op when invoked
|
||||
* to redefine an unnamed module. </p>
|
||||
*
|
||||
* <p> When expanding the services that a module uses or provides then the
|
||||
* onus is on the agent to ensure that the service type will be accessible at
|
||||
* each instrumentation site where the service type is used. This method
|
||||
* does not check if the service type is a member of the module or in a
|
||||
* package exported to the module by another module that it reads. </p>
|
||||
*
|
||||
* <p> The {@code extraExports} parameter is the map of additional packages
|
||||
* to export. The {@code extraOpens} parameter is the map of additional
|
||||
* packages to open. In both cases, the map key is the fully-qualified name
|
||||
* of the package as defined in section 6.5.3 of
|
||||
* <cite>The Java™ Language Specification </cite>, for example, {@code
|
||||
* "java.lang"}. The map value is the non-empty set of modules that the
|
||||
* package should be exported or opened to. </p>
|
||||
*
|
||||
* <p> The {@code extraProvides} parameter is the additional service providers
|
||||
* for the module to provide. The map key is the service type. The map value
|
||||
* is the non-empty list of implementation types, each of which is a member
|
||||
* of the module and an implementation of the service. </p>
|
||||
*
|
||||
* <p> This method is safe for concurrent use and so allows multiple agents
|
||||
* to instrument and update the same module at around the same time. </p>
|
||||
*
|
||||
* @param module the module to redefine
|
||||
* @param extraReads the possibly-empty set of additional modules to read
|
||||
* @param extraExports the possibly-empty map of additional packages to export
|
||||
* @param extraOpens the possibly-empty map of additional packages to open
|
||||
* @param extraUses the possibly-empty set of additional services to use
|
||||
* @param extraProvides the possibly-empty map of additional services to provide
|
||||
*
|
||||
* @throws IllegalArgumentException
|
||||
* If {@code extraExports} or {@code extraOpens} contains a key
|
||||
* that is not a package in the module; if {@code extraExports} or
|
||||
* {@code extraOpens} maps a key to an empty set; if a value in the
|
||||
* {@code extraProvides} map contains a service provider type that
|
||||
* is not a member of the module or an implementation of the service;
|
||||
* or {@code extraProvides} maps a key to an empty list
|
||||
* @throws UnmodifiableModuleException if the module cannot be modified
|
||||
* @throws NullPointerException if any of the arguments are {@code null} or
|
||||
* any of the Sets or Maps contains a {@code null} key or value
|
||||
*
|
||||
* @see #isModifiableModule(Module)
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
void redefineModule(Module module,
|
||||
Set<Module> extraReads,
|
||||
Map<String, Set<Module>> extraExports,
|
||||
Map<String, Set<Module>> extraOpens,
|
||||
Set<Class<?>> extraUses,
|
||||
Map<Class<?>, List<Class<?>>> extraProvides);
|
||||
|
||||
/**
|
||||
* Tests whether a module can be modified with {@link #redefineModule
|
||||
* redefineModule}. If a module is modifiable then this method returns
|
||||
* {@code true}. If a module is not modifiable then this method returns
|
||||
* {@code false}. This method always returns {@code true} when the module
|
||||
* is an unnamed module (as redefining an unnamed module is a no-op).
|
||||
*
|
||||
* @param module the module to test if it can be modified
|
||||
* @return {@code true} if the module is modifiable, otherwise {@code false}
|
||||
* @throws NullPointerException if the module is {@code null}
|
||||
*
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
boolean isModifiableModule(Module module);
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2004, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.lang.instrument;
|
||||
|
||||
/**
|
||||
* Thrown by an implementation of
|
||||
* {@link java.lang.instrument.Instrumentation#redefineClasses Instrumentation.redefineClasses}
|
||||
* when one of the specified classes cannot be modified.
|
||||
*
|
||||
* @see java.lang.instrument.Instrumentation#redefineClasses
|
||||
* @since 1.5
|
||||
*/
|
||||
public class UnmodifiableClassException extends Exception {
|
||||
private static final long serialVersionUID = 1716652643585309178L;
|
||||
|
||||
/**
|
||||
* Constructs an <code>UnmodifiableClassException</code> with no
|
||||
* detail message.
|
||||
*/
|
||||
public
|
||||
UnmodifiableClassException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an <code>UnmodifiableClassException</code> with the
|
||||
* specified detail message.
|
||||
*
|
||||
* @param s the detail message.
|
||||
*/
|
||||
public
|
||||
UnmodifiableClassException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.lang.instrument;
|
||||
|
||||
/**
|
||||
* Thrown to indicate that a module cannot be modified.
|
||||
*
|
||||
* @see Instrumentation#redefineModule
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
|
||||
public class UnmodifiableModuleException extends RuntimeException {
|
||||
private static final long serialVersionUID = 6912511912351080644L;
|
||||
|
||||
/**
|
||||
* Constructs an {@code UnmodifiableModuleException} with no
|
||||
* detail message.
|
||||
*/
|
||||
public UnmodifiableModuleException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an {@code UnmodifiableModuleException} with the
|
||||
* specified detail message.
|
||||
*
|
||||
* @param msg the detail message.
|
||||
*/
|
||||
public UnmodifiableModuleException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,326 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the Classpath exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2003 Wily Technology, Inc.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Provides services that allow Java programming language agents to instrument
|
||||
* programs running on the JVM. The mechanism for instrumentation is modification
|
||||
* of the byte-codes of methods.
|
||||
*
|
||||
* <p> An agent is deployed as a JAR file. An attribute in the JAR file manifest
|
||||
* specifies the agent class which will be loaded to start the agent. Agents can
|
||||
* be started in several ways:
|
||||
*
|
||||
* <ol>
|
||||
* <li><p> For implementations that support a command-line interface, an agent
|
||||
* can be started by specifying an option on the command-line. </p></li>
|
||||
*
|
||||
* <li><p> An implementation may support a mechanism to start agents some time
|
||||
* after the VM has started. For example, an implementation may provide a
|
||||
* mechanism that allows a tool to <i>attach</i> to a running application, and
|
||||
* initiate the loading of the tool's agent into the running application. </p></li>
|
||||
*
|
||||
* <li><p> An agent may be packaged with an application in an executable JAR
|
||||
* file.</p></li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> Each of these ways to start an agent is described below.
|
||||
*
|
||||
*
|
||||
* <h3>Starting an Agent from the Command-Line Interface</h3>
|
||||
*
|
||||
* <p> Where an implementation provides a means to start agents from the
|
||||
* command-line interface, an agent is started by adding the following option
|
||||
* to the command-line:
|
||||
*
|
||||
* <blockquote>{@code
|
||||
* -javaagent:<jarpath>[=<options>]
|
||||
* }</blockquote>
|
||||
*
|
||||
* where <i>{@code <jarpath>}</i> is the path to the agent JAR file and
|
||||
* <i>{@code <options>}</i> is the agent options.
|
||||
*
|
||||
* <p> The manifest of the agent JAR file must contain the attribute {@code
|
||||
* Premain-Class} in its main manifest. The value of this attribute is the
|
||||
* name of the <i>agent class</i>. The agent class must implement a public
|
||||
* static {@code premain} method similar in principle to the {@code main}
|
||||
* application entry point. After the Java Virtual Machine (JVM) has
|
||||
* initialized, the {@code premain} method will be called, then the real
|
||||
* application {@code main} method. The {@code premain} method must return
|
||||
* in order for the startup to proceed.
|
||||
*
|
||||
* <p> The {@code premain} method has one of two possible signatures. The
|
||||
* JVM first attempts to invoke the following method on the agent class:
|
||||
*
|
||||
* <blockquote>{@code
|
||||
* public static void premain(String agentArgs, Instrumentation inst)
|
||||
* }</blockquote>
|
||||
*
|
||||
* <p> If the agent class does not implement this method then the JVM will
|
||||
* attempt to invoke:
|
||||
* <blockquote>{@code
|
||||
* public static void premain(String agentArgs)
|
||||
* }</blockquote>
|
||||
|
||||
* <p> The agent class may also have an {@code agentmain} method for use when
|
||||
* the agent is started after VM startup (see below). When the agent is started
|
||||
* using a command-line option, the {@code agentmain} method is not invoked.
|
||||
*
|
||||
* <p> Each agent is passed its agent options via the {@code agentArgs} parameter.
|
||||
* The agent options are passed as a single string, any additional parsing
|
||||
* should be performed by the agent itself.
|
||||
*
|
||||
* <p> If the agent cannot be started (for example, because the agent class
|
||||
* cannot be loaded, or because the agent class does not have an appropriate
|
||||
* {@code premain} method), the JVM will abort. If a {@code premain} method
|
||||
* throws an uncaught exception, the JVM will abort.
|
||||
*
|
||||
* <p> An implementation is not required to provide a way to start agents
|
||||
* from the command-line interface. When it does, then it supports the
|
||||
* {@code -javaagent} option as specified above. The {@code -javaagent} option
|
||||
* may be used multiple times on the same command-line, thus starting multiple
|
||||
* agents. The {@code premain} methods will be called in the order that the
|
||||
* agents are specified on the command line. More than one agent may use the
|
||||
* same <i>{@code <jarpath>}</i>.
|
||||
*
|
||||
* <p> There are no modeling restrictions on what the agent {@code premain}
|
||||
* method may do. Anything application {@code main} can do, including creating
|
||||
* threads, is legal from {@code premain}.
|
||||
*
|
||||
*
|
||||
* <h3>Starting an Agent After VM Startup</h3>
|
||||
*
|
||||
* <p> An implementation may provide a mechanism to start agents sometime after
|
||||
* the the VM has started. The details as to how this is initiated are
|
||||
* implementation specific but typically the application has already started and
|
||||
* its {@code main} method has already been invoked. In cases where an
|
||||
* implementation supports the starting of agents after the VM has started the
|
||||
* following applies:
|
||||
*
|
||||
* <ol>
|
||||
*
|
||||
* <li><p> The manifest of the agent JAR must contain the attribute {@code
|
||||
* Agent-Class} in its main manfiest. The value of this attribute is the name
|
||||
* of the <i>agent class</i>. </p></li>
|
||||
*
|
||||
* <li><p> The agent class must implement a public static {@code agentmain}
|
||||
* method. </p></li>
|
||||
*
|
||||
* </ol>
|
||||
*
|
||||
* <p> The {@code agentmain} method has one of two possible signatures. The JVM
|
||||
* first attempts to invoke the following method on the agent class:
|
||||
*
|
||||
* <blockquote>{@code
|
||||
* public static void agentmain(String agentArgs, Instrumentation inst)
|
||||
* }</blockquote>
|
||||
*
|
||||
* <p> If the agent class does not implement this method then the JVM will
|
||||
* attempt to invoke:
|
||||
*
|
||||
* <blockquote>{@code
|
||||
* public static void agentmain(String agentArgs)
|
||||
* }</blockquote>
|
||||
*
|
||||
* <p> The agent class may also have a {@code premain} method for use when the
|
||||
* agent is started using a command-line option. When the agent is started after
|
||||
* VM startup the {@code premain} method is not invoked.
|
||||
*
|
||||
* <p> The agent is passed its agent options via the {@code agentArgs}
|
||||
* parameter. The agent options are passed as a single string, any additional
|
||||
* parsing should be performed by the agent itself.
|
||||
*
|
||||
* <p> The {@code agentmain} method should do any necessary initialization
|
||||
* required to start the agent. When startup is complete the method should
|
||||
* return. If the agent cannot be started (for example, because the agent class
|
||||
* cannot be loaded, or because the agent class does not have a conformant
|
||||
* {@code agentmain} method), the JVM will not abort. If the {@code agentmain}
|
||||
* method throws an uncaught exception it will be ignored (but may be logged
|
||||
* by the JVM for troubleshooting purposes).
|
||||
*
|
||||
*
|
||||
* <h3>Including an Agent in an Executable JAR file</h3>
|
||||
*
|
||||
* <p> The JAR File Specification defines manifest attributes for standalone
|
||||
* applications that are packaged as <em>executable JAR files</em>. If an
|
||||
* implementation supports a mechanism to start an application as an executable
|
||||
* JAR then the main manifest may include the {@code Launcher-Agent-Class}
|
||||
* attribute to specify the class name of an agent to start before the application
|
||||
* {@code main} method is invoked. The Java virtual machine attempts to
|
||||
* invoke the following method on the agent class:
|
||||
*
|
||||
* <blockquote>{@code
|
||||
* public static void agentmain(String agentArgs, Instrumentation inst)
|
||||
* }</blockquote>
|
||||
*
|
||||
* <p> If the agent class does not implement this method then the JVM will
|
||||
* attempt to invoke:
|
||||
*
|
||||
* <blockquote>{@code
|
||||
* public static void agentmain(String agentArgs)
|
||||
* }</blockquote>
|
||||
*
|
||||
* <p> The value of the {@code agentArgs} parameter is always the empty string.
|
||||
*
|
||||
* <p> The {@code agentmain} method should do any necessary initialization
|
||||
* required to start the agent and return. If the agent cannot be started, for
|
||||
* example the agent class cannot be loaded, the agent class does not define a
|
||||
* conformant {@code agentmain} method, or the {@code agentmain} method throws
|
||||
* an uncaught exception or error, the JVM will abort.
|
||||
*
|
||||
*
|
||||
* <h3> Loading agent classes and the modules/classes available to the agent
|
||||
* class </h3>
|
||||
*
|
||||
* <p> Classes loaded from the agent JAR file are loaded by the
|
||||
* {@linkplain ClassLoader#getSystemClassLoader() system class loader} and are
|
||||
* members of the system class loader's {@linkplain ClassLoader#getUnnamedModule()
|
||||
* unnamed module}. The system class loader typically defines the class containing
|
||||
* the application {@code main} method too.
|
||||
*
|
||||
* <p> The classes visible to the agent class are the classes visible to the system
|
||||
* class loader and minimally include:
|
||||
*
|
||||
* <ul>
|
||||
*
|
||||
* <li><p> The classes in packages exported by the modules in the {@linkplain
|
||||
* ModuleLayer#boot() boot layer}. Whether the boot layer contains all platform
|
||||
* modules or not will depend on the initial module or how the application was
|
||||
* started. </p></li>
|
||||
*
|
||||
* <li><p> The classes that can be defined by the system class loader (typically
|
||||
* the class path) to be members of its unnamed module. </p></li>
|
||||
*
|
||||
* <li><p> Any classes that the agent arranges to be defined by the bootstrap
|
||||
* class loader to be members of its unnamed module. </p></li>
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* <p> If agent classes need to link to classes in platform (or other) modules
|
||||
* that are not in the boot layer then the application may need to be started in
|
||||
* a way that ensures that these modules are in the boot layer. In the JDK
|
||||
* implementation for example, the {@code --add-modules} command line option can
|
||||
* be used to add modules to the set of root modules to resolve at startup. </p>
|
||||
*
|
||||
* <p> Supporting classes that the agent arranges to be loaded by the bootstrap
|
||||
* class loader (by means of {@link Instrumentation#appendToBootstrapClassLoaderSearch
|
||||
* appendToBootstrapClassLoaderSearch} or the {@code Boot-Class-Path} attribute
|
||||
* specified below), must link only to classes defined to the bootstrap class loader.
|
||||
* There is no guarantee that all platform classes can be defined by the boot
|
||||
* class loader.
|
||||
*
|
||||
* <p> If a custom system class loader is configured (by means of the system property
|
||||
* {@code java.system.class.loader} as specified in the {@link
|
||||
* ClassLoader#getSystemClassLoader() getSystemClassLoader} method) then it must
|
||||
* define the {@code appendToClassPathForInstrumentation} method as specified in
|
||||
* {@link Instrumentation#appendToSystemClassLoaderSearch appendToSystemClassLoaderSearch}.
|
||||
* In other words, a custom system class loader must support the mechanism to
|
||||
* add an agent JAR file to the system class loader search.
|
||||
*
|
||||
* <h3>Manifest Attributes</h3>
|
||||
*
|
||||
* <p> The following manifest attributes are defined for an agent JAR file:
|
||||
*
|
||||
* <blockquote><dl>
|
||||
*
|
||||
* <dt>{@code Premain-Class}</dt>
|
||||
* <dd> When an agent is specified at JVM launch time this attribute specifies
|
||||
* the agent class. That is, the class containing the {@code premain} method.
|
||||
* When an agent is specified at JVM launch time this attribute is required. If
|
||||
* the attribute is not present the JVM will abort. Note: this is a class name,
|
||||
* not a file name or path. </dd>
|
||||
*
|
||||
* <dt>{@code Agent-Class}</dt>
|
||||
* <dd> If an implementation supports a mechanism to start agents sometime after
|
||||
* the VM has started then this attribute specifies the agent class. That is,
|
||||
* the class containing the {@code agentmain} method. This attribute is required
|
||||
* if it is not present the agent will not be started. Note: this is a class name,
|
||||
* not a file name or path. </dd>
|
||||
*
|
||||
* <dt>{@code Launcher-Agent-Class}</dt>
|
||||
* <dd> If an implementation supports a mechanism to start an application as an
|
||||
* executable JAR then the main manifest may include this attribute to specify
|
||||
* the class name of an agent to start before the application {@code main}
|
||||
* method is invoked. </dd>
|
||||
*
|
||||
* <dt>{@code Boot-Class-Path}</dt>
|
||||
* <dd> A list of paths to be searched by the bootstrap class loader. Paths
|
||||
* represent directories or libraries (commonly referred to as JAR or zip
|
||||
* libraries on many platforms). These paths are searched by the bootstrap class
|
||||
* loader after the platform specific mechanisms of locating a class have failed.
|
||||
* Paths are searched in the order listed. Paths in the list are separated by one
|
||||
* or more spaces. A path takes the syntax of the path component of a hierarchical
|
||||
* URI. The path is absolute if it begins with a slash character ('/'), otherwise
|
||||
* it is relative. A relative path is resolved against the absolute path of the
|
||||
* agent JAR file. Malformed and non-existent paths are ignored. When an agent is
|
||||
* started sometime after the VM has started then paths that do not represent a
|
||||
* JAR file are ignored. This attribute is optional. </dd>
|
||||
*
|
||||
* <dt>{@code Can-Redefine-Classes}</dt>
|
||||
* <dd> Boolean ({@code true} or {@code false}, case irrelevant). Is the ability
|
||||
* to redefine classes needed by this agent. Values other than {@code true} are
|
||||
* considered {@code false}. This attribute is optional, the default is {@code
|
||||
* false}. </dd>
|
||||
*
|
||||
* <dt>{@code Can-Retransform-Classes}</dt>
|
||||
* <dd> Boolean ({@code true} or {@code false}, case irrelevant). Is the ability
|
||||
* to retransform classes needed by this agent. Values other than {@code true}
|
||||
* are considered {@code false}. This attribute is optional, the default is
|
||||
* {@code false}. </dd>
|
||||
*
|
||||
* <dt>{@code Can-Set-Native-Method-Prefix}</dt>
|
||||
* <dd> Boolean ({@code true} or {@code false}, case irrelevant). Is the ability
|
||||
* to set native method prefix needed by this agent. Values other than {@code
|
||||
* true} are considered {@code false}. This attribute is optional, the default
|
||||
* is {@code false}. </dd>
|
||||
*
|
||||
* </dl></blockquote>
|
||||
*
|
||||
* <p> An agent JAR file may have both the {@code Premain-Class} and {@code
|
||||
* Agent-Class} attributes present in the manifest. When the agent is started
|
||||
* on the command-line using the {@code -javaagent} option then the {@code
|
||||
* Premain-Class} attribute specifies the name of the agent class and the {@code
|
||||
* Agent-Class} attribute is ignored. Similarly, if the agent is started sometime
|
||||
* after the VM has started, then the {@code Agent-Class} attribute specifies
|
||||
* the name of the agent class (the value of {@code Premain-Class} attribute is
|
||||
* ignored).
|
||||
*
|
||||
*
|
||||
* <h3>Instrumenting code in modules</h3>
|
||||
*
|
||||
* <p> As an aid to agents that deploy supporting classes on the search path of
|
||||
* the bootstrap class loader, or the search path of the class loader that loads
|
||||
* the main agent class, the Java virtual machine arranges for the module of
|
||||
* transformed classes to read the unnamed module of both class loaders.
|
||||
*
|
||||
* @since 1.5
|
||||
* @revised 1.6
|
||||
* @revised 9
|
||||
*/
|
||||
|
||||
package java.lang.instrument;
|
39
src/java.instrument/share/classes/module-info.java
Normal file
39
src/java.instrument/share/classes/module-info.java
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Defines services that allow agents to
|
||||
* instrument programs running on the JVM.
|
||||
*
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
*/
|
||||
module java.instrument {
|
||||
exports java.lang.instrument;
|
||||
|
||||
// allow java launcher to load agents in executable JAR files
|
||||
exports sun.instrument to java.base;
|
||||
}
|
||||
|
|
@ -0,0 +1,569 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.instrument;
|
||||
|
||||
import java.lang.instrument.UnmodifiableModuleException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.instrument.ClassFileTransformer;
|
||||
import java.lang.instrument.ClassDefinition;
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.Collections;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
import jdk.internal.module.Modules;
|
||||
|
||||
/*
|
||||
* Copyright 2003 Wily Technology, Inc.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The Java side of the JPLIS implementation. Works in concert with a native JVMTI agent
|
||||
* to implement the JPLIS API set. Provides both the Java API implementation of
|
||||
* the Instrumentation interface and utility Java routines to support the native code.
|
||||
* Keeps a pointer to the native data structure in a scalar field to allow native
|
||||
* processing behind native methods.
|
||||
*/
|
||||
public class InstrumentationImpl implements Instrumentation {
|
||||
private final TransformerManager mTransformerManager;
|
||||
private TransformerManager mRetransfomableTransformerManager;
|
||||
// needs to store a native pointer, so use 64 bits
|
||||
private final long mNativeAgent;
|
||||
private final boolean mEnvironmentSupportsRedefineClasses;
|
||||
private volatile boolean mEnvironmentSupportsRetransformClassesKnown;
|
||||
private volatile boolean mEnvironmentSupportsRetransformClasses;
|
||||
private final boolean mEnvironmentSupportsNativeMethodPrefix;
|
||||
|
||||
private
|
||||
InstrumentationImpl(long nativeAgent,
|
||||
boolean environmentSupportsRedefineClasses,
|
||||
boolean environmentSupportsNativeMethodPrefix) {
|
||||
mTransformerManager = new TransformerManager(false);
|
||||
mRetransfomableTransformerManager = null;
|
||||
mNativeAgent = nativeAgent;
|
||||
mEnvironmentSupportsRedefineClasses = environmentSupportsRedefineClasses;
|
||||
mEnvironmentSupportsRetransformClassesKnown = false; // false = need to ask
|
||||
mEnvironmentSupportsRetransformClasses = false; // don't know yet
|
||||
mEnvironmentSupportsNativeMethodPrefix = environmentSupportsNativeMethodPrefix;
|
||||
}
|
||||
|
||||
public void
|
||||
addTransformer(ClassFileTransformer transformer) {
|
||||
addTransformer(transformer, false);
|
||||
}
|
||||
|
||||
public synchronized void
|
||||
addTransformer(ClassFileTransformer transformer, boolean canRetransform) {
|
||||
if (transformer == null) {
|
||||
throw new NullPointerException("null passed as 'transformer' in addTransformer");
|
||||
}
|
||||
if (canRetransform) {
|
||||
if (!isRetransformClassesSupported()) {
|
||||
throw new UnsupportedOperationException(
|
||||
"adding retransformable transformers is not supported in this environment");
|
||||
}
|
||||
if (mRetransfomableTransformerManager == null) {
|
||||
mRetransfomableTransformerManager = new TransformerManager(true);
|
||||
}
|
||||
mRetransfomableTransformerManager.addTransformer(transformer);
|
||||
if (mRetransfomableTransformerManager.getTransformerCount() == 1) {
|
||||
setHasRetransformableTransformers(mNativeAgent, true);
|
||||
}
|
||||
} else {
|
||||
mTransformerManager.addTransformer(transformer);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized boolean
|
||||
removeTransformer(ClassFileTransformer transformer) {
|
||||
if (transformer == null) {
|
||||
throw new NullPointerException("null passed as 'transformer' in removeTransformer");
|
||||
}
|
||||
TransformerManager mgr = findTransformerManager(transformer);
|
||||
if (mgr != null) {
|
||||
mgr.removeTransformer(transformer);
|
||||
if (mgr.isRetransformable() && mgr.getTransformerCount() == 0) {
|
||||
setHasRetransformableTransformers(mNativeAgent, false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean
|
||||
isModifiableClass(Class<?> theClass) {
|
||||
if (theClass == null) {
|
||||
throw new NullPointerException(
|
||||
"null passed as 'theClass' in isModifiableClass");
|
||||
}
|
||||
return isModifiableClass0(mNativeAgent, theClass);
|
||||
}
|
||||
|
||||
public boolean isModifiableModule(Module module) {
|
||||
if (module == null) {
|
||||
throw new NullPointerException("'module' is null");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean
|
||||
isRetransformClassesSupported() {
|
||||
// ask lazily since there is some overhead
|
||||
if (!mEnvironmentSupportsRetransformClassesKnown) {
|
||||
mEnvironmentSupportsRetransformClasses = isRetransformClassesSupported0(mNativeAgent);
|
||||
mEnvironmentSupportsRetransformClassesKnown = true;
|
||||
}
|
||||
return mEnvironmentSupportsRetransformClasses;
|
||||
}
|
||||
|
||||
public void
|
||||
retransformClasses(Class<?>... classes) {
|
||||
if (!isRetransformClassesSupported()) {
|
||||
throw new UnsupportedOperationException(
|
||||
"retransformClasses is not supported in this environment");
|
||||
}
|
||||
retransformClasses0(mNativeAgent, classes);
|
||||
}
|
||||
|
||||
public boolean
|
||||
isRedefineClassesSupported() {
|
||||
return mEnvironmentSupportsRedefineClasses;
|
||||
}
|
||||
|
||||
public void
|
||||
redefineClasses(ClassDefinition... definitions)
|
||||
throws ClassNotFoundException {
|
||||
if (!isRedefineClassesSupported()) {
|
||||
throw new UnsupportedOperationException("redefineClasses is not supported in this environment");
|
||||
}
|
||||
if (definitions == null) {
|
||||
throw new NullPointerException("null passed as 'definitions' in redefineClasses");
|
||||
}
|
||||
for (int i = 0; i < definitions.length; ++i) {
|
||||
if (definitions[i] == null) {
|
||||
throw new NullPointerException("element of 'definitions' is null in redefineClasses");
|
||||
}
|
||||
}
|
||||
if (definitions.length == 0) {
|
||||
return; // short-circuit if there are no changes requested
|
||||
}
|
||||
|
||||
redefineClasses0(mNativeAgent, definitions);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public Class[]
|
||||
getAllLoadedClasses() {
|
||||
return getAllLoadedClasses0(mNativeAgent);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public Class[]
|
||||
getInitiatedClasses(ClassLoader loader) {
|
||||
return getInitiatedClasses0(mNativeAgent, loader);
|
||||
}
|
||||
|
||||
public long
|
||||
getObjectSize(Object objectToSize) {
|
||||
if (objectToSize == null) {
|
||||
throw new NullPointerException("null passed as 'objectToSize' in getObjectSize");
|
||||
}
|
||||
return getObjectSize0(mNativeAgent, objectToSize);
|
||||
}
|
||||
|
||||
public void
|
||||
appendToBootstrapClassLoaderSearch(JarFile jarfile) {
|
||||
appendToClassLoaderSearch0(mNativeAgent, jarfile.getName(), true);
|
||||
}
|
||||
|
||||
public void
|
||||
appendToSystemClassLoaderSearch(JarFile jarfile) {
|
||||
appendToClassLoaderSearch0(mNativeAgent, jarfile.getName(), false);
|
||||
}
|
||||
|
||||
public boolean
|
||||
isNativeMethodPrefixSupported() {
|
||||
return mEnvironmentSupportsNativeMethodPrefix;
|
||||
}
|
||||
|
||||
public synchronized void
|
||||
setNativeMethodPrefix(ClassFileTransformer transformer, String prefix) {
|
||||
if (!isNativeMethodPrefixSupported()) {
|
||||
throw new UnsupportedOperationException(
|
||||
"setNativeMethodPrefix is not supported in this environment");
|
||||
}
|
||||
if (transformer == null) {
|
||||
throw new NullPointerException(
|
||||
"null passed as 'transformer' in setNativeMethodPrefix");
|
||||
}
|
||||
TransformerManager mgr = findTransformerManager(transformer);
|
||||
if (mgr == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"transformer not registered in setNativeMethodPrefix");
|
||||
}
|
||||
mgr.setNativeMethodPrefix(transformer, prefix);
|
||||
String[] prefixes = mgr.getNativeMethodPrefixes();
|
||||
setNativeMethodPrefixes(mNativeAgent, prefixes, mgr.isRetransformable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void redefineModule(Module module,
|
||||
Set<Module> extraReads,
|
||||
Map<String, Set<Module>> extraExports,
|
||||
Map<String, Set<Module>> extraOpens,
|
||||
Set<Class<?>> extraUses,
|
||||
Map<Class<?>, List<Class<?>>> extraProvides)
|
||||
{
|
||||
if (!module.isNamed())
|
||||
return;
|
||||
|
||||
if (!isModifiableModule(module))
|
||||
throw new UnmodifiableModuleException(module.getName());
|
||||
|
||||
// copy and check reads
|
||||
extraReads = new HashSet<>(extraReads);
|
||||
if (extraReads.contains(null))
|
||||
throw new NullPointerException("'extraReads' contains null");
|
||||
|
||||
// copy and check exports and opens
|
||||
extraExports = cloneAndCheckMap(module, extraExports);
|
||||
extraOpens = cloneAndCheckMap(module, extraOpens);
|
||||
|
||||
// copy and check uses
|
||||
extraUses = new HashSet<>(extraUses);
|
||||
if (extraUses.contains(null))
|
||||
throw new NullPointerException("'extraUses' contains null");
|
||||
|
||||
// copy and check provides
|
||||
Map<Class<?>, List<Class<?>>> tmpProvides = new HashMap<>();
|
||||
for (Map.Entry<Class<?>, List<Class<?>>> e : extraProvides.entrySet()) {
|
||||
Class<?> service = e.getKey();
|
||||
if (service == null)
|
||||
throw new NullPointerException("'extraProvides' contains null");
|
||||
List<Class<?>> providers = new ArrayList<>(e.getValue());
|
||||
if (providers.isEmpty())
|
||||
throw new IllegalArgumentException("list of providers is empty");
|
||||
providers.forEach(p -> {
|
||||
if (p.getModule() != module)
|
||||
throw new IllegalArgumentException(p + " not in " + module);
|
||||
if (!service.isAssignableFrom(p))
|
||||
throw new IllegalArgumentException(p + " is not a " + service);
|
||||
});
|
||||
tmpProvides.put(service, providers);
|
||||
}
|
||||
extraProvides = tmpProvides;
|
||||
|
||||
|
||||
// update reads
|
||||
extraReads.forEach(m -> Modules.addReads(module, m));
|
||||
|
||||
// update exports
|
||||
for (Map.Entry<String, Set<Module>> e : extraExports.entrySet()) {
|
||||
String pkg = e.getKey();
|
||||
Set<Module> targets = e.getValue();
|
||||
targets.forEach(m -> Modules.addExports(module, pkg, m));
|
||||
}
|
||||
|
||||
// update opens
|
||||
for (Map.Entry<String, Set<Module>> e : extraOpens.entrySet()) {
|
||||
String pkg = e.getKey();
|
||||
Set<Module> targets = e.getValue();
|
||||
targets.forEach(m -> Modules.addOpens(module, pkg, m));
|
||||
}
|
||||
|
||||
// update uses
|
||||
extraUses.forEach(service -> Modules.addUses(module, service));
|
||||
|
||||
// update provides
|
||||
for (Map.Entry<Class<?>, List<Class<?>>> e : extraProvides.entrySet()) {
|
||||
Class<?> service = e.getKey();
|
||||
List<Class<?>> providers = e.getValue();
|
||||
providers.forEach(p -> Modules.addProvides(module, service, p));
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Set<Module>>
|
||||
cloneAndCheckMap(Module module, Map<String, Set<Module>> map)
|
||||
{
|
||||
if (map.isEmpty())
|
||||
return Collections.emptyMap();
|
||||
|
||||
Map<String, Set<Module>> result = new HashMap<>();
|
||||
Set<String> packages = module.getPackages();
|
||||
for (Map.Entry<String, Set<Module>> e : map.entrySet()) {
|
||||
String pkg = e.getKey();
|
||||
if (pkg == null)
|
||||
throw new NullPointerException("package cannot be null");
|
||||
if (!packages.contains(pkg))
|
||||
throw new IllegalArgumentException(pkg + " not in module");
|
||||
Set<Module> targets = new HashSet<>(e.getValue());
|
||||
if (targets.isEmpty())
|
||||
throw new IllegalArgumentException("set of targets is empty");
|
||||
if (targets.contains(null))
|
||||
throw new NullPointerException("set of targets cannot include null");
|
||||
result.put(pkg, targets);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private TransformerManager
|
||||
findTransformerManager(ClassFileTransformer transformer) {
|
||||
if (mTransformerManager.includesTransformer(transformer)) {
|
||||
return mTransformerManager;
|
||||
}
|
||||
if (mRetransfomableTransformerManager != null &&
|
||||
mRetransfomableTransformerManager.includesTransformer(transformer)) {
|
||||
return mRetransfomableTransformerManager;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Natives
|
||||
*/
|
||||
private native boolean
|
||||
isModifiableClass0(long nativeAgent, Class<?> theClass);
|
||||
|
||||
private native boolean
|
||||
isRetransformClassesSupported0(long nativeAgent);
|
||||
|
||||
private native void
|
||||
setHasRetransformableTransformers(long nativeAgent, boolean has);
|
||||
|
||||
private native void
|
||||
retransformClasses0(long nativeAgent, Class<?>[] classes);
|
||||
|
||||
private native void
|
||||
redefineClasses0(long nativeAgent, ClassDefinition[] definitions)
|
||||
throws ClassNotFoundException;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private native Class[]
|
||||
getAllLoadedClasses0(long nativeAgent);
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private native Class[]
|
||||
getInitiatedClasses0(long nativeAgent, ClassLoader loader);
|
||||
|
||||
private native long
|
||||
getObjectSize0(long nativeAgent, Object objectToSize);
|
||||
|
||||
private native void
|
||||
appendToClassLoaderSearch0(long nativeAgent, String jarfile, boolean bootLoader);
|
||||
|
||||
private native void
|
||||
setNativeMethodPrefixes(long nativeAgent, String[] prefixes, boolean isRetransformable);
|
||||
|
||||
static {
|
||||
System.loadLibrary("instrument");
|
||||
}
|
||||
|
||||
/*
|
||||
* Internals
|
||||
*/
|
||||
|
||||
|
||||
// Enable or disable Java programming language access checks on a
|
||||
// reflected object (for example, a method)
|
||||
private static void setAccessible(final AccessibleObject ao, final boolean accessible) {
|
||||
AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
||||
public Object run() {
|
||||
ao.setAccessible(accessible);
|
||||
return null;
|
||||
}});
|
||||
}
|
||||
|
||||
// Attempt to load and start an agent
|
||||
private void
|
||||
loadClassAndStartAgent( String classname,
|
||||
String methodname,
|
||||
String optionsString)
|
||||
throws Throwable {
|
||||
|
||||
ClassLoader mainAppLoader = ClassLoader.getSystemClassLoader();
|
||||
Class<?> javaAgentClass = mainAppLoader.loadClass(classname);
|
||||
|
||||
Method m = null;
|
||||
NoSuchMethodException firstExc = null;
|
||||
boolean twoArgAgent = false;
|
||||
|
||||
// The agent class must have a premain or agentmain method that
|
||||
// has 1 or 2 arguments. We check in the following order:
|
||||
//
|
||||
// 1) declared with a signature of (String, Instrumentation)
|
||||
// 2) declared with a signature of (String)
|
||||
// 3) inherited with a signature of (String, Instrumentation)
|
||||
// 4) inherited with a signature of (String)
|
||||
//
|
||||
// So the declared version of either 1-arg or 2-arg always takes
|
||||
// primary precedence over an inherited version. After that, the
|
||||
// 2-arg version takes precedence over the 1-arg version.
|
||||
//
|
||||
// If no method is found then we throw the NoSuchMethodException
|
||||
// from the first attempt so that the exception text indicates
|
||||
// the lookup failed for the 2-arg method (same as JDK5.0).
|
||||
|
||||
try {
|
||||
m = javaAgentClass.getDeclaredMethod( methodname,
|
||||
new Class<?>[] {
|
||||
String.class,
|
||||
java.lang.instrument.Instrumentation.class
|
||||
}
|
||||
);
|
||||
twoArgAgent = true;
|
||||
} catch (NoSuchMethodException x) {
|
||||
// remember the NoSuchMethodException
|
||||
firstExc = x;
|
||||
}
|
||||
|
||||
if (m == null) {
|
||||
// now try the declared 1-arg method
|
||||
try {
|
||||
m = javaAgentClass.getDeclaredMethod(methodname,
|
||||
new Class<?>[] { String.class });
|
||||
} catch (NoSuchMethodException x) {
|
||||
// ignore this exception because we'll try
|
||||
// two arg inheritance next
|
||||
}
|
||||
}
|
||||
|
||||
if (m == null) {
|
||||
// now try the inherited 2-arg method
|
||||
try {
|
||||
m = javaAgentClass.getMethod( methodname,
|
||||
new Class<?>[] {
|
||||
String.class,
|
||||
java.lang.instrument.Instrumentation.class
|
||||
}
|
||||
);
|
||||
twoArgAgent = true;
|
||||
} catch (NoSuchMethodException x) {
|
||||
// ignore this exception because we'll try
|
||||
// one arg inheritance next
|
||||
}
|
||||
}
|
||||
|
||||
if (m == null) {
|
||||
// finally try the inherited 1-arg method
|
||||
try {
|
||||
m = javaAgentClass.getMethod(methodname,
|
||||
new Class<?>[] { String.class });
|
||||
} catch (NoSuchMethodException x) {
|
||||
// none of the methods exists so we throw the
|
||||
// first NoSuchMethodException as per 5.0
|
||||
throw firstExc;
|
||||
}
|
||||
}
|
||||
|
||||
// the premain method should not be required to be public,
|
||||
// make it accessible so we can call it
|
||||
// Note: The spec says the following:
|
||||
// The agent class must implement a public static premain method...
|
||||
setAccessible(m, true);
|
||||
|
||||
// invoke the 1 or 2-arg method
|
||||
if (twoArgAgent) {
|
||||
m.invoke(null, new Object[] { optionsString, this });
|
||||
} else {
|
||||
m.invoke(null, new Object[] { optionsString });
|
||||
}
|
||||
}
|
||||
|
||||
// WARNING: the native code knows the name & signature of this method
|
||||
private void
|
||||
loadClassAndCallPremain( String classname,
|
||||
String optionsString)
|
||||
throws Throwable {
|
||||
|
||||
loadClassAndStartAgent( classname, "premain", optionsString );
|
||||
}
|
||||
|
||||
|
||||
// WARNING: the native code knows the name & signature of this method
|
||||
private void
|
||||
loadClassAndCallAgentmain( String classname,
|
||||
String optionsString)
|
||||
throws Throwable {
|
||||
|
||||
loadClassAndStartAgent( classname, "agentmain", optionsString );
|
||||
}
|
||||
|
||||
// WARNING: the native code knows the name & signature of this method
|
||||
private byte[]
|
||||
transform( Module module,
|
||||
ClassLoader loader,
|
||||
String classname,
|
||||
Class<?> classBeingRedefined,
|
||||
ProtectionDomain protectionDomain,
|
||||
byte[] classfileBuffer,
|
||||
boolean isRetransformer) {
|
||||
TransformerManager mgr = isRetransformer?
|
||||
mRetransfomableTransformerManager :
|
||||
mTransformerManager;
|
||||
// module is null when not a class load or when loading a class in an
|
||||
// unnamed module and this is the first type to be loaded in the package.
|
||||
if (module == null) {
|
||||
if (classBeingRedefined != null) {
|
||||
module = classBeingRedefined.getModule();
|
||||
} else {
|
||||
module = (loader == null) ? jdk.internal.loader.BootLoader.getUnnamedModule()
|
||||
: loader.getUnnamedModule();
|
||||
}
|
||||
}
|
||||
if (mgr == null) {
|
||||
return null; // no manager, no transform
|
||||
} else {
|
||||
return mgr.transform( module,
|
||||
loader,
|
||||
classname,
|
||||
classBeingRedefined,
|
||||
protectionDomain,
|
||||
classfileBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Invoked by the java launcher to load a java agent that is packaged with
|
||||
* the main application in an executable JAR file.
|
||||
*/
|
||||
public static void loadAgent(String path) {
|
||||
loadAgent0(path);
|
||||
}
|
||||
|
||||
private static native void loadAgent0(String path);
|
||||
}
|
|
@ -0,0 +1,254 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.instrument;
|
||||
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.lang.instrument.ClassFileTransformer;
|
||||
import java.security.ProtectionDomain;
|
||||
|
||||
/*
|
||||
* Copyright 2003 Wily Technology, Inc.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Support class for the InstrumentationImpl. Manages the list of registered transformers.
|
||||
* Keeps everything in the right order, deals with sync of the list,
|
||||
* and actually does the calling of the transformers.
|
||||
*/
|
||||
public class TransformerManager
|
||||
{
|
||||
private class TransformerInfo {
|
||||
final ClassFileTransformer mTransformer;
|
||||
String mPrefix;
|
||||
|
||||
TransformerInfo(ClassFileTransformer transformer) {
|
||||
mTransformer = transformer;
|
||||
mPrefix = null;
|
||||
}
|
||||
|
||||
ClassFileTransformer transformer() {
|
||||
return mTransformer;
|
||||
}
|
||||
|
||||
String getPrefix() {
|
||||
return mPrefix;
|
||||
}
|
||||
|
||||
void setPrefix(String prefix) {
|
||||
mPrefix = prefix;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* a given instance of this list is treated as immutable to simplify sync;
|
||||
* we pay copying overhead whenever the list is changed rather than every time
|
||||
* the list is referenced.
|
||||
* The array is kept in the order the transformers are added via addTransformer
|
||||
* (first added is 0, last added is length-1)
|
||||
* Use an array, not a List or other Collection. This keeps the set of classes
|
||||
* used by this code to a minimum. We want as few dependencies as possible in this
|
||||
* code, since it is used inside the class definition system. Any class referenced here
|
||||
* cannot be transformed by Java code.
|
||||
*/
|
||||
private TransformerInfo[] mTransformerList;
|
||||
|
||||
/***
|
||||
* Is this TransformerManager for transformers capable of retransformation?
|
||||
*/
|
||||
private boolean mIsRetransformable;
|
||||
|
||||
TransformerManager(boolean isRetransformable) {
|
||||
mTransformerList = new TransformerInfo[0];
|
||||
mIsRetransformable = isRetransformable;
|
||||
}
|
||||
|
||||
boolean isRetransformable() {
|
||||
return mIsRetransformable;
|
||||
}
|
||||
|
||||
public synchronized void
|
||||
addTransformer( ClassFileTransformer transformer) {
|
||||
TransformerInfo[] oldList = mTransformerList;
|
||||
TransformerInfo[] newList = new TransformerInfo[oldList.length + 1];
|
||||
System.arraycopy( oldList,
|
||||
0,
|
||||
newList,
|
||||
0,
|
||||
oldList.length);
|
||||
newList[oldList.length] = new TransformerInfo(transformer);
|
||||
mTransformerList = newList;
|
||||
}
|
||||
|
||||
public synchronized boolean
|
||||
removeTransformer(ClassFileTransformer transformer) {
|
||||
boolean found = false;
|
||||
TransformerInfo[] oldList = mTransformerList;
|
||||
int oldLength = oldList.length;
|
||||
int newLength = oldLength - 1;
|
||||
|
||||
// look for it in the list, starting at the last added, and remember
|
||||
// where it was if we found it
|
||||
int matchingIndex = 0;
|
||||
for ( int x = oldLength - 1; x >= 0; x-- ) {
|
||||
if ( oldList[x].transformer() == transformer ) {
|
||||
found = true;
|
||||
matchingIndex = x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// make a copy of the array without the matching element
|
||||
if ( found ) {
|
||||
TransformerInfo[] newList = new TransformerInfo[newLength];
|
||||
|
||||
// copy up to but not including the match
|
||||
if ( matchingIndex > 0 ) {
|
||||
System.arraycopy( oldList,
|
||||
0,
|
||||
newList,
|
||||
0,
|
||||
matchingIndex);
|
||||
}
|
||||
|
||||
// if there is anything after the match, copy it as well
|
||||
if ( matchingIndex < (newLength) ) {
|
||||
System.arraycopy( oldList,
|
||||
matchingIndex + 1,
|
||||
newList,
|
||||
matchingIndex,
|
||||
(newLength) - matchingIndex);
|
||||
}
|
||||
mTransformerList = newList;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
synchronized boolean
|
||||
includesTransformer(ClassFileTransformer transformer) {
|
||||
for (TransformerInfo info : mTransformerList) {
|
||||
if ( info.transformer() == transformer ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// This function doesn't actually snapshot anything, but should be
|
||||
// used to set a local variable, which will snapshot the transformer
|
||||
// list because of the copying semantics of mTransformerList (see
|
||||
// the comment for mTransformerList).
|
||||
private TransformerInfo[]
|
||||
getSnapshotTransformerList() {
|
||||
return mTransformerList;
|
||||
}
|
||||
|
||||
public byte[]
|
||||
transform( Module module,
|
||||
ClassLoader loader,
|
||||
String classname,
|
||||
Class<?> classBeingRedefined,
|
||||
ProtectionDomain protectionDomain,
|
||||
byte[] classfileBuffer) {
|
||||
boolean someoneTouchedTheBytecode = false;
|
||||
|
||||
TransformerInfo[] transformerList = getSnapshotTransformerList();
|
||||
|
||||
byte[] bufferToUse = classfileBuffer;
|
||||
|
||||
// order matters, gotta run 'em in the order they were added
|
||||
for ( int x = 0; x < transformerList.length; x++ ) {
|
||||
TransformerInfo transformerInfo = transformerList[x];
|
||||
ClassFileTransformer transformer = transformerInfo.transformer();
|
||||
byte[] transformedBytes = null;
|
||||
|
||||
try {
|
||||
transformedBytes = transformer.transform( module,
|
||||
loader,
|
||||
classname,
|
||||
classBeingRedefined,
|
||||
protectionDomain,
|
||||
bufferToUse);
|
||||
}
|
||||
catch (Throwable t) {
|
||||
// don't let any one transformer mess it up for the others.
|
||||
// This is where we need to put some logging. What should go here? FIXME
|
||||
}
|
||||
|
||||
if ( transformedBytes != null ) {
|
||||
someoneTouchedTheBytecode = true;
|
||||
bufferToUse = transformedBytes;
|
||||
}
|
||||
}
|
||||
|
||||
// if someone modified it, return the modified buffer.
|
||||
// otherwise return null to mean "no transforms occurred"
|
||||
byte [] result;
|
||||
if ( someoneTouchedTheBytecode ) {
|
||||
result = bufferToUse;
|
||||
}
|
||||
else {
|
||||
result = null;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
getTransformerCount() {
|
||||
TransformerInfo[] transformerList = getSnapshotTransformerList();
|
||||
return transformerList.length;
|
||||
}
|
||||
|
||||
boolean
|
||||
setNativeMethodPrefix(ClassFileTransformer transformer, String prefix) {
|
||||
TransformerInfo[] transformerList = getSnapshotTransformerList();
|
||||
|
||||
for ( int x = 0; x < transformerList.length; x++ ) {
|
||||
TransformerInfo transformerInfo = transformerList[x];
|
||||
ClassFileTransformer aTransformer = transformerInfo.transformer();
|
||||
|
||||
if ( aTransformer == transformer ) {
|
||||
transformerInfo.setPrefix(prefix);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
String[]
|
||||
getNativeMethodPrefixes() {
|
||||
TransformerInfo[] transformerList = getSnapshotTransformerList();
|
||||
String[] prefixes = new String[transformerList.length];
|
||||
|
||||
for ( int x = 0; x < transformerList.length; x++ ) {
|
||||
TransformerInfo transformerInfo = transformerList[x];
|
||||
prefixes[x] = transformerInfo.getPrefix();
|
||||
}
|
||||
return prefixes;
|
||||
}
|
||||
}
|
146
src/java.instrument/share/native/libinstrument/EncodingSupport.c
Normal file
146
src/java.instrument/share/native/libinstrument/EncodingSupport.c
Normal file
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Determine length of this Standard UTF-8 in Modified UTF-8.
|
||||
* Validation is done of the basic UTF encoding rules, returns
|
||||
* length (no change) when errors are detected in the UTF encoding.
|
||||
*
|
||||
* Note: Accepts Modified UTF-8 also, no verification on the
|
||||
* correctness of Standard UTF-8 is done. e,g, 0xC080 input is ok.
|
||||
*/
|
||||
int
|
||||
modifiedUtf8LengthOfUtf8(char* string, int length) {
|
||||
int new_length;
|
||||
int i;
|
||||
|
||||
new_length = 0;
|
||||
for ( i = 0 ; i < length ; i++ ) {
|
||||
unsigned byte;
|
||||
|
||||
byte = (unsigned char)string[i];
|
||||
if ( (byte & 0x80) == 0 ) { /* 1byte encoding */
|
||||
new_length++;
|
||||
if ( byte == 0 ) {
|
||||
new_length++; /* We gain one byte in length on NULL bytes */
|
||||
}
|
||||
} else if ( (byte & 0xE0) == 0xC0 ) { /* 2byte encoding */
|
||||
/* Check encoding of following bytes */
|
||||
if ( (i+1) >= length || (string[i+1] & 0xC0) != 0x80 ) {
|
||||
break; /* Error condition */
|
||||
}
|
||||
i++; /* Skip next byte */
|
||||
new_length += 2;
|
||||
} else if ( (byte & 0xF0) == 0xE0 ) { /* 3byte encoding */
|
||||
/* Check encoding of following bytes */
|
||||
if ( (i+2) >= length || (string[i+1] & 0xC0) != 0x80
|
||||
|| (string[i+2] & 0xC0) != 0x80 ) {
|
||||
break; /* Error condition */
|
||||
}
|
||||
i += 2; /* Skip next two bytes */
|
||||
new_length += 3;
|
||||
} else if ( (byte & 0xF8) == 0xF0 ) { /* 4byte encoding */
|
||||
/* Check encoding of following bytes */
|
||||
if ( (i+3) >= length || (string[i+1] & 0xC0) != 0x80
|
||||
|| (string[i+2] & 0xC0) != 0x80
|
||||
|| (string[i+3] & 0xC0) != 0x80 ) {
|
||||
break; /* Error condition */
|
||||
}
|
||||
i += 3; /* Skip next 3 bytes */
|
||||
new_length += 6; /* 4byte encoding turns into 2 3byte ones */
|
||||
} else {
|
||||
break; /* Error condition */
|
||||
}
|
||||
}
|
||||
if ( i != length ) {
|
||||
/* Error in finding new length, return old length so no conversion */
|
||||
/* FIXUP: ERROR_MESSAGE? */
|
||||
return length;
|
||||
}
|
||||
return new_length;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert Standard UTF-8 to Modified UTF-8.
|
||||
* Assumes the UTF-8 encoding was validated by modifiedLength() above.
|
||||
*
|
||||
* Note: Accepts Modified UTF-8 also, no verification on the
|
||||
* correctness of Standard UTF-8 is done. e,g, 0xC080 input is ok.
|
||||
*/
|
||||
void
|
||||
convertUtf8ToModifiedUtf8(char *string, int length, char *new_string, int new_length)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
|
||||
j = 0;
|
||||
for ( i = 0 ; i < length ; i++ ) {
|
||||
unsigned byte1;
|
||||
|
||||
byte1 = (unsigned char)string[i];
|
||||
|
||||
/* NULL bytes and bytes starting with 11110xxx are special */
|
||||
if ( (byte1 & 0x80) == 0 ) { /* 1byte encoding */
|
||||
if ( byte1 == 0 ) {
|
||||
/* Bits out: 11000000 10000000 */
|
||||
new_string[j++] = (char)0xC0;
|
||||
new_string[j++] = (char)0x80;
|
||||
} else {
|
||||
/* Single byte */
|
||||
new_string[j++] = byte1;
|
||||
}
|
||||
} else if ( (byte1 & 0xE0) == 0xC0 ) { /* 2byte encoding */
|
||||
new_string[j++] = byte1;
|
||||
new_string[j++] = string[++i];
|
||||
} else if ( (byte1 & 0xF0) == 0xE0 ) { /* 3byte encoding */
|
||||
new_string[j++] = byte1;
|
||||
new_string[j++] = string[++i];
|
||||
new_string[j++] = string[++i];
|
||||
} else if ( (byte1 & 0xF8) == 0xF0 ) { /* 4byte encoding */
|
||||
/* Beginning of 4byte encoding, turn into 2 3byte encodings */
|
||||
unsigned byte2, byte3, byte4, u21;
|
||||
|
||||
/* Bits in: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
|
||||
byte2 = (unsigned char)string[++i];
|
||||
byte3 = (unsigned char)string[++i];
|
||||
byte4 = (unsigned char)string[++i];
|
||||
/* Reconstruct full 21bit value */
|
||||
u21 = (byte1 & 0x07) << 18;
|
||||
u21 += (byte2 & 0x3F) << 12;
|
||||
u21 += (byte3 & 0x3F) << 6;
|
||||
u21 += (byte4 & 0x3F);
|
||||
/* Bits out: 11101101 1010xxxx 10xxxxxx */
|
||||
new_string[j++] = (char)0xED;
|
||||
new_string[j++] = 0xA0 + (((u21 >> 16) - 1) & 0x0F);
|
||||
new_string[j++] = 0x80 + ((u21 >> 10) & 0x3F);
|
||||
/* Bits out: 11101101 1011xxxx 10xxxxxx */
|
||||
new_string[j++] = (char)0xED;
|
||||
new_string[j++] = 0xB0 + ((u21 >> 6) & 0x0F);
|
||||
new_string[j++] = byte4;
|
||||
}
|
||||
}
|
||||
new_string[j] = 0;
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Return length of UTF-8 in modified UTF-8.
|
||||
*/
|
||||
int modifiedUtf8LengthOfUtf8(char* utf_str, int utf8_len);
|
||||
|
||||
/**
|
||||
* Convert UTF-8 to modified UTF-8.
|
||||
*/
|
||||
void convertUtf8ToModifiedUtf8(char* utf8_str, int utf8_len, char* mutf8_str, int mutf8_len);
|
||||
|
||||
/**
|
||||
* Convert UTF-8 to a platform string
|
||||
*/
|
||||
int convertUft8ToPlatformString(char* utf8_str, int utf8_len, char* platform_str, int platform_len);
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "FileSystemSupport_md.h"
|
||||
|
||||
/**
|
||||
* Return the local filesystem's path-separator character.
|
||||
*/
|
||||
char pathSeparator();
|
||||
|
||||
/**
|
||||
* Compare two filenames represent and tell if they represent the same file
|
||||
* or not.
|
||||
*/
|
||||
int filenameStrcmp(const char* s1, const char* s2);
|
||||
|
||||
/**
|
||||
* Post-process the given URI path string if necessary. This is used on
|
||||
* win32, e.g., to transform "/c:/foo" into "c:/foo". The path string
|
||||
* still has slash separators; code in the File class will translate them
|
||||
* after this method returns.
|
||||
*/
|
||||
char* fromURIPath(const char* path);
|
||||
|
||||
/**
|
||||
* Return the basen path of the given pathname. If the string is already
|
||||
* the base path then it is simply returned.
|
||||
*/
|
||||
char* basePath(const char* path);
|
||||
|
||||
/**
|
||||
* Convert the given pathname string to normal form. If the string is
|
||||
* already in normal form then it is simply returned.
|
||||
*/
|
||||
char* normalize(const char* path);
|
||||
|
||||
/**
|
||||
* Tell whether or not the given abstract pathname is absolute.
|
||||
*/
|
||||
int isAbsolute(const char * path);
|
||||
|
||||
/**
|
||||
* Resolve the child pathname string against the parent.
|
||||
*/
|
||||
char* resolve(const char* parent, const char* child);
|
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include "JPLISAgent.h"
|
||||
#include "JPLISAssert.h"
|
||||
#include "Utilities.h"
|
||||
#include "JavaExceptions.h"
|
||||
#include "FileSystemSupport.h" /* For uintptr_t */
|
||||
#include "sun_instrument_InstrumentationImpl.h"
|
||||
|
||||
/*
|
||||
* Copyright 2003 Wily Technology, Inc.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This module contains the native method implementations to back the
|
||||
* sun.instrument.InstrumentationImpl class.
|
||||
* The bridge between Java and native code is built by storing a native
|
||||
* pointer to the JPLISAgent data structure in a 64 bit scalar field
|
||||
* in the InstrumentationImpl instance which is passed to each method.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Native methods
|
||||
*/
|
||||
|
||||
/*
|
||||
* Declare library specific JNI_Onload entry if static build
|
||||
*/
|
||||
DEF_STATIC_JNI_OnLoad
|
||||
|
||||
/*
|
||||
* Class: sun_instrument_InstrumentationImpl
|
||||
* Method: isModifiableClass0
|
||||
* Signature: (Ljava/lang/Class;)Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_sun_instrument_InstrumentationImpl_isModifiableClass0
|
||||
(JNIEnv * jnienv, jobject implThis, jlong agent, jclass clazz) {
|
||||
return isModifiableClass(jnienv, (JPLISAgent*)(intptr_t)agent, clazz);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_instrument_InstrumentationImpl
|
||||
* Method: isRetransformClassesSupported0
|
||||
* Signature: ()Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_sun_instrument_InstrumentationImpl_isRetransformClassesSupported0
|
||||
(JNIEnv * jnienv, jobject implThis, jlong agent) {
|
||||
return isRetransformClassesSupported(jnienv, (JPLISAgent*)(intptr_t)agent);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_instrument_InstrumentationImpl
|
||||
* Method: setHasRetransformableTransformers
|
||||
* Signature: (Z)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_instrument_InstrumentationImpl_setHasRetransformableTransformers
|
||||
(JNIEnv * jnienv, jobject implThis, jlong agent, jboolean has) {
|
||||
setHasRetransformableTransformers(jnienv, (JPLISAgent*)(intptr_t)agent, has);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_instrument_InstrumentationImpl
|
||||
* Method: retransformClasses0
|
||||
* Signature: ([Ljava/lang/Class;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_instrument_InstrumentationImpl_retransformClasses0
|
||||
(JNIEnv * jnienv, jobject implThis, jlong agent, jobjectArray classes) {
|
||||
retransformClasses(jnienv, (JPLISAgent*)(intptr_t)agent, classes);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_instrument_InstrumentationImpl
|
||||
* Method: redefineClasses0
|
||||
* Signature: ([Ljava/lang/instrument/ClassDefinition;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_instrument_InstrumentationImpl_redefineClasses0
|
||||
(JNIEnv * jnienv, jobject implThis, jlong agent, jobjectArray classDefinitions) {
|
||||
redefineClasses(jnienv, (JPLISAgent*)(intptr_t)agent, classDefinitions);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_instrument_InstrumentationImpl
|
||||
* Method: getAllLoadedClasses0
|
||||
* Signature: ()[Ljava/lang/Class;
|
||||
*/
|
||||
JNIEXPORT jobjectArray JNICALL Java_sun_instrument_InstrumentationImpl_getAllLoadedClasses0
|
||||
(JNIEnv * jnienv, jobject implThis, jlong agent) {
|
||||
return getAllLoadedClasses(jnienv, (JPLISAgent*)(intptr_t)agent);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_instrument_InstrumentationImpl
|
||||
* Method: getInitiatedClasses0
|
||||
* Signature: (Ljava/lang/ClassLoader;)[Ljava/lang/Class;
|
||||
*/
|
||||
JNIEXPORT jobjectArray JNICALL Java_sun_instrument_InstrumentationImpl_getInitiatedClasses0
|
||||
(JNIEnv * jnienv, jobject implThis, jlong agent, jobject classLoader) {
|
||||
return getInitiatedClasses(jnienv, (JPLISAgent*)(intptr_t)agent, classLoader);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_instrument_InstrumentationImpl
|
||||
* Method: getObjectSize0
|
||||
* Signature: (Ljava/lang/Object;)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_sun_instrument_InstrumentationImpl_getObjectSize0
|
||||
(JNIEnv * jnienv, jobject implThis, jlong agent, jobject objectToSize) {
|
||||
return getObjectSize(jnienv, (JPLISAgent*)(intptr_t)agent, objectToSize);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Class: sun_instrument_InstrumentationImpl
|
||||
* Method: appendToClassLoaderSearch0
|
||||
* Signature: (Ljava/lang/String;Z)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_instrument_InstrumentationImpl_appendToClassLoaderSearch0
|
||||
(JNIEnv * jnienv, jobject implThis, jlong agent, jstring jarFile, jboolean isBootLoader) {
|
||||
appendToClassLoaderSearch(jnienv, (JPLISAgent*)(intptr_t)agent, jarFile, isBootLoader);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Class: sun_instrument_InstrumentationImpl
|
||||
* Method: setNativeMethodPrefixes
|
||||
* Signature: ([Ljava/lang/String;Z)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_instrument_InstrumentationImpl_setNativeMethodPrefixes
|
||||
(JNIEnv * jnienv, jobject implThis, jlong agent, jobjectArray prefixArray, jboolean isRetransformable) {
|
||||
setNativeMethodPrefixes(jnienv, (JPLISAgent*)(intptr_t)agent, prefixArray, isRetransformable);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Class: sun_instrument_InstrumentationImpl
|
||||
* Method: loadAgent0
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_instrument_InstrumentationImpl_loadAgent0
|
||||
(JNIEnv* env, jclass clazz, jstring jarfile)
|
||||
{
|
||||
extern jint loadAgent(JNIEnv* env, jstring path);
|
||||
if (loadAgent(env, jarfile) != JNI_OK) {
|
||||
if (!(*env)->ExceptionCheck(env)) {
|
||||
createAndThrowInternalError(env);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,945 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2003 Wily Technology, Inc.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "jni.h"
|
||||
|
||||
#include "Utilities.h"
|
||||
#include "JPLISAssert.h"
|
||||
#include "JPLISAgent.h"
|
||||
#include "JavaExceptions.h"
|
||||
|
||||
#include "EncodingSupport.h"
|
||||
#include "FileSystemSupport.h"
|
||||
#include "JarFacade.h"
|
||||
#include "PathCharsValidator.h"
|
||||
|
||||
/**
|
||||
* This module contains the direct interface points with the JVMTI.
|
||||
* The OnLoad handler is here, along with the various event handlers.
|
||||
*/
|
||||
|
||||
static int
|
||||
appendClassPath(JPLISAgent* agent,
|
||||
const char* jarfile);
|
||||
|
||||
static void
|
||||
appendBootClassPath(JPLISAgent* agent,
|
||||
const char* jarfile,
|
||||
const char* pathList);
|
||||
|
||||
|
||||
/*
|
||||
* Parse -javaagent tail, of the form name[=options], into name
|
||||
* and options. Returned values are heap allocated and options maybe
|
||||
* NULL. Returns 0 if parse succeeds, -1 if allocation fails.
|
||||
*/
|
||||
static int
|
||||
parseArgumentTail(char* tail, char** name, char** options) {
|
||||
int len;
|
||||
char* pos;
|
||||
|
||||
pos = strchr(tail, '=');
|
||||
len = (pos == NULL) ? (int)strlen(tail) : (int)(pos - tail);
|
||||
|
||||
*name = (char*)malloc(len+1);
|
||||
if (*name == NULL) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(*name, tail, len);
|
||||
(*name)[len] = '\0';
|
||||
|
||||
if (pos == NULL) {
|
||||
*options = NULL;
|
||||
} else {
|
||||
char * str = (char*)malloc( (int)strlen(pos + 1) + 1 );
|
||||
if (str == NULL) {
|
||||
free(*name);
|
||||
return -1;
|
||||
}
|
||||
strcpy(str, pos +1);
|
||||
*options = str;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the value of an attribute in an attribute list. Returns NULL
|
||||
* if attribute not found.
|
||||
*/
|
||||
jboolean
|
||||
getBooleanAttribute(const jarAttribute* attributes, const char* name) {
|
||||
char* attributeValue = getAttribute(attributes, name);
|
||||
return attributeValue != NULL && strcasecmp(attributeValue, "true") == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse any capability settings in the JAR manifest and
|
||||
* convert them to JVM TI capabilities.
|
||||
*/
|
||||
void
|
||||
convertCapabilityAttributes(const jarAttribute* attributes, JPLISAgent* agent) {
|
||||
/* set redefineClasses capability */
|
||||
if (getBooleanAttribute(attributes, "Can-Redefine-Classes")) {
|
||||
addRedefineClassesCapability(agent);
|
||||
}
|
||||
|
||||
/* create an environment which has the retransformClasses capability */
|
||||
if (getBooleanAttribute(attributes, "Can-Retransform-Classes")) {
|
||||
retransformableEnvironment(agent);
|
||||
}
|
||||
|
||||
/* set setNativeMethodPrefix capability */
|
||||
if (getBooleanAttribute(attributes, "Can-Set-Native-Method-Prefix")) {
|
||||
addNativeMethodPrefixCapability(agent);
|
||||
}
|
||||
|
||||
/* for retransformClasses testing, set capability to use original method order */
|
||||
if (getBooleanAttribute(attributes, "Can-Maintain-Original-Method-Order")) {
|
||||
addOriginalMethodOrderCapability(agent);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This will be called once for every -javaagent on the command line.
|
||||
* Each call to Agent_OnLoad will create its own agent and agent data.
|
||||
*
|
||||
* The argument tail string provided to Agent_OnLoad will be of form
|
||||
* <jarfile>[=<options>]. The tail string is split into the jarfile and
|
||||
* options components. The jarfile manifest is parsed and the value of the
|
||||
* Premain-Class attribute will become the agent's premain class. The jar
|
||||
* file is then added to the system class path, and if the Boot-Class-Path
|
||||
* attribute is present then all relative URLs in the value are processed
|
||||
* to create boot class path segments to append to the boot class path.
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
DEF_Agent_OnLoad(JavaVM *vm, char *tail, void * reserved) {
|
||||
JPLISInitializationError initerror = JPLIS_INIT_ERROR_NONE;
|
||||
jint result = JNI_OK;
|
||||
JPLISAgent * agent = NULL;
|
||||
|
||||
initerror = createNewJPLISAgent(vm, &agent);
|
||||
if ( initerror == JPLIS_INIT_ERROR_NONE ) {
|
||||
int oldLen, newLen;
|
||||
char * jarfile;
|
||||
char * options;
|
||||
jarAttribute* attributes;
|
||||
char * premainClass;
|
||||
char * bootClassPath;
|
||||
|
||||
/*
|
||||
* Parse <jarfile>[=options] into jarfile and options
|
||||
*/
|
||||
if (parseArgumentTail(tail, &jarfile, &options) != 0) {
|
||||
fprintf(stderr, "-javaagent: memory allocation failure.\n");
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Agent_OnLoad is specified to provide the agent options
|
||||
* argument tail in modified UTF8. However for 1.5.0 this is
|
||||
* actually in the platform encoding - see 5049313.
|
||||
*
|
||||
* Open zip/jar file and parse archive. If can't be opened or
|
||||
* not a zip file return error. Also if Premain-Class attribute
|
||||
* isn't present we return an error.
|
||||
*/
|
||||
attributes = readAttributes(jarfile);
|
||||
if (attributes == NULL) {
|
||||
fprintf(stderr, "Error opening zip file or JAR manifest missing : %s\n", jarfile);
|
||||
free(jarfile);
|
||||
if (options != NULL) free(options);
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
premainClass = getAttribute(attributes, "Premain-Class");
|
||||
if (premainClass == NULL) {
|
||||
fprintf(stderr, "Failed to find Premain-Class manifest attribute in %s\n",
|
||||
jarfile);
|
||||
free(jarfile);
|
||||
if (options != NULL) free(options);
|
||||
freeAttributes(attributes);
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
/* Save the jarfile name */
|
||||
agent->mJarfile = jarfile;
|
||||
|
||||
/*
|
||||
* The value of the Premain-Class attribute becomes the agent
|
||||
* class name. The manifest is in UTF8 so need to convert to
|
||||
* modified UTF8 (see JNI spec).
|
||||
*/
|
||||
oldLen = (int)strlen(premainClass);
|
||||
newLen = modifiedUtf8LengthOfUtf8(premainClass, oldLen);
|
||||
if (newLen == oldLen) {
|
||||
premainClass = strdup(premainClass);
|
||||
} else {
|
||||
char* str = (char*)malloc( newLen+1 );
|
||||
if (str != NULL) {
|
||||
convertUtf8ToModifiedUtf8(premainClass, oldLen, str, newLen);
|
||||
}
|
||||
premainClass = str;
|
||||
}
|
||||
if (premainClass == NULL) {
|
||||
fprintf(stderr, "-javaagent: memory allocation failed\n");
|
||||
free(jarfile);
|
||||
if (options != NULL) free(options);
|
||||
freeAttributes(attributes);
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the Boot-Class-Path attribute is specified then we process
|
||||
* each relative URL and add it to the bootclasspath.
|
||||
*/
|
||||
bootClassPath = getAttribute(attributes, "Boot-Class-Path");
|
||||
if (bootClassPath != NULL) {
|
||||
appendBootClassPath(agent, jarfile, bootClassPath);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert JAR attributes into agent capabilities
|
||||
*/
|
||||
convertCapabilityAttributes(attributes, agent);
|
||||
|
||||
/*
|
||||
* Track (record) the agent class name and options data
|
||||
*/
|
||||
initerror = recordCommandLineData(agent, premainClass, options);
|
||||
|
||||
/*
|
||||
* Clean-up
|
||||
*/
|
||||
if (options != NULL) free(options);
|
||||
freeAttributes(attributes);
|
||||
free(premainClass);
|
||||
}
|
||||
|
||||
switch (initerror) {
|
||||
case JPLIS_INIT_ERROR_NONE:
|
||||
result = JNI_OK;
|
||||
break;
|
||||
case JPLIS_INIT_ERROR_CANNOT_CREATE_NATIVE_AGENT:
|
||||
result = JNI_ERR;
|
||||
fprintf(stderr, "java.lang.instrument/-javaagent: cannot create native agent.\n");
|
||||
break;
|
||||
case JPLIS_INIT_ERROR_FAILURE:
|
||||
result = JNI_ERR;
|
||||
fprintf(stderr, "java.lang.instrument/-javaagent: initialization of native agent failed.\n");
|
||||
break;
|
||||
case JPLIS_INIT_ERROR_ALLOCATION_FAILURE:
|
||||
result = JNI_ERR;
|
||||
fprintf(stderr, "java.lang.instrument/-javaagent: allocation failure.\n");
|
||||
break;
|
||||
case JPLIS_INIT_ERROR_AGENT_CLASS_NOT_SPECIFIED:
|
||||
result = JNI_ERR;
|
||||
fprintf(stderr, "-javaagent: agent class not specified.\n");
|
||||
break;
|
||||
default:
|
||||
result = JNI_ERR;
|
||||
fprintf(stderr, "java.lang.instrument/-javaagent: unknown error\n");
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Agent_OnAttach returns a jint. 0/JNI_OK indicates success and non-0
|
||||
* indicates an error. To allow the attach mechanism throw an
|
||||
* AgentInitializationException with a reasonable exception message we define
|
||||
* a few specific errors here.
|
||||
*/
|
||||
#define AGENT_ERROR_BADJAR ((jint)100) /* Agent JAR not found or no Agent-Class attribute */
|
||||
#define AGENT_ERROR_NOTONCP ((jint)101) /* Unable to add JAR file to system class path */
|
||||
#define AGENT_ERROR_STARTFAIL ((jint)102) /* No agentmain method or agentmain failed */
|
||||
|
||||
/*
|
||||
* This will be called once each time a tool attaches to the VM and loads
|
||||
* the JPLIS library.
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
DEF_Agent_OnAttach(JavaVM* vm, char *args, void * reserved) {
|
||||
JPLISInitializationError initerror = JPLIS_INIT_ERROR_NONE;
|
||||
jint result = JNI_OK;
|
||||
JPLISAgent * agent = NULL;
|
||||
JNIEnv * jni_env = NULL;
|
||||
|
||||
/*
|
||||
* Need JNIEnv - guaranteed to be called from thread that is already
|
||||
* attached to VM
|
||||
*/
|
||||
result = (*vm)->GetEnv(vm, (void**)&jni_env, JNI_VERSION_1_2);
|
||||
jplis_assert(result==JNI_OK);
|
||||
|
||||
initerror = createNewJPLISAgent(vm, &agent);
|
||||
if ( initerror == JPLIS_INIT_ERROR_NONE ) {
|
||||
int oldLen, newLen;
|
||||
char * jarfile;
|
||||
char * options;
|
||||
jarAttribute* attributes;
|
||||
char * agentClass;
|
||||
char * bootClassPath;
|
||||
jboolean success;
|
||||
|
||||
/*
|
||||
* Parse <jarfile>[=options] into jarfile and options
|
||||
*/
|
||||
if (parseArgumentTail(args, &jarfile, &options) != 0) {
|
||||
return JNI_ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open the JAR file and parse the manifest
|
||||
*/
|
||||
attributes = readAttributes( jarfile );
|
||||
if (attributes == NULL) {
|
||||
fprintf(stderr, "Error opening zip file or JAR manifest missing: %s\n", jarfile);
|
||||
free(jarfile);
|
||||
if (options != NULL) free(options);
|
||||
return AGENT_ERROR_BADJAR;
|
||||
}
|
||||
|
||||
agentClass = getAttribute(attributes, "Agent-Class");
|
||||
if (agentClass == NULL) {
|
||||
fprintf(stderr, "Failed to find Agent-Class manifest attribute from %s\n",
|
||||
jarfile);
|
||||
free(jarfile);
|
||||
if (options != NULL) free(options);
|
||||
freeAttributes(attributes);
|
||||
return AGENT_ERROR_BADJAR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the jarfile to the system class path
|
||||
*/
|
||||
if (appendClassPath(agent, jarfile)) {
|
||||
fprintf(stderr, "Unable to add %s to system class path "
|
||||
"- not supported by system class loader or configuration error!\n",
|
||||
jarfile);
|
||||
free(jarfile);
|
||||
if (options != NULL) free(options);
|
||||
freeAttributes(attributes);
|
||||
return AGENT_ERROR_NOTONCP;
|
||||
}
|
||||
|
||||
/*
|
||||
* The value of the Agent-Class attribute becomes the agent
|
||||
* class name. The manifest is in UTF8 so need to convert to
|
||||
* modified UTF8 (see JNI spec).
|
||||
*/
|
||||
oldLen = (int)strlen(agentClass);
|
||||
newLen = modifiedUtf8LengthOfUtf8(agentClass, oldLen);
|
||||
if (newLen == oldLen) {
|
||||
agentClass = strdup(agentClass);
|
||||
} else {
|
||||
char* str = (char*)malloc( newLen+1 );
|
||||
if (str != NULL) {
|
||||
convertUtf8ToModifiedUtf8(agentClass, oldLen, str, newLen);
|
||||
}
|
||||
agentClass = str;
|
||||
}
|
||||
if (agentClass == NULL) {
|
||||
free(jarfile);
|
||||
if (options != NULL) free(options);
|
||||
freeAttributes(attributes);
|
||||
return JNI_ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the Boot-Class-Path attribute is specified then we process
|
||||
* each URL - in the live phase only JAR files will be added.
|
||||
*/
|
||||
bootClassPath = getAttribute(attributes, "Boot-Class-Path");
|
||||
if (bootClassPath != NULL) {
|
||||
appendBootClassPath(agent, jarfile, bootClassPath);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert JAR attributes into agent capabilities
|
||||
*/
|
||||
convertCapabilityAttributes(attributes, agent);
|
||||
|
||||
/*
|
||||
* Create the java.lang.instrument.Instrumentation instance
|
||||
*/
|
||||
success = createInstrumentationImpl(jni_env, agent);
|
||||
jplis_assert(success);
|
||||
|
||||
/*
|
||||
* Turn on the ClassFileLoadHook.
|
||||
*/
|
||||
if (success) {
|
||||
success = setLivePhaseEventHandlers(agent);
|
||||
jplis_assert(success);
|
||||
}
|
||||
|
||||
/*
|
||||
* Start the agent
|
||||
*/
|
||||
if (success) {
|
||||
success = startJavaAgent(agent,
|
||||
jni_env,
|
||||
agentClass,
|
||||
options,
|
||||
agent->mAgentmainCaller);
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
fprintf(stderr, "Agent failed to start!\n");
|
||||
result = AGENT_ERROR_STARTFAIL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clean-up
|
||||
*/
|
||||
free(jarfile);
|
||||
if (options != NULL) free(options);
|
||||
free(agentClass);
|
||||
freeAttributes(attributes);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
DEF_Agent_OnUnload(JavaVM *vm) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked by the java launcher to load an agent in the main executable JAR.
|
||||
* The Launcher-Agent-Class attribute in the main manifest of the JAR file
|
||||
* is the agent class.
|
||||
*
|
||||
* Returns JNI_OK if the agent is loaded and initialized; JNI_ERR if this
|
||||
* function fails, possibly with a pending exception.
|
||||
*/
|
||||
jint loadAgent(JNIEnv* env, jstring path) {
|
||||
JavaVM* vm;
|
||||
JPLISAgent* agent;
|
||||
const char* jarfile = NULL;
|
||||
jarAttribute* attributes = NULL;
|
||||
char* agentClass = NULL;
|
||||
char* bootClassPath;
|
||||
int oldLen, newLen;
|
||||
jint result = JNI_ERR;
|
||||
|
||||
if ((*env)->GetJavaVM(env, &vm) < 0) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
// create JPLISAgent with JVMTI environment
|
||||
if (createNewJPLISAgent(vm, &agent) != JPLIS_INIT_ERROR_NONE) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
// get path to JAR file as UTF-8 string
|
||||
jarfile = (*env)->GetStringUTFChars(env, path, NULL);
|
||||
if (jarfile == NULL) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
// read the attributes in the main section of JAR manifest
|
||||
attributes = readAttributes(jarfile);
|
||||
if (attributes == NULL) {
|
||||
goto releaseAndReturn;
|
||||
}
|
||||
|
||||
// Launcher-Agent-Class is required
|
||||
agentClass = getAttribute(attributes, "Launcher-Agent-Class");
|
||||
if (agentClass == NULL) {
|
||||
goto releaseAndReturn;
|
||||
}
|
||||
|
||||
// The value of Launcher-Agent-Class is in UTF-8, convert it to modified UTF-8
|
||||
oldLen = (int) strlen(agentClass);
|
||||
newLen = modifiedUtf8LengthOfUtf8(agentClass, oldLen);
|
||||
if (newLen == oldLen) {
|
||||
agentClass = strdup(agentClass);
|
||||
} else {
|
||||
char* str = (char*) malloc(newLen + 1);
|
||||
if (str != NULL) {
|
||||
convertUtf8ToModifiedUtf8(agentClass, oldLen, str, newLen);
|
||||
}
|
||||
agentClass = str;
|
||||
}
|
||||
if (agentClass == NULL) {
|
||||
jthrowable oome = createThrowable(env, "java/lang/OutOfMemoryError", NULL);
|
||||
if (oome != NULL) (*env)->Throw(env, oome);
|
||||
goto releaseAndReturn;
|
||||
}
|
||||
|
||||
// Boot-Class-Path
|
||||
bootClassPath = getAttribute(attributes, "Boot-Class-Path");
|
||||
if (bootClassPath != NULL) {
|
||||
appendBootClassPath(agent, jarfile, bootClassPath);
|
||||
}
|
||||
|
||||
// Can-XXXX capabilities
|
||||
convertCapabilityAttributes(attributes, agent);
|
||||
|
||||
// Create the java.lang.instrument.Instrumentation object
|
||||
if (!createInstrumentationImpl(env, agent)) {
|
||||
goto releaseAndReturn;
|
||||
}
|
||||
|
||||
// Enable the ClassFileLoadHook
|
||||
if (!setLivePhaseEventHandlers(agent)) {
|
||||
goto releaseAndReturn;
|
||||
}
|
||||
|
||||
// invoke the agentmain method
|
||||
if (!startJavaAgent(agent, env, agentClass, "", agent->mAgentmainCaller)) {
|
||||
goto releaseAndReturn;
|
||||
}
|
||||
|
||||
// initialization complete
|
||||
result = JNI_OK;
|
||||
|
||||
releaseAndReturn:
|
||||
if (agentClass != NULL) {
|
||||
free(agentClass);
|
||||
}
|
||||
if (attributes != NULL) {
|
||||
freeAttributes(attributes);
|
||||
}
|
||||
if (jarfile != NULL) {
|
||||
(*env)->ReleaseStringUTFChars(env, path, jarfile);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* JVMTI callback support
|
||||
*
|
||||
* We have two "stages" of callback support.
|
||||
* At OnLoad time, we install a VMInit handler.
|
||||
* When the VMInit handler runs, we remove the VMInit handler and install a
|
||||
* ClassFileLoadHook handler.
|
||||
*/
|
||||
|
||||
void JNICALL
|
||||
eventHandlerVMInit( jvmtiEnv * jvmtienv,
|
||||
JNIEnv * jnienv,
|
||||
jthread thread) {
|
||||
JPLISEnvironment * environment = NULL;
|
||||
jboolean success = JNI_FALSE;
|
||||
|
||||
environment = getJPLISEnvironment(jvmtienv);
|
||||
|
||||
/* process the premain calls on the all the JPL agents */
|
||||
if ( environment != NULL ) {
|
||||
jthrowable outstandingException = NULL;
|
||||
/*
|
||||
* Add the jarfile to the system class path
|
||||
*/
|
||||
JPLISAgent * agent = environment->mAgent;
|
||||
if (appendClassPath(agent, agent->mJarfile)) {
|
||||
fprintf(stderr, "Unable to add %s to system class path - "
|
||||
"the system class loader does not define the "
|
||||
"appendToClassPathForInstrumentation method or the method failed\n",
|
||||
agent->mJarfile);
|
||||
free((void *)agent->mJarfile);
|
||||
abortJVM(jnienv, JPLIS_ERRORMESSAGE_CANNOTSTART);
|
||||
}
|
||||
free((void *)agent->mJarfile);
|
||||
agent->mJarfile = NULL;
|
||||
|
||||
outstandingException = preserveThrowable(jnienv);
|
||||
success = processJavaStart( environment->mAgent,
|
||||
jnienv);
|
||||
restoreThrowable(jnienv, outstandingException);
|
||||
}
|
||||
|
||||
/* if we fail to start cleanly, bring down the JVM */
|
||||
if ( !success ) {
|
||||
abortJVM(jnienv, JPLIS_ERRORMESSAGE_CANNOTSTART);
|
||||
}
|
||||
}
|
||||
|
||||
void JNICALL
|
||||
eventHandlerClassFileLoadHook( jvmtiEnv * jvmtienv,
|
||||
JNIEnv * jnienv,
|
||||
jclass class_being_redefined,
|
||||
jobject loader,
|
||||
const char* name,
|
||||
jobject protectionDomain,
|
||||
jint class_data_len,
|
||||
const unsigned char* class_data,
|
||||
jint* new_class_data_len,
|
||||
unsigned char** new_class_data) {
|
||||
JPLISEnvironment * environment = NULL;
|
||||
|
||||
environment = getJPLISEnvironment(jvmtienv);
|
||||
|
||||
/* if something is internally inconsistent (no agent), just silently return without touching the buffer */
|
||||
if ( environment != NULL ) {
|
||||
jthrowable outstandingException = preserveThrowable(jnienv);
|
||||
transformClassFile( environment->mAgent,
|
||||
jnienv,
|
||||
loader,
|
||||
name,
|
||||
class_being_redefined,
|
||||
protectionDomain,
|
||||
class_data_len,
|
||||
class_data,
|
||||
new_class_data_len,
|
||||
new_class_data,
|
||||
environment->mIsRetransformer);
|
||||
restoreThrowable(jnienv, outstandingException);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* URLs in Boot-Class-Path attributes are separated by one or more spaces.
|
||||
* This function splits the attribute value into a list of path segments.
|
||||
* The attribute value is in UTF8 but cannot contain NUL. Also non US-ASCII
|
||||
* characters must be escaped (URI syntax) so safe to iterate through the
|
||||
* value as a C string.
|
||||
*/
|
||||
static void
|
||||
splitPathList(const char* str, int* pathCount, char*** paths) {
|
||||
int count = 0;
|
||||
char** segments = NULL;
|
||||
char** new_segments;
|
||||
char* c = (char*) str;
|
||||
while (*c != '\0') {
|
||||
while (*c == ' ') c++; /* skip leading spaces */
|
||||
if (*c == '\0') {
|
||||
break;
|
||||
}
|
||||
new_segments = (char**)realloc(segments, (count+1)*sizeof(char*));
|
||||
if (new_segments == NULL) {
|
||||
jplis_assert(0);
|
||||
free(segments);
|
||||
count = 0;
|
||||
segments = NULL;
|
||||
break;
|
||||
}
|
||||
segments = new_segments;
|
||||
segments[count++] = c;
|
||||
c = strchr(c, ' ');
|
||||
if (c == NULL) {
|
||||
break;
|
||||
}
|
||||
*c = '\0';
|
||||
c++;
|
||||
}
|
||||
*pathCount = count;
|
||||
*paths = segments;
|
||||
}
|
||||
|
||||
|
||||
/* URI path decoding - ported from src/share/classes/java/net/URI.java */
|
||||
|
||||
static int
|
||||
decodeNibble(char c) {
|
||||
if ((c >= '0') && (c <= '9'))
|
||||
return c - '0';
|
||||
if ((c >= 'a') && (c <= 'f'))
|
||||
return c - 'a' + 10;
|
||||
if ((c >= 'A') && (c <= 'F'))
|
||||
return c - 'A' + 10;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
decodeByte(char c1, char c2) {
|
||||
return (((decodeNibble(c1) & 0xf) << 4) | ((decodeNibble(c2) & 0xf) << 0));
|
||||
}
|
||||
|
||||
/*
|
||||
* Evaluates all escapes in s. Assumes that escapes are well-formed
|
||||
* syntactically, i.e., of the form %XX.
|
||||
* If the path does not require decoding the original path is
|
||||
* returned. Otherwise the decoded path (heap allocated) is returned,
|
||||
* along with the length of the decoded path. Note that the return
|
||||
* string will not be null terminated after decoding.
|
||||
*/
|
||||
static
|
||||
char *decodePath(const char *s, int* decodedLen) {
|
||||
int n;
|
||||
char *result;
|
||||
char *resultp;
|
||||
int c;
|
||||
int i;
|
||||
|
||||
n = (int)strlen(s);
|
||||
if (n == 0) {
|
||||
*decodedLen = 0;
|
||||
return (char*)s;
|
||||
}
|
||||
if (strchr(s, '%') == NULL) {
|
||||
*decodedLen = n;
|
||||
return (char*)s; /* no escapes, we are done */
|
||||
}
|
||||
|
||||
resultp = result = calloc(n+1, 1);
|
||||
c = s[0];
|
||||
for (i = 0; i < n;) {
|
||||
if (c != '%') {
|
||||
*resultp++ = c;
|
||||
if (++i >= n)
|
||||
break;
|
||||
c = s[i];
|
||||
continue;
|
||||
}
|
||||
for (;;) {
|
||||
char b1 = s[++i];
|
||||
char b2 = s[++i];
|
||||
int decoded = decodeByte(b1, b2);
|
||||
*resultp++ = decoded;
|
||||
if (++i >= n)
|
||||
break;
|
||||
c = s[i];
|
||||
if (c != '%')
|
||||
break;
|
||||
}
|
||||
}
|
||||
*decodedLen = (int)(resultp - result);
|
||||
return result; // not null terminated.
|
||||
}
|
||||
|
||||
/*
|
||||
* Append the given jar file to the system class path. This should succeed in the
|
||||
* onload phase but may fail in the live phase if the system class loader doesn't
|
||||
* support appending to the class path.
|
||||
*/
|
||||
static int
|
||||
appendClassPath( JPLISAgent* agent,
|
||||
const char* jarfile ) {
|
||||
jvmtiEnv* jvmtienv = jvmti(agent);
|
||||
jvmtiError jvmtierr;
|
||||
|
||||
jvmtierr = (*jvmtienv)->AddToSystemClassLoaderSearch(jvmtienv, jarfile);
|
||||
check_phase_ret_1(jvmtierr);
|
||||
|
||||
switch (jvmtierr) {
|
||||
case JVMTI_ERROR_NONE :
|
||||
return 0;
|
||||
case JVMTI_ERROR_CLASS_LOADER_UNSUPPORTED :
|
||||
fprintf(stderr, "System class loader does not define "
|
||||
"the appendToClassPathForInstrumentation method\n");
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unexpected error (%d) returned by "
|
||||
"AddToSystemClassLoaderSearch\n", jvmtierr);
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* res = func, free'ing the previous value of 'res' if function
|
||||
* returns a new result.
|
||||
*/
|
||||
#define TRANSFORM(res,func) { \
|
||||
char* tmp = func; \
|
||||
if (tmp != res) { \
|
||||
free(res); \
|
||||
res = tmp; \
|
||||
} \
|
||||
jplis_assert((void*)res != (void*)NULL); \
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a pathname to canonical form.
|
||||
* This method is exported from libjava.
|
||||
*/
|
||||
extern int
|
||||
Canonicalize(JNIEnv *unused, char *orig, char *out, int len);
|
||||
|
||||
|
||||
/*
|
||||
* This function takes the value of the Boot-Class-Path attribute,
|
||||
* splits it into the individual path segments, and then combines it
|
||||
* with the path to the jar file to create the path to be added
|
||||
* to the bootclasspath.
|
||||
*
|
||||
* Each individual path segment starts out as a UTF8 string. Additionally
|
||||
* as the path is specified to use URI path syntax all non US-ASCII
|
||||
* characters are escaped. Once the URI path is decoded we get a UTF8
|
||||
* string which must then be converted to the platform encoding (as it
|
||||
* will be combined with the platform path of the jar file). Once
|
||||
* converted it is then normalized (remove duplicate slashes, etc.).
|
||||
* If the resulting path is an absolute path (starts with a slash for
|
||||
* example) then the path will be added to the bootclasspath. Otherwise
|
||||
* if it's not absolute then we get the canoncial path of the agent jar
|
||||
* file and then resolve the path in the context of the base path of
|
||||
* the agent jar.
|
||||
*/
|
||||
static void
|
||||
appendBootClassPath( JPLISAgent* agent,
|
||||
const char* jarfile,
|
||||
const char* pathList ) {
|
||||
char canonicalPath[MAXPATHLEN];
|
||||
char *parent = NULL;
|
||||
int haveBasePath = 0;
|
||||
|
||||
int count, i;
|
||||
char **paths;
|
||||
jvmtiEnv* jvmtienv = jvmti(agent);
|
||||
jvmtiError jvmtierr;
|
||||
|
||||
/*
|
||||
* Split the attribute value into the individual path segments
|
||||
* and process each in sequence
|
||||
*/
|
||||
splitPathList(pathList, &count, &paths);
|
||||
|
||||
for (i=0; i<count; i++) {
|
||||
int len;
|
||||
char* path;
|
||||
char* pos;
|
||||
|
||||
/*
|
||||
* The path segment at this point is a pointer into the attribute
|
||||
* value. As it will go through a number of transformation (tossing away
|
||||
* the previous results as we go along) it make it easier if the path
|
||||
* starts out as a heap allocated string.
|
||||
*/
|
||||
path = strdup(paths[i]);
|
||||
jplis_assert(path != (char*)NULL);
|
||||
|
||||
/*
|
||||
* The attribute is specified to be a list of relative URIs so in theory
|
||||
* there could be a query component - if so, get rid of it.
|
||||
*/
|
||||
pos = strchr(path, '?');
|
||||
if (pos != NULL) {
|
||||
*pos = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for characters that are not allowed in the path component of
|
||||
* a URI.
|
||||
*/
|
||||
if (validatePathChars(path)) {
|
||||
fprintf(stderr, "WARNING: illegal character in Boot-Class-Path value: %s\n",
|
||||
path);
|
||||
free(path);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Next decode any escaped characters. The result is a UTF8 string.
|
||||
*/
|
||||
TRANSFORM(path, decodePath(path,&len));
|
||||
|
||||
/*
|
||||
* Convert to the platform encoding
|
||||
*/
|
||||
{
|
||||
char platform[MAXPATHLEN];
|
||||
int new_len = convertUft8ToPlatformString(path, len, platform, MAXPATHLEN);
|
||||
free(path);
|
||||
if (new_len < 0) {
|
||||
/* bogus value - exceeds maximum path size or unable to convert */
|
||||
continue;
|
||||
}
|
||||
path = strdup(platform);
|
||||
jplis_assert(path != (char*)NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Post-process the URI path - needed on Windows to transform
|
||||
* /c:/foo to c:/foo.
|
||||
*/
|
||||
TRANSFORM(path, fromURIPath(path));
|
||||
|
||||
/*
|
||||
* Normalize the path - no duplicate slashes (except UNCs on Windows), trailing
|
||||
* slash removed.
|
||||
*/
|
||||
TRANSFORM(path, normalize(path));
|
||||
|
||||
/*
|
||||
* If the path is an absolute path then add to the bootclassloader
|
||||
* search path. Otherwise we get the canonical path of the agent jar
|
||||
* and then use its base path (directory) to resolve the given path
|
||||
* segment.
|
||||
*
|
||||
* NOTE: JVMTI is specified to use modified UTF8 strings (like JNI).
|
||||
* In 1.5.0 the AddToBootstrapClassLoaderSearch takes a platform string
|
||||
* - see 5049313.
|
||||
*/
|
||||
if (isAbsolute(path)) {
|
||||
jvmtierr = (*jvmtienv)->AddToBootstrapClassLoaderSearch(jvmtienv, path);
|
||||
} else {
|
||||
char* resolved;
|
||||
|
||||
if (!haveBasePath) {
|
||||
/* Use NULL as the JNIEnv since we know that Canonicalize does not use it. */
|
||||
if (Canonicalize(NULL, (char*)jarfile, canonicalPath, sizeof(canonicalPath)) != 0) {
|
||||
fprintf(stderr, "WARNING: unable to canonicalize %s\n", jarfile);
|
||||
free(path);
|
||||
continue;
|
||||
}
|
||||
parent = basePath(canonicalPath);
|
||||
jplis_assert(parent != (char*)NULL);
|
||||
haveBasePath = 1;
|
||||
}
|
||||
|
||||
resolved = resolve(parent, path);
|
||||
jvmtierr = (*jvmtienv)->AddToBootstrapClassLoaderSearch(jvmtienv, resolved);
|
||||
}
|
||||
|
||||
/* print warning if boot class path not updated */
|
||||
if (jvmtierr != JVMTI_ERROR_NONE) {
|
||||
check_phase_blob_ret(jvmtierr, free(path));
|
||||
|
||||
fprintf(stderr, "WARNING: %s not added to bootstrap class loader search: ", path);
|
||||
switch (jvmtierr) {
|
||||
case JVMTI_ERROR_ILLEGAL_ARGUMENT :
|
||||
fprintf(stderr, "Illegal argument or not JAR file\n");
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unexpected error: %d\n", jvmtierr);
|
||||
}
|
||||
}
|
||||
|
||||
/* finished with the path */
|
||||
free(path);
|
||||
}
|
||||
|
||||
|
||||
/* clean-up */
|
||||
if (haveBasePath && parent != canonicalPath) {
|
||||
free(parent);
|
||||
}
|
||||
}
|
1590
src/java.instrument/share/native/libinstrument/JPLISAgent.c
Normal file
1590
src/java.instrument/share/native/libinstrument/JPLISAgent.c
Normal file
File diff suppressed because it is too large
Load diff
317
src/java.instrument/share/native/libinstrument/JPLISAgent.h
Normal file
317
src/java.instrument/share/native/libinstrument/JPLISAgent.h
Normal file
|
@ -0,0 +1,317 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2003 Wily Technology, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _JPLISAGENT_H_
|
||||
#define _JPLISAGENT_H_
|
||||
|
||||
#include <jni.h>
|
||||
#include <jvmti.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The JPLISAgent manages the initialization all of the Java programming language Agents.
|
||||
* It also supports the native method bridge between the JPLIS and the JVMTI.
|
||||
* It maintains a single JVMTI Env that all JPL agents share.
|
||||
* It parses command line requests and creates individual Java agents.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Forward definitions
|
||||
*/
|
||||
struct _JPLISAgent;
|
||||
|
||||
typedef struct _JPLISAgent JPLISAgent;
|
||||
typedef struct _JPLISEnvironment JPLISEnvironment;
|
||||
|
||||
|
||||
/* constants for class names and methods names and such
|
||||
these all must stay in sync with Java code & interfaces
|
||||
*/
|
||||
#define JPLIS_INSTRUMENTIMPL_CLASSNAME "sun/instrument/InstrumentationImpl"
|
||||
#define JPLIS_INSTRUMENTIMPL_CONSTRUCTOR_METHODNAME "<init>"
|
||||
#define JPLIS_INSTRUMENTIMPL_CONSTRUCTOR_METHODSIGNATURE "(JZZ)V"
|
||||
#define JPLIS_INSTRUMENTIMPL_PREMAININVOKER_METHODNAME "loadClassAndCallPremain"
|
||||
#define JPLIS_INSTRUMENTIMPL_PREMAININVOKER_METHODSIGNATURE "(Ljava/lang/String;Ljava/lang/String;)V"
|
||||
#define JPLIS_INSTRUMENTIMPL_AGENTMAININVOKER_METHODNAME "loadClassAndCallAgentmain"
|
||||
#define JPLIS_INSTRUMENTIMPL_AGENTMAININVOKER_METHODSIGNATURE "(Ljava/lang/String;Ljava/lang/String;)V"
|
||||
#define JPLIS_INSTRUMENTIMPL_TRANSFORM_METHODNAME "transform"
|
||||
#define JPLIS_INSTRUMENTIMPL_TRANSFORM_METHODSIGNATURE \
|
||||
"(Ljava/lang/Module;Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/Class;Ljava/security/ProtectionDomain;[BZ)[B"
|
||||
|
||||
|
||||
/*
|
||||
* Error messages
|
||||
*/
|
||||
#define JPLIS_ERRORMESSAGE_CANNOTSTART "processing of -javaagent failed"
|
||||
|
||||
|
||||
/*
|
||||
* Our initialization errors
|
||||
*/
|
||||
typedef enum {
|
||||
JPLIS_INIT_ERROR_NONE,
|
||||
JPLIS_INIT_ERROR_CANNOT_CREATE_NATIVE_AGENT,
|
||||
JPLIS_INIT_ERROR_FAILURE,
|
||||
JPLIS_INIT_ERROR_ALLOCATION_FAILURE,
|
||||
JPLIS_INIT_ERROR_AGENT_CLASS_NOT_SPECIFIED
|
||||
} JPLISInitializationError;
|
||||
|
||||
|
||||
struct _JPLISEnvironment {
|
||||
jvmtiEnv * mJVMTIEnv; /* the JVM TI environment */
|
||||
JPLISAgent * mAgent; /* corresponding agent */
|
||||
jboolean mIsRetransformer; /* indicates if special environment */
|
||||
};
|
||||
|
||||
struct _JPLISAgent {
|
||||
JavaVM * mJVM; /* handle to the JVM */
|
||||
JPLISEnvironment mNormalEnvironment; /* for every thing but retransform stuff */
|
||||
JPLISEnvironment mRetransformEnvironment;/* for retransform stuff only */
|
||||
jobject mInstrumentationImpl; /* handle to the Instrumentation instance */
|
||||
jmethodID mPremainCaller; /* method on the InstrumentationImpl that does the premain stuff (cached to save lots of lookups) */
|
||||
jmethodID mAgentmainCaller; /* method on the InstrumentationImpl for agents loaded via attach mechanism */
|
||||
jmethodID mTransform; /* method on the InstrumentationImpl that does the class file transform */
|
||||
jboolean mRedefineAvailable; /* cached answer to "does this agent support redefine" */
|
||||
jboolean mRedefineAdded; /* indicates if can_redefine_classes capability has been added */
|
||||
jboolean mNativeMethodPrefixAvailable; /* cached answer to "does this agent support prefixing" */
|
||||
jboolean mNativeMethodPrefixAdded; /* indicates if can_set_native_method_prefix capability has been added */
|
||||
char const * mAgentClassName; /* agent class name */
|
||||
char const * mOptionsString; /* -javaagent options string */
|
||||
const char * mJarfile; /* agent jar file name */
|
||||
};
|
||||
|
||||
/*
|
||||
* JVMTI event handlers
|
||||
*/
|
||||
|
||||
/* VMInit event handler. Installed during OnLoad, then removed during VMInit. */
|
||||
extern void JNICALL
|
||||
eventHandlerVMInit( jvmtiEnv * jvmtienv,
|
||||
JNIEnv * jnienv,
|
||||
jthread thread);
|
||||
|
||||
/* ClassFileLoadHook event handler. Installed during VMInit, then left in place forever. */
|
||||
extern void JNICALL
|
||||
eventHandlerClassFileLoadHook( jvmtiEnv * jvmtienv,
|
||||
JNIEnv * jnienv,
|
||||
jclass class_being_redefined,
|
||||
jobject loader,
|
||||
const char* name,
|
||||
jobject protectionDomain,
|
||||
jint class_data_len,
|
||||
const unsigned char* class_data,
|
||||
jint* new_class_data_len,
|
||||
unsigned char** new_class_data);
|
||||
|
||||
/*
|
||||
* Main entry points for the JPLIS JVMTI agent code
|
||||
*/
|
||||
|
||||
/* looks up the environment instance. returns null if there isn't one */
|
||||
extern JPLISEnvironment *
|
||||
getJPLISEnvironment(jvmtiEnv * jvmtienv);
|
||||
|
||||
/* Creates a new JPLIS agent.
|
||||
* Returns error if the agent cannot be created and initialized.
|
||||
* The JPLISAgent* pointed to by agent_ptr is set to the new broker,
|
||||
* or NULL if an error has occurred.
|
||||
*/
|
||||
extern JPLISInitializationError
|
||||
createNewJPLISAgent(JavaVM * vm, JPLISAgent **agent_ptr);
|
||||
|
||||
/* Adds can_redefine_classes capability */
|
||||
extern void
|
||||
addRedefineClassesCapability(JPLISAgent * agent);
|
||||
|
||||
/* Add the can_set_native_method_prefix capability */
|
||||
extern void
|
||||
addNativeMethodPrefixCapability(JPLISAgent * agent);
|
||||
|
||||
/* Add the can_maintain_original_method_order capability (for testing) */
|
||||
extern void
|
||||
addOriginalMethodOrderCapability(JPLISAgent * agent);
|
||||
|
||||
|
||||
/* Our JPLIS agent is paralleled by a Java InstrumentationImpl instance.
|
||||
* This routine uses JNI to create and initialized the Java instance.
|
||||
* Returns true if it succeeds, false otherwise.
|
||||
*/
|
||||
extern jboolean
|
||||
createInstrumentationImpl( JNIEnv * jnienv,
|
||||
JPLISAgent * agent);
|
||||
|
||||
|
||||
/* during OnLoad phase (command line parsing)
|
||||
* record the parameters of -javaagent
|
||||
*/
|
||||
extern JPLISInitializationError
|
||||
recordCommandLineData( JPLISAgent * agent,
|
||||
const char * agentClass,
|
||||
const char * optionsString );
|
||||
|
||||
/* Swaps the start phase event handlers out and the live phase event handlers in.
|
||||
* Also used in attach to enabled live phase event handlers.
|
||||
* Returns true if it succeeds, false otherwise.
|
||||
*/
|
||||
extern jboolean
|
||||
setLivePhaseEventHandlers( JPLISAgent * agent);
|
||||
|
||||
/* Loads the Java agent according to the already processed command line. For each,
|
||||
* loads the Java agent class, then calls the premain method.
|
||||
* Returns true if all Java agent classes are loaded and all premain methods complete with no exceptions,
|
||||
* false otherwise.
|
||||
*/
|
||||
extern jboolean
|
||||
startJavaAgent( JPLISAgent * agent,
|
||||
JNIEnv * jnienv,
|
||||
const char * classname,
|
||||
const char * optionsString,
|
||||
jmethodID agentMainMethod);
|
||||
|
||||
|
||||
/* during VMInit processing
|
||||
* this is how the invocation engine (callback wrapper) tells us to start up all the javaagents
|
||||
*/
|
||||
extern jboolean
|
||||
processJavaStart( JPLISAgent * agent,
|
||||
JNIEnv * jnienv);
|
||||
|
||||
/* on an ongoing basis,
|
||||
* this is how the invocation engine (callback wrapper) tells us to process a class file
|
||||
*/
|
||||
extern void
|
||||
transformClassFile( JPLISAgent * agent,
|
||||
JNIEnv * jnienv,
|
||||
jobject loader,
|
||||
const char* name,
|
||||
jclass classBeingRedefined,
|
||||
jobject protectionDomain,
|
||||
jint class_data_len,
|
||||
const unsigned char* class_data,
|
||||
jint* new_class_data_len,
|
||||
unsigned char** new_class_data,
|
||||
jboolean is_retransformer);
|
||||
|
||||
/* on an ongoing basis,
|
||||
* Return the environment with the retransformation capability.
|
||||
* Create it if it doesn't exist.
|
||||
*/
|
||||
extern jvmtiEnv *
|
||||
retransformableEnvironment(JPLISAgent * agent);
|
||||
|
||||
/* on an ongoing basis,
|
||||
* these are implementations of the Instrumentation services.
|
||||
* Most are simple covers for JVMTI access services. These are the guts of the InstrumentationImpl
|
||||
* native methods.
|
||||
*/
|
||||
extern jboolean
|
||||
isModifiableClass(JNIEnv * jnienv, JPLISAgent * agent, jclass clazz);
|
||||
|
||||
extern jboolean
|
||||
isRetransformClassesSupported(JNIEnv * jnienv, JPLISAgent * agent);
|
||||
|
||||
extern void
|
||||
setHasRetransformableTransformers(JNIEnv * jnienv, JPLISAgent * agent, jboolean has);
|
||||
|
||||
extern void
|
||||
retransformClasses(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray classes);
|
||||
|
||||
extern void
|
||||
redefineClasses(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray classDefinitions);
|
||||
|
||||
extern jobjectArray
|
||||
getAllLoadedClasses(JNIEnv * jnienv, JPLISAgent * agent);
|
||||
|
||||
extern jobjectArray
|
||||
getInitiatedClasses(JNIEnv * jnienv, JPLISAgent * agent, jobject classLoader);
|
||||
|
||||
extern jlong
|
||||
getObjectSize(JNIEnv * jnienv, JPLISAgent * agent, jobject objectToSize);
|
||||
|
||||
extern void
|
||||
appendToClassLoaderSearch(JNIEnv * jnienv, JPLISAgent * agent, jstring jarFile, jboolean isBootLoader);
|
||||
|
||||
extern void
|
||||
setNativeMethodPrefixes(JNIEnv * jnienv, JPLISAgent * agent, jobjectArray prefixArray,
|
||||
jboolean isRetransformable);
|
||||
|
||||
#define jvmti(a) a->mNormalEnvironment.mJVMTIEnv
|
||||
|
||||
/*
|
||||
* A set of macros for insulating the JLI method callers from
|
||||
* JVMTI_ERROR_WRONG_PHASE return codes.
|
||||
*/
|
||||
|
||||
/* for a JLI method where "blob" is executed before simply returning */
|
||||
#define check_phase_blob_ret(ret, blob) \
|
||||
if ((ret) == JVMTI_ERROR_WRONG_PHASE) { \
|
||||
blob; \
|
||||
return; \
|
||||
}
|
||||
|
||||
/* for a JLI method where simply returning is benign */
|
||||
#define check_phase_ret(ret) \
|
||||
if ((ret) == JVMTI_ERROR_WRONG_PHASE) { \
|
||||
return; \
|
||||
}
|
||||
|
||||
/* for a JLI method where returning zero (0) is benign */
|
||||
#define check_phase_ret_0(ret) \
|
||||
if ((ret) == JVMTI_ERROR_WRONG_PHASE) { \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
/* for a JLI method where returning one (1) is benign */
|
||||
#define check_phase_ret_1(ret) \
|
||||
if ((ret) == JVMTI_ERROR_WRONG_PHASE) { \
|
||||
return 1; \
|
||||
}
|
||||
|
||||
/* for a case where a specific "blob" must be returned */
|
||||
#define check_phase_ret_blob(ret, blob) \
|
||||
if ((ret) == JVMTI_ERROR_WRONG_PHASE) { \
|
||||
return (blob); \
|
||||
}
|
||||
|
||||
/* for a JLI method where returning false is benign */
|
||||
#define check_phase_ret_false(ret) \
|
||||
if ((ret) == JVMTI_ERROR_WRONG_PHASE) { \
|
||||
return (jboolean) 0; \
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
#endif
|
66
src/java.instrument/share/native/libinstrument/JPLISAssert.c
Normal file
66
src/java.instrument/share/native/libinstrument/JPLISAssert.c
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2003 Wily Technology, Inc.
|
||||
*/
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include "JPLISAssert.h"
|
||||
|
||||
/*
|
||||
* Super-cheesy assertions that aren't efficient when they are turned on, but
|
||||
* are free when turned off (all pre-processor stuff)
|
||||
*/
|
||||
|
||||
void
|
||||
JPLISAssertCondition( jboolean condition,
|
||||
const char * assertionText,
|
||||
const char * file,
|
||||
int line) {
|
||||
if ( !condition ) {
|
||||
fprintf(stderr, "*** java.lang.instrument ASSERTION FAILED ***: \"%s\" at %s line: %d\n",
|
||||
assertionText,
|
||||
file,
|
||||
line);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JPLISAssertConditionWithMessage( jboolean condition,
|
||||
const char * assertionText,
|
||||
const char * message,
|
||||
const char * file,
|
||||
int line) {
|
||||
if ( !condition ) {
|
||||
fprintf(stderr, "*** java.lang.instrument ASSERTION FAILED ***: \"%s\" with message %s at %s line: %d\n",
|
||||
assertionText,
|
||||
message,
|
||||
file,
|
||||
line);
|
||||
}
|
||||
}
|
97
src/java.instrument/share/native/libinstrument/JPLISAssert.h
Normal file
97
src/java.instrument/share/native/libinstrument/JPLISAssert.h
Normal file
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2003 Wily Technology, Inc.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Super-cheesy assertions that aren't efficient when they are turned on, but
|
||||
* are free when turned off (all pre-processor stuff)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _JPLISASSERT_H_
|
||||
#define _JPLISASSERT_H_
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define JPLISASSERT_ENABLEASSERTIONS (1)
|
||||
|
||||
|
||||
#ifndef JPLISASSERT_ENABLEASSERTIONS
|
||||
#define JPLISASSERT_ENABLEASSERTIONS (0)
|
||||
#endif
|
||||
|
||||
/* Use THIS_FILE when it is available. */
|
||||
#ifndef THIS_FILE
|
||||
#define THIS_FILE __FILE__
|
||||
#endif
|
||||
|
||||
#if JPLISASSERT_ENABLEASSERTIONS
|
||||
#define jplis_assert(x) JPLISAssertCondition((jboolean)(x), #x, THIS_FILE, __LINE__)
|
||||
#define jplis_assert_msg(x, msg) JPLISAssertConditionWithMessage((jboolean)(x), #x, msg, THIS_FILE, __LINE__)
|
||||
#else
|
||||
#define jplis_assert(x)
|
||||
#define jplis_assert_msg(x, msg)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Test the supplied condition.
|
||||
* If false, print a constructed message including source site info to stderr.
|
||||
* If true, do nothing.
|
||||
*/
|
||||
extern void
|
||||
JPLISAssertCondition( jboolean condition,
|
||||
const char * assertionText,
|
||||
const char * file,
|
||||
int line);
|
||||
|
||||
/*
|
||||
* Test the supplied condition.
|
||||
* If false, print a constructed message including source site info
|
||||
* and the supplied message to stderr.
|
||||
* If true, do nothing.
|
||||
*/
|
||||
extern void
|
||||
JPLISAssertConditionWithMessage( jboolean condition,
|
||||
const char * assertionText,
|
||||
const char * message,
|
||||
const char * file,
|
||||
int line);
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
#endif
|
140
src/java.instrument/share/native/libinstrument/JarFacade.c
Normal file
140
src/java.instrument/share/native/libinstrument/JarFacade.c
Normal file
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* Copyright (c) 2004, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "manifest_info.h"
|
||||
#include "JarFacade.h"
|
||||
|
||||
typedef struct {
|
||||
jarAttribute* head;
|
||||
jarAttribute* tail;
|
||||
} iterationContext;
|
||||
|
||||
static void
|
||||
doAttribute(const char* name, const char* value, void* user_data) {
|
||||
iterationContext* context = (iterationContext*) user_data;
|
||||
|
||||
jarAttribute* attribute = (jarAttribute*)malloc(sizeof(jarAttribute));
|
||||
if (attribute != NULL) {
|
||||
attribute->name = strdup(name);
|
||||
if (attribute->name == NULL) {
|
||||
free(attribute);
|
||||
} else {
|
||||
char *begin = (char *)value;
|
||||
char *end;
|
||||
size_t value_len;
|
||||
|
||||
/* skip any leading white space */
|
||||
while (*begin == ' ') {
|
||||
begin++;
|
||||
}
|
||||
|
||||
/* skip any trailing white space */
|
||||
end = &begin[strlen(begin)];
|
||||
while (end > begin && end[-1] == ' ') {
|
||||
end--;
|
||||
}
|
||||
|
||||
if (begin == end) {
|
||||
/* no value so skip this attribute */
|
||||
free(attribute->name);
|
||||
free(attribute);
|
||||
return;
|
||||
}
|
||||
|
||||
value_len = (size_t)(end - begin);
|
||||
attribute->value = malloc(value_len + 1);
|
||||
if (attribute->value == NULL) {
|
||||
free(attribute->name);
|
||||
free(attribute);
|
||||
} else {
|
||||
/* save the value without leading or trailing whitespace */
|
||||
strncpy(attribute->value, begin, value_len);
|
||||
attribute->value[value_len] = '\0';
|
||||
attribute->next = NULL;
|
||||
if (context->head == NULL) {
|
||||
context->head = attribute;
|
||||
} else {
|
||||
context->tail->next = attribute;
|
||||
}
|
||||
context->tail = attribute;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a list of attributes from the main section of the given JAR
|
||||
* file. Returns NULL if there is an error or there aren't any attributes.
|
||||
*/
|
||||
jarAttribute*
|
||||
readAttributes(const char* jarfile)
|
||||
{
|
||||
int rc;
|
||||
iterationContext context = { NULL, NULL };
|
||||
|
||||
rc = JLI_ManifestIterate(jarfile, doAttribute, (void*)&context);
|
||||
|
||||
if (rc == 0) {
|
||||
return context.head;
|
||||
} else {
|
||||
freeAttributes(context.head);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Free a list of attributes
|
||||
*/
|
||||
void
|
||||
freeAttributes(jarAttribute* head) {
|
||||
while (head != NULL) {
|
||||
jarAttribute* next = (jarAttribute*)head->next;
|
||||
free(head->name);
|
||||
free(head->value);
|
||||
free(head);
|
||||
head = next;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the value of an attribute in an attribute list. Returns NULL
|
||||
* if attribute not found.
|
||||
*/
|
||||
char*
|
||||
getAttribute(const jarAttribute* attributes, const char* name) {
|
||||
while (attributes != NULL) {
|
||||
if (strcasecmp(attributes->name, name) == 0) {
|
||||
return attributes->value;
|
||||
}
|
||||
attributes = (jarAttribute*)attributes->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
44
src/java.instrument/share/native/libinstrument/JarFacade.h
Normal file
44
src/java.instrument/share/native/libinstrument/JarFacade.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifdef STATIC_BUILD
|
||||
#define getAttribute JarGetAttribute
|
||||
#endif
|
||||
|
||||
typedef struct _jarAttribute {
|
||||
char* name;
|
||||
char* value;
|
||||
struct _jarAttribute* next;
|
||||
} jarAttribute;
|
||||
|
||||
|
||||
/* Returns a list of attributes */
|
||||
jarAttribute* readAttributes(const char* jarfile);
|
||||
|
||||
/* Frees attribute list */
|
||||
void freeAttributes(jarAttribute* attributes);
|
||||
|
||||
/* Gets the attribute by name */
|
||||
char* getAttribute(const jarAttribute* attributes, const char* name);
|
414
src/java.instrument/share/native/libinstrument/JavaExceptions.c
Normal file
414
src/java.instrument/share/native/libinstrument/JavaExceptions.c
Normal file
|
@ -0,0 +1,414 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2003 Wily Technology, Inc.
|
||||
*/
|
||||
|
||||
#include <jni.h>
|
||||
#include <jvmti.h>
|
||||
|
||||
#include "JPLISAssert.h"
|
||||
#include "Utilities.h"
|
||||
#include "JavaExceptions.h"
|
||||
|
||||
/**
|
||||
* This module contains utility routines for manipulating Java throwables
|
||||
* and JNIEnv throwable state from native code.
|
||||
*/
|
||||
|
||||
static jthrowable sFallbackInternalError = NULL;
|
||||
|
||||
/*
|
||||
* Local forward declarations.
|
||||
*/
|
||||
|
||||
/* insist on having a throwable. If we already have one, return it.
|
||||
* If not, map to fallback
|
||||
*/
|
||||
jthrowable
|
||||
forceFallback(jthrowable potentialException);
|
||||
|
||||
|
||||
jthrowable
|
||||
forceFallback(jthrowable potentialException) {
|
||||
if ( potentialException == NULL ) {
|
||||
return sFallbackInternalError;
|
||||
}
|
||||
else {
|
||||
return potentialException;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if it properly sets up a fallback exception
|
||||
*/
|
||||
jboolean
|
||||
initializeFallbackError(JNIEnv* jnienv) {
|
||||
jplis_assert(isSafeForJNICalls(jnienv));
|
||||
sFallbackInternalError = createInternalError(jnienv, NULL);
|
||||
jplis_assert(isSafeForJNICalls(jnienv));
|
||||
return (sFallbackInternalError != NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Map everything to InternalError.
|
||||
*/
|
||||
jthrowable
|
||||
mapAllCheckedToInternalErrorMapper( JNIEnv * jnienv,
|
||||
jthrowable throwableToMap) {
|
||||
jthrowable mappedThrowable = NULL;
|
||||
jstring message = NULL;
|
||||
|
||||
jplis_assert(throwableToMap != NULL);
|
||||
jplis_assert(isSafeForJNICalls(jnienv));
|
||||
jplis_assert(!isUnchecked(jnienv, throwableToMap));
|
||||
|
||||
message = getMessageFromThrowable(jnienv, throwableToMap);
|
||||
mappedThrowable = createInternalError(jnienv, message);
|
||||
|
||||
jplis_assert(isSafeForJNICalls(jnienv));
|
||||
return mappedThrowable;
|
||||
}
|
||||
|
||||
|
||||
jboolean
|
||||
checkForThrowable( JNIEnv* jnienv) {
|
||||
return (*jnienv)->ExceptionCheck(jnienv);
|
||||
}
|
||||
|
||||
jboolean
|
||||
isSafeForJNICalls( JNIEnv * jnienv) {
|
||||
return !(*jnienv)->ExceptionCheck(jnienv);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
logThrowable( JNIEnv * jnienv) {
|
||||
if ( checkForThrowable(jnienv) ) {
|
||||
(*jnienv)->ExceptionDescribe(jnienv);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates an exception or error with the fully qualified classname (ie java/lang/Error)
|
||||
* and message passed to its constructor
|
||||
*/
|
||||
jthrowable
|
||||
createThrowable( JNIEnv * jnienv,
|
||||
const char * className,
|
||||
jstring message) {
|
||||
jthrowable exception = NULL;
|
||||
jmethodID constructor = NULL;
|
||||
jclass exceptionClass = NULL;
|
||||
jboolean errorOutstanding = JNI_FALSE;
|
||||
|
||||
jplis_assert(className != NULL);
|
||||
jplis_assert(isSafeForJNICalls(jnienv));
|
||||
|
||||
/* create new VMError with message from exception */
|
||||
exceptionClass = (*jnienv)->FindClass(jnienv, className);
|
||||
errorOutstanding = checkForAndClearThrowable(jnienv);
|
||||
jplis_assert(!errorOutstanding);
|
||||
|
||||
if (!errorOutstanding) {
|
||||
constructor = (*jnienv)->GetMethodID( jnienv,
|
||||
exceptionClass,
|
||||
"<init>",
|
||||
"(Ljava/lang/String;)V");
|
||||
errorOutstanding = checkForAndClearThrowable(jnienv);
|
||||
jplis_assert(!errorOutstanding);
|
||||
}
|
||||
|
||||
if (!errorOutstanding) {
|
||||
exception = (*jnienv)->NewObject(jnienv, exceptionClass, constructor, message);
|
||||
errorOutstanding = checkForAndClearThrowable(jnienv);
|
||||
jplis_assert(!errorOutstanding);
|
||||
}
|
||||
|
||||
jplis_assert(isSafeForJNICalls(jnienv));
|
||||
return exception;
|
||||
}
|
||||
|
||||
jthrowable
|
||||
createInternalError(JNIEnv * jnienv, jstring message) {
|
||||
return createThrowable( jnienv,
|
||||
"java/lang/InternalError",
|
||||
message);
|
||||
}
|
||||
|
||||
jthrowable
|
||||
createThrowableFromJVMTIErrorCode(JNIEnv * jnienv, jvmtiError errorCode) {
|
||||
const char * throwableClassName = NULL;
|
||||
const char * message = NULL;
|
||||
jstring messageString = NULL;
|
||||
|
||||
switch ( errorCode ) {
|
||||
case JVMTI_ERROR_NULL_POINTER:
|
||||
throwableClassName = "java/lang/NullPointerException";
|
||||
break;
|
||||
|
||||
case JVMTI_ERROR_ILLEGAL_ARGUMENT:
|
||||
throwableClassName = "java/lang/IllegalArgumentException";
|
||||
break;
|
||||
|
||||
case JVMTI_ERROR_OUT_OF_MEMORY:
|
||||
throwableClassName = "java/lang/OutOfMemoryError";
|
||||
break;
|
||||
|
||||
case JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION:
|
||||
throwableClassName = "java/lang/ClassCircularityError";
|
||||
break;
|
||||
|
||||
case JVMTI_ERROR_FAILS_VERIFICATION:
|
||||
throwableClassName = "java/lang/VerifyError";
|
||||
break;
|
||||
|
||||
case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED:
|
||||
throwableClassName = "java/lang/UnsupportedOperationException";
|
||||
message = "class redefinition failed: attempted to add a method";
|
||||
break;
|
||||
|
||||
case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED:
|
||||
throwableClassName = "java/lang/UnsupportedOperationException";
|
||||
message = "class redefinition failed: attempted to change the schema (add/remove fields)";
|
||||
break;
|
||||
|
||||
case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED:
|
||||
throwableClassName = "java/lang/UnsupportedOperationException";
|
||||
message = "class redefinition failed: attempted to change superclass or interfaces";
|
||||
break;
|
||||
|
||||
case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED:
|
||||
throwableClassName = "java/lang/UnsupportedOperationException";
|
||||
message = "class redefinition failed: attempted to delete a method";
|
||||
break;
|
||||
|
||||
case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED:
|
||||
throwableClassName = "java/lang/UnsupportedOperationException";
|
||||
message = "class redefinition failed: attempted to change the class modifiers";
|
||||
break;
|
||||
|
||||
case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED:
|
||||
throwableClassName = "java/lang/UnsupportedOperationException";
|
||||
message = "class redefinition failed: attempted to change method modifiers";
|
||||
break;
|
||||
|
||||
case JVMTI_ERROR_UNSUPPORTED_VERSION:
|
||||
throwableClassName = "java/lang/UnsupportedClassVersionError";
|
||||
break;
|
||||
|
||||
case JVMTI_ERROR_NAMES_DONT_MATCH:
|
||||
throwableClassName = "java/lang/NoClassDefFoundError";
|
||||
message = "class names don't match";
|
||||
break;
|
||||
|
||||
case JVMTI_ERROR_INVALID_CLASS_FORMAT:
|
||||
throwableClassName = "java/lang/ClassFormatError";
|
||||
break;
|
||||
|
||||
case JVMTI_ERROR_UNMODIFIABLE_CLASS:
|
||||
throwableClassName = "java/lang/instrument/UnmodifiableClassException";
|
||||
break;
|
||||
|
||||
case JVMTI_ERROR_INVALID_CLASS:
|
||||
throwableClassName = "java/lang/InternalError";
|
||||
message = "class redefinition failed: invalid class";
|
||||
break;
|
||||
|
||||
case JVMTI_ERROR_CLASS_LOADER_UNSUPPORTED:
|
||||
throwableClassName = "java/lang/UnsupportedOperationException";
|
||||
message = "unsupported operation";
|
||||
break;
|
||||
|
||||
case JVMTI_ERROR_INTERNAL:
|
||||
default:
|
||||
throwableClassName = "java/lang/InternalError";
|
||||
break;
|
||||
}
|
||||
|
||||
if ( message != NULL ) {
|
||||
jboolean errorOutstanding;
|
||||
|
||||
messageString = (*jnienv)->NewStringUTF(jnienv, message);
|
||||
errorOutstanding = checkForAndClearThrowable(jnienv);
|
||||
jplis_assert_msg(!errorOutstanding, "can't create exception java string");
|
||||
}
|
||||
return createThrowable( jnienv,
|
||||
throwableClassName,
|
||||
messageString);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calls toString() on the given message which is the same call made by
|
||||
* Exception when passed a throwable to its constructor
|
||||
*/
|
||||
jstring
|
||||
getMessageFromThrowable( JNIEnv* jnienv,
|
||||
jthrowable exception) {
|
||||
jclass exceptionClass = NULL;
|
||||
jmethodID method = NULL;
|
||||
jstring message = NULL;
|
||||
jboolean errorOutstanding = JNI_FALSE;
|
||||
|
||||
jplis_assert(isSafeForJNICalls(jnienv));
|
||||
|
||||
/* call getMessage on exception */
|
||||
exceptionClass = (*jnienv)->GetObjectClass(jnienv, exception);
|
||||
errorOutstanding = checkForAndClearThrowable(jnienv);
|
||||
jplis_assert(!errorOutstanding);
|
||||
|
||||
if (!errorOutstanding) {
|
||||
method = (*jnienv)->GetMethodID(jnienv,
|
||||
exceptionClass,
|
||||
"toString",
|
||||
"()Ljava/lang/String;");
|
||||
errorOutstanding = checkForAndClearThrowable(jnienv);
|
||||
jplis_assert(!errorOutstanding);
|
||||
}
|
||||
|
||||
if (!errorOutstanding) {
|
||||
message = (*jnienv)->CallObjectMethod(jnienv, exception, method);
|
||||
errorOutstanding = checkForAndClearThrowable(jnienv);
|
||||
jplis_assert(!errorOutstanding);
|
||||
}
|
||||
|
||||
jplis_assert(isSafeForJNICalls(jnienv));
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns whether the exception given is an unchecked exception:
|
||||
* a subclass of Error or RuntimeException
|
||||
*/
|
||||
jboolean
|
||||
isUnchecked( JNIEnv* jnienv,
|
||||
jthrowable exception) {
|
||||
jboolean result = JNI_FALSE;
|
||||
|
||||
jplis_assert(isSafeForJNICalls(jnienv));
|
||||
result = (exception == NULL) ||
|
||||
isInstanceofClassName(jnienv, exception, "java/lang/Error") ||
|
||||
isInstanceofClassName(jnienv, exception, "java/lang/RuntimeException");
|
||||
jplis_assert(isSafeForJNICalls(jnienv));
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the current throwable, if any. Clears the throwable state.
|
||||
* Clients can use this to preserve the current throwable state on the stack.
|
||||
*/
|
||||
jthrowable
|
||||
preserveThrowable(JNIEnv * jnienv) {
|
||||
jthrowable result = (*jnienv)->ExceptionOccurred(jnienv);
|
||||
if ( result != NULL ) {
|
||||
(*jnienv)->ExceptionClear(jnienv);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Installs the supplied throwable into the JNIEnv if the throwable is not null.
|
||||
* Clients can use this to preserve the current throwable state on the stack.
|
||||
*/
|
||||
void
|
||||
restoreThrowable( JNIEnv * jnienv,
|
||||
jthrowable preservedException) {
|
||||
throwThrowable( jnienv,
|
||||
preservedException);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
throwThrowable( JNIEnv * jnienv,
|
||||
jthrowable exception) {
|
||||
if ( exception != NULL ) {
|
||||
jint result = (*jnienv)->Throw(jnienv, exception);
|
||||
jplis_assert_msg(result == JNI_OK, "throwThrowable failed to re-throw");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Always clears the JNIEnv throwable state. Returns true if an exception was present
|
||||
* before the clearing operation.
|
||||
*/
|
||||
jboolean
|
||||
checkForAndClearThrowable( JNIEnv * jnienv) {
|
||||
jboolean result = (*jnienv)->ExceptionCheck(jnienv);
|
||||
if ( result ) {
|
||||
(*jnienv)->ExceptionClear(jnienv);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* creates a java.lang.InternalError and installs it into the JNIEnv */
|
||||
void
|
||||
createAndThrowInternalError(JNIEnv * jnienv) {
|
||||
jthrowable internalError = createInternalError( jnienv, NULL);
|
||||
throwThrowable(jnienv, forceFallback(internalError));
|
||||
}
|
||||
|
||||
void
|
||||
createAndThrowThrowableFromJVMTIErrorCode(JNIEnv * jnienv, jvmtiError errorCode) {
|
||||
jthrowable throwable = createThrowableFromJVMTIErrorCode(jnienv, errorCode);
|
||||
throwThrowable(jnienv, forceFallback(throwable));
|
||||
}
|
||||
|
||||
void
|
||||
mapThrownThrowableIfNecessary( JNIEnv * jnienv,
|
||||
CheckedExceptionMapper mapper) {
|
||||
jthrowable originalThrowable = NULL;
|
||||
jthrowable resultThrowable = NULL;
|
||||
|
||||
originalThrowable = preserveThrowable(jnienv);
|
||||
|
||||
/* the throwable is now cleared, so JNI calls are safe */
|
||||
if ( originalThrowable != NULL ) {
|
||||
/* if there is an exception: we can just throw it if it is unchecked. If checked,
|
||||
* we need to map it (mapper is conditional, will vary by usage, hence the callback)
|
||||
*/
|
||||
if ( isUnchecked(jnienv, originalThrowable) ) {
|
||||
resultThrowable = originalThrowable;
|
||||
}
|
||||
else {
|
||||
resultThrowable = (*mapper) (jnienv, originalThrowable);
|
||||
}
|
||||
}
|
||||
|
||||
/* re-establish the correct throwable */
|
||||
if ( resultThrowable != NULL ) {
|
||||
throwThrowable(jnienv, forceFallback(resultThrowable));
|
||||
}
|
||||
|
||||
}
|
162
src/java.instrument/share/native/libinstrument/JavaExceptions.h
Normal file
162
src/java.instrument/share/native/libinstrument/JavaExceptions.h
Normal file
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2003 Wily Technology, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _JAVAEXCEPTIONS_H_
|
||||
#define _JAVAEXCEPTIONS_H_
|
||||
|
||||
#include <jni.h>
|
||||
#include <jvmti.h>
|
||||
|
||||
/**
|
||||
* This module contains utility routines for manipulating Java throwables
|
||||
* and JNIEnv throwable state from native code.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set up static state. Needs java, must be called at or after VMInit.
|
||||
* Returns true if it succeeds, false if it fails.
|
||||
*/
|
||||
extern jboolean
|
||||
initializeFallbackError(JNIEnv* jnienv);
|
||||
|
||||
/*
|
||||
* Mapping support. Allows different clients to map checked exceptions in different ways.
|
||||
*/
|
||||
typedef jthrowable (*CheckedExceptionMapper)
|
||||
( JNIEnv * jnienv,
|
||||
jthrowable throwableToMap);
|
||||
|
||||
/* Default mapper. Map everything checked to InternalError; can return null if error */
|
||||
extern jthrowable
|
||||
mapAllCheckedToInternalErrorMapper( JNIEnv * jnienv,
|
||||
jthrowable throwableToMap);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Exception-helper routines that do not modify the JNIEnv.
|
||||
* They require a clean JNIEnv on entry, and they guarantee a clean JNIEnv on exit.
|
||||
*/
|
||||
|
||||
/* creates a throwable from the supplied parameters; can return null if error */
|
||||
extern jthrowable
|
||||
createThrowable( JNIEnv* jnienv,
|
||||
const char* className,
|
||||
jstring message);
|
||||
|
||||
/* creates a java.lang.InternalError; can return null if error */
|
||||
extern jthrowable
|
||||
createInternalError(JNIEnv * jnienv, jstring message);
|
||||
|
||||
/* creates the appropriate java Throwable based on the error code; can return null if error */
|
||||
extern jthrowable
|
||||
createThrowableFromJVMTIErrorCode(JNIEnv * jnienv, jvmtiError errorCode);
|
||||
|
||||
/* fetches the message string out of the supplied throwable, null if there is none, null if error */
|
||||
extern jstring
|
||||
getMessageFromThrowable( JNIEnv* jnienv,
|
||||
jthrowable exception);
|
||||
|
||||
/* true if the supplied throwable is unchecked. null will return true. */
|
||||
extern jboolean
|
||||
isUnchecked( JNIEnv* jnienv,
|
||||
jthrowable exception);
|
||||
|
||||
/* true if the env contains a thrown exception */
|
||||
extern jboolean
|
||||
checkForThrowable( JNIEnv* jnienv);
|
||||
|
||||
/* true if the env is clean for JNI calls */
|
||||
extern jboolean
|
||||
isSafeForJNICalls( JNIEnv * jnienv);
|
||||
|
||||
/*
|
||||
* Logs the outstanding throwable, if one exists.
|
||||
* This call assumes an outstanding exception, but does not
|
||||
* modify the JNIEnv outstanding Throwable state.
|
||||
*/
|
||||
extern void
|
||||
logThrowable( JNIEnv * jnienv);
|
||||
|
||||
|
||||
/*
|
||||
* These routines do modify the JNIEnv outstanding Throwable state.
|
||||
*/
|
||||
|
||||
/* Throws the supplied throwable. always sets the JNIEnv throwable */
|
||||
extern void
|
||||
throwThrowable( JNIEnv * jnienv,
|
||||
jthrowable exception);
|
||||
|
||||
/* returns current throwable. always clears the JNIEnv exception */
|
||||
extern jthrowable
|
||||
preserveThrowable(JNIEnv * jnienv);
|
||||
|
||||
/* undoes preserveThrowable (Throws the supplied throwable). always sets the JNIEnv throwable */
|
||||
extern void
|
||||
restoreThrowable( JNIEnv * jnienv,
|
||||
jthrowable preservedException);
|
||||
|
||||
/* always clears the JNIEnv throwable. returns true if an exception was pending on entry. */
|
||||
extern jboolean
|
||||
checkForAndClearThrowable( JNIEnv * jnienv);
|
||||
|
||||
/* creates the appropriate java Throwable based on the error code
|
||||
* does the very best it can to make sure an exception ends up installed; uses fallback if necessary
|
||||
* always sets the JNIEnv exception
|
||||
*/
|
||||
extern void
|
||||
createAndThrowThrowableFromJVMTIErrorCode(JNIEnv * jnienv, jvmtiError errorCode);
|
||||
|
||||
/* creates a java.lang.InternalError and installs it into the JNIEnv.
|
||||
* does the very best it can to make sure an exception ends up installed; uses fallback if necessary
|
||||
* always sets the JNIEnv exception
|
||||
*/
|
||||
extern void
|
||||
createAndThrowInternalError(JNIEnv * jnienv);
|
||||
|
||||
/* If no throwable is outstanding, do nothing.
|
||||
* If a throwable is outstanding, make sure it is of a legal type according to the supplied
|
||||
* mapping function.
|
||||
* Leaves the "thrown" state the same (none on exit if none on entry, thrown on exit if
|
||||
* thrown on entry); may change the type of the thrown exception.
|
||||
*/
|
||||
extern void
|
||||
mapThrownThrowableIfNecessary(JNIEnv * jnienv, CheckedExceptionMapper mapper);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "jni.h"
|
||||
|
||||
#ifndef max
|
||||
#define max(a,b) ( (a>b) ? a : b )
|
||||
#endif
|
||||
#ifndef min
|
||||
#define min(a,b) ( (a<b) ? a : b )
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Validates that a URI path component does not contain any illegal characters
|
||||
* - ported from src/share/classes/java/net/URI.java
|
||||
*/
|
||||
|
||||
static jlong L_HEX;
|
||||
static jlong H_HEX;
|
||||
static jlong L_PATH;
|
||||
static jlong H_PATH;
|
||||
|
||||
/* Compute the low-order mask for the characters in the given string */
|
||||
static jlong lowMask(char* s) {
|
||||
size_t n = strlen(s);
|
||||
jlong m = 0;
|
||||
size_t i;
|
||||
for (i = 0; i < n; i++) {
|
||||
int c = (int)s[i];
|
||||
if (c < 64)
|
||||
m |= ((jlong)1 << c);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
/* Compute the high-order mask for the characters in the given string */
|
||||
static jlong highMask(char* s) {
|
||||
size_t n = strlen(s);
|
||||
jlong m = 0;
|
||||
size_t i;
|
||||
for (i = 0; i < n; i++) {
|
||||
int c = (int)s[i];
|
||||
if ((c >= 64) && (c < 128))
|
||||
m |= ((jlong)1 << (c - 64));
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute a low-order mask for the characters
|
||||
* between first and last, inclusive
|
||||
*/
|
||||
static jlong lowMaskRange(char first, char last) {
|
||||
jlong m = 0;
|
||||
int f = max(min(first, 63), 0);
|
||||
int l = max(min(last, 63), 0);
|
||||
int i;
|
||||
|
||||
for (i = f; i <= l; i++) {
|
||||
m |= (jlong)1 << i;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute a high-order mask for the characters
|
||||
* between first and last, inclusive
|
||||
*/
|
||||
static jlong highMaskRange(char first, char last) {
|
||||
jlong m = 0;
|
||||
int f = max(min(first, 127), 64) - 64;
|
||||
int l = max(min(last, 127), 64) - 64;
|
||||
int i;
|
||||
for (i = f; i <= l; i++) {
|
||||
m |= (jlong)1 << i;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tell whether the given character is permitted by the given mask pair
|
||||
*/
|
||||
static int match(int c, jlong lowMask, jlong highMask) {
|
||||
if (c >= 0 && c < 64)
|
||||
if ((((jlong)1 << c) & lowMask) != 0) return 1;
|
||||
if (c >= 64 && c < 128)
|
||||
if ((((jlong)1 << (c - 64)) & highMask) != 0) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void initialize() {
|
||||
// digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
|
||||
// "8" | "9"
|
||||
jlong L_DIGIT = lowMaskRange('0', '9');
|
||||
jlong H_DIGIT = 0;
|
||||
|
||||
// upalpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" |
|
||||
// "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" |
|
||||
// "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z"
|
||||
jlong L_UPALPHA = 0;
|
||||
jlong H_UPALPHA = highMaskRange('A', 'Z');
|
||||
|
||||
// lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" |
|
||||
// "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" |
|
||||
// "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"
|
||||
jlong L_LOWALPHA = 0;
|
||||
jlong H_LOWALPHA = highMaskRange('a', 'z');
|
||||
|
||||
// alpha = lowalpha | upalpha
|
||||
jlong L_ALPHA = L_LOWALPHA | L_UPALPHA;
|
||||
jlong H_ALPHA = H_LOWALPHA | H_UPALPHA;
|
||||
|
||||
// alphanum = alpha | digit
|
||||
jlong L_ALPHANUM = L_DIGIT | L_ALPHA;
|
||||
jlong H_ALPHANUM = H_DIGIT | H_ALPHA;
|
||||
|
||||
// mark = "-" | "_" | "." | "!" | "~" | "*" | "'" |
|
||||
// "(" | ")"
|
||||
jlong L_MARK = lowMask("-_.!~*'()");
|
||||
jlong H_MARK = highMask("-_.!~*'()");
|
||||
|
||||
// unreserved = alphanum | mark
|
||||
jlong L_UNRESERVED = L_ALPHANUM | L_MARK;
|
||||
jlong H_UNRESERVED = H_ALPHANUM | H_MARK;
|
||||
|
||||
// pchar = unreserved |
|
||||
// ":" | "@" | "&" | "=" | "+" | "$" | ","
|
||||
jlong L_PCHAR = L_UNRESERVED | lowMask(":@&=+$,");
|
||||
jlong H_PCHAR = H_UNRESERVED | highMask(":@&=+$,");
|
||||
|
||||
// hex = digit | "A" | "B" | "C" | "D" | "E" | "F" |
|
||||
// "a" | "b" | "c" | "d" | "e" | "f"
|
||||
L_HEX = L_DIGIT;
|
||||
H_HEX = highMaskRange('A', 'F') | highMaskRange('a', 'f');
|
||||
|
||||
// All valid path characters
|
||||
L_PATH = L_PCHAR | lowMask(";/");
|
||||
H_PATH = H_PCHAR | highMask(";/");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Validates that the given URI path component does not contain any
|
||||
* illegal characters. Returns 0 if only validate characters are present.
|
||||
*/
|
||||
int validatePathChars(const char* path) {
|
||||
size_t i, n;
|
||||
|
||||
/* initialize on first usage */
|
||||
if (L_HEX == 0) {
|
||||
initialize();
|
||||
}
|
||||
|
||||
i=0;
|
||||
n = strlen(path);
|
||||
while (i < n) {
|
||||
int c = (int)(signed char)path[i];
|
||||
|
||||
/* definitely not us-ascii */
|
||||
if (c < 0) return -1;
|
||||
|
||||
/* start of an escapted character */
|
||||
if (c == '%') {
|
||||
if (i + 3 <= n) {
|
||||
int h1 = (int)(signed char)path[i+1];
|
||||
int h2 = (int)(signed char)path[i+2];
|
||||
if (h1 < 0 || h2 < 0) return -1;
|
||||
if (!match(h1, L_HEX, H_HEX)) return -1;
|
||||
if (!match(h2, L_HEX, H_HEX)) return -1;
|
||||
i += 3;
|
||||
} else {
|
||||
/* malformed escape pair */
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (!match(c, L_PATH, H_PATH)) return -1;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Validates that the given URI path component does not contain any
|
||||
* illegal characters. Returns 0 if only validate characters are present.
|
||||
*/
|
||||
int validatePathChars(const char* path);
|
165
src/java.instrument/share/native/libinstrument/Reentrancy.c
Normal file
165
src/java.instrument/share/native/libinstrument/Reentrancy.c
Normal file
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2003 Wily Technology, Inc.
|
||||
*/
|
||||
|
||||
#include <jni.h>
|
||||
#include <jvmti.h>
|
||||
|
||||
#include "JPLISAssert.h"
|
||||
#include "Reentrancy.h"
|
||||
#include "JPLISAgent.h"
|
||||
|
||||
/*
|
||||
* This module provides some utility functions to support the "same thread" re-entrancy management.
|
||||
* Uses JVMTI TLS to store a single bit per thread.
|
||||
* Non-zero means the thread is already inside; zero means the thread is not inside.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Local prototypes
|
||||
*/
|
||||
|
||||
/* Wrapper around set that does the set then re-fetches to make sure it worked.
|
||||
* Degenerates to a simple set when assertions are disabled.
|
||||
* This routine is only here because of a bug in the JVMTI where set to 0 fails.
|
||||
*/
|
||||
jvmtiError
|
||||
confirmingTLSSet( jvmtiEnv * jvmtienv,
|
||||
jthread thread,
|
||||
const void * newValue);
|
||||
|
||||
/* Confirmation routine only; used to assure that the TLS slot holds the value we expect it to. */
|
||||
void
|
||||
assertTLSValue( jvmtiEnv * jvmtienv,
|
||||
jthread thread,
|
||||
const void * expected);
|
||||
|
||||
|
||||
#define JPLIS_CURRENTLY_INSIDE_TOKEN ((void *) 0x7EFFC0BB)
|
||||
#define JPLIS_CURRENTLY_OUTSIDE_TOKEN ((void *) 0)
|
||||
|
||||
|
||||
jvmtiError
|
||||
confirmingTLSSet( jvmtiEnv * jvmtienv,
|
||||
jthread thread,
|
||||
const void * newValue) {
|
||||
jvmtiError error;
|
||||
|
||||
error = (*jvmtienv)->SetThreadLocalStorage(
|
||||
jvmtienv,
|
||||
thread,
|
||||
newValue);
|
||||
check_phase_ret_blob(error, error);
|
||||
|
||||
#if JPLISASSERT_ENABLEASSERTIONS
|
||||
assertTLSValue( jvmtienv,
|
||||
thread,
|
||||
newValue);
|
||||
#endif
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void
|
||||
assertTLSValue( jvmtiEnv * jvmtienv,
|
||||
jthread thread,
|
||||
const void * expected) {
|
||||
jvmtiError error;
|
||||
void * test = (void *) 0x99999999;
|
||||
|
||||
/* now check if we do a fetch we get what we wrote */
|
||||
error = (*jvmtienv)->GetThreadLocalStorage(
|
||||
jvmtienv,
|
||||
thread,
|
||||
&test);
|
||||
check_phase_ret(error);
|
||||
jplis_assert(error == JVMTI_ERROR_NONE);
|
||||
jplis_assert(test == expected);
|
||||
}
|
||||
|
||||
jboolean
|
||||
tryToAcquireReentrancyToken( jvmtiEnv * jvmtienv,
|
||||
jthread thread) {
|
||||
jboolean result = JNI_FALSE;
|
||||
jvmtiError error = JVMTI_ERROR_NONE;
|
||||
void * storedValue = NULL;
|
||||
|
||||
error = (*jvmtienv)->GetThreadLocalStorage(
|
||||
jvmtienv,
|
||||
thread,
|
||||
&storedValue);
|
||||
check_phase_ret_false(error);
|
||||
jplis_assert(error == JVMTI_ERROR_NONE);
|
||||
if ( error == JVMTI_ERROR_NONE ) {
|
||||
/* if this thread is already inside, just return false and short-circuit */
|
||||
if ( storedValue == JPLIS_CURRENTLY_INSIDE_TOKEN ) {
|
||||
result = JNI_FALSE;
|
||||
}
|
||||
else {
|
||||
/* stuff in the sentinel and return true */
|
||||
#if JPLISASSERT_ENABLEASSERTIONS
|
||||
assertTLSValue( jvmtienv,
|
||||
thread,
|
||||
JPLIS_CURRENTLY_OUTSIDE_TOKEN);
|
||||
#endif
|
||||
error = confirmingTLSSet ( jvmtienv,
|
||||
thread,
|
||||
JPLIS_CURRENTLY_INSIDE_TOKEN);
|
||||
check_phase_ret_false(error);
|
||||
jplis_assert(error == JVMTI_ERROR_NONE);
|
||||
if ( error != JVMTI_ERROR_NONE ) {
|
||||
result = JNI_FALSE;
|
||||
}
|
||||
else {
|
||||
result = JNI_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
releaseReentrancyToken( jvmtiEnv * jvmtienv,
|
||||
jthread thread) {
|
||||
jvmtiError error = JVMTI_ERROR_NONE;
|
||||
|
||||
/* assert we hold the token */
|
||||
#if JPLISASSERT_ENABLEASSERTIONS
|
||||
assertTLSValue( jvmtienv,
|
||||
thread,
|
||||
JPLIS_CURRENTLY_INSIDE_TOKEN);
|
||||
#endif
|
||||
|
||||
error = confirmingTLSSet( jvmtienv,
|
||||
thread,
|
||||
JPLIS_CURRENTLY_OUTSIDE_TOKEN);
|
||||
check_phase_ret(error);
|
||||
jplis_assert(error == JVMTI_ERROR_NONE);
|
||||
|
||||
}
|
63
src/java.instrument/share/native/libinstrument/Reentrancy.h
Normal file
63
src/java.instrument/share/native/libinstrument/Reentrancy.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2003 Wily Technology, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _REENTRANCY_H_
|
||||
#define _REENTRANCY_H_
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
/*
|
||||
* This module provides some utility functions to support the "same thread" re-entrancy management.
|
||||
* Uses JVMTI TLS to store a single bit per thread.
|
||||
* Non-zero means the thread is already inside; zero means the thread is not inside.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* returns true if the token is acquired by this call,
|
||||
* false if we already hold it and do not have to acquire it
|
||||
*/
|
||||
extern jboolean
|
||||
tryToAcquireReentrancyToken( jvmtiEnv * jvmtienv,
|
||||
jthread thread);
|
||||
|
||||
/* release the token; assumes we already hold it */
|
||||
extern void
|
||||
releaseReentrancyToken( jvmtiEnv * jvmtienv,
|
||||
jthread thread);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
#endif
|
110
src/java.instrument/share/native/libinstrument/Utilities.c
Normal file
110
src/java.instrument/share/native/libinstrument/Utilities.c
Normal file
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2003 Wily Technology, Inc.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "JPLISAssert.h"
|
||||
#include "Utilities.h"
|
||||
#include "JavaExceptions.h"
|
||||
|
||||
/*
|
||||
* This module provides various simple JNI and JVMTI utility functionality.
|
||||
*/
|
||||
|
||||
void *
|
||||
allocate(jvmtiEnv * jvmtienv, size_t bytecount) {
|
||||
void * resultBuffer = NULL;
|
||||
jvmtiError error = JVMTI_ERROR_NONE;
|
||||
|
||||
error = (*jvmtienv)->Allocate(jvmtienv,
|
||||
bytecount,
|
||||
(unsigned char**) &resultBuffer);
|
||||
/* may be called from any phase */
|
||||
jplis_assert(error == JVMTI_ERROR_NONE);
|
||||
if ( error != JVMTI_ERROR_NONE ) {
|
||||
resultBuffer = NULL;
|
||||
}
|
||||
return resultBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method that deallocates memory.
|
||||
* Throws assert on error.
|
||||
* JVMTI Deallocate can only fail due to internal error, that is, this
|
||||
* agent has done something wrong or JVMTI has done something wrong. These
|
||||
* errors aren't interesting to a JPLIS agent and so are not returned.
|
||||
*/
|
||||
void
|
||||
deallocate(jvmtiEnv * jvmtienv, void * buffer) {
|
||||
jvmtiError error = JVMTI_ERROR_NONE;
|
||||
|
||||
error = (*jvmtienv)->Deallocate(jvmtienv,
|
||||
(unsigned char*)buffer);
|
||||
/* may be called from any phase */
|
||||
jplis_assert_msg(error == JVMTI_ERROR_NONE, "Can't deallocate memory");
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the passed exception is an instance of the given classname
|
||||
* Clears any JNI exceptions before returning
|
||||
*/
|
||||
jboolean
|
||||
isInstanceofClassName( JNIEnv * jnienv,
|
||||
jobject instance,
|
||||
const char * className) {
|
||||
jboolean isInstanceof = JNI_FALSE;
|
||||
jboolean errorOutstanding = JNI_FALSE;
|
||||
jclass classHandle = NULL;
|
||||
|
||||
jplis_assert(isSafeForJNICalls(jnienv));
|
||||
|
||||
/* get an instance of unchecked exception for instanceof comparison */
|
||||
classHandle = (*jnienv)->FindClass(jnienv, className);
|
||||
errorOutstanding = checkForAndClearThrowable(jnienv);
|
||||
jplis_assert(!errorOutstanding);
|
||||
|
||||
if (!errorOutstanding) {
|
||||
isInstanceof = (*jnienv)->IsInstanceOf(jnienv, instance, classHandle);
|
||||
errorOutstanding = checkForAndClearThrowable(jnienv);
|
||||
jplis_assert(!errorOutstanding);
|
||||
}
|
||||
|
||||
jplis_assert(isSafeForJNICalls(jnienv));
|
||||
return isInstanceof;
|
||||
}
|
||||
|
||||
/* We don't come back from this
|
||||
*/
|
||||
void
|
||||
abortJVM( JNIEnv * jnienv,
|
||||
const char * message) {
|
||||
(*jnienv)->FatalError(jnienv, message);
|
||||
}
|
83
src/java.instrument/share/native/libinstrument/Utilities.h
Normal file
83
src/java.instrument/share/native/libinstrument/Utilities.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2003 Wily Technology, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _UTILITIES_H_
|
||||
#define _UTILITIES_H_
|
||||
|
||||
#include <jni.h>
|
||||
#include <jvmti.h>
|
||||
#include "jni_util.h"
|
||||
|
||||
#ifdef STATIC_BUILD
|
||||
#define allocate instAllocate
|
||||
#define deallocate instDeallocate
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This module provides various simple JNI and JVMTI utility functionality.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This allocate must be paired with this deallocate. Used for our own working buffers.
|
||||
* Implementation may vary.
|
||||
*/
|
||||
extern void *
|
||||
allocate(jvmtiEnv * jvmtienv, size_t bytecount);
|
||||
|
||||
extern void
|
||||
deallocate(jvmtiEnv * jvmtienv, void * buffer);
|
||||
|
||||
|
||||
/*
|
||||
* Misc. JNI support
|
||||
*/
|
||||
/* convenience wrapper around JNI instanceOf */
|
||||
extern jboolean
|
||||
isInstanceofClassName( JNIEnv* jnienv,
|
||||
jobject instance,
|
||||
const char* className);
|
||||
|
||||
|
||||
/* calling this stops the JVM and does not return */
|
||||
extern void
|
||||
abortJVM( JNIEnv * jnienv,
|
||||
const char * message);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
* Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <locale.h>
|
||||
#include <langinfo.h>
|
||||
#include <iconv.h>
|
||||
|
||||
/* Routines to convert back and forth between Platform Encoding and UTF-8 */
|
||||
|
||||
/* Use THIS_FILE when it is available. */
|
||||
#ifndef THIS_FILE
|
||||
#define THIS_FILE __FILE__
|
||||
#endif
|
||||
|
||||
/* Error and assert macros */
|
||||
#define UTF_ERROR(m) utfError(THIS_FILE, __LINE__, m)
|
||||
#define UTF_ASSERT(x) ( (x)==0 ? UTF_ERROR("ASSERT ERROR " #x) : (void)0 )
|
||||
#define UTF_DEBUG(x)
|
||||
|
||||
/* Global variables */
|
||||
static iconv_t iconvToPlatform = (iconv_t)-1;
|
||||
static iconv_t iconvFromPlatform = (iconv_t)-1;
|
||||
|
||||
/*
|
||||
* Error handler
|
||||
*/
|
||||
static void
|
||||
utfError(char *file, int line, char *message)
|
||||
{
|
||||
(void)fprintf(stderr, "UTF ERROR [\"%s\":%d]: %s\n", file, line, message);
|
||||
abort();
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize all utf processing.
|
||||
*/
|
||||
static void
|
||||
utfInitialize(void)
|
||||
{
|
||||
char *codeset;
|
||||
|
||||
/* Set the locale from the environment */
|
||||
(void)setlocale(LC_ALL, "");
|
||||
|
||||
/* Get the codeset name */
|
||||
codeset = (char*)nl_langinfo(CODESET);
|
||||
if ( codeset == NULL || codeset[0] == 0 ) {
|
||||
UTF_DEBUG(("NO codeset returned by nl_langinfo(CODESET)\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
UTF_DEBUG(("Codeset = %s\n", codeset));
|
||||
|
||||
/* If we don't need this, skip it */
|
||||
if (strcmp(codeset, "UTF-8") == 0 || strcmp(codeset, "utf8") == 0 ) {
|
||||
UTF_DEBUG(("NO iconv() being used because it is not needed\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Open conversion descriptors */
|
||||
iconvToPlatform = iconv_open(codeset, "UTF-8");
|
||||
if ( iconvToPlatform == (iconv_t)-1 ) {
|
||||
UTF_ERROR("Failed to complete iconv_open() setup");
|
||||
}
|
||||
iconvFromPlatform = iconv_open("UTF-8", codeset);
|
||||
if ( iconvFromPlatform == (iconv_t)-1 ) {
|
||||
UTF_ERROR("Failed to complete iconv_open() setup");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Terminate all utf processing
|
||||
*/
|
||||
static void
|
||||
utfTerminate(void)
|
||||
{
|
||||
if ( iconvFromPlatform!=(iconv_t)-1 ) {
|
||||
(void)iconv_close(iconvFromPlatform);
|
||||
}
|
||||
if ( iconvToPlatform!=(iconv_t)-1 ) {
|
||||
(void)iconv_close(iconvToPlatform);
|
||||
}
|
||||
iconvToPlatform = (iconv_t)-1;
|
||||
iconvFromPlatform = (iconv_t)-1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do iconv() conversion.
|
||||
* Returns length or -1 if output overflows.
|
||||
*/
|
||||
static int
|
||||
iconvConvert(iconv_t ic, char *bytes, int len, char *output, int outputMaxLen)
|
||||
{
|
||||
int outputLen = 0;
|
||||
|
||||
UTF_ASSERT(bytes);
|
||||
UTF_ASSERT(len>=0);
|
||||
UTF_ASSERT(output);
|
||||
UTF_ASSERT(outputMaxLen>len);
|
||||
|
||||
output[0] = 0;
|
||||
outputLen = 0;
|
||||
|
||||
if ( ic != (iconv_t)-1 ) {
|
||||
int returnValue;
|
||||
size_t inLeft;
|
||||
size_t outLeft;
|
||||
char *inbuf;
|
||||
char *outbuf;
|
||||
|
||||
inbuf = bytes;
|
||||
outbuf = output;
|
||||
inLeft = len;
|
||||
outLeft = outputMaxLen;
|
||||
returnValue = iconv(ic, (void*)&inbuf, &inLeft, &outbuf, &outLeft);
|
||||
if ( returnValue >= 0 && inLeft==0 ) {
|
||||
outputLen = outputMaxLen-outLeft;
|
||||
output[outputLen] = 0;
|
||||
return outputLen;
|
||||
}
|
||||
|
||||
/* Failed to do the conversion */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Just copy bytes */
|
||||
outputLen = len;
|
||||
(void)memcpy(output, bytes, len);
|
||||
output[len] = 0;
|
||||
return outputLen;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert UTF-8 to Platform Encoding.
|
||||
* Returns length or -1 if output overflows.
|
||||
*/
|
||||
static int
|
||||
utf8ToPlatform(char *utf8, int len, char *output, int outputMaxLen)
|
||||
{
|
||||
return iconvConvert(iconvToPlatform, utf8, len, output, outputMaxLen);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert Platform Encoding to UTF-8.
|
||||
* Returns length or -1 if output overflows.
|
||||
*/
|
||||
static int
|
||||
platformToUtf8(char *str, int len, char *output, int outputMaxLen)
|
||||
{
|
||||
return iconvConvert(iconvFromPlatform, str, len, output, outputMaxLen);
|
||||
}
|
||||
|
||||
int
|
||||
convertUft8ToPlatformString(char* utf8_str, int utf8_len, char* platform_str, int platform_len) {
|
||||
if (iconvToPlatform == (iconv_t)-1) {
|
||||
utfInitialize();
|
||||
}
|
||||
return utf8ToPlatform(utf8_str, utf8_len, platform_str, platform_len);
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "FileSystemSupport_md.h"
|
||||
|
||||
/*
|
||||
* Solaris/Linux implementation of the file system support functions.
|
||||
*/
|
||||
|
||||
#define slash '/'
|
||||
|
||||
char pathSeparator() {
|
||||
return ':';
|
||||
}
|
||||
|
||||
/* Filenames are case senstitive */
|
||||
int filenameStrcmp(const char* s1, const char* s2) {
|
||||
return strcmp(s1, s2);
|
||||
}
|
||||
|
||||
char* basePath(const char* path) {
|
||||
char* last = strrchr(path, slash);
|
||||
if (last == NULL) {
|
||||
return (char*)path;
|
||||
} else {
|
||||
int len = last - path;
|
||||
char* str = (char*)malloc(len+1);
|
||||
if (len > 0) {
|
||||
memcpy(str, path, len);
|
||||
}
|
||||
str[len] = '\0';
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
int isAbsolute(const char* path) {
|
||||
return (path[0] == slash) ? 1 : 0;
|
||||
}
|
||||
|
||||
/* Ported from src/solaris/classes/java/io/UnixFileSystem.java */
|
||||
|
||||
/* A normal Unix pathname contains no duplicate slashes and does not end
|
||||
with a slash. It may be the empty string. */
|
||||
|
||||
/* Normalize the given pathname, whose length is len, starting at the given
|
||||
offset; everything before this offset is already normal. */
|
||||
static char* normalizePath(const char* pathname, int len, int off) {
|
||||
char* sb;
|
||||
int sbLen, i, n;
|
||||
char prevChar;
|
||||
|
||||
if (len == 0) return (char*)pathname;
|
||||
n = len;
|
||||
while ((n > 0) && (pathname[n - 1] == slash)) n--;
|
||||
if (n == 0) return strdup("/");
|
||||
|
||||
sb = (char*)malloc(strlen(pathname)+1);
|
||||
sbLen = 0;
|
||||
|
||||
if (off > 0) {
|
||||
memcpy(sb, pathname, off);
|
||||
sbLen = off;
|
||||
}
|
||||
|
||||
prevChar = 0;
|
||||
for (i = off; i < n; i++) {
|
||||
char c = pathname[i];
|
||||
if ((prevChar == slash) && (c == slash)) continue;
|
||||
sb[sbLen++] = c;
|
||||
prevChar = c;
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
/* Check that the given pathname is normal. If not, invoke the real
|
||||
normalizer on the part of the pathname that requires normalization.
|
||||
This way we iterate through the whole pathname string only once. */
|
||||
char* normalize(const char* pathname) {
|
||||
int i;
|
||||
int n = strlen(pathname);
|
||||
char prevChar = 0;
|
||||
for (i = 0; i < n; i++) {
|
||||
char c = pathname[i];
|
||||
if ((prevChar == slash) && (c == slash))
|
||||
return normalizePath(pathname, n, i - 1);
|
||||
prevChar = c;
|
||||
}
|
||||
if (prevChar == slash) return normalizePath(pathname, n, n - 1);
|
||||
return (char*)pathname;
|
||||
}
|
||||
|
||||
char* resolve(const char* parent, const char* child) {
|
||||
int len;
|
||||
char* theChars;
|
||||
int pn = strlen(parent);
|
||||
int cn = strlen(child);
|
||||
int childStart = 0;
|
||||
int parentEnd = pn;
|
||||
|
||||
if (pn > 0 && parent[pn-1] == slash) {
|
||||
parentEnd--;
|
||||
}
|
||||
len = parentEnd + cn - childStart;
|
||||
if (child[0] == slash) {
|
||||
theChars = (char*)malloc(len+1);
|
||||
if (parentEnd > 0)
|
||||
memcpy(theChars, parent, parentEnd);
|
||||
if (cn > 0)
|
||||
memcpy(theChars+parentEnd, child, cn);
|
||||
theChars[len] = '\0';
|
||||
} else {
|
||||
theChars = (char*)malloc(len+2);
|
||||
if (parentEnd > 0)
|
||||
memcpy(theChars, parent, parentEnd);
|
||||
theChars[parentEnd] = slash;
|
||||
if (cn > 0)
|
||||
memcpy(theChars+parentEnd+1, child, cn);
|
||||
theChars[len+1] = '\0';
|
||||
}
|
||||
return theChars;
|
||||
}
|
||||
|
||||
char* fromURIPath(const char* path) {
|
||||
int len = strlen(path);
|
||||
if (len > 1 && path[len-1] == slash) {
|
||||
// "/foo/" --> "/foo", but "/" --> "/"
|
||||
char* str = (char*)malloc(len);
|
||||
if (str != NULL) {
|
||||
memcpy(str, path, len-1);
|
||||
str[len-1] = '\0';
|
||||
}
|
||||
return str;
|
||||
} else {
|
||||
return (char*)path;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2004, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h> /* For uintprt_t */
|
||||
#include <stdlib.h>
|
||||
#include <sys/param.h> /* For MAXPATHLEN */
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
#include <windows.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
/*
|
||||
* Convert UTF-8 to a platform string
|
||||
*/
|
||||
int
|
||||
convertUft8ToPlatformString(char* utf8_str, int utf8_len, char* platform_str, int platform_len) {
|
||||
LANGID langID;
|
||||
LCID localeID;
|
||||
TCHAR strCodePage[7]; // ANSI code page id
|
||||
UINT codePage;
|
||||
int wlen, plen;
|
||||
WCHAR* wstr;
|
||||
|
||||
/*
|
||||
* Get the code page for this locale
|
||||
*/
|
||||
langID = LANGIDFROMLCID(GetUserDefaultLCID());
|
||||
localeID = MAKELCID(langID, SORT_DEFAULT);
|
||||
if (GetLocaleInfo(localeID, LOCALE_IDEFAULTANSICODEPAGE,
|
||||
strCodePage, sizeof(strCodePage)/sizeof(TCHAR)) > 0 ) {
|
||||
codePage = atoi(strCodePage);
|
||||
} else {
|
||||
codePage = GetACP();
|
||||
}
|
||||
|
||||
/*
|
||||
* To convert the string to platform encoding we must first convert
|
||||
* to unicode, and then convert to the platform encoding
|
||||
*/
|
||||
plen = -1;
|
||||
wlen = MultiByteToWideChar(CP_UTF8, 0, utf8_str, utf8_len, NULL, 0);
|
||||
if (wlen > 0) {
|
||||
wstr = (WCHAR*)malloc(wlen * sizeof(WCHAR));
|
||||
if (wstr != NULL) {
|
||||
if (MultiByteToWideChar(CP_UTF8,
|
||||
0,
|
||||
utf8_str,
|
||||
utf8_len,
|
||||
wstr, wlen) > 0) {
|
||||
plen = WideCharToMultiByte(codePage,
|
||||
0,
|
||||
wstr,
|
||||
wlen,
|
||||
platform_str,
|
||||
platform_len,
|
||||
NULL,
|
||||
NULL);
|
||||
if (plen >= 0) {
|
||||
platform_str[plen] = '\0';
|
||||
}
|
||||
free(wstr);
|
||||
}
|
||||
}
|
||||
}
|
||||
return plen;
|
||||
}
|
|
@ -0,0 +1,329 @@
|
|||
/*
|
||||
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include "FileSystemSupport_md.h"
|
||||
|
||||
/*
|
||||
* Windows implementation of file system support functions
|
||||
*/
|
||||
|
||||
#define slash '\\'
|
||||
#define altSlash '/'
|
||||
|
||||
static int isSlash(char c) {
|
||||
return (c == '\\') || (c == '/');
|
||||
}
|
||||
|
||||
static int isLetter(char c) {
|
||||
return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'));
|
||||
}
|
||||
|
||||
char pathSeparator() {
|
||||
return ';';
|
||||
}
|
||||
|
||||
/* filename are case insensitive on windows */
|
||||
int filenameStrcmp(const char* s1, const char* s2) {
|
||||
return strcasecmp(s1, s2);
|
||||
}
|
||||
|
||||
char* basePath(const char* path) {
|
||||
char* pos = strchr(path, slash);
|
||||
char* last = NULL;
|
||||
while (pos != NULL) {
|
||||
last = pos;
|
||||
pos++;
|
||||
pos = strchr(pos, slash);
|
||||
}
|
||||
if (last == NULL) {
|
||||
return (char*)path;
|
||||
} else {
|
||||
int len = (int)(last - path);
|
||||
char* str = (char*)malloc(len+1);
|
||||
if (len > 0) {
|
||||
memcpy(str, path, len);
|
||||
}
|
||||
str[len] = '\0';
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -- Normalization - src/windows/classes/java/io/Win32FileSystem.java */
|
||||
|
||||
|
||||
/* A normal Win32 pathname contains no duplicate slashes, except possibly
|
||||
* for a UNC prefix, and does not end with a slash. It may be the empty
|
||||
* string. Normalized Win32 pathnames have the convenient property that
|
||||
* the length of the prefix almost uniquely identifies the type of the path
|
||||
* and whether it is absolute or relative:
|
||||
*
|
||||
* 0 relative to both drive and directory
|
||||
* 1 drive-relative (begins with '\\')
|
||||
* 2 absolute UNC (if first char is '\\'),
|
||||
* else directory-relative (has form "z:foo")
|
||||
* 3 absolute local pathname (begins with "z:\\")
|
||||
*/
|
||||
static int normalizePrefix(const char* path, int len, char* sb, int* sbLen) {
|
||||
char c;
|
||||
int src = 0;
|
||||
while ((src < len) && isSlash(path[src])) src++;
|
||||
if ((len - src >= 2)
|
||||
&& isLetter(c = path[src])
|
||||
&& path[src + 1] == ':') {
|
||||
/* Remove leading slashes if followed by drive specifier.
|
||||
This hack is necessary to support file URLs containing drive
|
||||
specifiers (e.g., "file://c:/path"). As a side effect,
|
||||
"/c:/path" can be used as an alternative to "c:/path". */
|
||||
sb[(*sbLen)++] = c;
|
||||
sb[(*sbLen)++] = ':';
|
||||
src += 2;
|
||||
} else {
|
||||
src = 0;
|
||||
if ((len >= 2)
|
||||
&& isSlash(path[0])
|
||||
&& isSlash(path[1])) {
|
||||
/* UNC pathname: Retain first slash; leave src pointed at
|
||||
second slash so that further slashes will be collapsed
|
||||
into the second slash. The result will be a pathname
|
||||
beginning with "\\\\" followed (most likely) by a host
|
||||
name. */
|
||||
src = 1;
|
||||
sb[(*sbLen)++] = slash;
|
||||
}
|
||||
}
|
||||
return src;
|
||||
}
|
||||
|
||||
/*
|
||||
* Normalize the given pathname, whose length is len, starting at the given
|
||||
* offset; everything before this offset is already normal.
|
||||
*/
|
||||
static char* normalizePath(const char* path, int len, int off) {
|
||||
int src;
|
||||
char* sb;
|
||||
int sbLen;
|
||||
|
||||
if (len == 0) return (char*)path;
|
||||
if (off < 3) off = 0; /* Avoid fencepost cases with UNC pathnames */
|
||||
|
||||
sb = (char*)malloc(len+1);
|
||||
sbLen = 0;
|
||||
|
||||
if (off == 0) {
|
||||
/* Complete normalization, including prefix */
|
||||
src = normalizePrefix(path, len, sb, &sbLen);
|
||||
} else {
|
||||
/* Partial normalization */
|
||||
src = off;
|
||||
memcpy(sb+sbLen, path, off);
|
||||
sbLen += off;
|
||||
}
|
||||
|
||||
/* Remove redundant slashes from the remainder of the path, forcing all
|
||||
slashes into the preferred slash */
|
||||
while (src < len) {
|
||||
char c = path[src++];
|
||||
if (isSlash(c)) {
|
||||
while ((src < len) && isSlash(path[src])) src++;
|
||||
if (src == len) {
|
||||
/* Check for trailing separator */
|
||||
if ((sbLen == 2) && (sb[1] == ':')) {
|
||||
/* "z:\\" */
|
||||
sb[sbLen++] = slash;
|
||||
break;
|
||||
}
|
||||
if (sbLen == 0) {
|
||||
/* "\\" */
|
||||
sb[sbLen++] = slash;
|
||||
break;
|
||||
}
|
||||
if ((sbLen == 1) && (isSlash(sb[0]))) {
|
||||
/* "\\\\" is not collapsed to "\\" because "\\\\" marks
|
||||
the beginning of a UNC pathname. Even though it is
|
||||
not, by itself, a valid UNC pathname, we leave it as
|
||||
is in order to be consistent with the win32 APIs,
|
||||
which treat this case as an invalid UNC pathname
|
||||
rather than as an alias for the root directory of
|
||||
the current drive. */
|
||||
sb[sbLen++] = slash;
|
||||
break;
|
||||
}
|
||||
/* Path does not denote a root directory, so do not append
|
||||
trailing slash */
|
||||
break;
|
||||
} else {
|
||||
sb[sbLen++] = slash;
|
||||
}
|
||||
} else {
|
||||
sb[sbLen++] = c;
|
||||
}
|
||||
}
|
||||
|
||||
sb[sbLen] = '\0';
|
||||
return sb;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that the given pathname is normal. If not, invoke the real
|
||||
* normalizer on the part of the pathname that requires normalization.
|
||||
* This way we iterate through the whole pathname string only once.
|
||||
*/
|
||||
char* normalize(char* path) {
|
||||
int n = (int)strlen(path);
|
||||
int i;
|
||||
char c = 0;
|
||||
int prev = 0;
|
||||
for (i = 0; i < n; i++) {
|
||||
char c = path[i];
|
||||
if (c == altSlash)
|
||||
return normalizePath(path, n, (prev == slash) ? i - 1 : i);
|
||||
if ((c == slash) && (prev == slash) && (i > 1))
|
||||
return normalizePath(path, n, i - 1);
|
||||
if ((c == ':') && (i > 1))
|
||||
return normalizePath(path, n, 0);
|
||||
prev = c;
|
||||
}
|
||||
if (prev == slash)
|
||||
return normalizePath(path, n, n - 1);
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
/* -- Resolution - src/windows/classes/java/io/Win32FileSystem.java */
|
||||
|
||||
|
||||
char* resolve(const char* parent, const char* child) {
|
||||
char* c;
|
||||
char* theChars;
|
||||
int parentEnd, childStart, len;
|
||||
|
||||
int pn = (int)strlen(parent);
|
||||
int cn = (int)strlen(child);
|
||||
|
||||
if (pn == 0) return (char*)child;
|
||||
if (cn == 0) return (char*)parent;
|
||||
|
||||
c = (char*)child;
|
||||
childStart = 0;
|
||||
parentEnd = pn;
|
||||
|
||||
if ((cn > 1) && (c[0] == slash)) {
|
||||
if (c[1] == slash) {
|
||||
/* Drop prefix when child is a UNC pathname */
|
||||
childStart = 2;
|
||||
} else {
|
||||
/* Drop prefix when child is drive-relative */
|
||||
childStart = 1;
|
||||
|
||||
}
|
||||
if (cn == childStart) { // Child is double slash
|
||||
if (parent[pn - 1] == slash) {
|
||||
char* str = strdup(parent);
|
||||
str[pn-1] = '\0';
|
||||
return str;
|
||||
}
|
||||
return (char*)parent;
|
||||
}
|
||||
}
|
||||
|
||||
if (parent[pn - 1] == slash)
|
||||
parentEnd--;
|
||||
|
||||
len = parentEnd + cn - childStart;
|
||||
|
||||
if (child[childStart] == slash) {
|
||||
theChars = (char*)malloc(len+1);
|
||||
memcpy(theChars, parent, parentEnd);
|
||||
memcpy(theChars+parentEnd, child+childStart, (cn-childStart));
|
||||
theChars[len] = '\0';
|
||||
} else {
|
||||
theChars = (char*)malloc(len+2);
|
||||
memcpy(theChars, parent, parentEnd);
|
||||
theChars[parentEnd] = slash;
|
||||
memcpy(theChars+parentEnd+1, child+childStart, (cn-childStart));
|
||||
theChars[len+1] = '\0';
|
||||
}
|
||||
return theChars;
|
||||
}
|
||||
|
||||
|
||||
static int prefixLength(const char* path) {
|
||||
char c0, c1;
|
||||
|
||||
int n = (int)strlen(path);
|
||||
if (n == 0) return 0;
|
||||
c0 = path[0];
|
||||
c1 = (n > 1) ? path[1] : 0;
|
||||
if (c0 == slash) {
|
||||
if (c1 == slash) return 2; /* Absolute UNC pathname "\\\\foo" */
|
||||
return 1; /* Drive-relative "\\foo" */
|
||||
}
|
||||
if (isLetter(c0) && (c1 == ':')) {
|
||||
if ((n > 2) && (path[2] == slash))
|
||||
return 3; /* Absolute local pathname "z:\\foo" */
|
||||
return 2; /* Directory-relative "z:foo" */
|
||||
}
|
||||
return 0; /* Completely relative */
|
||||
}
|
||||
|
||||
|
||||
int isAbsolute(const char* path) {
|
||||
int pl = prefixLength(path);
|
||||
return (((pl == 2) && (path[0] == slash)) || (pl == 3));
|
||||
}
|
||||
|
||||
|
||||
char* fromURIPath(const char* path) {
|
||||
int start = 0;
|
||||
int len = (int)strlen(path);
|
||||
|
||||
if ((len > 2) && (path[2] == ':')) {
|
||||
// "/c:/foo" --> "c:/foo"
|
||||
start = 1;
|
||||
// "c:/foo/" --> "c:/foo", but "c:/" --> "c:/"
|
||||
if ((len > 3) && path[len-1] == '/')
|
||||
len--;
|
||||
} else if ((len > 1) && path[len-1] == '/') {
|
||||
// "/foo/" --> "/foo"
|
||||
len--;
|
||||
}
|
||||
|
||||
if (start == 0 && len == (int)strlen(path)) {
|
||||
return (char*)path;
|
||||
} else {
|
||||
char* p = (char*)malloc(len+1);
|
||||
if (p != NULL) {
|
||||
memcpy(p, path+start, len);
|
||||
p[len] = '\0';
|
||||
}
|
||||
return p;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2004, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include <stddef.h> /* For uintprt_t */
|
||||
#include <stdlib.h>
|
||||
|
||||
#define MAXPATHLEN _MAX_PATH
|
Loading…
Add table
Add a link
Reference in a new issue