blob: 98ebd225e7b269056dbbf5dca01dae58d78f1c87 [file] [log] [blame]
/*
* 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 "ReferenceTypeImpl.h"
#include "inStream.h"
#include "outStream.h"
static jboolean
signature(PacketInputStream *in, PacketOutputStream *out)
{
char *signature = NULL;
jclass clazz;
jvmtiError error;
clazz = inStream_readClassRef(getEnv(), in);
if (inStream_error(in)) {
return JNI_TRUE;
}
error = classSignature(clazz, &signature, NULL);
if (error != JVMTI_ERROR_NONE) {
outStream_setError(out, map2jdwpError(error));
return JNI_TRUE;
}
(void)outStream_writeString(out, signature);
jvmtiDeallocate(signature);
return JNI_TRUE;
}
static jboolean
signatureWithGeneric(PacketInputStream *in, PacketOutputStream *out)
{
/* Returns both the signature and the generic signature */
char *signature = NULL;
char *genericSignature = NULL;
jclass clazz;
jvmtiError error;
clazz = inStream_readClassRef(getEnv(), in);
if (inStream_error(in)) {
return JNI_TRUE;
}
error = classSignature(clazz, &signature, &genericSignature);
if (error != JVMTI_ERROR_NONE) {
outStream_setError(out, map2jdwpError(error));
return JNI_TRUE;
}
(void)outStream_writeString(out, signature);
writeGenericSignature(out, genericSignature);
jvmtiDeallocate(signature);
if (genericSignature != NULL) {
jvmtiDeallocate(genericSignature);
}
return JNI_TRUE;
}
static jboolean
getClassLoader(PacketInputStream *in, PacketOutputStream *out)
{
jclass clazz;
jobject loader;
jvmtiError error;
JNIEnv *env;
env = getEnv();
clazz = inStream_readClassRef(env, in);
if (inStream_error(in)) {
return JNI_TRUE;
}
error = classLoader(clazz, &loader);
if (error != JVMTI_ERROR_NONE) {
outStream_setError(out, map2jdwpError(error));
return JNI_TRUE;
}
(void)outStream_writeObjectRef(env, out, loader);
return JNI_TRUE;
}
static jboolean
modifiers(PacketInputStream *in, PacketOutputStream *out)
{
jint modifiers;
jclass clazz;
jvmtiError error;
clazz = inStream_readClassRef(getEnv(), in);
if (inStream_error(in)) {
return JNI_TRUE;
}
error = JVMTI_FUNC_PTR(gdata->jvmti,GetClassModifiers)
(gdata->jvmti, clazz, &modifiers);
if (error != JVMTI_ERROR_NONE) {
outStream_setError(out, map2jdwpError(error));
return JNI_TRUE;
}
(void)outStream_writeInt(out, modifiers);
return JNI_TRUE;
}
static void
writeMethodInfo(PacketOutputStream *out, jclass clazz, jmethodID method,
int outputGenerics)
{
char *name = NULL;
char *signature = NULL;
char *genericSignature = NULL;
jint modifiers;
jvmtiError error;
jboolean isSynthetic;
error = isMethodSynthetic(method, &isSynthetic);
if (error != JVMTI_ERROR_NONE) {
outStream_setError(out, map2jdwpError(error));
return;
}
error = methodModifiers(method, &modifiers);
if (error != JVMTI_ERROR_NONE) {
outStream_setError(out, map2jdwpError(error));
return;
}
error = methodSignature(method, &name, &signature, &genericSignature);
if (error != JVMTI_ERROR_NONE) {
outStream_setError(out, map2jdwpError(error));
return;
}
if (isSynthetic) {
modifiers |= MOD_SYNTHETIC;
}
(void)outStream_writeMethodID(out, method);
(void)outStream_writeString(out, name);
(void)outStream_writeString(out, signature);
if (outputGenerics == 1) {
writeGenericSignature(out, genericSignature);
}
(void)outStream_writeInt(out, modifiers);
jvmtiDeallocate(name);
jvmtiDeallocate(signature);
if (genericSignature != NULL) {
jvmtiDeallocate(genericSignature);
}
}
static jboolean
methods1(PacketInputStream *in, PacketOutputStream *out,
int outputGenerics)
{
int i;
jclass clazz;
jint methodCount = 0;
jmethodID *methods = NULL;
jvmtiError error;
clazz = inStream_readClassRef(getEnv(), in);
if (inStream_error(in)) {
return JNI_TRUE;
}
error = JVMTI_FUNC_PTR(gdata->jvmti,GetClassMethods)
(gdata->jvmti, clazz, &methodCount, &methods);
if (error != JVMTI_ERROR_NONE) {
outStream_setError(out, map2jdwpError(error));
return JNI_TRUE;
}
(void)outStream_writeInt(out, methodCount);
for (i = 0; (i < methodCount) && !outStream_error(out); i++) {
writeMethodInfo(out, clazz, methods[i], outputGenerics);
}
/* Free methods array */
if ( methods != NULL ) {
jvmtiDeallocate(methods);
}
return JNI_TRUE;
}
static jboolean
methods(PacketInputStream *in, PacketOutputStream *out,
int outputGenerics)
{
return methods1(in, out, 0);
}
static jboolean
methodsWithGeneric(PacketInputStream *in, PacketOutputStream *out)
{
return methods1(in, out, 1);
}
static jboolean
instances(PacketInputStream *in, PacketOutputStream *out)
{
jint maxInstances;
jclass clazz;
JNIEnv *env;
if (gdata->vmDead) {
outStream_setError(out, JDWP_ERROR(VM_DEAD));
return JNI_TRUE;
}
env = getEnv();
clazz = inStream_readClassRef(env, in);
maxInstances = inStream_readInt(in);
if (inStream_error(in)) {
return JNI_TRUE;
}
WITH_LOCAL_REFS(env, 1) {
jvmtiError error;
ObjectBatch batch;
error = classInstances(clazz, &batch, maxInstances);
if (error != JVMTI_ERROR_NONE) {
outStream_setError(out, map2jdwpError(error));
} else {
int kk;
jbyte typeKey;
(void)outStream_writeInt(out, batch.count);
if (batch.count > 0) {
/*
* They are all instances of this class and will all have
* the same typeKey, so just compute it once.
*/
typeKey = specificTypeKey(env, batch.objects[0]);
for (kk = 0; kk < batch.count; kk++) {
jobject inst;
inst = batch.objects[kk];
(void)outStream_writeByte(out, typeKey);
(void)outStream_writeObjectRef(env, out, inst);
}
}
jvmtiDeallocate(batch.objects);
}
} END_WITH_LOCAL_REFS(env);
return JNI_TRUE;
}
static jboolean
getClassVersion(PacketInputStream *in, PacketOutputStream *out)
{
jclass clazz;
jvmtiError error;
jint majorVersion;
jint minorVersion;
clazz = inStream_readClassRef(getEnv(), in);
if (inStream_error(in)) {
return JNI_TRUE;
}
error = JVMTI_FUNC_PTR(gdata->jvmti, GetClassVersionNumbers)
(gdata->jvmti, clazz, &minorVersion, &majorVersion);
if (error != JVMTI_ERROR_NONE) {
outStream_setError(out, map2jdwpError(error));
return JNI_TRUE;
}
(void)outStream_writeInt(out, majorVersion);
(void)outStream_writeInt(out, minorVersion);
return JNI_TRUE;
}
static jboolean
getConstantPool(PacketInputStream *in, PacketOutputStream *out)
{
jclass clazz;
jvmtiError error;
jint cpCount;
jint cpByteCount;
unsigned char* cpBytesPtr;
clazz = inStream_readClassRef(getEnv(), in);
if (inStream_error(in)) {
return JNI_TRUE;
}
/* Initialize assuming no bytecodes and no error */
error = JVMTI_ERROR_NONE;
cpCount = 0;
cpByteCount = 0;
cpBytesPtr = NULL;
error = JVMTI_FUNC_PTR(gdata->jvmti,GetConstantPool)
(gdata->jvmti, clazz, &cpCount, &cpByteCount, &cpBytesPtr);
if (error != JVMTI_ERROR_NONE) {
outStream_setError(out, map2jdwpError(error));
} else {
(void)outStream_writeInt(out, cpCount);
(void)outStream_writeByteArray(out, cpByteCount, (jbyte *)cpBytesPtr);
jvmtiDeallocate(cpBytesPtr);
}
return JNI_TRUE;
}
static void
writeFieldInfo(PacketOutputStream *out, jclass clazz, jfieldID fieldID,
int outputGenerics)
{
char *name;
char *signature = NULL;
char *genericSignature = NULL;
jint modifiers;
jboolean isSynthetic;
jvmtiError error;
error = isFieldSynthetic(clazz, fieldID, &isSynthetic);
if (error != JVMTI_ERROR_NONE) {
outStream_setError(out, map2jdwpError(error));
return;
}
error = fieldModifiers(clazz, fieldID, &modifiers);
if (error != JVMTI_ERROR_NONE) {
outStream_setError(out, map2jdwpError(error));
return;
}
error = fieldSignature(clazz, fieldID, &name, &signature, &genericSignature);
if (error != JVMTI_ERROR_NONE) {
outStream_setError(out, map2jdwpError(error));
return;
}
if (isSynthetic) {
modifiers |= MOD_SYNTHETIC;
}
(void)outStream_writeFieldID(out, fieldID);
(void)outStream_writeString(out, name);
(void)outStream_writeString(out, signature);
if (outputGenerics == 1) {
writeGenericSignature(out, genericSignature);
}
(void)outStream_writeInt(out, modifiers);
jvmtiDeallocate(name);
jvmtiDeallocate(signature);
if (genericSignature != NULL) {
jvmtiDeallocate(genericSignature);
}
}
static jboolean
fields1(PacketInputStream *in, PacketOutputStream *out, int outputGenerics)
{
int i;
jclass clazz;
jint fieldCount = 0;
jfieldID *fields = NULL;
jvmtiError error;
clazz = inStream_readClassRef(getEnv(), in);
if (inStream_error(in)) {
return JNI_TRUE;
}
error = JVMTI_FUNC_PTR(gdata->jvmti,GetClassFields)
(gdata->jvmti, clazz, &fieldCount, &fields);
if (error != JVMTI_ERROR_NONE) {
outStream_setError(out, map2jdwpError(error));
return JNI_TRUE;
}
(void)outStream_writeInt(out, fieldCount);
for (i = 0; (i < fieldCount) && !outStream_error(out); i++) {
writeFieldInfo(out, clazz, fields[i], outputGenerics);
}
/* Free fields array */
if ( fields != NULL ) {
jvmtiDeallocate(fields);
}
return JNI_TRUE;
}
static jboolean
fields(PacketInputStream *in, PacketOutputStream *out)
{
return fields1(in, out, 0);
}
static jboolean
fieldsWithGeneric(PacketInputStream *in, PacketOutputStream *out)
{
return fields1(in, out, 1);
}
static jboolean
getValues(PacketInputStream *in, PacketOutputStream *out)
{
sharedGetFieldValues(in, out, JNI_TRUE);
return JNI_TRUE;
}
static jboolean
sourceFile(PacketInputStream *in, PacketOutputStream *out)
{
char *fileName;
jvmtiError error;
jclass clazz;
clazz = inStream_readClassRef(getEnv(), in);
if (inStream_error(in)) {
return JNI_TRUE;
}
error = JVMTI_FUNC_PTR(gdata->jvmti,GetSourceFileName)
(gdata->jvmti, clazz, &fileName);
if (error != JVMTI_ERROR_NONE) {
outStream_setError(out, map2jdwpError(error));
return JNI_TRUE;
}
(void)outStream_writeString(out, fileName);
jvmtiDeallocate(fileName);
return JNI_TRUE;
}
static jboolean
sourceDebugExtension(PacketInputStream *in, PacketOutputStream *out)
{
char *extension;
jvmtiError error;
jclass clazz;
clazz = inStream_readClassRef(getEnv(), in);
if (inStream_error(in)) {
return JNI_TRUE;
}
error = getSourceDebugExtension(clazz, &extension);
if (error != JVMTI_ERROR_NONE) {
outStream_setError(out, map2jdwpError(error));
return JNI_TRUE;
}
(void)outStream_writeString(out, extension);
jvmtiDeallocate(extension);
return JNI_TRUE;
}
static jboolean
nestedTypes(PacketInputStream *in, PacketOutputStream *out)
{
JNIEnv *env;
jclass clazz;
env = getEnv();
clazz = inStream_readClassRef(env, in);
if (inStream_error(in)) {
return JNI_TRUE;
}
WITH_LOCAL_REFS(env, 1) {
jvmtiError error;
jint count;
jclass *nested;
error = allNestedClasses(clazz, &nested, &count);
if (error != JVMTI_ERROR_NONE) {
outStream_setError(out, map2jdwpError(error));
} else {
int i;
(void)outStream_writeInt(out, count);
for (i = 0; i < count; i++) {
(void)outStream_writeByte(out, referenceTypeTag(nested[i]));
(void)outStream_writeObjectRef(env, out, nested[i]);
}
if ( nested != NULL ) {
jvmtiDeallocate(nested);
}
}
} END_WITH_LOCAL_REFS(env);
return JNI_TRUE;
}
static jboolean
getClassStatus(PacketInputStream *in, PacketOutputStream *out)
{
jint status;
jclass clazz;
clazz = inStream_readClassRef(getEnv(), in);
if (inStream_error(in)) {
return JNI_TRUE;
}
status = classStatus(clazz);
(void)outStream_writeInt(out, map2jdwpClassStatus(status));
return JNI_TRUE;
}
static jboolean
interfaces(PacketInputStream *in, PacketOutputStream *out)
{
JNIEnv *env;
jclass clazz;
env = getEnv();
clazz = inStream_readClassRef(env, in);
if (inStream_error(in)) {
return JNI_TRUE;
}
WITH_LOCAL_REFS(env, 1) {
jvmtiError error;
jint interfaceCount;
jclass *interfaces;
error = allInterfaces(clazz, &interfaces, &interfaceCount);
if (error != JVMTI_ERROR_NONE) {
outStream_setError(out, map2jdwpError(error));
} else {
int i;
(void)outStream_writeInt(out, interfaceCount);
for (i = 0; i < interfaceCount; i++) {
(void)outStream_writeObjectRef(env, out, interfaces[i]);
}
if ( interfaces != NULL ) {
jvmtiDeallocate(interfaces);
}
}
} END_WITH_LOCAL_REFS(env);
return JNI_TRUE;
}
static jboolean
classObject(PacketInputStream *in, PacketOutputStream *out)
{
jclass clazz;
JNIEnv *env;
env = getEnv();
clazz = inStream_readClassRef(env, in);
if (inStream_error(in)) {
return JNI_TRUE;
}
/*
* In our implementation, the reference type id is the same as the
* class object id, so we bounce it right back.
*
*/
(void)outStream_writeObjectRef(env, out, clazz);
return JNI_TRUE;
}
void *ReferenceType_Cmds[] = { (void *)18
,(void *)signature
,(void *)getClassLoader
,(void *)modifiers
,(void *)fields
,(void *)methods
,(void *)getValues
,(void *)sourceFile
,(void *)nestedTypes
,(void *)getClassStatus
,(void *)interfaces
,(void *)classObject
,(void *)sourceDebugExtension
,(void *)signatureWithGeneric
,(void *)fieldsWithGeneric
,(void *)methodsWithGeneric
,(void *)instances
,(void *)getClassVersion
,(void *)getConstantPool
};