/******************************************************************************* * 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.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.jdi.Bootstrap; import org.eclipse.jdi.internal.connect.PacketReceiveManager; import org.eclipse.jdi.internal.connect.PacketSendManager; import org.eclipse.jdi.internal.event.EventQueueImpl; import org.eclipse.jdi.internal.jdwp.JdwpCommandPacket; import org.eclipse.jdi.internal.jdwp.JdwpObjectID; import org.eclipse.jdi.internal.jdwp.JdwpReferenceTypeID; import org.eclipse.jdi.internal.jdwp.JdwpReplyPacket; import org.eclipse.jdi.internal.request.EventRequestManagerImpl; import org.eclipse.osgi.util.NLS; import com.sun.jdi.BooleanValue; import com.sun.jdi.ByteValue; import com.sun.jdi.CharValue; import com.sun.jdi.DoubleValue; import com.sun.jdi.FloatValue; import com.sun.jdi.IntegerValue; import com.sun.jdi.LongValue; import com.sun.jdi.ObjectCollectedException; import com.sun.jdi.ReferenceType; import com.sun.jdi.ShortValue; import com.sun.jdi.StringReference; import com.sun.jdi.ThreadGroupReference; import com.sun.jdi.ThreadReference; import com.sun.jdi.VMDisconnectedException; import com.sun.jdi.VirtualMachine; import com.sun.jdi.VoidValue; import com.sun.jdi.connect.spi.Connection; import com.sun.jdi.event.EventQueue; import com.sun.jdi.request.EventRequestManager; /** * This class implements the corresponding interfaces declared by the JDI * specification. See the com.sun.jdi package for more information. * */ public class VirtualMachineImpl extends MirrorImpl implements VirtualMachine, org.eclipse.jdi.hcr.VirtualMachine, org.eclipse.jdi.VirtualMachine { /** Result flags for Classes Have Changed command. */ public static final byte HCR_RELOAD_SUCCESS = 0; public static final byte HCR_RELOAD_FAILURE = 1; public static final byte HCR_RELOAD_IGNORED = 2; /* Indexes in HCR capabilities list. */ private static final int HCR_CAN_RELOAD_CLASSES = 0; private static final int HCR_CAN_GET_CLASS_VERSION = 1; private static final int HCR_CAN_DO_RETURN = 2; private static final int HCR_CAN_REENTER_ON_EXIT = 3; protected static final String JAVA_STRATUM_NAME = "Java"; //$NON-NLS-1$ /** Timeout value for requests to VM if not overridden for a particular VM. */ private int fRequestTimeout; /** Mapping of command codes to strings. */ private static Map<Integer, String> fgHCRResultMap = null; /** EventRequestManager that creates event objects on request. */ private EventRequestManagerImpl fEventReqMgr; /** EventQueue that returns EventSets from the Virtual Manager. */ private EventQueueImpl fEventQueue; /** If a launching connector is used, we store the process. */ private Process fLaunchedProcess; /** * The following field contains cached Mirrors. Note that these are * optional: their only purpose is to speed up the debugger by being able to * use the stored results of JDWP calls. */ private ValueCache fCachedReftypes = new ValueCache(); private ValueCache fCachedObjects = new ValueCache(); /** The following are the stored results of JDWP calls. */ private String fVersionDescription = null; // Text information on the VM // version. private int fJdwpMajorVersion; private int fJdwpMinorVersion; private String fVMVersion; // Target VM JRE version, as in the java.version // property. private String fVMName; // Target VM name, as in the java.vm.name property. private boolean fGotIDSizes = false; private int fFieldIDSize; private int fMethodIDSize; private int fObjectIDSize; private int fReferenceTypeIDSize; private int fFrameIDSize; private boolean fGotCapabilities = false; private boolean fCanWatchFieldModification; private boolean fCanWatchFieldAccess; private boolean fCanGetBytecodes; private boolean fCanGetSyntheticAttribute; private boolean fCanGetOwnedMonitorInfo; private boolean fCanGetCurrentContendedMonitor; private boolean fCanGetMonitorInfo; private boolean fCanRedefineClasses; private boolean fCanAddMethod; private boolean fCanUnrestrictedlyRedefineClasses; private boolean fCanPopFrames; private boolean fCanUseInstanceFilters; private boolean fCanGetSourceDebugExtension; private boolean fCanRequestVMDeathEvent; private boolean fCanSetDefaultStratum; private boolean fCanGetInstanceInfo; private boolean fCanGetConstantPool; private boolean fCanUseSourceNameFilters; private boolean fCanForceEarlyReturn; private boolean fCanRequestMonitorEvents; private boolean fCanGetMonitorFrameInfo; private boolean[] fHcrCapabilities = null; /* * singletons for primitive types */ private BooleanTypeImpl fBooleanType; private ByteTypeImpl fByteType; private CharTypeImpl fCharType; private DoubleTypeImpl fDoubleType; private FloatTypeImpl fFloatType; private IntegerTypeImpl fIntegerType; private LongTypeImpl fLongType; private ShortTypeImpl fShortType; /** * Disconnected flag */ private boolean fIsDisconnected = false; /** * The name of the current default stratum. */ private String fDefaultStratum; private PacketReceiveManager fPacketReceiveManager; private PacketSendManager fPacketSendManager; /** * Creates a new Virtual Machine. */ public VirtualMachineImpl(Connection connection) { super("VirtualMachine"); //$NON-NLS-1$ fEventReqMgr = new EventRequestManagerImpl(this); fEventQueue = new EventQueueImpl(this); fRequestTimeout = ((VirtualMachineManagerImpl) Bootstrap .virtualMachineManager()).getGlobalRequestTimeout(); fPacketReceiveManager = new PacketReceiveManager(connection, this); Thread receiveThread = new Thread(fPacketReceiveManager, JDIMessages.VirtualMachineImpl_0); receiveThread.setDaemon(true); fPacketReceiveManager.setPartnerThread(receiveThread); receiveThread.start(); fPacketSendManager = new PacketSendManager(connection); Thread sendThread = new Thread(fPacketSendManager, JDIMessages.VirtualMachineImpl_1); sendThread.setDaemon(true); fPacketReceiveManager.setPartnerThread(sendThread); sendThread.start(); } /** * @return Returns size of JDWP ID. */ public final int fieldIDSize() { return fFieldIDSize; } /** * @return Returns size of JDWP ID. */ public final int methodIDSize() { return fMethodIDSize; } /** * @return Returns size of JDWP ID. */ public final int objectIDSize() { return fObjectIDSize; } /** * @return Returns size of JDWP ID. */ public final int referenceTypeIDSize() { return fReferenceTypeIDSize; } /** * @return Returns size of JDWP ID. */ public final int frameIDSize() { return fFrameIDSize; } /** * @return Returns cached mirror object, or null if method is not in cache. */ public ReferenceTypeImpl getCachedMirror(JdwpReferenceTypeID ID) { return (ReferenceTypeImpl) fCachedReftypes.get(ID); } /** * @return Returns cached mirror object, or null if method is not in cache. */ public ObjectReferenceImpl getCachedMirror(JdwpObjectID ID) { return (ObjectReferenceImpl) fCachedObjects.get(ID); } /** * Adds mirror object to cache. */ public void addCachedMirror(ReferenceTypeImpl mirror) { fCachedReftypes.put(mirror.getRefTypeID(), mirror); // TBD: It is now yet possible to only ask for unload events for // classes that we know of due to a limitation in the J9 VM. // eventRequestManagerImpl().enableInternalClasUnloadEvent(mirror); } /** * Adds mirror object to cache. */ public void addCachedMirror(ObjectReferenceImpl mirror) { fCachedObjects.put(mirror.getObjectID(), mirror); } /** * Flushes all stored Jdwp results. */ public void flushStoredJdwpResults() { // All known classes also become invalid. Iterator<Object> iter = fCachedReftypes.values().iterator(); while (iter.hasNext()) { ReferenceTypeImpl refType = (ReferenceTypeImpl) iter.next(); refType.flushStoredJdwpResults(); } fVersionDescription = null; fGotIDSizes = false; fHcrCapabilities = null; } /* * Removes a known class. A class/interface is known if we have ever * received its ReferenceTypeID and we have not received an unload event for * it. */ public final void removeKnownRefType(String signature) { List<ReferenceType> refTypeList = classesBySignature(signature); if (refTypeList.isEmpty()) return; // If we have only one known class for this signature, we known that // this is the class // to be removed. if (refTypeList.size() == 1) { ReferenceTypeImpl refType = (ReferenceTypeImpl) refTypeList.get(0); refType.flushStoredJdwpResults(); fCachedReftypes.remove(refType.getRefTypeID()); return; } // We have more than one known class for the signature, let's find the // unloaded one(s). Iterator<ReferenceType> iter = refTypeList.iterator(); while (iter.hasNext()) { ReferenceTypeImpl refType = (ReferenceTypeImpl) iter.next(); boolean prepared = false; try { prepared = refType.isPrepared(); } catch (ObjectCollectedException exception) { // The type is unloaded. Fall through } if (!prepared) { refType.flushStoredJdwpResults(); iter.remove(); fCachedReftypes.remove(refType.getRefTypeID()); } } } /* * @exception Throws UnsupportedOperationException if VM does not support J9 * HCR. */ public void checkHCRSupported() throws UnsupportedOperationException { if (!isHCRSupported()) throw new UnsupportedOperationException( NLS.bind(JDIMessages.VirtualMachineImpl_Target_VM__0__does_not_support_Hot_Code_Replacement_1, new String[] { name() })); } /* * Returns whether J9 HCR is supported */ public boolean isHCRSupported() throws UnsupportedOperationException { return name().equals("j9"); //$NON-NLS-1$ } /* * @return Returns Manager for receiving packets from the Virtual Machine. */ public final PacketReceiveManager packetReceiveManager() { return fPacketReceiveManager; } /* * @return Returns Manager for sending packets to the Virtual Machine. */ public final PacketSendManager packetSendManager() { /* * Before we send out first bytes to the VM by JDI calls, we need some * initial requests: - Get the sizes of the IDs (fieldID, method ID * etc.) that the VM uses; - Request class prepare and unload events. We * used these to cache classes/interfaces and map their signatures. */ if (!fGotIDSizes) { getIDSizes(); if (!fGotIDSizes) { // We can't do much without them. disconnectVM(); throw new VMDisconnectedException( JDIMessages.VirtualMachineImpl_Failed_to_get_ID_sizes_2); } // TBD: This call should be moved to addKnownRefType() when it can // be made specific // for a reference type. eventRequestManagerImpl().enableInternalClasUnloadEvent(); } return fPacketSendManager; } /** * Returns all loaded types (classes, interfaces, and array types). For each * loaded type in the target VM a ReferenceType will be placed in the * returned list. */ @Override public List<ReferenceType> allClasses() { // Note that this information should not be cached. initJdwpRequest(); try { boolean withGenericSignature = virtualMachineImpl() .isJdwpVersionGreaterOrEqual(1, 5); int jdwpCommand = withGenericSignature ? JdwpCommandPacket.VM_ALL_CLASSES_WITH_GENERIC : JdwpCommandPacket.VM_ALL_CLASSES; JdwpReplyPacket replyPacket = requestVM(jdwpCommand); defaultReplyErrorHandler(replyPacket.errorCode()); DataInputStream replyData = replyPacket.dataInStream(); int nrOfElements = readInt("elements", replyData); //$NON-NLS-1$ List<ReferenceType> elements = new ArrayList<>(nrOfElements); for (int i = 0; i < nrOfElements; i++) { ReferenceTypeImpl elt = ReferenceTypeImpl .readWithTypeTagAndSignature(this, withGenericSignature, replyData); if (elt == null) { continue; } readInt("status", ReferenceTypeImpl.classStatusStrings(), replyData); //$NON-NLS-1$ elements.add(elt); } return elements; } catch (IOException e) { defaultIOExceptionHandler(e); return null; } finally { handledJdwpRequest(); } } /** * @return Returns an iterator over all loaded classes. */ protected final Iterator<ReferenceType> allRefTypes() { return allClasses().iterator(); } /** * @return Returns an iterator over all cached classes. */ protected final Iterator<Object> allCachedRefTypes() { return fCachedReftypes.values().iterator(); } /** * Returns a list of the currently running threads. For each running thread * in the target VM, a ThreadReference that mirrors it is placed in the * list. */ @Override public List<ThreadReference> allThreads() { // Note that this information should not be cached. initJdwpRequest(); try { JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.VM_ALL_THREADS); defaultReplyErrorHandler(replyPacket.errorCode()); DataInputStream replyData = replyPacket.dataInStream(); int nrOfElements = readInt("elements", replyData); //$NON-NLS-1$ List<ThreadReference> elements = new ArrayList<>(nrOfElements); for (int i = 0; i < nrOfElements; i++) { ThreadReferenceImpl elt = ThreadReferenceImpl.read(this, replyData); if (elt == null) { continue; } elements.add(elt); } return elements; } catch (IOException e) { defaultIOExceptionHandler(e); return null; } finally { handledJdwpRequest(); } } /** * Retrieve this VM's capabilities. */ public void getCapabilities() { if (fGotCapabilities) return; int command = JdwpCommandPacket.VM_CAPABILITIES; if (isJdwpVersionGreaterOrEqual(1, 4)) { command = JdwpCommandPacket.VM_CAPABILITIES_NEW; } initJdwpRequest(); try { JdwpReplyPacket replyPacket = requestVM(command); defaultReplyErrorHandler(replyPacket.errorCode()); DataInputStream replyData = replyPacket.dataInStream(); fCanWatchFieldModification = readBoolean( "watch field modification", replyData); //$NON-NLS-1$ fCanWatchFieldAccess = readBoolean("watch field access", replyData); //$NON-NLS-1$ fCanGetBytecodes = readBoolean("get bytecodes", replyData); //$NON-NLS-1$ fCanGetSyntheticAttribute = readBoolean("synth. attr", replyData); //$NON-NLS-1$ fCanGetOwnedMonitorInfo = readBoolean( "owned monitor info", replyData); //$NON-NLS-1$ fCanGetCurrentContendedMonitor = readBoolean( "curr. contended monitor", replyData); //$NON-NLS-1$ fCanGetMonitorInfo = readBoolean("monitor info", replyData); //$NON-NLS-1$ if (command == JdwpCommandPacket.VM_CAPABILITIES_NEW) { // extended capabilities fCanRedefineClasses = readBoolean("redefine classes", replyData); //$NON-NLS-1$ fCanAddMethod = readBoolean("add method", replyData); //$NON-NLS-1$ fCanUnrestrictedlyRedefineClasses = readBoolean( "unrestrictedly redefine classes", replyData); //$NON-NLS-1$ fCanPopFrames = readBoolean("pop frames", replyData); //$NON-NLS-1$ fCanUseInstanceFilters = readBoolean( "use instance filters", replyData); //$NON-NLS-1$ fCanGetSourceDebugExtension = readBoolean( "get source debug extension", replyData); //$NON-NLS-1$ fCanRequestVMDeathEvent = readBoolean( "request vm death", replyData); //$NON-NLS-1$ fCanSetDefaultStratum = readBoolean( "set default stratum", replyData); //$NON-NLS-1$ fCanGetInstanceInfo = readBoolean("instance info", replyData); //$NON-NLS-1$ fCanRequestMonitorEvents = readBoolean( "request monitor events", replyData); //$NON-NLS-1$ fCanGetMonitorFrameInfo = readBoolean( "monitor frame info", replyData); //$NON-NLS-1$ fCanUseSourceNameFilters = readBoolean( "source name filters", replyData); //$NON-NLS-1$ fCanGetConstantPool = readBoolean("constant pool", replyData); //$NON-NLS-1$ fCanForceEarlyReturn = readBoolean( "force early return", replyData); //$NON-NLS-1$ } else { fCanRedefineClasses = false; fCanAddMethod = false; fCanUnrestrictedlyRedefineClasses = false; fCanPopFrames = false; fCanUseInstanceFilters = false; fCanGetSourceDebugExtension = false; fCanRequestVMDeathEvent = false; fCanSetDefaultStratum = false; fCanGetInstanceInfo = false; fCanGetConstantPool = false; fCanUseSourceNameFilters = false; fCanForceEarlyReturn = false; fCanRequestMonitorEvents = false; fCanGetMonitorFrameInfo = false; } fGotCapabilities = true; } catch (IOException e) { fGotIDSizes = false; defaultIOExceptionHandler(e); } finally { handledJdwpRequest(); } } /** * @see com.sun.jdi.VirtualMachine#canForceEarlyReturn() * @since 3.3 */ @Override public boolean canForceEarlyReturn() { getCapabilities(); return fCanForceEarlyReturn; } /** * @return Returns true if this implementation supports the retrieval of a * method's bytecodes. */ @Override public boolean canGetBytecodes() { getCapabilities(); return fCanGetBytecodes; } /** * @return Returns true if this implementation supports the retrieval of the * monitor for which a thread is currently waiting. */ @Override public boolean canGetCurrentContendedMonitor() { getCapabilities(); return fCanGetCurrentContendedMonitor; } /** * @see com.sun.jdi.VirtualMachine#canGetInstanceInfo() * @since 3.3 */ @Override public boolean canGetInstanceInfo() { getCapabilities(); return fCanGetInstanceInfo; } /** * @see com.sun.jdi.VirtualMachine#canGetMethodReturnValues() * @since 3.3 */ @Override public boolean canGetMethodReturnValues() { return isJdwpVersionGreaterOrEqual(1, 6); } /** * @return Returns true if this implementation supports the retrieval of the * monitor information for an object. */ @Override public boolean canGetMonitorInfo() { getCapabilities(); return fCanGetMonitorInfo; } /** * @see com.sun.jdi.VirtualMachine#canGetMonitorFrameInfo() * @since 3.3 */ @Override public boolean canGetMonitorFrameInfo() { getCapabilities(); return fCanGetMonitorFrameInfo; } /** * @return Returns true if this implementation supports the retrieval of the * monitors owned by a thread. */ @Override public boolean canGetOwnedMonitorInfo() { getCapabilities(); return fCanGetOwnedMonitorInfo; } /** * @return Returns true if this implementation supports the query of the * synthetic attribute of a method or field. */ @Override public boolean canGetSyntheticAttribute() { getCapabilities(); return fCanGetSyntheticAttribute; } /** * @see com.sun.jdi.VirtualMachine#canRequestMonitorEvents() * @since 3.3 */ @Override public boolean canRequestMonitorEvents() { getCapabilities(); return fCanRequestMonitorEvents; } /** * @return Returns true if this implementation supports watchpoints for * field access. */ @Override public boolean canWatchFieldAccess() { getCapabilities(); return fCanWatchFieldAccess; } /** * @return Returns true if this implementation supports watchpoints for * field modification. */ @Override public boolean canWatchFieldModification() { getCapabilities(); return fCanWatchFieldModification; } /** * @return Returns the loaded reference types that match a given signature. */ public List<ReferenceType> classesBySignature(String signature) { // Note that this information should not be cached. initJdwpRequest(); try { ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); DataOutputStream outData = new DataOutputStream(outBytes); writeString(signature, "signature", outData); //$NON-NLS-1$ JdwpReplyPacket replyPacket = requestVM( JdwpCommandPacket.VM_CLASSES_BY_SIGNATURE, outBytes); defaultReplyErrorHandler(replyPacket.errorCode()); DataInputStream replyData = replyPacket.dataInStream(); int nrOfElements = readInt("elements", replyData); //$NON-NLS-1$ List<ReferenceType> elements = new ArrayList<>(nrOfElements); for (int i = 0; i < nrOfElements; i++) { ReferenceTypeImpl elt = ReferenceTypeImpl.readWithTypeTag(this, replyData); readInt("status", ReferenceTypeImpl.classStatusStrings(), replyData); //$NON-NLS-1$ if (elt == null) { continue; } elements.add(elt); } return elements; } catch (IOException e) { defaultIOExceptionHandler(e); return null; } finally { handledJdwpRequest(); } } /* (non-Javadoc) * @see com.sun.jdi.VirtualMachine#classesByName(java.lang.String) */ @Override public List<ReferenceType> classesByName(String name) { String signature = TypeImpl.classNameToSignature(name); return classesBySignature(signature); } /** * Invalidates this virtual machine mirror. */ @Override public void dispose() { initJdwpRequest(); try { requestVM(JdwpCommandPacket.VM_DISPOSE); disconnectVM(); } catch (VMDisconnectedException e) { // The VM can exit before we receive the reply. } finally { handledJdwpRequest(); } } /* (non-Javadoc) * @see com.sun.jdi.VirtualMachine#eventQueue() */ @Override public EventQueue eventQueue() { return fEventQueue; } /* (non-Javadoc) * @see com.sun.jdi.VirtualMachine#eventRequestManager() */ @Override public EventRequestManager eventRequestManager() { return fEventReqMgr; } /** * @return Returns EventRequestManagerImpl that creates all event objects on * request. */ public EventRequestManagerImpl eventRequestManagerImpl() { return fEventReqMgr; } /** * Causes the mirrored VM to terminate with the given error code. */ @Override public void exit(int exitCode) { initJdwpRequest(); try { ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); DataOutputStream outData = new DataOutputStream(outBytes); writeInt(exitCode, "exit code", outData); //$NON-NLS-1$ requestVM(JdwpCommandPacket.VM_EXIT, outBytes); disconnectVM(); } catch (VMDisconnectedException e) { // The VM can exit before we receive the reply. } catch (IOException e) { defaultIOExceptionHandler(e); } finally { handledJdwpRequest(); } } /* (non-Javadoc) * @see com.sun.jdi.VirtualMachine#mirrorOf(byte) */ @Override public ByteValue mirrorOf(byte value) { return new ByteValueImpl(virtualMachineImpl(), new Byte(value)); } /* (non-Javadoc) * @see com.sun.jdi.VirtualMachine#mirrorOf(char) */ @Override public CharValue mirrorOf(char value) { return new CharValueImpl(virtualMachineImpl(), new Character(value)); } /* (non-Javadoc) * @see com.sun.jdi.VirtualMachine#mirrorOf(double) */ @Override public DoubleValue mirrorOf(double value) { return new DoubleValueImpl(virtualMachineImpl(), new Double(value)); } /* (non-Javadoc) * @see com.sun.jdi.VirtualMachine#mirrorOf(float) */ @Override public FloatValue mirrorOf(float value) { return new FloatValueImpl(virtualMachineImpl(), new Float(value)); } /* (non-Javadoc) * @see com.sun.jdi.VirtualMachine#mirrorOf(int) */ @Override public IntegerValue mirrorOf(int value) { return new IntegerValueImpl(virtualMachineImpl(), new Integer(value)); } /* (non-Javadoc) * @see com.sun.jdi.VirtualMachine#mirrorOf(long) */ @Override public LongValue mirrorOf(long value) { return new LongValueImpl(virtualMachineImpl(), new Long(value)); } /* (non-Javadoc) * @see com.sun.jdi.VirtualMachine#mirrorOf(short) */ @Override public ShortValue mirrorOf(short value) { return new ShortValueImpl(virtualMachineImpl(), new Short(value)); } /* (non-Javadoc) * @see com.sun.jdi.VirtualMachine#mirrorOf(boolean) */ @Override public BooleanValue mirrorOf(boolean value) { return new BooleanValueImpl(virtualMachineImpl(), Boolean.valueOf(value)); } /* (non-Javadoc) * @see com.sun.jdi.VirtualMachine#mirrorOf(java.lang.String) */ @Override public StringReference mirrorOf(String value) { initJdwpRequest(); try { ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); DataOutputStream outData = new DataOutputStream(outBytes); writeString(value, "string value", outData); //$NON-NLS-1$ JdwpReplyPacket replyPacket = requestVM( JdwpCommandPacket.VM_CREATE_STRING, outBytes); defaultReplyErrorHandler(replyPacket.errorCode()); DataInputStream replyData = replyPacket.dataInStream(); StringReference result = StringReferenceImpl.read(this, replyData); return result; } catch (IOException e) { defaultIOExceptionHandler(e); return null; } finally { handledJdwpRequest(); } } /* (non-Javadoc) * @see com.sun.jdi.VirtualMachine#mirrorOfVoid() */ @Override public VoidValue mirrorOfVoid() { return new VoidValueImpl(this); } /* (non-Javadoc) * @see com.sun.jdi.VirtualMachine#process() */ @Override public Process process() { return fLaunchedProcess; } /** * Sets Process object for this virtual machine if launched by a * LaunchingConnector. */ public void setLaunchedProcess(Process proc) { fLaunchedProcess = proc; } /* (non-Javadoc) * @see com.sun.jdi.VirtualMachine#resume() */ @Override public void resume() { initJdwpRequest(); try { resetThreadEventFlags(); JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.VM_RESUME); defaultReplyErrorHandler(replyPacket.errorCode()); } finally { handledJdwpRequest(); } } /* (non-Javadoc) * @see com.sun.jdi.VirtualMachine#setDebugTraceMode(int) */ @Override public void setDebugTraceMode(int traceFlags) { // We don't have trace info. } /* (non-Javadoc) * @see com.sun.jdi.VirtualMachine#suspend() */ @Override public void suspend() { initJdwpRequest(); try { JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.VM_SUSPEND); defaultReplyErrorHandler(replyPacket.errorCode()); } finally { handledJdwpRequest(); } } /* (non-Javadoc) * @see com.sun.jdi.VirtualMachine#topLevelThreadGroups() */ @Override public List<ThreadGroupReference> topLevelThreadGroups() { // Note that this information should not be cached. initJdwpRequest(); try { JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.VM_TOP_LEVEL_THREAD_GROUPS); defaultReplyErrorHandler(replyPacket.errorCode()); DataInputStream replyData = replyPacket.dataInStream(); int nrGroups = readInt("nr of groups", replyData); //$NON-NLS-1$ ArrayList<ThreadGroupReference> result = new ArrayList<>(nrGroups); for (int i = 0; i < nrGroups; i++) { ThreadGroupReferenceImpl threadGroup = ThreadGroupReferenceImpl.read(this, replyData); result.add(threadGroup); } return result; } catch (IOException e) { defaultIOExceptionHandler(e); return null; } finally { handledJdwpRequest(); } } /* (non-Javadoc) * @see com.sun.jdi.VirtualMachine#name() */ @Override public String name() { getVersionInfo(); return fVMName; } /* (non-Javadoc) * @see com.sun.jdi.VirtualMachine#version() */ @Override public String version() { getVersionInfo(); return fVMVersion; } /* (non-Javadoc) * @see com.sun.jdi.VirtualMachine#description() */ @Override public String description() { getVersionInfo(); return fVersionDescription; } /** * Reset event flags of all threads. */ private void resetThreadEventFlags() { Iterator<ThreadReference> iter = allThreads().iterator(); ThreadReferenceImpl thread; while (iter.hasNext()) { thread = (ThreadReferenceImpl) iter.next(); thread.resetEventFlags(); } } /** * Request and fetch ID sizes of Virtual Machine. */ private void getIDSizes() { if (fGotIDSizes) return; /* * fGotIDSizes must first be assigned true to prevent an infinite loop * because getIDSizes() calls requestVM which calls packetSendManager. */ fGotIDSizes = true; // We use a different mirror to avoid having verbose output mixed with // the initiating command. MirrorImpl mirror = new VoidValueImpl(this); mirror.initJdwpRequest(); try { JdwpReplyPacket replyPacket = mirror .requestVM(JdwpCommandPacket.VM_ID_SIZES); mirror.defaultReplyErrorHandler(replyPacket.errorCode()); DataInputStream replyData = replyPacket.dataInStream(); fFieldIDSize = mirror.readInt("field ID size", replyData); //$NON-NLS-1$ fMethodIDSize = mirror.readInt("method ID size", replyData); //$NON-NLS-1$ fObjectIDSize = mirror.readInt("object ID size", replyData); //$NON-NLS-1$ fReferenceTypeIDSize = mirror.readInt("refType ID size", replyData); //$NON-NLS-1$ fFrameIDSize = mirror.readInt("frame ID size", replyData); //$NON-NLS-1$ } catch (IOException e) { fGotIDSizes = false; mirror.defaultIOExceptionHandler(e); } finally { mirror.handledJdwpRequest(); } } /** * Retrieves version info of the VM. */ public void getVersionInfo() { if (fVersionDescription != null) return; initJdwpRequest(); try { JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.VM_VERSION); defaultReplyErrorHandler(replyPacket.errorCode()); DataInputStream replyData = replyPacket.dataInStream(); fVersionDescription = readString("version descr.", replyData); //$NON-NLS-1$ fJdwpMajorVersion = readInt("major version", replyData); //$NON-NLS-1$ fJdwpMinorVersion = readInt("minor version", replyData); //$NON-NLS-1$ fVMVersion = readString("version", replyData); //$NON-NLS-1$ fVMName = readString("name", replyData); //$NON-NLS-1$ if ((fVMName != null) && fVMName.equals("KVM")) { //$NON-NLS-1$ // KVM requires class preparation events in order // to resolve things correctly eventRequestManagerImpl().enableInternalClassPrepareEvent(); } } catch (IOException e) { fVersionDescription = null; defaultIOExceptionHandler(e); } finally { handledJdwpRequest(); } } /** * Retrieves the HCR capabilities of the VM. */ public void getHCRCapabilities() { if (fHcrCapabilities != null) return; fHcrCapabilities = new boolean[HCR_CAN_REENTER_ON_EXIT + 1]; if (isHCRSupported()) { initJdwpRequest(); try { JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.HCR_CAPABILITIES); defaultReplyErrorHandler(replyPacket.errorCode()); DataInputStream replyData = replyPacket.dataInStream(); fHcrCapabilities[HCR_CAN_RELOAD_CLASSES] = readBoolean( "reload classes", replyData); //$NON-NLS-1$ fHcrCapabilities[HCR_CAN_GET_CLASS_VERSION] = readBoolean( "get class version", replyData); //$NON-NLS-1$ fHcrCapabilities[HCR_CAN_DO_RETURN] = readBoolean( "do return", replyData); //$NON-NLS-1$ fHcrCapabilities[HCR_CAN_REENTER_ON_EXIT] = readBoolean( "reenter on exit", replyData); //$NON-NLS-1$ } catch (IOException e) { fHcrCapabilities = null; defaultIOExceptionHandler(e); } finally { handledJdwpRequest(); } } else { for (int i = 0; i < fHcrCapabilities.length; i++) { fHcrCapabilities[i] = false; } } } /* (non-Javadoc) * @see org.eclipse.jdi.hcr.VirtualMachine#canReloadClasses() */ @Override public boolean canReloadClasses() { getHCRCapabilities(); return fHcrCapabilities[HCR_CAN_RELOAD_CLASSES]; } /** * @return Returns Whether VM can get the version of a given class file. */ public boolean canGetClassFileVersion1() { getHCRCapabilities(); return fHcrCapabilities[HCR_CAN_GET_CLASS_VERSION]; } /* (non-Javadoc) * @see com.sun.jdi.VirtualMachine#canGetClassFileVersion() */ @Override public boolean canGetClassFileVersion() { return isJdwpVersionGreaterOrEqual(1, 6); } /* (non-Javadoc) * @see com.sun.jdi.VirtualMachine#canGetConstantPool() */ @Override public boolean canGetConstantPool() { getCapabilities(); return fCanGetConstantPool; } /* (non-Javadoc) * @see org.eclipse.jdi.hcr.VirtualMachine#canDoReturn() */ @Override public boolean canDoReturn() { getHCRCapabilities(); return fHcrCapabilities[HCR_CAN_DO_RETURN]; } /* (non-Javadoc) * @see org.eclipse.jdi.hcr.VirtualMachine#canReenterOnExit() */ @Override public boolean canReenterOnExit() { getHCRCapabilities(); return fHcrCapabilities[HCR_CAN_REENTER_ON_EXIT]; } /* (non-Javadoc) * @see org.eclipse.jdi.hcr.VirtualMachine#classesHaveChanged(java.lang.String[]) */ @Override public int classesHaveChanged(String[] names) { checkHCRSupported(); // We convert the class/interface names to signatures. String[] signatures = new String[names.length]; initJdwpRequest(); try { ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); DataOutputStream outData = new DataOutputStream(outBytes); writeInt(names.length, "length", outData); //$NON-NLS-1$ for (int i = 0; i < names.length; i++) { signatures[i] = TypeImpl.classNameToSignature(names[i]); writeString(signatures[i], "signature", outData); //$NON-NLS-1$ } JdwpReplyPacket replyPacket = requestVM( JdwpCommandPacket.HCR_CLASSES_HAVE_CHANGED, outBytes); defaultReplyErrorHandler(replyPacket.errorCode()); DataInputStream replyData = replyPacket.dataInStream(); byte resultFlag = readByte("result", resultHCRMap(), replyData); //$NON-NLS-1$ switch (resultFlag) { case HCR_RELOAD_SUCCESS: return RELOAD_SUCCESS; case HCR_RELOAD_FAILURE: return RELOAD_FAILURE; case HCR_RELOAD_IGNORED: return RELOAD_IGNORED; } throw new InternalError( JDIMessages.VirtualMachineImpl_Invalid_result_flag_in_Classes_Have_Changed_response___3 + resultFlag + JDIMessages.VirtualMachineImpl__4); // } catch (IOException e) { defaultIOExceptionHandler(e); return 0; } finally { handledJdwpRequest(); } } /** * @return Returns description of Mirror object. */ @Override public String toString() { try { return name(); } catch (Exception e) { return fDescription; } } /** * Retrieves constant mappings. */ public static void getConstantMaps() { if (fgHCRResultMap != null) { return; } Field[] fields = VirtualMachineImpl.class.getDeclaredFields(); fgHCRResultMap = new HashMap<>(); for (Field field : fields) { if ((field.getModifiers() & Modifier.PUBLIC) == 0 || (field.getModifiers() & Modifier.STATIC) == 0 || (field.getModifiers() & Modifier.FINAL) == 0) { continue; } try { String name = field.getName(); if (name.startsWith("HCR_RELOAD_")) { //$NON-NLS-1$ Integer intValue = new Integer(field.getInt(null)); name = name.substring(4); fgHCRResultMap.put(intValue, name); } } catch (IllegalAccessException e) { // Will not occur for own class. } catch (IllegalArgumentException e) { // Should not occur. // We should take care that all public static final constants // in this class are numbers that are convertible to int. } } } /** * @return Returns a map with string representations of tags. */ public static Map<Integer, String> resultHCRMap() { getConstantMaps(); return fgHCRResultMap; } /* (non-Javadoc) * @see org.eclipse.jdi.VirtualMachine#setRequestTimeout(int) */ @Override public void setRequestTimeout(int timeout) { fRequestTimeout = timeout; } /* (non-Javadoc) * @see org.eclipse.jdi.VirtualMachine#getRequestTimeout() */ @Override public int getRequestTimeout() { return fRequestTimeout; } /** * Returns whether the JDWP version is greater than or equal to the * specified major/minor version numbers. * * @return whether the JDWP version is greater than or equal to the * specified major/minor version numbers */ public boolean isJdwpVersionGreaterOrEqual(int major, int minor) { getVersionInfo(); return (fJdwpMajorVersion > major) || (fJdwpMajorVersion == major && fJdwpMinorVersion >= minor); } @Override public void redefineClasses(Map<? extends ReferenceType, byte[]> typesToBytes) { if (!canRedefineClasses()) { throw new UnsupportedOperationException(); } initJdwpRequest(); try { ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); DataOutputStream outData = new DataOutputStream(outBytes); writeInt(typesToBytes.size(), "classes", outData); //$NON-NLS-1$ Set<? extends ReferenceType> types = typesToBytes.keySet(); Iterator<? extends ReferenceType> iter = types.iterator(); while (iter.hasNext()) { ReferenceTypeImpl type = (ReferenceTypeImpl) iter.next(); type.write(this, outData); byte[] bytes = typesToBytes.get(type); writeInt(bytes.length, "classfile", outData); //$NON-NLS-1$ for (byte b : bytes) { writeByte(b, "classByte", outData); //$NON-NLS-1$ } fCachedReftypes.remove(type.getRefTypeID()); // flush local // cache of // redefined // types } JdwpReplyPacket reply = requestVM( JdwpCommandPacket.VM_REDEFINE_CLASSES, outBytes); switch (reply.errorCode()) { case JdwpReplyPacket.UNSUPPORTED_VERSION: throw new UnsupportedClassVersionError(); case JdwpReplyPacket.INVALID_CLASS_FORMAT: throw new ClassFormatError(); case JdwpReplyPacket.CIRCULAR_CLASS_DEFINITION: throw new ClassCircularityError(); case JdwpReplyPacket.FAILS_VERIFICATION: throw new VerifyError(); case JdwpReplyPacket.NAMES_DONT_MATCH: throw new NoClassDefFoundError(); case JdwpReplyPacket.ADD_METHOD_NOT_IMPLEMENTED: throw new UnsupportedOperationException( JDIMessages.VirtualMachineImpl_Add_method_not_implemented_1); case JdwpReplyPacket.SCHEMA_CHANGE_NOT_IMPLEMENTED: throw new UnsupportedOperationException( JDIMessages.VirtualMachineImpl_Scheme_change_not_implemented_2); case JdwpReplyPacket.HIERARCHY_CHANGE_NOT_IMPLEMENTED: throw new UnsupportedOperationException( JDIMessages.VirtualMachineImpl_Hierarchy_change_not_implemented_3); case JdwpReplyPacket.DELETE_METHOD_NOT_IMPLEMENTED: throw new UnsupportedOperationException( JDIMessages.VirtualMachineImpl_Delete_method_not_implemented_4); case JdwpReplyPacket.CLASS_MODIFIERS_CHANGE_NOT_IMPLEMENTED: throw new UnsupportedOperationException( JDIMessages.VirtualMachineImpl_Class_modifiers_change_not_implemented_5); case JdwpReplyPacket.METHOD_MODIFIERS_CHANGE_NOT_IMPLEMENTED: throw new UnsupportedOperationException( JDIMessages.VirtualMachineImpl_Method_modifiers_change_not_implemented_6); default: defaultReplyErrorHandler(reply.errorCode()); } } catch (IOException ioe) { defaultIOExceptionHandler(ioe); return; } finally { handledJdwpRequest(); } } /* * @see VirtualMachine#canRedefineClasses() */ @Override public boolean canRedefineClasses() { getCapabilities(); return fCanRedefineClasses; } /* * @see VirtualMachine#canUseInstanceFilters() */ @Override public boolean canUseInstanceFilters() { getCapabilities(); return fCanUseInstanceFilters; } /* * @see VirtualMachine#canAddMethod() */ @Override public boolean canAddMethod() { getCapabilities(); return fCanAddMethod; } /* * @see VirtualMachine#canUnrestrictedlyRedefineClasses() */ @Override public boolean canUnrestrictedlyRedefineClasses() { getCapabilities(); return fCanUnrestrictedlyRedefineClasses; } /* (non-Javadoc) * @see com.sun.jdi.VirtualMachine#canUseSourceNameFilters() */ @Override public boolean canUseSourceNameFilters() { getCapabilities(); return fCanUseSourceNameFilters; } /* * @see VirtualMachine#canPopFrames() */ @Override public boolean canPopFrames() { getCapabilities(); return fCanPopFrames; } /* * @see VirtualMachine#canGetSourceDebugExtension() */ @Override public boolean canGetSourceDebugExtension() { getCapabilities(); return fCanGetSourceDebugExtension; } /* * @see VirtualMachine#canRequestVMDeathEvent() */ @Override public boolean canRequestVMDeathEvent() { getCapabilities(); return fCanRequestVMDeathEvent; } public boolean canSetDefaultStratum() { getCapabilities(); return fCanSetDefaultStratum; } /* * @see VirtualMachine#setDefaultStratum(String) */ @Override public void setDefaultStratum(String stratum) { fDefaultStratum = stratum; if (!canSetDefaultStratum()) { // TODO: how to inform the user that the VM doesn't manage // setDefaultStartum ? return; } if (stratum == null) { stratum = ""; //$NON-NLS-1$ } initJdwpRequest(); try { ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); DataOutputStream outData = new DataOutputStream(outBytes); writeString(stratum, "stratum ID", outData); //$NON-NLS-1$ JdwpReplyPacket replyPacket = requestVM( JdwpCommandPacket.VM_SET_DEFAULT_STRATUM, outBytes); defaultReplyErrorHandler(replyPacket.errorCode()); } catch (IOException e) { defaultIOExceptionHandler(e); } finally { handledJdwpRequest(); } } /* (non-Javadoc) * @see com.sun.jdi.VirtualMachine#getDefaultStratum() */ @Override public String getDefaultStratum() { return fDefaultStratum; } /* (non-Javadoc) * @see com.sun.jdi.VirtualMachine#instanceCounts(java.util.List) */ @Override public long[] instanceCounts(List<? extends ReferenceType> refTypes) { if (refTypes == null) { throw new NullPointerException(JDIMessages.VirtualMachineImpl_2); } int size = refTypes.size(); if (size == 0) { if (isJdwpVersionGreaterOrEqual(1, 6)) { return new long[0]; } throw new UnsupportedOperationException(JDIMessages.ReferenceTypeImpl_27); } try { ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); DataOutputStream outData = new DataOutputStream(outBytes); writeInt(size, "size", outData); //$NON-NLS-1$ for (int i = 0; i < size; i++) { ((ReferenceTypeImpl) refTypes.get(i)).getRefTypeID().write( outData); } JdwpReplyPacket replyPacket = requestVM( JdwpCommandPacket.VM_INSTANCE_COUNTS, outBytes); switch (replyPacket.errorCode()) { case JdwpReplyPacket.INVALID_CLASS: case JdwpReplyPacket.INVALID_OBJECT: throw new ObjectCollectedException( JDIMessages.class_or_object_not_known); case JdwpReplyPacket.ILLEGAL_ARGUMENT: throw new IllegalArgumentException( JDIMessages.VirtualMachineImpl_count_less_than_zero); case JdwpReplyPacket.NOT_IMPLEMENTED: throw new UnsupportedOperationException( JDIMessages.ReferenceTypeImpl_27); case JdwpReplyPacket.VM_DEAD: throw new VMDisconnectedException(JDIMessages.vm_dead); } defaultReplyErrorHandler(replyPacket.errorCode()); DataInputStream replyData = replyPacket.dataInStream(); int counts = readInt("counts", replyData); //$NON-NLS-1$ if (counts != size) { throw new InternalError(JDIMessages.VirtualMachineImpl_3); } long[] ret = new long[counts]; for (int i = 0; i < counts; i++) { ret[i] = readLong("ref count", replyData); //$NON-NLS-1$ } return ret; } catch (IOException e) { defaultIOExceptionHandler(e); return null; } finally { handledJdwpRequest(); } } /** * Returns whether this VM is disconnected. * * @return whether this VM is disconnected */ public boolean isDisconnected() { return fIsDisconnected; } /** * Sets whether this VM is disconnected. * * @param disconected * whether this VM is disconnected */ public synchronized void setDisconnected(boolean disconnected) { fIsDisconnected = disconnected; } /** * Return the boolean type for this VM. */ protected BooleanTypeImpl getBooleanType() { if (fBooleanType == null) { fBooleanType = new BooleanTypeImpl(this); } return fBooleanType; } /** * Return the byte type for this VM. */ protected ByteTypeImpl getByteType() { if (fByteType == null) { fByteType = new ByteTypeImpl(this); } return fByteType; } /** * Return the char type for this VM. */ protected CharTypeImpl getCharType() { if (fCharType == null) { fCharType = new CharTypeImpl(this); } return fCharType; } /** * Return the double type for this VM. */ protected DoubleTypeImpl getDoubleType() { if (fDoubleType == null) { fDoubleType = new DoubleTypeImpl(this); } return fDoubleType; } /** * Return the float type for this VM. */ protected FloatTypeImpl getFloatType() { if (fFloatType == null) { fFloatType = new FloatTypeImpl(this); } return fFloatType; } /** * Return the integer type for this VM. */ protected IntegerTypeImpl getIntegerType() { if (fIntegerType == null) { fIntegerType = new IntegerTypeImpl(this); } return fIntegerType; } /** * Return the long type for this VM. */ protected LongTypeImpl getLongType() { if (fLongType == null) { fLongType = new LongTypeImpl(this); } return fLongType; } /** * Return the short type for this VM. */ protected ShortTypeImpl getShortType() { if (fShortType == null) { fShortType = new ShortTypeImpl(this); } return fShortType; } /* * (non-Javadoc) * * @see com.sun.jdi.VirtualMachine#canBeModified() */ @Override public boolean canBeModified() { return true; } }