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 #include "agent_common.h"
  28 
  29 #ifdef __cplusplus
  30 extern "C" {
  31 #endif
  32 
  33 #ifndef JNI_ENV_ARG
  34 
  35 #ifdef __cplusplus
  36 #define JNI_ENV_ARG(x, y) y
  37 #define JNI_ENV_ARG1(x)
  38 #define JNI_ENV_PTR(x) x
  39 #else
  40 #define JNI_ENV_ARG(x,y) x, y
  41 #define JNI_ENV_ARG1(x) x
  42 #define JNI_ENV_PTR(x) (*x)
  43 #endif
  44 
  45 #endif
  46 
  47 #define JVMTI_ENV_ARG JNI_ENV_ARG
  48 #define JVMTI_ENV_ARG1 JNI_ENV_ARG1
  49 #define JVMTI_ENV_PTR JNI_ENV_PTR
  50 
  51 #define JVMTI_ERROR_CHECK(str,res) if ( res != JVMTI_ERROR_NONE) { printf(str); printf("%d\n",res); return res;}
  52 #define JVMTI_ERROR_CHECK_EXPECTED_ERROR(str,res,err) if ( res != err) { printf(str); printf("unexpected error %d\n",res); return res;}
  53 
  54 #define JVMTI_ERROR_CHECK_VOID(str,res) if ( res != JVMTI_ERROR_NONE) { printf(str); printf("%d\n",res); iGlobalStatus = 2; }
  55 
  56 #define JVMTI_ERROR_CHECK_EXPECTED_ERROR_VOID(str,res,err) if ( res != err) { printf(str); printf("unexpected error %d\n",res); iGlobalStatus = 2; }
  57 
  58 #define THREADS_LIMIT 2000
  59 
  60 
  61 jvmtiEnv *jvmti;
  62 jint iGlobalStatus = 0;
  63 jthread susp_thrd[THREADS_LIMIT];
  64 static jvmtiEventCallbacks callbacks;
  65 static jvmtiCapabilities jvmti_caps;
  66 jrawMonitorID jraw_monitor[20];
  67 int process_once = 0;
  68 
  69 /* forward decl */
  70 void print_method_name(jmethodID mid);
  71 
  72 int printdump = 0;
  73 
  74 
  75 void debug_printf(const char *fmt, ...) {
  76     va_list args;
  77 
  78     va_start(args, fmt);
  79     if (printdump) {
  80         vprintf(fmt, args);
  81     }
  82     va_end(args);
  83 }
  84 
  85 void JNICALL vmInit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread) {
  86     debug_printf("VMInit event\n");
  87 }
  88 
  89 void JNICALL vmExit(jvmtiEnv *jvmti_env, JNIEnv *env) {
  90     debug_printf("VMDeath event\n");
  91 }
  92 
  93 typedef jclass (*findLoadClass_type) (JNIEnv *env, jobject loader, jstring name);
  94 
  95 findLoadClass_type findLoadedClass_func;
  96 
  97 JNIEXPORT jclass JNICALL
  98 my_findLoadedClass(JNIEnv *env, jobject loader, jstring name) {
  99   const char* sname = env->GetStringUTFChars(name, NULL);
 100   debug_printf("Intercepted findLoadedClass, name = %s\n", sname);
 101   return (*findLoadedClass_func)(env, loader, name);
 102 }
 103 
 104 void JNICALL testNativeMethodBind(jvmtiEnv* jvmti_env, JNIEnv *jni_env,
 105                       jthread thread, jmethodID mid, void* func, void** func_ptr) {
 106     jvmtiPhase phase;
 107     char *mname;
 108     char *signature;
 109     jint ret;
 110 
 111     ret = jvmti_env->GetPhase(&phase);
 112     if (ret != JVMTI_ERROR_NONE) {
 113       printf("Error: GetPhase %d\n", ret);
 114       iGlobalStatus = 2;
 115       return;
 116     }
 117 
 118     if (phase != JVMTI_PHASE_START && phase != JVMTI_PHASE_LIVE)
 119         return;
 120 
 121     debug_printf("bind event: \n");
 122     print_method_name(mid);
 123 
 124     ret = jvmti_env->GetMethodName(mid, &mname, &signature, NULL);
 125     if (ret == JVMTI_ERROR_NONE) {
 126       if (strcmp(mname, "findLoadedClass") == 0) {
 127         findLoadedClass_func = (findLoadClass_type)func;
 128         *func_ptr = (void*)my_findLoadedClass;
 129         debug_printf("REDIRECTED findLoadedClass\n");
 130       }
 131     }
 132 }
 133 
 134 
 135 
 136 void init_callbacks() {
 137     memset((void *)&callbacks, 0, sizeof(jvmtiEventCallbacks));
 138     callbacks.VMInit = vmInit;
 139     callbacks.VMDeath = vmExit;
 140     callbacks.NativeMethodBind = testNativeMethodBind;
 141 }
 142 
 143 
 144 #ifdef STATIC_BUILD
 145 JNIEXPORT jint JNICALL Agent_OnLoad_JvmtiTest(JavaVM *jvm, char *options, void *reserved) {
 146     return Agent_Initialize(jvm, options, reserved);
 147 }
 148 JNIEXPORT jint JNICALL Agent_OnAttach_JvmtiTest(JavaVM *jvm, char *options, void *reserved) {
 149     return Agent_Initialize(jvm, options, reserved);
 150 }
 151 JNIEXPORT jint JNI_OnLoad_JvmtiTest(JavaVM *jvm, char *options, void *reserved) {
 152     return JNI_VERSION_1_8;
 153 }
 154 #endif
 155 jint Agent_Initialize(JavaVM * jvm, char *options, void *reserved) {
 156     jint res;
 157 
 158     if (options && strlen(options) > 0) {
 159         if (strstr(options, "printdump")) {
 160             printdump = 1;
 161         }
 162     }
 163 
 164     res = JNI_ENV_PTR(jvm)->
 165         GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti), JVMTI_VERSION_1_1);
 166     if (res < 0) {
 167         printf("Wrong result of a valid call to GetEnv!\n");
 168         return JNI_ERR;
 169     }
 170 
 171 
 172     /* Add capabilities */
 173     res = JVMTI_ENV_PTR(jvmti)->GetPotentialCapabilities(JVMTI_ENV_ARG(jvmti, &jvmti_caps));
 174     JVMTI_ERROR_CHECK("GetPotentialCapabilities returned error", res);
 175 
 176     res = JVMTI_ENV_PTR(jvmti)->AddCapabilities(JVMTI_ENV_ARG(jvmti, &jvmti_caps));
 177     JVMTI_ERROR_CHECK("AddCapabilities returned error", res);
 178 
 179     /* Enable events */
 180     init_callbacks();
 181     res = JVMTI_ENV_PTR(jvmti)->SetEventCallbacks(JVMTI_ENV_ARG(jvmti, &callbacks), sizeof(callbacks));
 182     JVMTI_ERROR_CHECK("SetEventCallbacks returned error", res);
 183 
 184     res = JVMTI_ENV_PTR(jvmti)->SetEventNotificationMode(JVMTI_ENV_ARG(jvmti,JVMTI_ENABLE),JVMTI_EVENT_VM_INIT,NULL);
 185     JVMTI_ERROR_CHECK("SetEventNotificationMode for VM_INIT returned error", res);
 186 
 187     res = JVMTI_ENV_PTR(jvmti)->SetEventNotificationMode(JVMTI_ENV_ARG(jvmti,JVMTI_ENABLE),JVMTI_EVENT_VM_DEATH,NULL);
 188     JVMTI_ERROR_CHECK("SetEventNotificationMode for vm death event returned error", res);
 189 
 190     res = JVMTI_ENV_PTR(jvmti)->SetEventNotificationMode(JVMTI_ENV_ARG(jvmti,JVMTI_ENABLE),JVMTI_EVENT_NATIVE_METHOD_BIND,NULL);
 191     JVMTI_ERROR_CHECK("SetEventNotificationMode for native method bind event returned error", res);
 192 
 193     return JNI_OK;
 194 }
 195 
 196 
 197 JNIEXPORT jint JNICALL
 198 Java_nsk_jvmti_unit_MethodBind_JvmtiTest_GetResult(JNIEnv * env, jclass cls) {
 199     return iGlobalStatus;
 200 }
 201 
 202 
 203 JNIEXPORT void JNICALL
 204 Java_nsk_jvmti_unit_MethodBind_JvmtiTest_CreateRawMonitor(JNIEnv * env, jclass cls, jint i) {
 205     jvmtiError ret;
 206     char sz[128];
 207 
 208     sprintf(sz, "Rawmonitor-%d",i);
 209     debug_printf("jvmti create raw monitor \n");
 210     ret = JVMTI_ENV_PTR(jvmti)->CreateRawMonitor(JVMTI_ENV_ARG(jvmti, sz), &jraw_monitor[i]);
 211 
 212     if (ret != JVMTI_ERROR_NONE) {
 213         printf("Error: ForceGarbageCollection %d \n", ret);
 214         iGlobalStatus = 2;
 215     }
 216 }
 217 
 218 JNIEXPORT void JNICALL
 219 Java_nsk_jvmti_unit_MethodBind_JvmtiTest_RawMonitorEnter(JNIEnv * env, jclass cls, jint i) {
 220     jvmtiError ret;
 221 
 222     debug_printf("jvmti Raw monitor enter \n");
 223     ret = JVMTI_ENV_PTR(jvmti)->RawMonitorEnter(JVMTI_ENV_ARG(jvmti, jraw_monitor[i]));
 224 
 225     if (ret != JVMTI_ERROR_NONE) {
 226         printf("Error: Raw monitor enter %d \n", ret);
 227         iGlobalStatus = 2;
 228     }
 229 }
 230 
 231 JNIEXPORT void JNICALL
 232 Java_nsk_jvmti_unit_MethodBind_JvmtiTest_RawMonitorExit(JNIEnv * env, jclass cls, jint i) {
 233     jvmtiError ret;
 234 
 235     debug_printf("jvmti raw monitor exit \n");
 236     ret = JVMTI_ENV_PTR(jvmti)->RawMonitorExit(JVMTI_ENV_ARG(jvmti, jraw_monitor[i]));
 237 
 238     if (ret != JVMTI_ERROR_NONE) {
 239         printf("Error: RawMonitorExit %d \n", ret);
 240         iGlobalStatus = 2;
 241     }
 242 }
 243 
 244 JNIEXPORT void JNICALL
 245 Java_nsk_jvmti_unit_MethodBind_JvmtiTest_RawMonitorWait(JNIEnv * env, jclass cls, jint i) {
 246     jvmtiError ret;
 247 
 248     debug_printf("jvmti RawMonitorWait \n");
 249     ret = JVMTI_ENV_PTR(jvmti)->RawMonitorWait(JVMTI_ENV_ARG(jvmti, jraw_monitor[i]), -1);
 250 
 251     if (ret != JVMTI_ERROR_NONE) {
 252         printf("Error: RawMonitorWait %d \n", ret);
 253         iGlobalStatus = 2;
 254     }
 255 }
 256 
 257 JNIEXPORT void JNICALL
 258 Java_nsk_jvmti_unit_MethodBind_JvmtiTest_RawMonitorNotify(JNIEnv * env, jclass cls, jint i) {
 259     jvmtiError ret;
 260 
 261     debug_printf("jvmti RawMonitorNotify \n");
 262     ret = JVMTI_ENV_PTR(jvmti)->RawMonitorNotifyAll(JVMTI_ENV_ARG(jvmti, jraw_monitor[i]));
 263 
 264     if (ret != JVMTI_ERROR_NONE) {
 265         printf("Error: RawMonitorNotify %d \n", ret);
 266         iGlobalStatus = 2;
 267     }
 268 }
 269 
 270 JNIEXPORT int JNICALL
 271 Java_nsk_jvmti_unit_MethodBind_JvmtiTest_GetFrameCount(JNIEnv * env, jclass cls, jobject thr) {
 272     jvmtiError ret;
 273     jint count;
 274 
 275     debug_printf("jvmti GetFrameCount \n");
 276     ret = JVMTI_ENV_PTR(jvmti)->GetFrameCount(JVMTI_ENV_ARG(jvmti, (jthread)thr),  &count);
 277     if (ret != JVMTI_ERROR_NONE) {
 278         printf("Error: GetFrameCount returned  %d \n", ret);
 279         iGlobalStatus = 2;
 280     }
 281     return count;
 282 }
 283 
 284 void
 285 print_method_name(jmethodID mid) {
 286     jvmtiError ret;
 287     jclass klass;
 288     char *mname;
 289     char *signature;
 290     char *clname = (char*) "unknown";
 291     ret = JVMTI_ENV_PTR(jvmti)->GetMethodDeclaringClass(JVMTI_ENV_ARG(jvmti, mid), &klass);
 292     if (ret != JVMTI_ERROR_NONE) {
 293       printf("Error: GetMethodDeclaringClass %d  \n", ret);
 294       iGlobalStatus = 2;
 295       return;
 296     }
 297 
 298     ret = JVMTI_ENV_PTR(jvmti)->GetClassSignature(JVMTI_ENV_ARG(jvmti, klass), &clname, NULL);
 299     if (ret != JVMTI_ERROR_NONE) {
 300       printf("Error: GetClassSignature %d  \n", ret);
 301       iGlobalStatus = 2;
 302       return;
 303     }
 304 
 305     ret = JVMTI_ENV_PTR(jvmti)->GetMethodName(JVMTI_ENV_ARG(jvmti, mid), &mname, &signature, NULL);
 306     if (ret != JVMTI_ERROR_NONE) {
 307       printf("Error: GetMethodName %d  \n", ret);
 308       iGlobalStatus = 2;
 309       return;
 310     }
 311 
 312     debug_printf("%s::%s(%s)\n", clname, mname, signature);
 313 }
 314 
 315 
 316 JNIEXPORT void JNICALL
 317 Java_nsk_jvmti_unit_MethodBind_JvmtiTest_GetStackTrace(JNIEnv * env, jclass cls, jobject thr) {
 318     jvmtiError ret;
 319     jvmtiFrameInfo *stack_buffer = NULL;
 320     jint max_count = 20;
 321     jint count;
 322 
 323 
 324     ret = JVMTI_ENV_PTR(jvmti)->Allocate(JVMTI_ENV_ARG(jvmti, sizeof(jvmtiFrameInfo) * max_count), (unsigned char**)&stack_buffer);
 325     if (ret != JVMTI_ERROR_NONE) {
 326         printf("Error: Allocate failed with  %d \n", ret);
 327         iGlobalStatus = 2;
 328     }
 329 
 330     ret = JVMTI_ENV_PTR(jvmti)->GetStackTrace(JVMTI_ENV_ARG(jvmti, thr), 0, max_count , stack_buffer, &count);
 331     if (ret != JVMTI_ERROR_NONE) {
 332         printf("Error: GetStackTrace %d \n", ret);
 333         iGlobalStatus = 2;
 334     }
 335 
 336     ret = JVMTI_ENV_PTR(jvmti)->Deallocate(JVMTI_ENV_ARG(jvmti, (unsigned char *)stack_buffer));
 337     if (ret != JVMTI_ERROR_NONE) {
 338         printf("Error: Deallocate failed with  %d \n", ret);
 339         iGlobalStatus = 2;
 340     }
 341 
 342 
 343 }
 344 
 345 JNIEXPORT void JNICALL
 346 Java_nsk_jvmti_unit_MethodBind_JvmtiTest_SaveThreadInfo(JNIEnv * env, jclass cls, jobject oobj) {
 347 
 348 }
 349 
 350 #ifdef __cplusplus
 351 }
 352 #endif