1 /* 2 * Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include "util.h" 27 #include "MethodImpl.h" 28 #include "inStream.h" 29 #include "outStream.h" 30 31 static jboolean 32 lineTable(PacketInputStream *in, PacketOutputStream *out) 33 { 34 jvmtiError error; 35 jint count = 0; 36 jvmtiLineNumberEntry *table = NULL; 37 jmethodID method; 38 jlocation firstCodeIndex; 39 jlocation lastCodeIndex; 40 jboolean isNative; 41 42 /* JVMDI needed the class, but JVMTI does not so we ignore it */ 43 (void)inStream_readClassRef(getEnv(), in); 44 if (inStream_error(in)) { 45 return JNI_TRUE; 46 } 47 method = inStream_readMethodID(in); 48 if (inStream_error(in)) { 49 return JNI_TRUE; 50 } 51 52 /* 53 * JVMTI behavior for the calls below is unspecified for native 54 * methods, so we must check explicitly. 55 */ 56 isNative = isMethodNative(method); 57 if (isNative) { 58 outStream_setError(out, JDWP_ERROR(NATIVE_METHOD)); 59 return JNI_TRUE; 60 } 61 62 error = methodLocation(method, &firstCodeIndex, &lastCodeIndex); 63 if (error != JVMTI_ERROR_NONE) { 64 outStream_setError(out, map2jdwpError(error)); 65 return JNI_TRUE; 66 } 67 (void)outStream_writeLocation(out, firstCodeIndex); 68 (void)outStream_writeLocation(out, lastCodeIndex); 69 70 error = JVMTI_FUNC_PTR(gdata->jvmti,GetLineNumberTable) 71 (gdata->jvmti, method, &count, &table); 72 if (error == JVMTI_ERROR_ABSENT_INFORMATION) { 73 /* 74 * Indicate no line info with an empty table. The code indices 75 * are still useful, so we don't want to return an error 76 */ 77 (void)outStream_writeInt(out, 0); 78 } else if (error == JVMTI_ERROR_NONE) { 79 jint i; 80 (void)outStream_writeInt(out, count); 81 for (i = 0; (i < count) && !outStream_error(out); i++) { 82 (void)outStream_writeLocation(out, table[i].start_location); 83 (void)outStream_writeInt(out, table[i].line_number); 84 } 85 jvmtiDeallocate(table); 86 } else { 87 outStream_setError(out, map2jdwpError(error)); 88 } 89 return JNI_TRUE; 90 } 91 92 93 static jboolean 94 doVariableTable(PacketInputStream *in, PacketOutputStream *out, 95 int outputGenerics) 96 { 97 jvmtiError error; 98 jint count; 99 jvmtiLocalVariableEntry *table; 100 jmethodID method; 101 jint argsSize; 102 jboolean isNative; 103 104 /* JVMDI needed the class, but JVMTI does not so we ignore it */ 105 (void)inStream_readClassRef(getEnv(), in); 106 if (inStream_error(in)) { 107 return JNI_TRUE; 108 } 109 method = inStream_readMethodID(in); 110 if (inStream_error(in)) { 111 return JNI_TRUE; 112 } 113 114 /* 115 * JVMTI behavior for the calls below is unspecified for native 116 * methods, so we must check explicitly. 117 */ 118 isNative = isMethodNative(method); 119 if (isNative) { 120 outStream_setError(out, JDWP_ERROR(NATIVE_METHOD)); 121 return JNI_TRUE; 122 } 123 124 error = JVMTI_FUNC_PTR(gdata->jvmti,GetArgumentsSize) 125 (gdata->jvmti, method, &argsSize); 126 if (error != JVMTI_ERROR_NONE) { 127 outStream_setError(out, map2jdwpError(error)); 128 return JNI_TRUE; 129 } 130 131 error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalVariableTable) 132 (gdata->jvmti, method, &count, &table); 133 if (error == JVMTI_ERROR_NONE) { 134 jint i; 135 (void)outStream_writeInt(out, argsSize); 136 (void)outStream_writeInt(out, count); 137 for (i = 0; (i < count) && !outStream_error(out); i++) { 138 jvmtiLocalVariableEntry *entry = &table[i]; 139 (void)outStream_writeLocation(out, entry->start_location); 140 (void)outStream_writeString(out, entry->name); 141 (void)outStream_writeString(out, entry->signature); 142 if (outputGenerics == 1) { 143 writeGenericSignature(out, entry->generic_signature); 144 } 145 (void)outStream_writeInt(out, entry->length); 146 (void)outStream_writeInt(out, entry->slot); 147 148 jvmtiDeallocate(entry->name); 149 jvmtiDeallocate(entry->signature); 150 if (entry->generic_signature != NULL) { 151 jvmtiDeallocate(entry->generic_signature); 152 } 153 } 154 155 jvmtiDeallocate(table); 156 } else { 157 outStream_setError(out, map2jdwpError(error)); 158 } 159 return JNI_TRUE; 160 } 161 162 163 static jboolean 164 variableTable(PacketInputStream *in, PacketOutputStream *out) { 165 return doVariableTable(in, out, 0); 166 } 167 168 static jboolean 169 variableTableWithGenerics(PacketInputStream *in, PacketOutputStream *out) { 170 return doVariableTable(in, out, 1); 171 } 172 173 174 static jboolean 175 bytecodes(PacketInputStream *in, PacketOutputStream *out) 176 { 177 jvmtiError error; 178 unsigned char * bcp; 179 jint bytecodeCount; 180 jmethodID method; 181 182 /* JVMDI needed the class, but JVMTI does not so we ignore it */ 183 (void)inStream_readClassRef(getEnv(), in); 184 if (inStream_error(in)) { 185 return JNI_TRUE; 186 } 187 method = inStream_readMethodID(in); 188 if (inStream_error(in)) { 189 return JNI_TRUE; 190 } 191 192 /* Initialize assuming no bytecodes and no error */ 193 error = JVMTI_ERROR_NONE; 194 bytecodeCount = 0; 195 bcp = NULL; 196 197 /* Only non-native methods have bytecodes, don't even ask if native. */ 198 if ( !isMethodNative(method) ) { 199 error = JVMTI_FUNC_PTR(gdata->jvmti,GetBytecodes) 200 (gdata->jvmti, method, &bytecodeCount, &bcp); 201 } 202 if (error != JVMTI_ERROR_NONE) { 203 outStream_setError(out, map2jdwpError(error)); 204 } else { 205 (void)outStream_writeByteArray(out, bytecodeCount, (jbyte *)bcp); 206 jvmtiDeallocate(bcp); 207 } 208 209 return JNI_TRUE; 210 } 211 212 static jboolean 213 isObsolete(PacketInputStream *in, PacketOutputStream *out) 214 { 215 jboolean isObsolete; 216 jmethodID method; 217 218 /* JVMDI needed the class, but JVMTI does not so we ignore it */ 219 (void)inStream_readClassRef(getEnv(), in); 220 if (inStream_error(in)) { 221 return JNI_TRUE; 222 } 223 method = inStream_readMethodID(in); 224 if (inStream_error(in)) { 225 return JNI_TRUE; 226 } 227 228 isObsolete = isMethodObsolete(method); 229 (void)outStream_writeBoolean(out, isObsolete); 230 231 return JNI_TRUE; 232 } 233 234 void *Method_Cmds[] = { (void *)0x5 235 ,(void *)lineTable 236 ,(void *)variableTable 237 ,(void *)bytecodes 238 ,(void *)isObsolete 239 ,(void *)variableTableWithGenerics 240 }; 241