0N/A/*
2362N/A * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
4378N/A/*
4378N/A * This source code is provided to illustrate the usage of a given feature
4378N/A * or technique and has been deliberately simplified. Additional steps
4378N/A * required for a production-quality application, such as security checks,
4378N/A * input validation and proper error handling, might not be present in
4378N/A * this sample code.
4378N/A */
4378N/A
4378N/A
0N/Apackage com.sun.tools.example.debug.gui;
0N/A
0N/Aimport java.io.*;
0N/Aimport java.util.*;
0N/A
0N/Aimport com.sun.jdi.*;
0N/Aimport com.sun.tools.example.debug.bdi.*;
0N/A
0N/Apublic class CommandInterpreter {
0N/A
0N/A boolean echo;
0N/A
0N/A Environment env;
0N/A
0N/A private ContextManager context;
0N/A private ExecutionManager runtime;
0N/A private ClassManager classManager;
0N/A private SourceManager sourceManager;
0N/A
0N/A private OutputSink out; //### Hack! Should be local in each method used.
0N/A private String lastCommand = "help";
0N/A
0N/A public CommandInterpreter(Environment env) {
0N/A this(env, true);
0N/A }
0N/A
0N/A public CommandInterpreter(Environment env, boolean echo) {
0N/A this.env = env;
0N/A this.echo = echo;
0N/A this.runtime = env.getExecutionManager();
0N/A this.context = env.getContextManager();
0N/A this.classManager = env.getClassManager();
0N/A this.sourceManager = env.getSourceManager();
0N/A }
0N/A
0N/A private ThreadReference[] threads = null;
0N/A
0N/A /*
0N/A * The numbering of threads is relative to the current set of threads,
0N/A * and may be affected by the creation and termination of new threads.
0N/A * Commands issued using such thread ids will only give reliable behavior
0N/A * relative to what was shown earlier in 'list' commands if the VM is interrupted.
0N/A * We need a better scheme.
0N/A */
0N/A
0N/A private ThreadReference[] threads() throws NoSessionException {
0N/A if (threads == null) {
0N/A ThreadIterator ti = new ThreadIterator(getDefaultThreadGroup());
0N/A List<ThreadReference> tlist = new ArrayList<ThreadReference>();
0N/A while (ti.hasNext()) {
0N/A tlist.add(ti.nextThread());
0N/A }
28N/A threads = tlist.toArray(new ThreadReference[tlist.size()]);
0N/A }
0N/A return threads;
0N/A }
0N/A
0N/A private ThreadReference findThread(String idToken) throws NoSessionException {
0N/A String id;
0N/A ThreadReference thread = null;
0N/A if (idToken.startsWith("t@")) {
0N/A id = idToken.substring(2);
0N/A } else {
0N/A id = idToken;
0N/A }
0N/A try {
0N/A ThreadReference[] threads = threads();
0N/A long threadID = Long.parseLong(id, 16);
4123N/A for (ThreadReference thread2 : threads) {
4123N/A if (thread2.uniqueID() == threadID) {
4123N/A thread = thread2;
0N/A break;
0N/A }
0N/A }
0N/A if (thread == null) {
0N/A //env.failure("No thread for id \"" + idToken + "\"");
0N/A env.failure("\"" + idToken + "\" is not a valid thread id.");
0N/A }
0N/A } catch (NumberFormatException e) {
0N/A env.error("Thread id \"" + idToken + "\" is ill-formed.");
0N/A thread = null;
0N/A }
0N/A return thread;
0N/A }
0N/A
0N/A private ThreadIterator allThreads() throws NoSessionException {
0N/A threads = null;
0N/A //### Why not use runtime.allThreads().iterator() ?
0N/A return new ThreadIterator(runtime.topLevelThreadGroups());
0N/A }
0N/A
0N/A private ThreadIterator currentThreadGroupThreads() throws NoSessionException {
0N/A threads = null;
0N/A return new ThreadIterator(getDefaultThreadGroup());
0N/A }
0N/A
0N/A private ThreadGroupIterator allThreadGroups() throws NoSessionException {
0N/A threads = null;
0N/A return new ThreadGroupIterator(runtime.topLevelThreadGroups());
0N/A }
0N/A
0N/A private ThreadGroupReference defaultThreadGroup;
0N/A
0N/A private ThreadGroupReference getDefaultThreadGroup() throws NoSessionException {
0N/A if (defaultThreadGroup == null) {
0N/A defaultThreadGroup = runtime.systemThreadGroup();
0N/A }
0N/A return defaultThreadGroup;
0N/A }
0N/A
0N/A private void setDefaultThreadGroup(ThreadGroupReference tg) {
0N/A defaultThreadGroup = tg;
0N/A }
0N/A
0N/A /*
0N/A * Command handlers.
0N/A */
0N/A
0N/A // Command: classes
0N/A
0N/A private void commandClasses() throws NoSessionException {
0N/A OutputSink out = env.getOutputSink();
0N/A //out.println("** classes list **");
28N/A for (ReferenceType refType : runtime.allClasses()) {
0N/A out.println(refType.name());
0N/A }
0N/A out.show();
0N/A }
0N/A
0N/A
0N/A // Command: methods
0N/A
0N/A private void commandMethods(StringTokenizer t) throws NoSessionException {
0N/A if (!t.hasMoreTokens()) {
0N/A env.error("No class specified.");
0N/A return;
0N/A }
0N/A String idClass = t.nextToken();
0N/A ReferenceType cls = findClass(idClass);
0N/A if (cls != null) {
28N/A List<Method> methods = cls.allMethods();
0N/A OutputSink out = env.getOutputSink();
0N/A for (int i = 0; i < methods.size(); i++) {
28N/A Method method = methods.get(i);
0N/A out.print(method.declaringType().name() + " " +
0N/A method.name() + "(");
28N/A Iterator<String> it = method.argumentTypeNames().iterator();
0N/A if (it.hasNext()) {
0N/A while (true) {
28N/A out.print(it.next());
0N/A if (!it.hasNext()) {
0N/A break;
0N/A }
0N/A out.print(", ");
0N/A }
0N/A }
0N/A out.println(")");
0N/A }
0N/A out.show();
0N/A } else {
0N/A //### Should validate class name syntax.
0N/A env.failure("\"" + idClass + "\" is not a valid id or class name.");
0N/A }
0N/A }
0N/A
0N/A private ReferenceType findClass(String pattern) throws NoSessionException {
28N/A List<ReferenceType> results = runtime.findClassesMatchingPattern(pattern);
0N/A if (results.size() > 0) {
0N/A //### Should handle multiple results sensibly.
28N/A return results.get(0);
0N/A }
0N/A return null;
0N/A }
0N/A
0N/A // Command: threads
0N/A
0N/A private void commandThreads(StringTokenizer t) throws NoSessionException {
0N/A if (!t.hasMoreTokens()) {
0N/A OutputSink out = env.getOutputSink();
0N/A printThreadGroup(out, getDefaultThreadGroup(), 0);
0N/A out.show();
0N/A return;
0N/A }
0N/A String name = t.nextToken();
0N/A ThreadGroupReference tg = findThreadGroup(name);
0N/A if (tg == null) {
0N/A env.failure(name + " is not a valid threadgroup name.");
0N/A } else {
0N/A OutputSink out = env.getOutputSink();
0N/A printThreadGroup(out, tg, 0);
0N/A out.show();
0N/A }
0N/A }
0N/A
0N/A private ThreadGroupReference findThreadGroup(String name) throws NoSessionException {
0N/A //### Issue: Uniqueness of thread group names is not enforced.
0N/A ThreadGroupIterator tgi = allThreadGroups();
0N/A while (tgi.hasNext()) {
0N/A ThreadGroupReference tg = tgi.nextThreadGroup();
0N/A if (tg.name().equals(name)) {
0N/A return tg;
0N/A }
0N/A }
0N/A return null;
0N/A }
0N/A
0N/A private int printThreadGroup(OutputSink out, ThreadGroupReference tg, int iThread) {
0N/A out.println("Group " + tg.name() + ":");
28N/A List<ThreadReference> tlist = tg.threads();
0N/A int maxId = 0;
0N/A int maxName = 0;
0N/A for (int i = 0 ; i < tlist.size() ; i++) {
28N/A ThreadReference thr = tlist.get(i);
0N/A int len = Utils.description(thr).length();
4123N/A if (len > maxId) {
0N/A maxId = len;
4123N/A }
0N/A String name = thr.name();
0N/A int iDot = name.lastIndexOf('.');
0N/A if (iDot >= 0 && name.length() > iDot) {
0N/A name = name.substring(iDot + 1);
0N/A }
4123N/A if (name.length() > maxName) {
0N/A maxName = name.length();
0N/A }
4123N/A }
0N/A String maxNumString = String.valueOf(iThread + tlist.size());
0N/A int maxNumDigits = maxNumString.length();
0N/A for (int i = 0 ; i < tlist.size() ; i++) {
28N/A ThreadReference thr = tlist.get(i);
0N/A char buf[] = new char[80];
0N/A for (int j = 0; j < 79; j++) {
0N/A buf[j] = ' ';
0N/A }
0N/A buf[79] = '\0';
0N/A StringBuffer sbOut = new StringBuffer();
0N/A sbOut.append(buf);
0N/A
0N/A // Right-justify the thread number at start of output string
0N/A String numString = String.valueOf(iThread + i + 1);
0N/A sbOut.insert(maxNumDigits - numString.length(),
0N/A numString);
0N/A sbOut.insert(maxNumDigits, ".");
0N/A
0N/A int iBuf = maxNumDigits + 2;
0N/A sbOut.insert(iBuf, Utils.description(thr));
0N/A iBuf += maxId + 1;
0N/A String name = thr.name();
0N/A int iDot = name.lastIndexOf('.');
0N/A if (iDot >= 0 && name.length() > iDot) {
0N/A name = name.substring(iDot + 1);
0N/A }
0N/A sbOut.insert(iBuf, name);
0N/A iBuf += maxName + 1;
0N/A sbOut.insert(iBuf, Utils.getStatus(thr));
0N/A sbOut.setLength(79);
0N/A out.println(sbOut.toString());
0N/A }
28N/A for (ThreadGroupReference tg0 : tg.threadGroups()) {
0N/A if (!tg.equals(tg0)) { // TODO ref mgt
0N/A iThread += printThreadGroup(out, tg0, iThread + tlist.size());
0N/A }
0N/A }
0N/A return tlist.size();
0N/A }
0N/A
0N/A // Command: threadgroups
0N/A
0N/A private void commandThreadGroups() throws NoSessionException {
0N/A ThreadGroupIterator it = allThreadGroups();
0N/A int cnt = 0;
0N/A OutputSink out = env.getOutputSink();
0N/A while (it.hasNext()) {
0N/A ThreadGroupReference tg = it.nextThreadGroup();
0N/A ++cnt;
0N/A out.println("" + cnt + ". " + Utils.description(tg) + " " + tg.name());
0N/A }
0N/A out.show();
0N/A }
0N/A
0N/A // Command: thread
0N/A
0N/A private void commandThread(StringTokenizer t) throws NoSessionException {
0N/A if (!t.hasMoreTokens()) {
0N/A env.error("Thread number not specified.");
0N/A return;
0N/A }
0N/A ThreadReference thread = findThread(t.nextToken());
0N/A if (thread != null) {
0N/A //### Should notify user.
0N/A context.setCurrentThread(thread);
0N/A }
0N/A }
0N/A
0N/A // Command: threadgroup
0N/A
0N/A private void commandThreadGroup(StringTokenizer t) throws NoSessionException {
0N/A if (!t.hasMoreTokens()) {
0N/A env.error("Threadgroup name not specified.");
0N/A return;
0N/A }
0N/A String name = t.nextToken();
0N/A ThreadGroupReference tg = findThreadGroup(name);
0N/A if (tg == null) {
0N/A env.failure(name + " is not a valid threadgroup name.");
0N/A } else {
0N/A //### Should notify user.
0N/A setDefaultThreadGroup(tg);
0N/A }
0N/A }
0N/A
0N/A // Command: run
0N/A
0N/A private void commandRun(StringTokenizer t) throws NoSessionException {
0N/A if (doLoad(false, t)) {
0N/A env.notice("Running ...");
0N/A }
0N/A }
0N/A
0N/A // Command: load
0N/A
0N/A private void commandLoad(StringTokenizer t) throws NoSessionException {
0N/A if (doLoad(true, t)) {}
0N/A }
0N/A
0N/A private boolean doLoad(boolean suspended,
0N/A StringTokenizer t) throws NoSessionException {
0N/A
0N/A String clname;
0N/A
0N/A if (!t.hasMoreTokens()) {
0N/A clname = context.getMainClassName();
0N/A if (!clname.equals("")) {
0N/A // Run from prevously-set class name.
0N/A try {
0N/A String vmArgs = context.getVmArguments();
0N/A runtime.run(suspended,
0N/A vmArgs,
0N/A clname,
0N/A context.getProgramArguments());
0N/A return true;
0N/A } catch (VMLaunchFailureException e) {
0N/A env.failure("Attempt to launch main class \"" + clname + "\" failed.");
0N/A }
0N/A } else {
0N/A env.failure("No main class specifed and no current default defined.");
0N/A }
0N/A } else {
0N/A clname = t.nextToken();
0N/A StringBuffer sbuf = new StringBuffer();
0N/A // Allow VM arguments to be specified here?
0N/A while (t.hasMoreTokens()) {
0N/A String tok = t.nextToken();
0N/A sbuf.append(tok);
0N/A if (t.hasMoreTokens()) {
0N/A sbuf.append(' ');
0N/A }
0N/A }
0N/A String args = sbuf.toString();
0N/A try {
0N/A String vmArgs = context.getVmArguments();
0N/A runtime.run(suspended, vmArgs, clname, args);
0N/A context.setMainClassName(clname);
0N/A //context.setVmArguments(vmArgs);
0N/A context.setProgramArguments(args);
0N/A return true;
0N/A } catch (VMLaunchFailureException e) {
0N/A env.failure("Attempt to launch main class \"" + clname + "\" failed.");
0N/A }
0N/A }
0N/A return false;
0N/A }
0N/A
0N/A // Command: connect
0N/A
0N/A private void commandConnect(StringTokenizer t) {
0N/A try {
0N/A LaunchTool.queryAndLaunchVM(runtime);
0N/A } catch (VMLaunchFailureException e) {
0N/A env.failure("Attempt to connect failed.");
0N/A }
0N/A }
0N/A
0N/A // Command: attach
0N/A
0N/A private void commandAttach(StringTokenizer t) {
0N/A String portName;
0N/A if (!t.hasMoreTokens()) {
0N/A portName = context.getRemotePort();
0N/A if (!portName.equals("")) {
0N/A try {
0N/A runtime.attach(portName);
0N/A } catch (VMLaunchFailureException e) {
0N/A env.failure("Attempt to attach to port \"" + portName + "\" failed.");
0N/A }
0N/A } else {
0N/A env.failure("No port specifed and no current default defined.");
0N/A }
0N/A } else {
0N/A portName = t.nextToken();
0N/A try {
0N/A runtime.attach(portName);
0N/A } catch (VMLaunchFailureException e) {
0N/A env.failure("Attempt to attach to port \"" + portName + "\" failed.");
0N/A }
0N/A context.setRemotePort(portName);
0N/A }
0N/A }
0N/A
0N/A // Command: detach
0N/A
0N/A private void commandDetach(StringTokenizer t) throws NoSessionException {
0N/A runtime.detach();
0N/A }
0N/A
0N/A // Command: interrupt
0N/A
0N/A private void commandInterrupt(StringTokenizer t) throws NoSessionException {
0N/A runtime.interrupt();
0N/A }
0N/A
0N/A // Command: suspend
0N/A
0N/A private void commandSuspend(StringTokenizer t) throws NoSessionException {
0N/A if (!t.hasMoreTokens()) {
0N/A // Suspend all threads in the current thread group.
0N/A //### Issue: help message says default is all threads.
0N/A //### Behavior here agrees with 'jdb', however.
0N/A ThreadIterator ti = currentThreadGroupThreads();
0N/A while (ti.hasNext()) {
0N/A // TODO - don't suspend debugger threads
0N/A ti.nextThread().suspend();
0N/A }
0N/A env.notice("All (non-system) threads suspended.");
0N/A } else {
0N/A while (t.hasMoreTokens()) {
0N/A ThreadReference thread = findThread(t.nextToken());
0N/A if (thread != null) {
0N/A //thread.suspend();
0N/A runtime.suspendThread(thread);
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A // Command: resume
0N/A
0N/A private void commandResume(StringTokenizer t) throws NoSessionException {
0N/A if (!t.hasMoreTokens()) {
0N/A // Suspend all threads in the current thread group.
0N/A //### Issue: help message says default is all threads.
0N/A //### Behavior here agrees with 'jdb', however.
0N/A ThreadIterator ti = currentThreadGroupThreads();
0N/A while (ti.hasNext()) {
0N/A // TODO - don't suspend debugger threads
0N/A ti.nextThread().resume();
0N/A }
0N/A env.notice("All threads resumed.");
0N/A } else {
0N/A while (t.hasMoreTokens()) {
0N/A ThreadReference thread = findThread(t.nextToken());
0N/A if (thread != null) {
0N/A //thread.resume();
0N/A runtime.resumeThread(thread);
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A // Command: cont
0N/A
0N/A private void commandCont() throws NoSessionException {
0N/A try {
0N/A runtime.go();
0N/A } catch (VMNotInterruptedException e) {
0N/A //### failure?
0N/A env.notice("Target VM is already running.");
0N/A }
0N/A }
0N/A
0N/A // Command: step
0N/A
0N/A private void commandStep(StringTokenizer t) throws NoSessionException{
0N/A ThreadReference current = context.getCurrentThread();
0N/A if (current == null) {
0N/A env.failure("No current thread.");
0N/A return;
0N/A }
0N/A try {
0N/A if (t.hasMoreTokens() &&
0N/A t.nextToken().toLowerCase().equals("up")) {
0N/A runtime.stepOut(current);
0N/A } else {
0N/A runtime.stepIntoLine(current);
0N/A }
0N/A } catch (AbsentInformationException e) {
0N/A env.failure("No linenumber information available -- " +
0N/A "Try \"stepi\" to step by instructions.");
0N/A }
0N/A }
0N/A
0N/A // Command: stepi
0N/A
0N/A private void commandStepi() throws NoSessionException {
0N/A ThreadReference current = context.getCurrentThread();
0N/A if (current == null) {
0N/A env.failure("No current thread.");
0N/A return;
0N/A }
0N/A runtime.stepIntoInstruction(current);
0N/A }
0N/A
0N/A // Command: next
0N/A
0N/A private void commandNext() throws NoSessionException {
0N/A ThreadReference current = context.getCurrentThread();
0N/A if (current == null) {
0N/A env.failure("No current thread.");
0N/A return;
0N/A }
0N/A try {
0N/A runtime.stepOverLine(current);
0N/A } catch (AbsentInformationException e) {
0N/A env.failure("No linenumber information available -- " +
0N/A "Try \"nexti\" to step by instructions.");
0N/A }
0N/A }
0N/A
0N/A // Command: nexti (NEW)
0N/A
0N/A private void commandNexti() throws NoSessionException {
0N/A ThreadReference current = context.getCurrentThread();
0N/A if (current == null) {
0N/A env.failure("No current thread.");
0N/A return;
0N/A }
0N/A runtime.stepOverInstruction(current);
0N/A }
0N/A
0N/A // Command: kill
0N/A
0N/A private void commandKill(StringTokenizer t) throws NoSessionException {
0N/A //### Should change the way in which thread ids and threadgroup names
0N/A //### are distinguished.
0N/A if (!t.hasMoreTokens()) {
0N/A env.error("Usage: kill <threadgroup name> or <thread id>");
0N/A return;
0N/A }
0N/A while (t.hasMoreTokens()) {
0N/A String idToken = t.nextToken();
0N/A ThreadReference thread = findThread(idToken);
0N/A if (thread != null) {
0N/A runtime.stopThread(thread);
0N/A env.notice("Thread " + thread.name() + " killed.");
0N/A return;
0N/A } else {
0N/A /* Check for threadgroup name, NOT skipping "system". */
0N/A //### Should skip "system"? Classic 'jdb' does this.
0N/A //### Should deal with possible non-uniqueness of threadgroup names.
0N/A ThreadGroupIterator itg = allThreadGroups();
0N/A while (itg.hasNext()) {
0N/A ThreadGroupReference tg = itg.nextThreadGroup();
0N/A if (tg.name().equals(idToken)) {
0N/A ThreadIterator it = new ThreadIterator(tg);
0N/A while (it.hasNext()) {
0N/A runtime.stopThread(it.nextThread());
0N/A }
0N/A env.notice("Threadgroup " + tg.name() + "killed.");
0N/A return;
0N/A }
0N/A }
0N/A env.failure("\"" + idToken +
0N/A "\" is not a valid threadgroup or id.");
0N/A }
0N/A }
0N/A }
0N/A
0N/A
0N/A /*************
0N/A // TODO
0N/A private void commandCatchException(StringTokenizer t) throws NoSessionException {}
0N/A // TODO
0N/A private void commandIgnoreException(StringTokenizer t) throws NoSessionException {}
0N/A *************/
0N/A
0N/A // Command: up
0N/A
0N/A //### Print current frame after command?
0N/A
0N/A int readCount(StringTokenizer t) {
0N/A int cnt = 1;
0N/A if (t.hasMoreTokens()) {
0N/A String idToken = t.nextToken();
0N/A try {
0N/A cnt = Integer.valueOf(idToken).intValue();
0N/A } catch (NumberFormatException e) {
0N/A cnt = -1;
0N/A }
0N/A }
0N/A return cnt;
0N/A }
0N/A
0N/A void commandUp(StringTokenizer t) throws NoSessionException {
0N/A ThreadReference current = context.getCurrentThread();
0N/A if (current == null) {
0N/A env.failure("No current thread.");
0N/A return;
0N/A }
0N/A int nLevels = readCount(t);
0N/A if (nLevels <= 0) {
0N/A env.error("usage: up [n frames]");
0N/A return;
0N/A }
0N/A try {
0N/A int delta = context.moveCurrentFrameIndex(current, -nLevels);
0N/A if (delta == 0) {
0N/A env.notice("Already at top of stack.");
0N/A } else if (-delta < nLevels) {
0N/A env.notice("Moved up " + delta + " frames to top of stack.");
0N/A }
0N/A } catch (VMNotInterruptedException e) {
0N/A env.failure("Target VM must be in interrupted state.");
0N/A }
0N/A }
0N/A
0N/A private void commandDown(StringTokenizer t) throws NoSessionException {
0N/A ThreadReference current = context.getCurrentThread();
0N/A if (current == null) {
0N/A env.failure("No current thread.");
0N/A return;
0N/A }
0N/A int nLevels = readCount(t);
0N/A if (nLevels <= 0) {
0N/A env.error("usage: down [n frames]");
0N/A return;
0N/A }
0N/A try {
0N/A int delta = context.moveCurrentFrameIndex(current, nLevels);
0N/A if (delta == 0) {
0N/A env.notice("Already at bottom of stack.");
0N/A } else if (delta < nLevels) {
0N/A env.notice("Moved down " + delta + " frames to bottom of stack.");
0N/A }
0N/A } catch (VMNotInterruptedException e) {
0N/A env.failure("Target VM must be in interrupted state.");
0N/A }
0N/A }
0N/A
0N/A // Command: frame
0N/A
0N/A private void commandFrame(StringTokenizer t) throws NoSessionException {
0N/A ThreadReference current = context.getCurrentThread();
0N/A if (current == null) {
0N/A env.failure("No current thread.");
0N/A return;
0N/A }
0N/A if (!t.hasMoreTokens()) {
0N/A env.error("usage: frame <frame-index>");
0N/A return;
0N/A }
0N/A String idToken = t.nextToken();
0N/A int n;
0N/A try {
0N/A n = Integer.valueOf(idToken).intValue();
0N/A } catch (NumberFormatException e) {
0N/A n = 0;
0N/A }
0N/A if (n <= 0) {
0N/A env.error("use positive frame index");
0N/A return;
0N/A }
0N/A try {
0N/A int delta = context.setCurrentFrameIndex(current, n);
0N/A if (delta == 0) {
0N/A env.notice("Frame unchanged.");
0N/A } else if (delta < 0) {
0N/A env.notice("Moved up " + -delta + " frames.");
0N/A } else {
0N/A env.notice("Moved down " + delta + " frames.");
0N/A }
0N/A } catch (VMNotInterruptedException e) {
0N/A env.failure("Target VM must be in interrupted state.");
0N/A }
0N/A }
0N/A
0N/A // Command: where
0N/A
0N/A //### Should we insist that VM be interrupted here?
0N/A //### There is an inconsistency between the 'where' command
0N/A //### and 'up' and 'down' in this respect.
0N/A
0N/A private void commandWhere(StringTokenizer t, boolean showPC)
0N/A throws NoSessionException {
0N/A ThreadReference current = context.getCurrentThread();
0N/A if (!t.hasMoreTokens()) {
0N/A if (current == null) {
0N/A env.error("No thread specified.");
0N/A return;
0N/A }
0N/A dumpStack(current, showPC);
0N/A } else {
0N/A String token = t.nextToken();
0N/A if (token.toLowerCase().equals("all")) {
0N/A ThreadIterator it = allThreads();
0N/A while (it.hasNext()) {
28N/A ThreadReference thread = it.next();
0N/A out.println(thread.name() + ": ");
0N/A dumpStack(thread, showPC);
0N/A }
0N/A } else {
0N/A ThreadReference thread = findThread(t.nextToken());
0N/A //### Do we want to set current thread here?
0N/A //### Should notify user of change.
0N/A if (thread != null) {
0N/A context.setCurrentThread(thread);
0N/A }
0N/A dumpStack(thread, showPC);
0N/A }
0N/A }
0N/A }
0N/A
0N/A private void dumpStack(ThreadReference thread, boolean showPC) {
0N/A //### Check for these.
0N/A //env.failure("Thread no longer exists.");
0N/A //env.failure("Target VM must be in interrupted state.");
0N/A //env.failure("Current thread isn't suspended.");
0N/A //### Should handle extremely long stack traces sensibly for user.
28N/A List<StackFrame> stack = null;
0N/A try {
0N/A stack = thread.frames();
0N/A } catch (IncompatibleThreadStateException e) {
0N/A env.failure("Thread is not suspended.");
0N/A }
0N/A //### Fix this!
0N/A //### Previously mishandled cases where thread was not current.
0N/A //### Now, prints all of the stack regardless of current frame.
0N/A int frameIndex = 0;
0N/A //int frameIndex = context.getCurrentFrameIndex();
0N/A if (stack == null) {
0N/A env.failure("Thread is not running (no stack).");
0N/A } else {
0N/A OutputSink out = env.getOutputSink();
0N/A int nFrames = stack.size();
0N/A for (int i = frameIndex; i < nFrames; i++) {
28N/A StackFrame frame = stack.get(i);
0N/A Location loc = frame.location();
0N/A Method meth = loc.method();
0N/A out.print(" [" + (i + 1) + "] ");
0N/A out.print(meth.declaringType().name());
0N/A out.print('.');
0N/A out.print(meth.name());
0N/A out.print(" (");
28N/A if (meth.isNative()) {
0N/A out.print("native method");
0N/A } else if (loc.lineNumber() != -1) {
0N/A try {
0N/A out.print(loc.sourceName());
0N/A } catch (AbsentInformationException e) {
0N/A out.print("<unknown>");
0N/A }
0N/A out.print(':');
0N/A out.print(loc.lineNumber());
0N/A }
0N/A out.print(')');
0N/A if (showPC) {
0N/A long pc = loc.codeIndex();
0N/A if (pc != -1) {
0N/A out.print(", pc = " + pc);
0N/A }
0N/A }
0N/A out.println();
0N/A }
0N/A out.show();
0N/A }
0N/A }
0N/A
0N/A private void listEventRequests() throws NoSessionException {
0N/A // Print set breakpoints
28N/A List<EventRequestSpec> specs = runtime.eventRequestSpecs();
28N/A if (specs.isEmpty()) {
0N/A env.notice("No breakpoints/watchpoints/exceptions set.");
0N/A } else {
0N/A OutputSink out = env.getOutputSink();
0N/A out.println("Current breakpoints/watchpoints/exceptions set:");
28N/A for (EventRequestSpec bp : specs) {
0N/A out.println("\t" + bp);
0N/A }
0N/A out.show();
0N/A }
0N/A }
0N/A
0N/A private BreakpointSpec parseBreakpointSpec(String bptSpec) {
0N/A StringTokenizer t = new StringTokenizer(bptSpec);
0N/A BreakpointSpec bpSpec = null;
0N/A// try {
0N/A String token = t.nextToken("@:( \t\n\r");
0N/A // We can't use hasMoreTokens here because it will cause any leading
0N/A // paren to be lost.
0N/A String rest;
0N/A try {
0N/A rest = t.nextToken("").trim();
0N/A } catch (NoSuchElementException e) {
0N/A rest = null;
0N/A }
0N/A if ((rest != null) && rest.startsWith("@")) {
0N/A t = new StringTokenizer(rest.substring(1));
0N/A String sourceName = token;
0N/A String lineToken = t.nextToken();
0N/A int lineNumber = Integer.valueOf(lineToken).intValue();
0N/A if (t.hasMoreTokens()) {
0N/A return null;
0N/A }
0N/A bpSpec = runtime.createSourceLineBreakpoint(sourceName,
0N/A lineNumber);
0N/A } else if ((rest != null) && rest.startsWith(":")) {
0N/A t = new StringTokenizer(rest.substring(1));
0N/A String classId = token;
0N/A String lineToken = t.nextToken();
0N/A int lineNumber = Integer.valueOf(lineToken).intValue();
0N/A if (t.hasMoreTokens()) {
0N/A return null;
0N/A }
0N/A bpSpec = runtime.createClassLineBreakpoint(classId, lineNumber);
0N/A } else {
0N/A // Try stripping method from class.method token.
0N/A int idot = token.lastIndexOf(".");
0N/A if ( (idot <= 0) || /* No dot or dot in first char */
0N/A (idot >= token.length() - 1) ) { /* dot in last char */
0N/A return null;
0N/A }
0N/A String methodName = token.substring(idot + 1);
0N/A String classId = token.substring(0, idot);
0N/A List<String> argumentList = null;
0N/A if (rest != null) {
0N/A if (!rest.startsWith("(") || !rest.endsWith(")")) {
0N/A //### Should throw exception with error message
0N/A //out.println("Invalid method specification: "
0N/A // + methodName + rest);
0N/A return null;
0N/A }
0N/A // Trim the parens
0N/A //### What about spaces in arglist?
0N/A rest = rest.substring(1, rest.length() - 1);
0N/A argumentList = new ArrayList<String>();
0N/A t = new StringTokenizer(rest, ",");
0N/A while (t.hasMoreTokens()) {
0N/A argumentList.add(t.nextToken());
0N/A }
0N/A }
0N/A bpSpec = runtime.createMethodBreakpoint(classId,
0N/A methodName,
0N/A argumentList);
0N/A }
0N/A// } catch (Exception e) {
0N/A// env.error("Exception attempting to create breakpoint: " + e);
0N/A// return null;
0N/A// }
0N/A return bpSpec;
0N/A }
0N/A
0N/A private void commandStop(StringTokenizer t) throws NoSessionException {
0N/A String token;
0N/A
0N/A if (!t.hasMoreTokens()) {
0N/A listEventRequests();
0N/A } else {
0N/A token = t.nextToken();
0N/A // Ignore optional "at" or "in" token.
0N/A // Allowed for backward compatibility.
0N/A if (token.equals("at") || token.equals("in")) {
0N/A if (t.hasMoreTokens()) {
0N/A token = t.nextToken();
0N/A } else {
0N/A env.error("Missing breakpoint specification.");
0N/A return;
0N/A }
0N/A }
0N/A BreakpointSpec bpSpec = parseBreakpointSpec(token);
0N/A if (bpSpec != null) {
0N/A //### Add sanity-checks for deferred breakpoint.
0N/A runtime.install(bpSpec);
0N/A } else {
0N/A env.error("Ill-formed breakpoint specification.");
0N/A }
0N/A }
0N/A }
0N/A
0N/A private void commandClear(StringTokenizer t) throws NoSessionException {
0N/A if (!t.hasMoreTokens()) {
0N/A // Print set breakpoints
0N/A listEventRequests();
0N/A return;
0N/A }
0N/A //### need 'clear all'
0N/A BreakpointSpec bpSpec = parseBreakpointSpec(t.nextToken());
0N/A if (bpSpec != null) {
28N/A List<EventRequestSpec> specs = runtime.eventRequestSpecs();
28N/A
28N/A if (specs.isEmpty()) {
0N/A env.notice("No breakpoints set.");
0N/A } else {
28N/A List<EventRequestSpec> toDelete = new ArrayList<EventRequestSpec>();
28N/A for (EventRequestSpec spec : specs) {
0N/A if (spec.equals(bpSpec)) {
0N/A toDelete.add(spec);
0N/A }
0N/A }
0N/A // The request used for matching should be found
0N/A if (toDelete.size() <= 1) {
0N/A env.notice("No matching breakpoint set.");
0N/A }
28N/A for (EventRequestSpec spec : toDelete) {
0N/A runtime.delete(spec);
0N/A }
0N/A }
0N/A } else {
0N/A env.error("Ill-formed breakpoint specification.");
0N/A }
0N/A }
0N/A
0N/A // Command: list
0N/A
0N/A private void commandList(StringTokenizer t) throws NoSessionException {
0N/A ThreadReference current = context.getCurrentThread();
0N/A if (current == null) {
0N/A env.error("No thread specified.");
0N/A return;
0N/A }
0N/A Location loc;
0N/A try {
0N/A StackFrame frame = context.getCurrentFrame(current);
0N/A if (frame == null) {
0N/A env.failure("Thread has not yet begun execution.");
0N/A return;
0N/A }
0N/A loc = frame.location();
0N/A } catch (VMNotInterruptedException e) {
0N/A env.failure("Target VM must be in interrupted state.");
0N/A return;
0N/A }
0N/A SourceModel source = sourceManager.sourceForLocation(loc);
0N/A if (source == null) {
0N/A if (loc.method().isNative()) {
0N/A env.failure("Current method is native.");
0N/A return;
0N/A }
0N/A env.failure("No source available for " + Utils.locationString(loc) + ".");
0N/A return;
0N/A }
0N/A ReferenceType refType = loc.declaringType();
0N/A int lineno = loc.lineNumber();
0N/A if (t.hasMoreTokens()) {
0N/A String id = t.nextToken();
0N/A // See if token is a line number.
0N/A try {
0N/A lineno = Integer.valueOf(id).intValue();
0N/A } catch (NumberFormatException nfe) {
0N/A // It isn't -- see if it's a method name.
28N/A List<Method> meths = refType.methodsByName(id);
0N/A if (meths == null || meths.size() == 0) {
0N/A env.failure(id +
0N/A " is not a valid line number or " +
0N/A "method name for class " +
0N/A refType.name());
0N/A return;
0N/A } else if (meths.size() > 1) {
0N/A env.failure(id +
0N/A " is an ambiguous method name in" +
0N/A refType.name());
0N/A return;
0N/A }
28N/A loc = meths.get(0).location();
0N/A lineno = loc.lineNumber();
0N/A }
0N/A }
0N/A int startLine = (lineno > 4) ? lineno - 4 : 1;
0N/A int endLine = startLine + 9;
0N/A String sourceLine = source.sourceLine(lineno);
0N/A if (sourceLine == null) {
0N/A env.failure("" +
0N/A lineno +
0N/A " is an invalid line number for " +
0N/A refType.name());
0N/A } else {
0N/A OutputSink out = env.getOutputSink();
0N/A for (int i = startLine; i <= endLine; i++) {
0N/A sourceLine = source.sourceLine(i);
0N/A if (sourceLine == null) {
0N/A break;
0N/A }
0N/A out.print(i);
0N/A out.print("\t");
0N/A if (i == lineno) {
0N/A out.print("=> ");
0N/A } else {
0N/A out.print(" ");
0N/A }
0N/A out.println(sourceLine);
0N/A }
0N/A out.show();
0N/A }
0N/A }
0N/A
0N/A // Command: use
0N/A // Get or set the source file path list.
0N/A
0N/A private void commandUse(StringTokenizer t) {
0N/A if (!t.hasMoreTokens()) {
0N/A out.println(sourceManager.getSourcePath().asString());
0N/A } else {
0N/A //### Should throw exception for invalid path.
0N/A //### E.g., vetoable property change.
0N/A sourceManager.setSourcePath(new SearchPath(t.nextToken()));
0N/A }
0N/A }
0N/A
0N/A // Command: sourcepath
0N/A // Get or set the source file path list. (Alternate to 'use'.)
0N/A
0N/A private void commandSourcepath(StringTokenizer t) {
0N/A if (!t.hasMoreTokens()) {
0N/A out.println(sourceManager.getSourcePath().asString());
0N/A } else {
0N/A //### Should throw exception for invalid path.
0N/A //### E.g., vetoable property change.
0N/A sourceManager.setSourcePath(new SearchPath(t.nextToken()));
0N/A }
0N/A }
0N/A
0N/A // Command: classpath
0N/A // Get or set the class file path list.
0N/A
0N/A private void commandClasspath(StringTokenizer t) {
0N/A if (!t.hasMoreTokens()) {
0N/A out.println(classManager.getClassPath().asString());
0N/A } else {
0N/A //### Should throw exception for invalid path.
0N/A //### E.g., vetoable property change.
0N/A classManager.setClassPath(new SearchPath(t.nextToken()));
0N/A }
0N/A }
0N/A
0N/A // Command: view
0N/A // Display source for source file or class.
0N/A
0N/A private void commandView(StringTokenizer t) throws NoSessionException {
0N/A if (!t.hasMoreTokens()) {
0N/A env.error("Argument required");
0N/A } else {
0N/A String name = t.nextToken();
0N/A if (name.endsWith(".java") ||
0N/A name.indexOf(File.separatorChar) >= 0) {
0N/A env.viewSource(name);
0N/A } else {
0N/A //### JDI crashes taking line number for class.
0N/A /*****
0N/A ReferenceType cls = findClass(name);
0N/A if (cls != null) {
0N/A env.viewLocation(cls.location());
0N/A } else {
0N/A env.failure("No such class");
0N/A }
0N/A *****/
0N/A String fileName = name.replace('.', File.separatorChar) + ".java";
0N/A env.viewSource(fileName);
0N/A }
0N/A }
0N/A }
0N/A
0N/A // Command: locals
0N/A // Print all local variables in current stack frame.
0N/A
0N/A private void commandLocals() throws NoSessionException {
0N/A ThreadReference current = context.getCurrentThread();
0N/A if (current == null) {
0N/A env.failure("No default thread specified: " +
0N/A "use the \"thread\" command first.");
0N/A return;
0N/A }
0N/A StackFrame frame;
0N/A try {
0N/A frame = context.getCurrentFrame(current);
0N/A if (frame == null) {
0N/A env.failure("Thread has not yet created any stack frames.");
0N/A return;
0N/A }
0N/A } catch (VMNotInterruptedException e) {
0N/A env.failure("Target VM must be in interrupted state.");
0N/A return;
0N/A }
0N/A
28N/A List<LocalVariable> vars;
0N/A try {
0N/A vars = frame.visibleVariables();
0N/A if (vars == null || vars.size() == 0) {
0N/A env.failure("No local variables");
0N/A return;
0N/A }
0N/A } catch (AbsentInformationException e) {
0N/A env.failure("Local variable information not available." +
0N/A " Compile with -g to generate variable information");
0N/A return;
0N/A }
0N/A
0N/A OutputSink out = env.getOutputSink();
0N/A out.println("Method arguments:");
28N/A for (LocalVariable var : vars) {
0N/A if (var.isArgument()) {
0N/A printVar(out, var, frame);
0N/A }
0N/A }
0N/A out.println("Local variables:");
28N/A for (LocalVariable var : vars) {
0N/A if (!var.isArgument()) {
0N/A printVar(out, var, frame);
0N/A }
0N/A }
0N/A out.show();
0N/A return;
0N/A }
0N/A
0N/A /**
0N/A * Command: monitor
0N/A * Monitor an expression
0N/A */
0N/A private void commandMonitor(StringTokenizer t) throws NoSessionException {
0N/A if (!t.hasMoreTokens()) {
0N/A env.error("Argument required");
0N/A } else {
0N/A env.getMonitorListModel().add(t.nextToken(""));
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Command: unmonitor
0N/A * Unmonitor an expression
0N/A */
0N/A private void commandUnmonitor(StringTokenizer t) throws NoSessionException {
0N/A if (!t.hasMoreTokens()) {
0N/A env.error("Argument required");
0N/A } else {
0N/A env.getMonitorListModel().remove(t.nextToken(""));
0N/A }
0N/A }
0N/A
0N/A // Print a stack variable.
0N/A
0N/A private void printVar(OutputSink out, LocalVariable var, StackFrame frame) {
0N/A out.print(" " + var.name());
0N/A if (var.isVisible(frame)) {
0N/A Value val = frame.getValue(var);
0N/A out.println(" = " + val.toString());
0N/A } else {
0N/A out.println(" is not in scope");
0N/A }
0N/A }
0N/A
0N/A // Command: print
0N/A // Evaluate an expression.
0N/A
0N/A private void commandPrint(StringTokenizer t, boolean dumpObject) throws NoSessionException {
0N/A if (!t.hasMoreTokens()) {
0N/A //### Probably confused if expresion contains whitespace.
0N/A env.error("No expression specified.");
0N/A return;
0N/A }
0N/A ThreadReference current = context.getCurrentThread();
0N/A if (current == null) {
0N/A env.failure("No default thread specified: " +
0N/A "use the \"thread\" command first.");
0N/A return;
0N/A }
0N/A StackFrame frame;
0N/A try {
0N/A frame = context.getCurrentFrame(current);
0N/A if (frame == null) {
0N/A env.failure("Thread has not yet created any stack frames.");
0N/A return;
0N/A }
0N/A } catch (VMNotInterruptedException e) {
0N/A env.failure("Target VM must be in interrupted state.");
0N/A return;
0N/A }
0N/A while (t.hasMoreTokens()) {
0N/A String expr = t.nextToken("");
0N/A Value val = null;
0N/A try {
0N/A val = runtime.evaluate(frame, expr);
0N/A } catch(Exception e) {
0N/A env.error("Exception: " + e);
0N/A //### Fix this!
0N/A }
0N/A if (val == null) {
0N/A return; // Error message already printed
0N/A }
0N/A OutputSink out = env.getOutputSink();
0N/A if (dumpObject && (val instanceof ObjectReference) &&
0N/A !(val instanceof StringReference)) {
0N/A ObjectReference obj = (ObjectReference)val;
0N/A ReferenceType refType = obj.referenceType();
0N/A out.println(expr + " = " + val.toString() + " {");
0N/A dump(out, obj, refType, refType);
0N/A out.println("}");
0N/A } else {
0N/A out.println(expr + " = " + val.toString());
0N/A }
0N/A out.show();
0N/A }
0N/A }
0N/A
0N/A private void dump(OutputSink out,
0N/A ObjectReference obj, ReferenceType refType,
0N/A ReferenceType refTypeBase) {
28N/A for (Field field : refType.fields()) {
0N/A out.print(" ");
0N/A if (!refType.equals(refTypeBase)) {
0N/A out.print(refType.name() + ".");
0N/A }
0N/A out.print(field.name() + ": ");
0N/A Object o = obj.getValue(field);
0N/A out.println((o == null) ? "null" : o.toString()); // Bug ID 4374471
0N/A }
0N/A if (refType instanceof ClassType) {
0N/A ClassType sup = ((ClassType)refType).superclass();
0N/A if (sup != null) {
0N/A dump(out, obj, sup, refTypeBase);
0N/A }
0N/A } else if (refType instanceof InterfaceType) {
28N/A for (InterfaceType sup : ((InterfaceType)refType).superinterfaces()) {
28N/A dump(out, obj, sup, refTypeBase);
0N/A }
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Display help message.
0N/A */
0N/A
0N/A private void help() {
0N/A out.println("** command list **");
0N/A out.println("threads [threadgroup] -- list threads");
0N/A out.println("thread <thread id> -- set default thread");
0N/A out.println("suspend [thread id(s)] -- suspend threads (default: all)");
0N/A out.println("resume [thread id(s)] -- resume threads (default: all)");
0N/A out.println("where [thread id] | all -- dump a thread's stack");
0N/A out.println("wherei [thread id] | all -- dump a thread's stack, with pc info");
0N/A out.println("threadgroups -- list threadgroups");
0N/A out.println("threadgroup <name> -- set current threadgroup\n");
0N/A// out.println("print <expression> -- print value of expression");
0N/A out.println("dump <expression> -- print all object information\n");
0N/A// out.println("eval <expression> -- evaluate expression (same as print)");
0N/A out.println("locals -- print all local variables in current stack frame\n");
0N/A out.println("classes -- list currently known classes");
0N/A out.println("methods <class id> -- list a class's methods\n");
0N/A out.println("stop [in] <class id>.<method>[(argument_type,...)] -- set a breakpoint in a method");
0N/A out.println("stop [at] <class id>:<line> -- set a breakpoint at a line");
0N/A out.println("up [n frames] -- move up a thread's stack");
0N/A out.println("down [n frames] -- move down a thread's stack");
0N/A out.println("frame <frame-id> -- to a frame");
0N/A out.println("clear <class id>.<method>[(argument_type,...)] -- clear a breakpoint in a method");
0N/A out.println("clear <class id>:<line> -- clear a breakpoint at a line");
0N/A out.println("clear -- list breakpoints");
0N/A out.println("step -- execute current line");
0N/A out.println("step up -- execute until the current method returns to its caller");
0N/A out.println("stepi -- execute current instruction");
0N/A out.println("next -- step one line (step OVER calls)");
0N/A out.println("nexti -- step one instruction (step OVER calls)");
0N/A out.println("cont -- continue execution from breakpoint\n");
0N/A// out.println("catch <class id> -- break for the specified exception");
0N/A// out.println("ignore <class id> -- ignore when the specified exception\n");
0N/A out.println("view classname|filename -- display source file");
0N/A out.println("list [line number|method] -- print source code context at line or method");
0N/A out.println("use <source file path> -- display or change the source path\n");
0N/A//### new
0N/A out.println("sourcepath <source file path> -- display or change the source path\n");
0N/A//### new
0N/A out.println("classpath <class file path> -- display or change the class path\n");
0N/A out.println("monitor <expression> -- evaluate an expression each time the program stops\n");
0N/A out.println("unmonitor <monitor#> -- delete a monitor\n");
0N/A out.println("read <filename> -- read and execute a command file\n");
0N/A// out.println("memory -- report memory usage");
0N/A// out.println("gc -- free unused objects\n");
0N/A out.println("run <class> [args] -- start execution of a Java class");
0N/A out.println("run -- re-execute last class run");
0N/A out.println("load <class> [args] -- start execution of a Java class, initially suspended");
0N/A out.println("load -- re-execute last class run, initially suspended");
0N/A out.println("attach <portname> -- debug existing process\n");
0N/A out.println("detach -- detach from debuggee process\n");
0N/A out.println("kill <thread(group)> -- kill a thread or threadgroup\n");
0N/A out.println("!! -- repeat last command");
0N/A out.println("help (or ?) -- list commands");
0N/A out.println("exit (or quit) -- exit debugger");
0N/A }
0N/A
0N/A /*
0N/A * Execute a command.
0N/A */
0N/A
0N/A public void executeCommand(String command) {
0N/A //### Treatment of 'out' here is dirty...
0N/A out = env.getOutputSink();
0N/A if (echo) {
0N/A out.println(">>> " + command);
0N/A }
0N/A StringTokenizer t = new StringTokenizer(command);
0N/A try {
0N/A String cmd;
0N/A if (t.hasMoreTokens()) {
0N/A cmd = t.nextToken().toLowerCase();
0N/A lastCommand = cmd;
0N/A } else {
0N/A cmd = lastCommand;
0N/A }
0N/A if (cmd.equals("print")) {
0N/A commandPrint(t, false);
0N/A } else if (cmd.equals("eval")) {
0N/A commandPrint(t, false);
0N/A } else if (cmd.equals("dump")) {
0N/A commandPrint(t, true);
0N/A } else if (cmd.equals("locals")) {
0N/A commandLocals();
0N/A } else if (cmd.equals("classes")) {
0N/A commandClasses();
0N/A } else if (cmd.equals("methods")) {
0N/A commandMethods(t);
0N/A } else if (cmd.equals("threads")) {
0N/A commandThreads(t);
0N/A } else if (cmd.equals("thread")) {
0N/A commandThread(t);
0N/A } else if (cmd.equals("suspend")) {
0N/A commandSuspend(t);
0N/A } else if (cmd.equals("resume")) {
0N/A commandResume(t);
0N/A } else if (cmd.equals("cont")) {
0N/A commandCont();
0N/A } else if (cmd.equals("threadgroups")) {
0N/A commandThreadGroups();
0N/A } else if (cmd.equals("threadgroup")) {
0N/A commandThreadGroup(t);
0N/A } else if (cmd.equals("run")) {
0N/A commandRun(t);
0N/A } else if (cmd.equals("load")) {
0N/A commandLoad(t);
0N/A } else if (cmd.equals("connect")) {
0N/A commandConnect(t);
0N/A } else if (cmd.equals("attach")) {
0N/A commandAttach(t);
0N/A } else if (cmd.equals("detach")) {
0N/A commandDetach(t);
0N/A } else if (cmd.equals("interrupt")) {
0N/A commandInterrupt(t);
0N/A//### Not implemented.
0N/A// } else if (cmd.equals("catch")) {
0N/A// commandCatchException(t);
0N/A//### Not implemented.
0N/A// } else if (cmd.equals("ignore")) {
0N/A// commandIgnoreException(t);
0N/A } else if (cmd.equals("step")) {
0N/A commandStep(t);
0N/A } else if (cmd.equals("stepi")) {
0N/A commandStepi();
0N/A } else if (cmd.equals("next")) {
0N/A commandNext();
0N/A } else if (cmd.equals("nexti")) {
0N/A commandNexti();
0N/A } else if (cmd.equals("kill")) {
0N/A commandKill(t);
0N/A } else if (cmd.equals("where")) {
0N/A commandWhere(t, false);
0N/A } else if (cmd.equals("wherei")) {
0N/A commandWhere(t, true);
0N/A } else if (cmd.equals("up")) {
0N/A commandUp(t);
0N/A } else if (cmd.equals("down")) {
0N/A commandDown(t);
0N/A } else if (cmd.equals("frame")) {
0N/A commandFrame(t);
0N/A } else if (cmd.equals("stop")) {
0N/A commandStop(t);
0N/A } else if (cmd.equals("clear")) {
0N/A commandClear(t);
0N/A } else if (cmd.equals("list")) {
0N/A commandList(t);
0N/A } else if (cmd.equals("use")) {
0N/A commandUse(t);
0N/A } else if (cmd.equals("sourcepath")) {
0N/A commandSourcepath(t);
0N/A } else if (cmd.equals("classpath")) {
0N/A commandClasspath(t);
0N/A } else if (cmd.equals("monitor")) {
0N/A commandMonitor(t);
0N/A } else if (cmd.equals("unmonitor")) {
0N/A commandUnmonitor(t);
0N/A } else if (cmd.equals("view")) {
0N/A commandView(t);
0N/A// } else if (cmd.equals("read")) {
0N/A// readCommand(t);
0N/A } else if (cmd.equals("help") || cmd.equals("?")) {
0N/A help();
0N/A } else if (cmd.equals("quit") || cmd.equals("exit")) {
0N/A try {
0N/A runtime.detach();
0N/A } catch (NoSessionException e) {
0N/A // ignore
0N/A }
0N/A env.terminate();
0N/A } else {
0N/A //### Dubious repeat-count feature inherited from 'jdb'
0N/A if (t.hasMoreTokens()) {
0N/A try {
0N/A int repeat = Integer.parseInt(cmd);
0N/A String subcom = t.nextToken("");
0N/A while (repeat-- > 0) {
0N/A executeCommand(subcom);
0N/A }
0N/A return;
0N/A } catch (NumberFormatException exc) {
0N/A }
0N/A }
0N/A out.println("huh? Try help...");
0N/A out.flush();
0N/A }
0N/A } catch (NoSessionException e) {
0N/A out.println("There is no currently attached VM session.");
0N/A out.flush();
0N/A } catch (Exception e) {
0N/A out.println("Internal exception: " + e.toString());
0N/A out.flush();
0N/A System.out.println("JDB internal exception: " + e.toString());
0N/A e.printStackTrace();
0N/A }
0N/A out.show();
0N/A }
0N/A}