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 "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; 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 an object 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_readObjectRef(JNIEnv *env, PacketInputStream *stream) 175 { 176 jobject ref; 177 jobject *refPtr; 178 jlong id = inStream_readLong(stream); 179 if (stream->error) { 180 return NULL; 181 } 182 if (id == NULL_OBJECT_ID) { 183 return NULL; 184 } 185 186 ref = commonRef_idToRef(env, id); 187 if (ref == NULL) { 188 stream->error = JDWP_ERROR(INVALID_OBJECT); 189 return NULL; 190 } 191 192 refPtr = bagAdd(stream->refs); 193 if (refPtr == NULL) { 194 commonRef_idToRef_delete(env, ref); 195 return NULL; 196 } 197 198 *refPtr = ref; 199 return ref; 200 } 201 202 /* 203 * Read a raw object id from the stream. This should be used rarely. 204 * Normally, inStream_readObjectRef is preferred since it takes care 205 * of reference conversion and tracking. Only code that needs to 206 * perform maintence of the commonRef hash table uses this function. 207 */ 208 jlong 209 inStream_readObjectID(PacketInputStream *stream) 210 { 211 return inStream_readLong(stream); 212 } 213 214 jclass 215 inStream_readClassRef(JNIEnv *env, PacketInputStream *stream) 216 { 217 jobject object = inStream_readObjectRef(env, stream); 218 if (object == NULL) { 219 /* 220 * Could be error or just the null reference. In either case, 221 * stop now. 222 */ 223 return NULL; 224 } 225 if (!isClass(object)) { 226 stream->error = JDWP_ERROR(INVALID_CLASS); 227 return NULL; 228 } 229 return object; 230 } 231 232 jthread 233 inStream_readThreadRef(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 (!isThread(object)) { 244 stream->error = JDWP_ERROR(INVALID_THREAD); 245 return NULL; 246 } 247 return object; 248 } 249 250 jthreadGroup 251 inStream_readThreadGroupRef(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 (!isThreadGroup(object)) { 262 stream->error = JDWP_ERROR(INVALID_THREAD_GROUP); 263 return NULL; 264 } 265 return object; 266 } 267 268 jstring 269 inStream_readStringRef(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 (!isString(object)) { 280 stream->error = JDWP_ERROR(INVALID_STRING); 281 return NULL; 282 } 283 return object; 284 } 285 286 jclass 287 inStream_readClassLoaderRef(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 (!isClassLoader(object)) { 298 stream->error = JDWP_ERROR(INVALID_CLASS_LOADER); 299 return NULL; 300 } 301 return object; 302 } 303 304 jarray 305 inStream_readArrayRef(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 (!isArray(object)) { 316 stream->error = JDWP_ERROR(INVALID_ARRAY); 317 return NULL; 318 } 319 return object; 320 } 321 322 /* 323 * Next 3 functions read an Int and convert to a Pointer!? 324 * If sizeof(jxxxID) == 8 we must read these values as Longs. 325 */ 326 FrameID 327 inStream_readFrameID(PacketInputStream *stream) 328 { 329 if (sizeof(FrameID) == 8) { 330 /*LINTED*/ 331 return (FrameID)inStream_readLong(stream); 332 } else { 333 /*LINTED*/ 334 return (FrameID)inStream_readInt(stream); 335 } 336 } 337 338 jmethodID 339 inStream_readMethodID(PacketInputStream *stream) 340 { 341 if (sizeof(jmethodID) == 8) { 342 /*LINTED*/ 343 return (jmethodID)(intptr_t)inStream_readLong(stream); 344 } else { 345 /*LINTED*/ 346 return (jmethodID)(intptr_t)inStream_readInt(stream); 347 } 348 } 349 350 jfieldID 351 inStream_readFieldID(PacketInputStream *stream) 352 { 353 if (sizeof(jfieldID) == 8) { 354 /*LINTED*/ 355 return (jfieldID)(intptr_t)inStream_readLong(stream); 356 } else { 357 /*LINTED*/ 358 return (jfieldID)(intptr_t)inStream_readInt(stream); 359 } 360 } 361 362 jlocation 363 inStream_readLocation(PacketInputStream *stream) 364 { 365 return (jlocation)inStream_readLong(stream); 366 } 367 368 char * 369 inStream_readString(PacketInputStream *stream) 370 { 371 int length; 372 char *string; 373 374 length = inStream_readInt(stream); 375 string = jvmtiAllocate(length + 1); 376 if (string != NULL) { 377 int new_length; 378 379 (void)readBytes(stream, string, length); 380 string[length] = '\0'; 381 382 /* This is Standard UTF-8, convert to Modified UTF-8 if necessary */ 383 new_length = utf8sToUtf8mLength((jbyte*)string, length); 384 if ( new_length != length ) { 385 char *new_string; 386 387 new_string = jvmtiAllocate(new_length+1); 388 utf8sToUtf8m((jbyte*)string, length, (jbyte*)new_string, new_length); 389 jvmtiDeallocate(string); 390 return new_string; 391 } 392 } 393 return string; 394 } 395 396 jboolean 397 inStream_endOfInput(PacketInputStream *stream) 398 { 399 return (stream->left > 0); 400 } 401 402 jdwpError 403 inStream_error(PacketInputStream *stream) 404 { 405 return stream->error; 406 } 407 408 void 409 inStream_clearError(PacketInputStream *stream) { 410 stream->error = JDWP_ERROR(NONE); 411 } 412 413 jvalue 414 inStream_readValue(PacketInputStream *stream, jbyte *typeKeyPtr) 415 { 416 jvalue value; 417 jbyte typeKey = inStream_readByte(stream); 418 if (stream->error) { 419 value.j = 0L; 420 return value; 421 } 422 423 if (isObjectTag(typeKey)) { 424 value.l = inStream_readObjectRef(getEnv(), stream); 425 } else { 426 switch (typeKey) { 427 case JDWP_TAG(BYTE): 428 value.b = inStream_readByte(stream); 429 break; 430 431 case JDWP_TAG(CHAR): 432 value.c = inStream_readChar(stream); 433 break; 434 435 case JDWP_TAG(FLOAT): 436 value.f = inStream_readFloat(stream); 437 break; 438 439 case JDWP_TAG(DOUBLE): 440 value.d = inStream_readDouble(stream); 441 break; 442 443 case JDWP_TAG(INT): 444 value.i = inStream_readInt(stream); 445 break; 446 447 case JDWP_TAG(LONG): 448 value.j = inStream_readLong(stream); 449 break; 450 451 case JDWP_TAG(SHORT): 452 value.s = inStream_readShort(stream); 453 break; 454 455 case JDWP_TAG(BOOLEAN): 456 value.z = inStream_readBoolean(stream); 457 break; 458 default: 459 stream->error = JDWP_ERROR(INVALID_TAG); 460 break; 461 } 462 } 463 if (typeKeyPtr) { 464 *typeKeyPtr = typeKey; 465 } 466 return value; 467 } 468 469 static jboolean 470 deleteRef(void *elementPtr, void *arg) 471 { 472 JNIEnv *env = arg; 473 jobject *refPtr = elementPtr; 474 commonRef_idToRef_delete(env, *refPtr); 475 return JNI_TRUE; 476 } 477 478 void 479 inStream_destroy(PacketInputStream *stream) 480 { 481 if (stream->packet.type.cmd.data != NULL) { 482 jvmtiDeallocate(stream->packet.type.cmd.data); 483 } 484 485 (void)bagEnumerateOver(stream->refs, deleteRef, (void *)getEnv()); 486 bagDestroyBag(stream->refs); 487 }