| /* | |
| * Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * 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. | |
| */ | |
| #include "util.h" | |
| #include "EventRequestImpl.h" | |
| #include "eventHandler.h" | |
| #include "inStream.h" | |
| #include "outStream.h" | |
| #include "stepControl.h" | |
| /** | |
| * Take JDWP "modifiers" (which are JDI explicit filters, like | |
| * addCountFilter(), and implicit filters, like the LocationOnly | |
| * filter that goes with breakpoints) and add them as filters | |
| * (eventFilter) to the HandlerNode (eventHandler). | |
| */ | |
| static jdwpError | |
| readAndSetFilters(JNIEnv *env, PacketInputStream *in, HandlerNode *node, | |
| jint filterCount) | |
| { | |
| int i; | |
| jdwpError serror = JDWP_ERROR(NONE); | |
| for (i = 0; i < filterCount; ++i) { | |
| jbyte modifier; | |
| modifier = inStream_readByte(in); | |
| if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) ) | |
| break; | |
| switch (modifier) { | |
| case JDWP_REQUEST_MODIFIER(Conditional): { | |
| jint exprID; | |
| exprID = inStream_readInt(in); | |
| if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) ) | |
| break; | |
| serror = map2jdwpError( | |
| eventFilter_setConditionalFilter(node, i, exprID)); | |
| break; | |
| } | |
| case JDWP_REQUEST_MODIFIER(Count): { | |
| jint count; | |
| count = inStream_readInt(in); | |
| if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) ) | |
| break; | |
| serror = map2jdwpError( | |
| eventFilter_setCountFilter(node, i, count)); | |
| break; | |
| } | |
| case JDWP_REQUEST_MODIFIER(ThreadOnly): { | |
| jthread thread; | |
| thread = inStream_readThreadRef(env, in); | |
| if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) ) | |
| break; | |
| serror = map2jdwpError( | |
| eventFilter_setThreadOnlyFilter(node, i, thread)); | |
| break; | |
| } | |
| case JDWP_REQUEST_MODIFIER(LocationOnly): { | |
| jbyte tag; | |
| jclass clazz; | |
| jmethodID method; | |
| jlocation location; | |
| tag = inStream_readByte(in); /* not currently used */ | |
| tag = tag; /* To shut up lint */ | |
| if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) ) | |
| break; | |
| clazz = inStream_readClassRef(env, in); | |
| if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) ) | |
| break; | |
| method = inStream_readMethodID(in); | |
| if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) ) | |
| break; | |
| location = inStream_readLocation(in); | |
| if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) ) | |
| break; | |
| serror = map2jdwpError( | |
| eventFilter_setLocationOnlyFilter(node, i, clazz, method, location)); | |
| break; | |
| } | |
| case JDWP_REQUEST_MODIFIER(FieldOnly): { | |
| jclass clazz; | |
| jfieldID field; | |
| clazz = inStream_readClassRef(env, in); | |
| if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) ) | |
| break; | |
| field = inStream_readFieldID(in); | |
| if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) ) | |
| break; | |
| serror = map2jdwpError( | |
| eventFilter_setFieldOnlyFilter(node, i, clazz, field)); | |
| break; | |
| } | |
| case JDWP_REQUEST_MODIFIER(ClassOnly): { | |
| jclass clazz; | |
| clazz = inStream_readClassRef(env, in); | |
| if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) ) | |
| break; | |
| serror = map2jdwpError( | |
| eventFilter_setClassOnlyFilter(node, i, clazz)); | |
| break; | |
| } | |
| case JDWP_REQUEST_MODIFIER(ExceptionOnly): { | |
| jclass exception; | |
| jboolean caught; | |
| jboolean uncaught; | |
| exception = inStream_readClassRef(env, in); | |
| if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) ) | |
| break; | |
| caught = inStream_readBoolean(in); | |
| if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) ) | |
| break; | |
| uncaught = inStream_readBoolean(in); | |
| if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) ) | |
| break; | |
| serror = map2jdwpError( | |
| eventFilter_setExceptionOnlyFilter(node, i, | |
| exception, caught, uncaught)); | |
| break; | |
| } | |
| case JDWP_REQUEST_MODIFIER(InstanceOnly): { | |
| jobject instance; | |
| instance = inStream_readObjectRef(env, in); | |
| if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) ) | |
| break; | |
| serror = map2jdwpError( | |
| eventFilter_setInstanceOnlyFilter(node, i, instance)); | |
| break; | |
| } | |
| case JDWP_REQUEST_MODIFIER(ClassMatch): { | |
| char *pattern; | |
| pattern = inStream_readString(in); | |
| if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) ) | |
| break; | |
| serror = map2jdwpError( | |
| eventFilter_setClassMatchFilter(node, i, | |
| pattern)); | |
| break; | |
| } | |
| case JDWP_REQUEST_MODIFIER(ClassExclude): { | |
| char *pattern; | |
| pattern = inStream_readString(in); | |
| if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) ) | |
| break; | |
| serror = map2jdwpError( | |
| eventFilter_setClassExcludeFilter(node, i, pattern)); | |
| break; | |
| } | |
| case JDWP_REQUEST_MODIFIER(Step): { | |
| jthread thread; | |
| jint size; | |
| jint depth; | |
| thread = inStream_readThreadRef(env, in); | |
| if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) ) | |
| break; | |
| size = inStream_readInt(in); | |
| if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) ) | |
| break; | |
| depth = inStream_readInt(in); | |
| if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) ) | |
| break; | |
| serror = map2jdwpError( | |
| eventFilter_setStepFilter(node, i, thread, size, depth)); | |
| break; | |
| } | |
| case JDWP_REQUEST_MODIFIER(SourceNameMatch): { | |
| char *sourceNamePattern; | |
| sourceNamePattern = inStream_readString(in); | |
| if ( (serror = inStream_error(in)) != JDWP_ERROR(NONE) ) { | |
| break; | |
| } | |
| serror = map2jdwpError( | |
| eventFilter_setSourceNameMatchFilter(node, i, sourceNamePattern)); | |
| break; | |
| } | |
| default: | |
| serror = JDWP_ERROR(ILLEGAL_ARGUMENT); | |
| break; | |
| } | |
| if ( serror != JDWP_ERROR(NONE) ) | |
| break; | |
| } | |
| return serror; | |
| } | |
| /** | |
| * This is the back-end implementation for enabling | |
| * (what are at the JDI level) EventRequests. | |
| * | |
| * Allocate the event request handler (eventHandler). | |
| * Add any filters (explicit or implicit). | |
| * Install the handler. | |
| * Return the handlerID which is used to map subsequent | |
| * events to the EventRequest that created it. | |
| */ | |
| static jboolean | |
| setCommand(PacketInputStream *in, PacketOutputStream *out) | |
| { | |
| jdwpError serror; | |
| HandlerNode *node; | |
| HandlerID requestID = -1; | |
| jdwpEvent eventType; | |
| jbyte suspendPolicy; | |
| jint filterCount; | |
| EventIndex ei; | |
| node = NULL; | |
| eventType = inStream_readByte(in); | |
| if (inStream_error(in)) { | |
| return JNI_TRUE; | |
| } | |
| suspendPolicy = inStream_readByte(in); | |
| if (inStream_error(in)) { | |
| return JNI_TRUE; | |
| } | |
| filterCount = inStream_readInt(in); | |
| if (inStream_error(in)) { | |
| return JNI_TRUE; | |
| } | |
| ei = jdwp2EventIndex(eventType); | |
| if (ei == 0) { | |
| outStream_setError(out, JDWP_ERROR(INVALID_EVENT_TYPE)); | |
| return JNI_TRUE; | |
| } | |
| if (ei == EI_VM_INIT) { | |
| /* | |
| * VM is already initialized so there's no need to install a handler | |
| * for this event. However we need to allocate a requestID to send in | |
| * the reply to the debugger. | |
| */ | |
| serror = JDWP_ERROR(NONE); | |
| requestID = eventHandler_allocHandlerID(); | |
| } else { | |
| node = eventHandler_alloc(filterCount, ei, suspendPolicy); | |
| if (node == NULL) { | |
| outStream_setError(out, JDWP_ERROR(OUT_OF_MEMORY)); | |
| return JNI_TRUE; | |
| } | |
| if (eventType == JDWP_EVENT(METHOD_EXIT_WITH_RETURN_VALUE)) { | |
| node->needReturnValue = 1; | |
| } else { | |
| node->needReturnValue = 0; | |
| } | |
| serror = readAndSetFilters(getEnv(), in, node, filterCount); | |
| if (serror == JDWP_ERROR(NONE)) { | |
| jvmtiError error; | |
| error = eventHandler_installExternal(node); | |
| serror = map2jdwpError(error); | |
| if (serror == JDWP_ERROR(NONE)) { | |
| requestID = node->handlerID; | |
| } | |
| } | |
| } | |
| if (serror == JDWP_ERROR(NONE)) { | |
| (void)outStream_writeInt(out, requestID); | |
| } else { | |
| (void)eventHandler_free(node); | |
| outStream_setError(out, serror); | |
| } | |
| return JNI_TRUE; | |
| } | |
| /** | |
| * This is the back-end implementation for disabling | |
| * (what are at the JDI level) EventRequests. | |
| */ | |
| static jboolean | |
| clearCommand(PacketInputStream *in, PacketOutputStream *out) | |
| { | |
| jvmtiError error; | |
| jdwpEvent eventType; | |
| HandlerID handlerID; | |
| EventIndex ei; | |
| eventType = inStream_readByte(in); | |
| if (inStream_error(in)) { | |
| return JNI_TRUE; | |
| } | |
| handlerID = inStream_readInt(in); | |
| if (inStream_error(in)) { | |
| return JNI_TRUE; | |
| } | |
| ei = jdwp2EventIndex(eventType); | |
| if (ei == 0) { | |
| /* NOTE: Clear command not yet spec'ed to return INVALID_EVENT_TYPE */ | |
| outStream_setError(out, JDWP_ERROR(INVALID_EVENT_TYPE)); | |
| return JNI_TRUE; | |
| } | |
| error = eventHandler_freeByID(ei, handlerID); | |
| if (error != JVMTI_ERROR_NONE) { | |
| outStream_setError(out, map2jdwpError(error)); | |
| } | |
| return JNI_TRUE; | |
| } | |
| static jboolean | |
| clearAllBreakpoints(PacketInputStream *in, PacketOutputStream *out) | |
| { | |
| jvmtiError error; | |
| error = eventHandler_freeAll(EI_BREAKPOINT); | |
| if (error != JVMTI_ERROR_NONE) { | |
| outStream_setError(out, map2jdwpError(error)); | |
| } | |
| return JNI_TRUE; | |
| } | |
| void *EventRequest_Cmds[] = { (void *)0x3 | |
| ,(void *)setCommand | |
| ,(void *)clearCommand | |
| ,(void *)clearAllBreakpoints}; |