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
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 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
316static jboolean
317getFrameCount(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
348static jboolean
349ownedMonitors(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
397static jboolean
398currentContendedMonitor(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
439static jboolean
440stop(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
469static jboolean
470interrupt(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
492static jboolean
493suspendCount(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
519static jboolean
520ownedMonitorsWithStackDepth(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
571static jboolean
572forceEarlyReturn(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
669void *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 };
685