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