|
Java example source code file (CommandInterpreter.java)
This example Java source code file (CommandInterpreter.java) is included in the alvinalexander.com
"Java Source Code
Warehouse" project. The intent of this project is to help you "Learn
Java by Example" TM.
Learn more about this Java project at its project page.
The CommandInterpreter.java Java example source code
/*
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* 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; //### Hack! Should be local in each method used.
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();
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("No thread for id \"" + idToken + "\"");
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;
//### Why not use runtime.allThreads().iterator() ?
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();
//out.println("** classes list **");
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 {
//### Should validate class name syntax.
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) {
//### Should handle multiple results sensibly.
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 {
//### Issue: Uniqueness of thread group names is not enforced.
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);
// Right-justify the thread number at start of output string
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)) { // TODO ref mgt
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) {
//### Should notify user.
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 {
//### Should notify user.
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("")) {
// Run from prevously-set class name.
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();
// Allow VM arguments to be specified here?
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.setVmArguments(vmArgs);
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.
//### Behavior here agrees with 'jdb', however.
ThreadIterator ti = currentThreadGroupThreads();
while (ti.hasNext()) {
// TODO - don't suspend debugger threads
ti.nextThread().suspend();
}
env.notice("All (non-system) threads suspended.");
} else {
while (t.hasMoreTokens()) {
ThreadReference thread = findThread(t.nextToken());
if (thread != null) {
//thread.suspend();
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.
//### Behavior here agrees with 'jdb', however.
ThreadIterator ti = currentThreadGroupThreads();
while (ti.hasNext()) {
// TODO - don't suspend debugger threads
ti.nextThread().resume();
}
env.notice("All threads resumed.");
} else {
while (t.hasMoreTokens()) {
ThreadReference thread = findThread(t.nextToken());
if (thread != null) {
//thread.resume();
runtime.resumeThread(thread);
}
}
}
}
// Command: cont
private void commandCont() throws NoSessionException {
try {
runtime.go();
} catch (VMNotInterruptedException e) {
//### failure?
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
//### are distinguished.
if (!t.hasMoreTokens()) {
env.error("Usage: kill <threadgroup name> or ");
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.
//### Should deal with possible non-uniqueness of threadgroup names.
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?
//### Should notify user of change.
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.");
//### Should handle extremely long stack traces sensibly for user.
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.
//### Now, prints all of the stack regardless of current frame.
int frameIndex = 0;
//int frameIndex = context.getCurrentFrameIndex();
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 {
// Print set breakpoints
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;
// try {
String token = t.nextToken("@:( \t\n\r");
// We can't use hasMoreTokens here because it will cause any leading
// paren to be lost.
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 {
// Try stripping method from class.method token.
int idot = token.lastIndexOf(".");
if ( (idot <= 0) || /* No dot or dot in first char */
(idot >= token.length() - 1) ) { /* dot in last char */
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: "
// + methodName + rest);
return null;
}
// Trim the parens
//### What about spaces in arglist?
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.
// Allowed for backward compatibility.
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) {
//### Add sanity-checks for deferred breakpoint.
runtime.install(bpSpec);
} else {
env.error("Ill-formed breakpoint specification.");
}
}
}
private void commandClear(StringTokenizer t) throws NoSessionException {
if (!t.hasMoreTokens()) {
// Print set breakpoints
listEventRequests();
return;
}
//### need 'clear all'
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();
for (EventRequestSpec spec : specs) {
if (spec.equals(bpSpec)) {
toDelete.add(spec);
}
}
// The request used for matching should be found
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();
// See if token is a line number.
try {
lineno = Integer.valueOf(id).intValue();
} catch (NumberFormatException nfe) {
// It isn't -- see if it's a method name.
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.
//### E.g., vetoable property change.
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.
//### E.g., vetoable property change.
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.
//### E.g., vetoable property change.
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.
/*****
ReferenceType cls = findClass(name);
if (cls != null) {
env.viewLocation(cls.location());
} else {
env.failure("No such 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;
}
/**
* Command: monitor
* Monitor an expression
*/
private void commandMonitor(StringTokenizer t) throws NoSessionException {
if (!t.hasMoreTokens()) {
env.error("Argument required");
} else {
env.getMonitorListModel().add(t.nextToken(""));
}
}
/**
* Command: unmonitor
* Unmonitor an expression
*/
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()) {
//### Probably confused if expresion contains whitespace.
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; // Error message already printed
}
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()); // Bug ID 4374471
}
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("print <expression> -- print value of expression");
out.println("dump <expression> -- print all object information\n");
// out.println("eval <expression> -- evaluate expression (same as print)");
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>.[(argument_type,...)] -- set a breakpoint in a method");
out.println("stop [at] <class id>: -- 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>.[(argument_type,...)] -- clear a breakpoint in a method");
out.println("clear <class id>: -- 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("ignore <class id> -- ignore when the specified exception\n");
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");
//### new
out.println("sourcepath <source file path> -- display or change the source path\n");
//### new
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("gc -- free unused objects\n");
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) {
//### Treatment of 'out' here is dirty...
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 {
//### Dubious repeat-count feature inherited from 'jdb'
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();
}
}
Other Java examples (source code examples)
Here is a short list of links related to this Java CommandInterpreter.java source code file:
|