/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*
* author Tomas Hurka
* Ian Formanek
* Misha Dmitriev
*/
#ifdef WIN32
#include <Windows.h>
#else
#include <sys/time.h>
#include <fcntl.h>
#include <time.h>
#endif
#ifdef SOLARIS
#define _STRUCTURED_PROC 1
#include <sys/procfs.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "jni.h"
#include "jvmti.h"
#include "org_netbeans_lib_profiler_server_system_Classes.h"
#include "common_functions.h"
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
/*
* Class: org_netbeans_lib_profiler_server_system_Classes
* Method: getAllLoadedClasses
* Signature: ()[Ljava/lang/Class;
*/
JNIEXPORT jobjectArray JNICALL Java_org_netbeans_lib_profiler_server_system_Classes
_getAllLoadedClasses
(JNIEnv *env, jclass clz)
{
jvmtiError res;
jint classCount, classStatus;
jclass *classes;
jobjectArray ret;
jclass type;
int i, j, n_linked_classes;
char *class_status;
res = (*_jvmti)->GetLoadedClasses(_jvmti, &classCount, &classes);
assert(res == JVMTI_ERROR_NONE);
n_linked_classes = 0;
class_status = malloc(classCount);
for (i = 0; i < classCount; i++) {
(*_jvmti)->GetClassStatus(_jvmti, classes[i], &classStatus);
if ((classStatus & JVMTI_CLASS_STATUS_PREPARED) != 0 && (classStatus & JVMTI_CLASS_STATUS_ERROR) == 0) {
class_status[i] = 1;
n_linked_classes++;
} else {
class_status[i] = 0;
}
}
type = (*env)->FindClass(env, "java/lang/Class" );
assert(type != NULL);
ret = (*env)->NewObjectArray(env, n_linked_classes, type, NULL);
if (ret != NULL) {
j = 0;
for (i = 0; i < classCount; i++) {
if (class_status[i]) {
(*env)->SetObjectArrayElement(env, ret, j++, classes[i]);
}
}
}
free(class_status);
res = (*_jvmti)->Deallocate(_jvmti, (unsigned char *) classes);
assert(res == JVMTI_ERROR_NONE);
return ret;
}
/*
* Class: org_netbeans_lib_profiler_server_system_Classes
* Method: cacheLoadedClasses
* Signature: ([Ljava/lang/Class;I)V
*/
JNIEXPORT void JNICALL Java_org_netbeans_lib_profiler_server_system_Classes_cacheLoadedClasses
(JNIEnv *env, jclass clz, jobjectArray non_system_classes, jint class_count)
{
jclass *classDefs = calloc(class_count,sizeof (jclass));
int i;
for (i = 0; i < class_count; i++) {
classDefs[i] = (*env)->GetObjectArrayElement(env, non_system_classes, i);
}
cache_loaded_classes(_jvmti,classDefs,class_count);
free(classDefs);
}
/*
* Class: org_netbeans_lib_profiler_server_system_Classes
* Method: getCachedClassFileBytes
* Signature: (Ljava/lang/Class;)[B
*/
JNIEXPORT jbyteArray JNICALL Java_org_netbeans_lib_profiler_server_system_Classes_getCachedClassFileBytes
(JNIEnv *env, jclass clz, jclass clazz)
{
char *class_sig, *class_gen_sig;
jobject loader;
unsigned char *class_data;
int class_data_len;
jbyteArray ret;
jvmtiError res;
res = (*_jvmti)->GetClassSignature(_jvmti, clazz, &class_sig, &class_gen_sig);
assert(res == JVMTI_ERROR_NONE);
res = (*_jvmti)->GetClassLoader(_jvmti, clazz, &loader);
assert(res == JVMTI_ERROR_NONE);
/* class_sig is gonna look something like Lfoo/Bar; Convert it back into normal */
class_sig[strlen(class_sig) - 1] = 0;
get_saved_class_file_bytes(env, class_sig+1, loader, (jint*)&class_data_len, &class_data);
(*_jvmti)->Deallocate(_jvmti, (void *) class_sig);
(*_jvmti)->Deallocate(_jvmti, (void *) class_gen_sig);
if (class_data == NULL) {
return NULL;
}
ret = (*env)->NewByteArray(env, class_data_len);
(*env)->SetByteArrayRegion(env, ret, 0, class_data_len, (jbyte*) class_data);
free(class_data);
return ret;
}
static jclass profilerInterfaceClazz;
static jmethodID classLoadHookMethod = NULL;
void JNICALL register_class_prepare(jvmtiEnv *jvmti_env, JNIEnv* env, jthread thread, jclass clazz) {
(*env)->CallStaticVoidMethod(env, profilerInterfaceClazz, classLoadHookMethod, clazz);
if ((*env)->ExceptionCheck(env)) {
(*env)->ExceptionDescribe(env);
}
}
/*
* Class: org_netbeans_lib_profiler_server_system_Classes
* Method: enableClassLoadHook
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_org_netbeans_lib_profiler_server_system_Classes_enableClassLoadHook
(JNIEnv *env, jclass clz)
{
jvmtiError res;
if (classLoadHookMethod == NULL) {
profilerInterfaceClazz = (*env)->FindClass(env, "org/netbeans/lib/profiler/server/ProfilerInterface" );
profilerInterfaceClazz = (*env)->NewGlobalRef(env, profilerInterfaceClazz);
classLoadHookMethod = (*env)->GetStaticMethodID(env, profilerInterfaceClazz, "classLoadHook" , "(Ljava/lang/Class;)V" );
_jvmti_callbacks->ClassPrepare = register_class_prepare;
res = (*_jvmti)->SetEventCallbacks(_jvmti, _jvmti_callbacks, sizeof (*_jvmti_callbacks));
assert (res == JVMTI_ERROR_NONE);
}
res = (*_jvmti)->SetEventNotificationMode(_jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_PREPARE, NULL);
assert(res == JVMTI_ERROR_NONE);
}
/*
* Class: org_netbeans_lib_profiler_server_system_Classes
* Method: disableClassLoadHook
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_org_netbeans_lib_profiler_server_system_Classes_disableClassLoadHook
(JNIEnv *env, jclass clz)
{
jvmtiError res;
res = (*_jvmti)->SetEventNotificationMode(_jvmti, JVMTI_DISABLE, JVMTI_EVENT_CLASS_PREPARE, NULL);
assert(res == JVMTI_ERROR_NONE);
}
/*
* Class: org_netbeans_lib_profiler_server_system_Classes
* Method: getObjectSize
* Signature: (Ljava/lang/Object;)J
*/
JNIEXPORT jlong JNICALL Java_org_netbeans_lib_profiler_server_system_Classes_getObjectSize
(JNIEnv *env, jclass clz, jobject jobject)
{
jlong res;
(*_jvmti)->GetObjectSize(_jvmti, jobject, &res);
return res;
}
/*
* Class: org_netbeans_lib_profiler_server_system_Classes
* Method: doRedefineClasses
* Signature: ([Ljava/lang/Class;[[B)I
*/
JNIEXPORT jint JNICALL Java_org_netbeans_lib_profiler_server_system_Classes_doRedefineClasses
(JNIEnv *env, jclass clz, jobjectArray jclasses, jobjectArray jnewClassFileBytes)
{
static jboolean nativeMethodBindDisabled = FALSE ;
jvmtiError res = JVMTI_ERROR_NONE;
jint nClasses, i;
jvmtiClassDefinition* classDefs;
if (!nativeMethodBindDisabled) {
// First, disable the NativeMethodBind event, assume that Thread.sleep and Object.wait have already been intercepted
res = (*_jvmti)->SetEventNotificationMode(_jvmti, JVMTI_DISABLE, JVMTI_EVENT_NATIVE_METHOD_BIND, NULL);
if (res != JVMTI_ERROR_NONE) {
fprintf (stderr, "Profiler Agent Error: Error while turning NativeMethodBind off: %d\n" ,res);
assert(res == JVMTI_ERROR_NONE);
}
nativeMethodBindDisabled = TRUE ;
}
nClasses = (*env)->GetArrayLength(env, jclasses);
classDefs = malloc(sizeof (jvmtiClassDefinition) * nClasses);
for (i = 0; i < nClasses; i++) {
jbyteArray jnewClassBytes;
jbyte *tmpClassBytes;
jint classBytesLen;
jvmtiClassDefinition *classDef = classDefs + i;
classDef->klass = (*env)->GetObjectArrayElement(env, jclasses, i);
jnewClassBytes = (*env)->GetObjectArrayElement(env, jnewClassFileBytes, i);
classBytesLen = classDef->class_byte_count = (*env)->GetArrayLength(env, jnewClassBytes);
assert(classBytesLen > 0);
tmpClassBytes = (*env)->GetByteArrayElements(env, jnewClassBytes, NULL);
classDef->class_bytes = malloc(classBytesLen);
memcpy((jbyte*) classDef->class_bytes, tmpClassBytes, classBytesLen);
(*env)->ReleaseByteArrayElements(env, jnewClassBytes, tmpClassBytes, JNI_ABORT);
(*env)->DeleteLocalRef(env, jnewClassBytes);
}
if (nClasses <= 100) {
res = (*_jvmti)->RedefineClasses(_jvmti, nClasses, classDefs);
} else {
// perform batch redefine in units of 100 classes
int idx = 0;
while (idx < nClasses) {
int redefineCount = nClasses - idx;
if (redefineCount > 100) {
redefineCount = 100;
}
fprintf (stdout, "Profiler Agent: Redefining %d classes at idx %d, out of total %d \n" ,redefineCount, idx, (int )nClasses);
res = (*_jvmti)->RedefineClasses(_jvmti, redefineCount, classDefs + idx);
idx += 100;
}
}
for (i = 0; i < nClasses; i++) {
(*env)->DeleteLocalRef(env, classDefs[i].klass);
free((jbyte*) classDefs[i].class_bytes);
}
free(classDefs);
return res;
}
/*
* Class: org_netbeans_lib_profiler_server_system_Classes
* Method: notifyAboutClassLoaderUnloading
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_org_netbeans_lib_profiler_server_system_Classes_notifyAboutClassLoaderUnloading
(JNIEnv *env, jclass clz)
{
try_removing_bytes_for_unloaded_classes(env);
}
Messung V0.5 C=96 H=96 G=95
¤ Dauer der Verarbeitung: 0.4 Sekunden
¤
*© Formatika GbR, Deutschland