1 /* 2 * Copyright (c) 1998, 2024, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include <ctype.h> 27 28 #include "util.h" 29 #include "utf_util.h" 30 #include "transport.h" 31 #include "eventHandler.h" 32 #include "threadControl.h" 33 #include "outStream.h" 34 #include "inStream.h" 35 #include "invoker.h" 36 #include "signature.h" 37 38 39 /* Global data area */ 40 BackendGlobalData *gdata = NULL; 41 42 /* Forward declarations */ 43 static jboolean isInterface(jclass clazz); 44 static jboolean isArrayClass(jclass clazz); 45 static char * getPropertyUTF8(JNIEnv *env, char *propertyName); 46 47 /* Save an object reference for use later (create a NewGlobalRef) */ 48 void 49 saveGlobalRef(JNIEnv *env, jobject obj, jobject *pobj) 50 { 51 jobject newobj; 52 53 if ( pobj == NULL ) { 54 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"saveGlobalRef pobj"); 55 } 56 if ( *pobj != NULL ) { 57 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"saveGlobalRef *pobj"); 58 } 59 if ( env == NULL ) { 60 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"saveGlobalRef env"); 61 } 62 if ( obj == NULL ) { 63 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"saveGlobalRef obj"); 64 } 65 newobj = JNI_FUNC_PTR(env,NewGlobalRef)(env, obj); 66 if ( newobj == NULL ) { 67 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"NewGlobalRef"); 68 } 69 *pobj = newobj; 70 } 71 72 /* Toss a previously saved object reference */ 73 void 74 tossGlobalRef(JNIEnv *env, jobject *pobj) 75 { 76 jobject obj; 77 78 if ( pobj == NULL ) { 79 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"tossGlobalRef pobj"); 80 } 81 obj = *pobj; 82 if ( env == NULL ) { 83 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"tossGlobalRef env"); 84 } 85 if ( obj == NULL ) { 86 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"tossGlobalRef obj"); 87 } 88 JNI_FUNC_PTR(env,DeleteGlobalRef)(env, obj); 89 *pobj = NULL; 90 } 91 92 jclass 93 findClass(JNIEnv *env, const char * name) 94 { 95 jclass x; 96 97 if ( env == NULL ) { 98 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"findClass env"); 99 } 100 if ( name == NULL || name[0] == 0 ) { 101 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"findClass name"); 102 } 103 x = JNI_FUNC_PTR(env,FindClass)(env, name); 104 if ( JNI_FUNC_PTR(env,ExceptionCheck)(env) ) { 105 JNI_FUNC_PTR(env,ExceptionClear)(env); // keep -Xcheck:jni happy 106 ERROR_MESSAGE(("JNI Exception occurred finding class %s", name)); 107 EXIT_ERROR(AGENT_ERROR_JNI_EXCEPTION,NULL); 108 } 109 return x; 110 } 111 112 jmethodID 113 getMethod(JNIEnv *env, jclass clazz, const char * name, const char *signature) 114 { 115 jmethodID method; 116 117 if ( env == NULL ) { 118 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"getMethod env"); 119 } 120 if ( clazz == NULL ) { 121 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"getMethod clazz"); 122 } 123 if ( name == NULL || name[0] == 0 ) { 124 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"getMethod name"); 125 } 126 if ( signature == NULL || signature[0] == 0 ) { 127 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"getMethod signature"); 128 } 129 method = JNI_FUNC_PTR(env,GetMethodID)(env, clazz, name, signature); 130 if ( JNI_FUNC_PTR(env,ExceptionCheck)(env) ) { 131 JNI_FUNC_PTR(env,ExceptionClear)(env); // keep -Xcheck:jni happy 132 ERROR_MESSAGE(("JNI Exception occurred finding method %s with signature %s", 133 name, signature)); 134 EXIT_ERROR(AGENT_ERROR_JNI_EXCEPTION,NULL); 135 } 136 return method; 137 } 138 139 static jmethodID 140 getStaticMethod(JNIEnv *env, jclass clazz, const char * name, const char *signature) 141 { 142 jmethodID method; 143 144 if ( env == NULL ) { 145 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"getStaticMethod env"); 146 } 147 if ( clazz == NULL ) { 148 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"getStaticMethod clazz"); 149 } 150 if ( name == NULL || name[0] == 0 ) { 151 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"getStaticMethod name"); 152 } 153 if ( signature == NULL || signature[0] == 0 ) { 154 EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"getStaticMethod signature"); 155 } 156 method = JNI_FUNC_PTR(env,GetStaticMethodID)(env, clazz, name, signature); 157 if ( JNI_FUNC_PTR(env,ExceptionCheck)(env) ) { 158 JNI_FUNC_PTR(env,ExceptionClear)(env); // keep -Xcheck:jni happy 159 ERROR_MESSAGE(("JDWP Exception occurred finding method %s with signature %s", 160 name, signature)); 161 EXIT_ERROR(AGENT_ERROR_JNI_EXCEPTION,NULL); 162 } 163 return method; 164 } 165 166 167 168 void 169 util_initialize(JNIEnv *env) 170 { 171 WITH_LOCAL_REFS(env, 6) { 172 173 jvmtiError error; 174 jclass localClassClass; 175 jclass localThreadClass; 176 jclass localThreadGroupClass; 177 jclass localClassLoaderClass; 178 jclass localStringClass; 179 jclass localSystemClass; 180 jclass localPropertiesClass; 181 jclass localVMSupportClass; 182 jobject localAgentProperties; 183 jmethodID getAgentProperties; 184 jint groupCount; 185 jthreadGroup *groups; 186 jthreadGroup localSystemThreadGroup; 187 188 /* Find some standard classes */ 189 190 localClassClass = findClass(env,"java/lang/Class"); 191 localThreadClass = findClass(env,"java/lang/Thread"); 192 localThreadGroupClass = findClass(env,"java/lang/ThreadGroup"); 193 localClassLoaderClass = findClass(env,"java/lang/ClassLoader"); 194 localStringClass = findClass(env,"java/lang/String"); 195 localSystemClass = findClass(env,"java/lang/System"); 196 localPropertiesClass = findClass(env,"java/util/Properties"); 197 198 /* Save references */ 199 200 saveGlobalRef(env, localClassClass, &(gdata->classClass)); 201 saveGlobalRef(env, localThreadClass, &(gdata->threadClass)); 202 saveGlobalRef(env, localThreadGroupClass, &(gdata->threadGroupClass)); 203 saveGlobalRef(env, localClassLoaderClass, &(gdata->classLoaderClass)); 204 saveGlobalRef(env, localStringClass, &(gdata->stringClass)); 205 saveGlobalRef(env, localSystemClass, &(gdata->systemClass)); 206 207 /* Find some standard methods */ 208 209 gdata->threadConstructor = 210 getMethod(env, gdata->threadClass, 211 "<init>", "(Ljava/lang/ThreadGroup;Ljava/lang/String;)V"); 212 gdata->threadSetDaemon = 213 getMethod(env, gdata->threadClass, "setDaemon", "(Z)V"); 214 gdata->systemGetProperty = 215 getStaticMethod(env, gdata->systemClass, 216 "getProperty", "(Ljava/lang/String;)Ljava/lang/String;"); 217 gdata->setProperty = 218 getMethod(env, localPropertiesClass, 219 "setProperty", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;"); 220 221 /* Find the system thread group */ 222 223 groups = NULL; 224 groupCount = 0; 225 error = JVMTI_FUNC_PTR(gdata->jvmti,GetTopThreadGroups) 226 (gdata->jvmti, &groupCount, &groups); 227 if (error != JVMTI_ERROR_NONE ) { 228 EXIT_ERROR(error, "Can't get system thread group"); 229 } 230 if ( groupCount == 0 ) { 231 EXIT_ERROR(AGENT_ERROR_NULL_POINTER, "Can't get system thread group"); 232 } 233 localSystemThreadGroup = groups[0]; 234 saveGlobalRef(env, localSystemThreadGroup, &(gdata->systemThreadGroup)); 235 jvmtiDeallocate(groups); 236 237 /* Get some basic Java property values we will need at some point */ 238 gdata->property_java_version 239 = getPropertyUTF8(env, "java.version"); 240 gdata->property_java_vm_name 241 = getPropertyUTF8(env, "java.vm.name"); 242 gdata->property_java_vm_info 243 = getPropertyUTF8(env, "java.vm.info"); 244 gdata->property_java_class_path 245 = getPropertyUTF8(env, "java.class.path"); 246 gdata->property_sun_boot_library_path 247 = getPropertyUTF8(env, "sun.boot.library.path"); 248 gdata->property_path_separator 249 = getPropertyUTF8(env, "path.separator"); 250 gdata->property_user_dir 251 = getPropertyUTF8(env, "user.dir"); 252 253 /* Get agent properties: invoke VMSupport.getAgentProperties */ 254 localVMSupportClass = JNI_FUNC_PTR(env,FindClass) 255 (env, "jdk/internal/vm/VMSupport"); 256 if (localVMSupportClass == NULL) { 257 gdata->agent_properties = NULL; 258 if (JNI_FUNC_PTR(env,ExceptionCheck)(env)) { 259 JNI_FUNC_PTR(env,ExceptionClear)(env); 260 } 261 } else { 262 getAgentProperties = 263 getStaticMethod(env, localVMSupportClass, 264 "getAgentProperties", "()Ljava/util/Properties;"); 265 localAgentProperties = 266 JNI_FUNC_PTR(env,CallStaticObjectMethod) 267 (env, localVMSupportClass, getAgentProperties); 268 if (JNI_FUNC_PTR(env,ExceptionCheck)(env)) { 269 JNI_FUNC_PTR(env,ExceptionClear)(env); 270 EXIT_ERROR(AGENT_ERROR_INTERNAL, 271 "Exception occurred calling VMSupport.getAgentProperties"); 272 } 273 saveGlobalRef(env, localAgentProperties, &(gdata->agent_properties)); 274 } 275 276 } END_WITH_LOCAL_REFS(env); 277 278 } 279 280 void 281 util_reset(void) 282 { 283 } 284 285 jboolean 286 isObjectTag(jbyte tag) { 287 return (tag == JDWP_TAG(OBJECT)) || 288 (tag == JDWP_TAG(STRING)) || 289 (tag == JDWP_TAG(THREAD)) || 290 (tag == JDWP_TAG(THREAD_GROUP)) || 291 (tag == JDWP_TAG(CLASS_LOADER)) || 292 (tag == JDWP_TAG(CLASS_OBJECT)) || 293 (tag == JDWP_TAG(ARRAY)); 294 } 295 296 jbyte 297 specificTypeKey(JNIEnv *env, jobject object) 298 { 299 if (object == NULL) { 300 return JDWP_TAG(OBJECT); 301 } else if (JNI_FUNC_PTR(env,IsInstanceOf)(env, object, gdata->stringClass)) { 302 return JDWP_TAG(STRING); 303 } else if (JNI_FUNC_PTR(env,IsInstanceOf)(env, object, gdata->threadClass)) { 304 return JDWP_TAG(THREAD); 305 } else if (JNI_FUNC_PTR(env,IsInstanceOf)(env, object, gdata->threadGroupClass)) { 306 return JDWP_TAG(THREAD_GROUP); 307 } else if (JNI_FUNC_PTR(env,IsInstanceOf)(env, object, gdata->classLoaderClass)) { 308 return JDWP_TAG(CLASS_LOADER); 309 } else if (JNI_FUNC_PTR(env,IsInstanceOf)(env, object, gdata->classClass)) { 310 return JDWP_TAG(CLASS_OBJECT); 311 } else { 312 jboolean classIsArray; 313 314 WITH_LOCAL_REFS(env, 1) { 315 jclass clazz; 316 clazz = JNI_FUNC_PTR(env,GetObjectClass)(env, object); 317 classIsArray = isArrayClass(clazz); 318 } END_WITH_LOCAL_REFS(env); 319 320 return (classIsArray ? JDWP_TAG(ARRAY) : JDWP_TAG(OBJECT)); 321 } 322 } 323 324 static void 325 writeFieldValue(JNIEnv *env, PacketOutputStream *out, jobject object, 326 jfieldID field) 327 { 328 jclass clazz; 329 char *signature = NULL; 330 jvmtiError error; 331 jbyte typeKey; 332 333 clazz = JNI_FUNC_PTR(env,GetObjectClass)(env, object); 334 error = fieldSignature(clazz, field, NULL, &signature, NULL); 335 if (error != JVMTI_ERROR_NONE) { 336 outStream_setError(out, map2jdwpError(error)); 337 return; 338 } 339 typeKey = jdwpTag(signature); 340 jvmtiDeallocate(signature); 341 342 if (isReferenceTag(typeKey)) { 343 344 jobject value = JNI_FUNC_PTR(env,GetObjectField)(env, object, field); 345 (void)outStream_writeByte(out, specificTypeKey(env, value)); 346 (void)outStream_writeObjectRef(env, out, value); 347 return; 348 349 } 350 351 /* 352 * For primitive types, the type key is bounced back as is. 353 */ 354 (void)outStream_writeByte(out, typeKey); 355 356 switch (typeKey) { 357 case JDWP_TAG(BYTE): 358 (void)outStream_writeByte(out, 359 JNI_FUNC_PTR(env,GetByteField)(env, object, field)); 360 break; 361 362 case JDWP_TAG(CHAR): 363 (void)outStream_writeChar(out, 364 JNI_FUNC_PTR(env,GetCharField)(env, object, field)); 365 break; 366 367 case JDWP_TAG(FLOAT): 368 (void)outStream_writeFloat(out, 369 JNI_FUNC_PTR(env,GetFloatField)(env, object, field)); 370 break; 371 372 case JDWP_TAG(DOUBLE): 373 (void)outStream_writeDouble(out, 374 JNI_FUNC_PTR(env,GetDoubleField)(env, object, field)); 375 break; 376 377 case JDWP_TAG(INT): 378 (void)outStream_writeInt(out, 379 JNI_FUNC_PTR(env,GetIntField)(env, object, field)); 380 break; 381 382 case JDWP_TAG(LONG): 383 (void)outStream_writeLong(out, 384 JNI_FUNC_PTR(env,GetLongField)(env, object, field)); 385 break; 386 387 case JDWP_TAG(SHORT): 388 (void)outStream_writeShort(out, 389 JNI_FUNC_PTR(env,GetShortField)(env, object, field)); 390 break; 391 392 case JDWP_TAG(BOOLEAN): 393 (void)outStream_writeBoolean(out, 394 JNI_FUNC_PTR(env,GetBooleanField)(env, object, field)); 395 break; 396 } 397 } 398 399 static void 400 writeStaticFieldValue(JNIEnv *env, PacketOutputStream *out, jclass clazz, 401 jfieldID field) 402 { 403 jvmtiError error; 404 char *signature = NULL; 405 jbyte typeKey; 406 407 error = fieldSignature(clazz, field, NULL, &signature, NULL); 408 if (error != JVMTI_ERROR_NONE) { 409 outStream_setError(out, map2jdwpError(error)); 410 return; 411 } 412 typeKey = jdwpTag(signature); 413 jvmtiDeallocate(signature); 414 415 416 if (isReferenceTag(typeKey)) { 417 418 jobject value = JNI_FUNC_PTR(env,GetStaticObjectField)(env, clazz, field); 419 (void)outStream_writeByte(out, specificTypeKey(env, value)); 420 (void)outStream_writeObjectRef(env, out, value); 421 422 return; 423 } 424 425 /* 426 * For primitive types, the type key is bounced back as is. 427 */ 428 (void)outStream_writeByte(out, typeKey); 429 switch (typeKey) { 430 case JDWP_TAG(BYTE): 431 (void)outStream_writeByte(out, 432 JNI_FUNC_PTR(env,GetStaticByteField)(env, clazz, field)); 433 break; 434 435 case JDWP_TAG(CHAR): 436 (void)outStream_writeChar(out, 437 JNI_FUNC_PTR(env,GetStaticCharField)(env, clazz, field)); 438 break; 439 440 case JDWP_TAG(FLOAT): 441 (void)outStream_writeFloat(out, 442 JNI_FUNC_PTR(env,GetStaticFloatField)(env, clazz, field)); 443 break; 444 445 case JDWP_TAG(DOUBLE): 446 (void)outStream_writeDouble(out, 447 JNI_FUNC_PTR(env,GetStaticDoubleField)(env, clazz, field)); 448 break; 449 450 case JDWP_TAG(INT): 451 (void)outStream_writeInt(out, 452 JNI_FUNC_PTR(env,GetStaticIntField)(env, clazz, field)); 453 break; 454 455 case JDWP_TAG(LONG): 456 (void)outStream_writeLong(out, 457 JNI_FUNC_PTR(env,GetStaticLongField)(env, clazz, field)); 458 break; 459 460 case JDWP_TAG(SHORT): 461 (void)outStream_writeShort(out, 462 JNI_FUNC_PTR(env,GetStaticShortField)(env, clazz, field)); 463 break; 464 465 case JDWP_TAG(BOOLEAN): 466 (void)outStream_writeBoolean(out, 467 JNI_FUNC_PTR(env,GetStaticBooleanField)(env, clazz, field)); 468 break; 469 } 470 } 471 472 void 473 sharedGetFieldValues(PacketInputStream *in, PacketOutputStream *out, 474 jboolean isStatic) 475 { 476 JNIEnv *env = getEnv(); 477 jint length; 478 jobject object; 479 jclass clazz; 480 481 object = NULL; 482 clazz = NULL; 483 484 if (isStatic) { 485 clazz = inStream_readClassRef(env, in); 486 } else { 487 object = inStream_readObjectRef(env, in); 488 } 489 490 length = inStream_readInt(in); 491 if (inStream_error(in)) { 492 return; 493 } 494 495 WITH_LOCAL_REFS(env, length + 1) { /* +1 for class with instance fields */ 496 497 int i; 498 499 (void)outStream_writeInt(out, length); 500 for (i = 0; (i < length) && !outStream_error(out); i++) { 501 jfieldID field = inStream_readFieldID(in); 502 503 if (isStatic) { 504 writeStaticFieldValue(env, out, clazz, field); 505 } else { 506 writeFieldValue(env, out, object, field); 507 } 508 } 509 510 } END_WITH_LOCAL_REFS(env); 511 } 512 513 jboolean 514 sharedInvoke(PacketInputStream *in, PacketOutputStream *out) 515 { 516 jvalue *arguments = NULL; 517 jint options; 518 jvmtiError error; 519 jbyte invokeType; 520 jclass clazz; 521 jmethodID method; 522 jint argumentCount; 523 jobject instance; 524 jthread thread; 525 JNIEnv *env; 526 527 /* 528 * Instance methods start with the instance, thread and class, 529 * and statics and constructors start with the class and then the 530 * thread. 531 */ 532 env = getEnv(); 533 if (inStream_command(in) == JDWP_COMMAND(ObjectReference, InvokeMethod)) { 534 instance = inStream_readObjectRef(env, in); 535 thread = inStream_readThreadRef(env, in); 536 clazz = inStream_readClassRef(env, in); 537 } else { /* static method or constructor */ 538 instance = NULL; 539 clazz = inStream_readClassRef(env, in); 540 thread = inStream_readThreadRef(env, in); 541 } 542 543 /* 544 * ... and the rest of the packet is identical for all commands 545 */ 546 method = inStream_readMethodID(in); 547 argumentCount = inStream_readInt(in); 548 if (inStream_error(in)) { 549 return JNI_TRUE; 550 } 551 552 /* If count == 0, don't try and allocate 0 bytes, you'll get NULL */ 553 if ( argumentCount > 0 ) { 554 int i; 555 /*LINTED*/ 556 arguments = jvmtiAllocate(argumentCount * (jint)sizeof(*arguments)); 557 if (arguments == NULL) { 558 outStream_setError(out, JDWP_ERROR(OUT_OF_MEMORY)); 559 return JNI_TRUE; 560 } 561 for (i = 0; (i < argumentCount) && !inStream_error(in); i++) { 562 arguments[i] = inStream_readValue(in); 563 } 564 if (inStream_error(in)) { 565 return JNI_TRUE; 566 } 567 } 568 569 options = inStream_readInt(in); 570 if (inStream_error(in)) { 571 if ( arguments != NULL ) { 572 jvmtiDeallocate(arguments); 573 } 574 return JNI_TRUE; 575 } 576 577 if (inStream_command(in) == JDWP_COMMAND(ClassType, NewInstance)) { 578 invokeType = INVOKE_CONSTRUCTOR; 579 } else if (inStream_command(in) == JDWP_COMMAND(ClassType, InvokeMethod)) { 580 invokeType = INVOKE_STATIC; 581 } else if (inStream_command(in) == JDWP_COMMAND(InterfaceType, InvokeMethod)) { 582 invokeType = INVOKE_STATIC; 583 } else if (inStream_command(in) == JDWP_COMMAND(ObjectReference, InvokeMethod)) { 584 invokeType = INVOKE_INSTANCE; 585 } else { 586 outStream_setError(out, JDWP_ERROR(INTERNAL)); 587 if ( arguments != NULL ) { 588 jvmtiDeallocate(arguments); 589 } 590 return JNI_TRUE; 591 } 592 593 /* 594 * Request the invoke. If there are no errors in the request, 595 * the interrupting thread will actually do the invoke and a 596 * reply will be generated subsequently, so we don't reply here. 597 */ 598 error = invoker_requestInvoke(invokeType, (jbyte)options, inStream_id(in), 599 thread, clazz, method, 600 instance, arguments, argumentCount); 601 if (error != JVMTI_ERROR_NONE) { 602 outStream_setError(out, map2jdwpError(error)); 603 if ( arguments != NULL ) { 604 jvmtiDeallocate(arguments); 605 } 606 return JNI_TRUE; 607 } 608 609 return JNI_FALSE; /* Don't reply */ 610 } 611 612 jint 613 uniqueID(void) 614 { 615 static jint currentID = 0; 616 return currentID++; 617 } 618 619 int 620 filterDebugThreads(jthread *threads, int count) 621 { 622 int i; 623 int current; 624 625 /* Squish out all of the debugger-spawned threads */ 626 for (i = 0, current = 0; i < count; i++) { 627 jthread thread = threads[i]; 628 if (!threadControl_isDebugThread(thread)) { 629 if (i > current) { 630 threads[current] = thread; 631 } 632 current++; 633 } 634 } 635 return current; 636 } 637 638 jbyte 639 referenceTypeTag(jclass clazz) 640 { 641 jbyte tag; 642 643 if (isInterface(clazz)) { 644 tag = JDWP_TYPE_TAG(INTERFACE); 645 } else if (isArrayClass(clazz)) { 646 tag = JDWP_TYPE_TAG(ARRAY); 647 } else { 648 tag = JDWP_TYPE_TAG(CLASS); 649 } 650 651 return tag; 652 } 653 654 /** 655 * Get field modifiers 656 */ 657 jvmtiError 658 fieldModifiers(jclass clazz, jfieldID field, jint *pmodifiers) 659 { 660 jvmtiError error; 661 662 *pmodifiers = 0; 663 error = JVMTI_FUNC_PTR(gdata->jvmti,GetFieldModifiers) 664 (gdata->jvmti, clazz, field, pmodifiers); 665 return error; 666 } 667 668 /** 669 * Get method modifiers 670 */ 671 jvmtiError 672 methodModifiers(jmethodID method, jint *pmodifiers) 673 { 674 jvmtiError error; 675 676 *pmodifiers = 0; 677 error = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodModifiers) 678 (gdata->jvmti, method, pmodifiers); 679 return error; 680 } 681 682 /* Returns a local ref to the declaring class for a method, or NULL. */ 683 jvmtiError 684 methodClass(jmethodID method, jclass *pclazz) 685 { 686 jvmtiError error; 687 688 *pclazz = NULL; 689 error = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodDeclaringClass) 690 (gdata->jvmti, method, pclazz); 691 return error; 692 } 693 694 /* Returns the start and end locations of the specified method. */ 695 jvmtiError 696 methodLocation(jmethodID method, jlocation *ploc1, jlocation *ploc2) 697 { 698 jvmtiError error; 699 700 error = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodLocation) 701 (gdata->jvmti, method, ploc1, ploc2); 702 return error; 703 } 704 705 /** 706 * Get method signature 707 */ 708 jvmtiError 709 methodSignature(jmethodID method, 710 char **pname, char **psignature, char **pgeneric_signature) 711 { 712 jvmtiError error; 713 char *name = NULL; 714 char *signature = NULL; 715 char *generic_signature = NULL; 716 717 error = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodName) 718 (gdata->jvmti, method, &name, &signature, &generic_signature); 719 720 if ( pname != NULL ) { 721 *pname = name; 722 } else if ( name != NULL ) { 723 jvmtiDeallocate(name); 724 } 725 if ( psignature != NULL ) { 726 *psignature = signature; 727 } else if ( signature != NULL ) { 728 jvmtiDeallocate(signature); 729 } 730 if ( pgeneric_signature != NULL ) { 731 *pgeneric_signature = generic_signature; 732 } else if ( generic_signature != NULL ) { 733 jvmtiDeallocate(generic_signature); 734 } 735 return error; 736 } 737 738 /* 739 * Get the return type key of the method 740 * V or B C D F I J S Z L [ 741 */ 742 jvmtiError 743 methodReturnType(jmethodID method, char *typeKey) 744 { 745 char *signature; 746 jvmtiError error; 747 748 signature = NULL; 749 error = methodSignature(method, NULL, &signature, NULL); 750 if (error == JVMTI_ERROR_NONE) { 751 if (signature == NULL ) { 752 error = AGENT_ERROR_INVALID_TAG; 753 } else { 754 char * xx; 755 756 xx = strchr(signature, ')'); 757 if (xx == NULL || *(xx + 1) == 0) { 758 error = AGENT_ERROR_INVALID_TAG; 759 } else { 760 *typeKey = *(xx + 1); 761 } 762 jvmtiDeallocate(signature); 763 } 764 } 765 return error; 766 } 767 768 769 /** 770 * Return class loader for a class (must be inside a WITH_LOCAL_REFS) 771 */ 772 jvmtiError 773 classLoader(jclass clazz, jobject *pclazz) 774 { 775 jvmtiError error; 776 777 *pclazz = NULL; 778 error = JVMTI_FUNC_PTR(gdata->jvmti,GetClassLoader) 779 (gdata->jvmti, clazz, pclazz); 780 return error; 781 } 782 783 /** 784 * Get field signature 785 */ 786 jvmtiError 787 fieldSignature(jclass clazz, jfieldID field, 788 char **pname, char **psignature, char **pgeneric_signature) 789 { 790 jvmtiError error; 791 char *name = NULL; 792 char *signature = NULL; 793 char *generic_signature = NULL; 794 795 error = JVMTI_FUNC_PTR(gdata->jvmti,GetFieldName) 796 (gdata->jvmti, clazz, field, &name, &signature, &generic_signature); 797 798 if ( pname != NULL ) { 799 *pname = name; 800 } else if ( name != NULL ) { 801 jvmtiDeallocate(name); 802 } 803 if ( psignature != NULL ) { 804 *psignature = signature; 805 } else if ( signature != NULL ) { 806 jvmtiDeallocate(signature); 807 } 808 if ( pgeneric_signature != NULL ) { 809 *pgeneric_signature = generic_signature; 810 } else if ( generic_signature != NULL ) { 811 jvmtiDeallocate(generic_signature); 812 } 813 return error; 814 } 815 816 JNIEnv * 817 getEnv(void) 818 { 819 JNIEnv *env = NULL; 820 jint rc; 821 822 rc = FUNC_PTR(gdata->jvm,GetEnv) 823 (gdata->jvm, (void **)&env, JNI_VERSION_1_2); 824 if (rc != JNI_OK) { 825 ERROR_MESSAGE(("JDWP Unable to get JNI 1.2 environment, jvm->GetEnv() return code = %d", 826 rc)); 827 EXIT_ERROR(AGENT_ERROR_NO_JNI_ENV,NULL); 828 } 829 return env; 830 } 831 832 jvmtiError 833 spawnNewThread(jvmtiStartFunction func, void *arg, char *name) 834 { 835 JNIEnv *env = getEnv(); 836 jvmtiError error; 837 838 LOG_MISC(("Spawning new thread: %s", name)); 839 840 WITH_LOCAL_REFS(env, 3) { 841 842 jthread thread; 843 jstring nameString; 844 845 nameString = JNI_FUNC_PTR(env,NewStringUTF)(env, name); 846 if (JNI_FUNC_PTR(env,ExceptionCheck)(env)) { 847 JNI_FUNC_PTR(env,ExceptionClear)(env); 848 error = AGENT_ERROR_OUT_OF_MEMORY; 849 goto err; 850 } 851 852 thread = JNI_FUNC_PTR(env,NewObject) 853 (env, gdata->threadClass, gdata->threadConstructor, 854 gdata->systemThreadGroup, nameString); 855 if (JNI_FUNC_PTR(env,ExceptionCheck)(env)) { 856 JNI_FUNC_PTR(env,ExceptionClear)(env); 857 error = AGENT_ERROR_OUT_OF_MEMORY; 858 goto err; 859 } 860 861 /* 862 * Make the debugger thread a daemon 863 */ 864 JNI_FUNC_PTR(env,CallVoidMethod) 865 (env, thread, gdata->threadSetDaemon, JNI_TRUE); 866 if (JNI_FUNC_PTR(env,ExceptionCheck)(env)) { 867 JNI_FUNC_PTR(env,ExceptionClear)(env); 868 error = AGENT_ERROR_JNI_EXCEPTION; 869 goto err; 870 } 871 872 error = threadControl_addDebugThread(thread); 873 if (error == JVMTI_ERROR_NONE) { 874 /* 875 * Debugger threads need cycles in all sorts of strange 876 * situations (e.g. infinite cpu-bound loops), so give the 877 * thread a high priority. Note that if the VM has an application 878 * thread running at the max priority, there is still a chance 879 * that debugger threads will be starved. (There needs to be 880 * a way to give debugger threads a priority higher than any 881 * application thread). 882 */ 883 error = JVMTI_FUNC_PTR(gdata->jvmti,RunAgentThread) 884 (gdata->jvmti, thread, func, arg, 885 JVMTI_THREAD_MAX_PRIORITY); 886 } 887 888 err: ; 889 890 } END_WITH_LOCAL_REFS(env); 891 892 return error; 893 } 894 895 jvmtiError 896 jvmtiGetCapabilities(jvmtiCapabilities *caps) 897 { 898 if ( gdata->vmDead ) { 899 return AGENT_ERROR_VM_DEAD; 900 } 901 if (!gdata->haveCachedJvmtiCapabilities) { 902 jvmtiError error; 903 904 error = JVMTI_FUNC_PTR(gdata->jvmti,GetCapabilities) 905 (gdata->jvmti, &(gdata->cachedJvmtiCapabilities)); 906 if (error != JVMTI_ERROR_NONE) { 907 return error; 908 } 909 gdata->haveCachedJvmtiCapabilities = JNI_TRUE; 910 } 911 912 *caps = gdata->cachedJvmtiCapabilities; 913 914 return JVMTI_ERROR_NONE; 915 } 916 917 static jint 918 jvmtiVersion(void) 919 { 920 if (gdata->cachedJvmtiVersion == 0) { 921 jvmtiError error; 922 error = JVMTI_FUNC_PTR(gdata->jvmti,GetVersionNumber) 923 (gdata->jvmti, &(gdata->cachedJvmtiVersion)); 924 if (error != JVMTI_ERROR_NONE) { 925 EXIT_ERROR(error, "on getting the JVMTI version number"); 926 } 927 } 928 return gdata->cachedJvmtiVersion; 929 } 930 931 jint 932 jvmtiMajorVersion(void) 933 { 934 return (jvmtiVersion() & JVMTI_VERSION_MASK_MAJOR) 935 >> JVMTI_VERSION_SHIFT_MAJOR; 936 } 937 938 jint 939 jvmtiMinorVersion(void) 940 { 941 return (jvmtiVersion() & JVMTI_VERSION_MASK_MINOR) 942 >> JVMTI_VERSION_SHIFT_MINOR; 943 } 944 945 jint 946 jvmtiMicroVersion(void) 947 { 948 return (jvmtiVersion() & JVMTI_VERSION_MASK_MICRO) 949 >> JVMTI_VERSION_SHIFT_MICRO; 950 } 951 952 jvmtiError 953 getSourceDebugExtension(jclass clazz, char **extensionPtr) 954 { 955 return JVMTI_FUNC_PTR(gdata->jvmti,GetSourceDebugExtension) 956 (gdata->jvmti, clazz, extensionPtr); 957 } 958 959 960 static void 961 handleInterrupt(void) 962 { 963 /* 964 * An interrupt is handled: 965 * 966 * 1) for running application threads by deferring the interrupt 967 * until the current event handler has concluded. 968 * 969 * 2) for debugger threads by ignoring the interrupt; this is the 970 * most robust solution since debugger threads don't use interrupts 971 * to signal any condition. 972 * 973 * 3) for application threads that have not started or already 974 * ended by ignoring the interrupt. In the former case, the application 975 * is relying on timing to determine whether or not the thread sees 976 * the interrupt; in the latter case, the interrupt is meaningless. 977 */ 978 jthread thread = threadControl_currentThread(); 979 if ((thread != NULL) && (!threadControl_isDebugThread(thread))) { 980 threadControl_setPendingInterrupt(thread); 981 } 982 } 983 984 static jvmtiError 985 ignore_vm_death(jvmtiError error) 986 { 987 if (error == JVMTI_ERROR_WRONG_PHASE) { 988 LOG_MISC(("VM_DEAD, in debugMonitor*()?")); 989 return JVMTI_ERROR_NONE; /* JVMTI does this, not JVMDI? */ 990 } 991 return error; 992 } 993 994 void 995 debugMonitorEnter(jrawMonitorID monitor) 996 { 997 jvmtiError error; 998 error = JVMTI_FUNC_PTR(gdata->jvmti,RawMonitorEnter) 999 (gdata->jvmti, monitor); 1000 error = ignore_vm_death(error); 1001 if (error != JVMTI_ERROR_NONE) { 1002 EXIT_ERROR(error, "on raw monitor enter"); 1003 } 1004 } 1005 1006 void 1007 debugMonitorExit(jrawMonitorID monitor) 1008 { 1009 jvmtiError error; 1010 1011 error = JVMTI_FUNC_PTR(gdata->jvmti,RawMonitorExit) 1012 (gdata->jvmti, monitor); 1013 error = ignore_vm_death(error); 1014 if (error != JVMTI_ERROR_NONE) { 1015 EXIT_ERROR(error, "on raw monitor exit"); 1016 } 1017 } 1018 1019 void 1020 debugMonitorWait(jrawMonitorID monitor) 1021 { 1022 jvmtiError error; 1023 error = JVMTI_FUNC_PTR(gdata->jvmti,RawMonitorWait) 1024 (gdata->jvmti, monitor, ((jlong)(-1))); 1025 1026 /* 1027 * According to the JLS (17.8), here we have 1028 * either : 1029 * a- been notified 1030 * b- gotten a spurious wakeup 1031 * c- been interrupted 1032 * If both a and c have happened, the VM must choose 1033 * which way to return - a or c. If it chooses c 1034 * then the notify is gone - either to some other 1035 * thread that is also waiting, or it is dropped 1036 * on the floor. 1037 * 1038 * a is what we expect. b won't hurt us any - 1039 * callers should be programmed to handle 1040 * spurious wakeups. In case of c, 1041 * then the interrupt has been cleared, but 1042 * we don't want to consume it. It came from 1043 * user code and is intended for user code, not us. 1044 * So, we will remember that the interrupt has 1045 * occurred and re-activate it when this thread 1046 * goes back into user code. 1047 * That being said, what do we do here? Since 1048 * we could have been notified too, here we will 1049 * just pretend that we have been. It won't hurt 1050 * anything to return in the same way as if 1051 * we were notified since callers have to be able to 1052 * handle spurious wakeups anyway. 1053 */ 1054 if (error == JVMTI_ERROR_INTERRUPT) { 1055 handleInterrupt(); 1056 error = JVMTI_ERROR_NONE; 1057 } 1058 error = ignore_vm_death(error); 1059 if (error != JVMTI_ERROR_NONE) { 1060 EXIT_ERROR(error, "on raw monitor wait"); 1061 } 1062 } 1063 1064 void 1065 debugMonitorNotify(jrawMonitorID monitor) 1066 { 1067 jvmtiError error; 1068 1069 error = JVMTI_FUNC_PTR(gdata->jvmti,RawMonitorNotify) 1070 (gdata->jvmti, monitor); 1071 error = ignore_vm_death(error); 1072 if (error != JVMTI_ERROR_NONE) { 1073 EXIT_ERROR(error, "on raw monitor notify"); 1074 } 1075 } 1076 1077 void 1078 debugMonitorNotifyAll(jrawMonitorID monitor) 1079 { 1080 jvmtiError error; 1081 1082 error = JVMTI_FUNC_PTR(gdata->jvmti,RawMonitorNotifyAll) 1083 (gdata->jvmti, monitor); 1084 error = ignore_vm_death(error); 1085 if (error != JVMTI_ERROR_NONE) { 1086 EXIT_ERROR(error, "on raw monitor notify all"); 1087 } 1088 } 1089 1090 jrawMonitorID 1091 debugMonitorCreate(char *name) 1092 { 1093 jrawMonitorID monitor; 1094 jvmtiError error; 1095 1096 error = JVMTI_FUNC_PTR(gdata->jvmti,CreateRawMonitor) 1097 (gdata->jvmti, name, &monitor); 1098 if (error != JVMTI_ERROR_NONE) { 1099 EXIT_ERROR(error, "on creation of a raw monitor"); 1100 } 1101 return monitor; 1102 } 1103 1104 void 1105 debugMonitorDestroy(jrawMonitorID monitor) 1106 { 1107 jvmtiError error; 1108 1109 error = JVMTI_FUNC_PTR(gdata->jvmti,DestroyRawMonitor) 1110 (gdata->jvmti, monitor); 1111 error = ignore_vm_death(error); 1112 if (error != JVMTI_ERROR_NONE) { 1113 EXIT_ERROR(error, "on destruction of raw monitor"); 1114 } 1115 } 1116 1117 /** 1118 * Return array of all threads (must be inside a WITH_LOCAL_REFS) 1119 */ 1120 jthread * 1121 allThreads(jint *count) 1122 { 1123 jthread *threads; 1124 jvmtiError error; 1125 1126 *count = 0; 1127 threads = NULL; 1128 error = JVMTI_FUNC_PTR(gdata->jvmti,GetAllThreads) 1129 (gdata->jvmti, count, &threads); 1130 if (error == AGENT_ERROR_OUT_OF_MEMORY) { 1131 return NULL; /* Let caller deal with no memory? */ 1132 } 1133 if (error != JVMTI_ERROR_NONE) { 1134 EXIT_ERROR(error, "getting all threads"); 1135 } 1136 return threads; 1137 } 1138 1139 /** 1140 * Fill the passed in structure with thread group info. 1141 * name field is JVMTI allocated. parent is global ref. 1142 */ 1143 void 1144 threadGroupInfo(jthreadGroup group, jvmtiThreadGroupInfo *info) 1145 { 1146 jvmtiError error; 1147 1148 error = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadGroupInfo) 1149 (gdata->jvmti, group, info); 1150 if (error != JVMTI_ERROR_NONE) { 1151 EXIT_ERROR(error, "on getting thread group info"); 1152 } 1153 } 1154 1155 /** 1156 * Return class signature string 1157 */ 1158 jvmtiError 1159 classSignature(jclass clazz, char **psignature, char **pgeneric_signature) 1160 { 1161 jvmtiError error; 1162 char *signature = NULL; 1163 1164 /* 1165 * pgeneric_signature can be NULL, and GetClassSignature 1166 * accepts NULL. 1167 */ 1168 error = JVMTI_FUNC_PTR(gdata->jvmti,GetClassSignature) 1169 (gdata->jvmti, clazz, &signature, pgeneric_signature); 1170 1171 if ( psignature != NULL ) { 1172 *psignature = signature; 1173 } else if ( signature != NULL ) { 1174 jvmtiDeallocate(signature); 1175 } 1176 return error; 1177 } 1178 1179 /* Get class name (not signature) */ 1180 char * 1181 getClassname(jclass clazz) 1182 { 1183 char *classname; 1184 1185 classname = NULL; 1186 if ( clazz != NULL ) { 1187 if (classSignature(clazz, &classname, NULL) != JVMTI_ERROR_NONE) { 1188 classname = NULL; 1189 } else { 1190 /* Convert in place */ 1191 convertSignatureToClassname(classname); 1192 } 1193 } 1194 return classname; /* Caller must free this memory */ 1195 } 1196 1197 void 1198 writeGenericSignature(PacketOutputStream *out, char *genericSignature) 1199 { 1200 if (genericSignature == NULL) { 1201 (void)outStream_writeString(out, ""); 1202 } else { 1203 (void)outStream_writeString(out, genericSignature); 1204 } 1205 } 1206 1207 jint 1208 classStatus(jclass clazz) 1209 { 1210 jint status; 1211 jvmtiError error; 1212 1213 error = JVMTI_FUNC_PTR(gdata->jvmti,GetClassStatus) 1214 (gdata->jvmti, clazz, &status); 1215 if (error != JVMTI_ERROR_NONE) { 1216 EXIT_ERROR(error, "on getting class status"); 1217 } 1218 return status; 1219 } 1220 1221 static jboolean 1222 isArrayClass(jclass clazz) 1223 { 1224 jboolean isArray = JNI_FALSE; 1225 jvmtiError error; 1226 1227 error = JVMTI_FUNC_PTR(gdata->jvmti,IsArrayClass) 1228 (gdata->jvmti, clazz, &isArray); 1229 if (error != JVMTI_ERROR_NONE) { 1230 EXIT_ERROR(error, "on checking for an array class"); 1231 } 1232 return isArray; 1233 } 1234 1235 static jboolean 1236 isInterface(jclass clazz) 1237 { 1238 jboolean isInterface = JNI_FALSE; 1239 jvmtiError error; 1240 1241 error = JVMTI_FUNC_PTR(gdata->jvmti,IsInterface) 1242 (gdata->jvmti, clazz, &isInterface); 1243 if (error != JVMTI_ERROR_NONE) { 1244 EXIT_ERROR(error, "on checking for an interface"); 1245 } 1246 return isInterface; 1247 } 1248 1249 jvmtiError 1250 isFieldSynthetic(jclass clazz, jfieldID field, jboolean *psynthetic) 1251 { 1252 jvmtiError error; 1253 1254 error = JVMTI_FUNC_PTR(gdata->jvmti,IsFieldSynthetic) 1255 (gdata->jvmti, clazz, field, psynthetic); 1256 if ( error == JVMTI_ERROR_MUST_POSSESS_CAPABILITY ) { 1257 /* If the query is not supported, we assume it is not synthetic. */ 1258 *psynthetic = JNI_FALSE; 1259 return JVMTI_ERROR_NONE; 1260 } 1261 return error; 1262 } 1263 1264 jvmtiError 1265 isMethodSynthetic(jmethodID method, jboolean *psynthetic) 1266 { 1267 jvmtiError error; 1268 1269 error = JVMTI_FUNC_PTR(gdata->jvmti,IsMethodSynthetic) 1270 (gdata->jvmti, method, psynthetic); 1271 if ( error == JVMTI_ERROR_MUST_POSSESS_CAPABILITY ) { 1272 /* If the query is not supported, we assume it is not synthetic. */ 1273 *psynthetic = JNI_FALSE; 1274 return JVMTI_ERROR_NONE; 1275 } 1276 return error; 1277 } 1278 1279 jboolean 1280 isMethodNative(jmethodID method) 1281 { 1282 jboolean isNative = JNI_FALSE; 1283 jvmtiError error; 1284 1285 error = JVMTI_FUNC_PTR(gdata->jvmti,IsMethodNative) 1286 (gdata->jvmti, method, &isNative); 1287 if (error != JVMTI_ERROR_NONE) { 1288 EXIT_ERROR(error, "on checking for a native interface"); 1289 } 1290 return isNative; 1291 } 1292 1293 jboolean 1294 isSameObject(JNIEnv *env, jobject o1, jobject o2) 1295 { 1296 if ( o1==o2 ) { 1297 return JNI_TRUE; 1298 } 1299 return FUNC_PTR(env,IsSameObject)(env, o1, o2); 1300 } 1301 1302 jint 1303 objectHashCode(jobject object) 1304 { 1305 jint hashCode = 0; 1306 jvmtiError error; 1307 1308 if ( object!=NULL ) { 1309 error = JVMTI_FUNC_PTR(gdata->jvmti,GetObjectHashCode) 1310 (gdata->jvmti, object, &hashCode); 1311 if (error != JVMTI_ERROR_NONE) { 1312 EXIT_ERROR(error, "on getting an object hash code"); 1313 } 1314 } 1315 return hashCode; 1316 } 1317 1318 /* Get all implemented interfaces (must be inside a WITH_LOCAL_REFS) */ 1319 jvmtiError 1320 allInterfaces(jclass clazz, jclass **ppinterfaces, jint *pcount) 1321 { 1322 jvmtiError error; 1323 1324 *pcount = 0; 1325 *ppinterfaces = NULL; 1326 error = JVMTI_FUNC_PTR(gdata->jvmti,GetImplementedInterfaces) 1327 (gdata->jvmti, clazz, pcount, ppinterfaces); 1328 return error; 1329 } 1330 1331 /* Get all loaded classes (must be inside a WITH_LOCAL_REFS) */ 1332 jvmtiError 1333 allLoadedClasses(jclass **ppclasses, jint *pcount) 1334 { 1335 jvmtiError error; 1336 1337 *pcount = 0; 1338 *ppclasses = NULL; 1339 error = JVMTI_FUNC_PTR(gdata->jvmti,GetLoadedClasses) 1340 (gdata->jvmti, pcount, ppclasses); 1341 return error; 1342 } 1343 1344 /* Get all loaded classes for a loader (must be inside a WITH_LOCAL_REFS) */ 1345 jvmtiError 1346 allClassLoaderClasses(jobject loader, jclass **ppclasses, jint *pcount) 1347 { 1348 jvmtiError error; 1349 1350 *pcount = 0; 1351 *ppclasses = NULL; 1352 error = JVMTI_FUNC_PTR(gdata->jvmti,GetClassLoaderClasses) 1353 (gdata->jvmti, loader, pcount, ppclasses); 1354 return error; 1355 } 1356 1357 static jboolean 1358 is_a_nested_class(char *outer_sig, int outer_sig_len, char *sig, int sep) 1359 { 1360 char *inner; 1361 1362 /* Assumed outer class signature is "LOUTERCLASSNAME;" 1363 * inner class signature is "LOUTERCLASSNAME$INNERNAME;" 1364 * 1365 * INNERNAME can take the form: 1366 * [0-9][1-9]* anonymous class somewhere in the file 1367 * [0-9][1-9]*NAME local class somewhere in the OUTER class 1368 * NAME nested class in OUTER 1369 * 1370 * If NAME itself contains a $ (sep) then classname is further nested 1371 * inside another class. 1372 * 1373 */ 1374 1375 /* Check prefix first */ 1376 if ( strncmp(sig, outer_sig, outer_sig_len-1) != 0 ) { 1377 return JNI_FALSE; 1378 } 1379 1380 /* Prefix must be followed by a $ (sep) */ 1381 if ( sig[outer_sig_len-1] != sep ) { 1382 return JNI_FALSE; /* No sep follows the match, must not be nested. */ 1383 } 1384 1385 /* Walk past any digits, if we reach the end, must be pure anonymous */ 1386 inner = sig + outer_sig_len; 1387 #if 1 /* We want to return local classes */ 1388 while ( *inner && isdigit(*inner) ) { 1389 inner++; 1390 } 1391 /* But anonymous class names can't be trusted. */ 1392 if ( *inner == ';' ) { 1393 return JNI_FALSE; /* A pure anonymous class */ 1394 } 1395 #else 1396 if ( *inner && isdigit(*inner) ) { 1397 return JNI_FALSE; /* A pure anonymous or local class */ 1398 } 1399 #endif 1400 1401 /* Nested deeper? */ 1402 if ( strchr(inner, sep) != NULL ) { 1403 return JNI_FALSE; /* Nested deeper than we want? */ 1404 } 1405 return JNI_TRUE; 1406 } 1407 1408 /* Get all nested classes for a class (must be inside a WITH_LOCAL_REFS) */ 1409 jvmtiError 1410 allNestedClasses(jclass parent_clazz, jclass **ppnested, jint *pcount) 1411 { 1412 jvmtiError error; 1413 jobject parent_loader; 1414 jclass *classes; 1415 char *signature; 1416 size_t len; 1417 jint count; 1418 jint ncount; 1419 int i; 1420 1421 *ppnested = NULL; 1422 *pcount = 0; 1423 1424 parent_loader = NULL; 1425 classes = NULL; 1426 signature = NULL; 1427 count = 0; 1428 ncount = 0; 1429 1430 error = classLoader(parent_clazz, &parent_loader); 1431 if (error != JVMTI_ERROR_NONE) { 1432 return error; 1433 } 1434 error = classSignature(parent_clazz, &signature, NULL); 1435 if (error != JVMTI_ERROR_NONE) { 1436 return error; 1437 } 1438 len = strlen(signature); 1439 1440 error = allClassLoaderClasses(parent_loader, &classes, &count); 1441 if ( error != JVMTI_ERROR_NONE ) { 1442 jvmtiDeallocate(signature); 1443 return error; 1444 } 1445 1446 for (i=0; i<count; i++) { 1447 jclass clazz; 1448 char *candidate_signature; 1449 1450 clazz = classes[i]; 1451 candidate_signature = NULL; 1452 error = classSignature(clazz, &candidate_signature, NULL); 1453 if (error != JVMTI_ERROR_NONE) { 1454 break; 1455 } 1456 1457 if ( is_a_nested_class(signature, (int)len, candidate_signature, '$') || 1458 is_a_nested_class(signature, (int)len, candidate_signature, '#') ) { 1459 /* Float nested classes to top */ 1460 classes[i] = classes[ncount]; 1461 classes[ncount++] = clazz; 1462 } 1463 jvmtiDeallocate(candidate_signature); 1464 } 1465 1466 jvmtiDeallocate(signature); 1467 1468 if ( count != 0 && ncount == 0 ) { 1469 jvmtiDeallocate(classes); 1470 classes = NULL; 1471 } 1472 1473 *ppnested = classes; 1474 *pcount = ncount; 1475 return error; 1476 } 1477 1478 void 1479 createLocalRefSpace(JNIEnv *env, jint capacity) 1480 { 1481 /* 1482 * Save current exception since it might get overwritten by 1483 * the calls below. Note we must depend on space in the existing 1484 * frame because asking for a new frame may generate an exception. 1485 */ 1486 jobject throwable = JNI_FUNC_PTR(env,ExceptionOccurred)(env); 1487 1488 /* 1489 * Use the current frame if necessary; otherwise create a new one 1490 */ 1491 if (JNI_FUNC_PTR(env,PushLocalFrame)(env, capacity) < 0) { 1492 EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"PushLocalFrame: Unable to push JNI frame"); 1493 } 1494 1495 /* 1496 * TO DO: This could be more efficient if it used EnsureLocalCapacity, 1497 * but that would not work if two functions on the call stack 1498 * use this function. We would need to either track reserved 1499 * references on a per-thread basis or come up with a convention 1500 * that would prevent two functions from depending on this function 1501 * at the same time. 1502 */ 1503 1504 /* 1505 * Restore exception state from before call 1506 */ 1507 if (throwable != NULL) { 1508 JNI_FUNC_PTR(env,Throw)(env, throwable); 1509 } else { 1510 JNI_FUNC_PTR(env,ExceptionClear)(env); 1511 } 1512 } 1513 1514 jboolean 1515 isClass(jobject object) 1516 { 1517 JNIEnv *env = getEnv(); 1518 return JNI_FUNC_PTR(env,IsInstanceOf)(env, object, gdata->classClass); 1519 } 1520 1521 jboolean 1522 isVThread(jobject object) 1523 { 1524 JNIEnv *env = getEnv(); 1525 return JNI_FUNC_PTR(env,IsVirtualThread)(env, object); 1526 } 1527 1528 jboolean 1529 isThread(jobject object) 1530 { 1531 JNIEnv *env = getEnv(); 1532 return JNI_FUNC_PTR(env,IsInstanceOf)(env, object, gdata->threadClass); 1533 } 1534 1535 jboolean 1536 isThreadGroup(jobject object) 1537 { 1538 JNIEnv *env = getEnv(); 1539 return JNI_FUNC_PTR(env,IsInstanceOf)(env, object, gdata->threadGroupClass); 1540 } 1541 1542 jboolean 1543 isString(jobject object) 1544 { 1545 JNIEnv *env = getEnv(); 1546 return JNI_FUNC_PTR(env,IsInstanceOf)(env, object, gdata->stringClass); 1547 } 1548 1549 jboolean 1550 isClassLoader(jobject object) 1551 { 1552 JNIEnv *env = getEnv(); 1553 return JNI_FUNC_PTR(env,IsInstanceOf)(env, object, gdata->classLoaderClass); 1554 } 1555 1556 jboolean 1557 isArray(jobject object) 1558 { 1559 JNIEnv *env = getEnv(); 1560 jboolean is; 1561 1562 WITH_LOCAL_REFS(env, 1) { 1563 jclass clazz; 1564 clazz = JNI_FUNC_PTR(env,GetObjectClass)(env, object); 1565 is = isArrayClass(clazz); 1566 } END_WITH_LOCAL_REFS(env); 1567 1568 return is; 1569 } 1570 1571 /** 1572 * Return property value as jstring 1573 */ 1574 static jstring 1575 getPropertyValue(JNIEnv *env, char *propertyName) 1576 { 1577 jstring valueString; 1578 jstring nameString; 1579 1580 valueString = NULL; 1581 1582 /* Create new String object to hold the property name */ 1583 nameString = JNI_FUNC_PTR(env,NewStringUTF)(env, propertyName); 1584 if (JNI_FUNC_PTR(env,ExceptionCheck)(env)) { 1585 JNI_FUNC_PTR(env,ExceptionClear)(env); 1586 /* NULL will be returned below */ 1587 } else { 1588 /* Call valueString = System.getProperty(nameString) */ 1589 valueString = JNI_FUNC_PTR(env,CallStaticObjectMethod) 1590 (env, gdata->systemClass, gdata->systemGetProperty, nameString); 1591 if (JNI_FUNC_PTR(env,ExceptionCheck)(env)) { 1592 JNI_FUNC_PTR(env,ExceptionClear)(env); 1593 valueString = NULL; 1594 } 1595 } 1596 return valueString; 1597 } 1598 1599 /** 1600 * Set an agent property 1601 */ 1602 void 1603 setAgentPropertyValue(JNIEnv *env, char *propertyName, char* propertyValue) 1604 { 1605 jstring nameString; 1606 jstring valueString; 1607 1608 if (gdata->agent_properties == NULL) { 1609 /* VMSupport doesn't exist; so ignore */ 1610 return; 1611 } 1612 1613 /* Create jstrings for property name and value */ 1614 nameString = JNI_FUNC_PTR(env,NewStringUTF)(env, propertyName); 1615 if (nameString != NULL) { 1616 /* convert the value to UTF8 */ 1617 int len; 1618 char *utf8value; 1619 int utf8maxSize; 1620 1621 len = (int)strlen(propertyValue); 1622 utf8maxSize = len * 4 + 1; 1623 utf8value = (char *)jvmtiAllocate(utf8maxSize); 1624 if (utf8value != NULL) { 1625 utf8FromPlatform(propertyValue, len, (jbyte *)utf8value, utf8maxSize); 1626 valueString = JNI_FUNC_PTR(env, NewStringUTF)(env, utf8value); 1627 jvmtiDeallocate(utf8value); 1628 1629 if (valueString != NULL) { 1630 /* invoke Properties.setProperty */ 1631 JNI_FUNC_PTR(env,CallObjectMethod) 1632 (env, gdata->agent_properties, 1633 gdata->setProperty, 1634 nameString, valueString); 1635 } 1636 } 1637 } 1638 if (JNI_FUNC_PTR(env,ExceptionCheck)(env)) { 1639 JNI_FUNC_PTR(env,ExceptionClear)(env); 1640 } 1641 } 1642 1643 #ifdef DEBUG 1644 // APIs that can be called when debugging the debug agent 1645 1646 #define check_jvmti_status(err, msg) \ 1647 if (err != JVMTI_ERROR_NONE) { \ 1648 EXIT_ERROR(err, msg); \ 1649 } 1650 1651 char* 1652 translateThreadState(jint flags) { 1653 char str[15 * 20]; 1654 str[0] = '\0'; 1655 1656 if (flags & JVMTI_THREAD_STATE_ALIVE) { 1657 strcat(str, " ALIVE"); 1658 } 1659 if (flags & JVMTI_THREAD_STATE_TERMINATED) { 1660 strcat(str, " TERMINATED"); 1661 } 1662 if (flags & JVMTI_THREAD_STATE_RUNNABLE) { 1663 strcat(str, " RUNNABLE"); 1664 } 1665 if (flags & JVMTI_THREAD_STATE_WAITING) { 1666 strcat(str, " WAITING"); 1667 } 1668 if (flags & JVMTI_THREAD_STATE_WAITING_INDEFINITELY) { 1669 strcat(str, " WAITING_INDEFINITELY"); 1670 } 1671 if (flags & JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT) { 1672 strcat(str, " WAITING_WITH_TIMEOUT"); 1673 } 1674 if (flags & JVMTI_THREAD_STATE_SLEEPING) { 1675 strcat(str, " SLEEPING"); 1676 } 1677 if (flags & JVMTI_THREAD_STATE_IN_OBJECT_WAIT) { 1678 strcat(str, " IN_OBJECT_WAIT"); 1679 } 1680 if (flags & JVMTI_THREAD_STATE_PARKED) { 1681 strcat(str, " PARKED"); 1682 } 1683 if (flags & JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER) { 1684 strcat(str, " BLOCKED_ON_MONITOR_ENTER"); 1685 } 1686 if (flags & JVMTI_THREAD_STATE_SUSPENDED) { 1687 strcat(str, " SUSPENDED"); 1688 } 1689 if (flags & JVMTI_THREAD_STATE_INTERRUPTED) { 1690 strcat(str, " INTERRUPTED"); 1691 } 1692 if (flags & JVMTI_THREAD_STATE_IN_NATIVE) { 1693 strcat(str, " IN_NATIVE"); 1694 } 1695 1696 if (strlen(str) == 0) { 1697 strcpy(str, "<none>"); 1698 } 1699 1700 char* tstate = (char*)jvmtiAllocate((int)strlen(str) + 1); 1701 strcpy(tstate, str); 1702 1703 return tstate; 1704 } 1705 1706 char* 1707 getThreadName(jthread thread) { 1708 jvmtiThreadInfo thr_info; 1709 jvmtiError err; 1710 1711 memset(&thr_info, 0, sizeof(thr_info)); 1712 err = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadInfo) 1713 (gdata->jvmti, thread, &thr_info); 1714 if (err == JVMTI_ERROR_WRONG_PHASE || err == JVMTI_ERROR_THREAD_NOT_ALIVE) { 1715 return NULL; // VM or target thread completed its work 1716 } 1717 check_jvmti_status(err, "getThreadName: error in JVMTI GetThreadInfo call"); 1718 1719 char* tname = thr_info.name; 1720 if (tname == NULL) { 1721 const char* UNNAMED_STR = "<Unnamed thread>"; 1722 size_t UNNAMED_LEN = strlen(UNNAMED_STR); 1723 tname = (char*)jvmtiAllocate((int)UNNAMED_LEN + 1); 1724 strcpy(tname, UNNAMED_STR); 1725 } 1726 return tname; 1727 } 1728 1729 char* 1730 getMethodName(jmethodID method) { 1731 char* mname = NULL; 1732 jvmtiError err; 1733 1734 err = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodName) 1735 (gdata->jvmti, method, &mname, NULL, NULL); 1736 check_jvmti_status(err, "getMethodName: error in JVMTI GetMethodName call"); 1737 1738 return mname; 1739 } 1740 1741 static char* 1742 get_method_class_name(jmethodID method) { 1743 jclass klass = NULL; 1744 char* cname = NULL; 1745 char* result = NULL; 1746 jvmtiError err; 1747 1748 err = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodDeclaringClass) 1749 (gdata->jvmti, method, &klass); 1750 check_jvmti_status(err, "get_method_class_name: error in JVMTI GetMethodDeclaringClass"); 1751 1752 err = JVMTI_FUNC_PTR(gdata->jvmti,GetClassSignature) 1753 (gdata->jvmti, klass, &cname, NULL); 1754 check_jvmti_status(err, "get_method_class_name: error in JVMTI GetClassSignature"); 1755 1756 size_t len = strlen(cname) - 2; // get rid of leading 'L' and trailing ';' 1757 result = (char*)jvmtiAllocate((int)len + 1); 1758 strncpy(result, cname + 1, len); // skip leading 'L' 1759 result[len] = '\0'; 1760 jvmtiDeallocate((void*)cname); 1761 return result; 1762 } 1763 1764 static void 1765 print_method(jmethodID method, jint depth) { 1766 char* cname = NULL; 1767 char* mname = NULL; 1768 char* msign = NULL; 1769 jvmtiError err; 1770 1771 cname = get_method_class_name(method); 1772 1773 err = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodName) 1774 (gdata->jvmti, method, &mname, &msign, NULL); 1775 check_jvmti_status(err, "print_method: error in JVMTI GetMethodName"); 1776 1777 tty_message("%2d: %s: %s%s", depth, cname, mname, msign); 1778 jvmtiDeallocate((void*)cname); 1779 jvmtiDeallocate((void*)mname); 1780 jvmtiDeallocate((void*)msign); 1781 } 1782 1783 #define MAX_FRAME_COUNT_PRINT_STACK_TRACE 200 1784 1785 void 1786 printStackTrace(jthread thread) { 1787 jvmtiFrameInfo frames[MAX_FRAME_COUNT_PRINT_STACK_TRACE]; 1788 char* tname = getThreadName(thread); 1789 jint count = 0; 1790 1791 jvmtiError err = JVMTI_FUNC_PTR(gdata->jvmti,GetStackTrace) 1792 (gdata->jvmti, thread, 0, MAX_FRAME_COUNT_PRINT_STACK_TRACE, frames, &count); 1793 check_jvmti_status(err, "printStackTrace: error in JVMTI GetStackTrace"); 1794 1795 tty_message("JVMTI Stack Trace for thread %s: frame count: %d", tname, count); 1796 for (int depth = 0; depth < count; depth++) { 1797 print_method(frames[depth].method, depth); 1798 } 1799 jvmtiDeallocate((void*)tname); 1800 } 1801 1802 void 1803 printThreadInfo(jthread thread) { 1804 jvmtiThreadInfo thread_info; 1805 jint thread_state; 1806 jvmtiError err; 1807 err = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadInfo) 1808 (gdata->jvmti, thread, &thread_info); 1809 check_jvmti_status(err, "Error in GetThreadInfo"); 1810 err = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadState) 1811 (gdata->jvmti, thread, &thread_state); 1812 check_jvmti_status(err, "Error in GetThreadState"); 1813 const char* state = translateThreadState(thread_state); 1814 tty_message("Thread: %p, name: %s, state(%x): %s, attrs: %s %s", 1815 thread, thread_info.name, thread_state, state, 1816 (isVThread(thread) ? "virtual": "platform"), 1817 (thread_info.is_daemon ? "daemon": "")); 1818 } 1819 1820 #endif /* DEBUG*/ 1821 1822 /** 1823 * Return property value as JDWP allocated string in UTF8 encoding 1824 */ 1825 static char * 1826 getPropertyUTF8(JNIEnv *env, char *propertyName) 1827 { 1828 jvmtiError error; 1829 char *value; 1830 1831 value = NULL; 1832 error = JVMTI_FUNC_PTR(gdata->jvmti,GetSystemProperty) 1833 (gdata->jvmti, (const char *)propertyName, &value); 1834 if (error != JVMTI_ERROR_NONE) { 1835 jstring valueString; 1836 1837 value = NULL; 1838 valueString = getPropertyValue(env, propertyName); 1839 1840 if (valueString != NULL) { 1841 const char *utf; 1842 1843 /* Get the UTF8 encoding for this property value string */ 1844 utf = JNI_FUNC_PTR(env,GetStringUTFChars)(env, valueString, NULL); 1845 /* Make a copy for returning, release the JNI copy */ 1846 value = jvmtiAllocate((int)strlen(utf) + 1); 1847 if (value != NULL) { 1848 (void)strcpy(value, utf); 1849 } 1850 JNI_FUNC_PTR(env,ReleaseStringUTFChars)(env, valueString, utf); 1851 } 1852 } 1853 if ( value == NULL ) { 1854 ERROR_MESSAGE(("JDWP Can't get property value for %s", propertyName)); 1855 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,NULL); 1856 } 1857 return value; 1858 } 1859 1860 jboolean 1861 isMethodObsolete(jmethodID method) 1862 { 1863 jvmtiError error; 1864 jboolean obsolete = JNI_TRUE; 1865 1866 if ( method != NULL ) { 1867 error = JVMTI_FUNC_PTR(gdata->jvmti,IsMethodObsolete) 1868 (gdata->jvmti, method, &obsolete); 1869 if (error != JVMTI_ERROR_NONE) { 1870 obsolete = JNI_TRUE; 1871 } 1872 } 1873 return obsolete; 1874 } 1875 1876 /* Get the jvmti environment to be used with tags */ 1877 jvmtiEnv * 1878 getSpecialJvmti(void) 1879 { 1880 jvmtiEnv *jvmti; 1881 jvmtiError error; 1882 int rc; 1883 1884 /* Get one time use JVMTI Env */ 1885 jvmtiCapabilities caps; 1886 1887 rc = JVM_FUNC_PTR(gdata->jvm,GetEnv) 1888 (gdata->jvm, (void **)&jvmti, JVMTI_VERSION); 1889 if (rc != JNI_OK) { 1890 return NULL; 1891 } 1892 (void)memset(&caps, 0, (int)sizeof(caps)); 1893 caps.can_tag_objects = 1; 1894 error = JVMTI_FUNC_PTR(jvmti,AddCapabilities)(jvmti, &caps); 1895 if ( error != JVMTI_ERROR_NONE ) { 1896 return NULL; 1897 } 1898 return jvmti; 1899 } 1900 1901 void 1902 writeCodeLocation(PacketOutputStream *out, jclass clazz, 1903 jmethodID method, jlocation location) 1904 { 1905 jbyte tag; 1906 1907 if (clazz != NULL) { 1908 tag = referenceTypeTag(clazz); 1909 } else { 1910 tag = JDWP_TYPE_TAG(CLASS); 1911 } 1912 (void)outStream_writeByte(out, tag); 1913 (void)outStream_writeObjectRef(getEnv(), out, clazz); 1914 (void)outStream_writeMethodID(out, isMethodObsolete(method)?NULL:method); 1915 (void)outStream_writeLocation(out, location); 1916 } 1917 1918 void * 1919 jvmtiAllocate(jint numBytes) 1920 { 1921 void *ptr; 1922 jvmtiError error; 1923 if ( numBytes == 0 ) { 1924 return NULL; 1925 } 1926 error = JVMTI_FUNC_PTR(gdata->jvmti,Allocate) 1927 (gdata->jvmti, numBytes, (unsigned char**)&ptr); 1928 if (error != JVMTI_ERROR_NONE ) { 1929 EXIT_ERROR(error, "Can't allocate jvmti memory"); 1930 } 1931 return ptr; 1932 } 1933 1934 void 1935 jvmtiDeallocate(void *ptr) 1936 { 1937 jvmtiError error; 1938 if ( ptr == NULL ) { 1939 return; 1940 } 1941 error = JVMTI_FUNC_PTR(gdata->jvmti,Deallocate) 1942 (gdata->jvmti, ptr); 1943 if (error != JVMTI_ERROR_NONE ) { 1944 EXIT_ERROR(error, "Can't deallocate jvmti memory"); 1945 } 1946 } 1947 1948 /* Rarely needed, transport library uses JDWP errors, only use? */ 1949 jvmtiError 1950 map2jvmtiError(jdwpError error) 1951 { 1952 switch ( error ) { 1953 case JDWP_ERROR(NONE): 1954 return JVMTI_ERROR_NONE; 1955 case JDWP_ERROR(INVALID_THREAD): 1956 return JVMTI_ERROR_INVALID_THREAD; 1957 case JDWP_ERROR(INVALID_THREAD_GROUP): 1958 return JVMTI_ERROR_INVALID_THREAD_GROUP; 1959 case JDWP_ERROR(INVALID_PRIORITY): 1960 return JVMTI_ERROR_INVALID_PRIORITY; 1961 case JDWP_ERROR(THREAD_NOT_SUSPENDED): 1962 return JVMTI_ERROR_THREAD_NOT_SUSPENDED; 1963 case JDWP_ERROR(THREAD_SUSPENDED): 1964 return JVMTI_ERROR_THREAD_SUSPENDED; 1965 case JDWP_ERROR(INVALID_OBJECT): 1966 return JVMTI_ERROR_INVALID_OBJECT; 1967 case JDWP_ERROR(INVALID_CLASS): 1968 return JVMTI_ERROR_INVALID_CLASS; 1969 case JDWP_ERROR(CLASS_NOT_PREPARED): 1970 return JVMTI_ERROR_CLASS_NOT_PREPARED; 1971 case JDWP_ERROR(INVALID_METHODID): 1972 return JVMTI_ERROR_INVALID_METHODID; 1973 case JDWP_ERROR(INVALID_LOCATION): 1974 return JVMTI_ERROR_INVALID_LOCATION; 1975 case JDWP_ERROR(INVALID_FIELDID): 1976 return JVMTI_ERROR_INVALID_FIELDID; 1977 case JDWP_ERROR(INVALID_FRAMEID): 1978 return AGENT_ERROR_INVALID_FRAMEID; 1979 case JDWP_ERROR(NO_MORE_FRAMES): 1980 return JVMTI_ERROR_NO_MORE_FRAMES; 1981 case JDWP_ERROR(OPAQUE_FRAME): 1982 return JVMTI_ERROR_OPAQUE_FRAME; 1983 case JDWP_ERROR(NOT_CURRENT_FRAME): 1984 return AGENT_ERROR_NOT_CURRENT_FRAME; 1985 case JDWP_ERROR(TYPE_MISMATCH): 1986 return JVMTI_ERROR_TYPE_MISMATCH; 1987 case JDWP_ERROR(INVALID_SLOT): 1988 return JVMTI_ERROR_INVALID_SLOT; 1989 case JDWP_ERROR(DUPLICATE): 1990 return JVMTI_ERROR_DUPLICATE; 1991 case JDWP_ERROR(NOT_FOUND): 1992 return JVMTI_ERROR_NOT_FOUND; 1993 case JDWP_ERROR(INVALID_MONITOR): 1994 return JVMTI_ERROR_INVALID_MONITOR; 1995 case JDWP_ERROR(NOT_MONITOR_OWNER): 1996 return JVMTI_ERROR_NOT_MONITOR_OWNER; 1997 case JDWP_ERROR(INTERRUPT): 1998 return JVMTI_ERROR_INTERRUPT; 1999 case JDWP_ERROR(INVALID_CLASS_FORMAT): 2000 return JVMTI_ERROR_INVALID_CLASS_FORMAT; 2001 case JDWP_ERROR(CIRCULAR_CLASS_DEFINITION): 2002 return JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION; 2003 case JDWP_ERROR(FAILS_VERIFICATION): 2004 return JVMTI_ERROR_FAILS_VERIFICATION; 2005 case JDWP_ERROR(ADD_METHOD_NOT_IMPLEMENTED): 2006 return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED; 2007 case JDWP_ERROR(SCHEMA_CHANGE_NOT_IMPLEMENTED): 2008 return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED; 2009 case JDWP_ERROR(INVALID_TYPESTATE): 2010 return JVMTI_ERROR_INVALID_TYPESTATE; 2011 case JDWP_ERROR(HIERARCHY_CHANGE_NOT_IMPLEMENTED): 2012 return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED; 2013 case JDWP_ERROR(DELETE_METHOD_NOT_IMPLEMENTED): 2014 return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED; 2015 case JDWP_ERROR(UNSUPPORTED_VERSION): 2016 return JVMTI_ERROR_UNSUPPORTED_VERSION; 2017 case JDWP_ERROR(NAMES_DONT_MATCH): 2018 return JVMTI_ERROR_NAMES_DONT_MATCH; 2019 case JDWP_ERROR(CLASS_MODIFIERS_CHANGE_NOT_IMPLEMENTED): 2020 return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED; 2021 case JDWP_ERROR(METHOD_MODIFIERS_CHANGE_NOT_IMPLEMENTED): 2022 return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED; 2023 case JDWP_ERROR(CLASS_ATTRIBUTE_CHANGE_NOT_IMPLEMENTED): 2024 return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED; 2025 case JDWP_ERROR(NOT_IMPLEMENTED): 2026 return JVMTI_ERROR_NOT_AVAILABLE; 2027 case JDWP_ERROR(NULL_POINTER): 2028 return JVMTI_ERROR_NULL_POINTER; 2029 case JDWP_ERROR(ABSENT_INFORMATION): 2030 return JVMTI_ERROR_ABSENT_INFORMATION; 2031 case JDWP_ERROR(INVALID_EVENT_TYPE): 2032 return JVMTI_ERROR_INVALID_EVENT_TYPE; 2033 case JDWP_ERROR(ILLEGAL_ARGUMENT): 2034 return JVMTI_ERROR_ILLEGAL_ARGUMENT; 2035 case JDWP_ERROR(OUT_OF_MEMORY): 2036 return JVMTI_ERROR_OUT_OF_MEMORY; 2037 case JDWP_ERROR(ACCESS_DENIED): 2038 return JVMTI_ERROR_ACCESS_DENIED; 2039 case JDWP_ERROR(VM_DEAD): 2040 return JVMTI_ERROR_WRONG_PHASE; 2041 case JDWP_ERROR(UNATTACHED_THREAD): 2042 return JVMTI_ERROR_UNATTACHED_THREAD; 2043 case JDWP_ERROR(INVALID_TAG): 2044 return AGENT_ERROR_INVALID_TAG; 2045 case JDWP_ERROR(ALREADY_INVOKING): 2046 return AGENT_ERROR_ALREADY_INVOKING; 2047 case JDWP_ERROR(INVALID_INDEX): 2048 return AGENT_ERROR_INVALID_INDEX; 2049 case JDWP_ERROR(INVALID_LENGTH): 2050 return AGENT_ERROR_INVALID_LENGTH; 2051 case JDWP_ERROR(INVALID_STRING): 2052 return AGENT_ERROR_INVALID_STRING; 2053 case JDWP_ERROR(INVALID_CLASS_LOADER): 2054 return AGENT_ERROR_INVALID_CLASS_LOADER; 2055 case JDWP_ERROR(INVALID_ARRAY): 2056 return AGENT_ERROR_INVALID_ARRAY; 2057 case JDWP_ERROR(TRANSPORT_LOAD): 2058 return AGENT_ERROR_TRANSPORT_LOAD; 2059 case JDWP_ERROR(TRANSPORT_INIT): 2060 return AGENT_ERROR_TRANSPORT_INIT; 2061 case JDWP_ERROR(NATIVE_METHOD): 2062 return AGENT_ERROR_NATIVE_METHOD; 2063 case JDWP_ERROR(INVALID_COUNT): 2064 return AGENT_ERROR_INVALID_COUNT; 2065 case JDWP_ERROR(INTERNAL): 2066 return AGENT_ERROR_JDWP_INTERNAL; 2067 } 2068 return AGENT_ERROR_INTERNAL; 2069 } 2070 2071 static jvmtiEvent index2jvmti[EI_max-EI_min+1]; 2072 static jdwpEvent index2jdwp [EI_max-EI_min+1]; 2073 2074 void 2075 eventIndexInit(void) 2076 { 2077 (void)memset(index2jvmti, 0, (int)sizeof(index2jvmti)); 2078 (void)memset(index2jdwp, 0, (int)sizeof(index2jdwp)); 2079 2080 index2jvmti[EI_SINGLE_STEP -EI_min] = JVMTI_EVENT_SINGLE_STEP; 2081 index2jvmti[EI_BREAKPOINT -EI_min] = JVMTI_EVENT_BREAKPOINT; 2082 index2jvmti[EI_FRAME_POP -EI_min] = JVMTI_EVENT_FRAME_POP; 2083 index2jvmti[EI_EXCEPTION -EI_min] = JVMTI_EVENT_EXCEPTION; 2084 index2jvmti[EI_THREAD_START -EI_min] = JVMTI_EVENT_THREAD_START; 2085 index2jvmti[EI_THREAD_END -EI_min] = JVMTI_EVENT_THREAD_END; 2086 index2jvmti[EI_CLASS_PREPARE -EI_min] = JVMTI_EVENT_CLASS_PREPARE; 2087 index2jvmti[EI_CLASS_UNLOAD -EI_min] = 0; // No mapping to JVMTI event 2088 index2jvmti[EI_CLASS_LOAD -EI_min] = JVMTI_EVENT_CLASS_LOAD; 2089 index2jvmti[EI_FIELD_ACCESS -EI_min] = JVMTI_EVENT_FIELD_ACCESS; 2090 index2jvmti[EI_FIELD_MODIFICATION -EI_min] = JVMTI_EVENT_FIELD_MODIFICATION; 2091 index2jvmti[EI_EXCEPTION_CATCH -EI_min] = JVMTI_EVENT_EXCEPTION_CATCH; 2092 index2jvmti[EI_METHOD_ENTRY -EI_min] = JVMTI_EVENT_METHOD_ENTRY; 2093 index2jvmti[EI_METHOD_EXIT -EI_min] = JVMTI_EVENT_METHOD_EXIT; 2094 index2jvmti[EI_MONITOR_CONTENDED_ENTER -EI_min] = JVMTI_EVENT_MONITOR_CONTENDED_ENTER; 2095 index2jvmti[EI_MONITOR_CONTENDED_ENTERED -EI_min] = JVMTI_EVENT_MONITOR_CONTENDED_ENTERED; 2096 index2jvmti[EI_MONITOR_WAIT -EI_min] = JVMTI_EVENT_MONITOR_WAIT; 2097 index2jvmti[EI_MONITOR_WAITED -EI_min] = JVMTI_EVENT_MONITOR_WAITED; 2098 index2jvmti[EI_VM_INIT -EI_min] = JVMTI_EVENT_VM_INIT; 2099 index2jvmti[EI_VM_DEATH -EI_min] = JVMTI_EVENT_VM_DEATH; 2100 index2jvmti[EI_VIRTUAL_THREAD_START -EI_min] = JVMTI_EVENT_VIRTUAL_THREAD_START; 2101 index2jvmti[EI_VIRTUAL_THREAD_END -EI_min] = JVMTI_EVENT_VIRTUAL_THREAD_END; 2102 2103 index2jdwp[EI_SINGLE_STEP -EI_min] = JDWP_EVENT(SINGLE_STEP); 2104 index2jdwp[EI_BREAKPOINT -EI_min] = JDWP_EVENT(BREAKPOINT); 2105 index2jdwp[EI_FRAME_POP -EI_min] = JDWP_EVENT(FRAME_POP); 2106 index2jdwp[EI_EXCEPTION -EI_min] = JDWP_EVENT(EXCEPTION); 2107 index2jdwp[EI_THREAD_START -EI_min] = JDWP_EVENT(THREAD_START); 2108 index2jdwp[EI_THREAD_END -EI_min] = JDWP_EVENT(THREAD_END); 2109 index2jdwp[EI_CLASS_PREPARE -EI_min] = JDWP_EVENT(CLASS_PREPARE); 2110 index2jdwp[EI_CLASS_UNLOAD -EI_min] = JDWP_EVENT(CLASS_UNLOAD); 2111 index2jdwp[EI_CLASS_LOAD -EI_min] = JDWP_EVENT(CLASS_LOAD); 2112 index2jdwp[EI_FIELD_ACCESS -EI_min] = JDWP_EVENT(FIELD_ACCESS); 2113 index2jdwp[EI_FIELD_MODIFICATION -EI_min] = JDWP_EVENT(FIELD_MODIFICATION); 2114 index2jdwp[EI_EXCEPTION_CATCH -EI_min] = JDWP_EVENT(EXCEPTION_CATCH); 2115 index2jdwp[EI_METHOD_ENTRY -EI_min] = JDWP_EVENT(METHOD_ENTRY); 2116 index2jdwp[EI_METHOD_EXIT -EI_min] = JDWP_EVENT(METHOD_EXIT); 2117 index2jdwp[EI_MONITOR_CONTENDED_ENTER -EI_min] = JDWP_EVENT(MONITOR_CONTENDED_ENTER); 2118 index2jdwp[EI_MONITOR_CONTENDED_ENTERED -EI_min] = JDWP_EVENT(MONITOR_CONTENDED_ENTERED); 2119 index2jdwp[EI_MONITOR_WAIT -EI_min] = JDWP_EVENT(MONITOR_WAIT); 2120 index2jdwp[EI_MONITOR_WAITED -EI_min] = JDWP_EVENT(MONITOR_WAITED); 2121 index2jdwp[EI_VM_INIT -EI_min] = JDWP_EVENT(VM_INIT); 2122 index2jdwp[EI_VM_DEATH -EI_min] = JDWP_EVENT(VM_DEATH); 2123 /* Just map VIRTUAL_THREAD_START/END to THREAD_START/END. */ 2124 index2jdwp[EI_VIRTUAL_THREAD_START -EI_min] = JDWP_EVENT(THREAD_START); 2125 index2jdwp[EI_VIRTUAL_THREAD_END -EI_min] = JDWP_EVENT(THREAD_END); 2126 } 2127 2128 jdwpEvent 2129 eventIndex2jdwp(EventIndex ei) 2130 { 2131 jdwpEvent event = 0; 2132 if (ei >= EI_min && ei <= EI_max) { 2133 event = index2jdwp[ei - EI_min]; 2134 } 2135 if (event == 0) { 2136 EXIT_ERROR(AGENT_ERROR_INVALID_INDEX, "bad EventIndex"); 2137 } 2138 return event; 2139 } 2140 2141 jvmtiEvent 2142 eventIndex2jvmti(EventIndex ei) 2143 { 2144 jvmtiEvent event = 0; 2145 if (ei >= EI_min && ei <= EI_max) { 2146 event = index2jvmti[ei - EI_min]; 2147 } 2148 if (event == 0) { 2149 EXIT_ERROR(AGENT_ERROR_INVALID_INDEX, "bad EventIndex"); 2150 } 2151 return event; 2152 } 2153 2154 char* 2155 eventIndex2EventName(EventIndex ei) 2156 { 2157 switch ( ei ) { 2158 case EI_SINGLE_STEP: 2159 return "EI_SINGLE_STEP"; 2160 case EI_BREAKPOINT: 2161 return "EI_BREAKPOINT"; 2162 case EI_FRAME_POP: 2163 return "EI_FRAME_POP"; 2164 case EI_EXCEPTION: 2165 return "EI_EXCEPTION"; 2166 case EI_THREAD_START: 2167 return "EI_THREAD_START"; 2168 case EI_THREAD_END: 2169 return "EI_THREAD_END"; 2170 case EI_CLASS_PREPARE: 2171 return "EI_CLASS_PREPARE"; 2172 case EI_CLASS_UNLOAD: 2173 return "EI_CLASS_UNLOAD"; 2174 case EI_CLASS_LOAD: 2175 return "EI_CLASS_LOAD"; 2176 case EI_FIELD_ACCESS: 2177 return "EI_FIELD_ACCESS"; 2178 case EI_FIELD_MODIFICATION: 2179 return "EI_FIELD_MODIFICATION"; 2180 case EI_EXCEPTION_CATCH: 2181 return "EI_EXCEPTION_CATCH"; 2182 case EI_METHOD_ENTRY: 2183 return "EI_METHOD_ENTRY"; 2184 case EI_METHOD_EXIT: 2185 return "EI_METHOD_EXIT"; 2186 case EI_MONITOR_CONTENDED_ENTER: 2187 return "EI_MONITOR_CONTENDED_ENTER"; 2188 case EI_MONITOR_CONTENDED_ENTERED: 2189 return "EI_MONITOR_CONTENDED_ENTERED"; 2190 case EI_MONITOR_WAIT: 2191 return "EI_MONITOR_WAIT"; 2192 case EI_MONITOR_WAITED: 2193 return "EI_MONITOR_WAITED"; 2194 case EI_VM_INIT: 2195 return "EI_VM_INIT"; 2196 case EI_VM_DEATH: 2197 return "EI_VM_DEATH"; 2198 case EI_VIRTUAL_THREAD_START: 2199 return "EI_VIRTUAL_THREAD_START"; 2200 case EI_VIRTUAL_THREAD_END: 2201 return "EI_VIRTUAL_THREAD_END"; 2202 default: 2203 JDI_ASSERT(JNI_FALSE); 2204 return "Bad EI"; 2205 } 2206 } 2207 2208 EventIndex 2209 jdwp2EventIndex(jdwpEvent eventType) 2210 { 2211 switch ( eventType ) { 2212 case JDWP_EVENT(SINGLE_STEP): 2213 return EI_SINGLE_STEP; 2214 case JDWP_EVENT(BREAKPOINT): 2215 return EI_BREAKPOINT; 2216 case JDWP_EVENT(FRAME_POP): 2217 return EI_FRAME_POP; 2218 case JDWP_EVENT(EXCEPTION): 2219 return EI_EXCEPTION; 2220 case JDWP_EVENT(THREAD_START): 2221 return EI_THREAD_START; 2222 case JDWP_EVENT(THREAD_END): 2223 return EI_THREAD_END; 2224 case JDWP_EVENT(CLASS_PREPARE): 2225 return EI_CLASS_PREPARE; 2226 case JDWP_EVENT(CLASS_UNLOAD): 2227 return EI_CLASS_UNLOAD; 2228 case JDWP_EVENT(CLASS_LOAD): 2229 return EI_CLASS_LOAD; 2230 case JDWP_EVENT(FIELD_ACCESS): 2231 return EI_FIELD_ACCESS; 2232 case JDWP_EVENT(FIELD_MODIFICATION): 2233 return EI_FIELD_MODIFICATION; 2234 case JDWP_EVENT(EXCEPTION_CATCH): 2235 return EI_EXCEPTION_CATCH; 2236 case JDWP_EVENT(METHOD_ENTRY): 2237 return EI_METHOD_ENTRY; 2238 case JDWP_EVENT(METHOD_EXIT): 2239 return EI_METHOD_EXIT; 2240 case JDWP_EVENT(METHOD_EXIT_WITH_RETURN_VALUE): 2241 return EI_METHOD_EXIT; 2242 case JDWP_EVENT(MONITOR_CONTENDED_ENTER): 2243 return EI_MONITOR_CONTENDED_ENTER; 2244 case JDWP_EVENT(MONITOR_CONTENDED_ENTERED): 2245 return EI_MONITOR_CONTENDED_ENTERED; 2246 case JDWP_EVENT(MONITOR_WAIT): 2247 return EI_MONITOR_WAIT; 2248 case JDWP_EVENT(MONITOR_WAITED): 2249 return EI_MONITOR_WAITED; 2250 case JDWP_EVENT(VM_INIT): 2251 return EI_VM_INIT; 2252 case JDWP_EVENT(VM_DEATH): 2253 return EI_VM_DEATH; 2254 default: 2255 break; 2256 } 2257 2258 /* 2259 * Event type not recognized - don't exit with error as caller 2260 * may wish to return error to debugger. 2261 */ 2262 return (EventIndex)0; 2263 } 2264 2265 EventIndex 2266 jvmti2EventIndex(jvmtiEvent kind) 2267 { 2268 switch ( kind ) { 2269 case JVMTI_EVENT_SINGLE_STEP: 2270 return EI_SINGLE_STEP; 2271 case JVMTI_EVENT_BREAKPOINT: 2272 return EI_BREAKPOINT; 2273 case JVMTI_EVENT_FRAME_POP: 2274 return EI_FRAME_POP; 2275 case JVMTI_EVENT_EXCEPTION: 2276 return EI_EXCEPTION; 2277 case JVMTI_EVENT_THREAD_START: 2278 return EI_THREAD_START; 2279 case JVMTI_EVENT_THREAD_END: 2280 return EI_THREAD_END; 2281 case JVMTI_EVENT_CLASS_PREPARE: 2282 return EI_CLASS_PREPARE; 2283 case JVMTI_EVENT_CLASS_LOAD: 2284 return EI_CLASS_LOAD; 2285 case JVMTI_EVENT_FIELD_ACCESS: 2286 return EI_FIELD_ACCESS; 2287 case JVMTI_EVENT_FIELD_MODIFICATION: 2288 return EI_FIELD_MODIFICATION; 2289 case JVMTI_EVENT_EXCEPTION_CATCH: 2290 return EI_EXCEPTION_CATCH; 2291 case JVMTI_EVENT_METHOD_ENTRY: 2292 return EI_METHOD_ENTRY; 2293 case JVMTI_EVENT_METHOD_EXIT: 2294 return EI_METHOD_EXIT; 2295 /* 2296 * There is no JVMTI_EVENT_METHOD_EXIT_WITH_RETURN_VALUE. 2297 * The normal JVMTI_EVENT_METHOD_EXIT always contains the return value. 2298 */ 2299 case JVMTI_EVENT_MONITOR_CONTENDED_ENTER: 2300 return EI_MONITOR_CONTENDED_ENTER; 2301 case JVMTI_EVENT_MONITOR_CONTENDED_ENTERED: 2302 return EI_MONITOR_CONTENDED_ENTERED; 2303 case JVMTI_EVENT_MONITOR_WAIT: 2304 return EI_MONITOR_WAIT; 2305 case JVMTI_EVENT_MONITOR_WAITED: 2306 return EI_MONITOR_WAITED; 2307 case JVMTI_EVENT_VM_INIT: 2308 return EI_VM_INIT; 2309 case JVMTI_EVENT_VM_DEATH: 2310 return EI_VM_DEATH; 2311 /* vthread events */ 2312 case JVMTI_EVENT_VIRTUAL_THREAD_START: 2313 return EI_VIRTUAL_THREAD_START; 2314 case JVMTI_EVENT_VIRTUAL_THREAD_END: 2315 return EI_VIRTUAL_THREAD_END; 2316 2317 default: 2318 EXIT_ERROR(AGENT_ERROR_INVALID_INDEX,"JVMTI to EventIndex mapping"); 2319 break; 2320 } 2321 return (EventIndex)0; 2322 } 2323 2324 /* This routine is commonly used, maps jvmti and agent errors to the best 2325 * jdwp error code we can map to. 2326 */ 2327 jdwpError 2328 map2jdwpError(jvmtiError error) 2329 { 2330 switch ( (int)error ) { 2331 case JVMTI_ERROR_NONE: 2332 return JDWP_ERROR(NONE); 2333 case AGENT_ERROR_INVALID_THREAD: 2334 case JVMTI_ERROR_INVALID_THREAD: 2335 return JDWP_ERROR(INVALID_THREAD); 2336 case JVMTI_ERROR_INVALID_THREAD_GROUP: 2337 return JDWP_ERROR(INVALID_THREAD_GROUP); 2338 case JVMTI_ERROR_INVALID_PRIORITY: 2339 return JDWP_ERROR(INVALID_PRIORITY); 2340 case JVMTI_ERROR_THREAD_NOT_SUSPENDED: 2341 return JDWP_ERROR(THREAD_NOT_SUSPENDED); 2342 case JVMTI_ERROR_THREAD_SUSPENDED: 2343 return JDWP_ERROR(THREAD_SUSPENDED); 2344 case JVMTI_ERROR_THREAD_NOT_ALIVE: 2345 return JDWP_ERROR(INVALID_THREAD); 2346 case AGENT_ERROR_INVALID_OBJECT: 2347 case JVMTI_ERROR_INVALID_OBJECT: 2348 return JDWP_ERROR(INVALID_OBJECT); 2349 case JVMTI_ERROR_INVALID_CLASS: 2350 return JDWP_ERROR(INVALID_CLASS); 2351 case JVMTI_ERROR_CLASS_NOT_PREPARED: 2352 return JDWP_ERROR(CLASS_NOT_PREPARED); 2353 case JVMTI_ERROR_INVALID_METHODID: 2354 return JDWP_ERROR(INVALID_METHODID); 2355 case JVMTI_ERROR_INVALID_LOCATION: 2356 return JDWP_ERROR(INVALID_LOCATION); 2357 case JVMTI_ERROR_INVALID_FIELDID: 2358 return JDWP_ERROR(INVALID_FIELDID); 2359 case AGENT_ERROR_NO_MORE_FRAMES: 2360 case JVMTI_ERROR_NO_MORE_FRAMES: 2361 return JDWP_ERROR(NO_MORE_FRAMES); 2362 case JVMTI_ERROR_OPAQUE_FRAME: 2363 return JDWP_ERROR(OPAQUE_FRAME); 2364 case JVMTI_ERROR_TYPE_MISMATCH: 2365 return JDWP_ERROR(TYPE_MISMATCH); 2366 case JVMTI_ERROR_INVALID_SLOT: 2367 return JDWP_ERROR(INVALID_SLOT); 2368 case JVMTI_ERROR_DUPLICATE: 2369 return JDWP_ERROR(DUPLICATE); 2370 case JVMTI_ERROR_NOT_FOUND: 2371 return JDWP_ERROR(NOT_FOUND); 2372 case JVMTI_ERROR_INVALID_MONITOR: 2373 return JDWP_ERROR(INVALID_MONITOR); 2374 case JVMTI_ERROR_NOT_MONITOR_OWNER: 2375 return JDWP_ERROR(NOT_MONITOR_OWNER); 2376 case JVMTI_ERROR_INTERRUPT: 2377 return JDWP_ERROR(INTERRUPT); 2378 case JVMTI_ERROR_INVALID_CLASS_FORMAT: 2379 return JDWP_ERROR(INVALID_CLASS_FORMAT); 2380 case JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION: 2381 return JDWP_ERROR(CIRCULAR_CLASS_DEFINITION); 2382 case JVMTI_ERROR_FAILS_VERIFICATION: 2383 return JDWP_ERROR(FAILS_VERIFICATION); 2384 case JVMTI_ERROR_INVALID_TYPESTATE: 2385 return JDWP_ERROR(INVALID_TYPESTATE); 2386 case JVMTI_ERROR_UNSUPPORTED_VERSION: 2387 return JDWP_ERROR(UNSUPPORTED_VERSION); 2388 case JVMTI_ERROR_NAMES_DONT_MATCH: 2389 return JDWP_ERROR(NAMES_DONT_MATCH); 2390 case AGENT_ERROR_NULL_POINTER: 2391 case JVMTI_ERROR_NULL_POINTER: 2392 return JDWP_ERROR(NULL_POINTER); 2393 case JVMTI_ERROR_ABSENT_INFORMATION: 2394 return JDWP_ERROR(ABSENT_INFORMATION); 2395 case AGENT_ERROR_INVALID_EVENT_TYPE: 2396 case JVMTI_ERROR_INVALID_EVENT_TYPE: 2397 return JDWP_ERROR(INVALID_EVENT_TYPE); 2398 case AGENT_ERROR_ILLEGAL_ARGUMENT: 2399 case JVMTI_ERROR_ILLEGAL_ARGUMENT: 2400 return JDWP_ERROR(ILLEGAL_ARGUMENT); 2401 case JVMTI_ERROR_OUT_OF_MEMORY: 2402 case AGENT_ERROR_OUT_OF_MEMORY: 2403 return JDWP_ERROR(OUT_OF_MEMORY); 2404 case JVMTI_ERROR_ACCESS_DENIED: 2405 return JDWP_ERROR(ACCESS_DENIED); 2406 case JVMTI_ERROR_WRONG_PHASE: 2407 case AGENT_ERROR_VM_DEAD: 2408 case AGENT_ERROR_NO_JNI_ENV: 2409 return JDWP_ERROR(VM_DEAD); 2410 case AGENT_ERROR_JNI_EXCEPTION: 2411 case JVMTI_ERROR_UNATTACHED_THREAD: 2412 return JDWP_ERROR(UNATTACHED_THREAD); 2413 case JVMTI_ERROR_NOT_AVAILABLE: 2414 case JVMTI_ERROR_MUST_POSSESS_CAPABILITY: 2415 return JDWP_ERROR(NOT_IMPLEMENTED); 2416 case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED: 2417 return JDWP_ERROR(HIERARCHY_CHANGE_NOT_IMPLEMENTED); 2418 case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED: 2419 return JDWP_ERROR(DELETE_METHOD_NOT_IMPLEMENTED); 2420 case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED: 2421 return JDWP_ERROR(ADD_METHOD_NOT_IMPLEMENTED); 2422 case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED: 2423 return JDWP_ERROR(SCHEMA_CHANGE_NOT_IMPLEMENTED); 2424 case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED: 2425 return JDWP_ERROR(CLASS_MODIFIERS_CHANGE_NOT_IMPLEMENTED); 2426 case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED: 2427 return JDWP_ERROR(METHOD_MODIFIERS_CHANGE_NOT_IMPLEMENTED); 2428 case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED: 2429 return JDWP_ERROR(CLASS_ATTRIBUTE_CHANGE_NOT_IMPLEMENTED); 2430 case JVMTI_ERROR_UNSUPPORTED_OPERATION: 2431 return JDWP_ERROR(NOT_IMPLEMENTED); 2432 case AGENT_ERROR_NOT_CURRENT_FRAME: 2433 return JDWP_ERROR(NOT_CURRENT_FRAME); 2434 case AGENT_ERROR_INVALID_TAG: 2435 return JDWP_ERROR(INVALID_TAG); 2436 case AGENT_ERROR_ALREADY_INVOKING: 2437 return JDWP_ERROR(ALREADY_INVOKING); 2438 case AGENT_ERROR_INVALID_INDEX: 2439 return JDWP_ERROR(INVALID_INDEX); 2440 case AGENT_ERROR_INVALID_LENGTH: 2441 return JDWP_ERROR(INVALID_LENGTH); 2442 case AGENT_ERROR_INVALID_STRING: 2443 return JDWP_ERROR(INVALID_STRING); 2444 case AGENT_ERROR_INVALID_CLASS_LOADER: 2445 return JDWP_ERROR(INVALID_CLASS_LOADER); 2446 case AGENT_ERROR_INVALID_ARRAY: 2447 return JDWP_ERROR(INVALID_ARRAY); 2448 case AGENT_ERROR_TRANSPORT_LOAD: 2449 return JDWP_ERROR(TRANSPORT_LOAD); 2450 case AGENT_ERROR_TRANSPORT_INIT: 2451 return JDWP_ERROR(TRANSPORT_INIT); 2452 case AGENT_ERROR_NATIVE_METHOD: 2453 return JDWP_ERROR(NATIVE_METHOD); 2454 case AGENT_ERROR_INVALID_COUNT: 2455 return JDWP_ERROR(INVALID_COUNT); 2456 case AGENT_ERROR_INVALID_FRAMEID: 2457 return JDWP_ERROR(INVALID_FRAMEID); 2458 case JVMTI_ERROR_INTERNAL: 2459 case JVMTI_ERROR_INVALID_ENVIRONMENT: 2460 case AGENT_ERROR_INTERNAL: 2461 case AGENT_ERROR_JVMTI_INTERNAL: 2462 case AGENT_ERROR_JDWP_INTERNAL: 2463 return JDWP_ERROR(INTERNAL); 2464 default: 2465 break; 2466 } 2467 return JDWP_ERROR(INTERNAL); 2468 } 2469 2470 jint 2471 map2jdwpSuspendStatus(jint state) 2472 { 2473 jint status = 0; 2474 if ( ( state & JVMTI_THREAD_STATE_SUSPENDED ) != 0 ) { 2475 status = JDWP_SUSPEND_STATUS(SUSPENDED); 2476 } 2477 return status; 2478 } 2479 2480 jdwpThreadStatus 2481 map2jdwpThreadStatus(jint state) 2482 { 2483 jdwpThreadStatus status; 2484 2485 status = (jdwpThreadStatus)(-1); 2486 2487 if ( ! ( state & JVMTI_THREAD_STATE_ALIVE ) ) { 2488 if ( state & JVMTI_THREAD_STATE_TERMINATED ) { 2489 status = JDWP_THREAD_STATUS(ZOMBIE); 2490 } else { 2491 /* FIXUP? New JDWP #define for not started? */ 2492 status = (jdwpThreadStatus)(-1); 2493 } 2494 } else { 2495 if ( state & JVMTI_THREAD_STATE_SLEEPING ) { 2496 status = JDWP_THREAD_STATUS(SLEEPING); 2497 } else if ( state & JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER ) { 2498 status = JDWP_THREAD_STATUS(MONITOR); 2499 } else if ( state & JVMTI_THREAD_STATE_WAITING ) { 2500 status = JDWP_THREAD_STATUS(WAIT); 2501 } else if ( state & JVMTI_THREAD_STATE_RUNNABLE ) { 2502 status = JDWP_THREAD_STATUS(RUNNING); 2503 } 2504 } 2505 return status; 2506 } 2507 2508 jint 2509 map2jdwpClassStatus(jint classStatus) 2510 { 2511 jint status = 0; 2512 if ( ( classStatus & JVMTI_CLASS_STATUS_VERIFIED ) != 0 ) { 2513 status |= JDWP_CLASS_STATUS(VERIFIED); 2514 } 2515 if ( ( classStatus & JVMTI_CLASS_STATUS_PREPARED ) != 0 ) { 2516 status |= JDWP_CLASS_STATUS(PREPARED); 2517 } 2518 if ( ( classStatus & JVMTI_CLASS_STATUS_INITIALIZED ) != 0 ) { 2519 status |= JDWP_CLASS_STATUS(INITIALIZED); 2520 } 2521 if ( ( classStatus & JVMTI_CLASS_STATUS_ERROR ) != 0 ) { 2522 status |= JDWP_CLASS_STATUS(ERROR); 2523 } 2524 return status; 2525 } 2526 2527 void 2528 log_debugee_location(const char *func, 2529 jthread thread, jmethodID method, jlocation location) 2530 { 2531 int logging_locations = LOG_TEST(JDWP_LOG_LOC); 2532 2533 if ( logging_locations ) { 2534 char *method_name; 2535 char *class_sig; 2536 jvmtiError error; 2537 jvmtiThreadInfo info; 2538 jint state; 2539 2540 /* Get thread information */ 2541 info.name = NULL; 2542 error = FUNC_PTR(gdata->jvmti,GetThreadInfo) 2543 (gdata->jvmti, thread, &info); 2544 if ( error != JVMTI_ERROR_NONE) { 2545 info.name = NULL; 2546 } 2547 error = FUNC_PTR(gdata->jvmti,GetThreadState) 2548 (gdata->jvmti, thread, &state); 2549 if ( error != JVMTI_ERROR_NONE) { 2550 state = 0; 2551 } 2552 2553 /* Get method if necessary */ 2554 if ( method==NULL ) { 2555 error = FUNC_PTR(gdata->jvmti,GetFrameLocation) 2556 (gdata->jvmti, thread, 0, &method, &location); 2557 if ( error != JVMTI_ERROR_NONE ) { 2558 method = NULL; 2559 location = 0; 2560 } 2561 } 2562 2563 /* Get method name */ 2564 method_name = NULL; 2565 if ( method != NULL ) { 2566 error = methodSignature(method, &method_name, NULL, NULL); 2567 if ( error != JVMTI_ERROR_NONE ) { 2568 method_name = NULL; 2569 } 2570 } 2571 2572 /* Get class signature */ 2573 class_sig = NULL; 2574 if ( method != NULL ) { 2575 jclass clazz; 2576 2577 error = methodClass(method, &clazz); 2578 if ( error == JVMTI_ERROR_NONE ) { 2579 error = classSignature(clazz, &class_sig, NULL); 2580 if ( error != JVMTI_ERROR_NONE ) { 2581 class_sig = NULL; 2582 } 2583 } 2584 } 2585 2586 /* Issue log message */ 2587 LOG_LOC(("%s: debuggee: thread=%p(%s:0x%x),method=%p(%s@%d;%s)", 2588 func, 2589 thread, info.name==NULL ? "?" : info.name, state, 2590 method, method_name==NULL ? "?" : method_name, 2591 (int)location, class_sig==NULL ? "?" : class_sig)); 2592 2593 /* Free memory */ 2594 if ( class_sig != NULL ) { 2595 jvmtiDeallocate(class_sig); 2596 } 2597 if ( method_name != NULL ) { 2598 jvmtiDeallocate(method_name); 2599 } 2600 if ( info.name != NULL ) { 2601 jvmtiDeallocate(info.name); 2602 } 2603 } 2604 } 2605 2606 /* ********************************************************************* */ 2607 /* JDK 6.0: Use of new Heap Iteration functions */ 2608 /* ********************************************************************* */ 2609 2610 /* ********************************************************************* */ 2611 /* Instances */ 2612 2613 /* Structure to hold class instances heap iteration data (arg user_data) */ 2614 typedef struct ClassInstancesData { 2615 jint instCount; 2616 jint maxInstances; 2617 jlong objTag; 2618 jvmtiError error; 2619 } ClassInstancesData; 2620 2621 /* Callback for instance object tagging (heap_reference_callback). */ 2622 static jint JNICALL 2623 cbObjectTagInstance(jvmtiHeapReferenceKind reference_kind, 2624 const jvmtiHeapReferenceInfo* reference_info, jlong class_tag, 2625 jlong referrer_class_tag, jlong size, 2626 jlong* tag_ptr, jlong* referrer_tag_ptr, jint length, void* user_data) 2627 { 2628 ClassInstancesData *data; 2629 2630 /* Check data structure */ 2631 data = (ClassInstancesData*)user_data; 2632 if (data == NULL) { 2633 return JVMTI_VISIT_ABORT; 2634 } 2635 2636 /* If we have tagged enough objects, just abort */ 2637 if ( data->maxInstances != 0 && data->instCount >= data->maxInstances ) { 2638 return JVMTI_VISIT_ABORT; 2639 } 2640 2641 /* If tagged already, just continue */ 2642 if ( (*tag_ptr) != (jlong)0 ) { 2643 return JVMTI_VISIT_OBJECTS; 2644 } 2645 2646 /* Tag the object so we don't count it again, and so we can retrieve it */ 2647 (*tag_ptr) = data->objTag; 2648 data->instCount++; 2649 return JVMTI_VISIT_OBJECTS; 2650 } 2651 2652 /* Get instances for one class */ 2653 jvmtiError 2654 classInstances(jclass klass, ObjectBatch *instances, int maxInstances) 2655 { 2656 ClassInstancesData data; 2657 jvmtiHeapCallbacks heap_callbacks; 2658 jvmtiError error; 2659 jvmtiEnv *jvmti; 2660 2661 /* Check interface assumptions */ 2662 2663 if (klass == NULL) { 2664 return AGENT_ERROR_INVALID_OBJECT; 2665 } 2666 2667 if ( maxInstances < 0 || instances == NULL) { 2668 return AGENT_ERROR_ILLEGAL_ARGUMENT; 2669 } 2670 2671 /* Initialize return information */ 2672 instances->count = 0; 2673 instances->objects = NULL; 2674 2675 /* Get jvmti environment to use */ 2676 jvmti = getSpecialJvmti(); 2677 if ( jvmti == NULL ) { 2678 return AGENT_ERROR_INTERNAL; 2679 } 2680 2681 /* Setup data to passed around the callbacks */ 2682 data.instCount = 0; 2683 data.maxInstances = maxInstances; 2684 data.objTag = (jlong)1; 2685 data.error = JVMTI_ERROR_NONE; 2686 2687 /* Clear out callbacks structure */ 2688 (void)memset(&heap_callbacks,0,sizeof(heap_callbacks)); 2689 2690 /* Set the callbacks we want */ 2691 heap_callbacks.heap_reference_callback = &cbObjectTagInstance; 2692 2693 /* Follow references, no initiating object, just this class, all objects */ 2694 error = JVMTI_FUNC_PTR(jvmti,FollowReferences) 2695 (jvmti, 0, klass, NULL, &heap_callbacks, &data); 2696 if ( error == JVMTI_ERROR_NONE ) { 2697 error = data.error; 2698 } 2699 2700 /* Get all the instances now that they are tagged */ 2701 if ( error == JVMTI_ERROR_NONE ) { 2702 error = JVMTI_FUNC_PTR(jvmti,GetObjectsWithTags) 2703 (jvmti, 1, &(data.objTag), &(instances->count), 2704 &(instances->objects), NULL); 2705 /* Verify we got the count we expected */ 2706 if ( data.instCount != instances->count ) { 2707 error = AGENT_ERROR_INTERNAL; 2708 } 2709 } 2710 2711 /* Dispose of any special jvmti environment */ 2712 (void)JVMTI_FUNC_PTR(jvmti,DisposeEnvironment)(jvmti); 2713 return error; 2714 } 2715 2716 /* ********************************************************************* */ 2717 /* Instance counts. */ 2718 2719 /* Macros to convert a class or instance tag to an index and back again */ 2720 #define INDEX2CLASSTAG(i) ((jlong)((i)+1)) 2721 #define CLASSTAG2INDEX(t) (((int)(t))-1) 2722 #define JLONG_ABS(x) (((x)<(jlong)0)?-(x):(x)) 2723 2724 /* Structure to hold class count heap traversal data (arg user_data) */ 2725 typedef struct ClassCountData { 2726 int classCount; 2727 jlong *counts; 2728 jlong negObjTag; 2729 jvmtiError error; 2730 } ClassCountData; 2731 2732 /* Two different cbObjectCounter's, one for FollowReferences, one for 2733 * IterateThroughHeap. Pick a card, any card. 2734 */ 2735 2736 /* Callback for object count heap traversal (heap_reference_callback) */ 2737 static jint JNICALL 2738 cbObjectCounterFromRef(jvmtiHeapReferenceKind reference_kind, 2739 const jvmtiHeapReferenceInfo* reference_info, jlong class_tag, 2740 jlong referrer_class_tag, jlong size, 2741 jlong* tag_ptr, jlong* referrer_tag_ptr, jint length, void* user_data) 2742 { 2743 ClassCountData *data; 2744 int index; 2745 jlong jindex; 2746 jlong tag; 2747 2748 /* Check data structure */ 2749 data = (ClassCountData*)user_data; 2750 if (data == NULL) { 2751 return JVMTI_VISIT_ABORT; 2752 } 2753 2754 /* Classes with no class_tag should have been filtered out. */ 2755 if ( class_tag == (jlong)0 ) { 2756 data->error = AGENT_ERROR_INTERNAL; 2757 return JVMTI_VISIT_ABORT; 2758 } 2759 2760 /* Class tag not one we really want (jclass not in supplied list) */ 2761 if ( class_tag == data->negObjTag ) { 2762 return JVMTI_VISIT_OBJECTS; 2763 } 2764 2765 /* If object tag is negative, just continue, we counted it */ 2766 tag = (*tag_ptr); 2767 if ( tag < (jlong)0 ) { 2768 return JVMTI_VISIT_OBJECTS; 2769 } 2770 2771 /* Tag the object with a negative value just so we don't count it again */ 2772 if ( tag == (jlong)0 ) { 2773 /* This object had no tag value, so we give it the negObjTag value */ 2774 (*tag_ptr) = data->negObjTag; 2775 } else { 2776 /* If this object had a positive tag value, it must be one of the 2777 * jclass objects we tagged. We need to preserve the value of 2778 * this tag for later objects that might have this as a class 2779 * tag, so we just make the existing tag value negative. 2780 */ 2781 (*tag_ptr) = -tag; 2782 } 2783 2784 /* Absolute value of class tag is an index into the counts[] array */ 2785 jindex = JLONG_ABS(class_tag); 2786 index = CLASSTAG2INDEX(jindex); 2787 if (index < 0 || index >= data->classCount) { 2788 data->error = AGENT_ERROR_ILLEGAL_ARGUMENT; 2789 return JVMTI_VISIT_ABORT; 2790 } 2791 2792 /* Bump instance count on this class */ 2793 data->counts[index]++; 2794 return JVMTI_VISIT_OBJECTS; 2795 } 2796 2797 /* Callback for instance count heap traversal (heap_iteration_callback) */ 2798 static jint JNICALL 2799 cbObjectCounter(jlong class_tag, jlong size, jlong* tag_ptr, jint length, 2800 void* user_data) 2801 { 2802 ClassCountData *data; 2803 int index; 2804 2805 /* Check data structure */ 2806 data = (ClassCountData*)user_data; 2807 if (data == NULL) { 2808 return JVMTI_VISIT_ABORT; 2809 } 2810 2811 /* Classes with no tag should be filtered out. */ 2812 if ( class_tag == (jlong)0 ) { 2813 data->error = AGENT_ERROR_INTERNAL; 2814 return JVMTI_VISIT_ABORT; 2815 } 2816 2817 /* Class tag is actually an index into data arrays */ 2818 index = CLASSTAG2INDEX(class_tag); 2819 if (index < 0 || index >= data->classCount) { 2820 data->error = AGENT_ERROR_ILLEGAL_ARGUMENT; 2821 return JVMTI_VISIT_ABORT; 2822 } 2823 2824 /* Bump instance count on this class */ 2825 data->counts[index]++; 2826 return JVMTI_VISIT_OBJECTS; 2827 } 2828 2829 /* Get instance counts for a set of classes */ 2830 jvmtiError 2831 classInstanceCounts(jint classCount, jclass *classes, jlong *counts) 2832 { 2833 jvmtiHeapCallbacks heap_callbacks; 2834 ClassCountData data; 2835 jvmtiError error; 2836 jvmtiEnv *jvmti; 2837 int i; 2838 2839 /* Check interface assumptions */ 2840 if ( classes == NULL || classCount <= 0 || counts == NULL ) { 2841 return AGENT_ERROR_ILLEGAL_ARGUMENT; 2842 } 2843 2844 /* Initialize return information */ 2845 for ( i = 0 ; i < classCount ; i++ ) { 2846 counts[i] = (jlong)0; 2847 } 2848 2849 /* Get jvmti environment to use */ 2850 jvmti = getSpecialJvmti(); 2851 if ( jvmti == NULL ) { 2852 return AGENT_ERROR_INTERNAL; 2853 } 2854 2855 /* Setup class data structure */ 2856 data.error = JVMTI_ERROR_NONE; 2857 data.classCount = classCount; 2858 data.counts = counts; 2859 2860 error = JVMTI_ERROR_NONE; 2861 /* Set tags on classes, use index in classes[] as the tag value. */ 2862 error = JVMTI_ERROR_NONE; 2863 for ( i = 0 ; i < classCount ; i++ ) { 2864 if (classes[i] != NULL) { 2865 jlong tag; 2866 2867 tag = INDEX2CLASSTAG(i); 2868 error = JVMTI_FUNC_PTR(jvmti,SetTag) (jvmti, classes[i], tag); 2869 if ( error != JVMTI_ERROR_NONE ) { 2870 break; 2871 } 2872 } 2873 } 2874 2875 /* Traverse heap, two ways to do this for instance counts. */ 2876 if ( error == JVMTI_ERROR_NONE ) { 2877 2878 /* Clear out callbacks structure */ 2879 (void)memset(&heap_callbacks,0,sizeof(heap_callbacks)); 2880 2881 /* Check debug flags to see how to do this. */ 2882 if ( (gdata->debugflags & USE_ITERATE_THROUGH_HEAP) == 0 ) { 2883 2884 /* Using FollowReferences only gives us live objects, but we 2885 * need to tag the objects to avoid counting them twice since 2886 * the callback is per reference. 2887 * The jclass objects have been tagged with their index in the 2888 * supplied list, and that tag may flip to negative if it 2889 * is also an object of interest. 2890 * All other objects being counted that weren't in the 2891 * supplied classes list will have a negative classCount 2892 * tag value. So all objects counted will have negative tags. 2893 * If the absolute tag value is an index in the supplied 2894 * list, then it's one of the supplied classes. 2895 */ 2896 data.negObjTag = -INDEX2CLASSTAG(classCount); 2897 2898 /* Setup callbacks, only using object reference callback */ 2899 heap_callbacks.heap_reference_callback = &cbObjectCounterFromRef; 2900 2901 /* Follow references, no initiating object, tagged classes only */ 2902 error = JVMTI_FUNC_PTR(jvmti,FollowReferences) 2903 (jvmti, JVMTI_HEAP_FILTER_CLASS_UNTAGGED, 2904 NULL, NULL, &heap_callbacks, &data); 2905 2906 } else { 2907 2908 /* Using IterateThroughHeap means that we will visit each object 2909 * once, so no special tag tricks here. Just simple counting. 2910 * However in this case the object might not be live, so we do 2911 * a GC beforehand to make sure we minimize this. 2912 */ 2913 2914 /* FIXUP: Need some kind of trigger here to avoid excessive GC's? */ 2915 error = JVMTI_FUNC_PTR(jvmti,ForceGarbageCollection)(jvmti); 2916 if ( error != JVMTI_ERROR_NONE ) { 2917 2918 /* Setup callbacks, just need object callback */ 2919 heap_callbacks.heap_iteration_callback = &cbObjectCounter; 2920 2921 /* Iterate through entire heap, tagged classes only */ 2922 error = JVMTI_FUNC_PTR(jvmti,IterateThroughHeap) 2923 (jvmti, JVMTI_HEAP_FILTER_CLASS_UNTAGGED, 2924 NULL, &heap_callbacks, &data); 2925 2926 } 2927 } 2928 2929 /* Use data error if needed */ 2930 if ( error == JVMTI_ERROR_NONE ) { 2931 error = data.error; 2932 } 2933 2934 } 2935 2936 /* Dispose of any special jvmti environment */ 2937 (void)JVMTI_FUNC_PTR(jvmti,DisposeEnvironment)(jvmti); 2938 return error; 2939 } 2940 2941 /* ********************************************************************* */ 2942 /* Referrers */ 2943 2944 /* Structure to hold object referrer heap traversal data (arg user_data) */ 2945 typedef struct ReferrerData { 2946 int refCount; 2947 int maxObjects; 2948 jlong refTag; 2949 jlong objTag; 2950 jboolean selfRef; 2951 jvmtiError error; 2952 } ReferrerData; 2953 2954 /* Callback for referrers object tagging (heap_reference_callback). */ 2955 static jint JNICALL 2956 cbObjectTagReferrer(jvmtiHeapReferenceKind reference_kind, 2957 const jvmtiHeapReferenceInfo* reference_info, jlong class_tag, 2958 jlong referrer_class_tag, jlong size, 2959 jlong* tag_ptr, jlong* referrer_tag_ptr, jint length, void* user_data) 2960 { 2961 ReferrerData *data; 2962 2963 /* Check data structure */ 2964 data = (ReferrerData*)user_data; 2965 if (data == NULL) { 2966 return JVMTI_VISIT_ABORT; 2967 } 2968 2969 /* If we have tagged enough objects, just abort */ 2970 if ( data->maxObjects != 0 && data->refCount >= data->maxObjects ) { 2971 return JVMTI_VISIT_ABORT; 2972 } 2973 2974 /* If not of interest, just continue */ 2975 if ( (*tag_ptr) != data->objTag ) { 2976 return JVMTI_VISIT_OBJECTS; 2977 } 2978 2979 /* Self reference that we haven't counted? */ 2980 if ( tag_ptr == referrer_tag_ptr ) { 2981 if ( data->selfRef == JNI_FALSE ) { 2982 data->selfRef = JNI_TRUE; 2983 data->refCount++; 2984 } 2985 return JVMTI_VISIT_OBJECTS; 2986 } 2987 2988 /* If the referrer can be tagged, and hasn't been tagged, tag it */ 2989 if ( referrer_tag_ptr != NULL ) { 2990 if ( (*referrer_tag_ptr) == (jlong)0 ) { 2991 *referrer_tag_ptr = data->refTag; 2992 data->refCount++; 2993 } 2994 } 2995 return JVMTI_VISIT_OBJECTS; 2996 } 2997 2998 /* Heap traversal to find referrers of an object */ 2999 jvmtiError 3000 objectReferrers(jobject obj, ObjectBatch *referrers, int maxObjects) 3001 { 3002 jvmtiHeapCallbacks heap_callbacks; 3003 ReferrerData data; 3004 jvmtiError error; 3005 jvmtiEnv *jvmti; 3006 3007 /* Check interface assumptions */ 3008 if (obj == NULL) { 3009 return AGENT_ERROR_INVALID_OBJECT; 3010 } 3011 if (referrers == NULL || maxObjects < 0 ) { 3012 return AGENT_ERROR_ILLEGAL_ARGUMENT; 3013 } 3014 3015 /* Initialize return information */ 3016 referrers->count = 0; 3017 referrers->objects = NULL; 3018 3019 /* Get jvmti environment to use */ 3020 jvmti = getSpecialJvmti(); 3021 if ( jvmti == NULL ) { 3022 return AGENT_ERROR_INTERNAL; 3023 } 3024 3025 /* Fill in the data structure passed around the callbacks */ 3026 data.refCount = 0; 3027 data.maxObjects = maxObjects; 3028 data.objTag = (jlong)1; 3029 data.refTag = (jlong)2; 3030 data.selfRef = JNI_FALSE; 3031 data.error = JVMTI_ERROR_NONE; 3032 3033 /* Tag the object of interest */ 3034 error = JVMTI_FUNC_PTR(jvmti,SetTag) (jvmti, obj, data.objTag); 3035 3036 /* No need to go any further if we can't tag the object */ 3037 if ( error == JVMTI_ERROR_NONE ) { 3038 3039 /* Clear out callbacks structure */ 3040 (void)memset(&heap_callbacks,0,sizeof(heap_callbacks)); 3041 3042 /* Setup callbacks we want */ 3043 heap_callbacks.heap_reference_callback = &cbObjectTagReferrer; 3044 3045 /* Follow references, no initiating object, all classes, 1 tagged objs */ 3046 error = JVMTI_FUNC_PTR(jvmti,FollowReferences) 3047 (jvmti, JVMTI_HEAP_FILTER_UNTAGGED, 3048 NULL, NULL, &heap_callbacks, &data); 3049 3050 /* Use data error if needed */ 3051 if ( error == JVMTI_ERROR_NONE ) { 3052 error = data.error; 3053 } 3054 3055 } 3056 3057 /* Watch out for self-reference */ 3058 if ( error == JVMTI_ERROR_NONE && data.selfRef == JNI_TRUE ) { 3059 /* Tag itself as a referer */ 3060 error = JVMTI_FUNC_PTR(jvmti,SetTag) (jvmti, obj, data.refTag); 3061 } 3062 3063 /* Get the jobjects for the tagged referrer objects. */ 3064 if ( error == JVMTI_ERROR_NONE ) { 3065 error = JVMTI_FUNC_PTR(jvmti,GetObjectsWithTags) 3066 (jvmti, 1, &(data.refTag), &(referrers->count), 3067 &(referrers->objects), NULL); 3068 /* Verify we got the count we expected */ 3069 if ( data.refCount != referrers->count ) { 3070 error = AGENT_ERROR_INTERNAL; 3071 } 3072 } 3073 3074 /* Dispose of any special jvmti environment */ 3075 (void)JVMTI_FUNC_PTR(jvmti,DisposeEnvironment)(jvmti); 3076 return error; 3077 } --- EOF ---