1 /* 2 * Copyright (c) 1998, 2008, 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 "util.h" 27 #include "ThreadReferenceImpl.h" 28 #include "eventHandler.h" 29 #include "threadControl.h" 30 #include "inStream.h" 31 #include "outStream.h" 32 #include "FrameID.h" 33 34 static jboolean 35 name(PacketInputStream *in, PacketOutputStream *out) 36 { 37 JNIEnv *env; 38 jthread thread; 39 40 env = getEnv(); 41 42 thread = inStream_readThreadRef(env, in); 43 if (inStream_error(in)) { 44 return JNI_TRUE; 45 } 46 47 if (threadControl_isDebugThread(thread)) { 48 outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); 49 return JNI_TRUE; 50 } 51 52 WITH_LOCAL_REFS(env, 1) { 53 54 jvmtiThreadInfo info; 55 jvmtiError error; 56 57 (void)memset(&info, 0, sizeof(info)); 58 59 error = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadInfo) 60 (gdata->jvmti, thread, &info); 61 62 if (error != JVMTI_ERROR_NONE) { 63 outStream_setError(out, map2jdwpError(error)); 64 } else { 65 (void)outStream_writeString(out, info.name); 66 } 67 68 if ( info.name != NULL ) 69 jvmtiDeallocate(info.name); 70 71 } END_WITH_LOCAL_REFS(env); 72 73 return JNI_TRUE; 74 } 75 76 static jboolean 77 suspend(PacketInputStream *in, PacketOutputStream *out) 78 { 79 jvmtiError error; 80 jthread thread; 81 82 thread = inStream_readThreadRef(getEnv(), in); 83 if (inStream_error(in)) { 84 return JNI_TRUE; 85 } 86 87 if (threadControl_isDebugThread(thread)) { 88 outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); 89 return JNI_TRUE; 90 } 91 error = threadControl_suspendThread(thread, JNI_FALSE); 92 if (error != JVMTI_ERROR_NONE) { 93 outStream_setError(out, map2jdwpError(error)); 94 } 95 return JNI_TRUE; 96 } 97 98 static jboolean 99 resume(PacketInputStream *in, PacketOutputStream *out) 100 { 101 jvmtiError error; 102 jthread thread; 103 104 thread = inStream_readThreadRef(getEnv(), in); 105 if (inStream_error(in)) { 106 return JNI_TRUE; 107 } 108 109 if (threadControl_isDebugThread(thread)) { 110 outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); 111 return JNI_TRUE; 112 } 113 114 /* true means it is okay to unblock the commandLoop thread */ 115 error = threadControl_resumeThread(thread, JNI_TRUE); 116 if (error != JVMTI_ERROR_NONE) { 117 outStream_setError(out, map2jdwpError(error)); 118 } 119 return JNI_TRUE; 120 } 121 122 static jboolean 123 status(PacketInputStream *in, PacketOutputStream *out) 124 { 125 jdwpThreadStatus threadStatus; 126 jint statusFlags; 127 jvmtiError error; 128 jthread thread; 129 130 thread = inStream_readThreadRef(getEnv(), in); 131 if (inStream_error(in)) { 132 return JNI_TRUE; 133 } 134 135 if (threadControl_isDebugThread(thread)) { 136 outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); 137 return JNI_TRUE; 138 } 139 140 error = threadControl_applicationThreadStatus(thread, &threadStatus, 141 &statusFlags); 142 if (error != JVMTI_ERROR_NONE) { 143 outStream_setError(out, map2jdwpError(error)); 144 return JNI_TRUE; 145 } 146 (void)outStream_writeInt(out, threadStatus); 147 (void)outStream_writeInt(out, statusFlags); 148 return JNI_TRUE; 149 } 150 151 static jboolean 152 threadGroup(PacketInputStream *in, PacketOutputStream *out) 153 { 154 JNIEnv *env; 155 jthread thread; 156 157 env = getEnv(); 158 159 thread = inStream_readThreadRef(env, in); 160 if (inStream_error(in)) { 161 return JNI_TRUE; 162 } 163 164 if (threadControl_isDebugThread(thread)) { 165 outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); 166 return JNI_TRUE; 167 } 168 169 WITH_LOCAL_REFS(env, 1) { 170 171 jvmtiThreadInfo info; 172 jvmtiError error; 173 174 (void)memset(&info, 0, sizeof(info)); 175 176 error = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadInfo) 177 (gdata->jvmti, thread, &info); 178 179 if (error != JVMTI_ERROR_NONE) { 180 outStream_setError(out, map2jdwpError(error)); 181 } else { 182 (void)outStream_writeObjectRef(env, out, info.thread_group); 183 } 184 185 if ( info.name!=NULL ) 186 jvmtiDeallocate(info.name); 187 188 } END_WITH_LOCAL_REFS(env); 189 190 return JNI_TRUE; 191 } 192 193 static jboolean 194 validateSuspendedThread(PacketOutputStream *out, jthread thread) 195 { 196 jvmtiError error; 197 jint count; 198 199 error = threadControl_suspendCount(thread, &count); 200 if (error != JVMTI_ERROR_NONE) { 201 outStream_setError(out, map2jdwpError(error)); 202 return JNI_FALSE; 203 } 204 205 if (count == 0) { 206 outStream_setError(out, JDWP_ERROR(THREAD_NOT_SUSPENDED)); 207 return JNI_FALSE; 208 } 209 210 return JNI_TRUE; 211 } 212 213 static jboolean 214 frames(PacketInputStream *in, PacketOutputStream *out) 215 { 216 jvmtiError error; 217 FrameNumber fnum; 218 jint count; 219 JNIEnv *env; 220 jthread thread; 221 jint startIndex; 222 jint length; 223 224 env = getEnv(); 225 226 thread = inStream_readThreadRef(env, in); 227 if (inStream_error(in)) { 228 return JNI_TRUE; 229 } 230 startIndex = inStream_readInt(in); 231 if (inStream_error(in)) { 232 return JNI_TRUE; 233 } 234 length = inStream_readInt(in); 235 if (inStream_error(in)) { 236 return JNI_TRUE; 237 } 238 239 if (threadControl_isDebugThread(thread)) { 240 outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); 241 return JNI_TRUE; 242 } 243 244 if (!validateSuspendedThread(out, thread)) { 245 return JNI_TRUE; 246 } 247 248 error = JVMTI_FUNC_PTR(gdata->jvmti,GetFrameCount) 249 (gdata->jvmti, thread, &count); 250 if (error != JVMTI_ERROR_NONE) { 251 outStream_setError(out, map2jdwpError(error)); 252 return JNI_TRUE; 253 } 254 255 if (length == -1) { 256 length = count - startIndex; 257 } 258 259 if (length == 0) { 260 (void)outStream_writeInt(out, 0); 261 return JNI_TRUE; 262 } 263 264 if ((startIndex < 0) || (startIndex > count - 1)) { 265 outStream_setError(out, JDWP_ERROR(INVALID_INDEX)); 266 return JNI_TRUE; 267 } 268 269 if ((length < 0) || (length + startIndex > count)) { 270 outStream_setError(out, JDWP_ERROR(INVALID_LENGTH)); 271 return JNI_TRUE; 272 } 273 274 (void)outStream_writeInt(out, length); 275 276 for(fnum = startIndex ; fnum < startIndex+length ; fnum++ ) { 277 278 WITH_LOCAL_REFS(env, 1) { 279 280 jclass clazz; 281 jmethodID method; 282 jlocation location; 283 284 /* Get location info */ 285 error = JVMTI_FUNC_PTR(gdata->jvmti,GetFrameLocation) 286 (gdata->jvmti, thread, fnum, &method, &location); 287 if (error == JVMTI_ERROR_OPAQUE_FRAME) { 288 clazz = NULL; 289 location = -1L; 290 error = JVMTI_ERROR_NONE; 291 } else if ( error == JVMTI_ERROR_NONE ) { 292 error = methodClass(method, &clazz); 293 if ( error == JVMTI_ERROR_NONE ) { 294 FrameID frame; 295 frame = createFrameID(thread, fnum); 296 (void)outStream_writeFrameID(out, frame); 297 writeCodeLocation(out, clazz, method, location); 298 } 299 } 300 301 } END_WITH_LOCAL_REFS(env); 302 303 if (error != JVMTI_ERROR_NONE) 304 break; 305 306 } 307 308 if (error != JVMTI_ERROR_NONE) { 309 outStream_setError(out, map2jdwpError(error)); 310 } 311 return JNI_TRUE; 312 } 313 314 static jboolean 315 getFrameCount(PacketInputStream *in, PacketOutputStream *out) 316 { 317 jvmtiError error; 318 jint count; 319 jthread thread; 320 321 thread = inStream_readThreadRef(getEnv(), in); 322 if (inStream_error(in)) { 323 return JNI_TRUE; 324 } 325 326 if (threadControl_isDebugThread(thread)) { 327 outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); 328 return JNI_TRUE; 329 } 330 331 if (!validateSuspendedThread(out, thread)) { 332 return JNI_TRUE; 333 } 334 335 error = JVMTI_FUNC_PTR(gdata->jvmti,GetFrameCount) 336 (gdata->jvmti, thread, &count); 337 if (error != JVMTI_ERROR_NONE) { 338 outStream_setError(out, map2jdwpError(error)); 339 return JNI_TRUE; 340 } 341 (void)outStream_writeInt(out, count); 342 343 return JNI_TRUE; 344 } 345 346 static jboolean 347 ownedMonitors(PacketInputStream *in, PacketOutputStream *out) 348 { 349 JNIEnv *env; 350 jthread thread; 351 352 env = getEnv(); 353 354 thread = inStream_readThreadRef(env, in); 355 if (inStream_error(in)) { 356 return JNI_TRUE; 357 } 358 359 if (threadControl_isDebugThread(thread)) { 360 outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); 361 return JNI_TRUE; 362 } 363 364 if (!validateSuspendedThread(out, thread)) { 365 return JNI_TRUE; 366 } 367 368 WITH_LOCAL_REFS(env, 1) { 369 370 jvmtiError error; 371 jint count = 0; 372 jobject *monitors = NULL; 373 374 error = JVMTI_FUNC_PTR(gdata->jvmti,GetOwnedMonitorInfo) 375 (gdata->jvmti, thread, &count, &monitors); 376 if (error != JVMTI_ERROR_NONE) { 377 outStream_setError(out, map2jdwpError(error)); 378 } else { 379 int i; 380 (void)outStream_writeInt(out, count); 381 for (i = 0; i < count; i++) { 382 jobject monitor = monitors[i]; 383 (void)outStream_writeByte(out, specificTypeKey(env, monitor)); 384 (void)outStream_writeObjectRef(env, out, monitor); 385 } 386 } 387 if (monitors != NULL) 388 jvmtiDeallocate(monitors); 389 390 } END_WITH_LOCAL_REFS(env); 391 392 return JNI_TRUE; 393 } 394 395 static jboolean 396 currentContendedMonitor(PacketInputStream *in, PacketOutputStream *out) 397 { 398 JNIEnv *env; 399 jthread thread; 400 401 env = getEnv(); 402 403 thread = inStream_readThreadRef(env, in); 404 if (inStream_error(in)) { 405 return JNI_TRUE; 406 } 407 408 if (thread == NULL || threadControl_isDebugThread(thread)) { 409 outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); 410 return JNI_TRUE; 411 } 412 413 if (!validateSuspendedThread(out, thread)) { 414 return JNI_TRUE; 415 } 416 417 WITH_LOCAL_REFS(env, 1) { 418 419 jobject monitor; 420 jvmtiError error; 421 422 error = JVMTI_FUNC_PTR(gdata->jvmti,GetCurrentContendedMonitor) 423 (gdata->jvmti, thread, &monitor); 424 425 if (error != JVMTI_ERROR_NONE) { 426 outStream_setError(out, map2jdwpError(error)); 427 } else { 428 (void)outStream_writeByte(out, specificTypeKey(env, monitor)); 429 (void)outStream_writeObjectRef(env, out, monitor); 430 } 431 432 } END_WITH_LOCAL_REFS(env); 433 434 return JNI_TRUE; 435 } 436 437 static jboolean 438 stop(PacketInputStream *in, PacketOutputStream *out) 439 { 440 jvmtiError error; 441 jthread thread; 442 jobject throwable; 443 JNIEnv *env; 444 445 env = getEnv(); 446 thread = inStream_readThreadRef(env, in); 447 if (inStream_error(in)) { 448 return JNI_TRUE; 449 } 450 throwable = inStream_readObjectRef(env, in); 451 if (inStream_error(in)) { 452 return JNI_TRUE; 453 } 454 455 if (threadControl_isDebugThread(thread)) { 456 outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); 457 return JNI_TRUE; 458 } 459 460 error = threadControl_stop(thread, throwable); 461 if (error != JVMTI_ERROR_NONE) { 462 outStream_setError(out, map2jdwpError(error)); 463 } 464 return JNI_TRUE; 465 } 466 467 static jboolean 468 interrupt(PacketInputStream *in, PacketOutputStream *out) 469 { 470 jvmtiError error; 471 jthread thread; 472 473 thread = inStream_readThreadRef(getEnv(), in); 474 if (inStream_error(in)) { 475 return JNI_TRUE; 476 } 477 478 if (threadControl_isDebugThread(thread)) { 479 outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); 480 return JNI_TRUE; 481 } 482 483 error = threadControl_interrupt(thread); 484 if (error != JVMTI_ERROR_NONE) { 485 outStream_setError(out, map2jdwpError(error)); 486 } 487 return JNI_TRUE; 488 } 489 490 static jboolean 491 suspendCount(PacketInputStream *in, PacketOutputStream *out) 492 { 493 jvmtiError error; 494 jint count; 495 jthread thread; 496 497 thread = inStream_readThreadRef(getEnv(), in); 498 if (inStream_error(in)) { 499 return JNI_TRUE; 500 } 501 502 if (threadControl_isDebugThread(thread)) { 503 outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); 504 return JNI_TRUE; 505 } 506 507 error = threadControl_suspendCount(thread, &count); 508 if (error != JVMTI_ERROR_NONE) { 509 outStream_setError(out, map2jdwpError(error)); 510 return JNI_TRUE; 511 } 512 513 (void)outStream_writeInt(out, count); 514 return JNI_TRUE; 515 } 516 517 static jboolean 518 ownedMonitorsWithStackDepth(PacketInputStream *in, PacketOutputStream *out) 519 { 520 JNIEnv *env; 521 jthread thread; 522 523 thread = inStream_readThreadRef(getEnv(), in); 524 if (inStream_error(in)) { 525 return JNI_TRUE; 526 } 527 528 if (thread == NULL || threadControl_isDebugThread(thread)) { 529 outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); 530 return JNI_TRUE; 531 } 532 533 if (!validateSuspendedThread(out, thread)) { 534 return JNI_TRUE; 535 } 536 537 env = getEnv(); 538 539 WITH_LOCAL_REFS(env, 1) { 540 541 jvmtiError error = JVMTI_ERROR_NONE; 542 jint count = 0; 543 jvmtiMonitorStackDepthInfo *monitors=NULL; 544 545 error = JVMTI_FUNC_PTR(gdata->jvmti,GetOwnedMonitorStackDepthInfo) 546 (gdata->jvmti, thread, &count, &monitors); 547 548 if (error != JVMTI_ERROR_NONE) { 549 outStream_setError(out, map2jdwpError(error)); 550 } else { 551 int i; 552 (void)outStream_writeInt(out, count); 553 for (i = 0; i < count; i++) { 554 jobject monitor = monitors[i].monitor; 555 (void)outStream_writeByte(out, specificTypeKey(env, monitor)); 556 (void)outStream_writeObjectRef(getEnv(), out, monitor); 557 (void)outStream_writeInt(out,monitors[i].stack_depth); 558 } 559 } 560 if (monitors != NULL) { 561 jvmtiDeallocate(monitors); 562 } 563 564 } END_WITH_LOCAL_REFS(env); 565 566 return JNI_TRUE; 567 } 568 569 static jboolean 570 forceEarlyReturn(PacketInputStream *in, PacketOutputStream *out) 571 { 572 JNIEnv *env; 573 jthread thread; 574 jvalue value; 575 jbyte typeKey; 576 jvmtiError error; 577 578 env = getEnv(); 579 thread = inStream_readThreadRef(env, in); 580 if (inStream_error(in)) { 581 return JNI_TRUE; 582 } 583 584 if (threadControl_isDebugThread(thread)) { 585 outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); 586 return JNI_TRUE; 587 } 588 589 typeKey = inStream_readByte(in); 590 if (inStream_error(in)) { 591 return JNI_TRUE; 592 } 593 594 if (isObjectTag(typeKey)) { 595 value.l = inStream_readObjectRef(env, in); 596 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnObject) 597 (gdata->jvmti, thread, value.l); 598 } else { 599 switch (typeKey) { 600 case JDWP_TAG(VOID): 601 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnVoid) 602 (gdata->jvmti, thread); 603 break; 604 case JDWP_TAG(BYTE): 605 value.b = inStream_readByte(in); 606 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnInt) 607 (gdata->jvmti, thread, value.b); 608 break; 609 610 case JDWP_TAG(CHAR): 611 value.c = inStream_readChar(in); 612 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnInt) 613 (gdata->jvmti, thread, value.c); 614 break; 615 616 case JDWP_TAG(FLOAT): 617 value.f = inStream_readFloat(in); 618 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnFloat) 619 (gdata->jvmti, thread, value.f); 620 break; 621 622 case JDWP_TAG(DOUBLE): 623 value.d = inStream_readDouble(in); 624 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnDouble) 625 (gdata->jvmti, thread, value.d); 626 break; 627 628 case JDWP_TAG(INT): 629 value.i = inStream_readInt(in); 630 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnInt) 631 (gdata->jvmti, thread, value.i); 632 break; 633 634 case JDWP_TAG(LONG): 635 value.j = inStream_readLong(in); 636 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnLong) 637 (gdata->jvmti, thread, value.j); 638 break; 639 640 case JDWP_TAG(SHORT): 641 value.s = inStream_readShort(in); 642 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnInt) 643 (gdata->jvmti, thread, value.s); 644 break; 645 646 case JDWP_TAG(BOOLEAN): 647 value.z = inStream_readBoolean(in); 648 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnInt) 649 (gdata->jvmti, thread, value.z); 650 break; 651 652 default: 653 error = AGENT_ERROR_INVALID_TAG; 654 break; 655 } 656 } 657 { 658 jdwpError serror = map2jdwpError(error); 659 if (serror != JDWP_ERROR(NONE)) { 660 outStream_setError(out, serror); 661 } 662 } 663 return JNI_TRUE; 664 } 665 666 667 void *ThreadReference_Cmds[] = { (void *)14, 668 (void *)name, 669 (void *)suspend, 670 (void *)resume, 671 (void *)status, 672 (void *)threadGroup, 673 (void *)frames, 674 (void *)getFrameCount, 675 (void *)ownedMonitors, 676 (void *)currentContendedMonitor, 677 (void *)stop, 678 (void *)interrupt, 679 (void *)suspendCount, 680 (void *)ownedMonitorsWithStackDepth, 681 (void *)forceEarlyReturn 682 }; 683