Home | History | Annotate | Download | only in back
      1 /*
      2  * Copyright (c) 1998, 2013, 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 "outStream.h"
     29 #include "inStream.h"
     30 #include "transport.h"
     31 #include "commonRef.h"
     32 #include "bag.h"
     33 #include "FrameID.h"
     34 
     35 #define INITIAL_ID_ALLOC  50
     36 #define SMALLEST(a, b) ((a) < (b)) ? (a) : (b)
     37 
     38 static void
     39 commonInit(PacketOutputStream *stream)
     40 {
     41     stream->current = &stream->initialSegment[0];
     42     stream->left = sizeof(stream->initialSegment);
     43     stream->segment = &stream->firstSegment;
     44     stream->segment->length = 0;
     45     stream->segment->data = &stream->initialSegment[0];
     46     stream->segment->next = NULL;
     47     stream->error = JDWP_ERROR(NONE);
     48     stream->sent = JNI_FALSE;
     49     stream->ids = bagCreateBag(sizeof(jlong), INITIAL_ID_ALLOC);
     50     if (stream->ids == NULL) {
     51         stream->error = JDWP_ERROR(OUT_OF_MEMORY);
     52     }
     53 }
     54 
     55 void
     56 outStream_initCommand(PacketOutputStream *stream, jint id,
     57                       jbyte flags, jbyte commandSet, jbyte command)
     58 {
     59     commonInit(stream);
     60 
     61     /*
     62      * Command-specific initialization
     63      */
     64     stream->packet.type.cmd.id = id;
     65     stream->packet.type.cmd.cmdSet = commandSet;
     66     stream->packet.type.cmd.cmd = command;
     67 
     68     stream->packet.type.cmd.flags = flags;
     69 }
     70 
     71 void
     72 outStream_initReply(PacketOutputStream *stream, jint id)
     73 {
     74     commonInit(stream);
     75 
     76     /*
     77      * Reply-specific initialization
     78      */
     79     stream->packet.type.reply.id = id;
     80     stream->packet.type.reply.errorCode = 0x0;
     81     stream->packet.type.cmd.flags = (jbyte)JDWPTRANSPORT_FLAGS_REPLY;
     82 }
     83 
     84 jint
     85 outStream_id(PacketOutputStream *stream)
     86 {
     87     return stream->packet.type.cmd.id;
     88 }
     89 
     90 jbyte
     91 outStream_command(PacketOutputStream *stream)
     92 {
     93     /* Only makes sense for commands */
     94     JDI_ASSERT(!(stream->packet.type.cmd.flags & JDWPTRANSPORT_FLAGS_REPLY));
     95     return stream->packet.type.cmd.cmd;
     96 }
     97 
     98 static jdwpError
     99 writeBytes(PacketOutputStream *stream, void *source, int size)
    100 {
    101     jbyte *bytes = (jbyte *)source;
    102 
    103     if (stream->error) {
    104         return stream->error;
    105     }
    106     while (size > 0) {
    107         jint count;
    108         if (stream->left == 0) {
    109             jint segSize = SMALLEST(2 * stream->segment->length, MAX_SEGMENT_SIZE);
    110             jbyte *newSeg = jvmtiAllocate(segSize);
    111             struct PacketData *newHeader = jvmtiAllocate(sizeof(*newHeader));
    112             if ((newSeg == NULL) || (newHeader == NULL)) {
    113                 jvmtiDeallocate(newSeg);
    114                 jvmtiDeallocate(newHeader);
    115                 stream->error = JDWP_ERROR(OUT_OF_MEMORY);
    116                 return stream->error;
    117             }
    118             newHeader->length = 0;
    119             newHeader->data = newSeg;
    120             newHeader->next = NULL;
    121             stream->segment->next = newHeader;
    122             stream->segment = newHeader;
    123             stream->current = newHeader->data;
    124             stream->left = segSize;
    125         }
    126         count = SMALLEST(size, stream->left);
    127         (void)memcpy(stream->current, bytes, count);
    128         stream->current += count;
    129         stream->left -= count;
    130         stream->segment->length += count;
    131         size -= count;
    132         bytes += count;
    133     }
    134     return JDWP_ERROR(NONE);
    135 }
    136 
    137 jdwpError
    138 outStream_writeBoolean(PacketOutputStream *stream, jboolean val)
    139 {
    140     jbyte byte = (val != 0) ? 1 : 0;
    141     return writeBytes(stream, &byte, sizeof(byte));
    142 }
    143 
    144 jdwpError
    145 outStream_writeByte(PacketOutputStream *stream, jbyte val)
    146 {
    147     return writeBytes(stream, &val, sizeof(val));
    148 }
    149 
    150 jdwpError
    151 outStream_writeChar(PacketOutputStream *stream, jchar val)
    152 {
    153     val = HOST_TO_JAVA_CHAR(val);
    154     return writeBytes(stream, &val, sizeof(val));
    155 }
    156 
    157 jdwpError
    158 outStream_writeShort(PacketOutputStream *stream, jshort val)
    159 {
    160     val = HOST_TO_JAVA_SHORT(val);
    161     return writeBytes(stream, &val, sizeof(val));
    162 }
    163 
    164 jdwpError
    165 outStream_writeInt(PacketOutputStream *stream, jint val)
    166 {
    167     val = HOST_TO_JAVA_INT(val);
    168     return writeBytes(stream, &val, sizeof(val));
    169 }
    170 
    171 jdwpError
    172 outStream_writeLong(PacketOutputStream *stream, jlong val)
    173 {
    174     val = HOST_TO_JAVA_LONG(val);
    175     return writeBytes(stream, &val, sizeof(val));
    176 }
    177 
    178 jdwpError
    179 outStream_writeFloat(PacketOutputStream *stream, jfloat val)
    180 {
    181     val = HOST_TO_JAVA_FLOAT(val);
    182     return writeBytes(stream, &val, sizeof(val));
    183 }
    184 
    185 jdwpError
    186 outStream_writeDouble(PacketOutputStream *stream, jdouble val)
    187 {
    188     val = HOST_TO_JAVA_DOUBLE(val);
    189     return writeBytes(stream, &val, sizeof(val));
    190 }
    191 
    192 jdwpError
    193 outStream_writeObjectTag(JNIEnv *env, PacketOutputStream *stream, jobject val)
    194 {
    195     return outStream_writeByte(stream, specificTypeKey(env, val));
    196 }
    197 
    198 jdwpError
    199 outStream_writeObjectRef(JNIEnv *env, PacketOutputStream *stream, jobject val)
    200 {
    201     jlong id;
    202     jlong *idPtr;
    203 
    204     if (stream->error) {
    205         return stream->error;
    206     }
    207 
    208     if (val == NULL) {
    209         id = NULL_OBJECT_ID;
    210     } else {
    211         /* Convert the object to an object id */
    212         id = commonRef_refToID(env, val);
    213         if (id == NULL_OBJECT_ID) {
    214             stream->error = JDWP_ERROR(OUT_OF_MEMORY);
    215             return stream->error;
    216         }
    217 
    218         /* Track the common ref in case we need to release it on a future error */
    219         idPtr = bagAdd(stream->ids);
    220         if (idPtr == NULL) {
    221             commonRef_release(env, id);
    222             stream->error = JDWP_ERROR(OUT_OF_MEMORY);
    223             return stream->error;
    224         } else {
    225             *idPtr = id;
    226         }
    227 
    228         /* Add the encoded object id to the stream */
    229         id = HOST_TO_JAVA_LONG(id);
    230     }
    231 
    232     return writeBytes(stream, &id, sizeof(id));
    233 }
    234 
    235 jdwpError
    236 outStream_writeFrameID(PacketOutputStream *stream, FrameID val)
    237 {
    238     /*
    239      * Not good - we're writing a pointer as a jint.  Need
    240      * to write as a jlong if sizeof(FrameID) == 8.
    241      */
    242     if (sizeof(FrameID) == 8) {
    243         /*LINTED*/
    244         return outStream_writeLong(stream, (jlong)val);
    245     } else {
    246         /*LINTED*/
    247         return outStream_writeInt(stream, (jint)val);
    248     }
    249 }
    250 
    251 jdwpError
    252 outStream_writeMethodID(PacketOutputStream *stream, jmethodID val)
    253 {
    254     /*
    255      * Not good - we're writing a pointer as a jint.  Need
    256      * to write as a jlong if sizeof(jmethodID) == 8.
    257      */
    258     if (sizeof(jmethodID) == 8) {
    259         /*LINTED*/
    260         return outStream_writeLong(stream, (jlong)(intptr_t)val);
    261     } else {
    262         /*LINTED*/
    263         return outStream_writeInt(stream, (jint)(intptr_t)val);
    264     }
    265 }
    266 
    267 jdwpError
    268 outStream_writeFieldID(PacketOutputStream *stream, jfieldID val)
    269 {
    270     /*
    271      * Not good - we're writing a pointer as a jint.  Need
    272      * to write as a jlong if sizeof(jfieldID) == 8.
    273      */
    274     if (sizeof(jfieldID) == 8) {
    275         /*LINTED*/
    276         return outStream_writeLong(stream, (jlong)(intptr_t)val);
    277     } else {
    278         /*LINTED*/
    279         return outStream_writeInt(stream, (jint)(intptr_t)val);
    280     }
    281 }
    282 
    283 jdwpError
    284 outStream_writeLocation(PacketOutputStream *stream, jlocation val)
    285 {
    286     return outStream_writeLong(stream, (jlong)val);
    287 }
    288 
    289 jdwpError
    290 outStream_writeByteArray(PacketOutputStream*stream, jint length,
    291                          jbyte *bytes)
    292 {
    293     (void)outStream_writeInt(stream, length);
    294     return writeBytes(stream, bytes, length);
    295 }
    296 
    297 jdwpError
    298 outStream_writeString(PacketOutputStream *stream, char *string)
    299 {
    300     jdwpError error;
    301     jint      length = string != NULL ? (int)strlen(string) : 0;
    302 
    303     /* Options utf8=y/n controls if we want Standard UTF-8 or Modified */
    304     if ( gdata->modifiedUtf8 ) {
    305         (void)outStream_writeInt(stream, length);
    306         error = writeBytes(stream, (jbyte *)string, length);
    307     } else {
    308         jint      new_length;
    309 
    310         new_length = (gdata->npt->utf8mToUtf8sLength)
    311                             (gdata->npt->utf, (jbyte*)string, length);
    312         if ( new_length == length ) {
    313             (void)outStream_writeInt(stream, length);
    314             error = writeBytes(stream, (jbyte *)string, length);
    315         } else {
    316             char *new_string;
    317 
    318             new_string = jvmtiAllocate(new_length+1);
    319             (gdata->npt->utf8mToUtf8s)
    320                             (gdata->npt->utf, (jbyte*)string, length,
    321                              (jbyte*)new_string, new_length);
    322             (void)outStream_writeInt(stream, new_length);
    323             error = writeBytes(stream, (jbyte *)new_string, new_length);
    324             jvmtiDeallocate(new_string);
    325         }
    326     }
    327     return error;
    328 }
    329 
    330 jdwpError
    331 outStream_writeValue(JNIEnv *env, PacketOutputStream *out,
    332                      jbyte typeKey, jvalue value)
    333 {
    334     if (typeKey == JDWP_TAG(OBJECT)) {
    335         (void)outStream_writeByte(out, specificTypeKey(env, value.l));
    336     } else {
    337         (void)outStream_writeByte(out, typeKey);
    338     }
    339     if (isObjectTag(typeKey)) {
    340         (void)outStream_writeObjectRef(env, out, value.l);
    341     } else {
    342         switch (typeKey) {
    343             case JDWP_TAG(BYTE):
    344                 return outStream_writeByte(out, value.b);
    345 
    346             case JDWP_TAG(CHAR):
    347                 return outStream_writeChar(out, value.c);
    348 
    349             case JDWP_TAG(FLOAT):
    350                 return outStream_writeFloat(out, value.f);
    351 
    352             case JDWP_TAG(DOUBLE):
    353                 return outStream_writeDouble(out, value.d);
    354 
    355             case JDWP_TAG(INT):
    356                 return outStream_writeInt(out, value.i);
    357 
    358             case JDWP_TAG(LONG):
    359                 return outStream_writeLong(out, value.j);
    360 
    361             case JDWP_TAG(SHORT):
    362                 return outStream_writeShort(out, value.s);
    363 
    364             case JDWP_TAG(BOOLEAN):
    365                 return outStream_writeBoolean(out, value.z);
    366 
    367             case JDWP_TAG(VOID):  /* happens with function return values */
    368                 /* write nothing */
    369                 return JDWP_ERROR(NONE);
    370 
    371             default:
    372                 EXIT_ERROR(AGENT_ERROR_INVALID_OBJECT,"Invalid type key");
    373                 break;
    374         }
    375     }
    376     return JDWP_ERROR(NONE);
    377 }
    378 
    379 jdwpError
    380 outStream_skipBytes(PacketOutputStream *stream, jint count)
    381 {
    382     int i;
    383     for (i = 0; i < count; i++) {
    384         (void)outStream_writeByte(stream, 0);
    385     }
    386     return stream->error;
    387 }
    388 
    389 jdwpError
    390 outStream_error(PacketOutputStream *stream)
    391 {
    392     return stream->error;
    393 }
    394 
    395 void
    396 outStream_setError(PacketOutputStream *stream, jdwpError error)
    397 {
    398     if (stream->error == JDWP_ERROR(NONE)) {
    399         stream->error = error;
    400         LOG_MISC(("outStream_setError error=%s(%d)", jdwpErrorText(error), error));
    401     }
    402 }
    403 
    404 static jint
    405 outStream_send(PacketOutputStream *stream) {
    406 
    407     jint rc;
    408     jint len = 0;
    409     PacketData *segment;
    410     jbyte *data, *posP;
    411 
    412     /*
    413      * If there's only 1 segment then we just send the
    414      * packet.
    415      */
    416     if (stream->firstSegment.next == NULL) {
    417         stream->packet.type.cmd.len = 11 + stream->firstSegment.length;
    418         stream->packet.type.cmd.data = stream->firstSegment.data;
    419         rc = transport_sendPacket(&stream->packet);
    420         return rc;
    421     }
    422 
    423     /*
    424      * Multiple segments
    425      */
    426     len = 0;
    427     segment = (PacketData *)&(stream->firstSegment);
    428     do {
    429         len += segment->length;
    430         segment = segment->next;
    431     } while (segment != NULL);
    432 
    433     data = jvmtiAllocate(len);
    434     if (data == NULL) {
    435         return JDWP_ERROR(OUT_OF_MEMORY);
    436     }
    437 
    438     posP = data;
    439     segment = (PacketData *)&(stream->firstSegment);
    440     while (segment != NULL) {
    441         (void)memcpy(posP, segment->data, segment->length);
    442         posP += segment->length;
    443         segment = segment->next;
    444     }
    445 
    446     stream->packet.type.cmd.len = 11 + len;
    447     stream->packet.type.cmd.data = data;
    448     rc = transport_sendPacket(&stream->packet);
    449     stream->packet.type.cmd.data = NULL;
    450     jvmtiDeallocate(data);
    451 
    452     return rc;
    453 }
    454 
    455 void
    456 outStream_sendReply(PacketOutputStream *stream)
    457 {
    458     jint rc;
    459     if (stream->error) {
    460         /*
    461          * Don't send any collected stream data on an error reply
    462          */
    463         stream->packet.type.reply.len = 0;
    464         stream->packet.type.reply.errorCode = (jshort)stream->error;
    465     }
    466     rc = outStream_send(stream);
    467     if (rc == 0) {
    468         stream->sent = JNI_TRUE;
    469     }
    470 }
    471 
    472 void
    473 outStream_sendCommand(PacketOutputStream *stream)
    474 {
    475     jint rc;
    476     if (!stream->error) {
    477         rc = outStream_send(stream);
    478         if (rc == 0) {
    479             stream->sent = JNI_TRUE;
    480         }
    481     }
    482 }
    483 
    484 
    485 static jboolean
    486 releaseID(void *elementPtr, void *arg)
    487 {
    488     jlong *idPtr = elementPtr;
    489     commonRef_release(getEnv(), *idPtr);
    490     return JNI_TRUE;
    491 }
    492 
    493 void
    494 outStream_destroy(PacketOutputStream *stream)
    495 {
    496     struct PacketData *next;
    497 
    498     if (stream->error || !stream->sent) {
    499         (void)bagEnumerateOver(stream->ids, releaseID, NULL);
    500     }
    501 
    502     next = stream->firstSegment.next;
    503     while (next != NULL) {
    504         struct PacketData *p = next;
    505         next = p->next;
    506         jvmtiDeallocate(p->data);
    507         jvmtiDeallocate(p);
    508     }
    509     bagDestroyBag(stream->ids);
    510 }
    511