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