diff --git a/org.ntlab.reverseDebugger/src/org/ntlab/reverseDebugger/CallStackLabelProvider.java b/org.ntlab.reverseDebugger/src/org/ntlab/reverseDebugger/CallStackLabelProvider.java index 1123a4f..da8a087 100644 --- a/org.ntlab.reverseDebugger/src/org/ntlab/reverseDebugger/CallStackLabelProvider.java +++ b/org.ntlab.reverseDebugger/src/org/ntlab/reverseDebugger/CallStackLabelProvider.java @@ -13,9 +13,9 @@ public String getText(Object element) { if (element instanceof TreeNode) { Object value = ((TreeNode)element).getValue(); - if (value instanceof JDIStaticMethodCaller) { - JDIStaticMethodCaller mc = (JDIStaticMethodCaller)value; - return "ThreadID: " + mc.getThreadId(); + if (value instanceof String) { + String threadId = (String)value; + return "ThreadID: " + threadId; } if (value instanceof CallStackModel) { CallStackModel callStackModel = (CallStackModel)value; diff --git a/org.ntlab.reverseDebugger/src/org/ntlab/reverseDebugger/CallStackModel.java b/org.ntlab.reverseDebugger/src/org/ntlab/reverseDebugger/CallStackModel.java index c5ce131..938c655 100644 --- a/org.ntlab.reverseDebugger/src/org/ntlab/reverseDebugger/CallStackModel.java +++ b/org.ntlab.reverseDebugger/src/org/ntlab/reverseDebugger/CallStackModel.java @@ -17,9 +17,10 @@ @SuppressWarnings("restriction") public class CallStackModel { private JDIInstanceMethodCaller methodExecutionMc; + private String threadId; private int callLineNo; - public CallStackModel(VirtualMachine vm, ThreadReference thread, ObjectReference methodExecution, int callLineNo) { + public CallStackModel(VirtualMachine vm, ThreadReference thread, ObjectReference methodExecution, String threadId, int callLineNo) { methodExecutionMc = new JDIInstanceMethodCaller(vm, thread, methodExecution); this.callLineNo = callLineNo; } @@ -36,6 +37,10 @@ return methodExecutionMc; } + public String getThreadId() { + return threadId; + } + public int getCallLineNo() { return callLineNo; } diff --git a/org.ntlab.reverseDebugger/src/org/ntlab/reverseDebugger/CallStackModels.java b/org.ntlab.reverseDebugger/src/org/ntlab/reverseDebugger/CallStackModels.java index d516d6a..c7d6956 100644 --- a/org.ntlab.reverseDebugger/src/org/ntlab/reverseDebugger/CallStackModels.java +++ b/org.ntlab.reverseDebugger/src/org/ntlab/reverseDebugger/CallStackModels.java @@ -1,60 +1,79 @@ package org.ntlab.reverseDebugger; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; - +import java.util.Map; import org.eclipse.jface.viewers.TreeNode; import org.ntlab.onlineAccessor.JDIInstanceMethodCaller; import org.ntlab.onlineAccessor.JDIStaticMethodCaller; - +import com.sun.jdi.BooleanValue; import com.sun.jdi.ClassNotLoadedException; import com.sun.jdi.IncompatibleThreadStateException; import com.sun.jdi.IntegerValue; import com.sun.jdi.InvalidTypeException; import com.sun.jdi.InvocationException; import com.sun.jdi.ObjectReference; +import com.sun.jdi.StringReference; import com.sun.jdi.ThreadReference; +import com.sun.jdi.Value; import com.sun.jdi.VirtualMachine; @SuppressWarnings("restriction") public class CallStackModels { - private List callStackModels = new ArrayList<>(); + private String debuggingThreadId = ""; + private List debuggingThreadCallStacks = new ArrayList<>(); + private Map> allCallStacks = new HashMap<>(); + private static final String TRACE = "org.ntlab.traceAnalysisPlatform.tracer.trace"; - public List getCallStackModels() { - return callStackModels; + public List getDebuggingThreadCallStacks() { + return debuggingThreadCallStacks; } - public TreeNode[] getCallStackModelsTreeNodes() { - TreeNode[] roots = new TreeNode[1]; - if (callStackModels.isEmpty()) { - return roots; + public TreeNode[] getAllCallStacksTree() { + TreeNode[] roots = new TreeNode[allCallStacks.size()]; + int rootIndex = 0; + for (String threadId : allCallStacks.keySet()) { + TreeNode node = getCallStackModelsTree(threadId); + roots[rootIndex++] = node; } - CallStackModel callStackModel = callStackModels.get(0); - roots[0] = new TreeNode(new JDIStaticMethodCaller(callStackModel.getVm(), callStackModel.getThread())); - TreeNode parentNode = roots[0]; - TreeNode[] childrenNode = new TreeNode[callStackModels.size()]; + return roots; + } + + public TreeNode getCallStackModelsTree(String threadId) { + List callStackModelsInThread = allCallStacks.get(threadId); + if (callStackModelsInThread.isEmpty()) return null; + TreeNode root = new TreeNode(threadId); + TreeNode parentNode = root; + TreeNode[] childrenNode = new TreeNode[callStackModelsInThread.size()]; parentNode.setChildren(childrenNode); - for (int i = 0; i < callStackModels.size(); i++) { - TreeNode childNode = new TreeNode(callStackModels.get(i)); + for (int i = 0; i < callStackModelsInThread.size(); i++) { + TreeNode childNode = new TreeNode(callStackModelsInThread.get(i)); childNode.setParent(parentNode); childrenNode[i] = childNode; } + return root; + } + + public TreeNode[] getDebugingThreadCallStacksTree() { + TreeNode[] roots = new TreeNode[1]; + roots[0] = getCallStackModelsTree(debuggingThreadId); return roots; } public void reset() { - callStackModels.clear(); + debuggingThreadId = ""; + debuggingThreadCallStacks.clear(); + allCallStacks.clear(); } public void updateByDebuggerStopMethodExecution(JDIInstanceMethodCaller me) { - if (me == null) { - return; - } + if (me == null) return; try { VirtualMachine vm = me.getVm(); ThreadReference thread = me.getThread(); int lineNo = thread.frame(0).location().lineNumber(); - update(vm, thread, me.getReceiver(), lineNo); + updateInAllThreads(vm, thread, me.getReceiver(), lineNo); } catch (InvalidTypeException | ClassNotLoadedException | InvocationException | IncompatibleThreadStateException e) { e.printStackTrace(); @@ -62,36 +81,144 @@ } public void updateByAlias(JDIInstanceMethodCaller alias) { - if (alias == null) { - return; - } + if (alias == null) return; VirtualMachine vm = alias.getVm(); ThreadReference thread = alias.getThread(); try { ObjectReference me = (ObjectReference)alias.callInstanceMethod("getMethodExecution"); int lineNo = ((IntegerValue)alias.callInstanceMethod("getLineNo")).value(); - update(vm, thread, me, lineNo); + updateInAllThreads(vm, thread, me, lineNo); } catch (InvalidTypeException | ClassNotLoadedException | InvocationException | IncompatibleThreadStateException e) { e.printStackTrace(); } } - - private void update(VirtualMachine vm, ThreadReference thread, ObjectReference me, int topMethodCallLineNo) + + private void updateInAllThreads(VirtualMachine vm, ThreadReference thread, ObjectReference me, int topMethodCallLineNo) throws InvalidTypeException, ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { - callStackModels.clear(); - ObjectReference childMe = null; + JDIInstanceMethodCaller mc = new JDIInstanceMethodCaller(vm, thread, null); + mc.changeReceiver(me); + ObjectReference statements = (ObjectReference)mc.callInstanceMethod("getStatements"); + mc.changeReceiver(statements); + int lastIndex = ((IntegerValue)mc.callInstanceMethod("size")).value() - 1; + mc.changeReceiver(me); + ObjectReference tp = (ObjectReference)mc.callInstanceMethod("getTracePoint", vm.mirrorOf(lastIndex)); + mc.changeReceiver(tp); + ObjectReference tpStatement = (ObjectReference)mc.callInstanceMethod("getStatement"); + mc.changeReceiver(tpStatement); + + reset(); + debuggingThreadId = ((StringReference)mc.callInstanceMethod("getThreadNo")).value(); + debuggingThreadCallStacks = update(vm, thread, me, debuggingThreadId, topMethodCallLineNo); + allCallStacks.put(debuggingThreadId, debuggingThreadCallStacks); + Value visitor = getVisitor(vm, thread, tp); + updateOtherThreadCallStacks(vm, thread, visitor); + } + + private List update(VirtualMachine vm, ThreadReference thread, ObjectReference me, String threadId, int topMethodCallLineNo) + throws InvalidTypeException, ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + List list = new ArrayList<>(); + JDIInstanceMethodCaller mc = new JDIInstanceMethodCaller(vm, thread, null); int callLineNo = topMethodCallLineNo; - while (me != null) { - CallStackModel callStackModel = new CallStackModel(vm, thread, me, callLineNo); - callStackModels.add(callStackModel); - childMe = me; - me = (ObjectReference)callStackModel.callInstanceMethod("getParent"); - if (me != null) { - JDIInstanceMethodCaller mc = new JDIInstanceMethodCaller(vm, thread, me); + ObjectReference childMe = null; + ObjectReference tmpMe = me; + while (tmpMe != null) { + CallStackModel callStackModel = new CallStackModel(vm, thread, tmpMe, threadId, callLineNo); + list.add(callStackModel); + childMe = tmpMe; + tmpMe = (ObjectReference)callStackModel.callInstanceMethod("getParent"); + if (tmpMe != null) { + mc.changeReceiver(tmpMe); ObjectReference callStatement = (ObjectReference)mc.callInstanceMethod("getMethodInvocation", childMe); callLineNo = ((IntegerValue)mc.changeReceiver(callStatement).callInstanceMethod("getLineNo")).value(); } } - } -} + return list; + } + + private void updateOtherThreadCallStacks(VirtualMachine vm, ThreadReference thread, Value visitor) { + try { + JDIInstanceMethodCaller mc = new JDIInstanceMethodCaller(vm, thread, null); + ObjectReference traceJSON = (ObjectReference)mc.callStaticMethod(TRACE, "TraceJSON", "getInstance"); + mc.changeReceiver(traceJSON); ObjectReference allThreads = (ObjectReference)mc.callInstanceMethod("getAllThreads"); + mc.changeReceiver(allThreads); ObjectReference keySet = (ObjectReference)mc.callInstanceMethod("keySet"); + mc.changeReceiver(keySet); ObjectReference iterator = (ObjectReference)mc.callInstanceMethod("iterator"); + mc.changeReceiver(iterator); boolean hasNext = ((BooleanValue)mc.callInstanceMethod("hasNext")).value(); + while (hasNext) { + StringReference threadId = (StringReference)mc.callInstanceMethod("next"); + if (threadId.value().equals(debuggingThreadId)) continue; + + ObjectReference start = getStart(vm, thread, allThreads, threadId); + mc.changeReceiver(traceJSON); + mc.callInstanceMethod("getLastStatementInThread", threadId, start, visitor); + ObjectReference resultTp = (ObjectReference)mc.callStaticMethod("java.lang.reflect", "Array", "get", start, vm.mirrorOf(0)); + updateOtherThreadCallStacks(vm, thread, threadId.value(), resultTp); + + mc.changeReceiver(iterator); + hasNext = ((BooleanValue)mc.callInstanceMethod("hasNext")).value(); + } + } catch (InvalidTypeException | ClassNotLoadedException + | InvocationException | IncompatibleThreadStateException e) { + e.printStackTrace(); + } + } + + private void updateOtherThreadCallStacks(VirtualMachine vm, ThreadReference thread, String threadId, ObjectReference tp) + throws InvalidTypeException, ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + JDIInstanceMethodCaller mc = new JDIInstanceMethodCaller(vm, thread, null); + mc.changeReceiver(tp); + ObjectReference me = (ObjectReference)mc.callInstanceMethod("getMethodExecution"); + mc.changeReceiver(me); + ObjectReference statements = (ObjectReference)mc.callInstanceMethod("getStatements"); + mc.changeReceiver(statements); + int lastIndex = ((IntegerValue)mc.callInstanceMethod("size")).value() - 1; + ObjectReference lastStatement = (ObjectReference)mc.callInstanceMethod("get", vm.mirrorOf(lastIndex)); + mc.changeReceiver(lastStatement); + int lineNo = ((IntegerValue)mc.callInstanceMethod("getLineNo")).value(); + allCallStacks.put(threadId, update(vm, thread, me, threadId, lineNo)); + } + + private ObjectReference getVisitor(VirtualMachine vm, ThreadReference thread, ObjectReference tp) + throws InvalidTypeException, ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + JDIInstanceMethodCaller mc = new JDIInstanceMethodCaller(vm, thread, null); + +// // visitor (�R���X�g���N�^�̈������Ȃ��ꍇ) +// ObjectReference clazz = (ObjectReference)mc.callStaticMethod( +// "java.lang", "Class", "forName", vm.mirrorOf("org.ntlab.reverseDebugger.CallStackVisitor")); +// mc.changeReceiver(clazz); +// ObjectReference visitor = (ObjectReference)mc.callInstanceMethod("newInstance"); + + // visitor (�R���X�g���N�^�Ɉ���������ꍇ) + ObjectReference visitorClass = (ObjectReference)mc.callStaticMethod( + "java.lang", "Class", "forName", vm.mirrorOf("org.ntlab.reverseDebugger.CallStackVisitor")); + ObjectReference classClass = (ObjectReference)mc.callStaticMethod( + "java.lang", "Class", "forName", vm.mirrorOf("java.lang.Class")); + ObjectReference classClassArray = (ObjectReference)mc.callStaticMethod("java.lang.reflect", "Array", "newInstance", classClass, vm.mirrorOf(1)); // �������•ϒ��̃��\�b�h��JDI�ŌĂяo���ۂ́A����1�‚ł��z��ɂ��Ȃ��ƃG���[���o�� + mc.changeReceiver(tp); + ObjectReference tpClass = (ObjectReference)mc.callInstanceMethod("getClass"); + mc.callStaticMethod("java.lang.reflect", "Array", "set", classClassArray, vm.mirrorOf(0), tpClass); + mc.changeReceiver(visitorClass); + ObjectReference constructor = (ObjectReference)mc.callInstanceMethod("getConstructor", classClassArray); + ObjectReference tpClassArray = (ObjectReference)mc.callStaticMethod("java.lang.reflect", "Array", "newInstance", tpClass, vm.mirrorOf(1)); // �������•ϒ��̃��\�b�h��JDI�ŌĂяo���ۂ́A����1�‚ł��z��ɂ��Ȃ��ƃG���[���o�� + mc.callStaticMethod("java.lang.reflect", "Array", "set", tpClassArray, vm.mirrorOf(0), tp); + mc.changeReceiver(constructor); + ObjectReference visitor = (ObjectReference)mc.callInstanceMethod("newInstance", tpClassArray); + return visitor; + } + + private ObjectReference getStart(VirtualMachine vm, ThreadReference thread, ObjectReference allThreads, StringReference threadId) + throws InvalidTypeException, ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + JDIInstanceMethodCaller mc = new JDIInstanceMethodCaller(vm, thread, null); + + // start + mc.changeReceiver(allThreads); + ObjectReference threadInstance = (ObjectReference)mc.callInstanceMethod("get", threadId); + mc.changeReceiver(threadInstance); + ObjectReference currentTp = (ObjectReference)mc.callInstanceMethod("getCurrentTracePoint"); + mc.changeReceiver(currentTp); + ObjectReference currentTpClass = (ObjectReference)mc.callInstanceMethod("getClass"); + ObjectReference start = (ObjectReference)mc.callStaticMethod("java.lang.reflect", "Array", "newInstance", currentTpClass, vm.mirrorOf(1)); + mc.callStaticMethod("java.lang.reflect", "Array", "set", start, vm.mirrorOf(0), currentTp); + return start; + } +} \ No newline at end of file diff --git a/org.ntlab.reverseDebugger/src/org/ntlab/reverseDebugger/CallStackView.java b/org.ntlab.reverseDebugger/src/org/ntlab/reverseDebugger/CallStackView.java index 1aa814d..d0ac8a6 100644 --- a/org.ntlab.reverseDebugger/src/org/ntlab/reverseDebugger/CallStackView.java +++ b/org.ntlab.reverseDebugger/src/org/ntlab/reverseDebugger/CallStackView.java @@ -97,12 +97,12 @@ } public void refresh() { - if (callStackModels.getCallStackModels().isEmpty()) { + if (callStackModels.getDebuggingThreadCallStacks().isEmpty()) { SeedAliasView seedAliasView = ((SeedAliasView)getOtherView(SeedAliasView.ID)); JDIInstanceMethodCaller currentMe = seedAliasView.getDebuggingMethodExecution(); callStackModels.updateByDebuggerStopMethodExecution(currentMe); } - TreeNode[] nodes = callStackModels.getCallStackModelsTreeNodes(); + TreeNode[] nodes = callStackModels.getAllCallStacksTree(); if (nodes == null || nodes[0] == null) { return; } diff --git a/org.ntlab.reverseDebugger/src/org/ntlab/reverseDebugger/CallStackVisitor.java b/org.ntlab.reverseDebugger/src/org/ntlab/reverseDebugger/CallStackVisitor.java new file mode 100644 index 0000000..605a664 --- /dev/null +++ b/org.ntlab.reverseDebugger/src/org/ntlab/reverseDebugger/CallStackVisitor.java @@ -0,0 +1,32 @@ +package org.ntlab.reverseDebugger; + +import org.ntlab.traceAnalysisPlatform.tracer.trace.IStatementVisitor; +import org.ntlab.traceAnalysisPlatform.tracer.trace.MethodInvocation; +import org.ntlab.traceAnalysisPlatform.tracer.trace.Statement; +import org.ntlab.traceAnalysisPlatform.tracer.trace.TracePoint; + +public class CallStackVisitor implements IStatementVisitor { + private TracePoint before = null; + + public CallStackVisitor() { + + } + + public CallStackVisitor(TracePoint before) { + this.before = before; + } + + @Override + public boolean preVisitStatement(Statement statement) { + System.out.println("CallStackVisitor#preVisitStatement(Statement)"); + if (!(statement instanceof MethodInvocation)) return false; + if (before == null) return true; + MethodInvocation mi = (MethodInvocation)statement; + return (mi.getTimeStamp() < before.getStatement().getTimeStamp()); + } + + @Override + public boolean postVisitStatement(Statement statement) { + return false; + } +}