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