|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
/* |
|
* 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.tty; |
|
|
|
import com.sun.jdi.*; |
|
import com.sun.jdi.connect.Connector; |
|
import com.sun.jdi.request.*; |
|
import com.sun.tools.example.debug.expr.ExpressionParser; |
|
import com.sun.tools.example.debug.expr.ParseException; |
|
|
|
import java.text.*; |
|
import java.util.*; |
|
import java.io.*; |
|
|
|
class Commands { |
|
|
|
abstract class AsyncExecution { |
|
abstract void action(); |
|
|
|
AsyncExecution() { |
|
execute(); |
|
} |
|
|
|
void execute() { |
|
|
|
|
|
*/ |
|
final ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo(); |
|
final int stackFrame = threadInfo == null? 0 : threadInfo.getCurrentFrameIndex(); |
|
Thread thread = new Thread("asynchronous jdb command") { |
|
@Override |
|
public void run() { |
|
try { |
|
action(); |
|
} catch (UnsupportedOperationException uoe) { |
|
|
|
MessageOutput.println("Operation is not supported on the target VM"); |
|
} catch (Exception e) { |
|
MessageOutput.println("Internal exception during operation:", |
|
e.getMessage()); |
|
} finally { |
|
|
|
|
|
|
|
|
|
*/ |
|
if (threadInfo != null) { |
|
ThreadInfo.setCurrentThreadInfo(threadInfo); |
|
try { |
|
threadInfo.setCurrentFrameIndex(stackFrame); |
|
} catch (IncompatibleThreadStateException e) { |
|
MessageOutput.println("Current thread isnt suspended."); |
|
} catch (ArrayIndexOutOfBoundsException e) { |
|
MessageOutput.println("Requested stack frame is no longer active:", |
|
new Object []{new Integer(stackFrame)}); |
|
} |
|
} |
|
MessageOutput.printPrompt(); |
|
} |
|
} |
|
}; |
|
thread.start(); |
|
} |
|
} |
|
|
|
Commands() { |
|
} |
|
|
|
private Value evaluate(String expr) { |
|
Value result = null; |
|
ExpressionParser.GetFrame frameGetter = null; |
|
try { |
|
final ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo(); |
|
if ((threadInfo != null) && (threadInfo.getCurrentFrame() != null)) { |
|
frameGetter = new ExpressionParser.GetFrame() { |
|
@Override |
|
public StackFrame get() throws IncompatibleThreadStateException { |
|
return threadInfo.getCurrentFrame(); |
|
} |
|
}; |
|
} |
|
result = ExpressionParser.evaluate(expr, Env.vm(), frameGetter); |
|
} catch (InvocationException ie) { |
|
MessageOutput.println("Exception in expression:", |
|
ie.exception().referenceType().name()); |
|
} catch (Exception ex) { |
|
String exMessage = ex.getMessage(); |
|
if (exMessage == null) { |
|
MessageOutput.printException(exMessage, ex); |
|
} else { |
|
String s; |
|
try { |
|
s = MessageOutput.format(exMessage); |
|
} catch (MissingResourceException mex) { |
|
s = ex.toString(); |
|
} |
|
MessageOutput.printDirectln(s); |
|
} |
|
} |
|
return result; |
|
} |
|
|
|
private String getStringValue() { |
|
Value val = null; |
|
String valStr = null; |
|
try { |
|
val = ExpressionParser.getMassagedValue(); |
|
valStr = val.toString(); |
|
} catch (ParseException e) { |
|
String msg = e.getMessage(); |
|
if (msg == null) { |
|
MessageOutput.printException(msg, e); |
|
} else { |
|
String s; |
|
try { |
|
s = MessageOutput.format(msg); |
|
} catch (MissingResourceException mex) { |
|
s = e.toString(); |
|
} |
|
MessageOutput.printDirectln(s); |
|
} |
|
} |
|
return valStr; |
|
} |
|
|
|
private ThreadInfo doGetThread(String idToken) { |
|
ThreadInfo threadInfo = ThreadInfo.getThreadInfo(idToken); |
|
if (threadInfo == null) { |
|
MessageOutput.println("is not a valid thread id", idToken); |
|
} |
|
return threadInfo; |
|
} |
|
|
|
String typedName(Method method) { |
|
StringBuffer buf = new StringBuffer(); |
|
buf.append(method.name()); |
|
buf.append("("); |
|
|
|
List<String> args = method.argumentTypeNames(); |
|
int lastParam = args.size() - 1; |
|
|
|
for (int ii = 0; ii < lastParam; ii++) { |
|
buf.append(args.get(ii)); |
|
buf.append(", "); |
|
} |
|
if (lastParam >= 0) { |
|
|
|
String lastStr = args.get(lastParam); |
|
if (method.isVarArgs()) { |
|
|
|
buf.append(lastStr.substring(0, lastStr.length() - 2)); |
|
buf.append("..."); |
|
} else { |
|
buf.append(lastStr); |
|
} |
|
} |
|
buf.append(")"); |
|
return buf.toString(); |
|
} |
|
|
|
void commandConnectors(VirtualMachineManager vmm) { |
|
Collection<Connector> ccs = vmm.allConnectors(); |
|
if (ccs.isEmpty()) { |
|
MessageOutput.println("Connectors available"); |
|
} |
|
for (Connector cc : ccs) { |
|
String transportName = |
|
cc.transport() == null ? "null" : cc.transport().name(); |
|
MessageOutput.println(); |
|
MessageOutput.println("Connector and Transport name", |
|
new Object [] {cc.name(), transportName}); |
|
MessageOutput.println("Connector description", cc.description()); |
|
|
|
for (Connector.Argument aa : cc.defaultArguments().values()) { |
|
MessageOutput.println(); |
|
|
|
boolean requiredArgument = aa.mustSpecify(); |
|
if (aa.value() == null || aa.value() == "") { |
|
|
|
MessageOutput.println(requiredArgument ? |
|
"Connector required argument nodefault" : |
|
"Connector argument nodefault", aa.name()); |
|
} else { |
|
MessageOutput.println(requiredArgument ? |
|
"Connector required argument default" : |
|
"Connector argument default", |
|
new Object [] {aa.name(), aa.value()}); |
|
} |
|
MessageOutput.println("Connector description", aa.description()); |
|
|
|
} |
|
} |
|
|
|
} |
|
|
|
void commandClasses() { |
|
StringBuffer classList = new StringBuffer(); |
|
for (ReferenceType refType : Env.vm().allClasses()) { |
|
classList.append(refType.name()); |
|
classList.append("\n"); |
|
} |
|
MessageOutput.print("** classes list **", classList.toString()); |
|
} |
|
|
|
void commandClass(StringTokenizer t) { |
|
|
|
if (!t.hasMoreTokens()) { |
|
MessageOutput.println("No class specified."); |
|
return; |
|
} |
|
|
|
String idClass = t.nextToken(); |
|
boolean showAll = false; |
|
|
|
if (t.hasMoreTokens()) { |
|
if (t.nextToken().toLowerCase().equals("all")) { |
|
showAll = true; |
|
} else { |
|
MessageOutput.println("Invalid option on class command"); |
|
return; |
|
} |
|
} |
|
ReferenceType type = Env.getReferenceTypeFromToken(idClass); |
|
if (type == null) { |
|
MessageOutput.println("is not a valid id or class name", idClass); |
|
return; |
|
} |
|
if (type instanceof ClassType) { |
|
ClassType clazz = (ClassType)type; |
|
MessageOutput.println("Class:", clazz.name()); |
|
|
|
ClassType superclass = clazz.superclass(); |
|
while (superclass != null) { |
|
MessageOutput.println("extends:", superclass.name()); |
|
superclass = showAll ? superclass.superclass() : null; |
|
} |
|
|
|
List<InterfaceType> interfaces = |
|
showAll ? clazz.allInterfaces() : clazz.interfaces(); |
|
for (InterfaceType interfaze : interfaces) { |
|
MessageOutput.println("implements:", interfaze.name()); |
|
} |
|
|
|
for (ClassType sub : clazz.subclasses()) { |
|
MessageOutput.println("subclass:", sub.name()); |
|
} |
|
for (ReferenceType nest : clazz.nestedTypes()) { |
|
MessageOutput.println("nested:", nest.name()); |
|
} |
|
} else if (type instanceof InterfaceType) { |
|
InterfaceType interfaze = (InterfaceType)type; |
|
MessageOutput.println("Interface:", interfaze.name()); |
|
for (InterfaceType superinterface : interfaze.superinterfaces()) { |
|
MessageOutput.println("extends:", superinterface.name()); |
|
} |
|
for (InterfaceType sub : interfaze.subinterfaces()) { |
|
MessageOutput.println("subinterface:", sub.name()); |
|
} |
|
for (ClassType implementor : interfaze.implementors()) { |
|
MessageOutput.println("implementor:", implementor.name()); |
|
} |
|
for (ReferenceType nest : interfaze.nestedTypes()) { |
|
MessageOutput.println("nested:", nest.name()); |
|
} |
|
} else { |
|
ArrayType array = (ArrayType)type; |
|
MessageOutput.println("Array:", array.name()); |
|
} |
|
} |
|
|
|
void commandMethods(StringTokenizer t) { |
|
if (!t.hasMoreTokens()) { |
|
MessageOutput.println("No class specified."); |
|
return; |
|
} |
|
|
|
String idClass = t.nextToken(); |
|
ReferenceType cls = Env.getReferenceTypeFromToken(idClass); |
|
if (cls != null) { |
|
StringBuffer methodsList = new StringBuffer(); |
|
for (Method method : cls.allMethods()) { |
|
methodsList.append(method.declaringType().name()); |
|
methodsList.append(" "); |
|
methodsList.append(typedName(method)); |
|
methodsList.append('\n'); |
|
} |
|
MessageOutput.print("** methods list **", methodsList.toString()); |
|
} else { |
|
MessageOutput.println("is not a valid id or class name", idClass); |
|
} |
|
} |
|
|
|
void commandFields(StringTokenizer t) { |
|
if (!t.hasMoreTokens()) { |
|
MessageOutput.println("No class specified."); |
|
return; |
|
} |
|
|
|
String idClass = t.nextToken(); |
|
ReferenceType cls = Env.getReferenceTypeFromToken(idClass); |
|
if (cls != null) { |
|
List<Field> fields = cls.allFields(); |
|
List<Field> visible = cls.visibleFields(); |
|
StringBuffer fieldsList = new StringBuffer(); |
|
for (Field field : fields) { |
|
String s; |
|
if (!visible.contains(field)) { |
|
s = MessageOutput.format("list field typename and name hidden", |
|
new Object [] {field.typeName(), |
|
field.name()}); |
|
} else if (!field.declaringType().equals(cls)) { |
|
s = MessageOutput.format("list field typename and name inherited", |
|
new Object [] {field.typeName(), |
|
field.name(), |
|
field.declaringType().name()}); |
|
} else { |
|
s = MessageOutput.format("list field typename and name", |
|
new Object [] {field.typeName(), |
|
field.name()}); |
|
} |
|
fieldsList.append(s); |
|
} |
|
MessageOutput.print("** fields list **", fieldsList.toString()); |
|
} else { |
|
MessageOutput.println("is not a valid id or class name", idClass); |
|
} |
|
} |
|
|
|
private void printThreadGroup(ThreadGroupReference tg) { |
|
ThreadIterator threadIter = new ThreadIterator(tg); |
|
|
|
MessageOutput.println("Thread Group:", tg.name()); |
|
int maxIdLength = 0; |
|
int maxNameLength = 0; |
|
while (threadIter.hasNext()) { |
|
ThreadReference thr = threadIter.next(); |
|
maxIdLength = Math.max(maxIdLength, |
|
Env.description(thr).length()); |
|
maxNameLength = Math.max(maxNameLength, |
|
thr.name().length()); |
|
} |
|
|
|
threadIter = new ThreadIterator(tg); |
|
while (threadIter.hasNext()) { |
|
ThreadReference thr = threadIter.next(); |
|
if (thr.threadGroup() == null) { |
|
continue; |
|
} |
|
|
|
if (!thr.threadGroup().equals(tg)) { |
|
tg = thr.threadGroup(); |
|
MessageOutput.println("Thread Group:", tg.name()); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
StringBuffer idBuffer = new StringBuffer(Env.description(thr)); |
|
for (int i = idBuffer.length(); i < maxIdLength; i++) { |
|
idBuffer.append(" "); |
|
} |
|
StringBuffer nameBuffer = new StringBuffer(thr.name()); |
|
for (int i = nameBuffer.length(); i < maxNameLength; i++) { |
|
nameBuffer.append(" "); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
String statusFormat; |
|
switch (thr.status()) { |
|
case ThreadReference.THREAD_STATUS_UNKNOWN: |
|
if (thr.isAtBreakpoint()) { |
|
statusFormat = "Thread description name unknownStatus BP"; |
|
} else { |
|
statusFormat = "Thread description name unknownStatus"; |
|
} |
|
break; |
|
case ThreadReference.THREAD_STATUS_ZOMBIE: |
|
if (thr.isAtBreakpoint()) { |
|
statusFormat = "Thread description name zombieStatus BP"; |
|
} else { |
|
statusFormat = "Thread description name zombieStatus"; |
|
} |
|
break; |
|
case ThreadReference.THREAD_STATUS_RUNNING: |
|
if (thr.isAtBreakpoint()) { |
|
statusFormat = "Thread description name runningStatus BP"; |
|
} else { |
|
statusFormat = "Thread description name runningStatus"; |
|
} |
|
break; |
|
case ThreadReference.THREAD_STATUS_SLEEPING: |
|
if (thr.isAtBreakpoint()) { |
|
statusFormat = "Thread description name sleepingStatus BP"; |
|
} else { |
|
statusFormat = "Thread description name sleepingStatus"; |
|
} |
|
break; |
|
case ThreadReference.THREAD_STATUS_MONITOR: |
|
if (thr.isAtBreakpoint()) { |
|
statusFormat = "Thread description name waitingStatus BP"; |
|
} else { |
|
statusFormat = "Thread description name waitingStatus"; |
|
} |
|
break; |
|
case ThreadReference.THREAD_STATUS_WAIT: |
|
if (thr.isAtBreakpoint()) { |
|
statusFormat = "Thread description name condWaitstatus BP"; |
|
} else { |
|
statusFormat = "Thread description name condWaitstatus"; |
|
} |
|
break; |
|
default: |
|
throw new InternalError(MessageOutput.format("Invalid thread status.")); |
|
} |
|
MessageOutput.println(statusFormat, |
|
new Object [] {idBuffer.toString(), |
|
nameBuffer.toString()}); |
|
} |
|
} |
|
|
|
void commandThreads(StringTokenizer t) { |
|
if (!t.hasMoreTokens()) { |
|
printThreadGroup(ThreadInfo.group()); |
|
return; |
|
} |
|
String name = t.nextToken(); |
|
ThreadGroupReference tg = ThreadGroupIterator.find(name); |
|
if (tg == null) { |
|
MessageOutput.println("is not a valid threadgroup name", name); |
|
} else { |
|
printThreadGroup(tg); |
|
} |
|
} |
|
|
|
void commandThreadGroups() { |
|
ThreadGroupIterator it = new ThreadGroupIterator(); |
|
int cnt = 0; |
|
while (it.hasNext()) { |
|
ThreadGroupReference tg = it.nextThreadGroup(); |
|
++cnt; |
|
MessageOutput.println("thread group number description name", |
|
new Object [] { new Integer (cnt), |
|
Env.description(tg), |
|
tg.name()}); |
|
} |
|
} |
|
|
|
void commandThread(StringTokenizer t) { |
|
if (!t.hasMoreTokens()) { |
|
MessageOutput.println("Thread number not specified."); |
|
return; |
|
} |
|
ThreadInfo threadInfo = doGetThread(t.nextToken()); |
|
if (threadInfo != null) { |
|
ThreadInfo.setCurrentThreadInfo(threadInfo); |
|
} |
|
} |
|
|
|
void commandThreadGroup(StringTokenizer t) { |
|
if (!t.hasMoreTokens()) { |
|
MessageOutput.println("Threadgroup name not specified."); |
|
return; |
|
} |
|
String name = t.nextToken(); |
|
ThreadGroupReference tg = ThreadGroupIterator.find(name); |
|
if (tg == null) { |
|
MessageOutput.println("is not a valid threadgroup name", name); |
|
} else { |
|
ThreadInfo.setThreadGroup(tg); |
|
} |
|
} |
|
|
|
void commandRun(StringTokenizer t) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
VMConnection connection = Env.connection(); |
|
if (!connection.isLaunch()) { |
|
if (!t.hasMoreTokens()) { |
|
commandCont(); |
|
} else { |
|
MessageOutput.println("run <args> command is valid only with launched VMs"); |
|
} |
|
return; |
|
} |
|
if (connection.isOpen()) { |
|
MessageOutput.println("VM already running. use cont to continue after events."); |
|
return; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
String args; |
|
if (t.hasMoreTokens()) { |
|
args = t.nextToken(""); |
|
boolean argsSet = connection.setConnectorArg("main", args); |
|
if (!argsSet) { |
|
MessageOutput.println("Unable to set main class and arguments"); |
|
return; |
|
} |
|
} else { |
|
args = connection.connectorArg("main"); |
|
if (args.length() == 0) { |
|
MessageOutput.println("Main class and arguments must be specified"); |
|
return; |
|
} |
|
} |
|
MessageOutput.println("run", args); |
|
|
|
|
|
|
|
*/ |
|
connection.open(); |
|
|
|
} |
|
|
|
void commandLoad(StringTokenizer t) { |
|
MessageOutput.println("The load command is no longer supported."); |
|
} |
|
|
|
private List<ThreadReference> allThreads(ThreadGroupReference group) { |
|
List<ThreadReference> list = new ArrayList<ThreadReference>(); |
|
list.addAll(group.threads()); |
|
for (ThreadGroupReference child : group.threadGroups()) { |
|
list.addAll(allThreads(child)); |
|
} |
|
return list; |
|
} |
|
|
|
void commandSuspend(StringTokenizer t) { |
|
if (!t.hasMoreTokens()) { |
|
Env.vm().suspend(); |
|
MessageOutput.println("All threads suspended."); |
|
} else { |
|
while (t.hasMoreTokens()) { |
|
ThreadInfo threadInfo = doGetThread(t.nextToken()); |
|
if (threadInfo != null) { |
|
threadInfo.getThread().suspend(); |
|
} |
|
} |
|
} |
|
} |
|
|
|
void commandResume(StringTokenizer t) { |
|
if (!t.hasMoreTokens()) { |
|
ThreadInfo.invalidateAll(); |
|
Env.vm().resume(); |
|
MessageOutput.println("All threads resumed."); |
|
} else { |
|
while (t.hasMoreTokens()) { |
|
ThreadInfo threadInfo = doGetThread(t.nextToken()); |
|
if (threadInfo != null) { |
|
threadInfo.invalidate(); |
|
threadInfo.getThread().resume(); |
|
} |
|
} |
|
} |
|
} |
|
|
|
void commandCont() { |
|
if (ThreadInfo.getCurrentThreadInfo() == null) { |
|
MessageOutput.println("Nothing suspended."); |
|
return; |
|
} |
|
ThreadInfo.invalidateAll(); |
|
Env.vm().resume(); |
|
} |
|
|
|
void clearPreviousStep(ThreadReference thread) { |
|
|
|
|
|
|
|
*/ |
|
EventRequestManager mgr = Env.vm().eventRequestManager(); |
|
for (StepRequest request : mgr.stepRequests()) { |
|
if (request.thread().equals(thread)) { |
|
mgr.deleteEventRequest(request); |
|
break; |
|
} |
|
} |
|
} |
|
|
|
|
|
*/ |
|
void commandStep(StringTokenizer t) { |
|
ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo(); |
|
if (threadInfo == null) { |
|
MessageOutput.println("Nothing suspended."); |
|
return; |
|
} |
|
int depth; |
|
if (t.hasMoreTokens() && |
|
t.nextToken().toLowerCase().equals("up")) { |
|
depth = StepRequest.STEP_OUT; |
|
} else { |
|
depth = StepRequest.STEP_INTO; |
|
} |
|
|
|
clearPreviousStep(threadInfo.getThread()); |
|
EventRequestManager reqMgr = Env.vm().eventRequestManager(); |
|
StepRequest request = reqMgr.createStepRequest(threadInfo.getThread(), |
|
StepRequest.STEP_LINE, depth); |
|
if (depth == StepRequest.STEP_INTO) { |
|
Env.addExcludes(request); |
|
} |
|
|
|
request.addCountFilter(1); |
|
request.enable(); |
|
ThreadInfo.invalidateAll(); |
|
Env.vm().resume(); |
|
} |
|
|
|
|
|
|
|
*/ |
|
void commandStepi() { |
|
ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo(); |
|
if (threadInfo == null) { |
|
MessageOutput.println("Nothing suspended."); |
|
return; |
|
} |
|
clearPreviousStep(threadInfo.getThread()); |
|
EventRequestManager reqMgr = Env.vm().eventRequestManager(); |
|
StepRequest request = reqMgr.createStepRequest(threadInfo.getThread(), |
|
StepRequest.STEP_MIN, |
|
StepRequest.STEP_INTO); |
|
Env.addExcludes(request); |
|
|
|
request.addCountFilter(1); |
|
request.enable(); |
|
ThreadInfo.invalidateAll(); |
|
Env.vm().resume(); |
|
} |
|
|
|
void commandNext() { |
|
ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo(); |
|
if (threadInfo == null) { |
|
MessageOutput.println("Nothing suspended."); |
|
return; |
|
} |
|
clearPreviousStep(threadInfo.getThread()); |
|
EventRequestManager reqMgr = Env.vm().eventRequestManager(); |
|
StepRequest request = reqMgr.createStepRequest(threadInfo.getThread(), |
|
StepRequest.STEP_LINE, |
|
StepRequest.STEP_OVER); |
|
Env.addExcludes(request); |
|
|
|
request.addCountFilter(1); |
|
request.enable(); |
|
ThreadInfo.invalidateAll(); |
|
Env.vm().resume(); |
|
} |
|
|
|
void doKill(ThreadReference thread, StringTokenizer t) { |
|
if (!t.hasMoreTokens()) { |
|
MessageOutput.println("No exception object specified."); |
|
return; |
|
} |
|
String expr = t.nextToken(""); |
|
Value val = evaluate(expr); |
|
if ((val != null) && (val instanceof ObjectReference)) { |
|
try { |
|
thread.stop((ObjectReference)val); |
|
MessageOutput.println("killed", thread.toString()); |
|
} catch (InvalidTypeException e) { |
|
MessageOutput.println("Invalid exception object"); |
|
} |
|
} else { |
|
MessageOutput.println("Expression must evaluate to an object"); |
|
} |
|
} |
|
|
|
void doKillThread(final ThreadReference threadToKill, |
|
final StringTokenizer tokenizer) { |
|
new AsyncExecution() { |
|
@Override |
|
void action() { |
|
doKill(threadToKill, tokenizer); |
|
} |
|
}; |
|
} |
|
|
|
void commandKill(StringTokenizer t) { |
|
if (!t.hasMoreTokens()) { |
|
MessageOutput.println("Usage: kill <thread id> <throwable>"); |
|
return; |
|
} |
|
ThreadInfo threadInfo = doGetThread(t.nextToken()); |
|
if (threadInfo != null) { |
|
MessageOutput.println("killing thread:", threadInfo.getThread().name()); |
|
doKillThread(threadInfo.getThread(), t); |
|
return; |
|
} |
|
} |
|
|
|
void listCaughtExceptions() { |
|
boolean noExceptions = true; |
|
|
|
|
|
for (EventRequestSpec spec : Env.specList.eventRequestSpecs()) { |
|
if (spec instanceof ExceptionSpec) { |
|
if (noExceptions) { |
|
noExceptions = false; |
|
MessageOutput.println("Exceptions caught:"); |
|
} |
|
MessageOutput.println("tab", spec.toString()); |
|
} |
|
} |
|
if (noExceptions) { |
|
MessageOutput.println("No exceptions caught."); |
|
} |
|
} |
|
|
|
private EventRequestSpec parseExceptionSpec(StringTokenizer t) { |
|
String notification = t.nextToken(); |
|
boolean notifyCaught = false; |
|
boolean notifyUncaught = false; |
|
EventRequestSpec spec = null; |
|
String classPattern = null; |
|
|
|
if (notification.equals("uncaught")) { |
|
notifyCaught = false; |
|
notifyUncaught = true; |
|
} else if (notification.equals("caught")) { |
|
notifyCaught = true; |
|
notifyUncaught = false; |
|
} else if (notification.equals("all")) { |
|
notifyCaught = true; |
|
notifyUncaught = true; |
|
} else { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
notifyCaught = true; |
|
notifyUncaught = true; |
|
classPattern = notification; |
|
} |
|
if (classPattern == null && t.hasMoreTokens()) { |
|
classPattern = t.nextToken(); |
|
} |
|
if ((classPattern != null) && (notifyCaught || notifyUncaught)) { |
|
try { |
|
spec = Env.specList.createExceptionCatch(classPattern, |
|
notifyCaught, |
|
notifyUncaught); |
|
} catch (ClassNotFoundException exc) { |
|
MessageOutput.println("is not a valid class name", classPattern); |
|
} |
|
} |
|
return spec; |
|
} |
|
|
|
void commandCatchException(StringTokenizer t) { |
|
if (!t.hasMoreTokens()) { |
|
listCaughtExceptions(); |
|
} else { |
|
EventRequestSpec spec = parseExceptionSpec(t); |
|
if (spec != null) { |
|
resolveNow(spec); |
|
} else { |
|
MessageOutput.println("Usage: catch exception"); |
|
} |
|
} |
|
} |
|
|
|
void commandIgnoreException(StringTokenizer t) { |
|
if (!t.hasMoreTokens()) { |
|
listCaughtExceptions(); |
|
} else { |
|
EventRequestSpec spec = parseExceptionSpec(t); |
|
if (Env.specList.delete(spec)) { |
|
MessageOutput.println("Removed:", spec.toString()); |
|
} else { |
|
if (spec != null) { |
|
MessageOutput.println("Not found:", spec.toString()); |
|
} |
|
MessageOutput.println("Usage: ignore exception"); |
|
} |
|
} |
|
} |
|
|
|
void commandUp(StringTokenizer t) { |
|
ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo(); |
|
if (threadInfo == null) { |
|
MessageOutput.println("Current thread not set."); |
|
return; |
|
} |
|
|
|
int nLevels = 1; |
|
if (t.hasMoreTokens()) { |
|
String idToken = t.nextToken(); |
|
int i; |
|
try { |
|
NumberFormat nf = NumberFormat.getNumberInstance(); |
|
nf.setParseIntegerOnly(true); |
|
Number n = nf.parse(idToken); |
|
i = n.intValue(); |
|
} catch (java.text.ParseException jtpe) { |
|
i = 0; |
|
} |
|
if (i <= 0) { |
|
MessageOutput.println("Usage: up [n frames]"); |
|
return; |
|
} |
|
nLevels = i; |
|
} |
|
|
|
try { |
|
threadInfo.up(nLevels); |
|
} catch (IncompatibleThreadStateException e) { |
|
MessageOutput.println("Current thread isnt suspended."); |
|
} catch (ArrayIndexOutOfBoundsException e) { |
|
MessageOutput.println("End of stack."); |
|
} |
|
} |
|
|
|
void commandDown(StringTokenizer t) { |
|
ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo(); |
|
if (threadInfo == null) { |
|
MessageOutput.println("Current thread not set."); |
|
return; |
|
} |
|
|
|
int nLevels = 1; |
|
if (t.hasMoreTokens()) { |
|
String idToken = t.nextToken(); |
|
int i; |
|
try { |
|
NumberFormat nf = NumberFormat.getNumberInstance(); |
|
nf.setParseIntegerOnly(true); |
|
Number n = nf.parse(idToken); |
|
i = n.intValue(); |
|
} catch (java.text.ParseException jtpe) { |
|
i = 0; |
|
} |
|
if (i <= 0) { |
|
MessageOutput.println("Usage: down [n frames]"); |
|
return; |
|
} |
|
nLevels = i; |
|
} |
|
|
|
try { |
|
threadInfo.down(nLevels); |
|
} catch (IncompatibleThreadStateException e) { |
|
MessageOutput.println("Current thread isnt suspended."); |
|
} catch (ArrayIndexOutOfBoundsException e) { |
|
MessageOutput.println("End of stack."); |
|
} |
|
} |
|
|
|
private void dumpStack(ThreadInfo threadInfo, boolean showPC) { |
|
List<StackFrame> stack = null; |
|
try { |
|
stack = threadInfo.getStack(); |
|
} catch (IncompatibleThreadStateException e) { |
|
MessageOutput.println("Current thread isnt suspended."); |
|
return; |
|
} |
|
if (stack == null) { |
|
MessageOutput.println("Thread is not running (no stack)."); |
|
} else { |
|
int nFrames = stack.size(); |
|
for (int i = threadInfo.getCurrentFrameIndex(); i < nFrames; i++) { |
|
StackFrame frame = stack.get(i); |
|
dumpFrame (i, showPC, frame); |
|
} |
|
} |
|
} |
|
|
|
private void dumpFrame (int frameNumber, boolean showPC, StackFrame frame) { |
|
Location loc = frame.location(); |
|
long pc = -1; |
|
if (showPC) { |
|
pc = loc.codeIndex(); |
|
} |
|
Method meth = loc.method(); |
|
|
|
long lineNumber = loc.lineNumber(); |
|
String methodInfo = null; |
|
if (meth.isNative()) { |
|
methodInfo = MessageOutput.format("native method"); |
|
} else if (lineNumber != -1) { |
|
try { |
|
methodInfo = loc.sourceName() + |
|
MessageOutput.format("line number", |
|
new Object [] {new Long(lineNumber)}); |
|
} catch (AbsentInformationException e) { |
|
methodInfo = MessageOutput.format("unknown"); |
|
} |
|
} |
|
if (pc != -1) { |
|
MessageOutput.println("stack frame dump with pc", |
|
new Object [] {new Integer(frameNumber + 1), |
|
meth.declaringType().name(), |
|
meth.name(), |
|
methodInfo, |
|
new Long(pc)}); |
|
} else { |
|
MessageOutput.println("stack frame dump", |
|
new Object [] {new Integer(frameNumber + 1), |
|
meth.declaringType().name(), |
|
meth.name(), |
|
methodInfo}); |
|
} |
|
} |
|
|
|
void commandWhere(StringTokenizer t, boolean showPC) { |
|
if (!t.hasMoreTokens()) { |
|
ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo(); |
|
if (threadInfo == null) { |
|
MessageOutput.println("No thread specified."); |
|
return; |
|
} |
|
dumpStack(threadInfo, showPC); |
|
} else { |
|
String token = t.nextToken(); |
|
if (token.toLowerCase().equals("all")) { |
|
for (ThreadInfo threadInfo : ThreadInfo.threads()) { |
|
MessageOutput.println("Thread:", |
|
threadInfo.getThread().name()); |
|
dumpStack(threadInfo, showPC); |
|
} |
|
} else { |
|
ThreadInfo threadInfo = doGetThread(token); |
|
if (threadInfo != null) { |
|
ThreadInfo.setCurrentThreadInfo(threadInfo); |
|
dumpStack(threadInfo, showPC); |
|
} |
|
} |
|
} |
|
} |
|
|
|
void commandInterrupt(StringTokenizer t) { |
|
if (!t.hasMoreTokens()) { |
|
ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo(); |
|
if (threadInfo == null) { |
|
MessageOutput.println("No thread specified."); |
|
return; |
|
} |
|
threadInfo.getThread().interrupt(); |
|
} else { |
|
ThreadInfo threadInfo = doGetThread(t.nextToken()); |
|
if (threadInfo != null) { |
|
threadInfo.getThread().interrupt(); |
|
} |
|
} |
|
} |
|
|
|
void commandMemory() { |
|
MessageOutput.println("The memory command is no longer supported."); |
|
} |
|
|
|
void commandGC() { |
|
MessageOutput.println("The gc command is no longer necessary."); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
static String locationString(Location loc) { |
|
return MessageOutput.format("locationString", |
|
new Object [] {loc.declaringType().name(), |
|
loc.method().name(), |
|
new Integer (loc.lineNumber()), |
|
new Long (loc.codeIndex())}); |
|
} |
|
|
|
void listBreakpoints() { |
|
boolean noBreakpoints = true; |
|
|
|
|
|
for (EventRequestSpec spec : Env.specList.eventRequestSpecs()) { |
|
if (spec instanceof BreakpointSpec) { |
|
if (noBreakpoints) { |
|
noBreakpoints = false; |
|
MessageOutput.println("Breakpoints set:"); |
|
} |
|
MessageOutput.println("tab", spec.toString()); |
|
} |
|
} |
|
if (noBreakpoints) { |
|
MessageOutput.println("No breakpoints set."); |
|
} |
|
} |
|
|
|
|
|
private void printBreakpointCommandUsage(String atForm, String inForm) { |
|
MessageOutput.println("printbreakpointcommandusage", |
|
new Object [] {atForm, inForm}); |
|
} |
|
|
|
protected BreakpointSpec parseBreakpointSpec(StringTokenizer t, |
|
String atForm, String inForm) { |
|
BreakpointSpec breakpoint = null; |
|
try { |
|
String token = t.nextToken(":( \t\n\r"); |
|
|
|
// We can't use hasMoreTokens here because it will cause any leading |
|
|
|
String rest; |
|
try { |
|
rest = t.nextToken("").trim(); |
|
} catch (NoSuchElementException e) { |
|
rest = null; |
|
} |
|
|
|
if ((rest != null) && rest.startsWith(":")) { |
|
t = new StringTokenizer(rest.substring(1)); |
|
String classId = token; |
|
String lineToken = t.nextToken(); |
|
|
|
NumberFormat nf = NumberFormat.getNumberInstance(); |
|
nf.setParseIntegerOnly(true); |
|
Number n = nf.parse(lineToken); |
|
int lineNumber = n.intValue(); |
|
|
|
if (t.hasMoreTokens()) { |
|
printBreakpointCommandUsage(atForm, inForm); |
|
return null; |
|
} |
|
try { |
|
breakpoint = Env.specList.createBreakpoint(classId, |
|
lineNumber); |
|
} catch (ClassNotFoundException exc) { |
|
MessageOutput.println("is not a valid class name", classId); |
|
} |
|
} else { |
|
|
|
int idot = token.lastIndexOf("."); |
|
if ( (idot <= 0) || |
|
(idot >= token.length() - 1) ) { |
|
printBreakpointCommandUsage(atForm, inForm); |
|
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(")")) { |
|
MessageOutput.println("Invalid method specification:", |
|
methodName + rest); |
|
printBreakpointCommandUsage(atForm, inForm); |
|
return null; |
|
} |
|
|
|
rest = rest.substring(1, rest.length() - 1); |
|
|
|
argumentList = new ArrayList<String>(); |
|
t = new StringTokenizer(rest, ","); |
|
while (t.hasMoreTokens()) { |
|
argumentList.add(t.nextToken()); |
|
} |
|
} |
|
try { |
|
breakpoint = Env.specList.createBreakpoint(classId, |
|
methodName, |
|
argumentList); |
|
} catch (MalformedMemberNameException exc) { |
|
MessageOutput.println("is not a valid method name", methodName); |
|
} catch (ClassNotFoundException exc) { |
|
MessageOutput.println("is not a valid class name", classId); |
|
} |
|
} |
|
} catch (Exception e) { |
|
printBreakpointCommandUsage(atForm, inForm); |
|
return null; |
|
} |
|
return breakpoint; |
|
} |
|
|
|
private void resolveNow(EventRequestSpec spec) { |
|
boolean success = Env.specList.addEagerlyResolve(spec); |
|
if (success && !spec.isResolved()) { |
|
MessageOutput.println("Deferring.", spec.toString()); |
|
} |
|
} |
|
|
|
void commandStop(StringTokenizer t) { |
|
String atIn; |
|
byte suspendPolicy = EventRequest.SUSPEND_ALL; |
|
|
|
if (t.hasMoreTokens()) { |
|
atIn = t.nextToken(); |
|
if (atIn.equals("go") && t.hasMoreTokens()) { |
|
suspendPolicy = EventRequest.SUSPEND_NONE; |
|
atIn = t.nextToken(); |
|
} else if (atIn.equals("thread") && t.hasMoreTokens()) { |
|
suspendPolicy = EventRequest.SUSPEND_EVENT_THREAD; |
|
atIn = t.nextToken(); |
|
} |
|
} else { |
|
listBreakpoints(); |
|
return; |
|
} |
|
|
|
BreakpointSpec spec = parseBreakpointSpec(t, "stop at", "stop in"); |
|
if (spec != null) { |
|
// Enforcement of "at" vs. "in". The distinction is really |
|
// unnecessary and we should consider not checking for this |
|
|
|
if (atIn.equals("at") && spec.isMethodBreakpoint()) { |
|
MessageOutput.println("Use stop at to set a breakpoint at a line number"); |
|
printBreakpointCommandUsage("stop at", "stop in"); |
|
return; |
|
} |
|
spec.suspendPolicy = suspendPolicy; |
|
resolveNow(spec); |
|
} |
|
} |
|
|
|
void commandClear(StringTokenizer t) { |
|
if (!t.hasMoreTokens()) { |
|
listBreakpoints(); |
|
return; |
|
} |
|
|
|
BreakpointSpec spec = parseBreakpointSpec(t, "clear", "clear"); |
|
if (spec != null) { |
|
if (Env.specList.delete(spec)) { |
|
MessageOutput.println("Removed:", spec.toString()); |
|
} else { |
|
MessageOutput.println("Not found:", spec.toString()); |
|
} |
|
} |
|
} |
|
|
|
private List<WatchpointSpec> parseWatchpointSpec(StringTokenizer t) { |
|
List<WatchpointSpec> list = new ArrayList<WatchpointSpec>(); |
|
boolean access = false; |
|
boolean modification = false; |
|
int suspendPolicy = EventRequest.SUSPEND_ALL; |
|
|
|
String fieldName = t.nextToken(); |
|
if (fieldName.equals("go")) { |
|
suspendPolicy = EventRequest.SUSPEND_NONE; |
|
fieldName = t.nextToken(); |
|
} else if (fieldName.equals("thread")) { |
|
suspendPolicy = EventRequest.SUSPEND_EVENT_THREAD; |
|
fieldName = t.nextToken(); |
|
} |
|
if (fieldName.equals("access")) { |
|
access = true; |
|
fieldName = t.nextToken(); |
|
} else if (fieldName.equals("all")) { |
|
access = true; |
|
modification = true; |
|
fieldName = t.nextToken(); |
|
} else { |
|
modification = true; |
|
} |
|
int dot = fieldName.lastIndexOf('.'); |
|
if (dot < 0) { |
|
MessageOutput.println("Class containing field must be specified."); |
|
return list; |
|
} |
|
String className = fieldName.substring(0, dot); |
|
fieldName = fieldName.substring(dot+1); |
|
|
|
try { |
|
WatchpointSpec spec; |
|
if (access) { |
|
spec = Env.specList.createAccessWatchpoint(className, |
|
fieldName); |
|
spec.suspendPolicy = suspendPolicy; |
|
list.add(spec); |
|
} |
|
if (modification) { |
|
spec = Env.specList.createModificationWatchpoint(className, |
|
fieldName); |
|
spec.suspendPolicy = suspendPolicy; |
|
list.add(spec); |
|
} |
|
} catch (MalformedMemberNameException exc) { |
|
MessageOutput.println("is not a valid field name", fieldName); |
|
} catch (ClassNotFoundException exc) { |
|
MessageOutput.println("is not a valid class name", className); |
|
} |
|
return list; |
|
} |
|
|
|
void commandWatch(StringTokenizer t) { |
|
if (!t.hasMoreTokens()) { |
|
MessageOutput.println("Field to watch not specified"); |
|
return; |
|
} |
|
|
|
for (WatchpointSpec spec : parseWatchpointSpec(t)) { |
|
resolveNow(spec); |
|
} |
|
} |
|
|
|
void commandUnwatch(StringTokenizer t) { |
|
if (!t.hasMoreTokens()) { |
|
MessageOutput.println("Field to unwatch not specified"); |
|
return; |
|
} |
|
|
|
for (WatchpointSpec spec : parseWatchpointSpec(t)) { |
|
if (Env.specList.delete(spec)) { |
|
MessageOutput.println("Removed:", spec.toString()); |
|
} else { |
|
MessageOutput.println("Not found:", spec.toString()); |
|
} |
|
} |
|
} |
|
|
|
void turnOnExitTrace(ThreadInfo threadInfo, int suspendPolicy) { |
|
EventRequestManager erm = Env.vm().eventRequestManager(); |
|
MethodExitRequest exit = erm.createMethodExitRequest(); |
|
if (threadInfo != null) { |
|
exit.addThreadFilter(threadInfo.getThread()); |
|
} |
|
Env.addExcludes(exit); |
|
exit.setSuspendPolicy(suspendPolicy); |
|
exit.enable(); |
|
|
|
} |
|
|
|
static String methodTraceCommand = null; |
|
|
|
void commandTrace(StringTokenizer t) { |
|
String modif; |
|
int suspendPolicy = EventRequest.SUSPEND_ALL; |
|
ThreadInfo threadInfo = null; |
|
String goStr = " "; |
|
|
|
|
|
|
|
|
|
*/ |
|
if (t.hasMoreTokens()) { |
|
modif = t.nextToken(); |
|
if (modif.equals("go")) { |
|
suspendPolicy = EventRequest.SUSPEND_NONE; |
|
goStr = " go "; |
|
if (t.hasMoreTokens()) { |
|
modif = t.nextToken(); |
|
} |
|
} else if (modif.equals("thread")) { |
|
|
|
suspendPolicy = EventRequest.SUSPEND_EVENT_THREAD; |
|
if (t.hasMoreTokens()) { |
|
modif = t.nextToken(); |
|
} |
|
} |
|
|
|
if (modif.equals("method")) { |
|
String traceCmd = null; |
|
|
|
if (t.hasMoreTokens()) { |
|
String modif1 = t.nextToken(); |
|
if (modif1.equals("exits") || modif1.equals("exit")) { |
|
if (t.hasMoreTokens()) { |
|
threadInfo = doGetThread(t.nextToken()); |
|
} |
|
if (modif1.equals("exit")) { |
|
StackFrame frame; |
|
try { |
|
frame = ThreadInfo.getCurrentThreadInfo().getCurrentFrame(); |
|
} catch (IncompatibleThreadStateException ee) { |
|
MessageOutput.println("Current thread isnt suspended."); |
|
return; |
|
} |
|
Env.setAtExitMethod(frame.location().method()); |
|
traceCmd = MessageOutput.format("trace" + |
|
goStr + "method exit " + |
|
"in effect for", |
|
Env.atExitMethod().toString()); |
|
} else { |
|
traceCmd = MessageOutput.format("trace" + |
|
goStr + "method exits " + |
|
"in effect"); |
|
} |
|
commandUntrace(new StringTokenizer("methods")); |
|
turnOnExitTrace(threadInfo, suspendPolicy); |
|
methodTraceCommand = traceCmd; |
|
return; |
|
} |
|
} else { |
|
MessageOutput.println("Can only trace"); |
|
return; |
|
} |
|
} |
|
if (modif.equals("methods")) { |
|
|
|
MethodEntryRequest entry; |
|
EventRequestManager erm = Env.vm().eventRequestManager(); |
|
if (t.hasMoreTokens()) { |
|
threadInfo = doGetThread(t.nextToken()); |
|
} |
|
if (threadInfo != null) { |
|
/* |
|
* To keep things simple we want each 'trace' to cancel |
|
* previous traces. However in this case, we don't do that |
|
* to preserve backward compatibility with pre JDK 6.0. |
|
* IE, you can currently do |
|
* trace methods 0x21 |
|
* trace methods 0x22 |
|
* and you will get xxx traced just on those two threads |
|
* But this feature is kind of broken because if you then do |
|
* untrace 0x21 |
|
* it turns off both traces instead of just the one. |
|
* Another bogosity is that if you do |
|
* trace methods |
|
* trace methods |
|
* and you will get two traces. |
|
*/ |
|
|
|
entry = erm.createMethodEntryRequest(); |
|
entry.addThreadFilter(threadInfo.getThread()); |
|
} else { |
|
commandUntrace(new StringTokenizer("methods")); |
|
entry = erm.createMethodEntryRequest(); |
|
} |
|
Env.addExcludes(entry); |
|
entry.setSuspendPolicy(suspendPolicy); |
|
entry.enable(); |
|
turnOnExitTrace(threadInfo, suspendPolicy); |
|
methodTraceCommand = MessageOutput.format("trace" + goStr + |
|
"methods in effect"); |
|
|
|
return; |
|
} |
|
|
|
MessageOutput.println("Can only trace"); |
|
return; |
|
} |
|
|
|
|
|
if (methodTraceCommand != null) { |
|
MessageOutput.printDirectln(methodTraceCommand); |
|
} |
|
|
|
// More trace lines can be added here. |
|
} |
|
|
|
void commandUntrace(StringTokenizer t) { |
|
// untrace |
|
// untrace methods |
|
|
|
String modif = null; |
|
EventRequestManager erm = Env.vm().eventRequestManager(); |
|
if (t.hasMoreTokens()) { |
|
modif = t.nextToken(); |
|
} |
|
if (modif == null || modif.equals("methods")) { |
|
erm.deleteEventRequests(erm.methodEntryRequests()); |
|
erm.deleteEventRequests(erm.methodExitRequests()); |
|
Env.setAtExitMethod(null); |
|
methodTraceCommand = null; |
|
} |
|
} |
|
|
|
void commandList(StringTokenizer t) { |
|
StackFrame frame = null; |
|
ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo(); |
|
if (threadInfo == null) { |
|
MessageOutput.println("No thread specified."); |
|
return; |
|
} |
|
try { |
|
frame = threadInfo.getCurrentFrame(); |
|
} catch (IncompatibleThreadStateException e) { |
|
MessageOutput.println("Current thread isnt suspended."); |
|
return; |
|
} |
|
|
|
if (frame == null) { |
|
MessageOutput.println("No frames on the current call stack"); |
|
return; |
|
} |
|
|
|
Location loc = frame.location(); |
|
if (loc.method().isNative()) { |
|
MessageOutput.println("Current method is native"); |
|
return; |
|
} |
|
|
|
String sourceFileName = null; |
|
try { |
|
sourceFileName = loc.sourceName(); |
|
|
|
ReferenceType refType = loc.declaringType(); |
|
int lineno = loc.lineNumber(); |
|
|
|
if (t.hasMoreTokens()) { |
|
String id = t.nextToken(); |
|
|
|
|
|
try { |
|
NumberFormat nf = NumberFormat.getNumberInstance(); |
|
nf.setParseIntegerOnly(true); |
|
Number n = nf.parse(id); |
|
lineno = n.intValue(); |
|
} catch (java.text.ParseException jtpe) { |
|
|
|
List<Method> meths = refType.methodsByName(id); |
|
if (meths == null || meths.size() == 0) { |
|
MessageOutput.println("is not a valid line number or method name for", |
|
new Object [] {id, refType.name()}); |
|
return; |
|
} else if (meths.size() > 1) { |
|
MessageOutput.println("is an ambiguous method name in", |
|
new Object [] {id, refType.name()}); |
|
return; |
|
} |
|
loc = meths.get(0).location(); |
|
lineno = loc.lineNumber(); |
|
} |
|
} |
|
int startLine = Math.max(lineno - 4, 1); |
|
int endLine = startLine + 9; |
|
if (lineno < 0) { |
|
MessageOutput.println("Line number information not available for"); |
|
} else if (Env.sourceLine(loc, lineno) == null) { |
|
MessageOutput.println("is an invalid line number for", |
|
new Object [] {new Integer (lineno), |
|
refType.name()}); |
|
} else { |
|
for (int i = startLine; i <= endLine; i++) { |
|
String sourceLine = Env.sourceLine(loc, i); |
|
if (sourceLine == null) { |
|
break; |
|
} |
|
if (i == lineno) { |
|
MessageOutput.println("source line number current line and line", |
|
new Object [] {new Integer (i), |
|
sourceLine}); |
|
} else { |
|
MessageOutput.println("source line number and line", |
|
new Object [] {new Integer (i), |
|
sourceLine}); |
|
} |
|
} |
|
} |
|
} catch (AbsentInformationException e) { |
|
MessageOutput.println("No source information available for:", loc.toString()); |
|
} catch(FileNotFoundException exc) { |
|
MessageOutput.println("Source file not found:", sourceFileName); |
|
} catch(IOException exc) { |
|
MessageOutput.println("I/O exception occurred:", exc.toString()); |
|
} |
|
} |
|
|
|
void commandLines(StringTokenizer t) { |
|
if (!t.hasMoreTokens()) { |
|
MessageOutput.println("Specify class and method"); |
|
} else { |
|
String idClass = t.nextToken(); |
|
String idMethod = t.hasMoreTokens() ? t.nextToken() : null; |
|
try { |
|
ReferenceType refType = Env.getReferenceTypeFromToken(idClass); |
|
if (refType != null) { |
|
List<Location> lines = null; |
|
if (idMethod == null) { |
|
lines = refType.allLineLocations(); |
|
} else { |
|
for (Method method : refType.allMethods()) { |
|
if (method.name().equals(idMethod)) { |
|
lines = method.allLineLocations(); |
|
} |
|
} |
|
if (lines == null) { |
|
MessageOutput.println("is not a valid method name", idMethod); |
|
} |
|
} |
|
for (Location line : lines) { |
|
MessageOutput.printDirectln(line.toString()); |
|
} |
|
} else { |
|
MessageOutput.println("is not a valid id or class name", idClass); |
|
} |
|
} catch (AbsentInformationException e) { |
|
MessageOutput.println("Line number information not available for", idClass); |
|
} |
|
} |
|
} |
|
|
|
void commandClasspath(StringTokenizer t) { |
|
if (Env.vm() instanceof PathSearchingVirtualMachine) { |
|
PathSearchingVirtualMachine vm = (PathSearchingVirtualMachine)Env.vm(); |
|
MessageOutput.println("base directory:", vm.baseDirectory()); |
|
MessageOutput.println("classpath:", vm.classPath().toString()); |
|
MessageOutput.println("bootclasspath:", vm.bootClassPath().toString()); |
|
} else { |
|
MessageOutput.println("The VM does not use paths"); |
|
} |
|
} |
|
|
|
|
|
void commandUse(StringTokenizer t) { |
|
if (!t.hasMoreTokens()) { |
|
MessageOutput.printDirectln(Env.getSourcePath()); |
|
} else { |
|
|
|
|
|
|
|
|
|
*/ |
|
Env.setSourcePath(t.nextToken("").trim()); |
|
} |
|
} |
|
|
|
|
|
private void printVar(LocalVariable var, Value value) { |
|
MessageOutput.println("expr is value", |
|
new Object [] {var.name(), |
|
value == null ? "null" : value.toString()}); |
|
} |
|
|
|
|
|
void commandLocals() { |
|
StackFrame frame; |
|
ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo(); |
|
if (threadInfo == null) { |
|
MessageOutput.println("No default thread specified:"); |
|
return; |
|
} |
|
try { |
|
frame = threadInfo.getCurrentFrame(); |
|
if (frame == null) { |
|
throw new AbsentInformationException(); |
|
} |
|
List<LocalVariable> vars = frame.visibleVariables(); |
|
|
|
if (vars.size() == 0) { |
|
MessageOutput.println("No local variables"); |
|
return; |
|
} |
|
Map<LocalVariable, Value> values = frame.getValues(vars); |
|
|
|
MessageOutput.println("Method arguments:"); |
|
for (LocalVariable var : vars) { |
|
if (var.isArgument()) { |
|
Value val = values.get(var); |
|
printVar(var, val); |
|
} |
|
} |
|
MessageOutput.println("Local variables:"); |
|
for (LocalVariable var : vars) { |
|
if (!var.isArgument()) { |
|
Value val = values.get(var); |
|
printVar(var, val); |
|
} |
|
} |
|
} catch (AbsentInformationException aie) { |
|
MessageOutput.println("Local variable information not available."); |
|
} catch (IncompatibleThreadStateException exc) { |
|
MessageOutput.println("Current thread isnt suspended."); |
|
} |
|
} |
|
|
|
private void dump(ObjectReference obj, ReferenceType refType, |
|
ReferenceType refTypeBase) { |
|
for (Field field : refType.fields()) { |
|
StringBuffer o = new StringBuffer(); |
|
o.append(" "); |
|
if (!refType.equals(refTypeBase)) { |
|
o.append(refType.name()); |
|
o.append("."); |
|
} |
|
o.append(field.name()); |
|
o.append(MessageOutput.format("colon space")); |
|
o.append(obj.getValue(field)); |
|
MessageOutput.printDirectln(o.toString()); |
|
} |
|
if (refType instanceof ClassType) { |
|
ClassType sup = ((ClassType)refType).superclass(); |
|
if (sup != null) { |
|
dump(obj, sup, refTypeBase); |
|
} |
|
} else if (refType instanceof InterfaceType) { |
|
for (InterfaceType sup : ((InterfaceType)refType).superinterfaces()) { |
|
dump(obj, sup, refTypeBase); |
|
} |
|
} else { |
|
|
|
if (obj instanceof ArrayReference) { |
|
for (Iterator<Value> it = ((ArrayReference)obj).getValues().iterator(); |
|
it.hasNext(); ) { |
|
MessageOutput.printDirect(it.next().toString()); |
|
if (it.hasNext()) { |
|
MessageOutput.printDirect(", "); |
|
} |
|
} |
|
MessageOutput.println(); |
|
} |
|
} |
|
} |
|
|
|
|
|
*/ |
|
void doPrint(StringTokenizer t, boolean dumpObject) { |
|
if (!t.hasMoreTokens()) { |
|
MessageOutput.println("No objects specified."); |
|
return; |
|
} |
|
|
|
while (t.hasMoreTokens()) { |
|
String expr = t.nextToken(""); |
|
Value val = evaluate(expr); |
|
if (val == null) { |
|
MessageOutput.println("expr is null", expr.toString()); |
|
} else if (dumpObject && (val instanceof ObjectReference) && |
|
!(val instanceof StringReference)) { |
|
ObjectReference obj = (ObjectReference)val; |
|
ReferenceType refType = obj.referenceType(); |
|
MessageOutput.println("expr is value", |
|
new Object [] {expr.toString(), |
|
MessageOutput.format("grouping begin character")}); |
|
dump(obj, refType, refType); |
|
MessageOutput.println("grouping end character"); |
|
} else { |
|
String strVal = getStringValue(); |
|
if (strVal != null) { |
|
MessageOutput.println("expr is value", new Object [] {expr.toString(), |
|
strVal}); |
|
} |
|
} |
|
} |
|
} |
|
|
|
void commandPrint(final StringTokenizer t, final boolean dumpObject) { |
|
new AsyncExecution() { |
|
@Override |
|
void action() { |
|
doPrint(t, dumpObject); |
|
} |
|
}; |
|
} |
|
|
|
void commandSet(final StringTokenizer t) { |
|
String all = t.nextToken(""); |
|
|
|
|
|
|
|
*/ |
|
if (all.indexOf('=') == -1) { |
|
MessageOutput.println("Invalid assignment syntax"); |
|
MessageOutput.printPrompt(); |
|
return; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
commandPrint(new StringTokenizer(all), false); |
|
} |
|
|
|
void doLock(StringTokenizer t) { |
|
if (!t.hasMoreTokens()) { |
|
MessageOutput.println("No object specified."); |
|
return; |
|
} |
|
|
|
String expr = t.nextToken(""); |
|
Value val = evaluate(expr); |
|
|
|
try { |
|
if ((val != null) && (val instanceof ObjectReference)) { |
|
ObjectReference object = (ObjectReference)val; |
|
String strVal = getStringValue(); |
|
if (strVal != null) { |
|
MessageOutput.println("Monitor information for expr", |
|
new Object [] {expr.trim(), |
|
strVal}); |
|
} |
|
ThreadReference owner = object.owningThread(); |
|
if (owner == null) { |
|
MessageOutput.println("Not owned"); |
|
} else { |
|
MessageOutput.println("Owned by:", |
|
new Object [] {owner.name(), |
|
new Integer (object.entryCount())}); |
|
} |
|
List<ThreadReference> waiters = object.waitingThreads(); |
|
if (waiters.size() == 0) { |
|
MessageOutput.println("No waiters"); |
|
} else { |
|
for (ThreadReference waiter : waiters) { |
|
MessageOutput.println("Waiting thread:", waiter.name()); |
|
} |
|
} |
|
} else { |
|
MessageOutput.println("Expression must evaluate to an object"); |
|
} |
|
} catch (IncompatibleThreadStateException e) { |
|
MessageOutput.println("Threads must be suspended"); |
|
} |
|
} |
|
|
|
void commandLock(final StringTokenizer t) { |
|
new AsyncExecution() { |
|
@Override |
|
void action() { |
|
doLock(t); |
|
} |
|
}; |
|
} |
|
|
|
private void printThreadLockInfo(ThreadInfo threadInfo) { |
|
ThreadReference thread = threadInfo.getThread(); |
|
try { |
|
MessageOutput.println("Monitor information for thread", thread.name()); |
|
List<ObjectReference> owned = thread.ownedMonitors(); |
|
if (owned.size() == 0) { |
|
MessageOutput.println("No monitors owned"); |
|
} else { |
|
for (ObjectReference monitor : owned) { |
|
MessageOutput.println("Owned monitor:", monitor.toString()); |
|
} |
|
} |
|
ObjectReference waiting = thread.currentContendedMonitor(); |
|
if (waiting == null) { |
|
MessageOutput.println("Not waiting for a monitor"); |
|
} else { |
|
MessageOutput.println("Waiting for monitor:", waiting.toString()); |
|
} |
|
} catch (IncompatibleThreadStateException e) { |
|
MessageOutput.println("Threads must be suspended"); |
|
} |
|
} |
|
|
|
void commandThreadlocks(final StringTokenizer t) { |
|
if (!t.hasMoreTokens()) { |
|
ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo(); |
|
if (threadInfo == null) { |
|
MessageOutput.println("Current thread not set."); |
|
} else { |
|
printThreadLockInfo(threadInfo); |
|
} |
|
return; |
|
} |
|
String token = t.nextToken(); |
|
if (token.toLowerCase().equals("all")) { |
|
for (ThreadInfo threadInfo : ThreadInfo.threads()) { |
|
printThreadLockInfo(threadInfo); |
|
} |
|
} else { |
|
ThreadInfo threadInfo = doGetThread(token); |
|
if (threadInfo != null) { |
|
ThreadInfo.setCurrentThreadInfo(threadInfo); |
|
printThreadLockInfo(threadInfo); |
|
} |
|
} |
|
} |
|
|
|
void doDisableGC(StringTokenizer t) { |
|
if (!t.hasMoreTokens()) { |
|
MessageOutput.println("No object specified."); |
|
return; |
|
} |
|
|
|
String expr = t.nextToken(""); |
|
Value val = evaluate(expr); |
|
if ((val != null) && (val instanceof ObjectReference)) { |
|
ObjectReference object = (ObjectReference)val; |
|
object.disableCollection(); |
|
String strVal = getStringValue(); |
|
if (strVal != null) { |
|
MessageOutput.println("GC Disabled for", strVal); |
|
} |
|
} else { |
|
MessageOutput.println("Expression must evaluate to an object"); |
|
} |
|
} |
|
|
|
void commandDisableGC(final StringTokenizer t) { |
|
new AsyncExecution() { |
|
@Override |
|
void action() { |
|
doDisableGC(t); |
|
} |
|
}; |
|
} |
|
|
|
void doEnableGC(StringTokenizer t) { |
|
if (!t.hasMoreTokens()) { |
|
MessageOutput.println("No object specified."); |
|
return; |
|
} |
|
|
|
String expr = t.nextToken(""); |
|
Value val = evaluate(expr); |
|
if ((val != null) && (val instanceof ObjectReference)) { |
|
ObjectReference object = (ObjectReference)val; |
|
object.enableCollection(); |
|
String strVal = getStringValue(); |
|
if (strVal != null) { |
|
MessageOutput.println("GC Enabled for", strVal); |
|
} |
|
} else { |
|
MessageOutput.println("Expression must evaluate to an object"); |
|
} |
|
} |
|
|
|
void commandEnableGC(final StringTokenizer t) { |
|
new AsyncExecution() { |
|
@Override |
|
void action() { |
|
doEnableGC(t); |
|
} |
|
}; |
|
} |
|
|
|
void doSave(StringTokenizer t) { |
|
if (!t.hasMoreTokens()) { |
|
MessageOutput.println("No save index specified."); |
|
return; |
|
} |
|
|
|
String key = t.nextToken(); |
|
|
|
if (!t.hasMoreTokens()) { |
|
MessageOutput.println("No expression specified."); |
|
return; |
|
} |
|
String expr = t.nextToken(""); |
|
Value val = evaluate(expr); |
|
if (val != null) { |
|
Env.setSavedValue(key, val); |
|
String strVal = getStringValue(); |
|
if (strVal != null) { |
|
MessageOutput.println("saved", strVal); |
|
} |
|
} else { |
|
MessageOutput.println("Expression cannot be void"); |
|
} |
|
} |
|
|
|
void commandSave(final StringTokenizer t) { |
|
if (!t.hasMoreTokens()) { |
|
Set<String> keys = Env.getSaveKeys(); |
|
if (keys.isEmpty()) { |
|
MessageOutput.println("No saved values"); |
|
return; |
|
} |
|
for (String key : keys) { |
|
Value value = Env.getSavedValue(key); |
|
if ((value instanceof ObjectReference) && |
|
((ObjectReference)value).isCollected()) { |
|
MessageOutput.println("expr is value <collected>", |
|
new Object [] {key, value.toString()}); |
|
} else { |
|
if (value == null){ |
|
MessageOutput.println("expr is null", key); |
|
} else { |
|
MessageOutput.println("expr is value", |
|
new Object [] {key, value.toString()}); |
|
} |
|
} |
|
} |
|
} else { |
|
new AsyncExecution() { |
|
@Override |
|
void action() { |
|
doSave(t); |
|
} |
|
}; |
|
} |
|
|
|
} |
|
|
|
void commandBytecodes(final StringTokenizer t) { |
|
if (!t.hasMoreTokens()) { |
|
MessageOutput.println("No class specified."); |
|
return; |
|
} |
|
String className = t.nextToken(); |
|
|
|
if (!t.hasMoreTokens()) { |
|
MessageOutput.println("No method specified."); |
|
return; |
|
} |
|
|
|
String methodName = t.nextToken(); |
|
|
|
List<ReferenceType> classes = Env.vm().classesByName(className); |
|
|
|
if (classes.size() == 0) { |
|
if (className.indexOf('.') < 0) { |
|
MessageOutput.println("not found (try the full name)", className); |
|
} else { |
|
MessageOutput.println("not found", className); |
|
} |
|
return; |
|
} |
|
|
|
ReferenceType rt = classes.get(0); |
|
if (!(rt instanceof ClassType)) { |
|
MessageOutput.println("not a class", className); |
|
return; |
|
} |
|
|
|
byte[] bytecodes = null; |
|
for (Method method : rt.methodsByName(methodName)) { |
|
if (!method.isAbstract()) { |
|
bytecodes = method.bytecodes(); |
|
break; |
|
} |
|
} |
|
|
|
StringBuffer line = new StringBuffer(80); |
|
line.append("0000: "); |
|
for (int i = 0; i < bytecodes.length; i++) { |
|
if ((i > 0) && (i % 16 == 0)) { |
|
MessageOutput.printDirectln(line.toString()); |
|
line.setLength(0); |
|
line.append(String.valueOf(i)); |
|
line.append(": "); |
|
int len = line.length(); |
|
for (int j = 0; j < 6 - len; j++) { |
|
line.insert(0, '0'); |
|
} |
|
} |
|
int val = 0xff & bytecodes[i]; |
|
String str = Integer.toHexString(val); |
|
if (str.length() == 1) { |
|
line.append('0'); |
|
} |
|
line.append(str); |
|
line.append(' '); |
|
} |
|
if (line.length() > 6) { |
|
MessageOutput.printDirectln(line.toString()); |
|
} |
|
} |
|
|
|
void commandExclude(StringTokenizer t) { |
|
if (!t.hasMoreTokens()) { |
|
MessageOutput.printDirectln(Env.excludesString()); |
|
} else { |
|
String rest = t.nextToken(""); |
|
if (rest.equals("none")) { |
|
rest = ""; |
|
} |
|
Env.setExcludes(rest); |
|
} |
|
} |
|
|
|
void commandRedefine(StringTokenizer t) { |
|
if (!t.hasMoreTokens()) { |
|
MessageOutput.println("Specify classes to redefine"); |
|
} else { |
|
String className = t.nextToken(); |
|
List<ReferenceType> classes = Env.vm().classesByName(className); |
|
if (classes.size() == 0) { |
|
MessageOutput.println("No class named", className); |
|
return; |
|
} |
|
if (classes.size() > 1) { |
|
MessageOutput.println("More than one class named", className); |
|
return; |
|
} |
|
Env.setSourcePath(Env.getSourcePath()); |
|
ReferenceType refType = classes.get(0); |
|
if (!t.hasMoreTokens()) { |
|
MessageOutput.println("Specify file name for class", className); |
|
return; |
|
} |
|
String fileName = t.nextToken(); |
|
File phyl = new File(fileName); |
|
byte[] bytes = new byte[(int)phyl.length()]; |
|
try { |
|
InputStream in = new FileInputStream(phyl); |
|
in.read(bytes); |
|
in.close(); |
|
} catch (Exception exc) { |
|
MessageOutput.println("Error reading file", |
|
new Object [] {fileName, exc.toString()}); |
|
return; |
|
} |
|
Map<ReferenceType, byte[]> map |
|
= new HashMap<ReferenceType, byte[]>(); |
|
map.put(refType, bytes); |
|
try { |
|
Env.vm().redefineClasses(map); |
|
} catch (Throwable exc) { |
|
MessageOutput.println("Error redefining class to file", |
|
new Object [] {className, |
|
fileName, |
|
exc}); |
|
} |
|
} |
|
} |
|
|
|
void commandPopFrames(StringTokenizer t, boolean reenter) { |
|
ThreadInfo threadInfo; |
|
|
|
if (t.hasMoreTokens()) { |
|
String token = t.nextToken(); |
|
threadInfo = doGetThread(token); |
|
if (threadInfo == null) { |
|
return; |
|
} |
|
} else { |
|
threadInfo = ThreadInfo.getCurrentThreadInfo(); |
|
if (threadInfo == null) { |
|
MessageOutput.println("No thread specified."); |
|
return; |
|
} |
|
} |
|
|
|
try { |
|
StackFrame frame = threadInfo.getCurrentFrame(); |
|
threadInfo.getThread().popFrames(frame); |
|
threadInfo = ThreadInfo.getCurrentThreadInfo(); |
|
ThreadInfo.setCurrentThreadInfo(threadInfo); |
|
if (reenter) { |
|
commandStepi(); |
|
} |
|
} catch (Throwable exc) { |
|
MessageOutput.println("Error popping frame", exc.toString()); |
|
} |
|
} |
|
|
|
void commandExtension(StringTokenizer t) { |
|
if (!t.hasMoreTokens()) { |
|
MessageOutput.println("No class specified."); |
|
return; |
|
} |
|
|
|
String idClass = t.nextToken(); |
|
ReferenceType cls = Env.getReferenceTypeFromToken(idClass); |
|
String extension = null; |
|
if (cls != null) { |
|
try { |
|
extension = cls.sourceDebugExtension(); |
|
MessageOutput.println("sourcedebugextension", extension); |
|
} catch (AbsentInformationException e) { |
|
MessageOutput.println("No sourcedebugextension specified"); |
|
} |
|
} else { |
|
MessageOutput.println("is not a valid id or class name", idClass); |
|
} |
|
} |
|
|
|
void commandVersion(String debuggerName, |
|
VirtualMachineManager vmm) { |
|
MessageOutput.println("minus version", |
|
new Object [] { debuggerName, |
|
new Integer(vmm.majorInterfaceVersion()), |
|
new Integer(vmm.minorInterfaceVersion()), |
|
System.getProperty("java.version")}); |
|
if (Env.connection() != null) { |
|
try { |
|
MessageOutput.printDirectln(Env.vm().description()); |
|
} catch (VMNotConnectedException e) { |
|
MessageOutput.println("No VM connected"); |
|
} |
|
} |
|
} |
|
} |