1 /*
  2  * Copyright (c) 1998, 2020, 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 
 33 static jdwpError
 34 validateThreadFrame(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 
 52 static jdwpError
 53 writeVariableValue(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 
145 static jdwpError
146 readVariableValue(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 
217 static jboolean
218 getValues(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 
275 static jboolean
276 setValues(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 
337 static jboolean
338 thisObject(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 
417 static jboolean
418 popFrames(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     /* vthread fixme: add vthread support */
452     error = threadControl_popFrames(thread, fnum);
453     if (error != JVMTI_ERROR_NONE) {
454         serror = map2jdwpError(error);
455         outStream_setError(out, serror);
456     }
457     return JNI_TRUE;
458 }
459 
460 Command StackFrame_Commands[] = {
461     {getValues, "GetValues"},
462     {setValues, "SetValues"},
463     {thisObject, "ThisObject"},
464     {popFrames, "PopFrames"}
465 };
466 
467 DEBUG_DISPATCH_DEFINE_CMDSET(StackFrame)