/* src/native/jvmti/jvmti.c - implementation of the Java Virtual Machine Tool Interface functions Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, Institut f. Computersprachen - TU Wien This file is part of CACAO. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program 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 for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Contact: cacao@cacaojvm.org Author: Martin Platter Changes: Edwin Steiner Samuel Vinson $Id: jvmti.c 4946 2006-05-24 11:00:38Z motse $ */ #include #include "native/jni.h" #include "native/native.h" #include "native/jvmti/cacaodbg.h" #include "native/jvmti/jvmti.h" #include "vm/global.h" #include "vm/loader.h" #include "vm/builtin.h" #include "vm/jit/asmpart.h" #include "vm/class.h" #include "vm/classcache.h" #include "mm/boehm.h" #include "toolbox/logging.h" #include "vm/options.h" #include "vm/stringlocal.h" #include "mm/memory.h" #include "threads/native/threads.h" #include "threads/native/lock.h" #include "vm/exceptions.h" #include "native/include/java_util_Vector.h" #include "native/include/java_io_PrintStream.h" #include "native/include/java_io_InputStream.h" #include "native/include/java_lang_Cloneable.h" #include "native/include/java_lang_ThreadGroup.h" #include "native/include/java_lang_VMObject.h" #include "native/include/java_lang_VMSystem.h" #include "native/include/java_lang_VMClass.h" #include "vm/suck.h" #include "boehm-gc/include/gc.h" #include #include #include #include "toolbox/logging.h" #include #include #include #include #include #if defined(ENABLE_THREADS) #include "threads/native/threads.h" #include #include #endif #include "dbg.h" typedef struct _environment environment; static environment *envs=NULL; pthread_mutex_t dbgcomlock; extern const struct JNIInvokeInterface _Jv_JNIInvokeInterface; static jvmtiPhase phase; typedef struct _jvmtiEventModeLL jvmtiEventModeLL; struct _jvmtiEventModeLL { jvmtiEventMode mode; jthread event_thread; jvmtiEventModeLL *next; }; typedef struct _jvmtiThreadLocalStorage jvmtiThreadLocalStorage; struct _jvmtiThreadLocalStorage{ jthread thread; void *data; jvmtiThreadLocalStorage *next; }; struct _environment { jvmtiEnv env; environment *next; jvmtiEventCallbacks callbacks; /* table for enabled/disabled jvmtiEvents - first element contains global behavior */ jvmtiEventModeLL events[JVMTI_EVENT_END_ENUM - JVMTI_EVENT_START_ENUM]; jvmtiCapabilities capabilities; void *EnvironmentLocalStorage; jvmtiThreadLocalStorage *tls; }; static struct jvmtiEnv_struct JVMTI_EnvTable; static jvmtiCapabilities JVMTI_Capabilities; static lt_ptr unload; #define CHECK_PHASE_START if (!(false #define CHECK_PHASE(chkphase) || (phase == chkphase) #define CHECK_PHASE_END )) return JVMTI_ERROR_WRONG_PHASE #define CHECK_CAPABILITY(env,CAP) if(((environment*)env)->capabilities.CAP == 0) \ return JVMTI_ERROR_MUST_POSSESS_CAPABILITY; #define CHECK_THREAD_IS_ALIVE(t) if(check_thread_is_alive(t)== \ JVMTI_ERROR_THREAD_NOT_ALIVE) \ return JVMTI_ERROR_THREAD_NOT_ALIVE; /* check_thread_is_alive ******************************************************* checks if the given thread is alive *******************************************************************************/ static jvmtiError check_thread_is_alive(jthread t) { if(t==NULL) return JVMTI_ERROR_THREAD_NOT_ALIVE; if(((java_lang_Thread*) t)->vmThread==NULL) return JVMTI_ERROR_THREAD_NOT_ALIVE; return JVMTI_ERROR_NONE; } /* execcallback *************************************************************** executes the registerd callbacks for the given jvmti event with parameter in the data structure. *******************************************************************************/ static void execute_callback(jvmtiEvent e, functionptr ec, genericEventData* data) { JNIEnv* jni_env = (JNIEnv*)_Jv_env; fprintf(stderr,"execcallback called (event: %d)\n",e); switch (e) { case JVMTI_EVENT_VM_INIT: if (phase != JVMTI_PHASE_LIVE) return; case JVMTI_EVENT_THREAD_START: case JVMTI_EVENT_THREAD_END: if ((phase == JVMTI_PHASE_START) || (phase == JVMTI_PHASE_LIVE)) ((jvmtiEventThreadStart)ec)(data->jvmti_env,jni_env,data->thread); break; case JVMTI_EVENT_CLASS_FILE_LOAD_HOOK: if ((phase == JVMTI_PHASE_START) || (phase == JVMTI_PHASE_LIVE) || (phase == JVMTI_PHASE_PRIMORDIAL)) ((jvmtiEventClassFileLoadHook)ec) (data->jvmti_env, jni_env, data->klass, data->object, data->name, data->protection_domain, data->jint1, data->class_data, data->new_class_data_len, data->new_class_data); break; case JVMTI_EVENT_CLASS_PREPARE: case JVMTI_EVENT_CLASS_LOAD: if ((phase == JVMTI_PHASE_START) || (phase == JVMTI_PHASE_LIVE)) ((jvmtiEventClassLoad)ec) (data->jvmti_env, jni_env, data->thread, data->klass); break; case JVMTI_EVENT_VM_DEATH: if (phase != JVMTI_PHASE_LIVE) return; case JVMTI_EVENT_VM_START: if ((phase == JVMTI_PHASE_START) || (phase == JVMTI_PHASE_LIVE)) ((jvmtiEventVMStart)ec) (data->jvmti_env, jni_env); break; case JVMTI_EVENT_NATIVE_METHOD_BIND: if ((phase == JVMTI_PHASE_START) || (phase == JVMTI_PHASE_LIVE) || (phase == JVMTI_PHASE_PRIMORDIAL)) ((jvmtiEventNativeMethodBind)ec) (data->jvmti_env, jni_env, data->thread, data->method, data->address, data->new_address_ptr); break; case JVMTI_EVENT_DYNAMIC_CODE_GENERATED: if ((phase == JVMTI_PHASE_START) || (phase == JVMTI_PHASE_LIVE) || (phase == JVMTI_PHASE_PRIMORDIAL)) ((jvmtiEventDynamicCodeGenerated)ec) (data->jvmti_env, data->name, data->address, data->jint1); break; default: if (phase != JVMTI_PHASE_LIVE) return; switch (e) { case JVMTI_EVENT_EXCEPTION: ((jvmtiEventException)ec) (data->jvmti_env, jni_env, data->thread, data->method, data->location, data->object, data->catch_method, data->catch_location); break; case JVMTI_EVENT_EXCEPTION_CATCH: ((jvmtiEventExceptionCatch)ec) (data->jvmti_env, jni_env, data->thread, data->method, data->location, data->object); break; case JVMTI_EVENT_BREAKPOINT: case JVMTI_EVENT_SINGLE_STEP: ((jvmtiEventSingleStep)ec) (data->jvmti_env, jni_env, data->thread, data->method, data->location); break; case JVMTI_EVENT_FRAME_POP: ((jvmtiEventFramePop)ec) (data->jvmti_env, jni_env, data->thread, data->method, data->b); break; case JVMTI_EVENT_FIELD_ACCESS: ((jvmtiEventFieldAccess)ec) (data->jvmti_env, jni_env, data->thread, data->method, data->location, data->klass, data->object, data->field); break; case JVMTI_EVENT_FIELD_MODIFICATION: ((jvmtiEventFieldModification)ec) (data->jvmti_env, jni_env, data->thread, data->method, data->location, data->klass, data->object, data->field, data->signature_type, data->value); break; case JVMTI_EVENT_METHOD_ENTRY: ((jvmtiEventMethodEntry)ec) (data->jvmti_env, jni_env, data->thread, data->method); break; case JVMTI_EVENT_METHOD_EXIT: ((jvmtiEventMethodExit)ec) (data->jvmti_env, jni_env, data->thread, data->method, data->b, data->value); break; case JVMTI_EVENT_COMPILED_METHOD_LOAD: ((jvmtiEventCompiledMethodLoad)ec) (data->jvmti_env, data->method, data->jint1, data->address, data->jint2, data->map, data->compile_info); break; case JVMTI_EVENT_COMPILED_METHOD_UNLOAD: ((jvmtiEventCompiledMethodUnload)ec) (data->jvmti_env, data->method, data->address); break; case JVMTI_EVENT_GARBAGE_COLLECTION_START: case JVMTI_EVENT_GARBAGE_COLLECTION_FINISH: case JVMTI_EVENT_DATA_DUMP_REQUEST: ((jvmtiEventDataDumpRequest)ec) (data->jvmti_env); break; case JVMTI_EVENT_MONITOR_WAIT: ((jvmtiEventMonitorWait)ec) (data->jvmti_env, jni_env, data->thread, data->object, data->jlong); break; case JVMTI_EVENT_MONITOR_WAITED: ((jvmtiEventMonitorWaited)ec) (data->jvmti_env, jni_env, data->thread, data->object, data->b); break; case JVMTI_EVENT_MONITOR_CONTENDED_ENTERED: case JVMTI_EVENT_MONITOR_CONTENDED_ENTER: ((jvmtiEventMonitorContendedEnter)ec) (data->jvmti_env, jni_env, data->thread, data->object); break; case JVMTI_EVENT_OBJECT_FREE: ((jvmtiEventObjectFree)ec) (data->jvmti_env, data->jlong); break; case JVMTI_EVENT_VM_OBJECT_ALLOC: ((jvmtiEventVMObjectAlloc)ec) (data->jvmti_env, jni_env, data->thread, data->object, data->klass, data->jlong); break; default: log_text ("unknown event"); } break; } } /* dofireEvent ****************************************************************** sends event if it is enabled either globally or for some threads *******************************************************************************/ static void dofireEvent(jvmtiEvent e, genericEventData* data) { environment* env; jvmtiEventModeLL *evm; functionptr ec; env = envs; while (env!=NULL) { if (env->events[e-JVMTI_EVENT_START_ENUM].mode == JVMTI_DISABLE) { evm = env->events[e-JVMTI_EVENT_START_ENUM].next; /* test if the event is enable for some threads */ while (evm!=NULL) { if (evm->mode == JVMTI_ENABLE) { data->jvmti_env=&env->env; ec = ((functionptr*)(&env->callbacks))[e-JVMTI_EVENT_START_ENUM]; execute_callback(e, ec, data); } evm=evm->next; } } else { /* event enabled globally */ data->jvmti_env=&env->env; ec = ((functionptr*)(&env->callbacks))[e-JVMTI_EVENT_START_ENUM]; execute_callback(e, ec, data); } env=env->next; } } /* fireEvent ****************************************************************** fire event callback with data arguments. This function mainly fills the missing EventData. *******************************************************************************/ void jvmti_fireEvent(genericEventData* d) { jthread thread; /* XXX todo : respect event order JVMTI-Spec:Multiple Co-located Events */ if (d->ev != JVMTI_EVENT_VM_START) thread = jvmti_get_current_thread(); else thread = NULL; d->thread = thread; dofireEvent(d->ev,d); } /* SetEventNotificationMode **************************************************** Control the generation of events *******************************************************************************/ static jvmtiError SetEventNotificationMode (jvmtiEnv * env, jvmtiEventMode mode, jvmtiEvent event_type, jthread event_thread, ...) { environment* cacao_env; jvmtiEventModeLL *ll; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_ONLOAD) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if(event_thread != NULL) { if (!builtin_instanceof(event_thread,class_java_lang_Thread)) return JVMTI_ERROR_INVALID_THREAD; CHECK_THREAD_IS_ALIVE(event_thread); } cacao_env = (environment*) env; if ((mode != JVMTI_ENABLE) && (mode != JVMTI_DISABLE)) return JVMTI_ERROR_ILLEGAL_ARGUMENT; switch (event_type) { /* check capability and set system breakpoint */ case JVMTI_EVENT_EXCEPTION: case JVMTI_EVENT_EXCEPTION_CATCH: CHECK_CAPABILITY(env,can_generate_exception_events) break; case JVMTI_EVENT_SINGLE_STEP: CHECK_CAPABILITY(env,can_generate_single_step_events) break; case JVMTI_EVENT_FRAME_POP: CHECK_CAPABILITY(env,can_generate_frame_pop_events) break; case JVMTI_EVENT_BREAKPOINT: CHECK_CAPABILITY(env,can_generate_breakpoint_events) break; case JVMTI_EVENT_FIELD_ACCESS: CHECK_CAPABILITY(env,can_generate_field_access_events) break; case JVMTI_EVENT_FIELD_MODIFICATION: CHECK_CAPABILITY(env,can_generate_field_modification_events) break; case JVMTI_EVENT_METHOD_ENTRY: CHECK_CAPABILITY(env,can_generate_method_entry_events) break; case JVMTI_EVENT_METHOD_EXIT: CHECK_CAPABILITY(env, can_generate_method_exit_events) break; case JVMTI_EVENT_NATIVE_METHOD_BIND: CHECK_CAPABILITY(env, can_generate_native_method_bind_events) break; case JVMTI_EVENT_COMPILED_METHOD_LOAD: case JVMTI_EVENT_COMPILED_METHOD_UNLOAD: CHECK_CAPABILITY(env,can_generate_compiled_method_load_events) break; case JVMTI_EVENT_MONITOR_WAIT: case JVMTI_EVENT_MONITOR_WAITED: case JVMTI_EVENT_MONITOR_CONTENDED_ENTER: case JVMTI_EVENT_MONITOR_CONTENDED_ENTERED: CHECK_CAPABILITY(env,can_generate_monitor_events) break; case JVMTI_EVENT_GARBAGE_COLLECTION_START: case JVMTI_EVENT_GARBAGE_COLLECTION_FINISH: CHECK_CAPABILITY(env,can_generate_garbage_collection_events) break; case JVMTI_EVENT_OBJECT_FREE: CHECK_CAPABILITY(env,can_generate_object_free_events) break; case JVMTI_EVENT_VM_OBJECT_ALLOC: CHECK_CAPABILITY(env,can_generate_vm_object_alloc_events) break; case JVMTI_EVENT_THREAD_START: jvmti_set_system_breakpoint(THREADSTARTBRK, mode); break; case JVMTI_EVENT_THREAD_END: jvmti_set_system_breakpoint(THREADENDBRK, mode); break; default: /* all other events are required */ if ((event_type < JVMTI_EVENT_START_ENUM) || (event_type > JVMTI_EVENT_END_ENUM)) return JVMTI_ERROR_INVALID_EVENT_TYPE; break; } if (event_thread != NULL) { /* thread level control */ if ((JVMTI_EVENT_VM_INIT == mode) || (JVMTI_EVENT_VM_DEATH == mode) || (JVMTI_EVENT_VM_START == mode) || (JVMTI_EVENT_THREAD_START == mode) || (JVMTI_EVENT_COMPILED_METHOD_LOAD == mode) || (JVMTI_EVENT_COMPILED_METHOD_UNLOAD == mode) || (JVMTI_EVENT_DYNAMIC_CODE_GENERATED == mode) || (JVMTI_EVENT_DATA_DUMP_REQUEST == mode)) return JVMTI_ERROR_ILLEGAL_ARGUMENT; ll = &(cacao_env->events[event_type-JVMTI_EVENT_START_ENUM]); while (ll->next != NULL) { ll = ll->next; if (ll->event_thread == event_thread) { ll->mode=mode; return JVMTI_ERROR_NONE; } } ll->next = heap_allocate(sizeof(jvmtiEventModeLL),true,NULL); ll->next->mode=mode; } else { /* global control */ cacao_env->events[event_type-JVMTI_EVENT_START_ENUM].mode=mode; } return JVMTI_ERROR_NONE; } /* GetAllThreads *************************************************************** Get all live threads *******************************************************************************/ static jvmtiError GetAllThreads (jvmtiEnv * env, jint * threads_count_ptr, jthread ** threads_ptr) { threadobject** threads; int i; jvmtiError retval; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if ((threads_count_ptr == NULL) || (threads_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER; retval=jvmti_get_all_threads(threads_count_ptr, &threads); if (retval != JVMTI_ERROR_NONE) return retval; *threads_ptr = heap_allocate(sizeof(jthread*)* (*threads_count_ptr),true,NULL); for (i=0; i<*threads_count_ptr; i++) (*threads_ptr)[i] = threads[i]->o.thread; return JVMTI_ERROR_NONE; } /* SuspendThread *************************************************************** Suspend specified thread *******************************************************************************/ static jvmtiError SuspendThread (jvmtiEnv * env, jthread thread) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_suspend); log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NOT_AVAILABLE; return JVMTI_ERROR_NONE; } /* ResumeThread *************************************************************** Resume a suspended thread *******************************************************************************/ static jvmtiError ResumeThread (jvmtiEnv * env, jthread thread) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_suspend); log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NOT_AVAILABLE; return JVMTI_ERROR_NONE; } /* StopThread ***************************************************************** Send asynchronous exception to the specified thread. Similar to java.lang.Thread.stop(). Used to kill thread. *******************************************************************************/ static jvmtiError StopThread (jvmtiEnv * env, jthread thread, jobject exception) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_signal_thread); log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NOT_AVAILABLE; return JVMTI_ERROR_NONE; } /* InterruptThread ************************************************************ Interrupt specified thread. Similar to java.lang.Thread.interrupt() *******************************************************************************/ static jvmtiError InterruptThread (jvmtiEnv * env, jthread thread) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_signal_thread) log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NOT_AVAILABLE; if(!builtin_instanceof(thread,class_java_lang_Thread)) return JVMTI_ERROR_INVALID_THREAD; CHECK_THREAD_IS_ALIVE(thread); return JVMTI_ERROR_NONE; } /* GetThreadInfo *************************************************************** Get thread information. Details of the specified thread are stored in the jvmtiThreadInfo structure. *******************************************************************************/ static jvmtiError GetThreadInfo (jvmtiEnv * env, jthread t, jvmtiThreadInfo * info_ptr) { java_lang_Thread* th = (java_lang_Thread*)t; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; info_ptr->priority=(jint)th->priority; info_ptr->is_daemon=(jboolean)th->daemon; info_ptr->thread_group=(jthreadGroup)th->group; info_ptr->context_class_loader=(jobject)th->contextClassLoader; info_ptr->name= javastring_tochar((java_objectheader *)th->name); return JVMTI_ERROR_NONE; } /* GetOwnedMonitorInfo ********************************************************* Get information about the monitors owned by the specified thread *******************************************************************************/ static jvmtiError GetOwnedMonitorInfo (jvmtiEnv * env, jthread thread, jint * owned_monitor_count_ptr, jobject ** owned_monitors_ptr) { int i,j,size=20; java_objectheader **om; lock_record_pool_t* lrp; log_text("GetOwnedMonitorInfo called"); CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_get_owned_monitor_info); if ((owned_monitors_ptr==NULL)||(owned_monitor_count_ptr==NULL)) return JVMTI_ERROR_NULL_POINTER; if(!builtin_instanceof(thread,class_java_lang_Thread)) return JVMTI_ERROR_INVALID_THREAD; CHECK_THREAD_IS_ALIVE(thread); #if defined(ENABLE_THREADS) om=MNEW(java_objectheader*,size); pthread_mutex_lock(&lock_global_pool_lock); lrp=lock_global_pool; while (lrp != NULL) { for (j=0; jheader.size; j++) { /* if((lrp->lr[j].owner==(threadobject*)thread)&& (!lrp->lr[j].waiting)) { if (i>=size) { MREALLOC(om,java_objectheader*,size,size*2); size=size*2; } om[i]=lrp->lr[j].o; i++; }*/ } lrp=lrp->header.next; } pthread_mutex_unlock(&lock_global_pool_lock); *owned_monitors_ptr = heap_allocate(sizeof(java_objectheader*)*i,true,NULL); memcpy(*owned_monitors_ptr,om,i*sizeof(java_objectheader*)); MFREE(om,java_objectheader*,size); *owned_monitor_count_ptr = i; #endif return JVMTI_ERROR_NONE; } /* GetCurrentContendedMonitor ************************************************* Get the object the specified thread waits for. *******************************************************************************/ static jvmtiError GetCurrentContendedMonitor (jvmtiEnv * env, jthread thread, jobject * monitor_ptr) { int j; lock_record_pool_t* lrp; java_objectheader* monitor; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env, can_get_current_contended_monitor) if (monitor_ptr==NULL) return JVMTI_ERROR_NULL_POINTER; *monitor_ptr=NULL; if(!builtin_instanceof(thread,class_java_lang_Thread)) return JVMTI_ERROR_INVALID_THREAD; CHECK_THREAD_IS_ALIVE(thread); #if defined(ENABLE_THREADS) pthread_mutex_lock(&lock_global_pool_lock); lrp=lock_global_pool; while ((lrp != NULL)&&(monitor==NULL)) { for (j=0; jheader.size; j++) { /* if((lrp->lr[j].owner==(threadobject*)thread)&&(lrp->lr[j].waiting)) { monitor=lrp->lr[j].o; break; }*/ } lrp=lrp->header.next; } pthread_mutex_unlock(&lock_global_pool_lock); if (monitor!=NULL) { *monitor_ptr = heap_allocate(sizeof(java_objectheader*),true,NULL); *monitor_ptr = (jobject)monitor; } #endif return JVMTI_ERROR_NONE; } typedef struct { jvmtiStartFunction sf; jvmtiEnv* jvmti_env; void* arg; } runagentparam; static void *threadstartup(void *t) { runagentparam *rap = (runagentparam*)t; rap->sf(rap->jvmti_env,(JNIEnv*)&_Jv_JNINativeInterface,rap->arg); return NULL; } /* RunAgentThread ************************************************************* Starts the execution of an agent thread of the specified native function within the specified thread *******************************************************************************/ static jvmtiError RunAgentThread (jvmtiEnv * env, jthread thread, jvmtiStartFunction proc, const void *arg, jint priority) { pthread_attr_t threadattr; struct sched_param sp; runagentparam rap; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if((thread != NULL)&&(!builtin_instanceof(thread,class_java_lang_Thread))) return JVMTI_ERROR_INVALID_THREAD; if (proc == NULL) return JVMTI_ERROR_NULL_POINTER; if ((priority < JVMTI_THREAD_MIN_PRIORITY) || (priority > JVMTI_THREAD_MAX_PRIORITY)) return JVMTI_ERROR_INVALID_PRIORITY; /* XXX: Threads started with with this function should not be visible to Java programming language queries but are included in JVM TI queries */ rap.sf = proc; rap.arg = (void*)arg; rap.jvmti_env = env; #if defined(ENABLE_THREADS) pthread_attr_init(&threadattr); pthread_attr_setdetachstate(&threadattr, PTHREAD_CREATE_DETACHED); if (priority == JVMTI_THREAD_MIN_PRIORITY) { sp.__sched_priority = sched_get_priority_min(SCHED_FIFO); } if (priority == JVMTI_THREAD_MAX_PRIORITY) { sp.__sched_priority = sched_get_priority_min(SCHED_FIFO); } pthread_attr_setschedparam(&threadattr,&sp); if (pthread_create(&((threadobject*) thread)->tid, &threadattr, &threadstartup, &rap)) { log_text("pthread_create failed"); assert(0); } #endif return JVMTI_ERROR_NONE; } /* GetTopThreadGroups ********************************************************* Get all top-level thread groups in the VM. *******************************************************************************/ static jvmtiError GetTopThreadGroups (jvmtiEnv * env, jint * group_count_ptr, jthreadGroup ** groups_ptr) { jint threads_count_ptr; threadobject *threads_ptr; int i,j,x,size=20; jthreadGroup **tg,*ttgp; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; log_text("GetTopThreadGroups called"); if ((groups_ptr == NULL) || (group_count_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER; #if defined(ENABLE_THREADS) tg = MNEW(jthreadGroup*,size); x = 0; if (JVMTI_ERROR_NONE!=GetAllThreads(env,&threads_count_ptr,(jthread**)&threads_ptr)) return JVMTI_ERROR_INTERNAL; for (i=0;igroup == NULL) { log_text("threadgroup not set"); return JVMTI_ERROR_INTERNAL; } ttgp = (jthreadGroup*)((java_lang_ThreadGroup*)threads_ptr[i].o.thread->group)->parent; if (ttgp == NULL) { j=0; while((j= size){ MREALLOC(tg,jthreadGroup*,size,size*2); size=size*2; } tg[x]=ttgp; x++; } } } *groups_ptr = heap_allocate(sizeof(jthreadGroup*)*x,true,NULL); memcpy(*groups_ptr,tg,x*sizeof(jthreadGroup*)); MFREE(tg,jthreadGroup*,size); *group_count_ptr = x; #else return JVMTI_ERROR_NOT_AVAILABLE; #endif return JVMTI_ERROR_NONE; } /* GetThreadGroupInfo ********************************************************* Get information about the specified thread group. *******************************************************************************/ static jvmtiError GetThreadGroupInfo (jvmtiEnv * env, jthreadGroup group, jvmtiThreadGroupInfo * info_ptr) { int size; char* name; java_lang_ThreadGroup* grp; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if (info_ptr == NULL) return JVMTI_ERROR_NULL_POINTER; if (!builtin_instanceof(group,class_java_lang_ThreadGroup)) return JVMTI_ERROR_INVALID_THREAD_GROUP; grp = (java_lang_ThreadGroup*)group; info_ptr->parent = (jthreadGroup) Java_java_lang_VMObject_clone(NULL, (jclass)grp->header.vftbl->class, (java_lang_Cloneable*) &grp->parent); name = javastring_tochar((java_objectheader*)grp->name); size = strlen(name); info_ptr->name=heap_allocate(size*sizeof(char),true,NULL); strncpy(info_ptr->name,name,size); info_ptr->max_priority= (jint)grp->maxpri; info_ptr->is_daemon= (jboolean)grp->daemon_flag; return JVMTI_ERROR_NONE; } /* GetThreadGroupChildren ***************************************************** Get the live threads and active subgroups in this thread group. *******************************************************************************/ static jvmtiError GetThreadGroupChildren (jvmtiEnv * env, jthreadGroup group, jint * thread_count_ptr, jthread ** threads_ptr, jint * group_count_ptr, jthreadGroup ** groups_ptr) { java_lang_ThreadGroup* tgp; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if ((thread_count_ptr == NULL) || (threads_ptr == NULL) || (group_count_ptr == NULL) || (groups_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER; if (!builtin_instanceof(group,class_java_lang_ThreadGroup)) return JVMTI_ERROR_INVALID_THREAD_GROUP; tgp = (java_lang_ThreadGroup*)group; *thread_count_ptr = (jint)tgp->threads->elementCount; *threads_ptr = heap_allocate(sizeof(jthread*)*(*thread_count_ptr),true,NULL); memcpy(*threads_ptr, &tgp->threads->elementData, (*thread_count_ptr)*sizeof(jthread*)); *group_count_ptr = (jint) tgp->groups->elementCount; *groups_ptr = heap_allocate(sizeof(jthreadGroup*)*(*group_count_ptr),true,NULL); memcpy(*groups_ptr, &tgp->threads->elementData, (*group_count_ptr)*sizeof(jthreadGroup*)); return JVMTI_ERROR_NONE; } /* getcacaostacktrace ********************************************************* Helper function that retrives stack trace for specified thread. Has to take care of suspend/resume issuses *******************************************************************************/ static jvmtiError getcacaostacktrace(stacktracebuffer** trace, jthread thread) { threadobject *t; log_text("getcacaostacktrace"); t = (threadobject*)((java_lang_Thread*)thread)->vmThread; /* XXX todo *trace = stacktrace_create(t); */ return JVMTI_ERROR_NONE; } /* GetFrameCount ************************************************************** Get the number of frames in the specified thread's stack. *******************************************************************************/ static jvmtiError GetFrameCount (jvmtiEnv * env, jthread thread, jint * count_ptr) { stacktracebuffer* trace; jvmtiError er; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if(!builtin_instanceof(thread,class_java_lang_Thread)) return JVMTI_ERROR_INVALID_THREAD; CHECK_THREAD_IS_ALIVE(thread); if(count_ptr == NULL) return JVMTI_ERROR_NULL_POINTER; er = getcacaostacktrace(&trace, thread); if (er==JVMTI_ERROR_NONE) return er; *count_ptr = trace->used; return JVMTI_ERROR_NONE; } /* GetThreadState ************************************************************** Get the state of a thread. *******************************************************************************/ static jvmtiError GetThreadState (jvmtiEnv * env, jthread thread, jint * thread_state_ptr) { java_lang_Thread* th = (java_lang_Thread*)thread; threadobject* t = (threadobject*)th->vmThread; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if(!builtin_instanceof(thread,class_java_lang_Thread)) return JVMTI_ERROR_INVALID_THREAD; if (thread_state_ptr == NULL) return JVMTI_ERROR_NULL_POINTER; *thread_state_ptr = 0; #if defined(ENABLE_THREADS) if((th->vmThread==NULL)&&(th->group==NULL)) { /* alive ? */ /* not alive */ if (((threadobject*)th->vmThread)->tid == 0) *thread_state_ptr = JVMTI_THREAD_STATE_TERMINATED; } else { /* alive */ *thread_state_ptr = JVMTI_THREAD_STATE_ALIVE; if (t->interrupted) *thread_state_ptr |= JVMTI_THREAD_STATE_INTERRUPTED; /* todo */ if (false) *thread_state_ptr |= JVMTI_THREAD_STATE_SUSPENDED; if (false) *thread_state_ptr |= JVMTI_THREAD_STATE_IN_NATIVE; if (false) *thread_state_ptr |= JVMTI_THREAD_STATE_RUNNABLE; if (false) *thread_state_ptr |= JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER; if (false /* t->ee.waiting ? */) *thread_state_ptr |= JVMTI_THREAD_STATE_WAITING; if (false) *thread_state_ptr |= JVMTI_THREAD_STATE_WAITING_INDEFINITELY; if (false) *thread_state_ptr |= JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT; if (false) *thread_state_ptr |= JVMTI_THREAD_STATE_IN_OBJECT_WAIT; if (false) *thread_state_ptr |= JVMTI_THREAD_STATE_PARKED; if (t->sleeping) *thread_state_ptr |= JVMTI_THREAD_STATE_SLEEPING; } #else return JVMTI_ERROR_INTERNAL; #endif return JVMTI_ERROR_NONE; } /* GetFrameLocation ************************************************************ Get the location of the instruction currently executing *******************************************************************************/ static jvmtiError GetFrameLocation (jvmtiEnv * env, jthread thread, jint depth, jmethodID * method_ptr, jlocation * location_ptr) { stackframeinfo *sfi; int i; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if(!builtin_instanceof(thread,class_java_lang_Thread)) return JVMTI_ERROR_INVALID_THREAD; CHECK_THREAD_IS_ALIVE(thread); if (depth < 0) return JVMTI_ERROR_ILLEGAL_ARGUMENT; if ((method_ptr == NULL)&&(location_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER; sfi = ((threadobject*)thread)->_stackframeinfo; i = 0; while ((sfi != NULL) && (iprev; i++; } if (i>depth) return JVMTI_ERROR_NO_MORE_FRAMES; *method_ptr=(jmethodID)sfi->method; *location_ptr = 0; /* todo: location MachinePC not avilable - Linenumber not expected */ return JVMTI_ERROR_NONE; } /* NotifyFramePop ************************************************************* *******************************************************************************/ static jvmtiError NotifyFramePop (jvmtiEnv * env, jthread thread, jint depth) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_generate_frame_pop_events) log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* GetLocalObject ************************************************************* *******************************************************************************/ static jvmtiError GetLocalObject (jvmtiEnv * env, jthread thread, jint depth, jint slot, jobject * value_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_access_local_variables) log_text ("JVMTI-Call: TBD-OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* GetLocalInt **************************************************************** *******************************************************************************/ static jvmtiError GetLocalInt (jvmtiEnv * env, jthread thread, jint depth, jint slot, jint * value_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_access_local_variables) log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* ***************************************************************************** *******************************************************************************/ static jvmtiError GetLocalLong (jvmtiEnv * env, jthread thread, jint depth, jint slot, jlong * value_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_access_local_variables) log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* ***************************************************************************** *******************************************************************************/ static jvmtiError GetLocalFloat (jvmtiEnv * env, jthread thread, jint depth, jint slot, jfloat * value_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_access_local_variables) log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* ***************************************************************************** *******************************************************************************/ static jvmtiError GetLocalDouble (jvmtiEnv * env, jthread thread, jint depth, jint slot, jdouble * value_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_access_local_variables) log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* ***************************************************************************** *******************************************************************************/ static jvmtiError SetLocalObject (jvmtiEnv * env, jthread thread, jint depth, jint slot, jobject value) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_access_local_variables) log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* ***************************************************************************** *******************************************************************************/ static jvmtiError SetLocalInt (jvmtiEnv * env, jthread thread, jint depth, jint slot, jint value) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_access_local_variables) log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* ***************************************************************************** *******************************************************************************/ static jvmtiError SetLocalLong (jvmtiEnv * env, jthread thread, jint depth, jint slot, jlong value) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_access_local_variables) log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* ***************************************************************************** *******************************************************************************/ static jvmtiError SetLocalFloat (jvmtiEnv * env, jthread thread, jint depth, jint slot, jfloat value) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_access_local_variables) log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* ***************************************************************************** *******************************************************************************/ static jvmtiError SetLocalDouble (jvmtiEnv * env, jthread thread, jint depth, jint slot, jdouble value) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_access_local_variables) log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* CreateRawMonitor *********************************************************** This function creates a new raw monitor. *******************************************************************************/ static jvmtiError CreateRawMonitor (jvmtiEnv * env, const char *name, jrawMonitorID * monitor_ptr) { struct _jrawMonitorID *monitor = (struct _jrawMonitorID*) monitor_ptr; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_ONLOAD) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if ((name == NULL) || (monitor_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER; #if defined(ENABLE_THREADS) monitor->name=javastring_new_from_ascii(name); #else log_text ("CreateRawMonitor not supported"); #endif return JVMTI_ERROR_NONE; } /* DestroyRawMonitor ********************************************************** This function destroys a raw monitor. *******************************************************************************/ static jvmtiError DestroyRawMonitor (jvmtiEnv * env, jrawMonitorID monitor) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_ONLOAD) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if (!builtin_instanceof((java_objectheader*)monitor->name,class_java_lang_String)) return JVMTI_ERROR_INVALID_MONITOR; #if defined(ENABLE_THREADS) if (!lock_is_held_by_current_thread((java_objectheader*)monitor->name)) return JVMTI_ERROR_NOT_MONITOR_OWNER; lock_monitor_exit((threadobject*)THREADOBJECT, (java_objectheader*)monitor->name); /* GC will clean monitor up */ #else log_text ("DestroyRawMonitor not supported"); #endif return JVMTI_ERROR_NONE; } /* RawMonitorEnter ************************************************************ Gain exclusive ownership of a raw monitor *******************************************************************************/ static jvmtiError RawMonitorEnter (jvmtiEnv * env, jrawMonitorID monitor) { if (!builtin_instanceof((java_objectheader*)monitor->name,class_java_lang_String)) return JVMTI_ERROR_INVALID_MONITOR; #if defined(ENABLE_THREADS) builtin_monitorenter((java_objectheader*)monitor->name); #else log_text ("RawMonitorEnter not supported"); #endif return JVMTI_ERROR_NONE; } /* RawMonitorExit ************************************************************* Release raw monitor *******************************************************************************/ static jvmtiError RawMonitorExit (jvmtiEnv * env, jrawMonitorID monitor) { if (!builtin_instanceof((java_objectheader*)monitor->name,class_java_lang_String)) return JVMTI_ERROR_INVALID_MONITOR; #if defined(ENABLE_THREADS) /* assure current thread owns this monitor */ if (!lock_is_held_by_current_thread((java_objectheader*)monitor->name)) return JVMTI_ERROR_NOT_MONITOR_OWNER; builtin_monitorexit((java_objectheader*)monitor->name); #else log_text ("RawMonitorExit not supported"); #endif return JVMTI_ERROR_NONE; } /* RawMonitorWait ************************************************************* Wait for notification of the raw monitor. *******************************************************************************/ static jvmtiError RawMonitorWait (jvmtiEnv * env, jrawMonitorID monitor, jlong millis) { if (!builtin_instanceof((java_objectheader*)monitor->name,class_java_lang_String)) return JVMTI_ERROR_INVALID_MONITOR; #if defined(ENABLE_THREADS) /* assure current thread owns this monitor */ if (!lock_is_held_by_current_thread((java_objectheader*)monitor->name)) return JVMTI_ERROR_NOT_MONITOR_OWNER; lock_wait_for_object(&monitor->name->header, millis,0); if (builtin_instanceof((java_objectheader*)exceptionptr, load_class_bootstrap(utf_new_char("java/lang/InterruptedException")))) return JVMTI_ERROR_INTERRUPT; #else log_text ("RawMonitorWait not supported"); #endif return JVMTI_ERROR_NONE; } /* RawMonitorNotify *********************************************************** Notify one thread waiting on the given monitor. *******************************************************************************/ static jvmtiError RawMonitorNotify (jvmtiEnv * env, jrawMonitorID monitor) { if (!builtin_instanceof((java_objectheader*)monitor->name,class_java_lang_String)) return JVMTI_ERROR_INVALID_MONITOR; #if defined(ENABLE_THREADS) /* assure current thread owns this monitor */ if (!lock_is_held_by_current_thread((java_objectheader*)monitor->name)) return JVMTI_ERROR_NOT_MONITOR_OWNER; lock_notify_object((java_objectheader*)&monitor->name); #else log_text ("RawMonitorNotify not supported"); #endif return JVMTI_ERROR_NONE; } /* RawMonitorNotifyAll ********************************************************* Notify all threads waiting on the given monitor. *******************************************************************************/ static jvmtiError RawMonitorNotifyAll (jvmtiEnv * env, jrawMonitorID monitor) { if (!builtin_instanceof((java_objectheader*)monitor->name,class_java_lang_String)) return JVMTI_ERROR_INVALID_MONITOR; #if defined(ENABLE_THREADS) /* assure current thread owns this monitor */ if (!lock_is_held_by_current_thread((java_objectheader*)monitor->name)) return JVMTI_ERROR_NOT_MONITOR_OWNER; lock_notify_all_object((java_objectheader*)&monitor->name); #else log_text ("RawMonitorNotifyAll not supported"); #endif return JVMTI_ERROR_NONE; } /* SetBreakpoint ************************************************************** *******************************************************************************/ static jvmtiError SetBreakpoint (jvmtiEnv * env, jmethodID method, jlocation location) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_generate_breakpoint_events) /* addbrkpt */ log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* ***************************************************************************** *******************************************************************************/ static jvmtiError ClearBreakpoint (jvmtiEnv * env, jmethodID method, jlocation location) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_generate_breakpoint_events) log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* SetFieldAccessWatch ******************************************************** *******************************************************************************/ static jvmtiError SetFieldAccessWatch (jvmtiEnv * env, jclass klass, jfieldID field) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_generate_field_access_events) log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* ***************************************************************************** *******************************************************************************/ static jvmtiError ClearFieldAccessWatch (jvmtiEnv * env, jclass klass, jfieldID field) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_generate_field_access_events) log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* ***************************************************************************** *******************************************************************************/ static jvmtiError SetFieldModificationWatch (jvmtiEnv * env, jclass klass, jfieldID field) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_generate_field_modification_events) log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* ***************************************************************************** *******************************************************************************/ static jvmtiError ClearFieldModificationWatch (jvmtiEnv * env, jclass klass, jfieldID field) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_generate_field_modification_events) log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* Allocate ******************************************************************** Allocate an area of memory through the JVM TI allocator. The allocated memory should be freed with Deallocate *******************************************************************************/ static jvmtiError Allocate (jvmtiEnv * env, jlong size, unsigned char **mem_ptr) { if (mem_ptr == NULL) return JVMTI_ERROR_NULL_POINTER; if (size < 0) return JVMTI_ERROR_ILLEGAL_ARGUMENT; *mem_ptr = heap_allocate(sizeof(size),true,NULL); if (*mem_ptr == NULL) return JVMTI_ERROR_OUT_OF_MEMORY; else return JVMTI_ERROR_NONE; } /* Deallocate ****************************************************************** Deallocate mem using the JVM TI allocator. *******************************************************************************/ static jvmtiError Deallocate (jvmtiEnv * env, unsigned char *mem) { /* let Boehm GC do the job */ heap_free(mem); return JVMTI_ERROR_NONE; } /* GetClassSignature ************************************************************ For the class indicated by klass, return the JNI type signature and the generic signature of the class. *******************************************************************************/ static jvmtiError GetClassSignature (jvmtiEnv * env, jclass klass, char **signature_ptr, char **generic_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if ((generic_ptr== NULL)||(signature_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER; *signature_ptr = (char*) heap_allocate(sizeof(char) * ((classinfo*)klass)->name->blength,true,NULL); utf_sprint_convert_to_latin1(*signature_ptr, ((classinfo*)klass)->name); *generic_ptr = NULL; return JVMTI_ERROR_NONE; } /* GetClassStatus ************************************************************* Get status of the class. *******************************************************************************/ static jvmtiError GetClassStatus (jvmtiEnv * env, jclass klass, jint * status_ptr) { classinfo *c; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if (!builtin_instanceof((java_objectheader*)klass,class_java_lang_Class)) return JVMTI_ERROR_INVALID_CLASS; if (status_ptr == NULL) return JVMTI_ERROR_NULL_POINTER; c = (classinfo*)klass; *status_ptr = 0; /* if (c) *status_ptr = *status_ptr | JVMTI_CLASS_STATUS_VERIFIED; ? */ if (c->state&=CLASS_LINKED) *status_ptr = *status_ptr | JVMTI_CLASS_STATUS_PREPARED; if (c->state&=CLASS_INITIALIZED) *status_ptr = *status_ptr | JVMTI_CLASS_STATUS_INITIALIZED; if (c->state&=CLASS_ERROR) *status_ptr = *status_ptr | JVMTI_CLASS_STATUS_ERROR; if (c->vftbl->arraydesc != NULL) *status_ptr = *status_ptr | JVMTI_CLASS_STATUS_ARRAY; if (Java_java_lang_VMClass_isPrimitive(NULL,NULL,(struct java_lang_Class*)c)) *status_ptr = *status_ptr | JVMTI_CLASS_STATUS_PRIMITIVE; return JVMTI_ERROR_NONE; } /* GetSourceFileName ********************************************************** For the class indicated by klass, return the source file name. *******************************************************************************/ static jvmtiError GetSourceFileName (jvmtiEnv * env, jclass klass, char **source_name_ptr) { int size; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_get_source_file_name) if ((klass == NULL)||(source_name_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER; size = (((classinfo*)klass)->sourcefile->blength)+1; *source_name_ptr = (char*) heap_allocate(sizeof(char)* size,true,NULL); memcpy(*source_name_ptr,((classinfo*)klass)->sourcefile->text, size); (*source_name_ptr)[size]='\0'; return JVMTI_ERROR_NONE; } /* GetClassModifiers ********************************************************** For class klass return the access flags *******************************************************************************/ static jvmtiError GetClassModifiers (jvmtiEnv * env, jclass klass, jint * modifiers_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if (modifiers_ptr == NULL) return JVMTI_ERROR_NULL_POINTER; if (!builtin_instanceof((java_objectheader*)klass,class_java_lang_Class)) return JVMTI_ERROR_INVALID_CLASS; *modifiers_ptr = (jint) ((classinfo*)klass)->flags; return JVMTI_ERROR_NONE; } /* GetClassMethods ************************************************************* For class klass return a count of methods and a list of method IDs *******************************************************************************/ static jvmtiError GetClassMethods (jvmtiEnv * env, jclass klass, jint * method_count_ptr, jmethodID ** methods_ptr) { int i; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if ((klass == NULL)||(methods_ptr == NULL)||(method_count_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER; if (!builtin_instanceof((java_objectheader*)klass,class_java_lang_Class)) return JVMTI_ERROR_INVALID_CLASS; *method_count_ptr = (jint)((classinfo*)klass)->methodscount; *methods_ptr = (jmethodID*) heap_allocate(sizeof(jmethodID) * (*method_count_ptr),true,NULL); for (i=0; i<*method_count_ptr;i++) (*methods_ptr)[i]=(jmethodID) &(((classinfo*)klass)->methods[i]); return JVMTI_ERROR_NONE; } /* GetClassFields ************************************************************* For the class indicated by klass, return a count of fields and a list of field IDs. *******************************************************************************/ static jvmtiError GetClassFields (jvmtiEnv * env, jclass klass, jint * field_count_ptr, jfieldID ** fields_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if ((klass == NULL)||(fields_ptr == NULL)||(field_count_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER; *field_count_ptr = (jint)((classinfo*)klass)->fieldscount; *fields_ptr = (jfieldID*) heap_allocate(sizeof(jfieldID) * (*field_count_ptr),true,NULL); memcpy (*fields_ptr, ((classinfo*)klass)->fields, sizeof(jfieldID) * (*field_count_ptr)); return JVMTI_ERROR_NONE; } /* GetImplementedInterfaces *************************************************** Return the direct super-interfaces of this class. *******************************************************************************/ static jvmtiError GetImplementedInterfaces (jvmtiEnv * env, jclass klass, jint * interface_count_ptr, jclass ** interfaces_ptr) { int i; classref_or_classinfo *interfaces; classinfo *tmp; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if ((interfaces_ptr == NULL) || (interface_count_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER; if (!builtin_instanceof((java_objectheader*)klass,class_java_lang_Class)) return JVMTI_ERROR_INVALID_CLASS; *interface_count_ptr = (jint)((classinfo*)klass)->interfacescount; *interfaces_ptr = heap_allocate(sizeof(jclass*) * (*interface_count_ptr),true,NULL); interfaces = ((classinfo*)klass)->interfaces; for (i=0; i<*interface_count_ptr; i++) { if (IS_CLASSREF(interfaces[i])) tmp = load_class_bootstrap(interfaces[i].ref->name); else tmp = interfaces[i].cls; *interfaces_ptr[i]=tmp; } return JVMTI_ERROR_NONE; } /* IsInterface **************************************************************** Determines whether a class object reference represents an interface. *******************************************************************************/ static jvmtiError IsInterface (jvmtiEnv * env, jclass klass, jboolean * is_interface_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if ((klass == NULL)||(is_interface_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER; *is_interface_ptr = (((classinfo*)klass)->flags & ACC_INTERFACE); return JVMTI_ERROR_NONE; } /* IsArrayClass *************************************************************** Determines whether a class object reference represents an array. *******************************************************************************/ static jvmtiError IsArrayClass (jvmtiEnv * env, jclass klass, jboolean * is_array_class_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if (is_array_class_ptr == NULL) return JVMTI_ERROR_NULL_POINTER; *is_array_class_ptr = ((classinfo*)klass)->vftbl->arraydesc != NULL; return JVMTI_ERROR_NONE; } /* GetClassLoader ************************************************************* For the class indicated by klass, return via classloader_ptr a reference to the class loader for the class. *******************************************************************************/ static jvmtiError GetClassLoader (jvmtiEnv * env, jclass klass, jobject * classloader_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if ((klass == NULL)||(classloader_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER; *classloader_ptr = (jobject)((classinfo*)klass)->classloader; return JVMTI_ERROR_NONE; } /* GetObjectHashCode ********************************************************** Return hash code for object object *******************************************************************************/ static jvmtiError GetObjectHashCode (jvmtiEnv * env, jobject object, jint * hash_code_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if (hash_code_ptr == NULL) return JVMTI_ERROR_NULL_POINTER; if (!builtin_instanceof(object,class_java_lang_Object)) return JVMTI_ERROR_INVALID_OBJECT; *hash_code_ptr = Java_java_lang_VMSystem_identityHashCode(NULL,NULL,(struct java_lang_Object*)object); return JVMTI_ERROR_NONE; } /* ***************************************************************************** *******************************************************************************/ static jvmtiError GetObjectMonitorUsage (jvmtiEnv * env, jobject object, jvmtiMonitorUsage * info_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_get_monitor_info) log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* GetFieldName *************************************************************** For the field indicated by klass and field, return the field name and signature. *******************************************************************************/ static jvmtiError GetFieldName (jvmtiEnv * env, jclass klass, jfieldID field, char **name_ptr, char **signature_ptr, char **generic_ptr) { int size; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if ((field == NULL)||(name_ptr == NULL)||(signature_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER; size = (((fieldinfo*)field)->name->blength); *name_ptr = (char*) heap_allocate(sizeof(char)* size,true,NULL); memcpy(*name_ptr,((fieldinfo*)field)->name->text, size); size = (((fieldinfo*)field)->descriptor->blength); *signature_ptr = (char*) heap_allocate(sizeof(char)* size,true,NULL); memcpy(*signature_ptr,((fieldinfo*)field)->descriptor->text, size); *generic_ptr = NULL; return JVMTI_ERROR_NONE; } /* GetFieldDeclaringClass ***************************************************** For the field indicated by klass and field return the class that defined it The declaring class will either be klass, a superclass, or an implemented interface. *******************************************************************************/ static jvmtiError GetFieldDeclaringClass (jvmtiEnv * env, jclass klass, jfieldID field, jclass * declaring_class_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; *declaring_class_ptr = (jclass) ((fieldinfo*)field)->class; return JVMTI_ERROR_NONE; } /* GetFieldModifiers ********************************************************** Return access flags of field field *******************************************************************************/ static jvmtiError GetFieldModifiers (jvmtiEnv * env, jclass klass, jfieldID field, jint * modifiers_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if (!builtin_instanceof((java_objectheader*)klass, class_java_lang_Class)) return JVMTI_ERROR_INVALID_OBJECT; if (modifiers_ptr == NULL) return JVMTI_ERROR_NULL_POINTER; /* todo: JVMTI_ERROR_INVALID_FIELDID; */ *modifiers_ptr = ((fieldinfo*)field)->flags; return JVMTI_ERROR_NONE; } /* IsFieldSynthetic *********************************************************** *******************************************************************************/ static jvmtiError IsFieldSynthetic (jvmtiEnv * env, jclass klass, jfieldID field, jboolean * is_synthetic_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_get_synthetic_attribute) log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* GetMethodName *************************************************************** For the method indicated by method, return the method name via name_ptr and method signature via signature_ptr. *******************************************************************************/ static jvmtiError GetMethodName (jvmtiEnv * env, jmethodID method, char **name_ptr, char **signature_ptr, char **generic_ptr) { methodinfo* m = (methodinfo*)method; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if ((method == NULL) || (name_ptr == NULL) || (signature_ptr == NULL) || (generic_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER; *name_ptr = (char*) heap_allocate(sizeof(char) * (m->name->blength),true,NULL); utf_sprint_convert_to_latin1(*name_ptr, m->name); *signature_ptr = (char*) heap_allocate(sizeof(char) * (m->descriptor->blength),true,NULL); utf_sprint_convert_to_latin1(*signature_ptr, m->descriptor); /* there is no generic signature attribute */ *generic_ptr = NULL; return JVMTI_ERROR_NONE; } /* GetMethodDeclaringClass ***************************************************** For the method indicated by method, return the class that defined it. *******************************************************************************/ static jvmtiError GetMethodDeclaringClass (jvmtiEnv * env, jmethodID method, jclass * declaring_class_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if ((method == NULL) || (declaring_class_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER; *declaring_class_ptr = (jclass)((methodinfo*)method)->class; return JVMTI_ERROR_NONE; } /* GetMethodModifiers ********************************************************** For the method indicated by method, return the access flags. *******************************************************************************/ static jvmtiError GetMethodModifiers (jvmtiEnv * env, jmethodID method, jint * modifiers_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if ((method == NULL) || (modifiers_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER; *modifiers_ptr = (jint) (((methodinfo*)method)->flags); return JVMTI_ERROR_NONE; } /* GetMaxLocals **************************************************************** For the method indicated by method, return the number of local variable slots used by the method, including the local variables used to pass parameters to the method on its invocation. *******************************************************************************/ static jvmtiError GetMaxLocals (jvmtiEnv * env, jmethodID method, jint * max_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if ((method == NULL)||(max_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER; if (((methodinfo*)method)->flags & ACC_NATIVE) return JVMTI_ERROR_NATIVE_METHOD; *max_ptr = (jint) ((methodinfo*)method)->maxlocals; return JVMTI_ERROR_NONE; } /* GetArgumentsSize ************************************************************ Return the number of local variable slots used by the method's arguments. *******************************************************************************/ static jvmtiError GetArgumentsSize (jvmtiEnv * env, jmethodID method, jint * size_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if ((method == NULL)||(size_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER; if (((methodinfo*)method)->flags & ACC_NATIVE) return JVMTI_ERROR_NATIVE_METHOD; /* todo *size_ptr = (jint)((methodinfo*)method)->paramcount;*/ return JVMTI_ERROR_NONE; } /* GetLineNumberTable *********************************************************** Return table of source line number entries for a given method *******************************************************************************/ static jvmtiError GetLineNumberTable (jvmtiEnv * env, jmethodID method, jint * entry_count_ptr, jvmtiLineNumberEntry ** table_ptr) { int i; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_get_line_numbers) if ((method == NULL) || (entry_count_ptr == NULL) || (table_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER; if (((methodinfo*)method)->flags & ACC_NATIVE) return JVMTI_ERROR_NATIVE_METHOD; if (((methodinfo*)method)->linenumbers == NULL) return JVMTI_ERROR_ABSENT_INFORMATION; *entry_count_ptr= (jint)((methodinfo*)method)->linenumbercount; *table_ptr = (jvmtiLineNumberEntry*) heap_allocate( sizeof(jvmtiLineNumberEntry) * (*entry_count_ptr),true,NULL); for (i=0; i < *entry_count_ptr; i++) { (*table_ptr[i]).start_location = (jlocation) ((methodinfo*)method)->linenumbers[i].start_pc; (*table_ptr[i]).line_number = (jint) ((methodinfo*)method)->linenumbers[i].line_number; } return JVMTI_ERROR_NONE; } /* GetMethodLocation *********************************************************** For the method indicated by method, return the beginning and ending addresses through start_location_ptr and end_location_ptr. In cacao this points to entry point in machine code and length of machine code *******************************************************************************/ static jvmtiError GetMethodLocation (jvmtiEnv * env, jmethodID method, jlocation * start_location_ptr, jlocation * end_location_ptr) { methodinfo* m = (methodinfo*)method; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if ((method == NULL) || (start_location_ptr == NULL) || (end_location_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER; /* XXX we return the location of the most recent code. Don't know * if there is a way to teach jvmti that a method can have more * than one location. -Edwin */ /* XXX Don't know if that's the right way to deal with not-yet- * compiled methods. -Edwin */ if (!m->code) return JVMTI_ERROR_NULL_POINTER; *start_location_ptr = (jlocation)m->code->mcode; *end_location_ptr = (jlocation)(m->code->mcode)+m->code->mcodelength; return JVMTI_ERROR_NONE; } /* GetLocalVariableTable ******************************************************* Return local variable information. *******************************************************************************/ static jvmtiError GetLocalVariableTable (jvmtiEnv * env, jmethodID method, jint * entry_count_ptr, jvmtiLocalVariableEntry ** table_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_access_local_variables) log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* GetBytecode ***************************************************************** For the method indicated by method, return the byte codes that implement the method. *******************************************************************************/ static jvmtiError GetBytecodes (jvmtiEnv * env, jmethodID method, jint * bytecode_count_ptr, unsigned char **bytecodes_ptr) { methodinfo* m = (methodinfo*)method;; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_get_bytecodes) if ((method == NULL) || (bytecode_count_ptr == NULL) || (bytecodes_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER; *bytecode_count_ptr = m->jcodelength; *bytecodes_ptr = (unsigned char*)heap_allocate(m->jcodelength,true,NULL); memcpy(*bytecodes_ptr, m->jcode, m->jcodelength); return JVMTI_ERROR_NONE; } /* IsMethodNative ************************************************************** For the method indicated by method, return a value indicating whether the method is a native function *******************************************************************************/ static jvmtiError IsMethodNative (jvmtiEnv * env, jmethodID method, jboolean * is_native_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if ((method == NULL)||(is_native_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER; if (((methodinfo*)method)->flags & ACC_NATIVE) *is_native_ptr = JNI_TRUE; else *is_native_ptr = JNI_FALSE; return JVMTI_ERROR_NONE; } /* IsMethodSynthetic *********************************************************** return a value indicating whether the method is synthetic. Synthetic methods are generated by the compiler but not present in the original source code. *******************************************************************************/ static jvmtiError IsMethodSynthetic (jvmtiEnv * env, jmethodID method, jboolean * is_synthetic_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_get_synthetic_attribute) log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* GetLoadedClasses ************************************************************ Return an array of all classes loaded in the virtual machine. *******************************************************************************/ static jvmtiError GetLoadedClasses (jvmtiEnv * env, jint * class_count_ptr, jclass ** classes_ptr) { int i,j=0; classcache_name_entry *nameentry; classcache_class_entry *classentry; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if (class_count_ptr == NULL) return JVMTI_ERROR_NULL_POINTER; if (classes_ptr == NULL) return JVMTI_ERROR_NULL_POINTER; CLASSCACHE_LOCK(); *classes_ptr = heap_allocate(sizeof(jclass)*(hashtable_classcache.entries),true,NULL); /* look in every slot of the hashtable */ for (i=0; iname->text[0]=='$') { *class_count_ptr -= 1; break; } classentry = nameentry->classes; while (classentry != NULL){ /* iterate over classes with same name */ if (classentry->classobj != NULL) { /*get only loaded classes */ assert(jclassobj; j++; } classentry = classentry->next; } nameentry = nameentry->hashlink; } } CLASSCACHE_UNLOCK(); *class_count_ptr = j; return JVMTI_ERROR_NONE; } /* GetClassLoaderClasses ******************************************************* Returns an array of those classes for which this class loader has been recorded as an initiating loader. *******************************************************************************/ static jvmtiError GetClassLoaderClasses (jvmtiEnv * env, jobject initiating_loader, jint * class_count_ptr, jclass ** classes_ptr) { log_text("GetClassLoaderClasses called"); CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; /* if (class_count_ptr == NULL) return JVMTI_ERROR_NULL_POINTER; if (classes_ptr == NULL) return JVMTI_ERROR_NULL_POINTER;*/ /* behave like jdk 1.1 and make no distinction between initiating and defining class loaders */ return GetLoadedClasses(env, class_count_ptr, classes_ptr); } /* PopFrame ******************************************************************* *******************************************************************************/ static jvmtiError PopFrame (jvmtiEnv * env, jthread thread) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_pop_frame) log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* RedefineClasses ************************************************************ *******************************************************************************/ static jvmtiError RedefineClasses (jvmtiEnv * env, jint class_count, const jvmtiClassDefinition * class_definitions) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_redefine_classes) CHECK_CAPABILITY(env,can_redefine_any_class) log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* GetVersionNumber *********************************************************** Return the JVM TI version identifier. *******************************************************************************/ static jvmtiError GetVersionNumber (jvmtiEnv * env, jint * version_ptr) { if (version_ptr == NULL) return JVMTI_ERROR_NULL_POINTER; *version_ptr = JVMTI_VERSION; return JVMTI_ERROR_NONE; } /* GetCapabilities ************************************************************ Returns the optional JVM TI features which this environment currently possesses. *******************************************************************************/ static jvmtiError GetCapabilities (jvmtiEnv * env, jvmtiCapabilities * capabilities_ptr) { if (capabilities_ptr == NULL) return JVMTI_ERROR_NULL_POINTER; memcpy(capabilities_ptr, &(((environment*) env)->capabilities), sizeof(JVMTI_Capabilities)); return JVMTI_ERROR_NONE; } /* ***************************************************************************** *******************************************************************************/ static jvmtiError GetSourceDebugExtension (jvmtiEnv * env, jclass klass, char **source_debug_extension_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_get_source_debug_extension) log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* IsMethodObsolete ************************************************************ Determine if a method ID refers to an obsolete method version. *******************************************************************************/ static jvmtiError IsMethodObsolete (jvmtiEnv * env, jmethodID method, jboolean * is_obsolete_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_redefine_classes) log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* SuspendThreadList ********************************************************** *******************************************************************************/ static jvmtiError SuspendThreadList (jvmtiEnv * env, jint request_count, const jthread * request_list, jvmtiError * results) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_suspend); log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* ResumeThreadList *********************************************************** *******************************************************************************/ static jvmtiError ResumeThreadList (jvmtiEnv * env, jint request_count, const jthread * request_list, jvmtiError * results) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_suspend); log_text ("JVMTI-Call: TBD OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* GetStackTrace ************************************************************** Get information about the stack of a thread *******************************************************************************/ static jvmtiError GetStackTrace (jvmtiEnv * env, jthread thread, jint start_depth, jint max_frame_count, jvmtiFrameInfo * frame_buffer, jint * count_ptr) { stacktracebuffer* trace; jvmtiError er; int i,j; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if(!builtin_instanceof(thread,class_java_lang_Thread)) return JVMTI_ERROR_INVALID_THREAD; CHECK_THREAD_IS_ALIVE(thread); if((count_ptr == NULL)||(frame_buffer == NULL)) return JVMTI_ERROR_NULL_POINTER; if (max_frame_count <0) return JVMTI_ERROR_ILLEGAL_ARGUMENT; er = getcacaostacktrace(&trace, thread); if (er==JVMTI_ERROR_NONE) return er; if ((trace->used >= start_depth) || ((trace->used * -1) > start_depth)) return JVMTI_ERROR_ILLEGAL_ARGUMENT; for (i=start_depth, j=0;iused;i++,j++) { frame_buffer[j].method = (jmethodID)trace->entries[i].method; /* todo: location BCI/MachinePC not avilable - Linenumber not expected */ frame_buffer[j].location = 0; } return JVMTI_ERROR_NONE; } /* GetThreadListStackTraces *************************************************** Get information about the stacks of the supplied threads. *******************************************************************************/ static jvmtiError GetThreadListStackTraces (jvmtiEnv * env, jint thread_count, const jthread * thread_list, jint max_frame_count, jvmtiStackInfo ** stack_info_ptr) { int i; jvmtiError er; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if ((stack_info_ptr == NULL)||(thread_list == NULL)) return JVMTI_ERROR_NULL_POINTER; if (thread_count < 0) return JVMTI_ERROR_ILLEGAL_ARGUMENT; if (max_frame_count < 0) return JVMTI_ERROR_ILLEGAL_ARGUMENT; *stack_info_ptr = (jvmtiStackInfo*) heap_allocate(sizeof(jvmtiStackInfo) * thread_count, true, NULL); for(i=0; itls; while ((tls->thread != thread) && (tls != NULL)) { tls = tls->next; } if (tls == NULL) return JVMTI_ERROR_INTERNAL; /* env/thread pair not found */ *data_ptr = tls->data; return JVMTI_ERROR_NONE; } /* SetThreadLocalStorage ******************************************************* Stores a pointer value associated with each environment-thread pair. The value is NULL unless set with this function. Agents can allocate memory in which they store thread specific information *******************************************************************************/ jvmtiError SetThreadLocalStorage (jvmtiEnv * jenv, jthread thread, const void *data) { jvmtiThreadLocalStorage *tls, *pre; environment* env = (environment*)jenv; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if(thread == NULL) thread = (jthread) THREADOBJECT; else { if (!builtin_instanceof(thread,class_java_lang_Thread)) return JVMTI_ERROR_INVALID_THREAD; CHECK_THREAD_IS_ALIVE(thread); } if (env->tls == NULL) { tls = env->tls = heap_allocate(sizeof(jvmtiThreadLocalStorage),true,NULL); } else { tls = env->tls; while ((tls->thread != thread) && (tls->next != NULL)) { tls = tls->next; } if (tls->thread != thread) { tls->next = heap_allocate(sizeof(jvmtiThreadLocalStorage),true,NULL); tls = tls->next; } } if (data != NULL) { tls->data = (void*)data; } else { /* remove current tls */ pre = env->tls; while (pre->next == tls) pre = pre->next; pre->next = tls->next; } return JVMTI_ERROR_NONE; } /* ***************************************************************************** *******************************************************************************/ static jvmtiError GetTag (jvmtiEnv * env, jobject object, jlong * tag_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_tag_objects) log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* ***************************************************************************** *******************************************************************************/ static jvmtiError SetTag (jvmtiEnv * env, jobject object, jlong tag) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_tag_objects) log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* ForceGarbageCollection ***************************************************** Force boehm-gc to perform a garbage collection *******************************************************************************/ static jvmtiError ForceGarbageCollection (jvmtiEnv * env) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; gc_call(); return JVMTI_ERROR_NONE; } /* IterateOverObjectsReachableFromObject ************************************** *******************************************************************************/ static jvmtiError IterateOverObjectsReachableFromObject (jvmtiEnv * env, jobject object, jvmtiObjectReferenceCallback object_reference_callback, void *user_data) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_tag_objects) log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* IterateOverReachableObjects ************************************************ *******************************************************************************/ static jvmtiError IterateOverReachableObjects (jvmtiEnv * env, jvmtiHeapRootCallback heap_root_callback, jvmtiStackReferenceCallback stack_ref_callback, jvmtiObjectReferenceCallback object_ref_callback, void *user_data) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_tag_objects) log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* IterateOverHeap ************************************************************ *******************************************************************************/ static jvmtiError IterateOverHeap (jvmtiEnv * env, jvmtiHeapObjectFilter object_filter, jvmtiHeapObjectCallback heap_object_callback, void *user_data) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_tag_objects) log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* IterateOverInstancesOfClass ************************************************ *******************************************************************************/ static jvmtiError IterateOverInstancesOfClass (jvmtiEnv * env, jclass klass, jvmtiHeapObjectFilter object_filter, jvmtiHeapObjectCallback heap_object_callback, void *user_data) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_tag_objects) log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* ***************************************************************************** *******************************************************************************/ static jvmtiError GetObjectsWithTags (jvmtiEnv * env, jint tag_count, const jlong * tags, jint * count_ptr, jobject ** object_result_ptr, jlong ** tag_result_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_tag_objects) log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* SetJNIFunctionTable ********************************************************** Set the JNI function table in all current and future JNI environments *******************************************************************************/ static jvmtiError SetJNIFunctionTable (jvmtiEnv * env, const jniNativeInterface * function_table) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END;; if (function_table == NULL) return JVMTI_ERROR_NULL_POINTER; _Jv_env->env = (void*)heap_allocate(sizeof(jniNativeInterface),true,NULL); memcpy((void*)_Jv_env->env, function_table, sizeof(jniNativeInterface)); return JVMTI_ERROR_NONE; } /* GetJNIFunctionTable ********************************************************* Get the JNI function table. The JNI function table is copied into allocated memory. *******************************************************************************/ static jvmtiError GetJNIFunctionTable (jvmtiEnv * env, jniNativeInterface ** function_table) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if (function_table == NULL) return JVMTI_ERROR_NULL_POINTER; *function_table = (jniNativeInterface*) heap_allocate(sizeof(jniNativeInterface),true,NULL); memcpy(*function_table, _Jv_env->env, sizeof(jniNativeInterface)); return JVMTI_ERROR_NONE; } /* SetEventCallbacks ********************************************************** Set the functions to be called for each event. The callbacks are specified by supplying a replacement function table. *******************************************************************************/ static jvmtiError SetEventCallbacks (jvmtiEnv * env, const jvmtiEventCallbacks * callbacks, jint size_of_callbacks) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_ONLOAD) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if (size_of_callbacks < 0) return JVMTI_ERROR_ILLEGAL_ARGUMENT; if (callbacks == NULL) { /* remove the existing callbacks */ memset(&(((environment* )env)->callbacks), 0, sizeof(jvmtiEventCallbacks)); } memcpy (&(((environment* )env)->callbacks),callbacks,size_of_callbacks); return JVMTI_ERROR_NONE; } /* GenerateEvents ************************************************************* Generate events (CompiledMethodLoad and DynamicCodeGenerated) to represent the current state of the VM. *******************************************************************************/ static jvmtiError GenerateEvents (jvmtiEnv * env, jvmtiEvent event_type) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; log_text ("JVMTI-Call: IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* GetExtensionFunctions ****************************************************** Returns the set of extension functions. *******************************************************************************/ static jvmtiError GetExtensionFunctions (jvmtiEnv * env, jint * extension_count_ptr, jvmtiExtensionFunctionInfo ** extensions) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_ONLOAD) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if ((extension_count_ptr== NULL)||(extensions == NULL)) return JVMTI_ERROR_NULL_POINTER; /* cacao has no extended functions yet */ *extension_count_ptr = 0; return JVMTI_ERROR_NONE; } /* GetExtensionEvents ********************************************************* Returns the set of extension events. *******************************************************************************/ static jvmtiError GetExtensionEvents (jvmtiEnv * env, jint * extension_count_ptr, jvmtiExtensionEventInfo ** extensions) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_ONLOAD) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if ((extension_count_ptr== NULL)||(extensions == NULL)) return JVMTI_ERROR_NULL_POINTER; /* cacao has no extended events yet */ *extension_count_ptr = 0; return JVMTI_ERROR_NONE; } /* SetExtensionEventCallback ************************************************** Sets the callback function for an extension event and enables the event. *******************************************************************************/ static jvmtiError SetExtensionEventCallback (jvmtiEnv * env, jint extension_event_index, jvmtiExtensionEvent callback) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_ONLOAD) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; /* cacao has no extended events yet */ return JVMTI_ERROR_ILLEGAL_ARGUMENT; } /* DisposeEnvironment ********************************************************** Shutdown a JVM TI connection created with JNI GetEnv. *******************************************************************************/ static jvmtiError DisposeEnvironment (jvmtiEnv * env) { environment* cacao_env = (environment*)env; environment* tenvs = envs; jvmtiThreadLocalStorage *jtls, *tjtls; if (tenvs != cacao_env) { while (tenvs->next != cacao_env) { tenvs = tenvs->next; } tenvs->next = cacao_env->next; } else envs = NULL; cacao_env->env=NULL; memset(&(cacao_env->callbacks),0,sizeof(jvmtiEventCallbacks)* (JVMTI_EVENT_END_ENUM-JVMTI_EVENT_START_ENUM)); memset(cacao_env->events,0,sizeof(jvmtiEventModeLL)* (JVMTI_EVENT_END_ENUM-JVMTI_EVENT_START_ENUM)); cacao_env->EnvironmentLocalStorage = NULL; jtls = cacao_env->tls; while (jtls != NULL) { tjtls = jtls; jtls = jtls->next; tjtls->next = NULL; } cacao_env->tls = NULL; jvmti_cacaodbgserver_quit(); /* let the GC do the rest */ return JVMTI_ERROR_NONE; } /* GetErrorName *************************************************************** Return the symbolic name for an error code. *******************************************************************************/ #define COPY_RESPONSE(name_ptr,str) *name_ptr = (char*) heap_allocate(sizeof(str),true,NULL); \ memcpy(*name_ptr, &str, sizeof(str)); \ break static jvmtiError GetErrorName (jvmtiEnv * env, jvmtiError error, char **name_ptr) { if (name_ptr == NULL) return JVMTI_ERROR_NULL_POINTER; switch (error) { case JVMTI_ERROR_NONE : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_NONE"); case JVMTI_ERROR_NULL_POINTER : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_NULL_POINTER"); case JVMTI_ERROR_OUT_OF_MEMORY : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_OUT_OF_MEMORY"); case JVMTI_ERROR_ACCESS_DENIED : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_ACCESS_DENIED"); case JVMTI_ERROR_UNATTACHED_THREAD : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_UNATTACHED_THREAD"); case JVMTI_ERROR_INVALID_ENVIRONMENT : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INVALID_ENVIRONMENT"); case JVMTI_ERROR_WRONG_PHASE : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_WRONG_PHASE"); case JVMTI_ERROR_INTERNAL : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INTERNAL"); case JVMTI_ERROR_INVALID_PRIORITY : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INVALID_PRIORITY"); case JVMTI_ERROR_THREAD_NOT_SUSPENDED : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_THREAD_NOT_SUSPENDED"); case JVMTI_ERROR_THREAD_SUSPENDED : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_THREAD_SUSPENDED"); case JVMTI_ERROR_THREAD_NOT_ALIVE : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_THREAD_NOT_ALIVE"); case JVMTI_ERROR_CLASS_NOT_PREPARED : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_CLASS_NOT_PREPARED"); case JVMTI_ERROR_NO_MORE_FRAMES : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_NO_MORE_FRAMES"); case JVMTI_ERROR_OPAQUE_FRAME : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_OPAQUE_FRAME"); case JVMTI_ERROR_DUPLICATE : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_DUPLICATE"); case JVMTI_ERROR_NOT_FOUND : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_NOT_FOUND"); case JVMTI_ERROR_NOT_MONITOR_OWNER : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_NOT_MONITOR_OWNER"); case JVMTI_ERROR_INTERRUPT : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INTERRUPT"); case JVMTI_ERROR_UNMODIFIABLE_CLASS : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_UNMODIFIABLE_CLASS"); case JVMTI_ERROR_NOT_AVAILABLE : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_NOT_AVAILABLE"); case JVMTI_ERROR_ABSENT_INFORMATION : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_ABSENT_INFORMATION"); case JVMTI_ERROR_INVALID_EVENT_TYPE : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INVALID_EVENT_TYPE"); case JVMTI_ERROR_NATIVE_METHOD : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_NATIVE_METHOD"); case JVMTI_ERROR_INVALID_THREAD : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INVALID_THREAD"); case JVMTI_ERROR_INVALID_FIELDID : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INVALID_FIELDID"); case JVMTI_ERROR_INVALID_METHODID : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INVALID_METHODID"); case JVMTI_ERROR_INVALID_LOCATION : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INVALID_LOCATION"); case JVMTI_ERROR_INVALID_OBJECT : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INVALID_OBJECT"); case JVMTI_ERROR_INVALID_CLASS : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INVALID_CLASS"); case JVMTI_ERROR_TYPE_MISMATCH : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_TYPE_MISMATCH"); case JVMTI_ERROR_INVALID_SLOT : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INVALID_SLOT"); case JVMTI_ERROR_MUST_POSSESS_CAPABILITY : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_MUST_POSSESS_CAPABILITY"); case JVMTI_ERROR_INVALID_THREAD_GROUP : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INVALID_THREAD_GROUP"); case JVMTI_ERROR_INVALID_MONITOR : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INVALID_MONITOR"); case JVMTI_ERROR_ILLEGAL_ARGUMENT : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_ILLEGAL_ARGUMENT"); case JVMTI_ERROR_INVALID_TYPESTATE : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INVALID_TYPESTATE"); case JVMTI_ERROR_UNSUPPORTED_VERSION : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_UNSUPPORTED_VERSION"); case JVMTI_ERROR_INVALID_CLASS_FORMAT : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_INVALID_CLASS_FORMAT"); case JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION"); case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED"); case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED"); case JVMTI_ERROR_FAILS_VERIFICATION : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_FAILS_VERIFICATION"); case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED"); case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED"); case JVMTI_ERROR_NAMES_DONT_MATCH : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_NAMES_DONT_MATCH"); case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED"); case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED : COPY_RESPONSE (name_ptr, "JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED"); default: return JVMTI_ERROR_ILLEGAL_ARGUMENT; } return JVMTI_ERROR_NONE; } /* GetJLocationFormat ********************************************************** This function describes the representation of jlocation used in this VM. *******************************************************************************/ static jvmtiError GetJLocationFormat (jvmtiEnv * env, jvmtiJlocationFormat * format_ptr) { *format_ptr = JVMTI_JLOCATION_MACHINEPC; return JVMTI_ERROR_NONE; } /* GetSystemProperties ******************************************************** The list of VM system property keys which may be used with GetSystemProperty is returned. *******************************************************************************/ static jvmtiError GetSystemProperties (jvmtiEnv * env, jint * count_ptr, char ***property_ptr) { jmethodID mid, moremid; classinfo *sysclass, *propclass, *enumclass; java_objectheader *sysprop, *keys, *obj; char* ch; int i; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_ONLOAD) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if ((count_ptr == NULL) || (property_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER; sysclass = load_class_from_sysloader( utf_new_char_classname ("java/lang/System")); if (!sysclass) throw_main_exception_exit(); mid = (jmethodID)class_resolvemethod(sysclass, utf_new_char("getProperties"), utf_new_char("()Ljava/util/Properties;")); if (!mid) throw_main_exception_exit(); sysprop = _Jv_JNINativeInterface.CallStaticObjectMethod(NULL, sysclass, mid); if (!sysprop) throw_main_exception_exit(); propclass = sysprop->vftbl->class; mid = (jmethodID)class_resolvemethod(propclass, utf_new_char("size"), utf_new_char("()I")); if (!mid) throw_main_exception_exit(); *count_ptr = _Jv_JNINativeInterface.CallIntMethod(NULL, sysprop, mid); *property_ptr = heap_allocate(sizeof(char*) * (*count_ptr) ,true,NULL); mid = (jmethodID)class_resolvemethod(propclass, utf_new_char("keys"), utf_new_char("()Ljava/util/Enumeration;")); if (!mid) throw_main_exception_exit(); keys = _Jv_JNINativeInterface.CallObjectMethod(NULL, sysprop, mid); enumclass = keys->vftbl->class; moremid = (jmethodID)class_resolvemethod(enumclass, utf_new_char("hasMoreElements"), utf_new_char("()Z")); if (!moremid) throw_main_exception_exit(); mid = (jmethodID)class_resolvemethod(propclass, utf_new_char("nextElement"), utf_new_char("()Ljava/lang/Object;")); if (!mid) throw_main_exception_exit(); i = 0; while (_Jv_JNINativeInterface.CallBooleanMethod(NULL,keys,(jmethodID)moremid)) { obj = _Jv_JNINativeInterface.CallObjectMethod(NULL, keys, mid); ch = javastring_tochar(obj); *property_ptr[i] = heap_allocate(sizeof(char*) * strlen (ch),true,NULL); memcpy(*property_ptr[i], ch, strlen (ch)); MFREE(ch,char,strlen(ch)+1); i++; } return JVMTI_ERROR_NONE; } /* GetSystemProperty ********************************************************** Return a VM system property value given the property key. *******************************************************************************/ static jvmtiError GetSystemProperty (jvmtiEnv * env, const char *property, char **value_ptr) { jmethodID mid; classinfo *sysclass, *propclass; java_objectheader *sysprop, *obj; char* ch; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_ONLOAD) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if ((value_ptr == NULL) || (property == NULL)) return JVMTI_ERROR_NULL_POINTER; sysclass = load_class_from_sysloader(utf_new_char("java/lang/System")); if (!sysclass) throw_main_exception_exit(); mid = (jmethodID)class_resolvemethod(sysclass, utf_new_char("getProperties"), utf_new_char("()Ljava/util/Properties;")); if (!mid) throw_main_exception_exit(); sysprop = _Jv_JNINativeInterface.CallStaticObjectMethod(NULL, (jclass)sysclass, mid); propclass = sysprop->vftbl->class; mid = (jmethodID)class_resolvemethod(propclass, utf_new_char("getProperty"), utf_new_char("(Ljava/lang/String;)Ljava/lang/String;")); if (!mid) throw_main_exception_exit(); obj = (java_objectheader*)_Jv_JNINativeInterface.CallObjectMethod( NULL, sysprop, mid, javastring_new_from_ascii(property)); if (!obj) return JVMTI_ERROR_NOT_AVAILABLE; ch = javastring_tochar(obj); *value_ptr = heap_allocate(sizeof(char*) * strlen (ch),true,NULL); memcpy(*value_ptr, ch, strlen (ch)); MFREE(ch,char,strlen(ch)+1); return JVMTI_ERROR_NONE; } /* SetSystemProperty ********************************************************** Set a VM system property value. *******************************************************************************/ static jvmtiError SetSystemProperty (jvmtiEnv * env, const char *property, const char *value) { jmethodID mid; classinfo *sysclass, *propclass; java_objectheader *sysprop; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE_END; if (property == NULL) return JVMTI_ERROR_NULL_POINTER; if (value == NULL) return JVMTI_ERROR_NOT_AVAILABLE; sysclass = load_class_from_sysloader(utf_new_char("java/lang/System")); if (!sysclass) throw_main_exception_exit(); mid = (jmethodID)class_resolvemethod(sysclass, utf_new_char("getProperties"), utf_new_char("()Ljava/util/Properties;")); if (!mid) throw_main_exception_exit(); sysprop = _Jv_JNINativeInterface.CallStaticObjectMethod(NULL, (jclass)sysclass, mid); propclass = sysprop->vftbl->class; mid = (jmethodID)class_resolvemethod(propclass, utf_new_char("setProperty"), utf_new_char("(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;")); if (!mid) throw_main_exception_exit(); _Jv_JNINativeInterface.CallObjectMethod( NULL, sysprop, mid, javastring_new_from_ascii(property),javastring_new_from_ascii(value)); return JVMTI_ERROR_NONE; } /* GetPhase ******************************************************************** Return the current phase of VM execution *******************************************************************************/ static jvmtiError GetPhase (jvmtiEnv * env, jvmtiPhase * phase_ptr) { if (phase_ptr == NULL) return JVMTI_ERROR_NULL_POINTER; *phase_ptr = phase; return JVMTI_ERROR_NONE; } /* GetCurrentThreadCpuTimerInfo ************************************************ *******************************************************************************/ static jvmtiError GetCurrentThreadCpuTimerInfo (jvmtiEnv * env, jvmtiTimerInfo * info_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_get_current_thread_cpu_time) log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* GetCurrentThreadCpuTime **************************************************** *******************************************************************************/ static jvmtiError GetCurrentThreadCpuTime (jvmtiEnv * env, jlong * nanos_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_get_current_thread_cpu_time) log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* GetThreadCpuTimerInfo ****************************************************** *******************************************************************************/ static jvmtiError GetThreadCpuTimerInfo (jvmtiEnv * env, jvmtiTimerInfo * info_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_get_thread_cpu_time) log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* GetThreadCpuTime *********************************************************** *******************************************************************************/ static jvmtiError GetThreadCpuTime (jvmtiEnv * env, jthread thread, jlong * nanos_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; CHECK_CAPABILITY(env,can_get_thread_cpu_time) log_text ("JVMTI-Call: OPTIONAL IMPLEMENT ME!!!"); return JVMTI_ERROR_NONE; } /* GetTimerInfo *************************************************************** Get information about the GetTime timer. *******************************************************************************/ static jvmtiError GetTimerInfo (jvmtiEnv * env, jvmtiTimerInfo * info_ptr) { if (info_ptr == NULL) return JVMTI_ERROR_NULL_POINTER; info_ptr->max_value = !0x0; info_ptr->may_skip_forward = true; info_ptr->may_skip_backward = true; info_ptr->kind = JVMTI_TIMER_TOTAL_CPU; return JVMTI_ERROR_NONE; } /* GetTime ******************************************************************** Return the current value of the system timer, in nanoseconds *******************************************************************************/ static jvmtiError GetTime (jvmtiEnv * env, jlong * nanos_ptr) { /* Note: this implementation copied directly from Japhar's, by Chris Toshok. */ struct timeval tp; if (nanos_ptr == NULL) return JVMTI_ERROR_NULL_POINTER; if (gettimeofday (&tp, NULL) == -1) _Jv_JNINativeInterface.FatalError (NULL, "gettimeofday call failed."); *nanos_ptr = (jlong) tp.tv_sec; *nanos_ptr *= 1000; *nanos_ptr += (tp.tv_usec / 1000); return JVMTI_ERROR_NONE; } /* GetPotentialCapabilities *************************************************** Returns the JVM TI features that can potentially be possessed by this environment at this time. *******************************************************************************/ static jvmtiError GetPotentialCapabilities (jvmtiEnv * env, jvmtiCapabilities * capabilities_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_ONLOAD) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if (capabilities_ptr == NULL) return JVMTI_ERROR_NULL_POINTER; memcpy(capabilities_ptr, &JVMTI_Capabilities, sizeof(JVMTI_Capabilities)); return JVMTI_ERROR_NONE; } #define CHECK_ADD_CAPABILITY(env,CAN) \ if (capabilities_ptr->CAN == 1) { \ if (JVMTI_Capabilities.CAN == 0) \ return JVMTI_ERROR_NOT_AVAILABLE; \ else \ env->capabilities.CAN = 1; \ } /* AddCapabilities ************************************************************ Set new capabilities by adding the capabilities pointed to by capabilities_ptr. All previous capabilities are retained. *******************************************************************************/ static jvmtiError AddCapabilities (jvmtiEnv * env, const jvmtiCapabilities * capabilities_ptr) { environment* cacao_env; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_ONLOAD) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if ((env == NULL) || (capabilities_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER; cacao_env = (environment*)env; CHECK_ADD_CAPABILITY(cacao_env,can_tag_objects) CHECK_ADD_CAPABILITY(cacao_env,can_generate_field_modification_events) CHECK_ADD_CAPABILITY(cacao_env,can_generate_field_access_events) CHECK_ADD_CAPABILITY(cacao_env,can_get_bytecodes) CHECK_ADD_CAPABILITY(cacao_env,can_get_synthetic_attribute) CHECK_ADD_CAPABILITY(cacao_env,can_get_owned_monitor_info) CHECK_ADD_CAPABILITY(cacao_env,can_get_current_contended_monitor) CHECK_ADD_CAPABILITY(cacao_env,can_get_monitor_info) CHECK_ADD_CAPABILITY(cacao_env,can_pop_frame) CHECK_ADD_CAPABILITY(cacao_env,can_redefine_classes) CHECK_ADD_CAPABILITY(cacao_env,can_signal_thread) CHECK_ADD_CAPABILITY(cacao_env,can_get_source_file_name) CHECK_ADD_CAPABILITY(cacao_env,can_get_line_numbers) CHECK_ADD_CAPABILITY(cacao_env,can_get_source_debug_extension) CHECK_ADD_CAPABILITY(cacao_env,can_access_local_variables) CHECK_ADD_CAPABILITY(cacao_env,can_maintain_original_method_order) CHECK_ADD_CAPABILITY(cacao_env,can_generate_single_step_events) CHECK_ADD_CAPABILITY(cacao_env,can_generate_exception_events) CHECK_ADD_CAPABILITY(cacao_env,can_generate_frame_pop_events) CHECK_ADD_CAPABILITY(cacao_env,can_generate_breakpoint_events) CHECK_ADD_CAPABILITY(cacao_env,can_suspend) CHECK_ADD_CAPABILITY(cacao_env,can_redefine_any_class) CHECK_ADD_CAPABILITY(cacao_env,can_get_current_thread_cpu_time) CHECK_ADD_CAPABILITY(cacao_env,can_get_thread_cpu_time) CHECK_ADD_CAPABILITY(cacao_env,can_generate_method_entry_events) CHECK_ADD_CAPABILITY(cacao_env,can_generate_method_exit_events) CHECK_ADD_CAPABILITY(cacao_env,can_generate_all_class_hook_events) CHECK_ADD_CAPABILITY(cacao_env,can_generate_compiled_method_load_events) CHECK_ADD_CAPABILITY(cacao_env,can_generate_monitor_events) CHECK_ADD_CAPABILITY(cacao_env,can_generate_vm_object_alloc_events) CHECK_ADD_CAPABILITY(cacao_env,can_generate_native_method_bind_events) CHECK_ADD_CAPABILITY(cacao_env,can_generate_garbage_collection_events) CHECK_ADD_CAPABILITY(cacao_env,can_generate_object_free_events) return JVMTI_ERROR_NONE; } #define CHECK_DEL_CAPABILITY(env,CAN) \ if (capabilities_ptr->CAN == 1) \ env->capabilities.CAN = 0; /* RelinquishCapabilities ***************************************************** Relinquish the capabilities pointed to by capabilities_ptr. *******************************************************************************/ static jvmtiError RelinquishCapabilities (jvmtiEnv * env, const jvmtiCapabilities * capabilities_ptr) { environment* cacao_env; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_ONLOAD) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if ((env == NULL) || (capabilities_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER; cacao_env = (environment*)env; CHECK_DEL_CAPABILITY(cacao_env,can_tag_objects) CHECK_DEL_CAPABILITY(cacao_env,can_generate_field_modification_events) CHECK_DEL_CAPABILITY(cacao_env,can_generate_field_access_events) CHECK_DEL_CAPABILITY(cacao_env,can_get_bytecodes) CHECK_DEL_CAPABILITY(cacao_env,can_get_synthetic_attribute) CHECK_DEL_CAPABILITY(cacao_env,can_get_owned_monitor_info) CHECK_DEL_CAPABILITY(cacao_env,can_get_current_contended_monitor) CHECK_DEL_CAPABILITY(cacao_env,can_get_monitor_info) CHECK_DEL_CAPABILITY(cacao_env,can_pop_frame) CHECK_DEL_CAPABILITY(cacao_env,can_redefine_classes) CHECK_DEL_CAPABILITY(cacao_env,can_signal_thread) CHECK_DEL_CAPABILITY(cacao_env,can_get_source_file_name) CHECK_DEL_CAPABILITY(cacao_env,can_get_line_numbers) CHECK_DEL_CAPABILITY(cacao_env,can_get_source_debug_extension) CHECK_DEL_CAPABILITY(cacao_env,can_access_local_variables) CHECK_DEL_CAPABILITY(cacao_env,can_maintain_original_method_order) CHECK_DEL_CAPABILITY(cacao_env,can_generate_single_step_events) CHECK_DEL_CAPABILITY(cacao_env,can_generate_exception_events) CHECK_DEL_CAPABILITY(cacao_env,can_generate_frame_pop_events) CHECK_DEL_CAPABILITY(cacao_env,can_generate_breakpoint_events) CHECK_DEL_CAPABILITY(cacao_env,can_suspend) CHECK_DEL_CAPABILITY(cacao_env,can_redefine_any_class) CHECK_DEL_CAPABILITY(cacao_env,can_get_current_thread_cpu_time) CHECK_DEL_CAPABILITY(cacao_env,can_get_thread_cpu_time) CHECK_DEL_CAPABILITY(cacao_env,can_generate_method_entry_events) CHECK_DEL_CAPABILITY(cacao_env,can_generate_method_exit_events) CHECK_DEL_CAPABILITY(cacao_env,can_generate_all_class_hook_events) CHECK_DEL_CAPABILITY(cacao_env,can_generate_compiled_method_load_events) CHECK_DEL_CAPABILITY(cacao_env,can_generate_monitor_events) CHECK_DEL_CAPABILITY(cacao_env,can_generate_vm_object_alloc_events) CHECK_DEL_CAPABILITY(cacao_env,can_generate_native_method_bind_events) CHECK_DEL_CAPABILITY(cacao_env,can_generate_garbage_collection_events) CHECK_DEL_CAPABILITY(cacao_env,can_generate_object_free_events) return JVMTI_ERROR_NONE; } /* ***************************************************************************** *******************************************************************************/ static jvmtiError GetAvailableProcessors (jvmtiEnv * env, jint * processor_count_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if (processor_count_ptr == NULL) return JVMTI_ERROR_NULL_POINTER; log_text ("GetAvailableProcessors IMPLEMENT ME!!!"); *processor_count_ptr = 1; /* where do I get this ?*/ return JVMTI_ERROR_NONE; } /* GetEnvironmentLocalStorage ************************************************** Called by the agent to get the value of the JVM TI environment-local storage. *******************************************************************************/ static jvmtiError GetEnvironmentLocalStorage (jvmtiEnv * env, void **data_ptr) { if ((env == NULL) || (data_ptr == NULL)) return JVMTI_ERROR_NULL_POINTER; *data_ptr = ((environment*)env)->EnvironmentLocalStorage; return JVMTI_ERROR_NONE; } /* SetEnvironmentLocalStorage ************************************************** The VM stores a pointer value associated with each environment. Agents can allocate memory in which they store environment specific information. *******************************************************************************/ static jvmtiError SetEnvironmentLocalStorage (jvmtiEnv * env, const void *data) { if (env == NULL) return JVMTI_ERROR_NULL_POINTER; ((environment*)env)->EnvironmentLocalStorage = (void*) data; return JVMTI_ERROR_NONE; } /* AddToBootstrapClassLoaderSearch ******************************************** After the bootstrap class loader unsuccessfully searches for a class, the specified platform-dependent search path segment will be searched as well. *******************************************************************************/ static jvmtiError AddToBootstrapClassLoaderSearch (jvmtiEnv * env, const char *segment) { char* tmp_bcp; int ln; CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_ONLOAD) CHECK_PHASE_END; if (segment == NULL) return JVMTI_ERROR_NULL_POINTER; ln = strlen(bootclasspath) + strlen(":") + strlen(segment); tmp_bcp = MNEW(char, ln); strcat(tmp_bcp, bootclasspath); strcat(tmp_bcp, ":"); strcat(tmp_bcp, segment); MFREE(bootclasspath,char,ln); bootclasspath = tmp_bcp; return JVMTI_ERROR_NONE; } /* SetVerboseFlag ************************************************************* Control verbose output. This is the output which typically is sent to stderr *******************************************************************************/ static jvmtiError SetVerboseFlag (jvmtiEnv * env, jvmtiVerboseFlag flag, jboolean value) { switch (flag) { case JVMTI_VERBOSE_OTHER: /* where is this defined ? runverbose = value; */ break; case JVMTI_VERBOSE_GC: opt_verbosegc = value; break; case JVMTI_VERBOSE_CLASS: loadverbose = value; break; case JVMTI_VERBOSE_JNI: break; default: return JVMTI_ERROR_ILLEGAL_ARGUMENT; } return JVMTI_ERROR_NONE; } /* GetObjectSize ************************************************************** For the object object return the size. *******************************************************************************/ static jvmtiError GetObjectSize (jvmtiEnv * env, jobject object, jlong * size_ptr) { CHECK_PHASE_START CHECK_PHASE(JVMTI_PHASE_START) CHECK_PHASE(JVMTI_PHASE_LIVE) CHECK_PHASE_END; if (size_ptr == NULL) return JVMTI_ERROR_NULL_POINTER; if (!builtin_instanceof(object,class_java_lang_Object)) return JVMTI_ERROR_INVALID_OBJECT; *size_ptr = ((java_objectheader*)object)->vftbl->class->instancesize; return JVMTI_ERROR_NONE; } /* ***************************************************************************** Environment variables *******************************************************************************/ static jvmtiCapabilities JVMTI_Capabilities = { 0, /* can_tag_objects */ 0, /* can_generate_field_modification_events */ 0, /* can_generate_field_access_events */ 1, /* can_get_bytecodes */ 0, /* can_get_synthetic_attribute */ #if defined(ENABLE_THREADS) 1, /* can_get_owned_monitor_info */ 1, /* can_get_current_contended_monitor */ #else 0, /* can_get_owned_monitor_info */ 0, /* can_get_current_contended_monitor */ #endif 0, /* can_get_monitor_info */ 0, /* can_pop_frame */ 0, /* can_redefine_classes */ 0, /* can_signal_thread */ 1, /* can_get_source_file_name */ 1, /* can_get_line_numbers */ 0, /* can_get_source_debug_extension */ 0, /* can_access_local_variables */ 0, /* can_maintain_original_method_order */ 0, /* can_generate_single_step_events */ 0, /* can_generate_exception_events */ 0, /* can_generate_frame_pop_events */ 0, /* can_generate_breakpoint_events */ 0, /* can_suspend */ 0, /* can_redefine_any_class */ 0, /* can_get_current_thread_cpu_time */ 0, /* can_get_thread_cpu_time */ 0, /* can_generate_method_entry_events */ 0, /* can_generate_method_exit_events */ 0, /* can_generate_all_class_hook_events */ 0, /* can_generate_compiled_method_load_events */ 0, /* can_generate_monitor_events */ 0, /* can_generate_vm_object_alloc_events */ 0, /* can_generate_native_method_bind_events */ 0, /* can_generate_garbage_collection_events */ 0, /* can_generate_object_free_events */ }; static struct jvmtiEnv_struct JVMTI_EnvTable = { NULL, &SetEventNotificationMode, NULL, &GetAllThreads, &SuspendThread, &ResumeThread, &StopThread, &InterruptThread, &GetThreadInfo, &GetOwnedMonitorInfo, &GetCurrentContendedMonitor, &RunAgentThread, &GetTopThreadGroups, &GetThreadGroupInfo, &GetThreadGroupChildren, &GetFrameCount, &GetThreadState, NULL, &GetFrameLocation, &NotifyFramePop, &GetLocalObject, &GetLocalInt, &GetLocalLong, &GetLocalFloat, &GetLocalDouble, &SetLocalObject, &SetLocalInt, &SetLocalLong, &SetLocalFloat, &SetLocalDouble, &CreateRawMonitor, &DestroyRawMonitor, &RawMonitorEnter, &RawMonitorExit, &RawMonitorWait, &RawMonitorNotify, &RawMonitorNotifyAll, &SetBreakpoint, &ClearBreakpoint, NULL, &SetFieldAccessWatch, &ClearFieldAccessWatch, &SetFieldModificationWatch, &ClearFieldModificationWatch, NULL, &Allocate, &Deallocate, &GetClassSignature, &GetClassStatus, &GetSourceFileName, &GetClassModifiers, &GetClassMethods, &GetClassFields, &GetImplementedInterfaces, &IsInterface, &IsArrayClass, &GetClassLoader, &GetObjectHashCode, &GetObjectMonitorUsage, &GetFieldName, &GetFieldDeclaringClass, &GetFieldModifiers, &IsFieldSynthetic, &GetMethodName, &GetMethodDeclaringClass, &GetMethodModifiers, NULL, &GetMaxLocals, &GetArgumentsSize, &GetLineNumberTable, &GetMethodLocation, &GetLocalVariableTable, NULL, NULL, &GetBytecodes, &IsMethodNative, &IsMethodSynthetic, &GetLoadedClasses, &GetClassLoaderClasses, &PopFrame, NULL, NULL, NULL, NULL, NULL, NULL, &RedefineClasses, &GetVersionNumber, &GetCapabilities, &GetSourceDebugExtension, &IsMethodObsolete, &SuspendThreadList, &ResumeThreadList, NULL, NULL, NULL, NULL, NULL, NULL, &GetAllStackTraces, &GetThreadListStackTraces, &GetThreadLocalStorage, &SetThreadLocalStorage, &GetStackTrace, NULL, &GetTag, &SetTag, &ForceGarbageCollection, &IterateOverObjectsReachableFromObject, &IterateOverReachableObjects, &IterateOverHeap, &IterateOverInstancesOfClass, NULL, &GetObjectsWithTags, NULL, NULL, NULL, NULL, NULL, &SetJNIFunctionTable, &GetJNIFunctionTable, &SetEventCallbacks, &GenerateEvents, &GetExtensionFunctions, &GetExtensionEvents, &SetExtensionEventCallback, &DisposeEnvironment, &GetErrorName, &GetJLocationFormat, &GetSystemProperties, &GetSystemProperty, &SetSystemProperty, &GetPhase, &GetCurrentThreadCpuTimerInfo, &GetCurrentThreadCpuTime, &GetThreadCpuTimerInfo, &GetThreadCpuTime, &GetTimerInfo, &GetTime, &GetPotentialCapabilities, NULL, &AddCapabilities, &RelinquishCapabilities, &GetAvailableProcessors, NULL, NULL, &GetEnvironmentLocalStorage, &SetEnvironmentLocalStorage, &AddToBootstrapClassLoaderSearch, &SetVerboseFlag, NULL, NULL, NULL, &GetObjectSize }; void jvmti_set_phase(jvmtiPhase p) { genericEventData d; fprintf (stderr,"set JVMTI phase %d\n",p); fflush(stderr); switch (p) { case JVMTI_PHASE_ONLOAD: phase = p; return; case JVMTI_PHASE_PRIMORDIAL: phase = p; return; case JVMTI_PHASE_START: phase = p; d.ev = JVMTI_EVENT_VM_START; break; case JVMTI_PHASE_LIVE: phase = p; d.ev = JVMTI_EVENT_VM_INIT; jvmti_fireEvent(&d); /* thread start event for main thread */ d.ev = JVMTI_EVENT_THREAD_START; break; case JVMTI_PHASE_DEAD: phase = p; d.ev = JVMTI_EVENT_VM_DEATH; break; default: log_text("wrong jvmti phase to be set"); exit(1); } jvmti_fireEvent(&d); } jvmtiEnv* jvmti_new_environment() { environment* env; if (envs == NULL) { envs = heap_allocate(sizeof(environment),true,NULL); env = envs; } else { env = envs; while (env->next != NULL) env = env->next; env->next = heap_allocate(sizeof(environment),true,NULL); env = env->next; } env->env = heap_allocate(sizeof(struct jvmtiEnv_struct),true,NULL); memcpy(env->env,&JVMTI_EnvTable,sizeof(struct jvmtiEnv_struct)); memset(&(env->events),JVMTI_DISABLE,(JVMTI_EVENT_END_ENUM - JVMTI_EVENT_START_ENUM)* sizeof(jvmtiEventModeLL)); /* To possess a capability, the agent must add the capability.*/ memset(&(env->capabilities), 0, sizeof(jvmtiCapabilities)); RelinquishCapabilities(&(env->env),&(env->capabilities)); env->EnvironmentLocalStorage = NULL; env->tls = NULL; /* initialize cacao debugging facilities */ jvmti_cacao_debug_init(); return (jvmtiEnv*)env; } void jvmti_agentload(char* opt_arg, bool agentbypath, lt_dlhandle *handle, char **libname) { lt_ptr onload; char *arg; int i=0,len; jint retval; len = strlen(opt_arg); /* separate argumtents */ while ((opt_arg[i]!='=')&&(i<=len)) i++; arg = &opt_arg[i]; if (agentbypath) { /* -agentpath */ *libname=heap_allocate(sizeof(char)*i,true,NULL); strncpy(*libname,opt_arg,i-1); (*libname)[i-1]='\0'; } else { /* -agentlib */ *libname=heap_allocate(sizeof(char)*(i+7),true,NULL); strncpy(*libname,"lib",3); strncpy(&(*libname)[3],opt_arg,i-1); strncpy(&(*libname)[i+2],".so",3); } /* try to open the library */ lt_dlinit(); if (!(*handle = lt_dlopen(*libname))) { fprintf(stderr,"Could not find agent library: %s (%s)\n",*libname,lt_dlerror()); vm_shutdown(1); } /* resolve Agent_OnLoad function */ if (!(onload = lt_dlsym(*handle, "Agent_OnLoad"))) { fprintf(stderr,"unable to load Agent_OnLoad function in %s (%s)\n",*libname,lt_dlerror()); vm_shutdown(1); } /* resolve Agent_UnLoad function */ unload = lt_dlsym(*handle, "Agent_Unload"); retval = ((JNIEXPORT jint JNICALL (*) (JavaVM *vm, char *options, void *reserved)) onload) ((JavaVM *) _Jv_jvm, arg, NULL); if (retval != 0) exit (retval); } void jvmti_agentunload() { if (unload != NULL) { ((JNIEXPORT void JNICALL (*) (JavaVM *vm)) unload) ((JavaVM*) &_Jv_JNIInvokeInterface); } } /* * These are local overrides for various environment variables in Emacs. * Please do not remove this and leave it at the end of the file, where * Emacs will automagically detect them. * --------------------------------------------------------------------- * Local variables: * mode: c * indent-tabs-mode: t * c-basic-offset: 4 * tab-width: 4 * End: * vim:noexpandtab:sw=4:ts=4: */