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