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
commonInit(PacketOutputStream * stream)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
outStream_initCommand(PacketOutputStream * stream,jint id,jbyte flags,jbyte commandSet,jbyte command)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
outStream_initReply(PacketOutputStream * stream,jint id)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
outStream_id(PacketOutputStream * stream)85 outStream_id(PacketOutputStream *stream)
86 {
87 return stream->packet.type.cmd.id;
88 }
89
90 jbyte
outStream_command(PacketOutputStream * stream)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
writeBytes(PacketOutputStream * stream,void * source,int size)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
outStream_writeBoolean(PacketOutputStream * stream,jboolean val)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
outStream_writeByte(PacketOutputStream * stream,jbyte val)145 outStream_writeByte(PacketOutputStream *stream, jbyte val)
146 {
147 return writeBytes(stream, &val, sizeof(val));
148 }
149
150 jdwpError
outStream_writeChar(PacketOutputStream * stream,jchar val)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
outStream_writeShort(PacketOutputStream * stream,jshort val)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
outStream_writeInt(PacketOutputStream * stream,jint val)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
outStream_writeLong(PacketOutputStream * stream,jlong val)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
outStream_writeFloat(PacketOutputStream * stream,jfloat val)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
outStream_writeDouble(PacketOutputStream * stream,jdouble val)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
outStream_writeObjectTag(JNIEnv * env,PacketOutputStream * stream,jobject val)193 outStream_writeObjectTag(JNIEnv *env, PacketOutputStream *stream, jobject val)
194 {
195 return outStream_writeByte(stream, specificTypeKey(env, val));
196 }
197
198 jdwpError
outStream_writeObjectRef(JNIEnv * env,PacketOutputStream * stream,jobject val)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
outStream_writeFrameID(PacketOutputStream * stream,FrameID val)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
outStream_writeMethodID(PacketOutputStream * stream,jmethodID val)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
outStream_writeFieldID(PacketOutputStream * stream,jfieldID val)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
outStream_writeLocation(PacketOutputStream * stream,jlocation val)284 outStream_writeLocation(PacketOutputStream *stream, jlocation val)
285 {
286 return outStream_writeLong(stream, (jlong)val);
287 }
288
289 jdwpError
outStream_writeByteArray(PacketOutputStream * stream,jint length,jbyte * bytes)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
outStream_writeString(PacketOutputStream * stream,char * string)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
outStream_writeValue(JNIEnv * env,PacketOutputStream * out,jbyte typeKey,jvalue value)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
outStream_skipBytes(PacketOutputStream * stream,jint count)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
outStream_error(PacketOutputStream * stream)390 outStream_error(PacketOutputStream *stream)
391 {
392 return stream->error;
393 }
394
395 void
outStream_setError(PacketOutputStream * stream,jdwpError error)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
outStream_send(PacketOutputStream * stream)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
outStream_sendReply(PacketOutputStream * stream)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
outStream_sendCommand(PacketOutputStream * stream)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
releaseID(void * elementPtr,void * arg)486 releaseID(void *elementPtr, void *arg)
487 {
488 jlong *idPtr = elementPtr;
489 commonRef_release(getEnv(), *idPtr);
490 return JNI_TRUE;
491 }
492
493 void
outStream_destroy(PacketOutputStream * stream)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