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 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 149 freeCommand(HelperCommand *command) 150 { 151 if ( command == NULL ) 152 return; 153 jvmtiDeallocate(command); 154 } 155 156 static void 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 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 * 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 264 void eventHelper_holdEvents(void) 265 { 266 debugMonitorEnter(commandQueueLock); 267 holdEvents = JNI_TRUE; 268 debugMonitorNotifyAll(commandQueueLock); 269 debugMonitorExit(commandQueueLock); 270 } 271 272 void eventHelper_releaseEvents(void) 273 { 274 debugMonitorEnter(commandQueueLock); 275 holdEvents = JNI_FALSE; 276 debugMonitorNotifyAll(commandQueueLock); 277 debugMonitorExit(commandQueueLock); 278 } 279 280 static void 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 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 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 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 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 341 writeThreadEvent(JNIEnv *env, PacketOutputStream *out, EventInfo *evinfo) 342 { 343 (void)outStream_writeObjectRef(env, out, evinfo->thread); 344 } 345 346 static void 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 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 398 writeVMDeathEvent(JNIEnv *env, PacketOutputStream *out, EventInfo *evinfo) 399 { 400 } 401 402 static void 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 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 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 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 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 560 handleReportInvokeDoneCommand(JNIEnv* env, ReportInvokeDoneCommand *command) 561 { 562 invoker_completeInvokeRequest(command->thread); 563 tossGlobalRef(env, &(command->thread)); 564 } 565 566 static void 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 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 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 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 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 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 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 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 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 749 eventHelper_lock(void) 750 { 751 debugMonitorEnter(commandQueueLock); 752 debugMonitorEnter(commandCompleteLock); 753 } 754 755 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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