1 /*
  2  * Copyright (c) 1998, 2021, 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     /* vthread fixme: We should just call throught to JVMTI and let the failure come from
463        there, but first we need a test that exercises this code for vthreads. */
464     if (isVThread(thread)) {
465         tty_message("ThreadReferenceImpl::stop() not supported.");
466         outStream_setError(out, JDWP_ERROR(INVALID_THREAD));
467         return JNI_TRUE;
468     }
469 
470     error = threadControl_stop(thread, throwable);
471     if (error != JVMTI_ERROR_NONE) {
472         outStream_setError(out, map2jdwpError(error));
473     }
474     return JNI_TRUE;
475 }
476 
477 static jboolean
478 interrupt(PacketInputStream *in, PacketOutputStream *out)
479 {
480     jvmtiError error;
481     jthread thread;
482 
483     thread = inStream_readThreadRef(getEnv(), in);
484     if (inStream_error(in)) {
485         return JNI_TRUE;
486     }
487 
488     if (threadControl_isDebugThread(thread)) {
489         outStream_setError(out, JDWP_ERROR(INVALID_THREAD));
490         return JNI_TRUE;
491     }
492 
493     /* vthread fixme: This should work. Need to disable this forced failure,
494        but first we need a test that exercises this code for vthreads. */
495     if (isVThread(thread)) {
496         tty_message("ThreadReferenceImpl::interrupt() not supported.");
497         outStream_setError(out, JDWP_ERROR(INVALID_THREAD));
498         return JNI_TRUE;
499     }
500 
501     error = threadControl_interrupt(thread);
502     if (error != JVMTI_ERROR_NONE) {
503         outStream_setError(out, map2jdwpError(error));
504     }
505     return JNI_TRUE;
506 }
507 
508 static jboolean
509 suspendCount(PacketInputStream *in, PacketOutputStream *out)
510 {
511     jvmtiError error;
512     jint count;
513     jthread thread;
514 
515     thread = inStream_readThreadRef(getEnv(), in);
516     if (inStream_error(in)) {
517         return JNI_TRUE;
518     }
519 
520     if (threadControl_isDebugThread(thread)) {
521         outStream_setError(out, JDWP_ERROR(INVALID_THREAD));
522         return JNI_TRUE;
523     }
524 
525     error = threadControl_suspendCount(thread, &count);
526     if (error != JVMTI_ERROR_NONE) {
527         outStream_setError(out, map2jdwpError(error));
528         return JNI_TRUE;
529     }
530 
531     (void)outStream_writeInt(out, count);
532     return JNI_TRUE;
533 }
534 
535 static jboolean
536 ownedMonitorsWithStackDepth(PacketInputStream *in, PacketOutputStream *out)
537 {
538     JNIEnv *env;
539     jthread thread;
540 
541     thread = inStream_readThreadRef(getEnv(), in);
542     if (inStream_error(in)) {
543         return JNI_TRUE;
544     }
545 
546     if (thread == NULL || threadControl_isDebugThread(thread)) {
547         outStream_setError(out, JDWP_ERROR(INVALID_THREAD));
548         return JNI_TRUE;
549     }
550 
551     if (!validateSuspendedThread(out, thread)) {
552         return JNI_TRUE;
553     }
554 
555     env = getEnv();
556 
557     WITH_LOCAL_REFS(env, 1) {
558 
559         jvmtiError error = JVMTI_ERROR_NONE;
560         jint count = 0;
561         jvmtiMonitorStackDepthInfo *monitors=NULL;
562 
563         error = JVMTI_FUNC_PTR(gdata->jvmti,GetOwnedMonitorStackDepthInfo)
564                                 (gdata->jvmti, thread, &count, &monitors);
565 
566         if (error != JVMTI_ERROR_NONE) {
567             outStream_setError(out, map2jdwpError(error));
568         } else {
569             int i;
570             (void)outStream_writeInt(out, count);
571             for (i = 0; i < count; i++) {
572                 jobject monitor = monitors[i].monitor;
573                 (void)outStream_writeByte(out, specificTypeKey(env, monitor));
574                 (void)outStream_writeObjectRef(getEnv(), out, monitor);
575                 (void)outStream_writeInt(out,monitors[i].stack_depth);
576             }
577         }
578         if (monitors != NULL) {
579             jvmtiDeallocate(monitors);
580         }
581 
582     } END_WITH_LOCAL_REFS(env);
583 
584     return JNI_TRUE;
585 }
586 
587 static jboolean
588 forceEarlyReturn(PacketInputStream *in, PacketOutputStream *out)
589 {
590     JNIEnv *env;
591     jthread thread;
592     jvalue value;
593     jbyte typeKey;
594     jvmtiError error;
595 
596     env = getEnv();
597     thread = inStream_readThreadRef(env, in);
598     if (inStream_error(in)) {
599         return JNI_TRUE;
600     }
601 
602     if (threadControl_isDebugThread(thread)) {
603         outStream_setError(out, JDWP_ERROR(INVALID_THREAD));
604         return JNI_TRUE;
605     }
606 
607     typeKey = inStream_readByte(in);
608     if (inStream_error(in)) {
609         return JNI_TRUE;
610     }
611 
612     if (isObjectTag(typeKey)) {
613         value.l = inStream_readObjectRef(env, in);
614         error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnObject)
615                         (gdata->jvmti, thread, value.l);
616     } else {
617         switch (typeKey) {
618             case JDWP_TAG(VOID):
619                 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnVoid)
620                                 (gdata->jvmti, thread);
621                 break;
622             case JDWP_TAG(BYTE):
623                 value.b = inStream_readByte(in);
624                 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnInt)
625                                 (gdata->jvmti, thread, value.b);
626                 break;
627 
628             case JDWP_TAG(CHAR):
629                 value.c = inStream_readChar(in);
630                 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnInt)
631                                 (gdata->jvmti, thread, value.c);
632                 break;
633 
634             case JDWP_TAG(FLOAT):
635                 value.f = inStream_readFloat(in);
636                 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnFloat)
637                                 (gdata->jvmti, thread, value.f);
638                 break;
639 
640             case JDWP_TAG(DOUBLE):
641                 value.d = inStream_readDouble(in);
642                 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnDouble)
643                                 (gdata->jvmti, thread, value.d);
644                 break;
645 
646             case JDWP_TAG(INT):
647                 value.i = inStream_readInt(in);
648                 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnInt)
649                                 (gdata->jvmti, thread, value.i);
650                 break;
651 
652             case JDWP_TAG(LONG):
653                 value.j = inStream_readLong(in);
654                 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnLong)
655                                 (gdata->jvmti, thread, value.j);
656                 break;
657 
658             case JDWP_TAG(SHORT):
659                 value.s = inStream_readShort(in);
660                 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnInt)
661                                 (gdata->jvmti, thread, value.s);
662                 break;
663 
664             case JDWP_TAG(BOOLEAN):
665                 value.z = inStream_readBoolean(in);
666                 error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnInt)
667                                 (gdata->jvmti, thread, value.z);
668                 break;
669 
670             default:
671                 error =  AGENT_ERROR_INVALID_TAG;
672                 break;
673         }
674     }
675     {
676       jdwpError serror = map2jdwpError(error);
677       if (serror != JDWP_ERROR(NONE)) {
678         outStream_setError(out, serror);
679       }
680     }
681     return JNI_TRUE;
682 }
683 
684 static jboolean
685 isVirtual(PacketInputStream *in, PacketOutputStream *out)
686 {
687     JNIEnv *env;
688     jthread thread;
689     jboolean isVirtual;
690 
691     env = getEnv();
692 
693     thread = inStream_readThreadRef(env, in);
694     if (inStream_error(in)) {
695         return JNI_TRUE;
696     }
697 
698     if (threadControl_isDebugThread(thread)) {
699         outStream_setError(out, JDWP_ERROR(INVALID_THREAD));
700         return JNI_TRUE;
701     }
702 
703     isVirtual = JNI_FUNC_PTR(env,IsVirtualThread)(env, thread);
704     (void)outStream_writeBoolean(out, isVirtual);
705 
706     return JNI_TRUE;
707 }
708 
709 Command ThreadReference_Commands[] = {
710     {name, "Name"},
711     {suspend, "Suspend"},
712     {resume, "Resume"},
713     {status, "Status"},
714     {threadGroup, "ThreadGroup"},
715     {frames, "Frames"},
716     {getFrameCount, "GetFrameCount"},
717     {ownedMonitors, "OwnedMonitors"},
718     {currentContendedMonitor, "CurrentContendedMonitor"},
719     {stop, "Stop"},
720     {interrupt, "Interrupt"},
721     {suspendCount, "SuspendCount"},
722     {ownedMonitorsWithStackDepth, "OwnedMonitorsWithStackDepth"},
723     {forceEarlyReturn, "ForceEarlyReturn"},
724     {isVirtual, "IsVirtual"}
725 };
726 
727 DEBUG_DISPATCH_DEFINE_CMDSET(ThreadReference)