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
commonInit(PacketOutputStream * stream)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
outStream_initCommand(PacketOutputStream * stream,jint id,jbyte flags,jbyte commandSet,jbyte command)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
outStream_initReply(PacketOutputStream * stream,jint id)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
outStream_id(PacketOutputStream * stream)86 outStream_id(PacketOutputStream *stream)
87 {
88 return stream->packet.type.cmd.id;
89 }
90
91 jbyte
outStream_command(PacketOutputStream * stream)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
writeBytes(PacketOutputStream * stream,void * source,int size)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
outStream_writeBoolean(PacketOutputStream * stream,jboolean val)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
outStream_writeByte(PacketOutputStream * stream,jbyte val)146 outStream_writeByte(PacketOutputStream *stream, jbyte val)
147 {
148 return writeBytes(stream, &val, sizeof(val));
149 }
150
151 jdwpError
outStream_writeChar(PacketOutputStream * stream,jchar val)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
outStream_writeShort(PacketOutputStream * stream,jshort val)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
outStream_writeInt(PacketOutputStream * stream,jint val)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
outStream_writeLong(PacketOutputStream * stream,jlong val)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
outStream_writeFloat(PacketOutputStream * stream,jfloat val)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
outStream_writeDouble(PacketOutputStream * stream,jdouble val)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
outStream_writeObjectTag(JNIEnv * env,PacketOutputStream * stream,jobject val)194 outStream_writeObjectTag(JNIEnv *env, PacketOutputStream *stream, jobject val)
195 {
196 return outStream_writeByte(stream, specificTypeKey(env, val));
197 }
198
199 jdwpError
outStream_writeModuleRef(JNIEnv * env,PacketOutputStream * stream,jobject val)200 outStream_writeModuleRef(JNIEnv *env, PacketOutputStream *stream, jobject val)
201 {
202 return outStream_writeObjectRef(env, stream, val);
203 }
204
205 jdwpError
outStream_writeObjectRef(JNIEnv * env,PacketOutputStream * stream,jobject val)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
outStream_writeFrameID(PacketOutputStream * stream,FrameID val)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
outStream_writeMethodID(PacketOutputStream * stream,jmethodID val)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
outStream_writeFieldID(PacketOutputStream * stream,jfieldID val)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
outStream_writeLocation(PacketOutputStream * stream,jlocation val)291 outStream_writeLocation(PacketOutputStream *stream, jlocation val)
292 {
293 return outStream_writeLong(stream, (jlong)val);
294 }
295
296 jdwpError
outStream_writeByteArray(PacketOutputStream * stream,jint length,jbyte * bytes)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
outStream_writeString(PacketOutputStream * stream,char * string)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
outStream_writeValue(JNIEnv * env,PacketOutputStream * out,jbyte typeKey,jvalue value)335 outStream_writeValue(JNIEnv *env, PacketOutputStream *out,
336 jbyte typeKey, jvalue value)
337 {
338 if (typeKey == JDWP_TAG(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
outStream_skipBytes(PacketOutputStream * stream,jint count)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
outStream_error(PacketOutputStream * stream)394 outStream_error(PacketOutputStream *stream)
395 {
396 return stream->error;
397 }
398
399 void
outStream_setError(PacketOutputStream * stream,jdwpError error)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
outStream_send(PacketOutputStream * stream)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
outStream_sendReply(PacketOutputStream * stream)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
outStream_sendCommand(PacketOutputStream * stream)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
releaseID(void * elementPtr,void * arg)490 releaseID(void *elementPtr, void *arg)
491 {
492 jlong *idPtr = elementPtr;
493 commonRef_release(getEnv(), *idPtr);
494 return JNI_TRUE;
495 }
496
497 void
outStream_destroy(PacketOutputStream * stream)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 }
515