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