/* * Copyright (c) 1998, 2008, 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 "ThreadReferenceImpl.h" #include "eventHandler.h" #include "threadControl.h" #include "inStream.h" #include "outStream.h" #include "FrameID.h" static jboolean name(PacketInputStream *in, PacketOutputStream *out) { JNIEnv *env; jthread thread; env = getEnv(); thread = inStream_readThreadRef(env, in); if (inStream_error(in)) { return JNI_TRUE; } if (threadControl_isDebugThread(thread)) { outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); return JNI_TRUE; } WITH_LOCAL_REFS(env, 1) { jvmtiThreadInfo info; jvmtiError error; (void)memset(&info, 0, sizeof(info)); error = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadInfo) (gdata->jvmti, thread, &info); if (error != JVMTI_ERROR_NONE) { outStream_setError(out, map2jdwpError(error)); } else { (void)outStream_writeString(out, info.name); } if ( info.name != NULL ) jvmtiDeallocate(info.name); } END_WITH_LOCAL_REFS(env); return JNI_TRUE; } static jboolean suspend(PacketInputStream *in, PacketOutputStream *out) { jvmtiError error; jthread thread; thread = inStream_readThreadRef(getEnv(), in); if (inStream_error(in)) { return JNI_TRUE; } if (threadControl_isDebugThread(thread)) { outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); return JNI_TRUE; } error = threadControl_suspendThread(thread, JNI_FALSE); if (error != JVMTI_ERROR_NONE) { outStream_setError(out, map2jdwpError(error)); } return JNI_TRUE; } static jboolean resume(PacketInputStream *in, PacketOutputStream *out) { jvmtiError error; jthread thread; thread = inStream_readThreadRef(getEnv(), in); if (inStream_error(in)) { return JNI_TRUE; } if (threadControl_isDebugThread(thread)) { outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); return JNI_TRUE; } /* true means it is okay to unblock the commandLoop thread */ error = threadControl_resumeThread(thread, JNI_TRUE); if (error != JVMTI_ERROR_NONE) { outStream_setError(out, map2jdwpError(error)); } return JNI_TRUE; } static jboolean status(PacketInputStream *in, PacketOutputStream *out) { jdwpThreadStatus threadStatus; jint statusFlags; jvmtiError error; jthread thread; thread = inStream_readThreadRef(getEnv(), in); if (inStream_error(in)) { return JNI_TRUE; } if (threadControl_isDebugThread(thread)) { outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); return JNI_TRUE; } error = threadControl_applicationThreadStatus(thread, &threadStatus, &statusFlags); if (error != JVMTI_ERROR_NONE) { outStream_setError(out, map2jdwpError(error)); return JNI_TRUE; } (void)outStream_writeInt(out, threadStatus); (void)outStream_writeInt(out, statusFlags); return JNI_TRUE; } static jboolean threadGroup(PacketInputStream *in, PacketOutputStream *out) { JNIEnv *env; jthread thread; env = getEnv(); thread = inStream_readThreadRef(env, in); if (inStream_error(in)) { return JNI_TRUE; } if (threadControl_isDebugThread(thread)) { outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); return JNI_TRUE; } WITH_LOCAL_REFS(env, 1) { jvmtiThreadInfo info; jvmtiError error; (void)memset(&info, 0, sizeof(info)); error = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadInfo) (gdata->jvmti, thread, &info); if (error != JVMTI_ERROR_NONE) { outStream_setError(out, map2jdwpError(error)); } else { (void)outStream_writeObjectRef(env, out, info.thread_group); } if ( info.name!=NULL ) jvmtiDeallocate(info.name); } END_WITH_LOCAL_REFS(env); return JNI_TRUE; } static jboolean validateSuspendedThread(PacketOutputStream *out, jthread thread) { jvmtiError error; jint count; error = threadControl_suspendCount(thread, &count); if (error != JVMTI_ERROR_NONE) { outStream_setError(out, map2jdwpError(error)); return JNI_FALSE; } if (count == 0) { outStream_setError(out, JDWP_ERROR(THREAD_NOT_SUSPENDED)); return JNI_FALSE; } return JNI_TRUE; } static jboolean frames(PacketInputStream *in, PacketOutputStream *out) { jvmtiError error; FrameNumber fnum; jint count; JNIEnv *env; jthread thread; jint startIndex; jint length; env = getEnv(); thread = inStream_readThreadRef(env, in); if (inStream_error(in)) { return JNI_TRUE; } startIndex = inStream_readInt(in); if (inStream_error(in)) { return JNI_TRUE; } length = inStream_readInt(in); if (inStream_error(in)) { return JNI_TRUE; } if (threadControl_isDebugThread(thread)) { outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); return JNI_TRUE; } if (!validateSuspendedThread(out, thread)) { return JNI_TRUE; } error = JVMTI_FUNC_PTR(gdata->jvmti,GetFrameCount) (gdata->jvmti, thread, &count); if (error != JVMTI_ERROR_NONE) { outStream_setError(out, map2jdwpError(error)); return JNI_TRUE; } if (length == -1) { length = count - startIndex; } if (length == 0) { (void)outStream_writeInt(out, 0); return JNI_TRUE; } if ((startIndex < 0) || (startIndex > count - 1)) { outStream_setError(out, JDWP_ERROR(INVALID_INDEX)); return JNI_TRUE; } if ((length < 0) || (length + startIndex > count)) { outStream_setError(out, JDWP_ERROR(INVALID_LENGTH)); return JNI_TRUE; } (void)outStream_writeInt(out, length); for(fnum = startIndex ; fnum < startIndex+length ; fnum++ ) { WITH_LOCAL_REFS(env, 1) { jclass clazz; jmethodID method; jlocation location; /* Get location info */ error = JVMTI_FUNC_PTR(gdata->jvmti,GetFrameLocation) (gdata->jvmti, thread, fnum, &method, &location); if (error == JVMTI_ERROR_OPAQUE_FRAME) { clazz = NULL; location = -1L; error = JVMTI_ERROR_NONE; } else if ( error == JVMTI_ERROR_NONE ) { error = methodClass(method, &clazz); if ( error == JVMTI_ERROR_NONE ) { FrameID frame; frame = createFrameID(thread, fnum); (void)outStream_writeFrameID(out, frame); writeCodeLocation(out, clazz, method, location); } } } END_WITH_LOCAL_REFS(env); if (error != JVMTI_ERROR_NONE) break; } if (error != JVMTI_ERROR_NONE) { outStream_setError(out, map2jdwpError(error)); } return JNI_TRUE; } static jboolean getFrameCount(PacketInputStream *in, PacketOutputStream *out) { jvmtiError error; jint count; jthread thread; thread = inStream_readThreadRef(getEnv(), in); if (inStream_error(in)) { return JNI_TRUE; } if (threadControl_isDebugThread(thread)) { outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); return JNI_TRUE; } if (!validateSuspendedThread(out, thread)) { return JNI_TRUE; } error = JVMTI_FUNC_PTR(gdata->jvmti,GetFrameCount) (gdata->jvmti, thread, &count); if (error != JVMTI_ERROR_NONE) { outStream_setError(out, map2jdwpError(error)); return JNI_TRUE; } (void)outStream_writeInt(out, count); return JNI_TRUE; } static jboolean ownedMonitors(PacketInputStream *in, PacketOutputStream *out) { JNIEnv *env; jthread thread; env = getEnv(); thread = inStream_readThreadRef(env, in); if (inStream_error(in)) { return JNI_TRUE; } if (threadControl_isDebugThread(thread)) { outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); return JNI_TRUE; } if (!validateSuspendedThread(out, thread)) { return JNI_TRUE; } WITH_LOCAL_REFS(env, 1) { jvmtiError error; jint count = 0; jobject *monitors = NULL; error = JVMTI_FUNC_PTR(gdata->jvmti,GetOwnedMonitorInfo) (gdata->jvmti, thread, &count, &monitors); if (error != JVMTI_ERROR_NONE) { outStream_setError(out, map2jdwpError(error)); } else { int i; (void)outStream_writeInt(out, count); for (i = 0; i < count; i++) { jobject monitor = monitors[i]; (void)outStream_writeByte(out, specificTypeKey(env, monitor)); (void)outStream_writeObjectRef(env, out, monitor); } } if (monitors != NULL) jvmtiDeallocate(monitors); } END_WITH_LOCAL_REFS(env); return JNI_TRUE; } static jboolean currentContendedMonitor(PacketInputStream *in, PacketOutputStream *out) { JNIEnv *env; jthread thread; env = getEnv(); thread = inStream_readThreadRef(env, in); if (inStream_error(in)) { return JNI_TRUE; } if (thread == NULL || threadControl_isDebugThread(thread)) { outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); return JNI_TRUE; } if (!validateSuspendedThread(out, thread)) { return JNI_TRUE; } WITH_LOCAL_REFS(env, 1) { jobject monitor; jvmtiError error; error = JVMTI_FUNC_PTR(gdata->jvmti,GetCurrentContendedMonitor) (gdata->jvmti, thread, &monitor); if (error != JVMTI_ERROR_NONE) { outStream_setError(out, map2jdwpError(error)); } else { (void)outStream_writeByte(out, specificTypeKey(env, monitor)); (void)outStream_writeObjectRef(env, out, monitor); } } END_WITH_LOCAL_REFS(env); return JNI_TRUE; } static jboolean stop(PacketInputStream *in, PacketOutputStream *out) { jvmtiError error; jthread thread; jobject throwable; JNIEnv *env; env = getEnv(); thread = inStream_readThreadRef(env, in); if (inStream_error(in)) { return JNI_TRUE; } throwable = inStream_readObjectRef(env, in); if (inStream_error(in)) { return JNI_TRUE; } if (threadControl_isDebugThread(thread)) { outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); return JNI_TRUE; } error = threadControl_stop(thread, throwable); if (error != JVMTI_ERROR_NONE) { outStream_setError(out, map2jdwpError(error)); } return JNI_TRUE; } static jboolean interrupt(PacketInputStream *in, PacketOutputStream *out) { jvmtiError error; jthread thread; thread = inStream_readThreadRef(getEnv(), in); if (inStream_error(in)) { return JNI_TRUE; } if (threadControl_isDebugThread(thread)) { outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); return JNI_TRUE; } error = threadControl_interrupt(thread); if (error != JVMTI_ERROR_NONE) { outStream_setError(out, map2jdwpError(error)); } return JNI_TRUE; } static jboolean suspendCount(PacketInputStream *in, PacketOutputStream *out) { jvmtiError error; jint count; jthread thread; thread = inStream_readThreadRef(getEnv(), in); if (inStream_error(in)) { return JNI_TRUE; } if (threadControl_isDebugThread(thread)) { outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); return JNI_TRUE; } error = threadControl_suspendCount(thread, &count); if (error != JVMTI_ERROR_NONE) { outStream_setError(out, map2jdwpError(error)); return JNI_TRUE; } (void)outStream_writeInt(out, count); return JNI_TRUE; } static jboolean ownedMonitorsWithStackDepth(PacketInputStream *in, PacketOutputStream *out) { JNIEnv *env; jthread thread; thread = inStream_readThreadRef(getEnv(), in); if (inStream_error(in)) { return JNI_TRUE; } if (thread == NULL || threadControl_isDebugThread(thread)) { outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); return JNI_TRUE; } if (!validateSuspendedThread(out, thread)) { return JNI_TRUE; } env = getEnv(); WITH_LOCAL_REFS(env, 1) { jvmtiError error = JVMTI_ERROR_NONE; jint count = 0; jvmtiMonitorStackDepthInfo *monitors=NULL; error = JVMTI_FUNC_PTR(gdata->jvmti,GetOwnedMonitorStackDepthInfo) (gdata->jvmti, thread, &count, &monitors); if (error != JVMTI_ERROR_NONE) { outStream_setError(out, map2jdwpError(error)); } else { int i; (void)outStream_writeInt(out, count); for (i = 0; i < count; i++) { jobject monitor = monitors[i].monitor; (void)outStream_writeByte(out, specificTypeKey(env, monitor)); (void)outStream_writeObjectRef(getEnv(), out, monitor); (void)outStream_writeInt(out,monitors[i].stack_depth); } } if (monitors != NULL) { jvmtiDeallocate(monitors); } } END_WITH_LOCAL_REFS(env); return JNI_TRUE; } static jboolean forceEarlyReturn(PacketInputStream *in, PacketOutputStream *out) { JNIEnv *env; jthread thread; jvalue value; jbyte typeKey; jvmtiError error; env = getEnv(); thread = inStream_readThreadRef(env, in); if (inStream_error(in)) { return JNI_TRUE; } if (threadControl_isDebugThread(thread)) { outStream_setError(out, JDWP_ERROR(INVALID_THREAD)); return JNI_TRUE; } typeKey = inStream_readByte(in); if (inStream_error(in)) { return JNI_TRUE; } if (isObjectTag(typeKey)) { value.l = inStream_readObjectRef(env, in); error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnObject) (gdata->jvmti, thread, value.l); } else { switch (typeKey) { case JDWP_TAG(VOID): error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnVoid) (gdata->jvmti, thread); break; case JDWP_TAG(BYTE): value.b = inStream_readByte(in); error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnInt) (gdata->jvmti, thread, value.b); break; case JDWP_TAG(CHAR): value.c = inStream_readChar(in); error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnInt) (gdata->jvmti, thread, value.c); break; case JDWP_TAG(FLOAT): value.f = inStream_readFloat(in); error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnFloat) (gdata->jvmti, thread, value.f); break; case JDWP_TAG(DOUBLE): value.d = inStream_readDouble(in); error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnDouble) (gdata->jvmti, thread, value.d); break; case JDWP_TAG(INT): value.i = inStream_readInt(in); error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnInt) (gdata->jvmti, thread, value.i); break; case JDWP_TAG(LONG): value.j = inStream_readLong(in); error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnLong) (gdata->jvmti, thread, value.j); break; case JDWP_TAG(SHORT): value.s = inStream_readShort(in); error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnInt) (gdata->jvmti, thread, value.s); break; case JDWP_TAG(BOOLEAN): value.z = inStream_readBoolean(in); error = JVMTI_FUNC_PTR(gdata->jvmti,ForceEarlyReturnInt) (gdata->jvmti, thread, value.z); break; default: error = AGENT_ERROR_INVALID_TAG; break; } } { jdwpError serror = map2jdwpError(error); if (serror != JDWP_ERROR(NONE)) { outStream_setError(out, serror); } } return JNI_TRUE; } void *ThreadReference_Cmds[] = { (void *)14, (void *)name, (void *)suspend, (void *)resume, (void *)status, (void *)threadGroup, (void *)frames, (void *)getFrameCount, (void *)ownedMonitors, (void *)currentContendedMonitor, (void *)stop, (void *)interrupt, (void *)suspendCount, (void *)ownedMonitorsWithStackDepth, (void *)forceEarlyReturn };