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