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
34 static jboolean
name(PacketInputStream * in,PacketOutputStream * out)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
suspend(PacketInputStream * in,PacketOutputStream * out)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
resume(PacketInputStream * in,PacketOutputStream * out)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
status(PacketInputStream * in,PacketOutputStream * out)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
threadGroup(PacketInputStream * in,PacketOutputStream * out)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
validateSuspendedThread(PacketOutputStream * out,jthread thread)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
frames(PacketInputStream * in,PacketOutputStream * out)214 frames(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
314 static jboolean
getFrameCount(PacketInputStream * in,PacketOutputStream * out)315 getFrameCount(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
346 static jboolean
ownedMonitors(PacketInputStream * in,PacketOutputStream * out)347 ownedMonitors(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
395 static jboolean
currentContendedMonitor(PacketInputStream * in,PacketOutputStream * out)396 currentContendedMonitor(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
437 static jboolean
stop(PacketInputStream * in,PacketOutputStream * out)438 stop(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
467 static jboolean
interrupt(PacketInputStream * in,PacketOutputStream * out)468 interrupt(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
490 static jboolean
suspendCount(PacketInputStream * in,PacketOutputStream * out)491 suspendCount(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
517 static jboolean
ownedMonitorsWithStackDepth(PacketInputStream * in,PacketOutputStream * out)518 ownedMonitorsWithStackDepth(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
569 static jboolean
forceEarlyReturn(PacketInputStream * in,PacketOutputStream * out)570 forceEarlyReturn(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
667 void *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