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