build a simple debugger with jdi to set breakpoints and retrieve the value of a variable

后端 未结 2 1454
死守一世寂寞
死守一世寂寞 2020-12-18 14:24

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

2条回答
  •  天涯浪人
    2020-12-18 15:19

    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 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() {
                            @Override
                            public void accept(Method m) {
                                List 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 visibleVariables = (Map) stackFrame.getValues(stackFrame.visibleVariables());
                        for (Map.Entry entry : visibleVariables.entrySet()) {
                            System.out.println(entry.getKey() + ":" + entry.getValue());
                        }
                    }
                    vm.resume();
                }
            }
        }
    }
    

    and this is how you call the method

    new jdiDebugger().onMehtodeExit("-cp ", "", "", "");
    

提交回复
热议问题