diff --git a/org.ntlab.reverseDebugger/.settings/CVS/Entries b/org.ntlab.reverseDebugger/.settings/CVS/Entries new file mode 100644 index 0000000..3f96714 --- /dev/null +++ b/org.ntlab.reverseDebugger/.settings/CVS/Entries @@ -0,0 +1 @@ +/org.eclipse.jdt.core.prefs/1.2/Wed Dec 9 07:18:21 2015// diff --git a/org.ntlab.reverseDebugger/.settings/CVS/Repository b/org.ntlab.reverseDebugger/.settings/CVS/Repository new file mode 100644 index 0000000..f9ae7d0 --- /dev/null +++ b/org.ntlab.reverseDebugger/.settings/CVS/Repository @@ -0,0 +1 @@ +org.ntlab.debuggingControl/.settings diff --git a/org.ntlab.reverseDebugger/.settings/CVS/Root b/org.ntlab.reverseDebugger/.settings/CVS/Root new file mode 100644 index 0000000..6041112 --- /dev/null +++ b/org.ntlab.reverseDebugger/.settings/CVS/Root @@ -0,0 +1 @@ +:pserver:n-nitta@nitta-lab-www.is.konan-u.ac.jp:\CVSProject diff --git a/org.ntlab.reverseDebugger/META-INF/CVS/Entries b/org.ntlab.reverseDebugger/META-INF/CVS/Entries new file mode 100644 index 0000000..8b3db2a --- /dev/null +++ b/org.ntlab.reverseDebugger/META-INF/CVS/Entries @@ -0,0 +1 @@ +/MANIFEST.MF/1.1/Wed Dec 9 07:11:31 2015// diff --git a/org.ntlab.reverseDebugger/META-INF/CVS/Repository b/org.ntlab.reverseDebugger/META-INF/CVS/Repository new file mode 100644 index 0000000..0ad0de2 --- /dev/null +++ b/org.ntlab.reverseDebugger/META-INF/CVS/Repository @@ -0,0 +1 @@ +org.ntlab.debuggingControl/META-INF diff --git a/org.ntlab.reverseDebugger/META-INF/CVS/Root b/org.ntlab.reverseDebugger/META-INF/CVS/Root new file mode 100644 index 0000000..6041112 --- /dev/null +++ b/org.ntlab.reverseDebugger/META-INF/CVS/Root @@ -0,0 +1 @@ +:pserver:n-nitta@nitta-lab-www.is.konan-u.ac.jp:\CVSProject diff --git a/org.ntlab.reverseDebugger/plugin.xml b/org.ntlab.reverseDebugger/plugin.xml index c7729d6..124c048 100644 --- a/org.ntlab.reverseDebugger/plugin.xml +++ b/org.ntlab.reverseDebugger/plugin.xml @@ -15,5 +15,41 @@ + + + + + + + + + + + + + + diff --git a/org.ntlab.reverseDebugger/src/org/ntlab/debuggingControl/DebuggingControlAction.java b/org.ntlab.reverseDebugger/src/org/ntlab/debuggingControl/DebuggingControlAction.java index 5db785d..24d1471 100644 --- a/org.ntlab.reverseDebugger/src/org/ntlab/debuggingControl/DebuggingControlAction.java +++ b/org.ntlab.reverseDebugger/src/org/ntlab/debuggingControl/DebuggingControlAction.java @@ -32,6 +32,7 @@ import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.IWorkbenchWindowActionDelegate; import org.eclipse.ui.PartInitException; +import org.ntlab.reversedebugger.ObjectFlowAliases; import com.sun.jdi.AbsentInformationException; import com.sun.jdi.BooleanValue; @@ -60,7 +61,7 @@ import com.sun.jdi.VirtualMachine; public class DebuggingControlAction implements IWorkbenchWindowActionDelegate { - + @Override public void run(IAction arg0) { // TODO Auto-generated method stub @@ -164,7 +165,7 @@ // printCallTreeDataFromRoot(vm, thread, threadInstance); // �I�����C����͒���traceCollector��TraceJSON#getObjectFlow()���Ăяo�����̃R�[�h - printObjectFlow(vm, thread, threadInstance); +// printObjectFlow(vm, thread, threadInstance); } /** @@ -218,34 +219,44 @@ int aliasNo = scanner.nextInt(); methodName = "get"; Value startAlias = callInstanceMethod(vm, thread, methodName, (ObjectReference)startAliasList, vm.mirrorOf(aliasNo)); - methodName = "toString"; - Value str = callInstanceMethod(vm, thread, methodName, (ObjectReference)startAlias); - printValue("", "", str, true); - methodName = "getObjectFlow"; - Value aliasLists = callStaticMethod(vm, thread, packageName, className, methodName, startAlias); - System.out.println(); - // �擾�������X�g�̒��g�����[�v�ʼn񂵂Ȃ���m�F��, �‚��łɓ��Y�\�[�X�t�@�C����Ώ�Eclipse�ŊJ�����Ă݂� - methodName = "size"; - int aliasListsSize = ((IntegerValue)callInstanceMethod(vm, thread, methodName, (ObjectReference)aliasLists)).value(); - for (int i = 0; i < aliasListsSize; i++) { - System.out.println("---------------------------------------------"); - System.out.println("���X�g" + i); - methodName = "get"; - Value aliasList = callInstanceMethod(vm, thread, methodName,(ObjectReference)aliasLists, vm.mirrorOf(i)); - methodName = "size"; - int aliasListSize = ((IntegerValue)callInstanceMethod(vm, thread, methodName, (ObjectReference)aliasList)).value(); - for (int j = 0; j < aliasListSize; j++) { - methodName = "get"; - Value alias = callInstanceMethod(vm, thread, methodName, (ObjectReference)aliasList, vm.mirrorOf(j)); - methodName = "toString"; - Value str2 = callInstanceMethod(vm, thread, methodName, (ObjectReference)alias); - printValue("", "", str2, true); - methodName = "getMethodExecution"; - Value aliasMethodExecution = callInstanceMethod(vm ,thread, methodName, (ObjectReference)alias); - openSrcFileOfMethodExecution(vm, thread, aliasMethodExecution); - } - } +// // DebuggingControl������GUI�֘A�̃N���X�̕��ɖ�����V�[�h�G�C���A�X��n���ăI�u�W�F�N�g�t���[�����s���Ă݂� +// // �ꎞ�I�Ȃ��̂�, �ŏI�I�ɂ͂����ł�鏈���ł͂Ȃ��Ȃ�̂ŕs�v�ɂȂ�͂� +// ObjectFlowAliases.getInstance().getObjectFlow(new MethodCaller(vm, thread, (ObjectReference)startAlias)); + + // �ȉ��͈ꎞ�I�ɃR�����g�A�E�g���Ă��� +// methodName = "toString"; +// Value str = callInstanceMethod(vm, thread, methodName, (ObjectReference)startAlias); +// printValue("", "", str, true); +// methodName = "getObjectFlow"; +// Value aliasLists = callStaticMethod(vm, thread, packageName, className, methodName, startAlias); +// System.out.println(); +// +// // �擾�������X�g�̒��g�����[�v�ʼn񂵂Ȃ���m�F��, �‚��łɓ��Y�\�[�X�t�@�C����Ώ�Eclipse�ŊJ�����Ă݂� +// methodName = "size"; +// int aliasListsSize = ((IntegerValue)callInstanceMethod(vm, thread, methodName, (ObjectReference)aliasLists)).value(); +// List> objectFlowAliasLists = new ArrayList<>(); +// for (int i = 0; i < aliasListsSize; i++) { +// List objectFlowAliasList = new ArrayList<>(); +// objectFlowAliasLists.add(objectFlowAliasList); +// System.out.println("---------------------------------------------"); +// System.out.println("���X�g" + i); +// methodName = "get"; +// Value aliasList = callInstanceMethod(vm, thread, methodName,(ObjectReference)aliasLists, vm.mirrorOf(i)); +// methodName = "size"; +// int aliasListSize = ((IntegerValue)callInstanceMethod(vm, thread, methodName, (ObjectReference)aliasList)).value(); +// for (int j = 0; j < aliasListSize; j++) { +// methodName = "get"; +// Value alias = callInstanceMethod(vm, thread, methodName, (ObjectReference)aliasList, vm.mirrorOf(j)); +// methodName = "toString"; +// Value str2 = callInstanceMethod(vm, thread, methodName, (ObjectReference)alias); +// printValue("", "", str2, true); +// methodName = "getMethodExecution"; +// Value aliasMethodExecution = callInstanceMethod(vm ,thread, methodName, (ObjectReference)alias); +// openSrcFileOfMethodExecution(vm, thread, aliasMethodExecution); +// objectFlowAliasList.add(new MethodCaller(vm, thread, (ObjectReference)alias)); +// } +// } } /** diff --git a/org.ntlab.reverseDebugger/src/org/ntlab/debuggingControl/MethodCaller.java b/org.ntlab.reverseDebugger/src/org/ntlab/debuggingControl/MethodCaller.java new file mode 100644 index 0000000..8ed4e37 --- /dev/null +++ b/org.ntlab.reverseDebugger/src/org/ntlab/debuggingControl/MethodCaller.java @@ -0,0 +1,93 @@ +package org.ntlab.debuggingControl; + +import java.util.Arrays; +import java.util.List; + +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.ClassType; +import com.sun.jdi.IncompatibleThreadStateException; +import com.sun.jdi.InvalidTypeException; +import com.sun.jdi.InvocationException; +import com.sun.jdi.LongValue; +import com.sun.jdi.Method; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.StringReference; +import com.sun.jdi.ThreadReference; +import com.sun.jdi.Value; +import com.sun.jdi.VirtualMachine; + +public class MethodCaller { + private VirtualMachine vm; + private ThreadReference thread; + private ObjectReference obj; + + public MethodCaller(VirtualMachine vm, ThreadReference thread) { + this.vm = vm; + this.thread = thread; + } + + public MethodCaller(VirtualMachine vm, ThreadReference thread, ObjectReference obj) { + this(vm, thread); + this.obj = obj; + } + + public VirtualMachine getVm() { + return vm; + } + + public ThreadReference getThread() { + return thread; + } + + public ObjectReference getObj() { + return obj; + } + + public long getThreadId() { + MethodCaller mc = new MethodCaller(vm, thread, thread); + try { + return ((LongValue)mc.callInstanceMethod("getId")).value(); + } catch (InvalidTypeException | ClassNotLoadedException + | InvocationException | IncompatibleThreadStateException e) { + e.printStackTrace(); + } + throw new IllegalStateException(); + } + + public MethodCaller setObj(ObjectReference obj) { + this.obj = obj; + return this; + } + + /** + * �p�b�P�[�W���ƃN���X���ƃ��\�b�h���ƈ������w�肵�Ă��̃N���X���\�b�h���Ăяo�� + * @param packageName �Ăт����������\�b�h������N���X�̃p�b�P�[�W�� + * @param className �Ăяo���������\�b�h������N���X�� + * @param methodName �Ăяo���������\�b�h�� (static) + * @param args �Ăяo���������\�b�h�ɓn������(Value �̃N���X�^�ʼn•ϒ�) + * @return �Ăяo�������\�b�h����̖߂�l(Value) + */ + public Value callStaticMethod(String packageName, String className, String methodName, Value... args) + throws InvalidTypeException, ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + List classes = vm.classesByName(packageName + "." + className); // �N���X�� (���S���薼) + ClassType type = (ClassType)classes.get(0); + List methodsByName = type.methodsByName(methodName); + List argList = Arrays.asList(args); // ���\�b�h�ɓn�������̃��X�g + return type.invokeMethod(thread, methodsByName.get(0), argList, thread.INVOKE_SINGLE_THREADED); // �f�o�b�O���̃v���O�������̃��\�b�h���Ăяo�� + } + + /** + * ���\�b�h����ObjectReference�ƈ������w�肵�Ă��̃I�u�W�F�N�g�̃C���X�^���X���\�b�h���Ăяo�� + * @param methodName �Ăяo���������\�b�h�� + * @param args �Ăяo���������\�b�h�ɓn������(Value �̃N���X�^�ʼn•ϒ�) + * @return �Ăяo�������\�b�h����̖߂�l(Value) + */ + public Value callInstanceMethod(String methodName, Value... args) + throws InvalidTypeException, ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + ClassType type = (ClassType)obj.type(); + List methodsByName = type.methodsByName(methodName); + List argList = Arrays.asList(args); // ���\�b�h�ɓn�������̃��X�g + return obj.invokeMethod(thread, methodsByName.get(0), argList, thread.INVOKE_SINGLE_THREADED); // �f�o�b�O���̃v���O�������̃��\�b�h���Ăяo�� + } +} diff --git a/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/CallStackLabelProvider.java b/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/CallStackLabelProvider.java new file mode 100644 index 0000000..de53070 --- /dev/null +++ b/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/CallStackLabelProvider.java @@ -0,0 +1,47 @@ +package org.ntlab.reversedebugger; + +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.TreeNode; +import org.eclipse.swt.graphics.Image; +import org.eclipse.ui.ISharedImages; +import org.eclipse.ui.PlatformUI; +import org.ntlab.debuggingControl.MethodCaller; + +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.IncompatibleThreadStateException; +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; + +public class CallStackLabelProvider extends LabelProvider { + + @Override + public String getText(Object element) { + if (element instanceof TreeNode) { + Object value = ((TreeNode)element).getValue(); + if (value instanceof MethodCaller) { + MethodCaller mc = (MethodCaller)value; + return "ThreadID: " + mc.getThreadId(); + } + if (value instanceof CallStackModel) { + CallStackModel callStackModel = (CallStackModel)value; + StringBuilder text = new StringBuilder(); + text.append(callStackModel.getSignature()); + text.append(" line: "); + text.append(callStackModel.getCallLineNo()); + return text.toString(); + } + } + return ""; + } + + @Override + public Image getImage(Object element) { + if (element instanceof TreeNode) { + return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_ELEMENT); + } + return null; + } +} diff --git a/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/CallStackModel.java b/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/CallStackModel.java new file mode 100644 index 0000000..86040d9 --- /dev/null +++ b/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/CallStackModel.java @@ -0,0 +1,83 @@ +package org.ntlab.reversedebugger; + +import org.ntlab.debuggingControl.MethodCaller; + +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; + +public class CallStackModel { + private ObjectReference methodExecution; +// private ObjectReference childMethodExecution; + private MethodCaller methodExecutionMc; + private int callLineNo; + +// public CallStackModel(VirtualMachine vm, ThreadReference thread, ObjectReference methodExecution, ObjectReference childMethodExecution) { +// methodExecutionMc = new MethodCaller(vm, thread, methodExecution); +// this.methodExecution = methodExecution; +// this.childMethodExecution = childMethodExecution; +// } + + public CallStackModel(VirtualMachine vm, ThreadReference thread, ObjectReference methodExecution, int callLineNo) { + methodExecutionMc = new MethodCaller(vm, thread, methodExecution); + this.methodExecution = methodExecution; + this.callLineNo = callLineNo; +// this.childMethodExecution = childMethodExecution; + } + + + public VirtualMachine getVm() { + return methodExecutionMc.getVm(); + } + + public ThreadReference getThread() { + return methodExecutionMc.getThread(); + } + + public MethodCaller getMethodCaller() { + return methodExecutionMc; + } + + public int getCallLineNo() { + return callLineNo; + } + +// public int getCallLineNo() { +// if (childMethodExecution == null) { +// return -1; +// } +// int callLineNo = -1; +// try { +// ObjectReference callStatement = (ObjectReference)methodExecutionMc.callInstanceMethod("getMethodInvocation", childMethodExecution); +// MethodCaller callStatementMc = new MethodCaller(methodExecutionMc.getVm(), methodExecutionMc.getThread(), callStatement); +// callLineNo = ((IntegerValue)callStatementMc.callInstanceMethod("getLineNo")).value(); +// } catch (InvalidTypeException | ClassNotLoadedException +// | InvocationException | IncompatibleThreadStateException e) { +// e.printStackTrace(); +// } +// return callLineNo; +// } + + public String getSignature() { + String signature = ""; + try { + signature = ((StringReference)methodExecutionMc.callInstanceMethod("getSignature")).value(); + } catch (InvalidTypeException | ClassNotLoadedException + | InvocationException | IncompatibleThreadStateException e) { + e.printStackTrace(); + } + return signature; + } + + public Value callInstanceMethod(String methodName, Value... args) + throws InvalidTypeException, ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + return methodExecutionMc.callInstanceMethod(methodName, args); + } +} diff --git a/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/CallStackModels.java b/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/CallStackModels.java new file mode 100644 index 0000000..971ae7a --- /dev/null +++ b/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/CallStackModels.java @@ -0,0 +1,97 @@ +package org.ntlab.reversedebugger; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jface.viewers.TreeNode; +import org.ntlab.debuggingControl.MethodCaller; + +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.ThreadReference; +import com.sun.jdi.Value; +import com.sun.jdi.VirtualMachine; +import com.sun.jdi.event.MethodEntryEvent; + +public class CallStackModels { + private List callStackModels = new ArrayList<>(); + + public List getCallStackModels() { + return callStackModels; + } + + public TreeNode[] getCallStackModelsTreeNodes() { + TreeNode[] roots = new TreeNode[1]; + if (callStackModels.isEmpty()) { + return roots; + } + CallStackModel callStackModel = callStackModels.get(0); + roots[0] = new TreeNode(new MethodCaller(callStackModel.getVm(), callStackModel.getThread())); + TreeNode parentNode = roots[0]; + TreeNode[] childrenNode = new TreeNode[callStackModels.size()]; + parentNode.setChildren(childrenNode); + for (int i = 0; i < callStackModels.size(); i++) { + TreeNode childNode = new TreeNode(callStackModels.get(i)); + childNode.setParent(parentNode); + childrenNode[i] = childNode; + } + return roots; + } + + public void reset() { + callStackModels.clear(); + } + + public void updateByDebuggerStopMethodExecution(MethodCaller me) { + if (me == null) { + return; + } + try { + VirtualMachine vm = me.getVm(); + ThreadReference thread = me.getThread(); + int lineNo = thread.frame(0).location().lineNumber(); + update(vm, thread, me.getObj(), lineNo); + } catch (InvalidTypeException | ClassNotLoadedException + | InvocationException | IncompatibleThreadStateException e) { + e.printStackTrace(); + } + } + + public void updateByAlias(MethodCaller alias) { + 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); + } catch (InvalidTypeException | ClassNotLoadedException + | InvocationException | IncompatibleThreadStateException e) { + e.printStackTrace(); + } + } + + private void update(VirtualMachine vm, ThreadReference thread, ObjectReference me, int topMethodCallLineNo) + throws InvalidTypeException, ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + callStackModels.clear(); + ObjectReference childMe = 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) { + MethodCaller mc = new MethodCaller(vm, thread, me); + ObjectReference callStatement = (ObjectReference)mc.callInstanceMethod("getMethodInvocation", childMe); + callLineNo = ((IntegerValue)mc.setObj(callStatement).callInstanceMethod("getLineNo")).value(); + } + } + } +} diff --git a/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/CallStackView.java b/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/CallStackView.java new file mode 100644 index 0000000..2c2ee60 --- /dev/null +++ b/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/CallStackView.java @@ -0,0 +1,107 @@ +package org.ntlab.reversedebugger; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.TreeNode; +import org.eclipse.jface.viewers.TreeNodeContentProvider; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.ISharedImages; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.part.ViewPart; +import org.ntlab.debuggingControl.MethodCaller; + +public class CallStackView extends ViewPart { + private static TreeViewer viewer; + private IAction refreshAction; + private static CallStackModels callStackModels = new CallStackModels(); + private JavaEditorOperator javaEditorOperator = new JavaEditorOperator(); + public static final String ID = "org.ntlab.reverseDebugger.callStackView"; + + public CallStackView() { + // TODO Auto-generated constructor stub + System.out.println("callStackView�N���X���������ꂽ��"); + } + + @Override + public void createPartControl(Composite parent) { + // TODO Auto-generated method stub + System.out.println("CallStackView#createPartControl(Composite)���Ă΂ꂽ��!"); + viewer = new TreeViewer(parent); + viewer.setContentProvider(new TreeNodeContentProvider()); + viewer.setLabelProvider(new CallStackLabelProvider()); + + // �I�������J�����ɑΉ����郁�\�b�h���s�̃\�[�X�t�@�C�����J�����郊�X�i�[��o�^���� + viewer.addSelectionChangedListener(new ISelectionChangedListener() { + @Override + public void selectionChanged(SelectionChangedEvent event) { + IStructuredSelection sel = (IStructuredSelection)event.getSelection(); + Object element = sel.getFirstElement(); + if (element instanceof TreeNode) { + Object value = ((TreeNode)element).getValue(); + if (value instanceof CallStackModel) { + MethodCaller methodExecution = ((CallStackModel)value).getMethodCaller(); + javaEditorOperator.openSrcFileOfMethodExecution(methodExecution); + } + } + } + }); + createActions(); + createToolBar(); + createMenuBar(); + } + + @Override + public void setFocus() { + // TODO Auto-generated method stub + viewer.getControl().setFocus(); + } + + private void createActions() { + refreshAction = new Action() { + @Override + public void run() { + refresh(); + } + }; + refreshAction.setText("refresh"); + refreshAction.setToolTipText("refresh"); + refreshAction.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_ELCL_SYNCED)); + } + + private void createToolBar() { + IToolBarManager mgr = getViewSite().getActionBars().getToolBarManager(); + mgr.add(refreshAction); + } + + private void createMenuBar() { + IMenuManager mgr = getViewSite().getActionBars().getMenuManager(); + mgr.add(refreshAction); + } + + public static void updateByAlias(MethodCaller alias) { + callStackModels.updateByAlias(alias); + } + + public static void refresh() { + if (callStackModels.getCallStackModels().isEmpty()) { + MethodCaller currentMe = SeedAliasView.getDebuggerStopMethodExecution(); + callStackModels.updateByDebuggerStopMethodExecution(currentMe); + } + TreeNode[] nodes = callStackModels.getCallStackModelsTreeNodes(); + if (nodes == null || nodes[0] == null) { + return; + } + viewer.setInput(callStackModels.getCallStackModelsTreeNodes()); + } + + public static void reset() { + callStackModels.reset(); + refresh(); + } +} diff --git a/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/JavaEditorOperator.java b/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/JavaEditorOperator.java new file mode 100644 index 0000000..33a603e --- /dev/null +++ b/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/JavaEditorOperator.java @@ -0,0 +1,219 @@ +package org.ntlab.reversedebugger; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IMethod; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.Signature; +import org.eclipse.jdt.ui.JavaUI; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.PartInitException; +import org.ntlab.debuggingControl.MethodCaller; + +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.IncompatibleThreadStateException; +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; + +public class JavaEditorOperator { + private static final String TRACE = "org.ntlab.traceCollector.tracer.trace"; + + public void openSrcFileOfAlias(MethodCaller alias) { + try { + ObjectReference methodExecution = (ObjectReference)alias.callInstanceMethod("getMethodExecution"); + MethodCaller meCaller = new MethodCaller(alias.getVm(), alias.getThread(), methodExecution); + openSrcFileOfMethodExecution(meCaller); + } catch (InvalidTypeException | ClassNotLoadedException + | InvocationException | IncompatibleThreadStateException e) { + e.printStackTrace(); + } + } + + /** + * �����œn����meCaller���ɂ���methodExecution����`����Ă���N���X�̃\�[�X�R�[�h��Ώ�Eclipse�̃G�f�B�^�ŊJ������ + * + * @param meCaller + */ + public void openSrcFileOfMethodExecution(MethodCaller meCaller) { + try { + IType type = findIType(meCaller); + if (type != null) { + IMethod method = findIMethod(meCaller, type); + if (method != null) { + openSrcFileOfIMethod(type, method); + } + } + } catch (InvalidTypeException | ClassNotLoadedException + | InvocationException | IncompatibleThreadStateException e) { + e.printStackTrace(); + } + } + + /** + * �����œn����IType��IMethod�ɑΉ�����\�[�X�R�[�h��Ώ�Eclipse�̃G�f�B�^�ŊJ������ + * + * @param type + * @param method + */ + private void openSrcFileOfIMethod(IType type, IMethod method) throws InvalidTypeException, ClassNotLoadedException, + InvocationException, IncompatibleThreadStateException { + openInJavaEditor(type, method); + } + + private IType findIType(MethodCaller meCaller) throws InvalidTypeException, + ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + StringReference declaringClassName = (StringReference)meCaller.callInstanceMethod("getDeclaringClassName"); + String projectPath = getLoaderPath(meCaller, declaringClassName); + IType type = null; + if (projectPath != null) { + IJavaProject javaProject = findJavaProject(projectPath); + if (javaProject != null) { + StringReference methodSignature = (StringReference)meCaller.callInstanceMethod("getSignature"); + try { + type = javaProject.findType(declaringClassName.value()); + } catch (JavaModelException e) { + e.printStackTrace(); + } + } + } + return type; + } + + private String getLoaderPath(MethodCaller meCaller, StringReference declaringClassName) + throws InvalidTypeException, ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + ObjectReference classInfo = (ObjectReference)meCaller.callStaticMethod(TRACE, "TraceJSON", "getClassInfo", declaringClassName); + if (classInfo == null) { + declaringClassName = (StringReference)meCaller.callInstanceMethod("getThisClassName"); + classInfo = (ObjectReference)meCaller.callStaticMethod(TRACE, "TraceJSON", "getClassInfo", declaringClassName); + } + String loaderPath = null; + if (classInfo != null) { + // �Ȃ���loaderPath���擾�ł��Ă��Ȃ����߁A���ۂɏo�͂����JSON�g���[�X���Q�l�ɂ���path����^���Ă݂� + MethodCaller classInfoMethodCaller = new MethodCaller(meCaller.getVm(), meCaller.getThread(), classInfo); + String path = ((StringReference)classInfoMethodCaller.callInstanceMethod("getPath")).value(); + String declaringClassNameString = declaringClassName.value().replace(".", "/"); + loaderPath = path.substring(0, path.indexOf(declaringClassNameString)); // path����N���X�̊��S���薼�ȍ~��S�ĊO�������̂�projectPath�ɂ��Ă݂� + } + return loaderPath; + } + + private IJavaProject findJavaProject(String projectPath) { + IJavaProject javaProject = null; + IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); + IProject[] projects = root.getProjects(); + for (IProject project : projects) { + if (checkProjectPath(project, projectPath)) { + javaProject = JavaCore.create(project); + break; + } + } + return javaProject; + } + + private boolean checkProjectPath(IProject project, String projectPath) { + String projectLocation = project.getLocation().toString(); + if (projectPath.startsWith(projectLocation)) { + String[] projectPathSplit = projectPath.split(projectLocation); + return (projectPathSplit[1].charAt(0) == '/'); // �v���W�F�N�g���̑O����v�ɂ�鑼�v���W�F�N�g�Ƃ̌딻�������� + } + return false; + } + + private void openInJavaEditor(IType type, IMethod method) { + try { + if (type != null && method != null) { + IEditorPart editor = JavaUI.openInEditor(type); + if (!type.isLocal() && !type.isMember()) { + JavaUI.revealInEditor(editor, (IJavaElement) method); + } + } + } catch (PartInitException | JavaModelException e) { + e.printStackTrace(); + } + } + + private IMethod findIMethod(MethodCaller meCaller, IType type) throws InvalidTypeException, + ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + IMethod method = null; + if (type != null) { + StringReference methodSignature = (StringReference)meCaller.callInstanceMethod("getSignature"); + method = findIMethod(type, methodSignature.value()); + } + return method; + } + + private IMethod findIMethod(IType type, String methodSignature) { + try { + for (IMethod method : type.getMethods()) { + if (checkMethodSignature(type, method, methodSignature)) { + return method; + } + } + } catch (JavaModelException e) { + e.printStackTrace(); + } + return null; + } + + private boolean checkMethodSignature(IType type, IMethod method, String methodSignature) { + String fqcn = type.getFullyQualifiedName(); + try { + StringBuilder jdtMethodSignature = new StringBuilder(); + jdtMethodSignature.append((method.isConstructor()) ? (fqcn + "(") : (fqcn + "." + method.getElementName() + "(")); + if (methodSignature.contains(jdtMethodSignature)) { + // ������v���Ă����ꍇ�Ɍ���A�������X�g����������ł���v���邩�ǂ����𔻒� (�I�[�o�[���[�h�ɂ��딻��������) + jdtMethodSignature.append(String.join(",", parseFQCNParameters(type, method)) + ")"); // �S�����̃V�O�l�`�������S����N���X���ɕϊ�����,�ŋ�؂��������� + return methodSignature.contains(jdtMethodSignature); + } + } catch (JavaModelException e) { + e.printStackTrace(); + } + return false; + } + + /** + * IMethod����擾�ł���S�����̃V�O�l�`�������S����N���X���ɒu�������Ċi�[�������X�g��Ԃ� + * + * @param type + * @param method + * @return + */ + private List parseFQCNParameters(IType type, IMethod method) throws JavaModelException { + List parameters = new ArrayList<>(); + for (String parameterType : method.getParameterTypes()) { + String readableType = Signature.toString(parameterType); // �V�O�l�`���̕�������^���̕�����ɕϊ� (�z��͌���[]���‚�) + String[] readableTypeSplit = { "", "" }; // �^����[]�̕����p + int firstBracketIndex = readableType.indexOf("[]"); + final int NO_BRACKET_INDEX = -1; + if (firstBracketIndex == NO_BRACKET_INDEX) { + readableTypeSplit[0] = readableType; // �^�� + } else { + readableTypeSplit[0] = readableType.substring(0, firstBracketIndex); // �^�� + readableTypeSplit[1] = readableType.substring(firstBracketIndex); // �^���̌���[]�S�� + } + String[][] resolveType = type.resolveType(readableTypeSplit[0]); // �p�b�P�[�W���ƃN���X���̑g�ݍ��킹���擾 + if (resolveType != null) { + if (resolveType[0][0].isEmpty()) { + readableTypeSplit[0] = (resolveType[0][1]); // �f�t�H���g�p�b�P�[�W�̏ꍇ�̓p�b�P�[�W����.�͓���Ȃ� + } else { + readableTypeSplit[0] = (resolveType[0][0] + "." + resolveType[0][1]); // ���S����N���X�� + } + } + parameters.add(readableTypeSplit[0] + readableTypeSplit[1]); + } + return parameters; + } +} diff --git a/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/ObjectFlowAliasLabelProvider.java b/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/ObjectFlowAliasLabelProvider.java new file mode 100644 index 0000000..035e55b --- /dev/null +++ b/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/ObjectFlowAliasLabelProvider.java @@ -0,0 +1,61 @@ +package org.ntlab.reversedebugger; + +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.swt.graphics.Image; +import org.eclipse.ui.ISharedImages; +import org.eclipse.ui.PlatformUI; +import org.ntlab.debuggingControl.MethodCaller; + +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; + +public class ObjectFlowAliasLabelProvider extends LabelProvider implements ITableLabelProvider { + + @Override + public String getColumnText(Object element, int columnIndex) { + if (element instanceof MethodCaller) { + MethodCaller mc = (MethodCaller)element; + if (mc.getObj() == null) { + return ""; + } + try { + switch (columnIndex) { + case 0: + return ((StringReference)mc.callInstanceMethod("getObjectId")).value(); + case 1: + return ((StringReference)mc.callInstanceMethod("getClassName")).value(); + case 2: + return ((StringReference)mc.callInstanceMethod("getMethodExecutionClassName")).value(); + case 3: + return String.valueOf(((IntegerValue)mc.callInstanceMethod("getLineNo")).value()); + case 4: + return ((StringReference)mc.callInstanceMethod("getStatementType")).value(); + case 5: + return ((StringReference)mc.callInstanceMethod("getStatementSignature")).value(); + case 6: + return ((StringReference)mc.callInstanceMethod("getOccurrenceText")).value(); + } + } catch (InvalidTypeException | ClassNotLoadedException + | InvocationException | IncompatibleThreadStateException e) { + e.printStackTrace(); + } + } + return "�e�X�g�p�e�L�X�g" + columnIndex; + } + + @Override + public Image getColumnImage(Object element, int columnIndex) { + return getImage(element); + } + + @Override + public Image getImage(Object element) { + return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_ELEMENT); + } +} diff --git a/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/ObjectFlowAliasView.java b/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/ObjectFlowAliasView.java new file mode 100644 index 0000000..e836290 --- /dev/null +++ b/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/ObjectFlowAliasView.java @@ -0,0 +1,174 @@ +package org.ntlab.reversedebugger; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IMenuListener; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.jface.viewers.ArrayContentProvider; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.ui.ISelectionListener; +import org.eclipse.ui.ISharedImages; +import org.eclipse.ui.IWorkbenchActionConstants; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.part.ViewPart; +import org.ntlab.debuggingControl.MethodCaller; + +public class ObjectFlowAliasView extends ViewPart { + private static TableViewer viewer; + private IAction refreshAction; + private IAction findSeedAliasesAction; + private MethodCaller selectObjectFlowAlias; + private static ObjectFlowAliases objectFlowAliases = new ObjectFlowAliases(); + private JavaEditorOperator javaEditorOperator = new JavaEditorOperator(); + public static final String ID = "org.ntlab.reverseDebugger.objectFlowAliasView"; + + public ObjectFlowAliasView() { + // TODO Auto-generated constructor stub + System.out.println("ObjectFlowView�N���X���������ꂽ��!"); + } + + @Override + public void createPartControl(Composite parent) { + // TODO Auto-generated method stub + System.out.println("ObjectFlowView#createPartControl(Composite)���Ă΂ꂽ��!"); + viewer = new TableViewer(parent, SWT.FULL_SELECTION); + Table table = viewer.getTable(); + table.setHeaderVisible(true); + table.setLinesVisible(true); + + // �e�[�u���̃J�������쐬 + String[] tableColumnTexts = {"objectID", "objectType", "srcFile", "lineNo", "statementType", "statementSignature", "occurrence"}; + int[] tableColumnWidth = {150, 160, 160, 80, 180, 300, 110}; + TableColumn[] tableColumns = new TableColumn[tableColumnTexts.length]; + for (int i = 0; i < tableColumns.length; i++) { + tableColumns[i] = new TableColumn(table, SWT.NULL); + tableColumns[i].setText(tableColumnTexts[i]); + tableColumns[i].setWidth(tableColumnWidth[i]); + } + viewer.setContentProvider(new ArrayContentProvider()); + viewer.setLabelProvider(new ObjectFlowAliasLabelProvider()); + viewer.setInput(objectFlowAliases.getObjectFlowSingleList(true)); + + // �I�������J�����ɑΉ�����G�C���A�X������郁�\�b�h���s���̑S�ẴV�[�h�G�C���A�X�̈ꗗ�𐶐����郊�X�i�[��o�^ +// viewer.addSelectionChangedListener(new ISelectionChangedListener() { +// @Override +// public void selectionChanged(SelectionChangedEvent event) { +// IStructuredSelection sel = (IStructuredSelection)event.getSelection(); +// Object element = sel.getFirstElement(); +// if (element instanceof MethodCaller) { +// MethodCaller alias = (MethodCaller)element; +// SeedAliasView.createSeedAliases(alias); +// SeedAliasView.refresh(); +// CallStackView.updateByAlias(alias); +// CallStackView.refresh(); +// javaEditorOperator.openSrcFileOfAlias(alias); +// } +// } +// }); + + viewer.addSelectionChangedListener(new ISelectionChangedListener() { + @Override + public void selectionChanged(SelectionChangedEvent event) { + IStructuredSelection sel = (IStructuredSelection)event.getSelection(); + Object element = sel.getFirstElement(); + if (element instanceof MethodCaller) { + selectObjectFlowAlias = (MethodCaller)element; + javaEditorOperator.openSrcFileOfAlias(selectObjectFlowAlias); + } + } + }); + + createActions(); + createToolBar(); + createMenuBar(); + createPopupMenu(); + } + + @Override + public void setFocus() { + // TODO Auto-generated method stub + viewer.getControl().setFocus(); +// viewer.setInput(objectFlowAliases.getObjectFlowSingleList(true)); + } + + private void createActions() { + refreshAction = new Action() { + @Override + public void run() { + refresh(); + } + }; + refreshAction.setText("refresh"); + refreshAction.setToolTipText("refresh"); + refreshAction.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_ELCL_SYNCED)); + + findSeedAliasesAction = new Action() { + @Override + public void run() { + findSeedAliases(); + } + }; + findSeedAliasesAction.setText("findSeedAliases"); + findSeedAliasesAction.setToolTipText("findSeedAliases"); + findSeedAliasesAction.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_OBJS_TASK_TSK)); + } + + private void createToolBar() { + IToolBarManager mgr = getViewSite().getActionBars().getToolBarManager(); + mgr.add(refreshAction); + } + + private void createMenuBar() { + IMenuManager mgr = getViewSite().getActionBars().getMenuManager(); + mgr.add(refreshAction); + } + + private void createPopupMenu() { + MenuManager menuMgr = new MenuManager("#PopupMenu"); + menuMgr.setRemoveAllWhenShown(true); + menuMgr.addMenuListener(new IMenuListener() { + @Override + public void menuAboutToShow(IMenuManager manager) { + manager.add(findSeedAliasesAction); + manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); + } + }); + Menu menu = menuMgr.createContextMenu(viewer.getControl()); + viewer.getControl().setMenu(menu); + getSite().registerContextMenu(menuMgr, viewer); + } + + public static void createObjectFlow(MethodCaller seedAlias) { + objectFlowAliases.createObjectFlow(seedAlias); + } + + private void findSeedAliases() { + SeedAliasView.createSeedAliases(selectObjectFlowAlias); + SeedAliasView.refresh(); + CallStackView.updateByAlias(selectObjectFlowAlias); + CallStackView.refresh(); + javaEditorOperator.openSrcFileOfAlias(selectObjectFlowAlias); + } + + public static void refresh() { + viewer.setInput(objectFlowAliases.getObjectFlowSingleList(true)); + } + + public static void reset() { + objectFlowAliases.reset(); + viewer.setInput(objectFlowAliases.getObjectFlowSingleList(true)); + } +} diff --git a/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/ObjectFlowAliases.java b/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/ObjectFlowAliases.java new file mode 100644 index 0000000..5b32580 --- /dev/null +++ b/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/ObjectFlowAliases.java @@ -0,0 +1,75 @@ +package org.ntlab.reversedebugger; + +import java.util.ArrayList; +import java.util.List; + +import org.ntlab.debuggingControl.MethodCaller; + +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.Value; +import com.sun.jdi.VirtualMachine; + +public class ObjectFlowAliases { + private List> objectFlowAliases = new ArrayList<>(); + private static final String TRACE = "org.ntlab.traceCollector.tracer.trace"; + + public void reset() { + objectFlowAliases.clear(); + } + + public List> getObjectFlow() { + return objectFlowAliases; + } + + public List> getObjectFlow(MethodCaller seedAlias) { + createObjectFlow(seedAlias); + return objectFlowAliases; + } + + public List getObjectFlowSingleList(boolean hasBound) { + List list = new ArrayList<>(); + for (int i = 0; i < objectFlowAliases.size(); i++) { + for (int j = 0; j < objectFlowAliases.get(i).size(); j++) { + list.add(objectFlowAliases.get(i).get(j)); + } + if (hasBound) { + list.add(new MethodCaller(null, null)); // ���E�p�̃_�~�[�C���X�^���X�𐶐����Ēlj� + } + } + return list; + } + + public List getObjectFlowSingleList(MethodCaller seedAlias, boolean hasBound) { + createObjectFlow(seedAlias); + return getObjectFlowSingleList(hasBound); + } + + public void createObjectFlow(MethodCaller seedAlias) { + MethodCaller mc = new MethodCaller(seedAlias.getVm(), seedAlias.getThread()); + objectFlowAliases.clear(); + try { + // �I�������G�C���A�X���N�_�ɃI�u�W�F�N�g�t���[���Ăяo���Č��ʂ����X�g�Ŏ󂯎�� + ObjectReference aliasListsReference = (ObjectReference)seedAlias.callStaticMethod(TRACE, "TraceJSON", "getObjectFlow", seedAlias.getObj()); + + // �擾�������X�g�̒��g�����[�v�ʼn񂵂Ȃ�����o��, �Ǘ��p�̃��X�g�ɋl�ߒ��� + int aliasListsSize = ((IntegerValue)mc.setObj(aliasListsReference).callInstanceMethod("size")).value(); + for (int i = 0; i < aliasListsSize; i++) { + List list = new ArrayList<>(); + objectFlowAliases.add(list); + ObjectReference aliasListReference = (ObjectReference)mc.setObj(aliasListsReference).callInstanceMethod("get", mc.getVm().mirrorOf(i)); + int aliasListSize = ((IntegerValue)mc.setObj(aliasListReference).callInstanceMethod("size")).value(); + for (int j = 0; j < aliasListSize; j++) { + ObjectReference aliasReference = (ObjectReference)mc.setObj(aliasListReference).callInstanceMethod("get", mc.getVm().mirrorOf(j)); + list.add(new MethodCaller(seedAlias.getVm(), seedAlias.getThread(), aliasReference)); + } + } + } catch (InvalidTypeException | ClassNotLoadedException | InvocationException | IncompatibleThreadStateException e) { + e.printStackTrace(); + } + } +} diff --git a/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/ReverseDebuggerPerspective.java b/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/ReverseDebuggerPerspective.java new file mode 100644 index 0000000..c3b5584 --- /dev/null +++ b/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/ReverseDebuggerPerspective.java @@ -0,0 +1,27 @@ +package org.ntlab.reversedebugger; + +import org.eclipse.ui.IFolderLayout; +import org.eclipse.ui.IPageLayout; +import org.eclipse.ui.IPerspectiveFactory; +import org.eclipse.ui.part.IPage; + +public class ReverseDebuggerPerspective implements IPerspectiveFactory { + + @Override + public void createInitialLayout(IPageLayout layout) { + // �G�f�B�^�̏ꏊ���擾 + String editorArea = layout.getEditorArea(); + + // ����ɃR�[���X�^�b�N�̃r���[��z�u + IFolderLayout topLeft = layout.createFolder("topLeft", IPageLayout.TOP, 0.35f, editorArea); + topLeft.addView(CallStackView.ID); + + // �E��ɃV�[�h�G�C���A�X�̃r���[��z�u + IFolderLayout topRight = layout.createFolder("topRight", IPageLayout.RIGHT, 0.5f, "topLeft"); + topRight.addView(SeedAliasView.ID); + + // �E���ɃI�u�W�F�N�g�t���[�G�C���A�X�̃r���[��z�u + IFolderLayout bottomRight = layout.createFolder("bottomRight", IPageLayout.RIGHT, 0.5f, editorArea); + bottomRight.addView(ObjectFlowAliasView.ID); + } +} diff --git a/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/SeedAliasLabelProvider.java b/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/SeedAliasLabelProvider.java new file mode 100644 index 0000000..e686586 --- /dev/null +++ b/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/SeedAliasLabelProvider.java @@ -0,0 +1,59 @@ +package org.ntlab.reversedebugger; + +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.swt.graphics.Image; +import org.eclipse.ui.ISharedImages; +import org.eclipse.ui.PlatformUI; +import org.ntlab.debuggingControl.MethodCaller; + +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.Value; + +public class SeedAliasLabelProvider extends LabelProvider implements ITableLabelProvider { + + @Override + public String getColumnText(Object element, int columnIndex) { + if (element instanceof MethodCaller) { + MethodCaller mc = (MethodCaller)element; + try { + switch (columnIndex) { + case 0: + return ((StringReference)mc.callInstanceMethod("getObjectId")).value(); + case 1: + return ((StringReference)mc.callInstanceMethod("getClassName")).value(); + case 2: + return ((StringReference)mc.callInstanceMethod("getMethodExecutionClassName")).value(); + case 3: + return String.valueOf(((IntegerValue)mc.callInstanceMethod("getLineNo")).value()); + case 4: + return ((StringReference)mc.callInstanceMethod("getStatementType")).value(); + case 5: + return ((StringReference)mc.callInstanceMethod("getStatementSignature")).value(); + case 6: + return ((StringReference)mc.callInstanceMethod("getOccurrenceText")).value(); + } + } catch (InvalidTypeException | ClassNotLoadedException + | InvocationException | IncompatibleThreadStateException e) { + e.printStackTrace(); + } + } + return "�e�X�g�p�e�L�X�g" + columnIndex; + } + + @Override + public Image getColumnImage(Object element, int columnIndex) { + return getImage(element); + } + + @Override + public Image getImage(Object element) { + return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_ELEMENT); + } +} diff --git a/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/SeedAliasView.java b/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/SeedAliasView.java new file mode 100644 index 0000000..6c6c043 --- /dev/null +++ b/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/SeedAliasView.java @@ -0,0 +1,192 @@ +package org.ntlab.reversedebugger; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IMenuListener; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.jface.viewers.ArrayContentProvider; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.ui.ISharedImages; +import org.eclipse.ui.IWorkbenchActionConstants; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.part.ViewPart; +import org.ntlab.debuggingControl.MethodCaller; + +public class SeedAliasView extends ViewPart { + private static TableViewer viewer; + private IAction refreshAction; + private IAction resetAction; + private IAction getObjectFlowAction; + private MethodCaller selectSeedAlias; + private static SeedAliases seedAliases = new SeedAliases(); + private static JavaEditorOperator javaEditorOperator = new JavaEditorOperator(); + public static final String ID = "org.ntlab.reverseDebugger.seedAliasView"; + + public SeedAliasView() { + // TODO Auto-generated constructor stub + System.out.println("SeedAliasView�N���X���������ꂽ��!"); + } + + @Override + public void createPartControl(Composite parent) { + // TODO Auto-generated method stub + System.out.println("SeedAliasView#createPartControl(Composite)���Ă΂ꂽ��!"); + viewer = new TableViewer(parent, SWT.FULL_SELECTION); + Table table = viewer.getTable(); + table.setHeaderVisible(true); + table.setLinesVisible(true); + + // �e�[�u���̃J�������쐬 + String[] tableColumnTexts = {"objectID", "objectType", "srcFile", "lineNo", "statementType", "statementSignature", "occurrence"}; + int[] tableColumnWidth = {150, 160, 160, 80, 180, 300, 110}; + TableColumn[] tableColumns = new TableColumn[tableColumnTexts.length]; + for (int i = 0; i < tableColumns.length; i++) { + tableColumns[i] = new TableColumn(table, SWT.NULL); + tableColumns[i].setText(tableColumnTexts[i]); + tableColumns[i].setWidth(tableColumnWidth[i]); + } + viewer.setContentProvider(new ArrayContentProvider()); + viewer.setLabelProvider(new SeedAliasLabelProvider()); + viewer.setInput(seedAliases.getSeedAliases()); + CallStackView.refresh(); + + // �I�������J�����ɑΉ�����V�[�h�G�C���A�X���N�_�ɃI�u�W�F�N�g�t���[�����s�����郊�X�i�[��o�^ +// viewer.addSelectionChangedListener(new ISelectionChangedListener() { +// @Override +// public void selectionChanged(SelectionChangedEvent event) { +// IStructuredSelection sel = (IStructuredSelection)event.getSelection(); +// Object element = sel.getFirstElement(); +// if (element instanceof MethodCaller) { +// MethodCaller seedAlias = (MethodCaller)element; +// ObjectFlowAliasView.createObjectFlow(seedAlias); +// ObjectFlowAliasView.refresh(); +// } +// } +// }); + + viewer.addSelectionChangedListener(new ISelectionChangedListener() { + @Override + public void selectionChanged(SelectionChangedEvent event) { + IStructuredSelection sel = (IStructuredSelection)event.getSelection(); + Object element = sel.getFirstElement(); + if (element instanceof MethodCaller) { + selectSeedAlias = (MethodCaller)element; + javaEditorOperator.openSrcFileOfAlias(selectSeedAlias); + } + } + }); + + createActions(); + createToolBar(); + createMenuBar(); + createPopupMenu(); + } + + @Override + public void setFocus() { + // TODO Auto-generated method stub + viewer.getControl().setFocus(); +// viewer.refresh(); + } + + private void createActions() { + refreshAction = new Action() { + @Override + public void run() { + refresh(); + } + }; + refreshAction.setText("refresh"); + refreshAction.setToolTipText("refresh"); + refreshAction.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_ELCL_SYNCED)); + + resetAction = new Action() { + @Override + public void run() { + reset(); + } + }; + resetAction.setText("reset"); + resetAction.setToolTipText("reset"); + resetAction.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_ETOOL_HOME_NAV)); + + getObjectFlowAction = new Action() { + @Override + public void run() { + getObjectFlow(); + } + }; + getObjectFlowAction.setText("getObjectFlow"); + getObjectFlowAction.setToolTipText("getObjectFlow"); + getObjectFlowAction.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_OBJS_TASK_TSK)); + } + + private void createToolBar() { + IToolBarManager mgr = getViewSite().getActionBars().getToolBarManager(); + mgr.add(refreshAction); + mgr.add(resetAction); + } + + private void createMenuBar() { + IMenuManager mgr = getViewSite().getActionBars().getMenuManager(); + mgr.add(refreshAction); + mgr.add(resetAction); + } + + private void createPopupMenu() { + MenuManager menuMgr = new MenuManager("#PopupMenu"); + menuMgr.setRemoveAllWhenShown(true); + menuMgr.addMenuListener(new IMenuListener() { + @Override + public void menuAboutToShow(IMenuManager manager) { + manager.add(getObjectFlowAction); + manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); + } + }); + Menu menu = menuMgr.createContextMenu(viewer.getControl()); + viewer.getControl().setMenu(menu); + getSite().registerContextMenu(menuMgr, viewer); + } + + public static MethodCaller getDebuggerStopMethodExecution() { + return seedAliases.getDebuggerStopMethodExecution(); + } + + public static void createSeedAliases(MethodCaller alias) { + seedAliases.createSeedAliases(alias); + } + + public static void refresh() { + if (seedAliases.getSeedAliases().isEmpty()) { + seedAliases.initSeedAliases(); + javaEditorOperator.openSrcFileOfMethodExecution(seedAliases.getDebuggerStopMethodExecution()); + CallStackView.reset(); + } + viewer.refresh(); + CallStackView.refresh(); + } + + private void reset() { + seedAliases.reset(); + ObjectFlowAliasView.reset(); + refresh(); + } + + private void getObjectFlow() { + if (selectSeedAlias != null) { + ObjectFlowAliasView.createObjectFlow(selectSeedAlias); + ObjectFlowAliasView.refresh(); + } + } +} diff --git a/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/SeedAliases.java b/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/SeedAliases.java new file mode 100644 index 0000000..e295db3 --- /dev/null +++ b/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/SeedAliases.java @@ -0,0 +1,141 @@ +package org.ntlab.reversedebugger; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Scanner; + +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.internal.core.LaunchManager; +import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.dialogs.MessageDialog; +import org.ntlab.debuggingControl.MethodCaller; + +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.ClassType; +import com.sun.jdi.IncompatibleThreadStateException; +import com.sun.jdi.IntegerValue; +import com.sun.jdi.InvalidTypeException; +import com.sun.jdi.InvocationException; +import com.sun.jdi.Location; +import com.sun.jdi.LongValue; +import com.sun.jdi.Method; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.StackFrame; +import com.sun.jdi.StringReference; +import com.sun.jdi.ThreadReference; +import com.sun.jdi.Value; +import com.sun.jdi.VirtualMachine; + +public class SeedAliases { + private MethodCaller debuggerStopMethodExecution = null; + private List seedAliases = new ArrayList<>(); + private final String TRACER = "org.ntlab.traceCollector.tracer.trace"; + + public SeedAliases() { + initSeedAliases(); + } + + public MethodCaller getDebuggerStopMethodExecution() { + return debuggerStopMethodExecution; + } + + public List getSeedAliases() { + return seedAliases; + } + + public void reset() { + seedAliases.clear(); + } + + public void initSeedAliases() { + // TODO Auto-generated method stub + LaunchManager lm = (LaunchManager)DebugPlugin.getDefault().getLaunchManager(); + + ILaunch[] launches = lm.getLaunches(); + if (launches.length != 0) { + ILaunch debugLaunch = null; + for (int i = 0; i < launches.length; i++) { + System.out.print(launches[i].getLaunchConfiguration().getName() + ":"); + System.out.print(launches[i].getDebugTarget()); + if (launches[i].getDebugTarget() != null) { + debugLaunch = launches[i]; + break; + } + } + if (debugLaunch != null) { + JDIDebugTarget debugTarget = ((JDIDebugTarget)debugLaunch.getDebugTarget()); + VirtualMachine vm = debugTarget.getVM(); + if (vm != null) { + // �f�o�b�O���s���̏ꍇ + List allThreads = vm.allThreads(); + for (int i = 0; i < allThreads.size(); i++) { + ThreadReference thread = allThreads.get(i); + if (thread.isSuspended()) { + createSeedAliases(vm, thread); + } + } + } + } + } + } + + /** + * ���݃f�o�b�K�Ŏ~�܂��Ă���n�_�ł̃��\�b�h���s���̑S�V�[�h�G�C���A�X�ꗗ���Z�b�g���� + * @param vm + * @param thread + */ + private void createSeedAliases(VirtualMachine vm, ThreadReference thread) { + MethodCaller mc = new MethodCaller(vm, thread); + try { + // threadId�̎擾��StringReference�^�ւ̕ϊ� + Value threadIdValue = mc.setObj(thread).callInstanceMethod("getId"); + StringReference threadId = vm.mirrorOf(String.valueOf(((LongValue)threadIdValue).value())); + + // threadId�ɑΉ�����ThreadInstance���擾 + ObjectReference threadInstance = (ObjectReference)mc.callStaticMethod(TRACER, "TraceJSON", "getThreadInstance", threadId); + Value methodExecution = mc.setObj(threadInstance).callInstanceMethod("getCurrentMethodExecution"); + debuggerStopMethodExecution = new MethodCaller(vm, thread, (ObjectReference)methodExecution); + findAllSeedAlias(vm, thread, methodExecution); + } catch (InvalidTypeException | ClassNotLoadedException | InvocationException | IncompatibleThreadStateException e) { + e.printStackTrace(); + } + } + + /** + * �n���ꂽ�G�C���A�X������郁�\�b�h���s���̑S�V�[�h�G�C���A�X�̈ꗗ���Z�b�g���� + * @param alias + */ + public void createSeedAliases(MethodCaller alias) { + VirtualMachine vm = alias.getVm(); + ThreadReference thread = alias.getThread(); + MethodCaller mc = new MethodCaller(vm, thread); + try { + Value methodExecution = alias.callInstanceMethod("getMethodExecution"); + findAllSeedAlias(vm, thread, methodExecution); + } catch (InvalidTypeException | ClassNotLoadedException | InvocationException | IncompatibleThreadStateException e) { + e.printStackTrace(); + } + } + + /** + * �n���ꂽ���\�b�h���s���̑S�V�[�h�G�C���A�X�̈ꗗ��, ���ۂ�traceCollector���ƒʐM���Ď擾���Z�b�g���� + * @param vm + * @param thread + * @param methodExecution + */ + private void findAllSeedAlias(VirtualMachine vm, ThreadReference thread, Value methodExecution) throws InvalidTypeException, + ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + MethodCaller mc = new MethodCaller(vm, thread); + seedAliases.clear(); + ObjectReference seedAliasList = (ObjectReference)mc.callStaticMethod(TRACER, "TraceJSON", "findAllStartAlias", methodExecution); + int seedAliasListSize = ((IntegerValue)mc.setObj(seedAliasList).callInstanceMethod("size")).value(); + for (int i = 0; i < seedAliasListSize; i++) { + ObjectReference seedAlias = (ObjectReference)mc.setObj(seedAliasList).callInstanceMethod("get", vm.mirrorOf(i)); + seedAliases.add(new MethodCaller(vm, thread, seedAlias)); + } + } +}