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/gui/CommandInterpreter.java (1 of 18352 files). Show all

Unified · Split

java/pkg/com/sun/tools/example/debug/gui/CommandInterpreter.java+1459−0
@@ -0,0 +1,1459 @@
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.gui;
27+
28+import java.io.*;
29+import java.util.*;
30+
31+import com.sun.jdi.*;
32+import com.sun.tools.example.debug.bdi.*;
33+
34+public class CommandInterpreter {
35+
36+ boolean echo;
37+
38+ Environment env;
39+
40+ private ContextManager context;
41+ private ExecutionManager runtime;
42+ private ClassManager classManager;
43+ private SourceManager sourceManager;
44+
45+ private OutputSink out; //### Hack! Should be local in each method used.
46+ private String lastCommand = "help";
47+
48+ public CommandInterpreter(Environment env) {
49+ this(env, true);
50+ }
51+
52+ public CommandInterpreter(Environment env, boolean echo) {
53+ this.env = env;
54+ this.echo = echo;
55+ this.runtime = env.getExecutionManager();
56+ this.context = env.getContextManager();
57+ this.classManager = env.getClassManager();
58+ this.sourceManager = env.getSourceManager();
59+ }
60+
61+ private ThreadReference[] threads = null;
62+
63+ /*
64+ * The numbering of threads is relative to the current set of threads,
65+ * and may be affected by the creation and termination of new threads.
66+ * Commands issued using such thread ids will only give reliable behavior
67+ * relative to what was shown earlier in 'list' commands if the VM is interrupted.
68+ * We need a better scheme.
69+ */
70+
71+ private ThreadReference[] threads() throws NoSessionException {
72+ if (threads == null) {
73+ ThreadIterator ti = new ThreadIterator(getDefaultThreadGroup());
74+ List<ThreadReference> tlist = new ArrayList<ThreadReference>();
75+ while (ti.hasNext()) {
76+ tlist.add(ti.nextThread());
77+ }
78+ threads = tlist.toArray(new ThreadReference[tlist.size()]);
79+ }
80+ return threads;
81+ }
82+
83+ private ThreadReference findThread(String idToken) throws NoSessionException {
84+ String id;
85+ ThreadReference thread = null;
86+ if (idToken.startsWith("t@")) {
87+ id = idToken.substring(2);
88+ } else {
89+ id = idToken;
90+ }
91+ try {
92+ ThreadReference[] threads = threads();
93+ long threadID = Long.parseLong(id, 16);
94+ for (ThreadReference thread2 : threads) {
95+ if (thread2.uniqueID() == threadID) {
96+ thread = thread2;
97+ break;
98+ }
99+ }
100+ if (thread == null) {
101+ //env.failure("No thread for id \"" + idToken + "\"");
102+ env.failure("\"" + idToken + "\" is not a valid thread id.");
103+ }
104+ } catch (NumberFormatException e) {
105+ env.error("Thread id \"" + idToken + "\" is ill-formed.");
106+ thread = null;
107+ }
108+ return thread;
109+ }
110+
111+ private ThreadIterator allThreads() throws NoSessionException {
112+ threads = null;
113+ //### Why not use runtime.allThreads().iterator() ?
114+ return new ThreadIterator(runtime.topLevelThreadGroups());
115+ }
116+
117+ private ThreadIterator currentThreadGroupThreads() throws NoSessionException {
118+ threads = null;
119+ return new ThreadIterator(getDefaultThreadGroup());
120+ }
121+
122+ private ThreadGroupIterator allThreadGroups() throws NoSessionException {
123+ threads = null;
124+ return new ThreadGroupIterator(runtime.topLevelThreadGroups());
125+ }
126+
127+ private ThreadGroupReference defaultThreadGroup;
128+
129+ private ThreadGroupReference getDefaultThreadGroup() throws NoSessionException {
130+ if (defaultThreadGroup == null) {
131+ defaultThreadGroup = runtime.systemThreadGroup();
132+ }
133+ return defaultThreadGroup;
134+ }
135+
136+ private void setDefaultThreadGroup(ThreadGroupReference tg) {
137+ defaultThreadGroup = tg;
138+ }
139+
140+ /*
141+ * Command handlers.
142+ */
143+
144+ // Command: classes
145+
146+ private void commandClasses() throws NoSessionException {
147+ OutputSink out = env.getOutputSink();
148+ //out.println("** classes list **");
149+ for (ReferenceType refType : runtime.allClasses()) {
150+ out.println(refType.name());
151+ }
152+ out.show();
153+ }
154+
155+
156+ // Command: methods
157+
158+ private void commandMethods(StringTokenizer t) throws NoSessionException {
159+ if (!t.hasMoreTokens()) {
160+ env.error("No class specified.");
161+ return;
162+ }
163+ String idClass = t.nextToken();
164+ ReferenceType cls = findClass(idClass);
165+ if (cls != null) {
166+ List<Method> methods = cls.allMethods();
167+ OutputSink out = env.getOutputSink();
168+ for (int i = 0; i < methods.size(); i++) {
169+ Method method = methods.get(i);
170+ out.print(method.declaringType().name() + " " +
171+ method.name() + "(");
172+ Iterator<String> it = method.argumentTypeNames().iterator();
173+ if (it.hasNext()) {
174+ while (true) {
175+ out.print(it.next());
176+ if (!it.hasNext()) {
177+ break;
178+ }
179+ out.print(", ");
180+ }
181+ }
182+ out.println(")");
183+ }
184+ out.show();
185+ } else {
186+ //### Should validate class name syntax.
187+ env.failure("\"" + idClass + "\" is not a valid id or class name.");
188+ }
189+ }
190+
191+ private ReferenceType findClass(String pattern) throws NoSessionException {
192+ List<ReferenceType> results = runtime.findClassesMatchingPattern(pattern);
193+ if (results.size() > 0) {
194+ //### Should handle multiple results sensibly.
195+ return results.get(0);
196+ }
197+ return null;
198+ }
199+
200+ // Command: threads
201+
202+ private void commandThreads(StringTokenizer t) throws NoSessionException {
203+ if (!t.hasMoreTokens()) {
204+ OutputSink out = env.getOutputSink();
205+ printThreadGroup(out, getDefaultThreadGroup(), 0);
206+ out.show();
207+ return;
208+ }
209+ String name = t.nextToken();
210+ ThreadGroupReference tg = findThreadGroup(name);
211+ if (tg == null) {
212+ env.failure(name + " is not a valid threadgroup name.");
213+ } else {
214+ OutputSink out = env.getOutputSink();
215+ printThreadGroup(out, tg, 0);
216+ out.show();
217+ }
218+ }
219+
220+ private ThreadGroupReference findThreadGroup(String name) throws NoSessionException {
221+ //### Issue: Uniqueness of thread group names is not enforced.
222+ ThreadGroupIterator tgi = allThreadGroups();
223+ while (tgi.hasNext()) {
224+ ThreadGroupReference tg = tgi.nextThreadGroup();
225+ if (tg.name().equals(name)) {
226+ return tg;
227+ }
228+ }
229+ return null;
230+ }
231+
232+ private int printThreadGroup(OutputSink out, ThreadGroupReference tg, int iThread) {
233+ out.println("Group " + tg.name() + ":");
234+ List<ThreadReference> tlist = tg.threads();
235+ int maxId = 0;
236+ int maxName = 0;
237+ for (int i = 0 ; i < tlist.size() ; i++) {
238+ ThreadReference thr = tlist.get(i);
239+ int len = Utils.description(thr).length();
240+ if (len > maxId) {
241+ maxId = len;
242+ }
243+ String name = thr.name();
244+ int iDot = name.lastIndexOf('.');
245+ if (iDot >= 0 && name.length() > iDot) {
246+ name = name.substring(iDot + 1);
247+ }
248+ if (name.length() > maxName) {
249+ maxName = name.length();
250+ }
251+ }
252+ String maxNumString = String.valueOf(iThread + tlist.size());
253+ int maxNumDigits = maxNumString.length();
254+ for (int i = 0 ; i < tlist.size() ; i++) {
255+ ThreadReference thr = tlist.get(i);
256+ char buf[] = new char[80];
257+ for (int j = 0; j < 79; j++) {
258+ buf[j] = ' ';
259+ }
260+ buf[79] = '\0';
261+ StringBuffer sbOut = new StringBuffer();
262+ sbOut.append(buf);
263+
264+ // Right-justify the thread number at start of output string
265+ String numString = String.valueOf(iThread + i + 1);
266+ sbOut.insert(maxNumDigits - numString.length(),
267+ numString);
268+ sbOut.insert(maxNumDigits, ".");
269+
270+ int iBuf = maxNumDigits + 2;
271+ sbOut.insert(iBuf, Utils.description(thr));
272+ iBuf += maxId + 1;
273+ String name = thr.name();
274+ int iDot = name.lastIndexOf('.');
275+ if (iDot >= 0 && name.length() > iDot) {
276+ name = name.substring(iDot + 1);
277+ }
278+ sbOut.insert(iBuf, name);
279+ iBuf += maxName + 1;
280+ sbOut.insert(iBuf, Utils.getStatus(thr));
281+ sbOut.setLength(79);
282+ out.println(sbOut.toString());
283+ }
284+ for (ThreadGroupReference tg0 : tg.threadGroups()) {
285+ if (!tg.equals(tg0)) { // TODO ref mgt
286+ iThread += printThreadGroup(out, tg0, iThread + tlist.size());
287+ }
288+ }
289+ return tlist.size();
290+ }
291+
292+ // Command: threadgroups
293+
294+ private void commandThreadGroups() throws NoSessionException {
295+ ThreadGroupIterator it = allThreadGroups();
296+ int cnt = 0;
297+ OutputSink out = env.getOutputSink();
298+ while (it.hasNext()) {
299+ ThreadGroupReference tg = it.nextThreadGroup();
300+ ++cnt;
301+ out.println("" + cnt + ". " + Utils.description(tg) + " " + tg.name());
302+ }
303+ out.show();
304+ }
305+
306+ // Command: thread
307+
308+ private void commandThread(StringTokenizer t) throws NoSessionException {
309+ if (!t.hasMoreTokens()) {
310+ env.error("Thread number not specified.");
311+ return;
312+ }
313+ ThreadReference thread = findThread(t.nextToken());
314+ if (thread != null) {
315+ //### Should notify user.
316+ context.setCurrentThread(thread);
317+ }
318+ }
319+
320+ // Command: threadgroup
321+
322+ private void commandThreadGroup(StringTokenizer t) throws NoSessionException {
323+ if (!t.hasMoreTokens()) {
324+ env.error("Threadgroup name not specified.");
325+ return;
326+ }
327+ String name = t.nextToken();
328+ ThreadGroupReference tg = findThreadGroup(name);
329+ if (tg == null) {
330+ env.failure(name + " is not a valid threadgroup name.");
331+ } else {
332+ //### Should notify user.
333+ setDefaultThreadGroup(tg);
334+ }
335+ }
336+
337+ // Command: run
338+
339+ private void commandRun(StringTokenizer t) throws NoSessionException {
340+ if (doLoad(false, t)) {
341+ env.notice("Running ...");
342+ }
343+ }
344+
345+ // Command: load
346+
347+ private void commandLoad(StringTokenizer t) throws NoSessionException {
348+ if (doLoad(true, t)) {}
349+ }
350+
351+ private boolean doLoad(boolean suspended,
352+ StringTokenizer t) throws NoSessionException {
353+
354+ String clname;
355+
356+ if (!t.hasMoreTokens()) {
357+ clname = context.getMainClassName();
358+ if (!clname.equals("")) {
359+ // Run from prevously-set class name.
360+ try {
361+ String vmArgs = context.getVmArguments();
362+ runtime.run(suspended,
363+ vmArgs,
364+ clname,
365+ context.getProgramArguments());
366+ return true;
367+ } catch (VMLaunchFailureException e) {
368+ env.failure("Attempt to launch main class \"" + clname + "\" failed.");
369+ }
370+ } else {
371+ env.failure("No main class specifed and no current default defined.");
372+ }
373+ } else {
374+ clname = t.nextToken();
375+ StringBuffer sbuf = new StringBuffer();
376+ // Allow VM arguments to be specified here?
377+ while (t.hasMoreTokens()) {
378+ String tok = t.nextToken();
379+ sbuf.append(tok);
380+ if (t.hasMoreTokens()) {
381+ sbuf.append(' ');
382+ }
383+ }
384+ String args = sbuf.toString();
385+ try {
386+ String vmArgs = context.getVmArguments();
387+ runtime.run(suspended, vmArgs, clname, args);
388+ context.setMainClassName(clname);
389+ //context.setVmArguments(vmArgs);
390+ context.setProgramArguments(args);
391+ return true;
392+ } catch (VMLaunchFailureException e) {
393+ env.failure("Attempt to launch main class \"" + clname + "\" failed.");
394+ }
395+ }
396+ return false;
397+ }
398+
399+ // Command: connect
400+
401+ private void commandConnect(StringTokenizer t) {
402+ try {
403+ LaunchTool.queryAndLaunchVM(runtime);
404+ } catch (VMLaunchFailureException e) {
405+ env.failure("Attempt to connect failed.");
406+ }
407+ }
408+
409+ // Command: attach
410+
411+ private void commandAttach(StringTokenizer t) {
412+ String portName;
413+ if (!t.hasMoreTokens()) {
414+ portName = context.getRemotePort();
415+ if (!portName.equals("")) {
416+ try {
417+ runtime.attach(portName);
418+ } catch (VMLaunchFailureException e) {
419+ env.failure("Attempt to attach to port \"" + portName + "\" failed.");
420+ }
421+ } else {
422+ env.failure("No port specifed and no current default defined.");
423+ }
424+ } else {
425+ portName = t.nextToken();
426+ try {
427+ runtime.attach(portName);
428+ } catch (VMLaunchFailureException e) {
429+ env.failure("Attempt to attach to port \"" + portName + "\" failed.");
430+ }
431+ context.setRemotePort(portName);
432+ }
433+ }
434+
435+ // Command: detach
436+
437+ private void commandDetach(StringTokenizer t) throws NoSessionException {
438+ runtime.detach();
439+ }
440+
441+ // Command: interrupt
442+
443+ private void commandInterrupt(StringTokenizer t) throws NoSessionException {
444+ runtime.interrupt();
445+ }
446+
447+ // Command: suspend
448+
449+ private void commandSuspend(StringTokenizer t) throws NoSessionException {
450+ if (!t.hasMoreTokens()) {
451+ // Suspend all threads in the current thread group.
452+ //### Issue: help message says default is all threads.
453+ //### Behavior here agrees with 'jdb', however.
454+ ThreadIterator ti = currentThreadGroupThreads();
455+ while (ti.hasNext()) {
456+ // TODO - don't suspend debugger threads
457+ ti.nextThread().suspend();
458+ }
459+ env.notice("All (non-system) threads suspended.");
460+ } else {
461+ while (t.hasMoreTokens()) {
462+ ThreadReference thread = findThread(t.nextToken());
463+ if (thread != null) {
464+ //thread.suspend();
465+ runtime.suspendThread(thread);
466+ }
467+ }
468+ }
469+ }
470+
471+ // Command: resume
472+
473+ private void commandResume(StringTokenizer t) throws NoSessionException {
474+ if (!t.hasMoreTokens()) {
475+ // Suspend all threads in the current thread group.
476+ //### Issue: help message says default is all threads.
477+ //### Behavior here agrees with 'jdb', however.
478+ ThreadIterator ti = currentThreadGroupThreads();
479+ while (ti.hasNext()) {
480+ // TODO - don't suspend debugger threads
481+ ti.nextThread().resume();
482+ }
483+ env.notice("All threads resumed.");
484+ } else {
485+ while (t.hasMoreTokens()) {
486+ ThreadReference thread = findThread(t.nextToken());
487+ if (thread != null) {
488+ //thread.resume();
489+ runtime.resumeThread(thread);
490+ }
491+ }
492+ }
493+ }
494+
495+ // Command: cont
496+
497+ private void commandCont() throws NoSessionException {
498+ try {
499+ runtime.go();
500+ } catch (VMNotInterruptedException e) {
501+ //### failure?
502+ env.notice("Target VM is already running.");
503+ }
504+ }
505+
506+ // Command: step
507+
508+ private void commandStep(StringTokenizer t) throws NoSessionException{
509+ ThreadReference current = context.getCurrentThread();
510+ if (current == null) {
511+ env.failure("No current thread.");
512+ return;
513+ }
514+ try {
515+ if (t.hasMoreTokens() &&
516+ t.nextToken().toLowerCase().equals("up")) {
517+ runtime.stepOut(current);
518+ } else {
519+ runtime.stepIntoLine(current);
520+ }
521+ } catch (AbsentInformationException e) {
522+ env.failure("No linenumber information available -- " +
523+ "Try \"stepi\" to step by instructions.");
524+ }
525+ }
526+
527+ // Command: stepi
528+
529+ private void commandStepi() throws NoSessionException {
530+ ThreadReference current = context.getCurrentThread();
531+ if (current == null) {
532+ env.failure("No current thread.");
533+ return;
534+ }
535+ runtime.stepIntoInstruction(current);
536+ }
537+
538+ // Command: next
539+
540+ private void commandNext() throws NoSessionException {
541+ ThreadReference current = context.getCurrentThread();
542+ if (current == null) {
543+ env.failure("No current thread.");
544+ return;
545+ }
546+ try {
547+ runtime.stepOverLine(current);
548+ } catch (AbsentInformationException e) {
549+ env.failure("No linenumber information available -- " +
550+ "Try \"nexti\" to step by instructions.");
551+ }
552+ }
553+
554+ // Command: nexti (NEW)
555+
556+ private void commandNexti() throws NoSessionException {
557+ ThreadReference current = context.getCurrentThread();
558+ if (current == null) {
559+ env.failure("No current thread.");
560+ return;
561+ }
562+ runtime.stepOverInstruction(current);
563+ }
564+
565+ // Command: kill
566+
567+ private void commandKill(StringTokenizer t) throws NoSessionException {
568+ //### Should change the way in which thread ids and threadgroup names
569+ //### are distinguished.
570+ if (!t.hasMoreTokens()) {
571+ env.error("Usage: kill <threadgroup name> or <thread id>");
572+ return;
573+ }
574+ while (t.hasMoreTokens()) {
575+ String idToken = t.nextToken();
576+ ThreadReference thread = findThread(idToken);
577+ if (thread != null) {
578+ runtime.stopThread(thread);
579+ env.notice("Thread " + thread.name() + " killed.");
580+ return;
581+ } else {
582+ /* Check for threadgroup name, NOT skipping "system". */
583+ //### Should skip "system"? Classic 'jdb' does this.
584+ //### Should deal with possible non-uniqueness of threadgroup names.
585+ ThreadGroupIterator itg = allThreadGroups();
586+ while (itg.hasNext()) {
587+ ThreadGroupReference tg = itg.nextThreadGroup();
588+ if (tg.name().equals(idToken)) {
589+ ThreadIterator it = new ThreadIterator(tg);
590+ while (it.hasNext()) {
591+ runtime.stopThread(it.nextThread());
592+ }
593+ env.notice("Threadgroup " + tg.name() + "killed.");
594+ return;
595+ }
596+ }
597+ env.failure("\"" + idToken +
598+ "\" is not a valid threadgroup or id.");
599+ }
600+ }
601+ }
602+
603+
604+ /*************
605+ // TODO
606+ private void commandCatchException(StringTokenizer t) throws NoSessionException {}
607+ // TODO
608+ private void commandIgnoreException(StringTokenizer t) throws NoSessionException {}
609+ *************/
610+
611+ // Command: up
612+
613+ //### Print current frame after command?
614+
615+ int readCount(StringTokenizer t) {
616+ int cnt = 1;
617+ if (t.hasMoreTokens()) {
618+ String idToken = t.nextToken();
619+ try {
620+ cnt = Integer.valueOf(idToken).intValue();
621+ } catch (NumberFormatException e) {
622+ cnt = -1;
623+ }
624+ }
625+ return cnt;
626+ }
627+
628+ void commandUp(StringTokenizer t) throws NoSessionException {
629+ ThreadReference current = context.getCurrentThread();
630+ if (current == null) {
631+ env.failure("No current thread.");
632+ return;
633+ }
634+ int nLevels = readCount(t);
635+ if (nLevels <= 0) {
636+ env.error("usage: up [n frames]");
637+ return;
638+ }
639+ try {
640+ int delta = context.moveCurrentFrameIndex(current, -nLevels);
641+ if (delta == 0) {
642+ env.notice("Already at top of stack.");
643+ } else if (-delta < nLevels) {
644+ env.notice("Moved up " + delta + " frames to top of stack.");
645+ }
646+ } catch (VMNotInterruptedException e) {
647+ env.failure("Target VM must be in interrupted state.");
648+ }
649+ }
650+
651+ private void commandDown(StringTokenizer t) throws NoSessionException {
652+ ThreadReference current = context.getCurrentThread();
653+ if (current == null) {
654+ env.failure("No current thread.");
655+ return;
656+ }
657+ int nLevels = readCount(t);
658+ if (nLevels <= 0) {
659+ env.error("usage: down [n frames]");
660+ return;
661+ }
662+ try {
663+ int delta = context.moveCurrentFrameIndex(current, nLevels);
664+ if (delta == 0) {
665+ env.notice("Already at bottom of stack.");
666+ } else if (delta < nLevels) {
667+ env.notice("Moved down " + delta + " frames to bottom of stack.");
668+ }
669+ } catch (VMNotInterruptedException e) {
670+ env.failure("Target VM must be in interrupted state.");
671+ }
672+ }
673+
674+ // Command: frame
675+
676+ private void commandFrame(StringTokenizer t) throws NoSessionException {
677+ ThreadReference current = context.getCurrentThread();
678+ if (current == null) {
679+ env.failure("No current thread.");
680+ return;
681+ }
682+ if (!t.hasMoreTokens()) {
683+ env.error("usage: frame <frame-index>");
684+ return;
685+ }
686+ String idToken = t.nextToken();
687+ int n;
688+ try {
689+ n = Integer.valueOf(idToken).intValue();
690+ } catch (NumberFormatException e) {
691+ n = 0;
692+ }
693+ if (n <= 0) {
694+ env.error("use positive frame index");
695+ return;
696+ }
697+ try {
698+ int delta = context.setCurrentFrameIndex(current, n);
699+ if (delta == 0) {
700+ env.notice("Frame unchanged.");
701+ } else if (delta < 0) {
702+ env.notice("Moved up " + -delta + " frames.");
703+ } else {
704+ env.notice("Moved down " + delta + " frames.");
705+ }
706+ } catch (VMNotInterruptedException e) {
707+ env.failure("Target VM must be in interrupted state.");
708+ }
709+ }
710+
711+ // Command: where
712+
713+ //### Should we insist that VM be interrupted here?
714+ //### There is an inconsistency between the 'where' command
715+ //### and 'up' and 'down' in this respect.
716+
717+ private void commandWhere(StringTokenizer t, boolean showPC)
718+ throws NoSessionException {
719+ ThreadReference current = context.getCurrentThread();
720+ if (!t.hasMoreTokens()) {
721+ if (current == null) {
722+ env.error("No thread specified.");
723+ return;
724+ }
725+ dumpStack(current, showPC);
726+ } else {
727+ String token = t.nextToken();
728+ if (token.toLowerCase().equals("all")) {
729+ ThreadIterator it = allThreads();
730+ while (it.hasNext()) {
731+ ThreadReference thread = it.next();
732+ out.println(thread.name() + ": ");
733+ dumpStack(thread, showPC);
734+ }
735+ } else {
736+ ThreadReference thread = findThread(t.nextToken());
737+ //### Do we want to set current thread here?
738+ //### Should notify user of change.
739+ if (thread != null) {
740+ context.setCurrentThread(thread);
741+ }
742+ dumpStack(thread, showPC);
743+ }
744+ }
745+ }
746+
747+ private void dumpStack(ThreadReference thread, boolean showPC) {
748+ //### Check for these.
749+ //env.failure("Thread no longer exists.");
750+ //env.failure("Target VM must be in interrupted state.");
751+ //env.failure("Current thread isn't suspended.");
752+ //### Should handle extremely long stack traces sensibly for user.
753+ List<StackFrame> stack = null;
754+ try {
755+ stack = thread.frames();
756+ } catch (IncompatibleThreadStateException e) {
757+ env.failure("Thread is not suspended.");
758+ }
759+ //### Fix this!
760+ //### Previously mishandled cases where thread was not current.
761+ //### Now, prints all of the stack regardless of current frame.
762+ int frameIndex = 0;
763+ //int frameIndex = context.getCurrentFrameIndex();
764+ if (stack == null) {
765+ env.failure("Thread is not running (no stack).");
766+ } else {
767+ OutputSink out = env.getOutputSink();
768+ int nFrames = stack.size();
769+ for (int i = frameIndex; i < nFrames; i++) {
770+ StackFrame frame = stack.get(i);
771+ Location loc = frame.location();
772+ Method meth = loc.method();
773+ out.print(" [" + (i + 1) + "] ");
774+ out.print(meth.declaringType().name());
775+ out.print('.');
776+ out.print(meth.name());
777+ out.print(" (");
778+ if (meth.isNative()) {
779+ out.print("native method");
780+ } else if (loc.lineNumber() != -1) {
781+ try {
782+ out.print(loc.sourceName());
783+ } catch (AbsentInformationException e) {
784+ out.print("<unknown>");
785+ }
786+ out.print(':');
787+ out.print(loc.lineNumber());
788+ }
789+ out.print(')');
790+ if (showPC) {
791+ long pc = loc.codeIndex();
792+ if (pc != -1) {
793+ out.print(", pc = " + pc);
794+ }
795+ }
796+ out.println();
797+ }
798+ out.show();
799+ }
800+ }
801+
802+ private void listEventRequests() throws NoSessionException {
803+ // Print set breakpoints
804+ List<EventRequestSpec> specs = runtime.eventRequestSpecs();
805+ if (specs.isEmpty()) {
806+ env.notice("No breakpoints/watchpoints/exceptions set.");
807+ } else {
808+ OutputSink out = env.getOutputSink();
809+ out.println("Current breakpoints/watchpoints/exceptions set:");
810+ for (EventRequestSpec bp : specs) {
811+ out.println("\t" + bp);
812+ }
813+ out.show();
814+ }
815+ }
816+
817+ private BreakpointSpec parseBreakpointSpec(String bptSpec) {
818+ StringTokenizer t = new StringTokenizer(bptSpec);
819+ BreakpointSpec bpSpec = null;
820+// try {
821+ String token = t.nextToken("@:( \t\n\r");
822+ // We can't use hasMoreTokens here because it will cause any leading
823+ // paren to be lost.
824+ String rest;
825+ try {
826+ rest = t.nextToken("").trim();
827+ } catch (NoSuchElementException e) {
828+ rest = null;
829+ }
830+ if ((rest != null) && rest.startsWith("@")) {
831+ t = new StringTokenizer(rest.substring(1));
832+ String sourceName = token;
833+ String lineToken = t.nextToken();
834+ int lineNumber = Integer.valueOf(lineToken).intValue();
835+ if (t.hasMoreTokens()) {
836+ return null;
837+ }
838+ bpSpec = runtime.createSourceLineBreakpoint(sourceName,
839+ lineNumber);
840+ } else if ((rest != null) && rest.startsWith(":")) {
841+ t = new StringTokenizer(rest.substring(1));
842+ String classId = token;
843+ String lineToken = t.nextToken();
844+ int lineNumber = Integer.valueOf(lineToken).intValue();
845+ if (t.hasMoreTokens()) {
846+ return null;
847+ }
848+ bpSpec = runtime.createClassLineBreakpoint(classId, lineNumber);
849+ } else {
850+ // Try stripping method from class.method token.
851+ int idot = token.lastIndexOf(".");
852+ if ( (idot <= 0) || /* No dot or dot in first char */
853+ (idot >= token.length() - 1) ) { /* dot in last char */
854+ return null;
855+ }
856+ String methodName = token.substring(idot + 1);
857+ String classId = token.substring(0, idot);
858+ List<String> argumentList = null;
859+ if (rest != null) {
860+ if (!rest.startsWith("(") || !rest.endsWith(")")) {
861+ //### Should throw exception with error message
862+ //out.println("Invalid method specification: "
863+ // + methodName + rest);
864+ return null;
865+ }
866+ // Trim the parens
867+ //### What about spaces in arglist?
868+ rest = rest.substring(1, rest.length() - 1);
869+ argumentList = new ArrayList<String>();
870+ t = new StringTokenizer(rest, ",");
871+ while (t.hasMoreTokens()) {
872+ argumentList.add(t.nextToken());
873+ }
874+ }
875+ bpSpec = runtime.createMethodBreakpoint(classId,
876+ methodName,
877+ argumentList);
878+ }
879+// } catch (Exception e) {
880+// env.error("Exception attempting to create breakpoint: " + e);
881+// return null;
882+// }
883+ return bpSpec;
884+ }
885+
886+ private void commandStop(StringTokenizer t) throws NoSessionException {
887+ String token;
888+
889+ if (!t.hasMoreTokens()) {
890+ listEventRequests();
891+ } else {
892+ token = t.nextToken();
893+ // Ignore optional "at" or "in" token.
894+ // Allowed for backward compatibility.
895+ if (token.equals("at") || token.equals("in")) {
896+ if (t.hasMoreTokens()) {
897+ token = t.nextToken();
898+ } else {
899+ env.error("Missing breakpoint specification.");
900+ return;
901+ }
902+ }
903+ BreakpointSpec bpSpec = parseBreakpointSpec(token);
904+ if (bpSpec != null) {
905+ //### Add sanity-checks for deferred breakpoint.
906+ runtime.install(bpSpec);
907+ } else {
908+ env.error("Ill-formed breakpoint specification.");
909+ }
910+ }
911+ }
912+
913+ private void commandClear(StringTokenizer t) throws NoSessionException {
914+ if (!t.hasMoreTokens()) {
915+ // Print set breakpoints
916+ listEventRequests();
917+ return;
918+ }
919+ //### need 'clear all'
920+ BreakpointSpec bpSpec = parseBreakpointSpec(t.nextToken());
921+ if (bpSpec != null) {
922+ List<EventRequestSpec> specs = runtime.eventRequestSpecs();
923+
924+ if (specs.isEmpty()) {
925+ env.notice("No breakpoints set.");
926+ } else {
927+ List<EventRequestSpec> toDelete = new ArrayList<EventRequestSpec>();
928+ for (EventRequestSpec spec : specs) {
929+ if (spec.equals(bpSpec)) {
930+ toDelete.add(spec);
931+ }
932+ }
933+ // The request used for matching should be found
934+ if (toDelete.size() <= 1) {
935+ env.notice("No matching breakpoint set.");
936+ }
937+ for (EventRequestSpec spec : toDelete) {
938+ runtime.delete(spec);
939+ }
940+ }
941+ } else {
942+ env.error("Ill-formed breakpoint specification.");
943+ }
944+ }
945+
946+ // Command: list
947+
948+ private void commandList(StringTokenizer t) throws NoSessionException {
949+ ThreadReference current = context.getCurrentThread();
950+ if (current == null) {
951+ env.error("No thread specified.");
952+ return;
953+ }
954+ Location loc;
955+ try {
956+ StackFrame frame = context.getCurrentFrame(current);
957+ if (frame == null) {
958+ env.failure("Thread has not yet begun execution.");
959+ return;
960+ }
961+ loc = frame.location();
962+ } catch (VMNotInterruptedException e) {
963+ env.failure("Target VM must be in interrupted state.");
964+ return;
965+ }
966+ SourceModel source = sourceManager.sourceForLocation(loc);
967+ if (source == null) {
968+ if (loc.method().isNative()) {
969+ env.failure("Current method is native.");
970+ return;
971+ }
972+ env.failure("No source available for " + Utils.locationString(loc) + ".");
973+ return;
974+ }
975+ ReferenceType refType = loc.declaringType();
976+ int lineno = loc.lineNumber();
977+ if (t.hasMoreTokens()) {
978+ String id = t.nextToken();
979+ // See if token is a line number.
980+ try {
981+ lineno = Integer.valueOf(id).intValue();
982+ } catch (NumberFormatException nfe) {
983+ // It isn't -- see if it's a method name.
984+ List<Method> meths = refType.methodsByName(id);
985+ if (meths == null || meths.size() == 0) {
986+ env.failure(id +
987+ " is not a valid line number or " +
988+ "method name for class " +
989+ refType.name());
990+ return;
991+ } else if (meths.size() > 1) {
992+ env.failure(id +
993+ " is an ambiguous method name in" +
994+ refType.name());
995+ return;
996+ }
997+ loc = meths.get(0).location();
998+ lineno = loc.lineNumber();
999+ }
1000+ }
1001+ int startLine = (lineno > 4) ? lineno - 4 : 1;
1002+ int endLine = startLine + 9;
1003+ String sourceLine = source.sourceLine(lineno);
1004+ if (sourceLine == null) {
1005+ env.failure("" +
1006+ lineno +
1007+ " is an invalid line number for " +
1008+ refType.name());
1009+ } else {
1010+ OutputSink out = env.getOutputSink();
1011+ for (int i = startLine; i <= endLine; i++) {
1012+ sourceLine = source.sourceLine(i);
1013+ if (sourceLine == null) {
1014+ break;
1015+ }
1016+ out.print(i);
1017+ out.print("\t");
1018+ if (i == lineno) {
1019+ out.print("=> ");
1020+ } else {
1021+ out.print(" ");
1022+ }
1023+ out.println(sourceLine);
1024+ }
1025+ out.show();
1026+ }
1027+ }
1028+
1029+ // Command: use
1030+ // Get or set the source file path list.
1031+
1032+ private void commandUse(StringTokenizer t) {
1033+ if (!t.hasMoreTokens()) {
1034+ out.println(sourceManager.getSourcePath().asString());
1035+ } else {
1036+ //### Should throw exception for invalid path.
1037+ //### E.g., vetoable property change.
1038+ sourceManager.setSourcePath(new SearchPath(t.nextToken()));
1039+ }
1040+ }
1041+
1042+ // Command: sourcepath
1043+ // Get or set the source file path list. (Alternate to 'use'.)
1044+
1045+ private void commandSourcepath(StringTokenizer t) {
1046+ if (!t.hasMoreTokens()) {
1047+ out.println(sourceManager.getSourcePath().asString());
1048+ } else {
1049+ //### Should throw exception for invalid path.
1050+ //### E.g., vetoable property change.
1051+ sourceManager.setSourcePath(new SearchPath(t.nextToken()));
1052+ }
1053+ }
1054+
1055+ // Command: classpath
1056+ // Get or set the class file path list.
1057+
1058+ private void commandClasspath(StringTokenizer t) {
1059+ if (!t.hasMoreTokens()) {
1060+ out.println(classManager.getClassPath().asString());
1061+ } else {
1062+ //### Should throw exception for invalid path.
1063+ //### E.g., vetoable property change.
1064+ classManager.setClassPath(new SearchPath(t.nextToken()));
1065+ }
1066+ }
1067+
1068+ // Command: view
1069+ // Display source for source file or class.
1070+
1071+ private void commandView(StringTokenizer t) throws NoSessionException {
1072+ if (!t.hasMoreTokens()) {
1073+ env.error("Argument required");
1074+ } else {
1075+ String name = t.nextToken();
1076+ if (name.endsWith(".java") ||
1077+ name.indexOf(File.separatorChar) >= 0) {
1078+ env.viewSource(name);
1079+ } else {
1080+ //### JDI crashes taking line number for class.
1081+ /*****
1082+ ReferenceType cls = findClass(name);
1083+ if (cls != null) {
1084+ env.viewLocation(cls.location());
1085+ } else {
1086+ env.failure("No such class");
1087+ }
1088+ *****/
1089+ String fileName = name.replace('.', File.separatorChar) + ".java";
1090+ env.viewSource(fileName);
1091+ }
1092+ }
1093+ }
1094+
1095+ // Command: locals
1096+ // Print all local variables in current stack frame.
1097+
1098+ private void commandLocals() throws NoSessionException {
1099+ ThreadReference current = context.getCurrentThread();
1100+ if (current == null) {
1101+ env.failure("No default thread specified: " +
1102+ "use the \"thread\" command first.");
1103+ return;
1104+ }
1105+ StackFrame frame;
1106+ try {
1107+ frame = context.getCurrentFrame(current);
1108+ if (frame == null) {
1109+ env.failure("Thread has not yet created any stack frames.");
1110+ return;
1111+ }
1112+ } catch (VMNotInterruptedException e) {
1113+ env.failure("Target VM must be in interrupted state.");
1114+ return;
1115+ }
1116+
1117+ List<LocalVariable> vars;
1118+ try {
1119+ vars = frame.visibleVariables();
1120+ if (vars == null || vars.size() == 0) {
1121+ env.failure("No local variables");
1122+ return;
1123+ }
1124+ } catch (AbsentInformationException e) {
1125+ env.failure("Local variable information not available." +
1126+ " Compile with -g to generate variable information");
1127+ return;
1128+ }
1129+
1130+ OutputSink out = env.getOutputSink();
1131+ out.println("Method arguments:");
1132+ for (LocalVariable var : vars) {
1133+ if (var.isArgument()) {
1134+ printVar(out, var, frame);
1135+ }
1136+ }
1137+ out.println("Local variables:");
1138+ for (LocalVariable var : vars) {
1139+ if (!var.isArgument()) {
1140+ printVar(out, var, frame);
1141+ }
1142+ }
1143+ out.show();
1144+ return;
1145+ }
1146+
1147+ /**
1148+ * Command: monitor
1149+ * Monitor an expression
1150+ */
1151+ private void commandMonitor(StringTokenizer t) throws NoSessionException {
1152+ if (!t.hasMoreTokens()) {
1153+ env.error("Argument required");
1154+ } else {
1155+ env.getMonitorListModel().add(t.nextToken(""));
1156+ }
1157+ }
1158+
1159+ /**
1160+ * Command: unmonitor
1161+ * Unmonitor an expression
1162+ */
1163+ private void commandUnmonitor(StringTokenizer t) throws NoSessionException {
1164+ if (!t.hasMoreTokens()) {
1165+ env.error("Argument required");
1166+ } else {
1167+ env.getMonitorListModel().remove(t.nextToken(""));
1168+ }
1169+ }
1170+
1171+ // Print a stack variable.
1172+
1173+ private void printVar(OutputSink out, LocalVariable var, StackFrame frame) {
1174+ out.print(" " + var.name());
1175+ if (var.isVisible(frame)) {
1176+ Value val = frame.getValue(var);
1177+ out.println(" = " + val.toString());
1178+ } else {
1179+ out.println(" is not in scope");
1180+ }
1181+ }
1182+
1183+ // Command: print
1184+ // Evaluate an expression.
1185+
1186+ private void commandPrint(StringTokenizer t, boolean dumpObject) throws NoSessionException {
1187+ if (!t.hasMoreTokens()) {
1188+ //### Probably confused if expresion contains whitespace.
1189+ env.error("No expression specified.");
1190+ return;
1191+ }
1192+ ThreadReference current = context.getCurrentThread();
1193+ if (current == null) {
1194+ env.failure("No default thread specified: " +
1195+ "use the \"thread\" command first.");
1196+ return;
1197+ }
1198+ StackFrame frame;
1199+ try {
1200+ frame = context.getCurrentFrame(current);
1201+ if (frame == null) {
1202+ env.failure("Thread has not yet created any stack frames.");
1203+ return;
1204+ }
1205+ } catch (VMNotInterruptedException e) {
1206+ env.failure("Target VM must be in interrupted state.");
1207+ return;
1208+ }
1209+ while (t.hasMoreTokens()) {
1210+ String expr = t.nextToken("");
1211+ Value val = null;
1212+ try {
1213+ val = runtime.evaluate(frame, expr);
1214+ } catch(Exception e) {
1215+ env.error("Exception: " + e);
1216+ //### Fix this!
1217+ }
1218+ if (val == null) {
1219+ return; // Error message already printed
1220+ }
1221+ OutputSink out = env.getOutputSink();
1222+ if (dumpObject && (val instanceof ObjectReference) &&
1223+ !(val instanceof StringReference)) {
1224+ ObjectReference obj = (ObjectReference)val;
1225+ ReferenceType refType = obj.referenceType();
1226+ out.println(expr + " = " + val.toString() + " {");
1227+ dump(out, obj, refType, refType);
1228+ out.println("}");
1229+ } else {
1230+ out.println(expr + " = " + val.toString());
1231+ }
1232+ out.show();
1233+ }
1234+ }
1235+
1236+ private void dump(OutputSink out,
1237+ ObjectReference obj, ReferenceType refType,
1238+ ReferenceType refTypeBase) {
1239+ for (Field field : refType.fields()) {
1240+ out.print(" ");
1241+ if (!refType.equals(refTypeBase)) {
1242+ out.print(refType.name() + ".");
1243+ }
1244+ out.print(field.name() + ": ");
1245+ Object o = obj.getValue(field);
1246+ out.println((o == null) ? "null" : o.toString()); // Bug ID 4374471
1247+ }
1248+ if (refType instanceof ClassType) {
1249+ ClassType sup = ((ClassType)refType).superclass();
1250+ if (sup != null) {
1251+ dump(out, obj, sup, refTypeBase);
1252+ }
1253+ } else if (refType instanceof InterfaceType) {
1254+ for (InterfaceType sup : ((InterfaceType)refType).superinterfaces()) {
1255+ dump(out, obj, sup, refTypeBase);
1256+ }
1257+ }
1258+ }
1259+
1260+ /*
1261+ * Display help message.
1262+ */
1263+
1264+ private void help() {
1265+ out.println("** command list **");
1266+ out.println("threads [threadgroup] -- list threads");
1267+ out.println("thread <thread id> -- set default thread");
1268+ out.println("suspend [thread id(s)] -- suspend threads (default: all)");
1269+ out.println("resume [thread id(s)] -- resume threads (default: all)");
1270+ out.println("where [thread id] | all -- dump a thread's stack");
1271+ out.println("wherei [thread id] | all -- dump a thread's stack, with pc info");
1272+ out.println("threadgroups -- list threadgroups");
1273+ out.println("threadgroup <name> -- set current threadgroup\n");
1274+// out.println("print <expression> -- print value of expression");
1275+ out.println("dump <expression> -- print all object information\n");
1276+// out.println("eval <expression> -- evaluate expression (same as print)");
1277+ out.println("locals -- print all local variables in current stack frame\n");
1278+ out.println("classes -- list currently known classes");
1279+ out.println("methods <class id> -- list a class's methods\n");
1280+ out.println("stop [in] <class id>.<method>[(argument_type,...)] -- set a breakpoint in a method");
1281+ out.println("stop [at] <class id>:<line> -- set a breakpoint at a line");
1282+ out.println("up [n frames] -- move up a thread's stack");
1283+ out.println("down [n frames] -- move down a thread's stack");
1284+ out.println("frame <frame-id> -- to a frame");
1285+ out.println("clear <class id>.<method>[(argument_type,...)] -- clear a breakpoint in a method");
1286+ out.println("clear <class id>:<line> -- clear a breakpoint at a line");
1287+ out.println("clear -- list breakpoints");
1288+ out.println("step -- execute current line");
1289+ out.println("step up -- execute until the current method returns to its caller");
1290+ out.println("stepi -- execute current instruction");
1291+ out.println("next -- step one line (step OVER calls)");
1292+ out.println("nexti -- step one instruction (step OVER calls)");
1293+ out.println("cont -- continue execution from breakpoint\n");
1294+// out.println("catch <class id> -- break for the specified exception");
1295+// out.println("ignore <class id> -- ignore when the specified exception\n");
1296+ out.println("view classname|filename -- display source file");
1297+ out.println("list [line number|method] -- print source code context at line or method");
1298+ out.println("use <source file path> -- display or change the source path\n");
1299+//### new
1300+ out.println("sourcepath <source file path> -- display or change the source path\n");
1301+//### new
1302+ out.println("classpath <class file path> -- display or change the class path\n");
1303+ out.println("monitor <expression> -- evaluate an expression each time the program stops\n");
1304+ out.println("unmonitor <monitor#> -- delete a monitor\n");
1305+ out.println("read <filename> -- read and execute a command file\n");
1306+// out.println("memory -- report memory usage");
1307+// out.println("gc -- free unused objects\n");
1308+ out.println("run <class> [args] -- start execution of a Java class");
1309+ out.println("run -- re-execute last class run");
1310+ out.println("load <class> [args] -- start execution of a Java class, initially suspended");
1311+ out.println("load -- re-execute last class run, initially suspended");
1312+ out.println("attach <portname> -- debug existing process\n");
1313+ out.println("detach -- detach from debuggee process\n");
1314+ out.println("kill <thread(group)> -- kill a thread or threadgroup\n");
1315+ out.println("!! -- repeat last command");
1316+ out.println("help (or ?) -- list commands");
1317+ out.println("exit (or quit) -- exit debugger");
1318+ }
1319+
1320+ /*
1321+ * Execute a command.
1322+ */
1323+
1324+ public void executeCommand(String command) {
1325+ //### Treatment of 'out' here is dirty...
1326+ out = env.getOutputSink();
1327+ if (echo) {
1328+ out.println(">>> " + command);
1329+ }
1330+ StringTokenizer t = new StringTokenizer(command);
1331+ try {
1332+ String cmd;
1333+ if (t.hasMoreTokens()) {
1334+ cmd = t.nextToken().toLowerCase();
1335+ lastCommand = cmd;
1336+ } else {
1337+ cmd = lastCommand;
1338+ }
1339+ if (cmd.equals("print")) {
1340+ commandPrint(t, false);
1341+ } else if (cmd.equals("eval")) {
1342+ commandPrint(t, false);
1343+ } else if (cmd.equals("dump")) {
1344+ commandPrint(t, true);
1345+ } else if (cmd.equals("locals")) {
1346+ commandLocals();
1347+ } else if (cmd.equals("classes")) {
1348+ commandClasses();
1349+ } else if (cmd.equals("methods")) {
1350+ commandMethods(t);
1351+ } else if (cmd.equals("threads")) {
1352+ commandThreads(t);
1353+ } else if (cmd.equals("thread")) {
1354+ commandThread(t);
1355+ } else if (cmd.equals("suspend")) {
1356+ commandSuspend(t);
1357+ } else if (cmd.equals("resume")) {
1358+ commandResume(t);
1359+ } else if (cmd.equals("cont")) {
1360+ commandCont();
1361+ } else if (cmd.equals("threadgroups")) {
1362+ commandThreadGroups();
1363+ } else if (cmd.equals("threadgroup")) {
1364+ commandThreadGroup(t);
1365+ } else if (cmd.equals("run")) {
1366+ commandRun(t);
1367+ } else if (cmd.equals("load")) {
1368+ commandLoad(t);
1369+ } else if (cmd.equals("connect")) {
1370+ commandConnect(t);
1371+ } else if (cmd.equals("attach")) {
1372+ commandAttach(t);
1373+ } else if (cmd.equals("detach")) {
1374+ commandDetach(t);
1375+ } else if (cmd.equals("interrupt")) {
1376+ commandInterrupt(t);
1377+//### Not implemented.
1378+// } else if (cmd.equals("catch")) {
1379+// commandCatchException(t);
1380+//### Not implemented.
1381+// } else if (cmd.equals("ignore")) {
1382+// commandIgnoreException(t);
1383+ } else if (cmd.equals("step")) {
1384+ commandStep(t);
1385+ } else if (cmd.equals("stepi")) {
1386+ commandStepi();
1387+ } else if (cmd.equals("next")) {
1388+ commandNext();
1389+ } else if (cmd.equals("nexti")) {
1390+ commandNexti();
1391+ } else if (cmd.equals("kill")) {
1392+ commandKill(t);
1393+ } else if (cmd.equals("where")) {
1394+ commandWhere(t, false);
1395+ } else if (cmd.equals("wherei")) {
1396+ commandWhere(t, true);
1397+ } else if (cmd.equals("up")) {
1398+ commandUp(t);
1399+ } else if (cmd.equals("down")) {
1400+ commandDown(t);
1401+ } else if (cmd.equals("frame")) {
1402+ commandFrame(t);
1403+ } else if (cmd.equals("stop")) {
1404+ commandStop(t);
1405+ } else if (cmd.equals("clear")) {
1406+ commandClear(t);
1407+ } else if (cmd.equals("list")) {
1408+ commandList(t);
1409+ } else if (cmd.equals("use")) {
1410+ commandUse(t);
1411+ } else if (cmd.equals("sourcepath")) {
1412+ commandSourcepath(t);
1413+ } else if (cmd.equals("classpath")) {
1414+ commandClasspath(t);
1415+ } else if (cmd.equals("monitor")) {
1416+ commandMonitor(t);
1417+ } else if (cmd.equals("unmonitor")) {
1418+ commandUnmonitor(t);
1419+ } else if (cmd.equals("view")) {
1420+ commandView(t);
1421+// } else if (cmd.equals("read")) {
1422+// readCommand(t);
1423+ } else if (cmd.equals("help") || cmd.equals("?")) {
1424+ help();
1425+ } else if (cmd.equals("quit") || cmd.equals("exit")) {
1426+ try {
1427+ runtime.detach();
1428+ } catch (NoSessionException e) {
1429+ // ignore
1430+ }
1431+ env.terminate();
1432+ } else {
1433+ //### Dubious repeat-count feature inherited from 'jdb'
1434+ if (t.hasMoreTokens()) {
1435+ try {
1436+ int repeat = Integer.parseInt(cmd);
1437+ String subcom = t.nextToken("");
1438+ while (repeat-- > 0) {
1439+ executeCommand(subcom);
1440+ }
1441+ return;
1442+ } catch (NumberFormatException exc) {
1443+ }
1444+ }
1445+ out.println("huh? Try help...");
1446+ out.flush();
1447+ }
1448+ } catch (NoSessionException e) {
1449+ out.println("There is no currently attached VM session.");
1450+ out.flush();
1451+ } catch (Exception e) {
1452+ out.println("Internal exception: " + e.toString());
1453+ out.flush();
1454+ System.out.println("JDB internal exception: " + e.toString());
1455+ e.printStackTrace();
1456+ }
1457+ out.show();
1458+ }
1459+}