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 "StackFrameImpl.h"
28#include "inStream.h"
29#include "outStream.h"
30#include "threadControl.h"
31#include "FrameID.h"
32
33static jdwpError
34validateThreadFrame(jthread thread, FrameID frame)
35{
36    jvmtiError error;
37    jdwpError  serror;
38    jint count;
39    error = threadControl_suspendCount(thread, &count);
40    if ( error == JVMTI_ERROR_NONE ) {
41        if ( count > 0 ) {
42            serror = validateFrameID(thread, frame);
43        } else {
44            serror = JDWP_ERROR(THREAD_NOT_SUSPENDED);
45        }
46    } else {
47        serror =  map2jdwpError(error);
48    }
49    return serror;
50}
51
52static jdwpError
53writeVariableValue(JNIEnv *env, PacketOutputStream *out, jthread thread,
54                   FrameNumber fnum, jint slot, jbyte typeKey)
55{
56    jvmtiError error;
57    jvalue value;
58
59    if (isObjectTag(typeKey)) {
60
61        WITH_LOCAL_REFS(env, 1) {
62
63            error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalObject)
64                        (gdata->jvmti, thread, fnum, slot, &value.l);
65
66            if (error != JVMTI_ERROR_NONE) {
67                outStream_setError(out, map2jdwpError(error));
68            } else {
69                (void)outStream_writeByte(out, specificTypeKey(env, value.l));
70                (void)outStream_writeObjectRef(env, out, value.l);
71            }
72
73        } END_WITH_LOCAL_REFS(env);
74
75    } else {
76        /*
77         * For primitive types, the type key is bounced back as is.
78         */
79        (void)outStream_writeByte(out, typeKey);
80        switch (typeKey) {
81            case JDWP_TAG(BYTE): {
82                    jint intValue;
83                    error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalInt)
84                                (gdata->jvmti, thread, fnum, slot, &intValue);
85                    (void)outStream_writeByte(out, (jbyte)intValue);
86                    break;
87                }
88
89            case JDWP_TAG(CHAR): {
90                    jint intValue;
91                    error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalInt)
92                                (gdata->jvmti, thread, fnum, slot, &intValue);
93                    (void)outStream_writeChar(out, (jchar)intValue);
94                    break;
95                }
96
97            case JDWP_TAG(FLOAT):
98                error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalFloat)
99                                (gdata->jvmti, thread, fnum, slot, &value.f);
100                (void)outStream_writeFloat(out, value.f);
101                break;
102
103            case JDWP_TAG(DOUBLE):
104                error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalDouble)
105                                (gdata->jvmti, thread, fnum, slot, &value.d);
106                (void)outStream_writeDouble(out, value.d);
107                break;
108
109            case JDWP_TAG(INT):
110                error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalInt)
111                                (gdata->jvmti, thread, fnum, slot, &value.i);
112                (void)outStream_writeInt(out, value.i);
113                break;
114
115            case JDWP_TAG(LONG):
116                error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalLong)
117                                (gdata->jvmti, thread, fnum, slot, &value.j);
118                (void)outStream_writeLong(out, value.j);
119                break;
120
121            case JDWP_TAG(SHORT): {
122                jint intValue;
123                error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalInt)
124                                (gdata->jvmti, thread, fnum, slot, &intValue);
125                (void)outStream_writeShort(out, (jshort)intValue);
126                break;
127            }
128
129            case JDWP_TAG(BOOLEAN):{
130                jint intValue;
131                error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalInt)
132                                (gdata->jvmti, thread, fnum, slot, &intValue);
133                (void)outStream_writeBoolean(out, (jboolean)intValue);
134                break;
135            }
136
137            default:
138                return JDWP_ERROR(INVALID_TAG);
139        }
140    }
141
142    return map2jdwpError(error);
143}
144
145static jdwpError
146readVariableValue(JNIEnv *env, PacketInputStream *in, jthread thread,
147                  FrameNumber fnum, jint slot, jbyte typeKey)
148{
149    jvmtiError error;
150    jvalue value;
151
152    if (isObjectTag(typeKey)) {
153
154        value.l = inStream_readObjectRef(env, in);
155
156        error = JVMTI_FUNC_PTR(gdata->jvmti,SetLocalObject)
157                        (gdata->jvmti, thread, fnum, slot, value.l);
158
159    } else {
160        switch (typeKey) {
161            case JDWP_TAG(BYTE):
162                value.b = inStream_readByte(in);
163                error = JVMTI_FUNC_PTR(gdata->jvmti,SetLocalInt)
164                                (gdata->jvmti, thread, fnum, slot, value.b);
165                break;
166
167            case JDWP_TAG(CHAR):
168                value.c = inStream_readChar(in);
169                error = JVMTI_FUNC_PTR(gdata->jvmti,SetLocalInt)
170                                (gdata->jvmti, thread, fnum, slot, value.c);
171                break;
172
173            case JDWP_TAG(FLOAT):
174                value.f = inStream_readFloat(in);
175                error = JVMTI_FUNC_PTR(gdata->jvmti,SetLocalFloat)
176                                (gdata->jvmti, thread, fnum, slot, value.f);
177                break;
178
179            case JDWP_TAG(DOUBLE):
180                value.d = inStream_readDouble(in);
181                error = JVMTI_FUNC_PTR(gdata->jvmti,SetLocalDouble)
182                                (gdata->jvmti, thread, fnum, slot, value.d);
183                break;
184
185            case JDWP_TAG(INT):
186                value.i = inStream_readInt(in);
187                error = JVMTI_FUNC_PTR(gdata->jvmti,SetLocalInt)
188                                (gdata->jvmti, thread, fnum, slot, value.i);
189                break;
190
191            case JDWP_TAG(LONG):
192                value.j = inStream_readLong(in);
193                error = JVMTI_FUNC_PTR(gdata->jvmti,SetLocalLong)
194                                (gdata->jvmti, thread, fnum, slot, value.j);
195                break;
196
197            case JDWP_TAG(SHORT):
198                value.s = inStream_readShort(in);
199                error = JVMTI_FUNC_PTR(gdata->jvmti,SetLocalInt)
200                                (gdata->jvmti, thread, fnum, slot, value.s);
201                break;
202
203            case JDWP_TAG(BOOLEAN):
204                value.z = inStream_readBoolean(in);
205                error = JVMTI_FUNC_PTR(gdata->jvmti,SetLocalInt)
206                                (gdata->jvmti, thread, fnum, slot, value.z);
207                break;
208
209            default:
210                return JDWP_ERROR(INVALID_TAG);
211        }
212    }
213
214    return map2jdwpError(error);
215}
216
217static jboolean
218getValues(PacketInputStream *in, PacketOutputStream *out)
219{
220    JNIEnv *env;
221    int i;
222    jdwpError serror;
223    jthread thread;
224    FrameID frame;
225    jint variableCount;
226
227    env = getEnv();
228
229    thread = inStream_readThreadRef(env, in);
230    if (inStream_error(in)) {
231        return JNI_TRUE;
232    }
233    frame = inStream_readFrameID(in);
234    if (inStream_error(in)) {
235        return JNI_TRUE;
236    }
237    variableCount = inStream_readInt(in);
238    if (inStream_error(in)) {
239        return JNI_TRUE;
240    }
241
242    /*
243     * Validate the frame id
244     */
245    serror = validateThreadFrame(thread, frame);
246    if (serror != JDWP_ERROR(NONE)) {
247        outStream_setError(out, serror);
248        return JNI_TRUE;
249    }
250
251    (void)outStream_writeInt(out, variableCount);
252    for (i = 0; (i < variableCount) && !outStream_error(out); i++) {
253        jint slot;
254        jbyte typeKey;
255        FrameNumber fnum;
256
257        slot = inStream_readInt(in);
258        if (inStream_error(in))
259            break;
260        typeKey = inStream_readByte(in);
261        if (inStream_error(in))
262            break;
263
264        fnum = getFrameNumber(frame);
265        serror = writeVariableValue(env, out, thread, fnum, slot, typeKey);
266        if (serror != JDWP_ERROR(NONE)) {
267            outStream_setError(out, serror);
268            break;
269        }
270    }
271
272    return JNI_TRUE;
273}
274
275static jboolean
276setValues(PacketInputStream *in, PacketOutputStream *out)
277{
278    JNIEnv *env;
279    jint i;
280    jdwpError serror;
281    jthread thread;
282    FrameID frame;
283    jint variableCount;
284
285    env = getEnv();
286
287    thread = inStream_readThreadRef(env, in);
288    if (inStream_error(in)) {
289        return JNI_TRUE;
290    }
291    frame = inStream_readFrameID(in);
292    if (inStream_error(in)) {
293        return JNI_TRUE;
294    }
295    variableCount = inStream_readInt(in);
296    if (inStream_error(in)) {
297        return JNI_TRUE;
298    }
299
300    /*
301     * Validate the frame id
302     */
303    serror = validateThreadFrame(thread, frame);
304    if (serror != JDWP_ERROR(NONE)) {
305        outStream_setError(out, serror);
306        return JNI_TRUE;
307    }
308
309    for (i = 0; (i < variableCount) && !inStream_error(in); i++) {
310
311        jint slot;
312        jbyte typeKey;
313        FrameNumber fnum;
314
315        slot = inStream_readInt(in);
316        if (inStream_error(in)) {
317            return JNI_TRUE;
318        }
319        typeKey = inStream_readByte(in);
320        if (inStream_error(in)) {
321            return JNI_TRUE;
322        }
323
324        fnum = getFrameNumber(frame);
325        serror = readVariableValue(env, in, thread, fnum, slot, typeKey);
326        if (serror != JDWP_ERROR(NONE))
327            break;
328    }
329
330    if (serror != JDWP_ERROR(NONE)) {
331        outStream_setError(out, serror);
332    }
333
334    return JNI_TRUE;
335}
336
337static jboolean
338thisObject(PacketInputStream *in, PacketOutputStream *out)
339{
340    JNIEnv *env;
341    jdwpError serror;
342    jthread thread;
343    FrameID frame;
344
345    env = getEnv();
346
347    thread = inStream_readThreadRef(env, in);
348    if (inStream_error(in)) {
349        return JNI_TRUE;
350    }
351
352    frame = inStream_readFrameID(in);
353    if (inStream_error(in)) {
354        return JNI_TRUE;
355    }
356
357    /*
358     * Validate the frame id
359     */
360    serror = validateThreadFrame(thread, frame);
361    if (serror != JDWP_ERROR(NONE)) {
362        outStream_setError(out, serror);
363        return JNI_TRUE;
364    }
365
366    WITH_LOCAL_REFS(env, 2) {
367
368        jvmtiError error;
369        jmethodID method;
370        jlocation location;
371        FrameNumber fnum;
372
373        /*
374         * Find out if the given frame is for a static or native method.
375         */
376        fnum = getFrameNumber(frame);
377        error = JVMTI_FUNC_PTR(gdata->jvmti,GetFrameLocation)
378                (gdata->jvmti, thread, fnum, &method, &location);
379        if (error == JVMTI_ERROR_NONE) {
380
381            jint modifiers;
382
383            error = methodModifiers(method, &modifiers);
384            if (error == JVMTI_ERROR_NONE) {
385
386                jobject this_object;
387
388                /*
389                 * Return null for static or native methods; otherwise, the JVM
390                 * spec guarantees that "this" is in slot 0
391                 */
392                if (modifiers & (MOD_STATIC | MOD_NATIVE)) {
393                    this_object = NULL;
394                    (void)outStream_writeByte(out, specificTypeKey(env, this_object));
395                    (void)outStream_writeObjectRef(env, out, this_object);
396                } else {
397                    error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalObject)
398                                (gdata->jvmti, thread, fnum, 0, &this_object);
399                    if (error == JVMTI_ERROR_NONE) {
400                        (void)outStream_writeByte(out, specificTypeKey(env, this_object));
401                        (void)outStream_writeObjectRef(env, out, this_object);
402                    }
403                }
404
405            }
406        }
407        serror = map2jdwpError(error);
408
409    } END_WITH_LOCAL_REFS(env);
410
411    if (serror != JDWP_ERROR(NONE))
412        outStream_setError(out, serror);
413
414    return JNI_TRUE;
415}
416
417static jboolean
418popFrames(PacketInputStream *in, PacketOutputStream *out)
419{
420    jvmtiError error;
421    jdwpError serror;
422    jthread thread;
423    FrameID frame;
424    FrameNumber fnum;
425
426    thread = inStream_readThreadRef(getEnv(), in);
427    if (inStream_error(in)) {
428        return JNI_TRUE;
429    }
430
431    frame = inStream_readFrameID(in);
432    if (inStream_error(in)) {
433        return JNI_TRUE;
434    }
435
436    /*
437     * Validate the frame id
438     */
439    serror = validateThreadFrame(thread, frame);
440    if (serror != JDWP_ERROR(NONE)) {
441        outStream_setError(out, serror);
442        return JNI_TRUE;
443    }
444
445    if (threadControl_isDebugThread(thread)) {
446        outStream_setError(out, JDWP_ERROR(INVALID_THREAD));
447        return JNI_TRUE;
448    }
449
450    fnum = getFrameNumber(frame);
451    error = threadControl_popFrames(thread, fnum);
452    if (error != JVMTI_ERROR_NONE) {
453        serror = map2jdwpError(error);
454        outStream_setError(out, serror);
455    }
456    return JNI_TRUE;
457}
458
459void *StackFrame_Cmds[] = { (void *)0x4
460    ,(void *)getValues
461    ,(void *)setValues
462    ,(void *)thisObject
463    ,(void *)popFrames
464};
465