/******************************************************************************* * 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.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.eclipse.jdi.internal.jdwp.JdwpCommandPacket; import org.eclipse.jdi.internal.jdwp.JdwpFrameID; import org.eclipse.jdi.internal.jdwp.JdwpID; import org.eclipse.jdi.internal.jdwp.JdwpReplyPacket; import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; import com.sun.jdi.AbsentInformationException; import com.sun.jdi.ClassNotLoadedException; import com.sun.jdi.InvalidStackFrameException; import com.sun.jdi.InvalidTypeException; import com.sun.jdi.LocalVariable; import com.sun.jdi.Locatable; import com.sun.jdi.Location; import com.sun.jdi.ObjectReference; import com.sun.jdi.StackFrame; import com.sun.jdi.ThreadReference; import com.sun.jdi.VMMismatchException; import com.sun.jdi.Value; /** * this class implements the corresponding interfaces declared by the JDI * specification. See the com.sun.jdi package for more information. * */ public class StackFrameImpl extends MirrorImpl implements StackFrame, Locatable { /** FrameID that corresponds to this reference. */ private JdwpFrameID fFrameID; /** Thread under which this frame's method is running. */ private ThreadReferenceImpl fThread; /** Location of the current instruction in the frame. */ private LocationImpl fLocation; /** * Creates new StackFrameImpl. */ public StackFrameImpl(VirtualMachineImpl vmImpl, JdwpFrameID ID, ThreadReferenceImpl thread, LocationImpl location) { super("StackFrame", vmImpl); //$NON-NLS-1$ fFrameID = ID; fThread = thread; fLocation = location; } /* (non-Javadoc) * @see com.sun.jdi.StackFrame#getValue(com.sun.jdi.LocalVariable) */ @Override public Value getValue(LocalVariable variable) throws IllegalArgumentException, InvalidStackFrameException, VMMismatchException { ArrayList<LocalVariable> list = new ArrayList<>(1); list.add(variable); return getValues(list).get(variable); } /* (non-Javadoc) * @see com.sun.jdi.StackFrame#getValues(java.util.List) */ @Override public Map<LocalVariable, Value> getValues(List<? extends LocalVariable> variables) throws IllegalArgumentException, InvalidStackFrameException, VMMismatchException { // Note that this information should not be cached. Map<LocalVariable, Value> map = new HashMap<>(variables.size()); // if the variable list is empty, nothing to do if (variables.isEmpty()) { return map; } /* * If 'this' is requested, we have to use a special JDWP request. * Therefore, we remember the positions in the list of requests for * 'this'. */ int sizeAll = variables.size(); int sizeThis = 0; boolean[] isThisValue = new boolean[sizeAll]; for (int i = 0; i < sizeAll; i++) { LocalVariableImpl var = (LocalVariableImpl) variables.get(i); isThisValue[i] = var.isThis(); if (isThisValue[i]) { sizeThis++; } } int sizeNotThis = sizeAll - sizeThis; if (sizeThis > 0) { Value thisValue = thisObject(); for (int i = 0; i < sizeAll; i++) { if (isThisValue[i]) { map.put(variables.get(i), thisValue); } } } // If only 'this' was requested, we're finished. if (sizeNotThis == 0) { return map; } // Request values for local variables other than 'this'. initJdwpRequest(); try { ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); DataOutputStream outData = new DataOutputStream(outBytes); writeWithThread(this, outData); writeInt(sizeNotThis, "size", outData); //$NON-NLS-1$ for (int i = 0; i < sizeAll; i++) { if (!isThisValue[i]) { LocalVariableImpl var = (LocalVariableImpl) variables .get(i); checkVM(var); writeInt(var.slot(), "slot", outData); //$NON-NLS-1$ writeByte(var.tag(), "tag", JdwpID.tagMap(), outData); //$NON-NLS-1$ } } JdwpReplyPacket replyPacket = requestVM( JdwpCommandPacket.SF_GET_VALUES, outBytes); defaultReplyErrorHandler(replyPacket.errorCode()); DataInputStream replyData = replyPacket.dataInStream(); int nrOfElements = readInt("elements", replyData); //$NON-NLS-1$ if (nrOfElements != sizeNotThis) throw new InternalError( JDIMessages.StackFrameImpl_Retrieved_a_different_number_of_values_from_the_VM_than_requested_1); for (int i = 0, j = 0; i < sizeAll; i++) { if (!isThisValue[i]) map.put(variables.get(j++), ValueImpl.readWithTag(this, replyData)); } return map; } catch (IOException e) { defaultIOExceptionHandler(e); return null; } finally { handledJdwpRequest(); } } /* (non-Javadoc) * @see com.sun.jdi.StackFrame#getArgumentValues() */ @Override public List<Value> getArgumentValues() throws InvalidStackFrameException { if (!thread().isSuspended()) { throw new InvalidStackFrameException( JDIMessages.StackFrameImpl_no_argument_values_available); } try { List<LocalVariable> list = location().method().variables(); ArrayList<Value> ret = new ArrayList<>(); LocalVariable var = null; for (Iterator<LocalVariable> iter = list.iterator(); iter.hasNext();) { var = iter.next(); if (var.isArgument()) { ret.add(getValue(var)); } } return ret; } catch (AbsentInformationException e) { JDIDebugPlugin.log(e); return null; } } /* (non-Javadoc) * @see com.sun.jdi.StackFrame#location() */ @Override public Location location() { return fLocation; } /* (non-Javadoc) * @see com.sun.jdi.StackFrame#setValue(com.sun.jdi.LocalVariable, com.sun.jdi.Value) */ @Override public void setValue(LocalVariable var, Value value) throws InvalidTypeException, ClassNotLoadedException { // Note that this information should not be cached. initJdwpRequest(); try { ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); DataOutputStream outData = new DataOutputStream(outBytes); ((ThreadReferenceImpl) thread()).write(this, outData); write(this, outData); writeInt(1, "size", outData); // We only set one field //$NON-NLS-1$ checkVM(var); writeInt(((LocalVariableImpl) var).slot(), "slot", outData); //$NON-NLS-1$ // check the type and the VM of the value, convert the value if // needed. ValueImpl checkedValue = ValueImpl.checkValue(value, var.type(), virtualMachineImpl()); if (checkedValue != null) { checkedValue.writeWithTag(this, outData); } else { ValueImpl.writeNullWithTag(this, outData); } JdwpReplyPacket replyPacket = requestVM( JdwpCommandPacket.SF_SET_VALUES, outBytes); switch (replyPacket.errorCode()) { case JdwpReplyPacket.INVALID_CLASS: throw new ClassNotLoadedException(var.typeName()); } defaultReplyErrorHandler(replyPacket.errorCode()); } catch (IOException e) { defaultIOExceptionHandler(e); } finally { handledJdwpRequest(); } } /* (non-Javadoc) * @see com.sun.jdi.StackFrame#thisObject() */ @Override public ObjectReference thisObject() throws InvalidStackFrameException { // Note that this information should not be cached. initJdwpRequest(); try { ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); DataOutputStream outData = new DataOutputStream(outBytes); writeWithThread(this, outData); JdwpReplyPacket replyPacket = requestVM( JdwpCommandPacket.SF_THIS_OBJECT, outBytes); defaultReplyErrorHandler(replyPacket.errorCode()); DataInputStream replyData = replyPacket.dataInStream(); ObjectReference result = ObjectReferenceImpl.readObjectRefWithTag( this, replyData); return result; } catch (IOException e) { defaultIOExceptionHandler(e); return null; } finally { handledJdwpRequest(); } } /* (non-Javadoc) * @see com.sun.jdi.StackFrame#thread() */ @Override public ThreadReference thread() { return fThread; } /* (non-Javadoc) * @see com.sun.jdi.StackFrame#visibleVariableByName(java.lang.String) */ @Override public LocalVariable visibleVariableByName(String name) throws AbsentInformationException { Iterator<LocalVariable> iter = visibleVariables().iterator(); while (iter.hasNext()) { LocalVariableImpl var = (LocalVariableImpl) iter.next(); if (var.name().equals(name)) { return var; } } return null; } /* (non-Javadoc) * @see com.sun.jdi.StackFrame#visibleVariables() */ @Override public List<LocalVariable> visibleVariables() throws AbsentInformationException { List<LocalVariable> variables = fLocation.method().variables(); Iterator<LocalVariable> iter = variables.iterator(); List<LocalVariable> visibleVars = new ArrayList<>(variables.size()); while (iter.hasNext()) { LocalVariableImpl var = (LocalVariableImpl) iter.next(); // Only return local variables other than the this pointer. if (var.isVisible(this) && !var.isThis()) { visibleVars.add(var); } } return visibleVars; } /** * @return Returns the hash code value. */ @Override public int hashCode() { return fThread.hashCode() + fFrameID.hashCode(); } /** * @return Returns true if two mirrors refer to the same entity in the * target VM. * @see java.lang.Object#equals(Object) */ @Override public boolean equals(Object object) { return object != null && object.getClass().equals(this.getClass()) && fThread.equals(((StackFrameImpl) object).fThread) && fFrameID.equals(((StackFrameImpl) object).fFrameID); } /** * Writes JDWP representation. */ public void write(MirrorImpl target, DataOutputStream out) throws IOException { fFrameID.write(out); if (target.fVerboseWriter != null) { target.fVerboseWriter.println("stackFrame", fFrameID.value()); //$NON-NLS-1$ } } /** * Writes JDWP representation. */ public void writeWithThread(MirrorImpl target, DataOutputStream out) throws IOException { fThread.write(target, out); write(target, out); } /** * @return Reads JDWP representation and returns new instance. */ public static StackFrameImpl readWithLocation(MirrorImpl target, ThreadReferenceImpl thread, DataInputStream in) throws IOException { VirtualMachineImpl vmImpl = target.virtualMachineImpl(); JdwpFrameID ID = new JdwpFrameID(vmImpl); ID.read(in); if (target.fVerboseWriter != null) { target.fVerboseWriter.println("stackFrame", ID.value()); //$NON-NLS-1$ } if (ID.isNull()) { return null; } LocationImpl location = LocationImpl.read(target, in); if (location == null) { return null; } return new StackFrameImpl(vmImpl, ID, thread, location); } }