| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
/*  | 
 | 
 * This source code is provided to illustrate the usage of a given feature  | 
 | 
 * or technique and has been deliberately simplified. Additional steps  | 
 | 
 * required for a production-quality application, such as security checks,  | 
 | 
 * input validation and proper error handling, might not be present in  | 
 | 
 * this sample code.  | 
 | 
 */  | 
 | 
 | 
 | 
 | 
 | 
package com.sun.tools.example.debug.gui;  | 
 | 
 | 
 | 
import java.io.*;  | 
 | 
import java.util.*;  | 
 | 
 | 
 | 
import com.sun.jdi.*;  | 
 | 
import com.sun.tools.example.debug.bdi.*;  | 
 | 
 | 
 | 
public class CommandInterpreter { | 
 | 
 | 
 | 
    boolean echo;  | 
 | 
 | 
 | 
    Environment env;  | 
 | 
 | 
 | 
    private ContextManager context;  | 
 | 
    private ExecutionManager runtime;  | 
 | 
    private ClassManager classManager;  | 
 | 
    private SourceManager sourceManager;  | 
 | 
 | 
 | 
    private OutputSink out;   | 
 | 
    private String lastCommand = "help";  | 
 | 
 | 
 | 
    public CommandInterpreter(Environment env) { | 
 | 
        this(env, true);  | 
 | 
    }  | 
 | 
 | 
 | 
    public CommandInterpreter(Environment env, boolean echo) { | 
 | 
        this.env = env;  | 
 | 
        this.echo = echo;  | 
 | 
        this.runtime = env.getExecutionManager();  | 
 | 
        this.context = env.getContextManager();  | 
 | 
        this.classManager = env.getClassManager();  | 
 | 
        this.sourceManager = env.getSourceManager();  | 
 | 
    }  | 
 | 
 | 
 | 
    private ThreadReference[] threads = null;  | 
 | 
 | 
 | 
    /*  | 
 | 
     * The numbering of threads is relative to the current set of threads,  | 
 | 
     * and may be affected by the creation and termination of new threads.  | 
 | 
     * Commands issued using such thread ids will only give reliable behavior  | 
 | 
     * relative to what was shown earlier in 'list' commands if the VM is interrupted.  | 
 | 
     * We need a better scheme.  | 
 | 
     */  | 
 | 
 | 
 | 
    private ThreadReference[] threads() throws NoSessionException { | 
 | 
        if (threads == null) { | 
 | 
            ThreadIterator ti = new ThreadIterator(getDefaultThreadGroup());  | 
 | 
            List<ThreadReference> tlist = new ArrayList<ThreadReference>();  | 
 | 
            while (ti.hasNext()) { | 
 | 
                tlist.add(ti.nextThread());  | 
 | 
            }  | 
 | 
            threads = tlist.toArray(new ThreadReference[tlist.size()]);  | 
 | 
        }  | 
 | 
        return threads;  | 
 | 
    }  | 
 | 
 | 
 | 
    private ThreadReference findThread(String idToken) throws NoSessionException { | 
 | 
        String id;  | 
 | 
        ThreadReference thread = null;  | 
 | 
        if (idToken.startsWith("t@")) { | 
 | 
            id = idToken.substring(2);  | 
 | 
        } else { | 
 | 
            id = idToken;  | 
 | 
        }  | 
 | 
        try { | 
 | 
            ThreadReference[] threads = threads();  | 
 | 
            long threadID = Long.parseLong(id, 16);  | 
 | 
            for (ThreadReference thread2 : threads) { | 
 | 
                if (thread2.uniqueID() == threadID) { | 
 | 
                    thread = thread2;  | 
 | 
                    break;  | 
 | 
                }  | 
 | 
            }  | 
 | 
            if (thread == null) { | 
 | 
                  | 
 | 
                env.failure("\"" + idToken + "\" is not a valid thread id."); | 
 | 
            }  | 
 | 
        } catch (NumberFormatException e) { | 
 | 
            env.error("Thread id \"" + idToken + "\" is ill-formed."); | 
 | 
            thread = null;  | 
 | 
        }  | 
 | 
        return thread;  | 
 | 
    }  | 
 | 
 | 
 | 
    private ThreadIterator allThreads() throws NoSessionException { | 
 | 
        threads = null;  | 
 | 
          | 
 | 
        return new ThreadIterator(runtime.topLevelThreadGroups());  | 
 | 
    }  | 
 | 
 | 
 | 
    private ThreadIterator currentThreadGroupThreads() throws NoSessionException { | 
 | 
        threads = null;  | 
 | 
        return new ThreadIterator(getDefaultThreadGroup());  | 
 | 
    }  | 
 | 
 | 
 | 
    private ThreadGroupIterator allThreadGroups() throws NoSessionException { | 
 | 
        threads = null;  | 
 | 
        return new ThreadGroupIterator(runtime.topLevelThreadGroups());  | 
 | 
    }  | 
 | 
 | 
 | 
    private ThreadGroupReference defaultThreadGroup;  | 
 | 
 | 
 | 
    private ThreadGroupReference getDefaultThreadGroup() throws NoSessionException { | 
 | 
        if (defaultThreadGroup == null) { | 
 | 
            defaultThreadGroup = runtime.systemThreadGroup();  | 
 | 
        }  | 
 | 
        return defaultThreadGroup;  | 
 | 
    }  | 
 | 
 | 
 | 
    private void setDefaultThreadGroup(ThreadGroupReference tg) { | 
 | 
        defaultThreadGroup = tg;  | 
 | 
    }  | 
 | 
 | 
 | 
    /*  | 
 | 
     * Command handlers.  | 
 | 
     */  | 
 | 
 | 
 | 
    // Command: classes  | 
 | 
 | 
 | 
    private void commandClasses() throws NoSessionException { | 
 | 
        OutputSink out = env.getOutputSink();  | 
 | 
          | 
 | 
        for (ReferenceType refType : runtime.allClasses()) { | 
 | 
            out.println(refType.name());  | 
 | 
        }  | 
 | 
        out.show();  | 
 | 
    }  | 
 | 
 | 
 | 
 | 
 | 
    // Command: methods  | 
 | 
 | 
 | 
    private void commandMethods(StringTokenizer t) throws NoSessionException { | 
 | 
        if (!t.hasMoreTokens()) { | 
 | 
            env.error("No class specified."); | 
 | 
            return;  | 
 | 
        }  | 
 | 
        String idClass = t.nextToken();  | 
 | 
        ReferenceType cls = findClass(idClass);  | 
 | 
        if (cls != null) { | 
 | 
            List<Method> methods = cls.allMethods();  | 
 | 
            OutputSink out = env.getOutputSink();  | 
 | 
            for (int i = 0; i < methods.size(); i++) { | 
 | 
                Method method = methods.get(i);  | 
 | 
                out.print(method.declaringType().name() + " " +  | 
 | 
                            method.name() + "("); | 
 | 
                Iterator<String> it = method.argumentTypeNames().iterator();  | 
 | 
                if (it.hasNext()) { | 
 | 
                    while (true) { | 
 | 
                        out.print(it.next());  | 
 | 
                        if (!it.hasNext()) { | 
 | 
                            break;  | 
 | 
                        }  | 
 | 
                        out.print(", "); | 
 | 
                    }  | 
 | 
                }  | 
 | 
                out.println(")"); | 
 | 
            }  | 
 | 
            out.show();  | 
 | 
        } else { | 
 | 
              | 
 | 
            env.failure("\"" + idClass + "\" is not a valid id or class name."); | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private ReferenceType findClass(String pattern) throws NoSessionException { | 
 | 
        List<ReferenceType> results = runtime.findClassesMatchingPattern(pattern);  | 
 | 
        if (results.size() > 0) { | 
 | 
              | 
 | 
            return results.get(0);  | 
 | 
        }  | 
 | 
        return null;  | 
 | 
    }  | 
 | 
 | 
 | 
    // Command: threads  | 
 | 
 | 
 | 
    private void commandThreads(StringTokenizer t) throws NoSessionException { | 
 | 
        if (!t.hasMoreTokens()) { | 
 | 
            OutputSink out = env.getOutputSink();  | 
 | 
            printThreadGroup(out, getDefaultThreadGroup(), 0);  | 
 | 
            out.show();  | 
 | 
            return;  | 
 | 
        }  | 
 | 
        String name = t.nextToken();  | 
 | 
        ThreadGroupReference tg = findThreadGroup(name);  | 
 | 
        if (tg == null) { | 
 | 
            env.failure(name + " is not a valid threadgroup name.");  | 
 | 
        } else { | 
 | 
            OutputSink out = env.getOutputSink();  | 
 | 
            printThreadGroup(out, tg, 0);  | 
 | 
            out.show();  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private ThreadGroupReference findThreadGroup(String name) throws NoSessionException { | 
 | 
          | 
 | 
        ThreadGroupIterator tgi = allThreadGroups();  | 
 | 
        while (tgi.hasNext()) { | 
 | 
            ThreadGroupReference tg = tgi.nextThreadGroup();  | 
 | 
            if (tg.name().equals(name)) { | 
 | 
                return tg;  | 
 | 
            }  | 
 | 
        }  | 
 | 
        return null;  | 
 | 
    }  | 
 | 
 | 
 | 
    private int printThreadGroup(OutputSink out, ThreadGroupReference tg, int iThread) { | 
 | 
        out.println("Group " + tg.name() + ":"); | 
 | 
        List<ThreadReference> tlist = tg.threads();  | 
 | 
        int maxId = 0;  | 
 | 
        int maxName = 0;  | 
 | 
        for (int i = 0 ; i < tlist.size() ; i++) { | 
 | 
            ThreadReference thr = tlist.get(i);  | 
 | 
            int len = Utils.description(thr).length();  | 
 | 
            if (len > maxId) { | 
 | 
                maxId = len;  | 
 | 
            }  | 
 | 
            String name = thr.name();  | 
 | 
            int iDot = name.lastIndexOf('.'); | 
 | 
            if (iDot >= 0 && name.length() > iDot) { | 
 | 
                name = name.substring(iDot + 1);  | 
 | 
            }  | 
 | 
            if (name.length() > maxName) { | 
 | 
                maxName = name.length();  | 
 | 
        }  | 
 | 
        }  | 
 | 
        String maxNumString = String.valueOf(iThread + tlist.size());  | 
 | 
        int maxNumDigits = maxNumString.length();  | 
 | 
        for (int i = 0 ; i < tlist.size() ; i++) { | 
 | 
            ThreadReference thr = tlist.get(i);  | 
 | 
            char buf[] = new char[80];  | 
 | 
            for (int j = 0; j < 79; j++) { | 
 | 
                buf[j] = ' ';  | 
 | 
            }  | 
 | 
            buf[79] = '\0';  | 
 | 
            StringBuffer sbOut = new StringBuffer();  | 
 | 
            sbOut.append(buf);  | 
 | 
 | 
 | 
              | 
 | 
            String numString = String.valueOf(iThread + i + 1);  | 
 | 
            sbOut.insert(maxNumDigits - numString.length(),  | 
 | 
                         numString);  | 
 | 
            sbOut.insert(maxNumDigits, ".");  | 
 | 
 | 
 | 
            int iBuf = maxNumDigits + 2;  | 
 | 
            sbOut.insert(iBuf, Utils.description(thr));  | 
 | 
            iBuf += maxId + 1;  | 
 | 
            String name = thr.name();  | 
 | 
            int iDot = name.lastIndexOf('.'); | 
 | 
            if (iDot >= 0 && name.length() > iDot) { | 
 | 
                name = name.substring(iDot + 1);  | 
 | 
            }  | 
 | 
            sbOut.insert(iBuf, name);  | 
 | 
            iBuf += maxName + 1;  | 
 | 
            sbOut.insert(iBuf, Utils.getStatus(thr));  | 
 | 
            sbOut.setLength(79);  | 
 | 
            out.println(sbOut.toString());  | 
 | 
        }  | 
 | 
        for (ThreadGroupReference tg0 : tg.threadGroups()) { | 
 | 
            if (!tg.equals(tg0)) {   | 
 | 
                iThread += printThreadGroup(out, tg0, iThread + tlist.size());  | 
 | 
            }  | 
 | 
        }  | 
 | 
        return tlist.size();  | 
 | 
    }  | 
 | 
 | 
 | 
    // Command: threadgroups  | 
 | 
 | 
 | 
    private void commandThreadGroups() throws NoSessionException { | 
 | 
        ThreadGroupIterator it = allThreadGroups();  | 
 | 
        int cnt = 0;  | 
 | 
        OutputSink out = env.getOutputSink();  | 
 | 
        while (it.hasNext()) { | 
 | 
            ThreadGroupReference tg = it.nextThreadGroup();  | 
 | 
            ++cnt;  | 
 | 
            out.println("" + cnt + ". " + Utils.description(tg) + " " + tg.name()); | 
 | 
        }  | 
 | 
        out.show();  | 
 | 
    }  | 
 | 
 | 
 | 
    // Command: thread  | 
 | 
 | 
 | 
    private void commandThread(StringTokenizer t) throws NoSessionException { | 
 | 
        if (!t.hasMoreTokens()) { | 
 | 
            env.error("Thread number not specified."); | 
 | 
            return;  | 
 | 
        }  | 
 | 
        ThreadReference thread = findThread(t.nextToken());  | 
 | 
        if (thread != null) { | 
 | 
              | 
 | 
            context.setCurrentThread(thread);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    // Command: threadgroup  | 
 | 
 | 
 | 
    private void commandThreadGroup(StringTokenizer t) throws NoSessionException { | 
 | 
        if (!t.hasMoreTokens()) { | 
 | 
            env.error("Threadgroup name not specified."); | 
 | 
            return;  | 
 | 
        }  | 
 | 
        String name = t.nextToken();  | 
 | 
        ThreadGroupReference tg = findThreadGroup(name);  | 
 | 
        if (tg == null) { | 
 | 
            env.failure(name + " is not a valid threadgroup name.");  | 
 | 
        } else { | 
 | 
              | 
 | 
            setDefaultThreadGroup(tg);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    // Command: run  | 
 | 
 | 
 | 
    private void commandRun(StringTokenizer t) throws NoSessionException { | 
 | 
        if (doLoad(false, t)) { | 
 | 
            env.notice("Running ..."); | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    // Command: load  | 
 | 
 | 
 | 
    private void commandLoad(StringTokenizer t) throws NoSessionException { | 
 | 
        if (doLoad(true, t)) {} | 
 | 
    }  | 
 | 
 | 
 | 
    private boolean doLoad(boolean suspended,  | 
 | 
                           StringTokenizer t) throws NoSessionException { | 
 | 
 | 
 | 
        String clname;  | 
 | 
 | 
 | 
        if (!t.hasMoreTokens()) { | 
 | 
            clname = context.getMainClassName();  | 
 | 
            if (!clname.equals("")) { | 
 | 
                  | 
 | 
                try { | 
 | 
                    String vmArgs = context.getVmArguments();  | 
 | 
                    runtime.run(suspended,  | 
 | 
                                vmArgs,  | 
 | 
                                clname,  | 
 | 
                                context.getProgramArguments());  | 
 | 
                    return true;  | 
 | 
                } catch (VMLaunchFailureException e) { | 
 | 
                    env.failure("Attempt to launch main class \"" + clname + "\" failed."); | 
 | 
                }  | 
 | 
            } else { | 
 | 
                env.failure("No main class specified and no current default defined."); | 
 | 
            }  | 
 | 
        } else { | 
 | 
            clname = t.nextToken();  | 
 | 
            StringBuffer sbuf = new StringBuffer();  | 
 | 
              | 
 | 
            while (t.hasMoreTokens()) { | 
 | 
                String tok = t.nextToken();  | 
 | 
                sbuf.append(tok);  | 
 | 
                if (t.hasMoreTokens()) { | 
 | 
                    sbuf.append(' '); | 
 | 
                }  | 
 | 
            }  | 
 | 
            String args = sbuf.toString();  | 
 | 
            try { | 
 | 
                String vmArgs = context.getVmArguments();  | 
 | 
                runtime.run(suspended, vmArgs, clname, args);  | 
 | 
                context.setMainClassName(clname);  | 
 | 
                  | 
 | 
                context.setProgramArguments(args);  | 
 | 
                return true;  | 
 | 
            } catch (VMLaunchFailureException e) { | 
 | 
                env.failure("Attempt to launch main class \"" + clname + "\" failed."); | 
 | 
            }  | 
 | 
        }  | 
 | 
        return false;  | 
 | 
    }  | 
 | 
 | 
 | 
    // Command: connect  | 
 | 
 | 
 | 
    private void commandConnect(StringTokenizer t) { | 
 | 
        try { | 
 | 
            LaunchTool.queryAndLaunchVM(runtime);  | 
 | 
        } catch (VMLaunchFailureException e) { | 
 | 
            env.failure("Attempt to connect failed."); | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    // Command: attach  | 
 | 
 | 
 | 
    private void commandAttach(StringTokenizer t) { | 
 | 
        String portName;  | 
 | 
        if (!t.hasMoreTokens()) { | 
 | 
            portName = context.getRemotePort();  | 
 | 
            if (!portName.equals("")) { | 
 | 
                try { | 
 | 
                    runtime.attach(portName);  | 
 | 
                } catch (VMLaunchFailureException e) { | 
 | 
                    env.failure("Attempt to attach to port \"" + portName + "\" failed."); | 
 | 
                }  | 
 | 
            } else { | 
 | 
                env.failure("No port specified and no current default defined."); | 
 | 
            }  | 
 | 
        } else { | 
 | 
            portName = t.nextToken();  | 
 | 
            try { | 
 | 
                runtime.attach(portName);  | 
 | 
            } catch (VMLaunchFailureException e) { | 
 | 
                env.failure("Attempt to attach to port \"" + portName + "\" failed."); | 
 | 
            }  | 
 | 
            context.setRemotePort(portName);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    // Command: detach  | 
 | 
 | 
 | 
    private void commandDetach(StringTokenizer t) throws NoSessionException { | 
 | 
        runtime.detach();  | 
 | 
    }  | 
 | 
 | 
 | 
    // Command: interrupt  | 
 | 
 | 
 | 
    private void commandInterrupt(StringTokenizer t) throws NoSessionException { | 
 | 
        runtime.interrupt();  | 
 | 
    }  | 
 | 
 | 
 | 
    // Command: suspend  | 
 | 
 | 
 | 
    private void commandSuspend(StringTokenizer t) throws NoSessionException { | 
 | 
        if (!t.hasMoreTokens()) { | 
 | 
            // Suspend all threads in the current thread group.  | 
 | 
            //### Issue: help message says default is all threads.  | 
 | 
              | 
 | 
            ThreadIterator ti = currentThreadGroupThreads();  | 
 | 
            while (ti.hasNext()) { | 
 | 
                  | 
 | 
                ti.nextThread().suspend();  | 
 | 
            }  | 
 | 
            env.notice("All (non-system) threads suspended."); | 
 | 
        } else { | 
 | 
            while (t.hasMoreTokens()) { | 
 | 
                ThreadReference thread = findThread(t.nextToken());  | 
 | 
                if (thread != null) { | 
 | 
                      | 
 | 
                    runtime.suspendThread(thread);  | 
 | 
                }  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    // Command: resume  | 
 | 
 | 
 | 
    private void commandResume(StringTokenizer t) throws NoSessionException { | 
 | 
         if (!t.hasMoreTokens()) { | 
 | 
            // Suspend all threads in the current thread group.  | 
 | 
            //### Issue: help message says default is all threads.  | 
 | 
              | 
 | 
            ThreadIterator ti = currentThreadGroupThreads();  | 
 | 
            while (ti.hasNext()) { | 
 | 
                  | 
 | 
                ti.nextThread().resume();  | 
 | 
            }  | 
 | 
            env.notice("All threads resumed."); | 
 | 
         } else { | 
 | 
             while (t.hasMoreTokens()) { | 
 | 
                ThreadReference thread = findThread(t.nextToken());  | 
 | 
                if (thread != null) { | 
 | 
                      | 
 | 
                    runtime.resumeThread(thread);  | 
 | 
                }  | 
 | 
             }  | 
 | 
         }  | 
 | 
    }  | 
 | 
 | 
 | 
    // Command: cont  | 
 | 
 | 
 | 
    private void commandCont() throws NoSessionException { | 
 | 
        try { | 
 | 
            runtime.go();  | 
 | 
        } catch (VMNotInterruptedException e) { | 
 | 
              | 
 | 
            env.notice("Target VM is already running."); | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    // Command: step  | 
 | 
 | 
 | 
    private void commandStep(StringTokenizer t) throws NoSessionException{ | 
 | 
        ThreadReference current = context.getCurrentThread();  | 
 | 
        if (current == null) { | 
 | 
            env.failure("No current thread."); | 
 | 
            return;  | 
 | 
        }  | 
 | 
        try { | 
 | 
            if (t.hasMoreTokens() &&  | 
 | 
                t.nextToken().toLowerCase().equals("up")) { | 
 | 
                runtime.stepOut(current);  | 
 | 
            } else { | 
 | 
                runtime.stepIntoLine(current);  | 
 | 
            }  | 
 | 
        } catch (AbsentInformationException e) { | 
 | 
            env.failure("No linenumber information available -- " + | 
 | 
                            "Try \"stepi\" to step by instructions.");  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    // Command: stepi  | 
 | 
 | 
 | 
    private void commandStepi() throws NoSessionException { | 
 | 
        ThreadReference current = context.getCurrentThread();  | 
 | 
        if (current == null) { | 
 | 
            env.failure("No current thread."); | 
 | 
            return;  | 
 | 
        }  | 
 | 
        runtime.stepIntoInstruction(current);  | 
 | 
    }  | 
 | 
 | 
 | 
    // Command: next  | 
 | 
 | 
 | 
    private void commandNext() throws NoSessionException { | 
 | 
        ThreadReference current = context.getCurrentThread();  | 
 | 
        if (current == null) { | 
 | 
            env.failure("No current thread."); | 
 | 
            return;  | 
 | 
        }  | 
 | 
        try { | 
 | 
            runtime.stepOverLine(current);  | 
 | 
        } catch (AbsentInformationException e) { | 
 | 
            env.failure("No linenumber information available -- " + | 
 | 
                            "Try \"nexti\" to step by instructions.");  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    // Command: nexti  (NEW)  | 
 | 
 | 
 | 
    private void commandNexti() throws NoSessionException { | 
 | 
        ThreadReference current = context.getCurrentThread();  | 
 | 
        if (current == null) { | 
 | 
            env.failure("No current thread."); | 
 | 
            return;  | 
 | 
        }  | 
 | 
        runtime.stepOverInstruction(current);  | 
 | 
    }  | 
 | 
 | 
 | 
    // Command: kill  | 
 | 
 | 
 | 
    private void commandKill(StringTokenizer t) throws NoSessionException { | 
 | 
        //### Should change the way in which thread ids and threadgroup names  | 
 | 
          | 
 | 
         if (!t.hasMoreTokens()) { | 
 | 
            env.error("Usage: kill <threadgroup name> or <thread id>"); | 
 | 
            return;  | 
 | 
        }  | 
 | 
        while (t.hasMoreTokens()) { | 
 | 
            String idToken = t.nextToken();  | 
 | 
            ThreadReference thread = findThread(idToken);  | 
 | 
            if (thread != null) { | 
 | 
                runtime.stopThread(thread);  | 
 | 
                env.notice("Thread " + thread.name() + " killed."); | 
 | 
                return;  | 
 | 
            } else { | 
 | 
                /* Check for threadgroup name, NOT skipping "system". */  | 
 | 
                //### Should skip "system"?  Classic 'jdb' does this.  | 
 | 
                  | 
 | 
                ThreadGroupIterator itg = allThreadGroups();  | 
 | 
                while (itg.hasNext()) { | 
 | 
                    ThreadGroupReference tg = itg.nextThreadGroup();  | 
 | 
                    if (tg.name().equals(idToken)) { | 
 | 
                        ThreadIterator it = new ThreadIterator(tg);  | 
 | 
                        while (it.hasNext()) { | 
 | 
                            runtime.stopThread(it.nextThread());  | 
 | 
                        }  | 
 | 
                        env.notice("Threadgroup " + tg.name() + "killed."); | 
 | 
                        return;  | 
 | 
                    }  | 
 | 
                }  | 
 | 
                env.failure("\"" + idToken + | 
 | 
                            "\" is not a valid threadgroup or id.");  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
 | 
 | 
    /*************  | 
 | 
    // TODO  | 
 | 
    private void commandCatchException(StringTokenizer t) throws NoSessionException {} | 
 | 
    // TODO  | 
 | 
    private void commandIgnoreException(StringTokenizer t) throws NoSessionException {} | 
 | 
    *************/  | 
 | 
 | 
 | 
    // Command: up  | 
 | 
 | 
 | 
    //### Print current frame after command?  | 
 | 
 | 
 | 
    int readCount(StringTokenizer t) { | 
 | 
        int cnt = 1;  | 
 | 
        if (t.hasMoreTokens()) { | 
 | 
            String idToken = t.nextToken();  | 
 | 
            try { | 
 | 
                cnt = Integer.valueOf(idToken).intValue();  | 
 | 
            } catch (NumberFormatException e) { | 
 | 
                cnt = -1;  | 
 | 
            }  | 
 | 
        }  | 
 | 
        return cnt;  | 
 | 
    }  | 
 | 
 | 
 | 
    void commandUp(StringTokenizer t) throws NoSessionException { | 
 | 
        ThreadReference current = context.getCurrentThread();  | 
 | 
        if (current == null) { | 
 | 
            env.failure("No current thread."); | 
 | 
            return;  | 
 | 
        }  | 
 | 
        int nLevels = readCount(t);  | 
 | 
        if (nLevels <= 0) { | 
 | 
            env.error("usage: up [n frames]"); | 
 | 
            return;  | 
 | 
        }  | 
 | 
        try { | 
 | 
            int delta = context.moveCurrentFrameIndex(current, -nLevels);  | 
 | 
            if (delta == 0) { | 
 | 
                env.notice("Already at top of stack."); | 
 | 
            } else if (-delta < nLevels) { | 
 | 
                env.notice("Moved up " + delta + " frames to top of stack."); | 
 | 
            }  | 
 | 
        } catch (VMNotInterruptedException e) { | 
 | 
            env.failure("Target VM must be in interrupted state."); | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private void commandDown(StringTokenizer t) throws NoSessionException { | 
 | 
        ThreadReference current = context.getCurrentThread();  | 
 | 
        if (current == null) { | 
 | 
            env.failure("No current thread."); | 
 | 
            return;  | 
 | 
        }  | 
 | 
        int nLevels = readCount(t);  | 
 | 
        if (nLevels <= 0) { | 
 | 
            env.error("usage: down [n frames]"); | 
 | 
            return;  | 
 | 
        }  | 
 | 
        try { | 
 | 
            int delta = context.moveCurrentFrameIndex(current, nLevels);  | 
 | 
            if (delta == 0) { | 
 | 
                env.notice("Already at bottom of stack."); | 
 | 
            } else if (delta < nLevels) { | 
 | 
                env.notice("Moved down " + delta + " frames to bottom of stack."); | 
 | 
            }  | 
 | 
        } catch (VMNotInterruptedException e) { | 
 | 
            env.failure("Target VM must be in interrupted state."); | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    // Command: frame  | 
 | 
 | 
 | 
    private void commandFrame(StringTokenizer t) throws NoSessionException { | 
 | 
        ThreadReference current = context.getCurrentThread();  | 
 | 
        if (current == null) { | 
 | 
            env.failure("No current thread."); | 
 | 
            return;  | 
 | 
        }  | 
 | 
        if (!t.hasMoreTokens()) { | 
 | 
            env.error("usage: frame <frame-index>"); | 
 | 
            return;  | 
 | 
        }  | 
 | 
        String idToken = t.nextToken();  | 
 | 
        int n;  | 
 | 
        try { | 
 | 
            n = Integer.valueOf(idToken).intValue();  | 
 | 
        } catch (NumberFormatException e) { | 
 | 
            n = 0;  | 
 | 
        }  | 
 | 
        if (n <= 0) { | 
 | 
            env.error("use positive frame index"); | 
 | 
            return;  | 
 | 
        }  | 
 | 
        try { | 
 | 
            int delta = context.setCurrentFrameIndex(current, n);  | 
 | 
            if (delta == 0) { | 
 | 
                env.notice("Frame unchanged."); | 
 | 
            } else if (delta < 0) { | 
 | 
                env.notice("Moved up " + -delta + " frames."); | 
 | 
            } else { | 
 | 
                env.notice("Moved down " + delta + " frames."); | 
 | 
            }  | 
 | 
        } catch (VMNotInterruptedException e) { | 
 | 
            env.failure("Target VM must be in interrupted state."); | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    // Command: where  | 
 | 
 | 
 | 
    //### Should we insist that VM be interrupted here?  | 
 | 
    //### There is an inconsistency between the 'where' command  | 
 | 
    //### and 'up' and 'down' in this respect.  | 
 | 
 | 
 | 
    private void commandWhere(StringTokenizer t, boolean showPC)  | 
 | 
                                                throws NoSessionException { | 
 | 
        ThreadReference current = context.getCurrentThread();  | 
 | 
        if (!t.hasMoreTokens()) { | 
 | 
            if (current == null) { | 
 | 
                env.error("No thread specified."); | 
 | 
                return;  | 
 | 
            }  | 
 | 
            dumpStack(current, showPC);  | 
 | 
        } else { | 
 | 
            String token = t.nextToken();  | 
 | 
            if (token.toLowerCase().equals("all")) { | 
 | 
                ThreadIterator it = allThreads();  | 
 | 
                while (it.hasNext()) { | 
 | 
                    ThreadReference thread = it.next();  | 
 | 
                    out.println(thread.name() + ": ");  | 
 | 
                    dumpStack(thread, showPC);  | 
 | 
                }  | 
 | 
            } else { | 
 | 
                ThreadReference thread = findThread(t.nextToken());  | 
 | 
                //### Do we want to set current thread here?  | 
 | 
                  | 
 | 
                if (thread != null) { | 
 | 
                    context.setCurrentThread(thread);  | 
 | 
                }  | 
 | 
                dumpStack(thread, showPC);  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private void dumpStack(ThreadReference thread, boolean showPC) { | 
 | 
        //### Check for these.  | 
 | 
        //env.failure("Thread no longer exists."); | 
 | 
        //env.failure("Target VM must be in interrupted state."); | 
 | 
        //env.failure("Current thread isn't suspended."); | 
 | 
          | 
 | 
        List<StackFrame> stack = null;  | 
 | 
        try { | 
 | 
            stack = thread.frames();  | 
 | 
        } catch (IncompatibleThreadStateException e) { | 
 | 
            env.failure("Thread is not suspended."); | 
 | 
        }  | 
 | 
        //### Fix this!  | 
 | 
        //### Previously mishandled cases where thread was not current.  | 
 | 
          | 
 | 
        int frameIndex = 0;  | 
 | 
          | 
 | 
        if (stack == null) { | 
 | 
            env.failure("Thread is not running (no stack)."); | 
 | 
        } else { | 
 | 
            OutputSink out = env.getOutputSink();  | 
 | 
            int nFrames = stack.size();  | 
 | 
            for (int i = frameIndex; i < nFrames; i++) { | 
 | 
                StackFrame frame = stack.get(i);  | 
 | 
                Location loc = frame.location();  | 
 | 
                Method meth = loc.method();  | 
 | 
                out.print("  [" + (i + 1) + "] "); | 
 | 
                out.print(meth.declaringType().name());  | 
 | 
                out.print('.'); | 
 | 
                out.print(meth.name());  | 
 | 
                out.print(" ("); | 
 | 
                if (meth.isNative()) { | 
 | 
                    out.print("native method"); | 
 | 
                } else if (loc.lineNumber() != -1) { | 
 | 
                    try { | 
 | 
                        out.print(loc.sourceName());  | 
 | 
                    } catch (AbsentInformationException e) { | 
 | 
                        out.print("<unknown>"); | 
 | 
                    }  | 
 | 
                    out.print(':'); | 
 | 
                    out.print(loc.lineNumber());  | 
 | 
                }  | 
 | 
                out.print(')'); | 
 | 
                if (showPC) { | 
 | 
                    long pc = loc.codeIndex();  | 
 | 
                    if (pc != -1) { | 
 | 
                        out.print(", pc = " + pc); | 
 | 
                    }  | 
 | 
                }  | 
 | 
                out.println();  | 
 | 
            }  | 
 | 
            out.show();  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private void listEventRequests() throws NoSessionException { | 
 | 
          | 
 | 
        List<EventRequestSpec> specs = runtime.eventRequestSpecs();  | 
 | 
        if (specs.isEmpty()) { | 
 | 
            env.notice("No breakpoints/watchpoints/exceptions set."); | 
 | 
        } else { | 
 | 
            OutputSink out = env.getOutputSink();  | 
 | 
            out.println("Current breakpoints/watchpoints/exceptions set:"); | 
 | 
            for (EventRequestSpec bp : specs) { | 
 | 
                out.println("\t" + bp); | 
 | 
            }  | 
 | 
            out.show();  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private BreakpointSpec parseBreakpointSpec(String bptSpec) { | 
 | 
        StringTokenizer t = new StringTokenizer(bptSpec);  | 
 | 
        BreakpointSpec bpSpec = null;  | 
 | 
 | 
 | 
            String token = t.nextToken("@:( \t\n\r"); | 
 | 
            // We can't use hasMoreTokens here because it will cause any leading  | 
 | 
              | 
 | 
            String rest;  | 
 | 
            try { | 
 | 
                rest = t.nextToken("").trim(); | 
 | 
            } catch (NoSuchElementException e) { | 
 | 
                rest = null;  | 
 | 
            }  | 
 | 
            if ((rest != null) && rest.startsWith("@")) { | 
 | 
                t = new StringTokenizer(rest.substring(1));  | 
 | 
                String sourceName = token;  | 
 | 
                String lineToken = t.nextToken();  | 
 | 
                int lineNumber = Integer.valueOf(lineToken).intValue();  | 
 | 
                if (t.hasMoreTokens()) { | 
 | 
                    return null;  | 
 | 
                }  | 
 | 
                bpSpec = runtime.createSourceLineBreakpoint(sourceName,  | 
 | 
                                                            lineNumber);  | 
 | 
            } else if ((rest != null) && rest.startsWith(":")) { | 
 | 
                t = new StringTokenizer(rest.substring(1));  | 
 | 
                String classId = token;  | 
 | 
                String lineToken = t.nextToken();  | 
 | 
                int lineNumber = Integer.valueOf(lineToken).intValue();  | 
 | 
                if (t.hasMoreTokens()) { | 
 | 
                    return null;  | 
 | 
                }  | 
 | 
                bpSpec = runtime.createClassLineBreakpoint(classId, lineNumber);  | 
 | 
            } else { | 
 | 
                  | 
 | 
                int idot = token.lastIndexOf("."); | 
 | 
                if ( (idot <= 0) ||          | 
 | 
                     (idot >= token.length() - 1) ) {  | 
 | 
                    return null;  | 
 | 
                }  | 
 | 
                String methodName = token.substring(idot + 1);  | 
 | 
                String classId = token.substring(0, idot);  | 
 | 
                List<String> argumentList = null;  | 
 | 
                if (rest != null) { | 
 | 
                    if (!rest.startsWith("(") || !rest.endsWith(")")) { | 
 | 
                        //### Should throw exception with error message  | 
 | 
                        //out.println("Invalid method specification: " | 
 | 
                          | 
 | 
                        return null;  | 
 | 
                    }  | 
 | 
                    // Trim the parens  | 
 | 
                      | 
 | 
                    rest = rest.substring(1, rest.length() - 1);  | 
 | 
                    argumentList = new ArrayList<String>();  | 
 | 
                    t = new StringTokenizer(rest, ",");  | 
 | 
                    while (t.hasMoreTokens()) { | 
 | 
                        argumentList.add(t.nextToken());  | 
 | 
                    }  | 
 | 
                }  | 
 | 
                bpSpec = runtime.createMethodBreakpoint(classId,  | 
 | 
                                                       methodName,  | 
 | 
                                                       argumentList);  | 
 | 
            }  | 
 | 
//        } catch (Exception e) { | 
 | 
//            env.error("Exception attempting to create breakpoint: " + e); | 
 | 
//            return null;  | 
 | 
 | 
 | 
        return bpSpec;  | 
 | 
    }  | 
 | 
 | 
 | 
    private void commandStop(StringTokenizer t) throws NoSessionException { | 
 | 
        String token;  | 
 | 
 | 
 | 
        if (!t.hasMoreTokens()) { | 
 | 
            listEventRequests();  | 
 | 
        } else { | 
 | 
            token = t.nextToken();  | 
 | 
            // Ignore optional "at" or "in" token.  | 
 | 
              | 
 | 
            if (token.equals("at") || token.equals("in")) { | 
 | 
                if (t.hasMoreTokens()) { | 
 | 
                    token = t.nextToken();  | 
 | 
                } else { | 
 | 
                    env.error("Missing breakpoint specification."); | 
 | 
                    return;  | 
 | 
                }  | 
 | 
            }  | 
 | 
            BreakpointSpec bpSpec = parseBreakpointSpec(token);  | 
 | 
            if (bpSpec != null) { | 
 | 
                  | 
 | 
                runtime.install(bpSpec);  | 
 | 
            } else { | 
 | 
                env.error("Ill-formed breakpoint specification."); | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private void commandClear(StringTokenizer t) throws NoSessionException { | 
 | 
        if (!t.hasMoreTokens()) { | 
 | 
              | 
 | 
            listEventRequests();  | 
 | 
            return;  | 
 | 
        }  | 
 | 
          | 
 | 
        BreakpointSpec bpSpec = parseBreakpointSpec(t.nextToken());  | 
 | 
        if (bpSpec != null) { | 
 | 
            List<EventRequestSpec> specs = runtime.eventRequestSpecs();  | 
 | 
 | 
 | 
            if (specs.isEmpty()) { | 
 | 
                env.notice("No breakpoints set."); | 
 | 
            } else { | 
 | 
                List<EventRequestSpec> toDelete = new ArrayList<EventRequestSpec>();  | 
 | 
                for (EventRequestSpec spec : specs) { | 
 | 
                    if (spec.equals(bpSpec)) { | 
 | 
                        toDelete.add(spec);  | 
 | 
                    }  | 
 | 
                }  | 
 | 
                  | 
 | 
                if (toDelete.size() <= 1) { | 
 | 
                    env.notice("No matching breakpoint set."); | 
 | 
                }  | 
 | 
                for (EventRequestSpec spec : toDelete) { | 
 | 
                    runtime.delete(spec);  | 
 | 
                }  | 
 | 
            }  | 
 | 
        } else { | 
 | 
            env.error("Ill-formed breakpoint specification."); | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    // Command: list  | 
 | 
 | 
 | 
    private void commandList(StringTokenizer t) throws NoSessionException { | 
 | 
        ThreadReference current = context.getCurrentThread();  | 
 | 
        if (current == null) { | 
 | 
            env.error("No thread specified."); | 
 | 
            return;  | 
 | 
        }  | 
 | 
        Location loc;  | 
 | 
        try { | 
 | 
            StackFrame frame = context.getCurrentFrame(current);  | 
 | 
            if (frame == null) { | 
 | 
                env.failure("Thread has not yet begun execution."); | 
 | 
                return;  | 
 | 
            }  | 
 | 
            loc = frame.location();  | 
 | 
        } catch (VMNotInterruptedException e) { | 
 | 
            env.failure("Target VM must be in interrupted state."); | 
 | 
            return;  | 
 | 
        }  | 
 | 
        SourceModel source = sourceManager.sourceForLocation(loc);  | 
 | 
        if (source == null) { | 
 | 
            if (loc.method().isNative()) { | 
 | 
                env.failure("Current method is native."); | 
 | 
                return;  | 
 | 
            }  | 
 | 
            env.failure("No source available for " + Utils.locationString(loc) + "."); | 
 | 
            return;  | 
 | 
        }  | 
 | 
        ReferenceType refType = loc.declaringType();  | 
 | 
        int lineno = loc.lineNumber();  | 
 | 
        if (t.hasMoreTokens()) { | 
 | 
            String id = t.nextToken();  | 
 | 
              | 
 | 
            try { | 
 | 
                lineno = Integer.valueOf(id).intValue();  | 
 | 
            } catch (NumberFormatException nfe) { | 
 | 
                  | 
 | 
                List<Method> meths = refType.methodsByName(id);  | 
 | 
                if (meths == null || meths.size() == 0) { | 
 | 
                    env.failure(id +  | 
 | 
                                " is not a valid line number or " +  | 
 | 
                                "method name for class " +  | 
 | 
                                refType.name());  | 
 | 
                    return;  | 
 | 
                } else if (meths.size() > 1) { | 
 | 
                    env.failure(id +  | 
 | 
                                " is an ambiguous method name in" +  | 
 | 
                                refType.name());  | 
 | 
                    return;  | 
 | 
                }  | 
 | 
                loc = meths.get(0).location();  | 
 | 
                lineno = loc.lineNumber();  | 
 | 
            }  | 
 | 
        }  | 
 | 
        int startLine = (lineno > 4) ? lineno - 4 : 1;  | 
 | 
        int endLine = startLine + 9;  | 
 | 
        String sourceLine = source.sourceLine(lineno);  | 
 | 
        if (sourceLine == null) { | 
 | 
            env.failure("" + | 
 | 
                        lineno +  | 
 | 
                        " is an invalid line number for " +  | 
 | 
                        refType.name());  | 
 | 
        } else { | 
 | 
            OutputSink out = env.getOutputSink();  | 
 | 
            for (int i = startLine; i <= endLine; i++) { | 
 | 
                sourceLine = source.sourceLine(i);  | 
 | 
                if (sourceLine == null) { | 
 | 
                    break;  | 
 | 
                }  | 
 | 
                out.print(i);  | 
 | 
                out.print("\t"); | 
 | 
                if (i == lineno) { | 
 | 
                    out.print("=> "); | 
 | 
                } else { | 
 | 
                    out.print("   "); | 
 | 
                }  | 
 | 
                out.println(sourceLine);  | 
 | 
            }  | 
 | 
            out.show();  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    // Command: use  | 
 | 
    // Get or set the source file path list.  | 
 | 
 | 
 | 
    private void commandUse(StringTokenizer t) { | 
 | 
        if (!t.hasMoreTokens()) { | 
 | 
            out.println(sourceManager.getSourcePath().asString());  | 
 | 
        } else { | 
 | 
            //### Should throw exception for invalid path.  | 
 | 
              | 
 | 
            sourceManager.setSourcePath(new SearchPath(t.nextToken()));  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    // Command: sourcepath  | 
 | 
    // Get or set the source file path list.  (Alternate to 'use'.)  | 
 | 
 | 
 | 
    private void commandSourcepath(StringTokenizer t) { | 
 | 
        if (!t.hasMoreTokens()) { | 
 | 
            out.println(sourceManager.getSourcePath().asString());  | 
 | 
        } else { | 
 | 
            //### Should throw exception for invalid path.  | 
 | 
              | 
 | 
            sourceManager.setSourcePath(new SearchPath(t.nextToken()));  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    // Command: classpath  | 
 | 
    // Get or set the class file path list.  | 
 | 
 | 
 | 
    private void commandClasspath(StringTokenizer t) { | 
 | 
        if (!t.hasMoreTokens()) { | 
 | 
            out.println(classManager.getClassPath().asString());  | 
 | 
        } else { | 
 | 
            //### Should throw exception for invalid path.  | 
 | 
              | 
 | 
            classManager.setClassPath(new SearchPath(t.nextToken()));  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    // Command: view  | 
 | 
    // Display source for source file or class.  | 
 | 
 | 
 | 
    private void commandView(StringTokenizer t) throws NoSessionException { | 
 | 
        if (!t.hasMoreTokens()) { | 
 | 
            env.error("Argument required"); | 
 | 
        } else { | 
 | 
            String name = t.nextToken();  | 
 | 
            if (name.endsWith(".java") || | 
 | 
                name.indexOf(File.separatorChar) >= 0) { | 
 | 
                env.viewSource(name);  | 
 | 
            } else { | 
 | 
                //### JDI crashes taking line number for class.  | 
 | 
                  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
                *****/  | 
 | 
                String fileName = name.replace('.', File.separatorChar) + ".java"; | 
 | 
                env.viewSource(fileName);  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    // Command: locals  | 
 | 
    // Print all local variables in current stack frame.  | 
 | 
 | 
 | 
    private void commandLocals() throws NoSessionException { | 
 | 
        ThreadReference current = context.getCurrentThread();  | 
 | 
        if (current == null) { | 
 | 
            env.failure("No default thread specified: " + | 
 | 
                        "use the \"thread\" command first.");  | 
 | 
            return;  | 
 | 
        }  | 
 | 
        StackFrame frame;  | 
 | 
        try { | 
 | 
            frame = context.getCurrentFrame(current);  | 
 | 
            if (frame == null) { | 
 | 
                env.failure("Thread has not yet created any stack frames."); | 
 | 
                return;  | 
 | 
            }  | 
 | 
        } catch (VMNotInterruptedException e) { | 
 | 
            env.failure("Target VM must be in interrupted state."); | 
 | 
            return;  | 
 | 
        }  | 
 | 
 | 
 | 
        List<LocalVariable> vars;  | 
 | 
        try { | 
 | 
            vars = frame.visibleVariables();  | 
 | 
            if (vars == null || vars.size() == 0) { | 
 | 
                env.failure("No local variables"); | 
 | 
                return;  | 
 | 
            }  | 
 | 
        } catch (AbsentInformationException e) { | 
 | 
            env.failure("Local variable information not available." + | 
 | 
                        " Compile with -g to generate variable information");  | 
 | 
            return;  | 
 | 
        }  | 
 | 
 | 
 | 
        OutputSink out = env.getOutputSink();  | 
 | 
        out.println("Method arguments:"); | 
 | 
        for (LocalVariable var : vars) { | 
 | 
            if (var.isArgument()) { | 
 | 
                printVar(out, var, frame);  | 
 | 
            }  | 
 | 
        }  | 
 | 
        out.println("Local variables:"); | 
 | 
        for (LocalVariable var : vars) { | 
 | 
            if (!var.isArgument()) { | 
 | 
                printVar(out, var, frame);  | 
 | 
            }  | 
 | 
        }  | 
 | 
        out.show();  | 
 | 
        return;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private void commandMonitor(StringTokenizer t) throws NoSessionException { | 
 | 
        if (!t.hasMoreTokens()) { | 
 | 
            env.error("Argument required"); | 
 | 
        } else { | 
 | 
            env.getMonitorListModel().add(t.nextToken("")); | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private void commandUnmonitor(StringTokenizer t) throws NoSessionException { | 
 | 
        if (!t.hasMoreTokens()) { | 
 | 
            env.error("Argument required"); | 
 | 
        } else { | 
 | 
            env.getMonitorListModel().remove(t.nextToken("")); | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    // Print a stack variable.  | 
 | 
 | 
 | 
    private void printVar(OutputSink out, LocalVariable var, StackFrame frame) { | 
 | 
        out.print("  " + var.name()); | 
 | 
        if (var.isVisible(frame)) { | 
 | 
            Value val = frame.getValue(var);  | 
 | 
            out.println(" = " + val.toString()); | 
 | 
        } else { | 
 | 
            out.println(" is not in scope"); | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    // Command: print  | 
 | 
    // Evaluate an expression.  | 
 | 
 | 
 | 
    private void commandPrint(StringTokenizer t, boolean dumpObject) throws NoSessionException { | 
 | 
        if (!t.hasMoreTokens()) { | 
 | 
              | 
 | 
            env.error("No expression specified."); | 
 | 
            return;  | 
 | 
        }  | 
 | 
        ThreadReference current = context.getCurrentThread();  | 
 | 
        if (current == null) { | 
 | 
            env.failure("No default thread specified: " + | 
 | 
                        "use the \"thread\" command first.");  | 
 | 
            return;  | 
 | 
        }  | 
 | 
        StackFrame frame;  | 
 | 
        try { | 
 | 
            frame = context.getCurrentFrame(current);  | 
 | 
            if (frame == null) { | 
 | 
                env.failure("Thread has not yet created any stack frames."); | 
 | 
                return;  | 
 | 
            }  | 
 | 
        } catch (VMNotInterruptedException e) { | 
 | 
            env.failure("Target VM must be in interrupted state."); | 
 | 
            return;  | 
 | 
        }  | 
 | 
        while (t.hasMoreTokens()) { | 
 | 
            String expr = t.nextToken(""); | 
 | 
            Value val = null;  | 
 | 
            try { | 
 | 
                val = runtime.evaluate(frame, expr);  | 
 | 
            } catch(Exception e) { | 
 | 
                env.error("Exception: " + e); | 
 | 
                //### Fix this!  | 
 | 
            }  | 
 | 
            if (val == null) { | 
 | 
                return;    | 
 | 
            }  | 
 | 
            OutputSink out = env.getOutputSink();  | 
 | 
            if (dumpObject && (val instanceof ObjectReference) &&  | 
 | 
                                 !(val instanceof StringReference)) { | 
 | 
                ObjectReference obj = (ObjectReference)val;  | 
 | 
                ReferenceType refType = obj.referenceType();  | 
 | 
                out.println(expr + " = " + val.toString() + " {"); | 
 | 
                dump(out, obj, refType, refType);  | 
 | 
                out.println("}"); | 
 | 
            } else { | 
 | 
                out.println(expr + " = " + val.toString());  | 
 | 
            }  | 
 | 
            out.show();  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private void dump(OutputSink out,  | 
 | 
                      ObjectReference obj, ReferenceType refType,  | 
 | 
                      ReferenceType refTypeBase) { | 
 | 
        for (Field field : refType.fields()) { | 
 | 
            out.print("    "); | 
 | 
            if (!refType.equals(refTypeBase)) { | 
 | 
                out.print(refType.name() + ".");  | 
 | 
            }  | 
 | 
            out.print(field.name() + ": ");  | 
 | 
            Object o = obj.getValue(field);  | 
 | 
            out.println((o == null) ? "null" : o.toString());   | 
 | 
        }  | 
 | 
        if (refType instanceof ClassType) { | 
 | 
            ClassType sup = ((ClassType)refType).superclass();  | 
 | 
            if (sup != null) { | 
 | 
                dump(out, obj, sup, refTypeBase);  | 
 | 
            }  | 
 | 
        } else if (refType instanceof InterfaceType) { | 
 | 
            for (InterfaceType sup : ((InterfaceType)refType).superinterfaces()) { | 
 | 
                dump(out, obj, sup, refTypeBase);  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    /*  | 
 | 
     * Display help message.  | 
 | 
     */  | 
 | 
 | 
 | 
    private void help() { | 
 | 
        out.println("** command list **"); | 
 | 
        out.println("threads [threadgroup]     -- list threads"); | 
 | 
        out.println("thread <thread id>        -- set default thread"); | 
 | 
        out.println("suspend [thread id(s)]    -- suspend threads (default: all)"); | 
 | 
        out.println("resume [thread id(s)]     -- resume threads (default: all)"); | 
 | 
        out.println("where [thread id] | all   -- dump a thread's stack"); | 
 | 
        out.println("wherei [thread id] | all  -- dump a thread's stack, with pc info"); | 
 | 
        out.println("threadgroups              -- list threadgroups"); | 
 | 
        out.println("threadgroup <name>        -- set current threadgroup\n"); | 
 | 
 | 
 | 
        out.println("dump <expression>         -- print all object information\n"); | 
 | 
 | 
 | 
        out.println("locals                    -- print all local variables in current stack frame\n"); | 
 | 
        out.println("classes                   -- list currently known classes"); | 
 | 
        out.println("methods <class id>        -- list a class's methods\n"); | 
 | 
        out.println("stop [in] <class id>.<method>[(argument_type,...)] -- set a breakpoint in a method"); | 
 | 
        out.println("stop [at] <class id>:<line> -- set a breakpoint at a line"); | 
 | 
        out.println("up [n frames]             -- move up a thread's stack"); | 
 | 
        out.println("down [n frames]           -- move down a thread's stack"); | 
 | 
        out.println("frame <frame-id>           -- to a frame"); | 
 | 
        out.println("clear <class id>.<method>[(argument_type,...)]   -- clear a breakpoint in a method"); | 
 | 
        out.println("clear <class id>:<line>   -- clear a breakpoint at a line"); | 
 | 
        out.println("clear                     -- list breakpoints"); | 
 | 
        out.println("step                      -- execute current line"); | 
 | 
        out.println("step up                   -- execute until the current method returns to its caller"); | 
 | 
        out.println("stepi                     -- execute current instruction"); | 
 | 
        out.println("next                      -- step one line (step OVER calls)"); | 
 | 
        out.println("nexti                     -- step one instruction (step OVER calls)"); | 
 | 
        out.println("cont                      -- continue execution from breakpoint\n"); | 
 | 
//      out.println("catch <class id>          -- break for the specified exception"); | 
 | 
 | 
 | 
        out.println("view classname|filename   -- display source file"); | 
 | 
        out.println("list [line number|method] -- print source code context at line or method"); | 
 | 
        out.println("use <source file path>    -- display or change the source path\n"); | 
 | 
 | 
 | 
        out.println("sourcepath <source file path>    -- display or change the source path\n"); | 
 | 
 | 
 | 
        out.println("classpath <class file path>    -- display or change the class path\n"); | 
 | 
        out.println("monitor <expression>      -- evaluate an expression each time the program stops\n"); | 
 | 
        out.println("unmonitor <monitor#>      -- delete a monitor\n"); | 
 | 
        out.println("read <filename>           -- read and execute a command file\n"); | 
 | 
//      out.println("memory                    -- report memory usage"); | 
 | 
 | 
 | 
        out.println("run <class> [args]        -- start execution of a Java class"); | 
 | 
        out.println("run                       -- re-execute last class run"); | 
 | 
        out.println("load <class> [args]       -- start execution of a Java class, initially suspended"); | 
 | 
        out.println("load                      -- re-execute last class run, initially suspended"); | 
 | 
        out.println("attach <portname>         -- debug existing process\n"); | 
 | 
        out.println("detach                    -- detach from debuggee process\n"); | 
 | 
        out.println("kill <thread(group)>      -- kill a thread or threadgroup\n"); | 
 | 
        out.println("!!                        -- repeat last command"); | 
 | 
        out.println("help (or ?)               -- list commands"); | 
 | 
        out.println("exit (or quit)            -- exit debugger"); | 
 | 
    }  | 
 | 
 | 
 | 
    /*  | 
 | 
     * Execute a command.  | 
 | 
     */  | 
 | 
 | 
 | 
    public void executeCommand(String command) { | 
 | 
          | 
 | 
        out = env.getOutputSink();  | 
 | 
        if (echo) { | 
 | 
            out.println(">>> " + command); | 
 | 
        }  | 
 | 
        StringTokenizer t = new StringTokenizer(command);  | 
 | 
        try { | 
 | 
            String cmd;  | 
 | 
            if (t.hasMoreTokens()) { | 
 | 
                cmd = t.nextToken().toLowerCase();  | 
 | 
                lastCommand = cmd;  | 
 | 
            } else { | 
 | 
                cmd = lastCommand;  | 
 | 
            }  | 
 | 
            if (cmd.equals("print")) { | 
 | 
                commandPrint(t, false);  | 
 | 
            } else if (cmd.equals("eval")) { | 
 | 
                commandPrint(t, false);  | 
 | 
            } else if (cmd.equals("dump")) { | 
 | 
                commandPrint(t, true);  | 
 | 
            } else if (cmd.equals("locals")) { | 
 | 
                commandLocals();  | 
 | 
            } else if (cmd.equals("classes")) { | 
 | 
                commandClasses();  | 
 | 
            } else if (cmd.equals("methods")) { | 
 | 
                commandMethods(t);  | 
 | 
            } else if (cmd.equals("threads")) { | 
 | 
                commandThreads(t);  | 
 | 
            } else if (cmd.equals("thread")) { | 
 | 
                commandThread(t);  | 
 | 
            } else if (cmd.equals("suspend")) { | 
 | 
                commandSuspend(t);  | 
 | 
            } else if (cmd.equals("resume")) { | 
 | 
                commandResume(t);  | 
 | 
            } else if (cmd.equals("cont")) { | 
 | 
                commandCont();  | 
 | 
            } else if (cmd.equals("threadgroups")) { | 
 | 
                commandThreadGroups();  | 
 | 
            } else if (cmd.equals("threadgroup")) { | 
 | 
                commandThreadGroup(t);  | 
 | 
            } else if (cmd.equals("run")) { | 
 | 
                commandRun(t);  | 
 | 
            } else if (cmd.equals("load")) { | 
 | 
                commandLoad(t);  | 
 | 
            } else if (cmd.equals("connect")) { | 
 | 
                commandConnect(t);  | 
 | 
            } else if (cmd.equals("attach")) { | 
 | 
                commandAttach(t);  | 
 | 
            } else if (cmd.equals("detach")) { | 
 | 
                commandDetach(t);  | 
 | 
            } else if (cmd.equals("interrupt")) { | 
 | 
                commandInterrupt(t);  | 
 | 
//### Not implemented.  | 
 | 
//          } else if (cmd.equals("catch")) { | 
 | 
//              commandCatchException(t);  | 
 | 
//### Not implemented.  | 
 | 
//          } else if (cmd.equals("ignore")) { | 
 | 
//              commandIgnoreException(t);  | 
 | 
            } else if (cmd.equals("step")) { | 
 | 
                commandStep(t);  | 
 | 
            } else if (cmd.equals("stepi")) { | 
 | 
                commandStepi();  | 
 | 
            } else if (cmd.equals("next")) { | 
 | 
                commandNext();  | 
 | 
            } else if (cmd.equals("nexti")) { | 
 | 
                commandNexti();  | 
 | 
            } else if (cmd.equals("kill")) { | 
 | 
                commandKill(t);  | 
 | 
            } else if (cmd.equals("where")) { | 
 | 
                commandWhere(t, false);  | 
 | 
            } else if (cmd.equals("wherei")) { | 
 | 
                commandWhere(t, true);  | 
 | 
            } else if (cmd.equals("up")) { | 
 | 
                commandUp(t);  | 
 | 
            } else if (cmd.equals("down")) { | 
 | 
                commandDown(t);  | 
 | 
            } else if (cmd.equals("frame")) { | 
 | 
                commandFrame(t);  | 
 | 
            } else if (cmd.equals("stop")) { | 
 | 
                commandStop(t);  | 
 | 
            } else if (cmd.equals("clear")) { | 
 | 
                commandClear(t);  | 
 | 
            } else if (cmd.equals("list")) { | 
 | 
                commandList(t);  | 
 | 
            } else if (cmd.equals("use")) { | 
 | 
                commandUse(t);  | 
 | 
            } else if (cmd.equals("sourcepath")) { | 
 | 
                commandSourcepath(t);  | 
 | 
            } else if (cmd.equals("classpath")) { | 
 | 
                commandClasspath(t);  | 
 | 
            } else if (cmd.equals("monitor")) { | 
 | 
                commandMonitor(t);  | 
 | 
            } else if (cmd.equals("unmonitor")) { | 
 | 
                commandUnmonitor(t);  | 
 | 
            } else if (cmd.equals("view")) { | 
 | 
                commandView(t);  | 
 | 
//          } else if (cmd.equals("read")) { | 
 | 
//              readCommand(t);  | 
 | 
            } else if (cmd.equals("help") || cmd.equals("?")) { | 
 | 
                help();  | 
 | 
            } else if (cmd.equals("quit") || cmd.equals("exit")) { | 
 | 
                try { | 
 | 
                    runtime.detach();  | 
 | 
                } catch (NoSessionException e) { | 
 | 
                    // ignore  | 
 | 
                }  | 
 | 
                env.terminate();  | 
 | 
            } else { | 
 | 
                  | 
 | 
                if (t.hasMoreTokens()) { | 
 | 
                    try { | 
 | 
                        int repeat = Integer.parseInt(cmd);  | 
 | 
                        String subcom = t.nextToken(""); | 
 | 
                        while (repeat-- > 0) { | 
 | 
                            executeCommand(subcom);  | 
 | 
                        }  | 
 | 
                        return;  | 
 | 
                    } catch (NumberFormatException exc) { | 
 | 
                    }  | 
 | 
                }  | 
 | 
                out.println("huh? Try help..."); | 
 | 
                out.flush();  | 
 | 
            }  | 
 | 
        } catch (NoSessionException e) { | 
 | 
            out.println("There is no currently attached VM session."); | 
 | 
            out.flush();  | 
 | 
        } catch (Exception e) { | 
 | 
            out.println("Internal exception: " + e.toString()); | 
 | 
            out.flush();  | 
 | 
            System.out.println("JDB internal exception: " + e.toString()); | 
 | 
            e.printStackTrace();  | 
 | 
        }  | 
 | 
        out.show();  | 
 | 
    }  | 
 | 
}  |