/* Command reader */ static void JNICALL reader(jvmtiEnv* jvmti_env, JNIEnv* jni_env, void* arg) { jdwpPacket packet; jdwpCmdPacket *cmd; jboolean shouldListen = JNI_TRUE; LOG_MISC(("Begin reader thread")); while (shouldListen) { jint rc; rc = transport_receivePacket(&packet); /* I/O error or EOF */ if (rc != 0 || (rc == 0 && packet.type.cmd.len == 0)) { shouldListen = JNI_FALSE; notifyTransportError(); } else { cmd = &packet.type.cmd; LOG_MISC(("Command set %d, command %d", cmd->cmdSet, cmd->cmd)); /* * FIXME! We need to deal with high priority * packets and queue flushes! */ enqueue(&packet); shouldListen = !lastCommand(cmd); } } LOG_MISC(("End reader thread")); }
static void JNICALL attachThread(jvmtiEnv* jvmti_env, JNIEnv* jni_env, void* arg) { LOG_MISC(("Begin attach thread")); connectionInitiated((jdwpTransportEnv *)(void*)arg); LOG_MISC(("End attach thread")); }
static void JNICALL acceptThread(jvmtiEnv* jvmti_env, JNIEnv* jni_env, void* arg) { TransportInfo *info; jdwpTransportEnv *t; jdwpTransportError rc; LOG_MISC(("Begin accept thread")); info = (TransportInfo*)(void*)arg; t = info->transport; rc = (*t)->Accept(t, info->timeout, 0); /* System property no longer needed */ setTransportProperty(jni_env, NULL); if (rc != JDWPTRANSPORT_ERROR_NONE) { /* * If accept fails it probably means a timeout, or another fatal error * We thus exit the VM after stopping the listener. */ printLastError(t, rc); (*t)->StopListening(t); EXIT_ERROR(JVMTI_ERROR_NONE, "could not connect, timeout or fatal error"); } else { (*t)->StopListening(t); connectionInitiated(t); } LOG_MISC(("End accept thread")); }
/* All normal exit doors lead here */ void debugInit_exit(jvmtiError error, const char *msg) { enum exit_codes { EXIT_NO_ERRORS = 0, EXIT_JVMTI_ERROR = 1, EXIT_TRANSPORT_ERROR = 2 }; // Prepare to exit. Log error and finish logging LOG_MISC(("Exiting with error %s(%d): %s", jvmtiErrorText(error), error, ((msg == NULL) ? "" : msg))); // coredump requested by command line. Keep JVMTI data dirty if (error != JVMTI_ERROR_NONE && docoredump) { LOG_MISC(("Dumping core as requested by command line")); finish_logging(); abort(); } finish_logging(); // Cleanup the JVMTI if we have one if (gdata != NULL) { gdata->vmDead = JNI_TRUE; if (gdata->jvmti != NULL) { // Dispose of jvmti (gdata->jvmti becomes NULL) disposeEnvironment(gdata->jvmti); } } // We are here with no errors. Kill entire process and exit with zero exit code if (error == JVMTI_ERROR_NONE) { forceExit(EXIT_NO_ERRORS); return; } // No transport initilized. // As we don't have any details here exiting with separate exit code if (error == AGENT_ERROR_TRANSPORT_INIT) { forceExit(EXIT_TRANSPORT_ERROR); return; } // We have JVMTI error. Call hotspot jni_FatalError handler jniFatalError(NULL, msg, error, EXIT_JVMTI_ERROR); // hotspot calls os:abort() so we should never reach code below, // but guard against possible hotspot changes // Last chance to die, this kills the entire process. forceExit(EXIT_JVMTI_ERROR); }
void outStream_setError(PacketOutputStream *stream, jdwpError error) { if (stream->error == JDWP_ERROR(NONE)) { stream->error = error; LOG_MISC(("outStream_setError error=%s(%d)", jdwpErrorText(error), error)); } }
static void deleteNode(JNIEnv *env, RefNode *node) { LOG_MISC(("Freeing %d (%x)\n", (int)node->seqNum, node->ref)); if (node->isStrong) { JNI_FUNC_PTR(env,DeleteGlobalRef)(env, node->ref); } else { JNI_FUNC_PTR(env,DeleteWeakGlobalRef)(env, node->ref); } jvmtiDeallocate(node); }
static void signalInitComplete(void) { /* * Initialization is complete */ LOG_MISC(("signal initialization complete")); debugMonitorEnter(initMonitor); initComplete = JNI_TRUE; debugMonitorNotifyAll(initMonitor); debugMonitorExit(initMonitor); }
static void JNICALL cbEarlyVMInit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread) { LOG_CB(("cbEarlyVMInit")); if ( gdata->vmDead ) { EXIT_ERROR(AGENT_ERROR_INTERNAL,"VM dead at VM_INIT time"); } if (initOnStartup) initialize(env, thread, EI_VM_INIT); vmInitialized = JNI_TRUE; LOG_MISC(("END cbEarlyVMInit")); }
/* * Restore all static data to the initialized state so that another * debugger can connect properly later. */ void debugInit_reset(JNIEnv *env) { EnumerateArg arg; LOG_MISC(("debugInit_reset() beginning")); currentSessionID++; initComplete = JNI_FALSE; eventHandler_reset(currentSessionID); transport_reset(); debugDispatch_reset(); invoker_reset(); stepControl_reset(); threadControl_reset(); util_reset(); commonRef_reset(env); classTrack_reset(); /* * If this is a server, we are now ready to accept another connection. * If it's a client, then we've cleaned up some (more should be added * later) and we're done. */ if (isServer) { arg.isServer = JNI_TRUE; arg.error = JDWP_ERROR(NONE); arg.startCount = 0; (void)bagEnumerateOver(transports, startTransport, &arg); signalInitComplete(); transport_waitForConnection(); } else { signalInitComplete(); /* Why? */ } LOG_MISC(("debugInit_reset() completed.")); }
static void JNICALL cbEarlyVMDeath(jvmtiEnv *jvmti_env, JNIEnv *env) { LOG_CB(("cbEarlyVMDeath")); if ( gdata->vmDead ) { EXIT_ERROR(AGENT_ERROR_INTERNAL,"VM died more than once"); } disposeEnvironment(jvmti_env); gdata->jvmti = NULL; gdata->jvm = NULL; gdata->vmDead = JNI_TRUE; LOG_MISC(("END cbEarlyVMDeath")); }
static jboolean startTransport(void *item, void *arg) { TransportSpec *transport = item; EnumerateArg *enumArg = arg; jdwpError serror; LOG_MISC(("Begin startTransport")); serror = transport_startTransport(enumArg->isServer, transport->name, transport->address, transport->timeout); if (serror != JDWP_ERROR(NONE)) { ERROR_MESSAGE(("JDWP Transport %s failed to initialize, %s(%d)", transport->name, jdwpErrorText(serror), serror)); enumArg->error = serror; } else { /* (Don't overwrite any previous error) */ enumArg->startCount++; } LOG_MISC(("End startTransport")); return JNI_TRUE; /* Always continue, even if there was an error */ }
/* Delete a RefNode allocation, delete weak/global ref and clear tag */ static void deleteNode(JNIEnv *env, RefNode *node) { LOG_MISC(("Freeing %d (%x)\n", (int)node->seqNum, node->ref)); if ( node->ref != NULL ) { /* Clear tag */ (void)JVMTI_FUNC_PTR(gdata->jvmti,SetTag) (gdata->jvmti, node->ref, NULL_OBJECT_ID); if (node->isStrong) { JNI_FUNC_PTR(env,DeleteGlobalRef)(env, node->ref); } else { JNI_FUNC_PTR(env,DeleteWeakGlobalRef)(env, node->ref); } } gdata->objectsByIDcount--; jvmtiDeallocate(node); }
/* All normal exit doors lead here */ void debugInit_exit(jvmtiError error, const char *msg) { int exit_code = 0; /* Pick an error code */ if ( error != JVMTI_ERROR_NONE ) { exit_code = 1; if ( docoredump ) { finish_logging(exit_code); abort(); } } if ( msg==NULL ) { msg = ""; } LOG_MISC(("Exiting with error %s(%d): %s", jvmtiErrorText(error), error, msg)); gdata->vmDead = JNI_TRUE; /* Let's try and cleanup the JVMTI, if we even have one */ if ( gdata->jvmti != NULL ) { /* Dispose of jvmti (gdata->jvmti becomes NULL) */ disposeEnvironment(gdata->jvmti); } /* Finish up logging. We reach here if JDWP is doing the exiting. */ finish_logging(exit_code); /* Only first call matters */ /* Let's give the JNI a FatalError if non-exit 0, which is historic way */ if ( exit_code != 0 ) { JNIEnv *env = NULL; jniFatalError(env, msg, error, exit_code); } /* Last chance to die, this kills the entire process. */ forceExit(exit_code); }
/* * The event helper thread. Dequeues commands and processes them. */ static void JNICALL commandLoop(jvmtiEnv* jvmti_env, JNIEnv* jni_env, void* arg) { LOG_MISC(("Begin command loop thread")); while (JNI_TRUE) { HelperCommand *command = dequeueCommand(); if (command != NULL) { /* * Setup for a potential doBlockCommand() call before calling * handleCommand() to prevent any races. */ jboolean doBlock = needBlockCommandLoop(command); log_debugee_location("commandLoop(): command being handled", NULL, NULL, 0); handleCommand(jni_env, command); completeCommand(command); /* if we just finished a suspend-all cmd, then we block here */ if (doBlock) { doBlockCommandLoop(); } } } /* This loop never ends, even as connections come and go with server=y */ }
static void JNICALL cbEarlyException(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread, jmethodID method, jlocation location, jobject exception, jmethodID catch_method, jlocation catch_location) { jvmtiError error; jthrowable currentException; LOG_CB(("cbEarlyException: thread=%p", thread)); if ( gdata->vmDead ) { EXIT_ERROR(AGENT_ERROR_INTERNAL,"VM dead at initial Exception event"); } if (!vmInitialized) { LOG_MISC(("VM is not initialized yet")); return; } /* * We want to preserve any current exception that might get wiped * out during event handling (e.g. JNI calls). We have to rely on * space for the local reference on the current frame because * doing a PushLocalFrame here might itself generate an exception. */ currentException = JNI_FUNC_PTR(env,ExceptionOccurred)(env); JNI_FUNC_PTR(env,ExceptionClear)(env); if (initOnUncaught && catch_method == NULL) { LOG_MISC(("Initializing on uncaught exception")); initialize(env, thread, EI_EXCEPTION); } else if (initOnException != NULL) { jclass clazz; /* Get class of exception thrown */ clazz = JNI_FUNC_PTR(env,GetObjectClass)(env, exception); if ( clazz != NULL ) { char *signature = NULL; /* initing on throw, check */ error = classSignature(clazz, &signature, NULL); LOG_MISC(("Checking specific exception: looking for %s, got %s", initOnException, signature)); if ( (error==JVMTI_ERROR_NONE) && (strcmp(signature, initOnException) == 0)) { LOG_MISC(("Initializing on specific exception")); initialize(env, thread, EI_EXCEPTION); } else { error = AGENT_ERROR_INTERNAL; /* Just to cause restore */ } if ( signature != NULL ) { jvmtiDeallocate(signature); } } else { error = AGENT_ERROR_INTERNAL; /* Just to cause restore */ } /* If initialize didn't happen, we need to restore things */ if ( error != JVMTI_ERROR_NONE ) { /* * Restore exception state from before callback call */ LOG_MISC(("No initialization, didn't find right exception")); if (currentException != NULL) { JNI_FUNC_PTR(env,Throw)(env, currentException); } else { JNI_FUNC_PTR(env,ExceptionClear)(env); } } } LOG_MISC(("END cbEarlyException")); }
void debugLoop_run(void) { jboolean shouldListen; jdwpPacket p; jvmtiStartFunction func; /* Initialize all statics */ /* We may be starting a new connection after an error */ cmdQueue = NULL; cmdQueueLock = debugMonitorCreate("JDWP Command Queue Lock"); transportError = JNI_FALSE; shouldListen = JNI_TRUE; func = &reader; (void)spawnNewThread(func, NULL, "JDWP Command Reader"); standardHandlers_onConnect(); threadControl_onConnect(); /* Okay, start reading cmds! */ while (shouldListen) { if (!dequeue(&p)) { break; } if (p.type.cmd.flags & JDWPTRANSPORT_FLAGS_REPLY) { /* * Its a reply packet. */ continue; } else { /* * Its a cmd packet. */ jdwpCmdPacket *cmd = &p.type.cmd; PacketInputStream in; PacketOutputStream out; CommandHandler func; /* Should reply be sent to sender. * For error handling, assume yes, since * only VM/exit does not reply */ jboolean replyToSender = JNI_TRUE; /* * For VirtualMachine.Resume commands we hold the resumeLock * while executing and replying to the command. This ensures * that a Resume after VM_DEATH will be allowed to complete * before the thread posting the VM_DEATH continues VM * termination. */ if (resumeCommand(cmd)) { debugMonitorEnter(resumeLock); } /* Initialize the input and output streams */ inStream_init(&in, p); outStream_initReply(&out, inStream_id(&in)); LOG_MISC(("Command set %d, command %d", cmd->cmdSet, cmd->cmd)); func = debugDispatch_getHandler(cmd->cmdSet,cmd->cmd); if (func == NULL) { /* we've never heard of this, so I guess we * haven't implemented it. * Handle gracefully for future expansion * and platform / vendor expansion. */ outStream_setError(&out, JDWP_ERROR(NOT_IMPLEMENTED)); } else if (gdata->vmDead && ((cmd->cmdSet) != JDWP_COMMAND_SET(VirtualMachine))) { /* Protect the VM from calls while dead. * VirtualMachine cmdSet quietly ignores some cmds * after VM death, so, it sends it's own errors. */ outStream_setError(&out, JDWP_ERROR(VM_DEAD)); } else { /* Call the command handler */ replyToSender = func(&in, &out); } /* Reply to the sender */ if (replyToSender) { if (inStream_error(&in)) { outStream_setError(&out, inStream_error(&in)); } outStream_sendReply(&out); } /* * Release the resumeLock as the reply has been posted. */ if (resumeCommand(cmd)) { debugMonitorExit(resumeLock); } inStream_destroy(&in); outStream_destroy(&out); shouldListen = !lastCommand(cmd); } } threadControl_onDisconnect(); standardHandlers_onDisconnect(); /* * Cut off the transport immediately. This has the effect of * cutting off any events that the eventHelper thread might * be trying to send. */ transport_close(); debugMonitorDestroy(cmdQueueLock); /* Reset for a new connection to this VM if it's still alive */ if ( ! gdata->vmDead ) { debugInit_reset(getEnv()); } }
/* OnLoad startup: * Returning JNI_ERR will cause the java_g VM to core dump, be careful. */ JNIEXPORT jint JNICALL DEF_Agent_OnLoad(JavaVM *vm, char *options, void *reserved) { jvmtiError error; jvmtiCapabilities needed_capabilities; jvmtiCapabilities potential_capabilities; jint jvmtiCompileTimeMajorVersion; jint jvmtiCompileTimeMinorVersion; jint jvmtiCompileTimeMicroVersion; /* See if it's already loaded */ if ( gdata!=NULL && gdata->isLoaded==JNI_TRUE ) { ERROR_MESSAGE(("Cannot load this JVM TI agent twice, check your java command line for duplicate jdwp options.")); return JNI_ERR; } /* If gdata is defined and the VM died, why are we here? */ if ( gdata!=NULL && gdata->vmDead ) { ERROR_MESSAGE(("JDWP unable to load, VM died")); return JNI_ERR; } /* Get global data area */ gdata = get_gdata(); if (gdata == NULL) { ERROR_MESSAGE(("JDWP unable to allocate memory")); return JNI_ERR; } gdata->isLoaded = JNI_TRUE; /* Start filling in gdata */ gdata->jvm = vm; vmInitialized = JNI_FALSE; gdata->vmDead = JNI_FALSE; /* Get the JVMTI Env, IMPORTANT: Do this first! For jvmtiAllocate(). */ error = JVM_FUNC_PTR(vm,GetEnv) (vm, (void **)&(gdata->jvmti), JVMTI_VERSION_1); if (error != JNI_OK) { ERROR_MESSAGE(("JDWP unable to access JVMTI Version 1 (0x%x)," " is your J2SE a 1.5 or newer version?" " JNIEnv's GetEnv() returned %d", JVMTI_VERSION_1, error)); forceExit(1); /* Kill entire process, no core dump */ } /* Check to make sure the version of jvmti.h we compiled with * matches the runtime version we are using. */ jvmtiCompileTimeMajorVersion = ( JVMTI_VERSION & JVMTI_VERSION_MASK_MAJOR ) >> JVMTI_VERSION_SHIFT_MAJOR; jvmtiCompileTimeMinorVersion = ( JVMTI_VERSION & JVMTI_VERSION_MASK_MINOR ) >> JVMTI_VERSION_SHIFT_MINOR; jvmtiCompileTimeMicroVersion = ( JVMTI_VERSION & JVMTI_VERSION_MASK_MICRO ) >> JVMTI_VERSION_SHIFT_MICRO; /* Check for compatibility */ if ( !compatible_versions(jvmtiMajorVersion(), jvmtiMinorVersion(), jvmtiCompileTimeMajorVersion, jvmtiCompileTimeMinorVersion) ) { ERROR_MESSAGE(("This jdwp native library will not work with this VM's " "version of JVMTI (%d.%d.%d), it needs JVMTI %d.%d[.%d].", jvmtiMajorVersion(), jvmtiMinorVersion(), jvmtiMicroVersion(), jvmtiCompileTimeMajorVersion, jvmtiCompileTimeMinorVersion, jvmtiCompileTimeMicroVersion)); /* Do not let VM get a fatal error, we don't want a core dump here. */ forceExit(1); /* Kill entire process, no core dump wanted */ } /* Parse input options */ if (!parseOptions(options)) { /* No message necessary, should have been printed out already */ /* Do not let VM get a fatal error, we don't want a core dump here. */ forceExit(1); /* Kill entire process, no core dump wanted */ } LOG_MISC(("Onload: %s", options)); /* Get potential capabilities */ (void)memset(&potential_capabilities,0,sizeof(potential_capabilities)); error = JVMTI_FUNC_PTR(gdata->jvmti,GetPotentialCapabilities) (gdata->jvmti, &potential_capabilities); if (error != JVMTI_ERROR_NONE) { ERROR_MESSAGE(("JDWP unable to get potential JVMTI capabilities: %s(%d)", jvmtiErrorText(error), error)); return JNI_ERR; } /* Fill in ones that we must have */ (void)memset(&needed_capabilities,0,sizeof(needed_capabilities)); needed_capabilities.can_access_local_variables = 1; needed_capabilities.can_generate_single_step_events = 1; needed_capabilities.can_generate_exception_events = 1; needed_capabilities.can_generate_frame_pop_events = 1; needed_capabilities.can_generate_breakpoint_events = 1; needed_capabilities.can_suspend = 1; needed_capabilities.can_generate_method_entry_events = 1; needed_capabilities.can_generate_method_exit_events = 1; needed_capabilities.can_generate_garbage_collection_events = 1; needed_capabilities.can_maintain_original_method_order = 1; needed_capabilities.can_generate_monitor_events = 1; needed_capabilities.can_tag_objects = 1; /* And what potential ones that would be nice to have */ needed_capabilities.can_force_early_return = potential_capabilities.can_force_early_return; needed_capabilities.can_generate_field_modification_events = potential_capabilities.can_generate_field_modification_events; needed_capabilities.can_generate_field_access_events = potential_capabilities.can_generate_field_access_events; needed_capabilities.can_get_bytecodes = potential_capabilities.can_get_bytecodes; needed_capabilities.can_get_synthetic_attribute = potential_capabilities.can_get_synthetic_attribute; needed_capabilities.can_get_owned_monitor_info = potential_capabilities.can_get_owned_monitor_info; needed_capabilities.can_get_current_contended_monitor = potential_capabilities.can_get_current_contended_monitor; needed_capabilities.can_get_monitor_info = potential_capabilities.can_get_monitor_info; needed_capabilities.can_pop_frame = potential_capabilities.can_pop_frame; needed_capabilities.can_redefine_classes = potential_capabilities.can_redefine_classes; needed_capabilities.can_redefine_any_class = potential_capabilities.can_redefine_any_class; needed_capabilities.can_get_owned_monitor_stack_depth_info = potential_capabilities.can_get_owned_monitor_stack_depth_info; needed_capabilities.can_get_constant_pool = potential_capabilities.can_get_constant_pool; { needed_capabilities.can_get_source_debug_extension = 1; needed_capabilities.can_get_source_file_name = 1; needed_capabilities.can_get_line_numbers = 1; needed_capabilities.can_signal_thread = potential_capabilities.can_signal_thread; } /* Add the capabilities */ error = JVMTI_FUNC_PTR(gdata->jvmti,AddCapabilities) (gdata->jvmti, &needed_capabilities); if (error != JVMTI_ERROR_NONE) { ERROR_MESSAGE(("JDWP unable to get necessary JVMTI capabilities.")); forceExit(1); /* Kill entire process, no core dump wanted */ } /* Initialize event number mapping tables */ eventIndexInit(); /* Set the initial JVMTI event notifications */ error = set_event_notification(JVMTI_ENABLE, EI_VM_DEATH); if (error != JVMTI_ERROR_NONE) { return JNI_ERR; } error = set_event_notification(JVMTI_ENABLE, EI_VM_INIT); if (error != JVMTI_ERROR_NONE) { return JNI_ERR; } if (initOnUncaught || (initOnException != NULL)) { error = set_event_notification(JVMTI_ENABLE, EI_EXCEPTION); if (error != JVMTI_ERROR_NONE) { return JNI_ERR; } } /* Set callbacks just for 3 functions */ (void)memset(&(gdata->callbacks),0,sizeof(gdata->callbacks)); gdata->callbacks.VMInit = &cbEarlyVMInit; gdata->callbacks.VMDeath = &cbEarlyVMDeath; gdata->callbacks.Exception = &cbEarlyException; error = JVMTI_FUNC_PTR(gdata->jvmti,SetEventCallbacks) (gdata->jvmti, &(gdata->callbacks), sizeof(gdata->callbacks)); if (error != JVMTI_ERROR_NONE) { ERROR_MESSAGE(("JDWP unable to set JVMTI event callbacks: %s(%d)", jvmtiErrorText(error), error)); return JNI_ERR; } LOG_MISC(("OnLoad: DONE")); return JNI_OK; }
/* * Initialize debugger back end modules */ static void initialize(JNIEnv *env, jthread thread, EventIndex triggering_ei) { jvmtiError error; EnumerateArg arg; jbyte suspendPolicy; LOG_MISC(("Begin initialize()")); currentSessionID = 0; initComplete = JNI_FALSE; if ( gdata->vmDead ) { EXIT_ERROR(AGENT_ERROR_INTERNAL,"VM dead at initialize() time"); } /* Turn off the initial JVMTI event notifications */ error = set_event_notification(JVMTI_DISABLE, EI_EXCEPTION); if (error != JVMTI_ERROR_NONE) { EXIT_ERROR(error, "unable to disable JVMTI event notification"); } error = set_event_notification(JVMTI_DISABLE, EI_VM_INIT); if (error != JVMTI_ERROR_NONE) { EXIT_ERROR(error, "unable to disable JVMTI event notification"); } error = set_event_notification(JVMTI_DISABLE, EI_VM_DEATH); if (error != JVMTI_ERROR_NONE) { EXIT_ERROR(error, "unable to disable JVMTI event notification"); } /* Remove initial event callbacks */ (void)memset(&(gdata->callbacks),0,sizeof(gdata->callbacks)); error = JVMTI_FUNC_PTR(gdata->jvmti,SetEventCallbacks) (gdata->jvmti, &(gdata->callbacks), sizeof(gdata->callbacks)); if (error != JVMTI_ERROR_NONE) { EXIT_ERROR(error, "unable to clear JVMTI callbacks"); } commonRef_initialize(); util_initialize(env); threadControl_initialize(); stepControl_initialize(); invoker_initialize(); debugDispatch_initialize(); classTrack_initialize(env); debugLoop_initialize(); initMonitor = debugMonitorCreate("JDWP Initialization Monitor"); /* * Initialize transports */ arg.isServer = isServer; arg.error = JDWP_ERROR(NONE); arg.startCount = 0; transport_initialize(); (void)bagEnumerateOver(transports, startTransport, &arg); /* * Exit with an error only if * 1) none of the transports was successfully started, and * 2) the application has not yet started running */ if ((arg.error != JDWP_ERROR(NONE)) && (arg.startCount == 0) && initOnStartup) { EXIT_ERROR(map2jvmtiError(arg.error), "No transports initialized"); } eventHandler_initialize(currentSessionID); signalInitComplete(); transport_waitForConnection(); suspendPolicy = suspendOnInit ? JDWP_SUSPEND_POLICY(ALL) : JDWP_SUSPEND_POLICY(NONE); if (triggering_ei == EI_VM_INIT) { LOG_MISC(("triggering_ei == EI_VM_INIT")); eventHelper_reportVMInit(env, currentSessionID, thread, suspendPolicy); } else { /* * TO DO: Kludgy way of getting the triggering event to the * just-attached debugger. It would be nice to make this a little * cleaner. There is also a race condition where other events * can get in the queue (from other not-yet-suspended threads) * before this one does. (Also need to handle allocation error below?) */ EventInfo info; struct bag *initEventBag; LOG_MISC(("triggering_ei != EI_VM_INIT")); initEventBag = eventHelper_createEventBag(); (void)memset(&info,0,sizeof(info)); info.ei = triggering_ei; eventHelper_recordEvent(&info, 0, suspendPolicy, initEventBag); (void)eventHelper_reportEvents(currentSessionID, initEventBag); bagDestroyBag(initEventBag); } if ( gdata->vmDead ) { EXIT_ERROR(AGENT_ERROR_INTERNAL,"VM dead before initialize() completes"); } LOG_MISC(("End initialize()")); }