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