/**
 * Clear a watchpoint if this is the last one on this field.
 */
static jvmtiError
clearWatchpoint(HandlerNode *node)
{
    jvmtiError error = JVMTI_ERROR_NONE;
    Filter *filter;

    filter = findFilter(node, JDWP_REQUEST_MODIFIER(FieldOnly));
    if (filter == NULL) {
        /* event with no field filter */
        error = AGENT_ERROR_INTERNAL;
    } else {
        FieldFilter *ff = &(filter->u.FieldOnly);

        /* if this is the last handler for this
         * field, clear wp at JVMTI level
         */
        if (!eventHandlerRestricted_iterator(
                NODE_EI(node), matchWatchpoint, ff)) {
            error = (NODE_EI(node) == EI_FIELD_ACCESS) ?
                JVMTI_FUNC_PTR(gdata->jvmti,ClearFieldAccessWatch)
                        (gdata->jvmti, ff->clazz, ff->field) :
                JVMTI_FUNC_PTR(gdata->jvmti,ClearFieldModificationWatch)
                                (gdata->jvmti, ff->clazz, ff->field);
        }
    }
    return error;
}
/**
 * Set a breakpoint if this is the first one at this location.
 */
static jvmtiError
setBreakpoint(HandlerNode *node)
{
    jvmtiError error = JVMTI_ERROR_NONE;
    Filter *filter;

    filter = findFilter(node, JDWP_REQUEST_MODIFIER(LocationOnly));
    if (filter == NULL) {
        /* bp event with no location filter */
        error = AGENT_ERROR_INTERNAL;
    } else {
        LocationFilter *lf = &(filter->u.LocationOnly);

        /* if this is the first handler for this
         * location, set bp at JVMTI level
         */
        if (!eventHandlerRestricted_iterator(
                EI_BREAKPOINT, matchBreakpoint, lf)) {
            LOG_LOC(("SetBreakpoint at location: method=%p,location=%d",
                        lf->method, (int)lf->location));
            error = JVMTI_FUNC_PTR(gdata->jvmti,SetBreakpoint)
                        (gdata->jvmti, lf->method, lf->location);
        }
    }
    return error;
}
Example #3
0
static jvmtiError
set_event_notification(jvmtiEventMode mode, EventIndex ei)
{
    jvmtiError error;
    error = JVMTI_FUNC_PTR(gdata->jvmti,SetEventNotificationMode)
            (gdata->jvmti, mode, eventIndex2jvmti(ei), NULL);
    if (error != JVMTI_ERROR_NONE) {
        ERROR_MESSAGE(("JDWP unable to configure initial JVMTI event %s: %s(%d)",
                       eventText(ei), jvmtiErrorText(error), error));
    }
    return error;
}
Example #4
0
static void
disposeEnvironment(jvmtiEnv *jvmti_env)
{
    jvmtiError error;

    error = JVMTI_FUNC_PTR(jvmti_env,DisposeEnvironment)(jvmti_env);
    if ( error == JVMTI_ERROR_MUST_POSSESS_CAPABILITY )
        error = JVMTI_ERROR_NONE;  /* Hack!  FIXUP when JVMTI has disposeEnv */
    /* What should error return say? */
    if (error != JVMTI_ERROR_NONE) {
        ERROR_MESSAGE(("JDWP unable to dispose of JVMTI environment: %s(%d)",
                       jvmtiErrorText(error), error));
    }
    gdata->jvmti = NULL;
}
Example #5
0
/*
 * Returns the node which contains the common reference for the 
 * given object. The passed reference should not be a weak reference
 * managed in the object hash table (i.e. returned by commonRef_idToRef)
 * because no sequence number checking is done.
 */
static RefNode *
findNodeByRef(JNIEnv *env, jobject ref) 
{
    jvmtiError error;
    jlong      tag;

    tag   = NULL_OBJECT_ID;
    error = JVMTI_FUNC_PTR(gdata->jvmti,GetTag)(gdata->jvmti, ref, &tag);
    if ( error == JVMTI_ERROR_NONE ) {
        RefNode   *node;
        
        node = (RefNode*)jlong_to_ptr(tag);
        return node;
    }
    return NULL;
}
/* Return NULL if static or if an error occurs */
static jobject
eventInstance(EventInfo *evinfo)
{
    jobject     object          = NULL;
    jthread     thread          ;
    jmethodID   method          ;
    jint        modifiers       = 0;
    jvmtiError  error;

    switch (evinfo->ei) {
        case EI_SINGLE_STEP:
        case EI_BREAKPOINT:
        case EI_FRAME_POP:
        case EI_METHOD_ENTRY:
        case EI_METHOD_EXIT:
        case EI_EXCEPTION:
        case EI_EXCEPTION_CATCH:
        case EI_MONITOR_CONTENDED_ENTER:
        case EI_MONITOR_CONTENDED_ENTERED:
        case EI_MONITOR_WAIT:
        case EI_MONITOR_WAITED:
            thread      = evinfo->thread;
            method      = evinfo->method;
            break;
        case EI_FIELD_ACCESS:
        case EI_FIELD_MODIFICATION:
            object = evinfo->object;
            return object;
        default:
            return object; /* NULL */
    }

    error = methodModifiers(method, &modifiers);

    /* fail if error or static (0x8) */
    if (error == JVMTI_ERROR_NONE && thread!=NULL && (modifiers & 0x8) == 0) {
        FrameNumber fnum            = 0;
        /* get slot zero object "this" */
        error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalObject)
                    (gdata->jvmti, thread, fnum, 0, &object);
        if (error != JVMTI_ERROR_NONE)
            object = NULL;
    }

    return object;
}
Example #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);
}
Example #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 void
handleFrameEvent(JNIEnv *env, EventInfo *evinfo,
                 HandlerNode *node,
                 struct bag *eventBag)
{
    /*
     * The frame id that comes with this event is very transient.
     * We can't send the frame to the helper thread because it
     * might be useless by the time the helper thread can use it
     * (if suspend policy is NONE). So, get the needed info from
     * the frame and then use a special command to the helper
     * thread.
     */

    jmethodID method;
    jlocation location;
    jvmtiError error;
    FrameNumber fnum = 0;
    jvalue returnValue;

    error = JVMTI_FUNC_PTR(gdata->jvmti,GetFrameLocation)
            (gdata->jvmti, evinfo->thread, fnum, &method, &location);
    if (error != JVMTI_ERROR_NONE) {
        location = -1;
    }
    returnValue = evinfo->u.method_exit.return_value;

    eventHelper_recordFrameEvent(node->handlerID,
                                 node->suspendPolicy,
                                 evinfo->ei,
                                 evinfo->thread,
                                 evinfo->clazz,
                                 evinfo->method,
                                 location,
                                 node->needReturnValue,
                                 returnValue,
                                 eventBag);
}
Example #10
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()"));
}
Example #11
0
/* OnLoad startup:
 *   Returning JNI_ERR will cause the java_g VM to core dump, be careful.
 */
JNIEXPORT jint JNICALL
DEF_Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
{
    jvmtiError error;
    jvmtiCapabilities needed_capabilities;
    jvmtiCapabilities potential_capabilities;
    jint              jvmtiCompileTimeMajorVersion;
    jint              jvmtiCompileTimeMinorVersion;
    jint              jvmtiCompileTimeMicroVersion;

    /* See if it's already loaded */
    if ( gdata!=NULL && gdata->isLoaded==JNI_TRUE ) {
        ERROR_MESSAGE(("Cannot load this JVM TI agent twice, check your java command line for duplicate jdwp options."));
        return JNI_ERR;
    }

    /* If gdata is defined and the VM died, why are we here? */
    if ( gdata!=NULL && gdata->vmDead ) {
        ERROR_MESSAGE(("JDWP unable to load, VM died"));
        return JNI_ERR;
    }

    /* Get global data area */
    gdata = get_gdata();
    if (gdata == NULL) {
        ERROR_MESSAGE(("JDWP unable to allocate memory"));
        return JNI_ERR;
    }
    gdata->isLoaded = JNI_TRUE;

    /* Start filling in gdata */
    gdata->jvm = vm;
    vmInitialized = JNI_FALSE;
    gdata->vmDead = JNI_FALSE;

    /* Get the JVMTI Env, IMPORTANT: Do this first! For jvmtiAllocate(). */
    error = JVM_FUNC_PTR(vm,GetEnv)
            (vm, (void **)&(gdata->jvmti), JVMTI_VERSION_1);
    if (error != JNI_OK) {
        ERROR_MESSAGE(("JDWP unable to access JVMTI Version 1 (0x%x),"
                       " is your J2SE a 1.5 or newer version?"
                       " JNIEnv's GetEnv() returned %d",
                       JVMTI_VERSION_1, error));
        forceExit(1); /* Kill entire process, no core dump */
    }

    /* Check to make sure the version of jvmti.h we compiled with
     *      matches the runtime version we are using.
     */
    jvmtiCompileTimeMajorVersion  = ( JVMTI_VERSION & JVMTI_VERSION_MASK_MAJOR )
                                    >> JVMTI_VERSION_SHIFT_MAJOR;
    jvmtiCompileTimeMinorVersion  = ( JVMTI_VERSION & JVMTI_VERSION_MASK_MINOR )
                                    >> JVMTI_VERSION_SHIFT_MINOR;
    jvmtiCompileTimeMicroVersion  = ( JVMTI_VERSION & JVMTI_VERSION_MASK_MICRO )
                                    >> JVMTI_VERSION_SHIFT_MICRO;

    /* Check for compatibility */
    if ( !compatible_versions(jvmtiMajorVersion(), jvmtiMinorVersion(),
                              jvmtiCompileTimeMajorVersion, jvmtiCompileTimeMinorVersion) ) {

        ERROR_MESSAGE(("This jdwp native library will not work with this VM's "
                       "version of JVMTI (%d.%d.%d), it needs JVMTI %d.%d[.%d].",
                       jvmtiMajorVersion(),
                       jvmtiMinorVersion(),
                       jvmtiMicroVersion(),
                       jvmtiCompileTimeMajorVersion,
                       jvmtiCompileTimeMinorVersion,
                       jvmtiCompileTimeMicroVersion));

        /* Do not let VM get a fatal error, we don't want a core dump here. */
        forceExit(1); /* Kill entire process, no core dump wanted */
    }

    /* Parse input options */
    if (!parseOptions(options)) {
        /* No message necessary, should have been printed out already */
        /* Do not let VM get a fatal error, we don't want a core dump here. */
        forceExit(1); /* Kill entire process, no core dump wanted */
    }

    LOG_MISC(("Onload: %s", options));

    /* Get potential capabilities */
    (void)memset(&potential_capabilities,0,sizeof(potential_capabilities));
    error = JVMTI_FUNC_PTR(gdata->jvmti,GetPotentialCapabilities)
            (gdata->jvmti, &potential_capabilities);
    if (error != JVMTI_ERROR_NONE) {
        ERROR_MESSAGE(("JDWP unable to get potential JVMTI capabilities: %s(%d)",
                       jvmtiErrorText(error), error));
        return JNI_ERR;
    }

    /* Fill in ones that we must have */
    (void)memset(&needed_capabilities,0,sizeof(needed_capabilities));
    needed_capabilities.can_access_local_variables              = 1;
    needed_capabilities.can_generate_single_step_events         = 1;
    needed_capabilities.can_generate_exception_events           = 1;
    needed_capabilities.can_generate_frame_pop_events           = 1;
    needed_capabilities.can_generate_breakpoint_events          = 1;
    needed_capabilities.can_suspend                             = 1;
    needed_capabilities.can_generate_method_entry_events        = 1;
    needed_capabilities.can_generate_method_exit_events         = 1;
    needed_capabilities.can_generate_garbage_collection_events  = 1;
    needed_capabilities.can_maintain_original_method_order      = 1;
    needed_capabilities.can_generate_monitor_events             = 1;
    needed_capabilities.can_tag_objects                         = 1;

    /* And what potential ones that would be nice to have */
    needed_capabilities.can_force_early_return
        = potential_capabilities.can_force_early_return;
    needed_capabilities.can_generate_field_modification_events
        = potential_capabilities.can_generate_field_modification_events;
    needed_capabilities.can_generate_field_access_events
        = potential_capabilities.can_generate_field_access_events;
    needed_capabilities.can_get_bytecodes
        = potential_capabilities.can_get_bytecodes;
    needed_capabilities.can_get_synthetic_attribute
        = potential_capabilities.can_get_synthetic_attribute;
    needed_capabilities.can_get_owned_monitor_info
        = potential_capabilities.can_get_owned_monitor_info;
    needed_capabilities.can_get_current_contended_monitor
        = potential_capabilities.can_get_current_contended_monitor;
    needed_capabilities.can_get_monitor_info
        = potential_capabilities.can_get_monitor_info;
    needed_capabilities.can_pop_frame
        = potential_capabilities.can_pop_frame;
    needed_capabilities.can_redefine_classes
        = potential_capabilities.can_redefine_classes;
    needed_capabilities.can_redefine_any_class
        = potential_capabilities.can_redefine_any_class;
    needed_capabilities.can_get_owned_monitor_stack_depth_info
        = potential_capabilities.can_get_owned_monitor_stack_depth_info;
    needed_capabilities.can_get_constant_pool
        = potential_capabilities.can_get_constant_pool;
    {
        needed_capabilities.can_get_source_debug_extension      = 1;
        needed_capabilities.can_get_source_file_name            = 1;
        needed_capabilities.can_get_line_numbers                = 1;
        needed_capabilities.can_signal_thread
            = potential_capabilities.can_signal_thread;
    }

    /* Add the capabilities */
    error = JVMTI_FUNC_PTR(gdata->jvmti,AddCapabilities)
            (gdata->jvmti, &needed_capabilities);
    if (error != JVMTI_ERROR_NONE) {
        ERROR_MESSAGE(("JDWP unable to get necessary JVMTI capabilities."));
        forceExit(1); /* Kill entire process, no core dump wanted */
    }

    /* Initialize event number mapping tables */
    eventIndexInit();

    /* Set the initial JVMTI event notifications */
    error = set_event_notification(JVMTI_ENABLE, EI_VM_DEATH);
    if (error != JVMTI_ERROR_NONE) {
        return JNI_ERR;
    }
    error = set_event_notification(JVMTI_ENABLE, EI_VM_INIT);
    if (error != JVMTI_ERROR_NONE) {
        return JNI_ERR;
    }
    if (initOnUncaught || (initOnException != NULL)) {
        error = set_event_notification(JVMTI_ENABLE, EI_EXCEPTION);
        if (error != JVMTI_ERROR_NONE) {
            return JNI_ERR;
        }
    }

    /* Set callbacks just for 3 functions */
    (void)memset(&(gdata->callbacks),0,sizeof(gdata->callbacks));
    gdata->callbacks.VMInit             = &cbEarlyVMInit;
    gdata->callbacks.VMDeath            = &cbEarlyVMDeath;
    gdata->callbacks.Exception  = &cbEarlyException;
    error = JVMTI_FUNC_PTR(gdata->jvmti,SetEventCallbacks)
            (gdata->jvmti, &(gdata->callbacks), sizeof(gdata->callbacks));
    if (error != JVMTI_ERROR_NONE) {
        ERROR_MESSAGE(("JDWP unable to set JVMTI event callbacks: %s(%d)",
                       jvmtiErrorText(error), error));
        return JNI_ERR;
    }

    LOG_MISC(("OnLoad: DONE"));
    return JNI_OK;
}
Example #12
0
/*
 * 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;
}