diff -r fd16c54261b3 -r 90ce3da70b43 jdk/src/share/back/VirtualMachineImpl.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/back/VirtualMachineImpl.c Sat Dec 01 00:00:00 2007 +0000 @@ -0,0 +1,915 @@ +/* + * Copyright 1998-2006 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +#include "util.h" +#include "VirtualMachineImpl.h" +#include "commonRef.h" +#include "inStream.h" +#include "outStream.h" +#include "eventHandler.h" +#include "eventHelper.h" +#include "threadControl.h" +#include "SDE.h" +#include "FrameID.h" + +static char *versionName = "Java Debug Wire Protocol (Reference Implementation)"; +static int majorVersion = 1; /* JDWP major version */ +static int minorVersion = 6; /* JDWP minor version */ + +static jboolean +version(PacketInputStream *in, PacketOutputStream *out) +{ + char buf[500]; + char *vmName; + char *vmVersion; + char *vmInfo; + + if (gdata->vmDead) { + outStream_setError(out, JDWP_ERROR(VM_DEAD)); + return JNI_TRUE; + } + + vmVersion = gdata->property_java_version; + if (vmVersion == NULL) { + vmVersion = ""; + } + vmName = gdata->property_java_vm_name; + if (vmName == NULL) { + vmName = ""; + } + vmInfo = gdata->property_java_vm_info; + if (vmInfo == NULL) { + vmInfo = ""; + } + + /* + * Write the descriptive version information + */ + (void)snprintf(buf, sizeof(buf), + "%s version %d.%d\nJVM Debug Interface version %d.%d\n" + "JVM version %s (%s, %s)", + versionName, majorVersion, minorVersion, + jvmtiMajorVersion(), jvmtiMinorVersion(), + vmVersion, vmName, vmInfo); + (void)outStream_writeString(out, buf); + + /* + * Write the JDWP version numbers + */ + (void)outStream_writeInt(out, majorVersion); + (void)outStream_writeInt(out, minorVersion); + + /* + * Write the VM version and name + */ + (void)outStream_writeString(out, vmVersion); + (void)outStream_writeString(out, vmName); + + return JNI_TRUE; +} + +static jboolean +classesForSignature(PacketInputStream *in, PacketOutputStream *out) +{ + JNIEnv *env; + char *signature; + + if (gdata->vmDead) { + outStream_setError(out, JDWP_ERROR(VM_DEAD)); + return JNI_TRUE; + } + + signature = inStream_readString(in); + if (signature == NULL) { + outStream_setError(out, JDWP_ERROR(OUT_OF_MEMORY)); + return JNI_TRUE; + } + if (inStream_error(in)) { + return JNI_TRUE; + } + + env = getEnv(); + + WITH_LOCAL_REFS(env, 1) { + + jint classCount; + jclass *theClasses; + jvmtiError error; + + error = allLoadedClasses(&theClasses, &classCount); + if ( error == JVMTI_ERROR_NONE ) { + /* Count classes in theClasses which match signature */ + int matchCount = 0; + /* Count classes written to the JDWP connection */ + int writtenCount = 0; + int i; + + for (i=0; ivmDead) { + outStream_setError(out, JDWP_ERROR(VM_DEAD)); + return JNI_TRUE; + } + + env = getEnv(); + + WITH_LOCAL_REFS(env, 1) { + + jint classCount; + jclass *theClasses; + jvmtiError error; + + error = allLoadedClasses(&theClasses, &classCount); + if ( error != JVMTI_ERROR_NONE ) { + outStream_setError(out, map2jdwpError(error)); + } else { + /* Count classes in theClasses which are prepared */ + int prepCount = 0; + /* Count classes written to the JDWP connection */ + int writtenCount = 0; + int i; + + for (i=0; ivmDead) { + outStream_setError(out, JDWP_ERROR(VM_DEAD)); + return JNI_TRUE; + } + + classCount = inStream_readInt(in); + + if (inStream_error(in)) { + return JNI_TRUE; + } + if (classCount == 0) { + (void)outStream_writeInt(out, 0); + return JNI_TRUE; + } + if (classCount < 0) { + outStream_setError(out, JDWP_ERROR(ILLEGAL_ARGUMENT)); + return JNI_TRUE; + } + env = getEnv(); + classes = jvmtiAllocate(classCount * (int)sizeof(jclass)); + for (ii = 0; ii < classCount; ii++) { + jdwpError errorCode; + classes[ii] = inStream_readClassRef(env, in); + errorCode = inStream_error(in); + if (errorCode != JDWP_ERROR(NONE)) { + /* + * A class could have been unloaded/gc'd so + * if we get an error, just ignore it and keep + * going. An instanceCount of 0 will be returned. + */ + if (errorCode == JDWP_ERROR(INVALID_OBJECT) || + errorCode == JDWP_ERROR(INVALID_CLASS)) { + inStream_clearError(in); + classes[ii] = NULL; + continue; + } + jvmtiDeallocate(classes); + return JNI_TRUE; + } + } + + WITH_LOCAL_REFS(env, 1) { + jlong *counts; + jvmtiError error; + + counts = jvmtiAllocate(classCount * (int)sizeof(jlong)); + /* Iterate over heap getting info on these classes */ + error = classInstanceCounts(classCount, classes, counts); + if (error != JVMTI_ERROR_NONE) { + outStream_setError(out, map2jdwpError(error)); + } else { + (void)outStream_writeInt(out, classCount); + for (ii = 0; ii < classCount; ii++) { + (void)outStream_writeLong(out, counts[ii]); + } + } + jvmtiDeallocate(counts); + } END_WITH_LOCAL_REFS(env); + jvmtiDeallocate(classes); + return JNI_TRUE; +} + +static jboolean +redefineClasses(PacketInputStream *in, PacketOutputStream *out) +{ + jvmtiClassDefinition *classDefs; + jboolean ok = JNI_TRUE; + jint classCount; + jint i; + JNIEnv *env; + + if (gdata->vmDead) { + /* quietly ignore */ + return JNI_TRUE; + } + + classCount = inStream_readInt(in); + if (inStream_error(in)) { + return JNI_TRUE; + } + if ( classCount == 0 ) { + return JNI_TRUE; + } + /*LINTED*/ + classDefs = jvmtiAllocate(classCount*(int)sizeof(jvmtiClassDefinition)); + if (classDefs == NULL) { + outStream_setError(out, JDWP_ERROR(OUT_OF_MEMORY)); + return JNI_TRUE; + } + /*LINTED*/ + (void)memset(classDefs, 0, classCount*sizeof(jvmtiClassDefinition)); + + env = getEnv(); + for (i = 0; i < classCount; ++i) { + int byteCount; + unsigned char * bytes; + jclass clazz; + + clazz = inStream_readClassRef(env, in); + if (inStream_error(in)) { + ok = JNI_FALSE; + break; + } + byteCount = inStream_readInt(in); + if (inStream_error(in)) { + ok = JNI_FALSE; + break; + } + if ( byteCount <= 0 ) { + outStream_setError(out, JDWP_ERROR(INVALID_CLASS_FORMAT)); + ok = JNI_FALSE; + break; + } + bytes = (unsigned char *)jvmtiAllocate(byteCount); + if (bytes == NULL) { + outStream_setError(out, JDWP_ERROR(OUT_OF_MEMORY)); + ok = JNI_FALSE; + break; + } + (void)inStream_readBytes(in, byteCount, (jbyte *)bytes); + if (inStream_error(in)) { + ok = JNI_FALSE; + break; + } + + classDefs[i].klass = clazz; + classDefs[i].class_byte_count = byteCount; + classDefs[i].class_bytes = bytes; + } + + if (ok == JNI_TRUE) { + jvmtiError error; + + error = JVMTI_FUNC_PTR(gdata->jvmti,RedefineClasses) + (gdata->jvmti, classCount, classDefs); + if (error != JVMTI_ERROR_NONE) { + outStream_setError(out, map2jdwpError(error)); + } else { + /* zap our BP info */ + for ( i = 0 ; i < classCount; i++ ) { + eventHandler_freeClassBreakpoints(classDefs[i].klass); + } + } + } + + /* free up allocated memory */ + for ( i = 0 ; i < classCount; i++ ) { + if ( classDefs[i].class_bytes != NULL ) { + jvmtiDeallocate((void*)classDefs[i].class_bytes); + } + } + jvmtiDeallocate(classDefs); + + return JNI_TRUE; +} + +static jboolean +setDefaultStratum(PacketInputStream *in, PacketOutputStream *out) +{ + char *stratumId; + + if (gdata->vmDead) { + /* quietly ignore */ + return JNI_TRUE; + } + + stratumId = inStream_readString(in); + if (inStream_error(in)) { + return JNI_TRUE; + } else if (strcmp(stratumId, "") == 0) { + stratumId = NULL; + } + setGlobalStratumId(stratumId); + + return JNI_TRUE; +} + +static jboolean +getAllThreads(PacketInputStream *in, PacketOutputStream *out) +{ + JNIEnv *env; + + if (gdata->vmDead) { + outStream_setError(out, JDWP_ERROR(VM_DEAD)); + return JNI_TRUE; + } + + env = getEnv(); + + WITH_LOCAL_REFS(env, 1) { + + int i; + jint threadCount; + jthread *theThreads; + + theThreads = allThreads(&threadCount); + if (theThreads == NULL) { + outStream_setError(out, JDWP_ERROR(OUT_OF_MEMORY)); + } else { + /* Squish out all of the debugger-spawned threads */ + threadCount = filterDebugThreads(theThreads, threadCount); + + (void)outStream_writeInt(out, threadCount); + for (i = 0; i vmDead) { + outStream_setError(out, JDWP_ERROR(VM_DEAD)); + return JNI_TRUE; + } + + env = getEnv(); + + WITH_LOCAL_REFS(env, 1) { + + jvmtiError error; + jint groupCount; + jthreadGroup *groups; + + groups = NULL; + error = JVMTI_FUNC_PTR(gdata->jvmti,GetTopThreadGroups) + (gdata->jvmti, &groupCount, &groups); + if (error != JVMTI_ERROR_NONE) { + outStream_setError(out, map2jdwpError(error)); + } else { + int i; + + (void)outStream_writeInt(out, groupCount); + for (i = 0; i < groupCount; i++) { + (void)outStream_writeObjectRef(env, out, groups[i]); + } + + jvmtiDeallocate(groups); + } + + } END_WITH_LOCAL_REFS(env); + + return JNI_TRUE; +} + +static jboolean +dispose(PacketInputStream *in, PacketOutputStream *out) +{ + return JNI_TRUE; +} + +static jboolean +idSizes(PacketInputStream *in, PacketOutputStream *out) +{ + (void)outStream_writeInt(out, sizeof(jfieldID)); /* fields */ + (void)outStream_writeInt(out, sizeof(jmethodID)); /* methods */ + (void)outStream_writeInt(out, sizeof(jlong)); /* objects */ + (void)outStream_writeInt(out, sizeof(jlong)); /* referent types */ + (void)outStream_writeInt(out, sizeof(FrameID)); /* frames */ + return JNI_TRUE; +} + +static jboolean +suspend(PacketInputStream *in, PacketOutputStream *out) +{ + jvmtiError error; + + if (gdata->vmDead) { + outStream_setError(out, JDWP_ERROR(VM_DEAD)); + return JNI_TRUE; + } + error = threadControl_suspendAll(); + if (error != JVMTI_ERROR_NONE) { + outStream_setError(out, map2jdwpError(error)); + } + return JNI_TRUE; +} + +static jboolean +resume(PacketInputStream *in, PacketOutputStream *out) +{ + jvmtiError error; + + if (gdata->vmDead) { + outStream_setError(out, JDWP_ERROR(VM_DEAD)); + return JNI_TRUE; + } + error = threadControl_resumeAll(); + if (error != JVMTI_ERROR_NONE) { + outStream_setError(out, map2jdwpError(error)); + } + return JNI_TRUE; +} + +static jboolean +doExit(PacketInputStream *in, PacketOutputStream *out) +{ + jint exitCode; + + exitCode = inStream_readInt(in); + if (gdata->vmDead) { + /* quietly ignore */ + return JNI_FALSE; + } + + /* We send the reply from here because we are about to exit. */ + if (inStream_error(in)) { + outStream_setError(out, inStream_error(in)); + } + outStream_sendReply(out); + + forceExit(exitCode); + + /* Shouldn't get here */ + JDI_ASSERT(JNI_FALSE); + + /* Shut up the compiler */ + return JNI_FALSE; + +} + +static jboolean +createString(PacketInputStream *in, PacketOutputStream *out) +{ + JNIEnv *env; + char *cstring; + + if (gdata->vmDead) { + outStream_setError(out, JDWP_ERROR(VM_DEAD)); + return JNI_TRUE; + } + + cstring = inStream_readString(in); + if (cstring == NULL) { + outStream_setError(out, JDWP_ERROR(OUT_OF_MEMORY)); + return JNI_TRUE; + } + if (inStream_error(in)) { + return JNI_TRUE; + } + + env = getEnv(); + + WITH_LOCAL_REFS(env, 1) { + + jstring string; + + string = JNI_FUNC_PTR(env,NewStringUTF)(env, cstring); + if (JNI_FUNC_PTR(env,ExceptionOccurred)(env)) { + outStream_setError(out, JDWP_ERROR(OUT_OF_MEMORY)); + } else { + (void)outStream_writeObjectRef(env, out, string); + } + + } END_WITH_LOCAL_REFS(env); + + jvmtiDeallocate(cstring); + + return JNI_TRUE; +} + +static jboolean +capabilities(PacketInputStream *in, PacketOutputStream *out) +{ + jvmtiCapabilities caps; + jvmtiError error; + + if (gdata->vmDead) { + outStream_setError(out, JDWP_ERROR(VM_DEAD)); + return JNI_TRUE; + } + error = jvmtiGetCapabilities(&caps); + if (error != JVMTI_ERROR_NONE) { + outStream_setError(out, map2jdwpError(error)); + return JNI_TRUE; + } + + (void)outStream_writeBoolean(out, (jboolean)caps.can_generate_field_modification_events); + (void)outStream_writeBoolean(out, (jboolean)caps.can_generate_field_access_events); + (void)outStream_writeBoolean(out, (jboolean)caps.can_get_bytecodes); + (void)outStream_writeBoolean(out, (jboolean)caps.can_get_synthetic_attribute); + (void)outStream_writeBoolean(out, (jboolean)caps.can_get_owned_monitor_info); + (void)outStream_writeBoolean(out, (jboolean)caps.can_get_current_contended_monitor); + (void)outStream_writeBoolean(out, (jboolean)caps.can_get_monitor_info); + return JNI_TRUE; +} + +static jboolean +capabilitiesNew(PacketInputStream *in, PacketOutputStream *out) +{ + jvmtiCapabilities caps; + jvmtiError error; + + if (gdata->vmDead) { + outStream_setError(out, JDWP_ERROR(VM_DEAD)); + return JNI_TRUE; + } + error = jvmtiGetCapabilities(&caps); + if (error != JVMTI_ERROR_NONE) { + outStream_setError(out, map2jdwpError(error)); + return JNI_TRUE; + } + + (void)outStream_writeBoolean(out, (jboolean)caps.can_generate_field_modification_events); + (void)outStream_writeBoolean(out, (jboolean)caps.can_generate_field_access_events); + (void)outStream_writeBoolean(out, (jboolean)caps.can_get_bytecodes); + (void)outStream_writeBoolean(out, (jboolean)caps.can_get_synthetic_attribute); + (void)outStream_writeBoolean(out, (jboolean)caps.can_get_owned_monitor_info); + (void)outStream_writeBoolean(out, (jboolean)caps.can_get_current_contended_monitor); + (void)outStream_writeBoolean(out, (jboolean)caps.can_get_monitor_info); + + /* new since JDWP version 1.4 */ + (void)outStream_writeBoolean(out, (jboolean)caps.can_redefine_classes); + (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE /* can_add_method */ ); + (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE /* can_unrestrictedly_redefine_classes */ ); + /* 11: canPopFrames */ + (void)outStream_writeBoolean(out, (jboolean)caps.can_pop_frame); + /* 12: canUseInstanceFilters */ + (void)outStream_writeBoolean(out, (jboolean)JNI_TRUE); + /* 13: canGetSourceDebugExtension */ + (void)outStream_writeBoolean(out, (jboolean)caps.can_get_source_debug_extension); + /* 14: canRequestVMDeathEvent */ + (void)outStream_writeBoolean(out, (jboolean)JNI_TRUE); + /* 15: canSetDefaultStratum */ + (void)outStream_writeBoolean(out, (jboolean)JNI_TRUE); + /* 16: canGetInstanceInfo */ + (void)outStream_writeBoolean(out, (jboolean)caps.can_tag_objects); + /* 17: canRequestMonitorEvents */ + (void)outStream_writeBoolean(out, (jboolean)caps.can_generate_monitor_events); + /* 18: canGetMonitorFrameInfo */ + (void)outStream_writeBoolean(out, (jboolean)caps.can_get_owned_monitor_stack_depth_info); + /* remaining reserved */ + (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 19 */ + /* 20 Can get constant pool information */ + (void)outStream_writeBoolean(out, (jboolean)caps.can_get_constant_pool); + /* 21 Can force early return */ + (void)outStream_writeBoolean(out, (jboolean)caps.can_force_early_return); + (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 22 */ + (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 23 */ + (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 24 */ + (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 25 */ + (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 26 */ + (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 27 */ + (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 28 */ + (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 29 */ + (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 30 */ + (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 31 */ + (void)outStream_writeBoolean(out, (jboolean)JNI_FALSE); /* 32 */ + return JNI_TRUE; +} + +static int +countPaths(char *string) { + int cnt = 1; /* always have one */ + char *pos = string; + char *ps; + + ps = gdata->property_path_separator; + if ( ps == NULL ) { + ps = ";"; + } + while ((pos = strchr(pos, ps[0])) != NULL) { + ++cnt; + ++pos; + } + return cnt; +} + +static void +writePaths(PacketOutputStream *out, char *string) { + char *pos; + char *ps; + char *buf; + int npaths; + int i; + + buf = jvmtiAllocate((int)strlen(string)+1); + + npaths = countPaths(string); + (void)outStream_writeInt(out, npaths); + + ps = gdata->property_path_separator; + if ( ps == NULL ) { + ps = ";"; + } + + pos = string; + for ( i = 0 ; i < npaths ; i++ ) { + char *psPos; + int plen; + + psPos = strchr(pos, ps[0]); + if ( psPos == NULL ) { + plen = (int)strlen(pos); + } else { + plen = (int)(psPos-pos); + psPos++; + } + (void)memcpy(buf, pos, plen); + buf[plen] = 0; + (void)outStream_writeString(out, buf); + pos = psPos; + } + + jvmtiDeallocate(buf); +} + + + +static jboolean +classPaths(PacketInputStream *in, PacketOutputStream *out) +{ + char *ud; + char *bp; + char *cp; + + ud = gdata->property_user_dir; + if ( ud == NULL ) { + ud = ""; + } + cp = gdata->property_java_class_path; + if ( cp == NULL ) { + cp = ""; + } + bp = gdata->property_sun_boot_class_path; + if ( bp == NULL ) { + bp = ""; + } + (void)outStream_writeString(out, ud); + writePaths(out, cp); + writePaths(out, bp); + return JNI_TRUE; +} + +static jboolean +disposeObjects(PacketInputStream *in, PacketOutputStream *out) +{ + int i; + int refCount; + jlong id; + int requestCount; + JNIEnv *env; + + if (gdata->vmDead) { + /* quietly ignore */ + return JNI_TRUE; + } + + requestCount = inStream_readInt(in); + if (inStream_error(in)) { + return JNI_TRUE; + } + + env = getEnv(); + for (i = 0; i < requestCount; i++) { + id = inStream_readObjectID(in); + refCount = inStream_readInt(in); + if (inStream_error(in)) { + return JNI_TRUE; + } + commonRef_releaseMultiple(env, id, refCount); + } + + return JNI_TRUE; +} + +static jboolean +holdEvents(PacketInputStream *in, PacketOutputStream *out) +{ + eventHelper_holdEvents(); + return JNI_TRUE; +} + +static jboolean +releaseEvents(PacketInputStream *in, PacketOutputStream *out) +{ + eventHelper_releaseEvents(); + return JNI_TRUE; +} + +void *VirtualMachine_Cmds[] = { (void *)21 + ,(void *)version + ,(void *)classesForSignature + ,(void *)allClasses + ,(void *)getAllThreads + ,(void *)topLevelThreadGroups + ,(void *)dispose + ,(void *)idSizes + ,(void *)suspend + ,(void *)resume + ,(void *)doExit + ,(void *)createString + ,(void *)capabilities + ,(void *)classPaths + ,(void *)disposeObjects + ,(void *)holdEvents + ,(void *)releaseEvents + ,(void *)capabilitiesNew + ,(void *)redefineClasses + ,(void *)setDefaultStratum + ,(void *)allClassesWithGeneric + ,(void *)instanceCounts +};