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;
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;
}
private void commandClasses() throws NoSessionException {
OutputSink out = env.getOutputSink();
for (ReferenceType refType : runtime.allClasses()) {
out.println(refType.name());
}
out.show();
}
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;
}
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();
}
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();
}
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);
}
}
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);
}
}
private void commandRun(StringTokenizer t) throws NoSessionException {
if (doLoad(false, t)) {
env.notice("Running ...");
}
}
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 specifed 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;
}
private void commandConnect(StringTokenizer t) {
try {
LaunchTool.queryAndLaunchVM(runtime);
} catch (VMLaunchFailureException e) {
env.failure("Attempt to connect failed.");
}
}
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 specifed 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);
}
}
private void commandDetach(StringTokenizer t) throws NoSessionException {
runtime.detach();
}
private void commandInterrupt(StringTokenizer t) throws NoSessionException {
runtime.interrupt();
}
private void commandSuspend(StringTokenizer t) throws NoSessionException {
if (!t.hasMoreTokens()) {
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);
}
}
}
}
private void commandResume(StringTokenizer t) throws NoSessionException {
if (!t.hasMoreTokens()) {
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);
}
}
}
}
private void commandCont() throws NoSessionException {
try {
runtime.go();
} catch (VMNotInterruptedException e) {
env.notice("Target VM is already running.");
}
}
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.");
}
}
private void commandStepi() throws NoSessionException {
ThreadReference current = context.getCurrentThread();
if (current == null) {
env.failure("No current thread.");
return;
}
runtime.stepIntoInstruction(current);
}
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.");
}
}
private void commandNexti() throws NoSessionException {
ThreadReference current = context.getCurrentThread();
if (current == null) {
env.failure("No current thread.");
return;
}
runtime.stepOverInstruction(current);
}
private void commandKill(StringTokenizer t) throws NoSessionException {
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 {
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.");
}
}
}
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.");
}
}
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.");
}
}
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());
if (thread != null) {
context.setCurrentThread(thread);
}
dumpStack(thread, showPC);
}
}
}
private void dumpStack(ThreadReference thread, boolean showPC) {
List<StackFrame> stack = null;
try {
stack = thread.frames();
} catch (IncompatibleThreadStateException e) {
env.failure("Thread is not suspended.");
}
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");
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(")")) {
return null;
}
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);
}
return bpSpec;
}
private void commandStop(StringTokenizer t) throws NoSessionException {
String token;
if (!t.hasMoreTokens()) {
listEventRequests();
} else {
token = t.nextToken();
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.");
}
}
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();
}
}
private void commandUse(StringTokenizer t) {
if (!t.hasMoreTokens()) {
out.println(sourceManager.getSourcePath().asString());
} else {
sourceManager.setSourcePath(new SearchPath(t.nextToken()));
}
}
private void commandSourcepath(StringTokenizer t) {
if (!t.hasMoreTokens()) {
out.println(sourceManager.getSourcePath().asString());
} else {
sourceManager.setSourcePath(new SearchPath(t.nextToken()));
}
}
private void commandClasspath(StringTokenizer t) {
if (!t.hasMoreTokens()) {
out.println(classManager.getClassPath().asString());
} else {
classManager.setClassPath(new SearchPath(t.nextToken()));
}
}
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 {
String fileName = name.replace('.', File.separatorChar) + ".java";
env.viewSource(fileName);
}
}
}
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(""));
}
}
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");
}
}
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);
}
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);
}
}
}
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("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("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");
}
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);
} 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("help") || cmd.equals("?")) {
help();
} else if (cmd.equals("quit") || cmd.equals("exit")) {
try {
runtime.detach();
} catch (NoSessionException e) {
}
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();
}
}