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