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 
  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     if (isFiber(thread)) {
 252         thread = threadControl_getFiberCarrierOrHelperThread(thread);
 253         if (thread == NULL) {
 254             /* fiber fixme: we failed to get the helper thread. Just return 0 locals. */
 255             (void)outStream_writeInt(out, 0);
 256             return JNI_TRUE;
 257         }
 258     }
 259 
 260     (void)outStream_writeInt(out, variableCount);
 261     for (i = 0; (i < variableCount) && !outStream_error(out); i++) {
 262         jint slot;
 263         jbyte typeKey;
 264         FrameNumber fnum;
 265 
 266         slot = inStream_readInt(in);
 267         if (inStream_error(in))
 268             break;
 269         typeKey = inStream_readByte(in);
 270         if (inStream_error(in))
 271             break;
 272 
 273         fnum = getFrameNumber(frame);
 274         serror = writeVariableValue(env, out, thread, fnum, slot, typeKey);
 275         if (serror != JDWP_ERROR(NONE)) {
 276             outStream_setError(out, serror);
 277             break;
 278         }
 279     }
 280 
 281     return JNI_TRUE;
 282 }
 283 
 284 static jboolean
 285 setValues(PacketInputStream *in, PacketOutputStream *out)
 286 {
 287     JNIEnv *env;
 288     jint i;
 289     jdwpError serror;
 290     jthread thread;
 291     FrameID frame;
 292     jint variableCount;
 293 
 294     env = getEnv();
 295 
 296     thread = inStream_readThreadRef(env, in);
 297     if (inStream_error(in)) {
 298         return JNI_TRUE;
 299     }
 300     frame = inStream_readFrameID(in);
 301     if (inStream_error(in)) {
 302         return JNI_TRUE;
 303     }
 304     variableCount = inStream_readInt(in);
 305     if (inStream_error(in)) {
 306         return JNI_TRUE;
 307     }
 308 
 309     /*
 310      * Validate the frame id
 311      */
 312     serror = validateThreadFrame(thread, frame);
 313     if (serror != JDWP_ERROR(NONE)) {
 314         outStream_setError(out, serror);
 315         return JNI_TRUE;
 316     }
 317 
 318     for (i = 0; (i < variableCount) && !inStream_error(in); i++) {
 319 
 320         jint slot;
 321         jbyte typeKey;
 322         FrameNumber fnum;
 323 
 324         slot = inStream_readInt(in);
 325         if (inStream_error(in)) {
 326             return JNI_TRUE;
 327         }
 328         typeKey = inStream_readByte(in);
 329         if (inStream_error(in)) {
 330             return JNI_TRUE;
 331         }
 332 
 333         fnum = getFrameNumber(frame);
 334         serror = readVariableValue(env, in, thread, fnum, slot, typeKey);
 335         if (serror != JDWP_ERROR(NONE))
 336             break;
 337     }
 338 
 339     if (serror != JDWP_ERROR(NONE)) {
 340         outStream_setError(out, serror);
 341     }
 342 
 343     return JNI_TRUE;
 344 }
 345 
 346 static jboolean
 347 thisObject(PacketInputStream *in, PacketOutputStream *out)
 348 {
 349     JNIEnv *env;
 350     jdwpError serror;
 351     jthread thread;
 352     FrameID frame;
 353 
 354     env = getEnv();
 355 
 356     thread = inStream_readThreadRef(env, in);
 357     if (inStream_error(in)) {
 358         return JNI_TRUE;
 359     }
 360 
 361     frame = inStream_readFrameID(in);
 362     if (inStream_error(in)) {
 363         return JNI_TRUE;
 364     }
 365 
 366     /*
 367      * Validate the frame id
 368      */
 369     serror = validateThreadFrame(thread, frame);
 370     if (serror != JDWP_ERROR(NONE)) {
 371         outStream_setError(out, serror);
 372         return JNI_TRUE;
 373     }
 374 
 375     WITH_LOCAL_REFS(env, 2) {
 376 
 377         jvmtiError error;
 378         jmethodID method;
 379         jlocation location;
 380         FrameNumber fnum;
 381 
 382         /*
 383          * Find out if the given frame is for a static or native method.
 384          */
 385         fnum = getFrameNumber(frame);
 386         error = JVMTI_FUNC_PTR(gdata->jvmti,GetFrameLocation)
 387                 (gdata->jvmti, thread, fnum, &method, &location);
 388         if (error == JVMTI_ERROR_NONE) {
 389 
 390             jint modifiers;
 391 
 392             error = methodModifiers(method, &modifiers);
 393             if (error == JVMTI_ERROR_NONE) {
 394 
 395                 jobject this_object;
 396 
 397                 /*
 398                  * Return null for static or native methods; otherwise, the JVM
 399                  * spec guarantees that "this" is in slot 0
 400                  */
 401                 if (modifiers & (MOD_STATIC | MOD_NATIVE)) {
 402                     this_object = NULL;
 403                     (void)outStream_writeByte(out, specificTypeKey(env, this_object));
 404                     (void)outStream_writeObjectRef(env, out, this_object);
 405                 } else {
 406                     error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalObject)
 407                                 (gdata->jvmti, thread, fnum, 0, &this_object);
 408                     if (error == JVMTI_ERROR_NONE) {
 409                         (void)outStream_writeByte(out, specificTypeKey(env, this_object));
 410                         (void)outStream_writeObjectRef(env, out, this_object);
 411                     }
 412                 }
 413 
 414             }
 415         }
 416         serror = map2jdwpError(error);
 417 
 418     } END_WITH_LOCAL_REFS(env);
 419 
 420     if (serror != JDWP_ERROR(NONE))
 421         outStream_setError(out, serror);
 422 
 423     return JNI_TRUE;
 424 }
 425 
 426 static jboolean
 427 popFrames(PacketInputStream *in, PacketOutputStream *out)
 428 {
 429     jvmtiError error;
 430     jdwpError serror;
 431     jthread thread;
 432     FrameID frame;
 433     FrameNumber fnum;
 434 
 435     thread = inStream_readThreadRef(getEnv(), in);
 436     if (inStream_error(in)) {
 437         return JNI_TRUE;
 438     }
 439 
 440     frame = inStream_readFrameID(in);
 441     if (inStream_error(in)) {
 442         return JNI_TRUE;
 443     }
 444 
 445     /*
 446      * Validate the frame id
 447      */
 448     serror = validateThreadFrame(thread, frame);
 449     if (serror != JDWP_ERROR(NONE)) {
 450         outStream_setError(out, serror);
 451         return JNI_TRUE;
 452     }
 453 
 454     if (threadControl_isDebugThread(thread)) {
 455         outStream_setError(out, JDWP_ERROR(INVALID_THREAD));
 456         return JNI_TRUE;
 457     }
 458 
 459     fnum = getFrameNumber(frame);
 460     /* fiber fixme: add fiber support */
 461     error = threadControl_popFrames(thread, fnum);
 462     if (error != JVMTI_ERROR_NONE) {
 463         serror = map2jdwpError(error);
 464         outStream_setError(out, serror);
 465     }
 466     return JNI_TRUE;
 467 }
 468 
 469 void *StackFrame_Cmds[] = { (void *)0x4
 470     ,(void *)getValues
 471     ,(void *)setValues
 472     ,(void *)thisObject
 473     ,(void *)popFrames
 474 };