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 }