/**
 * 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
reflectedType(PacketInputStream *in, PacketOutputStream *out)
{
    jbyte tag;
    jobject object;
    JNIEnv *env;

    env = getEnv();

    object = inStream_readObjectRef(env, in);
    if (inStream_error(in)) {
        return JNI_TRUE;
    }

    /*
     * In our implementation, the reference type id is the same as the
     * class object id, so we bounce it right back.
     *
     */

    tag = referenceTypeTag(object);
    (void)outStream_writeByte(out, tag);
    (void)outStream_writeObjectRef(env, out, object);

    return JNI_TRUE;
}
Example #3
0
static jboolean
length(PacketInputStream *in, PacketOutputStream *out)
{
    JNIEnv *env = getEnv();
    jsize arrayLength;

    jarray  array = inStream_readArrayRef(env, in);
    if (inStream_error(in)) {
        return JNI_TRUE;
    }

    arrayLength = JNI_FUNC_PTR(env,GetArrayLength)(env, array);
    (void)outStream_writeInt(out, arrayLength);
    return JNI_TRUE;
}
static jboolean 
parent(PacketInputStream *in, PacketOutputStream *out) 
{
    JNIEnv *env = getEnv();
    JVMDI_thread_group_info info;

    jthreadGroup group = inStream_readThreadGroupRef(in);
    if (inStream_error(in)) {
        return JNI_TRUE;
    }

    threadGroupInfo(group, &info);
    WRITE_GLOBAL_REF(env, out, info.parent);

    jdwpFree(info.name);
    return JNI_TRUE;
}
static jboolean 
name(PacketInputStream *in, PacketOutputStream *out) 
{
    JNIEnv *env = getEnv();
    JVMDI_thread_group_info info;

    jthreadGroup group = inStream_readThreadGroupRef(in);
    if (inStream_error(in)) {
        return JNI_TRUE;
    }

    threadGroupInfo(group, &info);
    outStream_writeString(out, info.name);

    (*env)->DeleteGlobalRef(env, info.parent);
    jdwpFree(info.name);
    return JNI_TRUE;
}
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;
}
/**
 * Take JDWP "modifiers" (which are JDI explicit filters, like
 * addCountFilter(), and implicit filters, like the LocationOnly
 * filter that goes with breakpoints) and add them as filters
 * (eventFilter) to the HandlerNode (eventHandler).
 */
static jdwpError
readAndSetFilters(JNIEnv *env, PacketInputStream *in, HandlerNode *node,
                  jint filterCount)
{
    int i;
    jdwpError serror = JDWP_ERROR(NONE);

    for (i = 0; i < filterCount; ++i) {

        jbyte modifier;

        modifier = inStream_readByte(in);
        if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) )
            break;

        switch (modifier) {

            case JDWP_REQUEST_MODIFIER(Conditional): {
                jint exprID;
                exprID = inStream_readInt(in);
                if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) )
                    break;
                serror = map2jdwpError(
                        eventFilter_setConditionalFilter(node, i, exprID));
                break;
            }

            case JDWP_REQUEST_MODIFIER(Count): {
                jint count;
                count = inStream_readInt(in);
                if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) )
                    break;
                serror = map2jdwpError(
                        eventFilter_setCountFilter(node, i, count));
                break;
            }

            case JDWP_REQUEST_MODIFIER(ThreadOnly): {
                jthread thread;
                thread = inStream_readThreadRef(env, in);
                if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) )
                    break;
                serror = map2jdwpError(
                        eventFilter_setThreadOnlyFilter(node, i, thread));
                break;
            }

            case JDWP_REQUEST_MODIFIER(LocationOnly): {
                jbyte tag;
                jclass clazz;
                jmethodID method;
                jlocation location;
                tag = inStream_readByte(in); /* not currently used */
                tag = tag; /* To shut up lint */
                if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) )
                    break;
                clazz = inStream_readClassRef(env, in);
                if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) )
                    break;
                method = inStream_readMethodID(in);
                if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) )
                    break;
                location = inStream_readLocation(in);
                if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) )
                    break;
                serror = map2jdwpError(
                        eventFilter_setLocationOnlyFilter(node, i, clazz, method, location));
                break;
            }

            case JDWP_REQUEST_MODIFIER(FieldOnly): {
                jclass clazz;
                jfieldID field;
                clazz = inStream_readClassRef(env, in);
                if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) )
                    break;
                field = inStream_readFieldID(in);
                if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) )
                    break;
                serror = map2jdwpError(
                        eventFilter_setFieldOnlyFilter(node, i, clazz, field));
                break;
            }

            case JDWP_REQUEST_MODIFIER(ClassOnly): {
                jclass clazz;
                clazz = inStream_readClassRef(env, in);
                if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) )
                    break;
                serror = map2jdwpError(
                        eventFilter_setClassOnlyFilter(node, i, clazz));
                break;
            }

            case JDWP_REQUEST_MODIFIER(ExceptionOnly): {
                jclass exception;
                jboolean caught;
                jboolean uncaught;
                exception = inStream_readClassRef(env, in);
                if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) )
                    break;
                caught = inStream_readBoolean(in);
                if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) )
                    break;
                uncaught = inStream_readBoolean(in);
                if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) )
                    break;
                serror = map2jdwpError(
                        eventFilter_setExceptionOnlyFilter(node, i,
                                             exception, caught, uncaught));
                break;
            }

            case JDWP_REQUEST_MODIFIER(InstanceOnly): {
                jobject instance;
                instance = inStream_readObjectRef(env, in);
                if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) )
                    break;
                serror = map2jdwpError(
                        eventFilter_setInstanceOnlyFilter(node, i, instance));
                break;
            }

            case JDWP_REQUEST_MODIFIER(ClassMatch): {
                char *pattern;
                pattern = inStream_readString(in);
                if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) )
                    break;
                serror = map2jdwpError(
                        eventFilter_setClassMatchFilter(node, i,
                                                                pattern));
                break;
            }

            case JDWP_REQUEST_MODIFIER(ClassExclude): {
                char *pattern;
                pattern = inStream_readString(in);
                if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) )
                    break;
                serror = map2jdwpError(
                        eventFilter_setClassExcludeFilter(node, i, pattern));
                break;
            }
            case JDWP_REQUEST_MODIFIER(Step): {
                jthread thread;
                jint size;
                jint depth;
                thread = inStream_readThreadRef(env, in);
                if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) )
                    break;
                size = inStream_readInt(in);
                if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) )
                    break;
                depth = inStream_readInt(in);
                if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) )
                    break;
                serror = map2jdwpError(
                      eventFilter_setStepFilter(node, i, thread, size, depth));
                break;
            }
            case JDWP_REQUEST_MODIFIER(SourceNameMatch): {
                char *sourceNamePattern;
                sourceNamePattern = inStream_readString(in);
                if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) ) {
                    break;
                }
                serror = map2jdwpError(
                        eventFilter_setSourceNameMatchFilter(node, i, sourceNamePattern));
                break;
            }

            default:
                serror = JDWP_ERROR(ILLEGAL_ARGUMENT);
                break;
        }
        if ( serror != JDWP_ERROR(NONE) )
            break;
    }
    return serror;
}
/**
 * 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;
}
Example #9
0
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());
    }
}