diff options
Diffstat (limited to 'runtime/openjdkjvmti')
| -rw-r--r-- | runtime/openjdkjvmti/Android.bp | 2 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/OpenjdkJvmTi.cc | 17 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/jvmti.h | 2 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/ti_jni.cc | 91 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/ti_jni.h | 58 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/ti_search.cc | 122 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/ti_search.h | 48 |
7 files changed, 334 insertions, 6 deletions
diff --git a/runtime/openjdkjvmti/Android.bp b/runtime/openjdkjvmti/Android.bp index af027f6ba6..d5c652035a 100644 --- a/runtime/openjdkjvmti/Android.bp +++ b/runtime/openjdkjvmti/Android.bp @@ -23,10 +23,12 @@ cc_defaults { "ti_class.cc", "ti_field.cc", "ti_heap.cc", + "ti_jni.cc", "ti_method.cc", "ti_monitor.cc", "ti_object.cc", "ti_properties.cc", + "ti_search.cc", "ti_stack.cc", "ti_redefine.cc", "ti_thread.cc", diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc index 3cba81771c..90467db8f6 100644 --- a/runtime/openjdkjvmti/OpenjdkJvmTi.cc +++ b/runtime/openjdkjvmti/OpenjdkJvmTi.cc @@ -51,11 +51,13 @@ #include "ti_class.h" #include "ti_field.h" #include "ti_heap.h" +#include "ti_jni.h" #include "ti_method.h" #include "ti_monitor.h" #include "ti_object.h" #include "ti_properties.h" #include "ti_redefine.h" +#include "ti_search.h" #include "ti_stack.h" #include "ti_thread.h" #include "ti_threadgroup.h" @@ -801,11 +803,11 @@ class JvmtiFunctions { } static jvmtiError SetJNIFunctionTable(jvmtiEnv* env, const jniNativeInterface* function_table) { - return ERR(NOT_IMPLEMENTED); + return JNIUtil::SetJNIFunctionTable(env, function_table); } static jvmtiError GetJNIFunctionTable(jvmtiEnv* env, jniNativeInterface** function_table) { - return ERR(NOT_IMPLEMENTED); + return JNIUtil::GetJNIFunctionTable(env, function_table); } // TODO: This will require locking, so that an agent can't remove callbacks when we're dispatching @@ -1067,11 +1069,11 @@ class JvmtiFunctions { } static jvmtiError AddToBootstrapClassLoaderSearch(jvmtiEnv* env, const char* segment) { - return ERR(NOT_IMPLEMENTED); + return SearchUtil::AddToBootstrapClassLoaderSearch(env, segment); } static jvmtiError AddToSystemClassLoaderSearch(jvmtiEnv* env, const char* segment) { - return ERR(NOT_IMPLEMENTED); + return SearchUtil::AddToSystemClassLoaderSearch(env, segment); } static jvmtiError GetSystemProperties(jvmtiEnv* env, jint* count_ptr, char*** property_ptr) { @@ -1246,7 +1248,12 @@ class JvmtiFunctions { } static jvmtiError GetJLocationFormat(jvmtiEnv* env, jvmtiJlocationFormat* format_ptr) { - return ERR(NOT_IMPLEMENTED); + // Report BCI as jlocation format. We report dex bytecode indices. + if (format_ptr == nullptr) { + return ERR(NULL_POINTER); + } + *format_ptr = jvmtiJlocationFormat::JVMTI_JLOCATION_JVMBCI; + return ERR(NONE); } // TODO Remove this once events are working. diff --git a/runtime/openjdkjvmti/jvmti.h b/runtime/openjdkjvmti/jvmti.h index ee708cb193..de07c163fc 100644 --- a/runtime/openjdkjvmti/jvmti.h +++ b/runtime/openjdkjvmti/jvmti.h @@ -74,7 +74,7 @@ typedef jobject jthreadGroup; typedef jlong jlocation; struct _jrawMonitorID; typedef struct _jrawMonitorID *jrawMonitorID; -typedef struct JNINativeInterface_ jniNativeInterface; +typedef struct JNINativeInterface jniNativeInterface; /* Constants */ diff --git a/runtime/openjdkjvmti/ti_jni.cc b/runtime/openjdkjvmti/ti_jni.cc new file mode 100644 index 0000000000..88f0395ba5 --- /dev/null +++ b/runtime/openjdkjvmti/ti_jni.cc @@ -0,0 +1,91 @@ +/* Copyright (C) 2017 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 "ti_jni.h" + +#include "jni.h" + +#include "art_jvmti.h" +#include "base/mutex.h" +#include "java_vm_ext.h" +#include "jni_env_ext.h" +#include "runtime.h" +#include "thread-inl.h" + +namespace openjdkjvmti { + +jvmtiError JNIUtil::SetJNIFunctionTable(jvmtiEnv* env ATTRIBUTE_UNUSED, + const jniNativeInterface* function_table) { + // While we supporting setting null (which will reset the table), the spec says no. + if (function_table == nullptr) { + return ERR(NULL_POINTER); + } + + art::JNIEnvExt::SetTableOverride(function_table); + return ERR(NONE); +} + +jvmtiError JNIUtil::GetJNIFunctionTable(jvmtiEnv* env, jniNativeInterface** function_table) { + if (function_table == nullptr) { + return ERR(NULL_POINTER); + } + + // We use the generic JNIEnvExt::GetFunctionTable instead of querying a specific JNIEnv, as + // this has to work in the start phase. + + // Figure out which table is current. Conservatively assume check-jni is off. + bool check_jni = false; + art::Runtime* runtime = art::Runtime::Current(); + if (runtime != nullptr && runtime->GetJavaVM() != nullptr) { + check_jni = runtime->GetJavaVM()->IsCheckJniEnabled(); + } + + // Get that table. + const JNINativeInterface* current_table; + { + art::MutexLock mu(art::Thread::Current(), *art::Locks::jni_function_table_lock_); + current_table = art::JNIEnvExt::GetFunctionTable(check_jni); + } + + // Allocate memory and copy the table. + unsigned char* data; + jvmtiError data_result = env->Allocate(sizeof(JNINativeInterface), &data); + if (data_result != ERR(NONE)) { + return data_result; + } + memcpy(data, current_table, sizeof(JNINativeInterface)); + + *function_table = reinterpret_cast<JNINativeInterface*>(data); + + return ERR(NONE); +} + +} // namespace openjdkjvmti diff --git a/runtime/openjdkjvmti/ti_jni.h b/runtime/openjdkjvmti/ti_jni.h new file mode 100644 index 0000000000..906aab0667 --- /dev/null +++ b/runtime/openjdkjvmti/ti_jni.h @@ -0,0 +1,58 @@ +/* Copyright (C) 2017 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. + */ + +#ifndef ART_RUNTIME_OPENJDKJVMTI_TI_JNI_H_ +#define ART_RUNTIME_OPENJDKJVMTI_TI_JNI_H_ + +#include "jni.h" +#include "jvmti.h" + +namespace openjdkjvmti { + +// Note: Currently, JNI function table changes are sensitive to the order of operations wrt/ +// CheckJNI. If an agent sets the function table, and a program than late-enables CheckJNI, +// CheckJNI will not be working (as the agent will forward to the non-CheckJNI table). +// +// This behavior results from our usage of the function table to avoid a check of the +// CheckJNI flag. A future implementation may install on loading of this plugin an +// intermediate function table that explicitly checks the flag, so that switching CheckJNI +// is transparently handled. + +class JNIUtil { + public: + static jvmtiError SetJNIFunctionTable(jvmtiEnv* env, const jniNativeInterface* function_table); + + static jvmtiError GetJNIFunctionTable(jvmtiEnv* env, jniNativeInterface** function_table); +}; + +} // namespace openjdkjvmti + +#endif // ART_RUNTIME_OPENJDKJVMTI_TI_JNI_H_ diff --git a/runtime/openjdkjvmti/ti_search.cc b/runtime/openjdkjvmti/ti_search.cc new file mode 100644 index 0000000000..913d2b6a74 --- /dev/null +++ b/runtime/openjdkjvmti/ti_search.cc @@ -0,0 +1,122 @@ +/* Copyright (C) 2017 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 "ti_search.h" + +#include "jni.h" + +#include "art_jvmti.h" +#include "base/macros.h" +#include "class_linker.h" +#include "dex_file.h" +#include "runtime.h" +#include "scoped_thread_state_change-inl.h" +#include "ScopedLocalRef.h" + +namespace openjdkjvmti { + +jvmtiError SearchUtil::AddToBootstrapClassLoaderSearch(jvmtiEnv* env ATTRIBUTE_UNUSED, + const char* segment) { + art::Runtime* current = art::Runtime::Current(); + if (current == nullptr) { + return ERR(WRONG_PHASE); + } + if (current->GetClassLinker() == nullptr) { + // TODO: Support boot classpath change in OnLoad. + return ERR(WRONG_PHASE); + } + if (segment == nullptr) { + return ERR(NULL_POINTER); + } + + std::string error_msg; + std::vector<std::unique_ptr<const art::DexFile>> dex_files; + if (!art::DexFile::Open(segment, segment, true, &error_msg, &dex_files)) { + LOG(WARNING) << "Could not open " << segment << " for boot classpath extension: " << error_msg; + return ERR(ILLEGAL_ARGUMENT); + } + + art::ScopedObjectAccess soa(art::Thread::Current()); + for (std::unique_ptr<const art::DexFile>& dex_file : dex_files) { + current->GetClassLinker()->AppendToBootClassPath(art::Thread::Current(), *dex_file.release()); + } + + return ERR(NONE); +} + +jvmtiError SearchUtil::AddToSystemClassLoaderSearch(jvmtiEnv* jvmti_env ATTRIBUTE_UNUSED, + const char* segment) { + if (segment == nullptr) { + return ERR(NULL_POINTER); + } + + art::Runtime* current = art::Runtime::Current(); + if (current == nullptr) { + return ERR(WRONG_PHASE); + } + jobject sys_class_loader = current->GetSystemClassLoader(); + if (sys_class_loader == nullptr) { + // TODO: Support classpath change in OnLoad. + return ERR(WRONG_PHASE); + } + + // We'll use BaseDexClassLoader.addDexPath, as it takes care of array resizing etc. As a downside, + // exceptions are swallowed. + + art::Thread* self = art::Thread::Current(); + JNIEnv* env = self->GetJniEnv(); + if (!env->IsInstanceOf(sys_class_loader, + art::WellKnownClasses::dalvik_system_BaseDexClassLoader)) { + return ERR(INTERNAL); + } + + jmethodID add_dex_path_id = env->GetMethodID( + art::WellKnownClasses::dalvik_system_BaseDexClassLoader, + "addDexPath", + "(Ljava/lang/String;)V"); + if (add_dex_path_id == nullptr) { + return ERR(INTERNAL); + } + + ScopedLocalRef<jstring> dex_path(env, env->NewStringUTF(segment)); + if (dex_path.get() == nullptr) { + return ERR(INTERNAL); + } + env->CallVoidMethod(sys_class_loader, add_dex_path_id, dex_path.get()); + + if (env->ExceptionCheck()) { + env->ExceptionClear(); + return ERR(ILLEGAL_ARGUMENT); + } + return ERR(NONE); +} + +} // namespace openjdkjvmti diff --git a/runtime/openjdkjvmti/ti_search.h b/runtime/openjdkjvmti/ti_search.h new file mode 100644 index 0000000000..6a52e80405 --- /dev/null +++ b/runtime/openjdkjvmti/ti_search.h @@ -0,0 +1,48 @@ +/* Copyright (C) 2017 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. + */ + +#ifndef ART_RUNTIME_OPENJDKJVMTI_TI_SEARCH_H_ +#define ART_RUNTIME_OPENJDKJVMTI_TI_SEARCH_H_ + +#include "jvmti.h" + +namespace openjdkjvmti { + +class SearchUtil { + public: + static jvmtiError AddToBootstrapClassLoaderSearch(jvmtiEnv* env, const char* segment); + + static jvmtiError AddToSystemClassLoaderSearch(jvmtiEnv* env, const char* segment); +}; + +} // namespace openjdkjvmti + +#endif // ART_RUNTIME_OPENJDKJVMTI_TI_SEARCH_H_ |