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
44 typedef struct ClassFilter {
45 jclass clazz;
46 } ClassFilter;
47
48 typedef struct LocationFilter {
49 jclass clazz;
50 jmethodID method;
51 jlocation location;
52 } LocationFilter;
53
54 typedef struct ThreadFilter {
55 jthread thread;
56 } ThreadFilter;
57
58 typedef struct CountFilter {
59 jint count;
60 } CountFilter;
61
62 typedef struct ConditionalFilter {
63 jint exprID;
64 } ConditionalFilter;
65
66 typedef struct FieldFilter {
67 jclass clazz;
68 jfieldID field;
69 } FieldFilter;
70
71 typedef struct ExceptionFilter {
72 jclass exception;
73 jboolean caught;
74 jboolean uncaught;
75 } ExceptionFilter;
76
77 typedef struct InstanceFilter {
78 jobject instance;
79 } InstanceFilter;
80
81 typedef struct StepFilter {
82 jint size;
83 jint depth;
84 jthread thread;
85 } StepFilter;
86
87 typedef struct MatchFilter {
88 char *classPattern;
89 } MatchFilter;
90
91 typedef struct SourceNameFilter {
92 char *sourceNamePattern;
93 } SourceNameFilter;
94
95 typedef 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
123 typedef struct EventFilters_ {
124 jint filterCount;
125 Filter filters[MAX_FILTERS];
126 } EventFilters;
127
128 typedef 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 */
149 HandlerNode *
eventFilterRestricted_alloc(jint filterCount)150 eventFilterRestricted_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 */
182 static jvmtiError
clearFilters(HandlerNode * node)183 clearFilters(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 */
246 static jboolean
patternStringMatch(char * classname,const char * pattern)247 patternStringMatch(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
isVersionGte12x()279 static 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);
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 */
299 static jobject
eventInstance(EventInfo * evinfo)300 eventInstance(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 */
373 jboolean
eventFilterRestricted_passesFilter(JNIEnv * env,char * classname,EventInfo * evinfo,HandlerNode * node,jboolean * shouldDelete)374 eventFilterRestricted_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 */
561 jboolean
eventFilterRestricted_passesUnloadFilter(JNIEnv * env,char * classname,HandlerNode * node,jboolean * shouldDelete)562 eventFilterRestricted_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 */
616 jboolean
eventFilter_predictFiltering(HandlerNode * node,jclass clazz,char * classname)617 eventFilter_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 */
683 jboolean
eventFilterRestricted_isBreakpointInClass(JNIEnv * env,jclass clazz,HandlerNode * node)684 eventFilterRestricted_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
701 jvmtiError
eventFilter_setConditionalFilter(HandlerNode * node,jint index,jint exprID)702 eventFilter_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
714 jvmtiError
eventFilter_setCountFilter(HandlerNode * node,jint index,jint count)715 eventFilter_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
731 jvmtiError
eventFilter_setThreadOnlyFilter(HandlerNode * node,jint index,jthread thread)732 eventFilter_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
751 jvmtiError
eventFilter_setLocationOnlyFilter(HandlerNode * node,jint index,jclass clazz,jmethodID method,jlocation location)752 eventFilter_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
779 jvmtiError
eventFilter_setFieldOnlyFilter(HandlerNode * node,jint index,jclass clazz,jfieldID field)780 eventFilter_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
802 jvmtiError
eventFilter_setClassOnlyFilter(HandlerNode * node,jint index,jclass clazz)803 eventFilter_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
826 jvmtiError
eventFilter_setExceptionOnlyFilter(HandlerNode * node,jint index,jclass exceptionClass,jboolean caught,jboolean uncaught)827 eventFilter_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
854 jvmtiError
eventFilter_setInstanceOnlyFilter(HandlerNode * node,jint index,jobject instance)855 eventFilter_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
876 jvmtiError
eventFilter_setClassMatchFilter(HandlerNode * node,jint index,char * classPattern)877 eventFilter_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
897 jvmtiError
eventFilter_setClassExcludeFilter(HandlerNode * node,jint index,char * classPattern)898 eventFilter_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
918 jvmtiError
eventFilter_setStepFilter(HandlerNode * node,jint index,jthread thread,jint size,jint depth)919 eventFilter_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
947 jvmtiError
eventFilter_setSourceNameMatchFilter(HandlerNode * node,jint index,char * sourceNamePattern)948 eventFilter_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 */
972 static Filter *
findFilter(HandlerNode * node,jint modifier)973 findFilter(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 */
994 static jboolean
matchBreakpoint(JNIEnv * env,HandlerNode * node,void * arg)995 matchBreakpoint(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 */
1019 static jvmtiError
setBreakpoint(HandlerNode * node)1020 setBreakpoint(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 */
1049 static jvmtiError
clearBreakpoint(HandlerNode * node)1050 clearBreakpoint(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 */
1079 jboolean
isBreakpointSet(jclass clazz,jmethodID method,jlocation location)1080 isBreakpointSet(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 */
1099 static jboolean
matchWatchpoint(JNIEnv * env,HandlerNode * node,void * arg)1100 matchWatchpoint(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 */
1123 static jvmtiError
setWatchpoint(HandlerNode * node)1124 setWatchpoint(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 */
1154 static jvmtiError
clearWatchpoint(HandlerNode * node)1155 clearWatchpoint(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 */
1186 static jthread
requestThread(HandlerNode * node)1187 requestThread(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 */
1209 static jboolean
matchThread(JNIEnv * env,HandlerNode * node,void * arg)1210 matchThread(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 */
1225 static jvmtiError
enableEvents(HandlerNode * node)1226 enableEvents(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 */
1281 static jvmtiError
disableEvents(HandlerNode * node)1282 disableEvents(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 */
1341 jvmtiError
eventFilterRestricted_install(HandlerNode * node)1342 eventFilterRestricted_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 */
1352 jvmtiError
eventFilterRestricted_deinstall(HandlerNode * node)1353 eventFilterRestricted_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