• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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