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 PASSED 0 33 #define STATUS_FAILED 2 34 #define TranslateError(err) "JVMTI error" 35 36 static jint result = PASSED; 37 static jvmtiEnv *jvmti = NULL; 38 static jvmtiCapabilities caps; 39 static const int ByteSlot = 0; 40 static const int ObjSlot = 1; 41 static const int DblSlot = 2; 42 static const int IntSlot = 4; 43 static const int InvalidSlot = 5; 44 45 static void 46 test_int(jvmtiEnv *jvmti, jthread thr, int depth, int slot, const char* exp_type) { 47 jint val = 0; 48 jvmtiError err = jvmti->GetLocalInt(thr, depth, slot, &val); 49 50 printf(" GetLocalInt: %s (%d)\n", TranslateError(err), err); 51 if (err != JVMTI_ERROR_NONE) { 52 printf(" FAIL: GetLocalInt failed to get value from a local %s\n", exp_type); 53 result = STATUS_FAILED; 54 } else { 55 printf(" GetLocalInt got value from a local %s as expected\n", exp_type); 56 } 57 } 58 59 static void 60 test_float(jvmtiEnv *jvmti, jthread thr, int depth, int slot, const char* exp_type) { 61 jfloat val = 0.0; 62 jvmtiError err = jvmti->GetLocalFloat(thr, depth, slot, &val); 63 64 printf(" GetLocalFloat: %s (%d)\n", TranslateError(err), err); 65 if (err != JVMTI_ERROR_NONE) { 66 printf(" FAIL: GetLocalFloat failed to get value from a local %s\n", exp_type); 67 result = STATUS_FAILED; 68 } else { 69 printf(" GetLocalFloat got value from a local %s as expected\n", exp_type); 70 } 71 } 72 73 static void 74 test_long(jvmtiEnv *jvmti, jthread thr, int depth, int slot, const char* exp_type) { 75 jlong val = 0L; 76 jvmtiError err = jvmti->GetLocalLong(thr, depth, slot, &val); 77 78 printf(" GetLocalLong: %s (%d)\n", TranslateError(err), err); 79 if (err != JVMTI_ERROR_NONE) { 80 printf(" FAIL: GetLocalLong failed to get value from a local %s\n", exp_type); 81 result = STATUS_FAILED; 82 } else { 83 printf(" GetLocalLong got value from a local %s as expected\n", exp_type); 84 } 85 } 86 87 static void 88 test_double(jvmtiEnv *jvmti, jthread thr, int depth, int slot, const char* exp_type) { 89 jdouble val = 0.0D; 90 jvmtiError err = jvmti->GetLocalDouble(thr, depth, slot, &val); 91 92 printf(" GetLocalDouble: %s (%d)\n", TranslateError(err), err); 93 if (err != JVMTI_ERROR_NONE) { 94 printf(" FAIL: GetLocalDouble failed to get value from a local %s\n", exp_type); 95 result = STATUS_FAILED; 96 } else { 97 printf(" GetLocalDouble got value from a local %s as expected\n", exp_type); 98 } 99 } 100 101 static void 102 test_object(jvmtiEnv *jvmti, jthread thr, int depth, int slot, const char* exp_type) { 103 jobject obj = NULL; 104 jvmtiError err = jvmti->GetLocalObject(thr, depth, slot, &obj); 105 106 printf(" GetLocalObject: %s (%d)\n", TranslateError(err), err); 107 if (err != JVMTI_ERROR_NONE) { 108 printf(" FAIL: GetLocalObject failed to get value from a local %s\n", exp_type); 109 result = STATUS_FAILED; 110 } else { 111 printf(" GetLocalObject got value from a local %s as expected\n", exp_type); 112 } 113 } 114 115 static void 116 test_int_inv_slot(jvmtiEnv *jvmti, jthread thr, int depth, int slot, const char* exp_type) { 117 jint val = 0; 118 jvmtiError err = jvmti->GetLocalInt(thr, depth, slot, &val); 119 120 printf(" GetLocalInt: %s (%d)\n", TranslateError(err), err); 121 if (err != JVMTI_ERROR_INVALID_SLOT) { 122 printf(" FAIL: GetLocalInt failed to return JVMTI_ERROR_INVALID_SLOT for local %s\n", exp_type); 123 result = STATUS_FAILED; 124 } else { 125 printf(" GetLocalInt returned JVMTI_ERROR_INVALID_SLOT for local %s as expected\n", exp_type); 126 } 127 } 128 129 static void 130 test_float_inv_slot(jvmtiEnv *jvmti, jthread thr, int depth, int slot, const char* exp_type) { 131 jfloat val = 0.0; 132 jvmtiError err = jvmti->GetLocalFloat(thr, depth, slot, &val); 133 134 printf(" GetLocalFloat: %s (%d)\n", TranslateError(err), err); 135 if (err != JVMTI_ERROR_INVALID_SLOT) { 136 printf(" FAIL: GetLocalFloat failed to return JVMTI_ERROR_INVALID_SLOT for local %s\n", exp_type); 137 result = STATUS_FAILED; 138 } else { 139 printf(" GetLocalFloat returned JVMTI_ERROR_INVALID_SLOT for local %s as expected\n", exp_type); 140 } 141 } 142 143 static void 144 test_long_inv_slot(jvmtiEnv *jvmti, jthread thr, int depth, int slot, const char* exp_type) { 145 jlong val = 0L; 146 jvmtiError err = jvmti->GetLocalLong(thr, depth, slot, &val); 147 148 printf(" GetLocalLong: %s (%d)\n", TranslateError(err), err); 149 if (err != JVMTI_ERROR_INVALID_SLOT) { 150 printf(" FAIL: GetLocalLong failed to return JVMTI_ERROR_INVALID_SLOT for local %s\n", exp_type); 151 result = STATUS_FAILED; 152 } else { 153 printf(" GetLocalLong returned JVMTI_ERROR_INVALID_SLOT for local %s as expected\n", exp_type); 154 } 155 } 156 157 static void 158 test_double_inv_slot(jvmtiEnv *jvmti, jthread thr, int depth, int slot, const char* exp_type) { 159 jdouble val = 0.0D; 160 jvmtiError err = jvmti->GetLocalDouble(thr, depth, slot, &val); 161 162 printf(" GetLocalDouble: %s (%d)\n", TranslateError(err), err); 163 if (err != JVMTI_ERROR_INVALID_SLOT) { 164 printf(" FAIL: GetLocalDouble failed to return JVMTI_ERROR_INVALID_SLOT for local %s\n", exp_type); 165 result = STATUS_FAILED; 166 } else { 167 printf(" GetLocalDouble returned JVMTI_ERROR_INVALID_SLOT for local %s as expected\n", exp_type); 168 } 169 } 170 171 static void 172 test_object_inv_slot(jvmtiEnv *jvmti, jthread thr, int depth, int slot, const char* exp_type) { 173 jobject obj = NULL; 174 jvmtiError err = jvmti->GetLocalObject(thr, depth, slot, &obj); 175 176 printf(" GetLocalObject: %s (%d)\n", TranslateError(err), err); 177 if (err != JVMTI_ERROR_INVALID_SLOT) { 178 printf(" FAIL: GetLocalObject failed to return JVMTI_ERROR_INVALID_SLOT for local %s\n", exp_type); 179 result = STATUS_FAILED; 180 } else { 181 printf(" GetLocalObject returned JVMTI_ERROR_INVALID_SLOT for local %s as expected\n", exp_type); 182 } 183 } 184 185 static void 186 test_int_type_mismatch(jvmtiEnv *jvmti, jthread thr, int depth, int slot, const char* exp_type) { 187 jint val = 0; 188 jvmtiError err = jvmti->GetLocalInt(thr, depth, slot, &val); 189 190 printf(" GetLocalInt: %s (%d)\n", TranslateError(err), err); 191 if (err != JVMTI_ERROR_TYPE_MISMATCH) { 192 printf(" FAIL: GetLocalInt failed to return JVMTI_ERROR_TYPE_MISMATCH for local %s\n", exp_type); 193 result = STATUS_FAILED; 194 } else { 195 printf(" GetLocalInt returned JVMTI_ERROR_TYPE_MISMATCH for local %s as expected\n", exp_type); 196 } 197 } 198 199 static void 200 test_float_type_mismatch(jvmtiEnv *jvmti, jthread thr, int depth, int slot, const char* exp_type) { 201 jfloat val = 0.0; 202 jvmtiError err = jvmti->GetLocalFloat(thr, depth, slot, &val); 203 204 printf(" GetLocalFloat: %s (%d)\n", TranslateError(err), err); 205 if (err != JVMTI_ERROR_TYPE_MISMATCH) { 206 printf(" FAIL: GetLocalFloat failed to return JVMTI_ERROR_TYPE_MISMATCH for local %s\n", exp_type); 207 result = STATUS_FAILED; 208 } else { 209 printf(" GetLocalFloat returned JVMTI_ERROR_TYPE_MISMATCH for local %s as expected\n", exp_type); 210 } 211 } 212 213 static void 214 test_long_type_mismatch(jvmtiEnv *jvmti, jthread thr, int depth, int slot, const char* exp_type) { 215 jlong val = 0L; 216 jvmtiError err = jvmti->GetLocalLong(thr, depth, slot, &val); 217 218 printf(" GetLocalLong: %s (%d)\n", TranslateError(err), err); 219 if (err != JVMTI_ERROR_TYPE_MISMATCH) { 220 printf(" FAIL: GetLocalLong failed to return JVMTI_ERROR_TYPE_MISMATCH for local %s\n", exp_type); 221 result = STATUS_FAILED; 222 } else { 223 printf(" GetLocalLong returned JVMTI_ERROR_TYPE_MISMATCH for local %s as expected\n", exp_type); 224 } 225 } 226 227 static void 228 test_double_type_mismatch(jvmtiEnv *jvmti, jthread thr, int depth, int slot, const char* exp_type) { 229 jdouble val = 0.0D; 230 jvmtiError err = jvmti->GetLocalDouble(thr, depth, slot, &val); 231 232 printf(" GetLocalDouble: %s (%d)\n", TranslateError(err), err); 233 if (err != JVMTI_ERROR_TYPE_MISMATCH) { 234 printf(" FAIL: GetLocalDouble failed to return JVMTI_ERROR_TYPE_MISMATCH for local %s\n", exp_type); 235 result = STATUS_FAILED; 236 } else { 237 printf(" GetLocalDouble returned JVMTI_ERROR_TYPE_MISMATCH for local %s as expected\n", exp_type); 238 } 239 } 240 241 static void 242 test_object_type_mismatch(jvmtiEnv *jvmti, jthread thr, int depth, int slot, const char* exp_type) { 243 jobject obj = NULL; 244 jvmtiError err = jvmti->GetLocalObject(thr, depth, slot, &obj); 245 246 printf(" GetLocalObject: %s (%d)\n", TranslateError(err), err); 247 if (err != JVMTI_ERROR_TYPE_MISMATCH) { 248 printf(" FAIL: GetLocalObject failed to return JVMTI_ERROR_TYPE_MISMATCH for local %s\n", exp_type); 249 result = STATUS_FAILED; 250 } else { 251 printf(" GetLocalObject returned JVMTI_ERROR_TYPE_MISMATCH for local %s as expected\n", exp_type); 252 } 253 } 254 255 static void 256 test_local_byte(jvmtiEnv *jvmti, jthread thr, int depth, int slot) { 257 printf("\n test_local_byte: BEGIN\n\n"); 258 259 test_int(jvmti, thr, depth, slot, "byte"); 260 test_long_inv_slot(jvmti, thr, depth, slot, "byte"); 261 test_float(jvmti, thr, depth, slot, "byte"); 262 test_double_inv_slot(jvmti, thr, depth, slot, "byte"); 263 test_object_type_mismatch(jvmti, thr, depth, slot, "byte"); 264 265 printf("\n test_local_byte: END\n\n"); 266 } 267 268 static void 269 test_local_object(jvmtiEnv *jvmti, jthread thr, int depth, int slot) { 270 printf("\n test_local_object: BEGIN\n\n"); 271 272 test_int_type_mismatch(jvmti, thr, depth, slot, "object"); 273 test_long_type_mismatch(jvmti, thr, depth, slot, "object"); 274 test_float_type_mismatch(jvmti, thr, depth, slot, "object"); 275 test_double_type_mismatch(jvmti, thr, depth, slot, "object"); 276 test_object(jvmti, thr, depth, slot, "object"); 277 278 printf("\n test_local_object: END\n\n"); 279 } 280 281 static void 282 test_local_double(jvmtiEnv *jvmti, jthread thr, int depth, int slot) { 283 printf("\n test_local_double: BEGIN\n\n"); 284 285 test_int(jvmti, thr, depth, slot, "double"); 286 test_long(jvmti, thr, depth, slot, "double"); 287 test_float(jvmti, thr, depth, slot, "double"); 288 test_double(jvmti, thr, depth, slot, "double"); 289 test_object_type_mismatch(jvmti, thr, depth, slot, "double"); 290 291 printf("\n test_local_double: END\n\n"); 292 } 293 294 static void 295 test_local_integer(jvmtiEnv *jvmti, jthread thr, int depth, int slot) { 296 printf("\n test_local_integer: BEGIN\n\n"); 297 298 test_int(jvmti, thr, depth, slot, "int"); 299 test_long_inv_slot(jvmti, thr, depth, slot, "int"); 300 test_float(jvmti, thr, depth, slot, "int"); 301 test_double_inv_slot(jvmti, thr, depth, slot, "int"); 302 test_object_type_mismatch(jvmti, thr, depth, slot, "double"); 303 304 printf("\n test_local_integer: END\n\n"); 305 } 306 307 static void 308 test_local_invalid(jvmtiEnv *jvmti, jthread thr, int depth, int slot) { 309 printf("\n test_local_invalid: BEGIN\n\n"); 310 311 test_int_inv_slot(jvmti, thr, depth, slot, "invalid"); 312 test_long_inv_slot(jvmti, thr, depth, slot, "invalid"); 313 test_float_inv_slot(jvmti, thr, depth, slot, "invalid"); 314 test_double_inv_slot(jvmti, thr, depth, slot, "invalid"); 315 test_object_inv_slot(jvmti, thr, depth, slot, "invalid"); 316 317 printf("\n test_local_invalid: END\n\n"); 318 } 319 320 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 321 jint res; 322 jvmtiError err; 323 324 res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1); 325 if (res != JNI_OK || jvmti == NULL) { 326 printf("Wrong result of a valid call to GetEnv!\n"); 327 return JNI_ERR; 328 } 329 caps.can_access_local_variables = 1; 330 331 err = jvmti->AddCapabilities(&caps); 332 if (err != JVMTI_ERROR_NONE) { 333 printf("AddCapabilities: unexpected error: %s (%d)\n", TranslateError(err), err); 334 return JNI_ERR; 335 } 336 err = jvmti->GetCapabilities(&caps); 337 if (err != JVMTI_ERROR_NONE) { 338 printf("GetCapabilities: unexpected error: %s (%d)\n", TranslateError(err), err); 339 return JNI_ERR; 340 } 341 if (!caps.can_access_local_variables) { 342 printf("Warning: Access to local variables is not implemented\n"); 343 return JNI_ERR; 344 } 345 return JNI_OK; 346 } 347 348 JNIEXPORT jint JNICALL 349 Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { 350 return Agent_Initialize(jvm, options, reserved); 351 } 352 353 JNIEXPORT jint JNICALL 354 Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) { 355 return Agent_Initialize(jvm, options, reserved); 356 } 357 358 JNIEXPORT void JNICALL 359 Java_GetLocalVars_testLocals(JNIEnv *env, jclass cls, jobject thread) { 360 static const char* METHOD_NAME = "staticMeth"; 361 static const char* METHOD_SIGN = "(BLjava/lang/Object;DI)I"; 362 static const int Depth = 1; 363 jmethodID mid = NULL; 364 365 if (jvmti == NULL) { 366 printf("JVMTI client was not properly loaded!\n"); 367 result = STATUS_FAILED; 368 return; 369 } 370 371 if (!caps.can_access_local_variables) { 372 return; 373 } 374 375 mid = env->GetStaticMethodID(cls, METHOD_NAME, METHOD_SIGN); 376 if (mid == NULL) { 377 printf("Cannot find Method ID for %s%s\n", METHOD_NAME, METHOD_SIGN); 378 result = STATUS_FAILED; 379 return; 380 } 381 382 test_local_byte(jvmti, thread, Depth, ByteSlot); 383 test_local_object(jvmti, thread, Depth, ObjSlot); 384 test_local_double(jvmti, thread, Depth, DblSlot); 385 test_local_integer(jvmti, thread, Depth, IntSlot); 386 test_local_invalid(jvmti, thread, Depth, InvalidSlot); 387 } 388 389 JNIEXPORT jint JNICALL 390 Java_GetLocalVars_getStatus(JNIEnv *env, jclass cls) { 391 return result; 392 } 393 394 #ifdef __cplusplus 395 } 396 #endif