Build a simple debugger with jdi to set breakpoints and get the value of a variable

I want to create a debugger using the java debug interface .
My goal is to set a breakpoint and get the value of a variable.
I found this answer close to what I'm looking for, I understand that I need to use the following interfaces: - VirtualMachineManager , LaunchingConnector , ClassPrepareEvent , ClassPrepareRequest . But I can’t understand how to set a breakpoint on a particular line and get the value of a variable or in what order to use the interfaces.

For example, in the code below, how can I run it with jdi to get the value of the S variable

 import java.io.*; class Hello { public static void main(String args[]) { String S = "Hello World"; int a = 12; } } 

I am thinking of setting a debug point on line a = 12 or when closing the main method to get the value of S

+1
source share
2 answers

found this article helpful. here is also a good example to help you.

you can check the next project

and here is a sample code for the game.

 /* * 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 so 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>"); 
+3
source

In addition to the existing answer, this article provides a simple Hello World example with a detailed explanation. It may be helpful to start with a basic understanding.

http://itsallbinary.com/java-debug-interface-api-jdi-hello-world-example-programmatic-debugging-for-beginners/

0
source

Source: https://habr.com/ru/post/1315405/


All Articles