8187443: Forest Consolidation: Move files to unified layout

Reviewed-by: darcy, ihse
This commit is contained in:
Erik Joelsson 2017-09-12 19:03:39 +02:00
parent 270fe13182
commit 3789983e89
56923 changed files with 3 additions and 15727 deletions

View file

@ -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;
}
}

View file

@ -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&trade; 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);
}
}

View file

@ -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);
}
}

View file

@ -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&trade; 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&trade; 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&trade; 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);
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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;

View 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;
}

View file

@ -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);
}

View file

@ -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;
}
}

View 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;
}

View file

@ -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);

View file

@ -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);

View file

@ -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);
}
}
}

View file

@ -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);
}
}

File diff suppressed because it is too large Load diff

View 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

View 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);
}
}

View 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

View 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;
}

View 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);

View 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));
}
}

View 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

View file

@ -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;
}

View file

@ -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);

View 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);
}

View 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

View 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);
}

View 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

View file

@ -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);
}

View file

@ -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;
}
}

View file

@ -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 */

View file

@ -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;
}

View file

@ -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;
}
}

View file

@ -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