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 <stdlib.h>
  25 #include <string.h>
  26 
  27 #include "native_thread.h"
  28 #include "jni_tools.h"
  29 #include "jvmti_tools.h"
  30 
  31 extern "C" {
  32 
  33 /* ============================================================================= */
  34 
  35 /* Be careful: do not build shared library which will be linked with different
  36  * agent libs while global variables are used
  37  * Now the same source is used to build different agent libs, so these
  38  * variables are not shared between agents */
  39 
  40 static jthread agentThread = NULL;
  41 static jvmtiStartFunction agentThreadProc = NULL;
  42 static void* agentThreadArg = NULL;
  43 
  44 
  45 typedef enum {NEW, RUNNABLE, WAITING, SUSPENDED, TERMINATED} thread_state_t;
  46 
  47 typedef struct agent_data_t {
  48     volatile thread_state_t thread_state;
  49     int last_debuggee_status;
  50     jrawMonitorID monitor;
  51 } agent_data_t;
  52 
  53 static agent_data_t agent_data;
  54 
  55 static jvmtiEnv* jvmti_env = NULL;
  56 static JavaVM* jvm = NULL;
  57 static JNIEnv* jni_env = NULL;
  58 
  59 static volatile int currentAgentStatus = NSK_STATUS_PASSED;
  60 
  61 /* ============================================================================= */
  62 
  63 void nsk_jvmti_setFailStatus() {
  64     currentAgentStatus = NSK_STATUS_FAILED;
  65 }
  66 
  67 int nsk_jvmti_isFailStatus() {
  68     return (nsk_jvmti_getStatus() != NSK_STATUS_PASSED);
  69 }
  70 
  71 jint nsk_jvmti_getStatus() {
  72     return currentAgentStatus;
  73 }
  74 
  75 /* ============================================================================= */
  76 static jvmtiError init_agent_data(jvmtiEnv *jvmti_env, agent_data_t *data) {
  77     data->thread_state = NEW;
  78     data->last_debuggee_status = NSK_STATUS_PASSED;
  79 
  80     return NSK_CPP_STUB3(CreateRawMonitor, jvmti_env, "agent_data_monitor", &data->monitor);
  81 }
  82 
  83 /** Reset agent data to prepare for another run. */
  84 void nsk_jvmti_resetAgentData() {
  85     rawMonitorEnter(jvmti_env, agent_data.monitor);
  86     /* wait for agentThreadWrapper() to finish */
  87     while (agent_data.thread_state != TERMINATED) {
  88         rawMonitorWait(jvmti_env, agent_data.monitor, 10);
  89     }
  90     agent_data.thread_state = NEW;
  91     agent_data.last_debuggee_status = NSK_STATUS_PASSED;
  92     rawMonitorExit(jvmti_env, agent_data.monitor);
  93 }
  94 
  95 static jvmtiError free_agent_data(jvmtiEnv *jvmti_env, agent_data_t *data) {
  96     return NSK_CPP_STUB2(DestroyRawMonitor, jvmti_env, data->monitor);
  97 }
  98 
  99 /** Create JVMTI environment. */
 100 jvmtiEnv* nsk_jvmti_createJVMTIEnv(JavaVM* javaVM, void* reserved) {
 101     jvm = javaVM;
 102     if (!NSK_VERIFY(
 103             NSK_CPP_STUB3(GetEnv, javaVM, (void **)&jvmti_env, JVMTI_VERSION_1_1) == JNI_OK)) {
 104         nsk_jvmti_setFailStatus();
 105         return NULL;
 106     }
 107 
 108     if (!NSK_JVMTI_VERIFY(init_agent_data(jvmti_env, &agent_data))) {
 109         nsk_jvmti_setFailStatus();
 110         return NULL;
 111     }
 112 
 113     return jvmti_env;
 114 }
 115 
 116 /** Dispose JVMTI environment */
 117 static int nsk_jvmti_disposeJVMTIEnv(jvmtiEnv* jvmti_env) {
 118     if (jvmti_env != NULL) {
 119         if (!NSK_JVMTI_VERIFY(
 120                 NSK_CPP_STUB1(DisposeEnvironment, jvmti_env))) {
 121             nsk_jvmti_setFailStatus();
 122             return NSK_FALSE;
 123         }
 124 
 125         if (!NSK_JVMTI_VERIFY(free_agent_data(jvmti_env, &agent_data))) {
 126             nsk_jvmti_setFailStatus();
 127             return NSK_FALSE;
 128         }
 129     }
 130     return NSK_TRUE;
 131 }
 132 
 133 /** Get JNI environment for agent thread. */
 134 JNIEnv* nsk_jvmti_getAgentJNIEnv() {
 135     return jni_env;
 136 }
 137 
 138 /** Get JVMTI environment for agent */
 139 jvmtiEnv* nsk_jvmti_getAgentJVMTIEnv() {
 140     return jvmti_env;
 141 }
 142 
 143 /* ============================================================================= */
 144 static void set_agent_thread_state(thread_state_t value) {
 145     rawMonitorEnter(jvmti_env, agent_data.monitor);
 146     agent_data.thread_state = value;
 147     rawMonitorNotify(jvmti_env, agent_data.monitor);
 148     rawMonitorExit(jvmti_env, agent_data.monitor);
 149 }
 150 
 151 /** Wrapper for user agent thread. */
 152 static void JNICALL
 153 agentThreadWrapper(jvmtiEnv* jvmti_env, JNIEnv* agentJNI, void* arg) {
 154     jni_env = agentJNI;
 155 
 156     /* run user agent proc */
 157     {
 158         set_agent_thread_state(RUNNABLE);
 159 
 160         NSK_TRACE((*agentThreadProc)(jvmti_env, agentJNI, agentThreadArg));
 161 
 162         set_agent_thread_state(TERMINATED);
 163     }
 164 
 165     /* finalize agent thread */
 166     {
 167         /* gelete global ref for agent thread */
 168         NSK_CPP_STUB2(DeleteGlobalRef, agentJNI, agentThread);
 169         agentThread = NULL;
 170     }
 171 }
 172 
 173 /** Start wrapper for user agent thread. */
 174 static jthread startAgentThreadWrapper(JNIEnv *jni_env, jvmtiEnv* jvmti_env) {
 175     const jint  THREAD_PRIORITY = JVMTI_THREAD_MAX_PRIORITY;
 176     const char* THREAD_NAME = "JVMTI agent thread";
 177     const char* THREAD_CLASS_NAME = "java/lang/Thread";
 178     const char* THREAD_CTOR_NAME = "<init>";
 179     const char* THREAD_CTOR_SIGNATURE = "(Ljava/lang/String;)V";
 180 
 181     jobject threadName = NULL;
 182     jclass threadClass = NULL;
 183     jmethodID threadCtor = NULL;
 184     jobject threadObject = NULL;
 185     jobject threadGlobalRef = NULL;
 186 
 187     if (!NSK_JNI_VERIFY(jni_env, (threadClass =
 188             NSK_CPP_STUB2(FindClass, jni_env, THREAD_CLASS_NAME)) != NULL)) {
 189         return NULL;
 190     }
 191 
 192     if (!NSK_JNI_VERIFY(jni_env, (threadCtor =
 193             NSK_CPP_STUB4(GetMethodID, jni_env, threadClass, THREAD_CTOR_NAME, THREAD_CTOR_SIGNATURE)) != NULL))
 194         return NULL;
 195 
 196     if (!NSK_JNI_VERIFY(jni_env, (threadName =
 197             NSK_CPP_STUB2(NewStringUTF, jni_env, THREAD_NAME)) != NULL))
 198         return NULL;
 199 
 200     if (!NSK_JNI_VERIFY(jni_env, (threadObject =
 201             NSK_CPP_STUB4(NewObject, jni_env, threadClass, threadCtor, threadName)) != NULL))
 202         return NULL;
 203 
 204     if (!NSK_JNI_VERIFY(jni_env, (threadGlobalRef =
 205             NSK_CPP_STUB2(NewGlobalRef, jni_env, threadObject)) != NULL)) {
 206         NSK_CPP_STUB2(DeleteLocalRef, jni_env, threadObject);
 207         return NULL;
 208     }
 209     agentThread = (jthread)threadGlobalRef;
 210 
 211     if (!NSK_JVMTI_VERIFY(
 212             NSK_CPP_STUB5(RunAgentThread, jvmti_env, agentThread,
 213                             &agentThreadWrapper, agentThreadArg, THREAD_PRIORITY))) {
 214         NSK_CPP_STUB2(DeleteGlobalRef, jni_env, threadGlobalRef);
 215         NSK_CPP_STUB2(DeleteLocalRef, jni_env, threadObject);
 216         return NULL;
 217     }
 218     return agentThread;
 219 }
 220 
 221 /** Register user agent thread with arg. */
 222 int nsk_jvmti_setAgentProc(jvmtiStartFunction proc, void* arg) {
 223     agentThreadProc = proc;
 224     agentThreadArg = arg;
 225     return NSK_TRUE;
 226 }
 227 
 228 /** Get agent thread ref. */
 229 jthread nsk_jvmti_getAgentThread() {
 230     return agentThread;
 231 }
 232 
 233 /** Run registered user agent thread via wrapper. */
 234 static jthread nsk_jvmti_runAgentThread(JNIEnv *jni_env, jvmtiEnv* jvmti_env) {
 235     /* start agent thread wrapper */
 236     jthread thread = startAgentThreadWrapper(jni_env, jvmti_env);
 237     if (thread == NULL) {
 238         nsk_jvmti_setFailStatus();
 239         return NULL;
 240     }
 241 
 242     return thread;
 243 }
 244 
 245 /* ============================================================================= */
 246 
 247 /** Sleep current thread. */
 248 void nsk_jvmti_sleep(jlong timeout) {
 249     int seconds = (int)((timeout + 999) / 1000);
 250     THREAD_sleep(seconds);
 251 }
 252 
 253 /** Sync point called from Java code. */
 254 static jint syncDebuggeeStatus(JNIEnv* jni_env, jvmtiEnv* jvmti_env, jint debuggeeStatus) {
 255     jint result = NSK_STATUS_FAILED;
 256 
 257     rawMonitorEnter(jvmti_env, agent_data.monitor);
 258 
 259     /* save last debugee status */
 260     agent_data.last_debuggee_status = debuggeeStatus;
 261 
 262     /* we don't enter if-stmt in second call */
 263     if (agent_data.thread_state == NEW) {
 264         if (nsk_jvmti_runAgentThread(jni_env, jvmti_env) == NULL)
 265             goto monitor_exit_and_return;
 266 
 267         /* SP2.2-w - wait for agent thread */
 268         while (agent_data.thread_state == NEW) {
 269             rawMonitorWait(jvmti_env, agent_data.monitor, 0);
 270         }
 271     }
 272 
 273     /* wait for sync permit */
 274     /* we don't enter loop in first call */
 275     while (agent_data.thread_state != WAITING && agent_data.thread_state != TERMINATED) {
 276         /* SP4.2-w - second wait for agent thread */
 277         rawMonitorWait(jvmti_env, agent_data.monitor, 0);
 278     }
 279 
 280     if (agent_data.thread_state != TERMINATED) {
 281         agent_data.thread_state = SUSPENDED;
 282         /* SP3.2-n - notify to start test */
 283         /* SP6.2-n - notify to end test */
 284         rawMonitorNotify(jvmti_env, agent_data.monitor);
 285     }
 286     else {
 287         NSK_COMPLAIN0("Debuggee status sync aborted because agent thread has finished\n");
 288         goto monitor_exit_and_return;
 289     }
 290 
 291     /* update status from debuggee */
 292     if (debuggeeStatus != NSK_STATUS_PASSED) {
 293         nsk_jvmti_setFailStatus();
 294     }
 295 
 296     while (agent_data.thread_state == SUSPENDED) {
 297         /* SP5.2-w - wait while testing */
 298         /* SP7.2 - wait for agent end */
 299         rawMonitorWait(jvmti_env, agent_data.monitor, 0);
 300     }
 301 
 302     agent_data.last_debuggee_status = nsk_jvmti_getStatus();
 303     result = agent_data.last_debuggee_status;
 304 
 305 monitor_exit_and_return:
 306     rawMonitorExit(jvmti_env, agent_data.monitor);
 307     return result;
 308 }
 309 
 310 /** Wait for sync point with Java code. */
 311 int nsk_jvmti_waitForSync(jlong timeout) {
 312     static const int inc_timeout = 1000;
 313 
 314     jlong t = 0;
 315     int result = NSK_TRUE;
 316 
 317     rawMonitorEnter(jvmti_env, agent_data.monitor);
 318 
 319     agent_data.thread_state = WAITING;
 320 
 321     /* SP2.2-n - notify agent is waiting and wait */
 322     /* SP4.1-n - notify agent is waiting and wait */
 323     rawMonitorNotify(jvmti_env, agent_data.monitor);
 324 
 325     while (agent_data.thread_state == WAITING) {
 326         /* SP3.2-w - wait to start test */
 327         /* SP6.2-w - wait to end test */
 328         rawMonitorWait(jvmti_env, agent_data.monitor, inc_timeout);
 329 
 330         if (timeout == 0) continue;
 331 
 332         t += inc_timeout;
 333 
 334         if (t >= timeout) break;
 335     }
 336 
 337     if (agent_data.thread_state == WAITING) {
 338         NSK_COMPLAIN1("No status sync occured for timeout: %" LL "d ms\n", timeout);
 339         nsk_jvmti_setFailStatus();
 340         result = NSK_FALSE;
 341     }
 342 
 343     rawMonitorExit(jvmti_env, agent_data.monitor);
 344 
 345     return result;
 346 }
 347 
 348 /** Resume java code suspended on sync point. */
 349 int nsk_jvmti_resumeSync() {
 350     int result;
 351     rawMonitorEnter(jvmti_env, agent_data.monitor);
 352 
 353     if (agent_data.thread_state == SUSPENDED) {
 354         result = NSK_TRUE;
 355         agent_data.thread_state = RUNNABLE;
 356         /* SP5.2-n - notify suspend done */
 357         /* SP7.2-n - notify agent end */
 358         rawMonitorNotify(jvmti_env, agent_data.monitor);
 359     }
 360     else {
 361         NSK_COMPLAIN0("Debuggee was not suspended on status sync\n");
 362         nsk_jvmti_setFailStatus();
 363         result = NSK_FALSE;
 364     }
 365 
 366     rawMonitorExit(jvmti_env, agent_data.monitor);
 367     return NSK_TRUE;
 368 }
 369 
 370 /** Native function for Java code to provide sync point. */
 371 JNIEXPORT jint JNICALL
 372 Java_nsk_share_jvmti_DebugeeClass_checkStatus(JNIEnv* jni_env, jclass cls, jint debuggeeStatus) {
 373     jint status;
 374     NSK_TRACE(status = syncDebuggeeStatus(jni_env, jvmti_env, debuggeeStatus));
 375     return status;
 376 }
 377 
 378 /** Native function for Java code to reset agent data. */
 379 JNIEXPORT void JNICALL
 380 Java_nsk_share_jvmti_DebugeeClass_resetAgentData(JNIEnv* jni_env, jclass cls) {
 381     NSK_TRACE(nsk_jvmti_resetAgentData());
 382 }
 383 
 384 /* ============================================================================= */
 385 
 386 /** Find loaded class by signature. */
 387 jclass nsk_jvmti_classBySignature(const char signature[]) {
 388     jclass* classes = NULL;
 389     jint count = 0;
 390     jclass foundClass = NULL;
 391     int i;
 392 
 393     if (!NSK_VERIFY(signature != NULL)) {
 394         nsk_jvmti_setFailStatus();
 395         return NULL;
 396     }
 397 
 398     if (!NSK_JVMTI_VERIFY(
 399             NSK_CPP_STUB3(GetLoadedClasses, jvmti_env, &count, &classes))) {
 400         nsk_jvmti_setFailStatus();
 401         return NULL;
 402     }
 403 
 404     for (i = 0; i < count; i++) {
 405         char* sig = NULL;
 406         char* generic = NULL;
 407 
 408         if (!NSK_JVMTI_VERIFY(
 409                 NSK_CPP_STUB4(GetClassSignature, jvmti_env, classes[i], &sig, &generic))) {
 410             nsk_jvmti_setFailStatus();
 411             break;
 412         }
 413 
 414         if (sig != NULL && strcmp(signature, sig) == 0) {
 415             foundClass = classes[i];
 416         }
 417 
 418         if (!(NSK_JVMTI_VERIFY(
 419                     NSK_CPP_STUB2(Deallocate, jvmti_env, (unsigned char*)sig))
 420                 && NSK_JVMTI_VERIFY(
 421                     NSK_CPP_STUB2(Deallocate, jvmti_env, (unsigned char*)generic)))) {
 422             nsk_jvmti_setFailStatus();
 423             break;
 424         }
 425 
 426         if (foundClass != NULL)
 427             break;
 428     }
 429 
 430     if (!NSK_JVMTI_VERIFY(
 431                 NSK_CPP_STUB2(Deallocate, jvmti_env, (unsigned char*)classes))) {
 432         nsk_jvmti_setFailStatus();
 433         return NULL;
 434     }
 435 
 436     if (!NSK_JNI_VERIFY(jni_env, (foundClass = (jclass)
 437                 NSK_CPP_STUB2(NewGlobalRef, jni_env, foundClass)) != NULL)) {
 438         nsk_jvmti_setFailStatus();
 439         return NULL;
 440     }
 441 
 442     return foundClass;
 443 }
 444 
 445 /** Find alive thread by name. */
 446 jthread nsk_jvmti_threadByName(const char name[]) {
 447     jthread* threads = NULL;
 448     jint count = 0;
 449     jthread foundThread = NULL;
 450     int i;
 451 
 452     if (!NSK_VERIFY(name != NULL)) {
 453         nsk_jvmti_setFailStatus();
 454         return NULL;
 455     }
 456 
 457     if (!NSK_JVMTI_VERIFY(
 458             NSK_CPP_STUB3(GetAllThreads, jvmti_env, &count, &threads))) {
 459         nsk_jvmti_setFailStatus();
 460         return NULL;
 461     }
 462 
 463     for (i = 0; i < count; i++) {
 464         jvmtiThreadInfo info;
 465 
 466         if (!NSK_JVMTI_VERIFY(
 467                 NSK_CPP_STUB3(GetThreadInfo, jvmti_env, threads[i], &info))) {
 468             nsk_jvmti_setFailStatus();
 469             break;
 470         }
 471 
 472         if (info.name != NULL && strcmp(name, info.name) == 0) {
 473             foundThread = threads[i];
 474             break;
 475         }
 476     }
 477 
 478     if (!NSK_JVMTI_VERIFY(
 479                 NSK_CPP_STUB2(Deallocate, jvmti_env, (unsigned char*)threads))) {
 480         nsk_jvmti_setFailStatus();
 481         return NULL;
 482     }
 483 
 484     if (!NSK_JNI_VERIFY(jni_env, (foundThread = (jthread)
 485                 NSK_CPP_STUB2(NewGlobalRef, jni_env, foundThread)) != NULL)) {
 486         nsk_jvmti_setFailStatus();
 487         return NULL;
 488     }
 489 
 490     return foundThread;
 491 }
 492 
 493 
 494 /* ============================================================================= */
 495 
 496 /** Add all capabilities for finding line locations. */
 497 int nsk_jvmti_addLocationCapabilities() {
 498     jvmtiCapabilities caps;
 499 
 500     memset(&caps, 0, sizeof(caps));
 501     caps.can_get_line_numbers = 1;
 502     if (!NSK_JVMTI_VERIFY(
 503             NSK_CPP_STUB2(AddCapabilities, jvmti_env, &caps)))
 504         return NSK_FALSE;
 505 
 506     return NSK_TRUE;
 507 }
 508 
 509 /** Add all capabilities for using breakpoints. */
 510 int nsk_jvmti_addBreakpointCapabilities() {
 511     jvmtiCapabilities caps;
 512 
 513     if (!nsk_jvmti_addLocationCapabilities())
 514         return NSK_FALSE;
 515 
 516     memset(&caps, 0, sizeof(caps));
 517     caps.can_generate_breakpoint_events = 1;
 518     if (!NSK_JVMTI_VERIFY(
 519             NSK_CPP_STUB2(AddCapabilities, jvmti_env, &caps)))
 520         return NSK_FALSE;
 521 
 522     return NSK_TRUE;
 523 }
 524 
 525 /** Find line location. */
 526 jlocation nsk_jvmti_getLineLocation(jclass cls, jmethodID method, int line) {
 527     jint count = 0;
 528     jvmtiLineNumberEntry* table = NULL;
 529     jlocation location = NSK_JVMTI_INVALID_JLOCATION;
 530     int i;
 531 
 532     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(GetLineNumberTable, jvmti_env, method, &count, &table)))
 533         return NSK_JVMTI_INVALID_JLOCATION;
 534 
 535     for (i = 0; i < count; i++) {
 536         if (table[i].line_number == line) {
 537             location = table[i].start_location;
 538             break;
 539         }
 540     }
 541 
 542     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(Deallocate, jvmti_env, (unsigned char*)table)))
 543         return NSK_JVMTI_INVALID_JLOCATION;
 544 
 545     return location;
 546 }
 547 
 548 /** Set breakpoint to a line. */
 549 jlocation nsk_jvmti_setLineBreakpoint(jclass cls, jmethodID method, int line) {
 550     jlocation location = NSK_JVMTI_INVALID_JLOCATION;
 551 
 552     if (!NSK_VERIFY((location =
 553             nsk_jvmti_getLineLocation(cls, method, line)) != NSK_JVMTI_INVALID_JLOCATION))
 554         return NSK_JVMTI_INVALID_JLOCATION;
 555 
 556     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(SetBreakpoint, jvmti_env, method, location)))
 557         return NSK_JVMTI_INVALID_JLOCATION;
 558 
 559     return location;
 560 }
 561 
 562 /** Remove breakpoint from a line. */
 563 jlocation nsk_jvmti_clearLineBreakpoint(jclass cls, jmethodID method, int line) {
 564     jlocation location = NSK_JVMTI_INVALID_JLOCATION;
 565 
 566     if (!NSK_VERIFY((location =
 567             nsk_jvmti_getLineLocation(cls, method, line)) != NSK_JVMTI_INVALID_JLOCATION))
 568         return NSK_JVMTI_INVALID_JLOCATION;
 569 
 570     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(ClearBreakpoint, jvmti_env, method, location)))
 571         return NSK_JVMTI_INVALID_JLOCATION;
 572 
 573     return location;
 574 }
 575 
 576 /* ============================================================================= */
 577 
 578 /** Enable or disable given events. */
 579 int nsk_jvmti_enableEvents(jvmtiEventMode enable, int size, jvmtiEvent list[], jthread thread) {
 580     int i;
 581 
 582     for (i = 0; i < size; i++) {
 583         if (!NSK_JVMTI_VERIFY(
 584                 NSK_CPP_STUB4(SetEventNotificationMode, jvmti_env, enable,
 585                                                 list[i], thread))) {
 586             nsk_jvmti_setFailStatus();
 587             return NSK_FALSE;
 588         }
 589     }
 590     return NSK_TRUE;
 591 }
 592 
 593 /* ============================================================================= */
 594 
 595 typedef jint (JNICALL *checkStatus_type)(JNIEnv* jni_env, jclass cls, jint debuggeeStatus);
 596 
 597 static checkStatus_type checkStatus_func = NULL;
 598 
 599 /**
 600  * Proxy function to gain sequential access to checkStatus of each agent
 601  */
 602 JNIEXPORT jint JNICALL
 603 MA_checkStatus(JNIEnv* jni_env, jclass cls, jint debuggeeStatus) {
 604     jint status;
 605 
 606     NSK_TRACE(status = syncDebuggeeStatus(jni_env, jvmti_env, debuggeeStatus));
 607     return (*checkStatus_func)(jni_env, cls, status);
 608 }
 609 
 610 /**
 611  * nativeMethodBind callback:
 612  *      if needed, redirects checkStatus native method call
 613  */
 614 static void JNICALL nativeMethodBind(jvmtiEnv* jvmti_env, JNIEnv *jni_env,
 615                               jthread thread, jmethodID mid,
 616                               void* address, void** new_address_ptr) {
 617     const char* BIND_CLASS_NAME = "Lnsk/share/jvmti/DebugeeClass;";
 618     const char* BIND_METHOD_NAME = "checkStatus";
 619     const char* BIND_METHOD_SIGNATURE = "(I)I";
 620 
 621     jvmtiPhase phase;
 622     jclass cls;
 623     char *class_sig = NULL;
 624     char *name = NULL;
 625     char *sig = NULL;
 626 
 627     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(GetPhase, jvmti_env, &phase))) {
 628         nsk_jvmti_setFailStatus();
 629         return;
 630     }
 631 
 632     if (phase != JVMTI_PHASE_START && phase != JVMTI_PHASE_LIVE)
 633         return;
 634 
 635     if (NSK_JVMTI_VERIFY(
 636             NSK_CPP_STUB5(GetMethodName, jvmti_env, mid, &name, &sig, NULL))) {
 637         if (strcmp(name, BIND_METHOD_NAME) == 0 &&
 638                 strcmp(sig, BIND_METHOD_SIGNATURE) == 0) {
 639 
 640             if (NSK_JVMTI_VERIFY(
 641                     NSK_CPP_STUB3(GetMethodDeclaringClass, jvmti_env, mid, &cls))
 642              && NSK_JVMTI_VERIFY(
 643                     NSK_CPP_STUB4(GetClassSignature, jvmti_env, cls, &class_sig, NULL))
 644              && strcmp(class_sig, BIND_CLASS_NAME) == 0
 645              && address != (void*)Java_nsk_share_jvmti_DebugeeClass_checkStatus) {
 646                 checkStatus_func = (checkStatus_type)address;
 647                 NSK_TRACE(*new_address_ptr = (void*)MA_checkStatus);
 648             }
 649         }
 650     }
 651 
 652     if (name != NULL)
 653         NSK_CPP_STUB2(Deallocate, jvmti_env, (unsigned char*)name);
 654 
 655     if (sig != NULL)
 656         NSK_CPP_STUB2(Deallocate, jvmti_env, (unsigned char*)sig);
 657 
 658     if (class_sig != NULL)
 659         NSK_CPP_STUB2(Deallocate, jvmti_env, (unsigned char*)class_sig);
 660 }
 661 
 662 /**
 663  * Initialize multiple agent:
 664  *      establish processing of nativeMethodBind events
 665  */
 666 int nsk_jvmti_init_MA(jvmtiEventCallbacks* callbacks) {
 667 
 668     if (callbacks == NULL) {
 669         NSK_COMPLAIN0("callbacks should not be NULL\n");
 670         nsk_jvmti_setFailStatus();
 671         return NSK_FALSE;
 672     }
 673 
 674     if (callbacks->NativeMethodBind != NULL) {
 675         NSK_COMPLAIN0("callbacks.NativeMethodBind should be NULL\n");
 676         nsk_jvmti_setFailStatus();
 677         return NSK_FALSE;
 678     }
 679 
 680     {
 681         jvmtiCapabilities caps;
 682         memset(&caps, 0, sizeof(caps));
 683         caps.can_generate_native_method_bind_events = 1;
 684         if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(AddCapabilities, jvmti_env, &caps)))
 685             return NSK_FALSE;
 686     }
 687 
 688     callbacks->NativeMethodBind = nativeMethodBind;
 689     if (!NSK_JVMTI_VERIFY(
 690             NSK_CPP_STUB3(SetEventCallbacks, jvmti_env, callbacks,
 691                 sizeof(jvmtiEventCallbacks))))
 692         return NSK_FALSE;
 693 
 694     if (!NSK_JVMTI_VERIFY(
 695             NSK_CPP_STUB4(SetEventNotificationMode, jvmti_env, JVMTI_ENABLE,
 696                 JVMTI_EVENT_NATIVE_METHOD_BIND, NULL)))
 697         return NSK_FALSE;
 698 
 699     return NSK_TRUE;
 700 }
 701 
 702 /* ============================================================================= */
 703 
 704 int nsk_jvmti_isOptionalEvent(jvmtiEvent event) {
 705 
 706     return (event == JVMTI_EVENT_EXCEPTION)
 707         || (event == JVMTI_EVENT_EXCEPTION_CATCH)
 708         || (event == JVMTI_EVENT_SINGLE_STEP)
 709         || (event == JVMTI_EVENT_FRAME_POP)
 710         || (event == JVMTI_EVENT_BREAKPOINT)
 711         || (event == JVMTI_EVENT_FIELD_ACCESS)
 712         || (event == JVMTI_EVENT_FIELD_MODIFICATION)
 713         || (event == JVMTI_EVENT_METHOD_ENTRY)
 714         || (event == JVMTI_EVENT_METHOD_EXIT)
 715         || (event == JVMTI_EVENT_NATIVE_METHOD_BIND)
 716         || (event == JVMTI_EVENT_COMPILED_METHOD_LOAD)
 717         || (event == JVMTI_EVENT_COMPILED_METHOD_UNLOAD)
 718         || (event == JVMTI_EVENT_MONITOR_WAIT)
 719         || (event == JVMTI_EVENT_MONITOR_WAITED)
 720         || (event == JVMTI_EVENT_MONITOR_CONTENDED_ENTER)
 721         || (event == JVMTI_EVENT_MONITOR_CONTENDED_ENTERED)
 722         || (event == JVMTI_EVENT_GARBAGE_COLLECTION_START)
 723         || (event == JVMTI_EVENT_GARBAGE_COLLECTION_FINISH)
 724         || (event == JVMTI_EVENT_OBJECT_FREE)
 725         || (event == JVMTI_EVENT_VM_OBJECT_ALLOC);
 726 }
 727 
 728 /* ============================================================================= */
 729 
 730 void nsk_jvmti_showPossessedCapabilities(jvmtiEnv *jvmti_env) {
 731 
 732     jvmtiCapabilities caps;
 733 
 734     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(GetCapabilities, jvmti_env, &caps))) {
 735         return;
 736     }
 737 
 738     NSK_DISPLAY0("\n");
 739     NSK_DISPLAY0("Possessed capabilities:\n");
 740     NSK_DISPLAY0("-----------------------\n");
 741     if (caps.can_tag_objects)
 742         NSK_DISPLAY0("\tcan_tag_objects\n");
 743     if (caps.can_generate_field_modification_events)
 744         NSK_DISPLAY0("\tcan_generate_field_modification_events\n");
 745     if (caps.can_generate_field_access_events)
 746         NSK_DISPLAY0("\tcan_generate_field_access_events\n");
 747     if (caps.can_get_bytecodes)
 748         NSK_DISPLAY0("\tcan_get_bytecodes\n");
 749     if (caps.can_get_synthetic_attribute)
 750         NSK_DISPLAY0("\tcan_get_synthetic_attribute\n");
 751     if (caps.can_get_owned_monitor_info)
 752         NSK_DISPLAY0("\tcan_get_owned_monitor_info\n");
 753     if (caps.can_get_current_contended_monitor)
 754         NSK_DISPLAY0("\tcan_get_current_contended_monitor\n");
 755     if (caps.can_get_monitor_info)
 756         NSK_DISPLAY0("\tcan_get_monitor_info\n");
 757     if (caps.can_pop_frame)
 758         NSK_DISPLAY0("\tcan_pop_frame\n");
 759     if (caps.can_redefine_classes)
 760         NSK_DISPLAY0("\tcan_redefine_classes\n");
 761     if (caps.can_signal_thread)
 762         NSK_DISPLAY0("\tcan_signal_thread\n");
 763     if (caps.can_get_source_file_name)
 764         NSK_DISPLAY0("\tcan_get_source_file_name\n");
 765     if (caps.can_get_line_numbers)
 766         NSK_DISPLAY0("\tcan_get_line_numbers\n");
 767     if (caps.can_get_source_debug_extension)
 768         NSK_DISPLAY0("\tcan_get_source_debug_extension\n");
 769     if (caps.can_access_local_variables)
 770         NSK_DISPLAY0("\tcan_access_local_variables\n");
 771     if (caps.can_maintain_original_method_order)
 772         NSK_DISPLAY0("\tcan_maintain_original_method_order\n");
 773     if (caps.can_generate_single_step_events)
 774         NSK_DISPLAY0("\tcan_generate_single_step_events\n");
 775     if (caps.can_generate_exception_events)
 776         NSK_DISPLAY0("\tcan_generate_exception_events\n");
 777     if (caps.can_generate_frame_pop_events)
 778         NSK_DISPLAY0("\tcan_generate_frame_pop_events\n");
 779     if (caps.can_generate_breakpoint_events)
 780         NSK_DISPLAY0("\tcan_generate_breakpoint_events\n");
 781     if (caps.can_suspend)
 782         NSK_DISPLAY0("\tcan_suspend\n");
 783     if (caps.can_get_current_thread_cpu_time)
 784         NSK_DISPLAY0("\tcan_get_current_thread_cpu_time\n");
 785     if (caps.can_get_thread_cpu_time)
 786         NSK_DISPLAY0("\tcan_get_thread_cpu_time\n");
 787     if (caps.can_generate_method_entry_events)
 788         NSK_DISPLAY0("\tcan_generate_method_entry_events\n");
 789     if (caps.can_generate_method_exit_events)
 790         NSK_DISPLAY0("\tcan_generate_method_exit_events\n");
 791     if (caps.can_generate_all_class_hook_events)
 792         NSK_DISPLAY0("\tcan_generate_all_class_hook_events\n");
 793     if (caps.can_generate_compiled_method_load_events)
 794         NSK_DISPLAY0("\tcan_generate_compiled_method_load_events\n");
 795     if (caps.can_generate_monitor_events)
 796         NSK_DISPLAY0("\tcan_generate_monitor_events\n");
 797     if (caps.can_generate_vm_object_alloc_events)
 798         NSK_DISPLAY0("\tcan_generate_vm_object_alloc_events\n");
 799     if (caps.can_generate_native_method_bind_events)
 800         NSK_DISPLAY0("\tcan_generate_native_method_bind_events\n");
 801     if (caps.can_generate_garbage_collection_events)
 802         NSK_DISPLAY0("\tcan_generate_garbage_collection_events\n");
 803     if (caps.can_generate_object_free_events)
 804         NSK_DISPLAY0("\tcan_generate_object_free_events\n");
 805 
 806     NSK_DISPLAY0("\n");
 807 }
 808 
 809 /* ============================================================================= */
 810 
 811 }