2

我正在寻找使用java debug interface构建调试器。
我的目标是设置断点并获取变量的值。
我发现这个答案与我正在寻找的答案很接近,我知道我必须使用以下界面:- VirtualMachineManager、、、、。但我不知道如何在特定行设置断点并获取变量的值或接口的使用顺序。LaunchingConnectorClassPrepareEventClassPrepareRequest

例如在下面的代码中,我如何继续运行它以jdi获取变量的值S

import java.io.*;

class Hello {

  public static void main(String args[]) {
    String S = "Hello World";
    int a = 12;
  }
}

我正在考虑在线上 a = 12或方法结束时设置调试点,main以便我获得S

4

2 回答 2

8

发现这篇文章很有用。这也是一个很好的例子,可以帮助你。

或者,您可以检查以下项目

这是一个示例代码供您使用。

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package jdidebugger;

import com.sun.jdi.AbsentInformationException;
import com.sun.jdi.Bootstrap;
import com.sun.jdi.ClassType;
import com.sun.jdi.IncompatibleThreadStateException;
import com.sun.jdi.LocalVariable;
import com.sun.jdi.Location;
import com.sun.jdi.Method;
import com.sun.jdi.StackFrame;
import com.sun.jdi.ThreadReference;
import com.sun.jdi.Value;
import com.sun.jdi.VirtualMachine;
import com.sun.jdi.VirtualMachineManager;
import com.sun.jdi.connect.Connector;
import com.sun.jdi.connect.IllegalConnectorArgumentsException;
import com.sun.jdi.connect.LaunchingConnector;
import com.sun.jdi.connect.VMStartException;
import com.sun.jdi.event.BreakpointEvent;
import com.sun.jdi.event.ClassPrepareEvent;
import com.sun.jdi.event.Event;
import com.sun.jdi.event.EventIterator;
import com.sun.jdi.event.EventQueue;
import com.sun.jdi.event.EventSet;
import com.sun.jdi.request.BreakpointRequest;
import com.sun.jdi.request.ClassPrepareRequest;
import com.sun.jdi.request.EventRequestManager;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author bonnie
 */
public class JdiDebugger {

    /**
     * @param options
     * @param main
     * @param classPattern
     * @param methodName
     * @param lineNumber
     * @throws java.io.IOException
     * @throws com.sun.jdi.connect.IllegalConnectorArgumentsException
     * @throws com.sun.jdi.connect.VMStartException
     * @throws java.lang.InterruptedException
     * @throws com.sun.jdi.AbsentInformationException
     * @throws com.sun.jdi.IncompatibleThreadStateException
     */
    public static void onMethodExit(String options, String main, String classPattern, String methodName) throws IOException, IllegalConnectorArgumentsException, VMStartException, InterruptedException, AbsentInformationException, IncompatibleThreadStateException {

        // create and launch a virtual machine
        VirtualMachineManager vmm = Bootstrap.virtualMachineManager();
        LaunchingConnector lc = vmm.defaultConnector();
        Map<String, Connector.Argument> env = lc.defaultArguments();
        env.get("options").setValue(options);
        env.get("main").setValue(main);
        VirtualMachine vm = lc.launch(env);

        // create a class prepare request
        EventRequestManager erm = vm.eventRequestManager();
        ClassPrepareRequest r = erm.createClassPrepareRequest();
        r.addClassFilter(classPattern);
        r.enable();

        EventQueue queue = vm.eventQueue();
        while (true) {
            EventSet eventSet = queue.remove();
            EventIterator it = eventSet.eventIterator();
            while (it.hasNext()) {
                Event event = it.nextEvent();
                if (event instanceof ClassPrepareEvent) {
                    ClassPrepareEvent evt = (ClassPrepareEvent) event;
                    ClassType classType = (ClassType) evt.referenceType();

                    classType.methodsByName(methodName).forEach(new Consumer<Method>() {
                        @Override
                        public void accept(Method m) {
                            List<Location> locations = null;
                            try {
                                locations = m.allLineLocations();
                            } catch (AbsentInformationException ex) {
                                Logger.getLogger(JdiDebuggerOld.class.getName()).log(Level.SEVERE, null, ex);
                            }
                            // get the last line location of the function and enable the 
                            // break point
                            Location location = locations.get(locations.size() - 1);
                            BreakpointRequest bpReq = erm.createBreakpointRequest(location);
                            bpReq.enable();
                        }
                    });

                }
                if (event instanceof BreakpointEvent) {
                    // disable the breakpoint event
                    event.request().disable();

                    ThreadReference thread = ((BreakpointEvent) event).thread();
                    StackFrame stackFrame = thread.frame(0);

                    // print all the visible variables with the respective values
                    Map<LocalVariable, Value> visibleVariables = (Map<LocalVariable, Value>) stackFrame.getValues(stackFrame.visibleVariables());
                    for (Map.Entry<LocalVariable, Value> entry : visibleVariables.entrySet()) {
                        System.out.println(entry.getKey() + ":" + entry.getValue());
                    }
                }
                vm.resume();
            }
        }
    }
}

这就是你调用方法的方式

new jdiDebugger().onMehtodeExit("-cp <whatever your class path is>", "<name of the class that contains the main method>", "<the name of the class that you wish to debug>", "<the name of the method that you want to debug>");
于 2017-12-24T22:36:21.827 回答
1

要回答有关接口的问题,这里是快速解释。

虚拟机 (VM) - 运行调试目标程序的 JVM。

连接器- 将调试器程序连接到调试目标的 JVM。LaunchingConnector 将启动 JVM 并连接到它。还有 AttachingConnector 连接到现有的正在运行的 JVM。

事件- 当 VM 在调试模式下运行调试目标程序时,它会触发几个事件,以便调试器程序可以根据需要采取行动。调试器程序还可以请求虚拟机触发某些默认情况下不触发的特殊事件。

要回答问题的断点部分,这里有一个片段。

Location location = classType.locationsOfLine(lineNumberToPutBreakpoint).get(0);
                    BreakpointRequest bpReq = vm.eventRequestManager().createBreakpointRequest(location);
                    bpReq.enable();

这篇文章有完整的简单的 Hello World 例子和进一步的解释。开始了解基本知识可能会很有用。

于 2019-04-10T06:38:25.013 回答