使用jdi构建一个简单的调试器来设置断点并检索变量的值 [英] build a simple debugger with jdi to set breakpoints and retrieve the value of a variable
问题描述
我希望使用 java debug来构建调试器接口。
我的目标是设置断点并获取变量的值。
我发现这个答案接近我要找的内容,我明白我必须使用以下界面: - VirtualMachineManager
, LaunchingConnector
, ClassPrepareEvent
, ClassPrepareRequest
。
但我无法弄清楚,如何在特定行设置断点并获取变量的值或接口的使用顺序。
I am looking to build a debugger using java debug interface.
My objective is to set a breakpoint and get the value of a variable.
I found this answer close to what i am looking for, I understand that i have to use the following interfaces :- VirtualMachineManager
, LaunchingConnector
, ClassPrepareEvent
, ClassPrepareRequest
.
But I cant figure out, how to set a breakpoint at a particular line and get the value of a variable or in what order should the interfaces be used.
例如,在下面的代码中,我如何继续使用 jdi
运行它,以便我得到变量的值 S
For example in the code below, how do i proceed to run it with jdi
such that i get the value of the variable S
import java.io.*;
class Hello {
public static void main(String args[]) {
String S = "Hello World";
int a = 12;
}
}
我正在考虑设置调试点在行 a = 12
或在方法 main
结束时,我得到<$ c的值$ c> S
I am thinking of setting the debug point on the line a = 12
or at the closing of the method main
such that i get the value of S
推荐答案
found this article useful. here is also an good example that would help you.
或者,您可以查看以下项目
alternatively, you can check the following project
以下是您可以使用的示例代码。
and here is an example code for you to play on.
/*
* 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();
}
}
}
}
和这就是你如何调用方法
and this is how you call the method
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>");
这篇关于使用jdi构建一个简单的调试器来设置断点并检索变量的值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!