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