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
31static jboolean
32lineTable(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
93static jboolean
94doVariableTable(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
163static jboolean
164variableTable(PacketInputStream *in, PacketOutputStream *out) {
165    return doVariableTable(in, out, 0);
166}
167
168static jboolean
169variableTableWithGenerics(PacketInputStream *in, PacketOutputStream *out) {
170    return doVariableTable(in, out, 1);
171}
172
173
174static jboolean
175bytecodes(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
212static jboolean
213isObsolete(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
234void *Method_Cmds[] = { (void *)0x5
235    ,(void *)lineTable
236    ,(void *)variableTable
237    ,(void *)bytecodes
238    ,(void *)isObsolete
239    ,(void *)variableTableWithGenerics
240};
241