/******************************************************************************* * Copyright (c) 2000, 2015 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jdi.internal; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.util.Date; import java.util.Map; import org.eclipse.jdi.Bootstrap; import org.eclipse.jdi.internal.jdwp.JdwpCommandPacket; import org.eclipse.jdi.internal.jdwp.JdwpPacket; import org.eclipse.jdi.internal.jdwp.JdwpReplyPacket; import org.eclipse.jdi.internal.jdwp.JdwpString; import org.eclipse.jdt.internal.debug.core.JDIDebugOptions; import com.sun.jdi.ClassNotPreparedException; import com.sun.jdi.InternalException; import com.sun.jdi.InvalidStackFrameException; import com.sun.jdi.Mirror; import com.sun.jdi.NativeMethodException; import com.sun.jdi.ObjectCollectedException; import com.sun.jdi.VMDisconnectedException; import com.sun.jdi.VMMismatchException; import com.sun.jdi.VMOutOfMemoryException; import com.sun.jdi.VirtualMachine; /** * this class implements the corresponding interfaces declared by the JDI * specification. See the com.sun.jdi package for more information. * */ public class MirrorImpl implements Mirror { /** Description of Mirror object. */ protected String fDescription; /** Virtual Machine of Mirror object. */ private VirtualMachineImpl fVirtualMachineImpl; /** * VerboseWriter where verbose info is written to, null if no verbose must * be given. */ protected VerboseWriter fVerboseWriter = null; /** * True if a Jdwp request has been sent to the VM and the response is not * yet (fully) processed. */ private boolean fPendingJdwpRequest = false; /** * Constructor only to be used by Virtual Machine objects: stores * description of Mirror object and Virtual Machine. */ public MirrorImpl(String description) { fDescription = description; fVirtualMachineImpl = (VirtualMachineImpl) this; PrintWriter writer = ((VirtualMachineManagerImpl) org.eclipse.jdi.Bootstrap .virtualMachineManager()).verbosePrintWriter(); if (writer != null) fVerboseWriter = new VerboseWriter(writer); } /** * Constructor stores description of Mirror object and its Virtual Machine. */ public MirrorImpl(String description, VirtualMachineImpl virtualMachineImpl) { fVirtualMachineImpl = virtualMachineImpl; fDescription = description; PrintWriter writer = ((VirtualMachineManagerImpl) org.eclipse.jdi.Bootstrap .virtualMachineManager()).verbosePrintWriter(); if (writer != null) fVerboseWriter = new VerboseWriter(writer); } /** * @return Returns description of Mirror object. */ @Override public String toString() { return fDescription; } /** * @return Returns Virtual Machine of Mirror object. */ @Override public VirtualMachine virtualMachine() { return fVirtualMachineImpl; } /** * @return Returns Virtual Machine implementation of Mirror object. */ public VirtualMachineImpl virtualMachineImpl() { return fVirtualMachineImpl; } /** * Processing before each Jdwp event. */ public void initJdwpEventSet(JdwpCommandPacket commandPacket) { if (fVerboseWriter != null) { fVerboseWriter.println("Received event set"); //$NON-NLS-1$ fVerboseWriter.println("length", commandPacket.getLength()); //$NON-NLS-1$ fVerboseWriter.println("id", commandPacket.getId()); //$NON-NLS-1$ fVerboseWriter.println( "flags", commandPacket.getFlags(), JdwpPacket.getFlagMap()); //$NON-NLS-1$ fVerboseWriter.println( "command set", (byte) (commandPacket.getCommand() >>> 8)); //$NON-NLS-1$ fVerboseWriter .println("command", (byte) commandPacket.getCommand()); //$NON-NLS-1$ } } /** * Processing after each Jdwp Event. */ public void handledJdwpEventSet() { if (fVerboseWriter != null) { fVerboseWriter.println(); fVerboseWriter.flush(); } } /** * Processing before each Jdwp request. Note that this includes building the * request message and parsing the response. */ public void initJdwpRequest() { if (fVerboseWriter != null) { fVerboseWriter.gotoPosition(6); } } /** * Writes command packet header if verbose is on. */ public void writeVerboseCommandPacketHeader(JdwpCommandPacket commandPacket) { if (fVerboseWriter != null) { int command = commandPacket.getCommand(); int currentPosition = fVerboseWriter.position(); fVerboseWriter.gotoPosition(0); fVerboseWriter.print("Sending command ("); //$NON-NLS-1$ fVerboseWriter.printValue(command, JdwpCommandPacket.commandMap()); fVerboseWriter.println(")"); //$NON-NLS-1$ fVerboseWriter.println("length", commandPacket.getLength()); //$NON-NLS-1$ fVerboseWriter.println("id", commandPacket.getId()); //$NON-NLS-1$ fVerboseWriter.println( "flags", commandPacket.getFlags(), JdwpPacket.getFlagMap()); //$NON-NLS-1$ fVerboseWriter.println("command set", (byte) (command >>> 8)); //$NON-NLS-1$ fVerboseWriter.println("command", (byte) command); //$NON-NLS-1$ fVerboseWriter.gotoPosition(currentPosition); } } /** * Processing after each Jdwp Request. */ public void handledJdwpRequest() { if (fVerboseWriter != null && fPendingJdwpRequest) { fVerboseWriter.println(); fVerboseWriter.flush(); } fPendingJdwpRequest = false; } /** * Performs a VM request. * * @return Returns reply data. */ public JdwpReplyPacket requestVM(int command, byte[] outData) { JdwpCommandPacket commandPacket = new JdwpCommandPacket(command); commandPacket.setData(outData); long sent = System.currentTimeMillis(); fVirtualMachineImpl.packetSendManager().sendPacket(commandPacket); fPendingJdwpRequest = true; writeVerboseCommandPacketHeader(commandPacket); JdwpReplyPacket reply = fVirtualMachineImpl.packetReceiveManager() .getReply(commandPacket); long recieved = System.currentTimeMillis(); if (JDIDebugOptions.DEBUG_JDI_REQUEST_TIMES) { StringBuffer buf = new StringBuffer(); buf.append(JDIDebugOptions.FORMAT.format(new Date(sent))); buf.append(" JDI Request: "); //$NON-NLS-1$ buf.append(commandPacket.toString()); buf.append("\n\tResponse Time: "); //$NON-NLS-1$ buf.append(recieved - sent); buf.append("ms"); //$NON-NLS-1$ buf.append(" length: "); //$NON-NLS-1$ buf.append(reply.getLength()); JDIDebugOptions.trace(buf.toString()); } if (fVerboseWriter != null) { fVerboseWriter.println(); fVerboseWriter.println("Received reply"); //$NON-NLS-1$ fVerboseWriter.println("length", reply.getLength()); //$NON-NLS-1$ fVerboseWriter.println("id", reply.getId()); //$NON-NLS-1$ fVerboseWriter.println( "flags", reply.getFlags(), JdwpPacket.getFlagMap()); //$NON-NLS-1$ fVerboseWriter .println( "error code", reply.errorCode(), JdwpReplyPacket.errorMap()); //$NON-NLS-1$ } return reply; } /** * Performs a VM request. * * @return Returns reply data. */ public JdwpReplyPacket requestVM(int command, ByteArrayOutputStream outData) { return requestVM(command, outData.toByteArray()); } /** * Performs a VM request for a specified object. * * @return Returns reply data. */ public JdwpReplyPacket requestVM(int command, ObjectReferenceImpl object) { ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream(); DataOutputStream dataOutStream = new DataOutputStream(byteOutStream); try { object.write(this, dataOutStream); } catch (IOException e) { defaultIOExceptionHandler(e); } return requestVM(command, byteOutStream); } /** * Performs a VM request for a specified object. * * @return Returns reply data. */ public JdwpReplyPacket requestVM(int command, ReferenceTypeImpl refType) { ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream(); DataOutputStream dataOutStream = new DataOutputStream(byteOutStream); try { refType.write(this, dataOutStream); } catch (IOException e) { defaultIOExceptionHandler(e); } return requestVM(command, byteOutStream); } /** * Performs a VM request. * * @return Returns reply data. */ public JdwpReplyPacket requestVM(int command) { return requestVM(command, (byte[]) null); } /** * Performs default error handling. */ public void defaultReplyErrorHandler(int error) { switch (error) { case JdwpReplyPacket.NONE: break; case JdwpReplyPacket.INVALID_OBJECT: throw new ObjectCollectedException(); case JdwpReplyPacket.INVALID_CLASS: throw new ClassNotPreparedException(); case JdwpReplyPacket.CLASS_NOT_PREPARED: throw new ClassNotPreparedException(); case JdwpReplyPacket.OUT_OF_MEMORY: throw new VMOutOfMemoryException(); case JdwpReplyPacket.ILLEGAL_ARGUMENT: throw new IllegalArgumentException(); case JdwpReplyPacket.NATIVE_METHOD: throw new NativeMethodException(); case JdwpReplyPacket.INVALID_FRAMEID: throw new InvalidStackFrameException(); case JdwpReplyPacket.NOT_IMPLEMENTED: throw new UnsupportedOperationException(); case JdwpReplyPacket.HCR_OPERATION_REFUSED: throw new org.eclipse.jdi.hcr.OperationRefusedException(); case JdwpReplyPacket.VM_DEAD: throw new VMDisconnectedException(); default: throw new InternalException( JDIMessages.MirrorImpl_Got_error_code_in_reply___1 + error, error); } } /** * Performs default handling of IOException in creating or interpreting a * Jdwp packet. */ public void defaultIOExceptionHandler(Exception e) { throw new InternalException(JDIMessages.MirrorImpl_Got_invalid_data___2 + e); } /** * Waits for a specified command packet from the VM. * * @return Returns Command Packet from VM. */ public final JdwpCommandPacket getCommandVM(int command, long timeout) throws InterruptedException { return fVirtualMachineImpl.packetReceiveManager().getCommand(command, timeout); } /** * @exception VMMismatchException * is thrown if the Mirror argument and this mirror do not * belong to the same VirtualMachine. */ public void checkVM(Mirror mirror) throws VMMismatchException { if (((MirrorImpl) mirror).virtualMachineImpl() != this .virtualMachineImpl()) throw new VMMismatchException(); } /** * Disconnects VM. */ public void disconnectVM() { fVirtualMachineImpl.setDisconnected(true); fVirtualMachineImpl.packetSendManager().disconnectVM(); fVirtualMachineImpl.packetReceiveManager().disconnectVM(); ((VirtualMachineManagerImpl) Bootstrap.virtualMachineManager()) .removeConnectedVM(fVirtualMachineImpl); } /** * Reads Jdwp data and, if verbose is on, outputs verbose info. * * @return Returns value that has been read. */ public byte readByte(String description, DataInputStream in) throws IOException { byte result = in.readByte(); if (fVerboseWriter != null) { fVerboseWriter.println(description, result); } return result; } /** * Reads Jdwp data and, if verbose is on, outputs verbose info. * * @return Returns value that has been read. */ public short readShort(String description, DataInputStream in) throws IOException { short result = in.readShort(); if (fVerboseWriter != null) { fVerboseWriter.println(description, result); } return result; } /** * Reads Jdwp data and, if verbose is on, outputs verbose info. * * @return Returns value that has been read. */ public int readInt(String description, DataInputStream in) throws IOException { int result = in.readInt(); if (fVerboseWriter != null) { fVerboseWriter.println(description, result); } return result; } /** * Reads Jdwp data and, if verbose is on, outputs verbose info. * * @return Returns value that has been read. */ public long readLong(String description, DataInputStream in) throws IOException { long result = in.readLong(); if (fVerboseWriter != null) { fVerboseWriter.println(description, result); } return result; } /** * Reads Jdwp data and, if verbose is on, outputs verbose info. * * @return Returns value that has been read. */ public byte readByte(String description, Map<Integer, String> valueToString, DataInputStream in) throws IOException { byte result = in.readByte(); if (fVerboseWriter != null) { fVerboseWriter.println(description, result, valueToString); } return result; } /** * Reads Jdwp data and, if verbose is on, outputs verbose info. * * @return Returns value that has been read. */ public short readShort(String description, Map<Integer, String> valueToString, DataInputStream in) throws IOException { short result = in.readShort(); if (fVerboseWriter != null) { fVerboseWriter.println(description, result, valueToString); } return result; } /** * Reads Jdwp data and, if verbose is on, outputs verbose info. * * @return Returns value that has been read. */ public int readInt(String description, Map<Integer, String> valueToString, DataInputStream in) throws IOException { int result = in.readInt(); if (fVerboseWriter != null) { fVerboseWriter.println(description, result, valueToString); } return result; } /** * Reads Jdwp data and, if verbose is on, outputs verbose info. * * @return Returns value that has been read. */ public String readString(String description, DataInputStream in) throws IOException { String result = JdwpString.read(in); if (fVerboseWriter != null) { fVerboseWriter.println(description, result); } return result; } /** * Reads Jdwp data and, if verbose is on, outputs verbose info. * * @return Returns value that has been read. */ public boolean readBoolean(String description, DataInputStream in) throws IOException { boolean result = in.readBoolean(); if (fVerboseWriter != null) { fVerboseWriter.println(description, result); } return result; } /** * Reads Jdwp data and, if verbose is on, outputs verbose info. * * @return Returns value that has been read. */ public char readChar(String description, DataInputStream in) throws IOException { char result = in.readChar(); if (fVerboseWriter != null) { fVerboseWriter.println(description, result); } return result; } /** * Reads Jdwp data and, if verbose is on, outputs verbose info. * * @return Returns value that has been read. */ public double readDouble(String description, DataInputStream in) throws IOException { double result = in.readDouble(); if (fVerboseWriter != null) { fVerboseWriter.println(description, result); } return result; } /** * Reads Jdwp data and, if verbose is on, outputs verbose info. * * @return Returns value that has been read. */ public float readFloat(String description, DataInputStream in) throws IOException { float result = in.readFloat(); if (fVerboseWriter != null) { fVerboseWriter.println(description, result); } return result; } /** * Reads Jdwp data and, if verbose is on, outputs verbose info. * * @return Returns value that has been read. */ public byte[] readByteArray(int length, String description, DataInputStream in) throws IOException { byte[] result = new byte[length]; in.readFully(result); if (fVerboseWriter != null) { fVerboseWriter.println(description, result); } return result; } /** * Writes Jdwp data and, if verbose is on, outputs verbose info. */ public void writeByte(byte value, String description, DataOutputStream out) throws IOException { out.writeByte(value); if (fVerboseWriter != null) { fVerboseWriter.println(description, value); } } /** * Writes Jdwp data and, if verbose is on, outputs verbose info. */ public void writeShort(short value, String description, DataOutputStream out) throws IOException { out.writeShort(value); if (fVerboseWriter != null) { fVerboseWriter.println(description, value); } } /** * Writes Jdwp data and, if verbose is on, outputs verbose info. */ public void writeInt(int value, String description, DataOutputStream out) throws IOException { out.writeInt(value); if (fVerboseWriter != null) { fVerboseWriter.println(description, value); } } /** * Writes Jdwp data and, if verbose is on, outputs verbose info. */ public void writeLong(long value, String description, DataOutputStream out) throws IOException { out.writeLong(value); if (fVerboseWriter != null) { fVerboseWriter.println(description, value); } } /** * Writes Jdwp data and, if verbose is on, outputs verbose info. */ public void writeByte(byte value, String description, Map<Integer, String> valueToString, DataOutputStream out) throws IOException { out.writeByte(value); if (fVerboseWriter != null) { fVerboseWriter.println(description, value, valueToString); } } /** * Writes Jdwp data and, if verbose is on, outputs verbose info. */ public void writeShort(short value, String description, Map<Integer, String> valueToString, DataOutputStream out) throws IOException { out.writeShort(value); if (fVerboseWriter != null) { fVerboseWriter.println(description, value, valueToString); } } /** * Writes Jdwp data and, if verbose is on, outputs verbose info. */ public void writeInt(int value, String description, Map<Integer, String> valueToString, DataOutputStream out) throws IOException { out.writeInt(value); if (fVerboseWriter != null) { fVerboseWriter.println(description, value, valueToString); } } /** * Writes Jdwp data and, if verbose is on, outputs verbose info. */ public void writeString(String value, String description, DataOutputStream out) throws IOException { JdwpString.write(value, out); if (fVerboseWriter != null) { fVerboseWriter.println(description, value); } } /** * Writes Jdwp data and, if verbose is on, outputs verbose info. */ public void writeBoolean(boolean value, String description, DataOutputStream out) throws IOException { out.writeBoolean(value); if (fVerboseWriter != null) { fVerboseWriter.println(description, value); } } /** * Writes Jdwp data and, if verbose is on, outputs verbose info. */ public void writeChar(char value, String description, DataOutputStream out) throws IOException { out.writeChar(value); if (fVerboseWriter != null) { fVerboseWriter.println(description, value); } } /** * Writes Jdwp data and, if verbose is on, outputs verbose info. */ public void writeDouble(double value, String description, DataOutputStream out) throws IOException { out.writeDouble(value); if (fVerboseWriter != null) { fVerboseWriter.println(description, value); } } /** * Writes Jdwp data and, if verbose is on, outputs verbose info. */ public void writeFloat(float value, String description, DataOutputStream out) throws IOException { out.writeFloat(value); if (fVerboseWriter != null) { fVerboseWriter.println(description, value); } } /** * Writes Jdwp data and, if verbose is on, outputs verbose info. */ public void writeShort(short value, String description, String[] bitNames, DataOutputStream out) throws IOException { out.writeShort(value); if (fVerboseWriter != null) { fVerboseWriter.println(description, value, bitNames); } } /** * Writes Jdwp data and, if verbose is on, outputs verbose info. */ public void writeInt(int value, String description, String[] bitNames, DataOutputStream out) throws IOException { out.writeInt(value); if (fVerboseWriter != null) { fVerboseWriter.println(description, value, bitNames); } } /** * Reads Jdwp data and, if verbose is on, outputs verbose info. * * @return Returns value that has been read. */ public byte readByte(String description, String[] bitNames, DataInputStream in) throws IOException { byte result = in.readByte(); if (fVerboseWriter != null) { fVerboseWriter.println(description, result, bitNames); } return result; } /** * Reads Jdwp data and, if verbose is on, outputs verbose info. * * @return Returns value that has been read. */ public short readShort(String description, String[] bitNames, DataInputStream in) throws IOException { short result = in.readShort(); if (fVerboseWriter != null) { fVerboseWriter.println(description, result, bitNames); } return result; } /** * Reads Jdwp data and, if verbose is on, outputs verbose info. * * @return Returns value that has been read. */ public int readInt(String description, String[] bitNames, DataInputStream in) throws IOException { int result = in.readInt(); if (fVerboseWriter != null) { fVerboseWriter.println(description, result, bitNames); } return result; } /** * Writes Jdwp data and, if verbose is on, outputs verbose info. */ public void writeByte(byte value, String description, String[] bitNames, DataOutputStream out) throws IOException { out.writeByte(value); if (fVerboseWriter != null) { fVerboseWriter.println(description, value, bitNames); } } /** * @return Returns VerboseWriter where verbose info is written to, null if * no verbose must be given. */ public VerboseWriter verboseWriter() { return fVerboseWriter; } }