blob: 9ff84fa8d846ede476aea7f0a748b808a3208bc1 [file] [log] [blame]
/* 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 <string>
#include <vector>
#include <jni.h>
#include "openjdkjvmti/jvmti.h"
#include "art_jvmti.h"
#include "base/mutex.h"
#include "events-inl.h"
#include "heap.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_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<unsigned char*>(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<art::mirror::Object> obj = soa.Decode<art::mirror::Object>(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<art::mirror::Object> obj = soa.Decode<art::mirror::Object>(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 ERR(NOT_IMPLEMENTED);
}
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 ERR(NOT_IMPLEMENTED);
}
static jvmtiError GetMethodModifiers(jvmtiEnv* env,
jmethodID method,
jint* modifiers_ptr) {
return ERR(NOT_IMPLEMENTED);
}
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<jvmtiEventCallbacks> tmp(new jvmtiEventCallbacks());
memset(tmp.get(), 0, sizeof(jvmtiEventCallbacks));
size_t copy_size = std::min(sizeof(jvmtiEventCallbacks),
static_cast<size_t>(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<ArtJvmTiEnv*>(env)->local_data = const_cast<void*>(data);
return OK;
}
static jvmtiError GetEnvironmentLocalStorage(jvmtiEnv* env, void** data_ptr) {
if (!IsValidEnv(env)) {
return ERR(INVALID_ENVIRONMENT);
}
*data_ptr = reinterpret_cast<ArtJvmTiEnv*>(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<char*>("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<char*>("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<jclass> classes;
classes.push_back(klass);
return RetransformClassesWithHook(reinterpret_cast<ArtJvmTiEnv*>(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<jclass>& 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<void*>(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