/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* eventFilter
*
* of the corresponding events. Used for filters on JDI EventRequests
* and also internal requests. Our data is in a private hidden section
* of the HandlerNode's data. See comment for enclosing
* module eventHandler.
*/
#include "util.h"
#include "eventFilter.h"
#include "eventFilterRestricted.h"
#include "eventHandlerRestricted.h"
#include "stepControl.h"
#include "threadControl.h"
#include "SDE.h"
#include "jvmti.h"
typedef struct ClassFilter {
} ClassFilter;
typedef struct LocationFilter {
typedef struct ThreadFilter {
} ThreadFilter;
typedef struct CountFilter {
} CountFilter;
typedef struct ConditionalFilter {
typedef struct FieldFilter {
} FieldFilter;
typedef struct ExceptionFilter {
typedef struct InstanceFilter {
typedef struct StepFilter {
} StepFilter;
typedef struct MatchFilter {
char *classPattern;
} MatchFilter;
typedef struct SourceNameFilter {
char *sourceNamePattern;
typedef struct Filter_ {
union {
} u;
} Filter;
/* The filters array is allocated to the specified filterCount.
* Theoretically, some compiler could do range checking on this
* array - so, we define it to have a ludicrously large size so
* that this range checking won't get upset.
*
* The actual allocated number of bytes is computed using the
* offset of "filters" and so is not effected by this number.
*/
typedef struct EventFilters_ {
} EventFilters;
typedef struct EventFilterPrivate_HandlerNode_ {
/**
* The following macros extract filter info (EventFilters) from private
* data at the end of a HandlerNode
*/
/***** filter set-up / destruction *****/
/**
* Allocate a HandlerNode.
* We do it because eventHandler doesn't know how big to make it.
*/
{
/*LINTED*/
(filterCount * (int)sizeof(Filter));
int i;
/* Initialize all modifiers
*/
i < filterCount;
i++, filter++) {
}
}
return node;
}
/**
* Free up global refs held by the filter.
* free things up at the JNI level if needed.
*/
static jvmtiError
{
jint i;
}
break;
break;
case JDWP_REQUEST_MODIFIER(FieldOnly):
break;
}
break;
}
break;
case JDWP_REQUEST_MODIFIER(ClassOnly):
break;
case JDWP_REQUEST_MODIFIER(ClassMatch):
break;
break;
if (error == JVMTI_ERROR_NONE) {
}
break;
}
}
}
if (error == JVMTI_ERROR_NONE) {
}
return error;
}
/***** filtering *****/
/*
* Match a string against a wildcard
* string pattern.
*/
static jboolean
{
int pattLen;
int compLen;
char *start;
int offset;
return JNI_FALSE;
}
/* An exact match is required when there is no *: bug 4331522 */
} else {
if (offset < 0) {
return JNI_FALSE;
} else {
if (pattern[0] == '*') {
pattern++;
} else {
}
}
}
}
if (err == JVMTI_ERROR_NONE) {
} else {
return JNI_FALSE;
}
}
/* Return the object instance in which the event occurred */
/* Return NULL if static or if an error occurs */
static jobject
{
if (!got_version) {
}
case EI_SINGLE_STEP:
case EI_BREAKPOINT:
case EI_FRAME_POP:
case EI_METHOD_ENTRY:
case EI_METHOD_EXIT:
case EI_EXCEPTION:
case EI_EXCEPTION_CATCH:
case EI_MONITOR_WAIT:
case EI_MONITOR_WAITED:
break;
case EI_FIELD_ACCESS:
case EI_FIELD_MODIFICATION:
return object;
default:
return object; /* NULL */
}
/* fail if error or static (0x8) */
if (is_version_gte_12x) {
/* Use new 1.2.x function, GetLocalInstance */
} else {
/* get slot zero object "this" */
}
if (error != JVMTI_ERROR_NONE) {
}
}
return object;
}
/*
* Determine if this event is interesting to this handler.
* Do so by checking each of the handler's filters.
* Return false if any of the filters fail,
* true if the handler wants this event.
* Anyone modifying this function should check
* eventFilterRestricted_passesUnloadFilter and
* eventFilter_predictFiltering as well.
*
* If shouldDelete is returned true, a count filter has expired
* and the corresponding node should be deleted.
*/
char *classname,
{
int i;
/*
* Suppress most events if they happen in debug threads
*/
return JNI_FALSE;
}
return JNI_FALSE;
}
break;
/* Class filters catch events in the specified
* class and any subclass/subinterface.
*/
return JNI_FALSE;
}
break;
/* This is kinda cheating assumming the event
* fields will be in the same locations, but it is
* true now.
*/
return JNI_FALSE;
}
break;
/* Field watchpoints can be triggered from the
* declared class or any subclass/subinterface.
*/
return JNI_FALSE;
}
break;
return JNI_FALSE;
}
/* do we care about exception class */
/* do we want this exception class */
return JNI_FALSE;
}
}
break;
/* if no error and doesn't match, don't pass
* filter
*/
return JNI_FALSE;
}
break;
}
return JNI_FALSE;
}
*shouldDelete = JNI_TRUE;
break;
}
case JDWP_REQUEST_MODIFIER(Conditional):
/***
if (... filter->u.Conditional.exprID ...) {
return JNI_FALSE;
}
***/
break;
if (!patternStringMatch(classname,
return JNI_FALSE;
}
break;
}
return JNI_FALSE;
}
break;
}
return JNI_FALSE;
}
return JNI_FALSE;
}
break;
desiredNamePattern) == 1) {
/* The name isn't in the SDE; try the sourceName in the ref
* type
*/
char *sourceName = 0;
if (error == JVMTI_ERROR_NONE &&
sourceName != 0 &&
// got a hit - report the event
break;
}
// We have no match, we have no source file name,
// or we got a JVM TI error. Don't report the event.
return JNI_FALSE;
}
break;
}
default:
return JNI_FALSE;
}
}
return JNI_TRUE;
}
/* Determine if this event is interesting to this handler. Do so
* by checking each of the handler's filters. Return false if any
* of the filters fail, true if the handler wants this event.
* Special version of filter for unloads since they don't have an
* event structure or a jclass.
*
* If shouldDelete is returned true, a count filter has expired
* and the corresponding node should be deleted.
*/
char *classname,
{
int i;
return JNI_FALSE;
}
*shouldDelete = JNI_TRUE;
break;
}
if (!patternStringMatch(classname,
return JNI_FALSE;
}
break;
}
return JNI_FALSE;
}
break;
}
default:
return JNI_FALSE;
}
}
return JNI_TRUE;
}
/**
* This function returns true only if it is certain that
* all events for the given node in the given stack frame will
* be filtered. It is used to optimize stepping. (If this
* function returns true the stepping algorithm does not
* have to step through every instruction in this stack frame;
* events.
*/
{
int count;
int i;
}
}
break;
/*
* If preceeding filters have determined that events will
* be filtered out, that is fine and we won't get here.
* However, the count must be decremented - even if
* subsequent filters will filter these events. We
* thus must end now unable to predict
*/
break;
}
if (!patternStringMatch(classname,
}
break;
}
}
break;
}
}
}
return willBeFiltered;
}
/**
* Determine if the given breakpoint node is in the specified class.
*/
{
int i;
}
}
return JNI_TRUE; /* should never come here */
}
/***** filter set-up *****/
{
return AGENT_ERROR_ILLEGAL_ARGUMENT;
}
return JVMTI_ERROR_NONE;
}
{
return AGENT_ERROR_ILLEGAL_ARGUMENT;
}
if (count <= 0) {
return JDWP_ERROR(INVALID_COUNT);
} else {
return JVMTI_ERROR_NONE;
}
}
{
return AGENT_ERROR_ILLEGAL_ARGUMENT;
}
return AGENT_ERROR_ILLEGAL_ARGUMENT;
}
/* Create a thread ref that will live beyond */
/* the end of this call */
return JVMTI_ERROR_NONE;
}
{
return AGENT_ERROR_ILLEGAL_ARGUMENT;
}
return AGENT_ERROR_ILLEGAL_ARGUMENT;
}
/* Create a class ref that will live beyond */
/* the end of this call */
return JVMTI_ERROR_NONE;
}
{
return AGENT_ERROR_ILLEGAL_ARGUMENT;
}
return AGENT_ERROR_ILLEGAL_ARGUMENT;
}
/* Create a class ref that will live beyond */
/* the end of this call */
return JVMTI_ERROR_NONE;
}
{
return AGENT_ERROR_ILLEGAL_ARGUMENT;
}
if (
return AGENT_ERROR_ILLEGAL_ARGUMENT;
}
/* Create a class ref that will live beyond */
/* the end of this call */
return JVMTI_ERROR_NONE;
}
{
return AGENT_ERROR_ILLEGAL_ARGUMENT;
}
return AGENT_ERROR_ILLEGAL_ARGUMENT;
}
if (exceptionClass != NULL) {
/* Create a class ref that will live beyond */
/* the end of this call */
}
return JVMTI_ERROR_NONE;
}
{
return AGENT_ERROR_ILLEGAL_ARGUMENT;
}
/* Create an object ref that will live beyond
* the end of this call
*/
}
return JVMTI_ERROR_NONE;
}
char *classPattern)
{
return AGENT_ERROR_ILLEGAL_ARGUMENT;
}
if (
return AGENT_ERROR_ILLEGAL_ARGUMENT;
}
return JVMTI_ERROR_NONE;
}
char *classPattern)
{
return AGENT_ERROR_ILLEGAL_ARGUMENT;
}
if (
return AGENT_ERROR_ILLEGAL_ARGUMENT;
}
return JVMTI_ERROR_NONE;
}
{
return AGENT_ERROR_ILLEGAL_ARGUMENT;
}
return AGENT_ERROR_ILLEGAL_ARGUMENT;
}
/* Create a thread ref that will live beyond */
/* the end of this call */
if (error != JVMTI_ERROR_NONE) {
return error;
}
return JVMTI_ERROR_NONE;
}
char *sourceNamePattern) {
return AGENT_ERROR_ILLEGAL_ARGUMENT;
}
return AGENT_ERROR_ILLEGAL_ARGUMENT;
}
return JVMTI_ERROR_NONE;
}
/***** JVMTI event enabling / disabling *****/
/**
* Return the Filter that is of the specified type (modifier).
* Return NULL if not found.
*/
static Filter *
{
int i;
i <FILTER_COUNT(node);
i++, filter++) {
return filter;
}
}
return NULL;
}
/**
* Determine if the specified breakpoint node is in the
* same location as the LocationFilter passed in arg.
*
* This is a match function called by a
* eventHandlerRestricted_iterator invokation.
*/
static jboolean
{
int i;
return JNI_TRUE;
}
}
}
}
return JNI_FALSE;
}
/**
* Set a breakpoint if this is the first one at this location.
*/
static jvmtiError
{
/* bp event with no location filter */
} else {
/* if this is the first handler for this
* location, set bp at JVMTI level
*/
LOG_LOC(("SetBreakpoint at location: method=%p,location=%d",
}
}
return error;
}
/**
* Clear a breakpoint if this is the last one at this location.
*/
static jvmtiError
{
/* bp event with no location filter */
} else {
/* if this is the last handler for this
* location, clear bp at JVMTI level
*/
LOG_LOC(("ClearBreakpoint at location: method=%p,location=%d",
}
}
return error;
}
/**
* Return true if a breakpoint is set at the specified location.
*/
{
matchBreakpoint, &lf);
}
/**
* Determine if the specified watchpoint node has the
* same field as the FieldFilter passed in arg.
*
* This is a match function called by a
* eventHandlerRestricted_iterator invokation.
*/
static jboolean
{
int i;
return JNI_TRUE;
}
}
}
}
return JNI_FALSE;
}
/**
* Set a watchpoint if this is the first one on this field.
*/
static jvmtiError
{
/* event with no field filter */
} else {
/* if this is the first handler for this
* field, set wp at JVMTI level
*/
}
}
return error;
}
/**
* Clear a watchpoint if this is the last one on this field.
*/
static jvmtiError
{
/* event with no field filter */
} else {
/* if this is the last handler for this
* field, clear wp at JVMTI level
*/
}
}
return error;
}
/**
* Determine the thread this node is filtered on.
* NULL if not thread filtered.
*/
static jthread
{
int i;
case JDWP_REQUEST_MODIFIER(ThreadOnly):
}
}
return NULL;
}
/**
* Determine if the specified node has a
* thread filter with the thread passed in arg.
*
* This is a match function called by a
* eventHandlerRestricted_iterator invokation.
*/
static jboolean
{
/* If the event's thread and the passed thread are the same
* (or both are NULL), we have a match.
*/
}
/**
* Do any enabling of events (including setting breakpoints etc)
* needed to get the events requested by this handler node.
*/
static jvmtiError
{
* necessary
*/
case EI_SINGLE_STEP:
/* Internal thread event handlers are always present
* (hardwired in the event hook), so we don't change the
* notification mode here.
*/
case EI_THREAD_START:
case EI_THREAD_END:
case EI_VM_INIT:
case EI_VM_DEATH:
case EI_CLASS_PREPARE:
case EI_GC_FINISH:
return error;
case EI_FIELD_ACCESS:
case EI_FIELD_MODIFICATION:
break;
case EI_BREAKPOINT:
break;
default:
break;
}
/* Don't globally enable if the above failed */
if (error == JVMTI_ERROR_NONE) {
/* If this is the first request of it's kind on this
* thread (or all threads (thread == NULL)) then enable
* these events on this thread.
*/
}
}
return error;
}
/**
* Do any disabling of events (including clearing breakpoints etc)
* needed to no longer get the events requested by this handler node.
*/
static jvmtiError
{
* necessary
*/
case EI_SINGLE_STEP:
/* Internal thread event handlers are always present
* (hardwired in the event hook), so we don't change the
* notification mode here.
*/
case EI_THREAD_START:
case EI_THREAD_END:
case EI_VM_INIT:
case EI_VM_DEATH:
case EI_CLASS_PREPARE:
case EI_GC_FINISH:
return error;
case EI_FIELD_ACCESS:
case EI_FIELD_MODIFICATION:
break;
case EI_BREAKPOINT:
break;
default:
break;
}
/* If this is the last request of it's kind on this thread
* (or all threads (thread == NULL)) then disable these
* events on this thread.
*
* Disable even if the above caused an error
*/
}
}
/***** filter (and event) installation and deinstallation *****/
/**
* Make the set of event filters that correspond with this
* node active (including enabling the corresponding events).
*/
{
return enableEvents(node);
}
/**
* Make the set of event filters that correspond with this
* node inactive (including disabling the corresponding events
* and freeing resources).
*/
{
}