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))) {
 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))) {
 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 }