1 /*
2  * Copyright (c) 1998, 2017, 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 "invoker.h"
28 #include "eventHandler.h"
29 #include "threadControl.h"
30 #include "outStream.h"
31 
32 static jrawMonitorID invokerLock;
33 
34 void
invoker_initialize(void)35 invoker_initialize(void)
36 {
37     invokerLock = debugMonitorCreate("JDWP Invocation Lock");
38 }
39 
40 void
invoker_reset(void)41 invoker_reset(void)
42 {
43 }
44 
invoker_lock(void)45 void invoker_lock(void)
46 {
47     debugMonitorEnter(invokerLock);
48 }
49 
invoker_unlock(void)50 void invoker_unlock(void)
51 {
52     debugMonitorExit(invokerLock);
53 }
54 
55 static jbyte
returnTypeTag(char * signature)56 returnTypeTag(char *signature)
57 {
58     char *tagPtr = strchr(signature, SIGNATURE_END_ARGS);
59     JDI_ASSERT(tagPtr);
60     tagPtr++;    /* 1st character after the end of args */
61     return (jbyte)*tagPtr;
62 }
63 
64 static jbyte
nextArgumentTypeTag(void ** cursor)65 nextArgumentTypeTag(void **cursor)
66 {
67     char *tagPtr = *cursor;
68     jbyte argumentTag = (jbyte)*tagPtr;
69 
70     if (*tagPtr != SIGNATURE_END_ARGS) {
71         /* Skip any array modifiers */
72         while (*tagPtr == JDWP_TAG(ARRAY)) {
73             tagPtr++;
74         }
75         /* Skip class name */
76         if (*tagPtr == JDWP_TAG(OBJECT)) {
77             tagPtr = strchr(tagPtr, SIGNATURE_END_CLASS) + 1;
78             JDI_ASSERT(tagPtr);
79         } else {
80             /* Skip primitive sig */
81             tagPtr++;
82         }
83     }
84 
85     *cursor = tagPtr;
86     return argumentTag;
87 }
88 
89 static jbyte
firstArgumentTypeTag(char * signature,void ** cursor)90 firstArgumentTypeTag(char *signature, void **cursor)
91 {
92     JDI_ASSERT(signature[0] == SIGNATURE_BEGIN_ARGS);
93     *cursor = signature + 1; /* skip to the first arg */
94     return nextArgumentTypeTag(cursor);
95 }
96 
97 
98 /*
99  * Note: argument refs may be destroyed on out-of-memory error
100  */
101 static jvmtiError
createGlobalRefs(JNIEnv * env,InvokeRequest * request)102 createGlobalRefs(JNIEnv *env, InvokeRequest *request)
103 {
104     jvmtiError error;
105     jclass clazz = NULL;
106     jobject instance = NULL;
107     jint argIndex;
108     jbyte argumentTag;
109     jvalue *argument;
110     void *cursor;
111     jobject *argRefs = NULL;
112 
113     error = JVMTI_ERROR_NONE;
114 
115     if ( request->argumentCount > 0 ) {
116         /*LINTED*/
117         argRefs = jvmtiAllocate((jint)(request->argumentCount*sizeof(jobject)));
118         if ( argRefs==NULL ) {
119             error = AGENT_ERROR_OUT_OF_MEMORY;
120         } else {
121             /*LINTED*/
122             (void)memset(argRefs, 0, request->argumentCount*sizeof(jobject));
123         }
124     }
125 
126     if ( error == JVMTI_ERROR_NONE ) {
127         saveGlobalRef(env, request->clazz, &clazz);
128         if (clazz == NULL) {
129             error = AGENT_ERROR_OUT_OF_MEMORY;
130         }
131     }
132 
133     if ( error == JVMTI_ERROR_NONE && request->instance != NULL ) {
134         saveGlobalRef(env, request->instance, &instance);
135         if (instance == NULL) {
136             error = AGENT_ERROR_OUT_OF_MEMORY;
137         }
138     }
139 
140     if ( error == JVMTI_ERROR_NONE && argRefs!=NULL ) {
141         argIndex = 0;
142         argumentTag = firstArgumentTypeTag(request->methodSignature, &cursor);
143         argument = request->arguments;
144         while (argumentTag != SIGNATURE_END_ARGS) {
145             if ( argIndex > request->argumentCount ) {
146                 break;
147             }
148             if ((argumentTag == JDWP_TAG(OBJECT)) ||
149                 (argumentTag == JDWP_TAG(ARRAY))) {
150                 /* Create a global ref for any non-null argument */
151                 if (argument->l != NULL) {
152                     saveGlobalRef(env, argument->l, &argRefs[argIndex]);
153                     if (argRefs[argIndex] == NULL) {
154                         error = AGENT_ERROR_OUT_OF_MEMORY;
155                         break;
156                     }
157                 }
158             }
159             argument++;
160             argIndex++;
161             argumentTag = nextArgumentTypeTag(&cursor);
162         }
163     }
164 
165 #ifdef FIXUP /* Why isn't this an error? */
166     /* Make sure the argument count matches */
167     if ( error == JVMTI_ERROR_NONE && argIndex != request->argumentCount ) {
168         error = AGENT_ERROR_INVALID_COUNT;
169     }
170 #endif
171 
172     /* Finally, put the global refs into the request if no errors */
173     if ( error == JVMTI_ERROR_NONE ) {
174         request->clazz = clazz;
175         request->instance = instance;
176         if ( argRefs!=NULL ) {
177             argIndex = 0;
178             argumentTag = firstArgumentTypeTag(request->methodSignature, &cursor);
179             argument = request->arguments;
180             while ( argIndex < request->argumentCount ) {
181                 if ((argumentTag == JDWP_TAG(OBJECT)) ||
182                     (argumentTag == JDWP_TAG(ARRAY))) {
183                     argument->l = argRefs[argIndex];
184                 }
185                 argument++;
186                 argIndex++;
187                 argumentTag = nextArgumentTypeTag(&cursor);
188             }
189             jvmtiDeallocate(argRefs);
190         }
191         return JVMTI_ERROR_NONE;
192 
193     } else {
194         /* Delete global references */
195         if ( clazz != NULL ) {
196             tossGlobalRef(env, &clazz);
197         }
198         if ( instance != NULL ) {
199             tossGlobalRef(env, &instance);
200         }
201         if ( argRefs!=NULL ) {
202             for ( argIndex=0; argIndex < request->argumentCount; argIndex++ ) {
203                 if ( argRefs[argIndex] != NULL ) {
204                     tossGlobalRef(env, &argRefs[argIndex]);
205                 }
206             }
207             jvmtiDeallocate(argRefs);
208         }
209     }
210 
211     return error;
212 }
213 
214 /*
215  * Delete global argument references from the request which got put there before a
216  * invoke request was carried out. See fillInvokeRequest().
217  */
218 static void
deleteGlobalArgumentRefs(JNIEnv * env,InvokeRequest * request)219 deleteGlobalArgumentRefs(JNIEnv *env, InvokeRequest *request)
220 {
221     void *cursor;
222     jint argIndex = 0;
223     jvalue *argument = request->arguments;
224     jbyte argumentTag = firstArgumentTypeTag(request->methodSignature, &cursor);
225 
226     if (request->clazz != NULL) {
227         tossGlobalRef(env, &(request->clazz));
228     }
229     if (request->instance != NULL) {
230         tossGlobalRef(env, &(request->instance));
231     }
232     /* Delete global argument references */
233     while (argIndex < request->argumentCount) {
234         if ((argumentTag == JDWP_TAG(OBJECT)) ||
235             (argumentTag == JDWP_TAG(ARRAY))) {
236             if (argument->l != NULL) {
237                 tossGlobalRef(env, &(argument->l));
238             }
239         }
240         argument++;
241         argIndex++;
242         argumentTag = nextArgumentTypeTag(&cursor);
243     }
244 }
245 
246 static jvmtiError
fillInvokeRequest(JNIEnv * env,InvokeRequest * request,jbyte invokeType,jbyte options,jint id,jthread thread,jclass clazz,jmethodID method,jobject instance,jvalue * arguments,jint argumentCount)247 fillInvokeRequest(JNIEnv *env, InvokeRequest *request,
248                   jbyte invokeType, jbyte options, jint id,
249                   jthread thread, jclass clazz, jmethodID method,
250                   jobject instance,
251                   jvalue *arguments, jint argumentCount)
252 {
253     jvmtiError error;
254     if (!request->available) {
255         /*
256          * Thread is not at a point where it can invoke.
257          */
258         return AGENT_ERROR_INVALID_THREAD;
259     }
260     if (request->pending) {
261         /*
262          * Pending invoke
263          */
264         return AGENT_ERROR_ALREADY_INVOKING;
265     }
266 
267     request->invokeType = invokeType;
268     request->options = options;
269     request->detached = JNI_FALSE;
270     request->id = id;
271     request->clazz = clazz;
272     request->method = method;
273     request->instance = instance;
274     request->arguments = arguments;
275     request->arguments = arguments;
276     request->argumentCount = argumentCount;
277 
278     request->returnValue.j = 0;
279     request->exception = 0;
280 
281     /*
282      * Squirrel away the method signature
283      */
284     error = methodSignature(method, NULL, &request->methodSignature,  NULL);
285     if (error != JVMTI_ERROR_NONE) {
286         return error;
287     }
288 
289     /*
290      * The given references for class and instance are not guaranteed
291      * to be around long enough for invocation, so create new ones
292      * here.
293      */
294     error = createGlobalRefs(env, request);
295     if (error != JVMTI_ERROR_NONE) {
296         jvmtiDeallocate(request->methodSignature);
297         return error;
298     }
299 
300     request->pending = JNI_TRUE;
301     request->available = JNI_FALSE;
302     return JVMTI_ERROR_NONE;
303 }
304 
305 void
invoker_enableInvokeRequests(jthread thread)306 invoker_enableInvokeRequests(jthread thread)
307 {
308     InvokeRequest *request;
309 
310     JDI_ASSERT(thread);
311 
312     debugMonitorEnter(invokerLock);
313     request = threadControl_getInvokeRequest(thread);
314     if (request == NULL) {
315         EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
316     }
317 
318     request->available = JNI_TRUE;
319     debugMonitorExit(invokerLock);
320 }
321 
322 /*
323  * Check that method is in the specified clazz or one of its super classes.
324  * We have to enforce this check at the JDWP layer because the JNI layer
325  * has different requirements.
326  */
check_methodClass(JNIEnv * env,jclass clazz,jmethodID method)327 static jvmtiError check_methodClass(JNIEnv *env, jclass clazz, jmethodID method)
328 {
329     jclass containing_class = NULL;
330     jvmtiError error;
331 
332     error = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodDeclaringClass)
333                 (gdata->jvmti, method, &containing_class);
334     if (error != JVMTI_ERROR_NONE) {
335         return JVMTI_ERROR_NONE;  /* Bad jmethodID ?  This will be handled elsewhere */
336     }
337 
338     if (JNI_FUNC_PTR(env,IsSameObject)(env, clazz, containing_class)) {
339         return JVMTI_ERROR_NONE;
340     }
341 
342     // If not the same class then check that containing_class is a superclass of
343     // clazz (not a superinterface).
344     if (JNI_FUNC_PTR(env,IsAssignableFrom)(env, clazz, containing_class) &&
345         referenceTypeTag(containing_class) != JDWP_TYPE_TAG(INTERFACE)) {
346         return JVMTI_ERROR_NONE;
347     }
348     return JVMTI_ERROR_INVALID_METHODID;
349 }
350 
351 jvmtiError
invoker_requestInvoke(jbyte invokeType,jbyte options,jint id,jthread thread,jclass clazz,jmethodID method,jobject instance,jvalue * arguments,jint argumentCount)352 invoker_requestInvoke(jbyte invokeType, jbyte options, jint id,
353                       jthread thread, jclass clazz, jmethodID method,
354                       jobject instance,
355                       jvalue *arguments, jint argumentCount)
356 {
357     JNIEnv *env = getEnv();
358     InvokeRequest *request;
359     jvmtiError error = JVMTI_ERROR_NONE;
360 
361     if (invokeType == INVOKE_STATIC) {
362         error = check_methodClass(env, clazz, method);
363         if (error != JVMTI_ERROR_NONE) {
364             return error;
365         }
366     }
367 
368     debugMonitorEnter(invokerLock);
369     request = threadControl_getInvokeRequest(thread);
370     if (request != NULL) {
371         error = fillInvokeRequest(env, request, invokeType, options, id,
372                                   thread, clazz, method, instance,
373                                   arguments, argumentCount);
374     }
375     debugMonitorExit(invokerLock);
376 
377     if (error == JVMTI_ERROR_NONE) {
378         if (options & JDWP_INVOKE_OPTIONS(SINGLE_THREADED) ) {
379             /* true means it is okay to unblock the commandLoop thread */
380             (void)threadControl_resumeThread(thread, JNI_TRUE);
381         } else {
382             (void)threadControl_resumeAll();
383         }
384     }
385 
386     return error;
387 }
388 
389 static void
invokeConstructor(JNIEnv * env,InvokeRequest * request)390 invokeConstructor(JNIEnv *env, InvokeRequest *request)
391 {
392     jobject object;
393 
394     JDI_ASSERT_MSG(request->clazz, "Request clazz null");
395     object = JNI_FUNC_PTR(env,NewObjectA)(env, request->clazz,
396                                      request->method,
397                                      request->arguments);
398     request->returnValue.l = NULL;
399     if (object != NULL) {
400         saveGlobalRef(env, object, &(request->returnValue.l));
401     }
402 }
403 
404 static void
invokeStatic(JNIEnv * env,InvokeRequest * request)405 invokeStatic(JNIEnv *env, InvokeRequest *request)
406 {
407     switch(returnTypeTag(request->methodSignature)) {
408         case JDWP_TAG(OBJECT):
409         case JDWP_TAG(ARRAY): {
410             jobject object;
411             JDI_ASSERT_MSG(request->clazz, "Request clazz null");
412             object = JNI_FUNC_PTR(env,CallStaticObjectMethodA)(env,
413                                        request->clazz,
414                                        request->method,
415                                        request->arguments);
416             request->returnValue.l = NULL;
417             if (object != NULL) {
418                 saveGlobalRef(env, object, &(request->returnValue.l));
419             }
420             break;
421         }
422 
423 
424         case JDWP_TAG(BYTE):
425             request->returnValue.b = JNI_FUNC_PTR(env,CallStaticByteMethodA)(env,
426                                                        request->clazz,
427                                                        request->method,
428                                                        request->arguments);
429             break;
430 
431         case JDWP_TAG(CHAR):
432             request->returnValue.c = JNI_FUNC_PTR(env,CallStaticCharMethodA)(env,
433                                                        request->clazz,
434                                                        request->method,
435                                                        request->arguments);
436             break;
437 
438         case JDWP_TAG(FLOAT):
439             request->returnValue.f = JNI_FUNC_PTR(env,CallStaticFloatMethodA)(env,
440                                                        request->clazz,
441                                                        request->method,
442                                                        request->arguments);
443             break;
444 
445         case JDWP_TAG(DOUBLE):
446             request->returnValue.d = JNI_FUNC_PTR(env,CallStaticDoubleMethodA)(env,
447                                                        request->clazz,
448                                                        request->method,
449                                                        request->arguments);
450             break;
451 
452         case JDWP_TAG(INT):
453             request->returnValue.i = JNI_FUNC_PTR(env,CallStaticIntMethodA)(env,
454                                                        request->clazz,
455                                                        request->method,
456                                                        request->arguments);
457             break;
458 
459         case JDWP_TAG(LONG):
460             request->returnValue.j = JNI_FUNC_PTR(env,CallStaticLongMethodA)(env,
461                                                        request->clazz,
462                                                        request->method,
463                                                        request->arguments);
464             break;
465 
466         case JDWP_TAG(SHORT):
467             request->returnValue.s = JNI_FUNC_PTR(env,CallStaticShortMethodA)(env,
468                                                        request->clazz,
469                                                        request->method,
470                                                        request->arguments);
471             break;
472 
473         case JDWP_TAG(BOOLEAN):
474             request->returnValue.z = JNI_FUNC_PTR(env,CallStaticBooleanMethodA)(env,
475                                                        request->clazz,
476                                                        request->method,
477                                                        request->arguments);
478             break;
479 
480         case JDWP_TAG(VOID):
481             JNI_FUNC_PTR(env,CallStaticVoidMethodA)(env,
482                                           request->clazz,
483                                           request->method,
484                                           request->arguments);
485             break;
486 
487         default:
488             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
489             break;
490     }
491 }
492 
493 static void
invokeVirtual(JNIEnv * env,InvokeRequest * request)494 invokeVirtual(JNIEnv *env, InvokeRequest *request)
495 {
496     switch(returnTypeTag(request->methodSignature)) {
497         case JDWP_TAG(OBJECT):
498         case JDWP_TAG(ARRAY): {
499             jobject object;
500             JDI_ASSERT_MSG(request->instance, "Request instance null");
501             object = JNI_FUNC_PTR(env,CallObjectMethodA)(env,
502                                  request->instance,
503                                  request->method,
504                                  request->arguments);
505             request->returnValue.l = NULL;
506             if (object != NULL) {
507                 saveGlobalRef(env, object, &(request->returnValue.l));
508             }
509             break;
510         }
511 
512         case JDWP_TAG(BYTE):
513             request->returnValue.b = JNI_FUNC_PTR(env,CallByteMethodA)(env,
514                                                  request->instance,
515                                                  request->method,
516                                                  request->arguments);
517             break;
518 
519         case JDWP_TAG(CHAR):
520             request->returnValue.c = JNI_FUNC_PTR(env,CallCharMethodA)(env,
521                                                  request->instance,
522                                                  request->method,
523                                                  request->arguments);
524             break;
525 
526         case JDWP_TAG(FLOAT):
527             request->returnValue.f = JNI_FUNC_PTR(env,CallFloatMethodA)(env,
528                                                  request->instance,
529                                                  request->method,
530                                                  request->arguments);
531             break;
532 
533         case JDWP_TAG(DOUBLE):
534             request->returnValue.d = JNI_FUNC_PTR(env,CallDoubleMethodA)(env,
535                                                  request->instance,
536                                                  request->method,
537                                                  request->arguments);
538             break;
539 
540         case JDWP_TAG(INT):
541             request->returnValue.i = JNI_FUNC_PTR(env,CallIntMethodA)(env,
542                                                  request->instance,
543                                                  request->method,
544                                                  request->arguments);
545             break;
546 
547         case JDWP_TAG(LONG):
548             request->returnValue.j = JNI_FUNC_PTR(env,CallLongMethodA)(env,
549                                                  request->instance,
550                                                  request->method,
551                                                  request->arguments);
552             break;
553 
554         case JDWP_TAG(SHORT):
555             request->returnValue.s = JNI_FUNC_PTR(env,CallShortMethodA)(env,
556                                                  request->instance,
557                                                  request->method,
558                                                  request->arguments);
559             break;
560 
561         case JDWP_TAG(BOOLEAN):
562             request->returnValue.z = JNI_FUNC_PTR(env,CallBooleanMethodA)(env,
563                                                  request->instance,
564                                                  request->method,
565                                                  request->arguments);
566             break;
567 
568         case JDWP_TAG(VOID):
569             JNI_FUNC_PTR(env,CallVoidMethodA)(env,
570                                     request->instance,
571                                     request->method,
572                                     request->arguments);
573             break;
574 
575         default:
576             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
577             break;
578     }
579 }
580 
581 static void
invokeNonvirtual(JNIEnv * env,InvokeRequest * request)582 invokeNonvirtual(JNIEnv *env, InvokeRequest *request)
583 {
584     switch(returnTypeTag(request->methodSignature)) {
585         case JDWP_TAG(OBJECT):
586         case JDWP_TAG(ARRAY): {
587             jobject object;
588             JDI_ASSERT_MSG(request->clazz, "Request clazz null");
589             JDI_ASSERT_MSG(request->instance, "Request instance null");
590             object = JNI_FUNC_PTR(env,CallNonvirtualObjectMethodA)(env,
591                                            request->instance,
592                                            request->clazz,
593                                            request->method,
594                                            request->arguments);
595             request->returnValue.l = NULL;
596             if (object != NULL) {
597                 saveGlobalRef(env, object, &(request->returnValue.l));
598             }
599             break;
600         }
601 
602         case JDWP_TAG(BYTE):
603             request->returnValue.b = JNI_FUNC_PTR(env,CallNonvirtualByteMethodA)(env,
604                                                  request->instance,
605                                                  request->clazz,
606                                                  request->method,
607                                                  request->arguments);
608             break;
609 
610         case JDWP_TAG(CHAR):
611             request->returnValue.c = JNI_FUNC_PTR(env,CallNonvirtualCharMethodA)(env,
612                                                  request->instance,
613                                                  request->clazz,
614                                                  request->method,
615                                                  request->arguments);
616             break;
617 
618         case JDWP_TAG(FLOAT):
619             request->returnValue.f = JNI_FUNC_PTR(env,CallNonvirtualFloatMethodA)(env,
620                                                  request->instance,
621                                                  request->clazz,
622                                                  request->method,
623                                                  request->arguments);
624             break;
625 
626         case JDWP_TAG(DOUBLE):
627             request->returnValue.d = JNI_FUNC_PTR(env,CallNonvirtualDoubleMethodA)(env,
628                                                  request->instance,
629                                                  request->clazz,
630                                                  request->method,
631                                                  request->arguments);
632             break;
633 
634         case JDWP_TAG(INT):
635             request->returnValue.i = JNI_FUNC_PTR(env,CallNonvirtualIntMethodA)(env,
636                                                  request->instance,
637                                                  request->clazz,
638                                                  request->method,
639                                                  request->arguments);
640             break;
641 
642         case JDWP_TAG(LONG):
643             request->returnValue.j = JNI_FUNC_PTR(env,CallNonvirtualLongMethodA)(env,
644                                                  request->instance,
645                                                  request->clazz,
646                                                  request->method,
647                                                  request->arguments);
648             break;
649 
650         case JDWP_TAG(SHORT):
651             request->returnValue.s = JNI_FUNC_PTR(env,CallNonvirtualShortMethodA)(env,
652                                                  request->instance,
653                                                  request->clazz,
654                                                  request->method,
655                                                  request->arguments);
656             break;
657 
658         case JDWP_TAG(BOOLEAN):
659             request->returnValue.z = JNI_FUNC_PTR(env,CallNonvirtualBooleanMethodA)(env,
660                                                  request->instance,
661                                                  request->clazz,
662                                                  request->method,
663                                                  request->arguments);
664             break;
665 
666         case JDWP_TAG(VOID):
667             JNI_FUNC_PTR(env,CallNonvirtualVoidMethodA)(env,
668                                     request->instance,
669                                     request->clazz,
670                                     request->method,
671                                     request->arguments);
672             break;
673 
674         default:
675             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
676             break;
677     }
678 }
679 
680 jboolean
invoker_doInvoke(jthread thread)681 invoker_doInvoke(jthread thread)
682 {
683     JNIEnv *env;
684     jboolean startNow;
685     InvokeRequest *request;
686     jbyte options;
687     jbyte invokeType;
688 
689     JDI_ASSERT(thread);
690 
691     debugMonitorEnter(invokerLock);
692 
693     request = threadControl_getInvokeRequest(thread);
694     if (request == NULL) {
695         EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
696     }
697 
698     request->available = JNI_FALSE;
699     startNow = request->pending && !request->started;
700 
701     if (startNow) {
702         request->started = JNI_TRUE;
703     }
704     options = request->options;
705     invokeType = request->invokeType;
706 
707     debugMonitorExit(invokerLock);
708 
709     if (!startNow) {
710         return JNI_FALSE;
711     }
712 
713     env = getEnv();
714 
715     WITH_LOCAL_REFS(env, 2) {  /* 1 for obj return values, 1 for exception */
716 
717         jobject exception;
718 
719         JNI_FUNC_PTR(env,ExceptionClear)(env);
720 
721         switch (invokeType) {
722             case INVOKE_CONSTRUCTOR:
723                 invokeConstructor(env, request);
724                 break;
725             case INVOKE_STATIC:
726                 invokeStatic(env, request);
727                 break;
728             case INVOKE_INSTANCE:
729                 if (options & JDWP_INVOKE_OPTIONS(NONVIRTUAL) ) {
730                     invokeNonvirtual(env, request);
731                 } else {
732                     invokeVirtual(env, request);
733                 }
734                 break;
735             default:
736                 JDI_ASSERT(JNI_FALSE);
737         }
738         request->exception = NULL;
739         exception = JNI_FUNC_PTR(env,ExceptionOccurred)(env);
740         if (exception != NULL) {
741             JNI_FUNC_PTR(env,ExceptionClear)(env);
742             saveGlobalRef(env, exception, &(request->exception));
743         }
744 
745     } END_WITH_LOCAL_REFS(env);
746 
747     return JNI_TRUE;
748 }
749 
750 void
invoker_completeInvokeRequest(jthread thread)751 invoker_completeInvokeRequest(jthread thread)
752 {
753     JNIEnv *env = getEnv();
754     PacketOutputStream out;
755     jbyte tag;
756     jobject exc;
757     jvalue returnValue;
758     jint id;
759     InvokeRequest *request;
760     jboolean detached;
761     jboolean mustReleaseReturnValue = JNI_FALSE;
762 
763     JDI_ASSERT(thread);
764 
765     /* Prevent gcc errors on uninitialized variables. */
766     tag = 0;
767     exc = NULL;
768     id  = 0;
769 
770     eventHandler_lock(); /* for proper lock order */
771     debugMonitorEnter(invokerLock);
772 
773     request = threadControl_getInvokeRequest(thread);
774     if (request == NULL) {
775         EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
776     }
777 
778     JDI_ASSERT(request->pending);
779     JDI_ASSERT(request->started);
780 
781     request->pending = JNI_FALSE;
782     request->started = JNI_FALSE;
783     request->available = JNI_TRUE; /* For next time around */
784 
785     detached = request->detached;
786     if (!detached) {
787         if (request->options & JDWP_INVOKE_OPTIONS(SINGLE_THREADED)) {
788             (void)threadControl_suspendThread(thread, JNI_FALSE);
789         } else {
790             (void)threadControl_suspendAll();
791         }
792 
793         if (request->invokeType == INVOKE_CONSTRUCTOR) {
794             /*
795              * Although constructors technically have a return type of
796              * void, we return the object created.
797              */
798             tag = specificTypeKey(env, request->returnValue.l);
799         } else {
800             tag = returnTypeTag(request->methodSignature);
801         }
802         id = request->id;
803         exc = request->exception;
804         returnValue = request->returnValue;
805 
806         /* Release return value and exception references, but delay the release
807          * until after the return packet was sent. */
808         mustReleaseReturnValue = request->invokeType == INVOKE_CONSTRUCTOR ||
809            returnTypeTag(request->methodSignature) == JDWP_TAG(OBJECT) ||
810            returnTypeTag(request->methodSignature) == JDWP_TAG(ARRAY);
811     }
812 
813     /*
814      * At this time, there's no need to retain global references on
815      * arguments since the reply is processed. No one will deal with
816      * this request ID anymore, so we must call deleteGlobalArgumentRefs().
817      *
818      * We cannot delete saved exception or return value references
819      * since otherwise a deleted handle would escape when writing
820      * the response to the stream. Instead, we clean those refs up
821      * after writing the respone.
822      */
823     deleteGlobalArgumentRefs(env, request);
824 
825     /* From now on, do not access the request structure anymore
826      * for this request id, because once we give up the invokerLock it may
827      * be immediately reused by a new invoke request.
828      */
829     request = NULL;
830 
831     /*
832      * Give up the lock before I/O operation
833      */
834     debugMonitorExit(invokerLock);
835     eventHandler_unlock();
836 
837     if (!detached) {
838         outStream_initReply(&out, id);
839         (void)outStream_writeValue(env, &out, tag, returnValue);
840         (void)outStream_writeObjectTag(env, &out, exc);
841         (void)outStream_writeObjectRef(env, &out, exc);
842         outStream_sendReply(&out);
843     }
844 
845     /*
846      * Delete potentially saved global references of return value
847      * and exception
848      */
849     eventHandler_lock(); // for proper lock order
850     debugMonitorEnter(invokerLock);
851     if (mustReleaseReturnValue && returnValue.l != NULL) {
852         tossGlobalRef(env, &returnValue.l);
853     }
854     if (exc != NULL) {
855         tossGlobalRef(env, &exc);
856     }
857     debugMonitorExit(invokerLock);
858     eventHandler_unlock();
859 }
860 
861 jboolean
invoker_isEnabled(jthread thread)862 invoker_isEnabled(jthread thread)
863 {
864     InvokeRequest *request;
865     jboolean isEnabled;
866 
867     JDI_ASSERT(thread);
868     debugMonitorEnter(invokerLock);
869     request = threadControl_getInvokeRequest(thread);
870     if (request == NULL) {
871         EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
872     }
873     isEnabled = request->available;
874     debugMonitorExit(invokerLock);
875     return isEnabled;
876 }
877 
878 void
invoker_detach(InvokeRequest * request)879 invoker_detach(InvokeRequest *request)
880 {
881     JDI_ASSERT(request);
882     debugMonitorEnter(invokerLock);
883     request->detached = JNI_TRUE;
884     debugMonitorExit(invokerLock);
885 }
886