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
lineTable(PacketInputStream * in,PacketOutputStream * out)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
doVariableTable(PacketInputStream * in,PacketOutputStream * out,int outputGenerics)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
variableTable(PacketInputStream * in,PacketOutputStream * out)164 variableTable(PacketInputStream *in, PacketOutputStream *out) {
165 return doVariableTable(in, out, 0);
166 }
167
168 static jboolean
variableTableWithGenerics(PacketInputStream * in,PacketOutputStream * out)169 variableTableWithGenerics(PacketInputStream *in, PacketOutputStream *out) {
170 return doVariableTable(in, out, 1);
171 }
172
173
174 static jboolean
bytecodes(PacketInputStream * in,PacketOutputStream * out)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
isObsolete(PacketInputStream * in,PacketOutputStream * out)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