Пример #1
0
/*
 * TO DO: Support processing of replies through command input streams.
 */
void
inStream_init(PacketInputStream *stream, jdwpPacket packet)
{
    stream->packet = packet;
    stream->error = JDWP_ERROR(NONE);
    stream->left = packet.type.cmd.len;
    stream->current = packet.type.cmd.data; 
    stream->refs = bagCreateBag(sizeof(jobject), INITIAL_REF_ALLOC);
    if (stream->refs == NULL) {
        stream->error = JDWP_ERROR(OUT_OF_MEMORY);
    }
}
Пример #2
0
jdwpError 
outStream_writeValue(JNIEnv *env, PacketOutputStream *out, 
                     jbyte typeKey, jvalue value)
{
    if (typeKey == JDWP_TAG(OBJECT)) {
        (void)outStream_writeByte(out, specificTypeKey(env, value.l));
    } else {
        (void)outStream_writeByte(out, typeKey);
    }
    if (isObjectTag(typeKey)) {
        (void)outStream_writeObjectRef(env, out, value.l);
    } else {
        switch (typeKey) {
            case JDWP_TAG(BYTE):
                return outStream_writeByte(out, value.b);
    
            case JDWP_TAG(CHAR):
                return outStream_writeChar(out, value.c);
    
            case JDWP_TAG(FLOAT):
                return outStream_writeFloat(out, value.f);
    
            case JDWP_TAG(DOUBLE):
                return outStream_writeDouble(out, value.d);
    
            case JDWP_TAG(INT):
                return outStream_writeInt(out, value.i);
    
            case JDWP_TAG(LONG):
                return outStream_writeLong(out, value.j);
    
            case JDWP_TAG(SHORT):
                return outStream_writeShort(out, value.s);
    
            case JDWP_TAG(BOOLEAN):
                return outStream_writeBoolean(out, value.z);
    
            case JDWP_TAG(VOID):  /* happens with function return values */   
                /* write nothing */
                return JDWP_ERROR(NONE);

            default:
                EXIT_ERROR(AGENT_ERROR_INVALID_OBJECT,"Invalid type key");
                break;
        }
    }
    return JDWP_ERROR(NONE);
}
Пример #3
0
/*
 * Read an object from the stream. The ID used in the wire protocol
 * is converted to a reference which is returned. The reference is 
 * global and strong, but it should *not* be deleted by the caller
 * since it is freed when this stream is destroyed. 
 */
jobject 
inStream_readObjectRef(PacketInputStream *stream)
{
    jobject ref;
    jobject *refPtr;
    jlong id = inStream_readLong(stream);
    if (stream->error) {
        return NULL;
    } 
    if (id == NULL_OBJECT_ID) {
        return NULL;
    }

    ref = commonRef_idToRef(id);
    if (ref == NULL) {
        stream->error = JDWP_ERROR(INVALID_OBJECT);
        return NULL;
    }

    refPtr = bagAdd(stream->refs);
    if (refPtr == NULL) {
        commonRef_idToRef_delete(NULL, ref);
        return NULL;
    }

    *refPtr = ref;
    return ref;
}
/**
 * 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;
}
Пример #5
0
static void
commonInit(PacketOutputStream *stream)
{
    stream->current = &stream->initialSegment[0];
    stream->left = sizeof(stream->initialSegment);
    stream->segment = &stream->firstSegment;
    stream->segment->length = 0;
    stream->segment->data = &stream->initialSegment[0];
    stream->segment->next = NULL;
    stream->error = JDWP_ERROR(NONE);
    stream->sent = JNI_FALSE;
    stream->ids = bagCreateBag(sizeof(jlong), INITIAL_ID_ALLOC);
    if (stream->ids == NULL) {
        stream->error = JDWP_ERROR(OUT_OF_MEMORY);
    }
}
Пример #6
0
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));
    }
}
Пример #7
0
jvalue 
inStream_readValue(PacketInputStream *stream, jbyte *typeKeyPtr)
{
    jvalue value;
    jbyte typeKey = inStream_readByte(stream);
    if (stream->error) {
        value.j = 0L;
        return value;
    }

    if (isObjectTag(typeKey)) {
        value.l = inStream_readObjectRef(stream);
    } else {
        switch (typeKey) {
            case JDWP_TAG(BYTE):
                value.b = inStream_readByte(stream);
                break;
    
            case JDWP_TAG(CHAR):
                value.c = inStream_readChar(stream);
                break;
    
            case JDWP_TAG(FLOAT):
                value.f = inStream_readFloat(stream);
                break;
    
            case JDWP_TAG(DOUBLE):
                value.d = inStream_readDouble(stream);
                break;
    
            case JDWP_TAG(INT):
                value.i = inStream_readInt(stream);
                break;
    
            case JDWP_TAG(LONG):
                value.j = inStream_readLong(stream);
                break;
    
            case JDWP_TAG(SHORT):
                value.s = inStream_readShort(stream);
                break;
    
            case JDWP_TAG(BOOLEAN):
                value.z = inStream_readBoolean(stream);
                break;
            default:
                stream->error = JDWP_ERROR(INVALID_TAG);
                break;
        }
    }
    if (typeKeyPtr) {
        *typeKeyPtr = typeKey;
    }
    return value;
}
Пример #8
0
static jdwpError
launch(char *command, char *name, char *address)
{
    jint rc;
    char *buf;
    char *commandLine;
    int  len;

    /* Construct complete command line (all in UTF-8) */
    commandLine = jvmtiAllocate((int)strlen(command) +
                                 (int)strlen(name) +
                                 (int)strlen(address) + 3);
    if (commandLine == NULL) {
        return JDWP_ERROR(OUT_OF_MEMORY);
    }
    (void)strcpy(commandLine, command);
    (void)strcat(commandLine, " ");
    (void)strcat(commandLine, name);
    (void)strcat(commandLine, " ");
    (void)strcat(commandLine, address);

    /* Convert commandLine from UTF-8 to platform encoding */
    len = (int)strlen(commandLine);
    buf = jvmtiAllocate(len*3+3);
    (void)(gdata->npt->utf8ToPlatform)(gdata->npt->utf,
        (jbyte*)commandLine, len, buf, len*3+3);

    /* Exec commandLine */
    rc = dbgsysExec(buf);

    /* Free up buffers */
    jvmtiDeallocate(buf);
    jvmtiDeallocate(commandLine);

    /* And non-zero exit status means we had an error */
    if (rc != SYS_OK) {
        return JDWP_ERROR(TRANSPORT_INIT);
    }
    return JDWP_ERROR(NONE);
}
Пример #9
0
static jdwpError 
writeBytes(PacketOutputStream *stream, void *source, int size)
{
    jbyte *bytes = (jbyte *)source;

    if (stream->error) {
        return stream->error;
    }
    while (size > 0) {
        jint count;
        if (stream->left == 0) {
            jint segSize = SMALLEST(2 * stream->segment->length, MAX_SEGMENT_SIZE);
            jbyte *newSeg = jvmtiAllocate(segSize);
            struct PacketData *newHeader = jvmtiAllocate(sizeof(*newHeader));
            if ((newSeg == NULL) || (newHeader == NULL)) {
                jvmtiDeallocate(newSeg);
                jvmtiDeallocate(newHeader);
                stream->error = JDWP_ERROR(OUT_OF_MEMORY);
                return stream->error;
            }
            newHeader->length = 0;
            newHeader->data = newSeg;
            newHeader->next = NULL;
            stream->segment->next = newHeader;
            stream->segment = newHeader;
            stream->current = newHeader->data;
            stream->left = segSize;
        }
        count = SMALLEST(size, stream->left);
        (void)memcpy(stream->current, bytes, count);
        stream->current += count;
        stream->left -= count;
        stream->segment->length += count;
        size -= count;
        bytes += count;
    }
    return JDWP_ERROR(NONE);
}
Пример #10
0
static jint
outStream_send(PacketOutputStream *stream) {

    jint rc;
    jint len = 0;
    PacketData *segment;
    jbyte *data, *posP;

    /*
     * If there's only 1 segment then we just send the 
     * packet. 
     */
    if (stream->firstSegment.next == NULL) {
        stream->packet.type.cmd.len = 11 + stream->firstSegment.length;
        stream->packet.type.cmd.data = stream->firstSegment.data;
        rc = transport_sendPacket(&stream->packet);
        return rc;
    }

    /*
     * Multiple segments
     */
    len = 0; 
    segment = (PacketData *)&(stream->firstSegment);
    do {
        len += segment->length;
        segment = segment->next;
    } while (segment != NULL); 

    data = jvmtiAllocate(len);
    if (data == NULL) {
        return JDWP_ERROR(OUT_OF_MEMORY);
    }

    posP = data;
    segment = (PacketData *)&(stream->firstSegment);
    while (segment != NULL) {
        (void)memcpy(posP, segment->data, segment->length);
        posP += segment->length;
        segment = segment->next;
    }

    stream->packet.type.cmd.len = 11 + len;
    stream->packet.type.cmd.data = data;
    rc = transport_sendPacket(&stream->packet);
    stream->packet.type.cmd.data = NULL;
    jvmtiDeallocate(data); 

    return rc;
}
Пример #11
0
jdwpError 
outStream_writeObjectRef(JNIEnv *env, PacketOutputStream *stream, jobject val)
{
    jlong id;
    jlong *idPtr;

    if (stream->error) {
        return stream->error;
    }

    if (val == NULL) {
        id = NULL_OBJECT_ID;
    } else {
        /* Convert the object to an object id */
        id = commonRef_refToID(env, val);
        if (id == NULL_OBJECT_ID) {
            stream->error = JDWP_ERROR(OUT_OF_MEMORY);
            return stream->error;
        }

        /* Track the common ref in case we need to release it on a future error */
        idPtr = bagAdd(stream->ids);
        if (idPtr == NULL) {
            commonRef_release(env, id);
            stream->error = JDWP_ERROR(OUT_OF_MEMORY);
            return stream->error;
        } else {
            *idPtr = id;
        }

        /* Add the encoded object id to the stream */
        id = HOST_TO_JAVA_LONG(id);
    }

    return writeBytes(stream, &id, sizeof(id));
}
Пример #12
0
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;
}
Пример #13
0
jint
eventFilter_setCountFilter(HandlerNode *node, jint index, 
                           jint count)
{
    CountFilter *filter = &FILTER(node, index).u.Count;
    if (index >= FILTER_COUNT(node)) {
        return JVMDI_ERROR_ILLEGAL_ARGUMENT;
    }
    if (count <= 0) {
        return JDWP_ERROR(INVALID_COUNT);
    } else {
        FILTER(node, index).modifier = JDWP_REQUEST_MODIFIER(Count);
        filter->count = count;
        return JVMDI_ERROR_NONE;
    }
}
Пример #14
0
jthreadGroup 
inStream_readThreadGroupRef(PacketInputStream *stream)
{
    jobject object = inStream_readObjectRef(stream);
    if (object == NULL) {
        /* 
         * Could be error or just the null reference. In either case,
         * stop now.
         */
        return NULL;
    }
    if (!isThreadGroup(object)) {
        stream->error = JDWP_ERROR(INVALID_THREAD_GROUP);
        return NULL;
    }
    return object;
}
Пример #15
0
jarray 
inStream_readArrayRef(PacketInputStream *stream)
{
    jobject object = inStream_readObjectRef(stream);
    if (object == NULL) {
        /* 
         * Could be error or just the null reference. In either case,
         * stop now.
         */
        return NULL;
    }
    if (!isArray(object)) {
        stream->error = JDWP_ERROR(INVALID_ARRAY);
        return NULL;
    }
    return object;
}
Пример #16
0
jthread
inStream_readThreadRef(JNIEnv *env, PacketInputStream *stream)
{
    jobject object = inStream_readObjectRef(env, stream);
    if (object == NULL) {
        /*
         * Could be error or just the null reference. In either case,
         * stop now.
         */
        return NULL;
    }
    if (!isThread(object)) {
        stream->error = JDWP_ERROR(INVALID_THREAD);
        return NULL;
    }
    return object;
}
Пример #17
0
jclass 
inStream_readClassLoaderRef(PacketInputStream *stream)
{
    jobject object = inStream_readObjectRef(stream);
    if (object == NULL) {
        /* 
         * Could be error or just the null reference. In either case,
         * stop now.
         */
        return NULL;
    }
    if (!isClassLoader(object)) {
        stream->error = JDWP_ERROR(INVALID_CLASS_LOADER);
        return NULL;
    }
    return object;
}
Пример #18
0
jstring 
inStream_readStringRef(PacketInputStream *stream)
{
    jobject object = inStream_readObjectRef(stream);
    if (object == NULL) {
        /* 
         * Could be error or just the null reference. In either case,
         * stop now.
         */
        return NULL;
    }
    if (!isString(object)) {
        stream->error = JDWP_ERROR(INVALID_STRING);
        return NULL;
    }
    return object;
}
Пример #19
0
static jdwpError 
readBytes(PacketInputStream *stream, void *dest, int size) 
{
    if (stream->error) {
        return stream->error;
    }

    if (size > stream->left) {
	stream->error = JDWP_ERROR(INTERNAL);
	return stream->error;
    }

    if (dest) {
        (void)memcpy(dest, stream->current, size);
    }
    stream->current += size;
    stream->left -= size;

    return stream->error;
}
Пример #20
0
/*
 * 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."));
}
Пример #21
0
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 */
}
Пример #22
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());
    }
}
/**
 * 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;
}
Пример #25
0
jdwpError
transport_startTransport(jboolean isServer, char *name, char *address,
                         long timeout)
{
    jvmtiStartFunction func;
    jdwpTransportEnv *trans;
    char threadName[MAXPATHLEN + 100];
    jint err;
    jdwpError serror;

    /*
     * If the transport is already loaded then use it
     * Note: We're assuming here that we don't support multiple
     * transports - when we do then we need to handle the case
     * where the transport library only supports a single environment.
     * That probably means we have a bag a transport environments
     * to correspond to the transports bag.
     */
    if (transport != NULL) {
        trans = transport;
    } else {
        serror = loadTransport(name, &trans);
        if (serror != JDWP_ERROR(NONE)) {
            return serror;
        }
    }

    if (isServer) {

        char *retAddress;
        char *launchCommand;
        TransportInfo *info;
        jvmtiError error;
        int len;
        char* prop_value;

        info = jvmtiAllocate(sizeof(*info));
        if (info == NULL) {
            return JDWP_ERROR(OUT_OF_MEMORY);
        }
        info->name = jvmtiAllocate((int)strlen(name)+1);
        (void)strcpy(info->name, name);
        info->address = NULL;
        info->timeout = timeout;
        if (info->name == NULL) {
            serror = JDWP_ERROR(OUT_OF_MEMORY);
            goto handleError;
        }
        if (address != NULL) {
            info->address = jvmtiAllocate((int)strlen(address)+1);
            (void)strcpy(info->address, address);
            if (info->address == NULL) {
                serror = JDWP_ERROR(OUT_OF_MEMORY);
                goto handleError;
            }
        }

        info->transport = trans;

        err = (*trans)->StartListening(trans, address, &retAddress);
        if (err != JDWPTRANSPORT_ERROR_NONE) {
            printLastError(trans, err);
            serror = JDWP_ERROR(TRANSPORT_INIT);
            goto handleError;
        }

        /*
         * Record listener address in a system property
         */
        len = (int)strlen(name) + (int)strlen(retAddress) + 2; /* ':' and '\0' */
        prop_value = (char*)jvmtiAllocate(len);
        strcpy(prop_value, name);
        strcat(prop_value, ":");
        strcat(prop_value, retAddress);
        setTransportProperty(getEnv(), prop_value);
        jvmtiDeallocate(prop_value);


        (void)strcpy(threadName, "JDWP Transport Listener: ");
        (void)strcat(threadName, name);

        func = &acceptThread;
        error = spawnNewThread(func, (void*)info, threadName);
        if (error != JVMTI_ERROR_NONE) {
            serror = map2jdwpError(error);
            goto handleError;
        }

        launchCommand = debugInit_launchOnInit();
        if (launchCommand != NULL) {
            serror = launch(launchCommand, name, retAddress);
            if (serror != JDWP_ERROR(NONE)) {
                goto handleError;
            }
        } else {
            if ( ! gdata->quiet ) {
                TTY_MESSAGE(("Listening for transport %s at address: %s",
                    name, retAddress));
            }
        }
        return JDWP_ERROR(NONE);

handleError:
        jvmtiDeallocate(info->name);
        jvmtiDeallocate(info->address);
        jvmtiDeallocate(info);
    } else {
        /*
         * Note that we don't attempt to do a launch here. Launching
         * is currently supported only in server mode.
         */

        /*
         * If we're connecting to another process, there shouldn't be
         * any concurrent listens, so its ok if we block here in this
         * thread, waiting for the attach to finish.
         */
         err = (*trans)->Attach(trans, address, timeout, 0);
         if (err != JDWPTRANSPORT_ERROR_NONE) {
             printLastError(trans, err);
             serror = JDWP_ERROR(TRANSPORT_INIT);
             return serror;
         }

         /*
          * Start the transport loop in a separate thread
          */
         (void)strcpy(threadName, "JDWP Transport Listener: ");
         (void)strcat(threadName, name);

         func = &attachThread;
         err = spawnNewThread(func, (void*)trans, threadName);
         serror = map2jdwpError(err);
    }
    return serror;
}
Пример #26
0
/*
 * 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()"));
}
Пример #27
0
/*
 * loadTransport() is adapted from loadJVMHelperLib() in
 * JDK 1.2 javai.c v1.61
 */
static jdwpError
loadTransport(char *name, jdwpTransportEnv **transportPtr)
{
    JNIEnv                 *env;
    jdwpTransport_OnLoad_t  onLoad;
    void                   *handle;
    char                   *libdir;

    /* Make sure library name is not empty */
    if (name == NULL) {
        ERROR_MESSAGE(("library name is empty"));
        return JDWP_ERROR(TRANSPORT_LOAD);
    }

    /* First, look in sun.boot.library.path. This should find the standard
     *  dt_socket and dt_shmem transport libraries, or any library
     *  that was delivered with the J2SE.
     *  Note: Since 6819213 fixed, Java property sun.boot.library.path can
     *  contain multiple paths. Dll_dir is the first entry and
     *  -Dsun.boot.library.path entries are appended.
     */
    libdir = gdata->property_sun_boot_library_path;
    if (libdir == NULL) {
        ERROR_MESSAGE(("Java property sun.boot.library.path is not set"));
        return JDWP_ERROR(TRANSPORT_LOAD);
    }
    handle = loadTransportLibrary(libdir, name);
    if (handle == NULL) {
        /* Second, look along the path used by the native dlopen/LoadLibrary
         *  functions. This should effectively try and load the simple
         *  library name, which will cause the default system library
         *  search technique to happen.
         *  We should only reach here if the transport library wasn't found
         *  in the J2SE directory, e.g. it's a custom transport library
         *  not installed in the J2SE like dt_socket and dt_shmem is.
         *
         *  Note: Why not use java.library.path? Several reasons:
         *        a) This matches existing agentlib search
         *        b) These are technically not JNI libraries
         */
        handle = loadTransportLibrary("", name);
    }

    /* See if a library was found with this name */
    if (handle == NULL) {
        ERROR_MESSAGE(("transport library not found: %s", name));
        return JDWP_ERROR(TRANSPORT_LOAD);
    }

    /* Find the onLoad address */
    onLoad = findTransportOnLoad(handle);
    if (onLoad == NULL) {
        ERROR_MESSAGE(("transport library missing onLoad entry: %s", name));
        return JDWP_ERROR(TRANSPORT_LOAD);
    }

    /* Get transport interface */
    env = getEnv();
    if ( env != NULL ) {
        jdwpTransportEnv *t;
        JavaVM           *jvm;
        jint              ver;

        JNI_FUNC_PTR(env,GetJavaVM)(env, &jvm);
        ver = (*onLoad)(jvm, &callback, JDWPTRANSPORT_VERSION_1_0, &t);
        if (ver != JNI_OK) {
            switch (ver) {
                case JNI_ENOMEM :
                    ERROR_MESSAGE(("insufficient memory to complete initialization"));
                    break;

                case JNI_EVERSION :
                    ERROR_MESSAGE(("transport doesn't recognize version %x",
                        JDWPTRANSPORT_VERSION_1_0));
                    break;

                case JNI_EEXIST :
                    ERROR_MESSAGE(("transport doesn't support multiple environments"));
                    break;

                default:
                    ERROR_MESSAGE(("unrecognized error %d from transport", ver));
                    break;
            }

            return JDWP_ERROR(TRANSPORT_INIT);
        }
        *transportPtr = t;
    } else {
        return JDWP_ERROR(TRANSPORT_LOAD);
    }

    return JDWP_ERROR(NONE);
}
Пример #28
0
/*
 * Determine the component class by looking thru all classes for
 * one that has the signature of the component and the same class loadeer
 * as the array.  See JVM spec 5.3.3:
 *     If the component type is a reference type, C is marked as having
 *     been defined by the defining class loader of the component type.
 */
static jdwpError 
getComponentClass(JNIEnv *env, jclass arrayClass, char *componentSignature, 
                jclass *componentClassPtr) 
{
    jobject arrayClassLoader;
    jclass *classes;
    jint count;
    jclass componentClass = NULL;
    jdwpError serror;
    jvmtiError error;

    serror = JDWP_ERROR(NONE);
    
    error = classLoader(arrayClass, &arrayClassLoader);
    if (error != JVMTI_ERROR_NONE) {
        return map2jdwpError(error);
    }
    
    error = allLoadedClasses(&classes, &count);
    if (error != JVMTI_ERROR_NONE) {
        serror = map2jdwpError(error);
    } else {
        int i;
        for (i = 0; (i < count) && (componentClass == NULL); i++) {
            char *signature = NULL;
            jclass clazz = classes[i];
            jboolean match;
            jvmtiError error;

            /* signature must match */
            error = classSignature(clazz, &signature, NULL);
            if (error != JVMTI_ERROR_NONE) {
                serror = map2jdwpError(error);
                break;
            }
            match = strcmp(signature, componentSignature) == 0;
            jvmtiDeallocate(signature);

            /* if signature matches, get class loader to check if
             * it matches 
             */
            if (match) {
                jobject loader;
                error = classLoader(clazz, &loader);
                if (error != JVMTI_ERROR_NONE) {
                    return map2jdwpError(error);
                }
                match = isSameObject(env, loader, arrayClassLoader);
            }

            if (match) {
                componentClass = clazz;
            }
        }
        jvmtiDeallocate(classes);

        *componentClassPtr = componentClass;
    }

    if (serror == JDWP_ERROR(NONE) && componentClass == NULL) {
        /* per JVM spec, component class is always loaded 
         * before array class, so this should never occur.
         */
        serror = JDWP_ERROR(NOT_FOUND);
    }

    return serror;
}
Пример #29
0
void
inStream_clearError(PacketInputStream *stream) {
    stream->error = JDWP_ERROR(NONE);
}