History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/com/sun/tools/example/debug/tty/Commands.java (1 of 18352 files). Show all

Unified · Split

java/pkg/com/sun/tools/example/debug/tty/Commands.java+2098−0
@@ -0,0 +1,2098 @@
1+/*
2+ * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package com.sun.tools.example.debug.tty;
27+
28+import com.sun.jdi.*;
29+import com.sun.jdi.connect.Connector;
30+import com.sun.jdi.request.*;
31+import com.sun.tools.example.debug.expr.ExpressionParser;
32+import com.sun.tools.example.debug.expr.ParseException;
33+
34+import java.text.*;
35+import java.util.*;
36+import java.io.*;
37+
38+class Commands {
39+
40+ abstract class AsyncExecution {
41+ abstract void action();
42+
43+ AsyncExecution() {
44+ execute();
45+ }
46+
47+ void execute() {
48+ /*
49+ * Save current thread and stack frame. (BugId 4296031)
50+ */
51+ final ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo();
52+ final int stackFrame = threadInfo == null? 0 : threadInfo.getCurrentFrameIndex();
53+ Thread thread = new Thread("asynchronous jdb command") {
54+ @Override
55+ public void run() {
56+ try {
57+ action();
58+ } catch (UnsupportedOperationException uoe) {
59+ //(BugId 4453329)
60+ MessageOutput.println("Operation is not supported on the target VM");
61+ } catch (Exception e) {
62+ MessageOutput.println("Internal exception during operation:",
63+ e.getMessage());
64+ } finally {
65+ /*
66+ * This was an asynchronous command. Events may have been
67+ * processed while it was running. Restore the thread and
68+ * stack frame the user was looking at. (BugId 4296031)
69+ */
70+ if (threadInfo != null) {
71+ ThreadInfo.setCurrentThreadInfo(threadInfo);
72+ try {
73+ threadInfo.setCurrentFrameIndex(stackFrame);
74+ } catch (IncompatibleThreadStateException e) {
75+ MessageOutput.println("Current thread isnt suspended.");
76+ } catch (ArrayIndexOutOfBoundsException e) {
77+ MessageOutput.println("Requested stack frame is no longer active:",
78+ new Object []{new Integer(stackFrame)});
79+ }
80+ }
81+ MessageOutput.printPrompt();
82+ }
83+ }
84+ };
85+ thread.start();
86+ }
87+ }
88+
89+ Commands() {
90+ }
91+
92+ private Value evaluate(String expr) {
93+ Value result = null;
94+ ExpressionParser.GetFrame frameGetter = null;
95+ try {
96+ final ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo();
97+ if ((threadInfo != null) && (threadInfo.getCurrentFrame() != null)) {
98+ frameGetter = new ExpressionParser.GetFrame() {
99+ @Override
100+ public StackFrame get() throws IncompatibleThreadStateException {
101+ return threadInfo.getCurrentFrame();
102+ }
103+ };
104+ }
105+ result = ExpressionParser.evaluate(expr, Env.vm(), frameGetter);
106+ } catch (InvocationException ie) {
107+ MessageOutput.println("Exception in expression:",
108+ ie.exception().referenceType().name());
109+ } catch (Exception ex) {
110+ String exMessage = ex.getMessage();
111+ if (exMessage == null) {
112+ MessageOutput.printException(exMessage, ex);
113+ } else {
114+ String s;
115+ try {
116+ s = MessageOutput.format(exMessage);
117+ } catch (MissingResourceException mex) {
118+ s = ex.toString();
119+ }
120+ MessageOutput.printDirectln(s);// Special case: use printDirectln()
121+ }
122+ }
123+ return result;
124+ }
125+
126+ private String getStringValue() {
127+ Value val = null;
128+ String valStr = null;
129+ try {
130+ val = ExpressionParser.getMassagedValue();
131+ valStr = val.toString();
132+ } catch (ParseException e) {
133+ String msg = e.getMessage();
134+ if (msg == null) {
135+ MessageOutput.printException(msg, e);
136+ } else {
137+ String s;
138+ try {
139+ s = MessageOutput.format(msg);
140+ } catch (MissingResourceException mex) {
141+ s = e.toString();
142+ }
143+ MessageOutput.printDirectln(s);
144+ }
145+ }
146+ return valStr;
147+ }
148+
149+ private ThreadInfo doGetThread(String idToken) {
150+ ThreadInfo threadInfo = ThreadInfo.getThreadInfo(idToken);
151+ if (threadInfo == null) {
152+ MessageOutput.println("is not a valid thread id", idToken);
153+ }
154+ return threadInfo;
155+ }
156+
157+ String typedName(Method method) {
158+ StringBuffer buf = new StringBuffer();
159+ buf.append(method.name());
160+ buf.append("(");
161+
162+ List<String> args = method.argumentTypeNames();
163+ int lastParam = args.size() - 1;
164+ // output param types except for the last
165+ for (int ii = 0; ii < lastParam; ii++) {
166+ buf.append(args.get(ii));
167+ buf.append(", ");
168+ }
169+ if (lastParam >= 0) {
170+ // output the last param
171+ String lastStr = args.get(lastParam);
172+ if (method.isVarArgs()) {
173+ // lastParam is an array. Replace the [] with ...
174+ buf.append(lastStr.substring(0, lastStr.length() - 2));
175+ buf.append("...");
176+ } else {
177+ buf.append(lastStr);
178+ }
179+ }
180+ buf.append(")");
181+ return buf.toString();
182+ }
183+
184+ void commandConnectors(VirtualMachineManager vmm) {
185+ Collection<Connector> ccs = vmm.allConnectors();
186+ if (ccs.isEmpty()) {
187+ MessageOutput.println("Connectors available");
188+ }
189+ for (Connector cc : ccs) {
190+ String transportName =
191+ cc.transport() == null ? "null" : cc.transport().name();
192+ MessageOutput.println();
193+ MessageOutput.println("Connector and Transport name",
194+ new Object [] {cc.name(), transportName});
195+ MessageOutput.println("Connector description", cc.description());
196+
197+ for (Connector.Argument aa : cc.defaultArguments().values()) {
198+ MessageOutput.println();
199+
200+ boolean requiredArgument = aa.mustSpecify();
201+ if (aa.value() == null || aa.value() == "") {
202+ //no current value and no default.
203+ MessageOutput.println(requiredArgument ?
204+ "Connector required argument nodefault" :
205+ "Connector argument nodefault", aa.name());
206+ } else {
207+ MessageOutput.println(requiredArgument ?
208+ "Connector required argument default" :
209+ "Connector argument default",
210+ new Object [] {aa.name(), aa.value()});
211+ }
212+ MessageOutput.println("Connector description", aa.description());
213+
214+ }
215+ }
216+
217+ }
218+
219+ void commandClasses() {
220+ StringBuffer classList = new StringBuffer();
221+ for (ReferenceType refType : Env.vm().allClasses()) {
222+ classList.append(refType.name());
223+ classList.append("\n");
224+ }
225+ MessageOutput.print("** classes list **", classList.toString());
226+ }
227+
228+ void commandClass(StringTokenizer t) {
229+
230+ if (!t.hasMoreTokens()) {
231+ MessageOutput.println("No class specified.");
232+ return;
233+ }
234+
235+ String idClass = t.nextToken();
236+ boolean showAll = false;
237+
238+ if (t.hasMoreTokens()) {
239+ if (t.nextToken().toLowerCase().equals("all")) {
240+ showAll = true;
241+ } else {
242+ MessageOutput.println("Invalid option on class command");
243+ return;
244+ }
245+ }
246+ ReferenceType type = Env.getReferenceTypeFromToken(idClass);
247+ if (type == null) {
248+ MessageOutput.println("is not a valid id or class name", idClass);
249+ return;
250+ }
251+ if (type instanceof ClassType) {
252+ ClassType clazz = (ClassType)type;
253+ MessageOutput.println("Class:", clazz.name());
254+
255+ ClassType superclass = clazz.superclass();
256+ while (superclass != null) {
257+ MessageOutput.println("extends:", superclass.name());
258+ superclass = showAll ? superclass.superclass() : null;
259+ }
260+
261+ List<InterfaceType> interfaces =
262+ showAll ? clazz.allInterfaces() : clazz.interfaces();
263+ for (InterfaceType interfaze : interfaces) {
264+ MessageOutput.println("implements:", interfaze.name());
265+ }
266+
267+ for (ClassType sub : clazz.subclasses()) {
268+ MessageOutput.println("subclass:", sub.name());
269+ }
270+ for (ReferenceType nest : clazz.nestedTypes()) {
271+ MessageOutput.println("nested:", nest.name());
272+ }
273+ } else if (type instanceof InterfaceType) {
274+ InterfaceType interfaze = (InterfaceType)type;
275+ MessageOutput.println("Interface:", interfaze.name());
276+ for (InterfaceType superinterface : interfaze.superinterfaces()) {
277+ MessageOutput.println("extends:", superinterface.name());
278+ }
279+ for (InterfaceType sub : interfaze.subinterfaces()) {
280+ MessageOutput.println("subinterface:", sub.name());
281+ }
282+ for (ClassType implementor : interfaze.implementors()) {
283+ MessageOutput.println("implementor:", implementor.name());
284+ }
285+ for (ReferenceType nest : interfaze.nestedTypes()) {
286+ MessageOutput.println("nested:", nest.name());
287+ }
288+ } else { // array type
289+ ArrayType array = (ArrayType)type;
290+ MessageOutput.println("Array:", array.name());
291+ }
292+ }
293+
294+ void commandMethods(StringTokenizer t) {
295+ if (!t.hasMoreTokens()) {
296+ MessageOutput.println("No class specified.");
297+ return;
298+ }
299+
300+ String idClass = t.nextToken();
301+ ReferenceType cls = Env.getReferenceTypeFromToken(idClass);
302+ if (cls != null) {
303+ StringBuffer methodsList = new StringBuffer();
304+ for (Method method : cls.allMethods()) {
305+ methodsList.append(method.declaringType().name());
306+ methodsList.append(" ");
307+ methodsList.append(typedName(method));
308+ methodsList.append('\n');
309+ }
310+ MessageOutput.print("** methods list **", methodsList.toString());
311+ } else {
312+ MessageOutput.println("is not a valid id or class name", idClass);
313+ }
314+ }
315+
316+ void commandFields(StringTokenizer t) {
317+ if (!t.hasMoreTokens()) {
318+ MessageOutput.println("No class specified.");
319+ return;
320+ }
321+
322+ String idClass = t.nextToken();
323+ ReferenceType cls = Env.getReferenceTypeFromToken(idClass);
324+ if (cls != null) {
325+ List<Field> fields = cls.allFields();
326+ List<Field> visible = cls.visibleFields();
327+ StringBuffer fieldsList = new StringBuffer();
328+ for (Field field : fields) {
329+ String s;
330+ if (!visible.contains(field)) {
331+ s = MessageOutput.format("list field typename and name hidden",
332+ new Object [] {field.typeName(),
333+ field.name()});
334+ } else if (!field.declaringType().equals(cls)) {
335+ s = MessageOutput.format("list field typename and name inherited",
336+ new Object [] {field.typeName(),
337+ field.name(),
338+ field.declaringType().name()});
339+ } else {
340+ s = MessageOutput.format("list field typename and name",
341+ new Object [] {field.typeName(),
342+ field.name()});
343+ }
344+ fieldsList.append(s);
345+ }
346+ MessageOutput.print("** fields list **", fieldsList.toString());
347+ } else {
348+ MessageOutput.println("is not a valid id or class name", idClass);
349+ }
350+ }
351+
352+ private void printThreadGroup(ThreadGroupReference tg) {
353+ ThreadIterator threadIter = new ThreadIterator(tg);
354+
355+ MessageOutput.println("Thread Group:", tg.name());
356+ int maxIdLength = 0;
357+ int maxNameLength = 0;
358+ while (threadIter.hasNext()) {
359+ ThreadReference thr = threadIter.next();
360+ maxIdLength = Math.max(maxIdLength,
361+ Env.description(thr).length());
362+ maxNameLength = Math.max(maxNameLength,
363+ thr.name().length());
364+ }
365+
366+ threadIter = new ThreadIterator(tg);
367+ while (threadIter.hasNext()) {
368+ ThreadReference thr = threadIter.next();
369+ if (thr.threadGroup() == null) {
370+ continue;
371+ }
372+ // Note any thread group changes
373+ if (!thr.threadGroup().equals(tg)) {
374+ tg = thr.threadGroup();
375+ MessageOutput.println("Thread Group:", tg.name());
376+ }
377+
378+ /*
379+ * Do a bit of filling with whitespace to get thread ID
380+ * and thread names to line up in the listing, and also
381+ * allow for proper localization. This also works for
382+ * very long thread names, at the possible cost of lines
383+ * being wrapped by the display device.
384+ */
385+ StringBuffer idBuffer = new StringBuffer(Env.description(thr));
386+ for (int i = idBuffer.length(); i < maxIdLength; i++) {
387+ idBuffer.append(" ");
388+ }
389+ StringBuffer nameBuffer = new StringBuffer(thr.name());
390+ for (int i = nameBuffer.length(); i < maxNameLength; i++) {
391+ nameBuffer.append(" ");
392+ }
393+
394+ /*
395+ * Select the output format to use based on thread status
396+ * and breakpoint.
397+ */
398+ String statusFormat;
399+ switch (thr.status()) {
400+ case ThreadReference.THREAD_STATUS_UNKNOWN:
401+ if (thr.isAtBreakpoint()) {
402+ statusFormat = "Thread description name unknownStatus BP";
403+ } else {
404+ statusFormat = "Thread description name unknownStatus";
405+ }
406+ break;
407+ case ThreadReference.THREAD_STATUS_ZOMBIE:
408+ if (thr.isAtBreakpoint()) {
409+ statusFormat = "Thread description name zombieStatus BP";
410+ } else {
411+ statusFormat = "Thread description name zombieStatus";
412+ }
413+ break;
414+ case ThreadReference.THREAD_STATUS_RUNNING:
415+ if (thr.isAtBreakpoint()) {
416+ statusFormat = "Thread description name runningStatus BP";
417+ } else {
418+ statusFormat = "Thread description name runningStatus";
419+ }
420+ break;
421+ case ThreadReference.THREAD_STATUS_SLEEPING:
422+ if (thr.isAtBreakpoint()) {
423+ statusFormat = "Thread description name sleepingStatus BP";
424+ } else {
425+ statusFormat = "Thread description name sleepingStatus";
426+ }
427+ break;
428+ case ThreadReference.THREAD_STATUS_MONITOR:
429+ if (thr.isAtBreakpoint()) {
430+ statusFormat = "Thread description name waitingStatus BP";
431+ } else {
432+ statusFormat = "Thread description name waitingStatus";
433+ }
434+ break;
435+ case ThreadReference.THREAD_STATUS_WAIT:
436+ if (thr.isAtBreakpoint()) {
437+ statusFormat = "Thread description name condWaitstatus BP";
438+ } else {
439+ statusFormat = "Thread description name condWaitstatus";
440+ }
441+ break;
442+ default:
443+ throw new InternalError(MessageOutput.format("Invalid thread status."));
444+ }
445+ MessageOutput.println(statusFormat,
446+ new Object [] {idBuffer.toString(),
447+ nameBuffer.toString()});
448+ }
449+ }
450+
451+ void commandThreads(StringTokenizer t) {
452+ if (!t.hasMoreTokens()) {
453+ printThreadGroup(ThreadInfo.group());
454+ return;
455+ }
456+ String name = t.nextToken();
457+ ThreadGroupReference tg = ThreadGroupIterator.find(name);
458+ if (tg == null) {
459+ MessageOutput.println("is not a valid threadgroup name", name);
460+ } else {
461+ printThreadGroup(tg);
462+ }
463+ }
464+
465+ void commandThreadGroups() {
466+ ThreadGroupIterator it = new ThreadGroupIterator();
467+ int cnt = 0;
468+ while (it.hasNext()) {
469+ ThreadGroupReference tg = it.nextThreadGroup();
470+ ++cnt;
471+ MessageOutput.println("thread group number description name",
472+ new Object [] { new Integer (cnt),
473+ Env.description(tg),
474+ tg.name()});
475+ }
476+ }
477+
478+ void commandThread(StringTokenizer t) {
479+ if (!t.hasMoreTokens()) {
480+ MessageOutput.println("Thread number not specified.");
481+ return;
482+ }
483+ ThreadInfo threadInfo = doGetThread(t.nextToken());
484+ if (threadInfo != null) {
485+ ThreadInfo.setCurrentThreadInfo(threadInfo);
486+ }
487+ }
488+
489+ void commandThreadGroup(StringTokenizer t) {
490+ if (!t.hasMoreTokens()) {
491+ MessageOutput.println("Threadgroup name not specified.");
492+ return;
493+ }
494+ String name = t.nextToken();
495+ ThreadGroupReference tg = ThreadGroupIterator.find(name);
496+ if (tg == null) {
497+ MessageOutput.println("is not a valid threadgroup name", name);
498+ } else {
499+ ThreadInfo.setThreadGroup(tg);
500+ }
501+ }
502+
503+ void commandRun(StringTokenizer t) {
504+ /*
505+ * The 'run' command makes little sense in a
506+ * that doesn't support restarts or multiple VMs. However,
507+ * this is an attempt to emulate the behavior of the old
508+ * JDB as much as possible. For new users and implementations
509+ * it is much more straightforward to launch immedidately
510+ * with the -launch option.
511+ */
512+ VMConnection connection = Env.connection();
513+ if (!connection.isLaunch()) {
514+ if (!t.hasMoreTokens()) {
515+ commandCont();
516+ } else {
517+ MessageOutput.println("run <args> command is valid only with launched VMs");
518+ }
519+ return;
520+ }
521+ if (connection.isOpen()) {
522+ MessageOutput.println("VM already running. use cont to continue after events.");
523+ return;
524+ }
525+
526+ /*
527+ * Set the main class and any arguments. Note that this will work
528+ * only with the standard launcher, "com.sun.jdi.CommandLineLauncher"
529+ */
530+ String args;
531+ if (t.hasMoreTokens()) {
532+ args = t.nextToken("");
533+ boolean argsSet = connection.setConnectorArg("main", args);
534+ if (!argsSet) {
535+ MessageOutput.println("Unable to set main class and arguments");
536+ return;
537+ }
538+ } else {
539+ args = connection.connectorArg("main");
540+ if (args.length() == 0) {
541+ MessageOutput.println("Main class and arguments must be specified");
542+ return;
543+ }
544+ }
545+ MessageOutput.println("run", args);
546+
547+ /*
548+ * Launch the VM.
549+ */
550+ connection.open();
551+
552+ }
553+
554+ void commandLoad(StringTokenizer t) {
555+ MessageOutput.println("The load command is no longer supported.");
556+ }
557+
558+ private List<ThreadReference> allThreads(ThreadGroupReference group) {
559+ List<ThreadReference> list = new ArrayList<ThreadReference>();
560+ list.addAll(group.threads());
561+ for (ThreadGroupReference child : group.threadGroups()) {
562+ list.addAll(allThreads(child));
563+ }
564+ return list;
565+ }
566+
567+ void commandSuspend(StringTokenizer t) {
568+ if (!t.hasMoreTokens()) {
569+ Env.vm().suspend();
570+ MessageOutput.println("All threads suspended.");
571+ } else {
572+ while (t.hasMoreTokens()) {
573+ ThreadInfo threadInfo = doGetThread(t.nextToken());
574+ if (threadInfo != null) {
575+ threadInfo.getThread().suspend();
576+ }
577+ }
578+ }
579+ }
580+
581+ void commandResume(StringTokenizer t) {
582+ if (!t.hasMoreTokens()) {
583+ ThreadInfo.invalidateAll();
584+ Env.vm().resume();
585+ MessageOutput.println("All threads resumed.");
586+ } else {
587+ while (t.hasMoreTokens()) {
588+ ThreadInfo threadInfo = doGetThread(t.nextToken());
589+ if (threadInfo != null) {
590+ threadInfo.invalidate();
591+ threadInfo.getThread().resume();
592+ }
593+ }
594+ }
595+ }
596+
597+ void commandCont() {
598+ if (ThreadInfo.getCurrentThreadInfo() == null) {
599+ MessageOutput.println("Nothing suspended.");
600+ return;
601+ }
602+ ThreadInfo.invalidateAll();
603+ Env.vm().resume();
604+ }
605+
606+ void clearPreviousStep(ThreadReference thread) {
607+ /*
608+ * A previous step may not have completed on this thread;
609+ * if so, it gets removed here.
610+ */
611+ EventRequestManager mgr = Env.vm().eventRequestManager();
612+ for (StepRequest request : mgr.stepRequests()) {
613+ if (request.thread().equals(thread)) {
614+ mgr.deleteEventRequest(request);
615+ break;
616+ }
617+ }
618+ }
619+ /* step
620+ *
621+ */
622+ void commandStep(StringTokenizer t) {
623+ ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo();
624+ if (threadInfo == null) {
625+ MessageOutput.println("Nothing suspended.");
626+ return;
627+ }
628+ int depth;
629+ if (t.hasMoreTokens() &&
630+ t.nextToken().toLowerCase().equals("up")) {
631+ depth = StepRequest.STEP_OUT;
632+ } else {
633+ depth = StepRequest.STEP_INTO;
634+ }
635+
636+ clearPreviousStep(threadInfo.getThread());
637+ EventRequestManager reqMgr = Env.vm().eventRequestManager();
638+ StepRequest request = reqMgr.createStepRequest(threadInfo.getThread(),
639+ StepRequest.STEP_LINE, depth);
640+ if (depth == StepRequest.STEP_INTO) {
641+ Env.addExcludes(request);
642+ }
643+ // We want just the next step event and no others
644+ request.addCountFilter(1);
645+ request.enable();
646+ ThreadInfo.invalidateAll();
647+ Env.vm().resume();
648+ }
649+
650+ /* stepi
651+ * step instruction.
652+ */
653+ void commandStepi() {
654+ ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo();
655+ if (threadInfo == null) {
656+ MessageOutput.println("Nothing suspended.");
657+ return;
658+ }
659+ clearPreviousStep(threadInfo.getThread());
660+ EventRequestManager reqMgr = Env.vm().eventRequestManager();
661+ StepRequest request = reqMgr.createStepRequest(threadInfo.getThread(),
662+ StepRequest.STEP_MIN,
663+ StepRequest.STEP_INTO);
664+ Env.addExcludes(request);
665+ // We want just the next step event and no others
666+ request.addCountFilter(1);
667+ request.enable();
668+ ThreadInfo.invalidateAll();
669+ Env.vm().resume();
670+ }
671+
672+ void commandNext() {
673+ ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo();
674+ if (threadInfo == null) {
675+ MessageOutput.println("Nothing suspended.");
676+ return;
677+ }
678+ clearPreviousStep(threadInfo.getThread());
679+ EventRequestManager reqMgr = Env.vm().eventRequestManager();
680+ StepRequest request = reqMgr.createStepRequest(threadInfo.getThread(),
681+ StepRequest.STEP_LINE,
682+ StepRequest.STEP_OVER);
683+ Env.addExcludes(request);
684+ // We want just the next step event and no others
685+ request.addCountFilter(1);
686+ request.enable();
687+ ThreadInfo.invalidateAll();
688+ Env.vm().resume();
689+ }
690+
691+ void doKill(ThreadReference thread, StringTokenizer t) {
692+ if (!t.hasMoreTokens()) {
693+ MessageOutput.println("No exception object specified.");
694+ return;
695+ }
696+ String expr = t.nextToken("");
697+ Value val = evaluate(expr);
698+ if ((val != null) && (val instanceof ObjectReference)) {
699+ try {
700+ thread.stop((ObjectReference)val);
701+ MessageOutput.println("killed", thread.toString());
702+ } catch (InvalidTypeException e) {
703+ MessageOutput.println("Invalid exception object");
704+ }
705+ } else {
706+ MessageOutput.println("Expression must evaluate to an object");
707+ }
708+ }
709+
710+ void doKillThread(final ThreadReference threadToKill,
711+ final StringTokenizer tokenizer) {
712+ new AsyncExecution() {
713+ @Override
714+ void action() {
715+ doKill(threadToKill, tokenizer);
716+ }
717+ };
718+ }
719+
720+ void commandKill(StringTokenizer t) {
721+ if (!t.hasMoreTokens()) {
722+ MessageOutput.println("Usage: kill <thread id> <throwable>");
723+ return;
724+ }
725+ ThreadInfo threadInfo = doGetThread(t.nextToken());
726+ if (threadInfo != null) {
727+ MessageOutput.println("killing thread:", threadInfo.getThread().name());
728+ doKillThread(threadInfo.getThread(), t);
729+ return;
730+ }
731+ }
732+
733+ void listCaughtExceptions() {
734+ boolean noExceptions = true;
735+
736+ // Print a listing of the catch patterns currently in place
737+ for (EventRequestSpec spec : Env.specList.eventRequestSpecs()) {
738+ if (spec instanceof ExceptionSpec) {
739+ if (noExceptions) {
740+ noExceptions = false;
741+ MessageOutput.println("Exceptions caught:");
742+ }
743+ MessageOutput.println("tab", spec.toString());
744+ }
745+ }
746+ if (noExceptions) {
747+ MessageOutput.println("No exceptions caught.");
748+ }
749+ }
750+
751+ private EventRequestSpec parseExceptionSpec(StringTokenizer t) {
752+ String notification = t.nextToken();
753+ boolean notifyCaught = false;
754+ boolean notifyUncaught = false;
755+ EventRequestSpec spec = null;
756+ String classPattern = null;
757+
758+ if (notification.equals("uncaught")) {
759+ notifyCaught = false;
760+ notifyUncaught = true;
761+ } else if (notification.equals("caught")) {
762+ notifyCaught = true;
763+ notifyUncaught = false;
764+ } else if (notification.equals("all")) {
765+ notifyCaught = true;
766+ notifyUncaught = true;
767+ } else {
768+ /*
769+ * Handle the same as "all" for backward
770+ * compatibility with existing .jdbrc files.
771+ *
772+ * Insert an "all" and take the current token as the
773+ * intended classPattern
774+ *
775+ */
776+ notifyCaught = true;
777+ notifyUncaught = true;
778+ classPattern = notification;
779+ }
780+ if (classPattern == null && t.hasMoreTokens()) {
781+ classPattern = t.nextToken();
782+ }
783+ if ((classPattern != null) && (notifyCaught || notifyUncaught)) {
784+ try {
785+ spec = Env.specList.createExceptionCatch(classPattern,
786+ notifyCaught,
787+ notifyUncaught);
788+ } catch (ClassNotFoundException exc) {
789+ MessageOutput.println("is not a valid class name", classPattern);
790+ }
791+ }
792+ return spec;
793+ }
794+
795+ void commandCatchException(StringTokenizer t) {
796+ if (!t.hasMoreTokens()) {
797+ listCaughtExceptions();
798+ } else {
799+ EventRequestSpec spec = parseExceptionSpec(t);
800+ if (spec != null) {
801+ resolveNow(spec);
802+ } else {
803+ MessageOutput.println("Usage: catch exception");
804+ }
805+ }
806+ }
807+
808+ void commandIgnoreException(StringTokenizer t) {
809+ if (!t.hasMoreTokens()) {
810+ listCaughtExceptions();
811+ } else {
812+ EventRequestSpec spec = parseExceptionSpec(t);
813+ if (Env.specList.delete(spec)) {
814+ MessageOutput.println("Removed:", spec.toString());
815+ } else {
816+ if (spec != null) {
817+ MessageOutput.println("Not found:", spec.toString());
818+ }
819+ MessageOutput.println("Usage: ignore exception");
820+ }
821+ }
822+ }
823+
824+ void commandUp(StringTokenizer t) {
825+ ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo();
826+ if (threadInfo == null) {
827+ MessageOutput.println("Current thread not set.");
828+ return;
829+ }
830+
831+ int nLevels = 1;
832+ if (t.hasMoreTokens()) {
833+ String idToken = t.nextToken();
834+ int i;
835+ try {
836+ NumberFormat nf = NumberFormat.getNumberInstance();
837+ nf.setParseIntegerOnly(true);
838+ Number n = nf.parse(idToken);
839+ i = n.intValue();
840+ } catch (java.text.ParseException jtpe) {
841+ i = 0;
842+ }
843+ if (i <= 0) {
844+ MessageOutput.println("Usage: up [n frames]");
845+ return;
846+ }
847+ nLevels = i;
848+ }
849+
850+ try {
851+ threadInfo.up(nLevels);
852+ } catch (IncompatibleThreadStateException e) {
853+ MessageOutput.println("Current thread isnt suspended.");
854+ } catch (ArrayIndexOutOfBoundsException e) {
855+ MessageOutput.println("End of stack.");
856+ }
857+ }
858+
859+ void commandDown(StringTokenizer t) {
860+ ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo();
861+ if (threadInfo == null) {
862+ MessageOutput.println("Current thread not set.");
863+ return;
864+ }
865+
866+ int nLevels = 1;
867+ if (t.hasMoreTokens()) {
868+ String idToken = t.nextToken();
869+ int i;
870+ try {
871+ NumberFormat nf = NumberFormat.getNumberInstance();
872+ nf.setParseIntegerOnly(true);
873+ Number n = nf.parse(idToken);
874+ i = n.intValue();
875+ } catch (java.text.ParseException jtpe) {
876+ i = 0;
877+ }
878+ if (i <= 0) {
879+ MessageOutput.println("Usage: down [n frames]");
880+ return;
881+ }
882+ nLevels = i;
883+ }
884+
885+ try {
886+ threadInfo.down(nLevels);
887+ } catch (IncompatibleThreadStateException e) {
888+ MessageOutput.println("Current thread isnt suspended.");
889+ } catch (ArrayIndexOutOfBoundsException e) {
890+ MessageOutput.println("End of stack.");
891+ }
892+ }
893+
894+ private void dumpStack(ThreadInfo threadInfo, boolean showPC) {
895+ List<StackFrame> stack = null;
896+ try {
897+ stack = threadInfo.getStack();
898+ } catch (IncompatibleThreadStateException e) {
899+ MessageOutput.println("Current thread isnt suspended.");
900+ return;
901+ }
902+ if (stack == null) {
903+ MessageOutput.println("Thread is not running (no stack).");
904+ } else {
905+ int nFrames = stack.size();
906+ for (int i = threadInfo.getCurrentFrameIndex(); i < nFrames; i++) {
907+ StackFrame frame = stack.get(i);
908+ dumpFrame (i, showPC, frame);
909+ }
910+ }
911+ }
912+
913+ private void dumpFrame (int frameNumber, boolean showPC, StackFrame frame) {
914+ Location loc = frame.location();
915+ long pc = -1;
916+ if (showPC) {
917+ pc = loc.codeIndex();
918+ }
919+ Method meth = loc.method();
920+
921+ long lineNumber = loc.lineNumber();
922+ String methodInfo = null;
923+ if (meth.isNative()) {
924+ methodInfo = MessageOutput.format("native method");
925+ } else if (lineNumber != -1) {
926+ try {
927+ methodInfo = loc.sourceName() +
928+ MessageOutput.format("line number",
929+ new Object [] {new Long(lineNumber)});
930+ } catch (AbsentInformationException e) {
931+ methodInfo = MessageOutput.format("unknown");
932+ }
933+ }
934+ if (pc != -1) {
935+ MessageOutput.println("stack frame dump with pc",
936+ new Object [] {new Integer(frameNumber + 1),
937+ meth.declaringType().name(),
938+ meth.name(),
939+ methodInfo,
940+ new Long(pc)});
941+ } else {
942+ MessageOutput.println("stack frame dump",
943+ new Object [] {new Integer(frameNumber + 1),
944+ meth.declaringType().name(),
945+ meth.name(),
946+ methodInfo});
947+ }
948+ }
949+
950+ void commandWhere(StringTokenizer t, boolean showPC) {
951+ if (!t.hasMoreTokens()) {
952+ ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo();
953+ if (threadInfo == null) {
954+ MessageOutput.println("No thread specified.");
955+ return;
956+ }
957+ dumpStack(threadInfo, showPC);
958+ } else {
959+ String token = t.nextToken();
960+ if (token.toLowerCase().equals("all")) {
961+ for (ThreadInfo threadInfo : ThreadInfo.threads()) {
962+ MessageOutput.println("Thread:",
963+ threadInfo.getThread().name());
964+ dumpStack(threadInfo, showPC);
965+ }
966+ } else {
967+ ThreadInfo threadInfo = doGetThread(token);
968+ if (threadInfo != null) {
969+ ThreadInfo.setCurrentThreadInfo(threadInfo);
970+ dumpStack(threadInfo, showPC);
971+ }
972+ }
973+ }
974+ }
975+
976+ void commandInterrupt(StringTokenizer t) {
977+ if (!t.hasMoreTokens()) {
978+ ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo();
979+ if (threadInfo == null) {
980+ MessageOutput.println("No thread specified.");
981+ return;
982+ }
983+ threadInfo.getThread().interrupt();
984+ } else {
985+ ThreadInfo threadInfo = doGetThread(t.nextToken());
986+ if (threadInfo != null) {
987+ threadInfo.getThread().interrupt();
988+ }
989+ }
990+ }
991+
992+ void commandMemory() {
993+ MessageOutput.println("The memory command is no longer supported.");
994+ }
995+
996+ void commandGC() {
997+ MessageOutput.println("The gc command is no longer necessary.");
998+ }
999+
1000+ /*
1001+ * The next two methods are used by this class and by EventHandler
1002+ * to print consistent locations and error messages.
1003+ */
1004+ static String locationString(Location loc) {
1005+ return MessageOutput.format("locationString",
1006+ new Object [] {loc.declaringType().name(),
1007+ loc.method().name(),
1008+ new Integer (loc.lineNumber()),
1009+ new Long (loc.codeIndex())});
1010+ }
1011+
1012+ void listBreakpoints() {
1013+ boolean noBreakpoints = true;
1014+
1015+ // Print set breakpoints
1016+ for (EventRequestSpec spec : Env.specList.eventRequestSpecs()) {
1017+ if (spec instanceof BreakpointSpec) {
1018+ if (noBreakpoints) {
1019+ noBreakpoints = false;
1020+ MessageOutput.println("Breakpoints set:");
1021+ }
1022+ MessageOutput.println("tab", spec.toString());
1023+ }
1024+ }
1025+ if (noBreakpoints) {
1026+ MessageOutput.println("No breakpoints set.");
1027+ }
1028+ }
1029+
1030+
1031+ private void printBreakpointCommandUsage(String atForm, String inForm) {
1032+ MessageOutput.println("printbreakpointcommandusage",
1033+ new Object [] {atForm, inForm});
1034+ }
1035+
1036+ protected BreakpointSpec parseBreakpointSpec(StringTokenizer t,
1037+ String atForm, String inForm) {
1038+ BreakpointSpec breakpoint = null;
1039+ try {
1040+ String token = t.nextToken(":( \t\n\r");
1041+
1042+ // We can't use hasMoreTokens here because it will cause any leading
1043+ // paren to be lost.
1044+ String rest;
1045+ try {
1046+ rest = t.nextToken("").trim();
1047+ } catch (NoSuchElementException e) {
1048+ rest = null;
1049+ }
1050+
1051+ if ((rest != null) && rest.startsWith(":")) {
1052+ t = new StringTokenizer(rest.substring(1));
1053+ String classId = token;
1054+ String lineToken = t.nextToken();
1055+
1056+ NumberFormat nf = NumberFormat.getNumberInstance();
1057+ nf.setParseIntegerOnly(true);
1058+ Number n = nf.parse(lineToken);
1059+ int lineNumber = n.intValue();
1060+
1061+ if (t.hasMoreTokens()) {
1062+ printBreakpointCommandUsage(atForm, inForm);
1063+ return null;
1064+ }
1065+ try {
1066+ breakpoint = Env.specList.createBreakpoint(classId,
1067+ lineNumber);
1068+ } catch (ClassNotFoundException exc) {
1069+ MessageOutput.println("is not a valid class name", classId);
1070+ }
1071+ } else {
1072+ // Try stripping method from class.method token.
1073+ int idot = token.lastIndexOf(".");
1074+ if ( (idot <= 0) || /* No dot or dot in first char */
1075+ (idot >= token.length() - 1) ) { /* dot in last char */
1076+ printBreakpointCommandUsage(atForm, inForm);
1077+ return null;
1078+ }
1079+ String methodName = token.substring(idot + 1);
1080+ String classId = token.substring(0, idot);
1081+ List<String> argumentList = null;
1082+ if (rest != null) {
1083+ if (!rest.startsWith("(") || !rest.endsWith(")")) {
1084+ MessageOutput.println("Invalid method specification:",
1085+ methodName + rest);
1086+ printBreakpointCommandUsage(atForm, inForm);
1087+ return null;
1088+ }
1089+ // Trim the parens
1090+ rest = rest.substring(1, rest.length() - 1);
1091+
1092+ argumentList = new ArrayList<String>();
1093+ t = new StringTokenizer(rest, ",");
1094+ while (t.hasMoreTokens()) {
1095+ argumentList.add(t.nextToken());
1096+ }
1097+ }
1098+ try {
1099+ breakpoint = Env.specList.createBreakpoint(classId,
1100+ methodName,
1101+ argumentList);
1102+ } catch (MalformedMemberNameException exc) {
1103+ MessageOutput.println("is not a valid method name", methodName);
1104+ } catch (ClassNotFoundException exc) {
1105+ MessageOutput.println("is not a valid class name", classId);
1106+ }
1107+ }
1108+ } catch (Exception e) {
1109+ printBreakpointCommandUsage(atForm, inForm);
1110+ return null;
1111+ }
1112+ return breakpoint;
1113+ }
1114+
1115+ private void resolveNow(EventRequestSpec spec) {
1116+ boolean success = Env.specList.addEagerlyResolve(spec);
1117+ if (success && !spec.isResolved()) {
1118+ MessageOutput.println("Deferring.", spec.toString());
1119+ }
1120+ }
1121+
1122+ void commandStop(StringTokenizer t) {
1123+ String atIn;
1124+ byte suspendPolicy = EventRequest.SUSPEND_ALL;
1125+
1126+ if (t.hasMoreTokens()) {
1127+ atIn = t.nextToken();
1128+ if (atIn.equals("go") && t.hasMoreTokens()) {
1129+ suspendPolicy = EventRequest.SUSPEND_NONE;
1130+ atIn = t.nextToken();
1131+ } else if (atIn.equals("thread") && t.hasMoreTokens()) {
1132+ suspendPolicy = EventRequest.SUSPEND_EVENT_THREAD;
1133+ atIn = t.nextToken();
1134+ }
1135+ } else {
1136+ listBreakpoints();
1137+ return;
1138+ }
1139+
1140+ BreakpointSpec spec = parseBreakpointSpec(t, "stop at", "stop in");
1141+ if (spec != null) {
1142+ // Enforcement of "at" vs. "in". The distinction is really
1143+ // unnecessary and we should consider not checking for this
1144+ // (and making "at" and "in" optional).
1145+ if (atIn.equals("at") && spec.isMethodBreakpoint()) {
1146+ MessageOutput.println("Use stop at to set a breakpoint at a line number");
1147+ printBreakpointCommandUsage("stop at", "stop in");
1148+ return;
1149+ }
1150+ spec.suspendPolicy = suspendPolicy;
1151+ resolveNow(spec);
1152+ }
1153+ }
1154+
1155+ void commandClear(StringTokenizer t) {
1156+ if (!t.hasMoreTokens()) {
1157+ listBreakpoints();
1158+ return;
1159+ }
1160+
1161+ BreakpointSpec spec = parseBreakpointSpec(t, "clear", "clear");
1162+ if (spec != null) {
1163+ if (Env.specList.delete(spec)) {
1164+ MessageOutput.println("Removed:", spec.toString());
1165+ } else {
1166+ MessageOutput.println("Not found:", spec.toString());
1167+ }
1168+ }
1169+ }
1170+
1171+ private List<WatchpointSpec> parseWatchpointSpec(StringTokenizer t) {
1172+ List<WatchpointSpec> list = new ArrayList<WatchpointSpec>();
1173+ boolean access = false;
1174+ boolean modification = false;
1175+ int suspendPolicy = EventRequest.SUSPEND_ALL;
1176+
1177+ String fieldName = t.nextToken();
1178+ if (fieldName.equals("go")) {
1179+ suspendPolicy = EventRequest.SUSPEND_NONE;
1180+ fieldName = t.nextToken();
1181+ } else if (fieldName.equals("thread")) {
1182+ suspendPolicy = EventRequest.SUSPEND_EVENT_THREAD;
1183+ fieldName = t.nextToken();
1184+ }
1185+ if (fieldName.equals("access")) {
1186+ access = true;
1187+ fieldName = t.nextToken();
1188+ } else if (fieldName.equals("all")) {
1189+ access = true;
1190+ modification = true;
1191+ fieldName = t.nextToken();
1192+ } else {
1193+ modification = true;
1194+ }
1195+ int dot = fieldName.lastIndexOf('.');
1196+ if (dot < 0) {
1197+ MessageOutput.println("Class containing field must be specified.");
1198+ return list;
1199+ }
1200+ String className = fieldName.substring(0, dot);
1201+ fieldName = fieldName.substring(dot+1);
1202+
1203+ try {
1204+ WatchpointSpec spec;
1205+ if (access) {
1206+ spec = Env.specList.createAccessWatchpoint(className,
1207+ fieldName);
1208+ spec.suspendPolicy = suspendPolicy;
1209+ list.add(spec);
1210+ }
1211+ if (modification) {
1212+ spec = Env.specList.createModificationWatchpoint(className,
1213+ fieldName);
1214+ spec.suspendPolicy = suspendPolicy;
1215+ list.add(spec);
1216+ }
1217+ } catch (MalformedMemberNameException exc) {
1218+ MessageOutput.println("is not a valid field name", fieldName);
1219+ } catch (ClassNotFoundException exc) {
1220+ MessageOutput.println("is not a valid class name", className);
1221+ }
1222+ return list;
1223+ }
1224+
1225+ void commandWatch(StringTokenizer t) {
1226+ if (!t.hasMoreTokens()) {
1227+ MessageOutput.println("Field to watch not specified");
1228+ return;
1229+ }
1230+
1231+ for (WatchpointSpec spec : parseWatchpointSpec(t)) {
1232+ resolveNow(spec);
1233+ }
1234+ }
1235+
1236+ void commandUnwatch(StringTokenizer t) {
1237+ if (!t.hasMoreTokens()) {
1238+ MessageOutput.println("Field to unwatch not specified");
1239+ return;
1240+ }
1241+
1242+ for (WatchpointSpec spec : parseWatchpointSpec(t)) {
1243+ if (Env.specList.delete(spec)) {
1244+ MessageOutput.println("Removed:", spec.toString());
1245+ } else {
1246+ MessageOutput.println("Not found:", spec.toString());
1247+ }
1248+ }
1249+ }
1250+
1251+ void turnOnExitTrace(ThreadInfo threadInfo, int suspendPolicy) {
1252+ EventRequestManager erm = Env.vm().eventRequestManager();
1253+ MethodExitRequest exit = erm.createMethodExitRequest();
1254+ if (threadInfo != null) {
1255+ exit.addThreadFilter(threadInfo.getThread());
1256+ }
1257+ Env.addExcludes(exit);
1258+ exit.setSuspendPolicy(suspendPolicy);
1259+ exit.enable();
1260+
1261+ }
1262+
1263+ static String methodTraceCommand = null;
1264+
1265+ void commandTrace(StringTokenizer t) {
1266+ String modif;
1267+ int suspendPolicy = EventRequest.SUSPEND_ALL;
1268+ ThreadInfo threadInfo = null;
1269+ String goStr = " ";
1270+
1271+ /*
1272+ * trace [go] methods [thread]
1273+ * trace [go] method exit | exits [thread]
1274+ */
1275+ if (t.hasMoreTokens()) {
1276+ modif = t.nextToken();
1277+ if (modif.equals("go")) {
1278+ suspendPolicy = EventRequest.SUSPEND_NONE;
1279+ goStr = " go ";
1280+ if (t.hasMoreTokens()) {
1281+ modif = t.nextToken();
1282+ }
1283+ } else if (modif.equals("thread")) {
1284+ // this is undocumented as it doesn't work right.
1285+ suspendPolicy = EventRequest.SUSPEND_EVENT_THREAD;
1286+ if (t.hasMoreTokens()) {
1287+ modif = t.nextToken();
1288+ }
1289+ }
1290+
1291+ if (modif.equals("method")) {
1292+ String traceCmd = null;
1293+
1294+ if (t.hasMoreTokens()) {
1295+ String modif1 = t.nextToken();
1296+ if (modif1.equals("exits") || modif1.equals("exit")) {
1297+ if (t.hasMoreTokens()) {
1298+ threadInfo = doGetThread(t.nextToken());
1299+ }
1300+ if (modif1.equals("exit")) {
1301+ StackFrame frame;
1302+ try {
1303+ frame = ThreadInfo.getCurrentThreadInfo().getCurrentFrame();
1304+ } catch (IncompatibleThreadStateException ee) {
1305+ MessageOutput.println("Current thread isnt suspended.");
1306+ return;
1307+ }
1308+ Env.setAtExitMethod(frame.location().method());
1309+ traceCmd = MessageOutput.format("trace" +
1310+ goStr + "method exit " +
1311+ "in effect for",
1312+ Env.atExitMethod().toString());
1313+ } else {
1314+ traceCmd = MessageOutput.format("trace" +
1315+ goStr + "method exits " +
1316+ "in effect");
1317+ }
1318+ commandUntrace(new StringTokenizer("methods"));
1319+ turnOnExitTrace(threadInfo, suspendPolicy);
1320+ methodTraceCommand = traceCmd;
1321+ return;
1322+ }
1323+ } else {
1324+ MessageOutput.println("Can only trace");
1325+ return;
1326+ }
1327+ }
1328+ if (modif.equals("methods")) {
1329+ // Turn on method entry trace
1330+ MethodEntryRequest entry;
1331+ EventRequestManager erm = Env.vm().eventRequestManager();
1332+ if (t.hasMoreTokens()) {
1333+ threadInfo = doGetThread(t.nextToken());
1334+ }
1335+ if (threadInfo != null) {
1336+ /*
1337+ * To keep things simple we want each 'trace' to cancel
1338+ * previous traces. However in this case, we don't do that
1339+ * to preserve backward compatibility with pre JDK 6.0.
1340+ * IE, you can currently do
1341+ * trace methods 0x21
1342+ * trace methods 0x22
1343+ * and you will get xxx traced just on those two threads
1344+ * But this feature is kind of broken because if you then do
1345+ * untrace 0x21
1346+ * it turns off both traces instead of just the one.
1347+ * Another bogosity is that if you do
1348+ * trace methods
1349+ * trace methods
1350+ * and you will get two traces.
1351+ */
1352+
1353+ entry = erm.createMethodEntryRequest();
1354+ entry.addThreadFilter(threadInfo.getThread());
1355+ } else {
1356+ commandUntrace(new StringTokenizer("methods"));
1357+ entry = erm.createMethodEntryRequest();
1358+ }
1359+ Env.addExcludes(entry);
1360+ entry.setSuspendPolicy(suspendPolicy);
1361+ entry.enable();
1362+ turnOnExitTrace(threadInfo, suspendPolicy);
1363+ methodTraceCommand = MessageOutput.format("trace" + goStr +
1364+ "methods in effect");
1365+
1366+ return;
1367+ }
1368+
1369+ MessageOutput.println("Can only trace");
1370+ return;
1371+ }
1372+
1373+ // trace all by itself.
1374+ if (methodTraceCommand != null) {
1375+ MessageOutput.printDirectln(methodTraceCommand);
1376+ }
1377+
1378+ // More trace lines can be added here.
1379+ }
1380+
1381+ void commandUntrace(StringTokenizer t) {
1382+ // untrace
1383+ // untrace methods
1384+
1385+ String modif = null;
1386+ EventRequestManager erm = Env.vm().eventRequestManager();
1387+ if (t.hasMoreTokens()) {
1388+ modif = t.nextToken();
1389+ }
1390+ if (modif == null || modif.equals("methods")) {
1391+ erm.deleteEventRequests(erm.methodEntryRequests());
1392+ erm.deleteEventRequests(erm.methodExitRequests());
1393+ Env.setAtExitMethod(null);
1394+ methodTraceCommand = null;
1395+ }
1396+ }
1397+
1398+ void commandList(StringTokenizer t) {
1399+ StackFrame frame = null;
1400+ ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo();
1401+ if (threadInfo == null) {
1402+ MessageOutput.println("No thread specified.");
1403+ return;
1404+ }
1405+ try {
1406+ frame = threadInfo.getCurrentFrame();
1407+ } catch (IncompatibleThreadStateException e) {
1408+ MessageOutput.println("Current thread isnt suspended.");
1409+ return;
1410+ }
1411+
1412+ if (frame == null) {
1413+ MessageOutput.println("No frames on the current call stack");
1414+ return;
1415+ }
1416+
1417+ Location loc = frame.location();
1418+ if (loc.method().isNative()) {
1419+ MessageOutput.println("Current method is native");
1420+ return;
1421+ }
1422+
1423+ String sourceFileName = null;
1424+ try {
1425+ sourceFileName = loc.sourceName();
1426+
1427+ ReferenceType refType = loc.declaringType();
1428+ int lineno = loc.lineNumber();
1429+
1430+ if (t.hasMoreTokens()) {
1431+ String id = t.nextToken();
1432+
1433+ // See if token is a line number.
1434+ try {
1435+ NumberFormat nf = NumberFormat.getNumberInstance();
1436+ nf.setParseIntegerOnly(true);
1437+ Number n = nf.parse(id);
1438+ lineno = n.intValue();
1439+ } catch (java.text.ParseException jtpe) {
1440+ // It isn't -- see if it's a method name.
1441+ List<Method> meths = refType.methodsByName(id);
1442+ if (meths == null || meths.size() == 0) {
1443+ MessageOutput.println("is not a valid line number or method name for",
1444+ new Object [] {id, refType.name()});
1445+ return;
1446+ } else if (meths.size() > 1) {
1447+ MessageOutput.println("is an ambiguous method name in",
1448+ new Object [] {id, refType.name()});
1449+ return;
1450+ }
1451+ loc = meths.get(0).location();
1452+ lineno = loc.lineNumber();
1453+ }
1454+ }
1455+ int startLine = Math.max(lineno - 4, 1);
1456+ int endLine = startLine + 9;
1457+ if (lineno < 0) {
1458+ MessageOutput.println("Line number information not available for");
1459+ } else if (Env.sourceLine(loc, lineno) == null) {
1460+ MessageOutput.println("is an invalid line number for",
1461+ new Object [] {new Integer (lineno),
1462+ refType.name()});
1463+ } else {
1464+ for (int i = startLine; i <= endLine; i++) {
1465+ String sourceLine = Env.sourceLine(loc, i);
1466+ if (sourceLine == null) {
1467+ break;
1468+ }
1469+ if (i == lineno) {
1470+ MessageOutput.println("source line number current line and line",
1471+ new Object [] {new Integer (i),
1472+ sourceLine});
1473+ } else {
1474+ MessageOutput.println("source line number and line",
1475+ new Object [] {new Integer (i),
1476+ sourceLine});
1477+ }
1478+ }
1479+ }
1480+ } catch (AbsentInformationException e) {
1481+ MessageOutput.println("No source information available for:", loc.toString());
1482+ } catch(FileNotFoundException exc) {
1483+ MessageOutput.println("Source file not found:", sourceFileName);
1484+ } catch(IOException exc) {
1485+ MessageOutput.println("I/O exception occurred:", exc.toString());
1486+ }
1487+ }
1488+
1489+ void commandLines(StringTokenizer t) { // Undocumented command: useful for testing
1490+ if (!t.hasMoreTokens()) {
1491+ MessageOutput.println("Specify class and method");
1492+ } else {
1493+ String idClass = t.nextToken();
1494+ String idMethod = t.hasMoreTokens() ? t.nextToken() : null;
1495+ try {
1496+ ReferenceType refType = Env.getReferenceTypeFromToken(idClass);
1497+ if (refType != null) {
1498+ List<Location> lines = null;
1499+ if (idMethod == null) {
1500+ lines = refType.allLineLocations();
1501+ } else {
1502+ for (Method method : refType.allMethods()) {
1503+ if (method.name().equals(idMethod)) {
1504+ lines = method.allLineLocations();
1505+ }
1506+ }
1507+ if (lines == null) {
1508+ MessageOutput.println("is not a valid method name", idMethod);
1509+ }
1510+ }
1511+ for (Location line : lines) {
1512+ MessageOutput.printDirectln(line.toString());// Special case: use printDirectln()
1513+ }
1514+ } else {
1515+ MessageOutput.println("is not a valid id or class name", idClass);
1516+ }
1517+ } catch (AbsentInformationException e) {
1518+ MessageOutput.println("Line number information not available for", idClass);
1519+ }
1520+ }
1521+ }
1522+
1523+ void commandClasspath(StringTokenizer t) {
1524+ if (Env.vm() instanceof PathSearchingVirtualMachine) {
1525+ PathSearchingVirtualMachine vm = (PathSearchingVirtualMachine)Env.vm();
1526+ MessageOutput.println("base directory:", vm.baseDirectory());
1527+ MessageOutput.println("classpath:", vm.classPath().toString());
1528+ MessageOutput.println("bootclasspath:", vm.bootClassPath().toString());
1529+ } else {
1530+ MessageOutput.println("The VM does not use paths");
1531+ }
1532+ }
1533+
1534+ /* Get or set the source file path list. */
1535+ void commandUse(StringTokenizer t) {
1536+ if (!t.hasMoreTokens()) {
1537+ MessageOutput.printDirectln(Env.getSourcePath());// Special case: use printDirectln()
1538+ } else {
1539+ /*
1540+ * Take the remainder of the command line, minus
1541+ * leading or trailing whitespace. Embedded
1542+ * whitespace is fine.
1543+ */
1544+ Env.setSourcePath(t.nextToken("").trim());
1545+ }
1546+ }
1547+
1548+ /* Print a stack variable */
1549+ private void printVar(LocalVariable var, Value value) {
1550+ MessageOutput.println("expr is value",
1551+ new Object [] {var.name(),
1552+ value == null ? "null" : value.toString()});
1553+ }
1554+
1555+ /* Print all local variables in current stack frame. */
1556+ void commandLocals() {
1557+ StackFrame frame;
1558+ ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo();
1559+ if (threadInfo == null) {
1560+ MessageOutput.println("No default thread specified:");
1561+ return;
1562+ }
1563+ try {
1564+ frame = threadInfo.getCurrentFrame();
1565+ if (frame == null) {
1566+ throw new AbsentInformationException();
1567+ }
1568+ List<LocalVariable> vars = frame.visibleVariables();
1569+
1570+ if (vars.size() == 0) {
1571+ MessageOutput.println("No local variables");
1572+ return;
1573+ }
1574+ Map<LocalVariable, Value> values = frame.getValues(vars);
1575+
1576+ MessageOutput.println("Method arguments:");
1577+ for (LocalVariable var : vars) {
1578+ if (var.isArgument()) {
1579+ Value val = values.get(var);
1580+ printVar(var, val);
1581+ }
1582+ }
1583+ MessageOutput.println("Local variables:");
1584+ for (LocalVariable var : vars) {
1585+ if (!var.isArgument()) {
1586+ Value val = values.get(var);
1587+ printVar(var, val);
1588+ }
1589+ }
1590+ } catch (AbsentInformationException aie) {
1591+ MessageOutput.println("Local variable information not available.");
1592+ } catch (IncompatibleThreadStateException exc) {
1593+ MessageOutput.println("Current thread isnt suspended.");
1594+ }
1595+ }
1596+
1597+ private void dump(ObjectReference obj, ReferenceType refType,
1598+ ReferenceType refTypeBase) {
1599+ for (Field field : refType.fields()) {
1600+ StringBuffer o = new StringBuffer();
1601+ o.append(" ");
1602+ if (!refType.equals(refTypeBase)) {
1603+ o.append(refType.name());
1604+ o.append(".");
1605+ }
1606+ o.append(field.name());
1607+ o.append(MessageOutput.format("colon space"));
1608+ o.append(obj.getValue(field));
1609+ MessageOutput.printDirectln(o.toString()); // Special case: use printDirectln()
1610+ }
1611+ if (refType instanceof ClassType) {
1612+ ClassType sup = ((ClassType)refType).superclass();
1613+ if (sup != null) {
1614+ dump(obj, sup, refTypeBase);
1615+ }
1616+ } else if (refType instanceof InterfaceType) {
1617+ for (InterfaceType sup : ((InterfaceType)refType).superinterfaces()) {
1618+ dump(obj, sup, refTypeBase);
1619+ }
1620+ } else {
1621+ /* else refType is an instanceof ArrayType */
1622+ if (obj instanceof ArrayReference) {
1623+ for (Iterator<Value> it = ((ArrayReference)obj).getValues().iterator();
1624+ it.hasNext(); ) {
1625+ MessageOutput.printDirect(it.next().toString());// Special case: use printDirect()
1626+ if (it.hasNext()) {
1627+ MessageOutput.printDirect(", ");// Special case: use printDirect()
1628+ }
1629+ }
1630+ MessageOutput.println();
1631+ }
1632+ }
1633+ }
1634+
1635+ /* Print a specified reference.
1636+ */
1637+ void doPrint(StringTokenizer t, boolean dumpObject) {
1638+ if (!t.hasMoreTokens()) {
1639+ MessageOutput.println("No objects specified.");
1640+ return;
1641+ }
1642+
1643+ while (t.hasMoreTokens()) {
1644+ String expr = t.nextToken("");
1645+ Value val = evaluate(expr);
1646+ if (val == null) {
1647+ MessageOutput.println("expr is null", expr.toString());
1648+ } else if (dumpObject && (val instanceof ObjectReference) &&
1649+ !(val instanceof StringReference)) {
1650+ ObjectReference obj = (ObjectReference)val;
1651+ ReferenceType refType = obj.referenceType();
1652+ MessageOutput.println("expr is value",
1653+ new Object [] {expr.toString(),
1654+ MessageOutput.format("grouping begin character")});
1655+ dump(obj, refType, refType);
1656+ MessageOutput.println("grouping end character");
1657+ } else {
1658+ String strVal = getStringValue();
1659+ if (strVal != null) {
1660+ MessageOutput.println("expr is value", new Object [] {expr.toString(),
1661+ strVal});
1662+ }
1663+ }
1664+ }
1665+ }
1666+
1667+ void commandPrint(final StringTokenizer t, final boolean dumpObject) {
1668+ new AsyncExecution() {
1669+ @Override
1670+ void action() {
1671+ doPrint(t, dumpObject);
1672+ }
1673+ };
1674+ }
1675+
1676+ void commandSet(final StringTokenizer t) {
1677+ String all = t.nextToken("");
1678+
1679+ /*
1680+ * Bare bones error checking.
1681+ */
1682+ if (all.indexOf('=') == -1) {
1683+ MessageOutput.println("Invalid assignment syntax");
1684+ MessageOutput.printPrompt();
1685+ return;
1686+ }
1687+
1688+ /*
1689+ * The set command is really just syntactic sugar. Pass it on to the
1690+ * print command.
1691+ */
1692+ commandPrint(new StringTokenizer(all), false);
1693+ }
1694+
1695+ void doLock(StringTokenizer t) {
1696+ if (!t.hasMoreTokens()) {
1697+ MessageOutput.println("No object specified.");
1698+ return;
1699+ }
1700+
1701+ String expr = t.nextToken("");
1702+ Value val = evaluate(expr);
1703+
1704+ try {
1705+ if ((val != null) && (val instanceof ObjectReference)) {
1706+ ObjectReference object = (ObjectReference)val;
1707+ String strVal = getStringValue();
1708+ if (strVal != null) {
1709+ MessageOutput.println("Monitor information for expr",
1710+ new Object [] {expr.trim(),
1711+ strVal});
1712+ }
1713+ ThreadReference owner = object.owningThread();
1714+ if (owner == null) {
1715+ MessageOutput.println("Not owned");
1716+ } else {
1717+ MessageOutput.println("Owned by:",
1718+ new Object [] {owner.name(),
1719+ new Integer (object.entryCount())});
1720+ }
1721+ List<ThreadReference> waiters = object.waitingThreads();
1722+ if (waiters.size() == 0) {
1723+ MessageOutput.println("No waiters");
1724+ } else {
1725+ for (ThreadReference waiter : waiters) {
1726+ MessageOutput.println("Waiting thread:", waiter.name());
1727+ }
1728+ }
1729+ } else {
1730+ MessageOutput.println("Expression must evaluate to an object");
1731+ }
1732+ } catch (IncompatibleThreadStateException e) {
1733+ MessageOutput.println("Threads must be suspended");
1734+ }
1735+ }
1736+
1737+ void commandLock(final StringTokenizer t) {
1738+ new AsyncExecution() {
1739+ @Override
1740+ void action() {
1741+ doLock(t);
1742+ }
1743+ };
1744+ }
1745+
1746+ private void printThreadLockInfo(ThreadInfo threadInfo) {
1747+ ThreadReference thread = threadInfo.getThread();
1748+ try {
1749+ MessageOutput.println("Monitor information for thread", thread.name());
1750+ List<ObjectReference> owned = thread.ownedMonitors();
1751+ if (owned.size() == 0) {
1752+ MessageOutput.println("No monitors owned");
1753+ } else {
1754+ for (ObjectReference monitor : owned) {
1755+ MessageOutput.println("Owned monitor:", monitor.toString());
1756+ }
1757+ }
1758+ ObjectReference waiting = thread.currentContendedMonitor();
1759+ if (waiting == null) {
1760+ MessageOutput.println("Not waiting for a monitor");
1761+ } else {
1762+ MessageOutput.println("Waiting for monitor:", waiting.toString());
1763+ }
1764+ } catch (IncompatibleThreadStateException e) {
1765+ MessageOutput.println("Threads must be suspended");
1766+ }
1767+ }
1768+
1769+ void commandThreadlocks(final StringTokenizer t) {
1770+ if (!t.hasMoreTokens()) {
1771+ ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo();
1772+ if (threadInfo == null) {
1773+ MessageOutput.println("Current thread not set.");
1774+ } else {
1775+ printThreadLockInfo(threadInfo);
1776+ }
1777+ return;
1778+ }
1779+ String token = t.nextToken();
1780+ if (token.toLowerCase().equals("all")) {
1781+ for (ThreadInfo threadInfo : ThreadInfo.threads()) {
1782+ printThreadLockInfo(threadInfo);
1783+ }
1784+ } else {
1785+ ThreadInfo threadInfo = doGetThread(token);
1786+ if (threadInfo != null) {
1787+ ThreadInfo.setCurrentThreadInfo(threadInfo);
1788+ printThreadLockInfo(threadInfo);
1789+ }
1790+ }
1791+ }
1792+
1793+ void doDisableGC(StringTokenizer t) {
1794+ if (!t.hasMoreTokens()) {
1795+ MessageOutput.println("No object specified.");
1796+ return;
1797+ }
1798+
1799+ String expr = t.nextToken("");
1800+ Value val = evaluate(expr);
1801+ if ((val != null) && (val instanceof ObjectReference)) {
1802+ ObjectReference object = (ObjectReference)val;
1803+ object.disableCollection();
1804+ String strVal = getStringValue();
1805+ if (strVal != null) {
1806+ MessageOutput.println("GC Disabled for", strVal);
1807+ }
1808+ } else {
1809+ MessageOutput.println("Expression must evaluate to an object");
1810+ }
1811+ }
1812+
1813+ void commandDisableGC(final StringTokenizer t) {
1814+ new AsyncExecution() {
1815+ @Override
1816+ void action() {
1817+ doDisableGC(t);
1818+ }
1819+ };
1820+ }
1821+
1822+ void doEnableGC(StringTokenizer t) {
1823+ if (!t.hasMoreTokens()) {
1824+ MessageOutput.println("No object specified.");
1825+ return;
1826+ }
1827+
1828+ String expr = t.nextToken("");
1829+ Value val = evaluate(expr);
1830+ if ((val != null) && (val instanceof ObjectReference)) {
1831+ ObjectReference object = (ObjectReference)val;
1832+ object.enableCollection();
1833+ String strVal = getStringValue();
1834+ if (strVal != null) {
1835+ MessageOutput.println("GC Enabled for", strVal);
1836+ }
1837+ } else {
1838+ MessageOutput.println("Expression must evaluate to an object");
1839+ }
1840+ }
1841+
1842+ void commandEnableGC(final StringTokenizer t) {
1843+ new AsyncExecution() {
1844+ @Override
1845+ void action() {
1846+ doEnableGC(t);
1847+ }
1848+ };
1849+ }
1850+
1851+ void doSave(StringTokenizer t) {// Undocumented command: useful for testing.
1852+ if (!t.hasMoreTokens()) {
1853+ MessageOutput.println("No save index specified.");
1854+ return;
1855+ }
1856+
1857+ String key = t.nextToken();
1858+
1859+ if (!t.hasMoreTokens()) {
1860+ MessageOutput.println("No expression specified.");
1861+ return;
1862+ }
1863+ String expr = t.nextToken("");
1864+ Value val = evaluate(expr);
1865+ if (val != null) {
1866+ Env.setSavedValue(key, val);
1867+ String strVal = getStringValue();
1868+ if (strVal != null) {
1869+ MessageOutput.println("saved", strVal);
1870+ }
1871+ } else {
1872+ MessageOutput.println("Expression cannot be void");
1873+ }
1874+ }
1875+
1876+ void commandSave(final StringTokenizer t) { // Undocumented command: useful for testing.
1877+ if (!t.hasMoreTokens()) {
1878+ Set<String> keys = Env.getSaveKeys();
1879+ if (keys.isEmpty()) {
1880+ MessageOutput.println("No saved values");
1881+ return;
1882+ }
1883+ for (String key : keys) {
1884+ Value value = Env.getSavedValue(key);
1885+ if ((value instanceof ObjectReference) &&
1886+ ((ObjectReference)value).isCollected()) {
1887+ MessageOutput.println("expr is value <collected>",
1888+ new Object [] {key, value.toString()});
1889+ } else {
1890+ if (value == null){
1891+ MessageOutput.println("expr is null", key);
1892+ } else {
1893+ MessageOutput.println("expr is value",
1894+ new Object [] {key, value.toString()});
1895+ }
1896+ }
1897+ }
1898+ } else {
1899+ new AsyncExecution() {
1900+ @Override
1901+ void action() {
1902+ doSave(t);
1903+ }
1904+ };
1905+ }
1906+
1907+ }
1908+
1909+ void commandBytecodes(final StringTokenizer t) { // Undocumented command: useful for testing.
1910+ if (!t.hasMoreTokens()) {
1911+ MessageOutput.println("No class specified.");
1912+ return;
1913+ }
1914+ String className = t.nextToken();
1915+
1916+ if (!t.hasMoreTokens()) {
1917+ MessageOutput.println("No method specified.");
1918+ return;
1919+ }
1920+ // Overloading is not handled here.
1921+ String methodName = t.nextToken();
1922+
1923+ List<ReferenceType> classes = Env.vm().classesByName(className);
1924+ // TO DO: handle multiple classes found
1925+ if (classes.size() == 0) {
1926+ if (className.indexOf('.') < 0) {
1927+ MessageOutput.println("not found (try the full name)", className);
1928+ } else {
1929+ MessageOutput.println("not found", className);
1930+ }
1931+ return;
1932+ }
1933+
1934+ ReferenceType rt = classes.get(0);
1935+ if (!(rt instanceof ClassType)) {
1936+ MessageOutput.println("not a class", className);
1937+ return;
1938+ }
1939+
1940+ byte[] bytecodes = null;
1941+ for (Method method : rt.methodsByName(methodName)) {
1942+ if (!method.isAbstract()) {
1943+ bytecodes = method.bytecodes();
1944+ break;
1945+ }
1946+ }
1947+
1948+ StringBuffer line = new StringBuffer(80);
1949+ line.append("0000: ");
1950+ for (int i = 0; i < bytecodes.length; i++) {
1951+ if ((i > 0) && (i % 16 == 0)) {
1952+ MessageOutput.printDirectln(line.toString());// Special case: use printDirectln()
1953+ line.setLength(0);
1954+ line.append(String.valueOf(i));
1955+ line.append(": ");
1956+ int len = line.length();
1957+ for (int j = 0; j < 6 - len; j++) {
1958+ line.insert(0, '0');
1959+ }
1960+ }
1961+ int val = 0xff & bytecodes[i];
1962+ String str = Integer.toHexString(val);
1963+ if (str.length() == 1) {
1964+ line.append('0');
1965+ }
1966+ line.append(str);
1967+ line.append(' ');
1968+ }
1969+ if (line.length() > 6) {
1970+ MessageOutput.printDirectln(line.toString());// Special case: use printDirectln()
1971+ }
1972+ }
1973+
1974+ void commandExclude(StringTokenizer t) {
1975+ if (!t.hasMoreTokens()) {
1976+ MessageOutput.printDirectln(Env.excludesString());// Special case: use printDirectln()
1977+ } else {
1978+ String rest = t.nextToken("");
1979+ if (rest.equals("none")) {
1980+ rest = "";
1981+ }
1982+ Env.setExcludes(rest);
1983+ }
1984+ }
1985+
1986+ void commandRedefine(StringTokenizer t) {
1987+ if (!t.hasMoreTokens()) {
1988+ MessageOutput.println("Specify classes to redefine");
1989+ } else {
1990+ String className = t.nextToken();
1991+ List<ReferenceType> classes = Env.vm().classesByName(className);
1992+ if (classes.size() == 0) {
1993+ MessageOutput.println("No class named", className);
1994+ return;
1995+ }
1996+ if (classes.size() > 1) {
1997+ MessageOutput.println("More than one class named", className);
1998+ return;
1999+ }
2000+ Env.setSourcePath(Env.getSourcePath());
2001+ ReferenceType refType = classes.get(0);
2002+ if (!t.hasMoreTokens()) {
2003+ MessageOutput.println("Specify file name for class", className);
2004+ return;
2005+ }
2006+ String fileName = t.nextToken();
2007+ File phyl = new File(fileName);
2008+ byte[] bytes = new byte[(int)phyl.length()];
2009+ try {
2010+ InputStream in = new FileInputStream(phyl);
2011+ in.read(bytes);
2012+ in.close();
2013+ } catch (Exception exc) {
2014+ MessageOutput.println("Error reading file",
2015+ new Object [] {fileName, exc.toString()});
2016+ return;
2017+ }
2018+ Map<ReferenceType, byte[]> map
2019+ = new HashMap<ReferenceType, byte[]>();
2020+ map.put(refType, bytes);
2021+ try {
2022+ Env.vm().redefineClasses(map);
2023+ } catch (Throwable exc) {
2024+ MessageOutput.println("Error redefining class to file",
2025+ new Object [] {className,
2026+ fileName,
2027+ exc});
2028+ }
2029+ }
2030+ }
2031+
2032+ void commandPopFrames(StringTokenizer t, boolean reenter) {
2033+ ThreadInfo threadInfo;
2034+
2035+ if (t.hasMoreTokens()) {
2036+ String token = t.nextToken();
2037+ threadInfo = doGetThread(token);
2038+ if (threadInfo == null) {
2039+ return;
2040+ }
2041+ } else {
2042+ threadInfo = ThreadInfo.getCurrentThreadInfo();
2043+ if (threadInfo == null) {
2044+ MessageOutput.println("No thread specified.");
2045+ return;
2046+ }
2047+ }
2048+
2049+ try {
2050+ StackFrame frame = threadInfo.getCurrentFrame();
2051+ threadInfo.getThread().popFrames(frame);
2052+ threadInfo = ThreadInfo.getCurrentThreadInfo();
2053+ ThreadInfo.setCurrentThreadInfo(threadInfo);
2054+ if (reenter) {
2055+ commandStepi();
2056+ }
2057+ } catch (Throwable exc) {
2058+ MessageOutput.println("Error popping frame", exc.toString());
2059+ }
2060+ }
2061+
2062+ void commandExtension(StringTokenizer t) {
2063+ if (!t.hasMoreTokens()) {
2064+ MessageOutput.println("No class specified.");
2065+ return;
2066+ }
2067+
2068+ String idClass = t.nextToken();
2069+ ReferenceType cls = Env.getReferenceTypeFromToken(idClass);
2070+ String extension = null;
2071+ if (cls != null) {
2072+ try {
2073+ extension = cls.sourceDebugExtension();
2074+ MessageOutput.println("sourcedebugextension", extension);
2075+ } catch (AbsentInformationException e) {
2076+ MessageOutput.println("No sourcedebugextension specified");
2077+ }
2078+ } else {
2079+ MessageOutput.println("is not a valid id or class name", idClass);
2080+ }
2081+ }
2082+
2083+ void commandVersion(String debuggerName,
2084+ VirtualMachineManager vmm) {
2085+ MessageOutput.println("minus version",
2086+ new Object [] { debuggerName,
2087+ new Integer(vmm.majorInterfaceVersion()),
2088+ new Integer(vmm.minorInterfaceVersion()),
2089+ System.getProperty("java.version")});
2090+ if (Env.connection() != null) {
2091+ try {
2092+ MessageOutput.printDirectln(Env.vm().description());// Special case: use printDirectln()
2093+ } catch (VMNotConnectedException e) {
2094+ MessageOutput.println("No VM connected");
2095+ }
2096+ }
2097+ }
2098+}