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