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