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