0N/A/*
2362N/A * Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A#include "util.h"
0N/A#include "stream.h"
0N/A#include "outStream.h"
0N/A#include "inStream.h"
0N/A#include "transport.h"
0N/A#include "commonRef.h"
0N/A#include "bag.h"
0N/A#include "FrameID.h"
0N/A
0N/A#define INITIAL_ID_ALLOC 50
0N/A#define SMALLEST(a, b) ((a) < (b)) ? (a) : (b)
0N/A
0N/Astatic void
0N/AcommonInit(PacketOutputStream *stream)
0N/A{
0N/A stream->current = &stream->initialSegment[0];
0N/A stream->left = sizeof(stream->initialSegment);
0N/A stream->segment = &stream->firstSegment;
0N/A stream->segment->length = 0;
0N/A stream->segment->data = &stream->initialSegment[0];
0N/A stream->segment->next = NULL;
0N/A stream->error = JDWP_ERROR(NONE);
0N/A stream->sent = JNI_FALSE;
0N/A stream->ids = bagCreateBag(sizeof(jlong), INITIAL_ID_ALLOC);
0N/A if (stream->ids == NULL) {
0N/A stream->error = JDWP_ERROR(OUT_OF_MEMORY);
0N/A }
0N/A}
0N/A
0N/Avoid
0N/AoutStream_initCommand(PacketOutputStream *stream, jint id,
0N/A jbyte flags, jbyte commandSet, jbyte command)
0N/A{
0N/A commonInit(stream);
0N/A
0N/A /*
0N/A * Command-specific initialization
0N/A */
0N/A stream->packet.type.cmd.id = id;
0N/A stream->packet.type.cmd.cmdSet = commandSet;
0N/A stream->packet.type.cmd.cmd = command;
0N/A
0N/A stream->packet.type.cmd.flags = flags;
0N/A}
0N/A
0N/Avoid
0N/AoutStream_initReply(PacketOutputStream *stream, jint id)
0N/A{
0N/A commonInit(stream);
0N/A
0N/A /*
0N/A * Reply-specific initialization
0N/A */
0N/A stream->packet.type.reply.id = id;
0N/A stream->packet.type.reply.errorCode = 0x0;
0N/A stream->packet.type.cmd.flags = (jbyte)JDWPTRANSPORT_FLAGS_REPLY;
0N/A}
0N/A
0N/Ajint
0N/AoutStream_id(PacketOutputStream *stream)
0N/A{
0N/A return stream->packet.type.cmd.id;
0N/A}
0N/A
0N/Ajbyte
0N/AoutStream_command(PacketOutputStream *stream)
0N/A{
0N/A /* Only makes sense for commands */
0N/A JDI_ASSERT(!(stream->packet.type.cmd.flags & JDWPTRANSPORT_FLAGS_REPLY));
0N/A return stream->packet.type.cmd.cmd;
0N/A}
0N/A
0N/Astatic jdwpError
0N/AwriteBytes(PacketOutputStream *stream, void *source, int size)
0N/A{
0N/A jbyte *bytes = (jbyte *)source;
0N/A
0N/A if (stream->error) {
0N/A return stream->error;
0N/A }
0N/A while (size > 0) {
0N/A jint count;
0N/A if (stream->left == 0) {
0N/A jint segSize = SMALLEST(2 * stream->segment->length, MAX_SEGMENT_SIZE);
0N/A jbyte *newSeg = jvmtiAllocate(segSize);
0N/A struct PacketData *newHeader = jvmtiAllocate(sizeof(*newHeader));
0N/A if ((newSeg == NULL) || (newHeader == NULL)) {
0N/A jvmtiDeallocate(newSeg);
0N/A jvmtiDeallocate(newHeader);
0N/A stream->error = JDWP_ERROR(OUT_OF_MEMORY);
0N/A return stream->error;
0N/A }
0N/A newHeader->length = 0;
0N/A newHeader->data = newSeg;
0N/A newHeader->next = NULL;
0N/A stream->segment->next = newHeader;
0N/A stream->segment = newHeader;
0N/A stream->current = newHeader->data;
0N/A stream->left = segSize;
0N/A }
0N/A count = SMALLEST(size, stream->left);
0N/A (void)memcpy(stream->current, bytes, count);
0N/A stream->current += count;
0N/A stream->left -= count;
0N/A stream->segment->length += count;
0N/A size -= count;
0N/A bytes += count;
0N/A }
0N/A return JDWP_ERROR(NONE);
0N/A}
0N/A
0N/AjdwpError
0N/AoutStream_writeBoolean(PacketOutputStream *stream, jboolean val)
0N/A{
0N/A jbyte byte = (val != 0) ? 1 : 0;
0N/A return writeBytes(stream, &byte, sizeof(byte));
0N/A}
0N/A
0N/AjdwpError
0N/AoutStream_writeByte(PacketOutputStream *stream, jbyte val)
0N/A{
0N/A return writeBytes(stream, &val, sizeof(val));
0N/A}
0N/A
0N/AjdwpError
0N/AoutStream_writeChar(PacketOutputStream *stream, jchar val)
0N/A{
0N/A val = HOST_TO_JAVA_CHAR(val);
0N/A return writeBytes(stream, &val, sizeof(val));
0N/A}
0N/A
0N/AjdwpError
0N/AoutStream_writeShort(PacketOutputStream *stream, jshort val)
0N/A{
0N/A val = HOST_TO_JAVA_SHORT(val);
0N/A return writeBytes(stream, &val, sizeof(val));
0N/A}
0N/A
0N/AjdwpError
0N/AoutStream_writeInt(PacketOutputStream *stream, jint val)
0N/A{
0N/A val = HOST_TO_JAVA_INT(val);
0N/A return writeBytes(stream, &val, sizeof(val));
0N/A}
0N/A
0N/AjdwpError
0N/AoutStream_writeLong(PacketOutputStream *stream, jlong val)
0N/A{
0N/A val = HOST_TO_JAVA_LONG(val);
0N/A return writeBytes(stream, &val, sizeof(val));
0N/A}
0N/A
0N/AjdwpError
0N/AoutStream_writeFloat(PacketOutputStream *stream, jfloat val)
0N/A{
0N/A val = HOST_TO_JAVA_FLOAT(val);
0N/A return writeBytes(stream, &val, sizeof(val));
0N/A}
0N/A
0N/AjdwpError
0N/AoutStream_writeDouble(PacketOutputStream *stream, jdouble val)
0N/A{
0N/A val = HOST_TO_JAVA_DOUBLE(val);
0N/A return writeBytes(stream, &val, sizeof(val));
0N/A}
0N/A
0N/AjdwpError
0N/AoutStream_writeObjectTag(JNIEnv *env, PacketOutputStream *stream, jobject val)
0N/A{
0N/A return outStream_writeByte(stream, specificTypeKey(env, val));
0N/A}
0N/A
0N/AjdwpError
0N/AoutStream_writeObjectRef(JNIEnv *env, PacketOutputStream *stream, jobject val)
0N/A{
0N/A jlong id;
0N/A jlong *idPtr;
0N/A
0N/A if (stream->error) {
0N/A return stream->error;
0N/A }
0N/A
0N/A if (val == NULL) {
0N/A id = NULL_OBJECT_ID;
0N/A } else {
0N/A /* Convert the object to an object id */
0N/A id = commonRef_refToID(env, val);
0N/A if (id == NULL_OBJECT_ID) {
0N/A stream->error = JDWP_ERROR(OUT_OF_MEMORY);
0N/A return stream->error;
0N/A }
0N/A
0N/A /* Track the common ref in case we need to release it on a future error */
0N/A idPtr = bagAdd(stream->ids);
0N/A if (idPtr == NULL) {
0N/A commonRef_release(env, id);
0N/A stream->error = JDWP_ERROR(OUT_OF_MEMORY);
0N/A return stream->error;
0N/A } else {
0N/A *idPtr = id;
0N/A }
0N/A
0N/A /* Add the encoded object id to the stream */
0N/A id = HOST_TO_JAVA_LONG(id);
0N/A }
0N/A
0N/A return writeBytes(stream, &id, sizeof(id));
0N/A}
0N/A
0N/AjdwpError
0N/AoutStream_writeFrameID(PacketOutputStream *stream, FrameID val)
0N/A{
0N/A /*
0N/A * Not good - we're writing a pointer as a jint. Need
0N/A * to write as a jlong if sizeof(FrameID) == 8.
0N/A */
0N/A if (sizeof(FrameID) == 8) {
0N/A /*LINTED*/
0N/A return outStream_writeLong(stream, (jlong)val);
0N/A } else {
0N/A /*LINTED*/
0N/A return outStream_writeInt(stream, (jint)val);
0N/A }
0N/A}
0N/A
0N/AjdwpError
0N/AoutStream_writeMethodID(PacketOutputStream *stream, jmethodID val)
0N/A{
0N/A /*
0N/A * Not good - we're writing a pointer as a jint. Need
0N/A * to write as a jlong if sizeof(jmethodID) == 8.
0N/A */
0N/A if (sizeof(jmethodID) == 8) {
0N/A /*LINTED*/
0N/A return outStream_writeLong(stream, (jlong)(intptr_t)val);
0N/A } else {
0N/A /*LINTED*/
0N/A return outStream_writeInt(stream, (jint)(intptr_t)val);
0N/A }
0N/A}
0N/A
0N/AjdwpError
0N/AoutStream_writeFieldID(PacketOutputStream *stream, jfieldID val)
0N/A{
0N/A /*
0N/A * Not good - we're writing a pointer as a jint. Need
0N/A * to write as a jlong if sizeof(jfieldID) == 8.
0N/A */
0N/A if (sizeof(jfieldID) == 8) {
0N/A /*LINTED*/
0N/A return outStream_writeLong(stream, (jlong)(intptr_t)val);
0N/A } else {
0N/A /*LINTED*/
0N/A return outStream_writeInt(stream, (jint)(intptr_t)val);
0N/A }
0N/A}
0N/A
0N/AjdwpError
0N/AoutStream_writeLocation(PacketOutputStream *stream, jlocation val)
0N/A{
0N/A return outStream_writeLong(stream, (jlong)val);
0N/A}
0N/A
0N/AjdwpError
0N/AoutStream_writeByteArray(PacketOutputStream*stream, jint length,
0N/A jbyte *bytes)
0N/A{
0N/A (void)outStream_writeInt(stream, length);
0N/A return writeBytes(stream, bytes, length);
0N/A}
0N/A
0N/AjdwpError
0N/AoutStream_writeString(PacketOutputStream *stream, char *string)
0N/A{
0N/A jdwpError error;
0N/A jint length;
0N/A
0N/A /* Options utf8=y/n controls if we want Standard UTF-8 or Modified */
0N/A if ( gdata->modifiedUtf8 ) {
0N/A length = (int)strlen(string);
0N/A (void)outStream_writeInt(stream, length);
0N/A error = writeBytes(stream, (jbyte *)string, length);
0N/A } else {
0N/A jint new_length;
0N/A
0N/A length = (int)strlen(string);
0N/A new_length = (gdata->npt->utf8mToUtf8sLength)
0N/A (gdata->npt->utf, (jbyte*)string, length);
0N/A if ( new_length == length ) {
0N/A (void)outStream_writeInt(stream, length);
0N/A error = writeBytes(stream, (jbyte *)string, length);
0N/A } else {
0N/A char *new_string;
0N/A
0N/A new_string = jvmtiAllocate(new_length+1);
0N/A (gdata->npt->utf8mToUtf8s)
0N/A (gdata->npt->utf, (jbyte*)string, length,
0N/A (jbyte*)new_string, new_length);
0N/A (void)outStream_writeInt(stream, new_length);
0N/A error = writeBytes(stream, (jbyte *)new_string, new_length);
0N/A jvmtiDeallocate(new_string);
0N/A }
0N/A }
0N/A return error;
0N/A}
0N/A
0N/AjdwpError
0N/AoutStream_writeValue(JNIEnv *env, PacketOutputStream *out,
0N/A jbyte typeKey, jvalue value)
0N/A{
0N/A if (typeKey == JDWP_TAG(OBJECT)) {
0N/A (void)outStream_writeByte(out, specificTypeKey(env, value.l));
0N/A } else {
0N/A (void)outStream_writeByte(out, typeKey);
0N/A }
0N/A if (isObjectTag(typeKey)) {
0N/A (void)outStream_writeObjectRef(env, out, value.l);
0N/A } else {
0N/A switch (typeKey) {
0N/A case JDWP_TAG(BYTE):
0N/A return outStream_writeByte(out, value.b);
0N/A
0N/A case JDWP_TAG(CHAR):
0N/A return outStream_writeChar(out, value.c);
0N/A
0N/A case JDWP_TAG(FLOAT):
0N/A return outStream_writeFloat(out, value.f);
0N/A
0N/A case JDWP_TAG(DOUBLE):
0N/A return outStream_writeDouble(out, value.d);
0N/A
0N/A case JDWP_TAG(INT):
0N/A return outStream_writeInt(out, value.i);
0N/A
0N/A case JDWP_TAG(LONG):
0N/A return outStream_writeLong(out, value.j);
0N/A
0N/A case JDWP_TAG(SHORT):
0N/A return outStream_writeShort(out, value.s);
0N/A
0N/A case JDWP_TAG(BOOLEAN):
0N/A return outStream_writeBoolean(out, value.z);
0N/A
0N/A case JDWP_TAG(VOID): /* happens with function return values */
0N/A /* write nothing */
0N/A return JDWP_ERROR(NONE);
0N/A
0N/A default:
0N/A EXIT_ERROR(AGENT_ERROR_INVALID_OBJECT,"Invalid type key");
0N/A break;
0N/A }
0N/A }
0N/A return JDWP_ERROR(NONE);
0N/A}
0N/A
0N/AjdwpError
0N/AoutStream_skipBytes(PacketOutputStream *stream, jint count)
0N/A{
0N/A int i;
0N/A for (i = 0; i < count; i++) {
0N/A (void)outStream_writeByte(stream, 0);
0N/A }
0N/A return stream->error;
0N/A}
0N/A
0N/AjdwpError
0N/AoutStream_error(PacketOutputStream *stream)
0N/A{
0N/A return stream->error;
0N/A}
0N/A
0N/Avoid
0N/AoutStream_setError(PacketOutputStream *stream, jdwpError error)
0N/A{
0N/A if (stream->error == JDWP_ERROR(NONE)) {
0N/A stream->error = error;
0N/A LOG_MISC(("outStream_setError error=%s(%d)", jdwpErrorText(error), error));
0N/A }
0N/A}
0N/A
0N/Astatic jint
0N/AoutStream_send(PacketOutputStream *stream) {
0N/A
0N/A jint rc;
0N/A jint len = 0;
0N/A PacketData *segment;
0N/A jbyte *data, *posP;
0N/A
0N/A /*
0N/A * If there's only 1 segment then we just send the
0N/A * packet.
0N/A */
0N/A if (stream->firstSegment.next == NULL) {
0N/A stream->packet.type.cmd.len = 11 + stream->firstSegment.length;
0N/A stream->packet.type.cmd.data = stream->firstSegment.data;
0N/A rc = transport_sendPacket(&stream->packet);
0N/A return rc;
0N/A }
0N/A
0N/A /*
0N/A * Multiple segments
0N/A */
0N/A len = 0;
0N/A segment = (PacketData *)&(stream->firstSegment);
0N/A do {
0N/A len += segment->length;
0N/A segment = segment->next;
0N/A } while (segment != NULL);
0N/A
0N/A data = jvmtiAllocate(len);
0N/A if (data == NULL) {
0N/A return JDWP_ERROR(OUT_OF_MEMORY);
0N/A }
0N/A
0N/A posP = data;
0N/A segment = (PacketData *)&(stream->firstSegment);
0N/A while (segment != NULL) {
0N/A (void)memcpy(posP, segment->data, segment->length);
0N/A posP += segment->length;
0N/A segment = segment->next;
0N/A }
0N/A
0N/A stream->packet.type.cmd.len = 11 + len;
0N/A stream->packet.type.cmd.data = data;
0N/A rc = transport_sendPacket(&stream->packet);
0N/A stream->packet.type.cmd.data = NULL;
0N/A jvmtiDeallocate(data);
0N/A
0N/A return rc;
0N/A}
0N/A
0N/Avoid
0N/AoutStream_sendReply(PacketOutputStream *stream)
0N/A{
0N/A jint rc;
0N/A if (stream->error) {
0N/A /*
0N/A * Don't send any collected stream data on an error reply
0N/A */
0N/A stream->packet.type.reply.len = 0;
0N/A stream->packet.type.reply.errorCode = (jshort)stream->error;
0N/A }
0N/A rc = outStream_send(stream);
0N/A if (rc == 0) {
0N/A stream->sent = JNI_TRUE;
0N/A }
0N/A}
0N/A
0N/Avoid
0N/AoutStream_sendCommand(PacketOutputStream *stream)
0N/A{
0N/A jint rc;
0N/A if (!stream->error) {
0N/A rc = outStream_send(stream);
0N/A if (rc == 0) {
0N/A stream->sent = JNI_TRUE;
0N/A }
0N/A }
0N/A}
0N/A
0N/A
0N/Astatic jboolean
0N/AreleaseID(void *elementPtr, void *arg)
0N/A{
0N/A jlong *idPtr = elementPtr;
0N/A commonRef_release(getEnv(), *idPtr);
0N/A return JNI_TRUE;
0N/A}
0N/A
0N/Avoid
0N/AoutStream_destroy(PacketOutputStream *stream)
0N/A{
0N/A struct PacketData *next;
0N/A
0N/A if (stream->error || !stream->sent) {
0N/A (void)bagEnumerateOver(stream->ids, releaseID, NULL);
0N/A }
0N/A
0N/A next = stream->firstSegment.next;
0N/A while (next != NULL) {
0N/A struct PacketData *p = next;
0N/A next = p->next;
0N/A jvmtiDeallocate(p->data);
0N/A jvmtiDeallocate(p);
0N/A }
0N/A bagDestroyBag(stream->ids);
0N/A}