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