Exemple #1
0
/*
 * Given an object ID obtained from the debugger front end, return a
 * strong, global reference to that object (or NULL if the object
 * has been collected). The reference can then be used for JNI and 
 * JVMTI calls. Caller is resposible for deleting the returned reference.
 */
jobject 
commonRef_idToRef(JNIEnv *env, jlong id) 
{
    jobject ref;
    
    ref = NULL;
    debugMonitorEnter(gdata->refLock); {
        RefNode *node;

        node = findNodeByID(env, id);
        if (node != NULL) {
            if (node->isStrong) {
                saveGlobalRef(env, node->ref, &ref);
            } else {
                jobject lref;
                
                lref = JNI_FUNC_PTR(env,NewLocalRef)(env, node->ref);
                if ( lref == NULL ) {
                    /* Object was GC'd shortly after we found the node */
                    deleteNodeByID(env, node->seqNum, ALL_REFS);
                } else {
                    saveGlobalRef(env, node->ref, &ref);
                    JNI_FUNC_PTR(env,DeleteLocalRef)(env, lref);
                }
            }
        }
    } debugMonitorExit(gdata->refLock);
    return ref;
}
Exemple #2
0
static RefNode *
createNode(JNIEnv *env, jobject ref) 
{
    RefNode *node;
    jobject weakRef;
    
    weakRef = JNI_FUNC_PTR(env,NewWeakGlobalRef)(env, ref);
    if (weakRef == NULL) {
        return NULL;
    }
                                                       
    /*
     * TO DO: Consider fewer allocations of bigger chunks if 
     * performance is a problem here.
     */
    node = jvmtiAllocate(sizeof(*node));     
    if (node == NULL) {
        JNI_FUNC_PTR(env,DeleteWeakGlobalRef)(env, weakRef);
        return NULL;
    }
    
    node->ref = weakRef;
    node->isStrong = JNI_FALSE;
    node->count = 1;
    node->seqNum = newSeqNum();
    return node;
}
Exemple #3
0
/* Change a RefNode to have a strong reference */
static jobject
strengthenNode(JNIEnv *env, RefNode *node) 
{
    if (!node->isStrong) {
        jobject strongRef;
        
        strongRef = JNI_FUNC_PTR(env,NewGlobalRef)(env, node->ref);
        /*
         * NewGlobalRef on a weak ref will return NULL if the weak 
         * reference has been collected or if out of memory. 
         * We need to distinguish those two occurrences.
         */
        if ((strongRef == NULL) && !isSameObject(env, node->ref, NULL)) {
            EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"NewGlobalRef");
        } 
        if (strongRef != NULL) {
            JNI_FUNC_PTR(env,DeleteWeakGlobalRef)(env, node->ref);
            node->ref      = strongRef;
            node->isStrong = JNI_TRUE; 
        }
        return strongRef;
    } else {
        return node->ref;
    }
}
Exemple #4
0
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);
}
Exemple #5
0
static jweak
weakenNode(JNIEnv *env, RefNode *node) 
{
    if (node->isStrong) {
        jweak weakRef = JNI_FUNC_PTR(env,NewWeakGlobalRef)(env, node->ref);
        if (weakRef != NULL) {
            JNI_FUNC_PTR(env,DeleteGlobalRef)(env, node->ref);
            node->ref = weakRef;
	    node->isStrong = JNI_FALSE;
        }
        return weakRef;
    } else {
        return node->ref;
    }
}
    WITH_LOCAL_REFS(env, length) {

        int i;
        jobject component;

        for (i = 0; i < length; i++) {
            component = JNI_FUNC_PTR(env,GetObjectArrayElement)(env, array, index + i);
            if (JNI_FUNC_PTR(env,ExceptionOccurred)(env)) {
                /* cleared by caller */
                break;
            }
            (void)outStream_writeByte(out, specificTypeKey(env, component));
            (void)outStream_writeObjectRef(env, out, component);
        }

    } END_WITH_LOCAL_REFS(env);
Exemple #7
0
/* 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);
}
Exemple #8
0
/* Create a fresh RefNode structure, create a weak ref and tag the object */
static RefNode *
createNode(JNIEnv *env, jobject ref) 
{
    RefNode   *node;
    jobject    weakRef;
    jvmtiError error;
  
    /* Could allocate RefNode's in blocks, not sure it would help much */
    node = (RefNode*)jvmtiAllocate((int)sizeof(RefNode));     
    if (node == NULL) {
        return NULL;
    }
    
    /* Create weak reference to make sure we have a reference */
    weakRef = JNI_FUNC_PTR(env,NewWeakGlobalRef)(env, ref);
    if (weakRef == NULL) {
        jvmtiDeallocate(node);
        return NULL;
    }

    /* Set tag on weakRef */
    error = JVMTI_FUNC_PTR(gdata->jvmti, SetTag)
                          (gdata->jvmti, weakRef, ptr_to_jlong(node));
    if ( error != JVMTI_ERROR_NONE ) {
        JNI_FUNC_PTR(env,DeleteWeakGlobalRef)(env, weakRef);
        jvmtiDeallocate(node);
        return NULL;
    }

    /* Fill in RefNode */
    node->ref      = weakRef;
    node->isStrong = JNI_FALSE;
    node->count    = 1;
    node->seqNum   = newSeqNum();

    /* Count RefNode's created */
    gdata->objectsByIDcount++;
    return node;
}
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;
}
Exemple #10
0
static void
writeByteComponents(JNIEnv *env, PacketOutputStream *out,
                    jarray array, jint index, jint length)
{
    jbyte *components;

    components = newComponents(out, length, sizeof(jbyte));
    if (components != NULL) {
        jint i;
        JNI_FUNC_PTR(env,GetByteArrayRegion)(env, array, index, length, components);
        for (i = 0; i < length; i++) {
            (void)outStream_writeByte(out, components[i]);
        }
        deleteComponents(components);
    }
}
/*
 * 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);
}
Exemple #12
0
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"));

}
Exemple #13
0
/* Change all references to global in the EventInfo struct */
static void 
saveEventInfoRefs(JNIEnv *env, EventInfo *evinfo)
{
    jthread *pthread;
    jclass *pclazz;
    jobject *pobject;
    jthread thread;
    jclass clazz;
    jobject object;
    char sig;
    
    JNI_FUNC_PTR(env,ExceptionClear)(env);

    if ( evinfo->thread != NULL ) {
        pthread = &(evinfo->thread);
        thread = *pthread;
        *pthread = NULL;
        saveGlobalRef(env, thread, pthread);
    }
    if ( evinfo->clazz != NULL ) {
        pclazz = &(evinfo->clazz);
        clazz = *pclazz;
        *pclazz = NULL;
        saveGlobalRef(env, clazz, pclazz);
    }
    if ( evinfo->object != NULL ) {
        pobject = &(evinfo->object);
        object = *pobject;
        *pobject = NULL;
        saveGlobalRef(env, object, pobject);
    }
    
    switch (evinfo->ei) {
        case EI_FIELD_MODIFICATION: 
            if ( evinfo->u.field_modification.field_clazz != NULL ) {
                pclazz = &(evinfo->u.field_modification.field_clazz);
                clazz = *pclazz;
                *pclazz = NULL;
                saveGlobalRef(env, clazz, pclazz);
            }
            sig = evinfo->u.field_modification.signature_type;
            if ((sig == JDWP_TAG(ARRAY)) || (sig == JDWP_TAG(OBJECT))) {
                if ( evinfo->u.field_modification.new_value.l != NULL ) {
                    pobject = &(evinfo->u.field_modification.new_value.l);
                    object = *pobject;
                    *pobject = NULL;
                    saveGlobalRef(env, object, pobject);
                }
            }
            break;
        case EI_FIELD_ACCESS:
            if ( evinfo->u.field_access.field_clazz != NULL ) {
                pclazz = &(evinfo->u.field_access.field_clazz);
                clazz = *pclazz;
                *pclazz = NULL;
                saveGlobalRef(env, clazz, pclazz);
            }
            break;
        case EI_EXCEPTION:
            if ( evinfo->u.exception.catch_clazz != NULL ) {
                pclazz = &(evinfo->u.exception.catch_clazz);
                clazz = *pclazz;
                *pclazz = NULL;
                saveGlobalRef(env, clazz, pclazz);
            }
            break;
        default:
            break;
    }

    if (JNI_FUNC_PTR(env,ExceptionOccurred)(env)) {
        EXIT_ERROR(AGENT_ERROR_INVALID_EVENT_TYPE,"ExceptionOccurred");
    }
}
/**
 * This function returns true only if it is certain that
 * all events for the given node in the given stack frame will
 * be filtered. It is used to optimize stepping. (If this
 * function returns true the stepping algorithm does not
 * have to step through every instruction in this stack frame;
 * instead, it can use more efficient method entry/exit
 * events.
 */
jboolean
eventFilter_predictFiltering(HandlerNode *node, jclass clazz, char *classname)
{
    JNIEnv     *env;
    jboolean    willBeFiltered;
    Filter     *filter;
    jboolean    done;
    int         count;
    int         i;

    willBeFiltered = JNI_FALSE;
    env            = NULL;
    filter         = FILTERS_ARRAY(node);
    count          = FILTER_COUNT(node);
    done           = JNI_FALSE;

    for (i = 0; (i < count) && (!done); ++i, ++filter) {
        switch (filter->modifier) {
            case JDWP_REQUEST_MODIFIER(ClassOnly):
                if ( env==NULL ) {
                    env = getEnv();
                }
                if (!JNI_FUNC_PTR(env,IsAssignableFrom)(env, clazz,
                                 filter->u.ClassOnly.clazz)) {
                    willBeFiltered = JNI_TRUE;
                    done = JNI_TRUE;
                }
                break;

            case JDWP_REQUEST_MODIFIER(Count): {
                /*
                 * If preceeding filters have determined that events will
                 * be filtered out, that is fine and we won't get here.
                 * However, the count must be decremented - even if
                 * subsequent filters will filter these events.  We
                 * thus must end now unable to predict
                 */
                done = JNI_TRUE;
                break;
            }

            case JDWP_REQUEST_MODIFIER(ClassMatch): {
                if (!patternStringMatch(classname,
                        filter->u.ClassMatch.classPattern)) {
                    willBeFiltered = JNI_TRUE;
                    done = JNI_TRUE;
                }
                break;
            }

            case JDWP_REQUEST_MODIFIER(ClassExclude): {
                if (patternStringMatch(classname,
                       filter->u.ClassExclude.classPattern)) {
                    willBeFiltered = JNI_TRUE;
                    done = JNI_TRUE;
                }
                break;
            }
        }
    }

    return willBeFiltered;
}
/*
 * Determine if this event is interesting to this handler.
 * Do so by checking each of the handler's filters.
 * Return false if any of the filters fail,
 * true if the handler wants this event.
 * Anyone modifying this function should check
 * eventFilterRestricted_passesUnloadFilter and
 * eventFilter_predictFiltering as well.
 *
 * If shouldDelete is returned true, a count filter has expired
 * and the corresponding node should be deleted.
 */
jboolean
eventFilterRestricted_passesFilter(JNIEnv *env,
                                   char *classname,
                                   EventInfo *evinfo,
                                   HandlerNode *node,
                                   jboolean *shouldDelete)
{
    jthread thread;
    jclass clazz;
    jmethodID method;
    Filter *filter = FILTERS_ARRAY(node);
    int i;

    *shouldDelete = JNI_FALSE;
    thread = evinfo->thread;
    clazz = evinfo->clazz;
    method = evinfo->method;

    /*
     * Suppress most events if they happen in debug threads
     */
    if ((evinfo->ei != EI_CLASS_PREPARE) &&
        (evinfo->ei != EI_GC_FINISH) &&
        (evinfo->ei != EI_CLASS_LOAD) &&
        threadControl_isDebugThread(thread)) {
        return JNI_FALSE;
    }

    for (i = 0; i < FILTER_COUNT(node); ++i, ++filter) {
        switch (filter->modifier) {
            case JDWP_REQUEST_MODIFIER(ThreadOnly):
                if (!isSameObject(env, thread, filter->u.ThreadOnly.thread)) {
                    return JNI_FALSE;
                }
                break;

            case JDWP_REQUEST_MODIFIER(ClassOnly):
                /* Class filters catch events in the specified
                 * class and any subclass/subinterface.
                 */
                if (!JNI_FUNC_PTR(env,IsAssignableFrom)(env, clazz,
                               filter->u.ClassOnly.clazz)) {
                    return JNI_FALSE;
                }
                break;

            /* This is kinda cheating assumming the event
             * fields will be in the same locations, but it is
             * true now.
             */
            case JDWP_REQUEST_MODIFIER(LocationOnly):
                if  (evinfo->method !=
                          filter->u.LocationOnly.method ||
                     evinfo->location !=
                          filter->u.LocationOnly.location ||
                     !isSameObject(env, clazz, filter->u.LocationOnly.clazz)) {
                    return JNI_FALSE;
                }
                break;

            case JDWP_REQUEST_MODIFIER(FieldOnly):
                /* Field watchpoints can be triggered from the
                 * declared class or any subclass/subinterface.
                 */
                if ((evinfo->u.field_access.field !=
                     filter->u.FieldOnly.field) ||
                    !isSameObject(env, evinfo->u.field_access.field_clazz,
                               filter->u.FieldOnly.clazz)) {
                    return JNI_FALSE;
                }
                break;

            case JDWP_REQUEST_MODIFIER(ExceptionOnly):
                /* do we want caught/uncaught exceptions */
                if (!((evinfo->u.exception.catch_clazz == NULL)?
                      filter->u.ExceptionOnly.uncaught :
                      filter->u.ExceptionOnly.caught)) {
                    return JNI_FALSE;
                }

                /* do we care about exception class */
                if (filter->u.ExceptionOnly.exception != NULL) {
                    jclass exception = evinfo->object;

                    /* do we want this exception class */
                    if (!JNI_FUNC_PTR(env,IsInstanceOf)(env, exception,
                            filter->u.ExceptionOnly.exception)) {
                        return JNI_FALSE;
                    }
                }
                break;

            case JDWP_REQUEST_MODIFIER(InstanceOnly): {
                jobject eventInst = eventInstance(evinfo);
                jobject filterInst = filter->u.InstanceOnly.instance;
                /* if no error and doesn't match, don't pass
                 * filter
                 */
                if (eventInst != NULL &&
                      !isSameObject(env, eventInst, filterInst)) {
                    return JNI_FALSE;
                }
                break;
            }
            case JDWP_REQUEST_MODIFIER(Count): {
                JDI_ASSERT(filter->u.Count.count > 0);
                if (--filter->u.Count.count > 0) {
                    return JNI_FALSE;
                }
                *shouldDelete = JNI_TRUE;
                break;
            }

            case JDWP_REQUEST_MODIFIER(Conditional):
/***
                if (...  filter->u.Conditional.exprID ...) {
                    return JNI_FALSE;
                }
***/
                break;

        case JDWP_REQUEST_MODIFIER(ClassMatch): {
            if (!patternStringMatch(classname,
                       filter->u.ClassMatch.classPattern)) {
                return JNI_FALSE;
            }
            break;
        }

        case JDWP_REQUEST_MODIFIER(ClassExclude): {
            if (patternStringMatch(classname,
                      filter->u.ClassExclude.classPattern)) {
                return JNI_FALSE;
            }
            break;
        }

        case JDWP_REQUEST_MODIFIER(Step):
                if (!isSameObject(env, thread, filter->u.Step.thread)) {
                    return JNI_FALSE;
                }
                if (!stepControl_handleStep(env, thread, clazz, method)) {
                    return JNI_FALSE;
                }
                break;

          case JDWP_REQUEST_MODIFIER(SourceNameMatch): {
              char* desiredNamePattern = filter->u.SourceNameOnly.sourceNamePattern;
              if (!searchAllSourceNames(env, clazz,
                           desiredNamePattern) == 1) {
                  /* The name isn't in the SDE; try the sourceName in the ref
                   * type
                   */
                  char *sourceName = 0;
                  jvmtiError error = JVMTI_FUNC_PTR(gdata->jvmti,GetSourceFileName)
                                            (gdata->jvmti, clazz, &sourceName);
                  if (error == JVMTI_ERROR_NONE &&
                      sourceName != 0 &&
                      patternStringMatch(sourceName, desiredNamePattern)) {
                          // got a hit - report the event
                          jvmtiDeallocate(sourceName);
                          break;
                  }
                  // We have no match, we have no source file name,
                  // or we got a JVM TI error. Don't report the event.
                  jvmtiDeallocate(sourceName);
                  return JNI_FALSE;
              }
              break;
          }

        default:
            EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"Invalid filter modifier");
            return JNI_FALSE;
        }
    }
    return JNI_TRUE;
}