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 <stdio.h>
  26 #include <stdarg.h>
  27 #include <string.h>
  28 #include <ctype.h>
  29 
  30 /*************************************************************/
  31 
  32 #include "jvmti.h"
  33 
  34 /*************************************************************/
  35 
  36 #include "nsk_tools.h"
  37 #include "jni_tools.h"
  38 #include "jvmti_tools.h"
  39 #include "JVMTITools.h"
  40 
  41 /*************************************************************/
  42 
  43 extern "C" {
  44 
  45 /*************************************************************/
  46 
  47 #define NSK_JVMTI_WAITTIME 2
  48 
  49 #define NSK_JVMTI_MAX_OPTIONS       10
  50 #define NSK_JVMTI_OPTION_START      '-'
  51 #define NSK_JVMTI_OPTION_VAL_SEP    '='
  52 
  53 #define NSK_JVMTI_OPT_PATH_TO_NEW_BYTE_CODE "pathToNewByteCode"
  54 #define PATH_FORMAT "%s%02d/%s"
  55 #define DIR_NAME "newclass"
  56 
  57 static volatile int redefineAttempted = NSK_FALSE;
  58 static volatile int redefineSucceed = NSK_FALSE;
  59 static volatile int agentFailed = NSK_FALSE;
  60 
  61 static struct {
  62     struct {
  63         int count;
  64         char* names[NSK_JVMTI_MAX_OPTIONS];
  65         char* values[NSK_JVMTI_MAX_OPTIONS];
  66         char* string;
  67     } options;
  68     int waittime;
  69 } context;
  70 
  71 /*************************************************************/
  72 
  73 static int check_option(int dashed, const char name[], const char value[]) {
  74     if (strcmp("verbose", name) == 0) {
  75         if (strlen(value) > 0) {
  76             nsk_complain("nsk_jvmti_parseOptions(): unexpected value in option: %s=%s\n", name, value);
  77             return NSK_FALSE;
  78         }
  79         nsk_setVerboseMode(NSK_TRUE);
  80     } else if (strcmp("trace", name) == 0) {
  81         if (strlen(value) <= 0) {
  82             nsk_complain("nsk_jvmti_parseOptions(): no value for option: %s\n", name);
  83             return NSK_FALSE;
  84         }
  85         if (strcmp("none", value) == 0) {
  86             nsk_setTraceMode(NSK_TRACE_NONE);
  87         } else if (strcmp("before", value) == 0) {
  88             nsk_setTraceMode(NSK_TRACE_BEFORE);
  89         } else if (strcmp("after", value) == 0) {
  90             nsk_setTraceMode(NSK_TRACE_AFTER);
  91         } else if (strcmp("all", value) == 0) {
  92             nsk_setTraceMode(NSK_TRACE_ALL);
  93         } else {
  94             nsk_complain("nsk_jvmti_parseOptions(): uexpected value in option: %s=%s\n", name, value);
  95             return NSK_FALSE;
  96         }
  97         nsk_setVerboseMode(NSK_TRUE);
  98     } else if (strcmp("waittime", name) == 0) {
  99         if (strlen(value) <= 0) {
 100             nsk_complain("nsk_jvmti_parseOptions(): no value for option: %s\n", name);
 101             return NSK_FALSE;
 102         }
 103         {
 104             char* end = NULL;
 105             long n = strtol(value, &end, 10);
 106             if (end == NULL || end == value || *end != '\0') {
 107                 nsk_complain("nsk_jvmti_parseOptions(): not integer value in option: %s=%s\n", name, value);
 108                 return NSK_FALSE;
 109             }
 110             if (n < 0) {
 111                 nsk_complain("nsk_jvmti_parseOptions(): negative value in option: %s=%s\n", name, value);
 112                 return NSK_FALSE;
 113             }
 114             context.waittime = (int)n;
 115         }
 116     } else if (dashed) {
 117         nsk_complain("nsk_jvmti_parseOptions(): unknown option: %c%s\n",
 118                                                         NSK_JVMTI_OPTION_START, name);
 119         return NSK_FALSE;
 120     }
 121     return NSK_TRUE;
 122 }
 123 
 124 static int add_option(const char opt[], int opt_len, const char val[], int val_len) {
 125     char* name;
 126     char* value;
 127 
 128     int success = NSK_TRUE;
 129     int dashed_opt = NSK_FALSE;
 130 
 131     if (opt[0] == NSK_JVMTI_OPTION_START) {
 132         dashed_opt = NSK_TRUE;
 133         opt++;
 134         opt_len--;
 135     }
 136     if (opt_len <= 0) {
 137         nsk_complain("nsk_jvmti_parseOptions(): found empty option\n");
 138         return NSK_FALSE;
 139     }
 140 
 141     name = (char*)malloc(opt_len + 1);
 142     value = (char*)malloc(val_len + 1);
 143 
 144     if (name == NULL || value == NULL) {
 145         nsk_complain("nsk_jvmti_parseOptions(): out of memory\n");
 146         success = NSK_FALSE;
 147     } else {
 148         strncpy(name, opt, opt_len);
 149         name[opt_len] = '\0';
 150         strncpy(value, val, val_len);
 151         value[val_len] = '\0';
 152 
 153         if (!check_option(dashed_opt, name, value)) {
 154             success = NSK_FALSE;
 155         }
 156     }
 157 
 158     if (success) {
 159         if (context.options.count >= NSK_JVMTI_MAX_OPTIONS) {
 160             nsk_complain("nsk_jvmti_parseOptions(): too many options for parsing\n");
 161             success = NSK_FALSE;
 162         } else {
 163             context.options.names[context.options.count] = name;
 164             context.options.values[context.options.count] = value;
 165             context.options.count++;
 166         }
 167     }
 168 
 169     if (!success) {
 170         if (name != NULL)
 171             free(name);
 172         if (value != NULL)
 173             free(value);
 174     }
 175 
 176     return success;
 177 }
 178 
 179 static void nsk_jvmti_free() {
 180     if (context.options.count > 0) {
 181         int i;
 182         for (i = 0; i < context.options.count; i++) {
 183             free(context.options.names[i]);
 184             free(context.options.values[i]);
 185         }
 186         context.options.count = 0;
 187     }
 188     if (context.options.string != NULL) {
 189         free(context.options.string);
 190         context.options.string = NULL;
 191     }
 192 }
 193 
 194 int isOptSep(char c) {
 195     return isspace(c) || c == '~';
 196 }
 197 
 198 
 199 /**
 200  *
 201  * The current option will not perform more than one
 202  * single option which given, this is due to places explained
 203  * in this question.
 204  *
 205  **/
 206 
 207  /*
 208   * This whole play can be reduced with simple StringTokenizer (strtok).
 209   *
 210   */
 211 
 212 int nsk_jvmti_parseOptions(const char options[]) {
 213     size_t len;
 214     const char* opt;
 215     int success = NSK_TRUE;
 216 
 217     context.options.string = NULL;
 218     context.options.count = 0;
 219     context.waittime = 2;
 220 
 221     if (options == NULL)
 222         return NSK_TRUE;
 223 
 224     len = strlen(options);
 225     context.options.string = (char*)malloc(len + 2);
 226 
 227     if (context.options.string == NULL) {
 228             nsk_complain("nsk_jvmti_parseOptions(): out of memory\n");
 229             return NSK_FALSE;
 230     }
 231     strncpy(context.options.string, options, len);
 232     context.options.string[len] = '\0';
 233     context.options.string[len+1] = '\0';
 234 
 235     for (opt = context.options.string; ; ) {
 236         const char* opt_end;
 237         const char* val_sep;
 238         int opt_len=0;
 239         int val_len=0;
 240                 int exit=1;
 241 
 242         while (*opt != '\0' && isOptSep(*opt)) opt++;
 243         if (*opt == '\0') break;
 244 
 245         val_sep = NULL;
 246         /*
 247             This should break when the first option it encounters other wise
 248         */
 249         for (opt_end = opt, opt_len=0; !(*opt_end == '\0' || isOptSep(*opt_end)); opt_end++,opt_len++) {
 250             if (*opt_end == NSK_JVMTI_OPTION_VAL_SEP) {
 251                 val_sep = opt_end;
 252                 exit=0;
 253                 break;
 254             }
 255         }
 256 
 257         if (exit == 1) break;
 258 
 259         /* now scan for the search  for the option value end.
 260 
 261         */
 262         exit =1;
 263         opt_end++;
 264         val_sep++;
 265         /**
 266          * I was expecting this jvmti_parseOptions(),
 267          * should be for multiple options as well.
 268          * If this break is not there then It will expects
 269          * to have. so a space should be sufficient as well.
 270          */
 271         for(val_len=0; !(*opt_end == '\0' || isOptSep(*opt_end)); opt_end++,val_len++) {
 272             //if (*opt_end == NSK_JVMTI_OPTION_START) {
 273             //    break;
 274             //}
 275         }
 276 
 277         if (!add_option(opt, opt_len, val_sep, val_len)) {
 278             success = NSK_FALSE;
 279             break;
 280         }
 281         opt_end++;
 282         opt = opt_end;
 283     }
 284 
 285     if (!success) {
 286         nsk_jvmti_free();
 287     }
 288 
 289     return success;
 290 }
 291 
 292 
 293 /*************************************************************/
 294 
 295 /**
 296  * Returns value of given option name; or NULL if no such option found.
 297  * If search name is NULL then complains an error and returns NULL.
 298  */
 299 const char* nsk_jvmti_findOptionValue(const char name[]) {
 300     int i;
 301 
 302     if (name == NULL) {
 303         nsk_complain("nsk_jvmti_findOptionValue(): option name is NULL\n");
 304         return NULL;
 305     }
 306 
 307     for (i = 0; i < context.options.count; i++) {
 308         if (strcmp(name, context.options.names[i]) == 0)
 309             return context.options.values[i];
 310     }
 311     return NULL;
 312 }
 313 
 314 /**
 315  * Returns string value of given option; or defaultValue if no such option found.
 316  * If options is specified but has empty value then complains an error and returns NULL.
 317  */
 318 const char* nsk_jvmti_findOptionStringValue(const char name[], const char* defaultValue) {
 319     const char* value;
 320 
 321     if (name == NULL) {
 322         nsk_complain("nsk_jvmti_findOptionStringValue(): option name is NULL\n");
 323         return NULL;
 324     }
 325 
 326     value = nsk_jvmti_findOptionValue(name);
 327     if (value == NULL) {
 328         return defaultValue;
 329     }
 330 
 331     if (strlen(value) <= 0) {
 332         nsk_complain("nsk_jvmti_findOptionStringValue(): empty value of option: %s=%s\n",
 333                                                                             name, value);
 334         return NULL;
 335     }
 336     return value;
 337 }
 338 
 339 /**
 340  * Returns integer value of given option; or defaultValue if no such option found.
 341  * If options is specified but has no integer value then complains an error and returns -1.
 342  */
 343 int nsk_jvmti_findOptionIntValue(const char name[], int defaultValue) {
 344     const char* value;
 345 
 346     if (name == NULL) {
 347         nsk_complain("nsk_jvmti_findOptionIntValue(): option name is NULL\n");
 348         return -1;
 349     }
 350 
 351     value = nsk_jvmti_findOptionValue(name);
 352     if (value == NULL) {
 353         return defaultValue;
 354     }
 355 
 356     if (strlen(value) <= 0) {
 357         nsk_complain("nsk_jvmti_findOptionIntValue(): empty value of option: %s=%s\n",
 358                                                                             name, value);
 359         return -1;
 360     }
 361 
 362     {
 363         char* endptr = NULL;
 364         int n = strtol(value, &endptr, 10);
 365 
 366         if (endptr == NULL || *endptr != '\0') {
 367             nsk_complain("nsk_jvmti_findOptionIntValue(): not integer value of option: %s=%s\n",
 368                                                                             name, value);
 369             return -1;
 370         }
 371         return n;
 372     }
 373 }
 374 
 375 /**
 376  * Returns number of parsed options.
 377  */
 378 int nsk_jvmti_getOptionsCount() {
 379     return context.options.count;
 380 }
 381 
 382 /**
 383  * Returns name of i-th parsed option.
 384  * If no such option then complains an error and returns NULL.
 385  */
 386 const char* nsk_jvmti_getOptionName(int i) {
 387     if (i < 0 || i >= context.options.count) {
 388         nsk_complain("nsk_jvmti_getOptionName(): option index out of bounds: %d\n", i);
 389         return NULL;
 390     }
 391     return context.options.names[i];
 392 }
 393 
 394 /**
 395  * Returns value of i-th parsed option.
 396  * If no such option then complains an error and returns NULL.
 397  */
 398 const char* nsk_jvmti_getOptionValue(int i) {
 399     if (i < 0 || i >= context.options.count) {
 400         nsk_complain("nsk_jvmti_getOptionValue(): option index out of bounds: %d\n", i);
 401         return NULL;
 402     }
 403     return context.options.values[i];
 404 }
 405 
 406 /*************************************************************/
 407 
 408 /**
 409  * Returns value of -waittime option or default value if not specified.
 410  */
 411 int  nsk_jvmti_getWaitTime() {
 412     return context.waittime;
 413 }
 414 
 415 /**
 416  * Sets specified waittime value.
 417  */
 418 void nsk_jvmti_setWaitTime(int waittime) {
 419     context.waittime = waittime;
 420 }
 421 
 422 /*************************************************************/
 423 
 424 int nsk_jvmti_lverify(int positive, jvmtiError error, jvmtiError expected,
 425                         const char file[], int line, const char format[], ...)
 426 {
 427     int failure=0;
 428     int negative = !positive;
 429     int errorCode = (int)error;
 430     const char* errorName = TranslateError(error);
 431     va_list ap;
 432     va_start(ap,format);
 433     nsk_lvtrace(NSK_TRACE_AFTER,file,line,format,ap);
 434     if (negative || expected != JVMTI_ERROR_NONE)
 435         nsk_ltrace(NSK_TRACE_AFTER,file,line,
 436             "  jvmti error: code=%d, name=%s\n",errorCode,errorName);
 437     if ((error == expected) == negative) {
 438         nsk_lvcomplain(file,line,format,ap);
 439         nsk_printf("#   jvmti error: code=%d, name=%s\n",errorCode,errorName);
 440         if (expected != JVMTI_ERROR_NONE)
 441             nsk_printf("#   error expected: code=%d, name=%s\n",
 442                 expected, TranslateError(expected));
 443         failure=1;
 444     };
 445     va_end(ap);
 446     return !failure;
 447 }
 448 
 449 /*************************************************************/
 450 
 451 JNIEXPORT jstring JNICALL
 452 Java_nsk_share_jvmti_ArgumentHandler_getAgentOptionsString(JNIEnv *jni, jobject obj) {
 453     jstring str_obj = NULL;
 454 
 455     if (!NSK_JNI_VERIFY(jni, (str_obj =
 456             NSK_CPP_STUB2(NewStringUTF, jni, context.options.string)) != NULL)) {
 457         return NULL;
 458     }
 459     return str_obj;
 460 }
 461 
 462 /*************************************************************/
 463 
 464 /**
 465   * This method will try to redefine the class (classToRedefine) by loading
 466   * physical file.  <b>pathToNewByteCode</b> option which is passed
 467   * on OnLoad Phase also used.
 468   *
 469   * So This method will do a file read pathToByteCode+fileName+.class (total path).
 470   * Constrcuts a class objects and does a redefine of the class.
 471   * On successfull redefine this method will return eaither JNI_TRUE or JNI_FALSE
 472   *
 473   * Hint::
 474   *     1)
 475   *      If there are many redefine on same testcase, then please try to use
 476   *      integer value (newclass00, newclass01, newclass02 , ....) way.
 477   *
 478   *     2) When you compile these please do keep, a metatag on testcase as
 479   *     # build : native classes classes.redef
 480   *
 481   *     3) When you do build these classes are psysically located in build as.
 482   *
 483   * TESTBASE/bin/newclass0* directory.
 484   * eg: for nks/jvmti/scenarios/hotswap/HS204/hs204t001 you should see
 485   * TESTBASE/bin/newclass0* /nsk/hotswap/HS204/hs204t001/MyClass.class
 486   *
 487   */
 488 
 489 int nsk_jvmti_redefineClass(jvmtiEnv * jvmti,
 490         jclass classToRedefine,
 491         const char * fileName) {
 492     redefineAttempted = NSK_TRUE;
 493     if ( nsk_jvmti_findOptionValue(NSK_JVMTI_OPT_PATH_TO_NEW_BYTE_CODE)
 494             == NULL  ) {
 495         nsk_printf("#   error expected: %s \n",
 496                 NSK_JVMTI_OPT_PATH_TO_NEW_BYTE_CODE );
 497         nsk_printf("Hint :: missing java -agentlib:agentlib=%s=DirName, ($TESTBASE/bin) \n",
 498                 NSK_JVMTI_OPT_PATH_TO_NEW_BYTE_CODE );
 499         return NSK_FALSE;
 500     }
 501     if ( fileName == NULL) {
 502         nsk_printf("# error file name expected did not found \n");
 503         return NSK_FALSE;
 504     }
 505     {
 506         char file [1024];
 507         //= "DEFAULT";
 508         sprintf(file,"%s/%s.class",
 509                 nsk_jvmti_findOptionValue(NSK_JVMTI_OPT_PATH_TO_NEW_BYTE_CODE),
 510                 fileName);
 511         nsk_printf("# info :: File = %s \n",file);
 512 
 513         {
 514             FILE *bytecode;
 515             unsigned char * classBytes;
 516             jvmtiError error;
 517             jint size;
 518 
 519             bytecode = fopen(file, "rb");
 520             error= JVMTI_ERROR_NONE;
 521             if ( bytecode == NULL ) {
 522                 nsk_printf("# error **Agent::error opening file %s \n",file);
 523                 return NSK_FALSE;
 524             }
 525 
 526             nsk_printf("#  info **Agent:: opening file %s \n",file);
 527             fseek(bytecode, 0, SEEK_END);
 528             size = ftell(bytecode);
 529             nsk_printf("# info file size= %ld\n",ftell(bytecode));
 530             rewind(bytecode);
 531             error = jvmti->Allocate(size,&classBytes);
 532             if ( error != JVMTI_ERROR_NONE) {
 533                 nsk_printf(" Failed to create memory %s \n",TranslateError(error));
 534                 return NSK_FALSE;
 535             }
 536 
 537             if ( ((jint) fread( classBytes, 1,size,bytecode )) != size ) {
 538                 nsk_printf(" # error failed to read all the bytes , could be less or more \n");
 539                 return NSK_FALSE;
 540             } else {
 541                 nsk_printf(" File red completely \n");
 542             }
 543             fclose(bytecode);
 544             {
 545                 jvmtiClassDefinition classDef;
 546                 classDef.klass = classToRedefine;
 547                 classDef.class_byte_count= size;
 548                 classDef.class_bytes = classBytes;
 549                 error = jvmti->RedefineClasses(1,&classDef);
 550                 if ( error != JVMTI_ERROR_NONE ) {
 551                     nsk_printf("# error occured while redefining %s ",
 552                             TranslateError(error) );
 553                     return NSK_FALSE;
 554                 }
 555             }
 556         }
 557     }
 558     redefineSucceed= NSK_TRUE;
 559     return NSK_TRUE;
 560 }
 561 
 562 JNIEXPORT jboolean JNICALL
 563 Java_nsk_share_jvmti_RedefineAgent_redefineAttempted(JNIEnv *jni,  jobject obj) {
 564 
 565     if (redefineAttempted == NSK_TRUE) {
 566         return JNI_TRUE;
 567     }else {
 568         return JNI_FALSE;
 569     }
 570 }
 571 
 572 
 573 JNIEXPORT jboolean JNICALL
 574 Java_nsk_share_jvmti_RedefineAgent_isRedefined(JNIEnv * jni,  jobject obj ) {
 575 
 576     if (redefineSucceed == NSK_TRUE) {
 577         return JNI_TRUE;
 578     }else {
 579         return JNI_FALSE;
 580     }
 581 }
 582 /**
 583  * This jni method is a Java wrapper for agent status.
 584  */
 585 JNIEXPORT jboolean JNICALL
 586 Java_nsk_share_jvmti_RedefineAgent_agentStatus(JNIEnv * jni,  jobject obj ) {
 587     if ( agentFailed == NSK_TRUE) {
 588         return JNI_FALSE;
 589     } else {
 590         return JNI_TRUE;
 591     }
 592 }
 593 
 594 void nsk_jvmti_getFileName(int redefineCnt, const char * dir,  char * buf, size_t bufsize) {
 595    snprintf(buf, bufsize, PATH_FORMAT, DIR_NAME, redefineCnt, dir);
 596    buf[bufsize-1] = '\0';
 597 }
 598 
 599 int nsk_jvmti_enableNotification(jvmtiEnv *jvmti,jvmtiEvent event, jthread thread) {
 600     jvmtiError rc=JVMTI_ERROR_NONE;
 601     rc = jvmti->SetEventNotificationMode(JVMTI_ENABLE, event, thread);
 602     if (rc != JVMTI_ERROR_NONE) {
 603         nsk_printf("# error Failed to set Notification for Event \n ");
 604         return NSK_FALSE;
 605     }
 606     return NSK_TRUE;
 607 }
 608 
 609 int nsk_jvmti_disableNotification(jvmtiEnv *jvmti,jvmtiEvent event, jthread thread) {
 610   jvmtiError rc=JVMTI_ERROR_NONE;
 611   rc = jvmti->SetEventNotificationMode(JVMTI_DISABLE, event, thread);
 612   if (rc != JVMTI_ERROR_NONE) {
 613       nsk_printf(" Failed to disaable Notification for Event ");
 614       return NSK_FALSE;
 615   }
 616   return NSK_TRUE;
 617 }
 618 
 619 void nsk_jvmti_agentFailed() {
 620     agentFailed = NSK_TRUE;
 621 }
 622 
 623 int isThreadExpected(jvmtiEnv *jvmti, jthread thread) {
 624     static const char *vm_jfr_buffer_thread_name = "VM JFR Buffer Thread";
 625     static const char *jfr_request_timer_thread_name = "JFR request timer";
 626 
 627     jvmtiThreadInfo threadinfo;
 628     NSK_JVMTI_VERIFY(jvmti->GetThreadInfo(thread, &threadinfo));
 629 
 630     if (strcmp(threadinfo.name, vm_jfr_buffer_thread_name) == 0)
 631         return 0;
 632 
 633     if (strcmp(threadinfo.name, jfr_request_timer_thread_name) == 0)
 634         return 0;
 635 
 636     return 1;
 637 }
 638 
 639 jint createRawMonitor(jvmtiEnv *env, const char *name, jrawMonitorID *monitor) {
 640     jvmtiError error = NSK_CPP_STUB3(CreateRawMonitor, env, name, monitor);
 641     if (!NSK_JVMTI_VERIFY(error)) {
 642         return JNI_ERR;
 643     }
 644     return JNI_OK;
 645 }
 646 
 647 void exitOnError(jvmtiError error) {
 648     if (!NSK_JVMTI_VERIFY(error)) {
 649         exit(error);
 650     }
 651 }
 652 
 653 void rawMonitorEnter(jvmtiEnv *env, jrawMonitorID monitor) {
 654     jvmtiError error = NSK_CPP_STUB2(RawMonitorEnter, env, monitor);
 655     exitOnError(error);
 656 }
 657 
 658 void rawMonitorExit(jvmtiEnv *env, jrawMonitorID monitor) {
 659     jvmtiError error = NSK_CPP_STUB2(RawMonitorExit, env, monitor);
 660     exitOnError(error);
 661 }
 662 
 663 void rawMonitorNotify(jvmtiEnv *env, jrawMonitorID monitor) {
 664     jvmtiError error = NSK_CPP_STUB2(RawMonitorNotify, env, monitor);
 665     exitOnError(error);
 666 }
 667 
 668 void rawMonitorWait(jvmtiEnv *env, jrawMonitorID monitor, jlong millis) {
 669     jvmtiError error = NSK_CPP_STUB3(RawMonitorWait, env, monitor, millis);
 670     exitOnError(error);
 671 }
 672 
 673 void getPhase(jvmtiEnv *env, jvmtiPhase *phase) {
 674     jvmtiError error = NSK_CPP_STUB2(GetPhase, env, phase);
 675     exitOnError(error);
 676 }
 677 
 678 /*************************************************************/
 679 
 680 }