You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by py...@apache.org on 2006/08/24 11:34:53 UTC

svn commit: r434359 - in /incubator/harmony/enhanced/classlib/trunk/modules/instrument/src/main/native/instrument: linux/libhyinstrument.exp linux/makefile shared/inst_agt.c windows/hyinstrument.def windows/makefile

Author: pyang
Date: Thu Aug 24 02:34:53 2006
New Revision: 434359

URL: http://svn.apache.org/viewvc?rev=434359&view=rev
Log:
patch applied for HARMONY-1227 ( [classlib][instrument]implementation of instrument agent initialization for launcher)

Added:
    incubator/harmony/enhanced/classlib/trunk/modules/instrument/src/main/native/instrument/shared/inst_agt.c
Modified:
    incubator/harmony/enhanced/classlib/trunk/modules/instrument/src/main/native/instrument/linux/libhyinstrument.exp
    incubator/harmony/enhanced/classlib/trunk/modules/instrument/src/main/native/instrument/linux/makefile
    incubator/harmony/enhanced/classlib/trunk/modules/instrument/src/main/native/instrument/windows/hyinstrument.def
    incubator/harmony/enhanced/classlib/trunk/modules/instrument/src/main/native/instrument/windows/makefile

Modified: incubator/harmony/enhanced/classlib/trunk/modules/instrument/src/main/native/instrument/linux/libhyinstrument.exp
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/instrument/src/main/native/instrument/linux/libhyinstrument.exp?rev=434359&r1=434358&r2=434359&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/instrument/src/main/native/instrument/linux/libhyinstrument.exp (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/instrument/src/main/native/instrument/linux/libhyinstrument.exp Thu Aug 24 02:34:53 2006
@@ -4,5 +4,7 @@
 	Java_org_apache_harmony_instrument_internal_InstrumentationImpl_getInitiatedClasses;
 	Java_org_apache_harmony_instrument_internal_InstrumentationImpl_getObjectSize_1native;
 	Java_org_apache_harmony_instrument_internal_InstrumentationImpl_redefineClasses_1native;
+	Agent_OnUnload;
+	Agent_OnLoad;
 	local : *;
 };

Modified: incubator/harmony/enhanced/classlib/trunk/modules/instrument/src/main/native/instrument/linux/makefile
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/instrument/src/main/native/instrument/linux/makefile?rev=434359&r1=434358&r2=434359&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/instrument/src/main/native/instrument/linux/makefile (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/instrument/src/main/native/instrument/linux/makefile Thu Aug 24 02:34:53 2006
@@ -21,7 +21,7 @@
 CFLAGS += -fpic
 
 BUILDFILES = \
-	../shared/instrument.o 
+	../shared/instrument.o ../shared/inst_agt.o 
 
 MDLLIBFILES = \
 	$(LIBPATH)libhycommon.a $(LIBPATH)libhyzip.a \

Added: incubator/harmony/enhanced/classlib/trunk/modules/instrument/src/main/native/instrument/shared/inst_agt.c
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/instrument/src/main/native/instrument/shared/inst_agt.c?rev=434359&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/instrument/src/main/native/instrument/shared/inst_agt.c (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/instrument/src/main/native/instrument/shared/inst_agt.c Thu Aug 24 02:34:53 2006
@@ -0,0 +1,372 @@
+/* Copyright 2006 The Apache Software Foundation or its licensors, as applicable
+ * 
+ * Licensed 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.
+ */
+
+#define USING_VMI
+
+#include "instrument.h"
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <zipsup.h>
+#include <jni.h>
+#include <vmi.h>
+
+/*
+ * This file implements a JVMTI agent to init Instrument instance, and handle class define/redefine events
+ */
+
+AgentList *tail = &list;
+int gsupport_redefine = 0;
+static JNIEnv *jnienv;
+
+//call back function for ClassLoad event
+void JNICALL callbackClassFileLoadHook(jvmtiEnv *jvmti_env,
+	JNIEnv* jni_env,
+	jclass class_being_redefined,
+	jobject loader,
+	const char* name,
+	jobject protection_domain,
+	jint class_data_len,
+	const unsigned char* class_data,
+	jint* new_class_data_len,
+	unsigned char** new_class_data){
+
+	jclass inst_class = *(gdata->inst_class);
+	jbyteArray jnew_bytes = NULL;
+	jbyteArray jold_bytes = (*jni_env)->NewByteArray(jni_env, class_data_len);
+	jmethodID transform_method = *(gdata->transform_method);
+	int name_len = strlen(name);
+	jbyteArray jname_bytes = (*jni_env)->NewByteArray(jni_env, name_len);
+	
+	//construct java byteArray for old class data and class name
+	(*jni_env)->SetByteArrayRegion(jni_env, jold_bytes, 0, class_data_len, (unsigned char *)class_data);
+	(*jni_env)->SetByteArrayRegion(jni_env, jname_bytes, 0, name_len, (char *)name);
+	
+	//invoke transform method
+	jnew_bytes = (jbyteArray)(*jni_env)->CallObjectMethod(jni_env, *(gdata->inst), transform_method, loader, jname_bytes, class_being_redefined, protection_domain, jold_bytes);	
+
+	//get transform result to native char array
+	if(0 != jnew_bytes){
+		*new_class_data_len = (*jni_env)->GetArrayLength(jni_env, jnew_bytes);
+		(*jvmti_env)->Allocate(jvmti_env, *new_class_data_len, new_class_data);		
+		*new_class_data = (*jni_env)->GetPrimitiveArrayCritical(jni_env, jnew_bytes, JNI_FALSE);
+		(*jni_env)->ReleasePrimitiveArrayCritical(jni_env, jnew_bytes, *new_class_data, 0);
+	}
+	return;
+}
+
+//call back function for VM init event
+void JNICALL callbackVMInit(jvmtiEnv *jvmti, JNIEnv *env, jthread thread){
+	jmethodID constructor;
+	static jmethodID transform_method;
+	static jmethodID premain_method;
+	static jobject inst_obj;
+	static jclass inst_class;
+	jvmtiError err;
+	AgentList *elem;
+	
+	PORT_ACCESS_FROM_ENV (env);	
+	inst_class = (*env)->FindClass(env, "org/apache/harmony/instrument/internal/InstrumentationImpl");
+	if(NULL == inst_class){		
+		(*env)->FatalError(env,"class cannot find: org/apache/harmony/instrument/internal/InstrumentationImpl");
+		return;	
+	}
+	inst_class = (jclass)(*env)->NewGlobalRef(env, inst_class);
+	gdata->inst_class = &inst_class;
+
+	constructor = (*env)->GetMethodID(env, inst_class,"<init>", "(Z)V");
+	if(NULL == constructor){
+		(*env)->FatalError(env,"constructor cannot be found.");				
+		return;
+	}
+	
+	inst_obj = (*env)->NewObject(env, inst_class, constructor, gsupport_redefine?JNI_TRUE:JNI_FALSE);
+	if(NULL == inst_obj){
+		(*env)->FatalError(env,"object cannot be inited.");				
+		return;		
+	}
+	
+	inst_obj = (*env)->NewGlobalRef(env, inst_obj);
+	gdata->inst = &inst_obj;
+
+	transform_method = (*env)->GetMethodID(env, inst_class, "transform", "(Ljava/lang/ClassLoader;[BLjava/lang/Class;Ljava/security/ProtectionDomain;[B)[B");
+	if(NULL == transform_method){
+		(*env)->FatalError(env,"transform method cannot find.");
+		return;
+	}
+	gdata->transform_method = &transform_method;
+
+	premain_method = (*env)->GetMethodID(env, inst_class, "executePremain", "([B[B)V");
+	if(NULL == premain_method){
+		(*env)->FatalError(env,"executePremain method cannot find.");
+		return;
+	}
+	gdata->premain_method = &premain_method;		
+	err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL);	
+	check_jvmti_error(env, err, "Cannot set JVMTI ClassFileLoadHook event notification mode.");
+	
+	//parse command options and run premain class here	
+	if(tail == &list){
+		return;
+	}
+	for(elem = list.next; elem != NULL; elem = list.next){
+		char *agent_options = elem->option;	
+		char *class_name = elem->class_name;
+		jbyteArray joptions=NULL, jclass_name;
+		if(class_name){
+			jclass_name = (*env)->NewByteArray(env, strlen(class_name));
+			(*env)->SetByteArrayRegion(env, jclass_name, 0, strlen(class_name), class_name);
+		}else{
+			goto DEALLOCATE;
+		}
+		if(agent_options){
+			joptions = (*env)->NewByteArray(env, strlen(agent_options));
+			(*env)->SetByteArrayRegion(env, joptions, 0, strlen(agent_options), agent_options);
+		}
+		
+		(*env)->CallObjectMethod(env, *(gdata->inst), *(gdata->premain_method), jclass_name, joptions);
+DEALLOCATE:
+		list.next = elem->next;
+		hymem_free_memory(elem->class_name);
+		hymem_free_memory(elem->option);
+		hymem_free_memory(elem);
+	}	
+	tail = &list;	
+}
+
+char* Read_Manifest(JavaVM *vm, JNIEnv *env,const char *jar_name){
+	I_32 retval;
+	HyZipFile zipFile;
+	HyZipEntry zipEntry;
+	char *result;
+	int size = 0;
+	char errorMessage[1024];
+
+	/* Reach for the VM interface */	
+	VMI_ACCESS_FROM_JAVAVM(vm);
+	PORT_ACCESS_FROM_JAVAVM(vm);
+
+	/* open zip file */
+	retval = zip_openZipFile(privatePortLibrary, (char *)jar_name, &zipFile, NULL);
+	if(retval){
+		sprintf(errorMessage,"failed to open file:%s, %d\n", jar_name, retval);
+		(*env)->FatalError(env, errorMessage);
+		return NULL;
+	}
+
+	/* get manifest entry */
+	zip_initZipEntry(privatePortLibrary, &zipEntry);
+	retval = zip_getZipEntry(privatePortLibrary, &zipFile, &zipEntry, "META-INF/MANIFEST.MF", TRUE);
+	if (retval) {
+		zip_freeZipEntry(PORTLIB, &zipEntry);
+		sprintf(errorMessage,"failed to get entry: %d\n", retval);
+		(*env)->FatalError(env, errorMessage);
+		return NULL;
+	}
+	
+	/* read bytes */
+	size = zipEntry.uncompressedSize;
+	result = (char *)hymem_allocate_memory(size*sizeof(char));
+	retval = zip_getZipEntryData(privatePortLibrary, &zipFile, &zipEntry, result, size);
+	if(retval){
+		zip_freeZipEntry(PORTLIB, &zipEntry);
+		sprintf(errorMessage,"failed to get bytes from zip entry, %d\n", zipEntry.extraFieldLength);
+		(*env)->FatalError(env, errorMessage);
+		return NULL;
+	}
+
+	/* free resource */
+	zip_freeZipEntry(privatePortLibrary, &zipEntry);
+	retval = zip_closeZipFile(privatePortLibrary, &zipFile);
+	if (retval) {
+		sprintf(errorMessage,"failed to close zip file: %s, %d\n", jar_name, retval);
+		(*env)->FatalError(env, errorMessage);
+		return NULL;
+	}
+	return result;
+}
+
+char* read_attribute(JavaVM *vm, char *manifest,char *lwrmanifest, const char * target){
+	char *pos = manifest+ (strstr(lwrmanifest,target) - lwrmanifest);
+	char *end;
+	char *value;
+	int length;
+
+	PORT_ACCESS_FROM_JAVAVM(vm);
+	
+	if(NULL == pos){
+		return NULL;
+	}
+	pos += strlen(target)+2;//": "
+	end = strchr(pos, '\r');
+	if(NULL == end){
+		end = manifest + strlen(manifest);
+	}
+	length = end - pos;
+	
+	value = (char *)hymem_allocate_memory(sizeof(char)*(length+1));
+	strncpy(value, pos, length);
+	*(value+length) = '\0';
+	return value;
+}
+
+int str2bol(char *str){	
+	return 0 == strcmp("true", strlwr(str));
+}
+
+jint Parse_Options(JavaVM *vm, JNIEnv *env, jvmtiEnv *jvmti,  const char *agent){
+	PORT_ACCESS_FROM_JAVAVM(vm);
+	VMI_ACCESS_FROM_JAVAVM(vm);
+	
+	AgentList *new_elem = (AgentList *)hymem_allocate_memory(sizeof(AgentList));
+	char *agent_cpy = (char *)hymem_allocate_memory(sizeof(char)*(strlen(agent)+1));
+	char *jar_name, *manifest;
+	char *options = NULL;
+	char *class_name, *bootclasspath, *str_support_redefine;	
+	char *bootclasspath_item;
+	char *classpath;
+	char *classpath_cpy;
+	int support_redefine = 0;
+	char *pos;
+	char *lwrmanifest;
+	
+	strcpy(agent_cpy, agent);
+	//parse jar name and options
+	pos = strchr(agent_cpy, '=');
+	if(pos>0){
+		*pos++ = 0;
+		options = (char *)hymem_allocate_memory(sizeof(char) * (strlen(pos)+1));
+		strcpy(options, pos);
+		hymem_free_memory(pos);
+	}
+	jar_name =agent_cpy;
+
+	//read jar files, find manifest entry and read bytes
+	//read attributes(premain class, support redefine, bootclasspath)
+	manifest = Read_Manifest(vm,env, jar_name);	
+	lwrmanifest = (char *)hymem_allocate_memory(sizeof(char) * (strlen(manifest)+1));
+	strcpy(lwrmanifest,manifest);
+	strlwr(lwrmanifest);
+	
+	//jar itself added to bootclasspath
+	check_jvmti_error(env, (*jvmti)->GetSystemProperty(jvmti,"java.class.path",&classpath),"Failed to get classpath.");
+	classpath_cpy = (char *)hymem_allocate_memory((sizeof(char)*(strlen(classpath)+strlen(jar_name)+2)));
+	strcpy(classpath_cpy,classpath);
+	strcat(classpath_cpy,";");
+	strcat(classpath_cpy,jar_name);
+	check_jvmti_error(env, (*jvmti)->SetSystemProperty(jvmti, "java.class.path",classpath_cpy),"Failed to set classpath.");
+	hymem_free_memory(classpath_cpy);
+	hymem_free_memory(jar_name);	
+
+	//save options, save class name, add to agent list
+	class_name = read_attribute(vm, manifest, lwrmanifest,"premain-class");
+	if(NULL == class_name){
+		hymem_free_memory(lwrmanifest);
+		hymem_free_memory(manifest);
+		(*env)->FatalError(env,"Cannot find Premain-Class attribute.");
+	}
+	new_elem->option = options;
+	new_elem->class_name = class_name;
+	new_elem->next = NULL;
+	tail->next = new_elem;
+	tail = new_elem;
+
+	//calculate support redefine
+	str_support_redefine = read_attribute(vm, manifest, lwrmanifest,"can-redefine-classes");
+	if(NULL != str_support_redefine){
+		support_redefine = str2bol(str_support_redefine);	
+		gsupport_redefine |= support_redefine;
+		hymem_free_memory(str_support_redefine);
+	}
+	
+	//add bootclasspath
+	
+	bootclasspath = read_attribute(vm, manifest, lwrmanifest,"boot-class-path");
+	if(NULL != bootclasspath){
+		bootclasspath_item = strtok(bootclasspath, " ");
+		while(NULL != bootclasspath_item){			
+			check_jvmti_error(env, (*jvmti)->AddToBootstrapClassLoaderSearch(jvmti, bootclasspath_item),"Failed to add bootstrap classpath.");			
+			bootclasspath_item = strtok(NULL, " ");
+		}
+		hymem_free_memory(bootclasspath);
+	}	
+	hymem_free_memory(lwrmanifest);
+	hymem_free_memory(manifest);
+	return 0;
+}
+
+JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved){	
+	PORT_ACCESS_FROM_JAVAVM(vm);
+	VMI_ACCESS_FROM_JAVAVM(vm);
+	jint err = (*vm)->GetEnv(vm, (void **)&jnienv, JNI_VERSION_1_2);
+	if(JNI_OK != err){
+		return err;
+	}
+	
+	if(!gdata){		
+		jvmtiCapabilities capabilities;		
+		jvmtiError err;
+		jvmtiEventCallbacks callbacks;
+		JNIEnv *env = NULL;
+		static jvmtiEnv *jvmti;
+
+		gdata = hymem_allocate_memory(sizeof(AgentData));
+		
+		//get jvmti environment
+		err = (*vm)->GetEnv(vm, (void **)&jvmti, JVMTI_VERSION_1_0);
+		if(JNI_OK != err){
+			return err;
+		}		
+		gdata->jvmti = jvmti;
+		
+		//set prerequisite capabilities for classfileloadhook, redefine, and VMInit event
+		memset(&capabilities, 0, sizeof(capabilities));
+		capabilities.can_generate_all_class_hook_events=1;
+		capabilities.can_redefine_classes = 1;
+		//FIXME VM doesnot support the capbility right now.
+		//capabilities.can_redefine_any_class = 1;
+		err = (*jvmti)->AddCapabilities(jvmti, &capabilities);
+		check_jvmti_error(env, err, "Cannot add JVMTI capabilities.");
+
+		//set events callback function
+		(void)memset(&callbacks, 0, sizeof(callbacks));
+		callbacks.ClassFileLoadHook = &callbackClassFileLoadHook;
+		callbacks.VMInit = &callbackVMInit;
+		err = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(jvmtiEventCallbacks));
+		check_jvmti_error(env, err, "Cannot set JVMTI event callback functions.");
+
+		//enable classfileloadhook event
+		err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL);
+		check_jvmti_error(env, err, "Cannot set JVMTI VMInit event notification mode.");
+	}		
+	
+	return Parse_Options(vm,jnienv, gdata->jvmti,options);	
+}
+
+JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm){	
+	PORT_ACCESS_FROM_JAVAVM(vm);
+	VMI_ACCESS_FROM_JAVAVM(vm);
+	//free the resource here	
+	if(gdata){
+		jvmtiEnv *jvmti = gdata->jvmti;
+		jvmtiError err = (*jvmti)->DisposeEnvironment(jvmti);
+		if(err != JVMTI_ERROR_NONE)	{
+		   (*jnienv)->FatalError(jnienv,"Cannot dispose JVMTI environment.");		   
+		}		
+		hymem_free_memory(gdata);
+		gdata = NULL;
+	}
+	return;
+}

Modified: incubator/harmony/enhanced/classlib/trunk/modules/instrument/src/main/native/instrument/windows/hyinstrument.def
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/instrument/src/main/native/instrument/windows/hyinstrument.def?rev=434359&r1=434358&r2=434359&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/instrument/src/main/native/instrument/windows/hyinstrument.def (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/instrument/src/main/native/instrument/windows/hyinstrument.def Thu Aug 24 02:34:53 2006
@@ -9,5 +9,7 @@
 	Java_org_apache_harmony_instrument_internal_InstrumentationImpl_getInitiatedClasses
 	Java_org_apache_harmony_instrument_internal_InstrumentationImpl_getObjectSize_1native
 	Java_org_apache_harmony_instrument_internal_InstrumentationImpl_redefineClasses_1native
+	Agent_OnUnload
+	Agent_OnLoad
 	
 

Modified: incubator/harmony/enhanced/classlib/trunk/modules/instrument/src/main/native/instrument/windows/makefile
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/instrument/src/main/native/instrument/windows/makefile?rev=434359&r1=434358&r2=434359&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/instrument/src/main/native/instrument/windows/makefile (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/instrument/src/main/native/instrument/windows/makefile Thu Aug 24 02:34:53 2006
@@ -25,7 +25,7 @@
 HYLDFLAGS = $(HYLDFLAGS) -def:$(LIBBASE).def
 
 BUILDFILES = \
-  $(SHAREDSUB)instrument.obj 
+  $(SHAREDSUB)instrument.obj $(SHAREDSUB)inst_agt.obj 
   
 VIRTFILES = hyinstrument.res