package st.gravel.support.jvm.debugger; import java.util.Arrays; import java.util.List; import st.gravel.support.jvm.ArrayExtensions; import st.gravel.support.jvm.Block1; import st.gravel.support.jvm.OrderedCollectionExtensions; import st.gravel.support.jvm.Predicate1; import sun.misc.VM; import com.sun.jdi.ClassNotLoadedException; import com.sun.jdi.IncompatibleThreadStateException; import com.sun.jdi.InvalidTypeException; import com.sun.jdi.InvocationException; import com.sun.jdi.Method; import com.sun.jdi.ObjectReference; import com.sun.jdi.ReferenceType; import com.sun.jdi.ThreadReference; import com.sun.jdi.Value; import com.sun.jdi.VirtualMachine; public abstract class VMRemoteInstance { private ObjectReference receiver; public VMRemoteInstance(ObjectReference receiver) { this.receiver = receiver; } protected Value invokeMethod(String methodName, Value... arguments) throws InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException, InvocationException { return invoke(receiver, getMethod(methodName), arguments); } private Value invoke(ObjectReference receiver, Method method, Value... arguments) throws InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException, InvocationException { String args = ArrayExtensions.join_with_(arguments, new Block1<String, Value>() { @Override public String value_(Value arg) { return arg.toString(); } }, ", "); System.out.print("" + debugPort() + " Invoking " + receiver + ">>" + method.name() + "(" + args + ")"); List<ThreadReference> suspendedThreads = OrderedCollectionExtensions.select_(receiver.virtualMachine().allThreads(), new Predicate1<ThreadReference>() { @Override public boolean value_(ThreadReference arg1) { return arg1.isSuspended(); } }); Value result = receiver.invokeMethod(bootThread(), method, Arrays.asList(arguments), 0); System.out.println(" -> " + result); List<ThreadReference> allThreads = receiver.virtualMachine().allThreads(); for (ThreadReference threadReference : allThreads) { if (suspendedThreads.contains(threadReference)) { System.out.println("- Keep suspended: "+ threadReference + " suspendCount: "+ threadReference.suspendCount()); } else { System.out.println("--------- Resume: "+ threadReference + " suspendCount: "+ threadReference.suspendCount()); threadReference.resume(); } } return result; } protected abstract int debugPort(); protected abstract ThreadReference bootThread(); protected abstract VirtualMachine vm(); protected Method getMethod(String methodName) { List<Method> methodsByName = receiver.referenceType().methodsByName( methodName); if (methodsByName.isEmpty()) { throw new RuntimeException("Receiver: " + receiver + " dnu: " + methodName); } return methodsByName.get(0); } protected Method getMethod(Class<?> class1, String methodName) { List<ReferenceType> targetClasses = vm() .classesByName(class1.getName()); ReferenceType classRef = targetClasses.get(0); return classRef.methodsByName(methodName).get(0); } public Value invokeMethod(ObjectReference receiver, String methodName, Value... arguments) throws Throwable { Method method = receiver.referenceType().methodsByName(methodName) .get(0); return invoke(receiver, method, arguments); } }