diff --git a/org.ntlab.reverseDebugger/.classpath b/org.ntlab.reverseDebugger/.classpath new file mode 100644 index 0000000..b1dabee --- /dev/null +++ b/org.ntlab.reverseDebugger/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.ntlab.reverseDebugger/.project b/org.ntlab.reverseDebugger/.project new file mode 100644 index 0000000..68e238d --- /dev/null +++ b/org.ntlab.reverseDebugger/.project @@ -0,0 +1,28 @@ + + + org.ntlab.reverseDebugger + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/org.ntlab.reverseDebugger/.settings/org.eclipse.jdt.core.prefs b/org.ntlab.reverseDebugger/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..11f6e46 --- /dev/null +++ b/org.ntlab.reverseDebugger/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.7 diff --git a/org.ntlab.reverseDebugger/META-INF/MANIFEST.MF b/org.ntlab.reverseDebugger/META-INF/MANIFEST.MF new file mode 100644 index 0000000..d51ce53 --- /dev/null +++ b/org.ntlab.reverseDebugger/META-INF/MANIFEST.MF @@ -0,0 +1,14 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: DebuggingControl +Bundle-SymbolicName: org.ntlab.reverseDebugger2;singleton:=true +Bundle-Version: 1.0.0.qualifier +Bundle-Activator: org.ntlab.debuggingControl.Activator +Require-Bundle: org.eclipse.ui, + org.eclipse.core.runtime, + org.eclipse.debug.core, + org.eclipse.jdt.debug, + org.eclipse.jdt.core;bundle-version="3.10.2", + org.eclipse.jdt.ui;bundle-version="3.10.2" +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Bundle-ActivationPolicy: lazy diff --git a/org.ntlab.reverseDebugger/bin/.gitignore b/org.ntlab.reverseDebugger/bin/.gitignore new file mode 100644 index 0000000..cf1db2e --- /dev/null +++ b/org.ntlab.reverseDebugger/bin/.gitignore @@ -0,0 +1 @@ +/org/ diff --git a/org.ntlab.reverseDebugger/build.properties b/org.ntlab.reverseDebugger/build.properties new file mode 100644 index 0000000..6f20375 --- /dev/null +++ b/org.ntlab.reverseDebugger/build.properties @@ -0,0 +1,5 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml diff --git a/org.ntlab.reverseDebugger/plugin.xml b/org.ntlab.reverseDebugger/plugin.xml new file mode 100644 index 0000000..c7729d6 --- /dev/null +++ b/org.ntlab.reverseDebugger/plugin.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + diff --git a/org.ntlab.reverseDebugger/src/org/ntlab/debuggingControl/Activator.java b/org.ntlab.reverseDebugger/src/org/ntlab/debuggingControl/Activator.java new file mode 100644 index 0000000..e6910b9 --- /dev/null +++ b/org.ntlab.reverseDebugger/src/org/ntlab/debuggingControl/Activator.java @@ -0,0 +1,50 @@ +package org.ntlab.debuggingControl; + +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "org.ntlab.helloWorld"; //$NON-NLS-1$ + + // The shared instance + private static Activator plugin; + + /** + * The constructor + */ + public Activator() { + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } + +} diff --git a/org.ntlab.reverseDebugger/src/org/ntlab/debuggingControl/DebuggingControlAction.java b/org.ntlab.reverseDebugger/src/org/ntlab/debuggingControl/DebuggingControlAction.java new file mode 100644 index 0000000..cc7f4cf --- /dev/null +++ b/org.ntlab.reverseDebugger/src/org/ntlab/debuggingControl/DebuggingControlAction.java @@ -0,0 +1,738 @@ +package org.ntlab.debuggingControl; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.internal.core.LaunchManager; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IMember; +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.internal.debug.core.model.JDIDebugTarget; +import org.eclipse.jdt.ui.JavaUI; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; +import org.eclipse.ui.PartInitException; + +import com.sun.jdi.AbsentInformationException; +import com.sun.jdi.BooleanValue; +import com.sun.jdi.ByteValue; +import com.sun.jdi.CharValue; +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.ClassType; +import com.sun.jdi.DoubleValue; +import com.sun.jdi.Field; +import com.sun.jdi.FloatValue; +import com.sun.jdi.IncompatibleThreadStateException; +import com.sun.jdi.IntegerValue; +import com.sun.jdi.InvalidTypeException; +import com.sun.jdi.InvocationException; +import com.sun.jdi.LocalVariable; +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.ShortValue; +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 DebuggingControlAction implements IWorkbenchWindowActionDelegate { + + @Override + public void run(IAction arg0) { + // TODO Auto-generated method stub + LaunchManager lm = (LaunchManager)DebugPlugin.getDefault().getLaunchManager(); + + ILaunch[] launches = lm.getLaunches(); + if (launches.length == 0) { + MessageDialog.openInformation(null, null, "��xJava�v���O���������s���Ă�������"); + } else { + 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()) { + try { + // ��~���Ă���X���b�h���ǂ̃N���X�i�ǂ̃��\�b�h�j�̉��s�ڂŒ�~���Ă���̂���\������ + List frames = thread.frames(); // ��~�X���b�h���̑S�X�^�b�N�t���[�� + StackFrame topFrame = frames.get(0); + Location location = topFrame.location(); // �X�^�b�N�g�b�v�ɂ���t���[��(�u���[�N�|�C���g�Œ�~��) + MessageDialog.openInformation(null, null, "Thread [" + thread.name() + "] \n" + + location.method().declaringType().name() + "." + location.method().name() + location.method().signature() + " line: " + + location.lineNumber()); + System.out.println(); + callCollectorMethods(vm, thread); // traceCollector�̃��\�b�h�Ăяo���֘A + System.out.println(); + } catch (InvalidTypeException + | ClassNotLoadedException + | InvocationException e) { + e.printStackTrace(); + } catch (IncompatibleThreadStateException e) { + e.printStackTrace(); + } + } + } + } else { + MessageDialog.openInformation(null, null, "Java�v���O�������f�o�b�O���s���̒�~��Ԃɂ��Ă�������"); + } + } else { + MessageDialog.openInformation(null, null, "Java�v���O�������f�o�b�O���s���Ă�������"); + } + } + } + + @Override + public void selectionChanged(IAction arg0, ISelection arg1) { + // TODO Auto-generated method stub + + } + + @Override + public void dispose() { + // TODO Auto-generated method stub + + } + + @Override + public void init(IWorkbenchWindow arg0) { + // TODO Auto-generated method stub + + } + + /** + * traceCollector�̃��\�b�h���Ă� + * @param vm + * @param thread + */ + private void callCollectorMethods(VirtualMachine vm, ThreadReference thread) throws InvalidTypeException, + ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + String packageName = "org.ntlab.traceCollector.tracer.trace"; + String className; + String methodName; + + // threadId�̎擾��StringReference�^�ւ̕ϊ� + methodName = "getId"; + Value threadIdValue = callInstanceMethod(vm, thread, methodName, thread); + StringReference threadId = vm.mirrorOf(String.valueOf(((LongValue)threadIdValue).value())); + System.out.print("threadId = " + threadId); // �擾����ThreadId�̊m�F�p + + // threadId�ɑΉ�����ThreadInstance���擾 + className = "TraceJSON"; + methodName = "getThreadInstanceForDebuggingControl"; + Value threadInstance = callStaticMethod(vm, thread, packageName, className, methodName, threadId); + + // threadInstance�̌Ăяo���X�^�b�N��̃��\�b�h�ɂ‚��Ă̊e��f�[�^���擾���ĕ\������ +// printStackData(vm, thread, threadInstance); + + // threadInstance�̃��\�b�h�Ăяo���؂̑S���\�b�h�ɂ‚��Ă̊e��f�[�^���擾���ĕ\������ + printCallTreeDataFromRoot(vm, thread, threadInstance); + } + + /** + * �����œn����threadInstance�̌Ăяo���X�^�b�N��̃��\�b�h�ɂ‚��Ă̊e��f�[�^���擾���ĕ\������ + * @param vm + * @param thread + * @param threadInstance + */ + private void printStackData(VirtualMachine vm, ThreadReference thread, Value threadInstance) throws InvalidTypeException, + ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + // ThreadInstance������curMethodExecution���擾 + String methodName = "getCurrentMethodExecution"; + Value methodExecution = callInstanceMethod(vm, thread, methodName, (ObjectReference)threadInstance); + Value child = null; + + // curMethodExetuion�̃V�O�l�`�����擾���A���̌Ăяo�����̃��\�b�h�ɂ‚��Ă����l�̏������J��Ԃ� + while (methodExecution != null) { + Value lineNo = (child != null) ? getMethodExecutionLineNo(vm, thread, methodExecution, child) + : vm.mirrorOf(thread.frame(0).location().lineNumber()); // child == null �̂Ƃ�(=�X�^�b�N�̃g�b�v�̂Ƃ�)�́A���m��lineNo��JDI���̃��\�b�h��p���Ď擾���� + + // �f�[�^�̎擾�ƕ\���֘A + String indent = " "; + Value methodSignature = getMethodExecutionSignature(vm, thread, methodExecution); + printValue("", "", methodSignature, true); + printValue(indent, "lineNo = ", lineNo, true); + System.out.println(); + IType type = findIType(vm, thread, methodExecution); + IMethod method = findIMethod(vm, thread, type, methodExecution); + openSrcFileOfIMethod(type, method); + printAllIdAndType(vm, thread, methodExecution, method, indent); + + // curMethodExecution�̌Ăяo�����\�b�h���擾 (MethodExecution) + child = methodExecution; + methodName = "getParent"; + methodExecution = callInstanceMethod(vm, thread, methodName, (ObjectReference)methodExecution); + } + } + + /** + * �����œn����threadInstance�̌Ăяo���؂̃��\�b�h�ɂ‚��Ă̊e��f�[�^���擾���ĕ\������
+ * �Ăяo���؂̃��\�b�h�͊ethreadInstance�ł�Root���珇�ԂɎ擾 + * @param vm + * @param thread + * @param threadInstance + */ + private void printCallTreeDataFromRoot(VirtualMachine vm, ThreadReference thread, Value threadInstance) throws InvalidTypeException, + ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + // ThreadInstance������root��MethodExecution���擾(ArrayList) + String methodName = "getRoot"; + Value methodExecutions = callInstanceMethod(vm, thread, methodName, (ObjectReference)threadInstance); + printCallTreeData(vm, thread, null, methodExecutions, ""); + } + + /** + * �����œn����methodExecution���X�g�����ƒ��\�b�h���N�_�Ƃ��āA�Ăяo���؂�[���D��T����
+ * �s���������ŒT�����āA���\�b�h�Ƃ��̊e��f�[�^���擾���ĕ\������ + * @param vm + * @param thread + * @param parent + * @param methodExecutions + * @param indent + */ + private void printCallTreeData(VirtualMachine vm, ThreadReference thread, Value parent, Value methodExecutions, String indent) throws InvalidTypeException, + ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + if (methodExecutions == null) { + return; + } + String methodName = "size"; + final int METHOD_EXECUTION_SIZE = ((IntegerValue)callInstanceMethod(vm, thread, methodName, (ObjectReference)methodExecutions)).value(); + if (METHOD_EXECUTION_SIZE == 0) { + return; + } + + final String DEEP_SPACE_INDENT = indent.replace("-", " ") + " "; // ���\�b�h�V�O�l�`���ȊO�ł̕\���p + for (int i = 0; i < METHOD_EXECUTION_SIZE; i++) { + IntegerValue index = vm.mirrorOf(i); + methodName = "get"; + Value methodExecution = callInstanceMethod(vm, thread, methodName, (ObjectReference)methodExecutions, index); + Value lineNo = (parent != null) ? getMethodExecutionLineNo(vm, thread, parent, methodExecution) : vm.mirrorOf(0); + + // �f�[�^�̎擾�ƕ\���֘A + Value methodSignature = getMethodExecutionSignature(vm, thread, methodExecution); + printValue(indent, "", methodSignature, true); + printValue(DEEP_SPACE_INDENT, "lineNoCalledByParent = ", lineNo, true); + System.out.println(); + IType type = findIType(vm, thread, methodExecution); + IMethod method = findIMethod(vm, thread, type, methodExecution); + openSrcFileOfIMethod(type, method); + printAllIdAndType(vm, thread, methodExecution, method, DEEP_SPACE_INDENT); + + // ���\�b�h�Ăяo���؂ɂ����Ă̎q���\�b�h�ɂ‚��Ă����l�̏������ċA�I�ɍs�� + methodName = "getChildren"; + Value children = callInstanceMethod(vm, thread, methodName, (ObjectReference)methodExecution); + printCallTreeData(vm, thread, methodExecution, children, (indent + "--------")); + } + } + + /** + * this�≼������ID��Type �y�� ����炪���ƒt�B�[���h��ID��Type��S�ĕ\������ + * @param vm + * @param thread + * @param methodExecution + * @param method + * @param indent + */ + private void printAllIdAndType(VirtualMachine vm, ThreadReference thread, Value methodExecution, IMethod method, String indent) throws InvalidTypeException, + ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + // this��ID��Type���擾���ĕ\�� + Value thisId = getMethodExecutionThisId(vm, thread, methodExecution); + printValue(indent, "this id = ", thisId, true); + Value thisType = getMethodExecutionThisType(vm, thread, methodExecution); + printValue("", " type = ", thisType, false); + + // this�̎��ƒt�B�[���h��ID��Type��\�� (�Ăяo����ōċA) + System.out.println(); + printFieldIdAndType(vm, thread, thisType, thisId, (indent + " ")); + + // ������ID��Type �y�т��̈��������ƒt�B�[���h��ID��Type��\�� (�Ăяo����ōċA) + System.out.println(); + printArgsIdAndType(vm, thread, methodExecution, method, indent); + } + + private Value getMethodExecutionSignature(VirtualMachine vm, ThreadReference thread, Value methodExecution) throws InvalidTypeException, + ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + // curMethodExecution�̃V�O�l�`�����擾(String) + String methodName = "getSignature"; + return callInstanceMethod(vm, thread, methodName, (ObjectReference)methodExecution); + } + + private Value getMethodExecutionThisType(VirtualMachine vm, ThreadReference thread, Value methodExecution) throws InvalidTypeException, + ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + // thisClassName���擾(String) + String methodName = "getThisClassName"; + return callInstanceMethod(vm, thread, methodName, (ObjectReference)methodExecution); + } + + private Value getMethodExecutionThisId(VirtualMachine vm, ThreadReference thread, Value methodExecution) throws InvalidTypeException, + ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + // thisObjId���擾(String) + String methodName = "getThisObjId"; + return callInstanceMethod(vm, thread, methodName, (ObjectReference)methodExecution); + } + + private Value getMethodExecutionLineNo(VirtualMachine vm, ThreadReference thread, Value methodExecution, Value child) throws InvalidTypeException, + ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + // methodExecution��child���Ăяo�����ꏊ��lineNo���擾(IntegerValue) + String methodName = "getMethodInvocation"; + ObjectReference methodInvocation = (ObjectReference)callInstanceMethod(vm, thread, methodName, (ObjectReference)methodExecution, child); + if (methodInvocation != null) { + methodName = "getLineNo"; + return callInstanceMethod(vm, thread, methodName, methodInvocation); + } + return null; + } + + private void printFieldIdAndType(VirtualMachine vm, ThreadReference thread, Value thisClassName, Value thisObjId, String indent) throws InvalidTypeException, + ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + String packageName = "org.ntlab.traceCollector.tracer.trace"; + String className = "TraceJSON"; + String methodName; + + // �t�B�[���h��ID��Type���擾���ĕ\�� + List classes = vm.classesByName(((StringReference)thisClassName).value()); + ClassType type = (ClassType)classes.get(0); + for (Field field : type.allFields()) { + if (field.isStatic()) { + continue; // static�t�B�[���h�͔�΂� (��낤�Ƃ��Ă��AID��Type�����Ȃ�) + } + String fieldName = field.declaringType().name() + "." + field.name(); // ���S���薼 + System.out.print(indent + fieldName); + + // ���̃t�B�[���h�ɂ‚��Ă̍ŐV�̍X�V�����擾(FieldUpdate) + methodName = "getRecentlyFieldUpdateForDebuggingControl"; + ObjectReference fieldUpdate = (ObjectReference)callStaticMethod(vm, thread, packageName, className, methodName, thisObjId, vm.mirrorOf(fieldName), thread); + if (fieldUpdate == null) { + System.out.println(" id = null����!" + " type = null����!"); + continue; + } + + // �t�B�[���h��ID��Type���擾(String) + methodName = "getValueObjId"; + Value fieldObjIdValue = callInstanceMethod(vm, thread, methodName, fieldUpdate); + printValue("", " id = ", fieldObjIdValue, false); + methodName = "getValueClassName"; + Value fieldTypeValue = callInstanceMethod(vm, thread, methodName, fieldUpdate); + printValue("", " type = ", fieldTypeValue, false); + + // �擾�����t�B�[���h���I�u�W�F�N�g��z��̏ꍇ�ɁA���̃I�u�W�F�N�g��z�񂪎��ƒt�B�[���h�ɂ‚��Ă̏������s�� + System.out.println(); + printDeepHierarchyField(vm, thread, fieldObjIdValue, fieldTypeValue, fieldName, (indent + " ")); + } + } + + /** + * �����œn�����t�B�[���h���Q�ƌ^�̏ꍇ��A�z��̏ꍇ�ɁA
+ * ���̎Q�ƌ^�I�u�W�F�N�g�������Ă���t�B�[���h��A�z��̊e�v�f�̃I�u�W�F�N�g�ɂ‚��āA
+ * ���ꂼ��ɑΉ��������\�b�h������ɌĂяo�� (���̃��\�b�h�ƑΉ����\�b�h�Ƃ̑��ݍċA) + * @param vm + * @param thread + * @param objIdValue + * @param typeValue + * @param fieldName + * @param indent + */ + private void printDeepHierarchyField(VirtualMachine vm, ThreadReference thread, Value objIdValue, Value typeValue, + String fieldName, String indent) throws InvalidTypeException, + ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + // �t�B�[���h��ID��Type���Ȃ��ꍇ��AType(=ActualType)��"---"�̏ꍇ�͉������Ȃ� + if (objIdValue == null + || typeValue == null + || ((StringReference)objIdValue).value().isEmpty() + || ((StringReference)typeValue).value().isEmpty()) { + return; + } + final String NULL_ACTUAL_TYPE = "---"; // �t�B�[���h�ɑ΂��Ė����I��null����ꂽ�ꍇ��ActualType�̎擾������ + String fieldType = ((StringReference)typeValue).value(); + if (fieldType.equals(NULL_ACTUAL_TYPE)) { + return; + } + + final String ARRAY_SIGNATURE_HEAD = "["; // �z��̃V�O�l�`���̐擪�́A�z��̎��������� [ ���A�Ȃ� + if (fieldType.startsWith(ARRAY_SIGNATURE_HEAD)) { + // �t�B�[���h��Type���z��^(�@[ �Ŏn�܂�@)�ꍇ (���̔z�񂪎��Še�v�f�ɂ‚��Ă���Ȃ�f�[�^�擾�������Ăяo��) + printArrayIdAndType(vm, thread, objIdValue, fieldName, indent); + } else { + String[] primitives = {"byte", "short", "int", "long", "float", "double", "char", "boolean"}; + if (!Arrays.asList(primitives).contains(fieldType)) { + // �t�B�[���h��Type���Q�ƌ^(=�I�u�W�F�N�g)�̏ꍇ (���̃I�u�W�F�N�g�������Ă���t�B�[���h�ɂ‚��Ă���Ȃ�f�[�^�擾�������Ăяo��) + printFieldIdAndType(vm, thread, typeValue, objIdValue, indent); + } + } + } + + private void printArrayIdAndType(VirtualMachine vm, ThreadReference thread, Value arrayObjId, String arrayName, String indent) throws InvalidTypeException, + ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + String packageName = "org.ntlab.traceCollector.tracer.trace"; + String className = "TraceJSON"; + String methodName; + + for (int i = 0;; i++){ + // ���̔z��v�f�ɂ‚��Ă̍ŐV�̍X�V�����擾(ArrayUpdate) + methodName = "getRecentlyArrayUpdateForDebuggingControl"; + IntegerValue index = vm.mirrorOf(i); + ObjectReference arrayUpdate = (ObjectReference)callStaticMethod(vm, thread, packageName, className, methodName, arrayObjId, index, thread); + if (arrayUpdate == null) { + // �z��̃T�C�Y���擾�ł��Ȃ����߁A�C���f�b�N�X���T�C�Y���߂̂Ƃ��Ɋm���ɔ���������@�Ƃ��ĉ����� + // �������A�z��v�f�̓r���ɖ���`���������ꍇ�ł��A�����Ă��܂��̂����_ + break; + } + String arrayIndexName = arrayName + "[" + index.value() + "]"; + System.out.print(indent + arrayIndexName); + + // �z��v�f��ID��Type���擾(String) + methodName = "getValueObjectId"; + Value valueObjId = callInstanceMethod(vm, thread, methodName, arrayUpdate); + printValue("", " id = ", valueObjId, false); + methodName = "getValueClassName"; + Value valueType = callInstanceMethod(vm, thread, methodName, arrayUpdate); + printValue("", " type = ", valueType, false); + + // �擾�����z��v�f���I�u�W�F�N�g��z��̏ꍇ�ɁA���̃I�u�W�F�N�g��z�񂪎��ƒt�B�[���h�ɂ‚��Ă̏������s�� + System.out.println(); + printDeepHierarchyField(vm, thread, valueObjId, valueType, arrayIndexName, (indent + " ")); + } + } + + private void printArgsIdAndType(VirtualMachine vm, ThreadReference thread, Value methodExecution, IMethod method, String indent) throws InvalidTypeException, + ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + // methodExecution������arguments���擾(ArrayList)���A����arguments�̃T�C�Y���擾(int) + String methodName = "getArguments"; + ObjectReference args = (ObjectReference)callInstanceMethod(vm, thread, methodName, (ObjectReference)methodExecution); + methodName = "size"; + final int ARGUMENTS_NUM = ((IntegerValue)callInstanceMethod(vm, thread, methodName, args)).value(); + if (ARGUMENTS_NUM > 0) { + String[] argNames = getParameterNames(method); // ������IMethod���牼���������擾���� + System.out.println(indent + "args"); + for (int i = 0; i < ARGUMENTS_NUM; i++) { + String argName = (argNames.length == ARGUMENTS_NUM) ? argNames[i] : "arg" + i; // ���Ȃ��Ƃ������̌����s��v�̂Ƃ��͐����������������Ă��Ȃ� + methodName = "get"; + ObjectReference arg = (ObjectReference)callInstanceMethod(vm, thread, methodName, args, vm.mirrorOf(i)); + methodName = "getId"; + Value argId = callInstanceMethod(vm, thread, methodName, arg); + methodName = "getActualType"; + Value argType = callInstanceMethod(vm, thread, methodName, arg); + System.out.println(indent + argName + " id = " + ((StringReference)argId).value() + " type = " + ((StringReference)argType).value()); + printDeepHierarchyField(vm, thread, argId, argType, argName, (indent + " ")); + System.out.println(); + } + } + } + + private String[] getParameterNames(IMethod method) { + String[] argNames = new String[0]; + if (method != null) { + try { + argNames = method.getParameterNames(); + } catch (JavaModelException e) { + e.printStackTrace(); + } + } + return argNames; + } + + /** + * �����œn����methodExecution����`����Ă���N���X�̃\�[�X�R�[�h��Ώ�Eclipse�̃G�f�B�^�ŊJ������ + * @param vm + * @param thread + * @param methodExecution + */ + private void openSrcFileOfMethodExecution(VirtualMachine vm, ThreadReference thread, Value methodExecution) throws InvalidTypeException, + ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + IType type = findIType(vm, thread, methodExecution); + if (type != null) { + IMethod method = findIMethod(vm, thread, type, methodExecution); + if (method != null) { + openSrcFileOfIMethod(type, method); + } + } + } + + /** + * �����œ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(VirtualMachine vm, ThreadReference thread, Value methodExecution) throws InvalidTypeException, + ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + String methodName = "getDeclaringClassName"; + StringReference declaringClassName = (StringReference)callInstanceMethod(vm, thread, methodName, (ObjectReference)methodExecution); + String projectPath = getLoaderPath(vm, thread, methodExecution, declaringClassName); + IType type = null; + if (projectPath != null) { + IJavaProject javaProject = findJavaProject(projectPath); + if (javaProject != null) { + StringReference methodSignature = (StringReference)getMethodExecutionSignature(vm, thread, methodExecution); + try { + type = javaProject.findType(declaringClassName.value()); + } catch (JavaModelException e) { + e.printStackTrace(); + } + } + } + return type; + } + + private String getLoaderPath(VirtualMachine vm, ThreadReference thread, Value methodExecution, StringReference declaringClassName) throws InvalidTypeException, + ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + String packageName = "org.ntlab.traceCollector.tracer.trace"; + String className = "TraceJSON"; + String methodName; + + methodName = "getClassInfo"; + ObjectReference classInfo = (ObjectReference)callStaticMethod(vm, thread, packageName, className, methodName, declaringClassName); + if (classInfo == null) { + methodName = "getThisClassName"; + declaringClassName = (StringReference)callInstanceMethod(vm, thread, methodName, (ObjectReference)methodExecution); + methodName = "getClassInfo"; + classInfo = (ObjectReference)callStaticMethod(vm, thread, packageName, className, methodName, declaringClassName); + } + String loaderPath = null; + if (classInfo != null) { +// // loaderPath���擾 +// methodName = "getLoaderPath"; +// loaderPath = ((StringReference)callInstanceMethod(vm, thread, methodName, classInfo)).value(); + + // �Ȃ���loaderPath���擾�ł��Ă��Ȃ����߁A���ۂɏo�͂����JSON�g���[�X���Q�l�ɂ���path����^���Ă݂� + methodName = "getPath"; + String path = ((StringReference)callInstanceMethod(vm, thread, methodName, classInfo)).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); + System.out.println("JavaUI.revealInEditor() ���Ăяo������!"); + } + } + } catch (PartInitException | JavaModelException e) { + e.printStackTrace(); + } + } + + private IMethod findIMethod(VirtualMachine vm, ThreadReference thread, IType type, Value methodExecution) throws InvalidTypeException, + ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + IMethod method = null; + if (type != null) { + StringReference methodSignature = (StringReference)getMethodExecutionSignature(vm, thread, methodExecution); + 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 { + String jdiMethodSignature = (method.isConstructor()) ? (fqcn + "(") : (fqcn + "." + method.getElementName() + "("); + System.out.println(jdiMethodSignature); + if (methodSignature.contains(jdiMethodSignature)) { + // ������v���Ă����ꍇ�Ɍ���A�������X�g����������ł���v���邩�ǂ����𔻒� (�I�[�o�[���[�h�ɂ��딻��������) + jdiMethodSignature += String.join(",", parseFQCNParameters(type, method)) + ")"; // �S�����̃V�O�l�`�������S���薼�ɕϊ�����,�ŋ�؂��������� + System.out.println(jdiMethodSignature); + return methodSignature.contains(jdiMethodSignature); + } + } catch (JavaModelException e) { + e.printStackTrace(); + } + return false; + } + + /** + * IMethod����擾�ł���S�����̃V�O�l�`�������S���薼�ɒu�������Ċi�[�������X�g��Ԃ� + * @param type + * @param method + * @return + * @throws JavaModelException + */ + 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) { + readableTypeSplit[0] = (resolveType[0][0] + "." + resolveType[0][1]); // ���S���薼 + } + parameters.add(readableTypeSplit[0] + readableTypeSplit[1]); + } + return parameters; + } + + /** + * �p�b�P�[�W���ƃN���X���ƃ��\�b�h���ƈ������w�肵�Ă��̃N���X���\�b�h���Ăяo�� + * @param vm + * @param thread + * @param packageName �Ăт����������\�b�h������N���X�̃p�b�P�[�W�� (�N���X���ƌq���Ŋ��S���薼�ɂ��邽�߁A������ . ���‚���) + * @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) + */ + private Value callStaticMethod(VirtualMachine vm, ThreadReference thread, 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 vm + * @param thread + * @param methodName �Ăяo���������\�b�h�� + * @param obj receiver�̃C���X�^���X�ɑΉ�����ObjectReference + * @param args �Ăяo���������\�b�h�ɓn������(Value �̃N���X�^�ʼn•ϒ�) + * @return �Ăяo�������\�b�h����̖߂�l(Value) + */ + private Value callInstanceMethod(VirtualMachine vm, ThreadReference thread, String methodName, ObjectReference obj, 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�� + } + + /** + * �����œn���ꂽValue�N���X��\������
+ * (Value�N���X�̎q�N���X����Ή������{�^��String�^�����邱�Ƃ̊m�F�����˂Ă���) + * @param indent �C���f���g + * @param msg Value�̕\���O�ɓ���郁�b�Z�[�W + * @param value �\����������Value + * @param isNewLine ���̃��\�b�h�ɂ��\��������ۂɉ��s�����Ă���\�����邩 + */ + private void printValue(String indent, String msg, Value value, boolean isNewLine) { + System.out.print(((isNewLine) ? "\n" : "") + indent + msg); + printValue(value); + } + + /** + * �����œn���ꂽValue�N���X��\������
+ * (Value�N���X�̎q�N���X����Ή������{�^��String�^�����邱�Ƃ̊m�F�����˂Ă���) + * @param value + */ + private void printValue(Value value) { + if (value == null) { + System.out.print("null����!"); + return; + } + if (value instanceof StringReference) { + String log = ((StringReference)value).value(); + System.out.print(log); + } else if (value instanceof IntegerValue) { + int log = ((IntegerValue)value).value(); + System.out.print(log); + } else if (value instanceof LongValue) { + long log = ((LongValue)value).value(); + System.out.print(log); + } else if (value instanceof BooleanValue) { + boolean log = ((BooleanValue)value).value(); + System.out.print(log); + } else if (value instanceof DoubleValue) { + double log = ((DoubleValue)value).value(); + System.out.print(log); + } else if (value instanceof FloatValue) { + float log = ((FloatValue)value).value(); + System.out.print(log); + } else if (value instanceof ShortValue) { + short log = ((ShortValue)value).value(); + System.out.print(log); + } else if (value instanceof ByteValue) { + byte log = ((ByteValue)value).value(); + System.out.print(log); + } else if (value instanceof CharValue) { + char log = ((CharValue)value).value(); + System.out.print(log); + } else { + throw new IllegalArgumentException("value is not Primitive or String"); + } + } +}