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