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 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 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 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 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 int nsk_jvmti_parseOptions(const char options[]) { 215 size_t len; 216 const char* opt; 217 int success = NSK_TRUE; 218 219 context.options.string = NULL; 220 context.options.count = 0; 221 context.waittime = 2; 222 223 if (options == NULL) 224 return NSK_TRUE; 225 226 len = strlen(options); 227 context.options.string = (char*)malloc(len + 2); 228 229 if (context.options.string == NULL) { 230 nsk_complain("nsk_jvmti_parseOptions(): out of memory\n"); 231 return NSK_FALSE; 232 } 233 strncpy(context.options.string, options, len); 234 context.options.string[len] = '\0'; 235 context.options.string[len+1] = '\0'; 236 237 for (opt = context.options.string; ; ) { 238 const char* opt_end; 239 const char* val_sep; 240 int opt_len=0; 241 int val_len=0; 242 int exit=1; 243 244 while (*opt != '\0' && isOptSep(*opt)) opt++; 245 if (*opt == '\0') break; 246 247 val_sep = NULL; 248 /* 249 This should break when the first option it encounters other wise 250 */ 251 for (opt_end = opt, opt_len=0; !(*opt_end == '\0' || isOptSep(*opt_end)); opt_end++,opt_len++) { 252 if (*opt_end == NSK_JVMTI_OPTION_VAL_SEP) { 253 val_sep = opt_end; 254 exit=0; 255 break; 256 } 257 } 258 259 if (exit == 1) break; 260 261 /* now scan for the search for the option value end. 262 263 */ 264 exit =1; 265 opt_end++; 266 val_sep++; 267 /** 268 * I was expecting this jvmti_parseOptions(), 269 * should be for multiple options as well. 270 * If this break is not there then It will expects 271 * to have. so a space should be sufficient as well. 272 */ 273 for(val_len=0; !(*opt_end == '\0' || isOptSep(*opt_end)); opt_end++,val_len++) { 274 //if (*opt_end == NSK_JVMTI_OPTION_START) { 275 // break; 276 //} 277 } 278 279 if (!add_option(opt, opt_len, val_sep, val_len)) { 280 success = NSK_FALSE; 281 break; 282 } 283 opt_end++; 284 opt = opt_end; 285 } 286 287 if (!success) { 288 nsk_jvmti_free(); 289 } 290 291 return success; 292 } 293 294 295 /*************************************************************/ 296 297 /** 298 * Returns value of given option name; or NULL if no such option found. 299 * If search name is NULL then complains an error and returns NULL. 300 */ 301 const char* nsk_jvmti_findOptionValue(const char name[]) { 302 int i; 303 304 if (name == NULL) { 305 nsk_complain("nsk_jvmti_findOptionValue(): option name is NULL\n"); 306 return NULL; 307 } 308 309 for (i = 0; i < context.options.count; i++) { 310 if (strcmp(name, context.options.names[i]) == 0) 311 return context.options.values[i]; 312 } 313 return NULL; 314 } 315 316 /** 317 * Returns string value of given option; or defaultValue if no such option found. 318 * If options is specified but has empty value then complains an error and returns NULL. 319 */ 320 const char* nsk_jvmti_findOptionStringValue(const char name[], const char* defaultValue) { 321 const char* value; 322 323 if (name == NULL) { 324 nsk_complain("nsk_jvmti_findOptionStringValue(): option name is NULL\n"); 325 return NULL; 326 } 327 328 value = nsk_jvmti_findOptionValue(name); 329 if (value == NULL) { 330 return defaultValue; 331 } 332 333 if (strlen(value) <= 0) { 334 nsk_complain("nsk_jvmti_findOptionStringValue(): empty value of option: %s=%s\n", 335 name, value); 336 return NULL; 337 } 338 return value; 339 } 340 341 /** 342 * Returns integer value of given option; or defaultValue if no such option found. 343 * If options is specified but has no integer value then complains an error and returns -1. 344 */ 345 int nsk_jvmti_findOptionIntValue(const char name[], int defaultValue) { 346 const char* value; 347 348 if (name == NULL) { 349 nsk_complain("nsk_jvmti_findOptionIntValue(): option name is NULL\n"); 350 return -1; 351 } 352 353 value = nsk_jvmti_findOptionValue(name); 354 if (value == NULL) { 355 return defaultValue; 356 } 357 358 if (strlen(value) <= 0) { 359 nsk_complain("nsk_jvmti_findOptionIntValue(): empty value of option: %s=%s\n", 360 name, value); 361 return -1; 362 } 363 364 { 365 char* endptr = NULL; 366 int n = strtol(value, &endptr, 10); 367 368 if (endptr == NULL || *endptr != '\0') { 369 nsk_complain("nsk_jvmti_findOptionIntValue(): not integer value of option: %s=%s\n", 370 name, value); 371 return -1; 372 } 373 return n; 374 } 375 } 376 377 /** 378 * Returns number of parsed options. 379 */ 380 int nsk_jvmti_getOptionsCount() { 381 return context.options.count; 382 } 383 384 /** 385 * Returns name of i-th parsed option. 386 * If no such option then complains an error and returns NULL. 387 */ 388 const char* nsk_jvmti_getOptionName(int i) { 389 if (i < 0 || i >= context.options.count) { 390 nsk_complain("nsk_jvmti_getOptionName(): option index out of bounds: %d\n", i); 391 return NULL; 392 } 393 return context.options.names[i]; 394 } 395 396 /** 397 * Returns value of i-th parsed option. 398 * If no such option then complains an error and returns NULL. 399 */ 400 const char* nsk_jvmti_getOptionValue(int i) { 401 if (i < 0 || i >= context.options.count) { 402 nsk_complain("nsk_jvmti_getOptionValue(): option index out of bounds: %d\n", i); 403 return NULL; 404 } 405 return context.options.values[i]; 406 } 407 408 /*************************************************************/ 409 410 /** 411 * Returns value of -waittime option or default value if not specified. 412 */ 413 int nsk_jvmti_getWaitTime() { 414 return context.waittime; 415 } 416 417 /** 418 * Sets specified waittime value. 419 */ 420 void nsk_jvmti_setWaitTime(int waittime) { 421 context.waittime = waittime; 422 } 423 424 /*************************************************************/ 425 426 int nsk_jvmti_lverify(int positive, jvmtiError error, jvmtiError expected, 427 const char file[], int line, const char format[], ...) 428 { 429 int failure=0; 430 int negative = !positive; 431 int errorCode = (int)error; 432 const char* errorName = TranslateError(error); 433 va_list ap; 434 va_start(ap,format); 435 nsk_lvtrace(NSK_TRACE_AFTER,file,line,format,ap); 436 if (negative || expected != JVMTI_ERROR_NONE) 437 nsk_ltrace(NSK_TRACE_AFTER,file,line, 438 " jvmti error: code=%d, name=%s\n",errorCode,errorName); 439 if ((error == expected) == negative) { 440 nsk_lvcomplain(file,line,format,ap); 441 nsk_printf("# jvmti error: code=%d, name=%s\n",errorCode,errorName); 442 if (expected != JVMTI_ERROR_NONE) 443 nsk_printf("# error expected: code=%d, name=%s\n", 444 expected, TranslateError(expected)); 445 failure=1; 446 }; 447 va_end(ap); 448 return !failure; 449 } 450 451 /*************************************************************/ 452 453 JNIEXPORT jstring JNICALL 454 Java_nsk_share_jvmti_ArgumentHandler_getAgentOptionsString(JNIEnv *jni, jobject obj) { 455 jstring str_obj = NULL; 456 457 if (!NSK_JNI_VERIFY(jni, (str_obj = 458 NSK_CPP_STUB2(NewStringUTF, jni, context.options.string)) != NULL)) { 459 return NULL; 460 } 461 return str_obj; 462 } 463 464 /*************************************************************/ 465 466 /** 467 * This method will try to redefine the class (classToRedefine) by loading 468 * physical file. <b>pathToNewByteCode</b> option which is passed 469 * on OnLoad Phase also used. 470 * 471 * So This method will do a file read pathToByteCode+fileName+.class (total path). 472 * Constrcuts a class objects and does a redefine of the class. 473 * On successfull redefine this method will return eaither JNI_TRUE or JNI_FALSE 474 * 475 * Hint:: 476 * 1) 477 * If there are many redefine on same testcase, then please try to use 478 * integer value (newclass00, newclass01, newclass02 , ....) way. 479 * 480 * 2) When you compile these please do keep, a metatag on testcase as 481 * # build : native classes classes.redef 482 * 483 * 3) When you do build these classes are psysically located in build as. 484 * 485 * TESTBASE/bin/newclass0* directory. 486 * eg: for nks/jvmti/scenarios/hotswap/HS204/hs204t001 you should see 487 * TESTBASE/bin/newclass0* /nsk/hotswap/HS204/hs204t001/MyClass.class 488 * 489 */ 490 491 int nsk_jvmti_redefineClass(jvmtiEnv * jvmti, 492 jclass classToRedefine, 493 const char * fileName) { 494 redefineAttempted = NSK_TRUE; 495 if ( nsk_jvmti_findOptionValue(NSK_JVMTI_OPT_PATH_TO_NEW_BYTE_CODE) 496 == NULL ) { 497 nsk_printf("# error expected: %s \n", 498 NSK_JVMTI_OPT_PATH_TO_NEW_BYTE_CODE ); 499 nsk_printf("Hint :: missing java -agentlib:agentlib=%s=DirName, ($TESTBASE/bin) \n", 500 NSK_JVMTI_OPT_PATH_TO_NEW_BYTE_CODE ); 501 return NSK_FALSE; 502 } 503 if ( fileName == NULL) { 504 nsk_printf("# error file name expected did not found \n"); 505 return NSK_FALSE; 506 } 507 { 508 char file [1024]; 509 //= "DEFAULT"; 510 sprintf(file,"%s/%s.class", 511 nsk_jvmti_findOptionValue(NSK_JVMTI_OPT_PATH_TO_NEW_BYTE_CODE), 512 fileName); 513 nsk_printf("# info :: File = %s \n",file); 514 515 { 516 FILE *bytecode; 517 unsigned char * classBytes; 518 jvmtiError error; 519 jint size; 520 521 bytecode = fopen(file, "rb"); 522 error= JVMTI_ERROR_NONE; 523 if ( bytecode == NULL ) { 524 nsk_printf("# error **Agent::error opening file %s \n",file); 525 return NSK_FALSE; 526 } 527 528 nsk_printf("# info **Agent:: opening file %s \n",file); 529 fseek(bytecode, 0, SEEK_END); 530 size = ftell(bytecode); 531 nsk_printf("# info file size= %ld\n",ftell(bytecode)); 532 rewind(bytecode); 533 error = (*jvmti)->Allocate(jvmti, size,&classBytes); 534 if ( error != JVMTI_ERROR_NONE) { 535 nsk_printf(" Failed to create memory %s \n",TranslateError(error)); 536 return NSK_FALSE; 537 } 538 539 if ( ((jint) fread( classBytes, 1,size,bytecode )) != size ) { 540 nsk_printf(" # error failed to read all the bytes , could be less or more \n"); 541 return NSK_FALSE; 542 } else { 543 nsk_printf(" File red completely \n"); 544 } 545 fclose(bytecode); 546 { 547 jvmtiClassDefinition classDef; 548 classDef.klass = classToRedefine; 549 classDef.class_byte_count= size; 550 classDef.class_bytes = classBytes; 551 error = (*jvmti)->RedefineClasses(jvmti,1,&classDef); 552 if ( error != JVMTI_ERROR_NONE ) { 553 nsk_printf("# error occured while redefining %s ", 554 TranslateError(error) ); 555 return NSK_FALSE; 556 } 557 } 558 } 559 } 560 redefineSucceed= NSK_TRUE; 561 return NSK_TRUE; 562 } 563 564 JNIEXPORT jboolean JNICALL 565 Java_nsk_share_jvmti_RedefineAgent_redefineAttempted(JNIEnv *jni, jobject obj) { 566 567 if (redefineAttempted == NSK_TRUE) { 568 return JNI_TRUE; 569 }else { 570 return JNI_FALSE; 571 } 572 } 573 574 575 JNIEXPORT jboolean JNICALL 576 Java_nsk_share_jvmti_RedefineAgent_isRedefined(JNIEnv * jni, jobject obj ) { 577 578 if (redefineSucceed == NSK_TRUE) { 579 return JNI_TRUE; 580 }else { 581 return JNI_FALSE; 582 } 583 } 584 /** 585 * This jni method is a Java wrapper for agent status. 586 */ 587 JNIEXPORT jboolean JNICALL 588 Java_nsk_share_jvmti_RedefineAgent_agentStatus(JNIEnv * jni, jobject obj ) { 589 if ( agentFailed == NSK_TRUE) { 590 return JNI_FALSE; 591 } else { 592 return JNI_TRUE; 593 } 594 } 595 596 void nsk_jvmti_getFileName(int redefineCnt, const char * dir, char * buf, size_t bufsize) { 597 snprintf(buf, bufsize, PATH_FORMAT, DIR_NAME, redefineCnt, dir); 598 buf[bufsize-1] = '\0'; 599 } 600 601 int nsk_jvmti_enableNotification(jvmtiEnv *jvmti,jvmtiEvent event, jthread thread) { 602 jvmtiError rc=JVMTI_ERROR_NONE; 603 rc = (*jvmti)->SetEventNotificationMode(jvmti,JVMTI_ENABLE, event, thread); 604 if (rc != JVMTI_ERROR_NONE) { 605 nsk_printf("# error Failed to set Notification for Event \n "); 606 return NSK_FALSE; 607 } 608 return NSK_TRUE; 609 } 610 611 int nsk_jvmti_disableNotification(jvmtiEnv *jvmti,jvmtiEvent event, jthread thread) { 612 jvmtiError rc=JVMTI_ERROR_NONE; 613 rc = (*jvmti)->SetEventNotificationMode(jvmti,JVMTI_DISABLE, event, thread); 614 if (rc != JVMTI_ERROR_NONE) { 615 nsk_printf(" Failed to disaable Notification for Event "); 616 return NSK_FALSE; 617 } 618 return NSK_TRUE; 619 } 620 621 void nsk_jvmti_agentFailed() { 622 agentFailed = NSK_TRUE; 623 } 624 625 int isThreadExpected(jvmtiEnv *jvmti, jthread thread) { 626 static const char *vm_jfr_buffer_thread_name = "VM JFR Buffer Thread"; 627 static const char *jfr_request_timer_thread_name = "JFR request timer"; 628 629 jvmtiThreadInfo threadinfo; 630 NSK_JVMTI_VERIFY((*jvmti)->GetThreadInfo(jvmti, thread, &threadinfo)); 631 632 if (strcmp(threadinfo.name, vm_jfr_buffer_thread_name) == 0) 633 return 0; 634 635 if (strcmp(threadinfo.name, jfr_request_timer_thread_name) == 0) 636 return 0; 637 638 return 1; 639 } 640 641 jint createRawMonitor(jvmtiEnv *env, const char *name, jrawMonitorID *monitor) { 642 jvmtiError error = NSK_CPP_STUB3(CreateRawMonitor, env, name, monitor); 643 if (!NSK_JVMTI_VERIFY(error)) { 644 return JNI_ERR; 645 } 646 return JNI_OK; 647 } 648 649 void exitOnError(jvmtiError error) { 650 if (!NSK_JVMTI_VERIFY(error)) { 651 exit(error); 652 } 653 } 654 655 void rawMonitorEnter(jvmtiEnv *env, jrawMonitorID monitor) { 656 jvmtiError error = NSK_CPP_STUB2(RawMonitorEnter, env, monitor); 657 exitOnError(error); 658 } 659 660 void rawMonitorExit(jvmtiEnv *env, jrawMonitorID monitor) { 661 jvmtiError error = NSK_CPP_STUB2(RawMonitorExit, env, monitor); 662 exitOnError(error); 663 } 664 665 void rawMonitorNotify(jvmtiEnv *env, jrawMonitorID monitor) { 666 jvmtiError error = NSK_CPP_STUB2(RawMonitorNotify, env, monitor); 667 exitOnError(error); 668 } 669 670 void rawMonitorWait(jvmtiEnv *env, jrawMonitorID monitor, jlong millis) { 671 jvmtiError error = NSK_CPP_STUB3(RawMonitorWait, env, monitor, millis); 672 exitOnError(error); 673 } 674 675 void getPhase(jvmtiEnv *env, jvmtiPhase *phase) { 676 jvmtiError error = NSK_CPP_STUB2(GetPhase, env, phase); 677 exitOnError(error); 678 } 679 680 /*************************************************************/ 681 682 #ifdef __cplusplus 683 } 684 #endif