/* * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.max.tele.channel.iostream; import java.io.*; import com.sun.max.program.*; import com.sun.max.tele.channel.*; import com.sun.max.tele.channel.agent.*; import com.sun.max.tele.util.*; /** * An implementation of {@link TeleChannelDataIOProtocol} that communicates using {@link DataInputStream} and {@link DataOutputStream} and is * essentially a custom remote method invocation system. * * Byte arrays are supported and, obviously, require special treatment. Arrays are tagged as {@link ArrayMode#IN in}, {@link ArrayMode#OUT out} * or {@link ArrayMode#INOUT inout}. That is, when an array is passed as parameter, the ordinal value of the {@link ArrayMode} is written first, * followed by the length of the array, followed by the bytes of the array, except in the case of {@link ArrayMode#OUT}, where no bytes are sent. * The contents of the array are "returned" as an auxiliary result if the mode is {@link ArrayMode#OUT} or {@link ArrayMode#INOUT}; the bytes * precede the method result value. * * For this to work, the {@link ArrayMode} of a parameter must be registered with {@link RemoteInvocationProtocolAdaptor} by the target end of the communication.. */ public class TeleChannelDataIOProtocolImpl implements TeleChannelDataIOProtocol { public enum ArrayMode { IN, OUT, INOUT } protected DataInputStream in; protected DataOutputStream out; protected TeleChannelDataIOProtocolImpl() { } protected void setStreams(InputStream in, OutputStream out) { this.in = new DataInputStream(in); this.out = new DataOutputStream(out); } @Override public boolean initialize(int tlaSize, boolean bigEndian) { try { out.writeUTF("initialize"); out.writeInt(tlaSize); out.writeBoolean(bigEndian); out.flush(); return in.readBoolean(); } catch (Exception ex) { Trace.line(1, ex); return false; } } @Override public long create(String pathName, String[] commandLineArguments) { try { out.writeUTF("create"); out.writeUTF(pathName); outStringArray(ArrayMode.IN, commandLineArguments); out.flush(); return in.readLong(); } catch (Exception ex) { Trace.line(1, ex); return -1; } } @Override public boolean kill() { try { out.writeUTF("kill"); out.flush(); return in.readBoolean(); } catch (IOException ex) { TeleError.unexpected(ex); return false; } } @Override public boolean activateWatchpoint(long start, long size, boolean after, boolean read, boolean write, boolean exec) { unimplemented("activateWatchpoint"); return false; } @Override public boolean attach(int id) { try { out.writeUTF("attach"); out.writeInt(id); out.flush(); boolean result = in.readBoolean(); return result; } catch (Exception ex) { Trace.line(1, ex); return false; } } @Override public boolean detach() { try { out.writeUTF("detach"); out.flush(); return in.readBoolean(); } catch (Exception ex) { Trace.line(1, ex); return false; } } @Override public int waitUntilStoppedAsInt() { try { out.writeUTF("waitUntilStoppedAsInt"); out.flush(); return in.readInt(); } catch (IOException ex) { TeleError.unexpected(ex); return 0; } } @Override public long getBootHeapStart() { try { out.writeUTF("getBootHeapStart"); out.flush(); return in.readLong(); } catch (IOException ex) { TeleError.unexpected(ex); return 0; } } @Override public int maxByteBufferSize() { try { out.writeUTF("maxByteBufferSize"); out.flush(); return in.readInt(); } catch (IOException ex) { TeleError.unexpected(ex); return 0; } } @Override public int readBytes(long src, byte[] dst, int dstOffset, int length) { try { out.writeUTF("readBytes"); out.writeLong(src); outByteArray(ArrayMode.OUT, dst); out.writeInt(dstOffset); out.writeInt(length); out.flush(); inByteArray(dst, dstOffset, length); final int result = in.readInt(); return result; } catch (IOException ex) { TeleError.unexpected(ex); return 0; } } @Override public boolean readRegisters(long threadId, byte[] integerRegisters, int integerRegistersSize, byte[] floatingPointRegisters, int floatingPointRegistersSize, byte[] stateRegisters, int stateRegistersSize) { try { out.writeUTF("readRegisters"); out.writeLong(threadId); outByteArray(ArrayMode.OUT, integerRegisters); out.writeInt(integerRegistersSize); outByteArray(ArrayMode.OUT, floatingPointRegisters); out.writeInt(floatingPointRegistersSize); outByteArray(ArrayMode.OUT, stateRegisters); out.writeInt(stateRegistersSize); out.flush(); inByteArray(integerRegisters, 0, integerRegistersSize); inByteArray(floatingPointRegisters, 0, floatingPointRegistersSize); inByteArray(stateRegisters, 0, stateRegistersSize); return in.readBoolean(); } catch (IOException ex) { TeleError.unexpected(ex); return false; } } @Override public int readWatchpointAccessCode() { try { out.writeUTF("readWatchpointAccessCode"); out.flush(); return in.readInt(); } catch (IOException ex) { TeleError.unexpected(ex); return 0; } } @Override public long readWatchpointAddress() { try { out.writeUTF("readWatchpointAddress"); out.flush(); return in.readLong(); } catch (IOException ex) { TeleError.unexpected(ex); return 0; } } @Override public boolean deactivateWatchpoint(long start, long size) { try { out.writeUTF("deactivateWatchpoint"); out.writeLong(start); out.writeLong(size); out.flush(); return in.readBoolean(); } catch (IOException ex) { TeleError.unexpected(ex); return false; } } @Override public boolean resume(long threadId) { try { out.writeUTF("resume"); out.writeLong(threadId); out.flush(); return in.readBoolean(); } catch (IOException ex) { TeleError.unexpected(ex); return false; } } @Override public boolean setInstructionPointer(long threadId, long ip) { try { out.writeUTF("setInstructionPointer"); out.writeLong(threadId); out.writeLong(ip); out.flush(); return in.readBoolean(); } catch (IOException ex) { TeleError.unexpected(ex); return false; } } @Override public int setTransportDebugLevel(int level) { try { out.writeUTF("setTransportDebugLevel"); out.flush(); return in.readInt(); } catch (IOException ex) { TeleError.unexpected(ex); return 0; } } @Override public boolean singleStep(long threadId) { try { out.writeUTF("singleStep"); out.writeLong(threadId); out.flush(); return in.readBoolean(); } catch (IOException ex) { TeleError.unexpected(ex); return false; } } @Override public boolean suspend(long threadId) { try { out.writeUTF("suspend"); out.writeLong(threadId); out.flush(); return in.readBoolean(); } catch (IOException ex) { TeleError.unexpected(ex); return false; } } @Override public boolean suspendAll() { try { out.writeUTF("suspendAll"); out.flush(); return in.readBoolean(); } catch (IOException ex) { TeleError.unexpected(ex); return false; } } @Override public boolean resumeAll() { try { out.writeUTF("resumeAll"); out.flush(); return in.readBoolean(); } catch (IOException ex) { TeleError.unexpected(ex); return false; } } @Override public int writeBytes(long dst, byte[] src, int srcOffset, int length) { try { out.writeUTF("writeBytes"); out.writeLong(dst); outByteArray(ArrayMode.IN, src); out.writeInt(srcOffset); out.writeInt(length); out.flush(); return in.readInt(); } catch (IOException ex) { TeleError.unexpected(ex); return 0; } } @Override public int gatherThreads(long tlaList) { try { out.writeUTF("gatherThreads"); out.writeLong(tlaList); out.flush(); return in.readInt(); } catch (IOException ex) { TeleError.unexpected(ex); return 0; } } @Override public int readThreads(int size, byte[] gatherThreadData) { try { out.writeUTF("readThreads"); out.writeInt(size); outByteArray(ArrayMode.OUT, gatherThreadData); out.flush(); inByteArray(gatherThreadData, 0, size); return in.readInt(); } catch (IOException ex) { TeleError.unexpected(ex); return 0; } } private void outByteArray(ArrayMode mode, byte[] array) throws IOException { out.writeInt(mode.ordinal()); // write b.length first so callee can allocate out.writeInt(array.length); if (mode != ArrayMode.OUT) { out.write(array); } } private void inByteArray(byte[] dst, int dstOffset, int length) throws IOException { byte[] result = new byte[dst.length]; in.readFully(result); System.arraycopy(result, dstOffset, dst, dstOffset, length); } private void outStringArray(ArrayMode mode, String[] array) throws IOException { out.writeInt(mode.ordinal()); // write b.length first so callee can allocate out.writeInt(array.length); if (mode != ArrayMode.OUT) { for (String s : array) { out.writeUTF(s); } } } private void unimplemented(String name) { TeleError.unimplemented(getClass().getName() + "." + name); } }