1 /* 2 * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 #include <stdio.h> 25 #include <string.h> 26 #include "jvmti.h" 27 #include "jni.h" 28 #include "jvmti_common.hpp" 29 30 #ifdef __cplusplus 31 extern "C" { 32 #endif 33 34 static jvmtiEnv *jvmti = nullptr; 35 36 37 JNIEXPORT jint JNICALL 38 Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { 39 jint res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1); 40 if (res != JNI_OK || jvmti == nullptr) { 41 LOG("GetEnv failed, res = %d", (int)res); 42 return JNI_ERR; 43 } 44 45 jvmtiCapabilities caps; 46 memset(&caps, 0, sizeof(caps)); 47 caps.can_access_local_variables = 1; 48 jvmtiError err = jvmti->AddCapabilities(&caps); 49 if (err != JVMTI_ERROR_NONE) { 50 LOG("AddCapabilities failed: %s (%d)\n", TranslateError(err), err); 51 return JNI_ERR; 52 } 53 54 return JNI_OK; 55 } 56 57 static void log_value(JNIEnv *jni, jobject value) { 58 jclass cls = jni->GetObjectClass(value); 59 if (cls == nullptr) { 60 LOG("ERROR: value class is NULL\n"); 61 return; 62 } 63 64 char* sig = nullptr; 65 check_jvmti_error(jvmti->GetClassSignature(cls, &sig, nullptr), "GetClassSignature"); 66 67 LOG(" - the value class: %s\n", sig); 68 jvmti->Deallocate((unsigned char *)sig); 69 } 70 71 static jobject get_local(JNIEnv *jni, jthread thread, jint depth, jint slot) { 72 LOG("GetLocalObject for slot %d...\n", (int)slot); 73 jobject value = nullptr; 74 check_jvmti_error(jvmti->GetLocalObject(thread, depth, slot, &value), "GetLocalObject"); 75 76 log_value(jni, value); 77 78 return value; 79 } 80 81 static void set_local(jthread thread, jint depth, jint slot, jobject value) { 82 LOG("SetLocalObject for slot %d...\n", (int)slot); 83 check_jvmti_error(jvmti->SetLocalObject(thread, depth, slot, value), "SetLocalObject"); 84 } 85 86 static jobject get_this(JNIEnv *jni, jthread thread, jint depth) { 87 LOG("GetLocalInstance...\n"); 88 jobject value = nullptr; 89 check_jvmti_error(jvmti->GetLocalInstance(thread, depth, &value), "GetLocalInstance"); 90 91 log_value(jni, value); 92 93 return value; 94 } 95 96 JNIEXPORT jboolean JNICALL 97 Java_ValueGetSetLocal_nTestLocals(JNIEnv *jni, jclass thisClass, jthread thread) { 98 bool result = true; 99 const jint depth = 1; 100 101 jobject obj0 = get_local(jni, thread, depth, 0); 102 jobject obj1 = get_local(jni, thread, depth, 1); 103 jobject obj2 = get_local(jni, thread, depth, 2); 104 jobject obj3 = get_local(jni, thread, depth, 3); 105 jobject obj_this = get_this(jni, thread, depth); 106 107 // obj0 is expected to be equal "this" 108 if (!jni->IsSameObject(obj0, obj_this)) { 109 LOG("ERROR: obj0 != obj_this\n"); 110 result = false; 111 } 112 // obj3 is expected to be equal obj2 113 if (!jni->IsSameObject(obj3, obj2)) { 114 LOG("ERROR: obj3 != obj2\n"); 115 result = false; 116 } 117 118 // set obj3 = obj1 119 set_local(thread, depth, 3, obj1); 120 121 return result ? JNI_TRUE : JNI_FALSE; 122 } 123 124 #ifdef __cplusplus 125 } 126 #endif 127