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