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
34static jboolean
35name(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
76static jboolean
77suspend(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
98static jboolean
99resume(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
122static jboolean
123status(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
151static jboolean
152threadGroup(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
193static jboolean
194validateSuspendedThread(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
213static jboolean
214frames(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
314static jboolean
315getFrameCount(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
346static jboolean
347ownedMonitors(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
395static jboolean
396currentContendedMonitor(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
437static jboolean
438stop(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
467static jboolean
468interrupt(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
490static jboolean
491suspendCount(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
517static jboolean
518ownedMonitorsWithStackDepth(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
569static jboolean
570forceEarlyReturn(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
667void *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