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