blob: 541c0eaddd8bbd6098cec7ecc9217b0e51700f8c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2015 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* 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(), Byte.valueOf(value));
}
/* (non-Javadoc)
* @see com.sun.jdi.VirtualMachine#mirrorOf(char)
*/
@Override
public CharValue mirrorOf(char value) {
return new CharValueImpl(virtualMachineImpl(), Character.valueOf(value));
}
/* (non-Javadoc)
* @see com.sun.jdi.VirtualMachine#mirrorOf(double)
*/
@Override
public DoubleValue mirrorOf(double value) {
return new DoubleValueImpl(virtualMachineImpl(), Double.valueOf(value));
}
/* (non-Javadoc)
* @see com.sun.jdi.VirtualMachine#mirrorOf(float)
*/
@Override
public FloatValue mirrorOf(float value) {
return new FloatValueImpl(virtualMachineImpl(), Float.valueOf(value));
}
/* (non-Javadoc)
* @see com.sun.jdi.VirtualMachine#mirrorOf(int)
*/
@Override
public IntegerValue mirrorOf(int value) {
return new IntegerValueImpl(virtualMachineImpl(), Integer.valueOf(value));
}
/* (non-Javadoc)
* @see com.sun.jdi.VirtualMachine#mirrorOf(long)
*/
@Override
public LongValue mirrorOf(long value) {
return new LongValueImpl(virtualMachineImpl(), Long.valueOf(value));
}
/* (non-Javadoc)
* @see com.sun.jdi.VirtualMachine#mirrorOf(short)
*/
@Override
public ShortValue mirrorOf(short value) {
return new ShortValueImpl(virtualMachineImpl(), Short.valueOf(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 = Integer.valueOf(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;
}
}