0N/A/*
2362N/A * Copyright (c) 1999, 2003, 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#include <string.h>
0N/A#include <stdlib.h>
0N/A#include <stddef.h>
0N/A#include <jni.h>
0N/A#include "SharedMemory.h"
0N/A#include "com_sun_tools_jdi_SharedMemoryConnection.h"
0N/A#include "jdwpTransport.h"
0N/A#include "shmemBase.h"
0N/A#include "sys.h"
0N/A
0N/A/*
0N/A * JNI interface to the shared memory transport. These JNI methods
0N/A * call the base shared memory support to do the real work.
0N/A *
0N/A * That is, this is the front-ends interface to our shared memory
0N/A * communication code.
0N/A */
0N/A
0N/A/*
0N/A * Cached architecture
0N/A */
0N/Astatic int byte_ordering_known;
0N/Astatic int is_big_endian;
0N/A
0N/A
0N/A/*
0N/A * Returns 1 if big endian architecture
0N/A */
0N/Astatic int isBigEndian() {
0N/A if (!byte_ordering_known) {
0N/A unsigned int i = 0xff000000;
0N/A if (((char *)(&i))[0] != 0) {
0N/A is_big_endian = 1;
0N/A } else {
0N/A is_big_endian = 0;
0N/A }
0N/A byte_ordering_known = 1;
0N/A }
0N/A return is_big_endian;
0N/A}
0N/A
0N/A/*
0N/A * Convert to big endian
0N/A */
0N/Astatic jint intToBigInt(jint i) {
0N/A unsigned int b[4];
0N/A if (isBigEndian()) {
0N/A return i;
0N/A }
0N/A b[0] = (i >> 24) & 0xff;
0N/A b[1] = (i >> 16) & 0xff;
0N/A b[2] = (i >> 8) & 0xff;
0N/A b[3] = i & 0xff;
0N/A
0N/A /*
0N/A * It doesn't matter that jint is signed as we are or'ing
0N/A * and hence end up with the correct bits.
0N/A */
0N/A return (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0];
0N/A}
0N/A
0N/A/*
0N/A * Convert unsigned short to big endian
0N/A */
0N/Astatic unsigned short shortToBigShort(unsigned short s) {
0N/A unsigned int b[2];
0N/A if (isBigEndian()) {
0N/A return s;
0N/A }
0N/A b[0] = (s >> 8) & 0xff;
0N/A b[1] = s & 0xff;
0N/A return (b[1] << 8) + b[0];
0N/A}
0N/A
0N/A/*
0N/A * Create a byte[] from a packet struct. All data in the byte array
0N/A * is JDWP packet suitable for wire transmission. That is, all fields,
0N/A * and data are in big-endian format as required by the JDWP
0N/A * specification.
0N/A */
0N/Astatic jbyteArray
0N/ApacketToByteArray(JNIEnv *env, jdwpPacket *str)
0N/A{
0N/A jbyteArray array;
0N/A jsize data_length;
0N/A jint total_length;
0N/A jint tmpInt;
0N/A
0N/A total_length = str->type.cmd.len;
0N/A data_length = total_length - 11;
0N/A
0N/A /* total packet length is header + data */
0N/A array = (*env)->NewByteArray(env, total_length);
0N/A if ((*env)->ExceptionOccurred(env)) {
0N/A return NULL;
0N/A }
0N/A
0N/A /* First 4 bytes of packet are the length (in big endian format) */
0N/A tmpInt = intToBigInt((unsigned int)total_length);
0N/A (*env)->SetByteArrayRegion(env, array, 0, 4, (const jbyte *)&tmpInt);
0N/A
0N/A /* Next 4 bytes are the id field */
0N/A tmpInt = intToBigInt(str->type.cmd.id);
0N/A (*env)->SetByteArrayRegion(env, array, 4, 4, (const jbyte *)&tmpInt);
0N/A
0N/A /* next byte is the flags */
0N/A (*env)->SetByteArrayRegion(env, array, 8, 1, (const jbyte *)&(str->type.cmd.flags));
0N/A
0N/A /* next two bytes are either the error code or the command set/command */
0N/A if (str->type.cmd.flags & JDWPTRANSPORT_FLAGS_REPLY) {
0N/A short s = shortToBigShort(str->type.reply.errorCode);
0N/A (*env)->SetByteArrayRegion(env, array, 9, 2, (const jbyte *)&(s));
0N/A } else {
0N/A (*env)->SetByteArrayRegion(env, array, 9, 1, (const jbyte *)&(str->type.cmd.cmdSet));
0N/A (*env)->SetByteArrayRegion(env, array, 10, 1, (const jbyte *)&(str->type.cmd.cmd));
0N/A }
0N/A
0N/A /* finally the data */
0N/A
0N/A if (data_length > 0) {
0N/A (*env)->SetByteArrayRegion(env, array, 11,
0N/A data_length, str->type.cmd.data);
0N/A if ((*env)->ExceptionOccurred(env)) {
0N/A return NULL;
0N/A }
0N/A }
0N/A
0N/A return array;
0N/A}
0N/A
0N/A/*
0N/A * Fill a packet struct from a byte array. The byte array is a
0N/A * JDWP packet suitable for wire transmission. That is, all fields,
0N/A * and data are in big-endian format as required by the JDWP
0N/A * specification. We thus need to convert the fields from big
0N/A * endian to the platform endian.
0N/A *
0N/A * The jbyteArray provided to this function is assumed to
0N/A * of a length than is equal or greater than the length of
0N/A * the JDWP packet that is contains.
0N/A */
0N/Astatic void
0N/AbyteArrayToPacket(JNIEnv *env, jbyteArray b, jdwpPacket *str)
0N/A{
0N/A jsize total_length, data_length;
0N/A jbyte *data;
0N/A unsigned char pktHeader[11]; /* sizeof length + id + flags + cmdSet + cmd */
0N/A
0N/A /*
0N/A * Get the packet header
0N/A */
0N/A (*env)->GetByteArrayRegion(env, b, 0, sizeof(pktHeader), pktHeader);
0N/A
0N/A total_length = (int)pktHeader[3] | ((int)pktHeader[2] << 8) |
0N/A ((int)pktHeader[1] << 16) | ((int)pktHeader[0] << 24);
0N/A /*
0N/A * The id field is in big endian (also errorCode field in the case
0N/A * of reply packets).
0N/A */
0N/A str->type.cmd.id = (int)pktHeader[7] | ((int)pktHeader[6] << 8) |
0N/A ((int)pktHeader[5] << 16) | ((int)pktHeader[4] << 24);
0N/A
0N/A str->type.cmd.flags = (jbyte)pktHeader[8];
0N/A
0N/A if (str->type.cmd.flags & JDWPTRANSPORT_FLAGS_REPLY) {
0N/A str->type.reply.errorCode = (int)pktHeader[9] + ((int)pktHeader[10] << 8);
0N/A } else {
0N/A /* command packet */
0N/A str->type.cmd.cmdSet = (jbyte)pktHeader[9];
0N/A str->type.cmd.cmd = (jbyte)pktHeader[10];
0N/A }
0N/A
0N/A /*
0N/A * The length of the JDWP packet is 11 + data
0N/A */
0N/A data_length = total_length - 11;
0N/A
0N/A if (data_length == 0) {
0N/A data = NULL;
0N/A } else {
0N/A data = malloc(data_length);
0N/A if (data == NULL) {
0N/A throwException(env, "java/lang/OutOfMemoryError",
0N/A "Unable to allocate command data buffer");
0N/A return;
0N/A }
0N/A
0N/A (*env)->GetByteArrayRegion(env, b, 11, /*sizeof(CmdPacket)+4*/ data_length, data);
0N/A if ((*env)->ExceptionOccurred(env)) {
0N/A free(data);
0N/A return;
0N/A }
0N/A }
0N/A
0N/A str->type.cmd.len = total_length;
0N/A str->type.cmd.data = data;
0N/A}
0N/A
0N/Astatic void
0N/AfreePacketData(jdwpPacket *packet)
0N/A{
0N/A if (packet->type.cmd.len > 0) {
0N/A free(packet->type.cmd.data);
0N/A }
0N/A}
0N/A
0N/A/*
0N/A * Class: com_sun_tools_jdi_SharedMemoryConnection
0N/A * Method: close0
0N/A * Signature: (J)V
0N/A */
0N/AJNIEXPORT void JNICALL Java_com_sun_tools_jdi_SharedMemoryConnection_close0
0N/A (JNIEnv *env, jobject thisObject, jlong id)
0N/A{
0N/A SharedMemoryConnection *connection = ID_TO_CONNECTION(id);
0N/A shmemBase_closeConnection(connection);
0N/A}
0N/A
0N/A/*
0N/A * Class: com_sun_tools_jdi_SharedMemoryConnection
0N/A * Method: receiveByte0
0N/A * Signature: (J)B
0N/A */
0N/AJNIEXPORT jbyte JNICALL Java_com_sun_tools_jdi_SharedMemoryConnection_receiveByte0
0N/A (JNIEnv *env, jobject thisObject, jlong id)
0N/A{
0N/A SharedMemoryConnection *connection = ID_TO_CONNECTION(id);
0N/A jbyte b = 0;
0N/A jint rc;
0N/A
0N/A rc = shmemBase_receiveByte(connection, &b);
0N/A if (rc != SYS_OK) {
0N/A throwShmemException(env, "shmemBase_receiveByte failed", rc);
0N/A }
0N/A
0N/A return b;
0N/A}
0N/A
0N/A/*
0N/A * Class: com_sun_tools_jdi_SharedMemoryConnection
0N/A * Method: receivePacket0
0N/A * Signature: (JLcom/sun/tools/jdi/Packet;)V
0N/A */
0N/AJNIEXPORT jbyteArray JNICALL Java_com_sun_tools_jdi_SharedMemoryConnection_receivePacket0
0N/A (JNIEnv *env, jobject thisObject, jlong id)
0N/A{
0N/A SharedMemoryConnection *connection = ID_TO_CONNECTION(id);
0N/A jdwpPacket packet;
0N/A jint rc;
0N/A
0N/A rc = shmemBase_receivePacket(connection, &packet);
0N/A if (rc != SYS_OK) {
0N/A throwShmemException(env, "shmemBase_receivePacket failed", rc);
0N/A return NULL;
0N/A } else {
0N/A jbyteArray array = packetToByteArray(env, &packet);
0N/A
0N/A /* Free the packet even if there was an exception above */
0N/A freePacketData(&packet);
0N/A return array;
0N/A }
0N/A}
0N/A
0N/A/*
0N/A * Class: com_sun_tools_jdi_SharedMemoryConnection
0N/A * Method: sendByte0
0N/A * Signature: (JB)V
0N/A */
0N/AJNIEXPORT void JNICALL Java_com_sun_tools_jdi_SharedMemoryConnection_sendByte0
0N/A (JNIEnv *env, jobject thisObject, jlong id, jbyte b)
0N/A{
0N/A SharedMemoryConnection *connection = ID_TO_CONNECTION(id);
0N/A jint rc;
0N/A
0N/A rc = shmemBase_sendByte(connection, b);
0N/A if (rc != SYS_OK) {
0N/A throwShmemException(env, "shmemBase_sendByte failed", rc);
0N/A }
0N/A}
0N/A
0N/A/*
0N/A * Class: com_sun_tools_jdi_SharedMemoryConnection
0N/A * Method: sendPacket0
0N/A * Signature: (JLcom/sun/tools/jdi/Packet;)V
0N/A */
0N/AJNIEXPORT void JNICALL Java_com_sun_tools_jdi_SharedMemoryConnection_sendPacket0
0N/A (JNIEnv *env, jobject thisObject, jlong id, jbyteArray b)
0N/A{
0N/A SharedMemoryConnection *connection = ID_TO_CONNECTION(id);
0N/A jdwpPacket packet;
0N/A jint rc;
0N/A
0N/A byteArrayToPacket(env, b, &packet);
0N/A if ((*env)->ExceptionOccurred(env)) {
0N/A return;
0N/A }
0N/A
0N/A rc = shmemBase_sendPacket(connection, &packet);
0N/A if (rc != SYS_OK) {
0N/A throwShmemException(env, "shmemBase_sendPacket failed", rc);
0N/A }
0N/A freePacketData(&packet);
0N/A}