1 /* 2 * Copyright (c) 1998, 2018, 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 index; 218 jint count; 219 jint filledIn; 220 JNIEnv *env; 221 jthread thread; 222 jint startIndex; 223 jint length; 224 jvmtiFrameInfo* frames; 225 226 env = getEnv(); 227 228 thread = inStream_readThreadRef(env, in); 229 if (inStream_error(in)) { 230 return JNI_TRUE; 231 } 232 startIndex = inStream_readInt(in); 233 if (inStream_error(in)) { 234 return JNI_TRUE; 235 } 236 length = inStream_readInt(in); 237 if (inStream_error(in)) { 238 return JNI_TRUE; 239 } 240 241 if (threadControl_isDebugThread(thread)) { 242 outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); 243 return JNI_TRUE; 244 } 245 246 if (!validateSuspendedThread(out, thread)) { 247 return JNI_TRUE; 248 } 249 250 error = JVMTI_FUNC_PTR(gdata->jvmti,GetFrameCount) 251 (gdata->jvmti, thread, &count); 252 if (error != JVMTI_ERROR_NONE) { 253 outStream_setError(out, map2jdwpError(error)); 254 return JNI_TRUE; 255 } 256 257 if (length == -1) { 258 length = count - startIndex; 259 } 260 261 if (length == 0) { 262 (void)outStream_writeInt(out, 0); 263 return JNI_TRUE; 264 } 265 266 if ((startIndex < 0) || (startIndex > count - 1)) { 267 outStream_setError(out, JDWP_ERROR(INVALID_INDEX)); 268 return JNI_TRUE; 269 } 270 271 if ((length < 0) || (length + startIndex > count)) { 272 outStream_setError(out, JDWP_ERROR(INVALID_LENGTH)); 273 return JNI_TRUE; 274 } 275 276 (void)outStream_writeInt(out, length); 277 278 frames = jvmtiAllocate(sizeof(jvmtiFrameInfo) * length); 279 280 if (frames == NULL) { 281 outStream_setError(out, JDWP_ERROR(OUT_OF_MEMORY)); 282 return JNI_TRUE; 283 } 284 285 error = JVMTI_FUNC_PTR(gdata->jvmti, GetStackTrace) 286 (gdata->jvmti, thread, startIndex, length, frames, 287 &filledIn); 288 289 /* Should not happen. */ 290 if (error == JVMTI_ERROR_NONE && length != filledIn) { 291 error = JVMTI_ERROR_INTERNAL; 292 } 293 294 for (index = 0; index < filledIn && error == JVMTI_ERROR_NONE; ++index) { 295 WITH_LOCAL_REFS(env, 1) { 296 jclass clazz; 297 error = methodClass(frames[index].method, &clazz); 298 299 if (error == JVMTI_ERROR_NONE) { 300 FrameID frame = createFrameID(thread, index + startIndex); 301 outStream_writeFrameID(out, frame); 302 writeCodeLocation(out, clazz, frames[index].method, 303 frames[index].location); 304 } 305 } END_WITH_LOCAL_REFS(env); 306 } 307 308 jvmtiDeallocate(frames); 309 310 if (error != JVMTI_ERROR_NONE) { 311 outStream_setError(out, map2jdwpError(error)); 312 } 313 return JNI_TRUE; 314 } 315 316 static jboolean 317 getFrameCount(PacketInputStream *in, PacketOutputStream *out) 318 { 319 jvmtiError error; 320 jint count; 321 jthread thread; 322 323 thread = inStream_readThreadRef(getEnv(), in); 324 if (inStream_error(in)) { 325 return JNI_TRUE; 326 } 327 328 if (threadControl_isDebugThread(thread)) { 329 outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); 330 return JNI_TRUE; 331 } 332 333 if (!validateSuspendedThread(out, thread)) { 334 return JNI_TRUE; 335 } 336 337 error = JVMTI_FUNC_PTR(gdata->jvmti,GetFrameCount) 338 (gdata->jvmti, thread, &count); 339 if (error != JVMTI_ERROR_NONE) { 340 outStream_setError(out, map2jdwpError(error)); 341 return JNI_TRUE; 342 } 343 (void)outStream_writeInt(out, count); 344 345 return JNI_TRUE; 346 } 347 348 static jboolean 349 ownedMonitors(PacketInputStream *in, PacketOutputStream *out) 350 { 351 JNIEnv *env; 352 jthread thread; 353 354 env = getEnv(); 355 356 thread = inStream_readThreadRef(env, in); 357 if (inStream_error(in)) { 358 return JNI_TRUE; 359 } 360 361 if (threadControl_isDebugThread(thread)) { 362 outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); 363 return JNI_TRUE; 364 } 365 366 if (!validateSuspendedThread(out, thread)) { 367 return JNI_TRUE; 368 } 369 370 WITH_LOCAL_REFS(env, 1) { 371 372 jvmtiError error; 373 jint count = 0; 374 jobject *monitors = NULL; 375 376 error = JVMTI_FUNC_PTR(gdata->jvmti,GetOwnedMonitorInfo) 377 (gdata->jvmti, thread, &count, &monitors); 378 if (error != JVMTI_ERROR_NONE) { 379 outStream_setError(out, map2jdwpError(error)); 380 } else { 381 int i; 382 (void)outStream_writeInt(out, count); 383 for (i = 0; i < count; i++) { 384 jobject monitor = monitors[i]; 385 (void)outStream_writeByte(out, specificTypeKey(env, monitor)); 386 (void)outStream_writeObjectRef(env, out, monitor); 387 } 388 } 389 if (monitors != NULL) 390 jvmtiDeallocate(monitors); 391 392 } END_WITH_LOCAL_REFS(env); 393 394 return JNI_TRUE; 395 } 396 397 static jboolean 398 currentContendedMonitor(PacketInputStream *in, PacketOutputStream *out) 399 { 400 JNIEnv *env; 401 jthread thread; 402 403 env = getEnv(); 404 405 thread = inStream_readThreadRef(env, in); 406 if (inStream_error(in)) { 407 return JNI_TRUE; 408 } 409 410 if (thread == NULL || threadControl_isDebugThread(thread)) { 411 outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); 412 return JNI_TRUE; 413 } 414 415 if (!validateSuspendedThread(out, thread)) { 416 return JNI_TRUE; 417 } 418 419 WITH_LOCAL_REFS(env, 1) { 420 421 jobject monitor; 422 jvmtiError error; 423 424 error = JVMTI_FUNC_PTR(gdata->jvmti,GetCurrentContendedMonitor) 425 (gdata->jvmti, thread, &monitor); 426 427 if (error != JVMTI_ERROR_NONE) { 428 outStream_setError(out, map2jdwpError(error)); 429 } else { 430 (void)outStream_writeByte(out, specificTypeKey(env, monitor)); 431 (void)outStream_writeObjectRef(env, out, monitor); 432 } 433 434 } END_WITH_LOCAL_REFS(env); 435 436 return JNI_TRUE; 437 } 438 439 static jboolean 440 stop(PacketInputStream *in, PacketOutputStream *out) 441 { 442 jvmtiError error; 443 jthread thread; 444 jobject throwable; 445 JNIEnv *env; 446 447 env = getEnv(); 448 thread = inStream_readThreadRef(env, in); 449 if (inStream_error(in)) { 450 return JNI_TRUE; 451 } 452 throwable = inStream_readObjectRef(env, in); 453 if (inStream_error(in)) { 454 return JNI_TRUE; 455 } 456 457 if (threadControl_isDebugThread(thread)) { 458 outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); 459 return JNI_TRUE; 460 } 461 462 error = threadControl_stop(thread, throwable); 463 if (error != JVMTI_ERROR_NONE) { 464 outStream_setError(out, map2jdwpError(error)); 465 } 466 return JNI_TRUE; 467 } 468 469 static jboolean 470 interrupt(PacketInputStream *in, PacketOutputStream *out) 471 { 472 jvmtiError error; 473 jthread thread; 474 475 thread = inStream_readThreadRef(getEnv(), in); 476 if (inStream_error(in)) { 477 return JNI_TRUE; 478 } 479 480 if (threadControl_isDebugThread(thread)) { 481 outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); 482 return JNI_TRUE; 483 } 484 485 error = threadControl_interrupt(thread); 486 if (error != JVMTI_ERROR_NONE) { 487 outStream_setError(out, map2jdwpError(error)); 488 } 489 return JNI_TRUE; 490 } 491 492 static jboolean 493 suspendCount(PacketInputStream *in, PacketOutputStream *out) 494 { 495 jvmtiError error; 496 jint count; 497 jthread thread; 498 499 thread = inStream_readThreadRef(getEnv(), in); 500 if (inStream_error(in)) { 501 return JNI_TRUE; 502 } 503 504 if (threadControl_isDebugThread(thread)) { 505 outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); 506 return JNI_TRUE; 507 } 508 509 error = threadControl_suspendCount(thread, &count); 510 if (error != JVMTI_ERROR_NONE) { 511 outStream_setError(out, map2jdwpError(error)); 512 return JNI_TRUE; 513 } 514 515 (void)outStream_writeInt(out, count); 516 return JNI_TRUE; 517 } 518 519 static jboolean 520 ownedMonitorsWithStackDepth(PacketInputStream *in, PacketOutputStream *out) 521 { 522 JNIEnv *env; 523 jthread thread; 524 525 thread = inStream_readThreadRef(getEnv(), in); 526 if (inStream_error(in)) { 527 return JNI_TRUE; 528 } 529 530 if (thread == NULL || threadControl_isDebugThread(thread)) { 531 outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); 532 return JNI_TRUE; 533 } 534 535 if (!validateSuspendedThread(out, thread)) { 536 return JNI_TRUE; 537 } 538 539 env = getEnv(); 540 541 WITH_LOCAL_REFS(env, 1) { 542 543 jvmtiError error = JVMTI_ERROR_NONE; 544 jint count = 0; 545 jvmtiMonitorStackDepthInfo *monitors=NULL; 546 547 error = JVMTI_FUNC_PTR(gdata->jvmti,GetOwnedMonitorStackDepthInfo) 548 (gdata->jvmti, thread, &count, &monitors); 549 550 if (error != JVMTI_ERROR_NONE) { 551 outStream_setError(out, map2jdwpError(error)); 552 } else { 553 int i; 554 (void)outStream_writeInt(out, count); 555 for (i = 0; i < count; i++) { 556 jobject monitor = monitors[i].monitor; 557 (void)outStream_writeByte(out, specificTypeKey(env, monitor)); 558 (void)outStream_writeObjectRef(getEnv(), out, monitor); 559 (void)outStream_writeInt(out,monitors[i].stack_depth); 560 } 561 } 562 if (monitors != NULL) { 563 jvmtiDeallocate(monitors); 564 } 565 566 } END_WITH_LOCAL_REFS(env); 567 568 return JNI_TRUE; 569 } 570 571 static jboolean 572 forceEarlyReturn(PacketInputStream *in, PacketOutputStream *out) 573 { 574 JNIEnv *env; 575 jthread thread; 576 jvalue value; 577 jbyte typeKey; 578 jvmtiError error; 579 580 env = getEnv(); 581 thread = inStream_readThreadRef(env, in); 582 if (inStream_error(in)) { 583 return JNI_TRUE; 584 } 585 586 if (threadControl_isDebugThread(thread)) { 587 outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); 588 return JNI_TRUE; 589 } 590 591 typeKey = inStream_readByte(in); 592 if (inStream_error(in)) { 593 return JNI_TRUE; 594 } 595 596 if (isObjectTag(typeKey)) { 597 value.l = inStream_readObjectRef(env, in); 598 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnObject) 599 (gdata->jvmti, thread, value.l); 600 } else { 601 switch (typeKey) { 602 case JDWP_TAG(VOID): 603 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnVoid) 604 (gdata->jvmti, thread); 605 break; 606 case JDWP_TAG(BYTE): 607 value.b = inStream_readByte(in); 608 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnInt) 609 (gdata->jvmti, thread, value.b); 610 break; 611 612 case JDWP_TAG(CHAR): 613 value.c = inStream_readChar(in); 614 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnInt) 615 (gdata->jvmti, thread, value.c); 616 break; 617 618 case JDWP_TAG(FLOAT): 619 value.f = inStream_readFloat(in); 620 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnFloat) 621 (gdata->jvmti, thread, value.f); 622 break; 623 624 case JDWP_TAG(DOUBLE): 625 value.d = inStream_readDouble(in); 626 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnDouble) 627 (gdata->jvmti, thread, value.d); 628 break; 629 630 case JDWP_TAG(INT): 631 value.i = inStream_readInt(in); 632 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnInt) 633 (gdata->jvmti, thread, value.i); 634 break; 635 636 case JDWP_TAG(LONG): 637 value.j = inStream_readLong(in); 638 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnLong) 639 (gdata->jvmti, thread, value.j); 640 break; 641 642 case JDWP_TAG(SHORT): 643 value.s = inStream_readShort(in); 644 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnInt) 645 (gdata->jvmti, thread, value.s); 646 break; 647 648 case JDWP_TAG(BOOLEAN): 649 value.z = inStream_readBoolean(in); 650 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnInt) 651 (gdata->jvmti, thread, value.z); 652 break; 653 654 default: 655 error = AGENT_ERROR_INVALID_TAG; 656 break; 657 } 658 } 659 { 660 jdwpError serror = map2jdwpError(error); 661 if (serror != JDWP_ERROR(NONE)) { 662 outStream_setError(out, serror); 663 } 664 } 665 return JNI_TRUE; 666 } 667 668 669 void *ThreadReference_Cmds[] = { (void *)14, 670 (void *)name, 671 (void *)suspend, 672 (void *)resume, 673 (void *)status, 674 (void *)threadGroup, 675 (void *)frames, 676 (void *)getFrameCount, 677 (void *)ownedMonitors, 678 (void *)currentContendedMonitor, 679 (void *)stop, 680 (void *)interrupt, 681 (void *)suspendCount, 682 (void *)ownedMonitorsWithStackDepth, 683 (void *)forceEarlyReturn 684 };