Home | History | Annotate | Download | only in back
      1 /*
      2  * Copyright (c) 1998, 2008, 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 "stream.h"
     28 #include "inStream.h"
     29 #include "transport.h"
     30 #include "bag.h"
     31 #include "commonRef.h"
     32 #include "FrameID.h"
     33 
     34 #define INITIAL_REF_ALLOC 50
     35 #define SMALLEST(a, b) ((a) < (b)) ? (a) : (b)
     36 
     37 /*
     38  * TO DO: Support processing of replies through command input streams.
     39  */
     40 void
     41 inStream_init(PacketInputStream *stream, jdwpPacket packet)
     42 {
     43     stream->packet = packet;
     44     stream->error = JDWP_ERROR(NONE);
     45     stream->left = packet.type.cmd.len;
     46     stream->current = packet.type.cmd.data;
     47     stream->refs = bagCreateBag(sizeof(jobject), INITIAL_REF_ALLOC);
     48     if (stream->refs == NULL) {
     49         stream->error = JDWP_ERROR(OUT_OF_MEMORY);
     50     }
     51 }
     52 
     53 jint
     54 inStream_id(PacketInputStream *stream)
     55 {
     56     return stream->packet.type.cmd.id;
     57 }
     58 
     59 jbyte
     60 inStream_command(PacketInputStream *stream)
     61 {
     62     return stream->packet.type.cmd.cmd;
     63 }
     64 
     65 static jdwpError
     66 readBytes(PacketInputStream *stream, void *dest, int size)
     67 {
     68     if (stream->error) {
     69         return stream->error;
     70     }
     71 
     72     if (size > stream->left) {
     73         stream->error = JDWP_ERROR(INTERNAL);
     74         return stream->error;
     75     }
     76 
     77     if (dest) {
     78         (void)memcpy(dest, stream->current, size);
     79     }
     80     stream->current += size;
     81     stream->left -= size;
     82 
     83     return stream->error;
     84 }
     85 
     86 jdwpError
     87 inStream_skipBytes(PacketInputStream *stream, jint size) {
     88     return readBytes(stream, NULL, size);
     89 }
     90 
     91 jboolean
     92 inStream_readBoolean(PacketInputStream *stream)
     93 {
     94     jbyte flag = 0;
     95     (void)readBytes(stream, &flag, sizeof(flag));
     96     if (stream->error) {
     97         return 0;
     98     } else {
     99         return flag ? JNI_TRUE : JNI_FALSE;
    100     }
    101 }
    102 
    103 jbyte
    104 inStream_readByte(PacketInputStream *stream)
    105 {
    106     jbyte val = 0;
    107     (void)readBytes(stream, &val, sizeof(val));
    108     return val;
    109 }
    110 
    111 jbyte *
    112 inStream_readBytes(PacketInputStream *stream, int length, jbyte *buf)
    113 {
    114     (void)readBytes(stream, buf, length);
    115     return buf;
    116 }
    117 
    118 jchar
    119 inStream_readChar(PacketInputStream *stream)
    120 {
    121     jchar val = 0;
    122     (void)readBytes(stream, &val, sizeof(val));
    123     return JAVA_TO_HOST_CHAR(val);
    124 }
    125 
    126 jshort
    127 inStream_readShort(PacketInputStream *stream)
    128 {
    129     jshort val = 0;
    130     (void)readBytes(stream, &val, sizeof(val));
    131     return JAVA_TO_HOST_SHORT(val);
    132 }
    133 
    134 jint
    135 inStream_readInt(PacketInputStream *stream)
    136 {
    137     jint val = 0;
    138     (void)readBytes(stream, &val, sizeof(val));
    139     return JAVA_TO_HOST_INT(val);
    140 }
    141 
    142 jlong
    143 inStream_readLong(PacketInputStream *stream)
    144 {
    145     jlong val = 0;
    146     (void)readBytes(stream, &val, sizeof(val));
    147     return JAVA_TO_HOST_LONG(val);
    148 }
    149 
    150 jfloat
    151 inStream_readFloat(PacketInputStream *stream)
    152 {
    153     jfloat val = 0;
    154     (void)readBytes(stream, &val, sizeof(val));
    155     return JAVA_TO_HOST_FLOAT(val);
    156 }
    157 
    158 jdouble
    159 inStream_readDouble(PacketInputStream *stream)
    160 {
    161     jdouble val = 0;
    162     (void)readBytes(stream, &val, sizeof(val));
    163     return JAVA_TO_HOST_DOUBLE(val);
    164 }
    165 
    166 /*
    167  * Read an object from the stream. The ID used in the wire protocol
    168  * is converted to a reference which is returned. The reference is
    169  * global and strong, but it should *not* be deleted by the caller
    170  * since it is freed when this stream is destroyed.
    171  */
    172 jobject
    173 inStream_readObjectRef(JNIEnv *env, PacketInputStream *stream)
    174 {
    175     jobject ref;
    176     jobject *refPtr;
    177     jlong id = inStream_readLong(stream);
    178     if (stream->error) {
    179         return NULL;
    180     }
    181     if (id == NULL_OBJECT_ID) {
    182         return NULL;
    183     }
    184 
    185     ref = commonRef_idToRef(env, id);
    186     if (ref == NULL) {
    187         stream->error = JDWP_ERROR(INVALID_OBJECT);
    188         return NULL;
    189     }
    190 
    191     refPtr = bagAdd(stream->refs);
    192     if (refPtr == NULL) {
    193         commonRef_idToRef_delete(env, ref);
    194         return NULL;
    195     }
    196 
    197     *refPtr = ref;
    198     return ref;
    199 }
    200 
    201 /*
    202  * Read a raw object id from the stream. This should be used rarely.
    203  * Normally, inStream_readObjectRef is preferred since it takes care
    204  * of reference conversion and tracking. Only code that needs to
    205  * perform maintence of the commonRef hash table uses this function.
    206  */
    207 jlong
    208 inStream_readObjectID(PacketInputStream *stream)
    209 {
    210     return inStream_readLong(stream);
    211 }
    212 
    213 jclass
    214 inStream_readClassRef(JNIEnv *env, PacketInputStream *stream)
    215 {
    216     jobject object = inStream_readObjectRef(env, stream);
    217     if (object == NULL) {
    218         /*
    219          * Could be error or just the null reference. In either case,
    220          * stop now.
    221          */
    222         return NULL;
    223     }
    224     if (!isClass(object)) {
    225         stream->error = JDWP_ERROR(INVALID_CLASS);
    226         return NULL;
    227     }
    228     return object;
    229 }
    230 
    231 jthread
    232 inStream_readThreadRef(JNIEnv *env, PacketInputStream *stream)
    233 {
    234     jobject object = inStream_readObjectRef(env, stream);
    235     if (object == NULL) {
    236         /*
    237          * Could be error or just the null reference. In either case,
    238          * stop now.
    239          */
    240         return NULL;
    241     }
    242     if (!isThread(object)) {
    243         stream->error = JDWP_ERROR(INVALID_THREAD);
    244         return NULL;
    245     }
    246     return object;
    247 }
    248 
    249 jthreadGroup
    250 inStream_readThreadGroupRef(JNIEnv *env, PacketInputStream *stream)
    251 {
    252     jobject object = inStream_readObjectRef(env, stream);
    253     if (object == NULL) {
    254         /*
    255          * Could be error or just the null reference. In either case,
    256          * stop now.
    257          */
    258         return NULL;
    259     }
    260     if (!isThreadGroup(object)) {
    261         stream->error = JDWP_ERROR(INVALID_THREAD_GROUP);
    262         return NULL;
    263     }
    264     return object;
    265 }
    266 
    267 jstring
    268 inStream_readStringRef(JNIEnv *env, PacketInputStream *stream)
    269 {
    270     jobject object = inStream_readObjectRef(env, stream);
    271     if (object == NULL) {
    272         /*
    273          * Could be error or just the null reference. In either case,
    274          * stop now.
    275          */
    276         return NULL;
    277     }
    278     if (!isString(object)) {
    279         stream->error = JDWP_ERROR(INVALID_STRING);
    280         return NULL;
    281     }
    282     return object;
    283 }
    284 
    285 jclass
    286 inStream_readClassLoaderRef(JNIEnv *env, PacketInputStream *stream)
    287 {
    288     jobject object = inStream_readObjectRef(env, stream);
    289     if (object == NULL) {
    290         /*
    291          * Could be error or just the null reference. In either case,
    292          * stop now.
    293          */
    294         return NULL;
    295     }
    296     if (!isClassLoader(object)) {
    297         stream->error = JDWP_ERROR(INVALID_CLASS_LOADER);
    298         return NULL;
    299     }
    300     return object;
    301 }
    302 
    303 jarray
    304 inStream_readArrayRef(JNIEnv *env, PacketInputStream *stream)
    305 {
    306     jobject object = inStream_readObjectRef(env, stream);
    307     if (object == NULL) {
    308         /*
    309          * Could be error or just the null reference. In either case,
    310          * stop now.
    311          */
    312         return NULL;
    313     }
    314     if (!isArray(object)) {
    315         stream->error = JDWP_ERROR(INVALID_ARRAY);
    316         return NULL;
    317     }
    318     return object;
    319 }
    320 
    321 /*
    322  * Next 3 functions read an Int and convert to a Pointer!?
    323  * If sizeof(jxxxID) == 8 we must read these values as Longs.
    324  */
    325 FrameID
    326 inStream_readFrameID(PacketInputStream *stream)
    327 {
    328     if (sizeof(FrameID) == 8) {
    329         /*LINTED*/
    330         return (FrameID)inStream_readLong(stream);
    331     } else {
    332         /*LINTED*/
    333         return (FrameID)inStream_readInt(stream);
    334     }
    335 }
    336 
    337 jmethodID
    338 inStream_readMethodID(PacketInputStream *stream)
    339 {
    340     if (sizeof(jmethodID) == 8) {
    341         /*LINTED*/
    342         return (jmethodID)(intptr_t)inStream_readLong(stream);
    343     } else {
    344         /*LINTED*/
    345         return (jmethodID)(intptr_t)inStream_readInt(stream);
    346     }
    347 }
    348 
    349 jfieldID
    350 inStream_readFieldID(PacketInputStream *stream)
    351 {
    352     if (sizeof(jfieldID) == 8) {
    353         /*LINTED*/
    354         return (jfieldID)(intptr_t)inStream_readLong(stream);
    355     } else {
    356         /*LINTED*/
    357         return (jfieldID)(intptr_t)inStream_readInt(stream);
    358     }
    359 }
    360 
    361 jlocation
    362 inStream_readLocation(PacketInputStream *stream)
    363 {
    364     return (jlocation)inStream_readLong(stream);
    365 }
    366 
    367 char *
    368 inStream_readString(PacketInputStream *stream)
    369 {
    370     int length;
    371     char *string;
    372 
    373     length = inStream_readInt(stream);
    374     string = jvmtiAllocate(length + 1);
    375     if (string != NULL) {
    376         int new_length;
    377 
    378         (void)readBytes(stream, string, length);
    379         string[length] = '\0';
    380 
    381         /* This is Standard UTF-8, convert to Modified UTF-8 if necessary */
    382         new_length = (gdata->npt->utf8sToUtf8mLength)
    383                              (gdata->npt->utf, (jbyte*)string, length);
    384         if ( new_length != length ) {
    385             char *new_string;
    386 
    387             new_string = jvmtiAllocate(new_length+1);
    388             (gdata->npt->utf8sToUtf8m)
    389                              (gdata->npt->utf, (jbyte*)string, length,
    390                               (jbyte*)new_string, new_length);
    391             jvmtiDeallocate(string);
    392             return new_string;
    393         }
    394     }
    395     return string;
    396 }
    397 
    398 jboolean
    399 inStream_endOfInput(PacketInputStream *stream)
    400 {
    401     return (stream->left > 0);
    402 }
    403 
    404 jdwpError
    405 inStream_error(PacketInputStream *stream)
    406 {
    407     return stream->error;
    408 }
    409 
    410 void
    411 inStream_clearError(PacketInputStream *stream) {
    412     stream->error = JDWP_ERROR(NONE);
    413 }
    414 
    415 jvalue
    416 inStream_readValue(PacketInputStream *stream, jbyte *typeKeyPtr)
    417 {
    418     jvalue value;
    419     jbyte typeKey = inStream_readByte(stream);
    420     if (stream->error) {
    421         value.j = 0L;
    422         return value;
    423     }
    424 
    425     if (isObjectTag(typeKey)) {
    426         value.l = inStream_readObjectRef(getEnv(), stream);
    427     } else {
    428         switch (typeKey) {
    429             case JDWP_TAG(BYTE):
    430                 value.b = inStream_readByte(stream);
    431                 break;
    432 
    433             case JDWP_TAG(CHAR):
    434                 value.c = inStream_readChar(stream);
    435                 break;
    436 
    437             case JDWP_TAG(FLOAT):
    438                 value.f = inStream_readFloat(stream);
    439                 break;
    440 
    441             case JDWP_TAG(DOUBLE):
    442                 value.d = inStream_readDouble(stream);
    443                 break;
    444 
    445             case JDWP_TAG(INT):
    446                 value.i = inStream_readInt(stream);
    447                 break;
    448 
    449             case JDWP_TAG(LONG):
    450                 value.j = inStream_readLong(stream);
    451                 break;
    452 
    453             case JDWP_TAG(SHORT):
    454                 value.s = inStream_readShort(stream);
    455                 break;
    456 
    457             case JDWP_TAG(BOOLEAN):
    458                 value.z = inStream_readBoolean(stream);
    459                 break;
    460             default:
    461                 stream->error = JDWP_ERROR(INVALID_TAG);
    462                 break;
    463         }
    464     }
    465     if (typeKeyPtr) {
    466         *typeKeyPtr = typeKey;
    467     }
    468     return value;
    469 }
    470 
    471 static jboolean
    472 deleteRef(void *elementPtr, void *arg)
    473 {
    474     JNIEnv *env = arg;
    475     jobject *refPtr = elementPtr;
    476     commonRef_idToRef_delete(env, *refPtr);
    477     return JNI_TRUE;
    478 }
    479 
    480 void
    481 inStream_destroy(PacketInputStream *stream)
    482 {
    483     if (stream->packet.type.cmd.data != NULL) {
    484     jvmtiDeallocate(stream->packet.type.cmd.data);
    485     }
    486 
    487     (void)bagEnumerateOver(stream->refs, deleteRef, (void *)getEnv());
    488     bagDestroyBag(stream->refs);
    489 }
    490