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