1/*
2 * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25/*
26 * eventFilter
27 *
28 * This module handles event filteration and the enabling/disabling
29 * of the corresponding events. Used for filters on JDI EventRequests
30 * and also internal requests.  Our data is in a private hidden section
31 * of the HandlerNode's data.  See comment for enclosing
32 * module eventHandler.
33 */
34
35#include "util.h"
36#include "eventFilter.h"
37#include "eventFilterRestricted.h"
38#include "eventHandlerRestricted.h"
39#include "stepControl.h"
40#include "threadControl.h"
41#include "SDE.h"
42#include "jvmti.h"
43
44typedef struct ClassFilter {
45    jclass clazz;
46} ClassFilter;
47
48typedef struct LocationFilter {
49    jclass clazz;
50    jmethodID method;
51    jlocation location;
52} LocationFilter;
53
54typedef struct ThreadFilter {
55    jthread thread;
56} ThreadFilter;
57
58typedef struct CountFilter {
59    jint count;
60} CountFilter;
61
62typedef struct ConditionalFilter {
63    jint exprID;
64} ConditionalFilter;
65
66typedef struct FieldFilter {
67    jclass clazz;
68    jfieldID field;
69} FieldFilter;
70
71typedef struct ExceptionFilter {
72    jclass exception;
73    jboolean caught;
74    jboolean uncaught;
75} ExceptionFilter;
76
77typedef struct InstanceFilter {
78    jobject instance;
79} InstanceFilter;
80
81typedef struct StepFilter {
82    jint size;
83    jint depth;
84    jthread thread;
85} StepFilter;
86
87typedef struct MatchFilter {
88    char *classPattern;
89} MatchFilter;
90
91typedef struct SourceNameFilter {
92    char *sourceNamePattern;
93} SourceNameFilter;
94
95typedef struct Filter_ {
96    jbyte modifier;
97    union {
98        struct ClassFilter ClassOnly;
99        struct LocationFilter LocationOnly;
100        struct ThreadFilter ThreadOnly;
101        struct CountFilter Count;
102        struct ConditionalFilter Conditional;
103        struct FieldFilter FieldOnly;
104        struct ExceptionFilter ExceptionOnly;
105        struct InstanceFilter InstanceOnly;
106        struct StepFilter Step;
107        struct MatchFilter ClassMatch;
108        struct MatchFilter ClassExclude;
109        struct SourceNameFilter SourceNameOnly;
110    } u;
111} Filter;
112
113/* The filters array is allocated to the specified filterCount.
114 * Theoretically, some compiler could do range checking on this
115 * array - so, we define it to have a ludicrously large size so
116 * that this range checking won't get upset.
117 *
118 * The actual allocated number of bytes is computed using the
119 * offset of "filters" and so is not effected by this number.
120 */
121#define MAX_FILTERS 10000
122
123typedef struct EventFilters_ {
124    jint filterCount;
125    Filter filters[MAX_FILTERS];
126} EventFilters;
127
128typedef struct EventFilterPrivate_HandlerNode_ {
129    EventHandlerRestricted_HandlerNode   not_for_us;
130    EventFilters                         ef;
131} EventFilterPrivate_HandlerNode;
132
133/**
134 * The following macros extract filter info (EventFilters) from private
135 * data at the end of a HandlerNode
136 */
137#define EVENT_FILTERS(node) (&(((EventFilterPrivate_HandlerNode*)(void*)node)->ef))
138#define FILTER_COUNT(node)  (EVENT_FILTERS(node)->filterCount)
139#define FILTERS_ARRAY(node) (EVENT_FILTERS(node)->filters)
140#define FILTER(node,index)  ((FILTERS_ARRAY(node))[index])
141#define NODE_EI(node)          (node->ei)
142
143/***** filter set-up / destruction *****/
144
145/**
146 * Allocate a HandlerNode.
147 * We do it because eventHandler doesn't know how big to make it.
148 */
149HandlerNode *
150eventFilterRestricted_alloc(jint filterCount)
151{
152    /*LINTED*/
153    size_t size = offsetof(EventFilterPrivate_HandlerNode, ef) +
154                  offsetof(EventFilters, filters) +
155                  (filterCount * (int)sizeof(Filter));
156    HandlerNode *node = jvmtiAllocate((jint)size);
157
158    if (node != NULL) {
159        int i;
160        Filter *filter;
161
162        (void)memset(node, 0, size);
163
164        FILTER_COUNT(node) = filterCount;
165
166        /* Initialize all modifiers
167         */
168        for (i = 0, filter = FILTERS_ARRAY(node);
169                                    i < filterCount;
170                                    i++, filter++) {
171            filter->modifier = JDWP_REQUEST_NONE;
172        }
173    }
174
175    return node;
176}
177
178/**
179 * Free up global refs held by the filter.
180 * free things up at the JNI level if needed.
181 */
182static jvmtiError
183clearFilters(HandlerNode *node)
184{
185    JNIEnv *env = getEnv();
186    jint i;
187    jvmtiError error = JVMTI_ERROR_NONE;
188    Filter *filter = FILTERS_ARRAY(node);
189
190    for (i = 0; i < FILTER_COUNT(node); ++i, ++filter) {
191        switch (filter->modifier) {
192            case JDWP_REQUEST_MODIFIER(ThreadOnly):
193                if ( filter->u.ThreadOnly.thread != NULL ) {
194                    tossGlobalRef(env, &(filter->u.ThreadOnly.thread));
195                }
196                break;
197            case JDWP_REQUEST_MODIFIER(LocationOnly):
198                tossGlobalRef(env, &(filter->u.LocationOnly.clazz));
199                break;
200            case JDWP_REQUEST_MODIFIER(FieldOnly):
201                tossGlobalRef(env, &(filter->u.FieldOnly.clazz));
202                break;
203            case JDWP_REQUEST_MODIFIER(ExceptionOnly):
204                if ( filter->u.ExceptionOnly.exception != NULL ) {
205                    tossGlobalRef(env, &(filter->u.ExceptionOnly.exception));
206                }
207                break;
208            case JDWP_REQUEST_MODIFIER(InstanceOnly):
209                if ( filter->u.InstanceOnly.instance != NULL ) {
210                    tossGlobalRef(env, &(filter->u.InstanceOnly.instance));
211                }
212                break;
213            case JDWP_REQUEST_MODIFIER(ClassOnly):
214                tossGlobalRef(env, &(filter->u.ClassOnly.clazz));
215                break;
216            case JDWP_REQUEST_MODIFIER(ClassMatch):
217                jvmtiDeallocate(filter->u.ClassMatch.classPattern);
218                break;
219            case JDWP_REQUEST_MODIFIER(ClassExclude):
220                jvmtiDeallocate(filter->u.ClassExclude.classPattern);
221                break;
222            case JDWP_REQUEST_MODIFIER(Step): {
223                jthread thread = filter->u.Step.thread;
224                error = stepControl_endStep(thread);
225                if (error == JVMTI_ERROR_NONE) {
226                    tossGlobalRef(env, &(filter->u.Step.thread));
227                }
228                break;
229            }
230        }
231    }
232    if (error == JVMTI_ERROR_NONE) {
233        FILTER_COUNT(node) = 0; /* blast so we don't clear again */
234    }
235
236    return error;
237}
238
239
240/***** filtering *****/
241
242/*
243 * Match a string against a wildcard
244 * string pattern.
245 */
246static jboolean
247patternStringMatch(char *classname, const char *pattern)
248{
249    int pattLen;
250    int compLen;
251    char *start;
252    int offset;
253
254    if ( pattern==NULL || classname==NULL ) {
255        return JNI_FALSE;
256    }
257    pattLen = (int)strlen(pattern);
258
259    if ((pattern[0] != '*') && (pattern[pattLen-1] != '*')) {
260        /* An exact match is required when there is no *: bug 4331522 */
261        return strcmp(pattern, classname) == 0;
262    } else {
263        compLen = pattLen - 1;
264        offset = (int)strlen(classname) - compLen;
265        if (offset < 0) {
266            return JNI_FALSE;
267        } else {
268            if (pattern[0] == '*') {
269                pattern++;
270                start = classname + offset;
271            }  else {
272                start = classname;
273            }
274            return strncmp(pattern, start, compLen) == 0;
275        }
276    }
277}
278
279static jboolean isVersionGte12x() {
280    jint version;
281    jvmtiError err =
282        JVMTI_FUNC_PTR(gdata->jvmti,GetVersionNumber)(gdata->jvmti, &version);
283
284    if (err == JVMTI_ERROR_NONE) {
285        jint major, minor;
286
287        major = (version & JVMTI_VERSION_MASK_MAJOR)
288                    >> JVMTI_VERSION_SHIFT_MAJOR;
289        minor = (version & JVMTI_VERSION_MASK_MINOR)
290                    >> JVMTI_VERSION_SHIFT_MINOR;
291        return (major > 1 || (major == 1 && minor >= 2)) ? JNI_TRUE : JNI_FALSE;
292    } else {
293        return JNI_FALSE;
294    }
295}
296
297/* Return the object instance in which the event occurred */
298/* Return NULL if static or if an error occurs */
299static jobject
300eventInstance(EventInfo *evinfo)
301{
302    jobject     object          = NULL;
303    jthread     thread          ;
304    jmethodID   method          ;
305    jint        modifiers       = 0;
306    jvmtiError  error;
307
308    static jboolean got_version = JNI_FALSE;
309    static jboolean is_version_gte_12x = JNI_FALSE;
310
311    if (!got_version) {
312        is_version_gte_12x = isVersionGte12x();
313        got_version = JNI_TRUE;
314    }
315
316    switch (evinfo->ei) {
317        case EI_SINGLE_STEP:
318        case EI_BREAKPOINT:
319        case EI_FRAME_POP:
320        case EI_METHOD_ENTRY:
321        case EI_METHOD_EXIT:
322        case EI_EXCEPTION:
323        case EI_EXCEPTION_CATCH:
324        case EI_MONITOR_CONTENDED_ENTER:
325        case EI_MONITOR_CONTENDED_ENTERED:
326        case EI_MONITOR_WAIT:
327        case EI_MONITOR_WAITED:
328            thread      = evinfo->thread;
329            method      = evinfo->method;
330            break;
331        case EI_FIELD_ACCESS:
332        case EI_FIELD_MODIFICATION:
333            object = evinfo->object;
334            return object;
335        default:
336            return object; /* NULL */
337    }
338
339    error = methodModifiers(method, &modifiers);
340
341    /* fail if error or static (0x8) */
342    if (error == JVMTI_ERROR_NONE && thread!=NULL && (modifiers & 0x8) == 0) {
343        FrameNumber fnum            = 0;
344        if (is_version_gte_12x) {
345            /* Use new 1.2.x function, GetLocalInstance */
346            error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalInstance)
347                        (gdata->jvmti, thread, fnum, &object);
348        } else {
349            /* get slot zero object "this" */
350            error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalObject)
351                        (gdata->jvmti, thread, fnum, 0, &object);
352        }
353        if (error != JVMTI_ERROR_NONE) {
354            object = NULL;
355        }
356    }
357
358    return object;
359}
360
361/*
362 * Determine if this event is interesting to this handler.
363 * Do so by checking each of the handler's filters.
364 * Return false if any of the filters fail,
365 * true if the handler wants this event.
366 * Anyone modifying this function should check
367 * eventFilterRestricted_passesUnloadFilter and
368 * eventFilter_predictFiltering as well.
369 *
370 * If shouldDelete is returned true, a count filter has expired
371 * and the corresponding node should be deleted.
372 */
373jboolean
374eventFilterRestricted_passesFilter(JNIEnv *env,
375                                   char *classname,
376                                   EventInfo *evinfo,
377                                   HandlerNode *node,
378                                   jboolean *shouldDelete)
379{
380    jthread thread;
381    jclass clazz;
382    jmethodID method;
383    Filter *filter = FILTERS_ARRAY(node);
384    int i;
385
386    *shouldDelete = JNI_FALSE;
387    thread = evinfo->thread;
388    clazz = evinfo->clazz;
389    method = evinfo->method;
390
391    /*
392     * Suppress most events if they happen in debug threads
393     */
394    if ((evinfo->ei != EI_CLASS_PREPARE) &&
395        (evinfo->ei != EI_GC_FINISH) &&
396        (evinfo->ei != EI_CLASS_LOAD) &&
397        threadControl_isDebugThread(thread)) {
398        return JNI_FALSE;
399    }
400
401    for (i = 0; i < FILTER_COUNT(node); ++i, ++filter) {
402        switch (filter->modifier) {
403            case JDWP_REQUEST_MODIFIER(ThreadOnly):
404                if (!isSameObject(env, thread, filter->u.ThreadOnly.thread)) {
405                    return JNI_FALSE;
406                }
407                break;
408
409            case JDWP_REQUEST_MODIFIER(ClassOnly):
410                /* Class filters catch events in the specified
411                 * class and any subclass/subinterface.
412                 */
413                if (!JNI_FUNC_PTR(env,IsAssignableFrom)(env, clazz,
414                               filter->u.ClassOnly.clazz)) {
415                    return JNI_FALSE;
416                }
417                break;
418
419            /* This is kinda cheating assumming the event
420             * fields will be in the same locations, but it is
421             * true now.
422             */
423            case JDWP_REQUEST_MODIFIER(LocationOnly):
424                if  (evinfo->method !=
425                          filter->u.LocationOnly.method ||
426                     evinfo->location !=
427                          filter->u.LocationOnly.location ||
428                     !isSameObject(env, clazz, filter->u.LocationOnly.clazz)) {
429                    return JNI_FALSE;
430                }
431                break;
432
433            case JDWP_REQUEST_MODIFIER(FieldOnly):
434                /* Field watchpoints can be triggered from the
435                 * declared class or any subclass/subinterface.
436                 */
437                if ((evinfo->u.field_access.field !=
438                     filter->u.FieldOnly.field) ||
439                    !isSameObject(env, evinfo->u.field_access.field_clazz,
440                               filter->u.FieldOnly.clazz)) {
441                    return JNI_FALSE;
442                }
443                break;
444
445            case JDWP_REQUEST_MODIFIER(ExceptionOnly):
446                /* do we want caught/uncaught exceptions */
447                if (!((evinfo->u.exception.catch_clazz == NULL)?
448                      filter->u.ExceptionOnly.uncaught :
449                      filter->u.ExceptionOnly.caught)) {
450                    return JNI_FALSE;
451                }
452
453                /* do we care about exception class */
454                if (filter->u.ExceptionOnly.exception != NULL) {
455                    jclass exception = evinfo->object;
456
457                    /* do we want this exception class */
458                    if (!JNI_FUNC_PTR(env,IsInstanceOf)(env, exception,
459                            filter->u.ExceptionOnly.exception)) {
460                        return JNI_FALSE;
461                    }
462                }
463                break;
464
465            case JDWP_REQUEST_MODIFIER(InstanceOnly): {
466                jobject eventInst = eventInstance(evinfo);
467                jobject filterInst = filter->u.InstanceOnly.instance;
468                /* if no error and doesn't match, don't pass
469                 * filter
470                 */
471                if (eventInst != NULL &&
472                      !isSameObject(env, eventInst, filterInst)) {
473                    return JNI_FALSE;
474                }
475                break;
476            }
477            case JDWP_REQUEST_MODIFIER(Count): {
478                JDI_ASSERT(filter->u.Count.count > 0);
479                if (--filter->u.Count.count > 0) {
480                    return JNI_FALSE;
481                }
482                *shouldDelete = JNI_TRUE;
483                break;
484            }
485
486            case JDWP_REQUEST_MODIFIER(Conditional):
487/***
488                if (...  filter->u.Conditional.exprID ...) {
489                    return JNI_FALSE;
490                }
491***/
492                break;
493
494        case JDWP_REQUEST_MODIFIER(ClassMatch): {
495            if (!patternStringMatch(classname,
496                       filter->u.ClassMatch.classPattern)) {
497                return JNI_FALSE;
498            }
499            break;
500        }
501
502        case JDWP_REQUEST_MODIFIER(ClassExclude): {
503            if (patternStringMatch(classname,
504                      filter->u.ClassExclude.classPattern)) {
505                return JNI_FALSE;
506            }
507            break;
508        }
509
510        case JDWP_REQUEST_MODIFIER(Step):
511                if (!isSameObject(env, thread, filter->u.Step.thread)) {
512                    return JNI_FALSE;
513                }
514                if (!stepControl_handleStep(env, thread, clazz, method)) {
515                    return JNI_FALSE;
516                }
517                break;
518
519          case JDWP_REQUEST_MODIFIER(SourceNameMatch): {
520              char* desiredNamePattern = filter->u.SourceNameOnly.sourceNamePattern;
521              if (searchAllSourceNames(env, clazz,
522                           desiredNamePattern) != 1) {
523                  /* The name isn't in the SDE; try the sourceName in the ref
524                   * type
525                   */
526                  char *sourceName = 0;
527                  jvmtiError error = JVMTI_FUNC_PTR(gdata->jvmti,GetSourceFileName)
528                                            (gdata->jvmti, clazz, &sourceName);
529                  if (error == JVMTI_ERROR_NONE &&
530                      sourceName != 0 &&
531                      patternStringMatch(sourceName, desiredNamePattern)) {
532                          // got a hit - report the event
533                          jvmtiDeallocate(sourceName);
534                          break;
535                  }
536                  // We have no match, we have no source file name,
537                  // or we got a JVM TI error. Don't report the event.
538                  jvmtiDeallocate(sourceName);
539                  return JNI_FALSE;
540              }
541              break;
542          }
543
544        default:
545            EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"Invalid filter modifier");
546            return JNI_FALSE;
547        }
548    }
549    return JNI_TRUE;
550}
551
552/* Determine if this event is interesting to this handler.  Do so
553 * by checking each of the handler's filters.  Return false if any
554 * of the filters fail, true if the handler wants this event.
555 * Special version of filter for unloads since they don't have an
556 * event structure or a jclass.
557 *
558 * If shouldDelete is returned true, a count filter has expired
559 * and the corresponding node should be deleted.
560 */
561jboolean
562eventFilterRestricted_passesUnloadFilter(JNIEnv *env,
563                                         char *classname,
564                                         HandlerNode *node,
565                                         jboolean *shouldDelete)
566{
567    Filter *filter = FILTERS_ARRAY(node);
568    int i;
569
570    *shouldDelete = JNI_FALSE;
571    for (i = 0; i < FILTER_COUNT(node); ++i, ++filter) {
572        switch (filter->modifier) {
573
574            case JDWP_REQUEST_MODIFIER(Count): {
575                JDI_ASSERT(filter->u.Count.count > 0);
576                if (--filter->u.Count.count > 0) {
577                    return JNI_FALSE;
578                }
579                *shouldDelete = JNI_TRUE;
580                break;
581            }
582
583            case JDWP_REQUEST_MODIFIER(ClassMatch): {
584                if (!patternStringMatch(classname,
585                        filter->u.ClassMatch.classPattern)) {
586                    return JNI_FALSE;
587                }
588                break;
589            }
590
591            case JDWP_REQUEST_MODIFIER(ClassExclude): {
592                if (patternStringMatch(classname,
593                       filter->u.ClassExclude.classPattern)) {
594                    return JNI_FALSE;
595                }
596                break;
597            }
598
599            default:
600                EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"Invalid filter modifier");
601                return JNI_FALSE;
602        }
603    }
604    return JNI_TRUE;
605}
606
607/**
608 * This function returns true only if it is certain that
609 * all events for the given node in the given stack frame will
610 * be filtered. It is used to optimize stepping. (If this
611 * function returns true the stepping algorithm does not
612 * have to step through every instruction in this stack frame;
613 * instead, it can use more efficient method entry/exit
614 * events.
615 */
616jboolean
617eventFilter_predictFiltering(HandlerNode *node, jclass clazz, char *classname)
618{
619    JNIEnv     *env;
620    jboolean    willBeFiltered;
621    Filter     *filter;
622    jboolean    done;
623    int         count;
624    int         i;
625
626    willBeFiltered = JNI_FALSE;
627    env            = NULL;
628    filter         = FILTERS_ARRAY(node);
629    count          = FILTER_COUNT(node);
630    done           = JNI_FALSE;
631
632    for (i = 0; (i < count) && (!done); ++i, ++filter) {
633        switch (filter->modifier) {
634            case JDWP_REQUEST_MODIFIER(ClassOnly):
635                if ( env==NULL ) {
636                    env = getEnv();
637                }
638                if (!JNI_FUNC_PTR(env,IsAssignableFrom)(env, clazz,
639                                 filter->u.ClassOnly.clazz)) {
640                    willBeFiltered = JNI_TRUE;
641                    done = JNI_TRUE;
642                }
643                break;
644
645            case JDWP_REQUEST_MODIFIER(Count): {
646                /*
647                 * If preceding filters have determined that events will
648                 * be filtered out, that is fine and we won't get here.
649                 * However, the count must be decremented - even if
650                 * subsequent filters will filter these events.  We
651                 * thus must end now unable to predict
652                 */
653                done = JNI_TRUE;
654                break;
655            }
656
657            case JDWP_REQUEST_MODIFIER(ClassMatch): {
658                if (!patternStringMatch(classname,
659                        filter->u.ClassMatch.classPattern)) {
660                    willBeFiltered = JNI_TRUE;
661                    done = JNI_TRUE;
662                }
663                break;
664            }
665
666            case JDWP_REQUEST_MODIFIER(ClassExclude): {
667                if (patternStringMatch(classname,
668                       filter->u.ClassExclude.classPattern)) {
669                    willBeFiltered = JNI_TRUE;
670                    done = JNI_TRUE;
671                }
672                break;
673            }
674        }
675    }
676
677    return willBeFiltered;
678}
679
680/**
681 * Determine if the given breakpoint node is in the specified class.
682 */
683jboolean
684eventFilterRestricted_isBreakpointInClass(JNIEnv *env, jclass clazz,
685                                          HandlerNode *node)
686{
687    Filter *filter = FILTERS_ARRAY(node);
688    int i;
689
690    for (i = 0; i < FILTER_COUNT(node); ++i, ++filter) {
691        switch (filter->modifier) {
692            case JDWP_REQUEST_MODIFIER(LocationOnly):
693                return isSameObject(env, clazz, filter->u.LocationOnly.clazz);
694        }
695    }
696    return JNI_TRUE; /* should never come here */
697}
698
699/***** filter set-up *****/
700
701jvmtiError
702eventFilter_setConditionalFilter(HandlerNode *node, jint index,
703                                 jint exprID)
704{
705    ConditionalFilter *filter = &FILTER(node, index).u.Conditional;
706    if (index >= FILTER_COUNT(node)) {
707        return AGENT_ERROR_ILLEGAL_ARGUMENT;
708    }
709    FILTER(node, index).modifier = JDWP_REQUEST_MODIFIER(Conditional);
710    filter->exprID = exprID;
711    return JVMTI_ERROR_NONE;
712}
713
714jvmtiError
715eventFilter_setCountFilter(HandlerNode *node, jint index,
716                           jint count)
717{
718    CountFilter *filter = &FILTER(node, index).u.Count;
719    if (index >= FILTER_COUNT(node)) {
720        return AGENT_ERROR_ILLEGAL_ARGUMENT;
721    }
722    if (count <= 0) {
723        return JDWP_ERROR(INVALID_COUNT);
724    } else {
725        FILTER(node, index).modifier = JDWP_REQUEST_MODIFIER(Count);
726        filter->count = count;
727        return JVMTI_ERROR_NONE;
728    }
729}
730
731jvmtiError
732eventFilter_setThreadOnlyFilter(HandlerNode *node, jint index,
733                                jthread thread)
734{
735    JNIEnv *env = getEnv();
736    ThreadFilter *filter = &FILTER(node, index).u.ThreadOnly;
737    if (index >= FILTER_COUNT(node)) {
738        return AGENT_ERROR_ILLEGAL_ARGUMENT;
739    }
740    if (NODE_EI(node) == EI_GC_FINISH) {
741        return AGENT_ERROR_ILLEGAL_ARGUMENT;
742    }
743
744    /* Create a thread ref that will live beyond */
745    /* the end of this call */
746    saveGlobalRef(env, thread, &(filter->thread));
747    FILTER(node, index).modifier = JDWP_REQUEST_MODIFIER(ThreadOnly);
748    return JVMTI_ERROR_NONE;
749}
750
751jvmtiError
752eventFilter_setLocationOnlyFilter(HandlerNode *node, jint index,
753                                  jclass clazz, jmethodID method,
754                                  jlocation location)
755{
756    JNIEnv *env = getEnv();
757    LocationFilter *filter = &FILTER(node, index).u.LocationOnly;
758    if (index >= FILTER_COUNT(node)) {
759        return AGENT_ERROR_ILLEGAL_ARGUMENT;
760    }
761    if ((NODE_EI(node) != EI_BREAKPOINT) &&
762        (NODE_EI(node) != EI_FIELD_ACCESS) &&
763        (NODE_EI(node) != EI_FIELD_MODIFICATION) &&
764        (NODE_EI(node) != EI_SINGLE_STEP) &&
765        (NODE_EI(node) != EI_EXCEPTION)) {
766
767        return AGENT_ERROR_ILLEGAL_ARGUMENT;
768    }
769
770    /* Create a class ref that will live beyond */
771    /* the end of this call */
772    saveGlobalRef(env, clazz, &(filter->clazz));
773    FILTER(node, index).modifier = JDWP_REQUEST_MODIFIER(LocationOnly);
774    filter->method = method;
775    filter->location = location;
776    return JVMTI_ERROR_NONE;
777}
778
779jvmtiError
780eventFilter_setFieldOnlyFilter(HandlerNode *node, jint index,
781                               jclass clazz, jfieldID field)
782{
783    JNIEnv *env = getEnv();
784    FieldFilter *filter = &FILTER(node, index).u.FieldOnly;
785    if (index >= FILTER_COUNT(node)) {
786        return AGENT_ERROR_ILLEGAL_ARGUMENT;
787    }
788    if ((NODE_EI(node) != EI_FIELD_ACCESS) &&
789        (NODE_EI(node) != EI_FIELD_MODIFICATION)) {
790
791        return AGENT_ERROR_ILLEGAL_ARGUMENT;
792    }
793
794    /* Create a class ref that will live beyond */
795    /* the end of this call */
796    saveGlobalRef(env, clazz, &(filter->clazz));
797    FILTER(node, index).modifier = JDWP_REQUEST_MODIFIER(FieldOnly);
798    filter->field = field;
799    return JVMTI_ERROR_NONE;
800}
801
802jvmtiError
803eventFilter_setClassOnlyFilter(HandlerNode *node, jint index,
804                               jclass clazz)
805{
806    JNIEnv *env = getEnv();
807    ClassFilter *filter = &FILTER(node, index).u.ClassOnly;
808    if (index >= FILTER_COUNT(node)) {
809        return AGENT_ERROR_ILLEGAL_ARGUMENT;
810    }
811    if (
812        (NODE_EI(node) == EI_GC_FINISH) ||
813        (NODE_EI(node) == EI_THREAD_START) ||
814        (NODE_EI(node) == EI_THREAD_END)) {
815
816        return AGENT_ERROR_ILLEGAL_ARGUMENT;
817    }
818
819    /* Create a class ref that will live beyond */
820    /* the end of this call */
821    saveGlobalRef(env, clazz, &(filter->clazz));
822    FILTER(node, index).modifier = JDWP_REQUEST_MODIFIER(ClassOnly);
823    return JVMTI_ERROR_NONE;
824}
825
826jvmtiError
827eventFilter_setExceptionOnlyFilter(HandlerNode *node, jint index,
828                                   jclass exceptionClass,
829                                   jboolean caught,
830                                   jboolean uncaught)
831{
832    JNIEnv *env = getEnv();
833    ExceptionFilter *filter = &FILTER(node, index).u.ExceptionOnly;
834    if (index >= FILTER_COUNT(node)) {
835        return AGENT_ERROR_ILLEGAL_ARGUMENT;
836    }
837    if (NODE_EI(node) != EI_EXCEPTION) {
838        return AGENT_ERROR_ILLEGAL_ARGUMENT;
839    }
840
841    filter->exception = NULL;
842    if (exceptionClass != NULL) {
843        /* Create a class ref that will live beyond */
844        /* the end of this call */
845        saveGlobalRef(env, exceptionClass, &(filter->exception));
846    }
847    FILTER(node, index).modifier =
848                       JDWP_REQUEST_MODIFIER(ExceptionOnly);
849    filter->caught = caught;
850    filter->uncaught = uncaught;
851    return JVMTI_ERROR_NONE;
852}
853
854jvmtiError
855eventFilter_setInstanceOnlyFilter(HandlerNode *node, jint index,
856                                  jobject instance)
857{
858    JNIEnv *env = getEnv();
859    InstanceFilter *filter = &FILTER(node, index).u.InstanceOnly;
860    if (index >= FILTER_COUNT(node)) {
861        return AGENT_ERROR_ILLEGAL_ARGUMENT;
862    }
863
864    filter->instance = NULL;
865    if (instance != NULL) {
866        /* Create an object ref that will live beyond
867         * the end of this call
868         */
869        saveGlobalRef(env, instance, &(filter->instance));
870    }
871    FILTER(node, index).modifier =
872                       JDWP_REQUEST_MODIFIER(InstanceOnly);
873    return JVMTI_ERROR_NONE;
874}
875
876jvmtiError
877eventFilter_setClassMatchFilter(HandlerNode *node, jint index,
878                                char *classPattern)
879{
880    MatchFilter *filter = &FILTER(node, index).u.ClassMatch;
881    if (index >= FILTER_COUNT(node)) {
882        return AGENT_ERROR_ILLEGAL_ARGUMENT;
883    }
884    if (
885        (NODE_EI(node) == EI_THREAD_START) ||
886        (NODE_EI(node) == EI_THREAD_END)) {
887
888        return AGENT_ERROR_ILLEGAL_ARGUMENT;
889    }
890
891    FILTER(node, index).modifier =
892                       JDWP_REQUEST_MODIFIER(ClassMatch);
893    filter->classPattern = classPattern;
894    return JVMTI_ERROR_NONE;
895}
896
897jvmtiError
898eventFilter_setClassExcludeFilter(HandlerNode *node, jint index,
899                                  char *classPattern)
900{
901    MatchFilter *filter = &FILTER(node, index).u.ClassExclude;
902    if (index >= FILTER_COUNT(node)) {
903        return AGENT_ERROR_ILLEGAL_ARGUMENT;
904    }
905    if (
906        (NODE_EI(node) == EI_THREAD_START) ||
907        (NODE_EI(node) == EI_THREAD_END)) {
908
909        return AGENT_ERROR_ILLEGAL_ARGUMENT;
910    }
911
912    FILTER(node, index).modifier =
913                       JDWP_REQUEST_MODIFIER(ClassExclude);
914    filter->classPattern = classPattern;
915    return JVMTI_ERROR_NONE;
916}
917
918jvmtiError
919eventFilter_setStepFilter(HandlerNode *node, jint index,
920                          jthread thread, jint size, jint depth)
921{
922    jvmtiError error;
923    JNIEnv *env = getEnv();
924    StepFilter *filter = &FILTER(node, index).u.Step;
925    if (index >= FILTER_COUNT(node)) {
926        return AGENT_ERROR_ILLEGAL_ARGUMENT;
927    }
928    if (NODE_EI(node) != EI_SINGLE_STEP) {
929        return AGENT_ERROR_ILLEGAL_ARGUMENT;
930    }
931
932    /* Create a thread ref that will live beyond */
933    /* the end of this call */
934    saveGlobalRef(env, thread, &(filter->thread));
935    error = stepControl_beginStep(env, filter->thread, size, depth, node);
936    if (error != JVMTI_ERROR_NONE) {
937        tossGlobalRef(env, &(filter->thread));
938        return error;
939    }
940    FILTER(node, index).modifier = JDWP_REQUEST_MODIFIER(Step);
941    filter->depth = depth;
942    filter->size = size;
943    return JVMTI_ERROR_NONE;
944}
945
946
947jvmtiError
948eventFilter_setSourceNameMatchFilter(HandlerNode *node,
949                                    jint index,
950                                    char *sourceNamePattern) {
951    SourceNameFilter *filter = &FILTER(node, index).u.SourceNameOnly;
952    if (index >= FILTER_COUNT(node)) {
953        return AGENT_ERROR_ILLEGAL_ARGUMENT;
954    }
955    if (NODE_EI(node) != EI_CLASS_PREPARE) {
956        return AGENT_ERROR_ILLEGAL_ARGUMENT;
957    }
958
959    FILTER(node, index).modifier =
960                       JDWP_REQUEST_MODIFIER(SourceNameMatch);
961    filter->sourceNamePattern = sourceNamePattern;
962    return JVMTI_ERROR_NONE;
963
964}
965
966/***** JVMTI event enabling / disabling *****/
967
968/**
969 * Return the Filter that is of the specified type (modifier).
970 * Return NULL if not found.
971 */
972static Filter *
973findFilter(HandlerNode *node, jint modifier)
974{
975    int i;
976    Filter *filter;
977    for (i = 0, filter = FILTERS_ARRAY(node);
978                      i <FILTER_COUNT(node);
979                      i++, filter++) {
980        if (filter->modifier == modifier) {
981            return filter;
982        }
983    }
984    return NULL;
985}
986
987/**
988 * Determine if the specified breakpoint node is in the
989 * same location as the LocationFilter passed in arg.
990 *
991 * This is a match function called by a
992 * eventHandlerRestricted_iterator invokation.
993 */
994static jboolean
995matchBreakpoint(JNIEnv *env, HandlerNode *node, void *arg)
996{
997    LocationFilter *goal = (LocationFilter *)arg;
998    Filter *filter = FILTERS_ARRAY(node);
999    int i;
1000
1001    for (i = 0; i < FILTER_COUNT(node); ++i, ++filter) {
1002        switch (filter->modifier) {
1003        case JDWP_REQUEST_MODIFIER(LocationOnly): {
1004            LocationFilter *trial = &(filter->u.LocationOnly);
1005            if (trial->method == goal->method &&
1006                trial->location == goal->location &&
1007                isSameObject(env, trial->clazz, goal->clazz)) {
1008                return JNI_TRUE;
1009            }
1010        }
1011        }
1012    }
1013    return JNI_FALSE;
1014}
1015
1016/**
1017 * Set a breakpoint if this is the first one at this location.
1018 */
1019static jvmtiError
1020setBreakpoint(HandlerNode *node)
1021{
1022    jvmtiError error = JVMTI_ERROR_NONE;
1023    Filter *filter;
1024
1025    filter = findFilter(node, JDWP_REQUEST_MODIFIER(LocationOnly));
1026    if (filter == NULL) {
1027        /* bp event with no location filter */
1028        error = AGENT_ERROR_INTERNAL;
1029    } else {
1030        LocationFilter *lf = &(filter->u.LocationOnly);
1031
1032        /* if this is the first handler for this
1033         * location, set bp at JVMTI level
1034         */
1035        if (!eventHandlerRestricted_iterator(
1036                EI_BREAKPOINT, matchBreakpoint, lf)) {
1037            LOG_LOC(("SetBreakpoint at location: method=%p,location=%d",
1038                        lf->method, (int)lf->location));
1039            error = JVMTI_FUNC_PTR(gdata->jvmti,SetBreakpoint)
1040                        (gdata->jvmti, lf->method, lf->location);
1041        }
1042    }
1043    return error;
1044}
1045
1046/**
1047 * Clear a breakpoint if this is the last one at this location.
1048 */
1049static jvmtiError
1050clearBreakpoint(HandlerNode *node)
1051{
1052    jvmtiError error = JVMTI_ERROR_NONE;
1053    Filter *filter;
1054
1055    filter = findFilter(node, JDWP_REQUEST_MODIFIER(LocationOnly));
1056    if (filter == NULL) {
1057        /* bp event with no location filter */
1058        error = AGENT_ERROR_INTERNAL;
1059    } else {
1060        LocationFilter *lf = &(filter->u.LocationOnly);
1061
1062        /* if this is the last handler for this
1063         * location, clear bp at JVMTI level
1064         */
1065        if (!eventHandlerRestricted_iterator(
1066                EI_BREAKPOINT, matchBreakpoint, lf)) {
1067            LOG_LOC(("ClearBreakpoint at location: method=%p,location=%d",
1068                        lf->method, (int)lf->location));
1069            error = JVMTI_FUNC_PTR(gdata->jvmti,ClearBreakpoint)
1070                        (gdata->jvmti, lf->method, lf->location);
1071        }
1072    }
1073    return error;
1074}
1075
1076/**
1077 * Return true if a breakpoint is set at the specified location.
1078 */
1079jboolean
1080isBreakpointSet(jclass clazz, jmethodID method, jlocation location)
1081{
1082    LocationFilter lf;
1083
1084    lf.clazz    = clazz;
1085    lf.method   = method;
1086    lf.location = location;
1087
1088    return eventHandlerRestricted_iterator(EI_BREAKPOINT,
1089                                           matchBreakpoint, &lf);
1090}
1091
1092/**
1093 * Determine if the specified watchpoint node has the
1094 * same field as the FieldFilter passed in arg.
1095 *
1096 * This is a match function called by a
1097 * eventHandlerRestricted_iterator invokation.
1098 */
1099static jboolean
1100matchWatchpoint(JNIEnv *env, HandlerNode *node, void *arg)
1101{
1102    FieldFilter *goal = (FieldFilter *)arg;
1103    Filter *filter = FILTERS_ARRAY(node);
1104    int i;
1105
1106    for (i = 0; i < FILTER_COUNT(node); ++i, ++filter) {
1107        switch (filter->modifier) {
1108        case JDWP_REQUEST_MODIFIER(FieldOnly): {
1109            FieldFilter *trial = &(filter->u.FieldOnly);
1110            if (trial->field == goal->field &&
1111                isSameObject(env, trial->clazz, goal->clazz)) {
1112                return JNI_TRUE;
1113            }
1114        }
1115        }
1116    }
1117    return JNI_FALSE;
1118}
1119
1120/**
1121 * Set a watchpoint if this is the first one on this field.
1122 */
1123static jvmtiError
1124setWatchpoint(HandlerNode *node)
1125{
1126    jvmtiError error = JVMTI_ERROR_NONE;
1127    Filter *filter;
1128
1129    filter = findFilter(node, JDWP_REQUEST_MODIFIER(FieldOnly));
1130    if (filter == NULL) {
1131        /* event with no field filter */
1132        error = AGENT_ERROR_INTERNAL;
1133    } else {
1134        FieldFilter *ff = &(filter->u.FieldOnly);
1135
1136        /* if this is the first handler for this
1137         * field, set wp at JVMTI level
1138         */
1139        if (!eventHandlerRestricted_iterator(
1140                NODE_EI(node), matchWatchpoint, ff)) {
1141            error = (NODE_EI(node) == EI_FIELD_ACCESS) ?
1142                JVMTI_FUNC_PTR(gdata->jvmti,SetFieldAccessWatch)
1143                        (gdata->jvmti, ff->clazz, ff->field) :
1144                JVMTI_FUNC_PTR(gdata->jvmti,SetFieldModificationWatch)
1145                        (gdata->jvmti, ff->clazz, ff->field);
1146        }
1147    }
1148    return error;
1149}
1150
1151/**
1152 * Clear a watchpoint if this is the last one on this field.
1153 */
1154static jvmtiError
1155clearWatchpoint(HandlerNode *node)
1156{
1157    jvmtiError error = JVMTI_ERROR_NONE;
1158    Filter *filter;
1159
1160    filter = findFilter(node, JDWP_REQUEST_MODIFIER(FieldOnly));
1161    if (filter == NULL) {
1162        /* event with no field filter */
1163        error = AGENT_ERROR_INTERNAL;
1164    } else {
1165        FieldFilter *ff = &(filter->u.FieldOnly);
1166
1167        /* if this is the last handler for this
1168         * field, clear wp at JVMTI level
1169         */
1170        if (!eventHandlerRestricted_iterator(
1171                NODE_EI(node), matchWatchpoint, ff)) {
1172            error = (NODE_EI(node) == EI_FIELD_ACCESS) ?
1173                JVMTI_FUNC_PTR(gdata->jvmti,ClearFieldAccessWatch)
1174                        (gdata->jvmti, ff->clazz, ff->field) :
1175                JVMTI_FUNC_PTR(gdata->jvmti,ClearFieldModificationWatch)
1176                                (gdata->jvmti, ff->clazz, ff->field);
1177        }
1178    }
1179    return error;
1180}
1181
1182/**
1183 * Determine the thread this node is filtered on.
1184 * NULL if not thread filtered.
1185 */
1186static jthread
1187requestThread(HandlerNode *node)
1188{
1189    int i;
1190    Filter *filter = FILTERS_ARRAY(node);
1191
1192    for (i = 0; i < FILTER_COUNT(node); ++i, ++filter) {
1193        switch (filter->modifier) {
1194            case JDWP_REQUEST_MODIFIER(ThreadOnly):
1195                return filter->u.ThreadOnly.thread;
1196        }
1197    }
1198
1199    return NULL;
1200}
1201
1202/**
1203 * Determine if the specified node has a
1204 * thread filter with the thread passed in arg.
1205 *
1206 * This is a match function called by a
1207 * eventHandlerRestricted_iterator invokation.
1208 */
1209static jboolean
1210matchThread(JNIEnv *env, HandlerNode *node, void *arg)
1211{
1212    jthread goalThread = (jthread)arg;
1213    jthread reqThread = requestThread(node);
1214
1215    /* If the event's thread and the passed thread are the same
1216     * (or both are NULL), we have a match.
1217     */
1218    return isSameObject(env, reqThread, goalThread);
1219}
1220
1221/**
1222 * Do any enabling of events (including setting breakpoints etc)
1223 * needed to get the events requested by this handler node.
1224 */
1225static jvmtiError
1226enableEvents(HandlerNode *node)
1227{
1228    jvmtiError error = JVMTI_ERROR_NONE;
1229
1230    switch (NODE_EI(node)) {
1231        /* The stepping code directly enables/disables stepping as
1232         * necessary
1233         */
1234        case EI_SINGLE_STEP:
1235        /* Internal thread event handlers are always present
1236         * (hardwired in the event hook), so we don't change the
1237         * notification mode here.
1238         */
1239        case EI_THREAD_START:
1240        case EI_THREAD_END:
1241        case EI_VM_INIT:
1242        case EI_VM_DEATH:
1243        case EI_CLASS_PREPARE:
1244        case EI_GC_FINISH:
1245            return error;
1246
1247        case EI_FIELD_ACCESS:
1248        case EI_FIELD_MODIFICATION:
1249            error = setWatchpoint(node);
1250            break;
1251
1252        case EI_BREAKPOINT:
1253            error = setBreakpoint(node);
1254            break;
1255
1256        default:
1257            break;
1258    }
1259
1260    /* Don't globally enable if the above failed */
1261    if (error == JVMTI_ERROR_NONE) {
1262        jthread thread = requestThread(node);
1263
1264        /* If this is the first request of it's kind on this
1265         * thread (or all threads (thread == NULL)) then enable
1266         * these events on this thread.
1267         */
1268        if (!eventHandlerRestricted_iterator(
1269                NODE_EI(node), matchThread, thread)) {
1270            error = threadControl_setEventMode(JVMTI_ENABLE,
1271                                               NODE_EI(node), thread);
1272        }
1273    }
1274    return error;
1275}
1276
1277/**
1278 * Do any disabling of events (including clearing breakpoints etc)
1279 * needed to no longer get the events requested by this handler node.
1280 */
1281static jvmtiError
1282disableEvents(HandlerNode *node)
1283{
1284    jvmtiError error = JVMTI_ERROR_NONE;
1285    jvmtiError error2 = JVMTI_ERROR_NONE;
1286    jthread thread;
1287
1288
1289    switch (NODE_EI(node)) {
1290        /* The stepping code directly enables/disables stepping as
1291         * necessary
1292         */
1293        case EI_SINGLE_STEP:
1294        /* Internal thread event handlers are always present
1295         * (hardwired in the event hook), so we don't change the
1296         * notification mode here.
1297         */
1298        case EI_THREAD_START:
1299        case EI_THREAD_END:
1300        case EI_VM_INIT:
1301        case EI_VM_DEATH:
1302        case EI_CLASS_PREPARE:
1303        case EI_GC_FINISH:
1304            return error;
1305
1306        case EI_FIELD_ACCESS:
1307        case EI_FIELD_MODIFICATION:
1308            error = clearWatchpoint(node);
1309            break;
1310
1311        case EI_BREAKPOINT:
1312            error = clearBreakpoint(node);
1313            break;
1314
1315        default:
1316            break;
1317    }
1318
1319    thread = requestThread(node);
1320
1321    /* If this is the last request of it's kind on this thread
1322     * (or all threads (thread == NULL)) then disable these
1323     * events on this thread.
1324     *
1325     * Disable even if the above caused an error
1326     */
1327    if (!eventHandlerRestricted_iterator(NODE_EI(node), matchThread, thread)) {
1328        error2 = threadControl_setEventMode(JVMTI_DISABLE,
1329                                            NODE_EI(node), thread);
1330    }
1331    return error != JVMTI_ERROR_NONE? error : error2;
1332}
1333
1334
1335/***** filter (and event) installation and deinstallation *****/
1336
1337/**
1338 * Make the set of event filters that correspond with this
1339 * node active (including enabling the corresponding events).
1340 */
1341jvmtiError
1342eventFilterRestricted_install(HandlerNode *node)
1343{
1344    return enableEvents(node);
1345}
1346
1347/**
1348 * Make the set of event filters that correspond with this
1349 * node inactive (including disabling the corresponding events
1350 * and freeing resources).
1351 */
1352jvmtiError
1353eventFilterRestricted_deinstall(HandlerNode *node)
1354{
1355    jvmtiError error1, error2;
1356
1357    error1 = disableEvents(node);
1358    error2 = clearFilters(node);
1359
1360    return error1 != JVMTI_ERROR_NONE? error1 : error2;
1361}
1362