• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "outStream.h"
28 #include "eventHandler.h"
29 #include "threadControl.h"
30 #include "invoker.h"
31 
32 /*
33  * Event helper thread command commandKinds
34  */
35 #define COMMAND_REPORT_EVENT_COMPOSITE          1
36 #define COMMAND_REPORT_INVOKE_DONE              2
37 #define COMMAND_REPORT_VM_INIT                  3
38 #define COMMAND_SUSPEND_THREAD                  4
39 
40 /*
41  * Event helper thread command singleKinds
42  */
43 #define COMMAND_SINGLE_EVENT                    11
44 #define COMMAND_SINGLE_UNLOAD                   12
45 #define COMMAND_SINGLE_FRAME_EVENT              13
46 
47 typedef struct EventCommandSingle {
48     jbyte suspendPolicy; /* NOTE: Must be the first field */
49     jint id;
50     EventInfo info;
51 } EventCommandSingle;
52 
53 typedef struct UnloadCommandSingle {
54     char *classSignature;
55     jint id;
56 } UnloadCommandSingle;
57 
58 typedef struct FrameEventCommandSingle {
59     jbyte suspendPolicy; /* NOTE: Must be the first field */
60     jint id;
61     EventIndex ei;
62     jthread thread;
63     jclass clazz;
64     jmethodID method;
65     jlocation location;
66     char typeKey;         /* Not used for method entry events */
67                           /* If typeKey is 0, then no return value is needed */
68     jvalue returnValue;   /* Not used for method entry events */
69 } FrameEventCommandSingle;
70 
71 typedef struct CommandSingle {
72     jint singleKind;
73     union {
74         EventCommandSingle eventCommand;
75         UnloadCommandSingle unloadCommand;
76         FrameEventCommandSingle frameEventCommand;
77     } u;
78 } CommandSingle;
79 
80 typedef struct ReportInvokeDoneCommand {
81     jthread thread;
82 } ReportInvokeDoneCommand;
83 
84 typedef struct ReportVMInitCommand {
85     jbyte suspendPolicy; /* NOTE: Must be the first field */
86     jthread thread;
87 } ReportVMInitCommand;
88 
89 typedef struct SuspendThreadCommand {
90     jthread thread;
91 } SuspendThreadCommand;
92 
93 typedef struct ReportEventCompositeCommand {
94     jbyte suspendPolicy; /* NOTE: Must be the first field */
95     jint eventCount;
96     CommandSingle singleCommand[1]; /* variable length */
97 } ReportEventCompositeCommand;
98 
99 typedef struct HelperCommand {
100     jint commandKind;
101     jboolean done;
102     jboolean waiting;
103     jbyte sessionID;
104     struct HelperCommand *next;
105     union {
106         /* NOTE: Each of the structs below must have the same first field */
107         ReportEventCompositeCommand reportEventComposite;
108         ReportInvokeDoneCommand     reportInvokeDone;
109         ReportVMInitCommand         reportVMInit;
110         SuspendThreadCommand        suspendThread;
111     } u;
112     /* composite array expand out, put nothing after */
113 } HelperCommand;
114 
115 typedef struct {
116     HelperCommand *head;
117     HelperCommand *tail;
118 } CommandQueue;
119 
120 static CommandQueue commandQueue;
121 static jrawMonitorID commandQueueLock;
122 static jrawMonitorID commandCompleteLock;
123 static jrawMonitorID blockCommandLoopLock;
124 static jint maxQueueSize = 50 * 1024; /* TO DO: Make this configurable */
125 static jboolean holdEvents;
126 static jint currentQueueSize = 0;
127 static jint currentSessionID;
128 
129 static void saveEventInfoRefs(JNIEnv *env, EventInfo *evinfo);
130 static void tossEventInfoRefs(JNIEnv *env, EventInfo *evinfo);
131 
132 static jint
commandSize(HelperCommand * command)133 commandSize(HelperCommand *command)
134 {
135     jint size = sizeof(HelperCommand);
136     if (command->commandKind == COMMAND_REPORT_EVENT_COMPOSITE) {
137         /*
138          * One event is accounted for in the Helper Command. If there are
139          * more, add to size here.
140          */
141         /*LINTED*/
142         size += ((int)sizeof(CommandSingle) *
143                      (command->u.reportEventComposite.eventCount - 1));
144     }
145     return size;
146 }
147 
148 static void
freeCommand(HelperCommand * command)149 freeCommand(HelperCommand *command)
150 {
151     if ( command == NULL )
152         return;
153     jvmtiDeallocate(command);
154 }
155 
156 static void
enqueueCommand(HelperCommand * command,jboolean wait,jboolean reportingVMDeath)157 enqueueCommand(HelperCommand *command,
158                jboolean wait, jboolean reportingVMDeath)
159 {
160     static jboolean vmDeathReported = JNI_FALSE;
161     CommandQueue *queue = &commandQueue;
162     jint size = commandSize(command);
163 
164     command->done = JNI_FALSE;
165     command->waiting = wait;
166     command->next = NULL;
167 
168     debugMonitorEnter(commandQueueLock);
169     while (size + currentQueueSize > maxQueueSize) {
170         debugMonitorWait(commandQueueLock);
171     }
172     log_debugee_location("enqueueCommand(): HelperCommand being processed", NULL, NULL, 0);
173     if (vmDeathReported) {
174         /* send no more events after VMDeath and don't wait */
175         wait = JNI_FALSE;
176     } else {
177         currentQueueSize += size;
178 
179         if (queue->head == NULL) {
180             queue->head = command;
181         } else {
182             queue->tail->next = command;
183         }
184         queue->tail = command;
185 
186         if (reportingVMDeath) {
187             vmDeathReported = JNI_TRUE;
188         }
189     }
190     debugMonitorNotifyAll(commandQueueLock);
191     debugMonitorExit(commandQueueLock);
192 
193     if (wait) {
194         debugMonitorEnter(commandCompleteLock);
195         while (!command->done) {
196             log_debugee_location("enqueueCommand(): HelperCommand wait", NULL, NULL, 0);
197             debugMonitorWait(commandCompleteLock);
198         }
199         freeCommand(command);
200         debugMonitorExit(commandCompleteLock);
201     }
202 }
203 
204 static void
completeCommand(HelperCommand * command)205 completeCommand(HelperCommand *command)
206 {
207     if (command->waiting) {
208         debugMonitorEnter(commandCompleteLock);
209         command->done = JNI_TRUE;
210         log_debugee_location("completeCommand(): HelperCommand done waiting", NULL, NULL, 0);
211         debugMonitorNotifyAll(commandCompleteLock);
212         debugMonitorExit(commandCompleteLock);
213     } else {
214         freeCommand(command);
215     }
216 }
217 
218 static HelperCommand *
dequeueCommand(void)219 dequeueCommand(void)
220 {
221     HelperCommand *command = NULL;
222     CommandQueue *queue = &commandQueue;
223     jint size;
224 
225     debugMonitorEnter(commandQueueLock);
226 
227     while (command == NULL) {
228         while (holdEvents || (queue->head == NULL)) {
229             debugMonitorWait(commandQueueLock);
230         }
231 
232         JDI_ASSERT(queue->head);
233         command = queue->head;
234         queue->head = command->next;
235         if (queue->tail == command) {
236             queue->tail = NULL;
237         }
238 
239         log_debugee_location("dequeueCommand(): command being dequeued", NULL, NULL, 0);
240 
241         size = commandSize(command);
242         /*
243          * Immediately close out any commands enqueued from
244          * a dead VM or a previously attached debugger.
245          */
246         if (gdata->vmDead || command->sessionID != currentSessionID) {
247             log_debugee_location("dequeueCommand(): command session removal", NULL, NULL, 0);
248             completeCommand(command);
249             command = NULL;
250         }
251 
252         /*
253          * There's room in the queue for more.
254          */
255         currentQueueSize -= size;
256         debugMonitorNotifyAll(commandQueueLock);
257     }
258 
259     debugMonitorExit(commandQueueLock);
260 
261     return command;
262 }
263 
eventHelper_holdEvents(void)264 void eventHelper_holdEvents(void)
265 {
266     debugMonitorEnter(commandQueueLock);
267     holdEvents = JNI_TRUE;
268     debugMonitorNotifyAll(commandQueueLock);
269     debugMonitorExit(commandQueueLock);
270 }
271 
eventHelper_releaseEvents(void)272 void eventHelper_releaseEvents(void)
273 {
274     debugMonitorEnter(commandQueueLock);
275     holdEvents = JNI_FALSE;
276     debugMonitorNotifyAll(commandQueueLock);
277     debugMonitorExit(commandQueueLock);
278 }
279 
280 static void
writeSingleStepEvent(JNIEnv * env,PacketOutputStream * out,EventInfo * evinfo)281 writeSingleStepEvent(JNIEnv *env, PacketOutputStream *out, EventInfo *evinfo)
282 {
283     (void)outStream_writeObjectRef(env, out, evinfo->thread);
284     writeCodeLocation(out, evinfo->clazz, evinfo->method, evinfo->location);
285 }
286 
287 static void
writeBreakpointEvent(JNIEnv * env,PacketOutputStream * out,EventInfo * evinfo)288 writeBreakpointEvent(JNIEnv *env, PacketOutputStream *out, EventInfo *evinfo)
289 {
290     (void)outStream_writeObjectRef(env, out, evinfo->thread);
291     writeCodeLocation(out, evinfo->clazz, evinfo->method, evinfo->location);
292 }
293 
294 static void
writeFieldAccessEvent(JNIEnv * env,PacketOutputStream * out,EventInfo * evinfo)295 writeFieldAccessEvent(JNIEnv *env, PacketOutputStream *out, EventInfo *evinfo)
296 {
297     jbyte fieldClassTag;
298 
299     fieldClassTag = referenceTypeTag(evinfo->u.field_access.field_clazz);
300 
301     (void)outStream_writeObjectRef(env, out, evinfo->thread);
302     writeCodeLocation(out, evinfo->clazz, evinfo->method, evinfo->location);
303     (void)outStream_writeByte(out, fieldClassTag);
304     (void)outStream_writeObjectRef(env, out, evinfo->u.field_access.field_clazz);
305     (void)outStream_writeFieldID(out, evinfo->u.field_access.field);
306     (void)outStream_writeObjectTag(env, out, evinfo->object);
307     (void)outStream_writeObjectRef(env, out, evinfo->object);
308 }
309 
310 static void
writeFieldModificationEvent(JNIEnv * env,PacketOutputStream * out,EventInfo * evinfo)311 writeFieldModificationEvent(JNIEnv *env, PacketOutputStream *out,
312                             EventInfo *evinfo)
313 {
314     jbyte fieldClassTag;
315 
316     fieldClassTag = referenceTypeTag(evinfo->u.field_modification.field_clazz);
317 
318     (void)outStream_writeObjectRef(env, out, evinfo->thread);
319     writeCodeLocation(out, evinfo->clazz, evinfo->method, evinfo->location);
320     (void)outStream_writeByte(out, fieldClassTag);
321     (void)outStream_writeObjectRef(env, out, evinfo->u.field_modification.field_clazz);
322     (void)outStream_writeFieldID(out, evinfo->u.field_modification.field);
323     (void)outStream_writeObjectTag(env, out, evinfo->object);
324     (void)outStream_writeObjectRef(env, out, evinfo->object);
325     (void)outStream_writeValue(env, out, (jbyte)evinfo->u.field_modification.signature_type,
326                          evinfo->u.field_modification.new_value);
327 }
328 
329 static void
writeExceptionEvent(JNIEnv * env,PacketOutputStream * out,EventInfo * evinfo)330 writeExceptionEvent(JNIEnv *env, PacketOutputStream *out, EventInfo *evinfo)
331 {
332     (void)outStream_writeObjectRef(env, out, evinfo->thread);
333     writeCodeLocation(out, evinfo->clazz, evinfo->method, evinfo->location);
334     (void)outStream_writeObjectTag(env, out, evinfo->object);
335     (void)outStream_writeObjectRef(env, out, evinfo->object);
336     writeCodeLocation(out, evinfo->u.exception.catch_clazz,
337                       evinfo->u.exception.catch_method, evinfo->u.exception.catch_location);
338 }
339 
340 static void
writeThreadEvent(JNIEnv * env,PacketOutputStream * out,EventInfo * evinfo)341 writeThreadEvent(JNIEnv *env, PacketOutputStream *out, EventInfo *evinfo)
342 {
343     (void)outStream_writeObjectRef(env, out, evinfo->thread);
344 }
345 
346 static void
writeMonitorEvent(JNIEnv * env,PacketOutputStream * out,EventInfo * evinfo)347 writeMonitorEvent(JNIEnv *env, PacketOutputStream *out, EventInfo *evinfo)
348 {
349     jclass klass;
350     (void)outStream_writeObjectRef(env, out, evinfo->thread);
351     (void)outStream_writeObjectTag(env, out, evinfo->object);
352     (void)outStream_writeObjectRef(env, out, evinfo->object);
353     if (evinfo->ei == EI_MONITOR_WAIT || evinfo->ei == EI_MONITOR_WAITED) {
354         /* clazz of evinfo was set to class of monitor object for monitor wait event class filtering.
355          * So get the method class to write location info.
356          * See cbMonitorWait() and cbMonitorWaited() function in eventHandler.c.
357          */
358         klass=getMethodClass(gdata->jvmti, evinfo->method);
359         writeCodeLocation(out, klass, evinfo->method, evinfo->location);
360         if (evinfo->ei == EI_MONITOR_WAIT) {
361             (void)outStream_writeLong(out, evinfo->u.monitor.timeout);
362         } else  if (evinfo->ei == EI_MONITOR_WAITED) {
363             (void)outStream_writeBoolean(out, evinfo->u.monitor.timed_out);
364         }
365         /* This runs in a command loop and this thread may not return to java.
366          * So we need to delete the local ref created by jvmti GetMethodDeclaringClass.
367          */
368         JNI_FUNC_PTR(env,DeleteLocalRef)(env, klass);
369     } else {
370         writeCodeLocation(out, evinfo->clazz, evinfo->method, evinfo->location);
371     }
372 }
373 
374 static void
writeClassEvent(JNIEnv * env,PacketOutputStream * out,EventInfo * evinfo)375 writeClassEvent(JNIEnv *env, PacketOutputStream *out, EventInfo *evinfo)
376 {
377     jbyte classTag;
378     jint status;
379     char *signature = NULL;
380     jvmtiError error;
381 
382     classTag = referenceTypeTag(evinfo->clazz);
383     error = classSignature(evinfo->clazz, &signature, NULL);
384     if (error != JVMTI_ERROR_NONE) {
385         EXIT_ERROR(error,"signature");
386     }
387     status = classStatus(evinfo->clazz);
388 
389     (void)outStream_writeObjectRef(env, out, evinfo->thread);
390     (void)outStream_writeByte(out, classTag);
391     (void)outStream_writeObjectRef(env, out, evinfo->clazz);
392     (void)outStream_writeString(out, signature);
393     (void)outStream_writeInt(out, map2jdwpClassStatus(status));
394     jvmtiDeallocate(signature);
395 }
396 
397 static void
writeVMDeathEvent(JNIEnv * env,PacketOutputStream * out,EventInfo * evinfo)398 writeVMDeathEvent(JNIEnv *env, PacketOutputStream *out, EventInfo *evinfo)
399 {
400 }
401 
402 static void
handleEventCommandSingle(JNIEnv * env,PacketOutputStream * out,EventCommandSingle * command)403 handleEventCommandSingle(JNIEnv *env, PacketOutputStream *out,
404                            EventCommandSingle *command)
405 {
406     EventInfo *evinfo = &command->info;
407 
408     (void)outStream_writeByte(out, eventIndex2jdwp(evinfo->ei));
409     (void)outStream_writeInt(out, command->id);
410 
411     switch (evinfo->ei) {
412         case EI_SINGLE_STEP:
413             writeSingleStepEvent(env, out, evinfo);
414             break;
415         case EI_BREAKPOINT:
416             writeBreakpointEvent(env, out, evinfo);
417             break;
418         case EI_FIELD_ACCESS:
419             writeFieldAccessEvent(env, out, evinfo);
420             break;
421         case EI_FIELD_MODIFICATION:
422             writeFieldModificationEvent(env, out, evinfo);
423             break;
424         case EI_EXCEPTION:
425             writeExceptionEvent(env, out, evinfo);
426             break;
427         case EI_THREAD_START:
428         case EI_THREAD_END:
429             writeThreadEvent(env, out, evinfo);
430             break;
431         case EI_CLASS_LOAD:
432         case EI_CLASS_PREPARE:
433             writeClassEvent(env, out, evinfo);
434             break;
435         case EI_MONITOR_CONTENDED_ENTER:
436         case EI_MONITOR_CONTENDED_ENTERED:
437         case EI_MONITOR_WAIT:
438         case EI_MONITOR_WAITED:
439             writeMonitorEvent(env, out, evinfo);
440             break;
441         case EI_VM_DEATH:
442             writeVMDeathEvent(env, out, evinfo);
443             break;
444         default:
445             EXIT_ERROR(AGENT_ERROR_INVALID_EVENT_TYPE,"unknown event index");
446             break;
447     }
448     tossEventInfoRefs(env, evinfo);
449 }
450 
451 static void
handleUnloadCommandSingle(JNIEnv * env,PacketOutputStream * out,UnloadCommandSingle * command)452 handleUnloadCommandSingle(JNIEnv* env, PacketOutputStream *out,
453                            UnloadCommandSingle *command)
454 {
455     (void)outStream_writeByte(out, JDWP_EVENT(CLASS_UNLOAD));
456     (void)outStream_writeInt(out, command->id);
457     (void)outStream_writeString(out, command->classSignature);
458     jvmtiDeallocate(command->classSignature);
459     command->classSignature = NULL;
460 }
461 
462 static void
handleFrameEventCommandSingle(JNIEnv * env,PacketOutputStream * out,FrameEventCommandSingle * command)463 handleFrameEventCommandSingle(JNIEnv* env, PacketOutputStream *out,
464                               FrameEventCommandSingle *command)
465 {
466     if (command->typeKey) {
467         (void)outStream_writeByte(out, JDWP_EVENT(METHOD_EXIT_WITH_RETURN_VALUE));
468     } else {
469         (void)outStream_writeByte(out, eventIndex2jdwp(command->ei));
470     }
471     (void)outStream_writeInt(out, command->id);
472     (void)outStream_writeObjectRef(env, out, command->thread);
473     writeCodeLocation(out, command->clazz, command->method, command->location);
474     if (command->typeKey) {
475         (void)outStream_writeValue(env, out, command->typeKey, command->returnValue);
476         if (isObjectTag(command->typeKey) &&
477             command->returnValue.l != NULL) {
478             tossGlobalRef(env, &(command->returnValue.l));
479         }
480     }
481     tossGlobalRef(env, &(command->thread));
482     tossGlobalRef(env, &(command->clazz));
483 }
484 
485 static void
suspendWithInvokeEnabled(jbyte policy,jthread thread)486 suspendWithInvokeEnabled(jbyte policy, jthread thread)
487 {
488     invoker_enableInvokeRequests(thread);
489 
490     if (policy == JDWP_SUSPEND_POLICY(ALL)) {
491         (void)threadControl_suspendAll();
492     } else {
493         (void)threadControl_suspendThread(thread, JNI_FALSE);
494     }
495 }
496 
497 static void
handleReportEventCompositeCommand(JNIEnv * env,ReportEventCompositeCommand * recc)498 handleReportEventCompositeCommand(JNIEnv *env,
499                                   ReportEventCompositeCommand *recc)
500 {
501     PacketOutputStream out;
502     jint count = recc->eventCount;
503     jint i;
504 
505     if (recc->suspendPolicy != JDWP_SUSPEND_POLICY(NONE)) {
506         /* must determine thread to interrupt before writing */
507         /* since writing destroys it */
508         jthread thread = NULL;
509         for (i = 0; i < count; i++) {
510             CommandSingle *single = &(recc->singleCommand[i]);
511             switch (single->singleKind) {
512                 case COMMAND_SINGLE_EVENT:
513                     thread = single->u.eventCommand.info.thread;
514                     break;
515                 case COMMAND_SINGLE_FRAME_EVENT:
516                     thread = single->u.frameEventCommand.thread;
517                     break;
518             }
519             if (thread != NULL) {
520                 break;
521             }
522         }
523 
524         if (thread == NULL) {
525             (void)threadControl_suspendAll();
526         } else {
527             suspendWithInvokeEnabled(recc->suspendPolicy, thread);
528         }
529     }
530 
531     outStream_initCommand(&out, uniqueID(), 0x0,
532                           JDWP_COMMAND_SET(Event),
533                           JDWP_COMMAND(Event, Composite));
534     (void)outStream_writeByte(&out, recc->suspendPolicy);
535     (void)outStream_writeInt(&out, count);
536 
537     for (i = 0; i < count; i++) {
538         CommandSingle *single = &(recc->singleCommand[i]);
539         switch (single->singleKind) {
540             case COMMAND_SINGLE_EVENT:
541                 handleEventCommandSingle(env, &out,
542                                          &single->u.eventCommand);
543                 break;
544             case COMMAND_SINGLE_UNLOAD:
545                 handleUnloadCommandSingle(env, &out,
546                                           &single->u.unloadCommand);
547                 break;
548             case COMMAND_SINGLE_FRAME_EVENT:
549                 handleFrameEventCommandSingle(env, &out,
550                                               &single->u.frameEventCommand);
551                 break;
552         }
553     }
554 
555     outStream_sendCommand(&out);
556     outStream_destroy(&out);
557 }
558 
559 static void
handleReportInvokeDoneCommand(JNIEnv * env,ReportInvokeDoneCommand * command)560 handleReportInvokeDoneCommand(JNIEnv* env, ReportInvokeDoneCommand *command)
561 {
562     invoker_completeInvokeRequest(command->thread);
563     tossGlobalRef(env, &(command->thread));
564 }
565 
566 static void
handleReportVMInitCommand(JNIEnv * env,ReportVMInitCommand * command)567 handleReportVMInitCommand(JNIEnv* env, ReportVMInitCommand *command)
568 {
569     PacketOutputStream out;
570 
571     if (command->suspendPolicy == JDWP_SUSPEND_POLICY(ALL)) {
572         (void)threadControl_suspendAll();
573     } else if (command->suspendPolicy == JDWP_SUSPEND_POLICY(EVENT_THREAD)) {
574         (void)threadControl_suspendThread(command->thread, JNI_FALSE);
575     }
576 
577     outStream_initCommand(&out, uniqueID(), 0x0,
578                           JDWP_COMMAND_SET(Event),
579                           JDWP_COMMAND(Event, Composite));
580     (void)outStream_writeByte(&out, command->suspendPolicy);
581     (void)outStream_writeInt(&out, 1);   /* Always one component */
582     (void)outStream_writeByte(&out, JDWP_EVENT(VM_INIT));
583     (void)outStream_writeInt(&out, 0);    /* Not in response to an event req. */
584 
585     (void)outStream_writeObjectRef(env, &out, command->thread);
586 
587     outStream_sendCommand(&out);
588     outStream_destroy(&out);
589     /* Why aren't we tossing this: tossGlobalRef(env, &(command->thread)); */
590 }
591 
592 static void
handleSuspendThreadCommand(JNIEnv * env,SuspendThreadCommand * command)593 handleSuspendThreadCommand(JNIEnv* env, SuspendThreadCommand *command)
594 {
595     /*
596      * For the moment, there's  nothing that can be done with the
597      * return code, so we don't check it here.
598      */
599     (void)threadControl_suspendThread(command->thread, JNI_TRUE);
600     tossGlobalRef(env, &(command->thread));
601 }
602 
603 static void
handleCommand(JNIEnv * env,HelperCommand * command)604 handleCommand(JNIEnv *env, HelperCommand *command)
605 {
606     switch (command->commandKind) {
607         case COMMAND_REPORT_EVENT_COMPOSITE:
608             handleReportEventCompositeCommand(env,
609                                         &command->u.reportEventComposite);
610             break;
611         case COMMAND_REPORT_INVOKE_DONE:
612             handleReportInvokeDoneCommand(env, &command->u.reportInvokeDone);
613             break;
614         case COMMAND_REPORT_VM_INIT:
615             handleReportVMInitCommand(env, &command->u.reportVMInit);
616             break;
617         case COMMAND_SUSPEND_THREAD:
618             handleSuspendThreadCommand(env, &command->u.suspendThread);
619             break;
620         default:
621             EXIT_ERROR(AGENT_ERROR_INVALID_EVENT_TYPE,"Event Helper Command");
622             break;
623     }
624 }
625 
626 /*
627  * There was an assumption that only one event with a suspend-all
628  * policy could be processed by commandLoop() at one time. It was
629  * assumed that native thread suspension from the first suspend-all
630  * event would prevent the second suspend-all event from making it
631  * into the command queue. For the Classic VM, this was a reasonable
632  * assumption. However, in HotSpot all thread suspension requires a
633  * VM operation and VM operations take time.
634  *
635  * The solution is to add a mechanism to prevent commandLoop() from
636  * processing more than one event with a suspend-all policy. This is
637  * accomplished by forcing commandLoop() to wait for either
638  * ThreadReferenceImpl.c: resume() or VirtualMachineImpl.c: resume()
639  * when an event with a suspend-all policy has been completed.
640  */
641 static jboolean blockCommandLoop = JNI_FALSE;
642 
643 /*
644  * We wait for either ThreadReferenceImpl.c: resume() or
645  * VirtualMachineImpl.c: resume() to be called.
646  */
647 static void
doBlockCommandLoop(void)648 doBlockCommandLoop(void) {
649     debugMonitorEnter(blockCommandLoopLock);
650     while (blockCommandLoop == JNI_TRUE) {
651         debugMonitorWait(blockCommandLoopLock);
652     }
653     debugMonitorExit(blockCommandLoopLock);
654 }
655 
656 /*
657  * If the command that we are about to execute has a suspend-all
658  * policy, then prepare for either ThreadReferenceImpl.c: resume()
659  * or VirtualMachineImpl.c: resume() to be called.
660  */
661 static jboolean
needBlockCommandLoop(HelperCommand * cmd)662 needBlockCommandLoop(HelperCommand *cmd) {
663     if (cmd->commandKind == COMMAND_REPORT_EVENT_COMPOSITE
664     && cmd->u.reportEventComposite.suspendPolicy == JDWP_SUSPEND_POLICY(ALL)) {
665         debugMonitorEnter(blockCommandLoopLock);
666         blockCommandLoop = JNI_TRUE;
667         debugMonitorExit(blockCommandLoopLock);
668 
669         return JNI_TRUE;
670     }
671 
672     return JNI_FALSE;
673 }
674 
675 /*
676  * Used by either ThreadReferenceImpl.c: resume() or
677  * VirtualMachineImpl.c: resume() to resume commandLoop().
678  */
679 void
unblockCommandLoop(void)680 unblockCommandLoop(void) {
681     debugMonitorEnter(blockCommandLoopLock);
682     blockCommandLoop = JNI_FALSE;
683     debugMonitorNotifyAll(blockCommandLoopLock);
684     debugMonitorExit(blockCommandLoopLock);
685 }
686 
687 /*
688  * The event helper thread. Dequeues commands and processes them.
689  */
690 static void JNICALL
commandLoop(jvmtiEnv * jvmti_env,JNIEnv * jni_env,void * arg)691 commandLoop(jvmtiEnv* jvmti_env, JNIEnv* jni_env, void* arg)
692 {
693     LOG_MISC(("Begin command loop thread"));
694 
695     while (JNI_TRUE) {
696         HelperCommand *command = dequeueCommand();
697         if (command != NULL) {
698             /*
699              * Setup for a potential doBlockCommand() call before calling
700              * handleCommand() to prevent any races.
701              */
702             jboolean doBlock = needBlockCommandLoop(command);
703             log_debugee_location("commandLoop(): command being handled", NULL, NULL, 0);
704             handleCommand(jni_env, command);
705             completeCommand(command);
706             /* if we just finished a suspend-all cmd, then we block here */
707             if (doBlock) {
708                 doBlockCommandLoop();
709             }
710         }
711     }
712     /* This loop never ends, even as connections come and go with server=y */
713 }
714 
715 void
eventHelper_initialize(jbyte sessionID)716 eventHelper_initialize(jbyte sessionID)
717 {
718     jvmtiStartFunction func;
719 
720     currentSessionID = sessionID;
721     holdEvents = JNI_FALSE;
722     commandQueue.head = NULL;
723     commandQueue.tail = NULL;
724 
725     commandQueueLock = debugMonitorCreate("JDWP Event Helper Queue Monitor");
726     commandCompleteLock = debugMonitorCreate("JDWP Event Helper Completion Monitor");
727     blockCommandLoopLock = debugMonitorCreate("JDWP Event Block CommandLoop Monitor");
728 
729     /* Start the event handler thread */
730     func = &commandLoop;
731     (void)spawnNewThread(func, NULL, "JDWP Event Helper Thread");
732 }
733 
734 void
eventHelper_reset(jbyte newSessionID)735 eventHelper_reset(jbyte newSessionID)
736 {
737     debugMonitorEnter(commandQueueLock);
738     currentSessionID = newSessionID;
739     holdEvents = JNI_FALSE;
740     debugMonitorNotifyAll(commandQueueLock);
741     debugMonitorExit(commandQueueLock);
742 }
743 
744 /*
745  * Provide a means for threadControl to ensure that crucial locks are not
746  * held by suspended threads.
747  */
748 void
eventHelper_lock(void)749 eventHelper_lock(void)
750 {
751     debugMonitorEnter(commandQueueLock);
752     debugMonitorEnter(commandCompleteLock);
753 }
754 
755 void
eventHelper_unlock(void)756 eventHelper_unlock(void)
757 {
758     debugMonitorExit(commandCompleteLock);
759     debugMonitorExit(commandQueueLock);
760 }
761 
762 /* Change all references to global in the EventInfo struct */
763 static void
saveEventInfoRefs(JNIEnv * env,EventInfo * evinfo)764 saveEventInfoRefs(JNIEnv *env, EventInfo *evinfo)
765 {
766     jthread *pthread;
767     jclass *pclazz;
768     jobject *pobject;
769     jthread thread;
770     jclass clazz;
771     jobject object;
772     char sig;
773 
774     JNI_FUNC_PTR(env,ExceptionClear)(env);
775 
776     if ( evinfo->thread != NULL ) {
777         pthread = &(evinfo->thread);
778         thread = *pthread;
779         *pthread = NULL;
780         saveGlobalRef(env, thread, pthread);
781     }
782     if ( evinfo->clazz != NULL ) {
783         pclazz = &(evinfo->clazz);
784         clazz = *pclazz;
785         *pclazz = NULL;
786         saveGlobalRef(env, clazz, pclazz);
787     }
788     if ( evinfo->object != NULL ) {
789         pobject = &(evinfo->object);
790         object = *pobject;
791         *pobject = NULL;
792         saveGlobalRef(env, object, pobject);
793     }
794 
795     switch (evinfo->ei) {
796         case EI_FIELD_MODIFICATION:
797             if ( evinfo->u.field_modification.field_clazz != NULL ) {
798                 pclazz = &(evinfo->u.field_modification.field_clazz);
799                 clazz = *pclazz;
800                 *pclazz = NULL;
801                 saveGlobalRef(env, clazz, pclazz);
802             }
803             sig = evinfo->u.field_modification.signature_type;
804             if ((sig == JDWP_TAG(ARRAY)) || (sig == JDWP_TAG(OBJECT))) {
805                 if ( evinfo->u.field_modification.new_value.l != NULL ) {
806                     pobject = &(evinfo->u.field_modification.new_value.l);
807                     object = *pobject;
808                     *pobject = NULL;
809                     saveGlobalRef(env, object, pobject);
810                 }
811             }
812             break;
813         case EI_FIELD_ACCESS:
814             if ( evinfo->u.field_access.field_clazz != NULL ) {
815                 pclazz = &(evinfo->u.field_access.field_clazz);
816                 clazz = *pclazz;
817                 *pclazz = NULL;
818                 saveGlobalRef(env, clazz, pclazz);
819             }
820             break;
821         case EI_EXCEPTION:
822             if ( evinfo->u.exception.catch_clazz != NULL ) {
823                 pclazz = &(evinfo->u.exception.catch_clazz);
824                 clazz = *pclazz;
825                 *pclazz = NULL;
826                 saveGlobalRef(env, clazz, pclazz);
827             }
828             break;
829         default:
830             break;
831     }
832 
833     if (JNI_FUNC_PTR(env,ExceptionOccurred)(env)) {
834         EXIT_ERROR(AGENT_ERROR_INVALID_EVENT_TYPE,"ExceptionOccurred");
835     }
836 }
837 
838 static void
tossEventInfoRefs(JNIEnv * env,EventInfo * evinfo)839 tossEventInfoRefs(JNIEnv *env, EventInfo *evinfo)
840 {
841     char sig;
842     if ( evinfo->thread != NULL ) {
843         tossGlobalRef(env, &(evinfo->thread));
844     }
845     if ( evinfo->clazz != NULL ) {
846         tossGlobalRef(env, &(evinfo->clazz));
847     }
848     if ( evinfo->object != NULL ) {
849         tossGlobalRef(env, &(evinfo->object));
850     }
851     switch (evinfo->ei) {
852         case EI_FIELD_MODIFICATION:
853             if ( evinfo->u.field_modification.field_clazz != NULL ) {
854                 tossGlobalRef(env, &(evinfo->u.field_modification.field_clazz));
855             }
856             sig = evinfo->u.field_modification.signature_type;
857             if ((sig == JDWP_TAG(ARRAY)) || (sig == JDWP_TAG(OBJECT))) {
858                 if ( evinfo->u.field_modification.new_value.l != NULL ) {
859                     tossGlobalRef(env, &(evinfo->u.field_modification.new_value.l));
860                 }
861             }
862             break;
863         case EI_FIELD_ACCESS:
864             if ( evinfo->u.field_access.field_clazz != NULL ) {
865                 tossGlobalRef(env, &(evinfo->u.field_access.field_clazz));
866             }
867             break;
868         case EI_EXCEPTION:
869             if ( evinfo->u.exception.catch_clazz != NULL ) {
870                 tossGlobalRef(env, &(evinfo->u.exception.catch_clazz));
871             }
872             break;
873         default:
874             break;
875     }
876 }
877 
878 struct bag *
eventHelper_createEventBag(void)879 eventHelper_createEventBag(void)
880 {
881     return bagCreateBag(sizeof(CommandSingle), 5 /* events */ );
882 }
883 
884 /* Return the combined suspend policy for the event set
885  */
886 static jboolean
enumForCombinedSuspendPolicy(void * cv,void * arg)887 enumForCombinedSuspendPolicy(void *cv, void *arg)
888 {
889     CommandSingle *command = cv;
890     jbyte thisPolicy;
891     jbyte *policy = arg;
892 
893     switch(command->singleKind) {
894         case COMMAND_SINGLE_EVENT:
895             thisPolicy = command->u.eventCommand.suspendPolicy;
896             break;
897         case COMMAND_SINGLE_FRAME_EVENT:
898             thisPolicy = command->u.frameEventCommand.suspendPolicy;
899             break;
900         default:
901             thisPolicy = JDWP_SUSPEND_POLICY(NONE);
902     }
903     /* Expand running policy value if this policy demands it */
904     if (*policy == JDWP_SUSPEND_POLICY(NONE)) {
905         *policy = thisPolicy;
906     } else if (*policy == JDWP_SUSPEND_POLICY(EVENT_THREAD)) {
907         *policy = (thisPolicy == JDWP_SUSPEND_POLICY(ALL))?
908                         thisPolicy : *policy;
909     }
910 
911     /* Short circuit if we reached maximal suspend policy */
912     if (*policy == JDWP_SUSPEND_POLICY(ALL)) {
913         return JNI_FALSE;
914     } else {
915         return JNI_TRUE;
916     }
917 }
918 
919 /* Determine whether we are reporting VM death
920  */
921 static jboolean
enumForVMDeath(void * cv,void * arg)922 enumForVMDeath(void *cv, void *arg)
923 {
924     CommandSingle *command = cv;
925     jboolean *reportingVMDeath = arg;
926 
927     if (command->singleKind == COMMAND_SINGLE_EVENT) {
928         if (command->u.eventCommand.info.ei == EI_VM_DEATH) {
929             *reportingVMDeath = JNI_TRUE;
930             return JNI_FALSE;
931         }
932     }
933     return JNI_TRUE;
934 }
935 
936 struct singleTracker {
937     ReportEventCompositeCommand *recc;
938     int index;
939 };
940 
941 static jboolean
enumForCopyingSingles(void * command,void * tv)942 enumForCopyingSingles(void *command, void *tv)
943 {
944     struct singleTracker *tracker = (struct singleTracker *)tv;
945     (void)memcpy(&tracker->recc->singleCommand[tracker->index++],
946            command,
947            sizeof(CommandSingle));
948     return JNI_TRUE;
949 }
950 
951 jbyte
eventHelper_reportEvents(jbyte sessionID,struct bag * eventBag)952 eventHelper_reportEvents(jbyte sessionID, struct bag *eventBag)
953 {
954     int size = bagSize(eventBag);
955     jbyte suspendPolicy = JDWP_SUSPEND_POLICY(NONE);
956     jboolean reportingVMDeath = JNI_FALSE;
957     jboolean wait;
958     int command_size;
959 
960     HelperCommand *command;
961     ReportEventCompositeCommand *recc;
962     struct singleTracker tracker;
963 
964     if (size == 0) {
965         return suspendPolicy;
966     }
967     (void)bagEnumerateOver(eventBag, enumForCombinedSuspendPolicy, &suspendPolicy);
968     (void)bagEnumerateOver(eventBag, enumForVMDeath, &reportingVMDeath);
969 
970     /*LINTED*/
971     command_size = (int)(sizeof(HelperCommand) +
972                          sizeof(CommandSingle)*(size-1));
973     command = jvmtiAllocate(command_size);
974     (void)memset(command, 0, command_size);
975     command->commandKind = COMMAND_REPORT_EVENT_COMPOSITE;
976     command->sessionID = sessionID;
977     recc = &command->u.reportEventComposite;
978     recc->suspendPolicy = suspendPolicy;
979     recc->eventCount = size;
980     tracker.recc = recc;
981     tracker.index = 0;
982     (void)bagEnumerateOver(eventBag, enumForCopyingSingles, &tracker);
983 
984     /*
985      * We must wait if this thread (the event thread) is to be
986      * suspended or if the VM is about to die. (Waiting in the latter
987      * case ensures that we get the event out before the process dies.)
988      */
989     wait = (jboolean)((suspendPolicy != JDWP_SUSPEND_POLICY(NONE)) ||
990                       reportingVMDeath);
991     enqueueCommand(command, wait, reportingVMDeath);
992     return suspendPolicy;
993 }
994 
995 void
eventHelper_recordEvent(EventInfo * evinfo,jint id,jbyte suspendPolicy,struct bag * eventBag)996 eventHelper_recordEvent(EventInfo *evinfo, jint id, jbyte suspendPolicy,
997                          struct bag *eventBag)
998 {
999     JNIEnv *env = getEnv();
1000     CommandSingle *command = bagAdd(eventBag);
1001     if (command == NULL) {
1002         EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"badAdd(eventBag)");
1003     }
1004 
1005     command->singleKind = COMMAND_SINGLE_EVENT;
1006     command->u.eventCommand.suspendPolicy = suspendPolicy;
1007     command->u.eventCommand.id = id;
1008 
1009     /*
1010      * Copy the event into the command so that it can be used
1011      * asynchronously by the event helper thread.
1012      */
1013     (void)memcpy(&command->u.eventCommand.info, evinfo, sizeof(*evinfo));
1014     saveEventInfoRefs(env, &command->u.eventCommand.info);
1015 }
1016 
1017 void
eventHelper_recordClassUnload(jint id,char * signature,struct bag * eventBag)1018 eventHelper_recordClassUnload(jint id, char *signature, struct bag *eventBag)
1019 {
1020     CommandSingle *command = bagAdd(eventBag);
1021     if (command == NULL) {
1022         EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"bagAdd(eventBag)");
1023     }
1024     command->singleKind = COMMAND_SINGLE_UNLOAD;
1025     command->u.unloadCommand.id = id;
1026     command->u.unloadCommand.classSignature = signature;
1027 }
1028 
1029 void
eventHelper_recordFrameEvent(jint id,jbyte suspendPolicy,EventIndex ei,jthread thread,jclass clazz,jmethodID method,jlocation location,int needReturnValue,jvalue returnValue,struct bag * eventBag)1030 eventHelper_recordFrameEvent(jint id, jbyte suspendPolicy, EventIndex ei,
1031                              jthread thread, jclass clazz,
1032                              jmethodID method, jlocation location,
1033                              int needReturnValue,
1034                              jvalue returnValue,
1035                              struct bag *eventBag)
1036 {
1037     JNIEnv *env = getEnv();
1038     FrameEventCommandSingle *frameCommand;
1039     CommandSingle *command = bagAdd(eventBag);
1040     jvmtiError err = JVMTI_ERROR_NONE;
1041     if (command == NULL) {
1042         EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"bagAdd(eventBag)");
1043     }
1044 
1045     command->singleKind = COMMAND_SINGLE_FRAME_EVENT;
1046     frameCommand = &command->u.frameEventCommand;
1047     frameCommand->suspendPolicy = suspendPolicy;
1048     frameCommand->id = id;
1049     frameCommand->ei = ei;
1050     saveGlobalRef(env, thread, &(frameCommand->thread));
1051     saveGlobalRef(env, clazz, &(frameCommand->clazz));
1052     frameCommand->method = method;
1053     frameCommand->location = location;
1054     if (needReturnValue) {
1055         err = methodReturnType(method, &frameCommand->typeKey);
1056         JDI_ASSERT(err == JVMTI_ERROR_NONE);
1057 
1058         /*
1059          * V or B C D F I J S Z L <classname> ;    [ ComponentType
1060          */
1061         if (isObjectTag(frameCommand->typeKey) &&
1062             returnValue.l != NULL) {
1063             saveGlobalRef(env, returnValue.l, &(frameCommand->returnValue.l));
1064         } else {
1065             frameCommand->returnValue = returnValue;
1066         }
1067     } else {
1068       /* This is not a JDWP METHOD_EXIT_WITH_RETURN_VALUE request,
1069        * so signal this by setting typeKey = 0 which is not
1070        * a legal typekey.
1071        */
1072        frameCommand->typeKey = 0;
1073     }
1074 }
1075 
1076 void
eventHelper_reportInvokeDone(jbyte sessionID,jthread thread)1077 eventHelper_reportInvokeDone(jbyte sessionID, jthread thread)
1078 {
1079     JNIEnv *env = getEnv();
1080     HelperCommand *command = jvmtiAllocate(sizeof(*command));
1081     if (command == NULL) {
1082         EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"HelperCommand");
1083     }
1084     (void)memset(command, 0, sizeof(*command));
1085     command->commandKind = COMMAND_REPORT_INVOKE_DONE;
1086     command->sessionID = sessionID;
1087     saveGlobalRef(env, thread, &(command->u.reportInvokeDone.thread));
1088     enqueueCommand(command, JNI_TRUE, JNI_FALSE);
1089 }
1090 
1091 /*
1092  * This, currently, cannot go through the normal event handling code
1093  * because the JVMTI event does not contain a thread.
1094  */
1095 void
eventHelper_reportVMInit(JNIEnv * env,jbyte sessionID,jthread thread,jbyte suspendPolicy)1096 eventHelper_reportVMInit(JNIEnv *env, jbyte sessionID, jthread thread, jbyte suspendPolicy)
1097 {
1098     HelperCommand *command = jvmtiAllocate(sizeof(*command));
1099     if (command == NULL) {
1100         EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"HelperCommmand");
1101     }
1102     (void)memset(command, 0, sizeof(*command));
1103     command->commandKind = COMMAND_REPORT_VM_INIT;
1104     command->sessionID = sessionID;
1105     saveGlobalRef(env, thread, &(command->u.reportVMInit.thread));
1106     command->u.reportVMInit.suspendPolicy = suspendPolicy;
1107     enqueueCommand(command, JNI_TRUE, JNI_FALSE);
1108 }
1109 
1110 void
eventHelper_suspendThread(jbyte sessionID,jthread thread)1111 eventHelper_suspendThread(jbyte sessionID, jthread thread)
1112 {
1113     JNIEnv *env = getEnv();
1114     HelperCommand *command = jvmtiAllocate(sizeof(*command));
1115     if (command == NULL) {
1116         EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"HelperCommmand");
1117     }
1118     (void)memset(command, 0, sizeof(*command));
1119     command->commandKind = COMMAND_SUSPEND_THREAD;
1120     command->sessionID = sessionID;
1121     saveGlobalRef(env, thread, &(command->u.suspendThread.thread));
1122     enqueueCommand(command, JNI_TRUE, JNI_FALSE);
1123 }
1124