1 /*
   2  * Copyright (c) 1998, 2017, 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_writeModuleRef(JNIEnv *env, PacketOutputStream *stream, jobject val)
 201 {
 202     return outStream_writeObjectRef(env, stream, val);
 203 }
 204 
 205 jdwpError
 206 outStream_writeObjectRef(JNIEnv *env, PacketOutputStream *stream, jobject val)
 207 {
 208     jlong id;
 209     jlong *idPtr;
 210 
 211     if (stream->error) {
 212         return stream->error;
 213     }
 214 
 215     if (val == NULL) {
 216         id = NULL_OBJECT_ID;
 217     } else {
 218         /* Convert the object to an object id */
 219         id = commonRef_refToID(env, val);
 220         if (id == NULL_OBJECT_ID) {
 221             stream->error = JDWP_ERROR(OUT_OF_MEMORY);
 222             return stream->error;
 223         }
 224 
 225         /* Track the common ref in case we need to release it on a future error */
 226         idPtr = bagAdd(stream->ids);
 227         if (idPtr == NULL) {
 228             commonRef_release(env, id);
 229             stream->error = JDWP_ERROR(OUT_OF_MEMORY);
 230             return stream->error;
 231         } else {
 232             *idPtr = id;
 233         }
 234 
 235         /* Add the encoded object id to the stream */
 236         id = HOST_TO_JAVA_LONG(id);
 237     }
 238 
 239     return writeBytes(stream, &id, sizeof(id));
 240 }
 241 
 242 jdwpError
 243 outStream_writeFrameID(PacketOutputStream *stream, FrameID val)
 244 {
 245     /*
 246      * Not good - we're writing a pointer as a jint.  Need
 247      * to write as a jlong if sizeof(FrameID) == 8.
 248      */
 249     if (sizeof(FrameID) == 8) {
 250         /*LINTED*/
 251         return outStream_writeLong(stream, (jlong)val);
 252     } else {
 253         /*LINTED*/
 254         return outStream_writeInt(stream, (jint)val);
 255     }
 256 }
 257 
 258 jdwpError
 259 outStream_writeMethodID(PacketOutputStream *stream, jmethodID val)
 260 {
 261     /*
 262      * Not good - we're writing a pointer as a jint.  Need
 263      * to write as a jlong if sizeof(jmethodID) == 8.
 264      */
 265     if (sizeof(jmethodID) == 8) {
 266         /*LINTED*/
 267         return outStream_writeLong(stream, (jlong)(intptr_t)val);
 268     } else {
 269         /*LINTED*/
 270         return outStream_writeInt(stream, (jint)(intptr_t)val);
 271     }
 272 }
 273 
 274 jdwpError
 275 outStream_writeFieldID(PacketOutputStream *stream, jfieldID val)
 276 {
 277     /*
 278      * Not good - we're writing a pointer as a jint.  Need
 279      * to write as a jlong if sizeof(jfieldID) == 8.
 280      */
 281     if (sizeof(jfieldID) == 8) {
 282         /*LINTED*/
 283         return outStream_writeLong(stream, (jlong)(intptr_t)val);
 284     } else {
 285         /*LINTED*/
 286         return outStream_writeInt(stream, (jint)(intptr_t)val);
 287     }
 288 }
 289 
 290 jdwpError
 291 outStream_writeLocation(PacketOutputStream *stream, jlocation val)
 292 {
 293     return outStream_writeLong(stream, (jlong)val);
 294 }
 295 
 296 jdwpError
 297 outStream_writeByteArray(PacketOutputStream*stream, jint length,
 298                          jbyte *bytes)
 299 {
 300     (void)outStream_writeInt(stream, length);
 301     return writeBytes(stream, bytes, length);
 302 }
 303 
 304 jdwpError
 305 outStream_writeString(PacketOutputStream *stream, char *string)
 306 {
 307     jdwpError error;
 308     jint      length = string != NULL ? (int)strlen(string) : 0;
 309 
 310     /* Options utf8=y/n controls if we want Standard UTF-8 or Modified */
 311     if ( gdata->modifiedUtf8 ) {
 312         (void)outStream_writeInt(stream, length);
 313         error = writeBytes(stream, (jbyte *)string, length);
 314     } else {
 315         jint      new_length;
 316 
 317         new_length = utf8mToUtf8sLength((jbyte*)string, length);
 318         if ( new_length == length ) {
 319             (void)outStream_writeInt(stream, length);
 320             error = writeBytes(stream, (jbyte *)string, length);
 321         } else {
 322             char *new_string;
 323 
 324             new_string = jvmtiAllocate(new_length+1);
 325             utf8mToUtf8s((jbyte*)string, length, (jbyte*)new_string, new_length);
 326             (void)outStream_writeInt(stream, new_length);
 327             error = writeBytes(stream, (jbyte *)new_string, new_length);
 328             jvmtiDeallocate(new_string);
 329         }
 330     }
 331     return error;
 332 }
 333 
 334 jdwpError
 335 outStream_writeValue(JNIEnv *env, PacketOutputStream *out,
 336                      jbyte typeKey, jvalue value)
 337 {
 338     if (typeKey == JDWP_TAG(OBJECT) || typeKey == JDWP_TAG(INLINE_OBJECT)) {
 339         (void)outStream_writeByte(out, specificTypeKey(env, value.l));
 340     } else {
 341         (void)outStream_writeByte(out, typeKey);
 342     }
 343     if (isObjectTag(typeKey)) {
 344         (void)outStream_writeObjectRef(env, out, value.l);
 345     } else {
 346         switch (typeKey) {
 347             case JDWP_TAG(BYTE):
 348                 return outStream_writeByte(out, value.b);
 349 
 350             case JDWP_TAG(CHAR):
 351                 return outStream_writeChar(out, value.c);
 352 
 353             case JDWP_TAG(FLOAT):
 354                 return outStream_writeFloat(out, value.f);
 355 
 356             case JDWP_TAG(DOUBLE):
 357                 return outStream_writeDouble(out, value.d);
 358 
 359             case JDWP_TAG(INT):
 360                 return outStream_writeInt(out, value.i);
 361 
 362             case JDWP_TAG(LONG):
 363                 return outStream_writeLong(out, value.j);
 364 
 365             case JDWP_TAG(SHORT):
 366                 return outStream_writeShort(out, value.s);
 367 
 368             case JDWP_TAG(BOOLEAN):
 369                 return outStream_writeBoolean(out, value.z);
 370 
 371             case JDWP_TAG(VOID):  /* happens with function return values */
 372                 /* write nothing */
 373                 return JDWP_ERROR(NONE);
 374 
 375             default:
 376                 EXIT_ERROR(AGENT_ERROR_INVALID_OBJECT,"Invalid type key");
 377                 break;
 378         }
 379     }
 380     return JDWP_ERROR(NONE);
 381 }
 382 
 383 jdwpError
 384 outStream_skipBytes(PacketOutputStream *stream, jint count)
 385 {
 386     int i;
 387     for (i = 0; i < count; i++) {
 388         (void)outStream_writeByte(stream, 0);
 389     }
 390     return stream->error;
 391 }
 392 
 393 jdwpError
 394 outStream_error(PacketOutputStream *stream)
 395 {
 396     return stream->error;
 397 }
 398 
 399 void
 400 outStream_setError(PacketOutputStream *stream, jdwpError error)
 401 {
 402     if (stream->error == JDWP_ERROR(NONE)) {
 403         stream->error = error;
 404         LOG_MISC(("outStream_setError error=%s(%d)", jdwpErrorText(error), error));
 405     }
 406 }
 407 
 408 static jint
 409 outStream_send(PacketOutputStream *stream) {
 410 
 411     jint rc;
 412     jint len = 0;
 413     PacketData *segment;
 414     jbyte *data, *posP;
 415 
 416     /*
 417      * If there's only 1 segment then we just send the
 418      * packet.
 419      */
 420     if (stream->firstSegment.next == NULL) {
 421         stream->packet.type.cmd.len = JDWP_HEADER_SIZE + stream->firstSegment.length;
 422         stream->packet.type.cmd.data = stream->firstSegment.data;
 423         rc = transport_sendPacket(&stream->packet);
 424         return rc;
 425     }
 426 
 427     /*
 428      * Multiple segments
 429      */
 430     len = 0;
 431     segment = (PacketData *)&(stream->firstSegment);
 432     do {
 433         len += segment->length;
 434         segment = segment->next;
 435     } while (segment != NULL);
 436 
 437     data = jvmtiAllocate(len);
 438     if (data == NULL) {
 439         return JDWP_ERROR(OUT_OF_MEMORY);
 440     }
 441 
 442     posP = data;
 443     segment = (PacketData *)&(stream->firstSegment);
 444     while (segment != NULL) {
 445         (void)memcpy(posP, segment->data, segment->length);
 446         posP += segment->length;
 447         segment = segment->next;
 448     }
 449 
 450     stream->packet.type.cmd.len = JDWP_HEADER_SIZE + len;
 451     stream->packet.type.cmd.data = data;
 452     rc = transport_sendPacket(&stream->packet);
 453     stream->packet.type.cmd.data = NULL;
 454     jvmtiDeallocate(data);
 455 
 456     return rc;
 457 }
 458 
 459 void
 460 outStream_sendReply(PacketOutputStream *stream)
 461 {
 462     jint rc;
 463     if (stream->error) {
 464         /*
 465          * Don't send any collected stream data on an error reply
 466          */
 467         stream->packet.type.reply.len = 0;
 468         stream->packet.type.reply.errorCode = (jshort)stream->error;
 469     }
 470     rc = outStream_send(stream);
 471     if (rc == 0) {
 472         stream->sent = JNI_TRUE;
 473     }
 474 }
 475 
 476 void
 477 outStream_sendCommand(PacketOutputStream *stream)
 478 {
 479     jint rc;
 480     if (!stream->error) {
 481         rc = outStream_send(stream);
 482         if (rc == 0) {
 483             stream->sent = JNI_TRUE;
 484         }
 485     }
 486 }
 487 
 488 
 489 static jboolean
 490 releaseID(void *elementPtr, void *arg)
 491 {
 492     jlong *idPtr = elementPtr;
 493     commonRef_release(getEnv(), *idPtr);
 494     return JNI_TRUE;
 495 }
 496 
 497 void
 498 outStream_destroy(PacketOutputStream *stream)
 499 {
 500     struct PacketData *next;
 501 
 502     if (stream->error || !stream->sent) {
 503         (void)bagEnumerateOver(stream->ids, releaseID, NULL);
 504     }
 505 
 506     next = stream->firstSegment.next;
 507     while (next != NULL) {
 508         struct PacketData *p = next;
 509         next = p->next;
 510         jvmtiDeallocate(p->data);
 511         jvmtiDeallocate(p);
 512     }
 513     bagDestroyBag(stream->ids);
 514 }