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 writeThreadOrFiber(JNIEnv *env, PacketOutputStream *out, EventInfo *evinfo)
 288 {
 289     /*
 290      * Write the fiber ref if the event matched a fiber filter, or if the event was not
 291      * filtered by thread, and came in on a carrier thread running a fiber. In either
 292      * case evinfo->matchesFiber will be true.
 293      */
 294     jthread thread = (evinfo->matchesFiber ? evinfo->fiber : evinfo->thread);
 295     (void)outStream_writeObjectRef(env, out, thread);
 296 }
 297 
 298 static void
 299 writeSingleStepEvent(JNIEnv *env, PacketOutputStream *out, EventInfo *evinfo)
 300 {
 301     writeThreadOrFiber(env, out, evinfo);
 302     writeCodeLocation(out, evinfo->clazz, evinfo->method, evinfo->location);
 303 }
 304 
 305 static void
 306 writeBreakpointEvent(JNIEnv *env, PacketOutputStream *out, EventInfo *evinfo)
 307 {
 308     writeThreadOrFiber(env, out, evinfo);
 309     writeCodeLocation(out, evinfo->clazz, evinfo->method, evinfo->location);
 310 }
 311 
 312 static void
 313 writeFieldAccessEvent(JNIEnv *env, PacketOutputStream *out, EventInfo *evinfo)
 314 {
 315     jbyte fieldClassTag;
 316 
 317     fieldClassTag = referenceTypeTag(evinfo->u.field_access.field_clazz);
 318 
 319     writeThreadOrFiber(env, out, evinfo);
 320     writeCodeLocation(out, evinfo->clazz, evinfo->method, evinfo->location);
 321     (void)outStream_writeByte(out, fieldClassTag);
 322     (void)outStream_writeObjectRef(env, out, evinfo->u.field_access.field_clazz);
 323     (void)outStream_writeFieldID(out, evinfo->u.field_access.field);
 324     (void)outStream_writeObjectTag(env, out, evinfo->object);
 325     (void)outStream_writeObjectRef(env, out, evinfo->object);
 326 }
 327 
 328 static void
 329 writeFieldModificationEvent(JNIEnv *env, PacketOutputStream *out,
 330                             EventInfo *evinfo)
 331 {
 332     jbyte fieldClassTag;
 333 
 334     fieldClassTag = referenceTypeTag(evinfo->u.field_modification.field_clazz);
 335 
 336     writeThreadOrFiber(env, out, evinfo);
 337     writeCodeLocation(out, evinfo->clazz, evinfo->method, evinfo->location);
 338     (void)outStream_writeByte(out, fieldClassTag);
 339     (void)outStream_writeObjectRef(env, out, evinfo->u.field_modification.field_clazz);
 340     (void)outStream_writeFieldID(out, evinfo->u.field_modification.field);
 341     (void)outStream_writeObjectTag(env, out, evinfo->object);
 342     (void)outStream_writeObjectRef(env, out, evinfo->object);
 343     (void)outStream_writeValue(env, out, (jbyte)evinfo->u.field_modification.signature_type,
 344                          evinfo->u.field_modification.new_value);
 345 }
 346 
 347 static void
 348 writeExceptionEvent(JNIEnv *env, PacketOutputStream *out, EventInfo *evinfo)
 349 {
 350     writeThreadOrFiber(env, out, evinfo);
 351     writeCodeLocation(out, evinfo->clazz, evinfo->method, evinfo->location);
 352     (void)outStream_writeObjectTag(env, out, evinfo->object);
 353     (void)outStream_writeObjectRef(env, out, evinfo->object);
 354     writeCodeLocation(out, evinfo->u.exception.catch_clazz,
 355                       evinfo->u.exception.catch_method, evinfo->u.exception.catch_location);
 356 }
 357 
 358 static void
 359 writeThreadEvent(JNIEnv *env, PacketOutputStream *out, EventInfo *evinfo)
 360 {
 361     writeThreadOrFiber(env, out, evinfo);
 362 }
 363 
 364 static void
 365 writeMonitorEvent(JNIEnv *env, PacketOutputStream *out, EventInfo *evinfo)
 366 {
 367     jclass klass;
 368     writeThreadOrFiber(env, out, evinfo);
 369     (void)outStream_writeObjectTag(env, out, evinfo->object);
 370     (void)outStream_writeObjectRef(env, out, evinfo->object);
 371     if (evinfo->ei == EI_MONITOR_WAIT || evinfo->ei == EI_MONITOR_WAITED) {
 372         /* clazz of evinfo was set to class of monitor object for monitor wait event class filtering.
 373          * So get the method class to write location info.
 374          * See cbMonitorWait() and cbMonitorWaited() function in eventHandler.c.
 375          */
 376         klass=getMethodClass(gdata->jvmti, evinfo->method);
 377         writeCodeLocation(out, klass, evinfo->method, evinfo->location);
 378         if (evinfo->ei == EI_MONITOR_WAIT) {
 379             (void)outStream_writeLong(out, evinfo->u.monitor.timeout);
 380         } else  if (evinfo->ei == EI_MONITOR_WAITED) {
 381             (void)outStream_writeBoolean(out, evinfo->u.monitor.timed_out);
 382         }
 383         /* This runs in a command loop and this thread may not return to java.
 384          * So we need to delete the local ref created by jvmti GetMethodDeclaringClass.
 385          */
 386         JNI_FUNC_PTR(env,DeleteLocalRef)(env, klass);
 387     } else {
 388         writeCodeLocation(out, evinfo->clazz, evinfo->method, evinfo->location);
 389     }
 390 }
 391 
 392 static void
 393 writeClassEvent(JNIEnv *env, PacketOutputStream *out, EventInfo *evinfo)
 394 {
 395     jbyte classTag;
 396     jint status;
 397     char *signature = NULL;
 398     jvmtiError error;
 399 
 400     classTag = referenceTypeTag(evinfo->clazz);
 401     error = classSignature(evinfo->clazz, &signature, NULL);
 402     if (error != JVMTI_ERROR_NONE) {
 403         EXIT_ERROR(error,"signature");
 404     }
 405     status = classStatus(evinfo->clazz);
 406 
 407     writeThreadOrFiber(env, out, evinfo);
 408     (void)outStream_writeByte(out, classTag);
 409     (void)outStream_writeObjectRef(env, out, evinfo->clazz);
 410     (void)outStream_writeString(out, signature);
 411     (void)outStream_writeInt(out, map2jdwpClassStatus(status));
 412     jvmtiDeallocate(signature);
 413 }
 414 
 415 static void
 416 writeVMDeathEvent(JNIEnv *env, PacketOutputStream *out, EventInfo *evinfo)
 417 {
 418 }
 419 
 420 static void
 421 handleEventCommandSingle(JNIEnv *env, PacketOutputStream *out,
 422                            EventCommandSingle *command)
 423 {
 424     EventInfo *evinfo = &command->info;
 425 
 426     (void)outStream_writeByte(out, eventIndex2jdwp(evinfo->ei));
 427     (void)outStream_writeInt(out, command->id);
 428 
 429     switch (evinfo->ei) {
 430         case EI_SINGLE_STEP:
 431             writeSingleStepEvent(env, out, evinfo);
 432             break;
 433         case EI_BREAKPOINT:
 434             writeBreakpointEvent(env, out, evinfo);
 435             break;
 436         case EI_FIELD_ACCESS:
 437             writeFieldAccessEvent(env, out, evinfo);
 438             break;
 439         case EI_FIELD_MODIFICATION:
 440             writeFieldModificationEvent(env, out, evinfo);
 441             break;
 442         case EI_EXCEPTION:
 443             writeExceptionEvent(env, out, evinfo);
 444             break;
 445         case EI_THREAD_START:
 446         case EI_THREAD_END:
 447             writeThreadEvent(env, out, evinfo);
 448             break;
 449         case EI_FIBER_SCHEDULED:
 450         case EI_FIBER_TERMINATED:
 451             /* Note that when we wrote the evinfo->ei byte above, it was mapped to an EI_THREAD_XXX event
 452              * by eventIndex2jdwp(), so we didn't actually write the FIBER ei byte.
 453              */
 454             writeThreadEvent(env, out, evinfo);
 455             break;
 456         case EI_FIBER_MOUNT:
 457         case EI_FIBER_UNMOUNT:
 458         case EI_CONTINUATION_RUN:
 459         case EI_CONTINUATION_YIELD:
 460             EXIT_ERROR(AGENT_ERROR_INVALID_EVENT_TYPE, "invalid event index");
 461             break;
 462         case EI_CLASS_LOAD:
 463         case EI_CLASS_PREPARE:
 464             writeClassEvent(env, out, evinfo);
 465             break;
 466         case EI_MONITOR_CONTENDED_ENTER:
 467         case EI_MONITOR_CONTENDED_ENTERED:
 468         case EI_MONITOR_WAIT:
 469         case EI_MONITOR_WAITED:
 470             writeMonitorEvent(env, out, evinfo);
 471             break;
 472         case EI_VM_DEATH:
 473             writeVMDeathEvent(env, out, evinfo);
 474             break;
 475         default:
 476             EXIT_ERROR(AGENT_ERROR_INVALID_EVENT_TYPE,"unknown event index");
 477             break;
 478     }
 479     tossEventInfoRefs(env, evinfo);
 480 }
 481 
 482 static void
 483 handleUnloadCommandSingle(JNIEnv* env, PacketOutputStream *out,
 484                            UnloadCommandSingle *command)
 485 {
 486     (void)outStream_writeByte(out, JDWP_EVENT(CLASS_UNLOAD));
 487     (void)outStream_writeInt(out, command->id);
 488     (void)outStream_writeString(out, command->classSignature);
 489     jvmtiDeallocate(command->classSignature);
 490     command->classSignature = NULL;
 491 }
 492 
 493 static void
 494 handleFrameEventCommandSingle(JNIEnv* env, PacketOutputStream *out,
 495                               FrameEventCommandSingle *command)
 496 {
 497     if (command->typeKey) {
 498         (void)outStream_writeByte(out, JDWP_EVENT(METHOD_EXIT_WITH_RETURN_VALUE));
 499     } else {
 500         (void)outStream_writeByte(out, eventIndex2jdwp(command->ei));
 501     }
 502     (void)outStream_writeInt(out, command->id);
 503     (void)outStream_writeObjectRef(env, out, command->thread);
 504     writeCodeLocation(out, command->clazz, command->method, command->location);
 505     if (command->typeKey) {
 506         (void)outStream_writeValue(env, out, command->typeKey, command->returnValue);
 507         if (isObjectTag(command->typeKey) &&
 508             command->returnValue.l != NULL) {
 509             tossGlobalRef(env, &(command->returnValue.l));
 510         }
 511     }
 512     tossGlobalRef(env, &(command->thread));
 513     tossGlobalRef(env, &(command->clazz));
 514 }
 515 
 516 static void
 517 suspendWithInvokeEnabled(jbyte policy, jthread thread)
 518 {
 519     invoker_enableInvokeRequests(thread);
 520 
 521     if (policy == JDWP_SUSPEND_POLICY(ALL)) {
 522         (void)threadControl_suspendAll();
 523     } else {
 524         (void)threadControl_suspendThread(thread, JNI_FALSE);
 525     }
 526 }
 527 
 528 static void
 529 handleReportEventCompositeCommand(JNIEnv *env,
 530                                   ReportEventCompositeCommand *recc)
 531 {
 532     PacketOutputStream out;
 533     jint count = recc->eventCount;
 534     jint i;
 535 
 536     if (recc->suspendPolicy != JDWP_SUSPEND_POLICY(NONE)) {
 537         /* must determine thread to interrupt before writing */
 538         /* since writing destroys it */
 539         jthread thread = NULL;
 540         for (i = 0; i < count; i++) {
 541             CommandSingle *single = &(recc->singleCommand[i]);
 542             switch (single->singleKind) {
 543                 case COMMAND_SINGLE_EVENT:
 544                     thread = single->u.eventCommand.info.thread;
 545                     break;
 546                 case COMMAND_SINGLE_FRAME_EVENT:
 547                     thread = single->u.frameEventCommand.thread;
 548                     break;
 549             }
 550             if (thread != NULL) {
 551                 break;
 552             }
 553         }
 554 
 555         if (thread == NULL) {
 556             (void)threadControl_suspendAll();
 557         } else {
 558             suspendWithInvokeEnabled(recc->suspendPolicy, thread);
 559         }
 560     }
 561 
 562     outStream_initCommand(&out, uniqueID(), 0x0,
 563                           JDWP_COMMAND_SET(Event),
 564                           JDWP_COMMAND(Event, Composite));
 565     (void)outStream_writeByte(&out, recc->suspendPolicy);
 566     (void)outStream_writeInt(&out, count);
 567 
 568     for (i = 0; i < count; i++) {
 569         CommandSingle *single = &(recc->singleCommand[i]);
 570         switch (single->singleKind) {
 571             case COMMAND_SINGLE_EVENT:
 572                 handleEventCommandSingle(env, &out,
 573                                          &single->u.eventCommand);
 574                 break;
 575             case COMMAND_SINGLE_UNLOAD:
 576                 handleUnloadCommandSingle(env, &out,
 577                                           &single->u.unloadCommand);
 578                 break;
 579             case COMMAND_SINGLE_FRAME_EVENT:
 580                 handleFrameEventCommandSingle(env, &out,
 581                                               &single->u.frameEventCommand);
 582                 break;
 583         }
 584     }
 585 
 586     outStream_sendCommand(&out);
 587     outStream_destroy(&out);
 588 }
 589 
 590 static void
 591 handleReportInvokeDoneCommand(JNIEnv* env, ReportInvokeDoneCommand *command)
 592 {
 593     invoker_completeInvokeRequest(command->thread);
 594     tossGlobalRef(env, &(command->thread));
 595 }
 596 
 597 static void
 598 handleReportVMInitCommand(JNIEnv* env, ReportVMInitCommand *command)
 599 {
 600     PacketOutputStream out;
 601 
 602     if (command->suspendPolicy == JDWP_SUSPEND_POLICY(ALL)) {
 603         (void)threadControl_suspendAll();
 604     } else if (command->suspendPolicy == JDWP_SUSPEND_POLICY(EVENT_THREAD)) {
 605         (void)threadControl_suspendThread(command->thread, JNI_FALSE);
 606     }
 607 
 608     outStream_initCommand(&out, uniqueID(), 0x0,
 609                           JDWP_COMMAND_SET(Event),
 610                           JDWP_COMMAND(Event, Composite));
 611     (void)outStream_writeByte(&out, command->suspendPolicy);
 612     (void)outStream_writeInt(&out, 1);   /* Always one component */
 613     (void)outStream_writeByte(&out, JDWP_EVENT(VM_INIT));
 614     (void)outStream_writeInt(&out, 0);    /* Not in response to an event req. */
 615 
 616     (void)outStream_writeObjectRef(env, &out, command->thread);
 617 
 618     outStream_sendCommand(&out);
 619     outStream_destroy(&out);
 620     /* Why aren't we tossing this: tossGlobalRef(env, &(command->thread)); */
 621 }
 622 
 623 static void
 624 handleSuspendThreadCommand(JNIEnv* env, SuspendThreadCommand *command)
 625 {
 626     /*
 627      * For the moment, there's  nothing that can be done with the
 628      * return code, so we don't check it here.
 629      */
 630     (void)threadControl_suspendThread(command->thread, JNI_TRUE);
 631     tossGlobalRef(env, &(command->thread));
 632 }
 633 
 634 static void
 635 handleCommand(JNIEnv *env, HelperCommand *command)
 636 {
 637     switch (command->commandKind) {
 638         case COMMAND_REPORT_EVENT_COMPOSITE:
 639             handleReportEventCompositeCommand(env,
 640                                         &command->u.reportEventComposite);
 641             break;
 642         case COMMAND_REPORT_INVOKE_DONE:
 643             handleReportInvokeDoneCommand(env, &command->u.reportInvokeDone);
 644             break;
 645         case COMMAND_REPORT_VM_INIT:
 646             handleReportVMInitCommand(env, &command->u.reportVMInit);
 647             break;
 648         case COMMAND_SUSPEND_THREAD:
 649             handleSuspendThreadCommand(env, &command->u.suspendThread);
 650             break;
 651         default:
 652             EXIT_ERROR(AGENT_ERROR_INVALID_EVENT_TYPE,"Event Helper Command");
 653             break;
 654     }
 655 }
 656 
 657 /*
 658  * There was an assumption that only one event with a suspend-all
 659  * policy could be processed by commandLoop() at one time. It was
 660  * assumed that native thread suspension from the first suspend-all
 661  * event would prevent the second suspend-all event from making it
 662  * into the command queue. For the Classic VM, this was a reasonable
 663  * assumption. However, in HotSpot all thread suspension requires a
 664  * VM operation and VM operations take time.
 665  *
 666  * The solution is to add a mechanism to prevent commandLoop() from
 667  * processing more than one event with a suspend-all policy. This is
 668  * accomplished by forcing commandLoop() to wait for either
 669  * ThreadReferenceImpl.c: resume() or VirtualMachineImpl.c: resume()
 670  * when an event with a suspend-all policy has been completed.
 671  */
 672 static jboolean blockCommandLoop = JNI_FALSE;
 673 
 674 /*
 675  * We wait for either ThreadReferenceImpl.c: resume() or
 676  * VirtualMachineImpl.c: resume() to be called.
 677  */
 678 static void
 679 doBlockCommandLoop(void) {
 680     debugMonitorEnter(blockCommandLoopLock);
 681     while (blockCommandLoop == JNI_TRUE) {
 682         debugMonitorWait(blockCommandLoopLock);
 683     }
 684     debugMonitorExit(blockCommandLoopLock);
 685 }
 686 
 687 /*
 688  * If the command that we are about to execute has a suspend-all
 689  * policy, then prepare for either ThreadReferenceImpl.c: resume()
 690  * or VirtualMachineImpl.c: resume() to be called.
 691  */
 692 static jboolean
 693 needBlockCommandLoop(HelperCommand *cmd) {
 694     if (cmd->commandKind == COMMAND_REPORT_EVENT_COMPOSITE
 695     && cmd->u.reportEventComposite.suspendPolicy == JDWP_SUSPEND_POLICY(ALL)) {
 696         debugMonitorEnter(blockCommandLoopLock);
 697         blockCommandLoop = JNI_TRUE;
 698         debugMonitorExit(blockCommandLoopLock);
 699 
 700         return JNI_TRUE;
 701     }
 702 
 703     return JNI_FALSE;
 704 }
 705 
 706 /*
 707  * Used by either ThreadReferenceImpl.c: resume() or
 708  * VirtualMachineImpl.c: resume() to resume commandLoop().
 709  */
 710 void
 711 unblockCommandLoop(void) {
 712     debugMonitorEnter(blockCommandLoopLock);
 713     blockCommandLoop = JNI_FALSE;
 714     debugMonitorNotifyAll(blockCommandLoopLock);
 715     debugMonitorExit(blockCommandLoopLock);
 716 }
 717 
 718 /*
 719  * The event helper thread. Dequeues commands and processes them.
 720  */
 721 static void JNICALL
 722 commandLoop(jvmtiEnv* jvmti_env, JNIEnv* jni_env, void* arg)
 723 {
 724     LOG_MISC(("Begin command loop thread"));
 725 
 726     while (JNI_TRUE) {
 727         HelperCommand *command = dequeueCommand();
 728         if (command != NULL) {
 729             /*
 730              * Setup for a potential doBlockCommand() call before calling
 731              * handleCommand() to prevent any races.
 732              */
 733             jboolean doBlock = needBlockCommandLoop(command);
 734             debugMonitorEnter(vmDeathLock);
 735             commandLoopEnteredVmDeathLock = JNI_TRUE;
 736             if (!gdata->vmDead) {
 737                 log_debugee_location("commandLoop(): command being handled", NULL, NULL, 0);
 738                 handleCommand(jni_env, command);
 739             }
 740             completeCommand(command);
 741             debugMonitorExit(vmDeathLock);
 742             commandLoopEnteredVmDeathLock = JNI_FALSE;
 743             /* if we just finished a suspend-all cmd, then we block here */
 744             if (doBlock) {
 745                 doBlockCommandLoop();
 746             }
 747         }
 748     }
 749     /* This loop never ends, even as connections come and go with server=y */
 750 }
 751 
 752 void
 753 eventHelper_initialize(jbyte sessionID)
 754 {
 755     jvmtiStartFunction func;
 756 
 757     currentSessionID = sessionID;
 758     holdEvents = JNI_FALSE;
 759     commandQueue.head = NULL;
 760     commandQueue.tail = NULL;
 761 
 762     commandQueueLock = debugMonitorCreate("JDWP Event Helper Queue Monitor");
 763     commandCompleteLock = debugMonitorCreate("JDWP Event Helper Completion Monitor");
 764     blockCommandLoopLock = debugMonitorCreate("JDWP Event Block CommandLoop Monitor");
 765     vmDeathLock = debugMonitorCreate("JDWP VM_DEATH CommandLoop Monitor");
 766 
 767     /* Start the event handler thread */
 768     func = &commandLoop;
 769     (void)spawnNewThread(func, NULL, COMMAND_LOOP_THREAD_NAME);
 770 }
 771 
 772 void
 773 eventHelper_reset(jbyte newSessionID)
 774 {
 775     debugMonitorEnter(commandQueueLock);
 776     currentSessionID = newSessionID;
 777     holdEvents = JNI_FALSE;
 778     debugMonitorNotifyAll(commandQueueLock);
 779     debugMonitorExit(commandQueueLock);
 780     unblockCommandLoop();
 781 }
 782 
 783 /*
 784  * Provide a means for threadControl to ensure that crucial locks are not
 785  * held by suspended threads.
 786  */
 787 void
 788 eventHelper_lock(void)
 789 {
 790     debugMonitorEnter(commandQueueLock);
 791     debugMonitorEnter(commandCompleteLock);
 792 }
 793 
 794 void
 795 eventHelper_unlock(void)
 796 {
 797     debugMonitorExit(commandCompleteLock);
 798     debugMonitorExit(commandQueueLock);
 799 }
 800 
 801 void commandLoop_exitVmDeathLockOnError()
 802 {
 803     const char* MSG_BASE = "exitVmDeathLockOnError: error in JVMTI %s: %d\n";
 804     jthread cur_thread = NULL;
 805     jvmtiThreadInfo thread_info;
 806     jvmtiError err = JVMTI_ERROR_NONE;
 807 
 808     err = JVMTI_FUNC_PTR(gdata->jvmti, GetCurrentThread)
 809               (gdata->jvmti, &cur_thread);
 810     if (err != JVMTI_ERROR_NONE) {
 811         LOG_ERROR((MSG_BASE, "GetCurrentThread", err));
 812         return;
 813     }
 814 
 815     err = JVMTI_FUNC_PTR(gdata->jvmti, GetThreadInfo)
 816               (gdata->jvmti, cur_thread, &thread_info);
 817     if (err != JVMTI_ERROR_NONE) {
 818         LOG_ERROR((MSG_BASE, "GetThreadInfo", err));
 819         return;
 820     }
 821     if (strcmp(thread_info.name, COMMAND_LOOP_THREAD_NAME) != 0) {
 822         return;
 823     }
 824     if (commandLoopEnteredVmDeathLock == JNI_TRUE) {
 825         debugMonitorExit(vmDeathLock);
 826         commandLoopEnteredVmDeathLock = JNI_FALSE;
 827     }
 828 }
 829 
 830 void
 831 commandLoop_sync(void)
 832 {
 833     debugMonitorEnter(vmDeathLock);
 834     debugMonitorExit(vmDeathLock);
 835 }
 836 
 837 /* Change all references to global in the EventInfo struct */
 838 static void
 839 saveEventInfoRefs(JNIEnv *env, EventInfo *evinfo)
 840 {
 841     jthread *pthread;
 842     jthread *pfiber;
 843     jclass *pclazz;
 844     jobject *pobject;
 845     jthread thread;
 846     jthread fiber;
 847     jclass clazz;
 848     jobject object;
 849     char sig;
 850 
 851     JNI_FUNC_PTR(env,ExceptionClear)(env);
 852 
 853     if ( evinfo->thread != NULL ) {
 854         pthread = &(evinfo->thread);
 855         thread = *pthread;
 856         *pthread = NULL;
 857         saveGlobalRef(env, thread, pthread);
 858     }
 859     if ( evinfo->fiber != NULL ) {
 860         pfiber = &(evinfo->fiber);
 861         fiber = *pfiber;
 862         *pfiber = NULL;
 863         saveGlobalRef(env, fiber, pfiber);
 864     }
 865     if ( evinfo->clazz != NULL ) {
 866         pclazz = &(evinfo->clazz);
 867         clazz = *pclazz;
 868         *pclazz = NULL;
 869         saveGlobalRef(env, clazz, pclazz);
 870     }
 871     if ( evinfo->object != NULL ) {
 872         pobject = &(evinfo->object);
 873         object = *pobject;
 874         *pobject = NULL;
 875         saveGlobalRef(env, object, pobject);
 876     }
 877 
 878     switch (evinfo->ei) {
 879         case EI_FIELD_MODIFICATION:
 880             if ( evinfo->u.field_modification.field_clazz != NULL ) {
 881                 pclazz = &(evinfo->u.field_modification.field_clazz);
 882                 clazz = *pclazz;
 883                 *pclazz = NULL;
 884                 saveGlobalRef(env, clazz, pclazz);
 885             }
 886             sig = evinfo->u.field_modification.signature_type;
 887             if ((sig == JDWP_TAG(ARRAY)) || (sig == JDWP_TAG(OBJECT))) {
 888                 if ( evinfo->u.field_modification.new_value.l != NULL ) {
 889                     pobject = &(evinfo->u.field_modification.new_value.l);
 890                     object = *pobject;
 891                     *pobject = NULL;
 892                     saveGlobalRef(env, object, pobject);
 893                 }
 894             }
 895             break;
 896         case EI_FIELD_ACCESS:
 897             if ( evinfo->u.field_access.field_clazz != NULL ) {
 898                 pclazz = &(evinfo->u.field_access.field_clazz);
 899                 clazz = *pclazz;
 900                 *pclazz = NULL;
 901                 saveGlobalRef(env, clazz, pclazz);
 902             }
 903             break;
 904         case EI_EXCEPTION:
 905             if ( evinfo->u.exception.catch_clazz != NULL ) {
 906                 pclazz = &(evinfo->u.exception.catch_clazz);
 907                 clazz = *pclazz;
 908                 *pclazz = NULL;
 909                 saveGlobalRef(env, clazz, pclazz);
 910             }
 911             break;
 912         default:
 913             break;
 914     }
 915 
 916     if (JNI_FUNC_PTR(env,ExceptionOccurred)(env)) {
 917         EXIT_ERROR(AGENT_ERROR_INVALID_EVENT_TYPE,"ExceptionOccurred");
 918     }
 919 }
 920 
 921 static void
 922 tossEventInfoRefs(JNIEnv *env, EventInfo *evinfo)
 923 {
 924     char sig;
 925     if ( evinfo->thread != NULL ) {
 926         tossGlobalRef(env, &(evinfo->thread));
 927     }
 928     if ( evinfo->fiber != NULL ) {
 929         tossGlobalRef(env, &(evinfo->fiber));
 930     }
 931     if ( evinfo->clazz != NULL ) {
 932         tossGlobalRef(env, &(evinfo->clazz));
 933     }
 934     if ( evinfo->object != NULL ) {
 935         tossGlobalRef(env, &(evinfo->object));
 936     }
 937     switch (evinfo->ei) {
 938         case EI_FIELD_MODIFICATION:
 939             if ( evinfo->u.field_modification.field_clazz != NULL ) {
 940                 tossGlobalRef(env, &(evinfo->u.field_modification.field_clazz));
 941             }
 942             sig = evinfo->u.field_modification.signature_type;
 943             if ((sig == JDWP_TAG(ARRAY)) || (sig == JDWP_TAG(OBJECT))) {
 944                 if ( evinfo->u.field_modification.new_value.l != NULL ) {
 945                     tossGlobalRef(env, &(evinfo->u.field_modification.new_value.l));
 946                 }
 947             }
 948             break;
 949         case EI_FIELD_ACCESS:
 950             if ( evinfo->u.field_access.field_clazz != NULL ) {
 951                 tossGlobalRef(env, &(evinfo->u.field_access.field_clazz));
 952             }
 953             break;
 954         case EI_EXCEPTION:
 955             if ( evinfo->u.exception.catch_clazz != NULL ) {
 956                 tossGlobalRef(env, &(evinfo->u.exception.catch_clazz));
 957             }
 958             break;
 959         default:
 960             break;
 961     }
 962 }
 963 
 964 struct bag *
 965 eventHelper_createEventBag(void)
 966 {
 967     return bagCreateBag(sizeof(CommandSingle), 5 /* events */ );
 968 }
 969 
 970 /* Return the combined suspend policy for the event set
 971  */
 972 static jboolean
 973 enumForCombinedSuspendPolicy(void *cv, void *arg)
 974 {
 975     CommandSingle *command = cv;
 976     jbyte thisPolicy;
 977     jbyte *policy = arg;
 978 
 979     switch(command->singleKind) {
 980         case COMMAND_SINGLE_EVENT:
 981             thisPolicy = command->u.eventCommand.suspendPolicy;
 982             break;
 983         case COMMAND_SINGLE_FRAME_EVENT:
 984             thisPolicy = command->u.frameEventCommand.suspendPolicy;
 985             break;
 986         default:
 987             thisPolicy = JDWP_SUSPEND_POLICY(NONE);
 988     }
 989     /* Expand running policy value if this policy demands it */
 990     if (*policy == JDWP_SUSPEND_POLICY(NONE)) {
 991         *policy = thisPolicy;
 992     } else if (*policy == JDWP_SUSPEND_POLICY(EVENT_THREAD)) {
 993         *policy = (thisPolicy == JDWP_SUSPEND_POLICY(ALL))?
 994                         thisPolicy : *policy;
 995     }
 996 
 997     /* Short circuit if we reached maximal suspend policy */
 998     if (*policy == JDWP_SUSPEND_POLICY(ALL)) {
 999         return JNI_FALSE;
1000     } else {
1001         return JNI_TRUE;
1002     }
1003 }
1004 
1005 /* Determine whether we are reporting VM death
1006  */
1007 static jboolean
1008 enumForVMDeath(void *cv, void *arg)
1009 {
1010     CommandSingle *command = cv;
1011     jboolean *reportingVMDeath = arg;
1012 
1013     if (command->singleKind == COMMAND_SINGLE_EVENT) {
1014         if (command->u.eventCommand.info.ei == EI_VM_DEATH) {
1015             *reportingVMDeath = JNI_TRUE;
1016             return JNI_FALSE;
1017         }
1018     }
1019     return JNI_TRUE;
1020 }
1021 
1022 struct singleTracker {
1023     ReportEventCompositeCommand *recc;
1024     int index;
1025 };
1026 
1027 static jboolean
1028 enumForCopyingSingles(void *command, void *tv)
1029 {
1030     struct singleTracker *tracker = (struct singleTracker *)tv;
1031     (void)memcpy(&tracker->recc->singleCommand[tracker->index++],
1032            command,
1033            sizeof(CommandSingle));
1034     return JNI_TRUE;
1035 }
1036 
1037 jbyte
1038 eventHelper_reportEvents(jbyte sessionID, struct bag *eventBag)
1039 {
1040     int size = bagSize(eventBag);
1041     jbyte suspendPolicy = JDWP_SUSPEND_POLICY(NONE);
1042     jboolean reportingVMDeath = JNI_FALSE;
1043     jboolean wait;
1044     int command_size;
1045 
1046     HelperCommand *command;
1047     ReportEventCompositeCommand *recc;
1048     struct singleTracker tracker;
1049 
1050     if (size == 0) {
1051         return suspendPolicy;
1052     }
1053     (void)bagEnumerateOver(eventBag, enumForCombinedSuspendPolicy, &suspendPolicy);
1054     (void)bagEnumerateOver(eventBag, enumForVMDeath, &reportingVMDeath);
1055 
1056     /*LINTED*/
1057     command_size = (int)(sizeof(HelperCommand) +
1058                          sizeof(CommandSingle)*(size-1));
1059     command = jvmtiAllocate(command_size);
1060     (void)memset(command, 0, command_size);
1061     command->commandKind = COMMAND_REPORT_EVENT_COMPOSITE;
1062     command->sessionID = sessionID;
1063     recc = &command->u.reportEventComposite;
1064     recc->suspendPolicy = suspendPolicy;
1065     recc->eventCount = size;
1066     tracker.recc = recc;
1067     tracker.index = 0;
1068     (void)bagEnumerateOver(eventBag, enumForCopyingSingles, &tracker);
1069 
1070     /*
1071      * We must wait if this thread (the event thread) is to be
1072      * suspended or if the VM is about to die. (Waiting in the latter
1073      * case ensures that we get the event out before the process dies.)
1074      */
1075     wait = (jboolean)((suspendPolicy != JDWP_SUSPEND_POLICY(NONE)) ||
1076                       reportingVMDeath);
1077     enqueueCommand(command, wait, reportingVMDeath);
1078     return suspendPolicy;
1079 }
1080 
1081 void
1082 eventHelper_recordEvent(EventInfo *evinfo, jint id, jbyte suspendPolicy,
1083                         struct bag *eventBag)
1084 {
1085     JNIEnv *env = getEnv();
1086     CommandSingle *command = bagAdd(eventBag);
1087     if (command == NULL) {
1088         EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"bagAdd(eventBag)");
1089     }
1090 
1091     command->singleKind = COMMAND_SINGLE_EVENT;
1092     command->u.eventCommand.suspendPolicy = suspendPolicy;
1093     command->u.eventCommand.id = id;
1094 
1095     /*
1096      * Copy the event into the command so that it can be used
1097      * asynchronously by the event helper thread.
1098      */
1099     (void)memcpy(&command->u.eventCommand.info, evinfo, sizeof(*evinfo));
1100     saveEventInfoRefs(env, &command->u.eventCommand.info);
1101 }
1102 
1103 void
1104 eventHelper_recordClassUnload(jint id, char *signature, struct bag *eventBag)
1105 {
1106     CommandSingle *command = bagAdd(eventBag);
1107     if (command == NULL) {
1108         EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"bagAdd(eventBag)");
1109     }
1110     command->singleKind = COMMAND_SINGLE_UNLOAD;
1111     command->u.unloadCommand.id = id;
1112     command->u.unloadCommand.classSignature = signature;
1113 }
1114 
1115 void
1116 eventHelper_recordFrameEvent(jint id, jbyte suspendPolicy, EventIndex ei,
1117                              jthread thread, jclass clazz,
1118                              jmethodID method, jlocation location,
1119                              int needReturnValue,
1120                              jvalue returnValue,
1121                              struct bag *eventBag)
1122 {
1123     JNIEnv *env = getEnv();
1124     FrameEventCommandSingle *frameCommand;
1125     CommandSingle *command = bagAdd(eventBag);
1126     jvmtiError err = JVMTI_ERROR_NONE;
1127     if (command == NULL) {
1128         EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"bagAdd(eventBag)");
1129     }
1130 
1131     command->singleKind = COMMAND_SINGLE_FRAME_EVENT;
1132     frameCommand = &command->u.frameEventCommand;
1133     frameCommand->suspendPolicy = suspendPolicy;
1134     frameCommand->id = id;
1135     frameCommand->ei = ei;
1136     saveGlobalRef(env, thread, &(frameCommand->thread));
1137     saveGlobalRef(env, clazz, &(frameCommand->clazz));
1138     frameCommand->method = method;
1139     frameCommand->location = location;
1140     if (needReturnValue) {
1141         err = methodReturnType(method, &frameCommand->typeKey);
1142         JDI_ASSERT(err == JVMTI_ERROR_NONE);
1143 
1144         /*
1145          * V or B C D F I J S Z L <classname> ;    [ ComponentType
1146          */
1147         if (isObjectTag(frameCommand->typeKey) &&
1148             returnValue.l != NULL) {
1149             saveGlobalRef(env, returnValue.l, &(frameCommand->returnValue.l));
1150         } else {
1151             frameCommand->returnValue = returnValue;
1152         }
1153     } else {
1154       /* This is not a JDWP METHOD_EXIT_WITH_RETURN_VALUE request,
1155        * so signal this by setting typeKey = 0 which is not
1156        * a legal typekey.
1157        */
1158        frameCommand->typeKey = 0;
1159     }
1160 }
1161 
1162 void
1163 eventHelper_reportInvokeDone(jbyte sessionID, jthread thread)
1164 {
1165     JNIEnv *env = getEnv();
1166     HelperCommand *command = jvmtiAllocate(sizeof(*command));
1167     if (command == NULL) {
1168         EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"HelperCommand");
1169     }
1170     (void)memset(command, 0, sizeof(*command));
1171     command->commandKind = COMMAND_REPORT_INVOKE_DONE;
1172     command->sessionID = sessionID;
1173     saveGlobalRef(env, thread, &(command->u.reportInvokeDone.thread));
1174     enqueueCommand(command, JNI_TRUE, JNI_FALSE);
1175 }
1176 
1177 /*
1178  * This, currently, cannot go through the normal event handling code
1179  * because the JVMTI event does not contain a thread.
1180  */
1181 void
1182 eventHelper_reportVMInit(JNIEnv *env, jbyte sessionID, jthread thread, jbyte suspendPolicy)
1183 {
1184     HelperCommand *command = jvmtiAllocate(sizeof(*command));
1185     if (command == NULL) {
1186         EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"HelperCommmand");
1187     }
1188     (void)memset(command, 0, sizeof(*command));
1189     command->commandKind = COMMAND_REPORT_VM_INIT;
1190     command->sessionID = sessionID;
1191     saveGlobalRef(env, thread, &(command->u.reportVMInit.thread));
1192     command->u.reportVMInit.suspendPolicy = suspendPolicy;
1193     enqueueCommand(command, JNI_TRUE, JNI_FALSE);
1194 }
1195 
1196 void
1197 eventHelper_suspendThread(jbyte sessionID, jthread thread)
1198 {
1199     JNIEnv *env = getEnv();
1200     HelperCommand *command = jvmtiAllocate(sizeof(*command));
1201     if (command == NULL) {
1202         EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"HelperCommmand");
1203     }
1204     (void)memset(command, 0, sizeof(*command));
1205     command->commandKind = COMMAND_SUSPEND_THREAD;
1206     command->sessionID = sessionID;
1207     saveGlobalRef(env, thread, &(command->u.suspendThread.thread));
1208     enqueueCommand(command, JNI_TRUE, JNI_FALSE);
1209 }