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     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 
 459 CommandSet StackFrame_Cmds = {
 460     4, "StackFrame",
 461     {
 462         {getValues, "GetValues"},
 463         {setValues, "SetValues"},
 464         {thisObject, "ThisObject"},
 465         {popFrames, "PopFrames"}
 466     }
 467 };