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