/* Copyright (C) 2016 The Android Open Source Project * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This file implements interfaces from the file jvmti.h. This implementation * is licensed under the same terms as the file jvmti.h. The * copyright and license information for the file jvmti.h follows. * * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ #include #include #include #include "openjdkjvmti/jvmti.h" #include "art_jvmti.h" #include "base/mutex.h" #include "events-inl.h" #include "jni_env_ext-inl.h" #include "object_tagging.h" #include "obj_ptr-inl.h" #include "runtime.h" #include "scoped_thread_state_change-inl.h" #include "thread_list.h" #include "thread-inl.h" #include "ti_class.h" #include "ti_heap.h" #include "ti_method.h" #include "ti_stack.h" #include "transform.h" // TODO Remove this at some point by annotating all the methods. It was put in to make the skeleton // easier to create. #pragma GCC diagnostic ignored "-Wunused-parameter" namespace openjdkjvmti { EventHandler gEventHandler; ObjectTagTable gObjectTagTable(&gEventHandler); class JvmtiFunctions { private: static bool IsValidEnv(jvmtiEnv* env) { return env != nullptr; } public: static jvmtiError Allocate(jvmtiEnv* env, jlong size, unsigned char** mem_ptr) { if (!IsValidEnv(env)) { return ERR(INVALID_ENVIRONMENT); } if (mem_ptr == nullptr) { return ERR(NULL_POINTER); } if (size < 0) { return ERR(ILLEGAL_ARGUMENT); } else if (size == 0) { *mem_ptr = nullptr; return OK; } *mem_ptr = static_cast(malloc(size)); return (*mem_ptr != nullptr) ? OK : ERR(OUT_OF_MEMORY); } static jvmtiError Deallocate(jvmtiEnv* env, unsigned char* mem) { if (!IsValidEnv(env)) { return ERR(INVALID_ENVIRONMENT); } if (mem != nullptr) { free(mem); } return OK; } static jvmtiError GetThreadState(jvmtiEnv* env, jthread thread, jint* thread_state_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetCurrentThread(jvmtiEnv* env, jthread* thread_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetAllThreads(jvmtiEnv* env, jint* threads_count_ptr, jthread** threads_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError SuspendThread(jvmtiEnv* env, jthread thread) { return ERR(NOT_IMPLEMENTED); } static jvmtiError SuspendThreadList(jvmtiEnv* env, jint request_count, const jthread* request_list, jvmtiError* results) { return ERR(NOT_IMPLEMENTED); } static jvmtiError ResumeThread(jvmtiEnv* env, jthread thread) { return ERR(NOT_IMPLEMENTED); } static jvmtiError ResumeThreadList(jvmtiEnv* env, jint request_count, const jthread* request_list, jvmtiError* results) { return ERR(NOT_IMPLEMENTED); } static jvmtiError StopThread(jvmtiEnv* env, jthread thread, jobject exception) { return ERR(NOT_IMPLEMENTED); } static jvmtiError InterruptThread(jvmtiEnv* env, jthread thread) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetThreadInfo(jvmtiEnv* env, jthread thread, jvmtiThreadInfo* info_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetOwnedMonitorInfo(jvmtiEnv* env, jthread thread, jint* owned_monitor_count_ptr, jobject** owned_monitors_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetOwnedMonitorStackDepthInfo(jvmtiEnv* env, jthread thread, jint* monitor_info_count_ptr, jvmtiMonitorStackDepthInfo** monitor_info_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetCurrentContendedMonitor(jvmtiEnv* env, jthread thread, jobject* monitor_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError RunAgentThread(jvmtiEnv* env, jthread thread, jvmtiStartFunction proc, const void* arg, jint priority) { return ERR(NOT_IMPLEMENTED); } static jvmtiError SetThreadLocalStorage(jvmtiEnv* env, jthread thread, const void* data) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetThreadLocalStorage(jvmtiEnv* env, jthread thread, void** data_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetTopThreadGroups(jvmtiEnv* env, jint* group_count_ptr, jthreadGroup** groups_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetThreadGroupInfo(jvmtiEnv* env, jthreadGroup group, jvmtiThreadGroupInfo* info_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetThreadGroupChildren(jvmtiEnv* env, jthreadGroup group, jint* thread_count_ptr, jthread** threads_ptr, jint* group_count_ptr, jthreadGroup** groups_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetStackTrace(jvmtiEnv* env, jthread thread, jint start_depth, jint max_frame_count, jvmtiFrameInfo* frame_buffer, jint* count_ptr) { return StackUtil::GetStackTrace(env, thread, start_depth, max_frame_count, frame_buffer, count_ptr); } static jvmtiError GetAllStackTraces(jvmtiEnv* env, jint max_frame_count, jvmtiStackInfo** stack_info_ptr, jint* thread_count_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetThreadListStackTraces(jvmtiEnv* env, jint thread_count, const jthread* thread_list, jint max_frame_count, jvmtiStackInfo** stack_info_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetFrameCount(jvmtiEnv* env, jthread thread, jint* count_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError PopFrame(jvmtiEnv* env, jthread thread) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetFrameLocation(jvmtiEnv* env, jthread thread, jint depth, jmethodID* method_ptr, jlocation* location_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError NotifyFramePop(jvmtiEnv* env, jthread thread, jint depth) { return ERR(NOT_IMPLEMENTED); } static jvmtiError ForceEarlyReturnObject(jvmtiEnv* env, jthread thread, jobject value) { return ERR(NOT_IMPLEMENTED); } static jvmtiError ForceEarlyReturnInt(jvmtiEnv* env, jthread thread, jint value) { return ERR(NOT_IMPLEMENTED); } static jvmtiError ForceEarlyReturnLong(jvmtiEnv* env, jthread thread, jlong value) { return ERR(NOT_IMPLEMENTED); } static jvmtiError ForceEarlyReturnFloat(jvmtiEnv* env, jthread thread, jfloat value) { return ERR(NOT_IMPLEMENTED); } static jvmtiError ForceEarlyReturnDouble(jvmtiEnv* env, jthread thread, jdouble value) { return ERR(NOT_IMPLEMENTED); } static jvmtiError ForceEarlyReturnVoid(jvmtiEnv* env, jthread thread) { return ERR(NOT_IMPLEMENTED); } static jvmtiError FollowReferences(jvmtiEnv* env, jint heap_filter, jclass klass, jobject initial_object, const jvmtiHeapCallbacks* callbacks, const void* user_data) { return ERR(NOT_IMPLEMENTED); } static jvmtiError IterateThroughHeap(jvmtiEnv* env, jint heap_filter, jclass klass, const jvmtiHeapCallbacks* callbacks, const void* user_data) { HeapUtil heap_util(&gObjectTagTable); return heap_util.IterateThroughHeap(env, heap_filter, klass, callbacks, user_data); } static jvmtiError GetTag(jvmtiEnv* env, jobject object, jlong* tag_ptr) { if (object == nullptr || tag_ptr == nullptr) { return ERR(NULL_POINTER); } JNIEnv* jni_env = GetJniEnv(env); if (jni_env == nullptr) { return ERR(INTERNAL); } art::ScopedObjectAccess soa(jni_env); art::ObjPtr obj = soa.Decode(object); if (!gObjectTagTable.GetTag(obj.Ptr(), tag_ptr)) { *tag_ptr = 0; } return ERR(NONE); } static jvmtiError SetTag(jvmtiEnv* env, jobject object, jlong tag) { if (object == nullptr) { return ERR(NULL_POINTER); } JNIEnv* jni_env = GetJniEnv(env); if (jni_env == nullptr) { return ERR(INTERNAL); } art::ScopedObjectAccess soa(jni_env); art::ObjPtr obj = soa.Decode(object); gObjectTagTable.Set(obj.Ptr(), tag); return ERR(NONE); } static jvmtiError GetObjectsWithTags(jvmtiEnv* env, jint tag_count, const jlong* tags, jint* count_ptr, jobject** object_result_ptr, jlong** tag_result_ptr) { JNIEnv* jni_env = GetJniEnv(env); if (jni_env == nullptr) { return ERR(INTERNAL); } art::ScopedObjectAccess soa(jni_env); return gObjectTagTable.GetTaggedObjects(env, tag_count, tags, count_ptr, object_result_ptr, tag_result_ptr); } static jvmtiError ForceGarbageCollection(jvmtiEnv* env) { return HeapUtil::ForceGarbageCollection(env); } static jvmtiError IterateOverObjectsReachableFromObject( jvmtiEnv* env, jobject object, jvmtiObjectReferenceCallback object_reference_callback, const void* user_data) { return ERR(NOT_IMPLEMENTED); } static jvmtiError IterateOverReachableObjects(jvmtiEnv* env, jvmtiHeapRootCallback heap_root_callback, jvmtiStackReferenceCallback stack_ref_callback, jvmtiObjectReferenceCallback object_ref_callback, const void* user_data) { return ERR(NOT_IMPLEMENTED); } static jvmtiError IterateOverHeap(jvmtiEnv* env, jvmtiHeapObjectFilter object_filter, jvmtiHeapObjectCallback heap_object_callback, const void* user_data) { return ERR(NOT_IMPLEMENTED); } static jvmtiError IterateOverInstancesOfClass(jvmtiEnv* env, jclass klass, jvmtiHeapObjectFilter object_filter, jvmtiHeapObjectCallback heap_object_callback, const void* user_data) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetLocalObject(jvmtiEnv* env, jthread thread, jint depth, jint slot, jobject* value_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetLocalInstance(jvmtiEnv* env, jthread thread, jint depth, jobject* value_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetLocalInt(jvmtiEnv* env, jthread thread, jint depth, jint slot, jint* value_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetLocalLong(jvmtiEnv* env, jthread thread, jint depth, jint slot, jlong* value_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetLocalFloat(jvmtiEnv* env, jthread thread, jint depth, jint slot, jfloat* value_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetLocalDouble(jvmtiEnv* env, jthread thread, jint depth, jint slot, jdouble* value_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError SetLocalObject(jvmtiEnv* env, jthread thread, jint depth, jint slot, jobject value) { return ERR(NOT_IMPLEMENTED); } static jvmtiError SetLocalInt(jvmtiEnv* env, jthread thread, jint depth, jint slot, jint value) { return ERR(NOT_IMPLEMENTED); } static jvmtiError SetLocalLong(jvmtiEnv* env, jthread thread, jint depth, jint slot, jlong value) { return ERR(NOT_IMPLEMENTED); } static jvmtiError SetLocalFloat(jvmtiEnv* env, jthread thread, jint depth, jint slot, jfloat value) { return ERR(NOT_IMPLEMENTED); } static jvmtiError SetLocalDouble(jvmtiEnv* env, jthread thread, jint depth, jint slot, jdouble value) { return ERR(NOT_IMPLEMENTED); } static jvmtiError SetBreakpoint(jvmtiEnv* env, jmethodID method, jlocation location) { return ERR(NOT_IMPLEMENTED); } static jvmtiError ClearBreakpoint(jvmtiEnv* env, jmethodID method, jlocation location) { return ERR(NOT_IMPLEMENTED); } static jvmtiError SetFieldAccessWatch(jvmtiEnv* env, jclass klass, jfieldID field) { return ERR(NOT_IMPLEMENTED); } static jvmtiError ClearFieldAccessWatch(jvmtiEnv* env, jclass klass, jfieldID field) { return ERR(NOT_IMPLEMENTED); } static jvmtiError SetFieldModificationWatch(jvmtiEnv* env, jclass klass, jfieldID field) { return ERR(NOT_IMPLEMENTED); } static jvmtiError ClearFieldModificationWatch(jvmtiEnv* env, jclass klass, jfieldID field) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetLoadedClasses(jvmtiEnv* env, jint* class_count_ptr, jclass** classes_ptr) { HeapUtil heap_util(&gObjectTagTable); return heap_util.GetLoadedClasses(env, class_count_ptr, classes_ptr); } static jvmtiError GetClassLoaderClasses(jvmtiEnv* env, jobject initiating_loader, jint* class_count_ptr, jclass** classes_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetClassSignature(jvmtiEnv* env, jclass klass, char** signature_ptr, char** generic_ptr) { return ClassUtil::GetClassSignature(env, klass, signature_ptr, generic_ptr); } static jvmtiError GetClassStatus(jvmtiEnv* env, jclass klass, jint* status_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetSourceFileName(jvmtiEnv* env, jclass klass, char** source_name_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetClassModifiers(jvmtiEnv* env, jclass klass, jint* modifiers_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetClassMethods(jvmtiEnv* env, jclass klass, jint* method_count_ptr, jmethodID** methods_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetClassFields(jvmtiEnv* env, jclass klass, jint* field_count_ptr, jfieldID** fields_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetImplementedInterfaces(jvmtiEnv* env, jclass klass, jint* interface_count_ptr, jclass** interfaces_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetClassVersionNumbers(jvmtiEnv* env, jclass klass, jint* minor_version_ptr, jint* major_version_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetConstantPool(jvmtiEnv* env, jclass klass, jint* constant_pool_count_ptr, jint* constant_pool_byte_count_ptr, unsigned char** constant_pool_bytes_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError IsInterface(jvmtiEnv* env, jclass klass, jboolean* is_interface_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError IsArrayClass(jvmtiEnv* env, jclass klass, jboolean* is_array_class_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError IsModifiableClass(jvmtiEnv* env, jclass klass, jboolean* is_modifiable_class_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetClassLoader(jvmtiEnv* env, jclass klass, jobject* classloader_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetSourceDebugExtension(jvmtiEnv* env, jclass klass, char** source_debug_extension_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError RetransformClasses(jvmtiEnv* env, jint class_count, const jclass* classes) { return ERR(NOT_IMPLEMENTED); } static jvmtiError RedefineClasses(jvmtiEnv* env, jint class_count, const jvmtiClassDefinition* class_definitions) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetObjectSize(jvmtiEnv* env, jobject object, jlong* size_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetObjectHashCode(jvmtiEnv* env, jobject object, jint* hash_code_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetObjectMonitorUsage(jvmtiEnv* env, jobject object, jvmtiMonitorUsage* info_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetFieldName(jvmtiEnv* env, jclass klass, jfieldID field, char** name_ptr, char** signature_ptr, char** generic_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetFieldDeclaringClass(jvmtiEnv* env, jclass klass, jfieldID field, jclass* declaring_class_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetFieldModifiers(jvmtiEnv* env, jclass klass, jfieldID field, jint* modifiers_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError IsFieldSynthetic(jvmtiEnv* env, jclass klass, jfieldID field, jboolean* is_synthetic_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetMethodName(jvmtiEnv* env, jmethodID method, char** name_ptr, char** signature_ptr, char** generic_ptr) { return MethodUtil::GetMethodName(env, method, name_ptr, signature_ptr, generic_ptr); } static jvmtiError GetMethodDeclaringClass(jvmtiEnv* env, jmethodID method, jclass* declaring_class_ptr) { return MethodUtil::GetMethodDeclaringClass(env, method, declaring_class_ptr); } static jvmtiError GetMethodModifiers(jvmtiEnv* env, jmethodID method, jint* modifiers_ptr) { return MethodUtil::GetMethodModifiers(env, method, modifiers_ptr); } static jvmtiError GetMaxLocals(jvmtiEnv* env, jmethodID method, jint* max_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetArgumentsSize(jvmtiEnv* env, jmethodID method, jint* size_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetLineNumberTable(jvmtiEnv* env, jmethodID method, jint* entry_count_ptr, jvmtiLineNumberEntry** table_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetMethodLocation(jvmtiEnv* env, jmethodID method, jlocation* start_location_ptr, jlocation* end_location_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetLocalVariableTable(jvmtiEnv* env, jmethodID method, jint* entry_count_ptr, jvmtiLocalVariableEntry** table_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetBytecodes(jvmtiEnv* env, jmethodID method, jint* bytecode_count_ptr, unsigned char** bytecodes_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError IsMethodNative(jvmtiEnv* env, jmethodID method, jboolean* is_native_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError IsMethodSynthetic(jvmtiEnv* env, jmethodID method, jboolean* is_synthetic_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError IsMethodObsolete(jvmtiEnv* env, jmethodID method, jboolean* is_obsolete_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError SetNativeMethodPrefix(jvmtiEnv* env, const char* prefix) { return ERR(NOT_IMPLEMENTED); } static jvmtiError SetNativeMethodPrefixes(jvmtiEnv* env, jint prefix_count, char** prefixes) { return ERR(NOT_IMPLEMENTED); } static jvmtiError CreateRawMonitor(jvmtiEnv* env, const char* name, jrawMonitorID* monitor_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError DestroyRawMonitor(jvmtiEnv* env, jrawMonitorID monitor) { return ERR(NOT_IMPLEMENTED); } static jvmtiError RawMonitorEnter(jvmtiEnv* env, jrawMonitorID monitor) { return ERR(NOT_IMPLEMENTED); } static jvmtiError RawMonitorExit(jvmtiEnv* env, jrawMonitorID monitor) { return ERR(NOT_IMPLEMENTED); } static jvmtiError RawMonitorWait(jvmtiEnv* env, jrawMonitorID monitor, jlong millis) { return ERR(NOT_IMPLEMENTED); } static jvmtiError RawMonitorNotify(jvmtiEnv* env, jrawMonitorID monitor) { return ERR(NOT_IMPLEMENTED); } static jvmtiError RawMonitorNotifyAll(jvmtiEnv* env, jrawMonitorID monitor) { return ERR(NOT_IMPLEMENTED); } static jvmtiError SetJNIFunctionTable(jvmtiEnv* env, const jniNativeInterface* function_table) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetJNIFunctionTable(jvmtiEnv* env, jniNativeInterface** function_table) { return ERR(NOT_IMPLEMENTED); } // TODO: This will require locking, so that an agent can't remove callbacks when we're dispatching // an event. static jvmtiError SetEventCallbacks(jvmtiEnv* env, const jvmtiEventCallbacks* callbacks, jint size_of_callbacks) { if (env == nullptr) { return ERR(NULL_POINTER); } if (size_of_callbacks < 0) { return ERR(ILLEGAL_ARGUMENT); } if (callbacks == nullptr) { ArtJvmTiEnv::AsArtJvmTiEnv(env)->event_callbacks.reset(); return ERR(NONE); } std::unique_ptr tmp(new jvmtiEventCallbacks()); memset(tmp.get(), 0, sizeof(jvmtiEventCallbacks)); size_t copy_size = std::min(sizeof(jvmtiEventCallbacks), static_cast(size_of_callbacks)); copy_size = art::RoundDown(copy_size, sizeof(void*)); memcpy(tmp.get(), callbacks, copy_size); ArtJvmTiEnv::AsArtJvmTiEnv(env)->event_callbacks = std::move(tmp); return ERR(NONE); } static jvmtiError SetEventNotificationMode(jvmtiEnv* env, jvmtiEventMode mode, jvmtiEvent event_type, jthread event_thread, ...) { art::Thread* art_thread = nullptr; if (event_thread != nullptr) { // TODO: Need non-aborting call here, to return JVMTI_ERROR_INVALID_THREAD. art::ScopedObjectAccess soa(art::Thread::Current()); art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_); art_thread = art::Thread::FromManagedThread(soa, event_thread); if (art_thread == nullptr || // The thread hasn't been started or is already dead. art_thread->IsStillStarting()) { // TODO: We may want to let the EventHandler know, so it could clean up masks, potentially. return ERR(THREAD_NOT_ALIVE); } } return gEventHandler.SetEvent(ArtJvmTiEnv::AsArtJvmTiEnv(env), art_thread, event_type, mode); } static jvmtiError GenerateEvents(jvmtiEnv* env, jvmtiEvent event_type) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetExtensionFunctions(jvmtiEnv* env, jint* extension_count_ptr, jvmtiExtensionFunctionInfo** extensions) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetExtensionEvents(jvmtiEnv* env, jint* extension_count_ptr, jvmtiExtensionEventInfo** extensions) { return ERR(NOT_IMPLEMENTED); } static jvmtiError SetExtensionEventCallback(jvmtiEnv* env, jint extension_event_index, jvmtiExtensionEvent callback) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetPotentialCapabilities(jvmtiEnv* env, jvmtiCapabilities* capabilities_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError AddCapabilities(jvmtiEnv* env, const jvmtiCapabilities* capabilities_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError RelinquishCapabilities(jvmtiEnv* env, const jvmtiCapabilities* capabilities_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetCapabilities(jvmtiEnv* env, jvmtiCapabilities* capabilities_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetCurrentThreadCpuTimerInfo(jvmtiEnv* env, jvmtiTimerInfo* info_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetCurrentThreadCpuTime(jvmtiEnv* env, jlong* nanos_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetThreadCpuTimerInfo(jvmtiEnv* env, jvmtiTimerInfo* info_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetThreadCpuTime(jvmtiEnv* env, jthread thread, jlong* nanos_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetTimerInfo(jvmtiEnv* env, jvmtiTimerInfo* info_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetTime(jvmtiEnv* env, jlong* nanos_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetAvailableProcessors(jvmtiEnv* env, jint* processor_count_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError AddToBootstrapClassLoaderSearch(jvmtiEnv* env, const char* segment) { return ERR(NOT_IMPLEMENTED); } static jvmtiError AddToSystemClassLoaderSearch(jvmtiEnv* env, const char* segment) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetSystemProperties(jvmtiEnv* env, jint* count_ptr, char*** property_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetSystemProperty(jvmtiEnv* env, const char* property, char** value_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError SetSystemProperty(jvmtiEnv* env, const char* property, const char* value) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetPhase(jvmtiEnv* env, jvmtiPhase* phase_ptr) { return ERR(NOT_IMPLEMENTED); } static jvmtiError DisposeEnvironment(jvmtiEnv* env) { if (!IsValidEnv(env)) { return ERR(INVALID_ENVIRONMENT); } delete env; return OK; } static jvmtiError SetEnvironmentLocalStorage(jvmtiEnv* env, const void* data) { if (!IsValidEnv(env)) { return ERR(INVALID_ENVIRONMENT); } reinterpret_cast(env)->local_data = const_cast(data); return OK; } static jvmtiError GetEnvironmentLocalStorage(jvmtiEnv* env, void** data_ptr) { if (!IsValidEnv(env)) { return ERR(INVALID_ENVIRONMENT); } *data_ptr = reinterpret_cast(env)->local_data; return OK; } static jvmtiError GetVersionNumber(jvmtiEnv* env, jint* version_ptr) { if (!IsValidEnv(env)) { return ERR(INVALID_ENVIRONMENT); } *version_ptr = JVMTI_VERSION; return OK; } static jvmtiError GetErrorName(jvmtiEnv* env, jvmtiError error, char** name_ptr) { if (!IsValidEnv(env)) { return ERR(INVALID_ENVIRONMENT); } if (name_ptr == nullptr) { return ERR(NULL_POINTER); } switch (error) { #define ERROR_CASE(e) case (JVMTI_ERROR_ ## e) : do { \ *name_ptr = const_cast("JVMTI_ERROR_"#e); \ return OK; \ } while (false) ERROR_CASE(NONE); ERROR_CASE(INVALID_THREAD); ERROR_CASE(INVALID_THREAD_GROUP); ERROR_CASE(INVALID_PRIORITY); ERROR_CASE(THREAD_NOT_SUSPENDED); ERROR_CASE(THREAD_NOT_ALIVE); ERROR_CASE(INVALID_OBJECT); ERROR_CASE(INVALID_CLASS); ERROR_CASE(CLASS_NOT_PREPARED); ERROR_CASE(INVALID_METHODID); ERROR_CASE(INVALID_LOCATION); ERROR_CASE(INVALID_FIELDID); ERROR_CASE(NO_MORE_FRAMES); ERROR_CASE(OPAQUE_FRAME); ERROR_CASE(TYPE_MISMATCH); ERROR_CASE(INVALID_SLOT); ERROR_CASE(DUPLICATE); ERROR_CASE(NOT_FOUND); ERROR_CASE(INVALID_MONITOR); ERROR_CASE(NOT_MONITOR_OWNER); ERROR_CASE(INTERRUPT); ERROR_CASE(INVALID_CLASS_FORMAT); ERROR_CASE(CIRCULAR_CLASS_DEFINITION); ERROR_CASE(FAILS_VERIFICATION); ERROR_CASE(UNSUPPORTED_REDEFINITION_METHOD_ADDED); ERROR_CASE(UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED); ERROR_CASE(INVALID_TYPESTATE); ERROR_CASE(UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED); ERROR_CASE(UNSUPPORTED_REDEFINITION_METHOD_DELETED); ERROR_CASE(UNSUPPORTED_VERSION); ERROR_CASE(NAMES_DONT_MATCH); ERROR_CASE(UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED); ERROR_CASE(UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED); ERROR_CASE(UNMODIFIABLE_CLASS); ERROR_CASE(NOT_AVAILABLE); ERROR_CASE(MUST_POSSESS_CAPABILITY); ERROR_CASE(NULL_POINTER); ERROR_CASE(ABSENT_INFORMATION); ERROR_CASE(INVALID_EVENT_TYPE); ERROR_CASE(ILLEGAL_ARGUMENT); ERROR_CASE(NATIVE_METHOD); ERROR_CASE(CLASS_LOADER_UNSUPPORTED); ERROR_CASE(OUT_OF_MEMORY); ERROR_CASE(ACCESS_DENIED); ERROR_CASE(WRONG_PHASE); ERROR_CASE(INTERNAL); ERROR_CASE(UNATTACHED_THREAD); ERROR_CASE(INVALID_ENVIRONMENT); #undef ERROR_CASE default: { *name_ptr = const_cast("JVMTI_ERROR_UNKNOWN"); return ERR(ILLEGAL_ARGUMENT); } } } static jvmtiError SetVerboseFlag(jvmtiEnv* env, jvmtiVerboseFlag flag, jboolean value) { return ERR(NOT_IMPLEMENTED); } static jvmtiError GetJLocationFormat(jvmtiEnv* env, jvmtiJlocationFormat* format_ptr) { return ERR(NOT_IMPLEMENTED); } // TODO Remove this once events are working. static jvmtiError RetransformClassWithHook(jvmtiEnv* env, jclass klass, jvmtiEventClassFileLoadHook hook) { std::vector classes; classes.push_back(klass); return RetransformClassesWithHook(reinterpret_cast(env), classes, hook); } // TODO This will be called by the event handler for the art::ti Event Load Event static jvmtiError RetransformClassesWithHook(ArtJvmTiEnv* env, const std::vector& classes, jvmtiEventClassFileLoadHook hook) { if (!IsValidEnv(env)) { return ERR(INVALID_ENVIRONMENT); } for (jclass klass : classes) { JNIEnv* jni_env = nullptr; jobject loader = nullptr; std::string name; jobject protection_domain = nullptr; jint data_len = 0; unsigned char* dex_data = nullptr; jvmtiError ret = OK; std::string location; if ((ret = GetTransformationData(env, klass, /*out*/&location, /*out*/&jni_env, /*out*/&loader, /*out*/&name, /*out*/&protection_domain, /*out*/&data_len, /*out*/&dex_data)) != OK) { // TODO Do something more here? Maybe give log statements? return ret; } jint new_data_len = 0; unsigned char* new_dex_data = nullptr; hook(env, jni_env, klass, loader, name.c_str(), protection_domain, data_len, dex_data, /*out*/&new_data_len, /*out*/&new_dex_data); // Check if anything actually changed. if ((new_data_len != 0 || new_dex_data != nullptr) && new_dex_data != dex_data) { MoveTransformedFileIntoRuntime(klass, std::move(location), new_data_len, new_dex_data); env->Deallocate(new_dex_data); } // Deallocate the old dex data. env->Deallocate(dex_data); } return OK; } }; static bool IsJvmtiVersion(jint version) { return version == JVMTI_VERSION_1 || version == JVMTI_VERSION_1_0 || version == JVMTI_VERSION_1_1 || version == JVMTI_VERSION_1_2 || version == JVMTI_VERSION; } // Creates a jvmtiEnv and returns it with the art::ti::Env that is associated with it. new_art_ti // is a pointer to the uninitialized memory for an art::ti::Env. static void CreateArtJvmTiEnv(art::JavaVMExt* vm, /*out*/void** new_jvmtiEnv) { struct ArtJvmTiEnv* env = new ArtJvmTiEnv(vm); *new_jvmtiEnv = env; gEventHandler.RegisterArtJvmTiEnv(env); } // A hook that the runtime uses to allow plugins to handle GetEnv calls. It returns true and // places the return value in 'env' if this library can handle the GetEnv request. Otherwise // returns false and does not modify the 'env' pointer. static jint GetEnvHandler(art::JavaVMExt* vm, /*out*/void** env, jint version) { if (IsJvmtiVersion(version)) { CreateArtJvmTiEnv(vm, env); return JNI_OK; } else { printf("version 0x%x is not valid!", version); return JNI_EVERSION; } } // The plugin initialization function. This adds the jvmti environment. extern "C" bool ArtPlugin_Initialize() { art::Runtime* runtime = art::Runtime::Current(); runtime->GetJavaVM()->AddEnvironmentHook(GetEnvHandler); runtime->AddSystemWeakHolder(&gObjectTagTable); return true; } // The actual struct holding all of the entrypoints into the jvmti interface. const jvmtiInterface_1 gJvmtiInterface = { // SPECIAL FUNCTION: RetransformClassWithHook Is normally reserved1 // TODO Remove once we have events working. reinterpret_cast(JvmtiFunctions::RetransformClassWithHook), // nullptr, // reserved1 JvmtiFunctions::SetEventNotificationMode, nullptr, // reserved3 JvmtiFunctions::GetAllThreads, JvmtiFunctions::SuspendThread, JvmtiFunctions::ResumeThread, JvmtiFunctions::StopThread, JvmtiFunctions::InterruptThread, JvmtiFunctions::GetThreadInfo, JvmtiFunctions::GetOwnedMonitorInfo, // 10 JvmtiFunctions::GetCurrentContendedMonitor, JvmtiFunctions::RunAgentThread, JvmtiFunctions::GetTopThreadGroups, JvmtiFunctions::GetThreadGroupInfo, JvmtiFunctions::GetThreadGroupChildren, JvmtiFunctions::GetFrameCount, JvmtiFunctions::GetThreadState, JvmtiFunctions::GetCurrentThread, JvmtiFunctions::GetFrameLocation, JvmtiFunctions::NotifyFramePop, // 20 JvmtiFunctions::GetLocalObject, JvmtiFunctions::GetLocalInt, JvmtiFunctions::GetLocalLong, JvmtiFunctions::GetLocalFloat, JvmtiFunctions::GetLocalDouble, JvmtiFunctions::SetLocalObject, JvmtiFunctions::SetLocalInt, JvmtiFunctions::SetLocalLong, JvmtiFunctions::SetLocalFloat, JvmtiFunctions::SetLocalDouble, // 30 JvmtiFunctions::CreateRawMonitor, JvmtiFunctions::DestroyRawMonitor, JvmtiFunctions::RawMonitorEnter, JvmtiFunctions::RawMonitorExit, JvmtiFunctions::RawMonitorWait, JvmtiFunctions::RawMonitorNotify, JvmtiFunctions::RawMonitorNotifyAll, JvmtiFunctions::SetBreakpoint, JvmtiFunctions::ClearBreakpoint, nullptr, // reserved40 JvmtiFunctions::SetFieldAccessWatch, JvmtiFunctions::ClearFieldAccessWatch, JvmtiFunctions::SetFieldModificationWatch, JvmtiFunctions::ClearFieldModificationWatch, JvmtiFunctions::IsModifiableClass, JvmtiFunctions::Allocate, JvmtiFunctions::Deallocate, JvmtiFunctions::GetClassSignature, JvmtiFunctions::GetClassStatus, JvmtiFunctions::GetSourceFileName, // 50 JvmtiFunctions::GetClassModifiers, JvmtiFunctions::GetClassMethods, JvmtiFunctions::GetClassFields, JvmtiFunctions::GetImplementedInterfaces, JvmtiFunctions::IsInterface, JvmtiFunctions::IsArrayClass, JvmtiFunctions::GetClassLoader, JvmtiFunctions::GetObjectHashCode, JvmtiFunctions::GetObjectMonitorUsage, JvmtiFunctions::GetFieldName, // 60 JvmtiFunctions::GetFieldDeclaringClass, JvmtiFunctions::GetFieldModifiers, JvmtiFunctions::IsFieldSynthetic, JvmtiFunctions::GetMethodName, JvmtiFunctions::GetMethodDeclaringClass, JvmtiFunctions::GetMethodModifiers, nullptr, // reserved67 JvmtiFunctions::GetMaxLocals, JvmtiFunctions::GetArgumentsSize, JvmtiFunctions::GetLineNumberTable, // 70 JvmtiFunctions::GetMethodLocation, JvmtiFunctions::GetLocalVariableTable, JvmtiFunctions::SetNativeMethodPrefix, JvmtiFunctions::SetNativeMethodPrefixes, JvmtiFunctions::GetBytecodes, JvmtiFunctions::IsMethodNative, JvmtiFunctions::IsMethodSynthetic, JvmtiFunctions::GetLoadedClasses, JvmtiFunctions::GetClassLoaderClasses, JvmtiFunctions::PopFrame, // 80 JvmtiFunctions::ForceEarlyReturnObject, JvmtiFunctions::ForceEarlyReturnInt, JvmtiFunctions::ForceEarlyReturnLong, JvmtiFunctions::ForceEarlyReturnFloat, JvmtiFunctions::ForceEarlyReturnDouble, JvmtiFunctions::ForceEarlyReturnVoid, JvmtiFunctions::RedefineClasses, JvmtiFunctions::GetVersionNumber, JvmtiFunctions::GetCapabilities, JvmtiFunctions::GetSourceDebugExtension, // 90 JvmtiFunctions::IsMethodObsolete, JvmtiFunctions::SuspendThreadList, JvmtiFunctions::ResumeThreadList, nullptr, // reserved94 nullptr, // reserved95 nullptr, // reserved96 nullptr, // reserved97 nullptr, // reserved98 nullptr, // reserved99 JvmtiFunctions::GetAllStackTraces, // 100 JvmtiFunctions::GetThreadListStackTraces, JvmtiFunctions::GetThreadLocalStorage, JvmtiFunctions::SetThreadLocalStorage, JvmtiFunctions::GetStackTrace, nullptr, // reserved105 JvmtiFunctions::GetTag, JvmtiFunctions::SetTag, JvmtiFunctions::ForceGarbageCollection, JvmtiFunctions::IterateOverObjectsReachableFromObject, JvmtiFunctions::IterateOverReachableObjects, // 110 JvmtiFunctions::IterateOverHeap, JvmtiFunctions::IterateOverInstancesOfClass, nullptr, // reserved113 JvmtiFunctions::GetObjectsWithTags, JvmtiFunctions::FollowReferences, JvmtiFunctions::IterateThroughHeap, nullptr, // reserved117 nullptr, // reserved118 nullptr, // reserved119 JvmtiFunctions::SetJNIFunctionTable, // 120 JvmtiFunctions::GetJNIFunctionTable, JvmtiFunctions::SetEventCallbacks, JvmtiFunctions::GenerateEvents, JvmtiFunctions::GetExtensionFunctions, JvmtiFunctions::GetExtensionEvents, JvmtiFunctions::SetExtensionEventCallback, JvmtiFunctions::DisposeEnvironment, JvmtiFunctions::GetErrorName, JvmtiFunctions::GetJLocationFormat, JvmtiFunctions::GetSystemProperties, // 130 JvmtiFunctions::GetSystemProperty, JvmtiFunctions::SetSystemProperty, JvmtiFunctions::GetPhase, JvmtiFunctions::GetCurrentThreadCpuTimerInfo, JvmtiFunctions::GetCurrentThreadCpuTime, JvmtiFunctions::GetThreadCpuTimerInfo, JvmtiFunctions::GetThreadCpuTime, JvmtiFunctions::GetTimerInfo, JvmtiFunctions::GetTime, JvmtiFunctions::GetPotentialCapabilities, // 140 nullptr, // reserved141 JvmtiFunctions::AddCapabilities, JvmtiFunctions::RelinquishCapabilities, JvmtiFunctions::GetAvailableProcessors, JvmtiFunctions::GetClassVersionNumbers, JvmtiFunctions::GetConstantPool, JvmtiFunctions::GetEnvironmentLocalStorage, JvmtiFunctions::SetEnvironmentLocalStorage, JvmtiFunctions::AddToBootstrapClassLoaderSearch, JvmtiFunctions::SetVerboseFlag, // 150 JvmtiFunctions::AddToSystemClassLoaderSearch, JvmtiFunctions::RetransformClasses, JvmtiFunctions::GetOwnedMonitorStackDepthInfo, JvmtiFunctions::GetObjectSize, JvmtiFunctions::GetLocalInstance, }; }; // namespace openjdkjvmti