我希望使用java debug interface构建调试器。
我的目标是设置断点并获取变量的值。
我发现this答案接近我要找的内容,我知道我必须使用以下界面: - VirtualMachineManager
,LaunchingConnector
,ClassPrepareEvent
, ClassPrepareRequest
。
但我无法弄清楚,如何在特定行设置断点并获取变量的值或接口的使用顺序。
例如,在下面的代码中,如何使用jdi
继续运行它,以便获取变量S
的值
import java.io.*;
class Hello {
public static void main(String args[]) {
String S = "Hello World";
int a = 12;
}
}
我正在考虑在a = 12
行或方法main
结束时设置调试点,以便获得S
的值
答案 0 :(得分:3)
发现此article有用。 这也是一个很好的example,可以帮助你。
或者,您可以查看以下project
以下是您可以使用的示例代码。
/*
* 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>");
答案 1 :(得分:0)
要回答有关接口的问题,这里是快速解释。
虚拟机(VM)-运行调试目标程序的JVM。
连接器-将调试器程序连接到调试目标的JVM。 LaunchingConnector将启动JVM并连接到它。还有连接到现有正在运行的JVM的AttachingConnector。
事件-VM在调试模式下运行调试目标程序时,它将触发多个事件,以便调试程序可以根据需要采取措施。调试器程序还可以请求VM触发默认情况下不会触发的某些特殊事件。
要回答问题的断点,这是一个片段。
Location location = classType.locationsOfLine(lineNumberToPutBreakpoint).get(0);
BreakpointRequest bpReq = vm.eventRequestManager().createBreakpointRequest(location);
bpReq.enable();
This article具有完整的简单Hello World示例,并有进一步的说明。可能对入门的基本了解很有帮助。