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