1 /* 2 * Copyright (c) 2003, 2018, 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 28 #ifdef __cplusplus 29 extern "C" { 30 #endif 31 32 #define STATUS_PASSED 0 33 #define STATUS_FAILED 2 34 #define TranslateError(err) "JVMTI error" 35 36 static jint result = STATUS_PASSED; 37 static jvmtiEnv *jvmti = NULL; 38 39 #define DECL_TEST_FUNC(type, Type) \ 40 static void \ 41 test_##type(jthread thr, int depth, int slot, const char* exp_type) { \ 42 j##type val; \ 43 jvmtiError err = jvmti->GetLocal##Type(thr, depth, slot, &val); \ 44 \ 45 printf(" GetLocal%s: %s (%d)\n", #Type, TranslateError(err), err); \ 46 if (err != JVMTI_ERROR_NONE) { \ 47 printf(" FAIL: GetLocal%s failed to get value from a local %s\n", #Type, exp_type); \ 48 result = STATUS_FAILED; \ 49 } else { \ 50 printf(" GetLocal%s got value from a local %s as expected\n", #Type, exp_type); \ 51 } \ 52 } 53 54 #define DECL_TEST_INV_SLOT_FUNC(type, Type) \ 55 static void \ 56 test_##type##_inv_slot(jthread thr, int depth, int slot, const char* exp_type) { \ 57 j##type val; \ 58 jvmtiError err = jvmti->GetLocal##Type(thr, depth, slot, &val); \ 59 \ 60 printf(" GetLocal%s: %s (%d)\n", #Type, TranslateError(err), err); \ 61 if (err != JVMTI_ERROR_INVALID_SLOT) { \ 62 printf(" FAIL: GetLocal%s failed to return JVMTI_ERROR_INVALID_SLOT for local %s\n", #Type, exp_type); \ 63 result = STATUS_FAILED; \ 64 } else { \ 65 printf(" GetLocal%s returned JVMTI_ERROR_INVALID_SLOT for local %s as expected\n", #Type, exp_type); \ 66 } \ 67 } 68 69 #define DECL_TEST_TYPE_MISMATCH_FUNC(type, Type) \ 70 static void \ 71 test_##type##_type_mismatch(jthread thr, int depth, int slot, const char* exp_type) { \ 72 j##type val; \ 73 jvmtiError err = jvmti->GetLocal##Type(thr, depth, slot, &val); \ 74 \ 75 printf(" GetLocal%s: %s (%d)\n", #Type, TranslateError(err), err); \ 76 if (err != JVMTI_ERROR_TYPE_MISMATCH) { \ 77 printf(" FAIL: GetLocal%s failed to return JVMTI_ERROR_TYPE_MISMATCH for local %s\n", #Type, exp_type); \ 78 result = STATUS_FAILED; \ 79 } else { \ 80 printf(" GetLocal%s returned JVMTI_ERROR_TYPE_MISMATCH for local %s as expected\n", #Type, exp_type); \ 81 } \ 82 } 83 84 DECL_TEST_FUNC(int, Int); 85 DECL_TEST_FUNC(float, Float); 86 DECL_TEST_FUNC(long, Long); 87 DECL_TEST_FUNC(double, Double); 88 DECL_TEST_FUNC(object, Object); 89 90 DECL_TEST_INV_SLOT_FUNC(int, Int); 91 DECL_TEST_INV_SLOT_FUNC(float, Float); 92 93 DECL_TEST_TYPE_MISMATCH_FUNC(int, Int); 94 DECL_TEST_TYPE_MISMATCH_FUNC(float, Float); 95 DECL_TEST_TYPE_MISMATCH_FUNC(long, Long); 96 DECL_TEST_TYPE_MISMATCH_FUNC(double, Double); 97 DECL_TEST_TYPE_MISMATCH_FUNC(object, Object); 98 99 static void 100 test_local_byte(jthread thr, int depth, int slot) { 101 printf("\n test_local_byte: BEGIN\n\n"); 102 103 test_int(thr, depth, slot, "byte"); 104 test_long_inv_slot(thr, depth, slot, "byte"); 105 test_float(thr, depth, slot, "byte"); 106 test_double_inv_slot(thr, depth, slot, "byte"); 107 test_object_type_mismatch(thr, depth, slot, "byte"); 108 109 printf("\n test_local_byte: END\n\n"); 110 } 111 112 static void 113 test_local_object(jthread thr, int depth, int slot) { 114 printf("\n test_local_object: BEGIN\n\n"); 115 116 test_int_type_mismatch(thr, depth, slot, "object"); 117 test_long_type_mismatch(thr, depth, slot, "object"); 118 test_float_type_mismatch(thr, depth, slot, "object"); 119 test_double_type_mismatch(thr, depth, slot, "object"); 120 test_object(thr, depth, slot, "object"); 121 122 printf("\n test_local_object: END\n\n"); 123 } 124 125 static void 126 test_local_double(jthread thr, int depth, int slot) { 127 printf("\n test_local_double: BEGIN\n\n"); 128 129 test_int(thr, depth, slot, "double"); 130 test_long(thr, depth, slot, "double"); 131 test_float(thr, depth, slot, "double"); 132 test_double(thr, depth, slot, "double"); 133 test_object_type_mismatch(thr, depth, slot, "double"); 134 135 printf("\n test_local_double: END\n\n"); 136 } 137 138 static void 139 test_local_integer(jthread thr, int depth, int slot) { 140 printf("\n test_local_integer: BEGIN\n\n"); 141 142 test_int(thr, depth, slot, "int"); 143 test_float(thr, depth, slot, "int"); 144 test_object_type_mismatch(thr, depth, slot, "double"); 145 146 printf("\n test_local_integer: END\n\n"); 147 } 148 149 static void 150 test_local_invalid(jthread thr, int depth, int slot) { 151 printf("\n test_local_invalid: BEGIN\n\n"); 152 153 test_int_inv_slot(thr, depth, slot, "invalid"); 154 test_long_inv_slot(thr, depth, slot, "invalid"); 155 test_float_inv_slot(thr, depth, slot, "invalid"); 156 test_double_inv_slot(thr, depth, slot, "invalid"); 157 158 printf("\n test_local_invalid: END\n\n"); 159 } 160 161 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 162 jint res; 163 jvmtiError err; 164 static jvmtiCapabilities caps; 165 166 res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_9); 167 if (res != JNI_OK || jvmti == NULL) { 168 printf("Wrong result of a valid call to GetEnv!\n"); 169 return JNI_ERR; 170 } 171 caps.can_access_local_variables = 1; 172 173 err = jvmti->AddCapabilities(&caps); 174 if (err != JVMTI_ERROR_NONE) { 175 printf("AddCapabilities: unexpected error: %s (%d)\n", TranslateError(err), err); 176 return JNI_ERR; 177 } 178 err = jvmti->GetCapabilities(&caps); 179 if (err != JVMTI_ERROR_NONE) { 180 printf("GetCapabilities: unexpected error: %s (%d)\n", TranslateError(err), err); 181 return JNI_ERR; 182 } 183 if (!caps.can_access_local_variables) { 184 printf("Warning: Access to local variables is not implemented\n"); 185 return JNI_ERR; 186 } 187 return JNI_OK; 188 } 189 190 JNIEXPORT jint JNICALL 191 Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { 192 return Agent_Initialize(jvm, options, reserved); 193 } 194 195 JNIEXPORT jint JNICALL 196 Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) { 197 return Agent_Initialize(jvm, options, reserved); 198 } 199 200 JNIEXPORT void JNICALL 201 Java_GetLocalVars_testLocals(JNIEnv *env, jclass cls, jobject thread) { 202 /* 203 * We test the JVMTI GetLocal<Type> for locals of the method: 204 * 205 * int staticMeth(byte byteArg, Object objArg, double dblArg, int intArg) { 206 * testLocals(Thread.currentThread()); 207 * { 208 * int intLoc = 9999; 209 * intArg = intLoc; 210 * } 211 * return intArg; 212 * } 213 */ 214 static const char* METHOD_NAME = "staticMeth"; 215 static const char* METHOD_SIGN = "(BLjava/lang/Object;DI)I"; 216 static const int Depth = 1; 217 static const int ByteSlot = 0; 218 static const int ObjSlot = 1; 219 static const int DblSlot = 2; 220 static const int IntSlot = 4; 221 static const int InvalidSlot = 5; 222 223 jmethodID mid = NULL; 224 225 if (jvmti == NULL) { 226 printf("JVMTI client was not properly loaded!\n"); 227 result = STATUS_FAILED; 228 return; 229 } 230 231 mid = env->GetStaticMethodID(cls, METHOD_NAME, METHOD_SIGN); 232 if (mid == NULL) { 233 printf("Cannot find Method ID for %s%s\n", METHOD_NAME, METHOD_SIGN); 234 result = STATUS_FAILED; 235 return; 236 } 237 238 test_local_byte(thread, Depth, ByteSlot); 239 test_local_object(thread, Depth, ObjSlot); 240 test_local_double(thread, Depth, DblSlot); 241 test_local_integer(thread, Depth, IntSlot); 242 test_local_invalid(thread, Depth, InvalidSlot); 243 } 244 245 JNIEXPORT jint JNICALL 246 Java_GetLocalVars_getStatus(JNIEnv *env, jclass cls) { 247 return result; 248 } 249 250 #ifdef __cplusplus 251 } 252 #endif