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 /* 25 */ 26 27 #include <stdio.h> 28 #include <string.h> 29 #include "jvmti.h" 30 #include "jni_tools.h" 31 #include "agent_common.h" 32 #include "JVMTITools.h" 33 34 extern "C" { 35 36 37 #define PASSED 0 38 #define STATUS_FAILED 2 39 40 static jvmtiEnv *jvmti = NULL; 41 static jvmtiCapabilities caps; 42 static jvmtiEventCallbacks callbacks; 43 static jint result = PASSED; 44 static jboolean printdump = JNI_FALSE; 45 static jmethodID mid = NULL; 46 static jvmtiLocalVariableEntry *table = NULL; 47 static jint entryCount = 0; 48 static jint methodExitCnt = -1; 49 50 void print_LocalVariableEntry(jvmtiLocalVariableEntry *lvt_elem) { 51 printf("\n Var name: %s, slot: %d", lvt_elem->name, lvt_elem->slot); 52 printf(", start_bci: %" LL "d", lvt_elem->start_location); 53 printf(", end_bci: %" LL "d", lvt_elem->start_location + lvt_elem->length); 54 printf(", signature: %s\n", lvt_elem->signature); 55 } 56 57 static void 58 test_locals(jvmtiEnv *jvmti, jthread thr, jlocation location) { 59 jvmtiError err; 60 jint intVal; 61 jlong longVal; 62 jfloat floatVal; 63 jdouble doubleVal; 64 jobject obj; 65 jint i; 66 67 for (i = 0; i < entryCount; i++) { 68 if (table[i].start_location > location || 69 table[i].start_location + table[i].length < location) { 70 continue; /* The local variable is not visible */ 71 } 72 print_LocalVariableEntry(&table[i]); 73 char sig = table[i].signature[0]; 74 75 if (sig == 'Z' || sig == 'B' || sig == 'C' || sig == 'S') { 76 sig = 'I'; // covered by GetLocalInt 77 } 78 err = jvmti->GetLocalInt(thr, 0, table[i].slot, &intVal); 79 printf(" GetLocalInt: %s (%d)\n", TranslateError(err), err); 80 if (err != JVMTI_ERROR_NONE && sig == 'I') { 81 printf("FAIL: GetLocalInt failed to get value of int\n"); 82 result = STATUS_FAILED; 83 } else if (err != JVMTI_ERROR_TYPE_MISMATCH && sig != 'I') { 84 printf("FAIL: GetLocalInt did not return JVMTI_ERROR_TYPE_MISMATCH for non-int\n"); 85 result = STATUS_FAILED; 86 } 87 88 err = jvmti->GetLocalLong(thr, 0, table[i].slot, &longVal); 89 printf(" GetLocalLong: %s (%d)\n", TranslateError(err), err); 90 if (err != JVMTI_ERROR_NONE && sig == 'J') { 91 printf("FAIL: GetLocalLong failed to get value of long\n"); 92 result = STATUS_FAILED; 93 } else if (err != JVMTI_ERROR_TYPE_MISMATCH && sig != 'J') { 94 printf("FAIL: GetLocalLong did not return JVMTI_ERROR_TYPE_MISMATCH for non-long\n"); 95 result = STATUS_FAILED; 96 } 97 98 err = jvmti->GetLocalFloat(thr, 0, table[i].slot, &floatVal); 99 printf(" GetLocalFloat: %s (%d)\n", TranslateError(err), err); 100 if (err != JVMTI_ERROR_NONE && table[i].signature[0] == 'F') { 101 printf("FAIL: GetLocalFloat failed to get value of float\n"); 102 result = STATUS_FAILED; 103 } else if (err != JVMTI_ERROR_TYPE_MISMATCH && table[i].signature[0] != 'F') { 104 printf("FAIL: GetLocalFloat did not return JVMTI_ERROR_TYPE_MISMATCH for non-float\n"); 105 result = STATUS_FAILED; 106 } 107 108 err = jvmti->GetLocalDouble(thr, 0, table[i].slot, &doubleVal); 109 printf(" GetLocalDouble: %s (%d)\n", TranslateError(err), err); 110 if (err != JVMTI_ERROR_NONE && table[i].signature[0] == 'D') { 111 printf("FAIL: GetLocalDouble failed to get value of double\n"); 112 result = STATUS_FAILED; 113 } else if (err != JVMTI_ERROR_TYPE_MISMATCH && table[i].signature[0] != 'D') { 114 printf("FAIL: GetLocalDouble did not return JVMTI_ERROR_TYPE_MISMATCH for non-double\n"); 115 result = STATUS_FAILED; 116 } 117 118 err = jvmti->GetLocalObject(thr, 0, table[i].slot, &obj); 119 printf(" GetLocalObject: %s (%d)\n", TranslateError(err), err); 120 if (err != JVMTI_ERROR_NONE && table[i].signature[0] == 'L') { 121 printf("FAIL: GetLocalObject failed to get value of object\n"); 122 result = STATUS_FAILED; 123 } else if (err != JVMTI_ERROR_TYPE_MISMATCH && table[i].signature[0] != 'L') { 124 printf("FAIL: GetLocalObject did not return JVMTI_ERROR_TYPE_MISMATCH for non-object\n"); 125 result = STATUS_FAILED; 126 } 127 } 128 } 129 130 static void JNICALL 131 MethodExit(jvmtiEnv *jvmti_env, 132 JNIEnv *env, 133 jthread thr, 134 jmethodID method, 135 jboolean was_poped_by_exception, 136 jvalue return_value) { 137 138 jvmtiError err; 139 jlocation location; 140 jmethodID frame_method = NULL; 141 142 if (mid != method) { 143 return; 144 } 145 err = jvmti->GetFrameLocation(thr, 0, &frame_method, &location); 146 if (err != JVMTI_ERROR_NONE) { 147 printf("\t failure: %s (%d)\n", TranslateError(err), err); 148 result = STATUS_FAILED; 149 return; 150 } 151 if (frame_method != method) { 152 printf("\t failure: GetFrameLocation returned wrong jmethodID\n"); 153 result = STATUS_FAILED; 154 return; 155 } 156 157 printf("\n MethodExit: BEGIN %d, Current frame bci: %" LL "d\n\n", 158 ++methodExitCnt, location); 159 160 test_locals(jvmti, thr, location); 161 162 printf("\n MethodExit: END %d\n\n", methodExitCnt); 163 fflush(stdout); 164 } 165 166 #ifdef STATIC_BUILD 167 JNIEXPORT jint JNICALL Agent_OnLoad_getlocal003(JavaVM *jvm, char *options, void *reserved) { 168 return Agent_Initialize(jvm, options, reserved); 169 } 170 JNIEXPORT jint JNICALL Agent_OnAttach_getlocal003(JavaVM *jvm, char *options, void *reserved) { 171 return Agent_Initialize(jvm, options, reserved); 172 } 173 JNIEXPORT jint JNI_OnLoad_getlocal003(JavaVM *jvm, char *options, void *reserved) { 174 return JNI_VERSION_1_8; 175 } 176 #endif 177 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 178 jint res; 179 jvmtiError err; 180 181 if (options != NULL && strcmp(options, "printdump") == 0) { 182 printdump = JNI_TRUE; 183 } 184 185 res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1); 186 if (res != JNI_OK || jvmti == NULL) { 187 printf("Wrong result of a valid call to GetEnv!\n"); 188 return JNI_ERR; 189 } 190 191 err = jvmti->GetPotentialCapabilities(&caps); 192 if (err != JVMTI_ERROR_NONE) { 193 printf("(GetPotentialCapabilities) unexpected error: %s (%d)\n", 194 TranslateError(err), err); 195 return JNI_ERR; 196 } 197 198 err = jvmti->AddCapabilities(&caps); 199 if (err != JVMTI_ERROR_NONE) { 200 printf("(AddCapabilities) unexpected error: %s (%d)\n", 201 TranslateError(err), err); 202 return JNI_ERR; 203 } 204 205 err = jvmti->GetCapabilities(&caps); 206 if (err != JVMTI_ERROR_NONE) { 207 printf("(GetCapabilities) unexpected error: %s (%d)\n", 208 TranslateError(err), err); 209 return JNI_ERR; 210 } 211 212 if (!caps.can_access_local_variables) { 213 printf("Warning: Access to local variables is not implemented\n"); 214 } else if (caps.can_generate_method_exit_events) { 215 callbacks.MethodExit = &MethodExit; 216 err = jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)); 217 if (err != JVMTI_ERROR_NONE) { 218 printf("(SetEventCallbacks) unexpected error: %s (%d)\n", 219 TranslateError(err), err); 220 return JNI_ERR; 221 } 222 } else { 223 printf("Warning: MethodExit event is not implemented\n"); 224 } 225 226 return JNI_OK; 227 } 228 229 JNIEXPORT void JNICALL 230 Java_nsk_jvmti_unit_GetLocalVariable_getlocal003_getMeth(JNIEnv *env, jclass cls) { 231 jvmtiError err; 232 233 if (jvmti == NULL) { 234 printf("JVMTI client was not properly loaded!\n"); 235 result = STATUS_FAILED; 236 return; 237 } 238 239 if (!caps.can_access_local_variables || 240 !caps.can_generate_method_exit_events) return; 241 242 mid = env->GetStaticMethodID(cls, "staticMeth", "(I)I"); 243 if (mid == NULL) { 244 printf("Cannot find Method ID for staticMeth\n"); 245 result = STATUS_FAILED; 246 return; 247 } 248 249 err = jvmti->GetLocalVariableTable(mid, &entryCount, &table); 250 if (err != JVMTI_ERROR_NONE) { 251 printf("(GetLocalVariableTable) unexpected error: %s (%d)\n", 252 TranslateError(err), err); 253 result = STATUS_FAILED; 254 return; 255 } 256 257 err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_METHOD_EXIT, NULL); 258 if (err != JVMTI_ERROR_NONE) { 259 printf("Failed to enable metod exit event: %s (%d)\n", 260 TranslateError(err), err); 261 result = STATUS_FAILED; 262 } 263 fflush(stdout); 264 } 265 266 JNIEXPORT void JNICALL 267 Java_nsk_jvmti_unit_GetLocalVariable_getlocal003_checkLoc(JNIEnv *env, 268 jclass cls, jthread thr) { 269 jvmtiError err; 270 jvmtiLocalVariableEntry *table; 271 jint entryCount; 272 jmethodID mid; 273 jint locVar; 274 jint i, j; 275 int overlap = 0; 276 277 if (jvmti == NULL) { 278 return; 279 } 280 printf("\n checkLoc: START\n"); 281 282 mid = env->GetStaticMethodID(cls, "staticMeth", "(I)I"); 283 if (mid == NULL) { 284 printf("Cannot find Method ID for staticMeth\n"); 285 result = STATUS_FAILED; 286 return; 287 } 288 289 err = jvmti->GetLocalVariableTable(mid, &entryCount, &table); 290 if (err != JVMTI_ERROR_NONE) { 291 printf("(GetLocalVariableTable) unexpected error: %s (%d)\n", 292 TranslateError(err), err); 293 result = STATUS_FAILED; 294 return; 295 } 296 297 for (i = 0; i < entryCount; i++) { 298 print_LocalVariableEntry(&table[i]); 299 300 err = jvmti->GetLocalInt(thr, 1, table[i].slot, &locVar); 301 302 if (strcmp(table[i].name, "intArg") == 0) { 303 if (err != JVMTI_ERROR_NONE) { 304 printf(" GetLocalInt: %s (%d)\n", TranslateError(err), err); 305 printf(" failure: JVMTI_ERROR_NONE is expected\n"); 306 result = STATUS_FAILED; 307 } 308 } 309 else if (strcmp(table[i].name, "pi") == 0) { 310 if (err != JVMTI_ERROR_TYPE_MISMATCH) { 311 printf(" GetLocalInt: %s (%d)\n", TranslateError(err), err); 312 printf(" failure: JVMTI_ERROR_TYPE_MISMATCH is expected\n"); 313 result = STATUS_FAILED; 314 } 315 } else { 316 if (err != JVMTI_ERROR_INVALID_SLOT) { 317 printf(" GetLocalInt: %s (%d)\n", TranslateError(err), err); 318 printf(" failure: JVMTI_ERROR_INVALID_SLOT is expected\n"); 319 result = STATUS_FAILED; 320 } 321 } 322 if (table[i].slot != 2) { 323 continue; 324 } 325 326 for (j = 0; j < entryCount; j++) { 327 /* We do cross checks between all variables having slot #2. 328 * No overlapping between location ranges are allowed. 329 */ 330 if (table[j].slot != 2 || i == j) { 331 continue; 332 } 333 if (table[i].start_location > table[j].start_location + table[j].length || 334 table[j].start_location > table[i].start_location + table[i].length 335 ) { 336 continue; /* Everything is Ok */ 337 } 338 339 printf(" failure: locations of vars with slot #2 are overlaped:\n"); 340 print_LocalVariableEntry(&table[i]); 341 print_LocalVariableEntry(&table[j]); 342 overlap++; 343 result = STATUS_FAILED; 344 } 345 } 346 if (!overlap) { 347 printf("\n Succes: locations of vars with slot #2 are NOT overlaped\n"); 348 } 349 printf("\n checkLoc: END\n\n"); 350 fflush(stdout); 351 } 352 353 JNIEXPORT jint JNICALL 354 Java_nsk_jvmti_unit_GetLocalVariable_getlocal003_getRes(JNIEnv *env, jclass cls) { 355 return result; 356 } 357 358 }