/** * This is the back-end implementation for disabling * (what are at the JDI level) EventRequests. */ static jboolean clearCommand(PacketInputStream *in, PacketOutputStream *out) { jvmtiError error; jdwpEvent eventType; HandlerID handlerID; EventIndex ei; eventType = inStream_readByte(in); if (inStream_error(in)) { return JNI_TRUE; } handlerID = inStream_readInt(in); if (inStream_error(in)) { return JNI_TRUE; } ei = jdwp2EventIndex(eventType); if (ei == 0) { /* NOTE: Clear command not yet spec'ed to return INVALID_EVENT_TYPE */ outStream_setError(out, JDWP_ERROR(INVALID_EVENT_TYPE)); return JNI_TRUE; } error = eventHandler_freeByID(ei, handlerID); if (error != JVMTI_ERROR_NONE) { outStream_setError(out, map2jdwpError(error)); } return JNI_TRUE; }
static jboolean clearAllBreakpoints(PacketInputStream *in, PacketOutputStream *out) { jvmtiError error; error = eventHandler_freeAll(EI_BREAKPOINT); if (error != JVMTI_ERROR_NONE) { outStream_setError(out, map2jdwpError(error)); } return JNI_TRUE; }
static void * newComponents(PacketOutputStream *out, jint length, size_t nbytes) { void *ptr = NULL; if ( length > 0 ) { ptr = jvmtiAllocate(length*((jint)nbytes)); if ( ptr == NULL ) { outStream_setError(out, JDWP_ERROR(OUT_OF_MEMORY)); } else { (void)memset(ptr, 0, length*nbytes); } } return ptr; }
static jboolean children(PacketInputStream *in, PacketOutputStream *out) { jint error; jint i; jint threadCount; jint groupCount; jthread *theThreads; jthread *theGroups; JNIEnv *env = getEnv(); jthreadGroup group = inStream_readThreadGroupRef(in); if (inStream_error(in)) { return JNI_TRUE; } error = jvmdi->GetThreadGroupChildren(group, &threadCount,&theThreads, &groupCount, &theGroups); if (error != JVMDI_ERROR_NONE) { outStream_setError(out, error); return JNI_TRUE; } /* Squish out all of the debugger-spawned threads */ threadCount = filterDebugThreads(theThreads, threadCount); outStream_writeInt(out, threadCount); for (i = 0; i < threadCount; i++) { WRITE_GLOBAL_REF(env, out, theThreads[i]); } outStream_writeInt(out, groupCount); for (i = 0; i < groupCount; i++) { WRITE_GLOBAL_REF(env, out, theGroups[i]); } jdwpFree(theGroups); jdwpFree(theThreads); return JNI_TRUE; }
/** * This is the back-end implementation for enabling * (what are at the JDI level) EventRequests. * * Allocate the event request handler (eventHandler). * Add any filters (explicit or implicit). * Install the handler. * Return the handlerID which is used to map subsequent * events to the EventRequest that created it. */ static jboolean setCommand(PacketInputStream *in, PacketOutputStream *out) { jdwpError serror; HandlerNode *node; HandlerID requestID = -1; jdwpEvent eventType; jbyte suspendPolicy; jint filterCount; EventIndex ei; node = NULL; eventType = inStream_readByte(in); if (inStream_error(in)) { return JNI_TRUE; } suspendPolicy = inStream_readByte(in); if (inStream_error(in)) { return JNI_TRUE; } filterCount = inStream_readInt(in); if (inStream_error(in)) { return JNI_TRUE; } ei = jdwp2EventIndex(eventType); if (ei == 0) { outStream_setError(out, JDWP_ERROR(INVALID_EVENT_TYPE)); return JNI_TRUE; } if (ei == EI_VM_INIT) { /* * VM is already initialized so there's no need to install a handler * for this event. However we need to allocate a requestID to send in * the reply to the debugger. */ serror = JDWP_ERROR(NONE); requestID = eventHandler_allocHandlerID(); } else { node = eventHandler_alloc(filterCount, ei, suspendPolicy); if (node == NULL) { outStream_setError(out, JDWP_ERROR(OUT_OF_MEMORY)); return JNI_TRUE; } if (eventType == JDWP_EVENT(METHOD_EXIT_WITH_RETURN_VALUE)) { node->needReturnValue = 1; } else { node->needReturnValue = 0; } serror = readAndSetFilters(getEnv(), in, node, filterCount); if (serror == JDWP_ERROR(NONE)) { jvmtiError error; error = eventHandler_installExternal(node); serror = map2jdwpError(error); if (serror == JDWP_ERROR(NONE)) { requestID = node->handlerID; } } } if (serror == JDWP_ERROR(NONE)) { (void)outStream_writeInt(out, requestID); } else { (void)eventHandler_free(node); outStream_setError(out, serror); } return JNI_TRUE; }
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()); } }