815 lines · 26.5 KB · Java
RawDownload
/* * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.tools.example.debug.bdi; import com.sun.jdi.*;import com.sun.jdi.request.*;import com.sun.jdi.connect.*;import com.sun.tools.example.debug.expr.ExpressionParser;import com.sun.tools.example.debug.expr.ParseException; import java.io.*;import java.util.*; import com.sun.tools.example.debug.event.*; import javax.swing.SwingUtilities; /** * Move this towards being only state and functionality * that spans across Sessions (and thus VMs). */public class ExecutionManager {     private Session session;     /**     * Get/set JDI trace mode.     */    int traceMode = VirtualMachine.TRACE_NONE;   //////////////////    Listener registration    //////////////////   // Session Listeners     ArrayList<SessionListener> sessionListeners = new ArrayList<SessionListener>();     public void addSessionListener(SessionListener listener) {        sessionListeners.add(listener);    }     public void removeSessionListener(SessionListener listener) {        sessionListeners.remove(listener);    }   // Spec Listeners   ArrayList<SpecListener> specListeners = new ArrayList<SpecListener>();     public void addSpecListener(SpecListener cl) {        specListeners.add(cl);    }     public void removeSpecListener(SpecListener cl) {        specListeners.remove(cl);    }     // JDI Listeners     ArrayList<JDIListener> jdiListeners = new ArrayList<JDIListener>();     /**     * Adds a JDIListener     */    public void addJDIListener(JDIListener jl) {        jdiListeners.add(jl);    }     /**     * Adds a JDIListener - at the specified position     */    public void addJDIListener(int index, JDIListener jl) {        jdiListeners.add(index, jl);    }     /**     * Removes a JDIListener     */    public void removeJDIListener(JDIListener jl) {        jdiListeners.remove(jl);    }   // App Echo Listeners     private ArrayList<OutputListener> appEchoListeners = new ArrayList<OutputListener>();     public void addApplicationEchoListener(OutputListener l) {        appEchoListeners.add(l);    }     public void removeApplicationEchoListener(OutputListener l) {        appEchoListeners.remove(l);    }   // App Output Listeners     private ArrayList<OutputListener> appOutputListeners = new ArrayList<OutputListener>();     public void addApplicationOutputListener(OutputListener l) {        appOutputListeners.add(l);    }     public void removeApplicationOutputListener(OutputListener l) {        appOutputListeners.remove(l);    }   // App Error Listeners     private ArrayList<OutputListener> appErrorListeners = new ArrayList<OutputListener>();     public void addApplicationErrorListener(OutputListener l) {        appErrorListeners.add(l);    }     public void removeApplicationErrorListener(OutputListener l) {        appErrorListeners.remove(l);    }   // Diagnostic Listeners     private ArrayList<OutputListener> diagnosticsListeners = new ArrayList<OutputListener>();     public void addDiagnosticsListener(OutputListener l) {        diagnosticsListeners.add(l);    }     public void removeDiagnosticsListener(OutputListener l) {        diagnosticsListeners.remove(l);    }   ///////////    End Listener Registration    //////////////     //### We probably don't want this public    public VirtualMachine vm() {        return session == null ? null : session.vm;    }     void ensureActiveSession() throws NoSessionException {        if (session == null) {         throw new NoSessionException();      }    }     public EventRequestManager eventRequestManager() {        return vm() == null ? null : vm().eventRequestManager();    }     /**     * Get JDI trace mode.     */    public int getTraceMode(int mode) {        return traceMode;    }     /**     * Set JDI trace mode.     */    public void setTraceMode(int mode) {        traceMode = mode;        if (session != null) {            session.setTraceMode(mode);        }    }     /**     * Determine if VM is interrupted, i.e, present and not running.     */    public boolean isInterrupted() /* should: throws NoSessionException */ {//      ensureActiveSession();        return session.interrupted;    }     /**     * Return a list of ReferenceType objects for all     * currently loaded classes and interfaces.     * Array types are not returned.     */    public List<ReferenceType> allClasses() throws NoSessionException {        ensureActiveSession();        return vm().allClasses();    }     /**     * Return a ReferenceType object for the currently     * loaded class or interface whose fully-qualified     * class name is specified, else return null if there     * is none.     *     * In general, we must return a list of types, because     * multiple class loaders could have loaded a class     * with the same fully-qualified name.     */    public List<ReferenceType> findClassesByName(String name) throws NoSessionException {        ensureActiveSession();        return vm().classesByName(name);    }     /**     * Return a list of ReferenceType objects for all     * currently loaded classes and interfaces whose name     * matches the given pattern.  The pattern syntax is     * open to some future revision, but currently consists     * of a fully-qualified class name in which the first     * component may optionally be a "*" character, designating     * an arbitrary prefix.     */    public List<ReferenceType> findClassesMatchingPattern(String pattern)                                                throws NoSessionException {        ensureActiveSession();        List<ReferenceType> result = new ArrayList<ReferenceType>();  //### Is default size OK?        if (pattern.startsWith("*.")) {            // Wildcard matches any leading package name.            pattern = pattern.substring(1);            for (ReferenceType type : vm().allClasses()) {                if (type.name().endsWith(pattern)) {                    result.add(type);                }            }            return result;        } else {            // It's a class name.            return vm().classesByName(pattern);        }    }     /*     * Return a list of ThreadReference objects corresponding     * to the threads that are currently active in the VM.     * A thread is removed from the list just before the     * thread terminates.     */     public List<ThreadReference> allThreads() throws NoSessionException {        ensureActiveSession();        return vm().allThreads();    }     /*     * Return a list of ThreadGroupReference objects corresponding     * to the top-level threadgroups that are currently active in the VM.     * Note that a thread group may be empty, or contain no threads as     * descendents.     */     public List<ThreadGroupReference> topLevelThreadGroups() throws NoSessionException {        ensureActiveSession();        return vm().topLevelThreadGroups();    }     /*     * Return the system threadgroup.     */     public ThreadGroupReference systemThreadGroup()                                                throws NoSessionException {        ensureActiveSession();        return vm().topLevelThreadGroups().get(0);    }     /*     * Evaluate an expression.     */     public Value evaluate(final StackFrame f, String expr)        throws ParseException,                                            InvocationException,                                            InvalidTypeException,                                            ClassNotLoadedException,                                            NoSessionException,                                            IncompatibleThreadStateException {        ExpressionParser.GetFrame frameGetter = null;        ensureActiveSession();        if (f != null) {            frameGetter = new ExpressionParser.GetFrame() {                @Override                public StackFrame get() /* throws IncompatibleThreadStateException */ {                    return f;                }            };        }        return ExpressionParser.evaluate(expr, vm(), frameGetter);    }      /*     * Start a new VM.     */     public void run(boolean suspended,                    String vmArgs,                    String className,                    String args) throws VMLaunchFailureException {         endSession();         //### Set a breakpoint on 'main' method.        //### Would be cleaner if we could just bring up VM already suspended.        if (suspended) {            //### Set breakpoint at 'main(java.lang.String[])'.            List<String> argList = new ArrayList<String>(1);            argList.add("java.lang.String[]");            createMethodBreakpoint(className, "main", argList);        }         String cmdLine = className + " " + args;         startSession(new ChildSession(this, vmArgs, cmdLine,                                      appInput, appOutput, appError,                                      diagnostics));    }     /*     * Attach to an existing VM.     */    public void attach(String portName) throws VMLaunchFailureException {        endSession();         //### Changes made here for connectors have broken the        //### the 'Session' abstraction.  The 'Session.attach()'        //### method is intended to encapsulate all of the various        //### ways in which session start-up can fail. (maddox 12/18/98)         /*         * Now that attaches and launches both go through Connectors,         * it may be worth creating a new subclass of Session for         * attach sessions.         */        VirtualMachineManager mgr = Bootstrap.virtualMachineManager();        AttachingConnector connector = mgr.attachingConnectors().get(0);        Map<String, Connector.Argument> arguments = connector.defaultArguments();        arguments.get("port").setValue(portName);         Session newSession = internalAttach(connector, arguments);        if (newSession != null) {            startSession(newSession);        }    }     private Session internalAttach(AttachingConnector connector,                                   Map<String, Connector.Argument> arguments) {        try {            VirtualMachine vm = connector.attach(arguments);            return new Session(vm, this, diagnostics);        } catch (IOException ioe) {            diagnostics.putString("\n Unable to attach to target VM: " +                                  ioe.getMessage());        } catch (IllegalConnectorArgumentsException icae) {            diagnostics.putString("\n Invalid connector arguments: " +                                  icae.getMessage());        }        return null;    }     private Session internalListen(ListeningConnector connector,                                   Map<String, Connector.Argument> arguments) {        try {            VirtualMachine vm = connector.accept(arguments);            return new Session(vm, this, diagnostics);        } catch (IOException ioe) {            diagnostics.putString(                  "\n Unable to accept connection to target VM: " +                                  ioe.getMessage());        } catch (IllegalConnectorArgumentsException icae) {            diagnostics.putString("\n Invalid connector arguments: " +                                  icae.getMessage());        }        return null;    }     /*     * Connect via user specified arguments     * @return true on success     */    public boolean explictStart(Connector connector, Map<String, Connector.Argument> arguments)                                           throws VMLaunchFailureException {        Session newSession = null;         endSession();         if (connector instanceof LaunchingConnector) {            // we were launched, use ChildSession            newSession = new ChildSession(this, (LaunchingConnector)connector,                                          arguments,                                          appInput, appOutput, appError,                                          diagnostics);        } else if (connector instanceof AttachingConnector) {            newSession = internalAttach((AttachingConnector)connector,                                        arguments);        } else if (connector instanceof ListeningConnector) {            newSession = internalListen((ListeningConnector)connector,                                        arguments);        } else {            diagnostics.putString("\n Unknown connector: " + connector);        }        if (newSession != null) {            startSession(newSession);        }        return newSession != null;    }     /*     * Detach from VM.  If VM was started by debugger, terminate it.     */    public void detach() throws NoSessionException {        ensureActiveSession();        endSession();    }     private void startSession(Session s) throws VMLaunchFailureException {        if (!s.attach()) {            throw new VMLaunchFailureException();        }        session = s;        EventRequestManager em = vm().eventRequestManager();        ClassPrepareRequest classPrepareRequest = em.createClassPrepareRequest();        //### We must allow the deferred breakpoints to be resolved before        //### we continue executing the class.  We could optimize if there        //### were no deferred breakpoints outstanding for a particular class.        //### Can we do this with JDI?        classPrepareRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL);        classPrepareRequest.enable();        ClassUnloadRequest classUnloadRequest = em.createClassUnloadRequest();        classUnloadRequest.setSuspendPolicy(EventRequest.SUSPEND_NONE);        classUnloadRequest.enable();        ThreadStartRequest threadStartRequest = em.createThreadStartRequest();        threadStartRequest.setSuspendPolicy(EventRequest.SUSPEND_NONE);        threadStartRequest.enable();        ThreadDeathRequest threadDeathRequest = em.createThreadDeathRequest();        threadDeathRequest.setSuspendPolicy(EventRequest.SUSPEND_NONE);        threadDeathRequest.enable();        ExceptionRequest exceptionRequest =                                em.createExceptionRequest(null, false, true);        exceptionRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL);        exceptionRequest.enable();        validateThreadInfo();        session.interrupted = true;        notifySessionStart();    }     void endSession() {        if (session != null) {            session.detach();            session = null;            invalidateThreadInfo();            notifySessionDeath();        }    }     /*     * Suspend all VM activity.     */     public void interrupt() throws NoSessionException {        ensureActiveSession();        vm().suspend();        //### Is it guaranteed that the interrupt has happened?        validateThreadInfo();        session.interrupted = true;        notifyInterrupted();    }     /*     * Resume interrupted VM.     */     public void go() throws NoSessionException, VMNotInterruptedException {        ensureActiveSession();        invalidateThreadInfo();        session.interrupted = false;        notifyContinued();        vm().resume();    }     /*     * Stepping.     */    void clearPreviousStep(ThreadReference thread) {        /*

Lines 1–500 of 815.