1 /*
2 * Copyright (c) 1998, 2008, 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 "inStream.h"
29 #include "transport.h"
30 #include "bag.h"
31 #include "commonRef.h"
32 #include "FrameID.h"
33
34 #define INITIAL_REF_ALLOC 50
35 #define SMALLEST(a, b) ((a) < (b)) ? (a) : (b)
36
37 /*
38 * TO DO: Support processing of replies through command input streams.
39 */
40 void
inStream_init(PacketInputStream * stream,jdwpPacket packet)41 inStream_init(PacketInputStream *stream, jdwpPacket packet)
42 {
43 stream->packet = packet;
44 stream->error = JDWP_ERROR(NONE);
45 stream->left = packet.type.cmd.len;
46 stream->current = packet.type.cmd.data;
47 stream->refs = bagCreateBag(sizeof(jobject), INITIAL_REF_ALLOC);
48 if (stream->refs == NULL) {
49 stream->error = JDWP_ERROR(OUT_OF_MEMORY);
50 }
51 }
52
53 jint
inStream_id(PacketInputStream * stream)54 inStream_id(PacketInputStream *stream)
55 {
56 return stream->packet.type.cmd.id;
57 }
58
59 jbyte
inStream_command(PacketInputStream * stream)60 inStream_command(PacketInputStream *stream)
61 {
62 return stream->packet.type.cmd.cmd;
63 }
64
65 static jdwpError
readBytes(PacketInputStream * stream,void * dest,int size)66 readBytes(PacketInputStream *stream, void *dest, int size)
67 {
68 if (stream->error) {
69 return stream->error;
70 }
71
72 if (size > stream->left) {
73 stream->error = JDWP_ERROR(INTERNAL);
74 return stream->error;
75 }
76
77 if (dest) {
78 (void)memcpy(dest, stream->current, size);
79 }
80 stream->current += size;
81 stream->left -= size;
82
83 return stream->error;
84 }
85
86 jdwpError
inStream_skipBytes(PacketInputStream * stream,jint size)87 inStream_skipBytes(PacketInputStream *stream, jint size) {
88 return readBytes(stream, NULL, size);
89 }
90
91 jboolean
inStream_readBoolean(PacketInputStream * stream)92 inStream_readBoolean(PacketInputStream *stream)
93 {
94 jbyte flag = 0;
95 (void)readBytes(stream, &flag, sizeof(flag));
96 if (stream->error) {
97 return 0;
98 } else {
99 return flag ? JNI_TRUE : JNI_FALSE;
100 }
101 }
102
103 jbyte
inStream_readByte(PacketInputStream * stream)104 inStream_readByte(PacketInputStream *stream)
105 {
106 jbyte val = 0;
107 (void)readBytes(stream, &val, sizeof(val));
108 return val;
109 }
110
111 jbyte *
inStream_readBytes(PacketInputStream * stream,int length,jbyte * buf)112 inStream_readBytes(PacketInputStream *stream, int length, jbyte *buf)
113 {
114 (void)readBytes(stream, buf, length);
115 return buf;
116 }
117
118 jchar
inStream_readChar(PacketInputStream * stream)119 inStream_readChar(PacketInputStream *stream)
120 {
121 jchar val = 0;
122 (void)readBytes(stream, &val, sizeof(val));
123 return JAVA_TO_HOST_CHAR(val);
124 }
125
126 jshort
inStream_readShort(PacketInputStream * stream)127 inStream_readShort(PacketInputStream *stream)
128 {
129 jshort val = 0;
130 (void)readBytes(stream, &val, sizeof(val));
131 return JAVA_TO_HOST_SHORT(val);
132 }
133
134 jint
inStream_readInt(PacketInputStream * stream)135 inStream_readInt(PacketInputStream *stream)
136 {
137 jint val = 0;
138 (void)readBytes(stream, &val, sizeof(val));
139 return JAVA_TO_HOST_INT(val);
140 }
141
142 jlong
inStream_readLong(PacketInputStream * stream)143 inStream_readLong(PacketInputStream *stream)
144 {
145 jlong val = 0;
146 (void)readBytes(stream, &val, sizeof(val));
147 return JAVA_TO_HOST_LONG(val);
148 }
149
150 jfloat
inStream_readFloat(PacketInputStream * stream)151 inStream_readFloat(PacketInputStream *stream)
152 {
153 jfloat val = 0;
154 (void)readBytes(stream, &val, sizeof(val));
155 return JAVA_TO_HOST_FLOAT(val);
156 }
157
158 jdouble
inStream_readDouble(PacketInputStream * stream)159 inStream_readDouble(PacketInputStream *stream)
160 {
161 jdouble val = 0;
162 (void)readBytes(stream, &val, sizeof(val));
163 return JAVA_TO_HOST_DOUBLE(val);
164 }
165
166 /*
167 * Read an object from the stream. The ID used in the wire protocol
168 * is converted to a reference which is returned. The reference is
169 * global and strong, but it should *not* be deleted by the caller
170 * since it is freed when this stream is destroyed.
171 */
172 jobject
inStream_readObjectRef(JNIEnv * env,PacketInputStream * stream)173 inStream_readObjectRef(JNIEnv *env, PacketInputStream *stream)
174 {
175 jobject ref;
176 jobject *refPtr;
177 jlong id = inStream_readLong(stream);
178 if (stream->error) {
179 return NULL;
180 }
181 if (id == NULL_OBJECT_ID) {
182 return NULL;
183 }
184
185 ref = commonRef_idToRef(env, id);
186 if (ref == NULL) {
187 stream->error = JDWP_ERROR(INVALID_OBJECT);
188 return NULL;
189 }
190
191 refPtr = bagAdd(stream->refs);
192 if (refPtr == NULL) {
193 commonRef_idToRef_delete(env, ref);
194 return NULL;
195 }
196
197 *refPtr = ref;
198 return ref;
199 }
200
201 /*
202 * Read a raw object id from the stream. This should be used rarely.
203 * Normally, inStream_readObjectRef is preferred since it takes care
204 * of reference conversion and tracking. Only code that needs to
205 * perform maintence of the commonRef hash table uses this function.
206 */
207 jlong
inStream_readObjectID(PacketInputStream * stream)208 inStream_readObjectID(PacketInputStream *stream)
209 {
210 return inStream_readLong(stream);
211 }
212
213 jclass
inStream_readClassRef(JNIEnv * env,PacketInputStream * stream)214 inStream_readClassRef(JNIEnv *env, PacketInputStream *stream)
215 {
216 jobject object = inStream_readObjectRef(env, stream);
217 if (object == NULL) {
218 /*
219 * Could be error or just the null reference. In either case,
220 * stop now.
221 */
222 return NULL;
223 }
224 if (!isClass(object)) {
225 stream->error = JDWP_ERROR(INVALID_CLASS);
226 return NULL;
227 }
228 return object;
229 }
230
231 jthread
inStream_readThreadRef(JNIEnv * env,PacketInputStream * stream)232 inStream_readThreadRef(JNIEnv *env, PacketInputStream *stream)
233 {
234 jobject object = inStream_readObjectRef(env, stream);
235 if (object == NULL) {
236 /*
237 * Could be error or just the null reference. In either case,
238 * stop now.
239 */
240 return NULL;
241 }
242 if (!isThread(object)) {
243 stream->error = JDWP_ERROR(INVALID_THREAD);
244 return NULL;
245 }
246 return object;
247 }
248
249 jthreadGroup
inStream_readThreadGroupRef(JNIEnv * env,PacketInputStream * stream)250 inStream_readThreadGroupRef(JNIEnv *env, PacketInputStream *stream)
251 {
252 jobject object = inStream_readObjectRef(env, stream);
253 if (object == NULL) {
254 /*
255 * Could be error or just the null reference. In either case,
256 * stop now.
257 */
258 return NULL;
259 }
260 if (!isThreadGroup(object)) {
261 stream->error = JDWP_ERROR(INVALID_THREAD_GROUP);
262 return NULL;
263 }
264 return object;
265 }
266
267 jstring
inStream_readStringRef(JNIEnv * env,PacketInputStream * stream)268 inStream_readStringRef(JNIEnv *env, PacketInputStream *stream)
269 {
270 jobject object = inStream_readObjectRef(env, stream);
271 if (object == NULL) {
272 /*
273 * Could be error or just the null reference. In either case,
274 * stop now.
275 */
276 return NULL;
277 }
278 if (!isString(object)) {
279 stream->error = JDWP_ERROR(INVALID_STRING);
280 return NULL;
281 }
282 return object;
283 }
284
285 jclass
inStream_readClassLoaderRef(JNIEnv * env,PacketInputStream * stream)286 inStream_readClassLoaderRef(JNIEnv *env, PacketInputStream *stream)
287 {
288 jobject object = inStream_readObjectRef(env, stream);
289 if (object == NULL) {
290 /*
291 * Could be error or just the null reference. In either case,
292 * stop now.
293 */
294 return NULL;
295 }
296 if (!isClassLoader(object)) {
297 stream->error = JDWP_ERROR(INVALID_CLASS_LOADER);
298 return NULL;
299 }
300 return object;
301 }
302
303 jarray
inStream_readArrayRef(JNIEnv * env,PacketInputStream * stream)304 inStream_readArrayRef(JNIEnv *env, PacketInputStream *stream)
305 {
306 jobject object = inStream_readObjectRef(env, stream);
307 if (object == NULL) {
308 /*
309 * Could be error or just the null reference. In either case,
310 * stop now.
311 */
312 return NULL;
313 }
314 if (!isArray(object)) {
315 stream->error = JDWP_ERROR(INVALID_ARRAY);
316 return NULL;
317 }
318 return object;
319 }
320
321 /*
322 * Next 3 functions read an Int and convert to a Pointer!?
323 * If sizeof(jxxxID) == 8 we must read these values as Longs.
324 */
325 FrameID
inStream_readFrameID(PacketInputStream * stream)326 inStream_readFrameID(PacketInputStream *stream)
327 {
328 if (sizeof(FrameID) == 8) {
329 /*LINTED*/
330 return (FrameID)inStream_readLong(stream);
331 } else {
332 /*LINTED*/
333 return (FrameID)inStream_readInt(stream);
334 }
335 }
336
337 jmethodID
inStream_readMethodID(PacketInputStream * stream)338 inStream_readMethodID(PacketInputStream *stream)
339 {
340 if (sizeof(jmethodID) == 8) {
341 /*LINTED*/
342 return (jmethodID)(intptr_t)inStream_readLong(stream);
343 } else {
344 /*LINTED*/
345 return (jmethodID)(intptr_t)inStream_readInt(stream);
346 }
347 }
348
349 jfieldID
inStream_readFieldID(PacketInputStream * stream)350 inStream_readFieldID(PacketInputStream *stream)
351 {
352 if (sizeof(jfieldID) == 8) {
353 /*LINTED*/
354 return (jfieldID)(intptr_t)inStream_readLong(stream);
355 } else {
356 /*LINTED*/
357 return (jfieldID)(intptr_t)inStream_readInt(stream);
358 }
359 }
360
361 jlocation
inStream_readLocation(PacketInputStream * stream)362 inStream_readLocation(PacketInputStream *stream)
363 {
364 return (jlocation)inStream_readLong(stream);
365 }
366
367 char *
inStream_readString(PacketInputStream * stream)368 inStream_readString(PacketInputStream *stream)
369 {
370 int length;
371 char *string;
372
373 length = inStream_readInt(stream);
374 string = jvmtiAllocate(length + 1);
375 if (string != NULL) {
376 int new_length;
377
378 (void)readBytes(stream, string, length);
379 string[length] = '\0';
380
381 /* This is Standard UTF-8, convert to Modified UTF-8 if necessary */
382 new_length = (gdata->npt->utf8sToUtf8mLength)
383 (gdata->npt->utf, (jbyte*)string, length);
384 if ( new_length != length ) {
385 char *new_string;
386
387 new_string = jvmtiAllocate(new_length+1);
388 (gdata->npt->utf8sToUtf8m)
389 (gdata->npt->utf, (jbyte*)string, length,
390 (jbyte*)new_string, new_length);
391 jvmtiDeallocate(string);
392 return new_string;
393 }
394 }
395 return string;
396 }
397
398 jboolean
inStream_endOfInput(PacketInputStream * stream)399 inStream_endOfInput(PacketInputStream *stream)
400 {
401 return (stream->left > 0);
402 }
403
404 jdwpError
inStream_error(PacketInputStream * stream)405 inStream_error(PacketInputStream *stream)
406 {
407 return stream->error;
408 }
409
410 void
inStream_clearError(PacketInputStream * stream)411 inStream_clearError(PacketInputStream *stream) {
412 stream->error = JDWP_ERROR(NONE);
413 }
414
415 jvalue
inStream_readValue(PacketInputStream * stream,jbyte * typeKeyPtr)416 inStream_readValue(PacketInputStream *stream, jbyte *typeKeyPtr)
417 {
418 jvalue value;
419 jbyte typeKey = inStream_readByte(stream);
420 if (stream->error) {
421 value.j = 0L;
422 return value;
423 }
424
425 if (isObjectTag(typeKey)) {
426 value.l = inStream_readObjectRef(getEnv(), stream);
427 } else {
428 switch (typeKey) {
429 case JDWP_TAG(BYTE):
430 value.b = inStream_readByte(stream);
431 break;
432
433 case JDWP_TAG(CHAR):
434 value.c = inStream_readChar(stream);
435 break;
436
437 case JDWP_TAG(FLOAT):
438 value.f = inStream_readFloat(stream);
439 break;
440
441 case JDWP_TAG(DOUBLE):
442 value.d = inStream_readDouble(stream);
443 break;
444
445 case JDWP_TAG(INT):
446 value.i = inStream_readInt(stream);
447 break;
448
449 case JDWP_TAG(LONG):
450 value.j = inStream_readLong(stream);
451 break;
452
453 case JDWP_TAG(SHORT):
454 value.s = inStream_readShort(stream);
455 break;
456
457 case JDWP_TAG(BOOLEAN):
458 value.z = inStream_readBoolean(stream);
459 break;
460 default:
461 stream->error = JDWP_ERROR(INVALID_TAG);
462 break;
463 }
464 }
465 if (typeKeyPtr) {
466 *typeKeyPtr = typeKey;
467 }
468 return value;
469 }
470
471 static jboolean
deleteRef(void * elementPtr,void * arg)472 deleteRef(void *elementPtr, void *arg)
473 {
474 JNIEnv *env = arg;
475 jobject *refPtr = elementPtr;
476 commonRef_idToRef_delete(env, *refPtr);
477 return JNI_TRUE;
478 }
479
480 void
inStream_destroy(PacketInputStream * stream)481 inStream_destroy(PacketInputStream *stream)
482 {
483 if (stream->packet.type.cmd.data != NULL) {
484 jvmtiDeallocate(stream->packet.type.cmd.data);
485 }
486
487 (void)bagEnumerateOver(stream->refs, deleteRef, (void *)getEnv());
488 bagDestroyBag(stream->refs);
489 }
490