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     };