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