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 DECL_TEST_INV_SLOT_FUNC(long, Long); 93 DECL_TEST_INV_SLOT_FUNC(double, Double); 94 DECL_TEST_INV_SLOT_FUNC(object, Object); 95 96 DECL_TEST_TYPE_MISMATCH_FUNC(int, Int); 97 DECL_TEST_TYPE_MISMATCH_FUNC(float, Float); 98 DECL_TEST_TYPE_MISMATCH_FUNC(long, Long); 99 DECL_TEST_TYPE_MISMATCH_FUNC(double, Double); 100 DECL_TEST_TYPE_MISMATCH_FUNC(object, Object); 101 102 static void 103 test_local_byte(jthread thr, int depth, int slot) { 104 printf("\n test_local_byte: BEGIN\n\n"); 105 106 test_int(thr, depth, slot, "byte"); 107 test_long_inv_slot(thr, depth, slot, "byte"); 108 test_float(thr, depth, slot, "byte"); 109 test_double_inv_slot(thr, depth, slot, "byte"); 110 test_object_type_mismatch(thr, depth, slot, "byte"); 111 112 printf("\n test_local_byte: END\n\n"); 113 } 114 115 static void 116 test_local_object(jthread thr, int depth, int slot) { 117 printf("\n test_local_object: BEGIN\n\n"); 118 119 test_int_type_mismatch(thr, depth, slot, "object"); 120 test_long_type_mismatch(thr, depth, slot, "object"); 121 test_float_type_mismatch(thr, depth, slot, "object"); 122 test_double_type_mismatch(thr, depth, slot, "object"); 123 test_object(thr, depth, slot, "object"); 124 125 printf("\n test_local_object: END\n\n"); 126 } 127 128 static void 129 test_local_double(jthread thr, int depth, int slot) { 130 printf("\n test_local_double: BEGIN\n\n"); 131 132 test_int(thr, depth, slot, "double"); 133 test_long(thr, depth, slot, "double"); 134 test_float(thr, depth, slot, "double"); 135 test_double(thr, depth, slot, "double"); 136 test_object_type_mismatch(thr, depth, slot, "double"); 137 138 printf("\n test_local_double: END\n\n"); 139 } 140 141 static void 142 test_local_integer(jthread thr, int depth, int slot) { 143 printf("\n test_local_integer: BEGIN\n\n"); 144 145 test_int(thr, depth, slot, "int"); 146 test_long_inv_slot(thr, depth, slot, "int"); 147 test_float(thr, depth, slot, "int"); 148 test_double_inv_slot(thr, depth, slot, "int"); 149 test_object_type_mismatch(thr, depth, slot, "double"); 150 151 printf("\n test_local_integer: END\n\n"); 152 } 153 154 static void 155 test_local_invalid(jthread thr, int depth, int slot) { 156 printf("\n test_local_invalid: BEGIN\n\n"); 157 158 test_int_inv_slot(thr, depth, slot, "invalid"); 159 test_long_inv_slot(thr, depth, slot, "invalid"); 160 test_float_inv_slot(thr, depth, slot, "invalid"); 161 test_double_inv_slot(thr, depth, slot, "invalid"); 162 test_object_inv_slot(thr, depth, slot, "invalid"); 163 164 printf("\n test_local_invalid: END\n\n"); 165 } 166 167 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 168 jint res; 169 jvmtiError err; 170 static jvmtiCapabilities caps; 171 172 res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_9); 173 if (res != JNI_OK || jvmti == NULL) { 174 printf("Wrong result of a valid call to GetEnv!\n"); 175 return JNI_ERR; 176 } 177 caps.can_access_local_variables = 1; 178 179 err = jvmti->AddCapabilities(&caps); 180 if (err != JVMTI_ERROR_NONE) { 181 printf("AddCapabilities: unexpected error: %s (%d)\n", TranslateError(err), err); 182 return JNI_ERR; 183 } 184 err = jvmti->GetCapabilities(&caps); 185 if (err != JVMTI_ERROR_NONE) { 186 printf("GetCapabilities: unexpected error: %s (%d)\n", TranslateError(err), err); 187 return JNI_ERR; 188 } 189 if (!caps.can_access_local_variables) { 190 printf("Warning: Access to local variables is not implemented\n"); 191 return JNI_ERR; 192 } 193 return JNI_OK; 194 } 195 196 JNIEXPORT jint JNICALL 197 Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { 198 return Agent_Initialize(jvm, options, reserved); 199 } 200 201 JNIEXPORT jint JNICALL 202 Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) { 203 return Agent_Initialize(jvm, options, reserved); 204 } 205 206 JNIEXPORT void JNICALL 207 Java_GetLocalVars_testLocals(JNIEnv *env, jclass cls, jobject thread) { 208 static const char* METHOD_NAME = "staticMeth"; 209 static const char* METHOD_SIGN = "(BLjava/lang/Object;DI)I"; 210 static const int Depth = 1; 211 static const int ByteSlot = 0; 212 static const int ObjSlot = 1; 213 static const int DblSlot = 2; 214 static const int IntSlot = 4; 215 static const int InvalidSlot = 5; 216 217 jmethodID mid = NULL; 218 219 if (jvmti == NULL) { 220 printf("JVMTI client was not properly loaded!\n"); 221 result = STATUS_FAILED; 222 return; 223 } 224 225 mid = env->GetStaticMethodID(cls, METHOD_NAME, METHOD_SIGN); 226 if (mid == NULL) { 227 printf("Cannot find Method ID for %s%s\n", METHOD_NAME, METHOD_SIGN); 228 result = STATUS_FAILED; 229 return; 230 } 231 232 test_local_byte(thread, Depth, ByteSlot); 233 test_local_object(thread, Depth, ObjSlot); 234 test_local_double(thread, Depth, DblSlot); 235 test_local_integer(thread, Depth, IntSlot); 236 test_local_invalid(thread, Depth, InvalidSlot); 237 } 238 239 JNIEXPORT jint JNICALL 240 Java_GetLocalVars_getStatus(JNIEnv *env, jclass cls) { 241 return result; 242 } 243 244 #ifdef __cplusplus 245 } 246 #endif