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